Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CC-163 Add annotation color as a tool in the layer's render tab #53

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 61 additions & 1 deletion src/layer/annotation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ import { RenderLayerRole } from "#src/renderlayer.js";
import type { SegmentationDisplayState } from "#src/segmentation_display_state/frontend.js";
import type { TrackableBoolean } from "#src/trackable_boolean.js";
import { TrackableBooleanCheckbox } from "#src/trackable_boolean.js";
import { makeCachedLazyDerivedWatchableValue } from "#src/trackable_value.js";
import {
makeCachedLazyDerivedWatchableValue,
observeWatchable,
} from "#src/trackable_value.js";
import type {
AnnotationLayerView,
MergedAnnotationStates,
Expand All @@ -69,6 +72,12 @@ import {
import { NullarySignal } from "#src/util/signal.js";
import { DependentViewWidget } from "#src/widget/dependent_view_widget.js";
import { makeHelpButton } from "#src/widget/help_button.js";
import {
addLayerControlToOptionsTab,
type LayerControlDefinition,
registerLayerControl,
} from "#src/widget/layer_control.js";
import { colorLayerControl } from "#src/widget/layer_control_color.js";
import { LayerReferenceWidget } from "#src/widget/layer_reference.js";
import { makeMaximizeButton } from "#src/widget/maximize_button.js";
import { RenderScaleWidget } from "#src/widget/render_scale_widget.js";
Expand All @@ -87,6 +96,7 @@ const CROSS_SECTION_RENDER_SCALE_JSON_KEY = "crossSectionAnnotationSpacing";
const PROJECTION_RENDER_SCALE_JSON_KEY = "projectionAnnotationSpacing";
const SHADER_JSON_KEY = "shader";
const SHADER_CONTROLS_JSON_KEY = "shaderControls";
const ANNOTATION_COLOR_JSON_KEY = "annotationColor";

function addPointAnnotations(annotations: LocalAnnotationSource, obj: any) {
if (obj === undefined) {
Expand Down Expand Up @@ -455,6 +465,9 @@ export class AnnotationUserLayer extends Base {
this.annotationDisplayState.shaderControls.restoreState(
specification[SHADER_CONTROLS_JSON_KEY],
);
this.annotationDisplayState.color.restoreState(
specification[ANNOTATION_COLOR_JSON_KEY],
);
}

getLegacyDataSourceSpecifications(
Expand Down Expand Up @@ -709,6 +722,7 @@ export class AnnotationUserLayer extends Base {
x[SHADER_JSON_KEY] = this.annotationDisplayState.shader.toJSON();
x[SHADER_CONTROLS_JSON_KEY] =
this.annotationDisplayState.shaderControls.toJSON();
x[ANNOTATION_COLOR_JSON_KEY] = this.annotationDisplayState.color.toJSON();
Object.assign(x, this.linkedSegmentationLayers.toJSON());
return x;
}
Expand Down Expand Up @@ -742,6 +756,7 @@ class RenderingOptionsTab extends Tab {
const { element } = this;
this.codeWidget = this.registerDisposer(makeShaderCodeWidget(this.layer));
element.classList.add("neuroglancer-annotation-rendering-tab");

element.appendChild(
this.registerDisposer(
new DependentViewWidget(
Expand Down Expand Up @@ -778,6 +793,7 @@ class RenderingOptionsTab extends Tab {
),
).element,
);

const topRow = document.createElement("div");
topRow.className =
"neuroglancer-segmentation-dropdown-skeleton-shader-header";
Expand Down Expand Up @@ -812,9 +828,53 @@ class RenderingOptionsTab extends Tab {
),
).element,
);

const colorControlToolWidget = element.appendChild(
addLayerControlToOptionsTab(
this,
layer,
this.visibility,
LAYER_CONTROLS[ANNOTATION_COLOR_JSON_KEY],
),
);
this.registerDisposer(
observeWatchable(
(hasDefaultColor) => {
if (hasDefaultColor) {
colorControlToolWidget.style.display = "";
} else {
colorControlToolWidget.style.display = "none";
this.layer.toolBinder.removeJsonString(ANNOTATION_COLOR_JSON_KEY);
}
},
makeCachedLazyDerivedWatchableValue(
(shader) => shader.match(/\bdefaultColor\b/) !== null,
layer.annotationDisplayState.shaderControls.processedFragmentMain,
),
),
);
}
}

const LAYER_CONTROLS: Record<
string,
LayerControlDefinition<AnnotationUserLayer>
> = {
[ANNOTATION_COLOR_JSON_KEY]: {
label: "Annotation default color",
title:
"Annotation shader default color (enabled with 'defaultColor()' in the shader code)",
toolJson: ANNOTATION_COLOR_JSON_KEY,
...colorLayerControl(
(layer: AnnotationUserLayer) => layer.annotationDisplayState.color,
),
},
};

for (const control of Object.values(LAYER_CONTROLS)) {
registerLayerControl(AnnotationUserLayer, control);
}

registerLayerType(AnnotationUserLayer);
registerLayerType(AnnotationUserLayer, "pointAnnotation");
registerLayerTypeDetector((subsource) => {
Expand Down
24 changes: 8 additions & 16 deletions src/ui/annotations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
* @file User interface for display and editing annotations.
*/

import svg_help from "ikonate/icons/help.svg?raw";
import "#src/ui/annotations.css";
import {
AnnotationDisplayState,
Expand Down Expand Up @@ -63,7 +64,6 @@ import {
registerCallbackWhenSegmentationDisplayStateChanged,
SegmentWidgetFactory,
} from "#src/segmentation_display_state/frontend.js";
import { ElementVisibilityFromTrackableBoolean } from "#src/trackable_boolean.js";
import type { WatchableValueInterface } from "#src/trackable_value.js";
import {
AggregateWatchableValue,
Expand Down Expand Up @@ -101,7 +101,6 @@ import { NullarySignal, Signal } from "#src/util/signal.js";
import { Uint64 } from "#src/util/uint64.js";
import * as vector from "#src/util/vector.js";
import { makeAddButton } from "#src/widget/add_button.js";
import { ColorWidget } from "#src/widget/color.js";
import { makeCopyButton } from "#src/widget/copy_button.js";
import { makeDeleteButton } from "#src/widget/delete_button.js";
import type { DependentViewContext } from "#src/widget/dependent_view_widget.js";
Expand Down Expand Up @@ -417,20 +416,6 @@ export class AnnotationLayerView extends Tab {
toolbox.className = "neuroglancer-annotation-toolbox";

layer.initializeAnnotationLayerViewTab(this);
const colorPicker = this.registerDisposer(
new ColorWidget(this.displayState.color),
);
colorPicker.element.title = "Change annotation display color";
this.registerDisposer(
new ElementVisibilityFromTrackableBoolean(
makeCachedLazyDerivedWatchableValue(
(shader) => shader.match(/\bdefaultColor\b/) !== null,
displayState.shaderControls.processedFragmentMain,
),
colorPicker.element,
),
);
toolbox.appendChild(colorPicker.element);
const { mutableControls } = this;
const pointButton = makeIcon({
text: annotationTypeHandlers[AnnotationType.POINT].icon,
Expand Down Expand Up @@ -468,6 +453,13 @@ export class AnnotationLayerView extends Tab {
},
});
mutableControls.appendChild(ellipsoidButton);
const helpIcon = document.createElement("div");
helpIcon.title =
"The left icons allows you to select the type of the anotation. Color and other display settings are available in the 'Redering' tab";
helpIcon.className = "neuroglancer-icon";
helpIcon.innerHTML = svg_help;
mutableControls.appendChild(helpIcon);

toolbox.appendChild(mutableControls);
this.element.appendChild(toolbox);

Expand Down
4 changes: 3 additions & 1 deletion src/ui/tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,9 @@ export class LocalToolBinder<
}

removeJsonString(toolJsonString: string) {
const key = this.jsonToKey.get(toolJsonString);
const key =
this.jsonToKey.get(toolJsonString) ||
this.jsonToKey.get(JSON.stringify(toolJsonString));
if (key === undefined) return;
this.set(key, undefined);
}
Expand Down
Loading