From 2dd3dd4a58cc4b5885a1736f58d72f7024ffcf67 Mon Sep 17 00:00:00 2001 From: Matt Dawkins Date: Wed, 7 Jan 2026 22:52:44 -0500 Subject: [PATCH 1/7] Add multi-cam top buttons option --- client/dive-common/components/EditorMenu.vue | 2 + .../components/TrackSettingsPanel.vue | 40 +++++++++++++++++++ client/dive-common/components/Viewer.vue | 14 +++++++ client/dive-common/store/settings.ts | 9 ++++- 4 files changed, 63 insertions(+), 2 deletions(-) diff --git a/client/dive-common/components/EditorMenu.vue b/client/dive-common/components/EditorMenu.vue index 748f9db8d..a4f84d8c5 100644 --- a/client/dive-common/components/EditorMenu.vue +++ b/client/dive-common/components/EditorMenu.vue @@ -243,7 +243,9 @@ export default Vue.extend({ {{ button.icon }} + + diff --git a/client/dive-common/components/TrackSettingsPanel.vue b/client/dive-common/components/TrackSettingsPanel.vue index 90ed67ed9..71b1ec1b2 100644 --- a/client/dive-common/components/TrackSettingsPanel.vue +++ b/client/dive-common/components/TrackSettingsPanel.vue @@ -32,6 +32,7 @@ export default defineComponent({ prompt: 'Prompt user before deleting a track?', filterTracksByFrame: 'Filter the track list by those with detections in the current frame', autoZoom: 'Automatically zoom to the track when selected', + showMultiCamToolbar: 'Show multi-camera tools in the top toolbar when a track is selected', }); const modes = ref(['Track', 'Detection']); // Add unknown as the default type to the typeList @@ -322,6 +323,45 @@ export default defineComponent({ + +
+ Multi-Camera Settings +
+ + + + + + + + {{ help.showMultiCamToolbar }} + + + diff --git a/client/dive-common/components/Viewer.vue b/client/dive-common/components/Viewer.vue index b05d9bf78..a3b77a2d9 100644 --- a/client/dive-common/components/Viewer.vue +++ b/client/dive-common/components/Viewer.vue @@ -49,6 +49,7 @@ import context from 'dive-common/store/context'; import { MarkChangesPendingFilter } from 'vue-media-annotator/BaseFilterControls'; import GroupSidebarVue from './GroupSidebar.vue'; import MultiCamToolsVue from './MultiCamTools.vue'; +import MultiCamToolbar from './MultiCamToolbar.vue'; import PrimaryAttributeTrackFilter from './PrimaryAttributeTrackFilter.vue'; export interface ImageDataItem { @@ -68,6 +69,7 @@ export default defineComponent({ ConfidenceFilter, UserGuideButton, EditorMenu, + MultiCamToolbar, PrimaryAttributeTrackFilter, }, @@ -1010,6 +1012,18 @@ export default defineComponent({ @delete-annotation="handler.removeAnnotation" /> + + Date: Wed, 7 Jan 2026 22:54:27 -0500 Subject: [PATCH 2/7] Check in vue for multi-cam toolbar --- .../components/MultiCamToolbar.vue | 287 ++++++++++++++++++ 1 file changed, 287 insertions(+) create mode 100644 client/dive-common/components/MultiCamToolbar.vue diff --git a/client/dive-common/components/MultiCamToolbar.vue b/client/dive-common/components/MultiCamToolbar.vue new file mode 100644 index 000000000..2a128978d --- /dev/null +++ b/client/dive-common/components/MultiCamToolbar.vue @@ -0,0 +1,287 @@ + + + + + From 8ca9daa8a953030cbfe2c0f004947718d72468e7 Mon Sep 17 00:00:00 2001 From: Matt Dawkins Date: Wed, 7 Jan 2026 23:00:29 -0500 Subject: [PATCH 3/7] Replace dropdown toggle with fast option to draw on opposite camera --- .../components/MultiCamToolbar.vue | 66 ++++++++----------- 1 file changed, 27 insertions(+), 39 deletions(-) diff --git a/client/dive-common/components/MultiCamToolbar.vue b/client/dive-common/components/MultiCamToolbar.vue index 2a128978d..e5798b4f8 100644 --- a/client/dive-common/components/MultiCamToolbar.vue +++ b/client/dive-common/components/MultiCamToolbar.vue @@ -71,6 +71,11 @@ export default defineComponent({ (cam) => !cameraTrackInfo.value[cam]?.hasTrack, )); + // The opposite camera (first camera that isn't the currently selected one) + const oppositeCamera = computed(() => cameras.value.find( + (cam) => cam !== selectedCamera.value, + )); + // Delete detection from current camera/frame const deleteDetection = async () => { if (selectedTrackId.value === null || !selectedCamera.value) return; @@ -121,6 +126,13 @@ export default defineComponent({ handler.selectCamera(camera, true); }; + // Edit on the opposite camera + const editOnOppositeCamera = () => { + if (oppositeCamera.value) { + editOnCamera(oppositeCamera.value); + } + }; + return { selectedTrackId, selectedCamera, @@ -130,11 +142,13 @@ export default defineComponent({ currentCameraHasTrack, currentCameraHasDetection, linkableCameras, + oppositeCamera, deleteDetection, deleteTrackFromCamera, unlinkCurrentCamera, startLinkingToCamera, editOnCamera, + editOnOppositeCamera, }; }, }); @@ -145,46 +159,20 @@ export default defineComponent({ v-if="selectedTrackId !== null && cameras.length > 1" class="d-flex align-center multicam-toolbar" > - - - - - + + + Edit detection on {{ oppositeCamera }} + Date: Wed, 7 Jan 2026 23:07:03 -0500 Subject: [PATCH 4/7] Add configuration option to settings --- .../desktop/frontend/components/Settings.vue | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/client/platform/desktop/frontend/components/Settings.vue b/client/platform/desktop/frontend/components/Settings.vue index 7a9ea7721..93ce64c5e 100644 --- a/client/platform/desktop/frontend/components/Settings.vue +++ b/client/platform/desktop/frontend/components/Settings.vue @@ -9,6 +9,7 @@ import { useRequest } from 'dive-common/use'; import { NvidiaSmiReply } from 'platform/desktop/constants'; import { cloneDeep, isEqual } from 'lodash'; +import { clientSettings } from 'dive-common/store/settings'; import { autoDiscover } from '../store/dataset'; import { settings, updateSettings, validateSettings } from '../store/settings'; import { nvidiaSmi } from '../api'; @@ -73,6 +74,7 @@ export default defineComponent({ appversion, arch, autoDiscoverState, + clientSettings, gitHash, platform, settings, @@ -96,7 +98,7 @@ export default defineComponent({ - Settings + Folder Settings @@ -180,6 +182,22 @@ export default defineComponent({ + Annotation Settings + + + + + + + + Platform support Not all checks must pass in order to use this application. From 0327c4dbbd7a94881460657c2eed2cbd0803fafc Mon Sep 17 00:00:00 2001 From: Matt Dawkins Date: Wed, 7 Jan 2026 23:12:29 -0500 Subject: [PATCH 5/7] Add quick keypress option --- client/dive-common/components/MultiCamToolbar.vue | 9 ++++++++- client/dive-common/components/Viewer.vue | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/client/dive-common/components/MultiCamToolbar.vue b/client/dive-common/components/MultiCamToolbar.vue index e5798b4f8..5c1ccf35b 100644 --- a/client/dive-common/components/MultiCamToolbar.vue +++ b/client/dive-common/components/MultiCamToolbar.vue @@ -10,6 +10,7 @@ import { useEditingMode, } from 'vue-media-annotator/provides'; import { AnnotationId } from 'vue-media-annotator/BaseAnnotation'; +import { Mousetrap } from 'vue-media-annotator/types'; export default defineComponent({ name: 'MultiCamToolbar', @@ -133,7 +134,12 @@ export default defineComponent({ } }; + const mousetrap: Mousetrap[] = [ + { bind: 'e', handler: editOnOppositeCamera }, + ]; + return { + mousetrap, selectedTrackId, selectedCamera, cameras, @@ -157,6 +163,7 @@ export default defineComponent({ - Edit detection on {{ oppositeCamera }} + Edit detection on {{ oppositeCamera }} (e) diff --git a/client/dive-common/components/Viewer.vue b/client/dive-common/components/Viewer.vue index a3b77a2d9..040837bcf 100644 --- a/client/dive-common/components/Viewer.vue +++ b/client/dive-common/components/Viewer.vue @@ -1139,6 +1139,7 @@ export default defineComponent({ { bind: 'n', handler: () => !readonlyState && handler.trackAdd() }, { bind: 'r', handler: () => aggregateController.resetZoom() }, { bind: 'esc', handler: () => handler.trackAbort() }, + { bind: 'e', handler: () => multiCamList.length === 1 && selectedTrackId !== null && handler.trackEdit(selectedTrackId) }, ]" class="d-flex flex-column grow" > From c151a0110d3d1862bf2ee104b5e50fcb0c997d16 Mon Sep 17 00:00:00 2001 From: Matt Dawkins Date: Thu, 8 Jan 2026 00:38:26 -0500 Subject: [PATCH 6/7] Switch to fixed 4 buttons --- .../components/MultiCamToolbar.vue | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/client/dive-common/components/MultiCamToolbar.vue b/client/dive-common/components/MultiCamToolbar.vue index 5c1ccf35b..d4caf26f5 100644 --- a/client/dive-common/components/MultiCamToolbar.vue +++ b/client/dive-common/components/MultiCamToolbar.vue @@ -72,6 +72,14 @@ export default defineComponent({ (cam) => !cameraTrackInfo.value[cam]?.hasTrack, )); + // Can unlink when current camera has track and multiple cameras have the track + const canUnlink = computed( + () => currentCameraHasTrack.value && camerasWithTrack.value > 1, + ); + + // Can link when there are cameras without the track + const canLink = computed(() => linkableCameras.value.length > 0); + // The opposite camera (first camera that isn't the currently selected one) const oppositeCamera = computed(() => cameras.value.find( (cam) => cam !== selectedCamera.value, @@ -148,6 +156,8 @@ export default defineComponent({ currentCameraHasTrack, currentCameraHasDetection, linkableCameras, + canUnlink, + canLink, oppositeCamera, deleteDetection, deleteTrackFromCamera, @@ -181,9 +191,10 @@ export default defineComponent({ Edit detection on {{ oppositeCamera }} (e) - + +