Sort out inputs, shortcut button

This commit is contained in:
Tamius Han 2022-04-12 00:48:33 +02:00
parent 6ce8bba6b7
commit 0daef615c1
7 changed files with 337 additions and 88 deletions

View File

@ -0,0 +1,189 @@
<template>
<div class="flex flex-row">
<div
class="flex-grow button"
@click="editShortcut()"
>
<template v-if="!editing">
{{shortcutDisplay}}
</template>
<template v-else>
{{currentKeypress ?? 'Press a key'}}
<input ref="input"
class="hidden-input"
@keyup.capture="keyup($event)"
@keydown.capture="keydown($event)"
@input.prevent=""
@blur="editing = false;"
>
</template>
</div>
</div>
</template>
<script>
import KeyboardShortcutParser from '../js/KeyboardShortcutParser';
export default {
props: {
shortcut: Object,
},
data() {
return {
currentKeypress: undefined,
currentKey: undefined,
editing: false,
}
},
computed: {
shortcutDisplay() {
if (!this.shortcut) {
return '(no shortcut)'
}
return KeyboardShortcutParser.parseShortcut(this.shortcut);
}
},
methods: {
editShortcut() {
this.editing = true;
this.currentKeypress = undefined;
this.currentKey = undefined;
// input doesn't exist now, but will exist on the next tick
this.$nextTick(()=> this.$refs.input.focus());
},
/**
* Updates currently pressed keypress for display
*/
keydown(event) {
// event.repeat is set to 'true' when key is being held down, but not on
// first keydown. We don't need to process subsequent repeats of a keypress
// we already processed.
if (event.repeat) {
return;
}
const shortcut = KeyboardShortcutParser.generateShortcutFromKeypress(event);
const fixedShortcut = this.handleModifierKeypress(shortcut);
if (this.currentKey === undefined) {
this.currentKey = fixedShortcut;
} else {
// here's a fun fact. Keydown doesn't do modifier keys the way we want
// notably, A-Z0-9 keys are returned without modifier state (all modifiers)
// are set to false in keydown events. That means we need to keep track of
// modifiers ourselves.
if (fixedShortcut.notModifier) {
this.currentKey.key = fixedShortcut.key;
this.currentKey.code = fixedShortcut.code;
} else {
this.currentKey = {
...fixedShortcut,
key: this.currentKey.key,
code: this.currentKey.code
}
}
}
// update display
this.currentKeypress = KeyboardShortcutParser.parseShortcut(this.currentKey);
},
/**
* Emits shortcutChanged when shortcut is considered changed
*/
keyup(event) {
const shortcut = KeyboardShortcutParser.generateShortcutFromKeypress(event);
const fixedShortcut = this.handleModifierKeypress(shortcut);
if (fixedShortcut.notModifier) {
this.editing = false;
this.$emit('shortcutChanged', this.currentKey);
console.log('emitted shortcut:', shortcut, 'raw event:', event);
} else {
// if none of the modifiers are pressed and if no other key is being held down,
// we need to reset label back to 'pls press key'
if (!fixedShortcut.altKey && !fixedShortcut.ctrlKey && !fixedShortcut.metaKey && !fixedShortcut.shiftKey && !fixedShortcut.code) {
this.currentKeypress = undefined;
this.currentKey = undefined;
} else {
this.currentKey = shortcut;
this.currentKeypress = KeyboardShortcutParser.parseShortcut(this.currentKey);
}
}
},
/**
* Handles current keypress if event.keyCode is a modifier key.
* Returns true if current event was a modifier key, false if
* if was a regular A-Z 0-9 key.
*/
handleModifierKeypress(event) {
const modifierPressed = event.type === 'keydown';
switch (event.code) {
case 'ShiftLeft':
case 'ShiftRight':
return {
...event,
key: '…',
code: null,
shiftKey: modifierPressed
}
case 'ControlLeft':
case 'ControlRight':
return {
...event,
key: '…',
code: null,
controlKey: modifierPressed
};
case 'MetaLeft':
case 'MetaRight':
return {
...event,
key: '…',
code: null,
metaKey: modifierPressed
};
case 'AltLeft':
case 'AltRight':
return {
...event,
key: '…',
code: null,
altKey: modifierPressed
};
}
return {
...event,
notModifier: true,
}
}
}
}
</script>
<style lang="scss" src="../../csui/src/res-common/common.scss" scoped></style>
<style lang="scss" scoped>
@import "../../csui/src/res-common/variables";
.center-text {
text-align: center;
}
.dark {
opacity: 50%;
}
.hidden-input {
position: absolute;
z-index: -9999;
opacity: 0;
}
</style>

View File

@ -1,38 +0,0 @@
<template>
<div class="flex flex-column flex-center">
<template v-if="!editing">
<div class="flex flex-self-center">
{{label}}
</div>
<div class="flex dark flex-self-center">
<small>
{{shortcut ? `(${shortcut})` : ''}}
</small>
</div>
</template>
<template v-else>
<div class="flex flex-row flex-center">
</div>
</template>
</div>
</template>
<script>
export default {
props: {
label: String,
shortcut: String,
editing: Boolean,
}
}
</script>
<style lang="scss" scoped>
.center-text {
text-align: center;
}
.dark {
opacity: 50%;
}
</style>

View File

@ -21,6 +21,19 @@ class KeyboardShortcutParser {
}
return shortcutCombo;
}
static generateShortcutFromKeypress(event) {
return {
ctrlKey: event.ctrlKey,
shiftKey: event.altKey,
altKey: event.altKey,
code: event.code,
key: event.key,
keyup: true,
keydown: false,
type: event.type, // only needed for purposes of EditShortcutButton
}
}
}
export default KeyboardShortcutParser;

View File

@ -50,48 +50,58 @@
</div>
<!-- EDIT MODE PANEL -->
<div class="edit-action-area">
<div>
Editing options for <b>{{editModeOptions?.crop?.selected?.label}}</b>
</div>
<!-- Some options are only shown for type 4 (fixed) crops -->
<template v-if="editModeOptions?.crop?.selected.arguments.type === AspectRatioType.Fixed">
<div>
Label: -- todo --
<div class="sub-panel-content">
<div class="edit-action-area">
<div class="edit-action-area-header">
Editing options for: <b>{{editModeOptions?.crop?.selected?.label}}</b>
</div>
<div>
Ratio: -- todo --
<!-- Some options are only shown for type 4 (fixed) crops -->
<template v-if="editModeOptions?.crop?.selected?.arguments?.type === AspectRatioType.Fixed">
<div class="field">
<div class="label">
Ratio:
</div>
<div class="input">
<input v-model="editModeOptions.crop.selected.arguments.ratio">
</div>
<div class="hint">
You can enter a ratio in width:height format (e.g. "21:9" or "1:2.39"), or just the factor
(in this case, "1:2.39" would become "2.39" and "21:9" would become "2.33"). You should enter
your numbers without quote marks. Number will be converted to factor form on save.
</div>
</div>
<div class="field">
<div class="label">
Label:
</div>
<div class="input">
<input v-model="editModeOptions.crop.selected.label">
</div>
<div class="hint">
Label for the button. You can make it say something other than ratio.
</div>
</div>
</template>
<!-- editing keyboard shortcuts is always allowed -->
<div class="field">
<div class="label">Shortcut:</div>
<div class="">
<EditShortcutButton
:shortcut="editModeOptions?.crop?.selected?.shortcut"
@shortcutChanged="updateSelectedShortcut($event, 'crop')"
>
</EditShortcutButton>
</div>
<div class="hint">
<b>Note:</b> Your browser and OS already use certain key combinations that involve Ctrl and Meta (Windows) keys and, to a lesser extent, Alt.
The extension doesn't (and cannot) check whether the keyboard shortcut you enter is actually free for you to use. The extension also won't override
any keyboard shortcuts defined by the site itself.
</div>
</div>
</template>
<!-- editing keyboard shortcuts is always allowed -->
<div>
-- todo: edit keyboard shortcut --
</div>
<div>
------------ <br/>>
present items:<br/>>
editModeOptions? {{!!editModeOptions}}<br/>
.crop? {{!!editModeOptions?.crop}}<br/>
.selected? {{!!editModeOptions?.crop?.selected}}<br/>
<br/>
selected action:<br/>{{editModeOptions?.crop?.selected}}
</div>
<!-- <select class=""
:value="selectedAction"
@change="setAction($event.target.value)"
>
<option :value="undefined" selected disabled>Select ...</option>
<option v-for="(action, key) in ActionList"
:value="key"
:key="key"
>
{{action.name}}
</option>
</select> -->
</div>
<div class="flex flex-row">
@ -297,6 +307,7 @@
import Button from '../../../common/components/Button.vue'
import KeyboardShortcutParser from '../../../common/js/KeyboardShortcutParser';
import ShortcutButton from '../../../common/components/ShortcutButton';
import EditShortcutButton from '../../../common/components/EditShortcutButton';
import ComputeActionsMixin from '../../../common/mixins/ComputeActionsMixin';
import ExecAction from '../ui-libs/ExecAction';
import BrowserDetect from '../../../ext/conf/BrowserDetect';
@ -319,7 +330,8 @@ export default {
y: 0
},
editMode: true,
editModeOptions: {},
editModeOptions: {
},
resizerConfig: {
crop: null,
stretch: null,
@ -357,6 +369,7 @@ export default {
},
components: {
ShortcutButton,
EditShortcutButton,
Button,
AlignmentOptionsControlComponent
},
@ -521,6 +534,18 @@ export default {
console.error(`[Ultrawidify] there's a problem with VideoSettings.vue::editAction():`, e);
}
},
updateSelectedShortcut(shortcut, actionType) {
try {
if (!this.editModeOptions[actionType]?.selected) {
return;
} else {
this.editModeOptions[actionType].selected.shortcut = shortcut
}
} catch (e) {
console.error(`[Ultrawidify] there's a problem with VideoSettings.vue::updateShortcut():`, e);
}
},
//#endregion
//#region comms and bus
@ -588,4 +613,13 @@ export default {
padding-bottom: 16px;
padding-top: 8px;
}
.edit-action-area {
background-color: rgba($blackBg,0.5);
padding: 0.5rem;
.edit-action-area-header {
border-bottom: 1px solid rgba(255,255,255,0.5);
}
}
</style>

View File

@ -3,3 +3,7 @@ $warning-color: #d6ba4a;
$primary: rgb(255, 147, 85);
$primaryBrighter: rgb(255, 174, 127);
$primaryBg: rgba(54, 31, 21, 0.5);
$blackBg: rgb(11,11,11);
$normalTransparentOpacity: 0.5;
$hoverTransparentOpacity: 0.9;

View File

@ -31,13 +31,18 @@ h1, h2, h3 {
}
.button {
background-color: rgba(11,11,11,0.5);
background-color: rgba($blackBg, $normalTransparentOpacity);
padding: 0.5rem 2rem;
margin: 3px;
color: #aaa;
border: 1px solid transparent;
user-select: none !important;
&:hover {
color: #fff;
background-color: rgba(11,11,11,0.9);
background-color: rgba($blackBg, $hoverTransparentOpacity);
border-bottom: 1px solid rgba($primary, 0.5);
}
@ -51,3 +56,47 @@ h1, h2, h3 {
margin: 0.25rem;
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;
.label {
flex: 0 0 25%;
text-align: right;
padding-right: 1rem;
}
.input {
flex: 0 0 70%;
background-color: rgba($blackBg, $normalTransparentOpacity);
border: 1px solid transparent;
border-bottom: 1px solid rgba(255,255,255,0.5);
padding-top: 0.25rem;
padding-bottom: 0.25rem;
&:active, &:focus, &:focus-within {
border-bottom: 1px solid rgba($primary, 0.5);
}
input {
width: 100%;
outline: none;
border: 1px solid transparent;
background-color: transparent;
color: #fff;
}
}
.hint {
padding-left: calc(25% + 1rem);
font-size: 0.8rem;
opacity: 0.7;
margin-top: 0.25rem;
}
}

View File

@ -226,18 +226,16 @@ small {
}
.button {
/*display: inline-block;*/
// padding-top: 8px;
// padding-bottom: 3px;
//padding-left: 5px;
//padding-right: 5px;
border: 1px solid rgb(39, 39, 39);
border: 1px solid transparent;
padding: 0.5rem 2rem;
margin-top: 3px;
margin-bottom: 3px;
color: $text-dim;
text-align: center;
cursor: pointer;
user-select: none;;
user-select: none;
}