From f5bf1bb9ec1734c4c17de0d53d6a09060ba5fd6c Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Thu, 24 Apr 2014 14:37:53 +0400 Subject: [PATCH] editor readonly mode support --- examples/example1/src/main.d | 1 + res/editbox_background.xml | 2 + res/mdpi/editbox_background_disabled.9.png | Bin 0 -> 3047 bytes ...box_background_disabled_focus_yellow.9.png | Bin 0 -> 3375 bytes src/dlangui/platforms/windows/winapp.d | 4 +- src/dlangui/widgets/editors.d | 85 +++++++++++------- 6 files changed, 60 insertions(+), 32 deletions(-) create mode 100644 res/mdpi/editbox_background_disabled.9.png create mode 100644 res/mdpi/editbox_background_disabled_focus_yellow.9.png diff --git a/examples/example1/src/main.d b/examples/example1/src/main.d index f7f58a12..b15bb318 100644 --- a/examples/example1/src/main.d +++ b/examples/example1/src/main.d @@ -11,6 +11,7 @@ Widget createEditorSettingsControl(EditWidgetBase editor) { HorizontalLayout res = new HorizontalLayout("editor_options"); res.addChild((new CheckBox("wantTabs", "wantTabs"d)).checked(editor.wantTabs).addOnCheckChangeListener(delegate(Widget, bool checked) { editor.wantTabs = checked; return true;})); res.addChild((new CheckBox("useSpacesForTabs", "useSpacesForTabs"d)).checked(editor.useSpacesForTabs).addOnCheckChangeListener(delegate(Widget, bool checked) { editor.useSpacesForTabs = checked; return true;})); + res.addChild((new CheckBox("readOnly", "readOnly"d)).checked(editor.readOnly).addOnCheckChangeListener(delegate(Widget, bool checked) { editor.readOnly = checked; return true;})); res.addChild((new CheckBox("fixedFont", "fixedFont"d)).checked(editor.fontFamily == FontFamily.MonoSpace).addOnCheckChangeListener(delegate(Widget, bool checked) { if (checked) editor.fontFamily(FontFamily.MonoSpace).fontFace("Courier New"); diff --git a/res/editbox_background.xml b/res/editbox_background.xml index 976a2127..dce9c53f 100644 --- a/res/editbox_background.xml +++ b/res/editbox_background.xml @@ -18,7 +18,9 @@ */ --> + + diff --git a/res/mdpi/editbox_background_disabled.9.png b/res/mdpi/editbox_background_disabled.9.png new file mode 100644 index 0000000000000000000000000000000000000000..7a9597ac2133f307ac9dad067dded07d82c54522 GIT binary patch literal 3047 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 FV1jzGMvDLd literal 0 HcmV?d00001 diff --git a/src/dlangui/platforms/windows/winapp.d b/src/dlangui/platforms/windows/winapp.d index b619d273..c9d065ae 100644 --- a/src/dlangui/platforms/windows/winapp.d +++ b/src/dlangui/platforms/windows/winapp.d @@ -659,8 +659,8 @@ int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int Platform.setInstance(platform); - if (true) { - /// testing freetype font manager + /// testing freetype font manager + if (false) { import dlangui.graphics.ftfonts; import win32.shlobj; FreeTypeFontManager ftfontMan = new FreeTypeFontManager(); diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index cdbe163f..0d500d70 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -224,9 +224,9 @@ class UndoBuffer { /// adds undo operation void saveForUndo(EditOperation op) { + _redoList.clear(); if (!_undoList.empty) { if (_undoList.back.merge(op)) { - _redoList.clear(); return; // merged - no need to add new operation } } @@ -589,6 +589,9 @@ class EditWidgetBase : WidgetGroup, EditableContentListener { protected bool _wantTabs = true; protected bool _useSpacesForTabs = false; + protected bool _replaceMode; + protected bool _readOnly; + this(string ID) { super(ID); @@ -665,6 +668,34 @@ class EditWidgetBase : WidgetGroup, EditableContentListener { return this; } + /// readonly flag (when true, user cannot change content of editor) + @property bool readOnly() { + return _readOnly; + } + + /// sets readonly flag + @property EditWidgetBase readOnly(bool readOnly) { + _readOnly = readOnly; + if (_readOnly) + resetState(State.Enabled); + else + setState(State.Enabled); + invalidate(); + return this; + } + + /// replace mode flag (when true, entered character replaces character under cursor) + @property bool replaceMode() { + return _replaceMode; + } + + /// sets replace mode flag + @property EditWidgetBase replaceMode(bool replaceMode) { + _replaceMode = replaceMode; + invalidate(); + return this; + } + /// when true, spaces will be inserted instead of tabs @property bool useSpacesForTabs() { return _useSpacesForTabs; @@ -902,6 +933,8 @@ class EditWidgetBase : WidgetGroup, EditableContentListener { } return true; case EditorActions.DelPrevChar: + if (_readOnly) + return true; if (!_selectionRange.empty) { // clear selection EditOperation op = new EditOperation(EditAction.Replace, _selectionRange, [""d]); @@ -927,6 +960,8 @@ class EditWidgetBase : WidgetGroup, EditableContentListener { } return true; case EditorActions.DelNextChar: + if (_readOnly) + return true; if (!_selectionRange.empty) { EditOperation op = new EditOperation(EditAction.Replace, _selectionRange, [""d]); _content.performOperation(op); @@ -958,12 +993,16 @@ class EditWidgetBase : WidgetGroup, EditableContentListener { if (!_selectionRange.empty) { dstring selectionText = concatDStrings(_content.rangeText(_selectionRange)); platform.setClipboardText(selectionText); + if (_readOnly) + return true; EditOperation op = new EditOperation(EditAction.Replace, _selectionRange, [""d]); _content.performOperation(op); } return true; case EditorActions.Paste: { + if (_readOnly) + return true; dstring selectionText = platform.getClipboardText(); dstring[] lines; if (_content.multiline) { @@ -977,16 +1016,22 @@ class EditWidgetBase : WidgetGroup, EditableContentListener { return true; case EditorActions.Undo: { + if (_readOnly) + return true; _content.undo(); } return true; case EditorActions.Redo: { + if (_readOnly) + return true; _content.redo(); } return true; case EditorActions.Tab: { + if (_readOnly) + return true; if (_selectionRange.empty) { if (_useSpacesForTabs) { // insert one or more spaces to @@ -1019,6 +1064,8 @@ class EditWidgetBase : WidgetGroup, EditableContentListener { return true; case EditorActions.BackTab: { + if (_readOnly) + return true; if (_selectionRange.empty) { // remove spaces before caret TextRange r = spaceBefore(_caretPos); @@ -1148,27 +1195,23 @@ class EditWidgetBase : WidgetGroup, EditableContentListener { /// map key to action override protected Action findKeyAction(uint keyCode, uint flags) { // don't handle tabs when disabled - if (keyCode == KeyCode.TAB && (flags == 0 || flags == KeyFlag.Shift) && !_wantTabs) + if (keyCode == KeyCode.TAB && (flags == 0 || flags == KeyFlag.Shift) && (!_wantTabs || _readOnly)) return null; return super.findKeyAction(keyCode, flags); } /// 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) { - // - //} - } else if (event.action == KeyAction.Text && event.text.length) { + if (event.action == KeyAction.Text && event.text.length) { Log.d("text entered: ", event.text); + if (_readOnly) + return true; dchar ch = event.text[0]; if (ch >= 32) { // ignore Backspace and Return EditOperation op = new EditOperation(EditAction.Replace, _selectionRange, [event.text]); _content.performOperation(op); - return true; } + return true; } return super.onKeyEvent(event); } @@ -1286,24 +1329,6 @@ class EditLine : EditWidgetBase { override protected bool handleAction(Action a) { switch (a.id) { - /* - case EditorActions.DelPrevChar: - if (_caretPos.pos > 0) { - TextRange range = TextRange(_caretPos, _caretPos); - range.start.pos--; - EditOperation op = new EditOperation(EditAction.Replace, range, [""d]); - _content.performOperation(op); - } - return true; - case EditorActions.DelNextChar: - if (_caretPos.pos < _measuredText.length) { - TextRange range = TextRange(_caretPos, _caretPos); - range.end.pos++; - EditOperation op = new EditOperation(EditAction.Replace, range, [""d]); - _content.performOperation(op); - } - return true; - */ case EditorActions.Up: break; case EditorActions.Down: @@ -1372,8 +1397,8 @@ class EditLine : EditWidgetBase { super.onDraw(buf); Rect rc = _pos; applyMargins(rc); - auto saver = ClipRectSaver(buf, rc); applyPadding(rc); + auto saver = ClipRectSaver(buf, rc); FontRef font = font(); dstring txt = text; Point sz = font.textSize(txt); @@ -1385,7 +1410,7 @@ class EditLine : EditWidgetBase { visibleRect.left = _clientRc.left; visibleRect.right = _clientRc.right; drawLineBackground(buf, lineRect, visibleRect); - font.drawText(buf, rc.left - _scrollPos.x, rc.top + sz.y / 10, txt, textColor, tabSize); + font.drawText(buf, rc.left - _scrollPos.x, rc.top, txt, textColor, tabSize); if (focused) { // draw caret Rect caretRc = textPosToClient(_caretPos);