diff --git a/config-serializer/config-items/Layer.ts b/config-serializer/config-items/Layer.ts index 97b0698b..21be0eaa 100644 --- a/config-serializer/config-items/Layer.ts +++ b/config-serializer/config-items/Layer.ts @@ -1,10 +1,12 @@ -import {Serializable} from '../Serializable'; -import {Modules} from './Modules'; -import {UhkBuffer} from '../UhkBuffer'; +import { Serializable } from '../Serializable'; +import { Modules } from './Modules'; +import { UhkBuffer } from '../UhkBuffer'; +import { AnimationKeyboard } from '../../src/components/svg/wrap'; export class Layer extends Serializable { modules: Modules; + animation: AnimationKeyboard = 'none'; _fromJsObject(jsObject: any): Layer { this.modules = new Modules().fromJsObject(jsObject.modules); diff --git a/config-serializer/uhk-config.json b/config-serializer/uhk-config.json index 083c2878..ec0ea54c 100644 --- a/config-serializer/uhk-config.json +++ b/config-serializer/uhk-config.json @@ -785,6 +785,25 @@ ] } ] + }, + { + "modules": [ + { + "id": 0, + "pointerRole": "scroll", + "keyActions": [] + }, + { + "id": 1, + "pointerRole": "move", + "keyActions": [ + { + "keyActionType": "keystroke", + "scancode": 111 + } + ] + } + ] } ] }, @@ -830,6 +849,63 @@ ] } ] + }, + { + "modules": [ + { + "id": 0, + "pointerRole": "scroll", + "keyActions": [] + }, + { + "id": 1, + "pointerRole": "move", + "keyActions": [ + { + "keyActionType": "keystroke", + "scancode": 111 + } + ] + } + ] + }, + { + "modules": [ + { + "id": 0, + "pointerRole": "scroll", + "keyActions": [] + }, + { + "id": 1, + "pointerRole": "move", + "keyActions": [ + { + "keyActionType": "keystroke", + "scancode": 111 + } + ] + } + ] + }, + { + "modules": [ + { + "id": 0, + "pointerRole": "scroll", + "keyActions": [] + }, + { + "id": 1, + "pointerRole": "move", + "keyActions": [ + { + "keyActionType": "keystroke", + "scancode": 111 + } + ] + } + ] } ] }, @@ -839,6 +915,48 @@ "abbreviation": "DVR", "name": "DVR", "layers": [ + { + "modules": [ + { + "id": 0, + "pointerRole": "move", + "keyActions": [] + }, + { + "id": 1, + "pointerRole": "move", + "keyActions": [] + } + ] + }, + { + "modules": [ + { + "id": 0, + "pointerRole": "move", + "keyActions": [] + }, + { + "id": 1, + "pointerRole": "move", + "keyActions": [] + } + ] + }, + { + "modules": [ + { + "id": 0, + "pointerRole": "move", + "keyActions": [] + }, + { + "id": 1, + "pointerRole": "move", + "keyActions": [] + } + ] + }, { "modules": [ { diff --git a/src/app.module.ts b/src/app.module.ts index f413800d..c546c282 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -13,6 +13,10 @@ import { MacroComponent } from './components/macro'; import { LegacyLoaderComponent } from './components/legacy-loader'; import { NotificationComponent } from './components/notification'; import { SvgKeystrokeKeyComponent, SvgOneLineTextKeyComponent, SvgTwoLineTextKeyComponent } from './components/svg/keys'; +import {SvgKeyboardWrapComponent} from './components/svg/wrap/svg-keyboard-wrap.component'; +import {LayersComponent} from './components/layers/layers.component'; +import {SvgKeyboardComponent} from './components/svg/keyboard/svg-keyboard.component'; +import {PopoverComponent} from './components/popover/popover.component'; @NgModule({ declarations: [ @@ -23,7 +27,11 @@ import { SvgKeystrokeKeyComponent, SvgOneLineTextKeyComponent, SvgTwoLineTextKey NotificationComponent, SvgKeystrokeKeyComponent, SvgOneLineTextKeyComponent, - SvgTwoLineTextKeyComponent + SvgTwoLineTextKeyComponent, + SvgKeyboardWrapComponent, + LayersComponent, + PopoverComponent, + SvgKeyboardComponent ], imports: [BrowserModule], providers: [ diff --git a/src/components/keymap/keymap.component.html b/src/components/keymap/keymap.component.html index 97e42a4a..36a1047c 100644 --- a/src/components/keymap/keymap.component.html +++ b/src/components/keymap/keymap.component.html @@ -9,29 +9,5 @@ data-toggle="tooltip" data-placement="left" data-original-title="Remove keymap"> -
-
- - - - - - -
-
- -
-
+ \ No newline at end of file diff --git a/src/components/keymap/keymap.component.scss b/src/components/keymap/keymap.component.scss index c5308be1..da3fcdcc 100644 --- a/src/components/keymap/keymap.component.scss +++ b/src/components/keymap/keymap.component.scss @@ -4,27 +4,6 @@ display: block; } -button { - margin: 2px; -} - -svg-keyboard-popover { - width: 95%; - max-width: 1400px; - position: absolute; - left: 50%; - transform: translateX(-50%); - animation-duration: 400ms; - animation-timing-function: ease-in-out; -} - -.keyboard-slider { - height: calc(100% - 45px); - position: relative; - overflow: hidden; - width: 100%; -} - .keymap { &__is-default { &.fa-star { @@ -70,53 +49,3 @@ svg-keyboard-popover { } } } - -.uhk { - &--wrapper { - height: calc(100% - 95px); - } - - &__layer-switcher { - &--wrapper { - position: relative; - margin-bottom: 2rem; - - &:before { - content: attr(data-title); - display: inline-block; - position: absolute; - bottom: -0.3em; - right: 100%; - font-size: 2.4rem; - padding-right: 0.25em; - margin: 0; - } - } - } -} - -@keyframes animate-center-left { - 0% { - transform: translateX(-50%); - left: 50%; - } - 100% { - transform: translateX(-100%); - left: 0; - } -} - -@keyframes animate-center-right { - 0% { - transform: translateX(-50%); - left: 50%; - } - 100% { - transform: translateX(0%); - left: 100%; - } -} - -[hidden] { - display: none; -} diff --git a/src/components/keymap/keymap.component.ts b/src/components/keymap/keymap.component.ts index fe0bd7b1..eb31e528 100644 --- a/src/components/keymap/keymap.component.ts +++ b/src/components/keymap/keymap.component.ts @@ -1,7 +1,6 @@ -import { Component, ViewChildren, QueryList, ElementRef, OnInit, AfterViewInit, Renderer } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { SvgKeyboardPopoverComponent } from '../svg/popover'; import { Layers } from '../../../config-serializer/config-items/Layers'; import { UhkConfigurationService } from '../../services/uhk-configuration.service'; import { Keymap } from '../../../config-serializer/config-items/Keymap'; @@ -11,37 +10,18 @@ import { Subscription } from 'rxjs/Subscription'; selector: 'keymap', template: require('./keymap.component.html'), styles: [require('./keymap.component.scss')], - directives: [SvgKeyboardPopoverComponent], providers: [UhkConfigurationService] }) -export class KeymapComponent implements OnInit, AfterViewInit { - @ViewChildren('baseButton,modButton,fnButton,mouseButton') - buttonsQueryList: QueryList; - - @ViewChildren(SvgKeyboardPopoverComponent, { read: ElementRef }) - keyboardsQueryList: QueryList; - - private buttons: ElementRef[]; - private keyboards: ElementRef[]; - private selectedLayerIndex: number; +export class KeymapComponent implements OnInit { private keymapId: number = 0; - private layers: Layers; private keymap: Keymap; - - private numAnimationInProgress: number; private subParams: Subscription; - private subQuery: Subscription; constructor( - private renderer: Renderer, private uhkConfigurationService: UhkConfigurationService, private route: ActivatedRoute ) { - this.buttons = []; - this.keyboards = []; - this.selectedLayerIndex = 0; - this.numAnimationInProgress = 0; } ngOnInit() { @@ -57,82 +37,7 @@ export class KeymapComponent implements OnInit, AfterViewInit { }); } - ngAfterViewInit() { - this.buttons = this.buttonsQueryList.toArray(); - this.afterView(); - - this.subQuery = this.keyboardsQueryList.changes.subscribe(() => { - this.afterView(); - }); - } - ngOnDestroy() { this.subParams.unsubscribe(); - this.subQuery.unsubscribe(); - } - - private afterView() { - this.keyboards = this.keyboardsQueryList.toArray(); - this.renderer.setElementAttribute(this.keyboards[0].nativeElement, 'hidden', undefined); - this.renderer.setElementClass(this.buttons[this.selectedLayerIndex].nativeElement, 'btn-primary', false); - this.renderer.setElementClass(this.buttons[0].nativeElement, 'btn-primary', true); - this.selectedLayerIndex = 0; - } - - /* tslint:disable:no-unused-variable */ - /* selectLayer is used in the template string */ - private selectLayer(index: number): void { - /* tslint:enable:no-unused-variable */ - if (this.selectedLayerIndex === index || index > this.keyboards.length - 1 || this.numAnimationInProgress > 0) { - return; - } - - this.renderer.setElementClass(this.buttons[this.selectedLayerIndex].nativeElement, 'btn-primary', false); - this.renderer.setElementClass(this.buttons[index].nativeElement, 'btn-primary', true); - - if (index > this.selectedLayerIndex) { - this.renderer.setElementStyle( - this.keyboards[this.selectedLayerIndex].nativeElement, - 'animation-name', - 'animate-center-left' - ); - this.renderer.setElementStyle( - this.keyboards[index].nativeElement, - 'animation-name', - 'animate-center-right' - ); - this.renderer.setElementStyle(this.keyboards[index].nativeElement, 'animation-direction', 'reverse'); - } else { - this.renderer.setElementStyle( - this.keyboards[this.selectedLayerIndex].nativeElement, - 'animation-name', - 'animate-center-right' - ); - this.renderer.setElementStyle(this.keyboards[index].nativeElement, 'animation-name', 'animate-center-left'); - this.renderer.setElementStyle(this.keyboards[index].nativeElement, 'animation-direction', 'reverse'); - } - this.numAnimationInProgress += 2; - - this.renderer.setElementAttribute(this.keyboards[index].nativeElement, 'hidden', undefined); - - this.selectedLayerIndex = index; - } - - /* tslint:disable:no-unused-variable */ - /* onKeyboardAnimationEnd is used in the template string */ - private onKeyboardAnimationEnd(event: AnimationEvent) { - /* tslint:enable:no-unused-variable */ - let animationNameTokens: string[] = event.animationName.split('-'); - let animationFrom: string = animationNameTokens[1]; - let animationTo: string = animationNameTokens[2]; - if ((event.target).style.animationDirection === 'reverse') { - animationFrom = animationNameTokens[2]; - animationTo = animationNameTokens[1]; - this.renderer.setElementStyle(event.target, 'animation-direction', undefined); - } - - --this.numAnimationInProgress; - this.renderer.setElementStyle(event.target, 'animation-name', undefined); - this.renderer.setElementAttribute(event.target, 'hidden', (animationTo === 'center') ? undefined : ''); } } diff --git a/src/components/layers/index.ts b/src/components/layers/index.ts new file mode 100644 index 00000000..2873e70d --- /dev/null +++ b/src/components/layers/index.ts @@ -0,0 +1 @@ +export * from './layers.component'; diff --git a/src/components/layers/layers.component.html b/src/components/layers/layers.component.html new file mode 100644 index 00000000..a4a5521f --- /dev/null +++ b/src/components/layers/layers.component.html @@ -0,0 +1,16 @@ +
+ + + + + + +
\ No newline at end of file diff --git a/src/components/layers/layers.component.scss b/src/components/layers/layers.component.scss new file mode 100644 index 00000000..620e5f26 --- /dev/null +++ b/src/components/layers/layers.component.scss @@ -0,0 +1,27 @@ +:host { + display: block; +} + +button { + margin: 2px; +} + +.uhk { + &__layer-switcher { + &--wrapper { + position: relative; + margin-bottom: 2rem; + + &:before { + content: attr(data-title); + display: inline-block; + position: absolute; + bottom: -0.3em; + right: 100%; + font-size: 2.4rem; + padding-right: 0.25em; + margin: 0; + } + } + } +} diff --git a/src/components/layers/layers.component.ts b/src/components/layers/layers.component.ts new file mode 100644 index 00000000..9c68cf7b --- /dev/null +++ b/src/components/layers/layers.component.ts @@ -0,0 +1,51 @@ +import { + Component, Output, EventEmitter, ElementRef, QueryList, ViewChildren, Renderer, Input +} from '@angular/core'; + +@Component({ + selector: 'layers', + template: require('./layers.component.html'), + styles: [require('./layers.component.scss')] +}) +export class LayersComponent { + @Input() current: number; + @Output() selected = new EventEmitter(); + + @ViewChildren('baseButton,modButton,fnButton,mouseButton') + buttonsQueryList: QueryList; + + private buttons: ElementRef[]; + private selectedLayerIndex: number; + + constructor(private renderer: Renderer) { + this.buttons = []; + this.selectedLayerIndex = 0; + } + + ngOnChanges() { + if (this.buttons.length > 0 && this.current !== this.selectedLayerIndex) { + this.buttons.forEach((button: ElementRef) => { + this.renderer.setElementClass(button.nativeElement, 'btn-primary', false); + }); + this.renderer.setElementClass(this.buttons[this.current].nativeElement, 'btn-primary', true); + this.selectedLayerIndex = 0; + } + } + + selectLayer(index: number) { + if (index === this.selectedLayerIndex) { + return; + } + + this.buttons = this.buttonsQueryList.toArray(); + this.selected.emit({ + oldIndex: this.selectedLayerIndex, + index: index + }); + + this.renderer.setElementClass(this.buttons[this.selectedLayerIndex].nativeElement, 'btn-primary', false); + this.renderer.setElementClass(this.buttons[index].nativeElement, 'btn-primary', true); + + this.selectedLayerIndex = index; + } +} diff --git a/src/components/popover/popover.component.scss b/src/components/popover/popover.component.scss index 5e7c9ca6..befdf1dd 100644 --- a/src/components/popover/popover.component.scss +++ b/src/components/popover/popover.component.scss @@ -3,6 +3,9 @@ flex-direction: column; max-width: none; padding: 0; + left: 50%; + transform: translateX(-50%); + top: 100px; } .popover-action { diff --git a/src/components/svg/popover/index.ts b/src/components/svg/popover/index.ts deleted file mode 100644 index 1697750e..00000000 --- a/src/components/svg/popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './svg-keyboard-popover.component'; diff --git a/src/components/svg/popover/svg-keyboard-popover.component.html b/src/components/svg/popover/svg-keyboard-popover.component.html deleted file mode 100644 index 19c7b515..00000000 --- a/src/components/svg/popover/svg-keyboard-popover.component.html +++ /dev/null @@ -1,4 +0,0 @@ - - - \ No newline at end of file diff --git a/src/components/svg/popover/svg-keyboard-popover.component.scss b/src/components/svg/popover/svg-keyboard-popover.component.scss deleted file mode 100644 index 1938a1a0..00000000 --- a/src/components/svg/popover/svg-keyboard-popover.component.scss +++ /dev/null @@ -1,6 +0,0 @@ -:host { - display: flex; - width: 100%; - height: 100%; - position: relative; -} diff --git a/src/components/svg/popover/svg-keyboard-popover.component.ts b/src/components/svg/popover/svg-keyboard-popover.component.ts deleted file mode 100644 index 38f1ca1a..00000000 --- a/src/components/svg/popover/svg-keyboard-popover.component.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Component, OnInit, Input} from '@angular/core'; - -import {Module} from '../../../../config-serializer/config-items/Module'; -import {KeyAction} from '../../../../config-serializer/config-items/KeyAction'; -import {SvgKeyboardComponent} from '../keyboard'; -import {PopoverComponent} from '../../popover'; - -@Component({ - selector: 'svg-keyboard-popover', - template: require('./svg-keyboard-popover.component.html'), - styles: [require('./svg-keyboard-popover.component.scss')], - directives: [SvgKeyboardComponent, PopoverComponent] -}) -export class SvgKeyboardPopoverComponent implements OnInit { - @Input() moduleConfig: Module[]; - - private popoverEnabled: boolean; - private keyEditConfig: { moduleId: number, keyId: number }; - private popoverInitKeyAction: KeyAction; - - constructor() { - this.keyEditConfig = { - moduleId: undefined, - keyId: undefined - }; - } - - ngOnInit() { } - - onKeyClick(moduleId: number, keyId: number): void { - if (!this.popoverEnabled) { - this.keyEditConfig = { - moduleId, - keyId - }; - - let keyActionToEdit: KeyAction = this.moduleConfig[moduleId].keyActions.elements[keyId]; - this.showPopover(keyActionToEdit); - } - } - - onRemap(keyAction: KeyAction): void { - this.changeKeyAction(keyAction); - this.hidePopover(); - } - - showPopover(keyAction?: KeyAction): void { - this.popoverInitKeyAction = keyAction; - this.popoverEnabled = true; - } - - hidePopover(): void { - this.popoverEnabled = false; - this.popoverInitKeyAction = undefined; - } - - changeKeyAction(keyAction: KeyAction): void { - let moduleId = this.keyEditConfig.moduleId; - let keyId = this.keyEditConfig.keyId; - this.moduleConfig[moduleId].keyActions.elements[keyId] = keyAction; - } - -} diff --git a/src/components/svg/wrap/animation.ts b/src/components/svg/wrap/animation.ts new file mode 100644 index 00000000..cca88c8c --- /dev/null +++ b/src/components/svg/wrap/animation.ts @@ -0,0 +1,6 @@ +export type AnimationKeyboard = + 'none' | + 'leftIn' | + 'leftOut' | + 'rightIn' | + 'rightOut'; diff --git a/src/components/svg/wrap/index.ts b/src/components/svg/wrap/index.ts new file mode 100644 index 00000000..3f099917 --- /dev/null +++ b/src/components/svg/wrap/index.ts @@ -0,0 +1,2 @@ +export * from './svg-keyboard-wrap.component'; +export * from './animation'; diff --git a/src/components/svg/wrap/svg-keyboard-wrap.component.html b/src/components/svg/wrap/svg-keyboard-wrap.component.html new file mode 100644 index 00000000..01dce6d2 --- /dev/null +++ b/src/components/svg/wrap/svg-keyboard-wrap.component.html @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/src/components/svg/wrap/svg-keyboard-wrap.component.scss b/src/components/svg/wrap/svg-keyboard-wrap.component.scss new file mode 100644 index 00000000..3debdd8c --- /dev/null +++ b/src/components/svg/wrap/svg-keyboard-wrap.component.scss @@ -0,0 +1,21 @@ +:host { + width: 100%; + height: 100%; + position: relative; + display: block; +} + +svg-keyboard { + width: 95%; + max-width: 1400px; + position: absolute; + left: 0; + transform: translateX(-100%); +} + +.keyboard-slider { + height: calc(100% - 145px); + position: relative; + overflow: hidden; + width: 100%; +} diff --git a/src/components/svg/wrap/svg-keyboard-wrap.component.ts b/src/components/svg/wrap/svg-keyboard-wrap.component.ts new file mode 100644 index 00000000..4f7abe24 --- /dev/null +++ b/src/components/svg/wrap/svg-keyboard-wrap.component.ts @@ -0,0 +1,153 @@ +import { + Component, Input, OnInit, style, + state, animate, transition, trigger +} from '@angular/core'; + +import { KeyAction } from '../../../../config-serializer/config-items/KeyAction'; +import { Layer } from '../../../../config-serializer/config-items/Layer'; + +@Component({ + selector: 'svg-keyboard-wrap', + template: require('./svg-keyboard-wrap.component.html'), + styles: [require('./svg-keyboard-wrap.component.scss')], + animations: [ + trigger('layerState', [ + /* Right -> Left animation*/ + state('leftIn', style({ + transform: 'translateX(-50%)', + left: '50%' + })), + state('leftOut', style({ + transform: 'translateX(-100%)', + left: '0' + })), + /* Right -> Left animation */ + state('rightIn', style({ + transform: 'translateX(-50%)', + left: '50%' + })), + state('rightOut', style({ + transform: 'translateX(0%)', + left: '100%' + })), + /* Transitions */ + transition('none => leftIn, leftOut => leftIn', [ + style({ + opacity: 0, + transform: 'translateX(0%)', + left: '100%' + }), + style({ + opacity: 1 + }), + animate('400ms ease-out') + ]), + transition('* => none', [ + style({ + opacity: 0, + transform: 'translateX(-100%)', + left: '0' + }), + style({ + opacity: 1 + }) + ]), + transition('none => rightIn, rightOut => rightIn', [ + style({ + opacity: 0, + transform: 'translateX(-100%)', + left: '0' + }), + style({ + opacity: 1 + }), + animate('400ms ease-out') + ]), + transition( + 'leftIn => leftOut,' + + 'rightIn => rightOut,' + + 'leftIn <=> rightOut,' + + 'rightIn <=> leftOut', + animate('400ms ease-out') + ) + ]) + ] +}) +export class SvgKeyboardWrapComponent implements OnInit { + @Input() layers: Layer[]; + @Input() popoverEnabled: boolean = true; + @Input() animationEnabled: boolean = true; + + private popoverShown: boolean; + private keyEditConfig: { moduleId: number, keyId: number }; + private popoverInitKeyAction: KeyAction; + private currentLayer: number = 0; + + constructor() { + this.keyEditConfig = { + moduleId: undefined, + keyId: undefined + }; + } + + ngOnInit() { + this.layers[0].animation = 'leftIn'; + } + + ngOnChanges() { + this.currentLayer = 0; + if (this.layers.length > 0) { + this.layers.forEach((element) => { + element.animation = 'none'; + + return element; + }); + this.layers[0].animation = 'leftIn'; + } + } + + onKeyClick(moduleId: number, keyId: number): void { + if (!this.popoverShown) { + this.keyEditConfig = { + moduleId, + keyId + }; + + let keyActionToEdit: KeyAction = this.layers[this.currentLayer].modules.elements[moduleId].keyActions.elements[keyId]; + this.showPopover(keyActionToEdit); + } + } + + onRemap(keyAction: KeyAction): void { + this.changeKeyAction(keyAction); + this.hidePopover(); + } + + showPopover(keyAction?: KeyAction): void { + this.popoverInitKeyAction = keyAction; + this.popoverShown = true; + } + + hidePopover(): void { + this.popoverShown = false; + this.popoverInitKeyAction = undefined; + } + + changeKeyAction(keyAction: KeyAction): void { + let moduleId = this.keyEditConfig.moduleId; + let keyId = this.keyEditConfig.keyId; + this.layers[this.currentLayer].modules.elements[moduleId].keyActions.elements[keyId] = keyAction; + } + + selectLayer(oldIndex: number, index: number): void { + if (index > oldIndex) { + this.layers[oldIndex].animation = 'leftOut'; + this.layers[index].animation = 'leftIn'; + } else { + this.layers[oldIndex].animation = 'rightOut'; + this.layers[index].animation = 'rightIn'; + } + + this.currentLayer = index; + } +}