diff --git a/autotest/CtrlChildren/CtrlChildren.upp b/autotest/CtrlChildren/CtrlChildren.upp new file mode 100644 index 000000000..eee14521c --- /dev/null +++ b/autotest/CtrlChildren/CtrlChildren.upp @@ -0,0 +1,10 @@ +uses + CtrlLib; + +file + etalon.log, + main.cpp; + +mainconfig + "" = "GUI"; + diff --git a/autotest/CtrlChildren/etalon.log b/autotest/CtrlChildren/etalon.log new file mode 100644 index 000000000..c8ee03a20 --- /dev/null +++ b/autotest/CtrlChildren/etalon.log @@ -0,0 +1,15 @@ +* C:\upp\out\gui_sizeof_autotest\CLANGx64.Debug.Debug_Full.Gui\CtrlChildren.exe 12.04.2022 11:30:36, user: cxl + +============================== +N3Upp5LabelE +N3Upp10EditMinMaxIiNS_10ConvertIntEEE +============================== +N3Upp5LabelE +N3Upp10StaticRectE +N3Upp10EditMinMaxIiNS_10ConvertIntEEE +============================== +N3Upp10StaticRectE +N3Upp10EditMinMaxIiNS_10ConvertIntEEE +============================== +N3Upp10StaticRectE +============================== diff --git a/autotest/CtrlChildren/main.cpp b/autotest/CtrlChildren/main.cpp new file mode 100644 index 000000000..f4d3cc10f --- /dev/null +++ b/autotest/CtrlChildren/main.cpp @@ -0,0 +1,29 @@ +#include + +using namespace Upp; + +GUI_APP_MAIN +{ + TopWindow top; + Label lbl; + EditInt edit; + StaticRect list; + auto Print = [&] { + DLOG("=============================="); + for(Ctrl& q : top) + DLOG(typeid(q).name()); + }; + + top << lbl << edit; + Print(); + top.AddChild(&list, &lbl); + Print(); + lbl.Remove(); + Print(); + edit.Ctrl::Remove(); + Print(); + list.Ctrl::Remove(); + Print(); + + CheckLogEtalon(); +} diff --git a/autotest/CtrlFrame/CtrlFrame.upp b/autotest/CtrlFrame/CtrlFrame.upp new file mode 100644 index 000000000..5872304d3 --- /dev/null +++ b/autotest/CtrlFrame/CtrlFrame.upp @@ -0,0 +1,9 @@ +uses + CtrlLib; + +file + main.cpp; + +mainconfig + "" = "GUI"; + diff --git a/autotest/CtrlFrame/main.cpp b/autotest/CtrlFrame/main.cpp new file mode 100644 index 000000000..c66d05e64 --- /dev/null +++ b/autotest/CtrlFrame/main.cpp @@ -0,0 +1,53 @@ +#include + +using namespace Upp; + +GUI_APP_MAIN +{ + NullFrameClass fr[50]; + for(int q = 0; q < 10000; q++) { + DLOG("=========="); + Ctrl h; + Vector h1; + int N = Random(40) + 1; + h1.Add(&NullFrame()); + for(int i = 0; i < N; i++) { + int pos = Random(h.GetFrameCount() + 1); + CtrlFrame& val = fr[Random(50)]; + h.InsertFrame(pos, val); + h1.Insert(pos, &val); + DDUMP(h.GetFrameCount()); + DDUMP(h1.GetCount()); + ASSERT(h1.GetCount() == h.GetFrameCount()); + for(int i = 0; i < h.GetFrameCount(); i++) + ASSERT(&h.GetFrame(i) == h1[i]); +#if 0 + DLOG("==========="); + DDUMP(pos); + DDUMP(val); + DDUMP(h.GetFrameCount()); + for(int i = 0; i < h.GetFrameCount(); i++) + DLOG(i << " " << h.GetFrame(i)); +#endif + } + while(h.GetFrameCount() > 1) { + int pos = Random(h.GetFrameCount()); + h.RemoveFrame(pos); + h1.Remove(pos); + DDUMP(h.GetFrameCount()); + DDUMP(h1.GetCount()); + ASSERT(h1.GetCount() == h.GetFrameCount()); + for(int i = 0; i < h.GetFrameCount(); i++) + ASSERT(&h.GetFrame(i) == h1[i]); +#if 0 + DLOG("==========="); + DDUMP(pos); + DDUMP(h.GetFrameCount()); + for(int i = 0; i < h.GetFrameCount(); i++) + DLOG(i << " " << h.GetFrame(i)); +#endif + } + } + + DLOG("================ OK"); +} diff --git a/autotest/CtrlInfoParts/CtrlInfoParts.upp b/autotest/CtrlInfoParts/CtrlInfoParts.upp new file mode 100644 index 000000000..eee14521c --- /dev/null +++ b/autotest/CtrlInfoParts/CtrlInfoParts.upp @@ -0,0 +1,10 @@ +uses + CtrlLib; + +file + etalon.log, + main.cpp; + +mainconfig + "" = "GUI"; + diff --git a/autotest/CtrlInfoParts/etalon.log b/autotest/CtrlInfoParts/etalon.log new file mode 100644 index 000000000..4091b7e14 --- /dev/null +++ b/autotest/CtrlInfoParts/etalon.log @@ -0,0 +1,27 @@ +* C:\upp\out\gui_sizeof_autotest\CLANGx64.Debug.Debug_Full.Gui\CtrlInfoParts.exe 11.04.2022 18:41:30, user: cxl + +======================== +h.GetLayoutId() = just some literal +h.GetTip() = +h.GetDescription() = +h.GetHelpLine() = +======================== +h.GetLayoutId() = just some text +h.GetTip() = +h.GetDescription() = +h.GetHelpLine() = +======================== +h.GetLayoutId() = just some literal +h.GetTip() = +h.GetDescription() = +h.GetHelpLine() = some helpline +======================== +h.GetLayoutId() = just some text +h.GetTip() = +h.GetDescription() = +h.GetHelpLine() = some helpline +======================== +h.GetLayoutId() = just some literal +h.GetTip() = this is tip +h.GetDescription() = this is description +h.GetHelpLine() = some helpline diff --git a/autotest/CtrlInfoParts/main.cpp b/autotest/CtrlInfoParts/main.cpp new file mode 100644 index 000000000..f0e248186 --- /dev/null +++ b/autotest/CtrlInfoParts/main.cpp @@ -0,0 +1,51 @@ +#include + +using namespace Upp; + +GUI_APP_MAIN +{ + auto Print = [&](Ctrl& h) { + DLOG("========================"); + DDUMP(h.GetLayoutId()); + DDUMP(h.GetTip()); + DDUMP(h.GetDescription()); + DDUMP(h.GetHelpLine()); + }; + + { + Ctrl h; + h.LayoutIdLiteral("just some literal"); + Print(h); + } + + { + Ctrl h; + h.LayoutId(String("just some text")); + Print(h); + } + + { + Ctrl h; + h.LayoutIdLiteral("just some literal"); + h.HelpLine("some helpline"); + Print(h); + } + + { + Ctrl h; + h.LayoutId(String("just some text")); + h.HelpLine("some helpline"); + Print(h); + } + + { + Ctrl h; + h.LayoutIdLiteral("just some literal"); + h.Tip("this is tip"); + h.HelpLine("some helpline"); + h.Description("this is description"); + Print(h); + } + + CheckLogEtalon(); +} diff --git a/benchmarks/sizeof_gui/main.cpp b/benchmarks/sizeof_gui/main.cpp index 897f5af10..79cd36800 100644 --- a/benchmarks/sizeof_gui/main.cpp +++ b/benchmarks/sizeof_gui/main.cpp @@ -25,8 +25,8 @@ GUI_APP_MAIN RDUMP(sizeof(EditIntSpin)); RDUMP(sizeof(DisplayPopup)); RDUMP(sizeof(PopUpTable)); - RDUMP(sizeof(WithDropChoice)); RDUMP(sizeof(DropList)); + RDUMP(sizeof(WithDropChoice)); RDUMP(sizeof(ArrayCtrl)); RDUMP(sizeof(TreeCtrl)); RDUMP(sizeof(TreeCtrl::Node)); diff --git a/uppsrc/Core/Core.upp b/uppsrc/Core/Core.upp index e02155dbc..51d7eae01 100644 --- a/uppsrc/Core/Core.upp +++ b/uppsrc/Core/Core.upp @@ -95,12 +95,14 @@ file Algo.h, CoAlgo.h, Sorted.h, - Sort.h, CoSort.h, Obsolete.h, + Sort.h, Vcont.h, BiCont.h, Other.h, + Other.hpp, + PackedData.cpp, Vcont.hpp, Vcont.cpp, Index.h, diff --git a/uppsrc/Core/Index.hpp b/uppsrc/Core/Index.hpp index e0be04824..1acdba1b7 100644 --- a/uppsrc/Core/Index.hpp +++ b/uppsrc/Core/Index.hpp @@ -343,15 +343,19 @@ void Index::Serialize(Stream& s) h.Serialize(s); if(s.IsLoading()) for(int i = 0; i < h.GetCount(); i++) - if(h[i] & 0x80000000) + if(i < GetCount() && h[i] & 0x80000000) Unlink(i); } else { Vector u = GetUnlinked(); u.Serialize(s); if(s.IsLoading()) - for(int i : ReverseRange(u)) // Reverse range to ensure the correct order of Put - Unlink(i); + for(int i : ReverseRange(u)) { // Reverse range to ensure the correct order of Put + if(i >= 0 && i < GetCount()) + Unlink(i); + else + s.LoadError(); + } } } diff --git a/uppsrc/Core/JSON.cpp b/uppsrc/Core/JSON.cpp index e43a9ec9d..5bff4ce77 100644 --- a/uppsrc/Core/JSON.cpp +++ b/uppsrc/Core/JSON.cpp @@ -147,7 +147,7 @@ String AsJSON(const Value& v, const String& sep, bool pretty) if(v.GetType() == BOOL_V) return (bool)v ? "true" : "false"; if(IsNumber(v)) - return FormatG((double)v, 17); + return FormatG((double)v, 15); if(IsString(v)) return AsCString((String)v, INT_MAX, NULL, ASCSTRING_JSON); if(IsDateTime(v)) diff --git a/uppsrc/Core/Map.hpp b/uppsrc/Core/Map.hpp index bb2b32696..2ee450528 100644 --- a/uppsrc/Core/Map.hpp +++ b/uppsrc/Core/Map.hpp @@ -113,6 +113,8 @@ template void AMap::Serialize(Stream& s) { int version = 0; s / version % key % value; + if(key.GetCount() != value.GetCount()) + s.LoadError(); } template @@ -167,6 +169,8 @@ void AMap::Sweep() template void FixedAMap::Serialize(Stream& s) { s % key % value; + if(key.GetCount() != value.GetCount()) + s.LoadError(); } template diff --git a/uppsrc/Core/Other.h b/uppsrc/Core/Other.h index 9d7d8949e..407d39076 100644 --- a/uppsrc/Core/Other.h +++ b/uppsrc/Core/Other.h @@ -103,117 +103,50 @@ public: void operator=(const Bits&) = delete; }; -//# System dependent -template -class Mitor : Moveable< Mitor > { - union { - mutable unsigned count; - mutable Vector *vector; - }; - byte elem0[sizeof(T)]; - - T& Get(int i) const; - void Pick(Mitor&& m); - void Copy(const Mitor& m); - void Chk() const { ASSERT(count != 2); } +class PackedData { + void *ptr = nullptr; + + template + T Get(int ii, T def) const; public: - T& operator[](int i) { return Get(i); } - const T& operator[](int i) const { return Get(i); } - int GetCount() const; - T& Add(); - void Add(const T& x); - void Clear(); - void Shrink(); + void SetRawPtr(void *p) { ptr = p; } + void *GetRawPtr() const { return ptr; } - Mitor(Mitor&& m) { Pick(pick(m)); } - void operator=(Mitor&& m) { if(this != &m) { Clear(); Pick(pick(m)); } } + void SetData(int ii, const void *data, int datalen); - Mitor(Mitor& m, int) { Copy(m); } + template + bool GetData(int ii, F out) const; + + void SetNull(int ii) { SetData(ii, NULL, 0); } - Mitor() { count = 0; } - ~Mitor() { Clear(); } + void SetString(int ii, const char *s) { SetData(ii, s, strlen(s)); } + void SetString(int ii, const String& s) { SetData(ii, s, s.GetCount()); } + String GetString(int ii) const { String r; GetData(ii, [&](const char *s, int n) { r = String(s, n); }); return r; } + + void SetInt(int ii, int val) { SetData(ii, &val, sizeof(int)); } + int GetInt(int ii, int def) const { return Get(ii, def); } + + void SetDword(int ii, dword val) { SetData(ii, &val, sizeof(dword)); } + int GetDword(int ii, dword def) const { return Get(ii, def); } + + void SetInt64(int ii, int64 val) { SetData(ii, &val, sizeof(int64)); } + int64 GetInt64(int ii, int64 def) const { return Get(ii, def); } + + void SetPtr(int ii, void *val) { SetData(ii, &val, sizeof(void *)); } + void *GetPtr(int ii) const { return Get(ii, nullptr); } + + void Clear(); + + Vector Unpack() const; + size_t GetPackedSize() const; + String GetPacked() const { return String((const char *)ptr, GetPackedSize()); } + + PackedData() {} + PackedData(const PackedData&) = delete; + ~PackedData(); }; -template -T& Mitor::Get(int i) const -{ - ASSERT(i >= 0 && i < GetCount()); - return i == 0 ? *(T*)elem0 : (*const_cast*>(vector))[i - 1]; -} - -template -void Mitor::Pick(Mitor&& m) -{ - m.Chk(); - vector = m.vector; - memcpy(&elem0, &m.elem0, sizeof(T)); - m.count = 2; -} - -template -void Mitor::Copy(const Mitor& m) -{ - m.Chk(); - if(m.count > 0) - DeepCopyConstruct(elem0, (const T*)m.elem0); - if(m.count > 1) - vector = new Vector(*m.vector, 1); -} - -template -int Mitor::GetCount() const -{ - Chk(); - return count > 1 ? vector->GetCount() + 1 : count; -} - -template -T& Mitor::Add() -{ - Chk(); - if(count == 0) { - count = 1; - return *new(elem0) T; - } - if(count == 1) - vector = new Vector; - return vector->Add(); -} - -template -void Mitor::Add(const T& x) -{ - Chk(); - if(count == 0) { - count = 1; - new((T*) elem0) T(x); - } - else { - if(count == 1) - vector = new Vector; - vector->Add(x); - } -} - -template -void Mitor::Clear() -{ - if(count > 2) - delete vector; - if(count && count != 2) - ((T*)elem0)->~T(); - count = 0; -} - -template -void Mitor::Shrink() -{ - if(count > 2) - vector->Shrink(); -} - -//# template struct Link { T *link_prev[N]; @@ -336,169 +269,4 @@ public: LRUCache() { head = -1; size = 0; count = 0; ClearCounters(); } }; -template -void LRUCache::LinkHead(int i) -{ - Item& m = data[i]; - if(head >= 0) { - int tail = data[head].prev; - m.next = head; - m.prev = tail; - data[head].prev = i; - data[tail].next = i; - } - else - m.prev = m.next = i; - head = i; - count++; -} - - -template -void LRUCache::Unlink(int i) -{ - Item& m = data[i]; - if(m.prev == i) - head = -1; - else { - if(head == i) - head = m.next; - data[m.next].prev = m.prev; - data[m.prev].next = m.next; - } - count--; -} - -template -T& LRUCache::GetLRU() -{ - int tail = data[head].prev; - return *data[tail].data; -} - -template -const K& LRUCache::GetLRUKey() -{ - int tail = data[head].prev; - return key[tail].key; -} - -template -void LRUCache::DropLRU() -{ - if(head >= 0) { - int tail = data[head].prev; - size -= data[tail].size; - data[tail].data.Clear(); - Unlink(tail); - key.Unlink(tail); - } -} - -template -template -void LRUCache::AdjustSize(P getsize) -{ - size = 0; - count = 0; - for(int i = 0; i < data.GetCount(); i++) - if(!key.IsUnlinked(i)) { - int sz = getsize(*data[i].data); - if(sz >= 0) - data[i].size = sz + InternalSize; - size += data[i].size; - count++; - } -} - -template -template -int LRUCache::Remove(P predicate) -{ - int n = 0; - int i = 0; - while(i < data.GetCount()) - if(!key.IsUnlinked(i) && predicate(*data[i].data)) { - size -= data[i].size; - Unlink(i); - key.Unlink(i); - n++; - } - else - i++; - return n; -} - -template -template -bool LRUCache::RemoveOne(P predicate) -{ - int i = head; - if(i >= 0) - for(;;) { - int next = data[i].next; - if(predicate(*data[i].data)) { - size -= data[i].size; - Unlink(i); - key.Unlink(i); - return true; - } - if(i == next || next == head || next < 0) - break; - i = next; - } - return false; -} - -template -void LRUCache::Shrink(int maxsize, int maxcount) -{ - if(maxsize >= 0 && maxcount >= 0) - while(count > maxcount || size > maxsize) - DropLRU(); -} - -template -void LRUCache::Clear() -{ - head = -1; - size = 0; - count = 0; - newsize = foundsize = 0; - key.Clear(); - data.Clear(); -} - -template -void LRUCache::ClearCounters() -{ - flag = !flag; - newsize = foundsize = 0; -} - -template -T& LRUCache::Get(const Maker& m) -{ - Key k; - k.key = m.Key(); - k.type = typeid(m).name(); - int q = key.Find(k); - if(q < 0) { - q = key.Put(k); - Item& t = data.At(q); - t.size = m.Make(t.data.Create()) + InternalSize; - size += t.size; - newsize += t.size; - t.flag = flag; - } - else { - Item& t = data[q]; - Unlink(q); - if(t.flag != flag) { - t.flag = flag; - foundsize += t.size; - } - } - LinkHead(q); - return *data[q].data; -} +#include "Other.hpp" diff --git a/uppsrc/Core/Other.hpp b/uppsrc/Core/Other.hpp new file mode 100644 index 000000000..ee7723061 --- /dev/null +++ b/uppsrc/Core/Other.hpp @@ -0,0 +1,204 @@ +template +bool PackedData::GetData(int ii, F out) const +{ + int i = 0; + const byte *s = (const byte *)ptr; + if(s) + for(;;) { + int len = *s++; + if(len == 255) + break; + if(len == 254) { + memcpy(&len, s, 4); + s += 4; + } + if(i == ii) { + out((const char *)s, len); + return true; + } + s += len; + i++; + } + out("", 0); + return false; +} + +template +T PackedData::Get(int ii, T def) const +{ + T q = def; + GetData(ii, [&](const char *ptr, int len) { + if(len) { + ASSERT(len == sizeof(T)); + memcpy(&q, ptr, sizeof(T)); + } + }); + return q; +} + +template +void LRUCache::LinkHead(int i) +{ + Item& m = data[i]; + if(head >= 0) { + int tail = data[head].prev; + m.next = head; + m.prev = tail; + data[head].prev = i; + data[tail].next = i; + } + else + m.prev = m.next = i; + head = i; + count++; +} + + +template +void LRUCache::Unlink(int i) +{ + Item& m = data[i]; + if(m.prev == i) + head = -1; + else { + if(head == i) + head = m.next; + data[m.next].prev = m.prev; + data[m.prev].next = m.next; + } + count--; +} + +template +T& LRUCache::GetLRU() +{ + int tail = data[head].prev; + return *data[tail].data; +} + +template +const K& LRUCache::GetLRUKey() +{ + int tail = data[head].prev; + return key[tail].key; +} + +template +void LRUCache::DropLRU() +{ + if(head >= 0) { + int tail = data[head].prev; + size -= data[tail].size; + data[tail].data.Clear(); + Unlink(tail); + key.Unlink(tail); + } +} + +template +template +void LRUCache::AdjustSize(P getsize) +{ + size = 0; + count = 0; + for(int i = 0; i < data.GetCount(); i++) + if(!key.IsUnlinked(i)) { + int sz = getsize(*data[i].data); + if(sz >= 0) + data[i].size = sz + InternalSize; + size += data[i].size; + count++; + } +} + +template +template +int LRUCache::Remove(P predicate) +{ + int n = 0; + int i = 0; + while(i < data.GetCount()) + if(!key.IsUnlinked(i) && predicate(*data[i].data)) { + size -= data[i].size; + Unlink(i); + key.Unlink(i); + n++; + } + else + i++; + return n; +} + +template +template +bool LRUCache::RemoveOne(P predicate) +{ + int i = head; + if(i >= 0) + for(;;) { + int next = data[i].next; + if(predicate(*data[i].data)) { + size -= data[i].size; + Unlink(i); + key.Unlink(i); + return true; + } + if(i == next || next == head || next < 0) + break; + i = next; + } + return false; +} + +template +void LRUCache::Shrink(int maxsize, int maxcount) +{ + if(maxsize >= 0 && maxcount >= 0) + while(count > maxcount || size > maxsize) + DropLRU(); +} + +template +void LRUCache::Clear() +{ + head = -1; + size = 0; + count = 0; + newsize = foundsize = 0; + key.Clear(); + data.Clear(); +} + +template +void LRUCache::ClearCounters() +{ + flag = !flag; + newsize = foundsize = 0; +} + +template +T& LRUCache::Get(const Maker& m) +{ + Key k; + k.key = m.Key(); + k.type = typeid(m).name(); + int q = key.Find(k); + if(q < 0) { + q = key.Put(k); + Item& t = data.At(q); + t.size = m.Make(t.data.Create()) + InternalSize; + size += t.size; + newsize += t.size; + t.flag = flag; + } + else { + Item& t = data[q]; + Unlink(q); + if(t.flag != flag) { + t.flag = flag; + foundsize += t.size; + } + } + LinkHead(q); + return *data[q].data; +} diff --git a/uppsrc/Core/PackedData.cpp b/uppsrc/Core/PackedData.cpp new file mode 100644 index 000000000..2f4494278 --- /dev/null +++ b/uppsrc/Core/PackedData.cpp @@ -0,0 +1,134 @@ +#include "Core.h" + +namespace Upp { + +PackedData::~PackedData() +{ + if(ptr) MemoryFree(ptr); +} + +void PackedData::Clear() +{ + if(ptr) MemoryFree(ptr); + ptr = nullptr; +} + +Vector PackedData::Unpack() const +{ + Vector r; + const byte *s = (const byte *)ptr; + for(;;) { + int len = *s++; + if(len == 255) + break; + if(len == 254) { + memcpy(&len, s, 4); + s += 4; + } + r << String(s, len); + s += len; + } + return r; +} + +void PackedData::SetData(int ii, const void *data, int datalen) +{ + size_t alloc = 32; + char *result = (char *)MemoryAllocSz(alloc); + char *t = result; + auto Reserve = [&](int n) { + size_t needs = t + n - result; + if(needs > alloc) { + alloc = 3 * needs / 2; + char *r2 = (char *)MemoryAllocSz(alloc); + memcpy(r2, result, t - result); + MemoryFree(result); + t = t - result + r2; + result = r2; + } + }; + auto Out1 = [&](int c) { + Reserve(1); + *t++ = c; + }; + auto Out = [&](const void *s, int len) { + Reserve(len); + memcpy(t, s, len); + t += len; + }; + int i = 0; + const byte *p = (const byte *)ptr; + const byte *s = p; + const byte *b = s; // before last control code + const byte *rb = NULL; // start of replaced area + const byte *re = NULL; // end of replaced area + if(s) + for(;;) { + b = s; + int len = *s++; + if(len == 255) + break; + if(len == 254) { + memcpy(&len, s, sizeof(int)); + s += sizeof(int); + } + if(i == ii) { + rb = b; + s += len; + re = s; + } + else + s += len; + i++; + } + + auto Put = [&]() { + if(datalen < 254) + Out1(datalen); + else { + Out1(254); + byte h[sizeof(int)]; + memcpy(h, &datalen, sizeof(int)); + Out(h, sizeof(int)); + } + Out(data, datalen); + }; + if(rb) { // we have found an area to replace + Out(p, int(rb - p)); + Put(); + Out(re, int((s - re))); + } + else { // we need to add new entries + if(p) // copy existing entries + Out(p, int(b - p)); + while(i < ii) { + Out1(0); + i++; + } + Put(); + Out1(255); + } + if(ptr) + MemoryFree(ptr); + ptr = result; +} + +size_t PackedData::GetPackedSize() const +{ + if(!ptr) + return 0; + const byte *s = (const byte *)ptr; + for(;;) { + int len = *s++; + if(len == 255) + break; + if(len == 254) { + memcpy(&len, s, 4); + s += 4; + } + s += len; + } + return s - (const byte *)ptr; +} + +}; \ No newline at end of file diff --git a/uppsrc/Core/Ptr.cpp b/uppsrc/Core/Ptr.cpp index 2d6900d43..b812bec4c 100644 --- a/uppsrc/Core/Ptr.cpp +++ b/uppsrc/Core/Ptr.cpp @@ -2,27 +2,6 @@ namespace Upp { -/* Faster, but consuming more memory.... -PteBase::Prec *PteBase::PtrAdd() -{ - AtomicInc(prec->n); - return prec; -} - -void PteBase::PtrRelease(Prec *prec) -{ - if(prec && AtomicDec(prec->n) == 0) - delete prec; -} - -PteBase::PteBase() -{ - prec = new Prec; - prec->n = 1; - prec->ptr = this; -} -*/ - static StaticMutex sPteLock; PteBase::Prec *PteBase::PtrAdd() diff --git a/uppsrc/Core/Ptr.h b/uppsrc/Core/Ptr.h index 34ce16578..1c348e01e 100644 --- a/uppsrc/Core/Ptr.h +++ b/uppsrc/Core/Ptr.h @@ -11,7 +11,6 @@ protected: Prec *PtrAdd(); static void PtrRelease(Prec *prec); - static Prec *PtrAdd(const Uuid& uuid); PteBase(); ~PteBase(); diff --git a/uppsrc/Core/ValueUtil.cpp b/uppsrc/Core/ValueUtil.cpp index 8d2ef2285..2cf5b0e61 100644 --- a/uppsrc/Core/ValueUtil.cpp +++ b/uppsrc/Core/ValueUtil.cpp @@ -290,6 +290,8 @@ bool ValueMap::Data::IsNull() const { void ValueMap::Data::Serialize(Stream& s) { s % key % value; + if(key.GetCount() != value.GetCount()) + s.LoadError(); } void ValueMap::Data::Xmlize(XmlIO& xio) diff --git a/uppsrc/Core/Vcont.cpp b/uppsrc/Core/Vcont.cpp index 5385bd1e2..df8242418 100644 --- a/uppsrc/Core/Vcont.cpp +++ b/uppsrc/Core/Vcont.cpp @@ -116,6 +116,8 @@ void Bits::Serialize(Stream& s) if(s.IsStoring()) dwords = GetLast() + 1; s % dwords; + if(dwords < 0) + s.LoadError(); if(s.IsLoading()) CreateRaw(dwords); s.SerializeRaw(bp, dwords); diff --git a/uppsrc/Core/Vcont.hpp b/uppsrc/Core/Vcont.hpp index 95e0f1905..66581b7c3 100644 --- a/uppsrc/Core/Vcont.hpp +++ b/uppsrc/Core/Vcont.hpp @@ -737,11 +737,12 @@ void BiVector::Free() { } } -#ifdef UPP template void BiVector::Serialize(Stream& s) { int n = items; s / n; + if(n < 0) + s.LoadError(); if(s.IsLoading()) { Clear(); while(n--) @@ -758,8 +759,6 @@ String BiVector::ToString() const return AsStringArray(*this); } -#endif - template BiVector::BiVector(std::initializer_list init) { @@ -794,11 +793,12 @@ void BiArray::DeepCopy0(const BiArray& v) { bv.AddTail() = new T(clone(v[i])); } -#ifdef UPP template void BiArray::Serialize(Stream& s) { int n = bv.GetCount(); s / n; + if(n < 0) + s.LoadError(); if(s.IsLoading()) { Clear(); while(n--) @@ -822,8 +822,6 @@ BiArray::BiArray(std::initializer_list init) AddTail(q); } -#endif - inline void Bits::Set(int i, dword bits, int count) { diff --git a/uppsrc/Core/Xmlize.cpp b/uppsrc/Core/Xmlize.cpp index d5e2c67fe..f69ff6fdd 100644 --- a/uppsrc/Core/Xmlize.cpp +++ b/uppsrc/Core/Xmlize.cpp @@ -62,7 +62,7 @@ template<> void XmlAttrLoad(dword& var, const String& text) template<> String XmlAttrStore(const double& var) { - return FormatG(var, 17); + return FormatG(var, 15); } template<> void XmlAttrLoad(double& var, const String& text) diff --git a/uppsrc/CtrlCore/Ctrl.cpp b/uppsrc/CtrlCore/Ctrl.cpp index ca00a80be..2319ba934 100644 --- a/uppsrc/CtrlCore/Ctrl.cpp +++ b/uppsrc/CtrlCore/Ctrl.cpp @@ -79,7 +79,9 @@ void Ctrl::Layout() {} void Ctrl::PostInput() { GuiLock __; - if(parent) parent->PostInput(); + Ctrl *parent = GetParent(); + if(parent) + parent->PostInput(); } void Ctrl::LeftDouble(Point p, dword keyflags) @@ -105,25 +107,33 @@ void Ctrl::RightTriple(Point p, dword keyflags) void Ctrl::ChildGotFocus() { GuiLock __; - if(parent) parent->ChildGotFocus(); + Ctrl *parent = GetParent(); + if(parent) + parent->ChildGotFocus(); } void Ctrl::ChildLostFocus() { GuiLock __; - if(parent) parent->ChildLostFocus(); + Ctrl *parent = GetParent(); + if(parent) + parent->ChildLostFocus(); } void Ctrl::ChildAdded(Ctrl *q) { GuiLock __; - if(parent) parent->ChildAdded(q); + Ctrl *parent = GetParent(); + if(parent) + parent->ChildAdded(q); } void Ctrl::ChildRemoved(Ctrl *q) { GuiLock __; - if(parent) parent->ChildRemoved(q); + Ctrl *parent = GetParent(); + if(parent) + parent->ChildRemoved(q); } void Ctrl::ParentChange() {} @@ -287,6 +297,7 @@ void Ctrl::Show(bool ashow) { visible = ashow; fullrefresh = false; RefreshFrame(); + Ctrl *parent = GetParent(); if(parent) StateH(SHOW); if(top) @@ -301,8 +312,9 @@ bool Ctrl::IsVisible() const { const Ctrl *q = this; for(;;) { if(!q->visible) return false; - if(!q->parent) break; - q = q->parent; + Ctrl *p = q->GetParent(); + if(!p) break; + q = p; } return q->visible; } @@ -312,7 +324,7 @@ void Ctrl::Enable(bool aenable) { if(enabled != aenable) { enabled = aenable; if(top) WndEnable(enabled); - if(!enabled && parent && HasFocusDeep()) + if(!enabled && GetParent() && HasFocusDeep()) IterateFocusForward(this, GetTopCtrl()); RefreshFrame(); StateH(ENABLE); @@ -322,6 +334,7 @@ void Ctrl::Enable(bool aenable) { bool Ctrl::IsShowEnabled() const { GuiLock __; + Ctrl *parent = GetParent(); return IsEnabled() && (!parent || parent->IsShowEnabled()); } @@ -353,8 +366,8 @@ void Ctrl::ClearModifyDeep() { GuiLock __; ClearModify(); - for(Ctrl *q = firstchild; q; q = q->next) - q->ClearModifyDeep(); + for(Ctrl& q : *this) + q.ClearModifyDeep(); } @@ -368,92 +381,14 @@ bool Ctrl::IsModifiedDeep() const { GuiLock __; if(IsModified()) return true; - for(Ctrl *q = firstchild; q; q = q->next) - if(q->IsModified()) return true; + for(const Ctrl& q : *this) + if(q.IsModified()) return true; return false; } -void Ctrl::SetCaret(const Rect& r) -{ - SetCaret(r.left, r.top, r.GetWidth(), r.GetHeight()); -} - Rect Ctrl::GetCaret() const { - return RectC(caretx, carety, caretcx, caretcy); -} - -void Ctrl::KillCaret() -{ - SetCaret(0, 0, 0, 0); -} - -void Ctrl::SetInfoPart(int i, const char *txt) -{ - Vector f = Split(info, '\x7f', false); - f.At(i) = txt; - info = Join(f, "\x7f"); -} - -Ctrl& Ctrl::Tip(const char *txt) -{ - SetInfoPart(0, txt); - return *this; -} - -Ctrl& Ctrl::HelpLine(const char *txt) -{ - SetInfoPart(1, txt); - return *this; -} - -Ctrl& Ctrl::Description(const char *txt) -{ - SetInfoPart(2, txt); - return *this; -} - -Ctrl& Ctrl::HelpTopic(const char *txt) -{ - SetInfoPart(3, txt); - return *this; -} - -Ctrl& Ctrl::LayoutId(const char *txt) -{ - SetInfoPart(4, txt); - return *this; -} - -String Ctrl::GetInfoPart(int i) const -{ - Vector f = Split(info, '\x7f', false); - return i < f.GetCount() ? f[i] : String(); -} - -String Ctrl::GetTip() const -{ - return GetInfoPart(0); -} - -String Ctrl::GetHelpLine() const -{ - return GetInfoPart(1); -} - -String Ctrl::GetDescription() const -{ - return GetInfoPart(2); -} - -String Ctrl::GetHelpTopic() const -{ - return GetInfoPart(3); -} - -String Ctrl::GetLayoutId() const -{ - return GetInfoPart(4); + return Null; } bool Ctrl::SetWantFocus() { @@ -493,8 +428,8 @@ void Ctrl::UpdateActionRefresh() { void Ctrl::CancelModeDeep() { GuiLock __; CancelMode(); - for(Ctrl *q = firstchild; q; q = q->next) - q->CancelModeDeep(); + for(Ctrl& q : *this) + q.CancelModeDeep(); } String Ctrl::GetDesc() const @@ -547,14 +482,14 @@ void Ctrl::Dump(Stream& s) const { sFLAG(wantfocus) << sFLAG(editable) << sFLAG(IsModified()) << sFLAG(transparent)); LG("Rect: " << GetRect()); LG("View: " << GetView()); - for(int i = 0; i < frame.GetCount(); i++) - LG("Frame " << i << ": " << typeid(decltype(*frame[i].frame)).name() << " - " << frame[i].view); + for(int i = 0; i < GetFrameCount(); i++) + LG("Frame " << i << ": " << typeid(decltype(*GetFrame0(i).frame)).name() << " - " << GetFrame0(i).GetView()); LG("Data: " << GetData().ToString()); - if(firstchild) { + if(children) { LG("Children"); s << LOG_BEGIN; - for(Ctrl *q = GetFirstChild(); q; q = q->GetNext()) { - q->Dump(s); + for(const Ctrl& q : *this) { + q.Dump(s); LG("------"); } s << LOG_END; @@ -592,16 +527,13 @@ Ctrl::Ctrl() { LLOG("Ctrl::Ctrl"); GuiPlatformConstruct(); destroying = false; - parent = prev = next = firstchild = lastchild = NULL; - top = NULL; - exitcode = 0; - frame.Add().frame = &NullFrame(); + multi_frame = false; + frame.frame = &NullFrame(); enabled = visible = wantfocus = initfocus = true; editable = true; backpaint = IsCompositedGui() ? FULLBACKPAINT : TRANSPARENTBACKPAINT; inframe = false; ignoremouse = transparent = false; - caretcx = caretcy = caretx = carety = 0; pos.x = PosLeft(0, 0); pos.y = PosTop(0, 0); rect = Rect(0, 0, 0, 0); @@ -611,6 +543,9 @@ Ctrl::Ctrl() { popupgrab = false; fullrefresh = false; akv = false; + layout_id_literal = false; + top = false; + uparent = nullptr; } void KillTimeCallbacks(void *id, void *idlim); @@ -626,6 +561,7 @@ void Ctrl::DoRemove() { mouseCtrl = NULL; LLOG("DoRemove " << Name() << " focusCtrl: " << UPP::Name(focusCtrl)); GuiPlatformRemove(); + Ctrl *parent = GetParent(); if(HasFocusDeep()) { LLOG("DoRemove - HasFocusDeep"); if(destroying) { @@ -675,7 +611,7 @@ void Ctrl::Close() Ctrl *q = GetTopCtrl(); if(!q->top) return; DoRemove(); - if(parent) return; + if(GetParent()) return; StateH(CLOSE); USRLOG(" CLOSE " + Desc(this)); WndDestroy(); @@ -689,10 +625,13 @@ Ctrl::~Ctrl() { destroying = true; while(GetFirstChild()) RemoveChild(GetFirstChild()); + Ctrl *parent = GetParent(); if(parent) parent->RemoveChild(this); Close(); KillTimeCallbacks(this, (byte *) this + sizeof(Ctrl)); + ClearInfo(); + FreeFrames(); } Vector& Ctrl::mousehook() { static Vector h; return h; } @@ -1035,7 +974,7 @@ String Ctrl::Name0() const { String id = q->GetLayoutId(); if(id.GetCount()) path = '.' + q->GetLayoutId() + path; - q = q->parent; + q = q->GetParent(); } s << ' ' << path; #ifdef CPU_64 @@ -1043,6 +982,7 @@ String Ctrl::Name0() const { #else s << " : " + Format("0x%x", (int) this); #endif + Ctrl *parent = GetParent(); if(IsChild()) s << " (parent " << CppDemangle(typeid(*parent).name()) << ")"; return s; @@ -1063,8 +1003,10 @@ void Ctrl::EndLoop() void Ctrl::EndLoop(int code) { GuiLock __; - ASSERT(!parent); - exitcode = code; + ASSERT(!GetParent()); + TopWindow *w = GetTopWindow(); + if(w) + w->exitcode = code; EndLoop(); } @@ -1080,12 +1022,6 @@ bool Ctrl::InCurrentLoop() const return GetLoopCtrl() == this; } -int Ctrl::GetExitCode() const -{ - GuiLock __; - return exitcode; -} - #ifdef HAS_TopFrameDraw ViewDraw::ViewDraw(Ctrl *ctrl, const Rect& r) diff --git a/uppsrc/CtrlCore/CtrlAttr.cpp b/uppsrc/CtrlCore/CtrlAttr.cpp new file mode 100644 index 000000000..9c48397af --- /dev/null +++ b/uppsrc/CtrlCore/CtrlAttr.cpp @@ -0,0 +1,181 @@ +#include "CtrlCore.h" + +namespace Upp { + +PackedData& Ctrl::Attrs() +{ + if(layout_id_literal) { + String layout_id((const char *)attrs.GetRawPtr()); + attrs.SetRawPtr(nullptr); + attrs.SetString(ATTR_LAYOUT_ID, layout_id); + layout_id_literal = false; + } + return attrs; +} + +void Ctrl::SetTextAttr(int ii, const char *s) +{ + Attrs().SetString(ii, s); +} + +void Ctrl::SetTextAttr(int ii, const String& s) +{ + Attrs().SetString(ii, s); +} + +String Ctrl::GetTextAttr(int ii) const +{ + return layout_id_literal ? String() : attrs.GetString(ii); +} + +Ctrl& Ctrl::Tip(const char *txt) +{ + SetTextAttr(ATTR_TIP, txt); + return *this; +} + +Ctrl& Ctrl::HelpLine(const char *txt) +{ + SetTextAttr(ATTR_HELPLINE, txt); + return *this; +} + +Ctrl& Ctrl::Description(const char *txt) +{ + SetTextAttr(ATTR_DESCRIPTION, txt); + return *this; +} + +Ctrl& Ctrl::HelpTopic(const char *txt) +{ + SetTextAttr(ATTR_HELPTOPIC, txt); + return *this; +} + +Ctrl& Ctrl::LayoutId(const char *txt) +{ + SetTextAttr(ATTR_LAYOUT_ID, txt); + return *this; +} + +Ctrl& Ctrl::LayoutIdLiteral(const char *txt) +{ + if(attrs.GetRawPtr() && !layout_id_literal) + LayoutId(txt); + else { + attrs.SetRawPtr((void *)txt); + layout_id_literal = true; + } + return *this; +} + +String Ctrl::GetLayoutId() const +{ + if(layout_id_literal) + return (const char *)attrs.GetRawPtr(); + return GetTextAttr(ATTR_LAYOUT_ID); +} + +String Ctrl::GetTip() const +{ + return GetTextAttr(ATTR_TIP); +} + +String Ctrl::GetHelpLine() const +{ + return GetTextAttr(ATTR_HELPLINE); +} + +String Ctrl::GetDescription() const +{ + return GetTextAttr(ATTR_DESCRIPTION); +} + +String Ctrl::GetHelpTopic() const +{ + return GetTextAttr(ATTR_HELPTOPIC); +} + +void Ctrl::ClearInfo() +{ + if(layout_id_literal) + attrs.SetRawPtr(nullptr); + layout_id_literal = false; + attrs.Clear(); +} + +void Ctrl::SetColorAttr(int ii, Color c) +{ + Attrs(); + if(IsNull(c)) + attrs.SetNull(ii); + else + attrs.SetDword(ii, c.GetRaw()); +} + +Color Ctrl::GetColorAttr(int ii) const +{ + if(layout_id_literal) + return Null; + static dword nullval = Color(Null).GetRaw(); + return Color::FromRaw(attrs.GetDword(ii, nullval)); +} + +void Ctrl::SetFontAttr(int ii, Font fnt) +{ + Attrs(); + if(IsNull(fnt)) + attrs.SetNull(ii); + else + attrs.SetInt64(ii, fnt.AsInt64()); +} + +Font Ctrl::GetFontAttr(int ii) const +{ + if(layout_id_literal) + return Null; + static dword nullval = Font(Null).AsInt64(); + return Font::FromInt64(attrs.GetInt64(ii, nullval)); +} + +void Ctrl::SetIntAttr(int ii, int val) +{ + Attrs().SetInt(ii, val); +} + +int Ctrl::GetIntAttr(int ii, int def) const +{ + if(layout_id_literal) + return def; + return attrs.GetInt(ii, def); +} + +void Ctrl::SetInt64Attr(int ii, int64 val) +{ + Attrs().SetInt64(ii, val); +} + +int Ctrl::GetInt64Attr(int ii, int64 def) const +{ + if(layout_id_literal) + return def; + return attrs.GetInt64(ii, def); +} + + +void Ctrl::SetVoidPtrAttr(int ii, const void *ptr) +{ + if(ptr) + Attrs().SetPtr(ii, (void *)ptr); + else + Attrs().SetNull(ii); +} + +void *Ctrl::GetVoidPtrAttr(int ii) const +{ + if(layout_id_literal) + return NULL; + return attrs.GetPtr(ii); +} + +}; \ No newline at end of file diff --git a/uppsrc/CtrlCore/CtrlChild.cpp b/uppsrc/CtrlCore/CtrlChild.cpp index caf4a6624..58a6d9da1 100644 --- a/uppsrc/CtrlCore/CtrlChild.cpp +++ b/uppsrc/CtrlCore/CtrlChild.cpp @@ -4,6 +4,25 @@ namespace Upp { #define LLOG(x) // DLOG(x) +void Ctrl::DeleteTop() +{ + if(top && utop) { + delete utop; + utop = nullptr; + top = false; + } +} + +void Ctrl::SetParent(Ctrl *parent) +{ + if(top && utop) { + Close(); + DeleteTop(); // if Close did not work as expected...: + } + uparent = parent; + top = false; +} + bool Ctrl::IsDHCtrl() const { return dynamic_cast(this); } @@ -15,38 +34,31 @@ void Ctrl::AddChild(Ctrl *q, Ctrl *p) LLOG("Add " << UPP::Name(q) << " to: " << Name()); if(p == q) return; bool updaterect = true; - if(q->parent) { + Ctrl *qparent = q->GetParent(); + if(qparent) { ASSERT(!q->inframe); - if(q->parent == this) { + if(qparent == this) { RemoveChild0(q); updaterect = false; } else - q->parent->RemoveChild(q); + qparent->RemoveChild(q); } - q->parent = this; - if(p) { - ASSERT(p->parent == this); - q->prev = p; - q->next = p->next; - if(p == lastchild) - lastchild = q; - else - p->next->prev = q; - p->next = q; + + if(children) { + if(!p) p = GetLastChild(); + ASSERT(p->GetParent() == this); + q->prev_sibling = p; + q->next_sibling = p->next_sibling; + p->next_sibling->prev_sibling = q; + p->next_sibling = q; } - else - if(firstchild) { - q->prev = NULL; - q->next = firstchild; - firstchild->prev = q; - firstchild = q; - } - else { - ASSERT(lastchild == NULL); - firstchild = lastchild = q; - q->prev = q->next = NULL; - } + else { + ASSERT(!p); + children = q->next_sibling = q->prev_sibling = q; + } + q->SetParent(this); + q->CancelModeDeep(); if(updaterect) q->UpdateRect(); @@ -58,13 +70,13 @@ void Ctrl::AddChild(Ctrl *q, Ctrl *p) void Ctrl::AddChild(Ctrl *child) { - AddChild(child, lastchild); + AddChild(child, GetLastChild()); } void Ctrl::AddChildBefore(Ctrl *child, Ctrl *insbefore) { if(insbefore) - AddChild(child, insbefore->prev); + AddChild(child, insbefore->GetPrev()); else AddChild(child); } @@ -73,23 +85,26 @@ void Ctrl::RemoveChild0(Ctrl *q) { GuiLock __; ChildRemoved(q); + if(!q->GetParent()) return; // ChildRemoved can remove q q->DoRemove(); - q->parent = NULL; - if(q == firstchild) - firstchild = firstchild->next; - if(q == lastchild) - lastchild = lastchild->prev; - if(q->prev) - q->prev->next = q->next; - if(q->next) - q->next->prev = q->prev; - q->next = q->prev = NULL; + if(!q->GetParent()) return; // DoRemove can remove q + q->SetParent(NULL); + + if(q == children) { + children = q->next_sibling; + if(children == q) + children = NULL; + } + + q->prev_sibling->next_sibling = q->next_sibling; + q->next_sibling->prev_sibling = q->prev_sibling; + q->next_sibling = q->prev_sibling = NULL; } void Ctrl::RemoveChild(Ctrl *q) { GuiLock __; - if(q->parent != this) return; + if(q->GetParent() != this) return; q->RefreshFrame(); RemoveChild0(q); q->ParentChange(); @@ -100,6 +115,7 @@ void Ctrl::RemoveChild(Ctrl *q) void Ctrl::Remove() { GuiLock __; + Ctrl *parent = GetParent(); if(parent) parent->RemoveChild(this); } @@ -171,15 +187,16 @@ Ctrl * Ctrl::GetViewIndexChild(int ii) const bool Ctrl::HasChild(Ctrl *q) const { GuiLock __; - return q && q->IsChild() && q->parent == this; + return q && q->GetParent() == this; } bool Ctrl::HasChildDeep(Ctrl *q) const { GuiLock __; while(q && q->IsChild()) { - if(q->parent == this) return true; - q = q->parent; + Ctrl *qparent = q->GetParent(); + if(qparent == this) return true; + q = qparent; } return false; } @@ -260,9 +277,12 @@ Ctrl *Ctrl::GetTopCtrl() { GuiLock __; Ctrl *q = this; - while(q->parent) - q = q->parent; - return q; + for(;;) { + Ctrl *qparent = q->GetParent(); + if(!qparent) + return q; + q = qparent; + } } const Ctrl *Ctrl::GetTopCtrl() const { return const_cast(this)->GetTopCtrl(); } @@ -270,7 +290,7 @@ const Ctrl *Ctrl::GetOwner() const { return const_cast(this)->Get Ctrl *Ctrl::GetTopCtrlOwner() { return GetTopCtrl()->GetOwner(); } const Ctrl *Ctrl::GetTopCtrlOwner() const { return GetTopCtrl()->GetOwner(); } -Ctrl *Ctrl::GetOwnerCtrl() { GuiLock __; return !IsChild() && top ? top->owner : NULL; } +Ctrl *Ctrl::GetOwnerCtrl() { GuiLock __; return !IsChild() && top && utop ? utop->owner : NULL; } const Ctrl *Ctrl::GetOwnerCtrl() const { return const_cast(this)->GetOwnerCtrl(); } TopWindow *Ctrl::GetTopWindow() diff --git a/uppsrc/CtrlCore/CtrlCore.h b/uppsrc/CtrlCore/CtrlCore.h index dedf5626b..16ee5dfd4 100644 --- a/uppsrc/CtrlCore/CtrlCore.h +++ b/uppsrc/CtrlCore/CtrlCore.h @@ -478,14 +478,29 @@ private: void operator=(Ctrl&); private: - struct Frame : Moveable { - CtrlFrame *frame; - Rect16 view; - - Frame() { view.Clear(); } + struct MultiFrame { // in case there are more than 1 CtrlFrames + int alloc; + int count; }; - Ctrl *parent; + struct Rect16_ { // so that it can be in union + int16 left, top, right, bottom; + }; + + struct Frame { + union { + CtrlFrame *frame; + Frame *frames; + }; + union { + MultiFrame multi; + Rect16_ view; + }; + + void SetView(const Rect& r) { view.left = r.left; view.right = r.right; view.top = r.top; view.bottom = r.bottom; } + Rect GetView() const { return Rect16(view.left, view.top, view.right, view.bottom); } + }; + struct Scroll : Moveable { Rect rect; int dx; @@ -508,16 +523,20 @@ private: Ptr owner; }; - Top *top; - int exitcode; - Ctrl *prev, *next; - Ctrl *firstchild, *lastchild;//16 + Frame frame; LogPos pos;//8 - Rect16 rect; - Mitor frame;//16 - String info;//16 - int16 caretx, carety, caretcx, caretcy;//8 + Rect16 rect; //8 + + union { + Ctrl *uparent; + Top *utop; + }; + + Ctrl *prev_sibling = nullptr; + Ctrl *next_sibling = nullptr; + Ctrl *children = nullptr; + PackedData attrs; byte overpaint; @@ -543,6 +562,9 @@ private: bool akv:1; bool destroying:1; + bool layout_id_literal:1; // info_ptr points to layout char * literal, no heap involved + bool multi_frame:1; // there is more than single frame, they are stored in heap + bool top:1; static Ptr eventCtrl; static Ptr mouseCtrl; @@ -551,8 +573,6 @@ private: static Ptr focusCtrl; static Ptr focusCtrlWnd; static Ptr lastActiveWnd; - static Ptr caretCtrl; - static Rect caretRect; static Ptr captureCtrl; static bool ignoreclick; static bool ignoremouseup; @@ -634,12 +654,20 @@ private: void RefreshAccessKeys(); void RefreshAccessKeysDo(bool vis); static void DefferedFocusSync(); - static void SyncCaret(); - static void RefreshCaret(); static bool DispatchKey(dword keycode, int count); void SetFocusWnd(); void KillFocusWnd(); + static Ptr caretCtrl; + static Ptr prevCaretCtrl; + static Rect caretRect; + static int WndCaretTime; + static bool WndCaretVisible; + + static void AnimateCaret(); + static void SyncCaret(); + static void RefreshCaret(); + static Ptr dndctrl; static Point dndpos; static bool dndframe; @@ -667,8 +695,6 @@ private: void UpdateArea(SystemDraw& draw, const Rect& clip); Ctrl *GetTopRect(Rect& r, bool inframe, bool clip = true); void DoSync(Ctrl *q, Rect r, bool inframe); - void SetInfoPart(int i, const char *txt); - String GetInfoPart(int i) const; Rect GetPreeditScreenRect(); void SyncPreedit(); @@ -718,6 +744,21 @@ private: void SysEndLoop(); String Name0() const; + + Top *GetTop() { return top ? utop : NULL; } + const Top *GetTop() const { return top ? utop : NULL; } + void DeleteTop(); + + void SetTop(Top *t) { utop = t; top = true; } + void SetParent(Ctrl *parent); + + Frame& GetFrame0(int i) { ASSERT(i < GetFrameCount()); return multi_frame ? frame.frames[i] : frame; } + const Frame& GetFrame0(int i) const { ASSERT(i < GetFrameCount()); return multi_frame ? frame.frames[i] : frame; } + void FreeFrames() { if(multi_frame) MemoryFree(frame.frames); } + Frame AllocFrames(int alloc); + + PackedData& Attrs(); + static void InitTimer(); @@ -779,7 +820,44 @@ protected: static void TimerProc(dword time); Ctrl& Unicode() { unicode = true; return *this; } + + enum { + ATTR_LAYOUT_ID, + ATTR_TIP, + ATTR_HELPLINE, + ATTR_DESCRIPTION, + ATTR_HELPTOPIC, + ATTR_LAST + }; + + void SetTextAttr(int ii, const char *s); + void SetTextAttr(int ii, const String& s); + String GetTextAttr(int ii) const; + + void SetColorAttr(int ii, Color c); + Color GetColorAttr(int ii) const; + + void SetFontAttr(int ii, Font fnt); + Font GetFontAttr(int ii) const; + + void SetIntAttr(int ii, int val); + int GetIntAttr(int ii, int def = Null) const; + void SetInt64Attr(int ii, int64 val); + int GetInt64Attr(int ii, int64 def = Null) const; + + void SetVoidPtrAttr(int ii, const void *ptr); + void *GetVoidPtrAttr(int ii) const; + + template + T& CreateAttr(int ii) { T *q = new T; SetVoidPtrAttr(ii, q); return *q; } + + template + T GetAttr(int ii) const { void *p = GetVoidPtrAttr(ii); return p ? *(T *)p : T(); } + + template + void DeleteAttr(int ii) { void *p = GetVoidPtrAttr(ii); if(p) { delete (T *)p; SetVoidPtrAttr(ii, nullptr); }; } + public: enum StateReason { FOCUS = 10, @@ -915,6 +993,8 @@ public: virtual Point GetPreedit(); virtual Font GetPreeditFont(); + virtual Rect GetCaret() const; + virtual void DragAndDrop(Point p, PasteClip& d); virtual void FrameDragAndDrop(Point p, PasteClip& d); virtual void DragRepeat(Point p); @@ -972,11 +1052,11 @@ public: void AddChild(Ctrl *child, Ctrl *insafter); void AddChildBefore(Ctrl *child, Ctrl *insbefore); void RemoveChild(Ctrl *child); - Ctrl *GetParent() const { return parent; } - Ctrl *GetLastChild() const { return lastchild; } - Ctrl *GetFirstChild() const { return firstchild; } - Ctrl *GetPrev() const { return parent ? prev : NULL; } - Ctrl *GetNext() const { return parent ? next : NULL; } + Ctrl *GetParent() const { return top ? NULL : uparent; } + Ctrl *GetLastChild() const { return children ? children->prev_sibling : nullptr; } + Ctrl *GetFirstChild() const { return children; } + Ctrl *GetPrev() const { Ctrl *parent = GetParent(); return parent && prev_sibling != parent->GetLastChild() ? prev_sibling : nullptr; } + Ctrl *GetNext() const { Ctrl *parent = GetParent(); return parent && next_sibling != parent->children ? next_sibling : nullptr; } int GetChildIndex(const Ctrl *child) const; Ctrl *GetIndexChild(int i) const; int GetChildCount() const; @@ -987,7 +1067,7 @@ public: int GetViewChildCount() const; Ctrl *GetViewIndexChild(int ii) const; - bool IsChild() const { return parent; } + bool IsChild() const { return GetParent(); } Ctrl *ChildFromPoint(Point& pt) const; @@ -1013,13 +1093,13 @@ public: Ctrl& SetFrame(int i, CtrlFrame& frm); Ctrl& SetFrame(CtrlFrame& frm) { return SetFrame(0, frm); } Ctrl& AddFrame(CtrlFrame& frm); - const CtrlFrame& GetFrame(int i = 0) const { return *frame[i].frame; } - CtrlFrame& GetFrame(int i = 0) { return *frame[i].frame; } + const CtrlFrame& GetFrame(int i = 0) const { return *const_cast(this)->GetFrame0(i).frame; } + CtrlFrame& GetFrame(int i = 0) { return *GetFrame0(i).frame; } void RemoveFrame(int i); void RemoveFrame(CtrlFrame& frm); void InsertFrame(int i, CtrlFrame& frm); - int FindFrame(CtrlFrame& frm); - int GetFrameCount() const { return frame.GetCount(); } + int FindFrame(CtrlFrame& frm) const; + int GetFrameCount() const { return multi_frame ? frame.multi.count : frame.frame ? 1 : 0; } void ClearFrames(); bool IsOpen() const; @@ -1055,10 +1135,10 @@ public: void RefreshLayout() { SyncLayout(1); } void RefreshLayoutDeep() { SyncLayout(2); } - void RefreshParentLayout() { if(parent) parent->RefreshLayout(); } + void RefreshParentLayout(); void UpdateLayout() { SyncLayout(); } - void UpdateParentLayout() { if(parent) parent->UpdateLayout(); } + void UpdateParentLayout(); Ctrl& LeftPos(int a, int size = STDSIZE); Ctrl& RightPos(int a, int size = STDSIZE); @@ -1157,11 +1237,6 @@ public: void CancelModeDeep(); - void SetCaret(int x, int y, int cx, int cy); - void SetCaret(const Rect& r); - Rect GetCaret() const; - void KillCaret(); - static void CancelPreedit(); void CancelMyPreedit() { if(HasFocus()) CancelPreedit(); } @@ -1211,21 +1286,19 @@ public: Ctrl& NoTransparent() { return Transparent(false); } bool IsTransparent() const { return transparent; } - Ctrl& Info(const char *txt) { info = txt; return *this; } - String GetInfo() const { return info; } - Ctrl& Tip(const char *txt); Ctrl& HelpLine(const char *txt); Ctrl& Description(const char *txt); Ctrl& HelpTopic(const char *txt); Ctrl& LayoutId(const char *txt); + Ctrl& LayoutIdLiteral(const char *txt); String GetTip() const; String GetHelpLine() const; String GetDescription() const; String GetHelpTopic() const; String GetLayoutId() const; - void ClearInfo() { info.Clear(); } + void ClearInfo(); void Add(Ctrl& ctrl) { AddChild(&ctrl); } Ctrl& operator<<(Ctrl& ctrl) { Add(ctrl); return *this; } @@ -1276,7 +1349,6 @@ public: void EndLoop(int code); bool InLoop() const; bool InCurrentLoop() const; - int GetExitCode() const; static PasteClip& Clipboard(); static PasteClip& Selection(); diff --git a/uppsrc/CtrlCore/CtrlCore.upp b/uppsrc/CtrlCore/CtrlCore.upp index 07aba46dd..9d14ed929 100644 --- a/uppsrc/CtrlCore/CtrlCore.upp +++ b/uppsrc/CtrlCore/CtrlCore.upp @@ -21,7 +21,9 @@ file Frame.cpp, CtrlMt.cpp, Ctrl.cpp, + CtrlAttr.cpp, CtrlChild.cpp, + CtrlFrame.cpp, CtrlPos.cpp, CtrlDraw.cpp, CtrlMouse.cpp, diff --git a/uppsrc/CtrlCore/CtrlDraw.cpp b/uppsrc/CtrlCore/CtrlDraw.cpp index ca293d63b..d5cbfd2d5 100644 --- a/uppsrc/CtrlCore/CtrlDraw.cpp +++ b/uppsrc/CtrlCore/CtrlDraw.cpp @@ -22,6 +22,7 @@ void Ctrl::RefreshFrame(const Rect& r) { if(GuiPlatformRefreshFrameSpecial(r)) return; if(!top && !IsDHCtrl()) { + Ctrl *parent = GetParent(); if(InFrame()) parent->RefreshFrame(r + GetRect().TopLeft()); else @@ -83,6 +84,7 @@ void Ctrl::ScrollRefresh(const Rect& r, int dx, int dy) bool Ctrl::AddScroll(const Rect& sr, int dx, int dy) { GuiLock __; + Top *top = GetTop(); if(!top) return true; for(int i = 0; i < top->scroll.GetCount(); i++) { @@ -113,12 +115,12 @@ Rect Ctrl::GetClippedView() GuiLock __; Rect sv = GetScreenView(); Rect view = sv; - Ctrl *q = parent; + Ctrl *q = GetParent(); Ctrl *w = this; while(q) { view &= w->InFrame() ? q->GetScreenRect() : q->GetScreenView(); w = q; - q = q->parent; + q = q->GetParent(); } return view - GetScreenRect().TopLeft(); } @@ -178,7 +180,7 @@ void Ctrl::ScrollView(const Rect& _r, int dx, int dy) Rect r = _r & vsz; LLOG("ScrollView2 " << r << " " << dx << " " << dy); Ctrl *w; - for(w = this; w->parent; w = w->parent) + for(w = this; w->GetParent(); w = w->GetParent()) if(w->InFrame()) { Refresh(); return; @@ -191,12 +193,12 @@ void Ctrl::ScrollView(const Rect& _r, int dx, int dy) Refresh(); else { LTIMING("ScrollCtrls1"); - Top *top = GetTopCtrl()->top; + Top *top = GetTopCtrl()->GetTop(); for(Ctrl *q = GetFirstChild(); q; q = q->GetNext()) if(q->InView()) ScrollCtrl(top, q, r, q->GetRect(), dx, dy); - if(parent) - for(Ctrl *q = parent->GetFirstChild(); q; q = q->GetNext()) + if(GetParent()) + for(Ctrl *q = GetParent()->GetFirstChild(); q; q = q->GetNext()) if(q->InView() && q != this) ScrollCtrl(top, q, r, q->GetScreenRect() - GetScreenView().TopLeft(), dx, dy); } @@ -214,6 +216,7 @@ void Ctrl::ScrollView(int dx, int dy) { void Ctrl::SyncScroll() { GuiLock __; + Top *top = GetTop(); if(!top) return; Vector scroll = pick(top->scroll); @@ -278,29 +281,31 @@ void Ctrl::CtrlPaint(SystemDraw& w, const Rect& clip) { return; Ctrl *q; Rect view = rect; - for(int i = 0; i < frame.GetCount(); i++) { + int n = GetFrameCount(); + for(int i = 0; i < n; i++) { LEVELCHECK(w, NULL); - frame[i].frame->FramePaint(w, view); - view = frame[i].view; + Frame& f = GetFrame0(i); + f.frame->FramePaint(w, view); + view = f.GetView(); } Rect oview = view.Inflated(overpaint); bool hasviewctrls = false; bool viewexcluded = false; bool hiddenbychild = false; - for(q = firstchild; q; q = q->next) - if(q->IsShown()) { - if(q->GetRect().Contains(orect) && !q->IsTransparent()) + for(Ctrl& q : *this) + if(q.IsShown()) { + if(q.GetRect().Contains(orect) && !q.IsTransparent()) hiddenbychild = true; - if(q->InFrame()) { - if(!viewexcluded && IsTransparent() && q->GetRect().Intersects(view)) { + if(q.InFrame()) { + if(!viewexcluded && IsTransparent() && q.GetRect().Intersects(view)) { w.Begin(); w.ExcludeClip(view); viewexcluded = true; } - LEVELCHECK(w, q); - Point off = q->GetRect().TopLeft(); + LEVELCHECK(w, &q); + Point off = q.GetRect().TopLeft(); w.Offset(off); - q->CtrlPaint(w, clip - off); + q.CtrlPaint(w, clip - off); w.End(); } else @@ -329,15 +334,15 @@ void Ctrl::CtrlPaint(SystemDraw& w, const Rect& clip) { if(hasviewctrls && !view.IsEmpty()) { Rect cl = clip & view; w.Clip(cl); - for(q = firstchild; q; q = q->next) - if(q->IsShown() && q->InView()) { - LEVELCHECK(w, q); - Rect qr = q->GetRect(); + for(Ctrl& q : *this) + if(q.IsShown() && q.InView()) { + LEVELCHECK(w, &q); + Rect qr = q.GetRect(); Point off = qr.TopLeft() + view.TopLeft(); Rect ocl = cl - off; if(ocl.Intersects(Rect(qr.GetSize()).Inflated(overpaint))) { w.Offset(off); - q->CtrlPaint(w, ocl); + q.CtrlPaint(w, ocl); w.End(); } } @@ -373,11 +378,11 @@ bool Ctrl::PaintOpaqueAreas(SystemDraw& w, const Rect& r, const Rect& clip, bool if(backpaint == EXCLUDEPAINT) return w.ExcludeClip(r); Rect cview = clip & (GetView() + off); - for(Ctrl *q = lastchild; q; q = q->prev) - if(!q->PaintOpaqueAreas(w, q->GetRect() + (q->InView() ? viewpos : off), - q->InView() ? cview : clip)) + for(Ctrl& q : *this) + if(!q.PaintOpaqueAreas(w, q.GetRect() + (q.InView() ? viewpos : off), + q.InView() ? cview : clip)) return false; - if(nochild && (lastchild || GetNext())) + if(nochild && (GetLastChild() || GetNext())) return true; Rect opaque = (GetOpaqueRect() + viewpos) & clip; if(opaque.IsEmpty()) @@ -461,11 +466,11 @@ void Ctrl::GatherTransparentAreas(Vector& area, SystemDraw& w, Rect r, con CombineArea(area, clip & Rect(notr.left, r.top, notr.right, notr.top)); CombineArea(area, clip & Rect(notr.left, notr.bottom, notr.right, r.bottom)); } - for(Ctrl *q = firstchild; q; q = q->next) { - Point qoff = q->InView() ? viewpos : off; - Rect qr = q->GetRect() + qoff; + for(Ctrl& q : *this) { + Point qoff = q.InView() ? viewpos : off; + Rect qr = q.GetRect() + qoff; if(clip.Intersects(qr)) - q->GatherTransparentAreas(area, w, qr, clip); + q.GatherTransparentAreas(area, w, qr, clip); } } } @@ -506,9 +511,9 @@ void Ctrl::ExcludeDHCtrls(SystemDraw& w, const Rect& r, const Rect& clip) return; } Rect cview = clip & (GetView() + off); - for(Ctrl *q = lastchild; q; q = q->prev) - q->ExcludeDHCtrls(w, q->GetRect() + (q->InView() ? viewpos : off), - q->InView() ? cview : clip); + for(Ctrl& q : *this) + q.ExcludeDHCtrls(w, q.GetRect() + (q.InView() ? viewpos : off), + q.InView() ? cview : clip); } void Ctrl::UpdateArea0(SystemDraw& draw, const Rect& clip, int backpaint) @@ -597,6 +602,7 @@ Ctrl *Ctrl::GetTopRect(Rect& r, bool inframe, bool clip) r &= Rect(GetSize()); r.Offset(GetView().TopLeft()); } + Ctrl *parent = GetParent(); if(parent) { r.Offset(GetRect().TopLeft()); return parent->GetTopRect(r, InFrame(), clip); @@ -620,6 +626,7 @@ void Ctrl::Sync() { GuiLock __; LLOG("Sync " << Name()); + Ctrl *parent = GetParent(); if(top && IsOpen()) { LLOG("Sync UpdateWindow " << Name()); SyncScroll(); @@ -642,6 +649,7 @@ void Ctrl::Sync(const Rect& sr) void Ctrl::DrawCtrlWithParent(Draw& w, int x, int y) { GuiLock __; + Ctrl *parent = GetParent(); if(parent) { Rect r = GetRect(); Ctrl *top = parent->GetTopRect(r, inframe); @@ -674,6 +682,7 @@ void Ctrl::DrawCtrl(Draw& w, int x, int y) void Ctrl::SyncMoves() { GuiLock __; + Top *top = GetTop(); if(!top) return; for(int i = 0; i < top->move.GetCount(); i++) { diff --git a/uppsrc/CtrlCore/CtrlFrame.cpp b/uppsrc/CtrlCore/CtrlFrame.cpp new file mode 100644 index 000000000..c29eaa19c --- /dev/null +++ b/uppsrc/CtrlCore/CtrlFrame.cpp @@ -0,0 +1,131 @@ +#include "CtrlCore.h" + +#define LLOG(x) + +namespace Upp { + +Ctrl::Frame Ctrl::AllocFrames(int alloc) +{ + Frame m; + size_t sz0 = alloc * sizeof(Frame); + size_t sz = sz0; + m.frames = (Frame *)MemoryAllocSz(sz); + m.multi.alloc = alloc + (int)((sz - sz0) / sizeof(Frame)); + return m; +} + +void Ctrl::InsertFrame(int i, CtrlFrame& fr) +{ + GuiLock __; + int fc = GetFrameCount(); + ASSERT(i <= fc); + if(i == 0 && fc == 0) { + frame.frame = &fr; + multi_frame = false; + } + else { + if(!multi_frame) { + Frame h = AllocFrames(2); + h.frames[0].frame = frame.frame; + h.multi.count = 1; + frame = h; + multi_frame = true; + } + if(frame.multi.count + 1 > frame.multi.alloc) { + Frame h = AllocFrames(3 * frame.multi.count / 2 + 1); + memcpy(h.frames, frame.frames, i * sizeof(Frame)); + memcpy(h.frames + i + 1, frame.frames + i, (frame.multi.count - i) * sizeof(Frame)); + h.multi.count = frame.multi.count; + FreeFrames(); + frame = h; + } + else + memmove(frame.frames + i + 1, frame.frames + i, (frame.multi.count - i) * sizeof(Frame)); + frame.frames[i].frame = &fr; + frame.multi.count++; + } + fr.FrameAdd(*this); + SyncLayout(); + RefreshFrame(); +} + +Ctrl& Ctrl::AddFrame(CtrlFrame& fr) { + InsertFrame(GetFrameCount(), fr); + return *this; +} + +void Ctrl::RemoveFrame(int i) { + ASSERT(i < GetFrameCount()); + GetFrame(i).FrameRemove(); + if(multi_frame) { + ASSERT(frame.multi.count > 1); + memmove(frame.frames + i, frame.frames + i + 1, (frame.multi.count - i - 1) * sizeof(Frame)); + frame.multi.count--; + if(frame.multi.count == 1) { + CtrlFrame *h = frame.frames[0].frame; + FreeFrames(); + multi_frame = false; + frame.frame = h; + } + else + if(3 * frame.multi.count < frame.multi.alloc) { + Frame h = AllocFrames(3 * frame.multi.count / 2 + 1); + memcpy(h.frames, frame.frames, frame.multi.count * sizeof(Frame)); + h.multi.count = frame.multi.count; + FreeFrames(); + frame = h; + } + } + else + frame.frame = nullptr; + if(GetFrameCount() == 0) + SetFrame(NullFrame()); + SyncLayout(); + RefreshFrame(); +} + +Ctrl& Ctrl::SetFrame(int i, CtrlFrame& fr) { + GuiLock __; + LLOG("SetFrame " << typeid(fr).name()); + while(GetFrameCount() <= i) + AddFrame(NullFrame()); + Frame& f = GetFrame0(i); + f.frame->FrameRemove(); + f.frame = &fr; + fr.FrameAdd(*this); + SyncLayout(); + RefreshFrame(); + return *this; +} + +void Ctrl::ClearFrames() { + GuiLock __; + int n = GetFrameCount(); + for(int i = 0; i < n; i++) + GetFrame(i).FrameRemove(); + FreeFrames(); + multi_frame = false; + frame.frame = &NullFrame(); + SyncLayout(); + RefreshFrame(); +} + +int Ctrl::FindFrame(CtrlFrame& frm) const +{ + GuiLock __; + int n = GetFrameCount(); + for(int i = 0; i < n; i++) + if(&GetFrame(i) == &frm) + return i; + return -1; +} + +void Ctrl::RemoveFrame(CtrlFrame& frm) +{ + GuiLock __; + int i = FindFrame(frm); + if(i >= 0) + RemoveFrame(i); +} + +}; \ No newline at end of file diff --git a/uppsrc/CtrlCore/CtrlKbd.cpp b/uppsrc/CtrlCore/CtrlKbd.cpp index d46778fad..3a9c7b532 100644 --- a/uppsrc/CtrlCore/CtrlKbd.cpp +++ b/uppsrc/CtrlCore/CtrlKbd.cpp @@ -7,8 +7,6 @@ namespace Upp { Ptr Ctrl::focusCtrl; Ptr Ctrl::focusCtrlWnd; Ptr Ctrl::lastActiveWnd; -Ptr Ctrl::caretCtrl; -Rect Ctrl::caretRect; bool Ctrl::ignorekeyup; Ptr Ctrl::defferedSetFocus; @@ -116,7 +114,7 @@ bool Ctrl::HotKey(dword key) GuiLock __; LLOG("HotKey " << GetKeyDesc(key) << " at " << Name(this)); if(!IsEnabled() || !IsVisible()) return false; - for(Ptr ctrl = firstchild; ctrl; ctrl = ctrl->next) + for(Ptr ctrl = GetFirstChild(); ctrl; ctrl = ctrl->GetNext()) { LLOG("Trying HotKey " << GetKeyDesc(key) << " at " << Name(ctrl)); if(ctrl->IsOpen() && ctrl->IsVisible() && ctrl->IsEnabled() && ctrl->HotKey(key)) @@ -158,8 +156,8 @@ void Ctrl::DoKillFocus(Ptr pfocusCtrl, Ptr nfocusCtrl) LLOG("LostFocus: " << Name(pfocusCtrl)); pfocusCtrl->LostFocus(); } - if(pfocusCtrl && pfocusCtrl->parent && !pfocusCtrl->parent->destroying) - pfocusCtrl->parent->ChildLostFocus(); + if(pfocusCtrl && pfocusCtrl->GetParent() && !pfocusCtrl->GetParent()->destroying) + pfocusCtrl->GetParent()->ChildLostFocus(); SyncCaret(); } @@ -179,9 +177,9 @@ void Ctrl::DoSetFocus(Ptr pfocusCtrl, Ptr nfocusCtrl, bool activate) nfocusCtrl->GotFocus(); nfocusCtrl->StateH(FOCUS); } - if(focusCtrl == nfocusCtrl && nfocusCtrl && nfocusCtrl->parent && - !nfocusCtrl->parent->destroying) - nfocusCtrl->parent->ChildGotFocus(); + if(focusCtrl == nfocusCtrl && nfocusCtrl && nfocusCtrl->GetParent() && + !nfocusCtrl->GetParent()->destroying) + nfocusCtrl->GetParent()->ChildGotFocus(); SyncCaret(); } @@ -340,14 +338,6 @@ void Ctrl::DefferedFocusSync() } } -void Ctrl::RefreshCaret() -{ - GuiLock __; - if(caretCtrl) - caretCtrl->Refresh(caretCtrl->caretx, caretCtrl->carety, - caretCtrl->caretcx, caretCtrl->caretcy); -} - Ctrl *Ctrl::GetActiveWindow() { GuiLock __; @@ -364,6 +354,61 @@ bool Ctrl::HasFocusDeep() const a = a->GetOwnerCtrl(); return a && HasChildDeep(a); } +Ptr Ctrl::caretCtrl; +Ptr Ctrl::prevCaretCtrl; +Rect Ctrl::caretRect; +int Ctrl::WndCaretTime; +bool Ctrl::WndCaretVisible; + +void Ctrl::RefreshCaret() +{ + GuiLock __; + if(prevCaretCtrl) { + prevCaretCtrl->Refresh(caretRect); + prevCaretCtrl = nullptr; + } + if(caretCtrl) { + caretRect = caretCtrl->GetCaret(); + caretCtrl->Refresh(caretRect); + prevCaretCtrl = caretCtrl; + } +} + +void Ctrl::AnimateCaret() +{ + GuiLock __; + bool v = !(((msecs() - WndCaretTime) / GetCaretBlinkTime()) & 1); + if(v != WndCaretVisible) { + WndCaretVisible = v; + RefreshCaret(); + } +} + +void Ctrl::PaintCaret(SystemDraw& w) +{ + GuiLock __; + LLOG("PaintCaret " << Name() << ", caretCtrl: " << caretCtrl << ", WndCaretVisible: " << WndCaretVisible); + if(this == caretCtrl && WndCaretVisible) + w.DrawRect(GetCaret(), InvertColor); +} + +void Ctrl::SyncCaret() { + GuiLock __; + LLOG("SyncCaret"); + if(focusCtrl != caretCtrl) { + LLOG("SyncCaret DO " << Upp::Name(caretCtrl) << " -> " << Upp::Name(focusCtrl)); + RefreshCaret(); + caretCtrl = focusCtrl; + WndCaretTime = msecs(); + RefreshCaret(); + } + else { + if(caretCtrl && caretCtrl->GetCaret() != caretRect) { + WndCaretTime = msecs(); + RefreshCaret(); + } + } +} Tuple KeyNames__[ ] = { { K_A, tt_("key\vA") }, { K_B, tt_("key\vB") }, { K_C, tt_("key\vC") }, { K_D, tt_("key\vD") }, diff --git a/uppsrc/CtrlCore/CtrlMouse.cpp b/uppsrc/CtrlCore/CtrlMouse.cpp index ac7fce29e..051e71fac 100644 --- a/uppsrc/CtrlCore/CtrlMouse.cpp +++ b/uppsrc/CtrlCore/CtrlMouse.cpp @@ -74,6 +74,7 @@ Image Ctrl::FrameMouseEventH(int event, Point p, int zdelta, dword keyflags) if(this_) LogMouseEvent("FRAME ", this, event, p, zdelta, keyflags); eventCtrl = this_; + Ctrl *parent = GetParent(); if(parent && this_) parent->ChildFrameMouseEvent(this, event, p, zdelta, keyflags); return this_ ? FrameMouseEvent(event, p, zdelta, keyflags) : Image(); @@ -93,6 +94,7 @@ Image Ctrl::MouseEvent0(int event, Point p, int zdelta, dword keyflags) bool pb = sPropagated; sPropagated = false; Image m = this_ ? MouseEvent(event, p, zdelta, keyflags) : Image(); + Ctrl *parent = this_ ? this_->GetParent() : NULL; if(event == MOUSEWHEEL && !sPropagated && this_ && parent) parent->ChildMouseEvent(this, event, p, zdelta, keyflags); sPropagated = pb; @@ -108,6 +110,7 @@ Image Ctrl::MouseEventH(int event, Point p, int zdelta, dword keyflags) return Image::Arrow(); if(this_) LogMouseEvent(NULL, this, event, p, zdelta, keyflags); + Ctrl *parent = this_ ? this_->GetParent() : NULL; if(this_ && parent && event != MOUSEWHEEL) parent->ChildMouseEvent(this, event, p, zdelta, keyflags); return MouseEvent0(event, p, zdelta, keyflags); @@ -115,6 +118,7 @@ Image Ctrl::MouseEventH(int event, Point p, int zdelta, dword keyflags) void Ctrl::MouseWheel(Point p, int zd, dword kf) { + Ctrl *parent = GetParent(); if(parent) { p += GetScreenView().TopLeft(); Rect r = parent->GetScreenView(); @@ -128,6 +132,7 @@ void Ctrl::MouseWheel(Point p, int zd, dword kf) void Ctrl::ChildFrameMouseEvent(Ctrl *child, int event, Point p, int zdelta, dword keyflags) { GuiLock __; + Ctrl *parent = GetParent(); if(parent) parent->ChildFrameMouseEvent(child, event, p, zdelta, keyflags); } @@ -135,6 +140,7 @@ void Ctrl::ChildFrameMouseEvent(Ctrl *child, int event, Point p, int zdelta, dwo void Ctrl::ChildMouseEvent(Ctrl *child, int event, Point p, int zdelta, dword keyflags) { GuiLock __; + Ctrl *parent = GetParent(); if(parent) parent->ChildMouseEvent(child, event, p, zdelta, keyflags); } @@ -280,7 +286,7 @@ Ctrl *Ctrl::ChildFromPoint(Point& pt) const Rect view = GetView(); if(view.Contains(p)) { Point vp = p - view.TopLeft(); - for(q = GetLastChild(); q; q = q->prev) { + for(q = GetLastChild(); q; q = q->GetPrev()) { if(q->InView() && q->IsMouseActive()) { Rect r = q->GetRect(); if(r.Contains(vp)) { @@ -291,7 +297,7 @@ Ctrl *Ctrl::ChildFromPoint(Point& pt) const } return NULL; } - for(q = GetLastChild(); q; q = q->prev) { + for(q = GetLastChild(); q; q = q->GetPrev()) { if(q->InFrame() && q->IsMouseActive()) { Rect r = q->GetRect(); if(r.Contains(p)) { diff --git a/uppsrc/CtrlCore/CtrlPos.cpp b/uppsrc/CtrlCore/CtrlPos.cpp index 5a83c7b54..49b6af21d 100644 --- a/uppsrc/CtrlCore/CtrlPos.cpp +++ b/uppsrc/CtrlCore/CtrlPos.cpp @@ -60,7 +60,8 @@ Rect Ctrl::GetRect() const Rect Ctrl::GetView() const { GuiLock __; - return frame.GetCount() == 0 ? Rect(Size(rect.Size())) : Rect(frame[frame.GetCount() - 1].view); + int n = GetFrameCount(); + return n == 0 ? Rect(Size(rect.Size())) : Rect(GetFrame0(n - 1).GetView()); } Size Ctrl::GetSize() const @@ -72,6 +73,7 @@ Rect Ctrl::GetScreenRect() const { GuiLock __; Rect r = GetRect(); + Ctrl *parent = GetParent(); if(parent) { Rect pr = inframe ? parent->GetScreenRect() : parent->GetScreenView(); r = r + pr.TopLeft(); @@ -91,6 +93,7 @@ Rect Ctrl::GetVisibleScreenRect() const { GuiLock __; Rect r = GetRect(); + Ctrl *parent = GetParent(); if(parent) { Rect pr = inframe ? parent->GetVisibleScreenRect() : parent->GetVisibleScreenView(); Rect pr1 = inframe ? parent->GetScreenRect() : parent->GetScreenView(); @@ -111,8 +114,8 @@ Size Ctrl::AddFrameSize(int cx, int cy) const { GuiLock __; Size sz = Size(cx, cy); - for(int i = frame.GetCount() - 1; i >= 0; i--) - frame[i].frame->FrameAddSize(sz); + for(int i = GetFrameCount() - 1; i >= 0; i--) + GetFrame0(i).frame->FrameAddSize(sz); return sz; } @@ -146,21 +149,22 @@ void Ctrl::SyncLayout(int force) Rect oview = GetView(); Rect view = GetRect().Size(); overpaint = OverPaint(); - for(int i = 0; i < frame.GetCount(); i++) { - Frame& f = frame[i]; + int n = GetFrameCount(); + for(int i = 0; i < n; i++) { + Frame& f = GetFrame0(i); f.frame->FrameLayout(view); - if(view != Rect(f.view)) { - f.view = view; + if(view != f.GetView()) { + f.SetView(view); refresh = true; } int q = f.frame->OverPaint(); if(q > overpaint) overpaint = q; } if(oview.Size() != view.Size() || force > 1) { - for(Ctrl *q = GetFirstChild(); q; q = q->next) { - q->rect = q->CalcRect(rect, view); - LLOG("Layout set rect " << q->Name() << " " << q->rect); - q->SyncLayout(force > 1 ? force : 0); + for(Ctrl& q : *this) { + q.rect = q.CalcRect(rect, view); + LLOG("Layout set rect " << q.Name() << " " << q.rect); + q.SyncLayout(force > 1 ? force : 0); } Refresh(); } @@ -172,6 +176,20 @@ void Ctrl::SyncLayout(int force) RefreshFrame(); } +void Ctrl::RefreshParentLayout() +{ + Ctrl *parent = GetParent(); + if(parent) + parent->RefreshLayout(); +} + +void Ctrl::UpdateParentLayout() +{ + Ctrl *parent = GetParent(); + if(parent) + parent->UpdateLayout(); +} + int Ctrl::FindMoveCtrl(const VectorMap& m, Ctrl *x) { int q = m.Find(x); @@ -188,10 +206,11 @@ void Ctrl::SetPos0(LogPos p, bool _inframe) { GuiLock __; if(p == pos && inframe == _inframe) return; + Ctrl *parent = GetParent(); if(parent && !IsDHCtrl()) { if(!globalbackbuffer) { Rect from = GetRect().Size(); - Top *top = GetTopRect(from, true)->top; + Top *top = GetTopRect(from, true)->GetTop(); if(top) { LTIMING("SetPos0 MoveCtrl"); pos = p; @@ -227,6 +246,7 @@ void Ctrl::UpdateRect0(bool sync) { GuiLock __; LTIMING("UpdateRect0"); + Ctrl *parent = GetParent(); if(parent) rect = CalcRect(parent->GetRect(), parent->GetView()); else { @@ -247,12 +267,13 @@ void Ctrl::UpdateRect(bool sync) { GuiLock __; UpdateRect0(sync); - if(parent) RefreshFrame(); + if(GetParent()) RefreshFrame(); } Ctrl& Ctrl::SetPos(LogPos p, bool _inframe) { GuiLock __; + Ctrl *parent = GetParent(); if(p != pos || inframe != _inframe) { if(parent || !IsOpen()) SetPos0(p, _inframe); @@ -336,93 +357,6 @@ void Ctrl::SetFrameRectY(int y, int cy) { SetFramePosY(PosTop(y, cy)); } -Ctrl& Ctrl::SetFrame(int i, CtrlFrame& fr) { - GuiLock __; - LLOG("SetFrame " << typeid(fr).name()); - while(frame.GetCount() <= i) - frame.Add().frame = &NullFrame(); - frame[i].frame->FrameRemove(); - frame[i].frame = &fr; - fr.FrameAdd(*this); - SyncLayout(); - RefreshFrame(); - return *this; -} - -Ctrl& Ctrl::AddFrame(CtrlFrame& fr) { - GuiLock __; - LLOG("AddFrame " << typeid(fr).name()); - frame.Add().frame = &fr; - fr.FrameAdd(*this); - SyncLayout(); - RefreshFrame(); - return *this; -} - -void Ctrl::ClearFrames() { - GuiLock __; - for(int i = 0; i < frame.GetCount(); i++) - frame[i].frame->FrameRemove(); - frame.Clear(); - frame.Add().frame = &NullFrame(); - RefreshFrame(); - SyncLayout(); -} - -void Ctrl::RemoveFrame(int i) { - GuiLock __; - int n = frame.GetCount(); - Mitor m; - if(n > 1) - for(int q = 0; q < n; q++) { - if(q != i) - m.Add().frame = frame[q].frame; - else - frame[q].frame->FrameRemove(); - } - frame = pick(m); - if(frame.GetCount() == 0) - frame.Add().frame = &NullFrame(); - RefreshFrame(); - SyncLayout(); -} - -int Ctrl::FindFrame(CtrlFrame& frm) -{ - GuiLock __; - for(int i = 0; i < frame.GetCount(); i++) - if(frame[i].frame == &frm) - return i; - return -1; -} - -void Ctrl::RemoveFrame(CtrlFrame& frm) -{ - GuiLock __; - int i = FindFrame(frm); - if(i >= 0) - RemoveFrame(i); -} - -void Ctrl::InsertFrame(int i, CtrlFrame& fr) -{ - GuiLock __; - ASSERT(i >= 0 && i <= frame.GetCount()); - int n = frame.GetCount(); - Mitor m; - if(n >= 1) - for(int q = 0; q < n; q++) { - if(q == i) m.Add().frame = &fr; - m.Add().frame = frame[q].frame; - } - if(i == n) - m.Add().frame = &fr; - frame = pick(m); - fr.FrameAdd(*this); - SyncLayout(); - RefreshFrame(); -} - Ctrl& Ctrl::LeftPos(int a, int size) { return SetPosX(PosLeft(a, size)); } diff --git a/uppsrc/CtrlCore/GtkCreate.cpp b/uppsrc/CtrlCore/GtkCreate.cpp index f03617ee9..40de141db 100644 --- a/uppsrc/CtrlCore/GtkCreate.cpp +++ b/uppsrc/CtrlCore/GtkCreate.cpp @@ -15,7 +15,8 @@ void Ctrl::Create(Ctrl *owner, bool popup) ASSERT(!IsChild() && !IsOpen()); LLOG("Ungrab1"); - top = new Top; + Top *top = new Top; + SetTop(top); top->window = gtk_window_new(popup && owner ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL); top->owner = owner; @@ -111,12 +112,13 @@ void Ctrl::WndDestroy() if(HasFocusDeep() || !GetFocusCtrl()) activeCtrl = owner; } + Top *top = GetTop(); if(top->im_context) g_object_unref(top->im_context); gtk_widget_destroy(top->window); isopen = false; popup = false; - delete top; + DeleteTop(); top = NULL; int q = FindCtrl(this); if(q >= 0) diff --git a/uppsrc/CtrlCore/GtkCtrl.cpp b/uppsrc/CtrlCore/GtkCtrl.cpp index 059e39121..75cf19c47 100644 --- a/uppsrc/CtrlCore/GtkCtrl.cpp +++ b/uppsrc/CtrlCore/GtkCtrl.cpp @@ -64,6 +64,20 @@ void Ctrl::InstallPanicBox() { } +GdkWindow *Ctrl::gdk() const +{ + const Top *top = GetTop(); + return top ? gtk_widget_get_window(top->window) : NULL; +} + +GtkWindow *Ctrl::gtk() const +{ + const Top *top = GetTop(); + return top ? (GtkWindow *)top->window : NULL; +} + + + } #endif diff --git a/uppsrc/CtrlCore/GtkCtrl.h b/uppsrc/CtrlCore/GtkCtrl.h index f4c25923e..90b07762b 100644 --- a/uppsrc/CtrlCore/GtkCtrl.h +++ b/uppsrc/CtrlCore/GtkCtrl.h @@ -95,8 +95,6 @@ _DBG_ static Vector> activePopup; // created with 'activate' flag - usually menu static Vector> visiblePopup; // any popup visible on screen static Vector wins; - static int WndCaretTime; - static bool WndCaretVisible; static Ptr grabwindow; static Ptr grabpopup; static Ptr sel_ctrl; @@ -115,7 +113,6 @@ _DBG_ void ReleasePopupCapture(); static void FocusSync(); - static void AnimateCaret(); static gboolean TimeHandler(GtkWidget *); static void InvalidateMousePos(); static void StopGrabPopup(); @@ -199,6 +196,8 @@ public: // really private: static int SCL(int x) { return scale * x; } static Rect SCL(int x, int y, int cx, int cy) { return RectC(SCL(x), SCL(y), SCL(cx), SCL(cy)); } static double LSC(int x) { return (double)x / scale; } + + static int GetCaretBlinkTime() { return 500; } public: static void EndSession() {} @@ -210,8 +209,8 @@ public: static guint32 CurrentTime; static GEvent CurrentEvent; - GdkWindow *gdk() const { return top ? gtk_widget_get_window(top->window) : NULL; } - GtkWindow *gtk() const { return top ? (GtkWindow *)top->window : NULL; } + GdkWindow *gdk() const; + GtkWindow *gtk() const; static GdkFilterReturn RootKeyFilter(GdkXEvent *xevent, GdkEvent *event, gpointer data); diff --git a/uppsrc/CtrlCore/GtkDnD.cpp b/uppsrc/CtrlCore/GtkDnD.cpp index 5f1944a13..2dc955916 100644 --- a/uppsrc/CtrlCore/GtkDnD.cpp +++ b/uppsrc/CtrlCore/GtkDnD.cpp @@ -124,14 +124,16 @@ int Ctrl::DoDragAndDrop(const char *fmts, const Image& sample, dword actions, iw.DrawImage(1, 1, sz.cx, sz.cy, sample); dnd_icon = iw; } -#if GTK_CHECK_VERSION(3, 10, 0) - gtk_drag_begin_with_coordinates(w->top->window, list, GdkDragAction(gdk_actions), - GetMouseLeft() ? 1 : GetMouseMiddle() ? 2 : 3, - CurrentEvent.event, -1, -1); -#else - gtk_drag_begin(w->top->window, list, GdkDragAction(gdk_actions), - GetMouseLeft() ? 1 : GetMouseMiddle() ? 2 : 3, CurrentEvent.event); -#endif + Top *top = w->GetTop(); + if(top) + #if GTK_CHECK_VERSION(3, 10, 0) + gtk_drag_begin_with_coordinates(top->window, list, GdkDragAction(gdk_actions), + GetMouseLeft() ? 1 : GetMouseMiddle() ? 2 : 3, + CurrentEvent.event, -1, -1); + #else + gtk_drag_begin(top->window, list, GdkDragAction(gdk_actions), + GetMouseLeft() ? 1 : GetMouseMiddle() ? 2 : 3, CurrentEvent.event); + #endif while(dnd_source && GetTopCtrls().GetCount()) ProcessEvents(); dnd_source_data = NULL; @@ -329,6 +331,9 @@ gboolean Ctrl::GtkDragDrop(GtkWidget *widget, GdkDragContext *context, gint x, g void Ctrl::DndInit() { + Top *top = GetTop(); + if(!top) + return; GtkWidget *w = top->window; gpointer id = (gpointer)(uintptr_t)top->id; g_signal_connect(w, "drag-begin", G_CALLBACK(GtkDragBegin), id); @@ -345,6 +350,7 @@ void Ctrl::DndInit() void Ctrl::DndExit() { + Top *top = GetTop(); if(top) gtk_drag_dest_unset(top->window); } diff --git a/uppsrc/CtrlCore/GtkEvent.cpp b/uppsrc/CtrlCore/GtkEvent.cpp index 86ba1da3b..29cc1bebf 100644 --- a/uppsrc/CtrlCore/GtkEvent.cpp +++ b/uppsrc/CtrlCore/GtkEvent.cpp @@ -135,10 +135,13 @@ gboolean Ctrl::GtkEvent(GtkWidget *widget, GdkEvent *event, gpointer user_data) case GDK_FOCUS_CHANGE: p->CancelPreedit(); if(p) { - if(((GdkEventFocus *)event)->in) - gtk_im_context_focus_in(p->top->im_context); - else - gtk_im_context_focus_out(p->top->im_context); + Top *top = p->GetTop(); + if(top) { + if(((GdkEventFocus *)event)->in) + gtk_im_context_focus_in(top->im_context); + else + gtk_im_context_focus_out(top->im_context); + } AddEvent(user_data, EVENT_FOCUS_CHANGE, value, event); } return false; @@ -181,8 +184,11 @@ gboolean Ctrl::GtkEvent(GtkWidget *widget, GdkEvent *event, gpointer user_data) value << (int) key->keyval << (int) key->hardware_keycode; if(pressed) { p = GetTopCtrlFromId(user_data); - if(p && gtk_im_context_filter_keypress(p->top->im_context, key)) - return true; + if(p) { + Top *top = p->GetTop(); + if(top && gtk_im_context_filter_keypress(top->im_context, key)) + return true; + } } break; case GDK_CONFIGURE: { @@ -344,7 +350,9 @@ void Ctrl::IMLocation(Ctrl *w) gr.y = LSC(e.top - q.top); gr.width = LSC(e.GetWidth()); gr.height = LSC(e.GetHeight()); - gtk_im_context_set_cursor_location(w->top->im_context, &gr); + Top *top = w->GetTop(); + if(top) + gtk_im_context_set_cursor_location(top->im_context, &gr); } } diff --git a/uppsrc/CtrlCore/GtkTop.cpp b/uppsrc/CtrlCore/GtkTop.cpp index 9e1c94d5a..e2a2845f2 100644 --- a/uppsrc/CtrlCore/GtkTop.cpp +++ b/uppsrc/CtrlCore/GtkTop.cpp @@ -33,15 +33,18 @@ void TopWindow::SyncSizeHints() m.max_width = LSC(sz.cx); m.max_height = LSC(sz.cy); gtk_window_set_resizable(gtk(), sizeable); - gtk_window_set_geometry_hints(gtk(), top->window, &m, - GdkWindowHints(GDK_HINT_MIN_SIZE|GDK_HINT_MAX_SIZE)); - gtk_widget_set_size_request(top->window, m.min_width, m.min_height); + Top *top = GetTop(); + if(top) { + gtk_window_set_geometry_hints(gtk(), top->window, &m, + GdkWindowHints(GDK_HINT_MIN_SIZE|GDK_HINT_MAX_SIZE)); + gtk_widget_set_size_request(top->window, m.min_width, m.min_height); + } } void TopWindow::SyncTitle() { GuiLock __; - if(top) + if(GetTop()) gtk_window_set_title(gtk(), FromUnicode(title, CHARSET_UTF8)); } @@ -127,7 +130,9 @@ void TopWindow::Open(Ctrl *owner) CenterRect(owner); IgnoreMouseUp(); Create(owner, false); - g_signal_connect(top->window, "window-state-event", G_CALLBACK(StateEvent), this); + Top *top = GetTop(); + if(top) + g_signal_connect(top->window, "window-state-event", G_CALLBACK(StateEvent), this); SyncSizeHints(); SyncCaption(); PlaceFocus(); diff --git a/uppsrc/CtrlCore/GtkWnd.cpp b/uppsrc/CtrlCore/GtkWnd.cpp index ccae03f1c..6d85ccda3 100644 --- a/uppsrc/CtrlCore/GtkWnd.cpp +++ b/uppsrc/CtrlCore/GtkWnd.cpp @@ -14,9 +14,6 @@ Vector Ctrl::wins; Ptr Ctrl::activeCtrl; -int Ctrl::WndCaretTime; -bool Ctrl::WndCaretVisible; - bool Ctrl::invalids; int Ctrl::FindId(int id) @@ -84,7 +81,7 @@ void Ctrl::SetMouseCursor(const Image& image) else topctrl = GetActiveCtrl(); if(topctrl) - top = topctrl->top; + top = topctrl->GetTop(); if(top && id != top->cursor_id) { top->cursor_id = id; int64 aux = image.GetAuxData(); @@ -122,6 +119,7 @@ void Ctrl::SetMouseCursor(const Image& image) Ctrl *Ctrl::GetOwner() { GuiLock __; + Top *top = GetTop(); return IsOpen() ? top->owner : NULL; } @@ -150,52 +148,6 @@ void Ctrl::UnregisterSystemHotKey(int id) #endif -void Ctrl::AnimateCaret() -{ - GuiLock __; - int v = !(((msecs() - WndCaretTime) / 500) & 1); - if(v != WndCaretVisible) { - WndCaretVisible = v; - RefreshCaret(); - } -} - -void Ctrl::PaintCaret(SystemDraw& w) -{ - GuiLock __; - LLOG("PaintCaret " << Name() << ", caretCtrl: " << caretCtrl << ", WndCaretVisible: " << WndCaretVisible); - if(this == caretCtrl && WndCaretVisible) - w.DrawRect(caretx, carety, caretcx, caretcy, InvertColor); -} - -void Ctrl::SetCaret(int x, int y, int cx, int cy) -{ - GuiLock __; - LLOG("SetCaret " << Name()); - if(this == caretCtrl) - RefreshCaret(); - caretx = x; - carety = y; - caretcx = cx; - caretcy = cy; - if(this == caretCtrl) { - WndCaretTime = msecs(); - RefreshCaret(); - AnimateCaret(); - } -} - -void Ctrl::SyncCaret() { - GuiLock __; - LLOG("SyncCaret"); - if(focusCtrl != caretCtrl) { - LLOG("SyncCaret DO " << Upp::Name(caretCtrl) << " -> " << Upp::Name(focusCtrl)); - RefreshCaret(); - caretCtrl = focusCtrl; - RefreshCaret(); - } -} - Rect Ctrl::GetWndScreenRect() const { GuiLock __; @@ -213,7 +165,9 @@ void Ctrl::WndShow(bool b) { GuiLock __; LLOG("WndShow " << Name() << ", " << b); - if(IsOpen()) { + Top *top = GetTop(); + if(IsOpen() && top) { + if(b) gtk_widget_show_now(top->window); else @@ -224,6 +178,7 @@ void Ctrl::WndShow(bool b) bool Ctrl::IsWndOpen() const { GuiLock __; + const Top *top = GetTop(); return top && top->window && gtk_widget_get_window(top->window); } @@ -400,12 +355,13 @@ void Ctrl::DoCancelPreedit() { if(!focusCtrl) return; - if(focusCtrl->top) + Top *top = focusCtrl->GetTop(); + if(top) focusCtrl->HidePreedit(); - if(focusCtrl->top) { - gtk_im_context_reset(focusCtrl->top->im_context); - gtk_im_context_focus_out(focusCtrl->top->im_context); - gtk_im_context_focus_in(focusCtrl->top->im_context); + if(top) { + gtk_im_context_reset(top->im_context); + gtk_im_context_focus_out(top->im_context); + gtk_im_context_focus_in(top->im_context); } } @@ -458,7 +414,8 @@ bool Ctrl::SweepConfigure(bool wait) FetchEvents(wait); for(int i = 0; i < Events.GetCount() && this_; i++) { GEvent& e = Events[i]; - if(e.type == GDK_CONFIGURE && this_ && top->id == e.windowid) { + Top *top = GetTop(); + if(e.type == GDK_CONFIGURE && this_ && top && top->id == e.windowid) { Rect rect = e.value; LLOG("SweepConfigure " << rect); if(GetRect() != rect) @@ -495,6 +452,7 @@ void Ctrl::WndEnable(bool b) { GuiLock __; if(IsOpen()) { + Top *top = GetTop(); gtk_widget_set_sensitive(top->window, b); StateH(ENABLE); } diff --git a/uppsrc/CtrlCore/MetaFile.cpp b/uppsrc/CtrlCore/MetaFile.cpp index 066ef2df4..0a548d300 100644 --- a/uppsrc/CtrlCore/MetaFile.cpp +++ b/uppsrc/CtrlCore/MetaFile.cpp @@ -150,8 +150,7 @@ void WinMetaFile::Serialize(Stream& s) { Clear(); s % size; if(size) { - Buffer buffer(size); - s.SerializeRaw(buffer, size); + String buffer = s.GetAll(size); HENHMETAFILE hemf = ::SetEnhMetaFileBits(size, buffer); Attach(hemf); } diff --git a/uppsrc/CtrlCore/TopWin32.cpp b/uppsrc/CtrlCore/TopWin32.cpp index f69a24c79..9a3a1a16b 100644 --- a/uppsrc/CtrlCore/TopWin32.cpp +++ b/uppsrc/CtrlCore/TopWin32.cpp @@ -273,6 +273,7 @@ void TopWindow::Open(Ctrl *owner) GuiLock __; LLOG("TopWindow::Open(Ctrl) -> " << UPP::Name(owner)); Open(owner ? owner->GetTopCtrl()->GetHWND() : NULL); + Top *top = GetTop(); if(IsOpen() && top) top->owner = owner; } diff --git a/uppsrc/CtrlCore/TopWindow.h b/uppsrc/CtrlCore/TopWindow.h index f6bd780e9..3bcc6e56a 100644 --- a/uppsrc/CtrlCore/TopWindow.h +++ b/uppsrc/CtrlCore/TopWindow.h @@ -48,6 +48,8 @@ private: bool fullscreen; byte center:2; + + int exitcode = 0; void PlaceFocus(); void ActiveFocus0(Ctrl& ctrl); @@ -91,6 +93,8 @@ private: GUIPLATFORM_TOPWINDOW_DECLS #endif + friend class Ctrl; + public: virtual void ShutdownWindow(); @@ -125,6 +129,8 @@ public: int Execute(); bool ExecuteOK() { return Execute() == IDOK; } bool ExecuteCancel() { return Execute() == IDCANCEL; } + + int GetExitCode() const { return exitcode; } void Minimize(bool effect = false); void Maximize(bool effect = false); diff --git a/uppsrc/CtrlCore/Win32Ctrl.cpp b/uppsrc/CtrlCore/Win32Ctrl.cpp index 02526550c..ea3396ff2 100644 --- a/uppsrc/CtrlCore/Win32Ctrl.cpp +++ b/uppsrc/CtrlCore/Win32Ctrl.cpp @@ -76,44 +76,6 @@ void GuiPlatformAfterMenuPopUp() { } -#if WINCARET -void Ctrl::SetCaret(int x, int y, int cx, int cy) -{ - GuiLock __; - caretx = x; - carety = y; - caretcx = cx; - caretcy = cy; - SyncCaret(); -} - -void Ctrl::SyncCaret() { - GuiLock __; - Rect cr; - cr.Clear(); - if(focusCtrl && focusCtrl->IsVisible()) { - bool inframe = focusCtrl->InFrame(); - cr = focusCtrl->GetScreenView(); - cr = RectC(focusCtrl->caretx + cr.left, focusCtrl->carety + cr.top, - focusCtrl->caretcx, focusCtrl->caretcy) & cr; - for(Ctrl *q = focusCtrl->GetParent(); q; q = q->GetParent()) { - cr &= inframe ? q->GetScreenRect() : q->GetScreenView(); - inframe = q->InFrame(); - } - } - if(focusCtrl != caretCtrl || cr != caretRect) { - LLOG("Do SyncCaret focusCtrl: " << UPP::Name(focusCtrl) - << ", caretCtrl: " << UPP::Name(caretCtrl) - << ", cr: " << cr); - WndDestroyCaret(); - if(focusCtrl && !cr.IsEmpty()) - focusCtrl->GetTopCtrl()->WndCreateCaret(cr); - caretCtrl = focusCtrl; - caretRect = cr; - } -} -#endif - String Ctrl::Name() const { GuiLock __; String s = Name0(); diff --git a/uppsrc/CtrlCore/Win32Ctrl.h b/uppsrc/CtrlCore/Win32Ctrl.h index b429fe49d..b73c28dc6 100644 --- a/uppsrc/CtrlCore/Win32Ctrl.h +++ b/uppsrc/CtrlCore/Win32Ctrl.h @@ -4,15 +4,6 @@ private: bool activex:1; bool isdhctrl:1; -#if WINCARET - static void WndDestroyCaret(); - void WndCreateCaret(const Rect& cr); -#else - static int WndCaretTime; - static bool WndCaretVisible; - static void AnimateCaret(); -#endif - static bool GetMsg(MSG& msg); static bool DumpMessage(Ctrl *w, UINT message, WPARAM wParam, LPARAM lParam); @@ -66,7 +57,7 @@ public: virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); virtual bool PreprocessMessage(MSG& msg); - HWND GetHWND() const { return parent ? NULL : top ? top->hwnd : NULL; } + HWND GetHWND() const { return GetParent() ? NULL : GetTop() ? GetTop()->hwnd : NULL; } HWND GetOwnerHWND() const; static Ctrl *CtrlFromHWND(HWND hwnd); diff --git a/uppsrc/CtrlCore/Win32Proc.cpp b/uppsrc/CtrlCore/Win32Proc.cpp index ea09c91f9..971508f2f 100644 --- a/uppsrc/CtrlCore/Win32Proc.cpp +++ b/uppsrc/CtrlCore/Win32Proc.cpp @@ -68,13 +68,14 @@ void Ctrl::DoCancelPreedit() { if(!focusCtrlWnd) return; - if(focusCtrlWnd->top) + Top *top = focusCtrl->GetTop(); + if(top) focusCtrl->HidePreedit(); - if(focusCtrlWnd->top && focusCtrlWnd->top->hwnd) { - HIMC himc = ImmGetContext(focusCtrlWnd->top->hwnd); + if(top && top->hwnd) { + HIMC himc = ImmGetContext(top->hwnd); if(himc && ImmGetOpenStatus(himc)) { ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0); - ImmReleaseContext(focusCtrlWnd->top->hwnd, himc); + ImmReleaseContext(top->hwnd, himc); } } } diff --git a/uppsrc/CtrlCore/Win32Wnd.cpp b/uppsrc/CtrlCore/Win32Wnd.cpp index 3bd72d2b7..1ab2f7825 100644 --- a/uppsrc/CtrlCore/Win32Wnd.cpp +++ b/uppsrc/CtrlCore/Win32Wnd.cpp @@ -397,7 +397,7 @@ Vector Ctrl::GetTopCtrls() Vector v; VectorMap< HWND, Ptr >& w = Windows(); for(int i = 0; i < w.GetCount(); i++) - if(w.GetKey(i) && w[i] && !w[i]->parent) + if(w.GetKey(i) && w[i] && !w[i]->GetParent()) v.Add(w[i]); return v; } @@ -472,7 +472,8 @@ void Ctrl::Create(HWND parent, DWORD style, DWORD exstyle, bool savebits, int sh Rect r = GetRect(); AdjustWindowRectEx(r, style, FALSE, exstyle); isopen = true; - top = new Top; + Top *top = new Top; + SetTop(top); ASSERT(!parent || IsWindow(parent)); style &= ~WS_VISIBLE; dropshadow = false; @@ -501,11 +502,11 @@ void ReleaseUDropTarget(UDropTarget *dt); void Ctrl::WndFree() { GuiLock __; - if(!top) return; + Top *top = GetTop(); RevokeDragDrop(GetHWND()); + if(!top) return; ReleaseUDropTarget(top->dndtgt); isopen = false; - if(!top) return; HWND owner = GetWindow(top->hwnd, GW_OWNER);// CXL 31.10.2003 z DoRemove bool focus = ::GetFocus() == top->hwnd; LLOG("Ctrl::WndDestroy owner " << (void *)owner @@ -519,13 +520,13 @@ void Ctrl::WndFree() ::SetFocus(owner); } LLOG(LOG_END << "//Ctrl::WndFree() in " <hwnd) { HWND hwnd = top->hwnd; WndFree(); @@ -563,14 +564,16 @@ sWinMsg[] = { void Ctrl::NcCreate(HWND hwnd) { GuiLock __; - if(!parent) + Top *top = GetTop(); + if(top) top->hwnd = hwnd; } void Ctrl::NcDestroy() { GuiLock __; - if(!parent) + Top *top = GetTop(); + if(top) WndFree(); } @@ -839,80 +842,6 @@ void Ctrl::GuiSleep(int ms) EnterGuiMutex(level); } -#if 0 -void Ctrl::WndDestroyCaret() -{ - DLOG("Ctrl::WndDestroyCaret()"); - ::DestroyCaret(); -} - -void Ctrl::WndCreateCaret(const Rect& cr) -{ - GuiLock __; - DLOG("Ctrl::WndCreateCaret(" << cr << ") in " << UPP::Name(this)); - HWND hwnd = GetHWND(); - if(!hwnd) return; - Rect r; - ::GetClientRect(hwnd, r); - Point p = r.TopLeft(); - ::ClientToScreen(hwnd, p); - ::CreateCaret(hwnd, NULL, cr.Width(), cr.Height()); - ::SetCaretPos(cr.left - p.x, cr.top - p.y); - ::ShowCaret(hwnd); -} -#else - -int Ctrl::WndCaretTime; -bool Ctrl::WndCaretVisible; - -void Ctrl::AnimateCaret() -{ - GuiLock __; - bool v = !(((msecs() - WndCaretTime) / GetCaretBlinkTime()) & 1); - if(v != WndCaretVisible) { - WndCaretVisible = v; - RefreshCaret(); - } -} - -void Ctrl::PaintCaret(SystemDraw& w) -{ - GuiLock __; - LLOG("PaintCaret " << Name() << ", caretCtrl: " << caretCtrl << ", WndCaretVisible: " << WndCaretVisible); - if(this == caretCtrl && WndCaretVisible) - w.DrawRect(caretx, carety, caretcx, caretcy, InvertColor); -} - -void Ctrl::SetCaret(int x, int y, int cx, int cy) -{ - GuiLock __; - LLOG("SetCaret " << Name() << " " << RectC(x, y, cx, cy)); - if(this == caretCtrl) - RefreshCaret(); - caretx = x; - carety = y; - caretcx = cx; - caretcy = cy; - if(this == caretCtrl) { - WndCaretTime = msecs(); - RefreshCaret(); - AnimateCaret(); - } -} - -void Ctrl::SyncCaret() { - GuiLock __; - LLOG("SyncCaret"); - if(focusCtrl != caretCtrl) { - LLOG("SyncCaret DO " << Upp::Name(caretCtrl) << " -> " << Upp::Name(focusCtrl)); - RefreshCaret(); - caretCtrl = focusCtrl; - RefreshCaret(); - } -} -#endif - - Rect Ctrl::GetWndScreenRect() const { GuiLock __; @@ -947,7 +876,7 @@ void Ctrl::SetAlpha(byte alpha) { GuiLock __; HWND hwnd = GetHWND(); - if(!IsAlphaSupported() || parent || !top || !hwnd) + if(!IsAlphaSupported() || GetParent() || !top || !hwnd) return; if(alpha == 255) { SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) & ~0x80000); @@ -1183,14 +1112,10 @@ void Ctrl::WndUpdate(const Rect& r) if(GetUpdateRgn(hwnd, hrgn, FALSE) != NULLREGION) { SelectClipRgn(hdc, hrgn); SystemDraw draw(hdc); - bool hcr = focusCtrl && focusCtrl->GetTopCtrl() == top && - caretRect.Intersects(r + top->GetRect().TopLeft()); - if(hcr) ::HideCaret(hwnd); draw.Clip(r); top->UpdateArea(draw, r); ValidateRect(hwnd, r); SelectClipRgn(hdc, NULL); - if(hcr) ::ShowCaret(hwnd); } ReleaseDC(hwnd, hdc); DeleteObject(hrgn); @@ -1201,14 +1126,8 @@ void Ctrl::WndScrollView(const Rect& r, int dx, int dy) { GuiLock __; LLOG("WndScrollView " << UPP::Name(this)); - if(caretCtrl && caretCtrl->GetTopCtrl() == this) { -#if WINCARET - WndDestroyCaret(); -#else + if(caretCtrl && caretCtrl->GetTopCtrl() == this) RefreshCaret(); -#endif - caretRect.Clear(); - } #ifdef PLATFORM_WINCE ::ScrollWindowEx(GetHWND(), dx, dy, r, r, NULL, NULL, 0); #else @@ -1234,6 +1153,7 @@ void Ctrl::PopUp(Ctrl *owner, bool savebits, bool activate, bool dropshadow, boo popup = false; Ctrl *q = owner ? owner->GetTopCtrl() : GetActiveCtrl(); PopUpHWND(q ? q->GetHWND() : NULL, savebits, activate, dropshadow, topmost); + Top *top = GetTop(); if(top) top->owner = owner; } diff --git a/uppsrc/CtrlCore/lay0.h b/uppsrc/CtrlCore/lay0.h index 28175f571..e2da1477b 100644 --- a/uppsrc/CtrlCore/lay0.h +++ b/uppsrc/CtrlCore/lay0.h @@ -54,9 +54,9 @@ #define LAYOUT(nm, x, y) template \ void InitLayout(UPP::Ctrl& parent, L& layout, D& uts, nm##__layid&) { \ - parent.LayoutId(#nm); -#define UNTYPED(var, param) uts.var.param; uts.var.LayoutId(#var); parent.Add(uts.var); -#define ITEM(clss, var, param) layout.var.param; layout.var.LayoutId(#var); parent.Add(layout.var); + parent.LayoutIdLiteral(#nm); +#define UNTYPED(var, param) uts.var.param; uts.var.LayoutIdLiteral(#var); parent.Add(uts.var); +#define ITEM(clss, var, param) layout.var.param; layout.var.LayoutIdLiteral(#var); parent.Add(layout.var); #define END_LAYOUT } #include LAYOUTFILE diff --git a/uppsrc/CtrlCore/src.tpp/Ctrl_en-us.tpp b/uppsrc/CtrlCore/src.tpp/Ctrl_en-us.tpp index ad9811287..3e6b851f9 100644 --- a/uppsrc/CtrlCore/src.tpp/Ctrl_en-us.tpp +++ b/uppsrc/CtrlCore/src.tpp/Ctrl_en-us.tpp @@ -1978,33 +1978,6 @@ pointer to it.&] its descendants.&] [s3;%- &] [s4;%- &] -[s5;:Ctrl`:`:SetCaret`(int`,int`,int`,int`):%- [@(0.0.255) void]_[* SetCaret]([@(0.0.255) i -nt]_[*@3 x], [@(0.0.255) int]_[*@3 y], [@(0.0.255) int]_[*@3 cx], [@(0.0.255) int]_[*@3 cy])&] -[s2;b17;a17; Place caret rectangle block at given position in view -area. Caret rectangle is full flashing box and usually indicates -place where text is to entered. Ctrl can have just one caret. -Only Ctrl with focus has its caret displayed (also means that -you do not need to remove caret when Ctrl goes out of focus).&] -[s7;i1120;a17; [%-*C@3 x]-|X position.&] -[s7;i1120;a17; [%-*C@3 y]-|Y position.&] -[s7;i1120;a17; [%-*C@3 cx]-|Horizontal size.&] -[s7;i1120;a17; [%-*C@3 cy]-|Vertical size.&] -[s3;%- &] -[s4;%- &] -[s5;:Ctrl`:`:SetCaret`(const `:`:Rect`&`):%- [@(0.0.255) void]_[* SetCaret]([@(0.0.255) con -st]_[_^`:`:Rect^ Rect][@(0.0.255) `&]_[*@3 r])&] -[s2;b17;a17; Place caret rectangle block at given position in view -area. Caret rectangle is full flashing box and usually indicates -place where text is to entered. Ctrl can have just one caret. -Only Ctrl with focus has its caret displayed (also means that -you do not need to remove caret when Ctrl goes out of focus).&] -[s7;i1120;a17; [%-*C@3 r]-|Caret block rectangle.&] -[s3;%- &] -[s4;%- &] -[s5;:Ctrl`:`:KillCaret`(`):%- [@(0.0.255) void]_[* KillCaret]()&] -[s2;b17;a17; Removes caret from Ctrl.&] -[s3;%- &] -[s4;%- &] [s5;:Upp`:`:Ctrl`:`:CancelPreedit`(`):%- [@(0.0.255) void]_[* CancelPreedit]()&] [s2; Terminates any input method composition in progress, if possible. Text input widgets typically call this on status change, like @@ -2240,14 +2213,6 @@ l]_[*@3 ax]_`=_[@(0.0.255) true])&] [s7;i1120;a17; [*/ Return value]-|Value of ActiveX flag.&] [s3;%- &] [s4;%- &] -[s5;:Ctrl`:`:Info`(const char`*`):%- [_^`:`:Ctrl^ Ctrl][@(0.0.255) `&]_[* Info]([@(0.0.255) c -onst]_[@(0.0.255) char]_`*[*@3 txt])&] -[s2;b17;a17; Sets Tip text of Ctrl. This text is displayed as tooltip -of Ctrl.&] -[s7;i1120;a17; [%-*C@3 txt]-|Text.&] -[s7;i1120;a17; [*/ Return value]-|`*this for method chaining.&] -[s3;%- &] -[s4;%- &] [s5;:Ctrl`:`:HelpLine`(const char`*`):%- [_^`:`:Ctrl^ Ctrl][@(0.0.255) `&]_[* HelpLine]([@(0.0.255) c onst]_[@(0.0.255) char]_`*[*@3 txt])&] [s2;b17;a17; Sets help topic link for Ctrl.&] diff --git a/uppsrc/CtrlCore/src.tpp/TopWindow_en-us.tpp b/uppsrc/CtrlCore/src.tpp/TopWindow_en-us.tpp index 2c0a015c1..1b9019636 100644 --- a/uppsrc/CtrlCore/src.tpp/TopWindow_en-us.tpp +++ b/uppsrc/CtrlCore/src.tpp/TopWindow_en-us.tpp @@ -260,6 +260,11 @@ while performing loop. If false, only TopWindow`'s relative windows [s7;%% [*/ Return value]-|Result true if Cancel otherwise false.&] [s3;%% &] [s4; &] +[s5;:Upp`:`:TopWindow`:`:GetExitCode`(`)const: [@(0.0.255) int]_[* GetExitCode]()_[@(0.0.255) c +onst]&] +[s2;%% Returns the result code of last Execute or Run methods.&] +[s3; &] +[s4; &] [s5;:TopWindow`:`:Minimize`(bool`): [@(0.0.255) void]_[* Minimize]([@(0.0.255) bool]_[*@3 eff ect]_`=_[@(0.0.255) false])&] [s2;%% Minimize window.&] diff --git a/uppsrc/CtrlLib/ArrayCtrl.cpp b/uppsrc/CtrlLib/ArrayCtrl.cpp index 71ba4aa4b..fe0f24415 100644 --- a/uppsrc/CtrlLib/ArrayCtrl.cpp +++ b/uppsrc/CtrlLib/ArrayCtrl.cpp @@ -1149,7 +1149,7 @@ ArrayCtrl::Column& ArrayCtrl::AddRowNumColumn(const char *text, int w) { int ArrayCtrl::FindColumnWithPos(int pos) const { for(int i = 0; i < column.GetCount(); i++) { - const Mitor& m = column[i].pos; + const Vector& m = column[i].pos; for(int j = 0; j < m.GetCount(); j++) if(Pos(m[j]) == pos) return i; } @@ -1165,7 +1165,7 @@ Vector ArrayCtrl::FindColumnsWithPos(int pos) const { Vector r; for(int i = 0; i < column.GetCount(); i++) { - const Mitor& m = column[i].pos; + const Vector& m = column[i].pos; for(int j = 0; j < m.GetCount(); j++) if(Pos(m[j]) == pos) r.Add(i); diff --git a/uppsrc/CtrlLib/ArrayCtrl.h b/uppsrc/CtrlLib/ArrayCtrl.h index a70b119b9..91d9a96da 100644 --- a/uppsrc/CtrlLib/ArrayCtrl.h +++ b/uppsrc/CtrlLib/ArrayCtrl.h @@ -55,7 +55,7 @@ public: class Column : FormatConvert { ArrayCtrl *arrayctrl; int index; - Mitor pos; + Vector pos; const Convert *convert; Function convertby; Ptr edit; diff --git a/uppsrc/CtrlLib/Button.cpp b/uppsrc/CtrlLib/Button.cpp index 064d22409..71495db3c 100644 --- a/uppsrc/CtrlLib/Button.cpp +++ b/uppsrc/CtrlLib/Button.cpp @@ -339,32 +339,38 @@ const Button::Style *Button::St() const return st; } -void Button::Paint(Draw& w) +void Button::PaintButton(Draw& w, const Rect& r, const Button::Style& st, int visualstate, bool focus, + const String& label, Font font, const Image& img, + bool monoimg, int accesskey, bool visibleaccesskeys, bool disabled) { - const Style *st = St(); - Size sz = GetSize(); - bool ds = !IsShowEnabled(); DrawLabel dl; dl.text = label; - dl.font = Nvl(font, st->font); + dl.font = Nvl(font, st.font); dl.limg = img; - dl.disabled = ds; + dl.disabled = disabled; dl.lspc = !label.IsEmpty() && !img.IsEmpty() ? 4 : 0; if(*label == '\1') dl.align = ALIGN_LEFT; - if(VisibleAccessKeys()) + if(visibleaccesskeys) dl.accesskey = accesskey; if(monoimg) dl.lcolor = SColorText; - int i = GetVisualState(); - ChPaint(w, sz, st->look[i]); - dl.ink = st->textcolor[i]; + ChPaint(w, r, st.look[visualstate]); + dl.ink = st.textcolor[visualstate]; if(monoimg) - dl.lcolor = st->monocolor[i]; - dl.Paint(w, 3 + IsPush() * st->pressoffset.x, 3 + IsPush() * st->pressoffset.y, - sz.cx - 6, sz.cy - 6); - if(HasFocus()) - DrawFocus(w, Rect(sz).Deflated(st->focusmargin)); + dl.lcolor = st.monocolor[visualstate]; + bool push = visualstate == CTRL_PRESSED; + dl.Paint(w, r.left + 3 + push * st.pressoffset.x, r.top + 3 + push * st.pressoffset.y, + r.GetWidth() - 6, r.GetHeight() - 6); + if(focus) + DrawFocus(w, r.Deflated(st.focusmargin)); +} + +void Button::Paint(Draw& w) +{ + PaintButton(w, GetSize(), *St(), GetVisualState(), HasFocus(), + label, font, img, + monoimg, accesskey, VisibleAccessKeys(), !IsShowEnabled()); } void Button::MouseEnter(Point, dword) @@ -498,6 +504,8 @@ void SpinButtons::FrameLayout(Rect& r) void SpinButtons::FrameAddSize(Size& sz) { + if(!visible) + return; sz.cx += (1 + style->onsides) * (min(sz.cx / 2, style->width) - style->over); } diff --git a/uppsrc/CtrlLib/CtrlLib.upp b/uppsrc/CtrlLib/CtrlLib.upp index ec77564e0..85c3b68e5 100644 --- a/uppsrc/CtrlLib/CtrlLib.upp +++ b/uppsrc/CtrlLib/CtrlLib.upp @@ -18,7 +18,9 @@ file PushCtrl.h, Button.cpp, Switch.cpp, + VirtualButtons.cpp, EditCtrl.h, + EditCtrl.hpp, EditField.cpp, TextEdit.h, Text.cpp, @@ -34,6 +36,7 @@ file MultiButton.cpp, DropChoice.h, PopupTable.cpp, + PopUpList.cpp, DropList.cpp, DropChoice.cpp, StaticCtrl.h, diff --git a/uppsrc/CtrlLib/DisplayPopup.cpp b/uppsrc/CtrlLib/DisplayPopup.cpp index f1c65e7a4..d9104878f 100644 --- a/uppsrc/CtrlLib/DisplayPopup.cpp +++ b/uppsrc/CtrlLib/DisplayPopup.cpp @@ -1,55 +1,55 @@ #include "CtrlLib.h" namespace Upp { - -Point DisplayPopup::Op(Point p) + +Point DisplayPopup::PopUp::Op(Point p) { return p + GetScreenView().TopLeft() - ctrl->GetScreenView().TopLeft(); } -void DisplayPopup::LeftDown(Point p, dword flags) +void DisplayPopup::PopUp::LeftDown(Point p, dword flags) { if(ctrl) ctrl->LeftDown(Op(p), flags); } -void DisplayPopup::LeftDrag(Point p, dword flags) +void DisplayPopup::PopUp::LeftDrag(Point p, dword flags) { if(ctrl) ctrl->LeftDrag(Op(p), flags); } -void DisplayPopup::LeftDouble(Point p, dword flags) +void DisplayPopup::PopUp::LeftDouble(Point p, dword flags) { if(ctrl) ctrl->LeftDouble(Op(p), flags); } -void DisplayPopup::RightDown(Point p, dword flags) +void DisplayPopup::PopUp::RightDown(Point p, dword flags) { if(ctrl) ctrl->RightDown(Op(p), flags); } -void DisplayPopup::LeftUp(Point p, dword flags) +void DisplayPopup::PopUp::LeftUp(Point p, dword flags) { if(ctrl) ctrl->LeftUp(Op(p), flags); } -void DisplayPopup::MouseWheel(Point p, int zdelta, dword flags) +void DisplayPopup::PopUp::MouseWheel(Point p, int zdelta, dword flags) { if(ctrl) ctrl->MouseWheel(Op(p), zdelta, flags); } -void DisplayPopup::MouseLeave() +void DisplayPopup::PopUp::MouseLeave() { Cancel(); } -void DisplayPopup::MouseMove(Point p, dword flags) +void DisplayPopup::PopUp::MouseMove(Point p, dword flags) { p += GetScreenView().TopLeft(); if(!slim.Contains(p)) MouseLeave(); } -void DisplayPopup::Paint(Draw& w) +void DisplayPopup::PopUp::Paint(Draw& w) { Rect r = GetSize(); w.DrawRect(r, SColorPaper); @@ -62,13 +62,13 @@ void DisplayPopup::Paint(Draw& w) } } -Vector& DisplayPopup::all() +Vector& DisplayPopup::PopUp::all() { - static Vector all; + static Vector all; return all; } -DisplayPopup::DisplayPopup() +DisplayPopup::PopUp::PopUp() { SetFrame(BlackFrame()); display = NULL; @@ -83,14 +83,14 @@ DisplayPopup::DisplayPopup() all().Add(this); } -DisplayPopup::~DisplayPopup() +DisplayPopup::PopUp::~PopUp() { int q = FindIndex(all(), this); if(q >= 0) all().Remove(q); } -void DisplayPopup::Sync() +void DisplayPopup::PopUp::Sync() { if(!IsMainThread()) { PostCallback(PTEBACK(Sync)); @@ -144,20 +144,20 @@ void DisplayPopup::Sync() } } if(IsOpen() && !GetDragAndDropSource()) - Close(); + WhenClose(); } -void DisplayPopup::SyncAll() +void DisplayPopup::PopUp::SyncAll() { int n = 0; - for(DisplayPopup *p : all()) + for(DisplayPopup::PopUp *p : all()) if(p->ctrl && p->ctrl->IsOpen()) { p->Sync(); n++; } } -bool DisplayPopup::StateHook(Ctrl *, int reason) +bool DisplayPopup::PopUp::StateHook(Ctrl *, int reason) { if(reason == FOCUS) SyncAll(); @@ -165,13 +165,13 @@ bool DisplayPopup::StateHook(Ctrl *, int reason) } -bool DisplayPopup::MouseHook(Ctrl *, bool, int, Point, int, dword) +bool DisplayPopup::PopUp::MouseHook(Ctrl *, bool, int, Point, int, dword) { SyncAll(); return false; } -void DisplayPopup::Cancel() +void DisplayPopup::PopUp::Cancel() { if(GetDragAndDropSource()) return; @@ -179,17 +179,17 @@ void DisplayPopup::Cancel() Sync(); } -bool DisplayPopup::IsOpen() +bool DisplayPopup::PopUp::IsOpen() { return Ctrl::IsOpen(); } -bool DisplayPopup::HasMouse() +bool DisplayPopup::PopUp::HasMouse() { return Ctrl::HasMouse() || ctrl && ctrl->HasMouse(); } -void DisplayPopup::Set(Ctrl *_ctrl, const Rect& _item, +void DisplayPopup::PopUp::Set(Ctrl *_ctrl, const Rect& _item, const Value& _value, const Display *_display, Color _ink, Color _paper, dword _style, int _margin) { @@ -212,4 +212,44 @@ void DisplayPopup::Set(Ctrl *_ctrl, const Rect& _item, } } + +void DisplayPopup::Set(Ctrl *ctrl, const Rect& item, const Value& v, const Display *display, Color ink, Color paper, dword style, int margin) +{ + if(!popup) { + popup.Create(); + popup->usedisplaystdsize = usedisplaystdsize; + popup->WhenClose << [=] { PostCallback([=] { popup.Clear(); }); }; + } + popup->Set(ctrl, item, v, display, ink, paper, style, margin); +} + +void DisplayPopup::Cancel() +{ + if(popup) + popup->Cancel(); +} + +bool DisplayPopup::IsOpen() +{ + return popup && popup->IsOpen(); +} + +bool DisplayPopup::HasMouse() +{ + return popup && popup->HasMouse(); +} + +void DisplayPopup::UseDisplayStdSize() +{ + usedisplaystdsize = true; + if(popup) + popup->usedisplaystdsize = true; +} + +DisplayPopup::~DisplayPopup() +{ + if(popup) + popup->Close(); +} + } diff --git a/uppsrc/CtrlLib/DisplayPopup.h b/uppsrc/CtrlLib/DisplayPopup.h index 90e2c183f..95b4b643a 100644 --- a/uppsrc/CtrlLib/DisplayPopup.h +++ b/uppsrc/CtrlLib/DisplayPopup.h @@ -1,29 +1,52 @@ -class DisplayPopup : public Ctrl, public Link { - virtual void Paint(Draw& w); - virtual void LeftDown(Point p, dword); - virtual void LeftDrag(Point p, dword); - virtual void LeftDouble(Point p, dword); - virtual void RightDown(Point p, dword); - virtual void LeftUp(Point p, dword); - virtual void MouseWheel(Point p, int zdelta, dword keyflags); - virtual void MouseLeave(); - virtual void MouseMove(Point p, dword); - +class DisplayPopup { private: - Ptr ctrl; - Rect item; - Rect slim; - - Value value; - Color paper, ink; - dword style; - const Display *display; - int margin; + struct PopUp : public Ctrl, public Link { + virtual void Paint(Draw& w); + virtual void LeftDown(Point p, dword); + virtual void LeftDrag(Point p, dword); + virtual void LeftDouble(Point p, dword); + virtual void RightDown(Point p, dword); + virtual void LeftUp(Point p, dword); + virtual void MouseWheel(Point p, int zdelta, dword keyflags); + virtual void MouseLeave(); + virtual void MouseMove(Point p, dword); + + Ptr ctrl; + Rect item; + Rect slim; + + Value value; + Color paper, ink; + dword style; + const Display *display; + int margin; + bool usedisplaystdsize = false; + + Point Op(Point p); + void Sync(); + + static Vector& all(); + static bool StateHook(Ctrl *, int reason); + static bool MouseHook(Ctrl *, bool, int, Point, int, dword); + static void SyncAll(); + + typedef DisplayPopup::PopUp CLASSNAME; + + Callback WhenClose; + + void Set(Ctrl *ctrl, const Rect& item, const Value& v, const Display *display, + Color ink, Color paper, dword style, int margin = 0); + void Cancel(); + bool IsOpen(); + bool HasMouse(); + + PopUp(); + ~PopUp(); + }; + + One popup; bool usedisplaystdsize = false; - Point Op(Point p); - void Sync(); - static Vector& all(); static bool StateHook(Ctrl *, int reason); static bool MouseHook(Ctrl *, bool, int, Point, int, dword); @@ -37,8 +60,7 @@ public: void Cancel(); bool IsOpen(); bool HasMouse(); - void UseDisplayStdSize() { usedisplaystdsize = true; } + void UseDisplayStdSize(); - DisplayPopup(); ~DisplayPopup(); }; diff --git a/uppsrc/CtrlLib/DocEdit.cpp b/uppsrc/CtrlLib/DocEdit.cpp index fac2d3a8e..06f607379 100644 --- a/uppsrc/CtrlLib/DocEdit.cpp +++ b/uppsrc/CtrlLib/DocEdit.cpp @@ -222,6 +222,11 @@ int DocEdit::GetCursorPos(Point p) { return GetLength32(); } +Rect DocEdit::GetCaret() const +{ + return caret; +} + void DocEdit::PlaceCaret(bool scroll) { Point cr = GetCaret((int)cursor); int fy = font.Info().GetLineHeight(); @@ -231,7 +236,7 @@ void DocEdit::PlaceCaret(bool scroll) { else sb.ScrollInto(cr.y, fy + 2); } - SetCaret(cr.x + 1, cr.y - sb, 1, fy); + caret = RectC(cr.x + 1, cr.y - sb, 1, fy); WhenSel(); } diff --git a/uppsrc/CtrlLib/DropChoice.cpp b/uppsrc/CtrlLib/DropChoice.cpp index 78e015133..0cd6ed860 100644 --- a/uppsrc/CtrlLib/DropChoice.cpp +++ b/uppsrc/CtrlLib/DropChoice.cpp @@ -6,7 +6,6 @@ DropChoice::DropChoice() { always_drop = hide_drop = false; AddButton().Main() <<= THISBACK(Drop); NoDisplay(); - list.Normal(); list.WhenSelect = [=] { Select(); }; dropfocus = true; EnableDrop(false); @@ -42,7 +41,11 @@ void DropChoice::Drop() { WhenDrop(); if(dropfocus) owner->SetWantFocus(); - if(!list.FindSetCursor(owner->GetData()) && list.GetCount() > 0) + int i = list.Find(owner->GetData()); + if(i >= 0) + list.SetCursor(i); + else + if(list.GetCount() > 0) list.SetCursor(0); list.PopUp(owner,dropwidth); } @@ -56,7 +59,7 @@ Value DropChoice::Get() const { if(!owner || owner->IsReadOnly() && !rodrop) return Value(); int c = list.GetCursor(); if(c < 0) return Value(); - return list.Get(c, 0); + return list.Get(c); } int DropChoice::GetIndex() const @@ -172,7 +175,7 @@ void DropChoice::SerializeList(Stream& s) { } else for(int i = 0; i < n; i++) { - v = list.Get(i, 0); + v = list.Get(i); s % v; } EnableDrop(list.GetCount() || always_drop); @@ -181,15 +184,15 @@ void DropChoice::SerializeList(Stream& s) { void DropChoice::AddHistory(const Value& v, int max) { if(IsNull(v)) return; for(int i = 0; i < list.GetCount(); i++) - if(list.Get(i, 0) == v) { + if(list.Get(i) == v) { list.Remove(i); break; } - list.Insert(0, Vector() << v); + list.Insert(0, v); if(list.GetCount() > max) list.SetCount(max); EnableDrop(list.GetCount() || always_drop); - list.KillCursor(); + list.SetCursor(-1); } DropChoice& DropChoice::AlwaysDrop(bool e) diff --git a/uppsrc/CtrlLib/DropChoice.h b/uppsrc/CtrlLib/DropChoice.h index 8e81ba6a7..5f3da638e 100644 --- a/uppsrc/CtrlLib/DropChoice.h +++ b/uppsrc/CtrlLib/DropChoice.h @@ -1,6 +1,6 @@ void DropEdge_Write(Value); -class PopUpTable : public ArrayCtrl { +class PopUpTable : public ArrayCtrl { // deprecated, replaced with PopUpList public: virtual void LeftUp(Point p, dword keyflags); virtual bool Key(dword key, int); @@ -39,27 +39,115 @@ public: virtual ~PopUpTable(); }; +class PopUpList { +protected: + void PopupDeactivate(); + void PopupCancelMode(); + + struct PopupArrayCtrl : ArrayCtrl { + PopUpList *list; + + virtual void LeftUp(Point p, dword keyflags); + virtual bool Key(dword key, int); + }; + + struct Popup : Ctrl { + PopUpList *list; + PopupArrayCtrl ac; + bool closing = false; + + virtual void Deactivate() { if(!closing) list->PopupDeactivate(); } + virtual void CancelMode() { if(!closing) list->PopupCancelMode(); } + + Popup(PopUpList *list); + }; + + Vector items; + Vector lineinfo; + Vector linedisplay; + One popup; + const ScrollBar::Style *sb_style = nullptr; + const Display *display; + const Convert *convert; + int linecy; + int cursor = -1; + int16 droplines; + int16 inpopup; + + void DoSelect(); + void DoCancel(); + void DoClose(); + + void Reset(); + + friend class Popup; + +public: + Event<> WhenCancel; + Event<> WhenSelect; + + void PopUp(Ctrl *owner, int x, int top, int bottom, int width); + void PopUp(Ctrl *owner, int width); + void PopUp(Ctrl *owner); + + void Clear(); + void SetCount(int n); + void Add(const Value& v); + void AddSeparator(); + void Remove(int i); + void Insert(int i, const Value& v); + + void SetCursor(int i); + int GetCursor() const; + + int GetCount() const { return items.GetCount(); } + void Set(int i, const Value& v); + Value Get(int i) const { return items[i]; } + int Find(const Value& v) const; + void SetScrollBarStyle(const ScrollBar::Style& s); + void SetLineCy(int cy); + int GetLineCy() const { return linecy; } + void SetLineCy(int ii, int cy); + int GetLineCy(int ii) const; + bool Key(int c); + bool IsLineEnabled(int ii) const; + + void SetDisplay(const Display& d); + const Display& GetDisplay() const { return *display; } + + void SetDisplay(int i, const Display& d); + const Display& GetDisplay(int i) const; + + void SetConvert(const Convert& c); + + PopUpList& SetDropLines(int _droplines) { droplines = _droplines; return *this; } + + PopUpList(); + virtual ~PopUpList(); +}; + class DropList : public MultiButton, public Convert { public: virtual void MouseWheel(Point p, int zdelta, dword keyflags); virtual bool Key(dword key, int); virtual void SetData(const Value& data); virtual Value GetData() const; + virtual void DropPush(); virtual Value Format(const Value& q) const; private: - PopUpTable list; + PopUpList list; Index key; Value value; - int dropwidth; const Convert *valueconvert; const Display *valuedisplay; - bool displayall; - bool dropfocus; - bool notnull; - bool alwaysdrop; - bool usewheel; + int16 dropwidth; + bool displayall:1; + bool dropfocus:1; + bool notnull:1; + bool alwaysdrop:1; + bool usewheel:1; void Select(); void Cancel(); @@ -105,7 +193,7 @@ public: void Trim(int n); const Value& GetKey(int i) const { return key[i]; } - Value GetValue(int i) const { return list.Get(i, 0); } + Value GetValue(int i) const { return list.Get(i); } Value GetValue() const; void SetValue(int i, const Value& v); void SetValue(const Value& v); @@ -113,10 +201,10 @@ public: void Adjust(); void Adjust(const Value& k); - +/* const PopUpTable& GetList() const { return list; } PopUpTable& ListObject() { return list; } - +*/ DropList& SetDropLines(int d) { list.SetDropLines(d); return *this; } DropList& SetValueConvert(const Convert& cv); DropList& SetConvert(const Convert& cv); @@ -160,7 +248,7 @@ public: virtual void Serialize(Stream& s); //empty protected: - PopUpTable list; + PopUpList list; Ctrl *owner; bool appending : 1; bool dropfocus : 1; @@ -189,12 +277,12 @@ public: void Add(const Value& data); int Find(const Value& data) const { return list.Find(data); } void FindAdd(const Value& data); - void Set(int i, const Value& data) { list.Set(i, 0, data); } + void Set(int i, const Value& data) { list.Set(i, data); } void Remove(int i); void SerializeList(Stream& s); int GetCount() const { return list.GetCount(); } - Value Get(int i) const { return list.Get(i, 0); } + Value Get(int i) const { return list.Get(i); } void AddHistory(const Value& data, int max = 12); @@ -204,11 +292,11 @@ public: Value Get() const; int GetIndex() const; - DropChoice& SetDisplay(int i, const Display& d) { list.SetDisplay(i, 0, d); return *this; } - DropChoice& SetDisplay(const Display& d) { list.ColumnAt(0).SetDisplay(d); return *this; } + DropChoice& SetDisplay(int i, const Display& d) { list.SetDisplay(i, d); return *this; } + DropChoice& SetDisplay(const Display& d) { list.SetDisplay(d); return *this; } DropChoice& SetLineCy(int lcy) { list.SetLineCy(lcy); return *this; } DropChoice& SetDisplay(const Display& d, int lcy) { SetDisplay(d); SetLineCy(lcy); return *this; } - DropChoice& SetConvert(const Convert& d) { list.ColumnAt(0).SetConvert(d); return *this; } + DropChoice& SetConvert(const Convert& d) { list.SetConvert(d); return *this; } DropChoice& SetDropLines(int n) { list.SetDropLines(n); return *this; } DropChoice& Appending() { appending = true; return *this; } DropChoice& AlwaysDrop(bool e = true); diff --git a/uppsrc/CtrlLib/DropList.cpp b/uppsrc/CtrlLib/DropList.cpp index 06943ad2c..1a18818ba 100644 --- a/uppsrc/CtrlLib/DropList.cpp +++ b/uppsrc/CtrlLib/DropList.cpp @@ -12,9 +12,9 @@ void DropList::Sync() { if(displayall) v = value; int i = key.Find(value); - const Display& d = valuedisplay ? *valuedisplay : i >= 0 ? list.GetDisplay(i, 0) - : list.GetDisplay(0); - if(i >= 0) v = list.Get(i, 0); + const Display& d = valuedisplay ? *valuedisplay : i >= 0 ? list.GetDisplay(i) + : list.GetDisplay(); + if(i >= 0) v = list.Get(i); MultiButton::SetDisplay(d); MultiButton::SetValueCy(list.GetLineCy()); v = valueconvert->Format(v); @@ -55,7 +55,7 @@ bool DropList::Key(dword k, int) { break; default: if(k >= 32 && k < K_CHAR_LIM) { - bool b = list.Key(k, 1); + bool b = list.Key(k); if(list.GetCursor() >= 0 && list.GetCursor() < key.GetCount() && key[list.GetCursor()] != value) Select(); return b; @@ -80,6 +80,11 @@ void DropList::Drop() { list.PopUp(this, dropwidth); } +void DropList::DropPush() +{ + Drop(); +} + void DropList::Select() { int c = list.GetCursor(); if(c >= 0) @@ -107,7 +112,6 @@ void DropList::ClearList() { key.Clear(); list.Clear(); Sync(); - list.Refresh(); EnableDrop(false); } @@ -124,7 +128,6 @@ DropList& DropList::Add(const Value& _key, const Value& text, bool enable) list.Add(text); if(!enable) list.SetLineCy(list.GetCount() - 1, 0); - list.Refresh(); EnableDrop(); Sync(); return *this; @@ -143,7 +146,6 @@ DropList& DropList::AddSeparator() { key.Add(RawToValue(DummyValue__())); list.AddSeparator(); - list.Refresh(); EnableDrop(); Sync(); return *this; @@ -155,7 +157,6 @@ void DropList::Trim(int n) { key.Trim(n); list.SetCount(n); Sync(); - list.Refresh(); EnableDrop(n); } @@ -177,7 +178,7 @@ Value DropList::GetValue() const { } void DropList::SetValue(int i, const Value& v) { - list.Set(i, 0, v); + list.Set(i, v); EnableDrop(); Sync(); } @@ -198,20 +199,20 @@ DropList& DropList::SetValueConvert(const Convert& cv) DropList& DropList::SetConvert(const Convert& cv) { - list.ColumnAt(0).SetConvert(cv); + list.SetConvert(cv); return SetValueConvert(cv); } DropList& DropList::SetDisplay(int i, const Display& d) { - list.SetDisplay(i, 0, d); + list.SetDisplay(i, d); Sync(); return *this; } DropList& DropList::SetDisplay(const Display& d) { - list.ColumnAt(0).SetDisplay(d); + list.SetDisplay(d); Sync(); return *this; } @@ -270,10 +271,9 @@ DropList::DropList() dropfocus = false; notnull = false; alwaysdrop = false; - AddButton().Main().WhenPush = THISBACK(Drop); + SetupDropPush(); NoInitFocus(); EnableDrop(false); - list.Normal(); list.WhenSelect = THISBACK(Select); list.WhenCancel = THISBACK(Cancel); dropwidth = 0; diff --git a/uppsrc/CtrlLib/EditCtrl.h b/uppsrc/CtrlLib/EditCtrl.h index f92baa389..a96a65aa6 100644 --- a/uppsrc/CtrlLib/EditCtrl.h +++ b/uppsrc/CtrlLib/EditCtrl.h @@ -63,6 +63,7 @@ public: virtual void CancelMode(); virtual String GetSelectionData(const String& fmt) const; virtual void State(int); + virtual Rect GetCaret() const; public: struct Style : ChStyle