diff --git a/src/components/SegmentGroupControls.vue b/src/components/SegmentGroupControls.vue
index 913e82e7..8f1f0dd9 100644
--- a/src/components/SegmentGroupControls.vue
+++ b/src/components/SegmentGroupControls.vue
@@ -11,6 +11,7 @@ import {
DataSelection,
} from '@/src/utils/dataSelection';
import { useSegmentGroupStore } from '@/src/store/segmentGroups';
+import { useGlobalLayerColorConfig } from '@/src/composables/useGlobalLayerColorConfig';
import { usePaintToolStore } from '@/src/store/tools/paint';
import { Maybe } from '@/src/types';
import { reactive, ref, computed, watch, toRaw } from 'vue';
@@ -26,9 +27,20 @@ const currentSegmentGroups = computed(() => {
const { orderByParent, metadataByID } = segmentGroupStore;
if (!(currentImageID.value in orderByParent)) return [];
return orderByParent[currentImageID.value].map((id) => {
+ const { sampledConfig, updateConfig } = useGlobalLayerColorConfig(id);
return {
id,
name: metadataByID[id].name,
+ visibility: sampledConfig.value?.config?.blendConfig.visibility ?? true,
+ toggleVisibility: () => {
+ const currentBlend = sampledConfig.value!.config!.blendConfig;
+ updateConfig({
+ blendConfig: {
+ ...currentBlend,
+ visibility: !currentBlend.visibility,
+ },
+ });
+ },
};
});
});
@@ -207,6 +219,20 @@ function openSaveDialog(id: string) {
{{ group.name }}
+
+ mdi-eye
+ mdi-eye-off
+ {{
+ group.visibility ? 'Hide' : 'Show'
+ }}
+
import { computed, toRefs } from 'vue';
-import { BlendConfig } from '@/src/types/views';
-import useLayerColoringStore from '@/src/store/view-configs/layers';
-import { useSegmentGroupConfigInitializer } from '@/src/composables/useSegmentGroupConfigInitializer';
-import { InitViewSpecs } from '../config';
+import { useGlobalLayerColorConfig } from '@/src/composables/useGlobalLayerColorConfig';
const props = defineProps<{
groupId: string;
@@ -11,37 +8,24 @@ const props = defineProps<{
const { groupId } = toRefs(props);
-const layerColoringStore = useLayerColoringStore();
+const { sampledConfig, updateConfig } = useGlobalLayerColorConfig(groupId);
-const VIEWS_2D = Object.entries(InitViewSpecs)
- .filter(([, { viewType }]) => viewType === '2D')
- .map(([viewID]) => viewID);
+const blendConfig = computed(() => sampledConfig.value!.config!.blendConfig);
-useSegmentGroupConfigInitializer(VIEWS_2D[0], groupId.value);
-
-const layerConfigs = computed(() =>
- VIEWS_2D.map((viewID) => ({
- config: layerColoringStore.getConfig(viewID, groupId.value),
- viewID,
- }))
-);
-
-const blendConfig = computed(
- () => layerConfigs.value.find(({ config }) => config)!.config!.blendConfig
-);
-
-const setBlendConfig = (key: keyof BlendConfig, value: any) => {
- layerConfigs.value.forEach(({ viewID }) =>
- layerColoringStore.updateBlendConfig(viewID, groupId.value, {
- [key]: value,
- })
- );
+const setOpacity = (opacity: number) => {
+ updateConfig({
+ blendConfig: {
+ ...blendConfig.value,
+ // 1.0 puts us in Opaque render pass which changes stack order.
+ opacity: Math.min(opacity, 0.9999),
+ },
+ });
};
{
hide-details
thumb-label
:model-value="blendConfig.opacity"
- @update:model-value="setBlendConfig('opacity', $event)"
+ @update:model-value="setOpacity($event)"
/>
diff --git a/src/components/vtk/VtkSegmentationSliceRepresentation.vue b/src/components/vtk/VtkSegmentationSliceRepresentation.vue
index 9d71df31..5a5a1d45 100644
--- a/src/components/vtk/VtkSegmentationSliceRepresentation.vue
+++ b/src/components/vtk/VtkSegmentationSliceRepresentation.vue
@@ -61,16 +61,26 @@ sliceRep.mapper.setResolveCoincidentTopologyToPolygonOffset();
sliceRep.mapper.setResolveCoincidentTopologyPolygonOffsetParameters(-2, -2);
useSegmentGroupConfigInitializer(viewId.value, segmentationId.value);
+const coloringStore = useLayerColoringStore();
+
+// visibility
+const visibility = computed(
+ () =>
+ coloringStore.getConfig(viewId.value, segmentationId.value)!.blendConfig
+ .visibility
+);
+watchEffect(() => {
+ sliceRep.actor.setVisibility(visibility.value);
+});
// opacity
-const coloringStore = useLayerColoringStore();
const opacity = computed(
() =>
- coloringStore.getConfig(viewId.value, segmentationId.value)?.blendConfig
+ coloringStore.getConfig(viewId.value, segmentationId.value)!.blendConfig
.opacity
);
watchEffect(() => {
- sliceRep.property.setOpacity(opacity.value!);
+ sliceRep.property.setOpacity(opacity.value);
});
// set slicing mode
diff --git a/src/composables/useGlobalLayerColorConfig.ts b/src/composables/useGlobalLayerColorConfig.ts
new file mode 100644
index 00000000..69dc247f
--- /dev/null
+++ b/src/composables/useGlobalLayerColorConfig.ts
@@ -0,0 +1,35 @@
+import { computed, MaybeRef, unref } from 'vue';
+import { InitViewSpecs } from '@/src/config';
+import useLayerColoringStore from '@/src/store/view-configs/layers';
+import { LayersConfig } from '@/src/store/view-configs/types';
+import { useSegmentGroupConfigInitializer } from '@/src/composables/useSegmentGroupConfigInitializer';
+
+// Returns first existing view's config as the "value" and updates all views' configs with updateConfig()
+export const useGlobalLayerColorConfig = (layerId: MaybeRef) => {
+ const layerColoringStore = useLayerColoringStore();
+
+ const VIEWS_2D = Object.entries(InitViewSpecs)
+ .filter(([, { viewType }]) => viewType === '2D')
+ .map(([viewID]) => viewID);
+
+ useSegmentGroupConfigInitializer(VIEWS_2D[0], unref(layerId));
+
+ const layerConfigs = computed(() =>
+ VIEWS_2D.map((viewID) => ({
+ config: layerColoringStore.getConfig(viewID, unref(layerId)),
+ viewID,
+ }))
+ );
+
+ const sampledConfig = computed(() =>
+ layerConfigs.value.find(({ config }) => config)
+ );
+
+ const updateConfig = (patch: Partial) => {
+ layerConfigs.value.forEach(({ viewID }) =>
+ layerColoringStore.updateConfig(viewID, unref(layerId), patch)
+ );
+ };
+
+ return { sampledConfig, updateConfig };
+};
diff --git a/src/io/state-file/schema.ts b/src/io/state-file/schema.ts
index 87f1a09c..53843aab 100644
--- a/src/io/state-file/schema.ts
+++ b/src/io/state-file/schema.ts
@@ -203,6 +203,7 @@ const VolumeColorConfig = z.object({
const BlendConfig = z.object({
opacity: z.number(),
+ visibility: z.boolean(),
}) satisfies z.ZodType;
const LayersConfig = z.object({
diff --git a/src/store/view-configs/layers.ts b/src/store/view-configs/layers.ts
index 74a38f8a..1cfc0baa 100644
--- a/src/store/view-configs/layers.ts
+++ b/src/store/view-configs/layers.ts
@@ -55,7 +55,7 @@ export const defaultLayersConfig = (): LayersConfig => ({
gaussians: [],
mappingRange: [0, 1],
},
- blendConfig: { opacity: 0.6 },
+ blendConfig: { opacity: 0.6, visibility: true },
});
export const useLayerColoringStore = defineStore('layerColoring', () => {
diff --git a/src/types/views.ts b/src/types/views.ts
index 953221ea..5e908a29 100644
--- a/src/types/views.ts
+++ b/src/types/views.ts
@@ -66,4 +66,5 @@ export interface CVRConfig {
export interface BlendConfig {
opacity: number;
+ visibility: boolean;
}