feat(ui): macro ui improvement (#473)
* Remove the "Input the text you want to type with this macro action." sentence from the type text macro action. * Move pointer and Scroll enhancement * remove the extra vertical space above the mouse buttons * macro delay enhancement * not allow user select on a few elements * fill the macro, keymap name the all space in the header
This commit is contained in:
committed by
László Monda
parent
bd49e26978
commit
9885439b10
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
"unit-case": "lower",
|
"unit-case": "lower",
|
||||||
"unit-no-unknown": true,
|
"unit-no-unknown": true,
|
||||||
"unit-whitelist": ["px", "%", "deg", "ms", "em", "rem", "vh", "vv", "s"],
|
"unit-whitelist": ["px", "%", "deg", "ms", "em", "rem", "vh", "vv", "s", "ch"],
|
||||||
|
|
||||||
"value-list-comma-space-after": "always-single-line",
|
"value-list-comma-space-after": "always-single-line",
|
||||||
"value-list-comma-space-before": "never",
|
"value-list-comma-space-before": "never",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
type="text"
|
type="text"
|
||||||
(change)="editKeymapName($event.target.value)"
|
(change)="editKeymapName($event.target.value)"
|
||||||
(keyup.enter)="name.blur()"
|
(keyup.enter)="name.blur()"
|
||||||
|
(keyup)="calculateHeaderTextWidth($event.target.value)"
|
||||||
/> keymap
|
/> keymap
|
||||||
(<input #abbr cancelable
|
(<input #abbr cancelable
|
||||||
class="keymap__abbrev pane-title__abbrev"
|
class="keymap__abbrev pane-title__abbrev"
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
Component,
|
Component,
|
||||||
ElementRef,
|
ElementRef,
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
|
HostListener,
|
||||||
Input,
|
Input,
|
||||||
OnChanges,
|
OnChanges,
|
||||||
Output,
|
Output,
|
||||||
@@ -16,6 +17,7 @@ import { Store } from '@ngrx/store';
|
|||||||
|
|
||||||
import { AppState } from '../../../store';
|
import { AppState } from '../../../store';
|
||||||
import { KeymapActions } from '../../../store/actions';
|
import { KeymapActions } from '../../../store/actions';
|
||||||
|
import * as util from '../../../util';
|
||||||
|
|
||||||
const DEFAULT_TRASH_TITLE = '<span class="text-nowrap">Delete keymap</span>';
|
const DEFAULT_TRASH_TITLE = '<span class="text-nowrap">Delete keymap</span>';
|
||||||
|
|
||||||
@@ -50,6 +52,11 @@ export class KeymapHeaderComponent implements OnChanges {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@HostListener('window:resize')
|
||||||
|
windowResize(): void {
|
||||||
|
this.calculateHeaderTextWidth(this.keymap.name);
|
||||||
|
}
|
||||||
|
|
||||||
setDefault() {
|
setDefault() {
|
||||||
if (!this.keymap.isDefault) {
|
if (!this.keymap.isDefault) {
|
||||||
this.store.dispatch(KeymapActions.setDefault(this.keymap.abbreviation));
|
this.store.dispatch(KeymapActions.setDefault(this.keymap.abbreviation));
|
||||||
@@ -103,8 +110,16 @@ export class KeymapHeaderComponent implements OnChanges {
|
|||||||
this.downloadClick.emit();
|
this.downloadClick.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
calculateHeaderTextWidth(text): void {
|
||||||
|
const htmlInput = this.keymapName.nativeElement as HTMLInputElement;
|
||||||
|
const maxWidth = htmlInput.parentElement.offsetWidth - 530;
|
||||||
|
const textWidth = util.getContentWidth(window.getComputedStyle(htmlInput), text);
|
||||||
|
this.renderer.setStyle(htmlInput, 'width', Math.min(maxWidth, textWidth) + 'px');
|
||||||
|
}
|
||||||
|
|
||||||
private setName(): void {
|
private setName(): void {
|
||||||
this.renderer.setProperty(this.keymapName.nativeElement, 'value', this.keymap.name);
|
this.renderer.setProperty(this.keymapName.nativeElement, 'value', this.keymap.name);
|
||||||
|
this.calculateHeaderTextWidth(this.keymap.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private setAbbreviation() {
|
private setAbbreviation() {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
a {
|
a {
|
||||||
border-top-right-radius: 0;
|
border-top-right-radius: 0;
|
||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
<div class="macro-delay">
|
<div class="macro-delay">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<h4>Enter delay in seconds</h4>
|
<h4>Delay</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-4">
|
<div class="col-xs-12">
|
||||||
|
<div class="form-group">
|
||||||
<input #macroDelayInput
|
<input #macroDelayInput
|
||||||
type="number"
|
type="number"
|
||||||
min="0"
|
min="0"
|
||||||
@@ -13,14 +14,17 @@
|
|||||||
step="0.1"
|
step="0.1"
|
||||||
placeholder="Delay amount"
|
placeholder="Delay amount"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
[value]="delay"
|
[ngModel]="delay"
|
||||||
(change)="setDelay(macroDelayInput.value)">
|
(ngModelChange)="setDelay(macroDelayInput.value)">
|
||||||
|
<label>seconds</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row macro-delay__presets">
|
<div class="row macro-delay__presets">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<h6>Choose a preset</h6>
|
<h6>Choose a preset</h6>
|
||||||
<button *ngFor="let delay of presets" class="btn btn-sm btn-default" (click)="setDelay(delay)">{{delay}}s</button>
|
<button *ngFor="let delay of presets" class="btn btn-sm btn-default" (click)="setDelay(delay)">{{delay}}s
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -14,3 +14,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control {
|
||||||
|
width: 16ch;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,9 +23,19 @@ export class MacroDelayTabComponent extends MacroBaseComponent implements OnInit
|
|||||||
@Input() macroAction: DelayMacroAction;
|
@Input() macroAction: DelayMacroAction;
|
||||||
@ViewChild('macroDelayInput') input: ElementRef;
|
@ViewChild('macroDelayInput') input: ElementRef;
|
||||||
|
|
||||||
delay: number;
|
|
||||||
presets: number[] = [0.3, 0.5, 0.8, 1, 2, 3, 4, 5];
|
presets: number[] = [0.3, 0.5, 0.8, 1, 2, 3, 4, 5];
|
||||||
|
|
||||||
|
get delay(): number {
|
||||||
|
return this._delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
set delay(value: number) {
|
||||||
|
this._delay = value;
|
||||||
|
this.validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _delay: number;
|
||||||
|
|
||||||
constructor() { super(); }
|
constructor() { super(); }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@@ -33,12 +43,11 @@ export class MacroDelayTabComponent extends MacroBaseComponent implements OnInit
|
|||||||
this.macroAction = new DelayMacroAction();
|
this.macroAction = new DelayMacroAction();
|
||||||
}
|
}
|
||||||
this.delay = this.macroAction.delay > 0 ? this.macroAction.delay / 1000 : INITIAL_DELAY;
|
this.delay = this.macroAction.delay > 0 ? this.macroAction.delay / 1000 : INITIAL_DELAY;
|
||||||
this.validate(); // initial validation as it has defaults
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setDelay(value: number): void {
|
setDelay(value: number): void {
|
||||||
this.delay = value;
|
this._delay = value;
|
||||||
this.macroAction.delay = this.delay * 1000;
|
this.macroAction.delay = this._delay * 1000;
|
||||||
this.validate();
|
this.validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,29 +36,55 @@
|
|||||||
<div class="col-xs-9 macro-mouse__actions" [ngSwitch]="activeTab">
|
<div class="col-xs-9 macro-mouse__actions" [ngSwitch]="activeTab">
|
||||||
<div #tab *ngSwitchCase="TabName.Move">
|
<div #tab *ngSwitchCase="TabName.Move">
|
||||||
<h4>Move pointer</h4>
|
<h4>Move pointer</h4>
|
||||||
<p>Use negative values to move down or left from current position.</p>
|
|
||||||
<div class="form-horizontal">
|
<div class="form-horizontal">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="move-mouse-x">X</label>
|
<label for="move-mouse-x">X:</label>
|
||||||
<input id="move-mouse-x" type="number" class="form-control" [(ngModel)]="macroAction['x']" (keyup)="validate()"> pixels
|
<input id="move-mouse-x"
|
||||||
|
type="number"
|
||||||
|
class="form-control"
|
||||||
|
[(ngModel)]="macroAction['x']"
|
||||||
|
(keyup)="validate()"
|
||||||
|
min="-9999"
|
||||||
|
max="9999"
|
||||||
|
maxlength="4"> pixels
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="move-mouse-y">Y</label>
|
<label for="move-mouse-y">Y:</label>
|
||||||
<input id="move-mouse-y" type="number" class="form-control" [(ngModel)]="macroAction['y']" (keyup)="validate()"> pixels
|
<input id="move-mouse-y"
|
||||||
|
type="number"
|
||||||
|
class="form-control"
|
||||||
|
[(ngModel)]="macroAction['y']"
|
||||||
|
(keyup)="validate()"
|
||||||
|
min="-9999"
|
||||||
|
max="9999"
|
||||||
|
maxlength="4"> pixels
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div #tab *ngSwitchCase="TabName.Scroll">
|
<div #tab *ngSwitchCase="TabName.Scroll">
|
||||||
<h4>Scroll</h4>
|
<h4>Scroll</h4>
|
||||||
<p>Use negative values to move down or left from current position.</p>
|
|
||||||
<div class="form-horizontal">
|
<div class="form-horizontal">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="scroll-mouse-x">X</label>
|
<label for="scroll-mouse-x">X:</label>
|
||||||
<input id="scroll-mouse-x" type="number" class="form-control" [(ngModel)]="macroAction['x']" (keyup)="validate()"> pixels
|
<input id="scroll-mouse-x"
|
||||||
|
type="number"
|
||||||
|
class="form-control"
|
||||||
|
[(ngModel)]="macroAction['x']"
|
||||||
|
(keyup)="validate()"
|
||||||
|
min="-9999"
|
||||||
|
max="9999"
|
||||||
|
maxlength="4"> pixels
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="scroll-mouse-y">Y</label>
|
<label for="scroll-mouse-y">Y:</label>
|
||||||
<input id="scroll-mouse-y" type="number" class="form-control" [(ngModel)]="macroAction['y']" (keyup)="validate()"> pixels
|
<input id="scroll-mouse-y"
|
||||||
|
type="number"
|
||||||
|
class="form-control"
|
||||||
|
[(ngModel)]="macroAction['y']"
|
||||||
|
(keyup)="validate()"
|
||||||
|
min="-9999"
|
||||||
|
max="9999"
|
||||||
|
maxlength="4"> pixels
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -66,11 +92,12 @@
|
|||||||
<h4 *ngIf="activeTab === TabName.Click">Click mouse button</h4>
|
<h4 *ngIf="activeTab === TabName.Click">Click mouse button</h4>
|
||||||
<h4 *ngIf="activeTab === TabName.Hold">Hold mouse button</h4>
|
<h4 *ngIf="activeTab === TabName.Hold">Hold mouse button</h4>
|
||||||
<h4 *ngIf="activeTab === TabName.Release">Release mouse button</h4>
|
<h4 *ngIf="activeTab === TabName.Release">Release mouse button</h4>
|
||||||
<div class="btn-group macro-mouse__buttons">
|
<div class="btn-group">
|
||||||
<button *ngFor="let buttonLabel of buttonLabels; let buttonIndex = index"
|
<button *ngFor="let buttonLabel of buttonLabels; let buttonIndex = index"
|
||||||
class="btn btn-default"
|
class="btn btn-default"
|
||||||
[class.btn-primary]="hasButton(buttonIndex)"
|
[class.btn-primary]="hasButton(buttonIndex)"
|
||||||
(click)="setMouseClick(buttonIndex)">{{buttonLabel}}</button>
|
(click)="setMouseClick(buttonIndex)">{{buttonLabel}}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,11 +15,6 @@
|
|||||||
padding-left: 3rem;
|
padding-left: 3rem;
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__buttons {
|
|
||||||
margin-top: 3rem;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.fa {
|
.fa {
|
||||||
@@ -38,6 +33,6 @@
|
|||||||
|
|
||||||
.form-control {
|
.form-control {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 60%;
|
width: 10ch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ enum TabName {
|
|||||||
'../../macro-action-editor.component.scss',
|
'../../macro-action-editor.component.scss',
|
||||||
'./macro-mouse.component.scss'
|
'./macro-mouse.component.scss'
|
||||||
],
|
],
|
||||||
host: { 'class': 'macro__mouse' }
|
host: {'class': 'macro__mouse'}
|
||||||
})
|
})
|
||||||
export class MacroMouseTabComponent extends MacroBaseComponent implements OnInit {
|
export class MacroMouseTabComponent extends MacroBaseComponent implements OnInit {
|
||||||
@Input() macroAction: MouseMacroAction;
|
@Input() macroAction: MouseMacroAction;
|
||||||
@@ -130,14 +130,14 @@ export class MacroMouseTabComponent extends MacroBaseComponent implements OnInit
|
|||||||
switch (this.macroAction.constructor) {
|
switch (this.macroAction.constructor) {
|
||||||
case MoveMouseMacroAction:
|
case MoveMouseMacroAction:
|
||||||
case ScrollMouseMacroAction:
|
case ScrollMouseMacroAction:
|
||||||
const { x, y } = this.macroAction as MoveMouseMacroAction;
|
const {x, y} = this.macroAction as MoveMouseMacroAction;
|
||||||
return x !== undefined && x !== null && y !== undefined && y !== null;
|
return x !== undefined && x !== null && y !== undefined && y !== null &&
|
||||||
|
(x !== 0 || y !== 0) && x < 10000 && x > -10000 && y < 10000 && y > -10000;
|
||||||
case MouseButtonMacroAction:
|
case MouseButtonMacroAction:
|
||||||
const { mouseButtonsMask } = this.macroAction as MouseButtonMacroAction;
|
const {mouseButtonsMask} = this.macroAction as MouseButtonMacroAction;
|
||||||
return !!mouseButtonsMask;
|
return !!mouseButtonsMask;
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<div>
|
<div>
|
||||||
<h4>Type text</h4>
|
<h4>Type text</h4>
|
||||||
<p>Input the text you want to type with this macro action.</p>
|
|
||||||
<textarea #macroTextInput name="macro-text" (change)="onTextChange()"
|
<textarea #macroTextInput name="macro-text" (change)="onTextChange()"
|
||||||
(keyup)="validate()" class="macro__text-input">{{ macroAction?.text }}</textarea>
|
(keyup)="validate()" class="macro__text-input">{{ macroAction?.text }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
type="text"
|
type="text"
|
||||||
(change)="editMacroName($event.target.value)"
|
(change)="editMacroName($event.target.value)"
|
||||||
(keyup.enter)="macroName.blur()"
|
(keyup.enter)="macroName.blur()"
|
||||||
/>
|
(keyup)="calculateHeaderTextWidth($event.target.value)">
|
||||||
<i class="glyphicon glyphicon-trash macro__remove pull-right" title=""
|
<i class="glyphicon glyphicon-trash macro__remove pull-right" title=""
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip"
|
||||||
data-placement="bottom"
|
data-placement="bottom"
|
||||||
|
|||||||
@@ -32,7 +32,6 @@
|
|||||||
border-bottom: 2px dotted #999;
|
border-bottom: 2px dotted #999;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0 0.25rem;
|
margin: 0 0.25rem;
|
||||||
width: 330px;
|
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
Component,
|
Component,
|
||||||
ElementRef,
|
ElementRef,
|
||||||
|
HostListener,
|
||||||
Input,
|
Input,
|
||||||
OnChanges,
|
OnChanges,
|
||||||
Renderer2,
|
Renderer2,
|
||||||
@@ -13,7 +14,8 @@ import { Store } from '@ngrx/store';
|
|||||||
import { Macro } from 'uhk-common';
|
import { Macro } from 'uhk-common';
|
||||||
|
|
||||||
import { MacroActions } from '../../../store/actions';
|
import { MacroActions } from '../../../store/actions';
|
||||||
import { AppState } from '../../../store/index';
|
import { AppState } from '../../../store';
|
||||||
|
import * as util from '../../../util';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'macro-header',
|
selector: 'macro-header',
|
||||||
@@ -43,6 +45,11 @@ export class MacroHeaderComponent implements AfterViewInit, OnChanges {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@HostListener('window:resize')
|
||||||
|
windowResize(): void {
|
||||||
|
this.calculateHeaderTextWidth(this.macro.name);
|
||||||
|
}
|
||||||
|
|
||||||
removeMacro() {
|
removeMacro() {
|
||||||
this.store.dispatch(MacroActions.removeMacro(this.macro.id));
|
this.store.dispatch(MacroActions.removeMacro(this.macro.id));
|
||||||
}
|
}
|
||||||
@@ -60,12 +67,20 @@ export class MacroHeaderComponent implements AfterViewInit, OnChanges {
|
|||||||
this.store.dispatch(MacroActions.editMacroName(this.macro.id, name));
|
this.store.dispatch(MacroActions.editMacroName(this.macro.id, name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
calculateHeaderTextWidth(text): void {
|
||||||
|
const htmlInput = this.macroName.nativeElement as HTMLInputElement;
|
||||||
|
const maxWidth = htmlInput.parentElement.offsetWidth * 0.8;
|
||||||
|
const textWidth = util.getContentWidth(window.getComputedStyle(htmlInput), text);
|
||||||
|
this.renderer.setStyle(htmlInput, 'width', Math.min(maxWidth, textWidth) + 'px');
|
||||||
|
}
|
||||||
|
|
||||||
private setFocusOnName() {
|
private setFocusOnName() {
|
||||||
this.macroName.nativeElement.select();
|
this.macroName.nativeElement.select();
|
||||||
}
|
}
|
||||||
|
|
||||||
private setName(): void {
|
private setName(): void {
|
||||||
this.renderer.setProperty(this.macroName.nativeElement, 'value', this.macro.name);
|
this.renderer.setProperty(this.macroName.nativeElement, 'value', this.macro.name);
|
||||||
|
this.calculateHeaderTextWidth(this.macro.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
border-bottom: 1px solid #ddd;
|
border-bottom: 1px solid #ddd;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
icon {
|
icon {
|
||||||
margin: 0 5px;
|
margin: 0 5px;
|
||||||
|
|||||||
17
packages/uhk-web/src/app/util/html-helper.ts
Normal file
17
packages/uhk-web/src/app/util/html-helper.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
let canvas: HTMLCanvasElement;
|
||||||
|
|
||||||
|
export function getContentWidth(style: CSSStyleDeclaration, text: string): number {
|
||||||
|
if (!text) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!canvas) {
|
||||||
|
canvas = document.createElement('canvas');
|
||||||
|
}
|
||||||
|
|
||||||
|
const context = canvas.getContext('2d');
|
||||||
|
context.font = style.font;
|
||||||
|
const metrics = context.measureText(text);
|
||||||
|
|
||||||
|
return metrics.width;
|
||||||
|
}
|
||||||
1
packages/uhk-web/src/app/util/index.ts
Normal file
1
packages/uhk-web/src/app/util/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './html-helper';
|
||||||
Reference in New Issue
Block a user