mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 06:05:58 -06:00
Restores "real popups" in display popup
These were removed year ago because the placement is imprecise (macos, gtk do not allow odd pixel placement when UHD scaling, so it was a pixel off) and because of Wayland concerns. But the usefulness outweights these glitches...
This commit is contained in:
parent
3a6e3ca22a
commit
7edd654237
4 changed files with 335 additions and 256 deletions
|
|
@ -239,13 +239,7 @@ public:
|
|||
}
|
||||
#endif
|
||||
};
|
||||
/*
|
||||
template <class T, int N = 1>
|
||||
class LinkOwner : public Link<T, N> {
|
||||
public:
|
||||
~LinkOwner() { Link<T, N>::DeleteList(); }
|
||||
};
|
||||
*/
|
||||
|
||||
template <class T, class K = String>
|
||||
class LRUCache {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -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 *>& DisplayPopup::Pop::all()
|
||||
{
|
||||
static Vector<DisplayPopup::Pop *> 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<Pop> 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<DisplayPopup> 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 *>& DisplayPopup::PopUp::all()
|
||||
{
|
||||
static Vector<DisplayPopup::PopUp *> 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<DisplayPopup> 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,55 +1,67 @@
|
|||
class DisplayPopup : public Pte<DisplayPopup> {
|
||||
private:
|
||||
struct Pop : Pte<Pop> {
|
||||
struct PopCtrl : public Ctrl {
|
||||
virtual void Paint(Draw& w);
|
||||
|
||||
struct Pop *p;
|
||||
};
|
||||
|
||||
Ptr<Ctrl> 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<Pop *>& all();
|
||||
|
||||
Pop();
|
||||
~Pop();
|
||||
};
|
||||
|
||||
One<Pop> 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<DisplayPopup> {
|
||||
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> 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<DisplayPopup::PopUp *>& 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> popup;
|
||||
bool usedisplaystdsize = false;
|
||||
|
||||
static Vector<DisplayPopup *>& 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();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue