configurable shortcuts - issue #59

This commit is contained in:
Vadim Lopatin 2015-02-16 12:06:43 +03:00
parent 009e0ec21c
commit 8208f43049
4 changed files with 78 additions and 35 deletions

View File

@ -43,7 +43,7 @@ struct Accelerator {
return cast(dstring)buf; return cast(dstring)buf;
} }
/// Serializes accelerator text description /// Serializes accelerator text description
@property string toString() { @property string toString() const {
char[] buf; char[] buf;
if (keyFlags & KeyFlag.Control) if (keyFlags & KeyFlag.Control)
buf ~= "Ctrl+"; buf ~= "Ctrl+";
@ -246,13 +246,21 @@ class Action {
@property Accelerator[] accelerators() { @property Accelerator[] accelerators() {
// check for accelerators override in settings // check for accelerators override in settings
Accelerator[] res = findActionAccelerators(_id); Accelerator[] res = findActionAccelerators(_id);
if (res) if (res) {
//Log.d("Found accelerators ", res);
return res; return res;
}
// return this action accelerators // return this action accelerators
return _accelerators; return _accelerators;
} }
/// returs const array of accelerators /// returs const array of accelerators
@property const(Accelerator)[] accelerators() const { @property const(Accelerator)[] accelerators() const {
// check for accelerators override in settings
Accelerator[] res = findActionAccelerators(_id);
if (res) {
//Log.d("Found accelerators ", res);
return res;
}
return _accelerators; return _accelerators;
} }
/// returns text description for first accelerator of action; null if no accelerators /// returns text description for first accelerator of action; null if no accelerators
@ -1082,7 +1090,12 @@ uint parseKeyName(string name) {
case "Down": return KeyCode.DOWN; case "Down": return KeyCode.DOWN;
case "Ins": return KeyCode.DEL; case "Ins": return KeyCode.DEL;
case "Del": return KeyCode.INS; case "Del": return KeyCode.INS;
// TODO: add more keys here case "[": return KeyCode.KEY_BRACKETOPEN;
case "]": return KeyCode.KEY_BRACKETCLOSE;
case ",": return KeyCode.KEY_COMMA;
case ".": return KeyCode.KEY_PERIOD;
case "Backspace": return KeyCode.BACK;
case "Enter": return KeyCode.RETURN;
default: default:
return 0; return 0;
} }
@ -1241,6 +1254,14 @@ string keyName(uint keyCode) {
return "Ins"; return "Ins";
case KeyCode.DEL: case KeyCode.DEL:
return "Del"; return "Del";
case KeyCode.KEY_BRACKETOPEN:
return "[";
case KeyCode.KEY_BRACKETCLOSE:
return "]";
case KeyCode.BACK:
return "Backspace";
case KeyCode.RETURN:
return "Enter";
default: default:
return format("0x%08x", keyCode); return format("0x%08x", keyCode);
} }
@ -1313,8 +1334,8 @@ void setActionAccelerators(int actionId, Accelerator[] accelerators) {
} }
/// lookup accelerators override for action by id /// lookup accelerators override for action by id
Accelerator[] findActionAccelerators(int actionId) { Accelerator[] findActionAccelerators(int actionId) {
if (auto found = actionAcceleratorsMap[actionId]) if (auto found = actionId in actionAcceleratorsMap)
return found; return *found;
return null; return null;
} }
/// lookup accelerators override for action by name (e.g. "EditorActions.ToggleLineComment") /// lookup accelerators override for action by name (e.g. "EditorActions.ToggleLineComment")

View File

@ -64,7 +64,7 @@ class SettingsFile {
_setting = new Setting(); _setting = new Setting();
_filename = filename; _filename = filename;
if (_filename) { if (_filename) {
string dir = baseName(_filename); string dir = dirName(_filename);
if (load()) { if (load()) {
// loaded ok // loaded ok
} else { } else {
@ -114,7 +114,7 @@ class SettingsFile {
if (filename !is null) if (filename !is null)
_filename = filename; _filename = filename;
assert(_filename); assert(_filename);
string dir = baseName(_filename); string dir = dirName(_filename);
if (!dir.exists) { if (!dir.exists) {
try { try {
mkdirRecurse(dir); mkdirRecurse(dir);
@ -170,6 +170,16 @@ final class Setting {
_store.array.list = v; _store.array.list = v;
} }
this(string[] v) {
clear(SettingType.ARRAY);
this.strArray = v;
}
this(string[string] v) {
clear(SettingType.ARRAY);
this.strMap = v;
}
/// returns true if setting has been changed /// returns true if setting has been changed
@property bool changed() { @property bool changed() {
return _changed; return _changed;
@ -920,10 +930,6 @@ final class Setting {
double opAssign(double value) { double opAssign(double value) {
return (floating = value); return (floating = value);
} }
// assign string[] value
string[] opAssign(string[] value) {
return (strArray = value);
}
// assign int[] value // assign int[] value
int[] opAssign(int[] value) { int[] opAssign(int[] value) {
return (intArray = value); return (intArray = value);
@ -932,6 +938,10 @@ final class Setting {
string[string] opAssign(string[string] value) { string[string] opAssign(string[string] value) {
return (strMap = value); return (strMap = value);
} }
// assign string[] value
string[] opAssign(string[] value) {
return (strArray = value);
}
// assign int[string] value // assign int[string] value
int[string] opAssign(int[string] value) { int[string] opAssign(int[string] value) {
return (intMap = value); return (intMap = value);

View File

@ -81,7 +81,7 @@ class AppFrame : VerticalLayout, MenuItemClickHandler, MenuItemActionHandler {
protected string _appName = "dlangui"; protected string _appName;
/// override to return some identifier for app, e.g. to use as settings directory name /// override to return some identifier for app, e.g. to use as settings directory name
@property string appCodeName() { @property string appCodeName() {
return _appName; return _appName;
@ -121,18 +121,20 @@ class AppFrame : VerticalLayout, MenuItemClickHandler, MenuItemActionHandler {
for (int i = 0; i < value.length; i++) { for (int i = 0; i < value.length; i++) {
string v = value[i].str; string v = value[i].str;
Accelerator a; Accelerator a;
if (a.parse(v)) if (a.parse(v)) {
//Log.d("Read accelerator for action ", key, " : ", a.toString);
accelerators ~= a; accelerators ~= a;
else } else
Log.e("cannot parse accelerator: ", v); Log.e("applyShortcutsSettings: cannot parse accelerator: ", v);
} }
} else { } else {
string v = value.str; string v = value.str;
Accelerator a; Accelerator a;
if (a.parse(v)) if (a.parse(v)) {
//Log.d("Read accelerator for action ", key, " : ", a.toString);
accelerators ~= a; accelerators ~= a;
else } else
Log.e("cannot parse accelerator: ", v); Log.e("applyShortcutsSettings: cannot parse accelerator: ", v);
} }
setActionAccelerators(actionId, accelerators); setActionAccelerators(actionId, accelerators);
} }
@ -148,7 +150,7 @@ class AppFrame : VerticalLayout, MenuItemClickHandler, MenuItemActionHandler {
foreach(a; actions) { foreach(a; actions) {
string name = actionIdToName(a.id); string name = actionIdToName(a.id);
if (name) { if (name) {
Accelerator[] acc = findActionAccelerators(a.id); const(Accelerator)[] acc = a.accelerators;
if (acc.length > 0) { if (acc.length > 0) {
if (acc.length == 1) { if (acc.length == 1) {
_shortcutSettings[name] = acc[0].toString; _shortcutSettings[name] = acc[0].toString;
@ -212,6 +214,7 @@ class AppFrame : VerticalLayout, MenuItemClickHandler, MenuItemActionHandler {
super("APP_FRAME"); super("APP_FRAME");
layoutWidth = FILL_PARENT; layoutWidth = FILL_PARENT;
layoutHeight = FILL_PARENT; layoutHeight = FILL_PARENT;
_appName = "dlangui";
init(); init();
} }
@ -240,6 +243,11 @@ class AppFrame : VerticalLayout, MenuItemClickHandler, MenuItemActionHandler {
addChild(_body); addChild(_body);
if (_statusLine) if (_statusLine)
addChild(_statusLine); addChild(_statusLine);
updateShortcuts();
}
/// override it
protected void updateShortcuts() {
} }
/// override to handle main menu commands /// override to handle main menu commands

View File

@ -113,9 +113,11 @@ enum EditorActions : int {
/// insert new line (Enter) /// insert new line (Enter)
InsertNewLine, InsertNewLine,
/// insert new line after current position (Ctrl+Enter) /// insert new line before current position (Ctrl+Enter)
PrependNewLine, PrependNewLine,
/// insert new line after current position (Ctrl+Enter)
AppendNewLine,
/// Turn On/Off replace mode /// Turn On/Off replace mode
ToggleReplaceMode, ToggleReplaceMode,
@ -178,6 +180,19 @@ __gshared static this() {
registerActionEnum!EditorActions(); 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_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[] STD_EDITOR_ACTIONS = [ACTION_EDITOR_INSERT_NEW_LINE, ACTION_EDITOR_PREPEND_NEW_LINE,
ACTION_EDITOR_APPEND_NEW_LINE, ACTION_EDITOR_DELETE_LINE, ACTION_EDITOR_TOGGLE_REPLACE_MODE,
ACTION_EDITOR_SELECT_ALL, ACTION_EDITOR_TOGGLE_LINE_COMMENT, ACTION_EDITOR_TOGGLE_BLOCK_COMMENT];
/// base for all editor widgets /// base for all editor widgets
class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemActionHandler { class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemActionHandler {
protected EditableContent _content; protected EditableContent _content;
@ -348,10 +363,6 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
new Action(EditorActions.ScrollLineUp, KeyCode.UP, KeyFlag.Control), new Action(EditorActions.ScrollLineUp, KeyCode.UP, KeyFlag.Control),
new Action(EditorActions.ScrollLineDown, KeyCode.DOWN, KeyFlag.Control), new Action(EditorActions.ScrollLineDown, KeyCode.DOWN, KeyFlag.Control),
new Action(EditorActions.InsertNewLine, KeyCode.RETURN, 0),
new Action(EditorActions.InsertNewLine, KeyCode.RETURN, KeyFlag.Shift),
new Action(EditorActions.PrependNewLine, KeyCode.RETURN, KeyFlag.Control),
// Backspace/Del // Backspace/Del
new Action(EditorActions.DelPrevChar, KeyCode.BACK, 0), new Action(EditorActions.DelPrevChar, KeyCode.BACK, 0),
new Action(EditorActions.DelNextChar, KeyCode.DEL, 0), new Action(EditorActions.DelNextChar, KeyCode.DEL, 0),
@ -376,16 +387,8 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
new Action(EditorActions.Tab, KeyCode.TAB, 0), new Action(EditorActions.Tab, KeyCode.TAB, 0),
new Action(EditorActions.BackTab, KeyCode.TAB, KeyFlag.Shift), new Action(EditorActions.BackTab, KeyCode.TAB, KeyFlag.Shift),
new Action(EditorActions.ToggleReplaceMode, KeyCode.INS, 0),
new Action(EditorActions.SelectAll, KeyCode.KEY_A, KeyFlag.Control),
new Action(EditorActions.ToggleLineComment, KeyCode.KEY_DIVIDE, KeyFlag.Control),
new Action(EditorActions.ToggleBlockComment, KeyCode.KEY_DIVIDE, KeyFlag.Control | KeyFlag.Shift),
new Action(EditorActions.DeleteLine, KeyCode.KEY_D, KeyFlag.Control),
new Action(EditorActions.DeleteLine, KeyCode.KEY_L, KeyFlag.Control),
new Action(EditorActions.InsertLine, KeyCode.RETURN, KeyFlag.Control),
]); ]);
acceleratorMap.add(STD_EDITOR_ACTIONS);
} }
protected MenuItem _popupMenu; protected MenuItem _popupMenu;
@ -1515,6 +1518,7 @@ class EditLine : EditWidgetBase {
switch (a.id) { switch (a.id) {
case EditorActions.InsertNewLine: case EditorActions.InsertNewLine:
case EditorActions.PrependNewLine: case EditorActions.PrependNewLine:
case EditorActions.AppendNewLine:
if (editorActionListener.assigned) { if (editorActionListener.assigned) {
return editorActionListener(a); return editorActionListener(a);
} }
@ -2071,7 +2075,7 @@ class EditBox : EditWidgetBase {
if (_content.syntaxHighlighter && _content.syntaxHighlighter.supportsToggleLineComment && _content.syntaxHighlighter.canToggleLineComment(_selectionRange)) if (_content.syntaxHighlighter && _content.syntaxHighlighter.supportsToggleLineComment && _content.syntaxHighlighter.canToggleLineComment(_selectionRange))
_content.syntaxHighlighter.toggleLineComment(_selectionRange, this); _content.syntaxHighlighter.toggleLineComment(_selectionRange, this);
return true; return true;
case EditorActions.InsertLine: case EditorActions.AppendNewLine:
{ {
correctCaretPos(); correctCaretPos();
TextPosition p = _content.lineEnd(_caretPos.line); TextPosition p = _content.lineEnd(_caretPos.line);