mirror of
https://github.com/PhotonVision/photonvision
synced 2026-07-06 03:31:41 +00:00
Vue 3 Upgrade (#1900)
## Description Upgrades to Vue 3 and necessary associated dependencies. Also fixes some issues with the layout and adds validation for object detection models. Closes #885, closes #1943, closes #1449. ## Meta Merge checklist: - [x] Pull Request title is [short, imperative summary](https://cbea.ms/git-commit/) of proposed changes - [x] The description documents the _what_ and _why_ - [ ] If this PR changes behavior or adds a feature, user documentation is updated - [ ] If this PR touches photon-serde, all messages have been regenerated and hashes have not changed unexpectedly - [ ] If this PR touches configuration, this is backwards compatible with settings back to v2024.3.1 - [ ] If this PR touches pipeline settings or anything related to data exchange, the frontend typing is updated - [ ] If this PR addresses a bug, a regression test for it is added --------- Co-authored-by: Matt M <matthew.morley.ca@gmail.com> Co-authored-by: Gold856 <117957790+Gold856@users.noreply.github.com> Co-authored-by: samfreund <techguy763@gmail.com>
This commit is contained in:
@@ -218,8 +218,8 @@ const setSelectedVideoFormat = (format: VideoFormat) => {
|
||||
<v-card class="mb-3" color="primary" dark>
|
||||
<v-card-title class="pa-6 pb-3">Camera Calibration</v-card-title>
|
||||
<v-card-text v-show="!isCalibrating">
|
||||
<v-card-subtitle class="pt-3 pl-2 pb-4 white--text">Current Calibration</v-card-subtitle>
|
||||
<v-simple-table fixed-header height="100%" dense>
|
||||
<v-card-subtitle class="pt-3 pl-2 pb-4 text-white">Current Calibration</v-card-subtitle>
|
||||
<v-table fixed-header height="100%" density="compact">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Resolution</th>
|
||||
@@ -239,20 +239,20 @@ const setSelectedVideoFormat = (format: VideoFormat) => {
|
||||
<td>{{ value.horizontalFOV !== undefined ? value.horizontalFOV.toFixed(2) + "°" : "-" }}</td>
|
||||
<td>{{ value.verticalFOV !== undefined ? value.verticalFOV.toFixed(2) + "°" : "-" }}</td>
|
||||
<td>{{ value.diagonalFOV !== undefined ? value.diagonalFOV.toFixed(2) + "°" : "-" }}</td>
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on, attrs }">
|
||||
<td v-bind="attrs" v-on="on" @click="setSelectedVideoFormat(value)">
|
||||
<v-icon small class="mr-2">mdi-information</v-icon>
|
||||
<v-tooltip location="bottom">
|
||||
<template #activator="{ props }">
|
||||
<td v-bind="props" @click="setSelectedVideoFormat(value)">
|
||||
<v-icon size="small" class="mr-2">mdi-information</v-icon>
|
||||
</td>
|
||||
</template>
|
||||
<span>Click for more info on this calibration.</span>
|
||||
</v-tooltip>
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-simple-table>
|
||||
</v-table>
|
||||
</v-card-text>
|
||||
<v-card-text v-if="useCameraSettingsStore().isConnected" class="d-flex flex-column pa-6 pt-0">
|
||||
<v-card-subtitle v-show="!isCalibrating" class="pl-0 pb-3 pt-3 white--text"
|
||||
<v-card-subtitle v-show="!isCalibrating" class="pl-0 pb-3 pt-3 text-white"
|
||||
>Configure New Calibration</v-card-subtitle
|
||||
>
|
||||
<v-form ref="form" v-model="settingsValid">
|
||||
@@ -272,7 +272,9 @@ const setSelectedVideoFormat = (format: VideoFormat) => {
|
||||
tooltip="Resolution to which camera frames are downscaled for detection. Calibration still uses full-res"
|
||||
:items="calibrationDivisors"
|
||||
:select-cols="8"
|
||||
@input="(v) => useCameraSettingsStore().changeCurrentPipelineSetting({ streamingFrameDivisor: +v }, false)"
|
||||
@update:modelValue="
|
||||
(v) => useCameraSettingsStore().changeCurrentPipelineSetting({ streamingFrameDivisor: +v }, false)
|
||||
"
|
||||
/>
|
||||
<pv-select
|
||||
v-model="boardType"
|
||||
@@ -353,14 +355,18 @@ const setSelectedVideoFormat = (format: VideoFormat) => {
|
||||
label="Draw Collected Corners"
|
||||
:switch-cols="8"
|
||||
tooltip="Draw all snapshots"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ drawAllSnapshots: args }, false)"
|
||||
@update:modelValue="
|
||||
(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ drawAllSnapshots: args }, false)
|
||||
"
|
||||
/>
|
||||
<pv-switch
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.cameraAutoExposure"
|
||||
label="Auto Exposure"
|
||||
:label-cols="4"
|
||||
tooltip="Enables or Disables camera automatic adjustment for current lighting conditions"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraAutoExposure: args }, false)"
|
||||
@update:modelValue="
|
||||
(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraAutoExposure: args }, false)
|
||||
"
|
||||
/>
|
||||
<pv-slider
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.cameraExposureRaw"
|
||||
@@ -371,7 +377,9 @@ const setSelectedVideoFormat = (format: VideoFormat) => {
|
||||
:max="useCameraSettingsStore().maxExposureRaw"
|
||||
:slider-cols="7"
|
||||
:step="1"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraExposureRaw: args }, false)"
|
||||
@update:modelValue="
|
||||
(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraExposureRaw: args }, false)
|
||||
"
|
||||
/>
|
||||
<pv-slider
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.cameraBrightness"
|
||||
@@ -379,7 +387,9 @@ const setSelectedVideoFormat = (format: VideoFormat) => {
|
||||
:min="0"
|
||||
:max="100"
|
||||
:slider-cols="7"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraBrightness: args }, false)"
|
||||
@update:modelValue="
|
||||
(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraBrightness: args }, false)
|
||||
"
|
||||
/>
|
||||
<pv-slider
|
||||
v-if="useCameraSettingsStore().currentPipelineSettings.cameraGain >= 0"
|
||||
@@ -389,7 +399,9 @@ const setSelectedVideoFormat = (format: VideoFormat) => {
|
||||
:min="0"
|
||||
:max="100"
|
||||
:slider-cols="7"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraGain: args }, false)"
|
||||
@update:modelValue="
|
||||
(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraGain: args }, false)
|
||||
"
|
||||
/>
|
||||
<pv-slider
|
||||
v-if="useCameraSettingsStore().currentPipelineSettings.cameraRedGain !== -1"
|
||||
@@ -399,7 +411,9 @@ const setSelectedVideoFormat = (format: VideoFormat) => {
|
||||
:max="100"
|
||||
:slider-cols="7"
|
||||
tooltip="Controls red automatic white balance gain, which affects how the camera captures colors in different conditions"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraRedGain: args }, false)"
|
||||
@update:modelValue="
|
||||
(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraRedGain: args }, false)
|
||||
"
|
||||
/>
|
||||
<pv-slider
|
||||
v-if="useCameraSettingsStore().currentPipelineSettings.cameraBlueGain !== -1"
|
||||
@@ -409,7 +423,9 @@ const setSelectedVideoFormat = (format: VideoFormat) => {
|
||||
:max="100"
|
||||
:slider-cols="7"
|
||||
tooltip="Controls blue automatic white balance gain, which affects how the camera captures colors in different conditions"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraBlueGain: args }, false)"
|
||||
@update:modelValue="
|
||||
(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraBlueGain: args }, false)
|
||||
"
|
||||
/>
|
||||
<v-banner
|
||||
v-if="tooManyPoints"
|
||||
@@ -423,7 +439,11 @@ const setSelectedVideoFormat = (format: VideoFormat) => {
|
||||
</v-banner>
|
||||
</v-card-text>
|
||||
<v-card-text v-if="isCalibrating" class="d-flex justify-center align-center pa-6 pt-0">
|
||||
<v-chip label :color="useStateStore().calibrationData.hasEnoughImages ? 'secondary' : 'gray'">
|
||||
<v-chip
|
||||
variant="flat"
|
||||
label
|
||||
:color="useStateStore().calibrationData.hasEnoughImages ? 'secondary' : 'grey-darken-2'"
|
||||
>
|
||||
Snapshots: {{ useStateStore().calibrationData.imageCount }} of at least
|
||||
{{ useStateStore().calibrationData.minimumImageCount }}
|
||||
</v-chip>
|
||||
@@ -431,26 +451,25 @@ const setSelectedVideoFormat = (format: VideoFormat) => {
|
||||
<v-card-text class="d-flex pa-6 pt-0">
|
||||
<v-col cols="6" class="pa-0 pr-2">
|
||||
<v-btn
|
||||
small
|
||||
size="small"
|
||||
block
|
||||
color="secondary"
|
||||
:disabled="!settingsValid || tooManyPoints"
|
||||
@click="isCalibrating ? useCameraSettingsStore().takeCalibrationSnapshot() : startCalibration()"
|
||||
>
|
||||
<v-icon left class="calib-btn-icon"> {{ isCalibrating ? "mdi-camera" : "mdi-flag-outline" }} </v-icon>
|
||||
<v-icon start class="calib-btn-icon"> {{ isCalibrating ? "mdi-camera" : "mdi-flag-outline" }} </v-icon>
|
||||
<span class="calib-btn-label">{{ isCalibrating ? "Take Snapshot" : "Start Calibration" }}</span>
|
||||
</v-btn>
|
||||
</v-col>
|
||||
<v-col cols="6" class="pa-0 pl-2">
|
||||
<v-btn
|
||||
small
|
||||
size="small"
|
||||
block
|
||||
:color="useStateStore().calibrationData.hasEnoughImages ? 'accent' : 'error'"
|
||||
:class="useStateStore().calibrationData.hasEnoughImages ? 'black--text' : 'white---text'"
|
||||
:disabled="!isCalibrating || !settingsValid"
|
||||
@click="endCalibration"
|
||||
>
|
||||
<v-icon left class="calib-btn-icon">
|
||||
<v-icon start class="calib-btn-icon">
|
||||
{{ useStateStore().calibrationData.hasEnoughImages ? "mdi-flag-checkered" : "mdi-flag-off-outline" }}
|
||||
</v-icon>
|
||||
<span class="calib-btn-label">{{
|
||||
@@ -460,8 +479,15 @@ const setSelectedVideoFormat = (format: VideoFormat) => {
|
||||
</v-col>
|
||||
</v-card-text>
|
||||
<v-card-text class="pa-6 pt-0">
|
||||
<v-btn color="accent" small block outlined :disabled="!settingsValid" @click="downloadCalibBoard">
|
||||
<v-icon left class="calib-btn-icon"> mdi-download </v-icon>
|
||||
<v-btn
|
||||
color="accent"
|
||||
size="small"
|
||||
block
|
||||
variant="outlined"
|
||||
:disabled="!settingsValid"
|
||||
@click="downloadCalibBoard"
|
||||
>
|
||||
<v-icon start class="calib-btn-icon"> mdi-download </v-icon>
|
||||
<span class="calib-btn-label">Generate Board</span>
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
@@ -507,7 +533,7 @@ const setSelectedVideoFormat = (format: VideoFormat) => {
|
||||
</div>
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn v-if="!isCalibrating" color="white" text @click="showCalibEndDialog = false"> OK </v-btn>
|
||||
<v-btn v-if="!isCalibrating" color="white" variant="text" @click="showCalibEndDialog = false"> OK </v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
@@ -518,7 +544,7 @@ const setSelectedVideoFormat = (format: VideoFormat) => {
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.v-data-table {
|
||||
.v-table {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ const calibrationImageURL = (index: number) =>
|
||||
</v-col>
|
||||
<v-col cols="6" md="3" class="d-flex align-center pt-0 pt-md-3 pl-6 pl-md-3">
|
||||
<v-btn color="secondary" style="width: 100%" @click="openUploadPhotonCalibJsonPrompt">
|
||||
<v-icon left> mdi-import</v-icon>
|
||||
<v-icon start> mdi-import</v-icon>
|
||||
<span>Import</span>
|
||||
</v-btn>
|
||||
<input
|
||||
@@ -115,7 +115,7 @@ const calibrationImageURL = (index: number) =>
|
||||
style="width: 100%"
|
||||
@click="openExportCalibrationPrompt"
|
||||
>
|
||||
<v-icon left>mdi-export</v-icon>
|
||||
<v-icon start>mdi-export</v-icon>
|
||||
<span>Export</span>
|
||||
</v-btn>
|
||||
<a
|
||||
@@ -126,16 +126,24 @@ const calibrationImageURL = (index: number) =>
|
||||
/>
|
||||
</v-col>
|
||||
</div>
|
||||
<v-card-title class="pt-0 pb-3"
|
||||
<v-card-title class="pl-6 pt-0 pb-0"
|
||||
>{{ useCameraSettingsStore().currentCameraName }}@{{ getResolutionString(videoFormat.resolution) }}</v-card-title
|
||||
>
|
||||
<v-card-text v-if="!currentCalibrationCoeffs">
|
||||
<v-banner rounded color="secondary" text-color="white" class="mt-3" icon="mdi-alert-circle-outline">
|
||||
<v-banner
|
||||
rounded
|
||||
bg-color="secondary"
|
||||
color="secondary"
|
||||
text-color="white"
|
||||
class="pt-3 pb-3 mt-3"
|
||||
density="compact"
|
||||
icon="mdi-alert-circle-outline"
|
||||
>
|
||||
The selected video format has not been calibrated.
|
||||
</v-banner>
|
||||
</v-card-text>
|
||||
<v-card-text>
|
||||
<v-simple-table dense style="width: 100%">
|
||||
<v-card-text class="pt-0">
|
||||
<v-table density="compact" style="width: 100%">
|
||||
<template #default>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -238,25 +246,36 @@ const calibrationImageURL = (index: number) =>
|
||||
</tr>
|
||||
</tbody>
|
||||
</template>
|
||||
</v-simple-table>
|
||||
</v-table>
|
||||
</v-card-text>
|
||||
<v-card-title v-if="currentCalibrationCoeffs" class="pt-0">Individual Observations</v-card-title>
|
||||
<v-card-text v-if="currentCalibrationCoeffs">
|
||||
<v-data-table
|
||||
dense
|
||||
density="compact"
|
||||
style="width: 100%"
|
||||
:headers="[
|
||||
{ text: 'Observation Id', value: 'index' },
|
||||
{ text: 'Mean Reprojection Error', value: 'mean' },
|
||||
{ text: '', value: 'data-table-expand' }
|
||||
{ title: 'Observation Id', key: 'index' },
|
||||
{ title: 'Mean Reprojection Error', key: 'mean' },
|
||||
{ title: '', key: 'data-table-expand' }
|
||||
]"
|
||||
:items="getObservationDetails()"
|
||||
item-key="index"
|
||||
item-value="index"
|
||||
show-expand
|
||||
expand-icon="mdi-eye"
|
||||
>
|
||||
<template #expanded-item="{ headers, item }">
|
||||
<td :colspan="headers.length">
|
||||
<template #item.data-table-expand="{ internalItem, toggleExpand }">
|
||||
<v-btn
|
||||
icon="mdi-eye"
|
||||
class="text-none"
|
||||
color="medium-emphasis"
|
||||
size="small"
|
||||
variant="text"
|
||||
slim
|
||||
@click="toggleExpand(internalItem)"
|
||||
></v-btn>
|
||||
</template>
|
||||
|
||||
<template #expanded-row="{ columns, item }">
|
||||
<td :colspan="columns.length">
|
||||
<div style="display: flex; justify-content: center; width: 100%">
|
||||
<img :src="calibrationImageURL(item.index)" alt="observation image" class="snapshot-preview pt-2 pb-2" />
|
||||
</div>
|
||||
|
||||
@@ -91,16 +91,16 @@ const expanded = ref([]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-card dark style="background-color: #006492">
|
||||
<v-card style="background-color: #006492">
|
||||
<v-card-title>Camera Control</v-card-title>
|
||||
<v-card-text>
|
||||
<v-btn color="secondary" @click="fetchSnapshots">
|
||||
<v-icon left class="open-icon"> mdi-folder </v-icon>
|
||||
<v-icon start class="open-icon"> mdi-folder </v-icon>
|
||||
<span class="open-label">Show Saved Snapshots</span>
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
<v-dialog v-model="showSnapshotViewerDialog">
|
||||
<v-card dark class="pt-3 pl-5 pr-5" color="primary" flat>
|
||||
<v-card class="pt-3 pl-5 pr-5" color="primary" flat>
|
||||
<v-card-title> View Saved Frame Snapshots </v-card-title>
|
||||
<v-divider />
|
||||
<v-card-text v-if="imgData.length === 0" style="font-size: 18px; font-weight: 600" class="pt-4">
|
||||
@@ -110,22 +110,33 @@ const expanded = ref([]);
|
||||
<v-data-table
|
||||
v-model:expanded="expanded"
|
||||
:headers="[
|
||||
{ text: 'Snapshot Name', value: 'snapshotShortName', sortable: false },
|
||||
{ text: 'Camera Unique Name', value: 'cameraUniqueName' },
|
||||
{ text: 'Camera Nickname', value: 'cameraNickname' },
|
||||
{ text: 'Stream Type', value: 'streamType' },
|
||||
{ text: 'Time Created', value: 'timeCreated' },
|
||||
{ text: 'Actions', value: 'actions', sortable: false }
|
||||
{ title: 'Snapshot Name', key: 'snapshotShortName', sortable: false },
|
||||
{ title: 'Camera Unique Name', key: 'cameraUniqueName' },
|
||||
{ title: 'Camera Nickname', key: 'cameraNickname' },
|
||||
{ title: 'Stream Type', key: 'streamType' },
|
||||
{ title: 'Time Created', key: 'timeCreated' },
|
||||
{ title: 'Actions', key: 'actions', sortable: false }
|
||||
]"
|
||||
:items="imgData"
|
||||
group-by="cameraUniqueName"
|
||||
:group-by="[{ key: 'cameraUniqueName' }]"
|
||||
class="elevation-0"
|
||||
item-key="index"
|
||||
item-value="index"
|
||||
show-expand
|
||||
expand-icon="mdi-eye"
|
||||
>
|
||||
<template #expanded-item="{ headers, item }">
|
||||
<td :colspan="headers.length">
|
||||
<template #item.data-table-expand="{ internalItem, toggleExpand }">
|
||||
<v-btn
|
||||
icon="mdi-eye"
|
||||
class="text-none"
|
||||
color="medium-emphasis"
|
||||
size="small"
|
||||
variant="text"
|
||||
slim
|
||||
@click="toggleExpand(internalItem)"
|
||||
></v-btn>
|
||||
</template>
|
||||
|
||||
<template #expanded-row="{ item, columns }">
|
||||
<td :colspan="columns.length">
|
||||
<div style="display: flex; justify-content: center; width: 100%">
|
||||
<img :src="item.snapshotSrc" alt="snapshot-image" class="snapshot-preview pt-2 pb-2" />
|
||||
</div>
|
||||
@@ -135,7 +146,7 @@ const expanded = ref([]);
|
||||
<template #item.actions="{ item }">
|
||||
<div style="display: flex; justify-content: center">
|
||||
<a :download="item.snapshotName" :href="item.snapshotSrc">
|
||||
<v-icon small> mdi-download </v-icon>
|
||||
<v-icon size="small"> mdi-download </v-icon>
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
@@ -157,7 +168,7 @@ const expanded = ref([]);
|
||||
.v-btn {
|
||||
width: 100%;
|
||||
}
|
||||
.v-data-table {
|
||||
.v-table {
|
||||
text-align: center;
|
||||
background-color: #006492 !important;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import PvSelect, { type SelectItem } from "@/components/common/pv-select.vue";
|
||||
import PvInput from "@/components/common/pv-input.vue";
|
||||
import PvNumberInput from "@/components/common/pv-number-input.vue";
|
||||
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
@@ -203,30 +204,30 @@ const wrappedCameras = computed<SelectItem[]>(() =>
|
||||
</v-card-text>
|
||||
<v-card-text class="d-flex pa-6 pt-0">
|
||||
<v-col cols="6" class="pa-0 pr-2">
|
||||
<v-btn block small color="secondary" :disabled="!settingsHaveChanged()" @click="saveCameraSettings">
|
||||
<v-icon left> mdi-content-save </v-icon>
|
||||
<v-btn block size="small" color="secondary" :disabled="!settingsHaveChanged()" @click="saveCameraSettings">
|
||||
<v-icon start> mdi-content-save </v-icon>
|
||||
Save Changes
|
||||
</v-btn>
|
||||
</v-col>
|
||||
<v-col cols="6" class="pa-0 pl-2">
|
||||
<v-btn block small color="error" @click="() => (showDeleteCamera = true)">
|
||||
<v-icon left> mdi-trash-can-outline </v-icon>
|
||||
<v-btn block size="small" color="error" @click="() => (showDeleteCamera = true)">
|
||||
<v-icon start> mdi-trash-can-outline </v-icon>
|
||||
Delete Camera
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-card-text>
|
||||
|
||||
<v-dialog v-model="showDeleteCamera" dark width="800">
|
||||
<v-card dark class="dialog-container pa-3 pb-2" color="primary" flat>
|
||||
<v-dialog v-model="showDeleteCamera" width="800">
|
||||
<v-card class="dialog-container pa-3 pb-2" color="primary" flat>
|
||||
<v-card-title> Delete {{ useCameraSettingsStore().currentCameraSettings.nickname }}? </v-card-title>
|
||||
<v-card-text>
|
||||
<v-row class="align-center pt-6">
|
||||
<v-col cols="12" md="6">
|
||||
<span class="white--text"> This will delete ALL OF YOUR SETTINGS and restart PhotonVision. </span>
|
||||
<span class="text-white"> This will delete ALL OF YOUR SETTINGS and restart PhotonVision. </span>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-btn color="secondary" block @click="openExportSettingsPrompt">
|
||||
<v-icon left class="open-icon"> mdi-export </v-icon>
|
||||
<v-icon start class="open-icon"> mdi-export </v-icon>
|
||||
<span class="open-label">Backup Settings</span>
|
||||
<a
|
||||
ref="exportSettings"
|
||||
@@ -257,7 +258,7 @@ const wrappedCameras = computed<SelectItem[]>(() =>
|
||||
:loading="deletingCamera"
|
||||
@click="deleteThisCamera"
|
||||
>
|
||||
<v-icon left class="open-icon"> mdi-trash-can-outline </v-icon>
|
||||
<v-icon start class="open-icon"> mdi-trash-can-outline </v-icon>
|
||||
<span class="open-label">DELETE (UNRECOVERABLE)</span>
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
|
||||
@@ -6,19 +6,7 @@ import { PipelineType } from "@/types/PipelineTypes";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
import { useSettingsStore } from "@/stores/settings/GeneralSettingsStore";
|
||||
|
||||
const props = defineProps<{
|
||||
// TODO fully update v-model usage in custom components on Vue3 update
|
||||
value: number[];
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "input", value: number[]): void;
|
||||
}>();
|
||||
|
||||
const localValue = computed({
|
||||
get: () => props.value,
|
||||
set: (v) => emit("input", v)
|
||||
});
|
||||
const value = defineModel<number[]>({ required: true });
|
||||
|
||||
const driverMode = computed<boolean>({
|
||||
get: () => useCameraSettingsStore().isDriverMode,
|
||||
@@ -52,15 +40,14 @@ const fpsTooLow = computed<boolean>(() => {
|
||||
v-if="useCameraSettingsStore().currentCameraSettings.isConnected"
|
||||
label
|
||||
:color="fpsTooLow ? 'error' : 'transparent'"
|
||||
:text-color="fpsTooLow ? '#C7EA46' : '#ff4d00'"
|
||||
style="font-size: 1rem; padding: 0; margin: 0"
|
||||
>
|
||||
<span class="pr-1">
|
||||
<span class="pr-1" :style="{ color: fpsTooLow ? '#C7EA46' : '#ff4d00' }">
|
||||
{{ Math.round(useStateStore().currentPipelineResults?.fps || 0) }} FPS –
|
||||
{{ Math.min(Math.round(useStateStore().currentPipelineResults?.latency || 0), 9999) }} ms latency
|
||||
</span>
|
||||
</v-chip>
|
||||
<v-chip v-else label color="transparent" text-color="red" style="font-size: 1rem; padding: 0; margin: 0">
|
||||
<v-chip v-else label color="red" variant="text" style="font-size: 1rem; padding: 0; margin: 0">
|
||||
<span class="pr-1">Camera not connected</span>
|
||||
</v-chip>
|
||||
</div>
|
||||
@@ -98,13 +85,20 @@ const fpsTooLow = computed<boolean>(() => {
|
||||
</div>
|
||||
</v-card-text>
|
||||
<v-card-text class="pt-0">
|
||||
<v-btn-toggle v-model="localValue" :multiple="true" mandatory dark class="fill" style="width: 100%">
|
||||
<v-btn-toggle
|
||||
v-model="value"
|
||||
:multiple="true"
|
||||
mandatory
|
||||
class="fill"
|
||||
style="width: 100%"
|
||||
base-color="surface-variant"
|
||||
>
|
||||
<v-btn
|
||||
color="secondary"
|
||||
class="fill"
|
||||
:disabled="useCameraSettingsStore().isDriverMode || useCameraSettingsStore().isCalibrationMode"
|
||||
>
|
||||
<v-icon left class="mode-btn-icon">mdi-import</v-icon>
|
||||
<v-icon start class="mode-btn-icon">mdi-import</v-icon>
|
||||
<span class="mode-btn-label">Raw</span>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
@@ -112,7 +106,7 @@ const fpsTooLow = computed<boolean>(() => {
|
||||
class="fill"
|
||||
:disabled="useCameraSettingsStore().isDriverMode || useCameraSettingsStore().isCalibrationMode"
|
||||
>
|
||||
<v-icon left class="mode-btn-icon">mdi-export</v-icon>
|
||||
<v-icon start class="mode-btn-icon">mdi-export</v-icon>
|
||||
<span class="mode-btn-label">Processed</span>
|
||||
</v-btn>
|
||||
</v-btn-toggle>
|
||||
@@ -123,7 +117,6 @@ const fpsTooLow = computed<boolean>(() => {
|
||||
<style scoped>
|
||||
.v-btn-toggle.fill {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.v-btn-toggle.fill > .v-btn {
|
||||
width: 50%;
|
||||
|
||||
Reference in New Issue
Block a user