From 8e4897aa9be4a6778eb44bdad829249164107ad9 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Sun, 20 Apr 2014 07:49:24 +0400 Subject: [PATCH] accelerator table; editline --- src/dlangui/core/events.d | 77 +++++++++++++++++++++++++++++++ src/dlangui/widgets/editors.d | 86 +++++++++++++++++++++++++++++++++++ src/dlangui/widgets/widget.d | 17 +++++++ 3 files changed, 180 insertions(+) diff --git a/src/dlangui/core/events.d b/src/dlangui/core/events.d index f5d7dfb5..5607cc38 100644 --- a/src/dlangui/core/events.d +++ b/src/dlangui/core/events.d @@ -20,15 +20,22 @@ Authors: $(WEB coolreader.org, Vadim Lopatin) module dlangui.core.events; import dlangui.core.i18n; +import dlangui.core.collections; private import dlangui.widgets.widget; import std.conv; +struct Accelerator { + uint keyCode; + uint keyFlags; +} + /// UI action class Action { protected int _id; protected UIString _label; protected string _iconId; + protected Accelerator[] _accelerators; this(int id, string labelResourceId, string iconResourceId = null) { _id = id; _label = labelResourceId; @@ -39,6 +46,22 @@ class Action { _label = label; _iconId = iconResourceId; } + /// action with accelerator, w/o label + this(int id, uint keyCode, uint keyFlags = 0) { + _id = id; + _accelerators ~= Accelerator(keyCode, keyFlags); + } + /// returs array of accelerators + @property Accelerator[] accelerators() { + return _accelerators; + } + /// returns true if accelerator matches provided key code and flags + bool checkAccelerator(uint keyCode, uint keyFlags) { + foreach(a; _accelerators) + if (a.keyCode == keyCode && a.keyFlags == keyFlags) + return true; + return false; + } @property int id() const { return _id; } @@ -69,6 +92,60 @@ class Action { } } +struct ActionMap { + protected Action[Accelerator] _map; + /// add from list + void add(ActionList items) { + foreach(a; items) { + foreach(acc; a.accelerators) + _map[acc] = a; + } + } + /// add array of actions + void add(Action[] items) { + foreach(a; items) { + foreach(acc; a.accelerators) + _map[acc] = a; + } + } + /// add action + void add(Action a) { + foreach(acc; a.accelerators) + _map[acc] = a; + } + /// find action by key, return null if not found + Action findByKey(uint keyCode, uint flags) { + Accelerator acc; + acc.keyCode = keyCode; + acc.keyFlags = flags; + if (acc in _map) + return _map[acc]; + return null; + } +} + +struct ActionList { + private Collection!Action _actions; + alias _actions this; + + void add(Action[] items) { + foreach(a; items) + _actions ~= a; + } + + void add(ref ActionList items) { + foreach(a; items) + _actions ~= a; + } + + /// find action by key, return null if not found + Action findByKey(uint keyCode, uint flags) { + foreach(a; _actions) + if (a.checkAccelerator(keyCode, flags)) + return a; + return null; + } +} enum MouseAction : ubyte { Cancel, // button down handling is cancelled diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index 41e21c15..127076fc 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -123,6 +123,22 @@ class EditableContent { } } +enum EditorActions { + None = 0, + Left = 1000, + Right, + Up, + Down, + WordLeft, + WordRight, + PageUp, + PageDown, + LineBegin, + LineEnd, + DocumentBegin, + DocumentEnd, +} + /// single line editor class EditLine : Widget { protected EditableContent _content; @@ -135,6 +151,18 @@ class EditLine : Widget { styleId = "EDIT_LINE"; focusable = true; text = initialContent; + acceleratorMap.add( [ + new Action(EditorActions.Up, KeyCode.UP, 0), + new Action(EditorActions.Down, KeyCode.DOWN, 0), + new Action(EditorActions.Left, KeyCode.LEFT, 0), + new Action(EditorActions.Right, KeyCode.RIGHT, 0), + new Action(EditorActions.WordLeft, KeyCode.LEFT, KeyFlag.Control), + new Action(EditorActions.WordRight, KeyCode.RIGHT, KeyFlag.Control), + new Action(EditorActions.LineBegin, KeyCode.HOME, 0), + new Action(EditorActions.LineEnd, KeyCode.END, 0), + new Action(EditorActions.DocumentBegin, KeyCode.HOME, KeyFlag.Control), + new Action(EditorActions.DocumentEnd, KeyCode.END, KeyFlag.Control), + ]); } /// get widget text @@ -213,6 +241,64 @@ class EditLine : Widget { } } + override protected bool handleAction(Action a) { + switch (a.id) { + case EditorActions.Left: + if (_caretPos.pos > 0) { + _caretPos.pos--; + invalidate(); + } + return true; + case EditorActions.Right: + if (_caretPos.pos < _measuredText.length) { + _caretPos.pos++; + invalidate(); + } + return true; + case EditorActions.Up: + break; + case EditorActions.Down: + break; + case EditorActions.WordLeft: + break; + case EditorActions.WordRight: + break; + case EditorActions.PageUp: + break; + case EditorActions.PageDown: + break; + case EditorActions.DocumentBegin: + case EditorActions.LineBegin: + if (_caretPos.pos > 0) { + _caretPos.pos = 0; + invalidate(); + } + return true; + case EditorActions.DocumentEnd: + case EditorActions.LineEnd: + if (_caretPos.pos < _measuredText.length) { + _caretPos.pos = _measuredText.length; + invalidate(); + } + return true; + default: + return false; + } + return super.handleAction(a); + } + + /// handle keys + override bool onKeyEvent(KeyEvent event) { + // + if (event.action == KeyAction.KeyDown) { + //EditorAction a = keyToAction(event.keyCode, event.flags & (KeyFlag.Shift | KeyFlag.Alt | KeyFlag.Ctrl)); + //switch(event.keyCode) { + // + //} + } + return super.onKeyEvent(event); + } + /// process mouse event; return true if event is processed by widget. override bool onMouseEvent(MouseEvent event) { //Log.d("onMouseEvent ", id, " ", event.action, " (", event.x, ",", event.y, ")"); diff --git a/src/dlangui/widgets/widget.d b/src/dlangui/widgets/widget.d index b1990dc6..1bf7b894 100644 --- a/src/dlangui/widgets/widget.d +++ b/src/dlangui/widgets/widget.d @@ -451,6 +451,17 @@ class Widget { // ======================================================= // Events + protected ActionMap _acceleratorMap; + @property ref ActionMap acceleratorMap() { return _acceleratorMap; } + + /// override to handle specific actions + protected bool handleAction(Action a) { + if (parent) // by default, pass to parent widget + return parent.handleAction(a); + return false; + } + + // called to process click and notify listeners protected bool handleClick() { bool res = onClickListener(this); @@ -459,6 +470,12 @@ class Widget { /// process key event, return true if event is processed. bool onKeyEvent(KeyEvent event) { + if (event.action == KeyAction.KeyDown) { + Action action = _acceleratorMap.findByKey(event.keyCode, event.flags & (KeyFlag.Shift | KeyFlag.Alt | KeyFlag.Control)); + if (action !is null) { + return handleAction(action); + } + } if (canClick) { // support onClick event initiated by Space or Return keys if (event.action == KeyAction.KeyDown) {