From 732b03a63ddcafed799e28fc52f897d07d6399dd Mon Sep 17 00:00:00 2001 From: cxl Date: Fri, 30 Jan 2015 14:32:29 +0000 Subject: [PATCH] LineEdit optimizations git-svn-id: svn://ultimatepp.org/upp/trunk@8108 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/CtrlLib/CtrlLib.upp | 2 +- uppsrc/CtrlLib/LineEdit.cpp | 49 +++++++++++++--- uppsrc/CtrlLib/Text.cpp | 69 ++++++++++++++++++++--- uppsrc/CtrlLib/TextEdit.h | 3 + uppsrc/CtrlLib/src.tpp/LineEdit$en-us.tpp | 15 ++++- uppsrc/CtrlLib/src.tpp/TextCtrl$en-us.tpp | 9 ++- 6 files changed, 127 insertions(+), 20 deletions(-) diff --git a/uppsrc/CtrlLib/CtrlLib.upp b/uppsrc/CtrlLib/CtrlLib.upp index 5531482b1..f8fd7c54e 100644 --- a/uppsrc/CtrlLib/CtrlLib.upp +++ b/uppsrc/CtrlLib/CtrlLib.upp @@ -9,7 +9,7 @@ uses uses(POSIX | LINUX | FREEBSD) PdfDraw; file - CtrlLib.h options PCH, + CtrlLib.h options(BUILDER_OPTION) PCH, CtrlLib readonly separator, LabelBase.h, LabelBase.cpp, diff --git a/uppsrc/CtrlLib/LineEdit.cpp b/uppsrc/CtrlLib/LineEdit.cpp index f63e84942..cef07918c 100644 --- a/uppsrc/CtrlLib/LineEdit.cpp +++ b/uppsrc/CtrlLib/LineEdit.cpp @@ -72,6 +72,17 @@ Size LineEdit::GetFontSize() const { return Size(max(fi['M'], fi['W']), fi.GetHeight()); } +void LineEdit::SetRectSelection(int anchor, int cursor) +{ + dorectsel = true; + SetSelection(anchor, cursor); + dorectsel = false; +} + +void LineEdit::SetRectSelection(const Rect& rect) +{ + SetRectSelection(GetGPos(rect.top, rect.left), GetGPos(rect.bottom, rect.right)); +} Rect LineEdit::GetRectSelection() const { @@ -102,6 +113,7 @@ int LineEdit::RemoveRectSelection() WString txt; for(int i = rect.top; i <= rect.bottom; i++) { int l, h; + CacheLinePos(i); GetRectSelection(rect, i, l, h); WString s = GetWLine(i); s.Remove(l - GetPos(i), h - l); @@ -123,6 +135,7 @@ WString LineEdit::CopyRectSelection() Rect rect = GetRectSelection(); for(int i = rect.top; i <= rect.bottom; i++) { int l, h; + CacheLinePos(i); int pos = GetPos(i); GetRectSelection(rect, i, l, h); txt.Cat(GetWLine(i).Mid(l - pos, h - l)); @@ -142,6 +155,7 @@ int LineEdit::PasteRectSelection(const WString& s) int n = 0; for(int i = 0; i < cl.GetCount() && rect.top + i <= rect.bottom; i++) { int l, h; + CacheLinePos(i); GetRectSelection(rect, i + rect.top, l, h); Remove(l, h - l); int nn = Insert(l, cl[i]); @@ -165,7 +179,8 @@ void LineEdit::PasteColumn(const WString& text) RemoveSelection(); Point p = t.TopLeft(); pos = cursor; - for(int i = 0; i < t.bottom - t.top + 1; i++) { + for(int i = 0; i < t.bottom - t.top + 1; i++) { + CacheLinePos(i + p.y); int l = GetGPos(i + p.y, p.x); pos = l + Insert(l, cl[i % cl.GetCount()]); } @@ -175,6 +190,7 @@ void LineEdit::PasteColumn(const WString& text) Point p = GetColumnLine(cursor); pos = cursor; for(int i = 0; i < cl.GetCount(); i++) { + CacheLinePos(i + p.y); int li = p.y + i; if(li < line.GetCount()) { int l = GetGPos(i + p.y, p.x); @@ -481,20 +497,39 @@ void LineEdit::Layout() { int LineEdit::GetGPos(int ln, int cl) const { ln = minmax(ln, 0, line.GetCount() - 1); - WString txt = line[ln]; - const wchar *b = txt; - const wchar *e = txt.End(); - const wchar *s = b; + const String& stxt = line[ln].text; + const char *s = stxt; + const char *e = stxt.End(); + const char *b = s; int gl = 0; + int wpos = 0; while(s < e) { if(*s == '\t') gl = (gl + tabsize) / tabsize * tabsize; else - gl += 1 + IsCJKIdeograph(*s); + if((byte)*s < 128) + gl++; + else { + WString txt = FromUtf8(s, int(e - s)); + const wchar *b = txt; + const wchar *e = txt.End(); + const wchar *s = b; + while(s < e) { + if(*s == '\t') + gl = (gl + tabsize) / tabsize * tabsize; + else + gl += 1 + IsCJKIdeograph(*s); + if(cl < gl) break; + s++; + } + wpos = int(s - b); + break; + } if(cl < gl) break; s++; } - return GetPos(ln, int(s - b)); + + return GetPos(ln, int(s - b) + wpos); } Point LineEdit::GetColumnLine(int pos) const { diff --git a/uppsrc/CtrlLib/Text.cpp b/uppsrc/CtrlLib/Text.cpp index f14716e30..dae786a8e 100644 --- a/uppsrc/CtrlLib/Text.cpp +++ b/uppsrc/CtrlLib/Text.cpp @@ -87,12 +87,21 @@ int TextCtrl::RemoveRectSelection() { return 0; } WString TextCtrl::CopyRectSelection() { return Null; } int TextCtrl::PasteRectSelection(const WString& s) { return 0; } -void TextCtrl::CachePos(int pos) { +void TextCtrl::CachePos(int pos) +{ int p = pos; cline = GetLinePos(p); cpos = pos - p; } +void TextCtrl::CacheLinePos(int linei) +{ + if(linei >= 0 && linei < GetLineCount()) { + cpos = GetPos(linei); + cline = linei; + } +} + int TextCtrl::Load(Stream& in, byte charset) { Clear(); line.Clear(); @@ -381,12 +390,15 @@ int TextCtrl::GetPos(int ln, int lpos) const { WString TextCtrl::GetW(int pos, int size) const { int i = GetLinePos(pos); - WString r; + WStringBuffer r; for(;;) { if(i >= line.GetCount()) break; WString ln = line[i++]; int sz = min(ln.GetLength() - pos, size); - r.Cat(ln.Mid(pos, sz)); + if(pos == 0 && sz == ln.GetLength()) + r.Cat(ln); + else + r.Cat(ln.Mid(pos, sz)); size -= sz; if(size == 0) break; #ifdef PLATFORM_WIN32 @@ -402,6 +414,29 @@ WString TextCtrl::GetW(int pos, int size) const String TextCtrl::Get(int pos, int size, byte charset) const { + if(charset == CHARSET_UTF8) { + int i = GetLinePos(pos); + StringBuffer r; + for(;;) { + if(i >= line.GetCount()) break; + int sz = min(line[i].GetLength() - pos, size); + const String& ln = line[i++].text; + if(pos == 0 && sz == ln.GetLength()) + r.Cat(ln); + else + r.Cat(ln.ToWString().Mid(pos, sz).ToString()); + size -= sz; + if(size == 0) break; + #ifdef PLATFORM_WIN32 + r.Cat('\r'); + #endif + r.Cat('\n'); + size--; + if(size == 0) break; + pos = 0; + } + return r; + } return FromUnicode(GetW(pos, size), charset); } @@ -420,19 +455,35 @@ int TextCtrl::Insert0(int pos, const WString& txt) { int i = GetLinePos(pos); DirtyFrom(i); int size = 0; - WString ln; + + WStringBuffer lnb; Vector iln; - for(const wchar *s = txt; s < txt.End(); s++) - if(*s >= ' ' || *s == '\t') { - ln.Cat(*s); + const wchar *s = txt; + while(s < txt.End()) + if(*s >= ' ') { + const wchar *b = s; + while(*s >= ' ') // txt is zero teminated... + s++; + int sz = int(s - b); + lnb.Cat(b, sz); + size += sz; + } + else + if(*s == '\t') { + lnb.Cat(*s); size++; + s++; } else if(*s == '\n') { - iln.Add(ln); + iln.Add(WString(lnb)); size++; - ln.Clear(); + lnb.Clear(); + s++; } + else + s++; + WString ln = lnb; WString l = line[i]; if(iln.GetCount()) { diff --git a/uppsrc/CtrlLib/TextEdit.h b/uppsrc/CtrlLib/TextEdit.h index 0a4a3a9dd..93cc1e875 100644 --- a/uppsrc/CtrlLib/TextEdit.h +++ b/uppsrc/CtrlLib/TextEdit.h @@ -105,6 +105,7 @@ public: Callback WhenSel; void CachePos(int pos); + void CacheLinePos(int linei); enum { CHARSET_UTF8_BOM = 250 }; enum { LE_DEFAULT, LE_CRLF, LE_LF }; @@ -311,6 +312,8 @@ public: Point GetIndexLine(int pos) const; int GetIndexLinePos(Point pos) const; + void SetRectSelection(int l, int h); + void SetRectSelection(const Rect& rect); Rect GetRectSelection() const; bool GetRectSelection(const Rect& rect, int line, int& l, int &h); diff --git a/uppsrc/CtrlLib/src.tpp/LineEdit$en-us.tpp b/uppsrc/CtrlLib/src.tpp/LineEdit$en-us.tpp index 74bcdfd4f..e0188657a 100644 --- a/uppsrc/CtrlLib/src.tpp/LineEdit$en-us.tpp +++ b/uppsrc/CtrlLib/src.tpp/LineEdit$en-us.tpp @@ -51,8 +51,8 @@ monospace glyphs `- the width of character is constant).&] [s5;:LineEdit`:`:GetGPos`(int`,int`)const: [@(0.0.255) int]_[* GetGPos]([@(0.0.255) int]_[*@3 l n], [@(0.0.255) int]_[*@3 cl])_[@(0.0.255) const]&] [s2;%% Returns `"graphical`" position of [%-*@3 ln] line and [%-*@3 cl] -column. This takes into account any tabulator characters int -the line.&] +column. This takes into account any tabulator characters in the +line.&] [s3; &] [s4; &] [s5;:LineEdit`:`:GetMousePos`(Point`)const: [@(0.0.255) int]_[* GetMousePos]([_^Point^ Poin @@ -85,6 +85,17 @@ 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])&] +[s2;%% Sets rectangular selection.&] +[s3;%% &] +[s4; &] +[s5;:LineEdit`:`:SetRectSelection`(const Rect`&`): [@(0.0.255) void]_[* SetRectSelection]( +[@(0.0.255) const]_[_^Rect^ Rect][@(0.0.255) `&]_[*@3 rect])&] +[s2;%% Same as SetRectSelection(GetGPos(rect.top, rect.left), GetGPos(rect.bottom, +rect.right));&] +[s3;%% &] +[s4; &] [s5;:LineEdit`:`:GetRectSelection`(`)const: [_^Rect^ Rect]_[* GetRectSelection]()_[@(0.0.255) c onst]&] [s2;%% Returns rectangular selection (as `"graphical`").&] diff --git a/uppsrc/CtrlLib/src.tpp/TextCtrl$en-us.tpp b/uppsrc/CtrlLib/src.tpp/TextCtrl$en-us.tpp index 4c7c655c1..8360a49bb 100644 --- a/uppsrc/CtrlLib/src.tpp/TextCtrl$en-us.tpp +++ b/uppsrc/CtrlLib/src.tpp/TextCtrl$en-us.tpp @@ -109,7 +109,14 @@ from not`-modified to modified (`"dirty`") or back.&] [s4; &] [s5;:TextCtrl`:`:CachePos`(int`): [@(0.0.255) void]_[* CachePos]([@(0.0.255) int]_[*@3 pos])&] [s2;%% This is specific optimization hint to the widget saying that -following operations will be performed near after [%-*@3 pos]. +following operations will be performed near [%-*@3 pos]. Unlikely +to be used in the client code.&] +[s3;%% &] +[s4; &] +[s5;:TextCtrl`:`:CacheLinePos`(int`): [@(0.0.255) void]_[* CacheLinePos]([@(0.0.255) int]_[*@3 l +inei])&] +[s2;%% This is specific optimization hint to the widget saying that +following operations will be performed near line [%-*@3 linei]. Unlikely to be used in the client code.&] [s3;%% &] [s4; &]