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 00000000..ffd0730d Binary files /dev/null and b/examples/example1/views/res/mdpi/edit-indent.png differ diff --git a/examples/example1/views/res/mdpi/edit-unindent.png b/examples/example1/views/res/mdpi/edit-unindent.png new file mode 100644 index 00000000..1e6f2cdb Binary files /dev/null and b/examples/example1/views/res/mdpi/edit-unindent.png differ diff --git a/examples/example1/views/resources.list b/examples/example1/views/resources.list index a1ea75c8..c767a4fe 100644 --- a/examples/example1/views/resources.list +++ b/examples/example1/views/resources.list @@ -9,8 +9,10 @@ res/mdpi/document-save-as.png res/mdpi/document-save.png res/mdpi/edit-copy.png res/mdpi/edit-cut.png +res/mdpi/edit-indent.png res/mdpi/edit-paste.png res/mdpi/edit-redo.png res/mdpi/edit-undo.png +res/mdpi/edit-unindent.png res/mdpi/tx_fabric.jpg res/theme_custom1.xml diff --git a/src/dlangui/core/editable.d b/src/dlangui/core/editable.d index f61427fd..ff032a62 100644 --- a/src/dlangui/core/editable.d +++ b/src/dlangui/core/editable.d @@ -598,8 +598,10 @@ class EditableContent { return TextPosition(lineIndex, lineLength(lineIndex)); } - /// returns text position for begin of line lineIndex + /// returns text position for begin of line lineIndex (if lineIndex > 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");