mirror of https://github.com/buggins/dlangui.git
accelerator table; editline
This commit is contained in:
parent
31e7a1de19
commit
8e4897aa9b
|
@ -20,15 +20,22 @@ Authors: $(WEB coolreader.org, Vadim Lopatin)
|
||||||
module dlangui.core.events;
|
module dlangui.core.events;
|
||||||
|
|
||||||
import dlangui.core.i18n;
|
import dlangui.core.i18n;
|
||||||
|
import dlangui.core.collections;
|
||||||
private import dlangui.widgets.widget;
|
private import dlangui.widgets.widget;
|
||||||
|
|
||||||
import std.conv;
|
import std.conv;
|
||||||
|
|
||||||
|
struct Accelerator {
|
||||||
|
uint keyCode;
|
||||||
|
uint keyFlags;
|
||||||
|
}
|
||||||
|
|
||||||
/// UI action
|
/// UI action
|
||||||
class Action {
|
class Action {
|
||||||
protected int _id;
|
protected int _id;
|
||||||
protected UIString _label;
|
protected UIString _label;
|
||||||
protected string _iconId;
|
protected string _iconId;
|
||||||
|
protected Accelerator[] _accelerators;
|
||||||
this(int id, string labelResourceId, string iconResourceId = null) {
|
this(int id, string labelResourceId, string iconResourceId = null) {
|
||||||
_id = id;
|
_id = id;
|
||||||
_label = labelResourceId;
|
_label = labelResourceId;
|
||||||
|
@ -39,6 +46,22 @@ class Action {
|
||||||
_label = label;
|
_label = label;
|
||||||
_iconId = iconResourceId;
|
_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 {
|
@property int id() const {
|
||||||
return _id;
|
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 {
|
enum MouseAction : ubyte {
|
||||||
Cancel, // button down handling is cancelled
|
Cancel, // button down handling is cancelled
|
||||||
|
|
|
@ -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
|
/// single line editor
|
||||||
class EditLine : Widget {
|
class EditLine : Widget {
|
||||||
protected EditableContent _content;
|
protected EditableContent _content;
|
||||||
|
@ -135,6 +151,18 @@ class EditLine : Widget {
|
||||||
styleId = "EDIT_LINE";
|
styleId = "EDIT_LINE";
|
||||||
focusable = true;
|
focusable = true;
|
||||||
text = initialContent;
|
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
|
/// 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.
|
/// process mouse event; return true if event is processed by widget.
|
||||||
override bool onMouseEvent(MouseEvent event) {
|
override bool onMouseEvent(MouseEvent event) {
|
||||||
//Log.d("onMouseEvent ", id, " ", event.action, " (", event.x, ",", event.y, ")");
|
//Log.d("onMouseEvent ", id, " ", event.action, " (", event.x, ",", event.y, ")");
|
||||||
|
|
|
@ -451,6 +451,17 @@ class Widget {
|
||||||
// =======================================================
|
// =======================================================
|
||||||
// Events
|
// 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
|
// called to process click and notify listeners
|
||||||
protected bool handleClick() {
|
protected bool handleClick() {
|
||||||
bool res = onClickListener(this);
|
bool res = onClickListener(this);
|
||||||
|
@ -459,6 +470,12 @@ class Widget {
|
||||||
|
|
||||||
/// process key event, return true if event is processed.
|
/// process key event, return true if event is processed.
|
||||||
bool onKeyEvent(KeyEvent event) {
|
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) {
|
if (canClick) {
|
||||||
// support onClick event initiated by Space or Return keys
|
// support onClick event initiated by Space or Return keys
|
||||||
if (event.action == KeyAction.KeyDown) {
|
if (event.action == KeyAction.KeyDown) {
|
||||||
|
|
Loading…
Reference in New Issue