diff --git a/client/dive-common/components/CameraRegistration/RegistrationTools.vue b/client/dive-common/components/CameraRegistration/RegistrationTools.vue
index a1771a1e1..49785bd77 100644
--- a/client/dive-common/components/CameraRegistration/RegistrationTools.vue
+++ b/client/dive-common/components/CameraRegistration/RegistrationTools.vue
@@ -502,10 +502,24 @@ export default defineComponent({
() => correspondences.value.length > 0 || hasLoadedTransform.value,
);
+ // Short L/R labels keep the toggle from overflowing on long camera
+ // names; the full names stay available as the button tooltip.
const alignmentModeItems = computed(() => [
- { text: 'Picking', value: 'original', disabled: false },
- { text: `${camLeft.value ?? 'A'} → ${camRight.value ?? 'B'}`, value: 'AtoB', disabled: !hasTransform.value },
- { text: `${camRight.value ?? 'B'} → ${camLeft.value ?? 'A'}`, value: 'BtoA', disabled: !hasTransform.value },
+ {
+ text: 'Picking', title: undefined, value: 'original', disabled: false,
+ },
+ {
+ text: 'L → R',
+ title: `${camLeft.value ?? 'A'} → ${camRight.value ?? 'B'}`,
+ value: 'AtoB',
+ disabled: !hasTransform.value,
+ },
+ {
+ text: 'R → L',
+ title: `${camRight.value ?? 'B'} → ${camLeft.value ?? 'A'}`,
+ value: 'BtoA',
+ disabled: !hasTransform.value,
+ },
]);
function setTransformType(type: TransformType) {
@@ -535,6 +549,18 @@ export default defineComponent({
return entries.length ? entries.join(' · ') : 'present (no displayable fields)';
});
+ /**
+ * Short L/R label for a camera in the active pair (falls back to the full
+ * name for anything else, though the readout only ever sees pair
+ * cameras) -- keeps the monospace cursor readout from overflowing on
+ * long camera names, matching the Overlay Warp toggle's labels.
+ */
+ function shortCameraLabel(cam: string): string {
+ if (cam === camLeft.value) return 'L';
+ if (cam === camRight.value) return 'R';
+ return cam;
+ }
+
/** Live cursor readout text: this camera's coord, and its linked point in the other camera. */
const cursorReadout = computed(() => {
const cursor = registration.cursorCoord.value;
@@ -543,12 +569,12 @@ export default defineComponent({
}
const [x, y] = cursor.coord;
const other = registration.linkedPoint(cursor.camera, cursor.coord);
- const here = `${cursor.camera}: (${x.toFixed(1)}, ${y.toFixed(1)})`;
+ const here = `${shortCameraLabel(cursor.camera)}: (${x.toFixed(1)}, ${y.toFixed(1)})`;
if (!other) {
return here;
}
const [ox, oy] = other.coord;
- return `${here} -> ${other.camera}: (${ox.toFixed(1)}, ${oy.toFixed(1)})`;
+ return `${here} -> ${shortCameraLabel(other.camera)}: (${ox.toFixed(1)}, ${oy.toFixed(1)})`;
});
/**
@@ -1339,6 +1365,7 @@ export default defineComponent({
:key="item.value"
:value="item.value"
:disabled="item.disabled"
+ :title="item.title"
small
class="flex-grow-1"
style="text-transform: none;"
diff --git a/client/dive-common/components/Viewer.vue b/client/dive-common/components/Viewer.vue
index cbc470dd8..6897cdf84 100644
--- a/client/dive-common/components/Viewer.vue
+++ b/client/dive-common/components/Viewer.vue
@@ -333,20 +333,20 @@ export default defineComponent({
const showUserSettingsDialog = ref(false);
// When the Camera Registration panel opens, minimize the workspace chrome
- // to give the picking view more room: collapse the left type-filter
- // sidebar. The bottom controls deliberately stay as they are -- the
- // timeline hosts the registration-frame marker row, which is most useful
- // exactly while this panel is open. This is a soft default -- the normal
- // sidebar toggle still works while registering -- and whatever layout the
- // user had before is restored on close.
+ // to give the picking view more room: hide the type-filter sidebar,
+ // whichever side it is on. Bottom especially -- it competes for the same
+ // vertical room the two picking panes want. The bottom controls
+ // deliberately stay as they are -- the timeline hosts the
+ // registration-frame marker row, which is most useful exactly while this
+ // panel is open. This is a soft default -- the normal sidebar toggle
+ // still works while registering -- and whatever layout the user had
+ // before is restored on close.
const registrationActive = computed(() => context.state.active === RegistrationToolsVue.name);
let preRegistrationSidebarMode: 'left' | 'bottom' | 'collapsed' | null = null;
watch(registrationActive, (active) => {
if (active) {
preRegistrationSidebarMode = sidebarMode.value;
- if (sidebarMode.value === 'left') {
- sidebarMode.value = 'collapsed';
- }
+ sidebarMode.value = 'collapsed';
} else if (preRegistrationSidebarMode !== null) {
sidebarMode.value = preRegistrationSidebarMode;
preRegistrationSidebarMode = null;
@@ -2372,6 +2372,7 @@ export default defineComponent({
cycleSidebarMode,
sidebarModeIcon,
sidebarModeTooltip,
+ registrationActive,
bottomRightPanelView,
toggleBottomRightPanel,
colorBy,
@@ -2543,7 +2544,14 @@ export default defineComponent({
+
diff --git a/client/platform/desktop/frontend/components/Export.vue b/client/platform/desktop/frontend/components/Export.vue
index a1516b693..2b041ee6b 100644
--- a/client/platform/desktop/frontend/components/Export.vue
+++ b/client/platform/desktop/frontend/components/Export.vue
@@ -409,9 +409,12 @@ export default defineComponent({
depressed
block
class="my-1"
+ :title="`Registration: ${file.camera}${file.destination ? ` → ${file.destination}` : ''}`"
@click="exportRegistration(file.camera)"
>
- Registration: {{ file.camera }}{{ file.destination ? ` → ${file.destination}` : '' }}
+
+ Registration: {{ file.camera }}{{ file.destination ? ` → ${file.destination}` : '' }}
+
@@ -454,4 +457,13 @@ export default defineComponent({
font-weight: 600;
line-height: 1.3;
}
+
+/* Long camera names overflow the block button otherwise; the full label is
+ still available via the button's native title tooltip on hover. */
+.registration-export-btn__label {
+ min-width: 0;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
diff --git a/client/platform/web-girder/views/Export.vue b/client/platform/web-girder/views/Export.vue
index 1f774185f..bbf4fa786 100644
--- a/client/platform/web-girder/views/Export.vue
+++ b/client/platform/web-girder/views/Export.vue
@@ -548,9 +548,12 @@ export default defineComponent({
depressed
block
class="my-1"
+ :title="`Registration: ${file.camera}${file.destination ? ` → ${file.destination}` : ''}`"
@click="exportRegistration(file.camera)"
>
- Registration: {{ file.camera }}{{ file.destination ? ` → ${file.destination}` : '' }}
+
+ Registration: {{ file.camera }}{{ file.destination ? ` → ${file.destination}` : '' }}
+
@@ -622,4 +625,13 @@ export default defineComponent({
overflow-y: auto;
overflow-x: hidden;
}
+
+/* Long camera names overflow the block button otherwise; the full label is
+ still available via the button's native title tooltip on hover. */
+.registration-export-btn__label {
+ min-width: 0;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
diff --git a/client/src/components/annotators/VideoAnnotator.vue b/client/src/components/annotators/VideoAnnotator.vue
index 35a591526..2ea308f17 100644
--- a/client/src/components/annotators/VideoAnnotator.vue
+++ b/client/src/components/annotators/VideoAnnotator.vue
@@ -305,6 +305,13 @@ export default defineComponent({
// is switching from number -> undefined, or vice versa.
function pendingUpdate() {
data.syncedFrame = Math.round(video.currentTime * props.frameRate);
+ // The aligned-view warp is a canvas snapshot of this