diff --git a/uppsrc/Core/Other.h b/uppsrc/Core/Other.h index bd4f9b1f3..d6817e749 100644 --- a/uppsrc/Core/Other.h +++ b/uppsrc/Core/Other.h @@ -239,13 +239,7 @@ public: } #endif }; -/* -template -class LinkOwner : public Link { -public: - ~LinkOwner() { Link::DeleteList(); } -}; -*/ + template class LRUCache { public: diff --git a/uppsrc/CtrlLib/DisplayPopup.cpp b/uppsrc/CtrlLib/DisplayPopup.cpp index 822a507d6..eac201759 100644 --- a/uppsrc/CtrlLib/DisplayPopup.cpp +++ b/uppsrc/CtrlLib/DisplayPopup.cpp @@ -1,192 +1,263 @@ -#include "CtrlLib.h" - -namespace Upp { - -void DisplayPopup::Pop::PopCtrl::Paint(Draw& w) -{ - Rect r = GetSize(); - w.DrawRect(r, SColorPaper); - if(!p) return; - if(p->display) { - p->display->PaintBackground(w, r, p->value, p->ink, p->paper, p->style); - r.left += p->margin; - if(p->usedisplaystdsize) - r.top += (r.Height() - p->display->GetStdSize(p->value).cy) / 2; - p->display->Paint(w, r, p->value, p->ink, p->paper, p->style); - } -} - -Vector& DisplayPopup::Pop::all() -{ - static Vector all; - return all; -} - -DisplayPopup::Pop::Pop() -{ - display = NULL; - paper = ink = Null; - style = 0; - item = Null; - margin = 0; - all().Add(this); - view.IgnoreMouse(); - view.SetFrame(BlackFrame()); - frame.IgnoreMouse(); - frame.SetFrame(BlackFrame()); - view.p = this; - frame.p = this; -} - -DisplayPopup::Pop::~Pop() -{ - view.p = nullptr; - frame.p = nullptr; - int q = FindIndex(all(), this); - if(q >= 0) - all().Remove(q); -} - -Rect DisplayPopup::Check(Ctrl *ctrl, const Rect& item, const Value& value, const Display *display, int margin) -{ - if(display && ctrl && !ctrl->IsDragAndDropTarget() && !(GetMouseLeft() || GetMouseRight() || GetMouseMiddle())) { - Ctrl *top = ctrl->GetTopCtrl(); - if(top && top->HasFocusDeep()) { - Size sz = display->GetStdSize(value); - if(sz.cx + 2 * margin > item.GetWidth() || sz.cy > item.GetHeight()) { - Rect vw = ctrl->GetScreenView(); - Rect r = (item + vw.TopLeft()) & vw; - if(r.Contains(GetMousePos())) - return r; - } - } - } - return Null; -} - -void DisplayPopup::Pop::Sync() -{ - if(!IsMainThread()) { - Ptr p; - PostCallback([=] { if(p) p->Sync(); }); - return; - } - Rect r = Check(ctrl, item, value, display, margin); - if(IsNull(r)) - WhenClose(); - else { - Ctrl *top = ctrl->GetTopCtrl(); - Size sz = display->GetStdSize(value); - Rect wa = top->GetScreenRect(); - r.right = min(wa.right, r.left + sz.cx + 2 * margin); - r.bottom = max(r.bottom, r.top + sz.cy); - r.Inflate(1, 1); - view.SetRect(r - top->GetScreenView().TopLeft()); - frame.SetFrameRect(r - wa.TopLeft()); - if(!frame.GetParent()) - *top << view << frame; - } -} - -DisplayPopup::DisplayPopup() -{ - ONCELOCK { - Ctrl::InstallStateHook(StateHook); - Ctrl::InstallMouseHook(MouseHook); - } -} - -void DisplayPopup::SyncAll() -{ - for(DisplayPopup::Pop *p : Pop::all()) - if(p->ctrl && p->ctrl->IsOpen()) - p->Sync(); -} - -bool DisplayPopup::StateHook(Ctrl *, int reason) -{ - if(reason == Ctrl::FOCUS) - SyncAll(); - return false; -} - - -bool DisplayPopup::MouseHook(Ctrl *, bool, int, Point, int, dword) -{ - SyncAll(); - return false; -} - -void DisplayPopup::Pop::Set(Ctrl *_ctrl, const Rect& _item, - const Value& _value, const Display *_display, - Color _ink, Color _paper, dword _style, int _margin) -{ - if(!GUI_ToolTips()) - return; - - if(item != _item || ctrl != _ctrl || value != _value || display != _display || ink != _ink || - paper != _paper || style != _style) { - item = _item; - ctrl = _ctrl; - value = _value; - display = _display; - ink = _ink; - paper = _paper; - style = _style; - margin = _margin; - if(ctrl) { - String h = ctrl->GetTip(); - view.Tip(h); - frame.Tip(h); - } - Sync(); - view.Refresh(); - frame.Refresh(); - } -} - -void DisplayPopup::Set(Ctrl *ctrl, const Rect& item, const Value& v, const Display *display, Color ink, Color paper, dword style, int margin) -{ - if(IsNull(Check(ctrl, item, v, display, margin))) - return; // precheck to avoid creating / deleting popup too often, avoid flooding timer with PostCallback - if(!popup) { - popup.Create(); - popup->usedisplaystdsize = usedisplaystdsize; - Ptr pt = this; - popup->WhenClose << [=] { PostCallback([=] { if(pt) pt->popup.Clear(); }); }; - } - popup->Set(ctrl, item, v, display, ink, paper, style, margin); -} - -void DisplayPopup::Cancel() -{ - if(popup) { - popup->display = nullptr; - popup->Sync(); - } -} - -bool DisplayPopup::IsOpen() -{ - return popup && popup->view.GetParent(); -} - -bool DisplayPopup::HasMouse() -{ // TODO: remove - return popup && (popup->view.HasMouse() || popup->frame.HasMouse()); -} - -void DisplayPopup::UseDisplayStdSize() -{ - usedisplaystdsize = true; - if(popup) - popup->usedisplaystdsize = true; -} - -DisplayPopup::~DisplayPopup() -{ - if(popup) - popup.Clear(); -} - -} +#include "CtrlLib.h" + +namespace Upp { + +Point DisplayPopup::PopUp::Op(Point p) +{ + return p + GetScreenView().TopLeft() - ctrl->GetScreenView().TopLeft(); +} + +void DisplayPopup::PopUp::LeftDown(Point p, dword flags) +{ + if(ctrl) ctrl->LeftDown(Op(p), flags); +} + +void DisplayPopup::PopUp::LeftDrag(Point p, dword flags) +{ + if(ctrl) ctrl->LeftDrag(Op(p), flags); +} + +void DisplayPopup::PopUp::LeftDouble(Point p, dword flags) +{ + if(ctrl) ctrl->LeftDouble(Op(p), flags); +} + +void DisplayPopup::PopUp::RightDown(Point p, dword flags) +{ + if(ctrl) ctrl->RightDown(Op(p), flags); +} + +void DisplayPopup::PopUp::LeftUp(Point p, dword flags) +{ + if(ctrl) ctrl->LeftUp(Op(p), flags); +} + +void DisplayPopup::PopUp::MouseWheel(Point p, int zdelta, dword flags) +{ + if(ctrl) ctrl->MouseWheel(Op(p), zdelta, flags); +} + +void DisplayPopup::PopUp::MouseLeave() +{ + Cancel(); +} + +void DisplayPopup::PopUp::MouseMove(Point p, dword flags) +{ + p += GetScreenView().TopLeft(); + if(!slim.Contains(p)) + MouseLeave(); +} + +void DisplayPopup::PopUp::Paint(Draw& w) +{ + Rect r = GetSize(); + w.DrawRect(r, SColorPaper); + if(display) { + display->PaintBackground(w, r, value, ink, paper, style); + r.left += margin; + if(usedisplaystdsize) + r.top += (r.Height() - display->GetStdSize(value).cy) / 2; + display->Paint(w, r, value, ink, paper, style); + } +} + +Vector& DisplayPopup::PopUp::all() +{ + static Vector all; + return all; +} + +DisplayPopup::PopUp::PopUp() +{ + SetFrame(BlackFrame()); + display = NULL; + paper = ink = Null; + style = 0; + item = slim = Null; + margin = 0; + ONCELOCK { + InstallStateHook(StateHook); + InstallMouseHook(MouseHook); + } + all().Add(this); +} + +DisplayPopup::PopUp::~PopUp() +{ + int q = FindIndex(all(), this); + if(q >= 0) + all().Remove(q); +} + +Rect DisplayPopup::Check(Ctrl *ctrl, const Rect& item, const Value& value, const Display *display, int margin) +{ + if(display && ctrl && !ctrl->IsDragAndDropTarget() && !(GetMouseLeft() || GetMouseRight() || GetMouseMiddle())) { + Ctrl *top = ctrl->GetTopCtrl(); + if(top && top->HasFocusDeep()) { + Size sz = display->GetStdSize(value); + if(sz.cx + 2 * margin > item.GetWidth() || sz.cy > item.GetHeight()) { + Rect vw = ctrl->GetScreenView(); + Rect r = (item + vw.TopLeft()) & vw; + if(r.Contains(GetMousePos())) + return r; + } + } + } + return Null; +} + +void DisplayPopup::PopUp::Sync() +{ + if(!IsMainThread()) { + PostCallback(PTEBACK(Sync)); + return; + } + + Rect r = Check(ctrl, item, value, display, margin); + if(IsNull(r)) { + DLOG("CLOSE"); + DDUMP(r); + DDUMP(ctrl); + DDUMP(item); + DDUMP(value); + DDUMP(display); + DDUMP(margin); + Ctrl *top = ctrl->GetTopCtrl(); + DDUMP(top); + if(top) + DDUMP(top->HasFocusDeep()); + WhenClose(); + } + else { + Ctrl *top = ctrl->GetTopCtrl(); + Size sz = display->GetStdSize(value); + Rect wa = top->GetWorkArea(); + r.right = min(wa.right, r.left + sz.cx + 2 * margin); + r.bottom = max(r.bottom, r.top + sz.cy); + slim = r; + r.Inflate(1, 1); + SetRect(r); + if(!IsOpen()) { + DLOG("POPUP " << r); + DDUMP(r); + DDUMP(ctrl); + DDUMP(item); + DDUMP(value); + DDUMP(display); + DDUMP(margin); + Ctrl::PopUp(ctrl, true, false, false); + } + } +} + +void DisplayPopup::PopUp::SyncAll() +{ + int n = 0; + for(DisplayPopup::PopUp *p : all()) + if(p->ctrl && p->ctrl->IsOpen()) { + p->Sync(); + n++; + } +} + +bool DisplayPopup::PopUp::StateHook(Ctrl *, int reason) +{ + if(reason == FOCUS) + SyncAll(); + return false; +} + + +bool DisplayPopup::PopUp::MouseHook(Ctrl *, bool, int, Point, int, dword) +{ + SyncAll(); + return false; +} + +void DisplayPopup::PopUp::Cancel() +{ + DLOG("CANCEL"); + if(GetDragAndDropSource()) + return; + display = nullptr; + Sync(); +} + +bool DisplayPopup::PopUp::IsOpen() +{ + return Ctrl::IsOpen(); +} + +bool DisplayPopup::PopUp::HasMouse() +{ + return Ctrl::HasMouse() || ctrl && ctrl->HasMouse(); +} + +void DisplayPopup::PopUp::Set(Ctrl *_ctrl, const Rect& _item, + const Value& _value, const Display *_display, + Color _ink, Color _paper, dword _style, int _margin) +{ + if(!GUI_ToolTips() || GetDragAndDropSource()) + return; + if(item != _item || ctrl != _ctrl || value != _value || display != _display || ink != _ink || + paper != _paper || style != _style) { + item = _item; + ctrl = _ctrl; + value = _value; + display = _display; + ink = _ink; + paper = _paper; + style = _style; + margin = _margin; + if(ctrl) + Tip(ctrl->GetTip()); + Sync(); + Refresh(); + } +} + + +void DisplayPopup::Set(Ctrl *ctrl, const Rect& item, const Value& v, const Display *display, Color ink, Color paper, dword style, int margin) +{ + if(IsNull(Check(ctrl, item, v, display, margin))) + return; // precheck to avoid creating / deleting popup too often, avoid flooding timer with PostCallback + if(!popup) { + popup.Create(); + popup->usedisplaystdsize = usedisplaystdsize; + Ptr pt = this; + popup->WhenClose << [=] { PostCallback([=] { if(pt) pt->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 cc7dcb050..8592915c9 100644 --- a/uppsrc/CtrlLib/DisplayPopup.h +++ b/uppsrc/CtrlLib/DisplayPopup.h @@ -1,55 +1,67 @@ -class DisplayPopup : public Pte { -private: - struct Pop : Pte { - struct PopCtrl : public Ctrl { - virtual void Paint(Draw& w); - - struct Pop *p; - }; - - Ptr ctrl; - Rect item; - - Value value; - Color paper, ink; - dword style; - const Display *display; - int margin; - bool usedisplaystdsize = false; - - PopCtrl view; - PopCtrl frame; - - 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 Sync(); - - static Vector& all(); - - Pop(); - ~Pop(); - }; - - One popup; - bool usedisplaystdsize = false; - - static bool StateHook(Ctrl *, int reason); - static bool MouseHook(Ctrl *, bool, int, Point, int, dword); - static void SyncAll(); - static Rect Check(Ctrl *ctrl, const Rect& item, const Value& value, const Display *display, int margin); - - typedef DisplayPopup CLASSNAME; - -public: - 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(); - void UseDisplayStdSize(); - - DisplayPopup(); - ~DisplayPopup(); -}; +class DisplayPopup : public Pte { +private: + struct PopUp : public Ctrl { + 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; + + static Vector& all(); + static bool StateHook(Ctrl *, int reason); + static bool MouseHook(Ctrl *, bool, int, Point, int, dword); + static void SyncAll(); + static Rect Check(Ctrl *ctrl, const Rect& item, const Value& value, const Display *display, int margin); + + typedef DisplayPopup CLASSNAME; + +public: + 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(); + void UseDisplayStdSize(); + + ~DisplayPopup(); +}; diff --git a/upptst/DisplayPopup2/main.cpp b/upptst/DisplayPopup2/main.cpp index c94266b42..4e2778af9 100644 --- a/upptst/DisplayPopup2/main.cpp +++ b/upptst/DisplayPopup2/main.cpp @@ -7,10 +7,12 @@ GUI_APP_MAIN ArrayCtrl list; list.AddColumn("Test"); list.Add("Simple"); - list.Add("Long " + String('X', 200)); + for(int i = 0; i < 10; i++) + list.Add("Long " + String('X', i * 100)); DropList dl; dl.Add("Simple"); - dl.Add("Long " + String('X', 200)); + for(int i = 0; i < 10; i++) + dl.Add("Long " + String('X', i * 100)); TopWindow win; win.Add(dl.TopPosZ(0).LeftPosZ(0, 100)); win.Add(list.VSizePosZ(Zx(20), 0).LeftPosZ(0, 100));