clipboard support in editors, part 1

This commit is contained in:
Vadim Lopatin 2014-04-23 10:00:16 +04:00
parent 99e4e4e732
commit 4348b859c7
3 changed files with 92 additions and 2 deletions

View File

@ -484,6 +484,11 @@ class Platform {
abstract void setClipboardText(dstring text, bool mouseBuffer = false); abstract void setClipboardText(dstring text, bool mouseBuffer = false);
} }
/// get current platform object instance
@property Platform platform() {
return Platform.instance;
}
version (USE_OPENGL) { version (USE_OPENGL) {
private __gshared bool _OPENGL_ENABLED = false; private __gshared bool _OPENGL_ENABLED = false;
/// check if hardware acceleration is enabled /// check if hardware acceleration is enabled

View File

@ -23,6 +23,7 @@ module dlangui.widgets.editors;
import dlangui.widgets.widget; import dlangui.widgets.widget;
import dlangui.widgets.controls; import dlangui.widgets.controls;
import dlangui.core.signals; import dlangui.core.signals;
import dlangui.platforms.common.platform;
import std.algorithm; import std.algorithm;
@ -32,10 +33,15 @@ immutable dchar EOL = '\n';
dstring[] splitDString(dstring source, dchar delimiter = EOL) { dstring[] splitDString(dstring source, dchar delimiter = EOL) {
int start = 0; int start = 0;
dstring[] res; dstring[] res;
dchar lastchar;
for (int i = 0; i <= source.length; i++) { for (int i = 0; i <= source.length; i++) {
if (i == source.length || source[i] == delimiter) { if (i == source.length || source[i] == delimiter) {
if (i >= start) { if (i >= start) {
dstring line = i > start ? cast(dstring)(source[start .. i].dup) : ""d; dchar prevchar = i > 1 && i > start + 1 ? source[i - 1] : 0;
int end = i;
if (delimiter == EOL && prevchar == '\r') // windows CR/LF
end--;
dstring line = i > start ? cast(dstring)(source[start .. end].dup) : ""d;
res ~= line; res ~= line;
} }
start = i + 1; start = i + 1;
@ -44,6 +50,41 @@ dstring[] splitDString(dstring source, dchar delimiter = EOL) {
return res; return res;
} }
version (Windows) {
immutable dstring SYSTEM_DEFAULT_EOL = "\r\n";
} else {
immutable dstring SYSTEM_DEFAULT_EOL = "\n";
}
/// concat strings from array using delimiter
dstring concatDStrings(dstring[] lines, dstring delimiter = SYSTEM_DEFAULT_EOL) {
dchar[] buf;
foreach(line; lines) {
if (buf.length)
buf ~= delimiter;
buf ~= line;
}
return cast(dstring)buf;
}
/// replace end of lines with spaces
dstring replaceEolsWithSpaces(dstring source) {
dchar[] buf;
dchar lastch;
foreach(ch; source) {
if (ch == '\r') {
buf ~= ' ';
} else if (ch == '\n') {
if (lastch != '\r')
buf ~= ' ';
} else {
buf ~= ch;
}
lastch = ch;
}
return cast(dstring)buf;
}
/// text content position /// text content position
struct TextPosition { struct TextPosition {
/// line number, zero based /// line number, zero based
@ -137,6 +178,9 @@ class EditableContent {
_lines.length = 1; // initial state: single empty line _lines.length = 1; // initial state: single empty line
} }
protected bool _multiline; protected bool _multiline;
/// returns true if miltyline content is supported
@property bool multiline() { return _multiline; }
protected dstring[] _lines; protected dstring[] _lines;
/// returns all lines concatenated delimited by '\n' /// returns all lines concatenated delimited by '\n'
@property dstring text() { @property dstring text() {
@ -358,6 +402,12 @@ enum EditorActions {
DelNextWord, DelNextWord,
/// insert new line (Enter) /// insert new line (Enter)
InsertNewLine, InsertNewLine,
/// Copy selection to clipboard
Copy,
/// Cut selection to clipboard
Cut,
/// Paste selection from clipboard
Paste,
} }
/// base for all editor widgets /// base for all editor widgets
@ -410,6 +460,14 @@ class EditWidgetBase : WidgetGroup, EditableContentListener {
new Action(EditorActions.DelNextChar, KeyCode.DEL, 0), new Action(EditorActions.DelNextChar, KeyCode.DEL, 0),
new Action(EditorActions.DelPrevWord, KeyCode.BACK, KeyFlag.Control), new Action(EditorActions.DelPrevWord, KeyCode.BACK, KeyFlag.Control),
new Action(EditorActions.DelNextWord, KeyCode.DEL, KeyFlag.Control), new Action(EditorActions.DelNextWord, KeyCode.DEL, KeyFlag.Control),
new Action(EditorActions.Copy, KeyCode.KEY_C, KeyFlag.Control),
new Action(EditorActions.Copy, KeyCode.INS, KeyFlag.Control),
new Action(EditorActions.Cut, KeyCode.KEY_X, KeyFlag.Control),
new Action(EditorActions.Cut, KeyCode.DEL, KeyFlag.Shift),
new Action(EditorActions.Paste, KeyCode.KEY_V, KeyFlag.Control),
new Action(EditorActions.Paste, KeyCode.INS, KeyFlag.Shift),
]); ]);
} }
@ -657,6 +715,33 @@ class EditWidgetBase : WidgetGroup, EditableContentListener {
EditOperation op = new EditOperation(EditAction.Replace, range, [""d]); EditOperation op = new EditOperation(EditAction.Replace, range, [""d]);
_content.performOperation(op); _content.performOperation(op);
} }
return true;
case EditorActions.Copy:
if (!_selectionRange.empty) {
dstring selectionText = concatDStrings(_content.rangeText(_selectionRange));
platform.setClipboardText(selectionText);
}
return true;
case EditorActions.Cut:
if (!_selectionRange.empty) {
dstring selectionText = concatDStrings(_content.rangeText(_selectionRange));
platform.setClipboardText(selectionText);
EditOperation op = new EditOperation(EditAction.Replace, _selectionRange, [""d]);
_content.performOperation(op);
}
return true;
case EditorActions.Paste:
{
dstring selectionText = platform.getClipboardText();
dstring[] lines;
if (_content.multiline) {
lines = splitDString(selectionText);
} else {
lines = [replaceEolsWithSpaces(selectionText)];
}
EditOperation op = new EditOperation(EditAction.Replace, _selectionRange, lines);
_content.performOperation(op);
}
return true; return true;
default: default:
break; break;