#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 CtrlFinder::ChildrenInRect(Ctrl& par, Rect& rect, int& f, const CtrlFilterType& filt) { GuiLock __; Vector 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 CtrlFinder::GetCtrls(Ctrl& c, Rect& rect, int& f, const CtrlFilterType& filt) { Vector 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& 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); }