From 72220186e34878ac8ac8097627a8592120a98172 Mon Sep 17 00:00:00 2001 From: aranega Date: Mon, 4 Nov 2024 09:26:45 -0600 Subject: [PATCH 01/16] Add option to hide/show code block for image layer --- src/layer/image/index.ts | 37 +++++++++++++++++++++++++++++++++++++ src/layer/index.ts | 14 ++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/layer/image/index.ts b/src/layer/image/index.ts index 256050060..1bc7f048e 100644 --- a/src/layer/image/index.ts +++ b/src/layer/image/index.ts @@ -15,6 +15,8 @@ */ import "#src/layer/image/style.css"; +import svgClosedEye from "ikonate/icons/eye-closed.svg?raw"; +import svgOpenedEye from "ikonate/icons/eye.svg?raw"; import type { CoordinateSpace } from "#src/coordinate_transform.js"; import { @@ -82,6 +84,7 @@ import { ChannelDimensionsWidget } from "#src/widget/channel_dimensions_widget.j import { makeCopyButton } from "#src/widget/copy_button.js"; import type { DependentViewContext } from "#src/widget/dependent_view_widget.js"; import { makeHelpButton } from "#src/widget/help_button.js"; +import { makeIcon } from "#src/widget/icon.js"; import type { LayerControlDefinition } from "#src/widget/layer_control.js"; import { addLayerControlToOptionsTab, @@ -540,6 +543,38 @@ class RenderingOptionsTab extends Tab { topRow.className = "neuroglancer-image-dropdown-top-row"; topRow.appendChild(document.createTextNode("Shader")); topRow.appendChild(spacer); + + const managedLayer = this.layer.managedLayer; + const codeVisibilityControl = makeIcon({ + title: managedLayer.codeVisible ? "Hide code": "Show code", + svg: managedLayer.codeVisible ? svgOpenedEye : svgClosedEye, + onClick: () => { + const button = codeVisibilityControl as HTMLDivElement; + managedLayer.setCodeVisible(!managedLayer.codeVisible) + if (managedLayer.codeVisible) { + button.title = "Hide code"; + button.innerHTML = svgOpenedEye + this.codeWidget.element.style.display = "block"; + } else { + button.title = "Show code"; + button.innerHTML = svgClosedEye + this.codeWidget.element.style.display = "none"; + } + }}); + // managedLayer.layerChanged.add(() => { + // const button = codeVisibilityControl as HTMLDivElement; + // if (managedLayer.codeVisible) { + // button.title = "Hide code"; + // button.innerHTML = svgOpenedEye + // this.codeWidget.element.style.display = "block"; + // } else { + // button.title = "Show code"; + // button.innerHTML = svgClosedEye + // this.codeWidget.element.style.display = "none"; + // } + // }); + + topRow.appendChild(codeVisibilityControl); topRow.appendChild( makeMaximizeButton({ title: "Show larger editor view", @@ -561,6 +596,8 @@ class RenderingOptionsTab extends Tab { new ChannelDimensionsWidget(layer.channelCoordinateSpaceCombiner), ).element, ); + + this.codeWidget.element.style.display = managedLayer.codeVisible ? "block" : "none"; element.appendChild(this.codeWidget.element); element.appendChild( this.registerDisposer( diff --git a/src/layer/index.ts b/src/layer/index.ts index ff3f7d8d2..0624af296 100644 --- a/src/layer/index.ts +++ b/src/layer/index.ts @@ -710,6 +710,7 @@ export class ManagedUserLayer extends RefCounted { } visible = true; + codeVisible = true; archived = false; get supportsPickOption() { @@ -764,6 +765,7 @@ export class ManagedUserLayer extends RefCounted { } const layerSpec = userLayer.toJSON(); layerSpec.name = this.name; + layerSpec.codeVisible = this.codeVisible; if (!this.visible) { if (this.archived) { layerSpec.archived = true; @@ -774,6 +776,12 @@ export class ManagedUserLayer extends RefCounted { return layerSpec; } + setCodeVisible(value: boolean) { + if (value === this.codeVisible) return; + this.codeVisible = value; + this.layerChanged.dispatch(); + } + setVisible(value: boolean) { if (value === this.visible) return; if (value && this.archived) { @@ -2018,6 +2026,12 @@ function initializeLayerFromSpecNoRestoreState( } else { managedLayer.visible = false; } + managedLayer.codeVisible = verifyOptionalObjectProperty( + spec, + "codeVisible", + verifyBoolean, + true, + ) const layerConstructor = layerTypes.get(layerType) || NewUserLayer; managedLayer.layer = new layerConstructor(managedLayer); return spec; From a783ebfdb00ff86020ca2ef747789374c5731023 Mon Sep 17 00:00:00 2001 From: aranega Date: Fri, 8 Nov 2024 05:29:31 -0600 Subject: [PATCH 02/16] CC-122 Clean code for code-box visibility --- src/layer/image/index.ts | 23 ++++++----------------- src/widget/shader_code_widget.ts | 8 ++++++++ 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/layer/image/index.ts b/src/layer/image/index.ts index 1bc7f048e..61dae218c 100644 --- a/src/layer/image/index.ts +++ b/src/layer/image/index.ts @@ -545,34 +545,24 @@ class RenderingOptionsTab extends Tab { topRow.appendChild(spacer); const managedLayer = this.layer.managedLayer; + const codeVisible = managedLayer.codeVisible; + this.codeWidget.element.style.display = managedLayer.codeVisible ? "block" : "none"; + this.codeWidget.setVisible(codeVisible); const codeVisibilityControl = makeIcon({ - title: managedLayer.codeVisible ? "Hide code": "Show code", - svg: managedLayer.codeVisible ? svgOpenedEye : svgClosedEye, + title: codeVisible ? "Hide code": "Show code", + svg: codeVisible ? svgOpenedEye : svgClosedEye, onClick: () => { const button = codeVisibilityControl as HTMLDivElement; managedLayer.setCodeVisible(!managedLayer.codeVisible) if (managedLayer.codeVisible) { button.title = "Hide code"; button.innerHTML = svgOpenedEye - this.codeWidget.element.style.display = "block"; } else { button.title = "Show code"; button.innerHTML = svgClosedEye - this.codeWidget.element.style.display = "none"; } + this.codeWidget.setVisible(managedLayer.codeVisible); }}); - // managedLayer.layerChanged.add(() => { - // const button = codeVisibilityControl as HTMLDivElement; - // if (managedLayer.codeVisible) { - // button.title = "Hide code"; - // button.innerHTML = svgOpenedEye - // this.codeWidget.element.style.display = "block"; - // } else { - // button.title = "Show code"; - // button.innerHTML = svgClosedEye - // this.codeWidget.element.style.display = "none"; - // } - // }); topRow.appendChild(codeVisibilityControl); topRow.appendChild( @@ -597,7 +587,6 @@ class RenderingOptionsTab extends Tab { ).element, ); - this.codeWidget.element.style.display = managedLayer.codeVisible ? "block" : "none"; element.appendChild(this.codeWidget.element); element.appendChild( this.registerDisposer( diff --git a/src/widget/shader_code_widget.ts b/src/widget/shader_code_widget.ts index c86fae81c..e6e3d0401 100644 --- a/src/widget/shader_code_widget.ts +++ b/src/widget/shader_code_widget.ts @@ -189,4 +189,12 @@ export class ShaderCodeWidget extends RefCounted { this.textEditor = undefined; super.disposed(); } + + setVisible(visible: boolean) { + this.element.style.display = visible ? "block" : "none"; + } + + isVisible() { + return this.element.style.display === "block"; + } } From e3ebbdf0b8e4e7bae3cd8037e1ec22a49ed57f72 Mon Sep 17 00:00:00 2001 From: aranega Date: Fri, 8 Nov 2024 05:44:38 -0600 Subject: [PATCH 03/16] CC-154 Add code block visibility control for annotation layer --- src/layer/annotation/index.ts | 25 +++++++++++++++++++++++++ src/layer/image/index.ts | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/layer/annotation/index.ts b/src/layer/annotation/index.ts index 35c1a4e43..76d4375e5 100644 --- a/src/layer/annotation/index.ts +++ b/src/layer/annotation/index.ts @@ -15,6 +15,8 @@ */ import "#src/layer/annotation/style.css"; +import svgClosedEye from "ikonate/icons/eye-closed.svg?raw"; +import svgOpenedEye from "ikonate/icons/eye.svg?raw"; import type { AnnotationDisplayState } from "#src/annotation/annotation_layer_state.js"; import { AnnotationLayerState } from "#src/annotation/annotation_layer_state.js"; @@ -69,6 +71,7 @@ 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 { makeIcon } from "#src/widget/icon.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"; @@ -783,6 +786,28 @@ class RenderingOptionsTab extends Tab { label.style.flex = "1"; label.textContent = "Annotation shader:"; topRow.appendChild(label); + + const managedLayer = this.layer.managedLayer; + const codeVisible = managedLayer.codeVisible; + this.codeWidget.element.style.display = managedLayer.codeVisible ? "block" : "none"; + this.codeWidget.setVisible(codeVisible); + const codeVisibilityControl = makeIcon({ + title: codeVisible ? "Hide code": "Show code", + svg: codeVisible ? svgOpenedEye : svgClosedEye, + onClick: () => { + const button = codeVisibilityControl as HTMLDivElement; + managedLayer.setCodeVisible(!managedLayer.codeVisible) + if (managedLayer.codeVisible) { + button.title = "Hide code"; + button.innerHTML = svgOpenedEye + } else { + button.title = "Show code"; + button.innerHTML = svgClosedEye + } + this.codeWidget.setVisible(managedLayer.codeVisible); + }}); + topRow.appendChild(codeVisibilityControl); + topRow.appendChild( makeMaximizeButton({ title: "Show larger editor view", diff --git a/src/layer/image/index.ts b/src/layer/image/index.ts index 61dae218c..5a338a10b 100644 --- a/src/layer/image/index.ts +++ b/src/layer/image/index.ts @@ -563,8 +563,8 @@ class RenderingOptionsTab extends Tab { } this.codeWidget.setVisible(managedLayer.codeVisible); }}); - topRow.appendChild(codeVisibilityControl); + topRow.appendChild( makeMaximizeButton({ title: "Show larger editor view", From 77532fbbdbf07b71e0f0a7c8fae4c998a8b77f95 Mon Sep 17 00:00:00 2001 From: aranega Date: Fri, 8 Nov 2024 06:00:21 -0600 Subject: [PATCH 04/16] CC-156 Add code visibility control for single mesh layer --- src/layer/single_mesh/index.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/layer/single_mesh/index.ts b/src/layer/single_mesh/index.ts index 6e2b68694..a8cc1c956 100644 --- a/src/layer/single_mesh/index.ts +++ b/src/layer/single_mesh/index.ts @@ -15,6 +15,8 @@ */ import "#src/layer/single_mesh/style.css"; +import svgClosedEye from "ikonate/icons/eye-closed.svg?raw"; +import svgOpenedEye from "ikonate/icons/eye.svg?raw"; import type { ManagedUserLayer } from "#src/layer/index.js"; import { @@ -37,6 +39,7 @@ import type { Borrowed } from "#src/util/disposable.js"; import { RefCounted } from "#src/util/disposable.js"; import { removeChildren, removeFromParent } from "#src/util/dom.js"; import { makeHelpButton } from "#src/widget/help_button.js"; +import { makeIcon } from "#src/widget/icon.js"; import { makeMaximizeButton } from "#src/widget/maximize_button.js"; import { ShaderCodeWidget } from "#src/widget/shader_code_widget.js"; import { @@ -207,6 +210,28 @@ class DisplayOptionsTab extends Tab { spacer.style.flex = "1"; topRow.appendChild(spacer); + + const managedLayer = this.layer.managedLayer; + const codeVisible = managedLayer.codeVisible; + this.codeWidget.element.style.display = managedLayer.codeVisible ? "block" : "none"; + this.codeWidget.setVisible(codeVisible); + const codeVisibilityControl = makeIcon({ + title: codeVisible ? "Hide code": "Show code", + svg: codeVisible ? svgOpenedEye : svgClosedEye, + onClick: () => { + const button = codeVisibilityControl as HTMLDivElement; + managedLayer.setCodeVisible(!managedLayer.codeVisible) + if (managedLayer.codeVisible) { + button.title = "Hide code"; + button.innerHTML = svgOpenedEye + } else { + button.title = "Show code"; + button.innerHTML = svgClosedEye + } + this.codeWidget.setVisible(managedLayer.codeVisible); + }}); + topRow.appendChild(codeVisibilityControl); + topRow.appendChild( makeMaximizeButton({ title: "Show larger editor view", From 87d9433202cf4e5950a41416723536f2871b6a70 Mon Sep 17 00:00:00 2001 From: aranega Date: Fri, 8 Nov 2024 06:10:47 -0600 Subject: [PATCH 05/16] CC-157 Improve state handling for code box hidden --- src/layer/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/layer/index.ts b/src/layer/index.ts index 0624af296..fb894cd0f 100644 --- a/src/layer/index.ts +++ b/src/layer/index.ts @@ -765,7 +765,9 @@ export class ManagedUserLayer extends RefCounted { } const layerSpec = userLayer.toJSON(); layerSpec.name = this.name; - layerSpec.codeVisible = this.codeVisible; + if (!this.codeVisible) { + layerSpec.codeVisible = false; + } if (!this.visible) { if (this.archived) { layerSpec.archived = true; From 684807c427d9b7071d9161b04cff235eb4bd6315 Mon Sep 17 00:00:00 2001 From: aranega Date: Thu, 14 Nov 2024 07:14:19 -0600 Subject: [PATCH 06/16] Hide shader properties in annotation when code is not displayed --- src/layer/annotation/index.ts | 77 ++++++++++++++++++----------------- src/layer/image/index.ts | 1 - 2 files changed, 40 insertions(+), 38 deletions(-) diff --git a/src/layer/annotation/index.ts b/src/layer/annotation/index.ts index 76d4375e5..d0ecf4c43 100644 --- a/src/layer/annotation/index.ts +++ b/src/layer/annotation/index.ts @@ -743,42 +743,42 @@ class RenderingOptionsTab extends Tab { super(); const { element } = this; element.classList.add("neuroglancer-annotation-rendering-tab"); - element.appendChild( - this.registerDisposer( - new DependentViewWidget( - layer.annotationDisplayState.annotationProperties, - (properties, parent) => { - if (properties === undefined || properties.length === 0) return; - const propertyList = document.createElement("div"); - parent.appendChild(propertyList); - propertyList.classList.add( - "neuroglancer-annotation-shader-property-list", + const shaderProperties = this.registerDisposer( + new DependentViewWidget( + layer.annotationDisplayState.annotationProperties, + (properties, parent) => { + if (properties === undefined || properties.length === 0) return; + const propertyList = document.createElement("div"); + parent.appendChild(propertyList); + propertyList.classList.add( + "neuroglancer-annotation-shader-property-list", + ); + for (const property of properties) { + const div = document.createElement("div"); + div.classList.add("neuroglancer-annotation-shader-property"); + const typeElement = document.createElement("span"); + typeElement.classList.add( + "neuroglancer-annotation-shader-property-type", ); - for (const property of properties) { - const div = document.createElement("div"); - div.classList.add("neuroglancer-annotation-shader-property"); - const typeElement = document.createElement("span"); - typeElement.classList.add( - "neuroglancer-annotation-shader-property-type", - ); - typeElement.textContent = property.type; - const nameElement = document.createElement("span"); - nameElement.classList.add( - "neuroglancer-annotation-shader-property-identifier", - ); - nameElement.textContent = `prop_${property.identifier}`; - div.appendChild(typeElement); - div.appendChild(nameElement); - const { description } = property; - if (description !== undefined) { - div.title = description; - } - propertyList.appendChild(div); + typeElement.textContent = property.type; + const nameElement = document.createElement("span"); + nameElement.classList.add( + "neuroglancer-annotation-shader-property-identifier", + ); + nameElement.textContent = `prop_${property.identifier}`; + div.appendChild(typeElement); + div.appendChild(nameElement); + const { description } = property; + if (description !== undefined) { + div.title = description; } - }, - ), - ).element, - ); + propertyList.appendChild(div); + } + }, + ), + ).element; + + element.appendChild(shaderProperties); const topRow = document.createElement("div"); topRow.className = "neuroglancer-segmentation-dropdown-skeleton-shader-header"; @@ -788,9 +788,10 @@ class RenderingOptionsTab extends Tab { topRow.appendChild(label); const managedLayer = this.layer.managedLayer; + shaderProperties.style.display = managedLayer.codeVisible ? "block" : "none"; const codeVisible = managedLayer.codeVisible; - this.codeWidget.element.style.display = managedLayer.codeVisible ? "block" : "none"; this.codeWidget.setVisible(codeVisible); + const codeVisibilityControl = makeIcon({ title: codeVisible ? "Hide code": "Show code", svg: codeVisible ? svgOpenedEye : svgClosedEye, @@ -799,10 +800,12 @@ class RenderingOptionsTab extends Tab { managedLayer.setCodeVisible(!managedLayer.codeVisible) if (managedLayer.codeVisible) { button.title = "Hide code"; - button.innerHTML = svgOpenedEye + button.innerHTML = svgOpenedEye; + shaderProperties.style.display = "block"; } else { button.title = "Show code"; - button.innerHTML = svgClosedEye + button.innerHTML = svgClosedEye; + shaderProperties.style.display = "none"; } this.codeWidget.setVisible(managedLayer.codeVisible); }}); diff --git a/src/layer/image/index.ts b/src/layer/image/index.ts index 5a338a10b..72c9b32d6 100644 --- a/src/layer/image/index.ts +++ b/src/layer/image/index.ts @@ -546,7 +546,6 @@ class RenderingOptionsTab extends Tab { const managedLayer = this.layer.managedLayer; const codeVisible = managedLayer.codeVisible; - this.codeWidget.element.style.display = managedLayer.codeVisible ? "block" : "none"; this.codeWidget.setVisible(codeVisible); const codeVisibilityControl = makeIcon({ title: codeVisible ? "Hide code": "Show code", From d5fe172436ca19be0cb9a315ac4b90490ef02957 Mon Sep 17 00:00:00 2001 From: aranega Date: Thu, 21 Nov 2024 06:17:53 -0600 Subject: [PATCH 07/16] Change button icon and background when clicked --- src/layer/annotation/index.ts | 10 +++++----- src/layer/image/index.ts | 10 +++++----- src/layer/single_mesh/index.ts | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/layer/annotation/index.ts b/src/layer/annotation/index.ts index d0ecf4c43..c8647a2b6 100644 --- a/src/layer/annotation/index.ts +++ b/src/layer/annotation/index.ts @@ -15,8 +15,7 @@ */ import "#src/layer/annotation/style.css"; -import svgClosedEye from "ikonate/icons/eye-closed.svg?raw"; -import svgOpenedEye from "ikonate/icons/eye.svg?raw"; +import svgCode from "ikonate/icons/code.svg?raw"; import type { AnnotationDisplayState } from "#src/annotation/annotation_layer_state.js"; import { AnnotationLayerState } from "#src/annotation/annotation_layer_state.js"; @@ -794,21 +793,22 @@ class RenderingOptionsTab extends Tab { const codeVisibilityControl = makeIcon({ title: codeVisible ? "Hide code": "Show code", - svg: codeVisible ? svgOpenedEye : svgClosedEye, + svg: svgCode, onClick: () => { const button = codeVisibilityControl as HTMLDivElement; managedLayer.setCodeVisible(!managedLayer.codeVisible) if (managedLayer.codeVisible) { button.title = "Hide code"; - button.innerHTML = svgOpenedEye; + button.style.backgroundColor = "rgba(255, 255, 255, 0.2)"; shaderProperties.style.display = "block"; } else { button.title = "Show code"; - button.innerHTML = svgClosedEye; + button.style.backgroundColor = ""; shaderProperties.style.display = "none"; } this.codeWidget.setVisible(managedLayer.codeVisible); }}); + codeVisibilityControl.style.backgroundColor = codeVisible ? "rgba(255, 255, 255, 0.2)" : ""; topRow.appendChild(codeVisibilityControl); topRow.appendChild( diff --git a/src/layer/image/index.ts b/src/layer/image/index.ts index 72c9b32d6..35c20b3a7 100644 --- a/src/layer/image/index.ts +++ b/src/layer/image/index.ts @@ -15,8 +15,7 @@ */ import "#src/layer/image/style.css"; -import svgClosedEye from "ikonate/icons/eye-closed.svg?raw"; -import svgOpenedEye from "ikonate/icons/eye.svg?raw"; +import svgCode from "ikonate/icons/code.svg?raw"; import type { CoordinateSpace } from "#src/coordinate_transform.js"; import { @@ -549,19 +548,20 @@ class RenderingOptionsTab extends Tab { this.codeWidget.setVisible(codeVisible); const codeVisibilityControl = makeIcon({ title: codeVisible ? "Hide code": "Show code", - svg: codeVisible ? svgOpenedEye : svgClosedEye, + svg: svgCode, onClick: () => { const button = codeVisibilityControl as HTMLDivElement; managedLayer.setCodeVisible(!managedLayer.codeVisible) if (managedLayer.codeVisible) { button.title = "Hide code"; - button.innerHTML = svgOpenedEye + button.style.backgroundColor = "rgba(255, 255, 255, 0.2)"; } else { button.title = "Show code"; - button.innerHTML = svgClosedEye + button.style.backgroundColor = ""; } this.codeWidget.setVisible(managedLayer.codeVisible); }}); + codeVisibilityControl.style.backgroundColor = codeVisible ? "rgba(255, 255, 255, 0.2)" : ""; topRow.appendChild(codeVisibilityControl); topRow.appendChild( diff --git a/src/layer/single_mesh/index.ts b/src/layer/single_mesh/index.ts index a8cc1c956..b7b4d0637 100644 --- a/src/layer/single_mesh/index.ts +++ b/src/layer/single_mesh/index.ts @@ -15,8 +15,7 @@ */ import "#src/layer/single_mesh/style.css"; -import svgClosedEye from "ikonate/icons/eye-closed.svg?raw"; -import svgOpenedEye from "ikonate/icons/eye.svg?raw"; +import svgCode from "ikonate/icons/code.svg?raw"; import type { ManagedUserLayer } from "#src/layer/index.js"; import { @@ -217,19 +216,20 @@ class DisplayOptionsTab extends Tab { this.codeWidget.setVisible(codeVisible); const codeVisibilityControl = makeIcon({ title: codeVisible ? "Hide code": "Show code", - svg: codeVisible ? svgOpenedEye : svgClosedEye, + svg: svgCode, onClick: () => { const button = codeVisibilityControl as HTMLDivElement; managedLayer.setCodeVisible(!managedLayer.codeVisible) if (managedLayer.codeVisible) { button.title = "Hide code"; - button.innerHTML = svgOpenedEye + button.style.backgroundColor = "rgba(255, 255, 255, 0.2)"; } else { button.title = "Show code"; - button.innerHTML = svgClosedEye + button.style.backgroundColor = ""; } this.codeWidget.setVisible(managedLayer.codeVisible); }}); + codeVisibilityControl.style.backgroundColor = codeVisible ? "rgba(255, 255, 255, 0.2)" : ""; topRow.appendChild(codeVisibilityControl); topRow.appendChild( From 635f9b9b5edf65d364b902aa9dafbe6f4095d5db Mon Sep 17 00:00:00 2001 From: aranega Date: Thu, 21 Nov 2024 06:21:27 -0600 Subject: [PATCH 08/16] Change icon from code to code-alt --- src/layer/annotation/index.ts | 2 +- src/layer/image/index.ts | 2 +- src/layer/single_mesh/index.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/layer/annotation/index.ts b/src/layer/annotation/index.ts index c8647a2b6..7825dd373 100644 --- a/src/layer/annotation/index.ts +++ b/src/layer/annotation/index.ts @@ -15,7 +15,7 @@ */ import "#src/layer/annotation/style.css"; -import svgCode from "ikonate/icons/code.svg?raw"; +import svgCode from "ikonate/icons/code-alt.svg?raw"; import type { AnnotationDisplayState } from "#src/annotation/annotation_layer_state.js"; import { AnnotationLayerState } from "#src/annotation/annotation_layer_state.js"; diff --git a/src/layer/image/index.ts b/src/layer/image/index.ts index 35c20b3a7..2d9e61648 100644 --- a/src/layer/image/index.ts +++ b/src/layer/image/index.ts @@ -15,7 +15,7 @@ */ import "#src/layer/image/style.css"; -import svgCode from "ikonate/icons/code.svg?raw"; +import svgCode from "ikonate/icons/code-alt.svg?raw"; import type { CoordinateSpace } from "#src/coordinate_transform.js"; import { diff --git a/src/layer/single_mesh/index.ts b/src/layer/single_mesh/index.ts index b7b4d0637..ca750f857 100644 --- a/src/layer/single_mesh/index.ts +++ b/src/layer/single_mesh/index.ts @@ -15,7 +15,7 @@ */ import "#src/layer/single_mesh/style.css"; -import svgCode from "ikonate/icons/code.svg?raw"; +import svgCode from "ikonate/icons/code-alt.svg?raw"; import type { ManagedUserLayer } from "#src/layer/index.js"; import { From 80d4256feac6a69a4ffc8d3087e41e7998e74fdd Mon Sep 17 00:00:00 2001 From: aranega Date: Tue, 26 Nov 2024 09:11:44 -0600 Subject: [PATCH 09/16] Refactor layer code visibility feature Use a trackable boolean instead of a simple value in the layer, and use CheckBoxIcon instead of a hand-crafted one in each layer that implements the feature. --- src/layer/annotation/index.ts | 41 ++++++++++++++-------------------- src/layer/image/index.ts | 33 ++++++++++++--------------- src/layer/index.ts | 28 ++++++++++++----------- src/layer/single_mesh/index.ts | 35 ++++++++++++----------------- 4 files changed, 60 insertions(+), 77 deletions(-) diff --git a/src/layer/annotation/index.ts b/src/layer/annotation/index.ts index 7825dd373..11ab9447d 100644 --- a/src/layer/annotation/index.ts +++ b/src/layer/annotation/index.ts @@ -46,7 +46,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, @@ -68,9 +71,9 @@ import { verifyStringArray, } from "#src/util/json.js"; import { NullarySignal } from "#src/util/signal.js"; +import { CheckboxIcon } from "#src/widget/checkbox_icon.js"; import { DependentViewWidget } from "#src/widget/dependent_view_widget.js"; import { makeHelpButton } from "#src/widget/help_button.js"; -import { makeIcon } from "#src/widget/icon.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"; @@ -787,29 +790,19 @@ class RenderingOptionsTab extends Tab { topRow.appendChild(label); const managedLayer = this.layer.managedLayer; - shaderProperties.style.display = managedLayer.codeVisible ? "block" : "none"; - const codeVisible = managedLayer.codeVisible; - this.codeWidget.setVisible(codeVisible); - - const codeVisibilityControl = makeIcon({ - title: codeVisible ? "Hide code": "Show code", + this.registerDisposer( + observeWatchable((visible) => { + shaderProperties.style.display = visible ? "block" : "none"; + this.codeWidget.setVisible(visible); + }, managedLayer.codeVisible), + ); + const codeVisibilityControl = new CheckboxIcon(managedLayer.codeVisible, { + enableTitle: "Hide code", + disableTitle: "Show code", + backgroundScheme: "dark", svg: svgCode, - onClick: () => { - const button = codeVisibilityControl as HTMLDivElement; - managedLayer.setCodeVisible(!managedLayer.codeVisible) - if (managedLayer.codeVisible) { - button.title = "Hide code"; - button.style.backgroundColor = "rgba(255, 255, 255, 0.2)"; - shaderProperties.style.display = "block"; - } else { - button.title = "Show code"; - button.style.backgroundColor = ""; - shaderProperties.style.display = "none"; - } - this.codeWidget.setVisible(managedLayer.codeVisible); - }}); - codeVisibilityControl.style.backgroundColor = codeVisible ? "rgba(255, 255, 255, 0.2)" : ""; - topRow.appendChild(codeVisibilityControl); + }); + topRow.appendChild(codeVisibilityControl.element); topRow.appendChild( makeMaximizeButton({ diff --git a/src/layer/image/index.ts b/src/layer/image/index.ts index 2d9e61648..ab89ca347 100644 --- a/src/layer/image/index.ts +++ b/src/layer/image/index.ts @@ -55,6 +55,7 @@ import type { WatchableValueInterface } from "#src/trackable_value.js"; import { makeCachedDerivedWatchableValue, makeCachedLazyDerivedWatchableValue, + observeWatchable, registerNested, WatchableValue, } from "#src/trackable_value.js"; @@ -80,10 +81,10 @@ import { ShaderControlState, } from "#src/webgl/shader_ui_controls.js"; import { ChannelDimensionsWidget } from "#src/widget/channel_dimensions_widget.js"; +import { CheckboxIcon } from "#src/widget/checkbox_icon.js"; import { makeCopyButton } from "#src/widget/copy_button.js"; import type { DependentViewContext } from "#src/widget/dependent_view_widget.js"; import { makeHelpButton } from "#src/widget/help_button.js"; -import { makeIcon } from "#src/widget/icon.js"; import type { LayerControlDefinition } from "#src/widget/layer_control.js"; import { addLayerControlToOptionsTab, @@ -544,25 +545,19 @@ class RenderingOptionsTab extends Tab { topRow.appendChild(spacer); const managedLayer = this.layer.managedLayer; - const codeVisible = managedLayer.codeVisible; - this.codeWidget.setVisible(codeVisible); - const codeVisibilityControl = makeIcon({ - title: codeVisible ? "Hide code": "Show code", + this.registerDisposer( + observeWatchable((visible) => { + this.codeWidget.setVisible(visible); + }, managedLayer.codeVisible), + ); + + const codeVisibilityControl = new CheckboxIcon(managedLayer.codeVisible, { + enableTitle: "Hide code", + disableTitle: "Show code", + backgroundScheme: "dark", svg: svgCode, - onClick: () => { - const button = codeVisibilityControl as HTMLDivElement; - managedLayer.setCodeVisible(!managedLayer.codeVisible) - if (managedLayer.codeVisible) { - button.title = "Hide code"; - button.style.backgroundColor = "rgba(255, 255, 255, 0.2)"; - } else { - button.title = "Show code"; - button.style.backgroundColor = ""; - } - this.codeWidget.setVisible(managedLayer.codeVisible); - }}); - codeVisibilityControl.style.backgroundColor = codeVisible ? "rgba(255, 255, 255, 0.2)" : ""; - topRow.appendChild(codeVisibilityControl); + }); + topRow.appendChild(codeVisibilityControl.element); topRow.appendChild( makeMaximizeButton({ diff --git a/src/layer/index.ts b/src/layer/index.ts index fb894cd0f..16927d667 100644 --- a/src/layer/index.ts +++ b/src/layer/index.ts @@ -705,12 +705,11 @@ export class ManagedUserLayer extends RefCounted { set name(value: string) { if (value !== this.name_) { this.name_ = value; - this.layerChanged.dispatch(); } } visible = true; - codeVisible = true; + codeVisible = new TrackableBoolean(true, true); archived = false; get supportsPickOption() { @@ -756,6 +755,7 @@ export class ManagedUserLayer extends RefCounted { this.localVelocity, ), ); + this.codeVisible.changed.add(this.layerChanged.dispatch); } toJSON() { @@ -765,9 +765,7 @@ export class ManagedUserLayer extends RefCounted { } const layerSpec = userLayer.toJSON(); layerSpec.name = this.name; - if (!this.codeVisible) { - layerSpec.codeVisible = false; - } + layerSpec.codeVisible = this.codeVisible.toJSON(); if (!this.visible) { if (this.archived) { layerSpec.archived = true; @@ -779,8 +777,9 @@ export class ManagedUserLayer extends RefCounted { } setCodeVisible(value: boolean) { - if (value === this.codeVisible) return; - this.codeVisible = value; + this.codeVisible.value = value; + // if (value === this.codeVisible) return; + // this.codeVisible = value; this.layerChanged.dispatch(); } @@ -2028,12 +2027,15 @@ function initializeLayerFromSpecNoRestoreState( } else { managedLayer.visible = false; } - managedLayer.codeVisible = verifyOptionalObjectProperty( - spec, - "codeVisible", - verifyBoolean, - true, - ) + managedLayer.codeVisible.restoreState( + verifyOptionalObjectProperty(spec, "codeVisible", verifyBoolean, true), + ); + // managedLayer.codeVisible.value = verifyOptionalObjectProperty( + // spec, + // "codeVisible", + // verifyBoolean, + // true, + // ); const layerConstructor = layerTypes.get(layerType) || NewUserLayer; managedLayer.layer = new layerConstructor(managedLayer); return spec; diff --git a/src/layer/single_mesh/index.ts b/src/layer/single_mesh/index.ts index ca750f857..dcb5c0af5 100644 --- a/src/layer/single_mesh/index.ts +++ b/src/layer/single_mesh/index.ts @@ -33,12 +33,12 @@ import { SingleMeshLayer, } from "#src/single_mesh/frontend.js"; import type { WatchableValueInterface } from "#src/trackable_value.js"; -import { WatchableValue } from "#src/trackable_value.js"; +import { observeWatchable, WatchableValue } from "#src/trackable_value.js"; import type { Borrowed } from "#src/util/disposable.js"; import { RefCounted } from "#src/util/disposable.js"; import { removeChildren, removeFromParent } from "#src/util/dom.js"; +import { CheckboxIcon } from "#src/widget/checkbox_icon.js"; import { makeHelpButton } from "#src/widget/help_button.js"; -import { makeIcon } from "#src/widget/icon.js"; import { makeMaximizeButton } from "#src/widget/maximize_button.js"; import { ShaderCodeWidget } from "#src/widget/shader_code_widget.js"; import { @@ -211,26 +211,19 @@ class DisplayOptionsTab extends Tab { topRow.appendChild(spacer); const managedLayer = this.layer.managedLayer; - const codeVisible = managedLayer.codeVisible; - this.codeWidget.element.style.display = managedLayer.codeVisible ? "block" : "none"; - this.codeWidget.setVisible(codeVisible); - const codeVisibilityControl = makeIcon({ - title: codeVisible ? "Hide code": "Show code", + this.registerDisposer( + observeWatchable((visible) => { + this.codeWidget.setVisible(visible); + }, managedLayer.codeVisible), + ); + + const codeVisibilityControl = new CheckboxIcon(managedLayer.codeVisible, { + enableTitle: "Hide code", + disableTitle: "Show code", + backgroundScheme: "dark", svg: svgCode, - onClick: () => { - const button = codeVisibilityControl as HTMLDivElement; - managedLayer.setCodeVisible(!managedLayer.codeVisible) - if (managedLayer.codeVisible) { - button.title = "Hide code"; - button.style.backgroundColor = "rgba(255, 255, 255, 0.2)"; - } else { - button.title = "Show code"; - button.style.backgroundColor = ""; - } - this.codeWidget.setVisible(managedLayer.codeVisible); - }}); - codeVisibilityControl.style.backgroundColor = codeVisible ? "rgba(255, 255, 255, 0.2)" : ""; - topRow.appendChild(codeVisibilityControl); + }); + topRow.appendChild(codeVisibilityControl.element); topRow.appendChild( makeMaximizeButton({ From 5b46a3f7ea0ef8bb794b1922490e7d2de214713b Mon Sep 17 00:00:00 2001 From: aranega Date: Thu, 5 Dec 2024 06:41:11 -0600 Subject: [PATCH 10/16] Fix tooltip swap for code visibility --- src/layer/annotation/index.ts | 4 ++-- src/layer/image/index.ts | 4 ++-- src/layer/index.ts | 6 ------ src/layer/single_mesh/index.ts | 4 ++-- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/layer/annotation/index.ts b/src/layer/annotation/index.ts index 11ab9447d..24494cae5 100644 --- a/src/layer/annotation/index.ts +++ b/src/layer/annotation/index.ts @@ -797,8 +797,8 @@ class RenderingOptionsTab extends Tab { }, managedLayer.codeVisible), ); const codeVisibilityControl = new CheckboxIcon(managedLayer.codeVisible, { - enableTitle: "Hide code", - disableTitle: "Show code", + enableTitle: "Show code", + disableTitle: "Hide code", backgroundScheme: "dark", svg: svgCode, }); diff --git a/src/layer/image/index.ts b/src/layer/image/index.ts index ab89ca347..265509a74 100644 --- a/src/layer/image/index.ts +++ b/src/layer/image/index.ts @@ -552,8 +552,8 @@ class RenderingOptionsTab extends Tab { ); const codeVisibilityControl = new CheckboxIcon(managedLayer.codeVisible, { - enableTitle: "Hide code", - disableTitle: "Show code", + enableTitle: "Show code", + disableTitle: "Hide code", backgroundScheme: "dark", svg: svgCode, }); diff --git a/src/layer/index.ts b/src/layer/index.ts index 16927d667..50eece844 100644 --- a/src/layer/index.ts +++ b/src/layer/index.ts @@ -2030,12 +2030,6 @@ function initializeLayerFromSpecNoRestoreState( managedLayer.codeVisible.restoreState( verifyOptionalObjectProperty(spec, "codeVisible", verifyBoolean, true), ); - // managedLayer.codeVisible.value = verifyOptionalObjectProperty( - // spec, - // "codeVisible", - // verifyBoolean, - // true, - // ); const layerConstructor = layerTypes.get(layerType) || NewUserLayer; managedLayer.layer = new layerConstructor(managedLayer); return spec; diff --git a/src/layer/single_mesh/index.ts b/src/layer/single_mesh/index.ts index dcb5c0af5..8a46d6952 100644 --- a/src/layer/single_mesh/index.ts +++ b/src/layer/single_mesh/index.ts @@ -218,8 +218,8 @@ class DisplayOptionsTab extends Tab { ); const codeVisibilityControl = new CheckboxIcon(managedLayer.codeVisible, { - enableTitle: "Hide code", - disableTitle: "Show code", + enableTitle: "Show code", + disableTitle: "Hide code", backgroundScheme: "dark", svg: svgCode, }); From feeba32bb6d13e86d6d42fe847fc00b88c82bfa8 Mon Sep 17 00:00:00 2001 From: Sean Martin Date: Thu, 5 Dec 2024 14:30:30 +0100 Subject: [PATCH 11/16] refactor: remove unused commented code --- src/layer/index.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/layer/index.ts b/src/layer/index.ts index 50eece844..8cb0c3e51 100644 --- a/src/layer/index.ts +++ b/src/layer/index.ts @@ -778,8 +778,6 @@ export class ManagedUserLayer extends RefCounted { setCodeVisible(value: boolean) { this.codeVisible.value = value; - // if (value === this.codeVisible) return; - // this.codeVisible = value; this.layerChanged.dispatch(); } From 7ce500c04b104089e19543d41573d56dd816c6f2 Mon Sep 17 00:00:00 2001 From: aranega Date: Wed, 18 Dec 2024 07:02:37 -0600 Subject: [PATCH 12/16] Add back event dispatch on name change for layers --- src/layer/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/layer/index.ts b/src/layer/index.ts index 50eece844..d8d5f85e7 100644 --- a/src/layer/index.ts +++ b/src/layer/index.ts @@ -705,6 +705,7 @@ export class ManagedUserLayer extends RefCounted { set name(value: string) { if (value !== this.name_) { this.name_ = value; + this.layerChanged.dispatch(); } } From 2a57ea59eaa32618c84e6a7410155f67c74a0bf5 Mon Sep 17 00:00:00 2001 From: Sean Martin Date: Wed, 22 Jan 2025 19:04:22 +0100 Subject: [PATCH 13/16] feat: save test on image user layer code visible --- src/layer/image/index.ts | 18 ++++++++++++------ src/layer/index.ts | 12 ++++++------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/layer/image/index.ts b/src/layer/image/index.ts index 265509a74..9e62104a7 100644 --- a/src/layer/image/index.ts +++ b/src/layer/image/index.ts @@ -50,12 +50,12 @@ import { } from "#src/sliceview/volume/image_renderlayer.js"; import { trackableAlphaValue } from "#src/trackable_alpha.js"; import { trackableBlendModeValue } from "#src/trackable_blend.js"; +import { TrackableBoolean } from "#src/trackable_boolean.js"; import { trackableFiniteFloat } from "#src/trackable_finite_float.js"; import type { WatchableValueInterface } from "#src/trackable_value.js"; import { makeCachedDerivedWatchableValue, makeCachedLazyDerivedWatchableValue, - observeWatchable, registerNested, WatchableValue, } from "#src/trackable_value.js"; @@ -108,6 +108,7 @@ import { Tab } from "#src/widget/tab_view.js"; const OPACITY_JSON_KEY = "opacity"; const BLEND_JSON_KEY = "blend"; const SHADER_JSON_KEY = "shader"; +const CODE_VISIBLE_KEY = "codeVisibleTEST"; const SHADER_CONTROLS_JSON_KEY = "shaderControls"; const CROSS_SECTION_RENDER_SCALE_JSON_KEY = "crossSectionRenderScale"; const CHANNEL_DIMENSIONS_JSON_KEY = "channelDimensions"; @@ -127,6 +128,7 @@ const [ export class ImageUserLayer extends Base { opacity = trackableAlphaValue(0.5); blendMode = trackableBlendModeValue(); + codeVisible = new TrackableBoolean(true, true); fragmentMain = getTrackableFragmentMain(); shaderError = makeWatchableShaderError(); dataType = new WatchableValue(undefined); @@ -207,6 +209,9 @@ export class ImageUserLayer extends Base { isLocalDimension; this.blendMode.changed.add(this.specificationChanged.dispatch); this.opacity.changed.add(this.specificationChanged.dispatch); + this.codeVisible.changed.add(() => { + this.specificationChanged.dispatch; + }); this.volumeRenderingGain.changed.add(this.specificationChanged.dispatch); this.fragmentMain.changed.add(this.specificationChanged.dispatch); this.shaderControlState.changed.add(this.specificationChanged.dispatch); @@ -296,6 +301,7 @@ export class ImageUserLayer extends Base { restoreState(specification: any) { super.restoreState(specification); this.opacity.restoreState(specification[OPACITY_JSON_KEY]); + this.codeVisible.restoreState(specification[CODE_VISIBLE_KEY]); verifyOptionalObjectProperty(specification, BLEND_JSON_KEY, (blendValue) => this.blendMode.restoreState(blendValue), ); @@ -341,6 +347,7 @@ export class ImageUserLayer extends Base { const x = super.toJSON(); x[OPACITY_JSON_KEY] = this.opacity.toJSON(); x[BLEND_JSON_KEY] = this.blendMode.toJSON(); + x[CODE_VISIBLE_KEY] = this.codeVisible.toJSON(); x[SHADER_JSON_KEY] = this.fragmentMain.toJSON(); x[SHADER_CONTROLS_JSON_KEY] = this.shaderControlState.toJSON(); x[CROSS_SECTION_RENDER_SCALE_JSON_KEY] = @@ -544,14 +551,13 @@ class RenderingOptionsTab extends Tab { topRow.appendChild(document.createTextNode("Shader")); topRow.appendChild(spacer); - const managedLayer = this.layer.managedLayer; this.registerDisposer( - observeWatchable((visible) => { - this.codeWidget.setVisible(visible); - }, managedLayer.codeVisible), + this.layer.codeVisible.changed.add(() => { + this.codeWidget.setVisible(this.layer.codeVisible.value); + }), ); - const codeVisibilityControl = new CheckboxIcon(managedLayer.codeVisible, { + const codeVisibilityControl = new CheckboxIcon(this.layer.codeVisible, { enableTitle: "Show code", disableTitle: "Hide code", backgroundScheme: "dark", diff --git a/src/layer/index.ts b/src/layer/index.ts index a592e1a6e..4387cc056 100644 --- a/src/layer/index.ts +++ b/src/layer/index.ts @@ -756,7 +756,7 @@ export class ManagedUserLayer extends RefCounted { this.localVelocity, ), ); - this.codeVisible.changed.add(this.layerChanged.dispatch); + // this.codeVisible.changed.add(this.layerChanged.dispatch); } toJSON() { @@ -766,7 +766,7 @@ export class ManagedUserLayer extends RefCounted { } const layerSpec = userLayer.toJSON(); layerSpec.name = this.name; - layerSpec.codeVisible = this.codeVisible.toJSON(); + // layerSpec.codeVisible = this.codeVisible.toJSON(); if (!this.visible) { if (this.archived) { layerSpec.archived = true; @@ -779,7 +779,7 @@ export class ManagedUserLayer extends RefCounted { setCodeVisible(value: boolean) { this.codeVisible.value = value; - this.layerChanged.dispatch(); + // this.layerChanged.dispatch(); } setVisible(value: boolean) { @@ -2026,9 +2026,9 @@ function initializeLayerFromSpecNoRestoreState( } else { managedLayer.visible = false; } - managedLayer.codeVisible.restoreState( - verifyOptionalObjectProperty(spec, "codeVisible", verifyBoolean, true), - ); + // managedLayer.codeVisible.restoreState( + // verifyOptionalObjectProperty(spec, "codeVisible", verifyBoolean, true), + // ); const layerConstructor = layerTypes.get(layerType) || NewUserLayer; managedLayer.layer = new layerConstructor(managedLayer); return spec; From 0e618b8712fcf35bb1426cd0e68211ad865f3b29 Mon Sep 17 00:00:00 2001 From: Sean Martin Date: Thu, 23 Jan 2025 11:37:12 +0100 Subject: [PATCH 14/16] fix: correct linking state and refactor code visibility --- src/layer/image/index.ts | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/layer/image/index.ts b/src/layer/image/index.ts index 9e62104a7..375336b36 100644 --- a/src/layer/image/index.ts +++ b/src/layer/image/index.ts @@ -50,7 +50,10 @@ import { } from "#src/sliceview/volume/image_renderlayer.js"; import { trackableAlphaValue } from "#src/trackable_alpha.js"; import { trackableBlendModeValue } from "#src/trackable_blend.js"; -import { TrackableBoolean } from "#src/trackable_boolean.js"; +import { + TrackableBoolean, + ElementVisibilityFromTrackableBoolean, +} from "#src/trackable_boolean.js"; import { trackableFiniteFloat } from "#src/trackable_finite_float.js"; import type { WatchableValueInterface } from "#src/trackable_value.js"; import { @@ -108,7 +111,7 @@ import { Tab } from "#src/widget/tab_view.js"; const OPACITY_JSON_KEY = "opacity"; const BLEND_JSON_KEY = "blend"; const SHADER_JSON_KEY = "shader"; -const CODE_VISIBLE_KEY = "codeVisibleTEST"; +const CODE_VISIBLE_KEY = "codeVisible"; const SHADER_CONTROLS_JSON_KEY = "shaderControls"; const CROSS_SECTION_RENDER_SCALE_JSON_KEY = "crossSectionRenderScale"; const CHANNEL_DIMENSIONS_JSON_KEY = "channelDimensions"; @@ -128,7 +131,7 @@ const [ export class ImageUserLayer extends Base { opacity = trackableAlphaValue(0.5); blendMode = trackableBlendModeValue(); - codeVisible = new TrackableBoolean(true, true); + codeVisible = new TrackableBoolean(true); fragmentMain = getTrackableFragmentMain(); shaderError = makeWatchableShaderError(); dataType = new WatchableValue(undefined); @@ -209,9 +212,7 @@ export class ImageUserLayer extends Base { isLocalDimension; this.blendMode.changed.add(this.specificationChanged.dispatch); this.opacity.changed.add(this.specificationChanged.dispatch); - this.codeVisible.changed.add(() => { - this.specificationChanged.dispatch; - }); + this.codeVisible.changed.add(this.specificationChanged.dispatch); this.volumeRenderingGain.changed.add(this.specificationChanged.dispatch); this.fragmentMain.changed.add(this.specificationChanged.dispatch); this.shaderControlState.changed.add(this.specificationChanged.dispatch); @@ -552,9 +553,10 @@ class RenderingOptionsTab extends Tab { topRow.appendChild(spacer); this.registerDisposer( - this.layer.codeVisible.changed.add(() => { - this.codeWidget.setVisible(this.layer.codeVisible.value); - }), + new ElementVisibilityFromTrackableBoolean( + this.layer.codeVisible, + this.codeWidget.element, + ), ); const codeVisibilityControl = new CheckboxIcon(this.layer.codeVisible, { From 0a81f6aba4a6fd239d919c805e60b98790350214 Mon Sep 17 00:00:00 2001 From: aranega Date: Thu, 23 Jan 2025 08:20:12 -0600 Subject: [PATCH 15/16] Move code visibility option to user layer for mesh and annotations --- src/layer/annotation/index.ts | 16 +++++++++++----- src/layer/single_mesh/index.ts | 23 ++++++++++++++++------- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/layer/annotation/index.ts b/src/layer/annotation/index.ts index 13f257d14..2761889a5 100644 --- a/src/layer/annotation/index.ts +++ b/src/layer/annotation/index.ts @@ -44,8 +44,10 @@ import { Overlay } from "#src/overlay.js"; import { getWatchableRenderLayerTransform } from "#src/render_coordinate_transform.js"; 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 { + TrackableBoolean, + TrackableBooleanCheckbox, +} from "#src/trackable_boolean.js"; import { makeCachedLazyDerivedWatchableValue, observeWatchable, @@ -143,6 +145,7 @@ interface LinkedSegmentationLayer { const LINKED_SEGMENTATION_LAYER_JSON_KEY = "linkedSegmentationLayer"; const FILTER_BY_SEGMENTATION_JSON_KEY = "filterBySegmentation"; const IGNORE_NULL_SEGMENT_FILTER_JSON_KEY = "ignoreNullSegmentFilter"; +const CODE_VISIBLE_KEY = "codeVisible"; class LinkedSegmentationLayers extends RefCounted { changed = new NullarySignal(); @@ -387,6 +390,7 @@ class LinkedSegmentationLayersWidget extends RefCounted { const Base = UserLayerWithAnnotationsMixin(UserLayer); export class AnnotationUserLayer extends Base { localAnnotations: LocalAnnotationSource | undefined; + codeVisible = new TrackableBoolean(true); private localAnnotationProperties: AnnotationPropertySpec[] | undefined; private localAnnotationRelationships: string[]; private localAnnotationsJson: any = undefined; @@ -412,6 +416,7 @@ export class AnnotationUserLayer extends Base { this.linkedSegmentationLayers.changed.add( this.specificationChanged.dispatch, ); + this.codeVisible.changed.add(this.specificationChanged.dispatch); this.annotationDisplayState.ignoreNullSegmentFilter.changed.add( this.specificationChanged.dispatch, ); @@ -432,6 +437,7 @@ export class AnnotationUserLayer extends Base { restoreState(specification: any) { super.restoreState(specification); this.linkedSegmentationLayers.restoreState(specification); + this.codeVisible.restoreState(specification[CODE_VISIBLE_KEY]); this.localAnnotationsJson = specification[ANNOTATIONS_JSON_KEY]; this.localAnnotationProperties = verifyOptionalObjectProperty( specification, @@ -693,6 +699,7 @@ export class AnnotationUserLayer extends Base { const x = super.toJSON(); x[CROSS_SECTION_RENDER_SCALE_JSON_KEY] = this.annotationCrossSectionRenderScaleTarget.toJSON(); + x[CODE_VISIBLE_KEY] = this.codeVisible.toJSON(); x[PROJECTION_RENDER_SCALE_JSON_KEY] = this.annotationProjectionRenderScaleTarget.toJSON(); if (this.localAnnotations !== undefined) { @@ -791,14 +798,13 @@ class RenderingOptionsTab extends Tab { label.textContent = "Annotation shader:"; topRow.appendChild(label); - const managedLayer = this.layer.managedLayer; this.registerDisposer( observeWatchable((visible) => { shaderProperties.style.display = visible ? "block" : "none"; this.codeWidget.setVisible(visible); - }, managedLayer.codeVisible), + }, this.layer.codeVisible), ); - const codeVisibilityControl = new CheckboxIcon(managedLayer.codeVisible, { + const codeVisibilityControl = new CheckboxIcon(this.layer.codeVisible, { enableTitle: "Show code", disableTitle: "Hide code", backgroundScheme: "dark", diff --git a/src/layer/single_mesh/index.ts b/src/layer/single_mesh/index.ts index c1554921b..094dea43a 100644 --- a/src/layer/single_mesh/index.ts +++ b/src/layer/single_mesh/index.ts @@ -32,8 +32,12 @@ import { SingleMeshDisplayState, SingleMeshLayer, } from "#src/single_mesh/frontend.js"; +import { + ElementVisibilityFromTrackableBoolean, + TrackableBoolean, +} from "#src/trackable_boolean.js"; import type { WatchableValueInterface } from "#src/trackable_value.js"; -import { observeWatchable, WatchableValue } from "#src/trackable_value.js"; +import { WatchableValue } from "#src/trackable_value.js"; import type { Borrowed } from "#src/util/disposable.js"; import { RefCounted } from "#src/util/disposable.js"; import { removeChildren, removeFromParent } from "#src/util/dom.js"; @@ -49,14 +53,18 @@ import { Tab } from "#src/widget/tab_view.js"; const SHADER_JSON_KEY = "shader"; const SHADER_CONTROLS_JSON_KEY = "shaderControls"; +const CODE_VISIBLE_KEY = "codeVisible"; export class SingleMeshUserLayer extends UserLayer { displayState = new SingleMeshDisplayState(); + codeVisible = new TrackableBoolean(true); + vertexAttributes = new WatchableValue( undefined, ); constructor(public managedLayer: Borrowed) { super(managedLayer); + this.codeVisible.changed.add(this.specificationChanged.dispatch); this.registerDisposer( this.displayState.shaderControlState.changed.add( this.specificationChanged.dispatch, @@ -77,6 +85,7 @@ export class SingleMeshUserLayer extends UserLayer { restoreState(specification: any) { super.restoreState(specification); + this.codeVisible.restoreState(specification[CODE_VISIBLE_KEY]); this.displayState.fragmentMain.restoreState(specification[SHADER_JSON_KEY]); this.displayState.shaderControlState.restoreState( specification[SHADER_CONTROLS_JSON_KEY], @@ -118,6 +127,7 @@ export class SingleMeshUserLayer extends UserLayer { const x = super.toJSON(); x[SHADER_JSON_KEY] = this.displayState.fragmentMain.toJSON(); x[SHADER_CONTROLS_JSON_KEY] = this.displayState.shaderControlState.toJSON(); + x[CODE_VISIBLE_KEY] = this.codeVisible.toJSON(); return x; } @@ -213,14 +223,13 @@ class DisplayOptionsTab extends Tab { topRow.appendChild(spacer); - const managedLayer = this.layer.managedLayer; this.registerDisposer( - observeWatchable((visible) => { - this.codeWidget.setVisible(visible); - }, managedLayer.codeVisible), + new ElementVisibilityFromTrackableBoolean( + this.layer.codeVisible, + this.codeWidget.element, + ), ); - - const codeVisibilityControl = new CheckboxIcon(managedLayer.codeVisible, { + const codeVisibilityControl = new CheckboxIcon(this.layer.codeVisible, { enableTitle: "Show code", disableTitle: "Hide code", backgroundScheme: "dark", From 6253e2fcba8b1b0d3a6c5c13bcb6cda3081b6deb Mon Sep 17 00:00:00 2001 From: Sean Martin Date: Thu, 23 Jan 2025 15:38:07 +0100 Subject: [PATCH 16/16] refactor: remove old comments and use ElementVisibilityFromTrackableBoolean --- src/layer/annotation/index.ts | 20 ++++++++++++-------- src/layer/index.ts | 11 ----------- src/widget/shader_code_widget.ts | 8 -------- 3 files changed, 12 insertions(+), 27 deletions(-) diff --git a/src/layer/annotation/index.ts b/src/layer/annotation/index.ts index 2761889a5..eba7104c4 100644 --- a/src/layer/annotation/index.ts +++ b/src/layer/annotation/index.ts @@ -47,11 +47,9 @@ import type { SegmentationDisplayState } from "#src/segmentation_display_state/f import { TrackableBoolean, TrackableBooleanCheckbox, + ElementVisibilityFromTrackableBoolean, } from "#src/trackable_boolean.js"; -import { - makeCachedLazyDerivedWatchableValue, - observeWatchable, -} from "#src/trackable_value.js"; +import { makeCachedLazyDerivedWatchableValue } from "#src/trackable_value.js"; import type { AnnotationLayerView, MergedAnnotationStates, @@ -799,10 +797,16 @@ class RenderingOptionsTab extends Tab { topRow.appendChild(label); this.registerDisposer( - observeWatchable((visible) => { - shaderProperties.style.display = visible ? "block" : "none"; - this.codeWidget.setVisible(visible); - }, this.layer.codeVisible), + new ElementVisibilityFromTrackableBoolean( + this.layer.codeVisible, + this.codeWidget.element, + ), + ); + this.registerDisposer( + new ElementVisibilityFromTrackableBoolean( + this.layer.codeVisible, + shaderProperties, + ), ); const codeVisibilityControl = new CheckboxIcon(this.layer.codeVisible, { enableTitle: "Show code", diff --git a/src/layer/index.ts b/src/layer/index.ts index a2c12b2e8..fea87063d 100644 --- a/src/layer/index.ts +++ b/src/layer/index.ts @@ -711,7 +711,6 @@ export class ManagedUserLayer extends RefCounted { } visible = true; - codeVisible = new TrackableBoolean(true, true); archived = false; get supportsPickOption() { @@ -757,7 +756,6 @@ export class ManagedUserLayer extends RefCounted { this.localVelocity, ), ); - // this.codeVisible.changed.add(this.layerChanged.dispatch); } toJSON() { @@ -767,7 +765,6 @@ export class ManagedUserLayer extends RefCounted { } const layerSpec = userLayer.toJSON(); layerSpec.name = this.name; - // layerSpec.codeVisible = this.codeVisible.toJSON(); if (!this.visible) { if (this.archived) { layerSpec.archived = true; @@ -778,11 +775,6 @@ export class ManagedUserLayer extends RefCounted { return layerSpec; } - setCodeVisible(value: boolean) { - this.codeVisible.value = value; - // this.layerChanged.dispatch(); - } - setVisible(value: boolean) { if (value === this.visible) return; if (value && this.archived) { @@ -2027,9 +2019,6 @@ function initializeLayerFromSpecNoRestoreState( } else { managedLayer.visible = false; } - // managedLayer.codeVisible.restoreState( - // verifyOptionalObjectProperty(spec, "codeVisible", verifyBoolean, true), - // ); const layerConstructor = layerTypes.get(layerType) || NewUserLayer; managedLayer.layer = new layerConstructor(managedLayer); return spec; diff --git a/src/widget/shader_code_widget.ts b/src/widget/shader_code_widget.ts index ea57244f0..df08d64f1 100644 --- a/src/widget/shader_code_widget.ts +++ b/src/widget/shader_code_widget.ts @@ -189,12 +189,4 @@ export class ShaderCodeWidget extends RefCounted { this.textEditor = undefined; super.disposed(); } - - setVisible(visible: boolean) { - this.element.style.display = visible ? "block" : "none"; - } - - isVisible() { - return this.element.style.display === "block"; - } }