+
+ {{ entry.valuePrepend }}
+
+
+
+ {{ attributeName }} Value
+
+
+
+
+ {{ displayValueText }}
+
+
+ {{ entry.tooltip }}
+
+
+
+
+
+
+
+
+
+ {{ displayValueText }}
+
+
+ {{ entry.tooltip }}
+
+
+
+
+
+ {{ truncatedDisplayValueText }}
+
+
+ {{ entry.tooltip }}
+
+ {{ entry.valueAppend }}
+
+
+
+
diff --git a/client/dive-common/components/CustomUI/CustomUIBase.vue b/client/dive-common/components/CustomUI/CustomUIBase.vue
index 2f72bcfd..6eba3123 100644
--- a/client/dive-common/components/CustomUI/CustomUIBase.vue
+++ b/client/dive-common/components/CustomUI/CustomUIBase.vue
@@ -6,14 +6,29 @@ import {
} from 'vue';
import StackedVirtualSidebarContainer from 'dive-common/components/StackedVirtualSidebarContainer.vue';
+import CustomUIAttributeValueDisplay from 'dive-common/components/CustomUI/CustomUIAttributeValueDisplay.vue';
import {
useAttributes, useCameraStore, useConfiguration, useSelectedTrackId, useTime,
- useHandler,
+ useHandler, useTrackStyleManager,
} from 'vue-media-annotator/provides';
import AttributeSubsection from 'dive-common/components/Attributes/AttributesSubsection.vue';
import { useStore } from 'platform/web-girder/store/types';
import { usePrompt } from 'dive-common/vue-utilities/prompt-service';
import { Attribute, AttributeShortcut } from 'vue-media-annotator/use/AttributeTypes';
+import {
+ formatAttributeDisplayValue,
+ getCustomUIDisplayValueColorStyle,
+ getStickyValueIndicatorStyle,
+ getStickyValueTooltip,
+ LONG_VALUE_EXPAND_THRESHOLD,
+ ResolvedAttributeCustomUI,
+ resolveAttributeCustomUI,
+ resolveCustomUIDisplayValueColor,
+ resolveStickyAttributeValue,
+ shouldShowAttributeInCustomUI,
+} from 'vue-media-annotator/use/attributeCustomUI';
+import type { AttributeDisplayValueInfo } from 'vue-media-annotator/use/attributeCustomUI';
+import createGetAttributeValueColor from 'vue-media-annotator/use/attributeValueColor';
import { DIVEAction, DIVEMetadataAction } from 'dive-common/use/useActions';
import useMetadataLinkUpdater from 'dive-common/use/useMetadataLinkUpdater';
import type { MetadataLinkUpdateContext } from 'dive-common/use/useMetadataLinkUpdater';
@@ -26,7 +41,6 @@ interface AttributeDisplayButton {
prependIcon?: string;
appendIcon?: string;
buttonToolTip?: string;
- displayValue?: boolean;
attrName: string;
type: Attribute['belongs'];
userAttribute: boolean;
@@ -51,6 +65,7 @@ interface AttributeButtons {
type: 'track' | 'detection';
description?: string;
buttons: AttributeDisplayButton[];
+ customUI: ResolvedAttributeCustomUI;
}
type AttributeButtonList = AttributeButtons[];
@@ -61,6 +76,7 @@ export default defineComponent({
components: {
StackedVirtualSidebarContainer,
AttributeSubsection,
+ CustomUIAttributeValueDisplay,
},
props: {
@@ -73,6 +89,7 @@ export default defineComponent({
setup(props) {
const configMan = useConfiguration();
const attributes = useAttributes();
+ const getAttributeValueColor = createGetAttributeValueColor(useTrackStyleManager());
const { inputValue } = usePrompt();
const { frame: frameRef, frameRate } = useTime();
const store = useStore();
@@ -404,11 +421,61 @@ export default defineComponent({
return handler;
};
+ const getAttributeDisplayValueInfo = (
+ attribute: Attribute,
+ ): AttributeDisplayValueInfo => {
+ const customUI = resolveAttributeCustomUI(attribute);
+ let currentValue: unknown;
+ const hasSegmentShortcut = attribute.shortcuts?.some((shortcut) => shortcut.segment);
+ if (hasSegmentShortcut && selectedTrackIdRef.value !== null && frameRef.value !== undefined) {
+ const track = cameraStore.getAnyTrack(selectedTrackIdRef.value);
+ const rangeVals = track.getFrameAttributeRanges(
+ [attribute.name],
+ store.state.User.user?.login || null,
+ );
+ const ranges = rangeVals[attribute.name];
+ if (ranges && ranges.length > 0) {
+ for (let i = 0; i < ranges.length; i += 2) {
+ const start = ranges[i];
+ const end = ranges[i + 1];
+ if (frameRef.value >= start && frameRef.value <= end) {
+ const [real] = track.getFeature(start);
+ if (real?.attributes) {
+ if (attribute.user && real.attributes.userAttributes) {
+ const user = store.state.User.user?.login;
+ if (user && real.attributes.userAttributes[user]) {
+ currentValue = (real.attributes.userAttributes[user] as StringKeyObject)[attribute.name];
+ }
+ } else {
+ currentValue = real.attributes[attribute.name];
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ if (currentValue === undefined) {
+ currentValue = getAttributeValue(attribute.name, attribute.belongs, !!attribute.user);
+ }
+ const track = selectedTrackIdRef.value !== null
+ ? cameraStore.getAnyTrack(selectedTrackIdRef.value)
+ : null;
+ return resolveStickyAttributeValue(attribute, {
+ frame: frameRef.value,
+ track,
+ userLogin: store.state.User.user?.login || null,
+ stickyValue: customUI.stickyValue,
+ currentValue,
+ });
+ };
+
const attributeButtons = computed(() => {
const attributeButtonList: AttributeButtonList = [];
attributes.value.forEach((attribute) => {
- if (attribute.shortcuts && attribute.shortcuts.length > 0) {
- const buttons: AttributeDisplayButton[] = [];
+ const customUI = resolveAttributeCustomUI(attribute);
+ const buttons: AttributeDisplayButton[] = [];
+ if (attribute.shortcuts?.length) {
attribute.shortcuts.forEach((shortcut) => {
if (shortcut.button) {
const { disabled, tooltip } = getButtonDisabled(attribute, shortcut);
@@ -418,7 +485,6 @@ export default defineComponent({
prependIcon: shortcut.button.iconPrepend,
appendIcon: shortcut.button.iconAppend,
buttonToolTip: tooltip,
- displayValue: shortcut.button.displayValue,
attrName: attribute.name,
type: attribute.belongs,
userAttribute: !!attribute.user,
@@ -429,15 +495,16 @@ export default defineComponent({
});
}
});
- if (buttons.length > 0) {
- attributeButtonList.push({
- name: attribute.displayText || attribute.name,
- attrName: attribute.name,
- description: attribute.description,
- type: attribute.belongs,
- buttons,
- });
- }
+ }
+ if (shouldShowAttributeInCustomUI(attribute, buttons.length)) {
+ attributeButtonList.push({
+ name: attribute.displayText || attribute.name,
+ attrName: attribute.name,
+ description: attribute.description,
+ type: attribute.belongs,
+ buttons,
+ customUI,
+ });
}
});
const order = configMan.configuration.value?.customUI?.attributeButtonOrder || [];
@@ -568,55 +635,107 @@ export default defineComponent({
// return buttonMapping;
// });
- const buttonValueMap: Ref