Enable distance-based UI showing. Add "show while holding CTRL" option to the in-player UI
This commit is contained in:
parent
f25749470b
commit
f0baa6ad67
@ -1,3 +1,5 @@
|
||||
import { InPlayerUIOptions } from '@src/common/interfaces/SettingsInterface';
|
||||
|
||||
export interface MenuItemConfig {
|
||||
label: string;
|
||||
subitems?: MenuItemConfig[];
|
||||
@ -20,7 +22,7 @@ export enum MenuPosition {
|
||||
|
||||
export interface MenuConfig {
|
||||
isGlobal?: boolean;
|
||||
ui: InPlayerUIOptions;
|
||||
menuPosition: MenuPosition;
|
||||
activationRadius?: number;
|
||||
items: MenuItemConfig[];
|
||||
}
|
||||
|
||||
@ -308,6 +308,23 @@ interface DevSettings {
|
||||
loadFromSnapshot: boolean,
|
||||
}
|
||||
|
||||
export interface InPlayerUIOptions {
|
||||
activatorAlignment: 'left' | 'right',
|
||||
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',
|
||||
triggerZoneDimensions: { // how large the trigger zone is (relative to player size)
|
||||
width: number
|
||||
height: number,
|
||||
offsetX: number, // fed to translateX(offsetX + '%'). Valid range [-100, 0]
|
||||
offsetY: number // fed to translateY(offsetY + '%'). Valid range [-100, 100]
|
||||
},
|
||||
};
|
||||
|
||||
interface SettingsInterface {
|
||||
_updateFlags?: {
|
||||
requireReload?: SettingsReloadFlags,
|
||||
@ -319,18 +336,7 @@ interface SettingsInterface {
|
||||
aard: AardSettings,
|
||||
|
||||
ui: {
|
||||
inPlayer: {
|
||||
popupAlignment: 'left' | 'right',
|
||||
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' | 'trigger-zone' | 'distance' | 'none', // what needs to be hovered in order for UI to be visible
|
||||
triggerZoneDimensions: { // how large the trigger zone is (relative to player size)
|
||||
width: number
|
||||
height: number,
|
||||
offsetX: number, // fed to translateX(offsetX + '%'). Valid range [-100, 0]
|
||||
offsetY: number // fed to translateY(offsetY + '%'). Valid range [-100, 100]
|
||||
},
|
||||
},
|
||||
inPlayer: InPlayerUIOptions,
|
||||
devMode?: boolean,
|
||||
dev: DevUiConfig,
|
||||
}
|
||||
|
||||
@ -264,7 +264,11 @@ const ExtensionConf: SettingsInterface = {
|
||||
minEnabledWidth: 0.75,
|
||||
minEnabledHeight: 0.75,
|
||||
activation: 'player',
|
||||
popupAlignment: 'left',
|
||||
activationDistance: 100,
|
||||
activationDistanceUnits: '%',
|
||||
activatorAlignment: 'left',
|
||||
activatorPadding: 10,
|
||||
activatorPaddingUnit: '%',
|
||||
triggerZoneDimensions: {
|
||||
width: 0.5,
|
||||
height: 0.5,
|
||||
|
||||
@ -12,6 +12,7 @@ export class ClientMenu {
|
||||
public get root(): HTMLDivElement {
|
||||
return this._root;
|
||||
}
|
||||
private trigger: HTMLDivElement;
|
||||
private visible = false;
|
||||
|
||||
private menuPositionClasses: string[] = [];
|
||||
@ -22,6 +23,8 @@ export class ClientMenu {
|
||||
private lastMouseMove = performance.now();
|
||||
private idleTimer?: number;
|
||||
|
||||
|
||||
|
||||
private onDocumentMouseMove?: (e: MouseEvent) => void;
|
||||
private onDocumentMouseLeave?: () => void;
|
||||
private idleIntervalId?: number;
|
||||
@ -75,16 +78,19 @@ export class ClientMenu {
|
||||
}
|
||||
|
||||
private getActivationRadius(anchorEl: HTMLElement): number | null {
|
||||
if (this.config.activationRadius == null) return null;
|
||||
if (this.config.ui.activation !== 'distance') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (typeof this.config.activationRadius === 'number') {
|
||||
return this.config.activationRadius;
|
||||
if (this.config.ui.activationDistanceUnits === 'px') {
|
||||
return +this.config.ui.activationDistance;
|
||||
}
|
||||
|
||||
// percentage string
|
||||
const rect = anchorEl.getBoundingClientRect();
|
||||
const pct = parseFloat(this.config.activationRadius);
|
||||
return Math.max(rect.width, rect.height) * (pct / 100);
|
||||
const percent = +this.config.ui.activationDistance;
|
||||
|
||||
return Math.max(rect.width, rect.height) * (percent / 100);
|
||||
}
|
||||
|
||||
private injectStyles() {
|
||||
@ -154,8 +160,6 @@ export class ClientMenu {
|
||||
pointerEvents: 'none',
|
||||
background: 'transparent',
|
||||
});
|
||||
|
||||
console.log('UI host created:', this.host);
|
||||
}
|
||||
|
||||
private createShadow() {
|
||||
@ -208,7 +212,9 @@ export class ClientMenu {
|
||||
|
||||
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;
|
||||
|
||||
const submenu = this.buildSubmenu(this.config.items);
|
||||
|
||||
@ -281,24 +287,38 @@ export class ClientMenu {
|
||||
}
|
||||
|
||||
private bindGlobalMouse(anchorEl: HTMLElement) {
|
||||
const rect = anchorEl.getBoundingClientRect();
|
||||
const cx = rect.left + rect.width / 2;
|
||||
const cy = rect.top + rect.height / 2;
|
||||
const playerRect = anchorEl.getBoundingClientRect();
|
||||
|
||||
let menuActivatorRect, cx, cy;
|
||||
|
||||
const activationRadius = this.getActivationRadius(anchorEl);
|
||||
|
||||
const recalculateActivator = () => {
|
||||
menuActivatorRect = this.trigger.getBoundingClientRect();
|
||||
cx = menuActivatorRect.left + menuActivatorRect.width / 2;
|
||||
cy = menuActivatorRect.top + menuActivatorRect.height / 2;
|
||||
}
|
||||
|
||||
recalculateActivator();
|
||||
|
||||
this.onDocumentMouseMove = (e: MouseEvent) => {
|
||||
this.lastMouseMove = performance.now();
|
||||
|
||||
if (activationRadius != null) {
|
||||
if (! menuActivatorRect.width) {
|
||||
recalculateActivator();
|
||||
}
|
||||
|
||||
const d = Math.hypot(e.clientX - cx, e.clientY - cy);
|
||||
this.isWithinActivation = d <= activationRadius;
|
||||
|
||||
} else {
|
||||
this.isWithinActivation =
|
||||
e.clientX >= rect.left &&
|
||||
e.clientX <= rect.right &&
|
||||
e.clientY >= rect.top &&
|
||||
e.clientY <= rect.bottom;
|
||||
e.clientX >= playerRect.left &&
|
||||
e.clientX <= playerRect.right &&
|
||||
e.clientY >= playerRect.top &&
|
||||
e.clientY <= playerRect.bottom &&
|
||||
(this.config.ui.activation !== 'player-ctrl' || e.ctrlKey);
|
||||
}
|
||||
|
||||
this.updateVisibility();
|
||||
@ -319,7 +339,7 @@ export class ClientMenu {
|
||||
private startIdleWatcher() {
|
||||
this.idleIntervalId = window.setInterval(() => {
|
||||
const idle = performance.now() - this.lastMouseMove > 1000;
|
||||
if (idle) {
|
||||
if (idle && !this.isHovered) {
|
||||
this.hide();
|
||||
}
|
||||
}, 200);
|
||||
|
||||
@ -184,7 +184,7 @@ class UI {
|
||||
if (this.uiConfig.parentElement) {
|
||||
const menuConfig = {
|
||||
isGlobal: this.isGlobal,
|
||||
menuPosition: MenuPosition.Left,
|
||||
ui: this.settings.active.ui.inPlayer,
|
||||
items: [
|
||||
{
|
||||
customClassList: 'uw-site-info',
|
||||
|
||||
@ -5,17 +5,32 @@
|
||||
<!-- The rest of the tab is under 'edit ratios and shortcuts' row -->
|
||||
<div v-if="settings" class="flex flex-col" style="width: 100%">
|
||||
|
||||
<div class="flex flex-col compact-form">
|
||||
<div class="flex flex-col gap-2">
|
||||
<div
|
||||
class="flex flex-col field-group compact-form"
|
||||
class="flex flex-col field-group compact-form gap-2"
|
||||
>
|
||||
<div class="field disabled">
|
||||
<div class="field">
|
||||
<div class="label">
|
||||
Popup activator position:
|
||||
</div>
|
||||
<div class="select">
|
||||
<select
|
||||
v-model="settings.active.ui.inPlayer.popupAlignment"
|
||||
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>
|
||||
@ -34,11 +49,47 @@
|
||||
@change="saveSettings()"
|
||||
>
|
||||
<option value="player">
|
||||
When mouse hovers over player
|
||||
When mouse moves over player, always
|
||||
</option>
|
||||
<option value="trigger-zone">
|
||||
When mouse hovers over trigger zone
|
||||
<option value="player-ctrl">
|
||||
When mouse moves over player, while holding CTRL key
|
||||
</option>
|
||||
<option value="distance">
|
||||
When mouse is close to the menu activator
|
||||
</option>
|
||||
<!-- <option value="trigger-zone">
|
||||
When mouse moves over trigger zone
|
||||
</option> -->
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-show="settings.active.ui.inPlayer.activation === 'distance'" class="field">
|
||||
<div class="label">
|
||||
Show menu when mouse is closer than:
|
||||
</div>
|
||||
<div class="input range-input">
|
||||
<input
|
||||
v-model="settings.active.ui.inPlayer.activationDistance"
|
||||
class="slider"
|
||||
type="range"
|
||||
min="10"
|
||||
max="100"
|
||||
step="1"
|
||||
@change="(event) => saveSettings()"
|
||||
>
|
||||
<input
|
||||
style="margin-right: 0.6rem;"
|
||||
v-model="settings.active.ui.inPlayer.activationDistance"
|
||||
@change="(event) => saveSettings(true)"
|
||||
>
|
||||
<select
|
||||
class="unit-select !min-w-[72px]"
|
||||
v-model="settings.active.ui.inPlayer.activationDistanceUnit"
|
||||
@change="(event) => saveSettings(true)"
|
||||
>
|
||||
<option value="%">%</option>
|
||||
<option value="px">px</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user