Disable button when action is not valid in popover (#244)

Resolves #161
This commit is contained in:
Nejc Zdovc
2016-12-31 13:19:20 +01:00
committed by József Farkas
parent cc9081fe81
commit 52fd854e92
10 changed files with 91 additions and 43 deletions

View File

@@ -47,16 +47,36 @@
</ul> </ul>
</div> </div>
<div [ngSwitch]="activeTab"> <div [ngSwitch]="activeTab">
<keypress-tab #tab *ngSwitchCase="tabName.Keypress" class="popover-content" [defaultKeyAction]="defaultKeyAction" [longPressEnabled]="true"></keypress-tab> <keypress-tab #tab *ngSwitchCase="tabName.Keypress" class="popover-content"
<layer-tab #tab *ngSwitchCase="tabName.Layer" class="popover-content" [defaultKeyAction]="defaultKeyAction" [currentLayer]="currentLayer"></layer-tab> [defaultKeyAction]="defaultKeyAction"
<mouse-tab #tab *ngSwitchCase="tabName.Mouse" class="popover-content" [defaultKeyAction]="defaultKeyAction"></mouse-tab> [longPressEnabled]="true"
<macro-tab #tab *ngSwitchCase="tabName.Macro" class="popover-content" [defaultKeyAction]="defaultKeyAction"></macro-tab> (validAction)="keyActionValid=$event"
<keymap-tab #tab *ngSwitchCase="tabName.Keymap" class="popover-content" [defaultKeyAction]="defaultKeyAction" [keymaps]="keymaps$ | async"></keymap-tab> ></keypress-tab>
<none-tab #tab *ngSwitchCase="tabName.None" class="popover-content"></none-tab> <layer-tab #tab *ngSwitchCase="tabName.Layer" class="popover-content"
[defaultKeyAction]="defaultKeyAction"
[currentLayer]="currentLayer"
(validAction)="keyActionValid=$event"
></layer-tab>
<mouse-tab #tab *ngSwitchCase="tabName.Mouse" class="popover-content"
[defaultKeyAction]="defaultKeyAction"
(validAction)="keyActionValid=$event"
></mouse-tab>
<macro-tab #tab *ngSwitchCase="tabName.Macro" class="popover-content"
[defaultKeyAction]="defaultKeyAction"
(validAction)="keyActionValid=$event"
></macro-tab>
<keymap-tab #tab *ngSwitchCase="tabName.Keymap" class="popover-content"
[defaultKeyAction]="defaultKeyAction"
[keymaps]="keymaps$ | async"
(validAction)="keyActionValid=$event"
></keymap-tab>
<none-tab #tab *ngSwitchCase="tabName.None" class="popover-content"
(validAction)="keyActionValid=$event"
></none-tab>
</div> </div>
<div class="popover-action"> <div class="popover-action">
<button class="btn btn-sm btn-default" type="button" (click)="onCancelClick()"> Cancel </button> <button class="btn btn-sm btn-default" type="button" (click)="onCancelClick()"> Cancel </button>
<button class="btn btn-sm btn-primary" type="button" (click)="onRemapKey()"> Remap Key </button> <button class="btn btn-sm btn-primary" [class.disabled]="!keyActionValid" type="button" (click)="onRemapKey()"> Remap Key </button>
</div> </div>
</div> </div>
<div class="popover-overlay" [class.display]="visible" (click)="onOverlay()"></div> <div class="popover-overlay" [class.display]="visible" (click)="onOverlay()"></div>

View File

@@ -79,6 +79,7 @@ export class PopoverComponent implements OnChanges {
@ViewChild('popover') popoverHost: ElementRef; @ViewChild('popover') popoverHost: ElementRef;
public tabName = TabName; public tabName = TabName;
public keyActionValid: boolean;
private activeTab: TabName; private activeTab: TabName;
private keymaps$: Observable<Keymap[]>; private keymaps$: Observable<Keymap[]>;
private leftArrow: boolean = false; private leftArrow: boolean = false;
@@ -134,16 +135,19 @@ export class PopoverComponent implements OnChanges {
} }
onRemapKey(): void { onRemapKey(): void {
try { if (this.keyActionValid) {
let keyAction = this.selectedTab.toKeyAction(); try {
this.remap.emit(keyAction); let keyAction = this.selectedTab.toKeyAction();
} catch (e) { this.remap.emit(keyAction);
// TODO: show error dialog } catch (e) {
console.error(e); // TODO: show error dialog
console.error(e);
}
} }
} }
@HostListener('keydown.escape') onEscape(): void { @HostListener('keydown.escape')
onEscape(): void {
this.cancel.emit(); this.cancel.emit();
} }

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, Input, OnChanges, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core';
import { Select2OptionData } from 'ng2-select2/ng2-select2'; import { Select2OptionData } from 'ng2-select2/ng2-select2';
@@ -12,7 +12,7 @@ import { Tab } from '../tab';
styles: [require('./keymap-tab.component.scss')], styles: [require('./keymap-tab.component.scss')],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class KeymapTabComponent implements OnInit, OnChanges, Tab { export class KeymapTabComponent extends Tab implements OnInit, OnChanges {
@Input() defaultKeyAction: KeyAction; @Input() defaultKeyAction: KeyAction;
@Input() keymaps: Keymap[]; @Input() keymaps: Keymap[];
@@ -20,6 +20,7 @@ export class KeymapTabComponent implements OnInit, OnChanges, Tab {
private selectedKeymap: Keymap; private selectedKeymap: Keymap;
constructor() { constructor() {
super();
this.keymapOptions = []; this.keymapOptions = [];
} }
@@ -38,6 +39,7 @@ export class KeymapTabComponent implements OnInit, OnChanges, Tab {
ngOnChanges() { ngOnChanges() {
this.fromKeyAction(this.defaultKeyAction); this.fromKeyAction(this.defaultKeyAction);
this.validAction.emit(true);
} }
// TODO: change to the correct type when the wrapper has added it. // TODO: change to the correct type when the wrapper has added it.

View File

@@ -1,4 +1,4 @@
import { Component, Input, OnChanges } from '@angular/core'; import { Component, Input, EventEmitter, OnChanges, Output } from '@angular/core';
import { Select2OptionData, Select2TemplateFunction } from 'ng2-select2'; import { Select2OptionData, Select2TemplateFunction } from 'ng2-select2';
@@ -12,7 +12,7 @@ import { MapperService } from '../../../../services/mapper.service';
template: require('./keypress-tab.component.html'), template: require('./keypress-tab.component.html'),
styles: [require('./keypress-tab.component.scss')] styles: [require('./keypress-tab.component.scss')]
}) })
export class KeypressTabComponent implements OnChanges, Tab { export class KeypressTabComponent extends Tab implements OnChanges {
@Input() defaultKeyAction: KeyAction; @Input() defaultKeyAction: KeyAction;
@Input() longPressEnabled: boolean; @Input() longPressEnabled: boolean;
@@ -30,6 +30,7 @@ export class KeypressTabComponent implements OnChanges, Tab {
private selectedLongPressIndex: number; private selectedLongPressIndex: number;
constructor(private mapper: MapperService) { constructor(private mapper: MapperService) {
super();
this.leftModifiers = ['LShift', 'LCtrl', 'LSuper', 'LAlt']; this.leftModifiers = ['LShift', 'LCtrl', 'LSuper', 'LAlt'];
this.rightModifiers = ['RShift', 'RCtrl', 'RSuper', 'RAlt']; this.rightModifiers = ['RShift', 'RCtrl', 'RSuper', 'RAlt'];
this.scanCodeGroups = [{ this.scanCodeGroups = [{
@@ -58,13 +59,15 @@ export class KeypressTabComponent implements OnChanges, Tab {
ngOnChanges() { ngOnChanges() {
this.fromKeyAction(this.defaultKeyAction); this.fromKeyAction(this.defaultKeyAction);
this.validAction.emit(this.keyActionValid());
} }
keyActionValid(keystrokeAction?: KeystrokeAction): boolean { keyActionValid(keystrokeAction?: KeystrokeAction): boolean {
if (!keystrokeAction) { if (!keystrokeAction) {
keystrokeAction = this.toKeyAction(); keystrokeAction = this.toKeyAction();
} }
return keystrokeAction.scancode > 0 || keystrokeAction.modifierMask > 0;
return (keystrokeAction) ? (keystrokeAction.scancode > 0 || keystrokeAction.modifierMask > 0) : false;
} }
onKeysCapture(event: {code: number, left: boolean[], right: boolean[]}) { onKeysCapture(event: {code: number, left: boolean[], right: boolean[]}) {
@@ -76,6 +79,7 @@ export class KeypressTabComponent implements OnChanges, Tab {
this.leftModifierSelects = event.left; this.leftModifierSelects = event.left;
this.rightModifierSelects = event.right; this.rightModifierSelects = event.right;
this.validAction.emit(this.keyActionValid());
} }
fromKeyAction(keyAction: KeyAction): boolean { fromKeyAction(keyAction: KeyAction): boolean {
@@ -120,11 +124,9 @@ export class KeypressTabComponent implements OnChanges, Tab {
? undefined ? undefined
: this.mapper.modifierMapper(this.selectedLongPressIndex); : this.mapper.modifierMapper(this.selectedLongPressIndex);
if (!this.keyActionValid(keystrokeAction)) { if (this.keyActionValid(keystrokeAction)) {
throw new Error('KeyAction is invalid!'); return keystrokeAction;
} }
return keystrokeAction;
} }
scanCodeTemplateResult: Select2TemplateFunction = (state: Select2OptionData): JQuery | string => { scanCodeTemplateResult: Select2TemplateFunction = (state: Select2OptionData): JQuery | string => {
@@ -149,6 +151,8 @@ export class KeypressTabComponent implements OnChanges, Tab {
toggleModifier(right: boolean, index: number) { toggleModifier(right: boolean, index: number) {
let modifierSelects: boolean[] = right ? this.rightModifierSelects : this.leftModifierSelects; let modifierSelects: boolean[] = right ? this.rightModifierSelects : this.leftModifierSelects;
modifierSelects[index] = !modifierSelects[index]; modifierSelects[index] = !modifierSelects[index];
this.validAction.emit(this.keyActionValid());
} }
onLongpressChange(event: {value: string}) { onLongpressChange(event: {value: string}) {
@@ -157,5 +161,6 @@ export class KeypressTabComponent implements OnChanges, Tab {
onScancodeChange(event: {value: string}) { onScancodeChange(event: {value: string}) {
this.scanCode = +event.value; this.scanCode = +event.value;
this.validAction.emit(this.keyActionValid());
} }
} }

View File

@@ -1,4 +1,4 @@
import { Component, HostBinding, Input, OnChanges, SimpleChanges } from '@angular/core'; import { Component, EventEmitter, HostBinding, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { KeyAction, LayerName, SwitchLayerAction } from '../../../../config-serializer/config-items/key-action'; import { KeyAction, LayerName, SwitchLayerAction } from '../../../../config-serializer/config-items/key-action';
@@ -9,7 +9,7 @@ import { Tab } from '../tab';
template: require('./layer-tab.component.html'), template: require('./layer-tab.component.html'),
styles: [require('./layer-tab.component.scss')] styles: [require('./layer-tab.component.scss')]
}) })
export class LayerTabComponent implements OnChanges, Tab { export class LayerTabComponent extends Tab implements OnChanges {
@Input() defaultKeyAction: KeyAction; @Input() defaultKeyAction: KeyAction;
@Input() currentLayer: number; @Input() currentLayer: number;
@@ -45,6 +45,7 @@ export class LayerTabComponent implements OnChanges, Tab {
private layer: LayerName; private layer: LayerName;
constructor() { constructor() {
super();
this.toggle = false; this.toggle = false;
this.layer = LayerName.mod; this.layer = LayerName.mod;
} }
@@ -57,6 +58,8 @@ export class LayerTabComponent implements OnChanges, Tab {
if (changes['currentLayer']) { if (changes['currentLayer']) {
this.isNotBase = this.currentLayer > 0; this.isNotBase = this.currentLayer > 0;
} }
this.validAction.emit(true);
} }
keyActionValid(): boolean { keyActionValid(): boolean {

View File

@@ -1,4 +1,4 @@
import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output } from '@angular/core';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
@@ -19,7 +19,7 @@ import { getMacroEntities } from '../../../../store/reducers/macro';
template: require('./macro-tab.component.html'), template: require('./macro-tab.component.html'),
styles: [require('./macro-tab.component.scss')] styles: [require('./macro-tab.component.scss')]
}) })
export class MacroTabComponent implements OnInit, OnChanges, OnDestroy, Tab { export class MacroTabComponent extends Tab implements OnInit, OnChanges, OnDestroy {
@Input() defaultKeyAction: KeyAction; @Input() defaultKeyAction: KeyAction;
private macros: Macro[]; private macros: Macro[];
@@ -28,6 +28,7 @@ export class MacroTabComponent implements OnInit, OnChanges, OnDestroy, Tab {
private subscription: Subscription; private subscription: Subscription;
constructor(private store: Store<AppState>) { constructor(private store: Store<AppState>) {
super();
this.subscription = store.let(getMacroEntities()) this.subscription = store.let(getMacroEntities())
.subscribe((macros: Macro[]) => this.macros = macros); .subscribe((macros: Macro[]) => this.macros = macros);
this.macroOptions = []; this.macroOptions = [];
@@ -45,6 +46,7 @@ export class MacroTabComponent implements OnInit, OnChanges, OnDestroy, Tab {
ngOnChanges() { ngOnChanges() {
this.fromKeyAction(this.defaultKeyAction); this.fromKeyAction(this.defaultKeyAction);
this.validAction.emit(true);
} }
// TODO: change to the correct type when the wrapper has added it. // TODO: change to the correct type when the wrapper has added it.

View File

@@ -86,20 +86,20 @@
<p>Press this key along with mouse movement/scrolling to accelerate/decelerate the speed of the action.</p> <p>Press this key along with mouse movement/scrolling to accelerate/decelerate the speed of the action.</p>
</div> </div>
<div class="btn-group btn-group-lg" role="group"> <div class="btn-group btn-group-lg" role="group">
<div class="btn btn-default" <button class="btn btn-default"
[class.btn-primary]="mouseActionParam === MouseActionParam.decelerate" [class.btn-primary]="mouseActionParam === MouseActionParam.decelerate"
(click)="setMouseActionParam(MouseActionParam.decelerate)" (click)="setMouseActionParam(MouseActionParam.decelerate)"
> >
- -
<span>Decelerate</span> <span>Decelerate</span>
</div> </button>
<div class="btn btn-default" <button class="btn btn-default"
[class.btn-primary]="mouseActionParam === MouseActionParam.accelerate" [class.btn-primary]="mouseActionParam === MouseActionParam.accelerate"
(click)="setMouseActionParam(MouseActionParam.accelerate)" (click)="setMouseActionParam(MouseActionParam.accelerate)"
> >
+ +
<span>Accelerate</span> <span>Accelerate</span>
</div> </button>
</div> </div>
<div class="help-text--mouse-speed last-help text-left"> <div class="help-text--mouse-speed last-help text-left">
<p>You can set the multiplier in the <a [routerLink]="['/settings']" title="Settings">settings</a>.</p> <p>You can set the multiplier in the <a [routerLink]="['/settings']" title="Settings">settings</a>.</p>

View File

@@ -1,4 +1,4 @@
import { Component, Input, OnChanges } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core';
import { KeyAction, MouseAction, MouseActionParam } from '../../../../config-serializer/config-items/key-action'; import { KeyAction, MouseAction, MouseActionParam } from '../../../../config-serializer/config-items/key-action';
import { Tab } from '../tab'; import { Tab } from '../tab';
@@ -8,7 +8,7 @@ import { Tab } from '../tab';
template: require('./mouse-tab.component.html'), template: require('./mouse-tab.component.html'),
styles: [require('./mouse-tab.component.scss')] styles: [require('./mouse-tab.component.scss')]
}) })
export class MouseTabComponent implements OnChanges, Tab { export class MouseTabComponent extends Tab implements OnChanges {
@Input() defaultKeyAction: KeyAction; @Input() defaultKeyAction: KeyAction;
private mouseActionParam: MouseActionParam; private mouseActionParam: MouseActionParam;
@@ -21,12 +21,14 @@ export class MouseTabComponent implements OnChanges, Tab {
private pages: string[]; private pages: string[];
constructor() { constructor() {
super();
this.selectedPageIndex = 0; this.selectedPageIndex = 0;
this.pages = ['Move', 'Scroll', 'Click', 'Speed']; this.pages = ['Move', 'Scroll', 'Click', 'Speed'];
} }
ngOnChanges() { ngOnChanges() {
this.fromKeyAction(this.defaultKeyAction); this.fromKeyAction(this.defaultKeyAction);
this.validAction.emit(this.keyActionValid());
} }
keyActionValid(): boolean { keyActionValid(): boolean {
@@ -37,12 +39,14 @@ export class MouseTabComponent implements OnChanges, Tab {
if (!(keyAction instanceof MouseAction)) { if (!(keyAction instanceof MouseAction)) {
return false; return false;
} }
let mouseAction: MouseAction = <MouseAction>keyAction; let mouseAction: MouseAction = <MouseAction>keyAction;
this.mouseActionParam = mouseAction.mouseAction; this.mouseActionParam = mouseAction.mouseAction;
if (mouseAction.mouseAction === MouseActionParam.moveUp) { if (mouseAction.mouseAction === MouseActionParam.moveUp) {
this.selectedPageIndex = 0; this.selectedPageIndex = 0;
} }
switch (mouseAction.mouseAction) { switch (mouseAction.mouseAction) {
case MouseActionParam.moveDown: case MouseActionParam.moveDown:
case MouseActionParam.moveUp: case MouseActionParam.moveUp:
@@ -68,13 +72,11 @@ export class MouseTabComponent implements OnChanges, Tab {
default: default:
return false; return false;
} }
return true; return true;
} }
toKeyAction(): MouseAction { toKeyAction(): MouseAction {
if (!this.keyActionValid()) {
throw new Error('KeyAction is not valid. No selected mouse action!');
}
let mouseAction: MouseAction = new MouseAction(); let mouseAction: MouseAction = new MouseAction();
mouseAction.mouseAction = this.mouseActionParam; mouseAction.mouseAction = this.mouseActionParam;
return mouseAction; return mouseAction;
@@ -85,12 +87,14 @@ export class MouseTabComponent implements OnChanges, Tab {
console.error(`Invalid index error: ${index}`); console.error(`Invalid index error: ${index}`);
return; return;
} }
this.selectedPageIndex = index; this.selectedPageIndex = index;
this.mouseActionParam = undefined; this.mouseActionParam = undefined;
this.validAction.emit(false);
} }
setMouseActionParam(mouseActionParam: MouseActionParam) { setMouseActionParam(mouseActionParam: MouseActionParam) {
this.mouseActionParam = mouseActionParam; this.mouseActionParam = mouseActionParam;
this.validAction.emit(true);
} }
} }

View File

@@ -1,4 +1,4 @@
import { Component } from '@angular/core'; import { Component, EventEmitter, OnChanges, Output } from '@angular/core';
import { Tab } from '../tab'; import { Tab } from '../tab';
@@ -7,7 +7,11 @@ import { Tab } from '../tab';
template: require('./none-tab.component.html'), template: require('./none-tab.component.html'),
styles: [require('./none-tab.component.scss')] styles: [require('./none-tab.component.scss')]
}) })
export class NoneTabComponent implements Tab { export class NoneTabComponent extends Tab implements OnChanges {
ngOnChanges(event: any) {
this.validAction.emit(true);
}
keyActionValid(): boolean { keyActionValid(): boolean {
return true; return true;
} }

View File

@@ -1,7 +1,11 @@
import { EventEmitter, Output } from '@angular/core';
import { KeyAction } from '../../../config-serializer/config-items/key-action'; import { KeyAction } from '../../../config-serializer/config-items/key-action';
export interface Tab { export abstract class Tab {
keyActionValid(): boolean; @Output() validAction = new EventEmitter<boolean>();
fromKeyAction(keyAction: KeyAction): boolean;
toKeyAction(): KeyAction; abstract keyActionValid(): boolean;
abstract fromKeyAction(keyAction: KeyAction): boolean;
abstract toKeyAction(): KeyAction;
} }