1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 13:48:12 +00:00

LibGUI: Introduce widget content margins + improve splitters

A GUI::Widget can now set an optional content margin (4x0 by default.)
Pixels in the content margin will be ignored for hit testing purposes.

Use this to allow frame-like widgets (like GUI::Frame!) to ignore any
mouse events in the frame area, and instead let those go to parent.

This allows GUI::Splitter to react "sooner" to mouse events that were
previously swallowed by the child widgets instead of ending up in the
splitter. The net effect is that 2 more pixels on each side of a
splitter handle are now interactive and usable for splitting! :^)
This commit is contained in:
Andreas Kling 2020-04-24 18:55:29 +02:00
parent 9badcff1ba
commit 42f0b2522b
6 changed files with 57 additions and 17 deletions

View file

@ -76,17 +76,23 @@ void Splitter::leave_event(Core::Event&)
bool Splitter::get_resize_candidates_at(const Gfx::Point& position, Widget*& first, Widget*& second)
{
int x_or_y = position.primary_offset_for_orientation(m_orientation);
int fudge = layout()->spacing();
for_each_child_widget([&](auto& child) {
int child_start = child.relative_rect().first_edge_for_orientation(m_orientation);
int child_end = child.relative_rect().last_edge_for_orientation(m_orientation);
if (x_or_y > child_end && (x_or_y - fudge) <= child_end)
first = &child;
if (x_or_y < child_start && (x_or_y + fudge) >= child_start)
second = &child;
return IterationDecision::Continue;
});
return first && second;
auto child_widgets = this->child_widgets();
if (child_widgets.size() < 2)
return false;
for (size_t i = 0; i < child_widgets.size() - 1; ++i) {
auto* first_candidate = child_widgets[i];
auto* second_candidate = child_widgets[i + 1];
if (x_or_y > first_candidate->content_rect().last_edge_for_orientation(m_orientation)
&& x_or_y <= second_candidate->content_rect().first_edge_for_orientation(m_orientation)) {
first = first_candidate;
second = second_candidate;
return true;
}
}
return false;
}
void Splitter::mousedown_event(MouseEvent& event)
@ -109,13 +115,14 @@ void Splitter::mousedown_event(MouseEvent& event)
void Splitter::recompute_grabbable_rect(const Widget& first, const Widget& second)
{
auto first_edge = first.relative_rect().primary_offset_for_orientation(m_orientation) + first.relative_rect().primary_size_for_orientation(m_orientation);
auto second_edge = second.relative_rect().primary_offset_for_orientation(m_orientation);
auto first_edge = first.content_rect().primary_offset_for_orientation(m_orientation) + first.content_rect().primary_size_for_orientation(m_orientation);
auto second_edge = second.content_rect().primary_offset_for_orientation(m_orientation);
Gfx::Rect rect;
rect.set_primary_offset_for_orientation(m_orientation, first_edge);
rect.set_primary_size_for_orientation(m_orientation, second_edge - first_edge);
rect.set_secondary_offset_for_orientation(m_orientation, first.relative_rect().secondary_offset_for_orientation(m_orientation));
rect.set_secondary_size_for_orientation(m_orientation, first.relative_rect().secondary_size_for_orientation(m_orientation));
rect.set_secondary_offset_for_orientation(m_orientation, first.content_rect().secondary_offset_for_orientation(m_orientation));
rect.set_secondary_size_for_orientation(m_orientation, first.content_rect().secondary_size_for_orientation(m_orientation));
if (m_grabbable_rect != rect) {
m_grabbable_rect = rect;
update();