重构拖拽到拼接墙开窗坐标计算逻辑。

添加修改窗口矩形对话框。
字幕对话框隐藏背景颜色设置。
This commit is contained in:
fangxiang 2022-04-25 16:41:42 +08:00
parent 243b6555be
commit c6d206703d
8 changed files with 514 additions and 68 deletions

View File

@ -1,6 +1,6 @@
{
"name": "media_player_client",
"version": "1.4.1",
"version": "1.4.2",
"description": "A Quasar Framework app",
"author": "fangxiang <fangxiang@cloudview.work>",
"private": true,
@ -9,4 +9,4 @@
"@capacitor/cli": "^2.0.0",
"@capacitor/core": "^2.0.0"
}
}
}

View File

@ -12,7 +12,7 @@
"
>
<q-card class="overflow-hidden" style="overflow-y: scroll; max-width: 35vw">
<q-form @submit="onSubmit">
<q-form>
<q-card-section class="q-ma-none q-pa-sm">
<div class="row">
<div class="col-auto text-h6">AdvancedDebug</div>
@ -56,14 +56,6 @@
color="primary"
v-close-popup
/>
<q-btn
ref="accept"
flat
:label="$t('Accept')"
:loading="loading"
type="submit"
color="primary"
/>
</q-card-actions>
</q-form>
</q-card>

View File

@ -56,9 +56,9 @@
<q-separator />
<q-card-section class="scroll" style="width: 60vw">
<q-card-section class="scroll" style="width: 70vw">
<q-list>
<q-item>
<q-item v-if="false">
<q-item-section>
<q-input
:label="$t('background color')"

View File

@ -43,6 +43,14 @@
>
<q-item-section> {{ $t("replace window") }} </q-item-section>
</q-item>
<q-item
clickable
v-close-popup
:disable="$props.disable"
@click="$emit('edit_rect', $props.window.window_id)"
>
<q-item-section> {{ $t("edit window rect") }} </q-item-section>
</q-item>
<q-item
clickable
v-close-popup
@ -274,6 +282,7 @@ export default defineComponent({
"start_polling",
"polling_setting",
"dbtouch",
"edit_rect",
],
setup(props, { emit }) {
const $store = useStore();

View File

@ -0,0 +1,347 @@
<template>
<q-dialog
persistent
v-model="show_dialog"
@before-hide="resetData"
@keydown="
(evt) => {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
}
}
"
>
<q-card class="overflow-hidden" style="overflow-y: scroll; max-width: 50vw">
<q-form @submit="onSubmit">
<q-card-section class="q-ma-none q-pa-sm">
<div class="row">
<div class="col-auto text-h6">
{{ $t("window rect") }}
</div>
<q-space />
<div>
<q-btn
:loading="loading"
flat
round
icon="close"
color="red"
v-close-popup
>
<q-tooltip>
{{ $t("close") }}
</q-tooltip>
</q-btn>
</div>
</div>
</q-card-section>
<q-separator />
<q-card-section style="max-height: 40vh; width: 50vw" class="scroll">
<q-list>
<q-item class="text-center text-h6">
<q-item-section>
<q-item-label>
<span>{{ $t("desktop width") }}: </span>
<span>
{{ $store.state.device_screen_width }}
</span>
<span>{{ $t("px") }}</span>
</q-item-label>
</q-item-section>
<q-item-section>
<q-item-label>
<span>{{ $t("desktop height") }}: </span>
<span>
{{ $store.state.device_screen_height }}
</span>
<span>{{ $t("px") }}</span>
</q-item-label>
</q-item-section>
</q-item>
<q-separator />
<q-item>
<q-item-section>
<q-item>
<q-item-section avatar>
<span class="q-mb-md">{{ $t("X") }}:</span>
</q-item-section>
<q-item-section>
<q-input
autofocus
type="number"
min="0"
v-model="window_rect.x"
:rules="[
(val) =>
(val != null &&
val != undefined &&
val.toString().length > 0) ||
$t('Please type something'),
(val) =>
parseInt(val) >= 0 ||
$t('the number must be greater than 0'),
]"
lazy-rules
>
<template v-slot:append>
<span class="input_append">{{ $t("px") }}</span>
</template>
</q-input>
</q-item-section>
</q-item>
</q-item-section>
<q-item-section>
<q-item>
<q-item-section avatar>
<span class="q-mb-md">{{ $t("Y") }}:</span>
</q-item-section>
<q-item-section>
<q-input
type="number"
min="0"
v-model="window_rect.y"
:rules="[
(val) =>
(val != null &&
val != undefined &&
val.toString().length > 0) ||
$t('Please type something'),
(val) =>
parseInt(val) >= 0 ||
$t('the number must be greater than 0'),
]"
lazy-rules
>
<template v-slot:append>
<span class="input_append">{{ $t("px") }}</span>
</template>
</q-input>
</q-item-section>
</q-item>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-item>
<q-item-section avatar>
<span class="q-mb-md">{{ $t("width") }}:</span>
</q-item-section>
<q-item-section>
<q-input
type="number"
min="1"
v-model="window_rect.width"
:rules="[
(val) =>
(val != null &&
val != undefined &&
val.toString().length > 0) ||
$t('Please type something'),
(val) =>
parseInt(val) >= 1 ||
$t('the number must be greater than 1'),
]"
lazy-rules
>
<template v-slot:append>
<span class="input_append">{{ $t("px") }}</span>
</template>
</q-input>
</q-item-section>
</q-item>
</q-item-section>
<q-item-section>
<q-item>
<q-item-section avatar>
<span class="q-mb-md">{{ $t("height") }}:</span>
</q-item-section>
<q-item-section>
<q-input
type="number"
min="1"
v-model="window_rect.height"
:rules="[
(val) =>
(val != null &&
val != undefined &&
val.toString().length > 0) ||
$t('Please type something'),
(val) =>
parseInt(val) >= 1 ||
$t('the number must be greater than 1'),
]"
lazy-rules
>
<template v-slot:append>
<span class="input_append">{{ $t("px") }}</span>
</template>
</q-input>
</q-item-section>
</q-item>
</q-item-section>
</q-item>
</q-list>
</q-card-section>
<q-separator />
<q-card-actions align="right">
<q-btn
:loading="loading"
flat
:label="$t('Cancel')"
color="primary"
v-close-popup
/>
<q-btn
ref="accept"
flat
:label="$t('Accept')"
:loading="loading"
type="submit"
color="primary"
/>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
</template>
<style scoped>
.input_append {
font-size: 1rem;
}
</style>
<script lang="ts">
import { defineComponent, ref, watch, computed, reactive } from "vue";
import { useStore } from "src/store";
import { useQuasar } from "quasar";
import { useI18n } from "vue-i18n";
import GlobalData from "src/common/GlobalData";
export default defineComponent({
name: "ComponentWindowRectEditDialog",
setup() {
let $store = useStore();
let $q = useQuasar();
let $t = useI18n();
let show_dialog = ref(false);
let loading = ref(false);
const window_rect = reactive({
x: 0,
y: 0,
width: 0,
height: 0,
clean: function () {
this.x = 0;
this.y = 0;
this.width = 0;
this.height = 0;
},
formartNumber: function () {
this.x = parseInt(<any>this.x);
this.y = parseInt(<any>this.y);
this.width = parseInt(<any>this.width);
this.height = parseInt(<any>this.height);
},
});
let _resolve: any = null;
let _reject: any = null;
const clean_promise = () => {
try {
if (_resolve && typeof _resolve == "function") {
_resolve(null);
} else if (_reject && typeof _reject == "function") {
_reject(null);
}
_resolve = null;
_reject = null;
} catch {}
};
return {
show_dialog,
loading,
window_rect,
showDialog() {
throw "please use showDialogAsync function";
},
showDialogAsync(x: number, y: number, width: number, height: number) {
return new Promise((resolve, reject) => {
clean_promise();
window_rect.clean();
window_rect.x = Math.round(x);
window_rect.y = Math.round(y);
window_rect.width = Math.round(width);
window_rect.height = Math.round(height);
_resolve = resolve;
_reject = reject;
show_dialog.value = true;
});
},
resetData() {
show_dialog.value = false;
loading.value = false;
if (_reject) {
try {
_reject(null);
} catch {}
}
_resolve = null;
_reject = null;
},
onSubmit() {
loading.value = true;
window_rect.formartNumber();
const resolve_data = () => {
if (_resolve) {
try {
_resolve(window_rect);
} catch {}
}
_resolve = null;
_reject = null;
loading.value = false;
show_dialog.value = false;
};
if (
window_rect.x + window_rect.width >
$store.state.device_screen_width ||
window_rect.y + window_rect.height > $store.state.device_screen_height
) {
$q.dialog({
title: $t.t("Warning"),
message:
$t.t(
"set the window rectangle beyond the desktop rectangle, the window rectangle will be clipped, are you sure to use this window rectangle"
) + "?",
cancel: true,
persistent: true,
})
.onOk(() => resolve_data())
.onCancel(() => (loading.value = false));
} else {
resolve_data();
}
},
};
},
});
</script>

View File

@ -480,4 +480,16 @@ export default {
"plan running! can't open window!": "预案正在运行!不能开窗!",
"full screen window": "全屏",
"restore window size": "恢复",
"window rect": "窗口矩形",
"the number must be greater than 0": "数字必须大于0",
"the number must be greater than 1": "数字必须大于1",
X: "X坐标",
Y: "Y坐标",
"edit window rect": "修改窗口矩形",
"set the window rectangle beyond the desktop rectangle, the window rectangle will be clipped, are you sure to use this window rectangle":
"设置的窗口矩形超出桌面矩形,窗口矩形将会被裁剪,确定使用这个窗口矩形吗",
"desktop width": "桌面宽度",
"desktop height": "桌面高度",
px: "像素",
Warning: "警告",
};

View File

@ -52,6 +52,7 @@
@mute_unmute="mute_unmute"
@start_polling="start_polling"
@stop_polling="stop_polling"
@edit_rect="editRect"
:ref="'window_' + item.window_id"
:id="'window_' + item.window_id"
:uuid="item.uuid"
@ -74,7 +75,7 @@
:key="row"
class="row"
:style="{
height: cell_height + 'px',
height: wall_height.value / $store.state.wall_row + 'px',
}"
>
<div
@ -83,9 +84,11 @@
:key="col"
class="col wall_item wall_item_flag"
:style="{
width: cell_width + 'px',
height: cell_height + 'px',
width: wall_width / $store.state.wall_col + 'px',
height: wall_height / $store.state.wall_row + 'px',
}"
:a_row="row"
:a_col="col"
>
<q-popup-proxy context-menu @show="onContextMenuShow($event)">
<q-list>
@ -121,6 +124,7 @@
</div>
</div>
<file-manage-dialog ref="file_manage_dialog" />
<window-rect-edit-dialog ref="window_rect_edit_dialog" />
</template>
<style scoped>
@ -152,13 +156,14 @@ import {
nextTick,
onUpdated,
} from "vue";
import { useQuasar } from "quasar";
import { useQuasar, dom as DomUtil } from "quasar";
import { useI18n } from "vue-i18n";
import { useStore } from "src/store";
const elementResizeDetectorMaker = require("element-resize-detector");
import vue3ResizeDrag from "../third_lib/vue3-resize-drag/components/vue3-resize-drag/index.vue";
import Window from "src/components/Window.vue";
import WindowRectEditDialog from "src/components/WindowRectEditDialog.vue";
import GlobalData from "src/common/GlobalData";
import FileEntity from "src/entities/FileEntity";
import { SignalSourceEntity } from "src/entities/SignalSourceEntity";
@ -185,7 +190,12 @@ class Rect {
export default defineComponent({
name: "PadContentWallPage",
components: { FileManageDialog, Window, vue3ResizeDrag },
components: {
FileManageDialog,
Window,
vue3ResizeDrag,
WindowRectEditDialog,
},
setup() {
const $store = useStore();
const $q = useQuasar();
@ -197,6 +207,7 @@ export default defineComponent({
const wall: Ref<any> = ref(null);
const wall_content: Ref<any> = ref(null);
const dom_windows: Ref<any> = ref(null);
const window_rect_edit_dialog: Ref<any> = ref(null);
const wall_content_client_width = ref(0);
const wall_content_client_height = ref(0);
@ -215,8 +226,6 @@ export default defineComponent({
get: () => $store.state.wall_col,
set: (val) => $store.commit("setWallCol", val),
});
const cell_width = ref(0);
const cell_height = ref(0);
const refresh_window_pos = () => {
setTimeout(() => {
@ -497,11 +506,8 @@ export default defineComponent({
width = 1;
}
wall_height.value = height;
wall_width.value = width;
cell_height.value = wall_height.value / $store.state.wall_row;
cell_width.value = wall_width.value / $store.state.wall_col;
wall_height.value = parseInt(height.toFixed(0));
wall_width.value = parseInt(width.toFixed(0));
}
}
);
@ -515,8 +521,8 @@ export default defineComponent({
wall_content.value,
(element: HTMLElement) => {
if (element) {
wall_content_client_height.value = element.clientHeight;
wall_content_client_width.value = element.clientWidth;
wall_content_client_height.value = DomUtil.height(element);
wall_content_client_width.value = DomUtil.width(element);
}
}
);
@ -622,7 +628,7 @@ export default defineComponent({
const onDropSignalSourceOrPolliong = (evt: _IDropToWall) => {
if (!plan_running.value) {
if (evt && evt.data) {
let dom = document.elementFromPoint(
let dom_element = document.elementFromPoint(
evt.pos.x,
evt.pos.y
) as HTMLElement;
@ -632,26 +638,40 @@ export default defineComponent({
);
//
if (dom) {
const temp = find_parent_dom(dom, [
if (dom_element) {
const temp = find_parent_dom(dom_element, [
"wall_item_flag",
"window_flag",
]);
if (temp) {
dom = temp;
dom_element = temp;
}
}
if (dom) {
if (dom.classList.contains("wall_item_flag")) {
if (dom_element) {
if (dom_element.classList.contains("wall_item_flag")) {
//
// 1
const wall_width = wall_content_client_width.value;
const wall_height = wall_content_client_height.value;
const x = dom.offsetLeft / wall_width;
const y = dom.offsetTop / wall_height;
const width = dom.offsetWidth / wall_width;
const height = dom.offsetHeight / wall_height;
const cell_width = 1 / $store.state.wall_col;
const cell_height = 1 / $store.state.wall_row;
let col = 0;
let row = 0;
try {
col = parseInt(dom_element.getAttribute("a_col") ?? "1") - 1;
row = parseInt(dom_element.getAttribute("a_row") ?? "1") - 1;
if (isNaN(row)) {
row = 0;
}
if (isNaN(col)) {
col = 0;
}
} catch {}
const x = col * cell_width;
const y = row * cell_height;
const width = cell_width;
const height = cell_height;
switch (evt.type) {
case "polling":
@ -686,9 +706,9 @@ export default defineComponent({
}
break;
}
} else if (dom.classList.contains("window_flag")) {
} else if (dom_element.classList.contains("window_flag")) {
//
const rep_uuid = dom.getAttribute("uuid");
const rep_uuid = dom_element.getAttribute("uuid");
if (rep_uuid) {
let window = $store.state.windows.find(
(item) => item.uuid == rep_uuid
@ -837,13 +857,12 @@ export default defineComponent({
return {
wall,
window_rect_edit_dialog,
file_manage_dialog,
wall_width,
wall_height,
wall_rows,
wall_cols,
cell_width,
cell_height,
plan_running,
area_open_window_flag,
area_open_window_rect,
@ -891,6 +910,34 @@ export default defineComponent({
GlobalData.getInstance().getCurrentClient()?.stopPolling(window_id);
}
},
async editRect(window_id: number) {
if (window_rect_edit_dialog.value) {
try {
const window = $store.state.windows.find(
(element) => element && element.window_id == window_id
);
if (window) {
const result =
await window_rect_edit_dialog.value.showDialogAsync(
window.x * $store.state.device_screen_width,
window.y * $store.state.device_screen_height,
window.width * $store.state.device_screen_width,
window.height * $store.state.device_screen_height
);
if (result) {
let { x, y, width, height } = result;
x /= $store.state.device_screen_width;
y /= $store.state.device_screen_height;
width /= $store.state.device_screen_width;
height /= $store.state.device_screen_height;
GlobalData.getInstance()
.getCurrentClient()
?.setWindowGeometry(window_id, x, y, width, height);
}
}
} catch {}
}
},
topWindow(window_id: number) {
GlobalData.getInstance().getCurrentClient()?.focusIn(window_id);
},

View File

@ -47,6 +47,7 @@
@start_polling="start_polling"
@stop_polling="stop_polling"
@polling_setting="polling_setting"
@edit_rect="editRect"
:ref="'window_' + item.window_id"
:id="'window_' + item.window_id"
:uuid="item.uuid"
@ -79,6 +80,8 @@
width: item_witdh + 'px',
height: item_height + 'px',
}"
:a_row="row"
:a_col="col"
>
<q-popup-proxy
context-menu
@ -140,6 +143,7 @@
<edit-volume-dialog ref="edit_volume_dialog" />
<polling-setting-dialog ref="polling_setting_dialog" />
<file-manage-dialog ref="file_manage_dialog" />
<window-rect-edit-dialog ref="window_rect_edit_dialog" />
</template>
<style scoped>
@ -170,6 +174,7 @@ import { defineComponent, ref, Ref, computed, onMounted } from "vue";
const elementResizeDetectorMaker = require("element-resize-detector");
import { Protocol } from "src/entities/WSProtocol";
import Window from "src/components/Window.vue";
import WindowRectEditDialog from "src/components/WindowRectEditDialog.vue";
import { useI18n } from "vue-i18n";
import { useStore } from "src/store";
@ -211,6 +216,7 @@ export default defineComponent({
EditVolumeDialog,
PollingSettingDialog,
FileManageDialog,
WindowRectEditDialog,
},
setup() {
const $q = useQuasar();
@ -220,6 +226,7 @@ export default defineComponent({
const edit_volume_dialog: Ref<any> = ref(null);
const polling_setting_dialog: Ref<any> = ref(null);
const file_manage_dialog: Ref<any> = ref(null);
const window_rect_edit_dialog: Ref<any> = ref(null);
const last_context_menu_pos_x = ref(0);
const last_context_menu_pos_y = ref(0);
@ -654,15 +661,7 @@ export default defineComponent({
rect.height = rect.height ?? 0;
rect.left = rect.left ?? 0;
rect.top = rect.top ?? 0;
// moveWindow(window_id, evt);
if (wall.value) {
// GlobalData.getInstance()
// .getCurrentClient()
// ?.resizeWindow(
// window_id,
// evt.width / wall.value.clientWidth,
// evt.height / wall.value.clientHeight
// );
const x =
rect.left -
(wall.value.parentElement?.offsetLeft ?? 0) -
@ -686,6 +685,7 @@ export default defineComponent({
return {
windows,
wall,
window_rect_edit_dialog,
wall_rows,
wall_cols,
item_witdh,
@ -726,14 +726,31 @@ export default defineComponent({
);
{
const dom: HTMLElement | null = e.target as HTMLElement;
if (wall.value && dom) {
if (dom.classList.contains("wall_item_flag")) {
const dom_element: HTMLElement | null = e.target as HTMLElement;
if (wall.value && dom_element) {
if (dom_element.classList.contains("wall_item_flag")) {
//
const x = dom.offsetLeft / wall.value.clientWidth;
const y = dom.offsetTop / wall.value.clientHeight;
const width = dom.offsetWidth / wall.value.clientWidth;
const height = dom.offsetHeight / wall.value.clientHeight;
const cell_width = 1 / $store.state.wall_col;
const cell_height = 1 / $store.state.wall_row;
let col = 0;
let row = 0;
try {
col = parseInt(dom_element.getAttribute("a_col") ?? "1") - 1;
row = parseInt(dom_element.getAttribute("a_row") ?? "1") - 1;
if (isNaN(row)) {
row = 0;
}
if (isNaN(col)) {
col = 0;
}
} catch {}
const x = col * cell_width;
const y = row * cell_height;
const width = cell_width;
const height = cell_height;
switch (type) {
case "polling":
@ -768,9 +785,9 @@ export default defineComponent({
}
break;
}
} else if (dom.classList.contains("window_flag")) {
} else if (dom_element.classList.contains("window_flag")) {
//
const rep_uuid = dom.getAttribute("uuid");
const rep_uuid = dom_element.getAttribute("uuid");
if (rep_uuid) {
let window = $store.state.windows.find(
(item) => item.uuid == rep_uuid
@ -892,13 +909,6 @@ export default defineComponent({
moveWindow,
resizeWindow,
closeAllWindows() {
// for (const window of $store.state.windows) {
// if (window) {
// GlobalData.getInstance()
// .getCurrentClient()
// ?.closeWindow(window.window_id);
// }
// }
GlobalData.getInstance().getCurrentClient()?.closeWindow(-1);
},
topWindow(window_id: number) {
@ -963,6 +973,35 @@ export default defineComponent({
GlobalData.getInstance().getCurrentClient()?.stopPolling(window_id);
}
},
async editRect(window_id: number) {
if (window_rect_edit_dialog.value) {
try {
const window = $store.state.windows.find(
(element) => element && element.window_id == window_id
);
if (window) {
const result =
await window_rect_edit_dialog.value.showDialogAsync(
window.x * $store.state.device_screen_width,
window.y * $store.state.device_screen_height,
window.width * $store.state.device_screen_width,
window.height * $store.state.device_screen_height
);
if (result) {
let { x, y, width, height } = result;
x /= $store.state.device_screen_width;
y /= $store.state.device_screen_height;
width /= $store.state.device_screen_width;
height /= $store.state.device_screen_height;
GlobalData.getInstance()
.getCurrentClient()
?.setWindowGeometry(window_id, x, y, width, height);
}
}
} catch {}
}
},
async polling_setting(window_id: number) {
const window = windows.value.find(
(element) => element && element.window_id == window_id