// Find all windows containing a given point (x, y) and interested in at least // one of the input evens in wantedInputMask. We have to traverse all windows // because children are not guaranteed to be bounded by their parent. // It's very likely to return more than one window because our window hierarchy // is a tree. Because we traverse the tree breadth-first, parent windows will be // in windows array before child windows. In most cases caller can use the last // window in returned array (but can use a custom logic as well). // Returns number of matched windows as a convenience. size_t CollectWindowsAt(Control *wndRoot, int x, int y, uint16 wantedInputMask, Vec<CtrlAndOffset> *controls) { WndInputWantedFilter filter(x, y, wantedInputMask); controls->Reset(); CollectWindowsBreathFirst(wndRoot, 0, 0, &filter, controls); return controls->Count(); }
// Paint windows in z-order by first collecting the windows // and then painting consecutive layers with the same z-order, // starting with the lowest z-order. // We don't sort because we want to preserve the order of // containment of windows with the same z-order and non-stable // sort could change it. static void PaintWindowsInZOrder(Graphics *g, Control *c) { Vec<CtrlAndOffset> toPaint; WndFilter wndFilter; CtrlAndOffset * coff; Pen debugPen(Color(255, 0, 0), 1); CollectWindowsBreathFirst(c, 0, 0, &wndFilter, &toPaint); size_t paintedCount = 0; int16 lastPaintedZOrder = INT16_MIN; for (;;) { // find which z-order should we paint now int16 minUnpaintedZOrder = INT16_MAX; for (coff = toPaint.IterStart(); coff; coff = toPaint.IterNext()) { int16 zOrder = coff->c->zOrder; if ((zOrder > lastPaintedZOrder) && (zOrder < minUnpaintedZOrder)) minUnpaintedZOrder = zOrder; } for (coff = toPaint.IterStart(); coff; coff = toPaint.IterNext()) { if (minUnpaintedZOrder == coff->c->zOrder) { coff->c->Paint(g, coff->offX, coff->offY); if (IsDebugPaint()) { Rect bbox(coff->offX, coff->offY, coff->c->pos.Width, coff->c->pos.Height); g->DrawRectangle(&debugPen, bbox); } ++paintedCount; } } if (paintedCount == toPaint.Count()) return; CrashIf(paintedCount > toPaint.Count()); lastPaintedZOrder = minUnpaintedZOrder; } }
void CollectWindowsBreathFirst(Control *c, int offX, int offY, WndFilter *wndFilter, Vec<CtrlAndOffset> *ctrls) { if (wndFilter->skipInvisibleSubtrees && !c->IsVisible()) return; offX += c->pos.X; offY += c->pos.Y; if (wndFilter->Matches(c, offX, offY)) { CtrlAndOffset coff = { c, offX, offY }; ctrls->Append(coff); } size_t children = c->GetChildCount(); for (size_t i = 0; i < children; i++) { CollectWindowsBreathFirst(c->GetChild(i), offX, offY, wndFilter, ctrls); } }