@@ -47,14 +47,19 @@ import { observeWatchable, registerNestedSync } from "#src/trackable_value.js";
47
47
import { isWithinSelectionPanel } from "#src/ui/selection_details.js" ;
48
48
import type { Uint64Map } from "#src/uint64_map.js" ;
49
49
import { setClipboard } from "#src/util/clipboard.js" ;
50
- import { useWhiteBackground } from "#src/util/color.js" ;
50
+ import {
51
+ packColor ,
52
+ serializeColor ,
53
+ TrackableRGB ,
54
+ useWhiteBackground ,
55
+ } from "#src/util/color.js" ;
51
56
import { RefCounted } from "#src/util/disposable.js" ;
52
57
import { measureElementClone } from "#src/util/dom.js" ;
53
- import type { vec3 } from "#src/util/geom.js" ;
54
- import { kOneVec , vec4 } from "#src/util/geom.js" ;
58
+ import { kOneVec , vec3 , vec4 } from "#src/util/geom.js" ;
55
59
import { NullarySignal } from "#src/util/signal.js" ;
56
60
import { Uint64 } from "#src/util/uint64.js" ;
57
61
import { withSharedVisibility } from "#src/visibility_priority/frontend.js" ;
62
+ import { ColorWidget } from "#src/widget/color.js" ;
58
63
import { makeCopyButton } from "#src/widget/copy_button.js" ;
59
64
import { makeEyeButton } from "#src/widget/eye_button.js" ;
60
65
import { makeFilterButton } from "#src/widget/filter_button.js" ;
@@ -347,6 +352,8 @@ const segmentWidgetTemplate = (() => {
347
352
filterElement . classList . add ( "neuroglancer-segment-list-entry-filter" ) ;
348
353
const filterIndex = template . childElementCount ;
349
354
template . appendChild ( filterElement ) ;
355
+ const colorWidgetIndex = template . childElementCount ;
356
+ template . appendChild ( ColorWidget . template ( ) ) ;
350
357
return {
351
358
template,
352
359
copyContainerIndex,
@@ -357,6 +364,7 @@ const segmentWidgetTemplate = (() => {
357
364
labelIndex,
358
365
filterIndex,
359
366
starIndex,
367
+ colorWidgetIndex,
360
368
unmappedIdIndex : - 1 ,
361
369
unmappedCopyIndex : - 1 ,
362
370
} ;
@@ -426,7 +434,7 @@ function makeRegisterSegmentWidgetEventHandlers(
426
434
const onMouseEnter = ( event : Event ) => {
427
435
const entryElement = event . currentTarget as HTMLElement ;
428
436
const idString = entryElement . dataset . id ! ;
429
- const id = tempStatedColor ;
437
+ const id = tempObjectId ;
430
438
id . tryParseString ( idString ) ;
431
439
displayState . segmentSelectionState . set ( id ) ;
432
440
if ( ! isWithinSelectionPanel ( entryElement ) ) {
@@ -437,7 +445,7 @@ function makeRegisterSegmentWidgetEventHandlers(
437
445
const selectHandler = ( event : Event ) => {
438
446
const entryElement = event . currentTarget as HTMLElement ;
439
447
const idString = entryElement . dataset . id ! ;
440
- const id = tempStatedColor ;
448
+ const id = tempObjectId ;
441
449
id . tryParseString ( idString ) ;
442
450
displayState . selectSegment (
443
451
id ,
@@ -470,7 +478,7 @@ function makeRegisterSegmentWidgetEventHandlers(
470
478
const visibleCheckboxHandler = ( event : Event ) => {
471
479
const entryElement = getEntryElement ( event ) ;
472
480
const idString = entryElement . dataset . id ! ;
473
- const id = tempStatedColor ;
481
+ const id = tempObjectId ;
474
482
id . tryParseString ( idString ) ;
475
483
const { selectedSegments, visibleSegments } =
476
484
displayState . segmentationGroupState . value ;
@@ -486,7 +494,7 @@ function makeRegisterSegmentWidgetEventHandlers(
486
494
const filterHandler = ( event : Event ) => {
487
495
const entryElement = getEntryElement ( event ) ;
488
496
const idString = entryElement . dataset . id ! ;
489
- const id = tempStatedColor ;
497
+ const id = tempObjectId ;
490
498
id . tryParseString ( idString ) ;
491
499
displayState . filterBySegmentLabel ( id ) ;
492
500
event . stopPropagation ( ) ;
@@ -504,7 +512,7 @@ function makeRegisterSegmentWidgetEventHandlers(
504
512
}
505
513
const entryElement = event . currentTarget as HTMLElement ;
506
514
const idString = entryElement . dataset . id ! ;
507
- const id = tempStatedColor ;
515
+ const id = tempObjectId ;
508
516
id . tryParseString ( idString ) ;
509
517
displayState . moveToSegment ( id ) ;
510
518
} ;
@@ -539,11 +547,35 @@ function makeRegisterSegmentWidgetEventHandlers(
539
547
starButton . addEventListener ( "click" , ( event : MouseEvent ) => {
540
548
const entryElement = getEntryElement ( event ) ;
541
549
const idString = entryElement . dataset . id ! ;
542
- const id = tempStatedColor ;
550
+ const id = tempObjectId ;
543
551
id . tryParseString ( idString ) ;
544
552
const { selectedSegments } = displayState . segmentationGroupState . value ;
545
553
selectedSegments . set ( id , ! selectedSegments . has ( id ) ) ;
546
554
} ) ;
555
+
556
+ const trackableRGB = new TrackableRGB ( vec3 . fromValues ( 0 , 0 , 0 ) ) ;
557
+ trackableRGB . changed . add ( ( ) => {
558
+ const testU = new Uint64 ( packColor ( trackableRGB . value ) ) ;
559
+ const idString = element . dataset . id ! ;
560
+ const id = tempObjectId ;
561
+ id . tryParseString ( idString ) ;
562
+ displayState . segmentStatedColors . value . delete ( id ) ;
563
+ displayState . segmentStatedColors . value . set ( id , testU ) ;
564
+ } ) ;
565
+
566
+ // TODO, need to register disposer?
567
+ new ColorWidget (
568
+ trackableRGB ,
569
+ undefined ,
570
+ children [ template . colorWidgetIndex ] as HTMLInputElement ,
571
+ ( ) => {
572
+ const idString = element . dataset . id ! ;
573
+ const id = tempObjectId ;
574
+ id . tryParseString ( idString ) ;
575
+ displayState . segmentStatedColors . value . delete ( id ) ;
576
+ } ,
577
+ false ,
578
+ ) ;
547
579
} ;
548
580
}
549
581
@@ -641,7 +673,7 @@ export class SegmentWidgetFactory<Template extends SegmentWidgetTemplate> {
641
673
}
642
674
643
675
update ( container : HTMLElement ) {
644
- const id = tempStatedColor ;
676
+ const id = tempObjectId ;
645
677
const idString = container . dataset . id ;
646
678
if ( idString === undefined ) return ;
647
679
id . parseString ( idString ) ;
@@ -670,19 +702,26 @@ export class SegmentWidgetFactory<Template extends SegmentWidgetTemplate> {
670
702
const idContainer = stickyChildren [
671
703
template . idContainerIndex
672
704
] as HTMLElement ;
705
+ let color = getBaseObjectColor ( this . displayState , mapped ) as vec3 ;
673
706
setSegmentIdElementStyle (
674
707
idContainer . children [ template . idIndex ] as HTMLElement ,
675
- getBaseObjectColor ( this . displayState , mapped ) as vec3 ,
708
+ color ,
709
+ ) ;
710
+ const isOverridden =
711
+ ! ! this . displayState ?. segmentStatedColors . value . has ( mapped ) ;
712
+ setColorWidgetColor (
713
+ children [ template . colorWidgetIndex ] as HTMLInputElement ,
714
+ color ,
715
+ isOverridden ,
676
716
) ;
677
717
const { unmappedIdIndex } = template ;
678
718
if ( unmappedIdIndex !== - 1 ) {
679
719
let unmappedIdString : string | undefined ;
680
- let color : vec3 ;
681
720
if (
682
721
displayState ! . baseSegmentColoring . value &&
683
722
( unmappedIdString = container . dataset . unmappedId ) !== undefined
684
723
) {
685
- const unmappedId = tempStatedColor ;
724
+ const unmappedId = tempObjectId ;
686
725
unmappedId . parseString ( unmappedIdString ) ;
687
726
color = getBaseObjectColor ( this . displayState , unmappedId ) as vec3 ;
688
727
} else {
@@ -692,6 +731,13 @@ export class SegmentWidgetFactory<Template extends SegmentWidgetTemplate> {
692
731
idContainer . children [ unmappedIdIndex ] as HTMLElement ,
693
732
color ,
694
733
) ;
734
+ const isOverridden =
735
+ ! ! this . displayState ?. segmentStatedColors . value . has ( mapped ) ;
736
+ setColorWidgetColor (
737
+ children [ template . colorWidgetIndex ] as HTMLInputElement ,
738
+ color ,
739
+ isOverridden ,
740
+ ) ;
695
741
}
696
742
}
697
743
}
@@ -701,6 +747,15 @@ function setSegmentIdElementStyle(element: HTMLElement, color: vec3) {
701
747
element . style . color = useWhiteBackground ( color ) ? "white" : "black" ;
702
748
}
703
749
750
+ function setColorWidgetColor (
751
+ element : HTMLInputElement ,
752
+ color : vec3 ,
753
+ isOverridden : boolean ,
754
+ ) {
755
+ element . value = serializeColor ( color . subarray ( 0 , 3 ) as vec3 ) ;
756
+ element . classList . toggle ( "overridden" , isOverridden ) ;
757
+ }
758
+
704
759
export class SegmentWidgetWithExtraColumnsFactory extends SegmentWidgetFactory < SegmentWidgetWithExtraColumnsTemplate > {
705
760
segmentPropertyMap : PreprocessedSegmentPropertyMap | undefined ;
706
761
numericalProperties : InlineSegmentNumericalProperty [ ] ;
@@ -885,6 +940,9 @@ export function registerCallbackWhenSegmentationDisplayStateChanged(
885
940
displayState . baseSegmentColoring . changed . add ( callback ) ,
886
941
) ;
887
942
context . registerDisposer ( displayState . hoverHighlight . changed . add ( callback ) ) ;
943
+ context . registerDisposer (
944
+ displayState . segmentStatedColors . changed . add ( callback ) ,
945
+ ) ;
888
946
}
889
947
890
948
export function registerRedrawWhenSegmentationDisplayStateChanged (
@@ -941,6 +999,7 @@ export function registerRedrawWhenSegmentationDisplayState3DChanged(
941
999
* Temporary values used by getObjectColor.
942
1000
*/
943
1001
const tempColor = vec4 . create ( ) ;
1002
+ const tempObjectId = new Uint64 ( ) ;
944
1003
const tempStatedColor = new Uint64 ( ) ;
945
1004
946
1005
export function getBaseObjectColor (
0 commit comments