replace mode support in editors (toggled by INS)

This commit is contained in:
Vadim Lopatin 2014-04-24 15:14:50 +04:00
parent f5bf1bb9ec
commit 37194b81b2
2 changed files with 71 additions and 35 deletions

View File

@ -557,6 +557,9 @@ enum EditorActions {
/// insert new line after current position (Ctrl+Enter) /// insert new line after current position (Ctrl+Enter)
PrependNewLine, PrependNewLine,
/// Turn On/Off replace mode
ToggleReplaceMode,
/// Copy selection to clipboard /// Copy selection to clipboard
Copy, Copy,
/// Cut selection to clipboard /// Cut selection to clipboard
@ -590,8 +593,6 @@ class EditWidgetBase : WidgetGroup, EditableContentListener {
protected bool _useSpacesForTabs = false; protected bool _useSpacesForTabs = false;
protected bool _replaceMode; protected bool _replaceMode;
protected bool _readOnly;
this(string ID) { this(string ID) {
super(ID); super(ID);
@ -654,6 +655,9 @@ class EditWidgetBase : WidgetGroup, EditableContentListener {
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),
]); ]);
} }
@ -670,16 +674,12 @@ class EditWidgetBase : WidgetGroup, EditableContentListener {
/// readonly flag (when true, user cannot change content of editor) /// readonly flag (when true, user cannot change content of editor)
@property bool readOnly() { @property bool readOnly() {
return _readOnly; return !enabled;
} }
/// sets readonly flag /// sets readonly flag
@property EditWidgetBase readOnly(bool readOnly) { @property EditWidgetBase readOnly(bool readOnly) {
_readOnly = readOnly; enabled = !readOnly;
if (_readOnly)
resetState(State.Enabled);
else
setState(State.Enabled);
invalidate(); invalidate();
return this; return this;
} }
@ -768,6 +768,40 @@ class EditWidgetBase : WidgetGroup, EditableContentListener {
abstract protected Point measureVisibleText(); abstract protected Point measureVisibleText();
/// returns cursor rectangle
protected Rect caretRect() {
Rect caretRc = textPosToClient(_caretPos);
if (_replaceMode) {
dstring s = _content[_caretPos.line];
if (_caretPos.pos < s.length) {
TextPosition nextPos = _caretPos;
nextPos.pos++;
Rect nextRect = textPosToClient(nextPos);
caretRc.right = nextRect.right;
} else {
caretRc.right += _spaceWidth;
}
}
caretRc.offset(_clientRc.left, _clientRc.top);
return caretRc;
}
/// draws caret
protected void drawCaret(DrawBuf buf) {
if (focused) {
// draw caret
Rect caretRc = caretRect();
if (caretRc.intersects(_clientRc)) {
Rect rc1 = caretRc;
rc1.right = rc1.left + 1;
caretRc.left++;
if (_replaceMode)
buf.fillRect(caretRc, 0x808080FF);
buf.fillRect(rc1, 0x000000);
}
}
}
protected void updateFontProps() { protected void updateFontProps() {
FontRef font = font(); FontRef font = font();
_fixedFont = font.isFixed; _fixedFont = font.isFixed;
@ -933,7 +967,7 @@ class EditWidgetBase : WidgetGroup, EditableContentListener {
} }
return true; return true;
case EditorActions.DelPrevChar: case EditorActions.DelPrevChar:
if (_readOnly) if (readOnly)
return true; return true;
if (!_selectionRange.empty) { if (!_selectionRange.empty) {
// clear selection // clear selection
@ -960,7 +994,7 @@ class EditWidgetBase : WidgetGroup, EditableContentListener {
} }
return true; return true;
case EditorActions.DelNextChar: case EditorActions.DelNextChar:
if (_readOnly) if (readOnly)
return true; return true;
if (!_selectionRange.empty) { if (!_selectionRange.empty) {
EditOperation op = new EditOperation(EditAction.Replace, _selectionRange, [""d]); EditOperation op = new EditOperation(EditAction.Replace, _selectionRange, [""d]);
@ -993,7 +1027,7 @@ class EditWidgetBase : WidgetGroup, EditableContentListener {
if (!_selectionRange.empty) { if (!_selectionRange.empty) {
dstring selectionText = concatDStrings(_content.rangeText(_selectionRange)); dstring selectionText = concatDStrings(_content.rangeText(_selectionRange));
platform.setClipboardText(selectionText); platform.setClipboardText(selectionText);
if (_readOnly) if (readOnly)
return true; return true;
EditOperation op = new EditOperation(EditAction.Replace, _selectionRange, [""d]); EditOperation op = new EditOperation(EditAction.Replace, _selectionRange, [""d]);
_content.performOperation(op); _content.performOperation(op);
@ -1001,7 +1035,7 @@ class EditWidgetBase : WidgetGroup, EditableContentListener {
return true; return true;
case EditorActions.Paste: case EditorActions.Paste:
{ {
if (_readOnly) if (readOnly)
return true; return true;
dstring selectionText = platform.getClipboardText(); dstring selectionText = platform.getClipboardText();
dstring[] lines; dstring[] lines;
@ -1016,21 +1050,21 @@ class EditWidgetBase : WidgetGroup, EditableContentListener {
return true; return true;
case EditorActions.Undo: case EditorActions.Undo:
{ {
if (_readOnly) if (readOnly)
return true; return true;
_content.undo(); _content.undo();
} }
return true; return true;
case EditorActions.Redo: case EditorActions.Redo:
{ {
if (_readOnly) if (readOnly)
return true; return true;
_content.redo(); _content.redo();
} }
return true; return true;
case EditorActions.Tab: case EditorActions.Tab:
{ {
if (_readOnly) if (readOnly)
return true; return true;
if (_selectionRange.empty) { if (_selectionRange.empty) {
if (_useSpacesForTabs) { if (_useSpacesForTabs) {
@ -1064,7 +1098,7 @@ class EditWidgetBase : WidgetGroup, EditableContentListener {
return true; return true;
case EditorActions.BackTab: case EditorActions.BackTab:
{ {
if (_readOnly) if (readOnly)
return true; return true;
if (_selectionRange.empty) { if (_selectionRange.empty) {
// remove spaces before caret // remove spaces before caret
@ -1098,6 +1132,9 @@ class EditWidgetBase : WidgetGroup, EditableContentListener {
} }
} }
} }
return true;
case EditorActions.ToggleReplaceMode:
replaceMode = !replaceMode;
return true; return true;
default: default:
break; break;
@ -1195,7 +1232,7 @@ class EditWidgetBase : WidgetGroup, EditableContentListener {
/// map key to action /// map key to action
override protected Action findKeyAction(uint keyCode, uint flags) { override protected Action findKeyAction(uint keyCode, uint flags) {
// don't handle tabs when disabled // don't handle tabs when disabled
if (keyCode == KeyCode.TAB && (flags == 0 || flags == KeyFlag.Shift) && (!_wantTabs || _readOnly)) if (keyCode == KeyCode.TAB && (flags == 0 || flags == KeyFlag.Shift) && (!_wantTabs || readOnly))
return null; return null;
return super.findKeyAction(keyCode, flags); return super.findKeyAction(keyCode, flags);
} }
@ -1204,13 +1241,21 @@ class EditWidgetBase : WidgetGroup, EditableContentListener {
override bool onKeyEvent(KeyEvent event) { override bool onKeyEvent(KeyEvent event) {
if (event.action == KeyAction.Text && event.text.length) { if (event.action == KeyAction.Text && event.text.length) {
Log.d("text entered: ", event.text); Log.d("text entered: ", event.text);
if (_readOnly) if (readOnly)
return true; return true;
dchar ch = event.text[0]; dchar ch = event.text[0];
if (ch >= 32) { // ignore Backspace and Return if (ch >= 32) { // ignore Backspace, Tab, Return, etc. chars
if (replaceMode && _selectionRange.empty && _content[_caretPos.line].length >= _caretPos.pos + event.text.length) {
// replace next char(s)
TextRange range = _selectionRange;
range.end.pos += cast(int)event.text.length;
EditOperation op = new EditOperation(EditAction.Replace, range, [event.text]);
_content.performOperation(op);
} else {
EditOperation op = new EditOperation(EditAction.Replace, _selectionRange, [event.text]); EditOperation op = new EditOperation(EditAction.Replace, _selectionRange, [event.text]);
_content.performOperation(op); _content.performOperation(op);
} }
}
return true; return true;
} }
return super.onKeyEvent(event); return super.onKeyEvent(event);
@ -1411,12 +1456,8 @@ class EditLine : EditWidgetBase {
visibleRect.right = _clientRc.right; visibleRect.right = _clientRc.right;
drawLineBackground(buf, lineRect, visibleRect); drawLineBackground(buf, lineRect, visibleRect);
font.drawText(buf, rc.left - _scrollPos.x, rc.top, txt, textColor, tabSize); font.drawText(buf, rc.left - _scrollPos.x, rc.top, txt, textColor, tabSize);
if (focused) {
// draw caret drawCaret(buf);
Rect caretRc = textPosToClient(_caretPos);
caretRc.offset(_clientRc.left, _clientRc.top);
buf.fillRect(caretRc, 0x000000);
}
} }
} }
@ -1779,6 +1820,7 @@ class EditBox : EditWidgetBase, OnScrollHandler {
} }
} }
/// draw content /// draw content
override void onDraw(DrawBuf buf) { override void onDraw(DrawBuf buf) {
if (visibility != Visibility.Visible) if (visibility != Visibility.Visible)
@ -1809,13 +1851,7 @@ class EditBox : EditWidgetBase, OnScrollHandler {
} }
} }
//buf.fillRect(_clientRc, 0x80E0E0FF); // testing clientRc drawCaret(buf);
if (focused) {
// draw caret
Rect caretRc = textPosToClient(_caretPos);
caretRc.offset(_clientRc.left, _clientRc.top);
buf.fillRect(caretRc, 0x000000);
}
} }
} }

View File

@ -640,7 +640,7 @@ Theme createDefaultTheme() {
res.fontFace = "Verdana"; res.fontFace = "Verdana";
} }
//res.fontFace = "Arial Narrow"; //res.fontFace = "Arial Narrow";
res.fontSize = 13; // TODO: choose based on DPI res.fontSize = 15; // TODO: choose based on DPI
Style button = res.createSubstyle("BUTTON").backgroundImageId("btn_default_small").alignment(Align.Center); Style button = res.createSubstyle("BUTTON").backgroundImageId("btn_default_small").alignment(Align.Center);
res.createSubstyle("BUTTON_TRANSPARENT").backgroundImageId("btn_default_small_transparent").alignment(Align.Center); res.createSubstyle("BUTTON_TRANSPARENT").backgroundImageId("btn_default_small_transparent").alignment(Align.Center);
res.createSubstyle("BUTTON_LABEL").layoutWidth(FILL_PARENT).alignment(Align.Left|Align.VCenter); res.createSubstyle("BUTTON_LABEL").layoutWidth(FILL_PARENT).alignment(Align.Left|Align.VCenter);