Merge pull request #456 from and3md/actions

Action improvements fixes #454
This commit is contained in:
Vadim Lopatin 2017-09-25 10:39:24 +03:00 committed by GitHub
commit 2d30f44752
9 changed files with 638 additions and 558 deletions

View File

@ -26,6 +26,20 @@ private import std.string;
private import std.conv;
private import std.utf : toUTF32;
/// Define when action need state update - optimization for high frequently uses actions
enum ActionStateUpdateFlag : uint {
/// action never change state so there is no need to search for dispatch action state request
never = 0,
/// dispatch action state change if action added to widget
inWidget = 1,
/// dispatch action state change if run from accelerator (keyboard)
inAccelerator = 2,
/// always dispatch action state change
always = inWidget | inAccelerator
}
/// Keyboard accelerator (key + modifiers)
struct Accelerator {
/// Key code, usually one of KeyCode enum items
@ -301,6 +315,8 @@ class Action {
protected ActionState _defaultState = ACTION_STATE_ENABLED;
protected uint _stateUpdateFlag = ActionStateUpdateFlag.always;
/// set default state to disabled, visible, not-checked
Action disableByDefault() { _defaultState = ACTION_STATE_DISABLE; return this; }
/// set default state to disabled, invisible, not-checked
@ -327,6 +343,15 @@ class Action {
return this;
}
/// return action state update flag (see ActionStateUpdateFlag for details)
@property uint stateUpdateFlag() const { return _stateUpdateFlag; }
/// sets action state update flag (see ActionStateUpdateFlag for details)
@property Action stateUpdateFlag(uint newStateUpdateFlag) {
_stateUpdateFlag = newStateUpdateFlag;
return this;
}
/// returns optional string parameter
@property string stringParam() const {
return _stringParam;
@ -358,6 +383,7 @@ class Action {
_objectParam = v;
return this;
}
/// deep copy constructor
this(immutable Action a) {
_id = a._id;
@ -368,6 +394,7 @@ class Action {
_accelerators = a._accelerators.dup;
_stringParam = a._stringParam;
_longParam = a._longParam;
_stateUpdateFlag = a._stateUpdateFlag;
if (a._objectParam)
_objectParam = cast(Object)a._objectParam;
}
@ -382,7 +409,8 @@ class Action {
_id = id;
}
/// create action with id, labelResourceId, and optional icon and key accelerator.
this(int id, string labelResourceId, string iconResourceId = null, uint keyCode = 0, uint keyFlags = 0) {
this(int id, string labelResourceId, string iconResourceId = null, uint keyCode = 0, uint keyFlags = 0,
uint stateUpdateFlag = ActionStateUpdateFlag.always ) {
_id = id;
_label.id = labelResourceId;
_iconId = iconResourceId;
@ -394,9 +422,10 @@ class Action {
}
_accelerators ~= Accelerator(keyCode, keyFlags);
}
_stateUpdateFlag = stateUpdateFlag;
}
/// action with accelerator, w/o label
this(int id, uint keyCode, uint keyFlags = 0) {
this(int id, uint keyCode, uint keyFlags = 0, uint stateUpdateFlag = ActionStateUpdateFlag.always) {
_id = id;
version (OSX) {
if (keyFlags & KeyFlag.Control) {
@ -404,9 +433,11 @@ class Action {
}
}
_accelerators ~= Accelerator(keyCode, keyFlags);
_stateUpdateFlag = stateUpdateFlag;
}
/// action with label, icon, and accelerator
this(int id, dstring label, string iconResourceId = null, uint keyCode = 0, uint keyFlags = 0) {
this(int id, dstring label, string iconResourceId = null, uint keyCode = 0, uint keyFlags = 0,
uint stateUpdateFlag = ActionStateUpdateFlag.always) {
_id = id;
_label.value = label;
_iconId = iconResourceId;
@ -418,6 +449,7 @@ class Action {
}
_accelerators ~= Accelerator(keyCode, keyFlags);
}
_stateUpdateFlag = stateUpdateFlag;
}
/// returs array of accelerators
@property Accelerator[] accelerators() {
@ -613,6 +645,18 @@ struct ActionMap {
}
return null;
}
int opApply(int delegate(ref Action) op) {
int result = 0;
foreach (ref Accelerator acc; _map.byKey) {
result = op(_map[acc]);
if (result)
break;
}
return result;
}
}
/// List of Actions, for looking up Action by key

File diff suppressed because it is too large Load Diff

View File

@ -1823,6 +1823,8 @@ class Platform {
* When returned from this method, application is shutting down.
*/
abstract int enterMessageLoop();
/// check has clipboard text
abstract bool hasClipboardText(bool mouseBuffer = false);
/// retrieves text from clipboard (when mouseBuffer == true, use mouse selection clipboard - under linux)
abstract dstring getClipboardText(bool mouseBuffer = false);
/// sets text to clipboard (when mouseBuffer == true, use mouse selection clipboard - under linux)

View File

@ -240,6 +240,12 @@ class ConsolePlatform : Platform {
return 0;
}
private dstring _clipboardText;
/// check has clipboard text
override bool hasClipboardText(bool mouseBuffer = false) {
return (_clipboardText.length > 0);
}
/// retrieves text from clipboard (when mouseBuffer == true, use mouse selection clipboard - under linux)
override dstring getClipboardText(bool mouseBuffer = false) {
return _clipboardText;

View File

@ -1462,10 +1462,13 @@ class SDLPlatform : Platform {
return 0;
}
/// check has clipboard text
override bool hasClipboardText(bool mouseBuffer = false) {
return (SDL_HasClipboardText() == SDL_TRUE);
}
/// retrieves text from clipboard (when mouseBuffer == true, use mouse selection clipboard - under linux)
override dstring getClipboardText(bool mouseBuffer = false) {
if (!SDL_HasClipboardText())
return ""d;
char * txt = SDL_GetClipboardText();
if (!txt)
return ""d;

View File

@ -1158,6 +1158,13 @@ class Win32Platform : Platform {
_windowsToDestroy.length = 0;
}
/// check has clipboard text
override bool hasClipboardText(bool mouseBuffer = false) {
if (mouseBuffer)
return false;
return (IsClipboardFormatAvailable(CF_UNICODETEXT) != 0);
}
/// retrieves text from clipboard (when mouseBuffer == true, use mouse selection clipboard - under linux)
override dstring getClipboardText(bool mouseBuffer = false) {
dstring res = null;

View File

@ -1633,6 +1633,11 @@ class X11Platform : Platform {
return 0;
}
/// check has clipboard text
override bool hasClipboardText(bool mouseBuffer = false) {
return (localClipboardContent.length != 0);
}
/// retrieves text from clipboard (when mouseBuffer == true, use mouse selection clipboard - under linux)
override dstring getClipboardText(bool mouseBuffer = false) {
return toUTF32(localClipboardContent);

View File

@ -210,12 +210,12 @@ void initStandardEditorActions() {
registerActionEnum!EditorActions();
}
const Action ACTION_EDITOR_INSERT_NEW_LINE = (new Action(EditorActions.InsertNewLine, KeyCode.RETURN, 0)).addAccelerator(KeyCode.RETURN, KeyFlag.Shift);
const Action ACTION_EDITOR_PREPEND_NEW_LINE = (new Action(EditorActions.PrependNewLine, KeyCode.RETURN, KeyFlag.Control|KeyFlag.Shift));
const Action ACTION_EDITOR_APPEND_NEW_LINE = (new Action(EditorActions.AppendNewLine, KeyCode.RETURN, KeyFlag.Control));
const Action ACTION_EDITOR_DELETE_LINE = (new Action(EditorActions.DeleteLine, KeyCode.KEY_D, KeyFlag.Control)).addAccelerator(KeyCode.KEY_L, KeyFlag.Control);
const Action ACTION_EDITOR_TOGGLE_REPLACE_MODE = (new Action(EditorActions.ToggleReplaceMode, KeyCode.INS, 0));
const Action ACTION_EDITOR_SELECT_ALL = (new Action(EditorActions.SelectAll, KeyCode.KEY_A, KeyFlag.Control));
const Action ACTION_EDITOR_INSERT_NEW_LINE = (new Action(EditorActions.InsertNewLine, KeyCode.RETURN, 0, ActionStateUpdateFlag.never)).addAccelerator(KeyCode.RETURN, KeyFlag.Shift);
const Action ACTION_EDITOR_PREPEND_NEW_LINE = (new Action(EditorActions.PrependNewLine, KeyCode.RETURN, KeyFlag.Control | KeyFlag.Shift, ActionStateUpdateFlag.never));
const Action ACTION_EDITOR_APPEND_NEW_LINE = (new Action(EditorActions.AppendNewLine, KeyCode.RETURN, KeyFlag.Control, ActionStateUpdateFlag.never));
const Action ACTION_EDITOR_DELETE_LINE = (new Action(EditorActions.DeleteLine, KeyCode.KEY_D, KeyFlag.Control, ActionStateUpdateFlag.never)).addAccelerator(KeyCode.KEY_L, KeyFlag.Control);
const Action ACTION_EDITOR_TOGGLE_REPLACE_MODE = (new Action(EditorActions.ToggleReplaceMode, KeyCode.INS, 0, ActionStateUpdateFlag.never));
const Action ACTION_EDITOR_SELECT_ALL = (new Action(EditorActions.SelectAll, KeyCode.KEY_A, KeyFlag.Control, ActionStateUpdateFlag.never));
const Action ACTION_EDITOR_TOGGLE_LINE_COMMENT = (new Action(EditorActions.ToggleLineComment, KeyCode.KEY_DIVIDE, KeyFlag.Control));
const Action ACTION_EDITOR_TOGGLE_BLOCK_COMMENT = (new Action(EditorActions.ToggleBlockComment, KeyCode.KEY_DIVIDE, KeyFlag.Control | KeyFlag.Shift));
const Action ACTION_EDITOR_TOGGLE_BOOKMARK = (new Action(EditorActions.ToggleBookmark, "ACTION_EDITOR_TOGGLE_BOOKMARK"c, null, KeyCode.KEY_B, KeyFlag.Control | KeyFlag.Shift));
@ -534,64 +534,64 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
super(ID, hscrollbarMode, vscrollbarMode);
focusable = true;
acceleratorMap.add( [
new Action(EditorActions.Up, KeyCode.UP, 0),
new Action(EditorActions.SelectUp, KeyCode.UP, KeyFlag.Shift),
new Action(EditorActions.SelectUp, KeyCode.UP, KeyFlag.Control | KeyFlag.Shift),
new Action(EditorActions.Down, KeyCode.DOWN, 0),
new Action(EditorActions.SelectDown, KeyCode.DOWN, KeyFlag.Shift),
new Action(EditorActions.SelectDown, KeyCode.DOWN, KeyFlag.Control | KeyFlag.Shift),
new Action(EditorActions.Left, KeyCode.LEFT, 0),
new Action(EditorActions.SelectLeft, KeyCode.LEFT, KeyFlag.Shift),
new Action(EditorActions.Right, KeyCode.RIGHT, 0),
new Action(EditorActions.SelectRight, KeyCode.RIGHT, KeyFlag.Shift),
new Action(EditorActions.WordLeft, KeyCode.LEFT, KeyFlag.Control),
new Action(EditorActions.SelectWordLeft, KeyCode.LEFT, KeyFlag.Control | KeyFlag.Shift),
new Action(EditorActions.WordRight, KeyCode.RIGHT, KeyFlag.Control),
new Action(EditorActions.SelectWordRight, KeyCode.RIGHT, KeyFlag.Control | KeyFlag.Shift),
new Action(EditorActions.PageUp, KeyCode.PAGEUP, 0),
new Action(EditorActions.SelectPageUp, KeyCode.PAGEUP, KeyFlag.Shift),
new Action(EditorActions.PageDown, KeyCode.PAGEDOWN, 0),
new Action(EditorActions.SelectPageDown, KeyCode.PAGEDOWN, KeyFlag.Shift),
new Action(EditorActions.PageBegin, KeyCode.PAGEUP, KeyFlag.Control),
new Action(EditorActions.SelectPageBegin, KeyCode.PAGEUP, KeyFlag.Control | KeyFlag.Shift),
new Action(EditorActions.PageEnd, KeyCode.PAGEDOWN, KeyFlag.Control),
new Action(EditorActions.SelectPageEnd, KeyCode.PAGEDOWN, KeyFlag.Control | KeyFlag.Shift),
new Action(EditorActions.LineBegin, KeyCode.HOME, 0),
new Action(EditorActions.SelectLineBegin, KeyCode.HOME, KeyFlag.Shift),
new Action(EditorActions.LineEnd, KeyCode.END, 0),
new Action(EditorActions.SelectLineEnd, KeyCode.END, KeyFlag.Shift),
new Action(EditorActions.DocumentBegin, KeyCode.HOME, KeyFlag.Control),
new Action(EditorActions.SelectDocumentBegin, KeyCode.HOME, KeyFlag.Control | KeyFlag.Shift),
new Action(EditorActions.DocumentEnd, KeyCode.END, KeyFlag.Control),
new Action(EditorActions.SelectDocumentEnd, KeyCode.END, KeyFlag.Control | KeyFlag.Shift),
new Action(EditorActions.Up, KeyCode.UP, 0, ActionStateUpdateFlag.never),
new Action(EditorActions.SelectUp, KeyCode.UP, KeyFlag.Shift, ActionStateUpdateFlag.never),
new Action(EditorActions.SelectUp, KeyCode.UP, KeyFlag.Control | KeyFlag.Shift, ActionStateUpdateFlag.never),
new Action(EditorActions.Down, KeyCode.DOWN, 0, ActionStateUpdateFlag.never),
new Action(EditorActions.SelectDown, KeyCode.DOWN, KeyFlag.Shift, ActionStateUpdateFlag.never),
new Action(EditorActions.SelectDown, KeyCode.DOWN, KeyFlag.Control | KeyFlag.Shift, ActionStateUpdateFlag.never),
new Action(EditorActions.Left, KeyCode.LEFT, 0, ActionStateUpdateFlag.never),
new Action(EditorActions.SelectLeft, KeyCode.LEFT, KeyFlag.Shift, ActionStateUpdateFlag.never),
new Action(EditorActions.Right, KeyCode.RIGHT, 0, ActionStateUpdateFlag.never),
new Action(EditorActions.SelectRight, KeyCode.RIGHT, KeyFlag.Shift, ActionStateUpdateFlag.never),
new Action(EditorActions.WordLeft, KeyCode.LEFT, KeyFlag.Control, ActionStateUpdateFlag.never),
new Action(EditorActions.SelectWordLeft, KeyCode.LEFT, KeyFlag.Control | KeyFlag.Shift, ActionStateUpdateFlag.never),
new Action(EditorActions.WordRight, KeyCode.RIGHT, KeyFlag.Control, ActionStateUpdateFlag.never),
new Action(EditorActions.SelectWordRight, KeyCode.RIGHT, KeyFlag.Control | KeyFlag.Shift, ActionStateUpdateFlag.never),
new Action(EditorActions.PageUp, KeyCode.PAGEUP, 0, ActionStateUpdateFlag.never),
new Action(EditorActions.SelectPageUp, KeyCode.PAGEUP, KeyFlag.Shift, ActionStateUpdateFlag.never),
new Action(EditorActions.PageDown, KeyCode.PAGEDOWN, 0, ActionStateUpdateFlag.never),
new Action(EditorActions.SelectPageDown, KeyCode.PAGEDOWN, KeyFlag.Shift, ActionStateUpdateFlag.never),
new Action(EditorActions.PageBegin, KeyCode.PAGEUP, KeyFlag.Control, ActionStateUpdateFlag.never),
new Action(EditorActions.SelectPageBegin, KeyCode.PAGEUP, KeyFlag.Control | KeyFlag.Shift, ActionStateUpdateFlag.never),
new Action(EditorActions.PageEnd, KeyCode.PAGEDOWN, KeyFlag.Control, ActionStateUpdateFlag.never),
new Action(EditorActions.SelectPageEnd, KeyCode.PAGEDOWN, KeyFlag.Control | KeyFlag.Shift, ActionStateUpdateFlag.never),
new Action(EditorActions.LineBegin, KeyCode.HOME, 0, ActionStateUpdateFlag.never),
new Action(EditorActions.SelectLineBegin, KeyCode.HOME, KeyFlag.Shift, ActionStateUpdateFlag.never),
new Action(EditorActions.LineEnd, KeyCode.END, 0, ActionStateUpdateFlag.never),
new Action(EditorActions.SelectLineEnd, KeyCode.END, KeyFlag.Shift, ActionStateUpdateFlag.never),
new Action(EditorActions.DocumentBegin, KeyCode.HOME, KeyFlag.Control, ActionStateUpdateFlag.never),
new Action(EditorActions.SelectDocumentBegin, KeyCode.HOME, KeyFlag.Control | KeyFlag.Shift, ActionStateUpdateFlag.never),
new Action(EditorActions.DocumentEnd, KeyCode.END, KeyFlag.Control, ActionStateUpdateFlag.never),
new Action(EditorActions.SelectDocumentEnd, KeyCode.END, KeyFlag.Control | KeyFlag.Shift, ActionStateUpdateFlag.never),
new Action(EditorActions.ScrollLineUp, KeyCode.UP, KeyFlag.Control),
new Action(EditorActions.ScrollLineDown, KeyCode.DOWN, KeyFlag.Control),
new Action(EditorActions.ScrollLineUp, KeyCode.UP, KeyFlag.Control, ActionStateUpdateFlag.never),
new Action(EditorActions.ScrollLineDown, KeyCode.DOWN, KeyFlag.Control, ActionStateUpdateFlag.never),
// Backspace/Del
new Action(EditorActions.DelPrevChar, KeyCode.BACK, 0),
new Action(EditorActions.DelNextChar, KeyCode.DEL, 0),
new Action(EditorActions.DelPrevWord, KeyCode.BACK, KeyFlag.Control),
new Action(EditorActions.DelNextWord, KeyCode.DEL, KeyFlag.Control),
new Action(EditorActions.DelPrevChar, KeyCode.BACK, 0, ActionStateUpdateFlag.never),
new Action(EditorActions.DelNextChar, KeyCode.DEL, 0, ActionStateUpdateFlag.never),
new Action(EditorActions.DelPrevWord, KeyCode.BACK, KeyFlag.Control, ActionStateUpdateFlag.never),
new Action(EditorActions.DelNextWord, KeyCode.DEL, KeyFlag.Control, ActionStateUpdateFlag.never),
// Copy/Paste
new Action(EditorActions.Copy, KeyCode.KEY_C, KeyFlag.Control),
new Action(EditorActions.Copy, KeyCode.KEY_C, KeyFlag.Control|KeyFlag.Shift),
new Action(EditorActions.Copy, KeyCode.KEY_C, KeyFlag.Control | KeyFlag.Shift),
new Action(EditorActions.Copy, KeyCode.INS, KeyFlag.Control),
new Action(EditorActions.Cut, KeyCode.KEY_X, KeyFlag.Control),
new Action(EditorActions.Cut, KeyCode.KEY_X, KeyFlag.Control|KeyFlag.Shift),
new Action(EditorActions.Cut, KeyCode.KEY_X, KeyFlag.Control | KeyFlag.Shift),
new Action(EditorActions.Cut, KeyCode.DEL, KeyFlag.Shift),
new Action(EditorActions.Paste, KeyCode.KEY_V, KeyFlag.Control),
new Action(EditorActions.Paste, KeyCode.KEY_V, KeyFlag.Control|KeyFlag.Shift),
new Action(EditorActions.Paste, KeyCode.KEY_V, KeyFlag.Control | KeyFlag.Shift),
new Action(EditorActions.Paste, KeyCode.INS, KeyFlag.Shift),
// Undo/Redo
new Action(EditorActions.Undo, KeyCode.KEY_Z, KeyFlag.Control),
new Action(EditorActions.Redo, KeyCode.KEY_Y, KeyFlag.Control),
new Action(EditorActions.Redo, KeyCode.KEY_Z, KeyFlag.Control|KeyFlag.Shift),
new Action(EditorActions.Redo, KeyCode.KEY_Z, KeyFlag.Control | KeyFlag.Shift),
new Action(EditorActions.Tab, KeyCode.TAB, 0),
new Action(EditorActions.BackTab, KeyCode.TAB, KeyFlag.Shift),
new Action(EditorActions.Tab, KeyCode.TAB, 0, ActionStateUpdateFlag.never),
new Action(EditorActions.BackTab, KeyCode.TAB, KeyFlag.Shift, ActionStateUpdateFlag.never),
new Action(EditorActions.Find, KeyCode.KEY_F, KeyFlag.Control),
new Action(EditorActions.Replace, KeyCode.KEY_H, KeyFlag.Control),
@ -642,7 +642,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
case Cut:
return enabled && (_copyCurrentLineWhenNoSelection || !_selectionRange.empty);
case Paste:
return enabled && Platform.instance.getClipboardText().length > 0;
return enabled && Platform.instance.hasClipboardText();
case Undo:
return enabled && _content.hasUndo;
case Redo:

View File

@ -741,7 +741,7 @@ public:
}
/// call to update state for action (if action is assigned for widget)
void updateActionState(bool force = false) {
if (!_action)
if (!_action || !(action.stateUpdateFlag & ActionStateUpdateFlag.inWidget))
return;
if (updateActionState(_action, force))
handleActionStateChanged();
@ -1189,7 +1189,13 @@ public:
Action action = findKeyAction(event.keyCode, event.flags); // & (KeyFlag.Shift | KeyFlag.Alt | KeyFlag.Control | KeyFlag.Menu)
if (action !is null) {
//Log.d("Action found: ", action.id, " ", action.labelValue.id);
return dispatchAction(action);
// update action state
if ((action.stateUpdateFlag & ActionStateUpdateFlag.inAccelerator) && updateActionState(action, true) && action is _action)
handleActionStateChanged();
//run only enabled actions
if (action.state.enabled)
return dispatchAction(action);
}
}
// handle focus navigation using keys