mirror of https://github.com/buggins/dlangui.git
clipboard support in editors, part 1
This commit is contained in:
parent
99e4e4e732
commit
4348b859c7
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue