Compare commits
4 Commits
11fa12001c
...
b2cd8197d4
| Author | SHA1 | Date | |
|---|---|---|---|
| b2cd8197d4 | |||
| 23ea9e77c4 | |||
| 42ac51f1e9 | |||
| d433878680 |
@ -76,6 +76,29 @@
|
|||||||
</GhettoContextMenuOption>
|
</GhettoContextMenuOption>
|
||||||
</slot>
|
</slot>
|
||||||
</GhettoContextMenu>
|
</GhettoContextMenu>
|
||||||
|
<GhettoContextMenu alignment="right">
|
||||||
|
<template v-slot:activator>
|
||||||
|
Zoom
|
||||||
|
</template>
|
||||||
|
<slot>
|
||||||
|
<GhettoContextMenuOption
|
||||||
|
v-for="(command, index) of settings?.active.commands.zoom"
|
||||||
|
:key="index"
|
||||||
|
:label="command.label"
|
||||||
|
:shortcut="getKeyboardShortcutLabel(command)"
|
||||||
|
@click="execAction(command)"
|
||||||
|
>
|
||||||
|
</GhettoContextMenuOption>
|
||||||
|
<GhettoContextMenuItem
|
||||||
|
:disableHover="true"
|
||||||
|
>
|
||||||
|
<ZoomControl
|
||||||
|
:settings="settings"
|
||||||
|
:eventBus="eventBus"
|
||||||
|
/>
|
||||||
|
</GhettoContextMenuItem>
|
||||||
|
</slot>
|
||||||
|
</GhettoContextMenu>
|
||||||
<GhettoContextMenu alignment="right">
|
<GhettoContextMenu alignment="right">
|
||||||
<template v-slot:activator>
|
<template v-slot:activator>
|
||||||
<div class="context-item">
|
<div class="context-item">
|
||||||
@ -186,20 +209,21 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import PlayerUIWindow from './src/PlayerUIWindow.vue';
|
import PlayerUIWindow from '@csui/src/PlayerUIWindow.vue';
|
||||||
import GhettoContextMenu from './src/components/GhettoContextMenu.vue';
|
import GhettoContextMenu from '@csui/src/components/GhettoContextMenu.vue';
|
||||||
import GhettoContextMenuItem from './src/components/GhettoContextMenuItem.vue';
|
import GhettoContextMenuItem from '@csui/src/components/GhettoContextMenuItem.vue';
|
||||||
import GhettoContextMenuOption from './src/components/GhettoContextMenuOption.vue';
|
import GhettoContextMenuOption from '@csui/src/components/GhettoContextMenuOption.vue';
|
||||||
import AlignmentOptionsControlComponent from './src/PlayerUiPanels/AlignmentOptionsControlComponent.vue';
|
import AlignmentOptionsControlComponent from '@csui/src/PlayerUiPanels/AlignmentOptionsControlComponent.vue';
|
||||||
import BrowserDetect from '../ext/conf/BrowserDetect';
|
import BrowserDetect from '@src/ext/conf/BrowserDetect';
|
||||||
import Logger from '../ext/lib/Logger';
|
import Logger from '@src/ext/lib/Logger';
|
||||||
import Settings from '../ext/lib/Settings';
|
import Settings from '@src/ext/lib/Settings';
|
||||||
import EventBus from '../ext/lib/EventBus';
|
import EventBus from '@src/ext/lib/EventBus';
|
||||||
import UIProbeMixin from './src/utils/UIProbeMixin';
|
import UIProbeMixin from '@csui/src/utils/UIProbeMixin';
|
||||||
import KeyboardShortcutParserMixin from './src/utils/KeyboardShortcutParserMixin';
|
import KeyboardShortcutParserMixin from '@csui/src/utils/KeyboardShortcutParserMixin';
|
||||||
import CommsMixin from './src/utils/CommsMixin';
|
import CommsMixin from '@csui/src/utils/CommsMixin';
|
||||||
import SupportLevelIndicator from './src/components/SupportLevelIndicator.vue';
|
import SupportLevelIndicator from '@csui/src/components/SupportLevelIndicator.vue';
|
||||||
import TriggerZoneEditor from './src/components/TriggerZoneEditor.vue';
|
import TriggerZoneEditor from '@csui/src/components/TriggerZoneEditor.vue';
|
||||||
|
import ZoomControl from '@csui/src/popup/player-menu/ZoomControl.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@ -210,6 +234,7 @@ export default {
|
|||||||
AlignmentOptionsControlComponent,
|
AlignmentOptionsControlComponent,
|
||||||
SupportLevelIndicator,
|
SupportLevelIndicator,
|
||||||
TriggerZoneEditor,
|
TriggerZoneEditor,
|
||||||
|
ZoomControl,
|
||||||
},
|
},
|
||||||
mixins: [
|
mixins: [
|
||||||
UIProbeMixin,
|
UIProbeMixin,
|
||||||
@ -570,9 +595,8 @@ export default {
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style lang="scss" src="./src/res-common/panels.scss" scoped module></style>
|
<style lang="scss" src="@csui/src/res-common/panels.scss" scoped module></style>
|
||||||
<style lang="scss" src="./src/res-common/common.scss" scoped module></style>
|
<style lang="scss" src="@csui/src/res-common/common.scss" scoped module></style>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
.uw-hover {
|
.uw-hover {
|
||||||
|
|||||||
@ -63,7 +63,7 @@
|
|||||||
|
|
||||||
<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
|
||||||
</div>
|
</div>
|
||||||
<div class="input range-input">
|
<div class="input range-input">
|
||||||
<input
|
<input
|
||||||
@ -77,16 +77,18 @@
|
|||||||
@change="(event) => saveSettings()"
|
@change="(event) => saveSettings()"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
|
style="margin-right: 0.6rem;"
|
||||||
:value="ghettoComputed.minEnabledWidth"
|
:value="ghettoComputed.minEnabledWidth"
|
||||||
@input="(event) => setPlayerRestrictions('minEnabledWidth', event.target.value, true)"
|
@input="(event) => setPlayerRestrictions('minEnabledWidth', event.target.value, true)"
|
||||||
@change="(event) => saveSettings(true)"
|
@change="(event) => saveSettings(true)"
|
||||||
>
|
>
|
||||||
|
<div class="unit">% of screen</div>
|
||||||
</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 shorter than (% of screen width)
|
Do not show in-player UI when video player is shorter than
|
||||||
</div>
|
</div>
|
||||||
<div class="input range-input">
|
<div class="input range-input">
|
||||||
<input
|
<input
|
||||||
@ -100,10 +102,12 @@
|
|||||||
@change="(event) => saveSettings()"
|
@change="(event) => saveSettings()"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
|
style="margin-right: 0.6rem;"
|
||||||
:value="ghettoComputed.minEnabledHeight"
|
:value="ghettoComputed.minEnabledHeight"
|
||||||
@input="(event) => setPlayerRestrictions('minEnabledHeight', event.target.value, true)"
|
@input="(event) => setPlayerRestrictions('minEnabledHeight', event.target.value, true)"
|
||||||
@change="(event) => saveSettings(true)"
|
@change="(event) => saveSettings(true)"
|
||||||
>
|
>
|
||||||
|
<div class="unit">% of screen</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -242,8 +246,6 @@ export default {
|
|||||||
max-width: 24rem;
|
max-width: 24rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.trigger-zone-editor {
|
.trigger-zone-editor {
|
||||||
background-color: rgba(0,0,0,0.25);
|
background-color: rgba(0,0,0,0.25);
|
||||||
|
|
||||||
|
|||||||
112
src/csui/src/popup/player-menu/ZoomControl.vue
Normal file
112
src/csui/src/popup/player-menu/ZoomControl.vue
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
Custom zoom
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="top-label">Zoom:</div>
|
||||||
|
<div class="input range-input">
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
class="slider"
|
||||||
|
min="0"
|
||||||
|
max="3"
|
||||||
|
step="0.01"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template v-if="true">
|
||||||
|
<div class="top-label">Vertical zoom:</div>
|
||||||
|
<div class="input range-input">
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
class="slider"
|
||||||
|
min="0"
|
||||||
|
max="3"
|
||||||
|
step="0.01"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div><input type="checkbox"/> Control vertical and horizontal zoom independently.</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
zoomAspectRatioLocked: true,
|
||||||
|
zoom: {
|
||||||
|
x: 0,
|
||||||
|
y: 0
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO: this should be mixin?
|
||||||
|
resizerConfig: {
|
||||||
|
crop: null,
|
||||||
|
stretch: null,
|
||||||
|
zoom: null,
|
||||||
|
pan: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mixins: [
|
||||||
|
|
||||||
|
],
|
||||||
|
props: [
|
||||||
|
'settings', // required for buttons and actions, which are global
|
||||||
|
'eventBus'
|
||||||
|
],
|
||||||
|
methods: {
|
||||||
|
getZoomForDisplay(axis) {
|
||||||
|
// zoom is internally handled logarithmically, because we want to have x0.5, x1, x2, x4 ... magnifications
|
||||||
|
// spaced out at regular intervals. When displaying, we need to convert that to non-logarithmic values.
|
||||||
|
|
||||||
|
return `${(Math.pow(2, this.zoom[axis]) * 100).toFixed()}%`
|
||||||
|
},
|
||||||
|
toggleZoomAr() {
|
||||||
|
this.zoomAspectRatioLocked = !this.zoomAspectRatioLocked;
|
||||||
|
},
|
||||||
|
|
||||||
|
resetZoom() {
|
||||||
|
// we store zoom logarithmically on this component
|
||||||
|
this.zoom = {x: 0, y: 0};
|
||||||
|
|
||||||
|
// we do not use logarithmic zoom elsewhere
|
||||||
|
// todo: replace eventBus with postMessage to parent
|
||||||
|
// 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, axis: 'y'});
|
||||||
|
this.eventBus?.sendToTunnel('set-zoom', {zoom: 1, axis: 'x'});
|
||||||
|
},
|
||||||
|
changeZoom(newZoom, axis) {
|
||||||
|
// we store zoom logarithmically on this compnent
|
||||||
|
if (!axis) {
|
||||||
|
this.zoom.x = newZoom;
|
||||||
|
} else {
|
||||||
|
this.zoom[axis] = newZoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we do not use logarithmic zoom elsewhere, therefore we need to convert
|
||||||
|
newZoom = Math.pow(2, newZoom);
|
||||||
|
|
||||||
|
if (this.zoomAspectRatioLocked) {
|
||||||
|
this.eventBus?.sendToTunnel('set-zoom', {zoom: newZoom, axis: 'y'});
|
||||||
|
this.eventBus?.sendToTunnel('set-zoom', {zoom: newZoom, axis: 'x'});
|
||||||
|
} else {
|
||||||
|
this.eventBus?.sendToTunnel('set-zoom', {zoom: newZoom, axis: axis ?? 'x'});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" src="@csui/res/css/flex.scss" scoped></style>
|
||||||
|
<style lang="scss" src="@csui/src/res-common/panels.scss" scoped module></style>
|
||||||
|
<style lang="scss" src="@csui/src/res-common/common.scss" scoped module></style>
|
||||||
@ -62,30 +62,7 @@ button, .button {
|
|||||||
padding: 0.5rem 2rem;
|
padding: 0.5rem 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.field {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
padding-top: 0.5rem;
|
|
||||||
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
&.l2 {
|
|
||||||
margin-left: 4rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
flex: 0 0 25%;
|
|
||||||
text-align: right;
|
|
||||||
padding-right: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input, .range-input {
|
.input, .range-input {
|
||||||
flex: 0 0 70%;
|
|
||||||
max-width: 24rem;
|
|
||||||
background-color: rgba($blackBg, $normalTransparentOpacity);
|
background-color: rgba($blackBg, $normalTransparentOpacity);
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
border-bottom: 1px solid rgba(255,255,255,0.5);
|
border-bottom: 1px solid rgba(255,255,255,0.5);
|
||||||
@ -135,6 +112,32 @@ button, .button {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.field {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&.l2 {
|
||||||
|
margin-left: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
flex: 0 0 25%;
|
||||||
|
text-align: right;
|
||||||
|
padding-right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input, .range-input {
|
||||||
|
flex: 0 0 70%;
|
||||||
|
max-width: 24rem;
|
||||||
|
}
|
||||||
|
|
||||||
.hint {
|
.hint {
|
||||||
padding-left: calc(25% + 1rem);
|
padding-left: calc(25% + 1rem);
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
|
|||||||
@ -112,9 +112,16 @@ export default {
|
|||||||
if (! this.uwWindowVisible) {
|
if (! this.uwWindowVisible) {
|
||||||
this.uwTriggerZoneVisible = true;
|
this.uwTriggerZoneVisible = true;
|
||||||
clearTimeout(this.uwTriggerZoneTimeout);
|
clearTimeout(this.uwTriggerZoneTimeout);
|
||||||
|
|
||||||
|
const windowParent = window.parent;
|
||||||
this.uwTriggerZoneTimeout = setTimeout(
|
this.uwTriggerZoneTimeout = setTimeout(
|
||||||
() => {
|
() => {
|
||||||
this.uwTriggerZoneVisible = false;
|
this.uwTriggerZoneVisible = false;
|
||||||
|
|
||||||
|
windowParent.postMessage(
|
||||||
|
{action: 'uwui-hidden', opacity: false},
|
||||||
|
origin
|
||||||
|
);
|
||||||
},
|
},
|
||||||
500
|
500
|
||||||
);
|
);
|
||||||
@ -134,6 +141,7 @@ export default {
|
|||||||
{
|
{
|
||||||
action: 'uwui-clickable',
|
action: 'uwui-clickable',
|
||||||
clickable: isClickable,
|
clickable: isClickable,
|
||||||
|
opacity: isClickable || this.contextMenuActive || this.uwTriggerZoneVisible,
|
||||||
hoverStats: {
|
hoverStats: {
|
||||||
isOverTriggerZone: isOverTriggerZone,
|
isOverTriggerZone: isOverTriggerZone,
|
||||||
isOverMenuTrigger: isOverMenuTrigger,
|
isOverMenuTrigger: isOverMenuTrigger,
|
||||||
|
|||||||
@ -95,6 +95,7 @@ class UI {
|
|||||||
iframe.style.zIndex = this.isGlobal ? '90009' : '90000';
|
iframe.style.zIndex = this.isGlobal ? '90009' : '90000';
|
||||||
iframe.style.border = 0;
|
iframe.style.border = 0;
|
||||||
iframe.style.pointerEvents = 'none';
|
iframe.style.pointerEvents = 'none';
|
||||||
|
iframe.style.opacity = 0;
|
||||||
iframe.style.backgroundColor = 'transparent !important';
|
iframe.style.backgroundColor = 'transparent !important';
|
||||||
|
|
||||||
/* so we have a problem: we want iframe to be clickthrough everywhere except
|
/* so we have a problem: we want iframe to be clickthrough everywhere except
|
||||||
@ -323,7 +324,7 @@ class UI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.uiIframe.style.pointerEvents = event.data.clickable ? 'auto' : 'none';
|
this.uiIframe.style.pointerEvents = event.data.clickable ? 'auto' : 'none';
|
||||||
this.uiIframe.style.display = event.data.opacity ? '100' : '0';
|
this.uiIframe.style.opacity = event.data.opacity ? '100' : '0';
|
||||||
break;
|
break;
|
||||||
case 'uw-bus-tunnel':
|
case 'uw-bus-tunnel':
|
||||||
const busCommand = event.data.payload;
|
const busCommand = event.data.payload;
|
||||||
@ -335,6 +336,9 @@ class UI {
|
|||||||
case 'uwui-interface-ready':
|
case 'uwui-interface-ready':
|
||||||
this.setUiVisibility(!this.isGlobal);
|
this.setUiVisibility(!this.isGlobal);
|
||||||
break;
|
break;
|
||||||
|
case 'uwui-hidden':
|
||||||
|
this.uiIframe.style.opacity = event.data.opacity ? '100' : '0';
|
||||||
|
break;
|
||||||
case 'uwui-global-window-hidden':
|
case 'uwui-global-window-hidden':
|
||||||
if (!this.isGlobal) {
|
if (!this.isGlobal) {
|
||||||
return; // This shouldn't even happen in non-global windows
|
return; // This shouldn't even happen in non-global windows
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user