From 6bb69b2471baf9d5979f735f8f296943625d6018 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Mon, 9 Feb 2015 09:45:23 +0300 Subject: [PATCH] indent/unindent editor actions improved --- examples/example1/src/example1.d | 4 ++ examples/example1/views/res/i18n/en.ini | 2 + .../example1/views/res/mdpi/edit-indent.png | Bin 0 -> 413 bytes .../example1/views/res/mdpi/edit-unindent.png | Bin 0 -> 367 bytes examples/example1/views/resources.list | 2 + src/dlangui/core/editable.d | 4 +- src/dlangui/widgets/editors.d | 52 ++++++++++++++---- src/dlangui/widgets/srcedit.d | 1 + 8 files changed, 54 insertions(+), 11 deletions(-) create mode 100644 examples/example1/views/res/mdpi/edit-indent.png create mode 100644 examples/example1/views/res/mdpi/edit-unindent.png diff --git a/examples/example1/src/example1.d b/examples/example1/src/example1.d index 42835599..28aa18bc 100644 --- a/examples/example1/src/example1.d +++ b/examples/example1/src/example1.d @@ -280,6 +280,8 @@ extern (C) int UIAppMain(string[] args) { editItem.add(new Action(EditorActions.Cut, "MENU_EDIT_CUT"c, "edit-cut", KeyCode.KEY_X, KeyFlag.Control)); editItem.add(new Action(EditorActions.Undo, "MENU_EDIT_UNDO"c, "edit-undo", KeyCode.KEY_Z, KeyFlag.Control)); editItem.add(new Action(EditorActions.Redo, "MENU_EDIT_REDO"c, "edit-redo", KeyCode.KEY_Y, KeyFlag.Control)); + editItem.add(new Action(EditorActions.Indent, "MENU_EDIT_INDENT"c, "edit-indent", KeyCode.TAB, 0)); + editItem.add(new Action(EditorActions.Unindent, "MENU_EDIT_UNINDENT"c, "edit-unindent", KeyCode.TAB, KeyFlag.Control)); editItem.add(new Action(20, "MENU_EDIT_PREFERENCES")); MenuItem editPopupItem = new MenuItem(null); @@ -288,6 +290,8 @@ extern (C) int UIAppMain(string[] args) { editPopupItem.add(new Action(EditorActions.Cut, "MENU_EDIT_CUT"c, "edit-cut", KeyCode.KEY_X, KeyFlag.Control)); editPopupItem.add(new Action(EditorActions.Undo, "MENU_EDIT_UNDO"c, "edit-undo", KeyCode.KEY_Z, KeyFlag.Control)); editPopupItem.add(new Action(EditorActions.Redo, "MENU_EDIT_REDO"c, "edit-redo", KeyCode.KEY_Y, KeyFlag.Control)); + editPopupItem.add(new Action(EditorActions.Indent, "MENU_EDIT_INDENT"c, "edit-indent", KeyCode.TAB, 0)); + editPopupItem.add(new Action(EditorActions.Unindent, "MENU_EDIT_UNINDENT"c, "edit-unindent", KeyCode.TAB, KeyFlag.Control)); MenuItem viewItem = new MenuItem(new Action(60, "MENU_VIEW")); MenuItem langItem = new MenuItem(new Action(61, "MENU_VIEW_LANGUAGE")); diff --git a/examples/example1/views/res/i18n/en.ini b/examples/example1/views/res/i18n/en.ini index f0415321..87cfc368 100644 --- a/examples/example1/views/res/i18n/en.ini +++ b/examples/example1/views/res/i18n/en.ini @@ -10,6 +10,8 @@ MENU_EDIT_PASTE=&Paste MENU_EDIT_CUT=Cu&t MENU_EDIT_UNDO=&Undo MENU_EDIT_REDO=&Redo +MENU_EDIT_INDENT=Indent block +MENU_EDIT_UNINDENT=Unindent block MENU_EDIT_PREFERENCES=&Preferences MENU_VIEW=&View MENU_VIEW_LANGUAGE=Interface &Language diff --git a/examples/example1/views/res/mdpi/edit-indent.png b/examples/example1/views/res/mdpi/edit-indent.png new file mode 100644 index 0000000000000000000000000000000000000000..ffd0730d8fb289098ee222778cf7d986a89cb79b GIT binary patch literal 413 zcmV;O0b>4%P)Px#24YJ`L;zd>SO8c9zdw5b000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2j2n+ z5)%~kU!5cX00A9IL_t(I%f*vTO2beP$A2@ELa5{f^#Gou9w6I-?iH8zB<|{7q1zll zkC3$oP=tO!Xt2;EWL&iN1KU_};lLl><30W}^Lz6I;Ih|qj*N%lP`3BVA434#o$+LX zs-hx@Dk8Gf>S7c{h{!jC;A>%Ks4DqvMw+H8`=vn~$KF%`?oO6v%<`NhNpSZa0e(Om z24;q-a&!0Y0F&u--Nq`@K5YzC6*B|i^!(mU^>~P#?qF|^FUf_d87J-bK?aR!&f>=( zD``A^d%l)13>z7&U!f=ps;Z*X9eAfZ@Q?ZYCi`h}2ZGU}nfkI58?1n4i9~h6^V&8EnY(qzHrDXQT9hderyr0NE!9&Pn=%AB1NIc>o29afEqmS47?XN(wnvM} za|d} number of lines, returns end of last line) TextPosition lineBegin(int lineIndex) { + if (lineIndex >= _lines.length) + return lineEnd(lineIndex - 1); return TextPosition(lineIndex, 0); } diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index f5a4b08b..e2baecab 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -134,7 +134,11 @@ enum EditorActions : int { Tab, /// Tab (unindent text, or remove whitespace before cursor, usually Shift+Tab) BackTab, - + /// Indent text block or single line + Indent, + /// Unindent text + Unindent, + /// Select whole content (usually, Ctrl+A) SelectAll, @@ -414,6 +418,8 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction case EditorActions.ToggleLineComment: case EditorActions.Tab: case EditorActions.BackTab: + case EditorActions.Indent: + case EditorActions.Unindent: return enabled; case EditorActions.Copy: return !_selectionRange.empty; @@ -910,6 +916,8 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction case EditorActions.ToggleLineComment: case EditorActions.Tab: case EditorActions.BackTab: + case EditorActions.Indent: + case EditorActions.Unindent: if (isActionEnabled(a)) a.state = ACTION_STATE_ENABLED; else @@ -1108,6 +1116,12 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction return true; _content.redo(this); } + return true; + case EditorActions.Indent: + indentRange(false); + return true; + case EditorActions.Unindent: + indentRange(true); return true; case EditorActions.Tab: { @@ -1126,7 +1140,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction } else { if (wholeLinesSelected()) { // indent range - indentRange(false); + return handleAction(new Action(EditorActions.Indent)); } else { // insert tab if (_useSpacesForTabs) { @@ -1157,7 +1171,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction } else { if (wholeLinesSelected()) { // unindent range - indentRange(true); + return handleAction(new Action(EditorActions.Unindent)); } else { // remove space before selection TextRange r = spaceBefore(_selectionRange.start); @@ -1224,10 +1238,11 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction } /// change line indent - protected dstring indentLine(dstring src, bool back) { + protected dstring indentLine(dstring src, bool back, TextPosition * cursorPos) { int firstNonSpace = -1; int x = 0; int unindentPos = -1; + int cursor = cursorPos ? cursorPos.pos : 0; for (int i = 0; i < src.length; i++) { dchar ch = src[i]; if (ch == ' ') { @@ -1247,14 +1262,23 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction // unindent if (unindentPos == -1) return src; // no change - if (unindentPos == src.length) + if (unindentPos == src.length) { + if (cursorPos) + cursorPos.pos = 0; return ""d; + } + if (cursor >= unindentPos) + cursorPos.pos -= unindentPos; return src[unindentPos .. $].dup; } else { // indent if (_useSpacesForTabs) { + if (cursor > 0) + cursorPos.pos += tabSize; return spacesForTab(0) ~ src; } else { + if (cursor > 0) + cursorPos.pos++; return "\t"d ~ src; } } @@ -1262,20 +1286,28 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction /// indent / unindent range protected void indentRange(bool back) { - int lineCount = _selectionRange.end.line - _selectionRange.start.line; + TextRange r = _selectionRange; + r.start.pos = 0; + if (r.end.pos > 0) + r.end = _content.lineBegin(r.end.line + 1); + if (r.end.line <= r.start.line) + r = TextRange(_content.lineBegin(_caretPos.line), _content.lineBegin(_caretPos.line + 1)); + int lineCount = r.end.line - r.start.line; + if (r.end.pos > 0) + lineCount++; dstring[] newContent = new dstring[lineCount + 1]; bool changed = false; for (int i = 0; i < lineCount; i++) { - dstring srcline = _content.line(_selectionRange.start.line + i); - dstring dstline = indentLine(srcline, back); + dstring srcline = _content.line(r.start.line + i); + dstring dstline = indentLine(srcline, back, r.start.line + i == _caretPos.line ? &_caretPos : null); newContent[i] = dstline; if (dstline.length != srcline.length) changed = true; } if (changed) { - TextRange saveRange = _selectionRange; + TextRange saveRange = r; TextPosition saveCursor = _caretPos; - EditOperation op = new EditOperation(EditAction.Replace, _selectionRange, newContent); + EditOperation op = new EditOperation(EditAction.Replace, r, newContent); _content.performOperation(op, this); _selectionRange = saveRange; _caretPos = saveCursor; diff --git a/src/dlangui/widgets/srcedit.d b/src/dlangui/widgets/srcedit.d index a61bac25..0ed37eac 100644 --- a/src/dlangui/widgets/srcedit.d +++ b/src/dlangui/widgets/srcedit.d @@ -34,6 +34,7 @@ class SourceEdit : EditBox { showModificationMarks = true; _showLineNumbers = true; + } this() { this("SRCEDIT");