smoosic
Version:
<sub>[Github site](https://github.com/Smoosic/smoosic) | [source documentation](https://smoosic.github.io/Smoosic/release/docs/modules.html) | [change notes](https://aarondavidnewman.github.io/Smoosic/changes.html) | [application](https://smoosic.github.i
158 lines (150 loc) • 6.24 kB
text/typescript
import { SuiScoreViewOperations } from "../render/sui/scoreViewOperations";
import { SuiTracker } from "../render/sui/tracker";
import { CompleteNotifier } from "../ui/common";
import { ModalComponent } from "../ui/common";
import { KeyEvent } from "../smo/data/common";
import { BrowserEventSource, EventHandler } from "../ui/eventSource";
export type trackerKeyAction = "moveHome" | "moveEnd" | "moveSelectionRight" | "moveSelectionLeft" |
"moveSelectionUp" | "moveSelectionDown" | "moveSelectionRightMeasure" | "moveSelectionLeftMeasure" |
"advanceModifierSelection" | "growSelectionRight" | "growSelectionLeft" |
"growSelectionRightMeasure" | "growSelectionRightMeasure" |
"moveSelectionPitchUp" | "moveSelectionPitchDown";
export const trackerKeyActions = ["moveHome" , "moveEnd" , "moveSelectionRight" , "moveSelectionLeft" ,
"moveSelectionUp" , "moveSelectionDown" , "moveSelectionRightMeasure" , "moveSelectionLeftMeasure" ,
"advanceModifierSelection" , "growSelectionRight" , "growSelectionLeft" , "growSelectionRightMeasure",
"moveSelectionPitchUp" , "moveSelectionPitchDown"];
export type editorKeyAction = "transposeUp" | "transposeDown" | "upOctave" | "downOctave" |
"toggleCourtesyAccidental" | "toggleEnharmonic" |
"doubleDuration" | "halveDuration" | "dotDuration" | "undotDuration" | "setPitch" |
"slashGraceNotes" | "addGraceNote" | "removeGraceNote" |
"playScore" | "stopPlayer" | "pausePlayer" | "togglePlayer" |
"undo" | "copy" | "paste" |
"makeTuplet" | "interval" | "unmakeTuplet" | "addMeasure" | "deleteNote" | "makeRest"|
"unbeamSelections" | "beamSelections" | "toggleBeamDirection" |
"addRemoveAccent" | "addRemoveTenuto" | "addRemoveStaccato" |
"addRemovePizzicato" | "addRemoveMarcato";
export const editorKeyActions = ["transposeUp" , "transposeDown" , "upOctave" , "downOctave" ,
"toggleCourtesyAccidental" , "toggleEnharmonic",
"doubleDuration" , "halveDuration" , "dotDuration" , "undotDuration" , "setPitch" ,
"slashGraceNotes" , "addGraceNote" , "removeGraceNote" ,
"playScore" , "stopPlayer" , "pausePlayer", "togglePlayer",
"undo", "copy", "paste",
"makeTuplet" , "interval" , "unmakeTuplet" , "addMeasure" , "deleteNote" , "makeRest",
"unbeamSelections" , "beamSelections" , "toggleBeamDirection",
"addRemoveAccent" , "addRemoveTenuto" , "addRemoveStaccato",
"addRemovePizzicato", "addRemoveMarcato"
];
export function isEditorKeyAction(action: string) { return editorKeyActions.indexOf(action) >= 0 };
export function isTrackerKeyAction(action: string) { return trackerKeyActions.indexOf(action) >= 0 };
/**
* A binding of a key to some action performed by a module
* @category SuiApplication
*/
export interface KeyBinding {
event: string,
key: string,
ctrlKey: boolean,
altKey: boolean,
shiftKey: boolean,
action: string,
module?: string
}
/**
* parameters for the key handlers
* @param view
* @param slashMode indicates that the dreaded 'slash' menus are up
* @param completeNotifier notified when modals close
* @param tracker
* @param eventSource register for event handlers
* @category SuiApplication
*/
export interface KeyCommandParams {
view: SuiScoreViewOperations;
slashMode: boolean;
completeNotifier: CompleteNotifier;
tracker: SuiTracker;
eventSource: BrowserEventSource;
}
/**
* Shared interface for menus, dialogs, etc that can
* accept UI events
* @category SuiApplication
*/
export abstract class ModalEventHandler {
abstract mouseMove(ev: any): void;
abstract mouseClick(ev: any): void;
abstract evKey(evdata: any): Promise<void>;
abstract keyUp(evdata: any): void;
}
export type handler = (ev: any) => void;
/**
* Dependency injection, sends events to a proxy object, gets around some
* cyclic dependencies when bootstrapping the application.
* @category SuiApplication
*/
export class ModalEventHandlerProxy {
_handler: ModalEventHandler | null = null;
eventSource: BrowserEventSource;
unbound: boolean = true;
keydownHandler: EventHandler | null = null;
keyupHandler: EventHandler | null = null;
mouseMoveHandler: EventHandler | null = null;
mouseClickHandler: EventHandler | null = null;
constructor(evSource: BrowserEventSource) {
this.eventSource = evSource;
this.bindEvents();
}
set handler(value: ModalEventHandler) {
this._handler = value;
this.unbound = false;
}
async evKey(ev: any) {
if (this._handler) {
await this._handler.evKey(ev);
}
}
keyUp(ev: any) {
if (this._handler) {
this._handler.keyUp(ev);
}
}
mouseMove(ev: any) {
if (this._handler) {
this._handler.mouseMove(ev);
}
}
mouseClick(ev: any) {
if (this._handler) {
this._handler.mouseClick(ev);
}
}
bindEvents() {
const mousemove = async (ev: any) => { this.mouseMove(ev); }
const mouseclick = async (ev: any) => { this.mouseClick(ev); }
const keydown = async (ev: any) => { this.evKey(ev); }
const keyup = async (ev: any) => { this.keyUp(ev); }
this.mouseMoveHandler = this.eventSource.bindMouseMoveHandler(mousemove);
this.mouseClickHandler = this.eventSource.bindMouseClickHandler(mouseclick);
this.keydownHandler = this.eventSource.bindKeydownHandler(keydown);
this.keyupHandler = this.eventSource.bindKeyupHandler(keyup);
}
unbindKeyboardForModal(dialog: ModalComponent) {
if (this.unbound) {
console.log('received duplicate bind event');
return;
}
if (!this.keydownHandler || !this.mouseMoveHandler || !this.mouseClickHandler) {
console.log('received bind with no handlers');
return;
}
this.unbound = true;
const rebind = () => {
this.unbound = false;
this.bindEvents();
}
this.eventSource.unbindKeydownHandler(this.keydownHandler!);
this.eventSource.unbindMouseMoveHandler(this.mouseMoveHandler!);
this.eventSource.unbindMouseClickHandler(this.mouseClickHandler!);
dialog.closeModalPromise.then(rebind);
}
}