mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-17 14:16:10 -06:00
350 lines
7.7 KiB
C++
350 lines
7.7 KiB
C++
#include "CtrlFinder.h"
|
|
|
|
//this one filters
|
|
//check if the found ctrl is to be kept and returned as found
|
|
//according to the selection flags f
|
|
//set q = NULL will continue the search.
|
|
//keeping q will return it as found, but probably continue a DEEP search in it if flag set
|
|
void CtrlFinder::StdCtrlFilter(Ctrl*& q, int& f)
|
|
{
|
|
if((f & VIEW) && q->InView())
|
|
{
|
|
if( ((f & VISIBLE) && q->IsShown())
|
|
|| ((f & INVISIBLE) && !q->IsShown())
|
|
|| ((f & ENABLED) && q->IsEnabled())
|
|
|| ((f & DISABLED) && !q->IsEnabled())
|
|
) return;
|
|
}
|
|
|
|
if((f & FRAME) && q->InFrame())
|
|
if( ((f & VISIBLE) && q->IsShown())
|
|
|| ((f & INVISIBLE) && !q->IsShown())
|
|
|| ((f & ENABLED) && q->IsEnabled())
|
|
|| ((f & DISABLED) && !q->IsEnabled())
|
|
) return;
|
|
q = NULL;
|
|
}
|
|
|
|
Ctrl* CtrlFinder::ChildAtPoint(Ctrl& par, Point& pt, int& f, const CtrlFilterType& filt)
|
|
{
|
|
GuiLock __;
|
|
Ctrl *q;
|
|
Point p(pt);
|
|
Rect view = par.GetView();
|
|
|
|
if(f & VIEW)
|
|
if(view.Contains(p)) {
|
|
Point vp = p - view.TopLeft();
|
|
for(q = par.GetLastChild(); q; q = q->GetPrev()) {
|
|
if((f & VIEW) && q->InView())
|
|
{
|
|
Rect r = q->GetRect();
|
|
if(r.Contains(vp)) {
|
|
pt = vp - r.TopLeft();
|
|
Ctrl* w(q);
|
|
filt(w, f);
|
|
if(w) return w;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(f & FRAME)
|
|
for(q = par.GetLastChild(); q; q = q->GetPrev()) {
|
|
if((f & FRAME) && q->InFrame())
|
|
{
|
|
Rect r = q->GetRect();
|
|
if(r.Contains(p)) {
|
|
pt = p - r.TopLeft();
|
|
Ctrl* w(q);
|
|
filt(w, f);
|
|
if(w) return w;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//find a ctrl at point (in pctrl coords). The search can go deep, if specified.
|
|
//a filter can prohibit to look deep in a returned found ctrl, resetting a DEEP flag
|
|
//or prohibit a deep look in a fellow to be found child resetting DEEP flag and returning NULL
|
|
Ctrl* CtrlFinder::GetCtrl(Ctrl& c, Point& p, int& f, const CtrlFilterType& filt)
|
|
{
|
|
Ctrl* q = ChildAtPoint(c, p, f, filt);
|
|
if(q && (f & DEEP))
|
|
{
|
|
Point pt(p);
|
|
Ctrl* qc = GetCtrl(*q, pt, f, filt);
|
|
if(qc) { p = pt; return qc; }
|
|
}
|
|
return q;
|
|
}
|
|
|
|
Ctrl* CtrlFinder::ChildInRect(Ctrl& par, Rect& rect, int& f, const CtrlFilterType& filt)
|
|
{
|
|
GuiLock __;
|
|
Ctrl *q;
|
|
Rect rc(rect);
|
|
Rect view = par.GetView();
|
|
|
|
if(f & VIEW)
|
|
if(view.Contains(rc)) {
|
|
Rect vrc = rc - view.TopLeft();
|
|
for(q = par.GetLastChild(); q; q = q->GetPrev()) {
|
|
if((f & VIEW) && q->InView())
|
|
{
|
|
Rect r = q->GetRect();
|
|
if(r.Contains(vrc)) {
|
|
rect = vrc - r.TopLeft();
|
|
Ctrl* w(q);
|
|
filt(w, f);
|
|
if(w) return w;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(f & FRAME)
|
|
for(q = par.GetLastChild(); q; q = q->GetPrev()) {
|
|
if((f & FRAME) && q->InFrame())
|
|
{
|
|
Rect r = q->GetRect();
|
|
if(r.Contains(rc)) {
|
|
rect = rc - r.TopLeft();
|
|
Ctrl* w(q);
|
|
filt(w, f);
|
|
if(w) return w;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//see rect as a big Point, the found Ctrl needs to Contain it.
|
|
Ctrl* CtrlFinder::GetCtrl(Ctrl& c, Rect& rect, int& f, const CtrlFilterType& filt)
|
|
{
|
|
Ctrl* q = ChildInRect(c, rect, f, filt);
|
|
if(q && (f & DEEP))
|
|
{
|
|
Rect rc(rect);
|
|
Ctrl* qc = GetCtrl(*q, rc, f, filt);
|
|
if(qc) { rect = rc; return qc; }
|
|
}
|
|
return q;
|
|
}
|
|
|
|
Vector<Ctrl*> CtrlFinder::ChildrenInRect(Ctrl& par, Rect& rect, int& f, const CtrlFilterType& filt)
|
|
{
|
|
GuiLock __;
|
|
Vector<Ctrl*> vc;
|
|
Ctrl *q;
|
|
Rect rc(rect);
|
|
Rect view = par.GetView();
|
|
|
|
if(f & VIEW)
|
|
if(view.Contains(rc)) {
|
|
Rect vrc = rc - view.TopLeft();
|
|
for(q = par.GetLastChild(); q; q = q->GetPrev()) {
|
|
if((f & VIEW) && q->InView())
|
|
{
|
|
Rect r = q->GetRect();
|
|
if(vrc.Contains(r)) {
|
|
Ctrl* w(q);
|
|
filt(w, f);
|
|
if(w) vc.Add(w);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(f & FRAME)
|
|
for(q = par.GetLastChild(); q; q = q->GetPrev()) {
|
|
if((f & FRAME) && q->InFrame())
|
|
{
|
|
Rect r = q->GetRect();
|
|
if(rc.Contains(r)) {
|
|
Ctrl* w(q);
|
|
filt(w, f);
|
|
if(w) vc.Add(w);
|
|
}
|
|
}
|
|
}
|
|
return vc;
|
|
}
|
|
|
|
Vector<Ctrl*> CtrlFinder::GetCtrls(Ctrl& c, Rect& rect, int& f, const CtrlFilterType& filt)
|
|
{
|
|
Vector<Ctrl*> vq = ChildrenInRect(c, rect, f, filt);
|
|
if(vq.IsEmpty() && (f & DEEP)) //difference between child and children, we stop if we found some in rect
|
|
{
|
|
//find a child, that has rect fully within, so we can try in there
|
|
//if no recursable child is found, we can return the empty vector
|
|
Rect rc(rect);
|
|
|
|
Ctrl* q = ChildInRect(c, rc, f, filt);
|
|
if(q)
|
|
{
|
|
vq = GetCtrls(*q, rc, f, filt);
|
|
if(!vq.IsEmpty()) { rect = rc; }
|
|
}
|
|
}
|
|
return vq;
|
|
}
|
|
|
|
bool CtrlFinder::IsParentR(const Ctrl* p, const Ctrl* c)
|
|
{
|
|
while(c && p) {
|
|
if(c == p) return true;
|
|
c = c->GetParent();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//Offset calculation:
|
|
// A Rect is always related to it housing/encapsulating/parent context.
|
|
|
|
//adds the view offset of a ctrl's parent context, if the ctrl happens to sit in its parent's view
|
|
//effectively, it's the frame to view coord. offset of the parent context of c
|
|
void CtrlFinder::AddParentViewOffset(const Ctrl& c, Point& p)
|
|
{
|
|
if(c.InView())
|
|
p += c.GetParent()->GetView().TopLeft();
|
|
}
|
|
|
|
//adds the offset of a source context to a (far) parent context q, all frame coordinates
|
|
void CtrlFinder::AddContextOffset(const Ctrl& c, const Ctrl& q, Point& p)
|
|
{
|
|
if(&c == &q) return;
|
|
|
|
p += c.GetRect().TopLeft();
|
|
AddParentViewOffset(c, p);
|
|
AddContextOffset(*c.GetParent(), q, p); //recurse
|
|
}
|
|
|
|
Point CtrlFinder::GetContextOffset(const Ctrl& c, const Ctrl& q)
|
|
{
|
|
Point p; p.Clear();
|
|
AddContextOffset(c, q, p);
|
|
return p;
|
|
}
|
|
|
|
Point CtrlFinder::GetOffset(const Ctrl& ctxuser, const Ctrl& finalctx)
|
|
{
|
|
ASSERT(&ctxuser != &finalctx); //a user of a context cant be the context itself
|
|
Point p; p.Clear();
|
|
AddParentViewOffset(ctxuser, p);
|
|
AddContextOffset(*ctxuser.GetParent(), finalctx, p);
|
|
return p;
|
|
}
|
|
|
|
Rect CtrlFinder::SurroundingRect(const Vector<Ctrl*>& ctrls)
|
|
{
|
|
Rect r; r.Clear();
|
|
|
|
for(int i = 0; i < ctrls.GetCount(); i++)
|
|
{
|
|
Rect rc = ctrls[i]->GetRect();
|
|
if(r.IsEmpty()) r = rc;
|
|
else r.Union(rc);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
void CtrlFinder::Updated()
|
|
{
|
|
if(!pctrl) return;
|
|
SetPos(pctrl->GetPos());
|
|
}
|
|
|
|
void CtrlFinder::UpdatedSource()
|
|
{
|
|
Remove();
|
|
ClearCtrl();
|
|
if(!pctrl) return;
|
|
ASSERT(pctrl->GetParent());
|
|
//finder adds itself on top of any child in the search ctrl's parent
|
|
pctrl->GetParent()->AddChild(this, pctrl);
|
|
}
|
|
|
|
void CtrlFinder::SetCtrl(Ctrl* c)
|
|
{
|
|
if(pctrl && c) { ASSERT(IsParentR(pctrl, c)); }
|
|
if(c)
|
|
{
|
|
ctrls.SetCount(1);
|
|
ctrls.Top() = c;
|
|
}
|
|
else ctrls.Clear();
|
|
Update();
|
|
}
|
|
|
|
void CtrlFinder::LeftDown(Point p, dword keyflags)
|
|
{
|
|
if(!pctrl) return;
|
|
Point pt(p);
|
|
int f(flags);
|
|
|
|
Rect r; r.Clear();
|
|
|
|
//try to find multiple first
|
|
if(multi)
|
|
{
|
|
RectTracker tr(*this);
|
|
r = tr.Track(Rect(p,p), ALIGN_NULL, ALIGN_NULL);
|
|
}
|
|
|
|
if(!r.IsEmpty())
|
|
{
|
|
ctrls = GetCtrls(*pctrl, r, f, filter);
|
|
if(ctrls.IsEmpty())
|
|
ctrls << pctrl;
|
|
WhenLeftSelectMulti(&ctrls, r, keyflags);
|
|
}
|
|
else
|
|
{
|
|
ctrls.SetCount(1);
|
|
ctrls.Top() = GetCtrl(*pctrl, pt, f, filter);
|
|
if(!ctrls.Top())
|
|
ctrls.Top() = pctrl;
|
|
WhenLeftSelect(*ctrls.Top(), p, keyflags);
|
|
}
|
|
|
|
Action();
|
|
}
|
|
void CtrlFinder::RightDown(Point p, dword keyflags)
|
|
{
|
|
if(!pctrl) return;
|
|
Point pt(p);
|
|
int f(flags);
|
|
|
|
Rect r; r.Clear();
|
|
|
|
//try to find multiple first
|
|
if(multi)
|
|
{
|
|
RectTracker tr(*this);
|
|
r = tr.Track(Rect(p,p), ALIGN_NULL, ALIGN_NULL);
|
|
}
|
|
|
|
if(!r.IsEmpty())
|
|
{
|
|
ctrls = GetCtrls(*pctrl, r, f, filter);
|
|
if(ctrls.IsEmpty())
|
|
ctrls << pctrl;
|
|
WhenRightSelectMulti(&ctrls, r, keyflags);
|
|
}
|
|
else
|
|
{
|
|
ctrls.SetCount(1);
|
|
ctrls.Top() = GetCtrl(*pctrl, pt, f, filter);
|
|
if(!ctrls.Top())
|
|
ctrls.Top() = pctrl;
|
|
WhenRightSelect(*ctrls.Top(), p, keyflags);
|
|
}
|
|
|
|
Action();
|
|
|
|
if(WhenBar)
|
|
MenuBar::Execute(WhenBar);
|
|
}
|
|
|