diff --git a/src/layer/image/index.ts b/src/layer/image/index.ts index 241b69853..d8d4a4156 100644 --- a/src/layer/image/index.ts +++ b/src/layer/image/index.ts @@ -103,6 +103,7 @@ import { ShaderControls, } from "#src/widget/shader_controls.js"; import { Tab } from "#src/widget/tab_view.js"; +import { applyAccordion, makeAccordionHeader } from "#src/widget/accordion.js"; const OPACITY_JSON_KEY = "opacity"; const BLEND_JSON_KEY = "blend"; @@ -535,12 +536,16 @@ class RenderingOptionsTab extends Tab { this.codeWidget = this.registerDisposer(makeShaderCodeWidget(this.layer)); element.classList.add("neuroglancer-image-dropdown"); + element.appendChild(makeAccordionHeader("Layer controls")); + for (const control of LAYER_CONTROLS) { element.appendChild( addLayerControlToOptionsTab(this, layer, this.visibility, control), ); } + element.appendChild(makeAccordionHeader("Shader")); + element.appendChild( makeShaderCodeWidgetTopRow( this.layer, @@ -573,6 +578,7 @@ class RenderingOptionsTab extends Tab { ), ).element, ); + applyAccordion(element); } } diff --git a/src/ui/segmentation_display_options_tab.ts b/src/ui/segmentation_display_options_tab.ts index 7bb6e9fc8..6c4c14c25 100644 --- a/src/ui/segmentation_display_options_tab.ts +++ b/src/ui/segmentation_display_options_tab.ts @@ -27,6 +27,7 @@ import { } from "#src/widget/shader_code_widget.js"; import { ShaderControls } from "#src/widget/shader_controls.js"; import { Tab } from "#src/widget/tab_view.js"; +import { applyAccordion, makeAccordionHeader } from "#src/widget/accordion.js"; function makeSkeletonShaderCodeWidget(layer: SegmentationUserLayer) { return new ShaderCodeWidget({ @@ -43,6 +44,8 @@ export class DisplayOptionsTab extends Tab { const { element } = this; element.classList.add("neuroglancer-segmentation-rendering-tab"); + element.appendChild(makeAccordionHeader("Segmentation links")); + // Linked segmentation control { const widget = this.registerDisposer( @@ -63,12 +66,16 @@ export class DisplayOptionsTab extends Tab { element.appendChild(widget.element); } + element.appendChild(makeAccordionHeader("Display options")); + for (const control of LAYER_CONTROLS) { element.appendChild( addLayerControlToOptionsTab(this, layer, this.visibility, control), ); } + element.appendChild(makeAccordionHeader("Skeleton rendering")); + const skeletonControls = this.registerDisposer( new DependentViewWidget( layer.hasSkeletonsLayer, @@ -109,6 +116,7 @@ export class DisplayOptionsTab extends Tab { ), ); element.appendChild(skeletonControls.element); + applyAccordion(element); } } diff --git a/src/widget/accordion.css b/src/widget/accordion.css new file mode 100644 index 000000000..4931e5bd6 --- /dev/null +++ b/src/widget/accordion.css @@ -0,0 +1,25 @@ +.neuroglancer-accordion-section { + border: 1px solid #444; + margin-top: 4px; +} + +.neuroglancer-accordion-section > summary.neuroglancer-accordion-header { + cursor: pointer; + padding: 2px; + background-color: #333; + list-style: none; +} + +.neuroglancer-accordion-section-body { + padding: 4px; +} + +.neuroglancer-accordion-section[open] > summary.neuroglancer-accordion-header::before { + content: "\25BC"; + margin-right: 4px; +} + +.neuroglancer-accordion-section:not([open]) > summary.neuroglancer-accordion-header::before { + content: "\25B6"; + margin-right: 4px; +} diff --git a/src/widget/accordion.ts b/src/widget/accordion.ts new file mode 100644 index 000000000..b59760d4d --- /dev/null +++ b/src/widget/accordion.ts @@ -0,0 +1,41 @@ +import "#src/widget/accordion.css"; + +import { removeChildren } from "#src/util/dom.js"; + +export function makeAccordionHeader(text: string) { + const header = document.createElement("div"); + header.textContent = text; + header.classList.add("neuroglancer-accordion-header"); + return header; +} + +export function applyAccordion( + element: HTMLElement, + headerClass = "neuroglancer-accordion-header", +) { + const children = Array.from(element.children); + const accordion = document.createElement("div"); + accordion.classList.add("neuroglancer-accordion"); + let currentSection: HTMLDetailsElement | null = null; + let body: HTMLElement | null = null; + for (const child of children) { + if (child.classList.contains(headerClass)) { + currentSection = document.createElement("details"); + currentSection.classList.add("neuroglancer-accordion-section"); + const summary = document.createElement("summary"); + summary.classList.add(headerClass); + summary.appendChild(child); + currentSection.appendChild(summary); + body = document.createElement("div"); + body.classList.add("neuroglancer-accordion-section-body"); + currentSection.appendChild(body); + accordion.appendChild(currentSection); + } else if (currentSection !== null) { + body!.appendChild(child); + } else { + accordion.appendChild(child); + } + } + removeChildren(element); + element.appendChild(accordion); +}