Zone editor mostly finished

This commit is contained in:
Tamius Han 2024-12-27 04:41:35 +01:00
parent 5d7d249fff
commit 6d8d8493a6
2 changed files with 366 additions and 159 deletions

View File

@ -2,17 +2,16 @@
<div class="flex flex-col" style="position: relative; width: 100%;"> <div class="flex flex-col" style="position: relative; width: 100%;">
<!-- The rest of the tab is under 'edit ratios and shortcuts' row --> <!-- The rest of the tab is under 'edit ratios and shortcuts' row -->
<div class="flex flex-col" style="width: 100%"> <div class="flex flex-col" style="width: 100%">
<h2>Player UI options</h2> <h2>Player UI options</h2>
<div class="flex flex-col compact-form">
<div class="field"> <div class="field">
<div class="label">Enable in-player UI</div> <div class="label">Enable in-player UI</div>
<input type="checkbox" v-model="settings.active.ui.inPlayer.enabled" /> <input type="checkbox" v-model="settings.active.ui.inPlayer.enabled" />
</div> </div>
<div <div
class="flex flex-col" class="flex flex-col field-group compact-form"
:class="{disabled: settings.active.ui.inPlayer.enabled}" :class="{disabled: !settings.active.ui.inPlayer.enabled}"
> >
<div class="field"> <div class="field">
<div class="label">Enable only in full screen</div> <div class="label">Enable only in full screen</div>
@ -53,92 +52,11 @@
</div> </div>
</div> </div>
<div class="field"> <div class="field" :class="{disabled: settings.active.ui.inPlayer.activation !== 'trigger-zone'}">
<div class="label">Edit trigger zone:</div> <div class="label">Edit trigger zone:</div>
<button @click="startTriggerZoneEdit()">Edit</button> <button @click="startTriggerZoneEdit()">Edit</button>
</div> </div>
<div v-if="settings.active.ui.inPlayer.activation === 'trigger-zone'">
<div class="trigger-zone-editor">
<div class="heading">
<h3>Trigger zone editor</h3>
</div>
<div class="field">
<div class="label">Trigger zone width:</div>
<div class="input range-input">
<input
v-model="settings.active.ui.inPlayer.triggerZoneDimensions.width"
class="slider"
type="range"
min="0.1"
max="1"
step="0.01"
>
<input
:value="(settings.active.ui.inPlayer.triggerZoneDimensions.width * 100).toFixed(2)"
@input="(event) => setTriggerZoneSize('width', event.target.value)"
>
</div>
<div class="hint">
Width of the trigger zone (% of player area).
</div>
</div>
<div class="field">
<div class="label">Trigger zone height:</div>
<div class="input range-input">
<input
v-model="settings.active.ui.inPlayer.triggerZoneDimensions.height"
type="range"
min="0.1"
max="1"
step="0.01"
>
<input
:value="(settings.active.ui.inPlayer.triggerZoneDimensions.height * 100).toFixed(2)"
@input="(event) => setTriggerZoneSize('width', event.target.value)"
>
</div>
<div class="hint">
Height of the trigger zone (% of player area).
</div>
</div>
<div class="field">
<div class="label">Trigger zone horizontal offset:</div>
<div class="input range-input">
<input
v-model="settings.active.ui.inPlayer.triggerZoneDimensions.offsetX"
type="range"
min="-100"
max="100"
>
<input
v-model="settings.active.ui.inPlayer.triggerZoneDimensions.offsetX"
>
</div>
<div class="hint">
By default, trigger zone is centered around the button. This option moves trigger zone left and right.
</div>
</div>
<div class="field">
<div class="label">Trigger zone vertical offset:</div>
<div class="input range-input">
<input
v-model="settings.active.ui.inPlayer.triggerZoneDimensions.offsetY"
type="range"
min="-100"
max="100"
>
<input
v-model="settings.active.ui.inPlayer.triggerZoneDimensions.offsetY"
>
</div>
<div class="hint">
By default, trigger zone is centered around the button. This option moves trigger zone up and down.
</div>
</div>
</div>
</div>
<div class="field"> <div class="field">
<div class="label"> <div class="label">
Do not show in-player UI when video player is narrower than (% of screen width) Do not show in-player UI when video player is narrower than (% of screen width)
@ -146,6 +64,39 @@
<div>TODO: slider</div> <div>TODO: slider</div>
</div> </div>
</div> </div>
</div>
<h2>Menu options and keyboard shortcuts</h2>
<div class="flex flex-row">
<!-- CROP OPTIONS -->
<div>
<div class="flex flex-row">
<mdicon name="crop" :size="32" />
<h3>Crop video:</h3>
</div>
<CropOptionsPanel
:settings="settings"
:eventBus="eventBus"
:isEditing="true"
>
</CropOptionsPanel>
</div>
<!-- STRETCH OPTIONS -->
<div>
<div class="flex flex-row">
<mdicon name="stretch-to-page-outline" :size="32" />
<h3>Stretch video:</h3>
</div>
<StretchOptionsPanel
:settings="settings"
:eventBus="eventBus"
:isEditing="true"
></StretchOptionsPanel>
</div>
</div>
</div> </div>
</div> </div>
@ -154,8 +105,15 @@
<script> <script>
import Button from '../components/Button.vue' import Button from '../components/Button.vue'
import BrowserDetect from '../../../ext/conf/BrowserDetect'; import BrowserDetect from '../../../ext/conf/BrowserDetect';
import CropOptionsPanel from './PanelComponents/VideoSettings/CropOptionsPanel.vue'
import StretchOptionsPanel from './PanelComponents/VideoSettings/StretchOptionsPanel.vue'
export default { export default {
components: {
Button,
CropOptionsPanel,
StretchOptionsPanel
},
data() { data() {
return { return {
@ -171,30 +129,11 @@ export default {
}, },
mounted() { mounted() {
}, },
components: {
Button,
},
methods: { methods: {
setUiPage(key, event) { setUiPage(key, event) {
}, },
forceNumber(value) {
// Change EU format to US if needed
// | remove everything after second period if necessary
// | | | remove non-numeric characters
// | | | |
return value.replaceAll(',', '.').split('.', 2).join('.').replace(/[^0-9.]/g, '');
},
setTriggerZoneSize(key, value) {
let size = (+this.forceNumber(value) / 100);
if (isNaN(+size)) {
size = 0.5;
}
this.settings.active.ui.inPlayer.triggerZoneDimensions[key] = size;
this.settings.saveWithoutReload();
},
startTriggerZoneEdit() { startTriggerZoneEdit() {
this.eventBus.send('start-trigger-zone-edit'); this.eventBus.send('start-trigger-zone-edit');
}, },
@ -250,6 +189,21 @@ export default {
.field { .field {
margin-bottom: -1em; margin-bottom: -1em;
} }
} }
.disabled {
pointer-events: none;
/* color: #666; */
filter: contrast(50%) brightness(40%) grayscale(100%);
}
.compact-form {
> .field, > .field-group {
margin-top: 0;
margin-bottom: 0;
}
}
</style> </style>

View File

@ -1,4 +1,6 @@
<template> <template>
<!-- Preview + editor -->
<div <div
v-if="settings?.active?.ui" v-if="settings?.active?.ui"
class="active-trigger-area uw-clickable" class="active-trigger-area uw-clickable"
@ -29,12 +31,126 @@
</div> </div>
</div> </div>
</div> </div>
<!-- Sliders -->
<div
class="trigger-zone-editor-sliders-container"
>
<div class="panel uw-clickable">
<div class="trigger-zone-editor-window">
<div class="heading">
<h2>Trigger zone editor</h2>
</div>
<div>
<p>
Trigger zone is represented by this very obvious gold grid. Ultrawidify menu button will only show when mouse enters the area marked by the grid.
</p>
<p>
Note that interacting with the grid area is slightly broken. The distance dragged doesn't correspond with the amount of resizing. I don't plan on
fixing that because the amount of effort required to get it working perfectly doesn't correspond with the amount of utility this part of the UI will
see. Like, it works well enough and I want to enjoy some of my end-of-year PTO.
</p>
<p>
Sliders work as they should.
</p>
</div>
<div class="field">
<div class="label">Trigger zone width:</div>
<div class="input range-input">
<input
:value="settings.active.ui.inPlayer.triggerZoneDimensions.width"
class="slider"
type="range"
min="0.1"
max="1"
step="0.01"
@input="(event) => setTriggerZoneOffset('width', event.target.value, true)"
>
<input
:value="triggerZoneWidth"
@input="(event) => setTriggerZoneSize('width', event.target.value)"
@change="(event) => updateSettings()"
>
</div>
<div class="hint">
Width of the trigger zone (% of player area).
</div>
</div>
<div class="field">
<div class="label">Trigger zone height:</div>
<div class="input range-input">
<input
:value="settings.active.ui.inPlayer.triggerZoneDimensions.height"
type="range"
min="0.1"
max="1"
step="0.01"
@input="(event) => setTriggerZoneOffset('height', event.target.value, true)"
>
<input
:value="triggerZoneHeight"
@input="(event) => setTriggerZoneSize('height', event.target.value)"
@change="(event) => updateSettings()"
>
</div>
<div class="hint">
Height of the trigger zone (% of player area).
</div>
</div>
<div class="field">
<div class="label">Trigger zone horizontal offset:</div>
<div class="input range-input">
<input
v-model="settings.active.ui.inPlayer.triggerZoneDimensions.offsetX"
type="range"
min="-100"
max="100"
@input="(event) => setTriggerZoneOffset('offsetX', event.target.value, true)"
>
<input
:value="settings.active.ui.inPlayer.triggerZoneDimensions.offsetX"
@input="(event) => setTriggerZoneOffset('offsetX', event.target.value)"
@change="(event) => updateSettings()"
>
</div>
<div class="hint">
By default, trigger zone is centered around the button. This option moves trigger zone left and right.
</div>
</div>
<div class="field">
<div class="label">Trigger zone vertical offset:</div>
<div class="input range-input">
<input
v-model="settings.active.ui.inPlayer.triggerZoneDimensions.offsetY"
type="range"
min="-100"
max="100"
@input="(event) => setTriggerZoneOffset('offsetY', event.target.value, true)"
>
<input
:value="settings.active.ui.inPlayer.triggerZoneDimensions.offsetY"
@input="(event) => setTriggerZoneOffset('offsetY', event.target.value)"
@change="(event) => updateSettings()"
>
</div>
<div class="hint">
By default, trigger zone is centered around the button. This option moves trigger zone up and down.
</div>
</div>
<div class="action-row">
<button @click="finishTriggerZoneEdit">Finish editing</button>
</div>
</div>
</div>
</div>
</template> </template>
<script> <script>
export default { export default {
props: [ props: [
'settings', 'settings',
'eventBus',
'playerDimensions', 'playerDimensions',
], ],
watch: { watch: {
@ -53,10 +169,26 @@ export default {
created() { created() {
document.addEventListener("mouseup", this.handleMouseUp); document.addEventListener("mouseup", this.handleMouseUp);
document.addEventListener("mousemove", this.handleMouseMove); document.addEventListener("mousemove", this.handleMouseMove);
this.updateTriggerZones(); this.updateTriggerZones(false);
},
computed: {
triggerZoneWidth() {
const v = this.settings.active.ui.inPlayer.triggerZoneDimensions.width * 100;
return this.optionalToFixed(v, 2);
},
triggerZoneHeight() {
const v = this.settings.active.ui.inPlayer.triggerZoneDimensions.height * 100;
return this.optionalToFixed(v, 2);
}
}, },
methods: { methods: {
updateTriggerZones() { optionalToFixed(v, n) {
if ((`${v}`.split('.')[1]?.length ?? 0) > n) {
return v.toFixed(2);
}
return v;
},
updateTriggerZones(forceRefresh = true) {
if (this.playerDimensions && this.settings?.active?.ui?.inPlayer?.triggerZoneDimensions) { if (this.playerDimensions && this.settings?.active?.ui?.inPlayer?.triggerZoneDimensions) {
this.triggerZoneStyles = { this.triggerZoneStyles = {
width: `${Math.round(this.playerDimensions.width * this.settings.active.ui.inPlayer.triggerZoneDimensions.width)}px`, width: `${Math.round(this.playerDimensions.width * this.settings.active.ui.inPlayer.triggerZoneDimensions.width)}px`,
@ -64,6 +196,9 @@ export default {
transform: `translate(${(this.settings.active.ui.inPlayer.triggerZoneDimensions.offsetX)}%, ${this.settings.active.ui.inPlayer.triggerZoneDimensions.offsetY}%)`, transform: `translate(${(this.settings.active.ui.inPlayer.triggerZoneDimensions.offsetX)}%, ${this.settings.active.ui.inPlayer.triggerZoneDimensions.offsetY}%)`,
}; };
} }
// if (forceRefresh) {
// this.$forceUpdate();
// }
}, },
handleMouseDown(corner, event) { handleMouseDown(corner, event) {
this.activeCornerDrag = corner; this.activeCornerDrag = corner;
@ -130,8 +265,8 @@ export default {
} }
// ensure everything is properly limited // ensure everything is properly limited
const cw = Math.min(0.95, Math.max(0.125, nw)); const cw = Math.min(1, Math.max(0.125, nw));
const ch = Math.min(0.95, Math.max(0.125, nh)); const ch = Math.min(1, Math.max(0.125, nh));
// // update properties // // update properties
this.settings.active.ui.inPlayer.triggerZoneDimensions.width = cw; this.settings.active.ui.inPlayer.triggerZoneDimensions.width = cw;
@ -157,11 +292,58 @@ export default {
this.settings.active.ui.inPlayer.triggerZoneDimensions.offsetX = cx; this.settings.active.ui.inPlayer.triggerZoneDimensions.offsetX = cx;
this.settings.active.ui.inPlayer.triggerZoneDimensions.offsetY = cy; this.settings.active.ui.inPlayer.triggerZoneDimensions.offsetY = cy;
},
//#region slider window
forceNumber(value) {
// Change EU format to US if needed
// | remove everything after second period if necessary
// | | | remove non-numeric characters
// | | | |
return value.replaceAll(',', '.').split('.', 2).join('.').replace(/[^0-9.\-]/g, '');
},
setTriggerZoneSize(key, value, instantUpdate) {
console.log('setting trigger zone size:', key, value);
let size = (+this.forceNumber(value) / 100);
if (isNaN(+size)) {
size = 0.5;
} }
this.settings.active.ui.inPlayer.triggerZoneDimensions[key] = size;
if (instantUpdate) {
this.updateSettings();
}
},
setTriggerZoneOffset(key, value, instantUpdate) {
let offset = +this.forceNumber(value);
this.settings.active.ui.inPlayer.triggerZoneDimensions[key] = offset;
if (instantUpdate) {
this.updateSettings();
}
},
updateSettings() {
this.settings.saveWithoutReload();
this.updateTriggerZones();
},
//#endregion
finishTriggerZoneEdit() {
this.eventBus.send('finish-trigger-zone-edit');
},
} }
} }
</script> </script>
<style lang="scss" src="../res-common/panels.scss" scoped module></style>
<style lang="scss" src="../res-common/common.scss" scoped module></style>
<style lang="scss" scoped> <style lang="scss" scoped>
.active-trigger-area { .active-trigger-area {
background-image: url('/res/img/grid_512.webp'); background-image: url('/res/img/grid_512.webp');
@ -206,4 +388,75 @@ export default {
} }
} }
.trigger-zone-editor-window {
max-width: 69rem;
}
.trigger-zone-editor-sliders-container {
position: fixed;
width: 100dvw;
height: 100dvh;
top: 0;
left: 0;
z-index: 2000;
pointer-events: none;
display: flex;
align-items: center;
justify-content: center;
.panel {
backdrop-filter: blur(0.5rem) brightness(0.5);
color: #ccc;
pointer-events: all;
padding: 1rem;
}
.range-input {
display: flex;
flex-direction: row;
* {
margin-left: 0.5rem;
margin-right: 0.5rem;
}
input {
max-width: 5rem;
}
input[type=range] {
max-width: none;
}
}
.trigger-zone-editor {
padding-bottom: 2rem;
.field {
margin-bottom: -1em;
}
}
}
.range-input {
display: flex;
flex-direction: row;
* {
margin-left: 0.5rem;
margin-right: 0.5rem;
}
input {
max-width: 5rem;
}
input[type=range] {
max-width: none;
}
}
</style> </style>