From 72220186e34878ac8ac8097627a8592120a98172 Mon Sep 17 00:00:00 2001 From: aranega Date: Mon, 4 Nov 2024 09:26:45 -0600 Subject: [PATCH 01/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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(); } }