@@ -15,6 +15,7 @@ import { useGlobalLayerColorConfig } from '@/src/composables/useGlobalLayerColor
1515import { usePaintToolStore } from ' @/src/store/tools/paint' ;
1616import { Maybe } from ' @/src/types' ;
1717import { reactive , ref , computed , watch , toRaw } from ' vue' ;
18+ import { useMultiSelection } from ' @/src/composables/useMultiSelection' ;
1819
1920const UNNAMED_GROUP_NAME = ' Unnamed Segment Group' ;
2021
@@ -160,6 +161,63 @@ function openSaveDialog(id: string) {
160161 saveId .value = id ;
161162 saveDialog .value = true ;
162163}
164+
165+ const segGroupIds = computed (() =>
166+ currentSegmentGroups .value .map ((group ) => group .id )
167+ );
168+
169+ const { selected, selectedAll, selectedSome } = useMultiSelection (segGroupIds );
170+
171+ // ensure currentSegmentGroupID is always in selected
172+ watch (
173+ currentSegmentGroupID ,
174+ (segGroupId ) => {
175+ if (segGroupId == null ) {
176+ return ;
177+ }
178+ selected .value = [segGroupId ];
179+ },
180+ { immediate: true }
181+ );
182+
183+ // ensure currentSegmentGroupID is always in selected
184+ function toggleSelectAll() {
185+ if (selectedAll .value ) {
186+ selected .value = currentSegmentGroupID .value
187+ ? [currentSegmentGroupID .value ]
188+ : [];
189+ } else {
190+ selected .value = [... segGroupIds .value ];
191+ }
192+ }
193+
194+ const allHidden = computed (() => {
195+ return selected .value
196+ .map ((id ) => currentSegmentGroups .value .find ((group ) => id === group .id ))
197+ .filter ((group ): group is NonNullable <typeof group > => group != null )
198+ .every ((group ) => ! group .visibility );
199+ });
200+
201+ function toggleGlobalVisibility() {
202+ const shouldShow = allHidden .value ;
203+ selected .value .forEach ((id ) => {
204+ const group = currentSegmentGroups .value .find ((g ) => g .id === id );
205+ if (group ) {
206+ const { sampledConfig, updateConfig } = useGlobalLayerColorConfig (id );
207+ const currentBlend = sampledConfig .value ! .config ! .blendConfig ;
208+ updateConfig ({
209+ blendConfig: {
210+ ... currentBlend ,
211+ visibility: shouldShow ,
212+ },
213+ });
214+ }
215+ });
216+ }
217+
218+ function deleteSelected() {
219+ selected .value .forEach ((id ) => deleteGroup (id ));
220+ }
163221 </script >
164222
165223<template >
@@ -203,63 +261,100 @@ function openSaveDialog(id: string) {
203261 </v-list >
204262 </v-menu >
205263 </div >
206- <v-divider class =" my-4" />
207264
208265 <segment-group-opacity
209266 v-if =" currentSegmentGroupID"
210267 :group-id =" currentSegmentGroupID"
268+ :selected =" selected"
211269 />
212- <v-radio-group
213- v-model =" currentSegmentGroupID"
214- hide-details
215- density =" comfortable"
216- class =" my-1 segment-group-list"
217- >
218- <v-radio
270+
271+ <div class =" d-flex align-center" >
272+ <v-checkbox
273+ class =" ml-3"
274+ :indeterminate =" selectedSome && !selectedAll"
275+ label =" Select All"
276+ :model-value =" selectedAll"
277+ @update:model-value =" toggleSelectAll"
278+ density =" compact"
279+ hide-details
280+ />
281+ <v-btn
282+ icon
283+ variant =" text"
284+ :disabled =" selected.length === 0"
285+ @click.stop =" toggleGlobalVisibility"
286+ >
287+ <v-icon v-if =" allHidden" >mdi-eye-off</v-icon >
288+ <v-icon v-else >mdi-eye</v-icon >
289+ <v-tooltip location =" top" activator =" parent" >
290+ {{ allHidden ? 'Show' : 'Hide' }} selected
291+ </v-tooltip >
292+ </v-btn >
293+ <v-btn
294+ icon
295+ variant =" text"
296+ :disabled =" selected.length === 0"
297+ @click.stop =" deleteSelected"
298+ >
299+ <v-icon >mdi-delete</v-icon >
300+ <v-tooltip location =" top" activator =" parent" >
301+ Delete selected
302+ </v-tooltip >
303+ </v-btn >
304+ </div >
305+ <v-list density =" comfortable" class =" my-1 segment-group-list" >
306+ <v-list-item
219307 v-for =" group in currentSegmentGroups"
220308 :key =" group.id"
221- :value =" group.id"
309+ :active =" currentSegmentGroupID === group.id"
310+ @click =" currentSegmentGroupID = group.id"
222311 >
223- <template #label >
224- <div class =" d-flex flex-row align-center w-100" :title =" group.name" >
225- <span class =" group-name" >{{ group.name }}</span >
226- <v-spacer />
227- <v-btn
228- icon
229- variant =" flat"
230- size =" small"
231- @click.stop =" group.toggleVisibility"
312+ <div class =" d-flex flex-row align-center w-100" :title =" group.name" >
313+ <v-checkbox
314+ class =" no-grow mr-4"
315+ density =" compact"
316+ hide-details
317+ @click.stop
318+ :value =" group.id"
319+ v-model =" selected"
320+ />
321+ <span class =" group-name" >{{ group.name }}</span >
322+ <v-spacer />
323+ <v-btn
324+ icon
325+ variant =" text"
326+ size =" small"
327+ @click.stop =" group.toggleVisibility"
328+ >
329+ <v-icon v-if =" group.visibility" style =" pointer-events : none "
330+ >mdi-eye</v-icon
232331 >
233- <v-icon v-if =" group.visibility" style =" pointer-events : none "
234- >mdi-eye</v-icon
235- >
236- <v-icon v-else style =" pointer-events : none " >mdi-eye-off</v-icon >
237- <v-tooltip location =" left" activator =" parent" >{{
238- group.visibility ? 'Hide' : 'Show'
239- }}</v-tooltip >
240- </v-btn >
241- <v-btn
242- icon =" mdi-content-save"
243- size =" small"
244- variant =" flat"
245- @click.stop =" openSaveDialog(group.id)"
246- ></v-btn >
247- <v-btn
248- icon =" mdi-pencil"
249- size =" small"
250- variant =" flat"
251- @click.stop =" startEditing(group.id)"
252- ></v-btn >
253- <v-btn
254- icon =" mdi-delete"
255- size =" small"
256- variant =" flat"
257- @click.stop =" deleteGroup(group.id)"
258- ></v-btn >
259- </div >
260- </template >
261- </v-radio >
262- </v-radio-group >
332+ <v-icon v-else style =" pointer-events : none " >mdi-eye-off</v-icon >
333+ <v-tooltip location =" left" activator =" parent" >
334+ {{ group.visibility ? 'Hide' : 'Show' }}
335+ </v-tooltip >
336+ </v-btn >
337+ <v-btn
338+ icon =" mdi-content-save"
339+ size =" small"
340+ variant =" text"
341+ @click.stop =" openSaveDialog(group.id)"
342+ />
343+ <v-btn
344+ icon =" mdi-pencil"
345+ size =" small"
346+ variant =" text"
347+ @click.stop =" startEditing(group.id)"
348+ />
349+ <v-btn
350+ icon =" mdi-delete"
351+ size =" small"
352+ variant =" text"
353+ @click.stop =" deleteGroup(group.id)"
354+ />
355+ </div >
356+ </v-list-item >
357+ </v-list >
263358 <v-divider class =" my-4" />
264359 </div >
265360 <div v-else class =" text-center text-caption" >No selected image</div >
@@ -306,5 +401,11 @@ function openSaveDialog(id: string) {
306401 white-space : nowrap ;
307402 overflow : hidden ;
308403 text-overflow : ellipsis ;
404+ padding-right : 10px ;
405+ text-align : left ;
406+ }
407+
408+ .no-grow {
409+ flex : 0 0 auto ;
309410}
310411 </style >
0 commit comments