Add keymap page (#80)

This commit is contained in:
Nejc Zdovc
2016-08-29 21:51:30 +02:00
committed by József Farkas
parent bb3a2d77b6
commit dee9c1077b
20 changed files with 1258 additions and 34 deletions

View File

@@ -10,11 +10,15 @@ import { KeymapComponent } from './components/keymap';
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';
import {
SvgKeystrokeKeyComponent, SvgOneLineTextKeyComponent, SvgTwoLineTextKeyComponent
} from './components/svg/keys';
import { SvgKeyboardWrapComponent } from './components/svg/wrap';
import { LayersComponent } from './components/layers';
import { SvgKeyboardComponent } from './components/svg/keyboard';
import { PopoverComponent } from './components/popover';
import { KeymapAddComponent } from './components/keymap';
import {UhkConfigurationService} from './services/uhk-configuration.service';
@NgModule({
declarations: [
@@ -29,11 +33,13 @@ import {PopoverComponent} from './components/popover/popover.component';
SvgKeyboardWrapComponent,
LayersComponent,
PopoverComponent,
SvgKeyboardComponent
SvgKeyboardComponent,
KeymapAddComponent
],
imports: [BrowserModule],
providers: [
DataProviderService,
UhkConfigurationService,
MapperService,
APP_ROUTER_PROVIDERS,
{ provide: LocationStrategy, useClass: HashLocationStrategy }

View File

@@ -0,0 +1,32 @@
<h1>
<i class="fa fa-keyboard-o"></i>
<span>Add new keymap</span>
</h1>
<div class="keymap__search clearfix">
<div class="input-group">
<span class="input-group-addon" id="sizing-addon1">
<i class="fa fa-search"></i>
</span>
<input type="text" class="form-control" placeholder="Search ..." (input)="filterKeyboards($event.target.value)">
</div>
<div class="keymap__search_amount">
{{ keymaps.length }} / {{ keymapsAll.length }} keymaps shown
</div>
</div>
<div class="keymap__list">
<div #keyboard class="keymap__list_item" *ngFor="let keymap of keymaps">
<h2>{{ keymap.name }}</h2>
<p class="keymap__description">
{{ keymap.description }}
</p>
<svg-keyboard-wrap
[layers]="keymap.layers.elements"
[popoverEnabled]="false"
[tooltipEnabled]="true"
>
</svg-keyboard-wrap>
<div class="btn-group btn-group-lg">
<button class="btn btn-default">Add keymap</button>
</div>
</div>
</div>

View File

@@ -0,0 +1,61 @@
:host {
overflow-y: auto;
display: block;
height: 100%;
}
.uhk__layer-switcher--wrapper {
position: relative;
&: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;
}
}
.keymap {
&__search {
margin-top: 10px;
.input-group {
width: 100%;
max-width: 350px;
float: left;
}
&_amount {
float: left;
margin: 7px 0 0 20px;
}
}
&__description {
margin-bottom: 20px;
}
&__list {
margin-top: 40px;
&_item {
margin-bottom: 50px;
}
.btn-group-lg {
margin: 30px 0 0;
width: 100%;
text-align: center;
.btn {
float: none;
padding-left: 50px;
padding-right: 50px;
}
}
}
}

View File

@@ -0,0 +1,27 @@
import { Component } from '@angular/core';
import { Keymap } from '../../../config-serializer/config-items/Keymap';
import { Keymaps } from '../../../config-serializer/config-items/Keymaps';
import {DataProviderService} from '../../../services/data-provider.service';
@Component({
selector: 'keymap-add',
template: require('./keymap-add.component.html'),
styles: [require('./keymap-add.component.scss')]
})
export class KeymapAddComponent {
private keymaps: Keymap[];
private keymapsAll: Keymap[];
private currentKeyboards: number;
constructor(data: DataProviderService) {
let json: any = data.getDefaultKeymaps();
let all: Keymaps = new Keymaps().fromJsObject(json.keymaps);
this.keymaps = all.elements;
this.keymapsAll = this.keymaps.slice(0);
this.currentKeyboards = this.keymaps.length;
}
filterKeyboards(value: string) {
this.keymaps = this.keymapsAll.filter((item: Keymap) => item.name.toLocaleLowerCase().indexOf(value) !== -1);
}
}

View File

@@ -1,2 +1,3 @@
export * from './keymap.component';
export * from './keymap.routes';
export * from './add/keymap-add.component';

View File

@@ -9,8 +9,7 @@ import { Subscription } from 'rxjs/Subscription';
@Component({
selector: 'keymap',
template: require('./keymap.component.html'),
styles: [require('./keymap.component.scss')],
providers: [UhkConfigurationService]
styles: [require('./keymap.component.scss')]
})
export class KeymapComponent implements OnInit {
private keymapId: number = 0;

View File

@@ -1,5 +1,6 @@
import { RouterConfig } from '@angular/router';
import { KeymapComponent } from './keymap.component';
import { KeymapAddComponent } from './add/keymap-add.component';
export const keymapRoutes: RouterConfig = [
{
@@ -11,6 +12,10 @@ export const keymapRoutes: RouterConfig = [
path: 'keymap',
component: KeymapComponent
},
{
path: 'keymap/add',
component: KeymapAddComponent
},
{
path: 'keymap/:id',
component: KeymapComponent

View File

@@ -2,7 +2,7 @@
<li class="sidebar__level-1--item">
<div class="sidebar__level-1">
<i class="fa fa-keyboard-o"></i> Keymaps
<a href="#" class="btn btn-default pull-right btn-sm">
<a [routerLink]="['/keymap/add']" class="btn btn-default pull-right btn-sm">
<i class="fa fa-plus"></i>
</a>
<i class="fa fa-chevron-up pull-right" (click)="toggleHide($event, keymapElement)"></i>

View File

@@ -9,7 +9,6 @@ import { ROUTER_DIRECTIVES } from '@angular/router';
selector: 'side-menu',
template: require('./side-menu.component.html'),
styles: [require('./side-menu.component.scss')],
providers: [UhkConfigurationService],
directives: [ROUTER_DIRECTIVES]
})
export class SideMenuComponent implements OnInit {

View File

@@ -5,7 +5,8 @@
[keyboardKeys]="module.keyboardKeys"
[attr.transform]="module.attributes.transform"
[keyActions]="moduleConfig[i].keyActions.elements"
(editKeyActionRequest)="onEditKeyActionRequest(i, $event)"
(keyClick)="onKeyClick(i, $event)"
(keyHover)="onKeyHover($event.index, $event.event, $event.over, i)"
/>
</svg:g>
</svg>

Before

Width:  |  Height:  |  Size: 602 B

After

Width:  |  Height:  |  Size: 662 B

View File

@@ -13,6 +13,7 @@ import {DataProviderService} from '../../../services/data-provider.service';
export class SvgKeyboardComponent implements OnInit {
@Input() moduleConfig: Module[];
@Output() keyClick = new EventEmitter();
@Output() keyHover = new EventEmitter();
private modules: SvgModule[];
private svgAttributes: { viewBox: string, transform: string, fill: string };
@@ -26,11 +27,20 @@ export class SvgKeyboardComponent implements OnInit {
this.modules = this.dps.getSvgModules();
}
onEditKeyActionRequest(moduleId: number, keyId: number): void {
onKeyClick(moduleId: number, keyId: number): void {
this.keyClick.emit({
moduleId,
keyId
});
}
onKeyHover(keyId: number, event: MouseEvent, over: boolean, moduleId: number): void {
this.keyHover.emit({
moduleId,
event,
over,
keyId
});
}
}

View File

@@ -6,5 +6,6 @@
[attr.transform]="'translate(' + key.x + ' ' + key.y + ')'"
[keyAction]="keyActions[i]"
(click)="onKeyClick(i)"
/>
<popover *ngIf="popOverEnabled"></popover>
(mouseover)="onKeyHover(i, $event, true)"
(mouseleave)="onKeyHover(i, $event, false)"
/>

Before

Width:  |  Height:  |  Size: 424 B

After

Width:  |  Height:  |  Size: 483 B

View File

@@ -1,4 +1,4 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { SvgKeyboardKey, SvgKeyboardKeyComponent } from '../keys';
import {KeyAction} from '../../../config-serializer/config-items/KeyAction';
@@ -9,20 +9,27 @@ import {KeyAction} from '../../../config-serializer/config-items/KeyAction';
styles: [require('./svg-module.component.scss')],
directives: [SvgKeyboardKeyComponent]
})
export class SvgModuleComponent implements OnInit {
export class SvgModuleComponent {
@Input() coverages: any[];
@Input() keyboardKeys: SvgKeyboardKey[];
@Input() keyActions: KeyAction[];
@Output() editKeyActionRequest = new EventEmitter<number>();
@Output() keyClick = new EventEmitter<number>();
@Output() keyHover = new EventEmitter();
constructor() {
this.keyboardKeys = [];
}
ngOnInit() { }
onKeyClick(index: number): void {
this.editKeyActionRequest.emit(index);
this.keyClick.emit(index);
}
onKeyHover(index: number, event: MouseEvent, over: boolean): void {
this.keyHover.emit({
index,
event,
over
});
}
}

View File

@@ -1,12 +1,25 @@
<template ngIf="layers">
<layers (select)="selectLayer($event.oldIndex, $event.index)" [current]="currentLayer"></layers>
<div class="keyboard-slider" >
<div class="keyboard-slider" (mouseout)="hideTooltip($event)">
<svg-keyboard *ngFor="let layer of layers"
[@layerState]="layer.animation"
[moduleConfig]="layer.modules.elements"
(keyClick)="onKeyClick($event.moduleId, $event.keyId)"
(keyHover)="onKeyHover($event.moduleId, $event.event, $event.over, $event.keyId)"
>
</svg-keyboard>
</div>
<popover *ngIf="popoverShown && popoverEnabled" [defaultKeyAction]="popoverInitKeyAction" (cancel)="hidePopover()" (remap)="onRemap($event)"></popover>
<popover *ngIf="popoverShown" [defaultKeyAction]="popoverInitKeyAction" (cancel)="hidePopover()" (remap)="onRemap($event)"></popover>
<div class="tooltip top fade" role="tooltip"
[class.in]="tooltipData.shown"
[style.top.px]="tooltipData.posTop"
[style.left.px]="tooltipData.posLeft"
>
<div class="tooltip-arrow"></div>
<div class="tooltip-inner">
<p *ngFor="let item of tooltipData.content">
{{ item.name }}: {{ item.value }}
</p>
</div>
</div>
</template>

View File

@@ -10,12 +10,42 @@ svg-keyboard {
max-width: 1400px;
position: absolute;
left: 0;
transform: translateX(-100%);
transform: translateX(-101%);
}
.keyboard-slider {
height: calc(100% - 145px);
position: relative;
overflow: hidden;
width: 100%;
/* TODO create dynamic */
height: 500px;
margin-top: 30px;
}
.tooltip {
position: fixed;
transform: translate(-50%, -85%);
&-inner {
background: #fff;
color: #000;
box-shadow: 0 1px 5px #000;
text-align: left;
p {
margin-bottom: 2px;
&:last-of-type {
margin-bottom: 0;
}
}
}
&.top {
.tooltip-arrow {
border-top-color: #fff;
}
}
&.in {
opacity: 1;
}
}

View File

@@ -1,15 +1,17 @@
import {
Component, Input, OnInit, style,
state, animate, transition, trigger
state, animate, transition, trigger, OnChanges
} from '@angular/core';
import { KeyAction } from '../../../config-serializer/config-items/KeyAction';
import { Layer } from '../../../config-serializer/config-items/Layer';
import { NoneAction } from '../../../config-serializer/config-items/NoneAction';
@Component({
selector: 'svg-keyboard-wrap',
template: require('./svg-keyboard-wrap.component.html'),
styles: [require('./svg-keyboard-wrap.component.scss')],
// We use 101%, because there was still a trace of the keyboard in the screen when animation was done
animations: [
trigger('layerState', [
/* Right -> Left animation*/
@@ -18,7 +20,7 @@ import { Layer } from '../../../config-serializer/config-items/Layer';
left: '50%'
})),
state('leftOut', style({
transform: 'translateX(-100%)',
transform: 'translateX(-101%)',
left: '0'
})),
/* Right -> Left animation */
@@ -28,14 +30,14 @@ import { Layer } from '../../../config-serializer/config-items/Layer';
})),
state('rightOut', style({
transform: 'translateX(0%)',
left: '100%'
left: '101%'
})),
/* Transitions */
transition('none => leftIn, leftOut => leftIn', [
style({
opacity: 0,
transform: 'translateX(0%)',
left: '100%'
left: '101%'
}),
style({
opacity: 1
@@ -45,7 +47,7 @@ import { Layer } from '../../../config-serializer/config-items/Layer';
transition('* => none', [
style({
opacity: 0,
transform: 'translateX(-100%)',
transform: 'translateX(-101%)',
left: '0'
}),
style({
@@ -55,7 +57,7 @@ import { Layer } from '../../../config-serializer/config-items/Layer';
transition('none => rightIn, rightOut => rightIn', [
style({
opacity: 0,
transform: 'translateX(-100%)',
transform: 'translateX(-101%)',
left: '0'
}),
style({
@@ -73,21 +75,29 @@ import { Layer } from '../../../config-serializer/config-items/Layer';
])
]
})
export class SvgKeyboardWrapComponent implements OnInit {
export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
@Input() layers: Layer[];
@Input() popoverEnabled: boolean = true;
@Input() animationEnabled: boolean = true;
@Input() tooltipEnabled: boolean = false;
private popoverShown: boolean;
private keyEditConfig: { moduleId: number, keyId: number };
private popoverInitKeyAction: KeyAction;
private currentLayer: number = 0;
private tooltipData: { posTop: number, posLeft: number, content: {name: string, value: string}[], shown: boolean };
constructor() {
this.keyEditConfig = {
moduleId: undefined,
keyId: undefined
};
this.tooltipData = {
posTop: 0,
posLeft: 0,
content: [],
shown: false
};
}
ngOnInit() {
@@ -107,7 +117,7 @@ export class SvgKeyboardWrapComponent implements OnInit {
}
onKeyClick(moduleId: number, keyId: number): void {
if (!this.popoverShown) {
if (!this.popoverShown && this.popoverEnabled) {
this.keyEditConfig = {
moduleId,
keyId
@@ -118,6 +128,18 @@ export class SvgKeyboardWrapComponent implements OnInit {
}
}
onKeyHover(moduleId: number, event: MouseEvent, over: boolean, keyId: number): void {
let keyActionToEdit: KeyAction = this.layers[this.currentLayer].modules.elements[moduleId].keyActions.elements[keyId];
if (this.tooltipEnabled) {
if (over) {
this.showTooltip(keyActionToEdit, event);
} else {
this.hideTooltip(event);
}
}
}
onRemap(keyAction: KeyAction): void {
this.changeKeyAction(keyAction);
this.hidePopover();
@@ -128,6 +150,56 @@ export class SvgKeyboardWrapComponent implements OnInit {
this.popoverShown = true;
}
showTooltip(keyAction: KeyAction, event: MouseEvent): void {
if (keyAction instanceof NoneAction || keyAction === undefined) {
return;
}
let el: Element = event.target as Element || event.srcElement;
let position: ClientRect = el.getBoundingClientRect();
let posLeft: number = this.tooltipData.posLeft;
let posTop: number = this.tooltipData.posTop;
if (el.tagName === 'rect') {
posLeft = position.left + (position.width / 2);
posTop = position.top;
}
// TODO connect with real data
let dummyData = [
{
name: 'Key action',
value: 'o'
},
{
name: 'Scancode',
value: '55'
}
];
this.tooltipData = {
posLeft: posLeft,
posTop: posTop,
content: dummyData,
shown: true
};
}
hideTooltip(event: MouseEvent) {
let target: HTMLElement = event.relatedTarget as HTMLElement;
if (!target) {
this.tooltipData.shown = false;
return;
}
// Check if we are hovering tooltip
let list: DOMTokenList = target.classList;
if (!list.contains('tooltip') && !list.contains('tooltip-inner')) {
this.tooltipData.shown = false;
}
}
hidePopover(): void {
this.popoverShown = false;
this.popoverInitKeyAction = undefined;

View File

@@ -10,6 +10,8 @@ export class Keymap extends Serializable<Keymap> {
name: string;
description: string;
abbreviation: string;
isDefault: boolean;
@@ -21,6 +23,7 @@ export class Keymap extends Serializable<Keymap> {
this.isDefault = jsObject.isDefault;
this.abbreviation = jsObject.abbreviation;
this.name = jsObject.name;
this.description = jsObject.description;
this.layers = new Layers().fromJsObject(jsObject.layers);
return this;
}
@@ -30,6 +33,7 @@ export class Keymap extends Serializable<Keymap> {
this.isDefault = buffer.readBoolean();
this.abbreviation = buffer.readString();
this.name = buffer.readString();
this.description = buffer.readString();
this.layers = new Layers().fromBinary(buffer);
return this;
}
@@ -40,6 +44,7 @@ export class Keymap extends Serializable<Keymap> {
isDefault: this.isDefault,
abbreviation: this.abbreviation,
name: this.name,
description: this.description,
layers: this.layers.toJsObject()
};
}
@@ -49,6 +54,7 @@ export class Keymap extends Serializable<Keymap> {
buffer.writeBoolean(this.isDefault);
buffer.writeString(this.abbreviation);
buffer.writeString(this.name);
buffer.writeString(this.description);
this.layers.toBinary(buffer);
}

File diff suppressed because it is too large Load Diff

View File

@@ -18,6 +18,7 @@
"isDefault": true,
"abbreviation": "QTY",
"name": "QWERTY",
"description": "",
"layers": [
{
"modules": [
@@ -812,6 +813,7 @@
"isDefault": false,
"abbreviation": "VIM",
"name": "VIM",
"description": "",
"layers": [
{
"modules": [
@@ -914,6 +916,7 @@
"isDefault": false,
"abbreviation": "DVR",
"name": "DVR",
"description": "",
"layers": [
{
"modules": [

View File

@@ -11,6 +11,10 @@ export class DataProviderService {
return require('json!../config-serializer/uhk-config.json');
}
getDefaultKeymaps(): any {
return require('json!../config-serializer/default-keymaps.json');
}
getKeyboardSvgAttributes(): { viewBox: string, transform: string, fill: string } {
let svg: any = this.getBaseLayer();
return {