<template> <q-scroll-area :style="{ height: content_height + 'px' }" style="width: 20vw"> <q-tree ref="tree" :nodes="tree_nodes" node-key="uuid" labelKey="name"> <template v-slot:default-header="prop"> <q-item class="full-width" clickable :disable="!$store.state.power_state" :draggable=" prop.node.uuid != '' && $store.state.power_state && (!prop.node.item_data.system_default || !prop.node.is_group) " @dragstart="(evt) => onDragStart(evt, prop.node)" @dragover="(evt) => onDragOver(evt, prop.node)" @drop="(evt) => onDrop(evt, prop.node)" @click=" $store.commit( 'setSelectedSignalSource', prop.node.is_group ? $store.state.selected_signal_source : prop.node.uuid ) " :style="{ border: $store.state.selected_signal_source == prop.node.uuid ? '1px solid #aacceec2' : 'none', }" > <!-- {{ prop.node }} --> <q-item-section avatar> <q-icon style="pointer-events: none" :name=" prop.node.is_group ? 'img:source_icon/group.png' : getItemIcon(prop.node.item_data?.window_type) " color="orange" size="28px" class="q-mr-sm" /> </q-item-section> <q-item-section> <div class="text-weight-bold text-primary"> {{ prop.node.name }} </div> </q-item-section> <q-popup-proxy :context-menu="$store.state.power_state" @before-show="updateContextMenu" > <q-list> <q-item clickable v-ripple v-close-popup v-if="prop.node.item_data?.window_type == 'EwindowType::HdmiIn'" @click="setHdmiInDecodeType(1, 'NV12')" > <q-item-section> {{ $t("lossy ") + $t("picture quality") }} </q-item-section> <q-item-section side v-if="lossy_pic"> <q-icon name="done" /> </q-item-section> </q-item> <q-item clickable v-ripple v-close-popup v-if="prop.node.item_data?.window_type == 'EwindowType::HdmiIn'" @click="setHdmiInDecodeType(1, 'NV16')" > <q-item-section> {{ $t("lossless ") + $t("picture quality") }} </q-item-section> <q-item-section side v-if="!lossy_pic"> <q-icon name="done" /> </q-item-section> </q-item> <q-item clickable v-ripple v-if=" $store.state.isSpecialVideo() && prop.node.item_data?.window_type == 'EwindowType::HdmiIn' " > <q-item-section> {{ $t("rotation") }} </q-item-section> <q-item-section side> <q-icon name="keyboard_arrow_right" /> </q-item-section> <q-menu @before-show="updateCurrentHdmiRotation" anchor="top end" self="top start" > <q-list> <q-item v-close-popup v-for="n in [0, 90, 180, 270]" :key="n" clickable @click="setHDMIRotation(n)" > <q-item-section>{{ n }}°</q-item-section> <q-item-section side> <q-icon v-if="n == current_hdmi_rotation" name="done" /> </q-item-section> </q-item> </q-list> </q-menu> </q-item> <q-item v-if=" prop.node.name == $t('signal source') || (prop.node.is_group && prop.node.item_data && !prop.node.item_data.system_default) " clickable v-close-popup v-ripple @click=" $refs.signal_source_dialog.showDialog({ type: 1, parent_node: prop.node.uuid, }) " > <q-item-section avatar><q-icon name="add" /></q-item-section> <q-item-section>{{ $t("add signal source item") }}</q-item-section> </q-item> <q-item clickable v-close-popup v-if=" prop.node.name == $t('signal source') || (prop.node.is_group && prop.node.item_data && !prop.node.item_data.system_default) " v-ripple @click=" () => $refs.group_dialog.showDialog({ type: 1, data: prop.node, }) " > <q-item-section avatar ><q-icon name="create_new_folder" /></q-item-section> <q-item-section>{{ $t("add group") }}</q-item-section> </q-item> <q-item clickable v-ripple v-close-popup v-if=" prop.node.item_data && prop.node.item_data.uuid && !prop.node.item_data.system_default " @click=" () => (prop.node.is_group ? $refs.group_dialog : $refs.signal_source_dialog ).showDialog({ type: 2, data: prop.node, }) " > <q-item-section avatar><q-icon name="edit" /></q-item-section> <q-item-section>{{ $t("edit") }}</q-item-section> </q-item> <q-item clickable v-ripple v-close-popup v-if=" prop.node.item_data && prop.node.item_data.uuid && !prop.node.item_data.system_default " @click=" (evt) => deleteItem(evt, prop.node.is_group, prop.node.uuid) " > <q-item-section avatar ><q-icon color="red" name="delete" /></q-item-section> <q-item-section>{{ $t("delete") }} </q-item-section> </q-item> </q-list> </q-popup-proxy> </q-item> </template> </q-tree> </q-scroll-area> <signal-source-group-dialog ref="group_dialog" /> <signal-source-dialog ref="signal_source_dialog" /> </template> <script lang="ts"> import { defineComponent, computed, onMounted, ref } from "vue"; import { useStore } from "src/store"; import { SignalSourceEntity, SignalSourceTreeItemEntity, } from "src/entities/SignalSourceEntity"; import SignalSourceGroupDialog from "src/components/SignalSourceGroupDialog.vue"; import SignalSourceDialog from "src/components/SignalSourceDialog.vue"; import { Common } from "src/common/Common"; import GlobalData from "src/common/GlobalData"; import { useQuasar, extend } from "quasar"; import { useI18n } from "vue-i18n"; import EventBus, { EventNamesDefine } from "src/common/EventBus"; import { Protocol } from "src/entities/WSProtocol"; import { NotifyMessage } from "src/common/ClientConnection"; export default defineComponent({ name: "ComponentSignalSourceTree", components: { SignalSourceGroupDialog, SignalSourceDialog }, setup() { const $store = useStore(); const $q = useQuasar(); const $t = useI18n(); const lossy_pic = ref(false); const content_height = ref(0); const current_hdmi_rotation = ref(0); const refresh_content_height = () => { content_height.value = window.innerHeight - 135; }; refresh_content_height(); EventBus.getInstance().on(EventNamesDefine.WindowResize, () => { refresh_content_height(); }); const tree_nodes = computed({ get: () => $store.state.signal_source_tree, set: (val) => $store.commit("setSignalSourceTree", val), }); const tree: any | null = ref(null); onMounted(async () => { while (!tree.value?.nodes?.length) { await Common.waitFor(100); } tree.value?.setExpanded("", true); }); return { tree, tree_nodes, content_height, lossy_pic, current_hdmi_rotation, loga(a: any) { console.log(a); }, onDragStart(e: DragEvent, node: SignalSourceTreeItemEntity) { e.dataTransfer?.setData("uuid", node.uuid); e.dataTransfer?.setData("type", "signal_source"); e.dataTransfer?.setData("group", node.is_group ? "true" : "false"); e.dataTransfer?.setData("node_object", JSON.stringify(node)); if (e.dataTransfer) { e.dataTransfer.dropEffect = "move"; } }, onDragOver(e: DragEvent, node: SignalSourceTreeItemEntity) { if (node && node.is_group && !node.item_data?.system_default) { e.preventDefault(); } }, onDrop(e: DragEvent, node: SignalSourceTreeItemEntity) { if ( node && node.is_group && node.item_data && !node.item_data.system_default ) { if (e.dataTransfer) { const type = e.dataTransfer.getData("type"); if (type == "signal_source") { const uuid = e.dataTransfer.getData("uuid"); const group = e.dataTransfer.getData("group"); if ( typeof uuid == "string" && type && type.length > 0 && group && group.length > 0 ) { if (group == "true") { const signal_source_group = GlobalData.getInstance().signal_source_groups.find( (item) => item && (item as any).uuid == uuid ); if (signal_source_group) { if (signal_source_group.system_default) { return; } if ( signal_source_group.parent_uuid == node.item_data.uuid ) { return; } GlobalData.getInstance() .getCurrentClient() ?.editSignalSourceGroup( signal_source_group.uuid, signal_source_group.name, node.item_data.uuid ); } else { console.log("can't find signal source group, uuid:" + uuid); } } else if (group == "false") { const signal_source = GlobalData.getInstance().signal_source.find( (item) => item && (item as any).uuid == uuid ); if (signal_source) { if (signal_source.system_default) { return; } if (signal_source.group_uuid == node.item_data.uuid) { return; } const entity = extend( false, signal_source ) as SignalSourceEntity; entity.group_uuid = node.item_data.uuid; GlobalData.getInstance() .getCurrentClient() ?.editSignalSource(entity); } else { console.log("can't find signal source, uuid:" + uuid); } } } } else { console.log("type error"); } } } }, getItemIcon(item_type: string) { return Common.getSignalSourceIcon(item_type); }, deleteItem(evt: PointerEvent | null, is_group: boolean, uuid: string) { const show_tooltip = (success: boolean) => { $q.notify({ color: success ? "positive" : "negative", icon: success ? "done" : "warning", message: $t.t("delete") + (success ? $t.t("success") : $t.t("fail")) + "!", position: "top", timeout: 1500, }); }; if (is_group) { $q.dialog({ title: $t.t("Confirm"), message: $t.t( "delete group should be delete all child! do you want to delete this group?" ), ok: { label: $t.t("ok"), noCaps: true, flat: true, }, cancel: { label: $t.t("cancel"), noCaps: true, flat: true, }, persistent: true, }).onOk(async () => { let success = false; let response = await GlobalData.getInstance() .getCurrentClient() ?.deleteSignalSourceGroup(uuid); if (response) { success = response.success; } show_tooltip(success); }); } else { $q.dialog({ title: $t.t("Confirm"), message: $t.t("do you want to delete the item") + "?", ok: { label: $t.t("ok"), noCaps: true, flat: true, }, cancel: { label: $t.t("cancel"), noCaps: true, flat: true, }, persistent: true, }).onOk(async () => { let success = false; let response = await GlobalData.getInstance() .getCurrentClient() ?.deleteSignalSource(uuid); if (response) { success = response.success; } show_tooltip(success); }); } }, updateContextMenu() { lossy_pic.value = GlobalData.getInstance().applicationConfig?.hdmi_in_decode_type_1 == "NV12"; }, async setHdmiInDecodeType(index: number, type: string) { let success = false; const response = await GlobalData.getInstance() .getCurrentClient() ?.setHdmiInDecodeType(index, type); if (response) { success = response.success; } $q.notify({ color: success ? "positive" : "negative", icon: success ? "done" : "warning", message: $t.t("set") + (success ? $t.t("success") : $t.t("fail")) + "!", position: "top", timeout: 1500, }); }, updateCurrentHdmiRotation() { current_hdmi_rotation.value = GlobalData.getInstance().applicationConfig?.device_hdmi_rotation ?? 0; }, setHDMIRotation(rotation: number) { let success = true; try { GlobalData.getInstance() .getCurrentClient() ?.setHdmiRotation(rotation); } catch { success = false; } $q.notify({ color: success ? "positive" : "negative", icon: success ? "done" : "warning", message: $t.t("set") + (success ? $t.t("success") : $t.t("fail")) + "!", position: "top", timeout: 1500, }); }, }; }, }); </script>