Finalize menu position settings, replace eventBus.sendToTunnel() with eventBus.send()

This commit is contained in:
Tamius Han 2026-01-15 02:33:21 +01:00
parent 925a9fdea3
commit 35bb5b477b
12 changed files with 188 additions and 74 deletions

View File

@ -23,6 +23,6 @@ export enum MenuPosition {
export interface MenuConfig {
isGlobal?: boolean;
ui: InPlayerUIOptions;
menuPosition: MenuPosition;
options?: {forceShow?: boolean};
items: MenuItemConfig[];
}

View File

@ -9,6 +9,7 @@ import StretchType from '@src/common/enums/StretchType.enum'
import VideoAlignmentType from '@src/common/enums/VideoAlignmentType.enum'
import { PlayerDetectionMode } from '@src/common/enums/PlayerDetectionMode.enum';
import { InputHandlingMode } from '@src/common/enums/InputHandlingMode.enum';
import { MenuPosition } from '@src/common/interfaces/ClientUiMenu.interface';
export enum ExtensionEnvironment {
Normal = ExtensionMode.All,
@ -309,14 +310,14 @@ interface DevSettings {
}
export interface InPlayerUIOptions {
activatorAlignment: 'left' | 'right',
activatorAlignment: MenuPosition,
minEnabledWidth: number, // don't show UI if player is narrower than % of screen width
minEnabledHeight: number, // don't show UI if player is narrower than % of screen height
activation: 'player' | 'player-ctrl' | 'trigger-zone' | 'distance' | 'none', // what needs to be hovered in order for UI to be visible
activationDistance: number,
activationDistanceUnits: '%' | 'px',
activatorPadding: 10,
activatorPaddingUnit: '%' | 'px',
activatorPadding: {x: number, y: number}
activatorPaddingUnit: {x: '%' | 'px', y: '%' | 'px'},
triggerZoneDimensions: { // how large the trigger zone is (relative to player size)
width: number
height: number,

View File

@ -267,8 +267,8 @@ const ExtensionConf: SettingsInterface = {
activationDistance: 100,
activationDistanceUnits: '%',
activatorAlignment: 'left',
activatorPadding: 10,
activatorPaddingUnit: '%',
activatorPadding: {x: 16, y: 16},
activatorPaddingUnit: {x: 'px', y: 'px'},
triggerZoneDimensions: {
width: 0.5,
height: 0.5,

View File

@ -19,6 +19,7 @@ export class ClientMenu {
private isHovered = false;
private forceShow = false;
private isWithinActivation = false;
private lastMouseMove = performance.now();
private idleTimer?: number;
@ -29,7 +30,11 @@ export class ClientMenu {
private onDocumentMouseLeave?: () => void;
private idleIntervalId?: number;
constructor(private config: MenuConfig) {}
constructor(private config: MenuConfig) {
if (config.options?.forceShow !== undefined) {
this.forceShow = config.options.forceShow;
}
}
mount(anchorElement: HTMLElement) {
this.buildMenuPositionClassList();
@ -173,7 +178,8 @@ export class ClientMenu {
*/
private buildMenuPositionClassList() {
let classList;
switch (this.config.menuPosition) {
console.log('BUILDING MENU POS:', MenuPosition[this.config.ui.activatorAlignment]);
switch (this.config.ui.activatorAlignment) {
case MenuPosition.TopLeft:
classList = ['uw-menu-left','uw-menu-top'];
break;
@ -209,10 +215,14 @@ export class ClientMenu {
private createMenu() {
this.root = document.createElement('div');
this.root.className = 'uw-menu-root uw-hidden';
this.root.setAttribute(
'style',
`padding: ${this.config.ui.activatorPadding.y ?? 16}${this.config.ui.activatorPaddingUnit.y ?? 'px'} ${this.config.ui.activatorPadding.x ?? 16}${this.config.ui.activatorPaddingUnit.x ?? 'px'}`
);
const trigger = document.createElement('div');
trigger.classList = 'uw-menu-trigger uw-trigger';
trigger.style = `margin: ${this.config.ui.activatorPadding ?? 10} ${this.config.ui.activatorPaddingUnit ?? '%'}`;
trigger.textContent = 'Ultrawidify';
this.trigger = trigger;
@ -364,7 +374,7 @@ export class ClientMenu {
}
}
private show() {
show(options?: {forceShow?: boolean}) {
this.lastMouseMove = performance.now();
if (!this.visible) {
@ -372,10 +382,18 @@ export class ClientMenu {
this.root.classList.add('uw-visible');
this.root.classList.remove('uw-hidden');
}
if (options?.forceShow !== undefined) {
this.forceShow = options.forceShow;
}
}
private hide() {
if (this.visible) {
hide(options?: {forceShow?: boolean}) {
if (options?.forceShow !== undefined) {
this.forceShow = options.forceShow;
}
if (this.visible && !this.forceShow) {
this.visible = false;
this.root.classList.remove('uw-visible');
this.root.classList.add('uw-hidden');

View File

@ -68,6 +68,24 @@ class UI {
// UI will be initialized when setUiVisibility is called
if (!this.isGlobal) {
this.init();
this.eventBus.subscribeMulti({
'reload-menu': {
function: () => {
this.createExtensionMenu({forceShow: true});
this.extensionMenu.show({forceShow: true});
}
},
'force-menu-activator-state': {
function: (commandData) => {
if (commandData.visibility) {
this.extensionMenu.show({forceShow: true});
} else {
this.extensionMenu.show({forceShow: false});
}
}
}
});
}
}
@ -164,7 +182,7 @@ class UI {
}
}
createExtensionMenu() {
createExtensionMenu(options?: {forceShow?: boolean}) {
if (+this.siteSettings?.data.enableUI === ExtensionMode.Disabled || this.isGlobal) {
return; // don't
}
@ -185,6 +203,7 @@ class UI {
const menuConfig = {
isGlobal: this.isGlobal,
ui: this.settings.active.ui.inPlayer,
options,
items: [
{
customClassList: 'uw-site-info',
@ -339,7 +358,7 @@ class UI {
action: () => this.createSettingsWindow('about'),
}
]
}
};
this.extensionMenu = new ClientMenu(menuConfig);
this.extensionMenu.mount(this.uiConfig.parentElement);
@ -347,10 +366,13 @@ class UI {
* SETUP MENU INTERACTIONS
*
* Interactions are needed for the following things:
* 0. [ ] both sliders. Needs to read the state of the sliders and update the labels
* 1. [ ] lock X/Y button needs to update icon state of the button and the linked bar
* 2. [ ] reset button just needs to reset, no icon changes necessary
* 0. [X] both sliders. Needs to read the state of the sliders and update the labels
* 1. [X] lock X/Y button needs to update icon state of the button and the linked bar
* 2. [X] reset button just needs to reset, no icon changes necessary
* 3. [X] alignment indicator also needs to update indicator state
* A
* |
* (yay done!)
*/
const menuElement = this.extensionMenu.root;

View File

@ -206,7 +206,7 @@
<div class="flex flex-row w-full gap-2">
<div class="grow flex flex-col gap-2">
<div>
<button v-if="eventBus" @click="eventBus?.sendToTunnel('aard-enable-debug', true)">Show debug overlay</button>
<button v-if="eventBus" @click="eventBus?.send('aard-enable-debug', true)">Show debug overlay</button>
</div>
<div class="field">
<div class="label">Show debug overlay on startup</div>
@ -277,7 +277,7 @@ export default defineComponent({
);
},
mounted() {
this.eventBus?.sendToTunnel('get-aard-timing');
this.eventBus?.send('get-aard-timing');
// this.graphRefreshInterval = setInterval(() => this.eventBus.sendToTunnel('get-aard-timing'), 500);
this.resetSettingsEditor();
},
@ -302,7 +302,7 @@ export default defineComponent({
this.settings.saveWithoutReload();
},
refreshGraph() {
this.eventBus.sendToTunnel('get-aard-timing');
this.eventBus.send('get-aard-timing');
},
handleConfigBroadcast(data) {
if (data.type === 'aard-performance-data') {

View File

@ -183,11 +183,7 @@ export default defineComponent({
this.tutorialStep = 0;
},
getPlayerTree() {
if (this.isPopup) {
this.eventBus.send('get-player-tree');
} else {
this.eventBus.sendToTunnel('get-player-tree');
}
},
handleElementStack(configBroadcast) {
if (configBroadcast.type === 'player-tree') {
@ -196,7 +192,7 @@ export default defineComponent({
}
},
markElement(parentIndex, enable) {
this.eventBus.sendToTunnel('set-mark-element', {parentIndex, enable});
this.eventBus.send('set-mark-element', {parentIndex, enable});
},
async setPlayer(index) {
// yup.

View File

@ -139,11 +139,7 @@ export default({
this.tutorialStep = 0;
},
getPlayerTree() {
if (this.isPopup) {
this.eventBus.send('get-player-tree');
} else {
this.eventBus.sendToTunnel('get-player-tree');
}
},
handleElementStack(configBroadcast) {
if (configBroadcast.type === 'player-tree') {
@ -152,7 +148,7 @@ export default({
}
},
markElement(parentIndex, enable) {
this.eventBus.sendToTunnel('set-mark-element', {parentIndex, enable});
this.eventBus.send('set-mark-element', {parentIndex, enable});
},
async setPlayer(index) {
// yup.

View File

@ -9,35 +9,6 @@
<div
class="flex flex-col field-group compact-form gap-2"
>
<div class="field">
<div class="label">
Popup activator position:
</div>
<div class="select">
<select
v-model="settings.active.ui.inPlayer.activatorAlignment"
@change="saveSettings()"
>
<option value="left">Left</option>
<option value="right">Right</option>
</select>
</div>
</div>
<div class="field">
<div class="label">
Popup activator padding:
</div>
<div class="select">
<select
v-model="settings.active.ui.inPlayer.activatorAlignment"
@change="saveSettings()"
>
<option value="left">Left</option>
<option value="right">Right</option>
</select>
</div>
</div>
<div class="field">
<div class="label">
@ -99,6 +70,92 @@
<button @click="startTriggerZoneEdit()">Edit</button>
</div>
<div class="field">
<div class="label">
Menu activator position:
</div>
<div class="select">
<select
v-model="settings.active.ui.inPlayer.activatorAlignment"
@change="saveSettings()"
>
<optgroup label="Edges">
<option :value="MenuPosition.Left">Left</option>
<option :value="MenuPosition.Right">Right</option>
<option :value="MenuPosition.Top">Top</option>
<option :value="MenuPosition.Bottom">Bottom</option>
</optgroup>
<optgroup label="corners">
<option :value="MenuPosition.TopLeft">Top left</option>
<option :value="MenuPosition.BottomLeft">Bottom left</option>
<option :value="MenuPosition.TopRight">Top right"</option>
<option :value="MenuPosition.BottomRight">Bottom right"</option>
</optgroup>
</select>
</div>
</div>
<div class="field">
<div class="label">
Menu activator horizontal padding:
</div>
<div class="input range-input">
<input
v-model="settings.active.ui.inPlayer.activatorPadding.x"
class="slider"
type="range"
min="0"
max="100"
step="1"
@change="(event) => saveSettings()"
>
<input
style="margin-right: 0.6rem;"
v-model="settings.active.ui.inPlayer.activatorPadding.x"
@change="(event) => saveSettings(true)"
>
<select
class="unit-select !min-w-[72px]"
v-model="settings.active.ui.inPlayer.activatorPaddingUnit.x"
@change="(event) => saveSettings(true)"
>
<option value="%">%</option>
<option value="px">px</option>
</select>
</div>
</div>
<div class="field">
<div class="label">
Menu activator vertical padding:
</div>
<div class="input range-input">
<input
v-model="settings.active.ui.inPlayer.activatorPadding.y"
class="slider"
type="range"
min="0"
max="100"
step="1"
@change="(event) => saveSettings()"
>
<input
style="margin-right: 0.6rem;"
v-model="settings.active.ui.inPlayer.activatorPadding.y"
@change="(event) => saveSettings(true)"
>
<select
class="unit-select !min-w-[72px]"
v-model="settings.active.ui.inPlayer.activatorPaddingUnit.y"
@change="(event) => saveSettings(true)"
>
<option value="%">%</option>
<option value="px">px</option>
</select>
</div>
</div>
<div class="field">
<div class="label">
Do not show in-player UI when video player is narrower than
@ -159,6 +216,7 @@
</template>
<script lang="ts">
import { MenuPosition } from '@src/common/interfaces/ClientUiMenu.interface';
import BrowserDetect from '@src/ext/conf/BrowserDetect';
import { defineComponent } from 'vue';
@ -167,6 +225,7 @@ export default defineComponent({
},
data() {
return {
MenuPosition,
ghettoComputed: { }
}
},
@ -181,7 +240,12 @@ export default defineComponent({
this.ghettoComputed = {
minEnabledWidth: this.optionalToFixed(this.settings.active.ui.inPlayer.minEnabledWidth * 100, 0),
minEnabledHeight: this.optionalToFixed(this.settings.active.ui.inPlayer.minEnabledHeight * 100, 0),
}
};
this.eventBus?.send('force-menu-activator-state', {visibility: true});
},
unmounted() {
this.eventBus?.send('force-menu-activator-state', {visibility: false});
},
methods: {
forcePositiveNumber(value) {
@ -213,11 +277,13 @@ export default defineComponent({
this.ghettoComputed[key] = this.optionalToFixed(value * 100, 0);
}
},
saveSettings(forceRefresh) {
this.settings.saveWithoutReload();
async saveSettings(forceRefresh) {
await this.settings.saveWithoutReload();
this.eventBus.send('reload-menu');
if (forceRefresh) {
this.$nextTick( () => this.$forceRefresh() );
this.$nextTick( () => this.$forceUpdate() );
}
},
startTriggerZoneEdit() {

View File

@ -173,7 +173,7 @@ export default defineComponent({
}
}
this.eventBus.sendToTunnel('get-ar');
this.eventBus.send('get-ar');
},
destroyed() {
this.eventBus.unsubscribeAll(this);
@ -201,7 +201,7 @@ export default defineComponent({
// this.eventBus.send('set-zoom', {zoom: 1, axis: 'y'});
// this.eventBus.send('set-zoom', {zoom: 1, axis: 'x'});
this.eventBus?.sendToTunnel('set-zoom', {zoom: 1});
this.eventBus?.send('set-zoom', {zoom: 1});
},
changeZoom(logZoom: number, axis: 'x' | 'y') {
// we do not use logarithmic zoom elsewhere, therefore we need to convert
@ -210,17 +210,17 @@ export default defineComponent({
if (this.zoomOptions.lockAr) {
this.zoom.x = logZoom;
this.zoom.y = logZoom;
this.eventBus?.sendToTunnel('set-zoom', {zoom: linearZoom});
this.eventBus?.send('set-zoom', {zoom: linearZoom});
} else {
this.zoom[axis] = logZoom;
this.eventBus?.sendToTunnel('set-zoom', {zoom: {[axis]: linearZoom}});
this.eventBus?.send('set-zoom', {zoom: {[axis]: linearZoom}});
}
},
isActiveZoom(command) {
return false;
},
align(alignmentX: VideoAlignmentType, alignmentY: VideoAlignmentType) {
this.eventBus?.sendToTunnel('set-alignment', {x: alignmentX, y: alignmentY})
this.eventBus?.send('set-alignment', {x: alignmentX, y: alignmentY})
}
}

View File

@ -106,13 +106,28 @@
}
&.uw-menu-center {
@apply left-1/2 -translate-x-1/2 flex-row;
@apply flex-row;
left: 50%;
transform: translateX(-50%);
&.uw-menu-top {
@apply bottom-0;
@apply top-full;
}
&.uw-menu-bottom {
@apply top-0;
@apply bottom-full;
}
.uw-menu-item {
@apply px-8 relative;
&:not(:first-child):after {
content: '·';
@apply absolute;
left: -1rem;
transform: translateX(50%);
}
}
}

View File

@ -15,7 +15,7 @@ export default {
*/
execAction(command) {
const cmd = JSON.parse(JSON.stringify(command));
this.eventBus?.sendToTunnel(cmd.action, cmd.arguments);
this.eventBus?.send(cmd.action, cmd.arguments);
},
}
}