Multiline cursor

This commit is contained in:
Mirek Fidler 2024-12-03 14:16:35 +01:00
parent 70f4f0fbe2
commit 5210c590fb
5 changed files with 97 additions and 54 deletions

View file

@ -1093,6 +1093,8 @@ bool CodeEditor::Key(dword code, int count) {
Replace();
return true;
}
if(IsRectSelection())
return LineEdit::Key(code, count);
switch(code) {
case K_SHIFT_CTRL_UP:
SwapUpDown(true);
@ -1137,7 +1139,8 @@ bool CodeEditor::Key(dword code, int count) {
case K_SHIFT_CTRL_TAB:
return LineEdit::Key(K_TAB, count);
case K_ENTER:
IndentInsert('\n', count);
if(!IsRectSelection())
IndentInsert('\n', count);
return true;
}
bool sel = code & K_SHIFT;

View file

@ -132,33 +132,8 @@ bool LineEdit::GetRectSelection(const Rect& rect, int line, int64& l, int64& h)
return false;
}
void LineEdit::RectSelectionChar(int c)
{
Rect rect = GetRectSelection();
if(rect.GetWidth())
RemoveRectSelection();
WString txt;
for(int i = rect.top; i <= rect.bottom; i++) {
int64 l, h;
CacheLinePos(i);
GetRectSelection(rect, i, l, h);
WString s = GetWLine(i);
s.Insert(int(l - GetPos64(i)), c);
txt.Cat(s);
txt.Cat('\n');
}
int l = GetPos32(rect.top);
int h = GetPos32(rect.bottom) + GetLineLength(rect.bottom);
if(h < GetLength32())
h++;
Remove((int)l, int(h - l));
Insert((int)l, txt);
anchor = (int)GetGPos(rect.top, rect.left + 1);
cursor = (int)GetGPos(rect.bottom, rect.left + 1);
PlaceCaret0();
}
int LineEdit::RemoveRectSelection()
int LineEdit::RectSelectionOp(Event<int, Rect, int64, int64, WString&> op, Event<Rect&> changesel)
{
Rect rect = GetRectSelection();
WString txt;
@ -167,7 +142,7 @@ int LineEdit::RemoveRectSelection()
CacheLinePos(i);
GetRectSelection(rect, i, l, h);
WString s = GetWLine(i);
s.Remove(int(l - GetPos64(i)), int(h - l));
op(i, rect, l, h, s);
txt.Cat(s);
txt.Cat('\n');
}
@ -177,12 +152,63 @@ int LineEdit::RemoveRectSelection()
h++;
Remove((int)l, int(h - l));
Insert((int)l, txt);
changesel(rect);
anchor = (int)GetGPos(rect.top, rect.left);
cursor = (int)GetGPos(rect.bottom, rect.left);
PlaceCaret0();
return cursor;
}
void LineEdit::RectSelectionChar(int c)
{
if(GetRectSelection().GetWidth())
RemoveRectSelection();
int p = -1; // position after insertion, because of '\t' and double size chars cannot do just left+1
RectSelectionOp(
[&](int i, Rect rect, int64 l, int64 h, WString& s) {
int x = GetColumnLine(l).x;
int cursor;
if(x < rect.left) {
s.Cat(' ', rect.left - x);
s.Cat(c);
if(p < 0)
p = GetPos(i) + s.GetCount();
}
else {
s.Insert(int(l - GetPos64(i)), c);
if(p < 0) // first time the position is unchanged after whole text is replaced
p = l + 1;
}
},
[&](Rect& r) { r.left = GetColumnLine(p).x; }
);
}
void LineEdit::RectSelectionBackspace()
{
Rect r = GetRectSelection();
if(r.GetWidth())
RemoveRectSelection();
else
if(r.left > 0)
RectSelectionOp(
[&](int i, Rect rect, int64 l, int64 h, WString& s) {
int p = int(l - GetPos64(i));
if(GetColumnLine(l).x == rect.left && p - 1 < s.GetCount())
s.Remove(p - 1, 1);
},
[&](Rect& r) { r.left--; }
);
}
int LineEdit::RemoveRectSelection()
{
return RectSelectionOp(
[&](int i, Rect, int64 l, int64 h, WString& s) { s.Remove(int(l - GetPos64(i)), int(h - l)); }
);
}
WString LineEdit::CopyRectSelection()
{
WString txt;
@ -204,20 +230,23 @@ WString LineEdit::CopyRectSelection()
int LineEdit::PasteRectSelection(const WString& s)
{
Vector<WString> cl = Split(s, '\n', false);
Rect rect = GetRectSelection();
int64 pos = cursor;
int n = 0;
for(int i = 0; i < cl.GetCount() && rect.top + i <= rect.bottom; i++) {
int64 l, h;
CacheLinePos(i);
GetRectSelection(rect, i + rect.top, l, h);
Remove((int)l, int(h - l));
int nn = Insert((int)l, cl[i]);
n += nn;
pos = l + nn;
int cursor0 = cursor;
if(cl.GetCount() == 1)
PasteColumn(cl[0]);
else {
Rect rect = GetRectSelection();
int64 pos = cursor;
for(int i = 0; i < cl.GetCount() && rect.top + i <= rect.bottom; i++) {
int64 l, h;
CacheLinePos(i);
GetRectSelection(rect, i + rect.top, l, h);
Remove((int)l, int(h - l));
int nn = Insert((int)l, cl[i]);
pos = l + nn;
}
PlaceCaret(pos);
}
PlaceCaret(pos);
return n;
return cursor - cursor0;
}
void LineEdit::PasteColumn(const WString& text)
@ -655,8 +684,8 @@ void LineEdit::Paint0(Draw& w)
if(!IsNull(vline))
rw.DrawRect(caretpos.x, y, 1, fsz.cy, vline);
}
if(rectsel && rect.left == rect.right && i >= rect.top && i <= rect.bottom)
rw.DrawRect(rect.left * fsz.cx - scx, y, 2, fsz.cy, Blend(color[PAPER_SELECTED], color[PAPER_NORMAL]));
// if(rectsel && rect.left == rect.right && i >= rect.top && i <= rect.bottom)
// rw.DrawRect(rect.left * fsz.cx - scx, y, 2, fsz.cy, Blend(color[PAPER_SELECTED], color[PAPER_NORMAL]));
}
}
}
@ -1078,6 +1107,8 @@ void LineEdit::MoveTextEnd(bool sel) {
bool LineEdit::InsertChar(dword key, int count, bool canow) {
if(key == K_TAB && !processtab)
return false;
if(findarg(key, '\n', K_ENTER) >= 0 && IsRectSelection())
return true;
if(filter && key >= 32 && key < K_CHAR_LIM)
key = (*filter)(key);
if(!IsReadOnly() && (key >= 32 && key < K_CHAR_LIM || key == '\t' || key == '\n' ||
@ -1273,6 +1304,8 @@ bool LineEdit::Key(dword key, int count) {
case K_CTRL_A:
SelectAll();
break;
case K_ALT_KEY|K_KEYUP:
return IsRectSelection(); // prevent opening menu on Alt+Click
default:
dorectsel = false;
if(IsReadOnly())
@ -1282,6 +1315,10 @@ bool LineEdit::Key(dword key, int count) {
DeleteChar();
break;
case K_BACKSPACE:
if(IsRectSelection()) {
RectSelectionBackspace();
break;
}
case K_SHIFT|K_BACKSPACE:
Backspace();
break;

View file

@ -378,6 +378,8 @@ protected:
void SyncFont();
bool IsDoubleChar(int ch) const;
void RectSelectionChar(int c);
void RectSelectionBackspace();
int RectSelectionOp(Event<int, Rect, int64, int64, WString&> op, Event<Rect&> changesel = Null);
struct RefreshDraw;
friend class TextCtrl;

View file

@ -64,8 +64,8 @@ t]_[*@3 p])_[@(0.0.255) const]&]
[s2;%% Get the the offset of character placed at [%-*@3 p].&]
[s3; &]
[s4; &]
[s5;:LineEdit`:`:GetColumnLine`(int`)const: [_^Point^ Point]_[* GetColumnLine]([@(0.0.255) i
nt]_[*@3 pos])_[@(0.0.255) const]&]
[s5;:Upp`:`:LineEdit`:`:GetColumnLine`(int64`)const: Point [* GetColumnLine](int64
[*@3 pos]) [@(0.0.255) const]&]
[s2;%% Returns the line and column for the character at [%-*@3 pos]
accounting for any tabulators. Column is x member of resulting
Point, line is y.&]
@ -77,8 +77,8 @@ oint]_[*@3 pos])_[@(0.0.255) const]&]
Does account for tabulators.&]
[s3; &]
[s4; &]
[s5;:LineEdit`:`:GetIndexLine`(int`)const: [_^Point^ Point]_[* GetIndexLine]([@(0.0.255) in
t]_[*@3 pos])_[@(0.0.255) const]&]
[s5;:Upp`:`:LineEdit`:`:GetIndexLine`(int64`)const: Point [* GetIndexLine](int64
[*@3 pos]) [@(0.0.255) const]&]
[s2;%% Returns the line and index of character in the line for the
given [%-*@3 pos]. Does not account for tabulators.&]
[s3; &]
@ -89,8 +89,8 @@ oint]_[*@3 pos])_[@(0.0.255) const]&]
Does not account for tabulators.&]
[s3; &]
[s4; &]
[s5;:LineEdit`:`:SetRectSelection`(int`,int`): [@(0.0.255) void]_[* SetRectSelection]([@(0.0.255) i
nt]_[*@3 l], [@(0.0.255) int]_[*@3 h])&]
[s5;:Upp`:`:LineEdit`:`:SetRectSelection`(int64`,int64`): [@(0.0.255) void]
[* SetRectSelection](int64 [*@3 l], int64 [*@3 h])&]
[s2;%% Sets rectangular selection.&]
[s3;%% &]
[s4; &]
@ -105,9 +105,10 @@ onst]&]
[s2;%% Returns rectangular selection (as `"graphical`").&]
[s3; &]
[s4; &]
[s5;:LineEdit`:`:GetRectSelection`(const Rect`&`,int`,int`&`,int`&`): [@(0.0.255) bool]_
[* GetRectSelection]([@(0.0.255) const]_[_^Rect^ Rect][@(0.0.255) `&]_[*@3 rect],
[@(0.0.255) int]_[*@3 line], [@(0.0.255) int`&]_[*@3 l], [@(0.0.255) int]_`&[*@3 h])&]
[s5;:Upp`:`:LineEdit`:`:GetRectSelection`(const Rect`&`,int`,int64`&`,int64`&`): [@(0.0.255) b
ool] [* GetRectSelection]([@(0.0.255) const] Rect[@(0.0.255) `&] [*@3 rect],
[@(0.0.255) int] [*@3 line], int64[@(0.0.255) `&] [*@3 l], int64[@(0.0.255) `&]
[*@3 h])&]
[s2;%% Returns lower and upper limits [%-*@3 l] [%-*@3 h] of characters
of [%-*@3 line] that are in rectangular selection [%-*@3 rect]. Returns
false when line is not in selection.&]
@ -217,7 +218,7 @@ the text).&]
[s5;:LineEdit`:`:PasteColumn`(const WString`&`): [@(0.0.255) void]_[* PasteColumn]([@(0.0.255) c
onst]_[_^WString^ WString][@(0.0.255) `&]_[*@3 text])&]
[s2;%% Pastes lines of [%-*@3 text] into actual graphical column of
text.&]
text. Returns final cursor position.&]
[s3;%% &]
[s4; &]
[s5;:LineEdit`:`:PasteColumn`(`): [@(0.0.255) void]_[* PasteColumn]()&]

View file

@ -1073,7 +1073,7 @@ bool AssistEditor::Key(dword key, int count)
bool b = CodeEditor::Key(key, count);
if(b && search.HasFocus())
SetFocus();
if(IsReadOnly())
if(IsReadOnly() || IsRectSelection())
return b;
if(assist.IsOpen()) {
bool (*test)(int c) = include_assist ? isincludefnchar : isaid;