/* Crafter®.Graphics Copyright (C) 2026 Catcrafts® catcrafts.net This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3.0 as published by the Free Software Foundation; This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ export module Crafter.Graphics:UIHit; import std; import :UILength; import :UIWidget; export namespace Crafter::UI { // Find the topmost widget whose computedRect contains (x, y). // Children are visited in reverse order so later children (drawn on // top) win ties. Returns nullptr if the point is outside `root`. inline Widget* HitTest(Widget& root, float x, float y) { if (!root.computedRect.Contains(x, y)) return nullptr; // Search children in reverse — the last-added child is on top in // our draw order, so it wins overlapping hits. for (auto it = root.children_.rbegin(); it != root.children_.rend(); ++it) { if (Widget* hit = HitTest(**it, x, y); hit) return hit; } return &root; } // Dispatch a click at (x, y) to the topmost widget under the cursor, // bubbling to ancestors until one returns true (handled). The default // Widget::OnMouseClick returns false, so leaf widgets that don't care // automatically defer to their parents. inline void DispatchClick(Widget& root, float x, float y) { Widget* target = HitTest(root, x, y); while (target) { if (target->OnMouseClick(x, y)) return; target = target->parent; } } }