diff options
author | Andreas Kling <kling@serenityos.org> | 2020-04-24 18:55:29 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-04-24 19:05:02 +0200 |
commit | 42f0b2522b6e24e0269265597cebfda9f0b7b329 (patch) | |
tree | ccdabd18cf6bee50fde21912d2204cfff4394728 | |
parent | 9badcff1bab051e0dfb50d6dd9c7775a4f1d3af3 (diff) | |
download | serenity-42f0b2522b6e24e0269265597cebfda9f0b7b329.zip |
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! :^)
-rw-r--r-- | Libraries/LibGUI/Frame.cpp | 8 | ||||
-rw-r--r-- | Libraries/LibGUI/Frame.h | 2 | ||||
-rw-r--r-- | Libraries/LibGUI/MultiView.cpp | 1 | ||||
-rw-r--r-- | Libraries/LibGUI/Splitter.cpp | 37 | ||||
-rw-r--r-- | Libraries/LibGUI/Widget.cpp | 19 | ||||
-rw-r--r-- | Libraries/LibGUI/Widget.h | 7 |
6 files changed, 57 insertions, 17 deletions
diff --git a/Libraries/LibGUI/Frame.cpp b/Libraries/LibGUI/Frame.cpp index e2cb7c23d0..9b82c5b7f9 100644 --- a/Libraries/LibGUI/Frame.cpp +++ b/Libraries/LibGUI/Frame.cpp @@ -42,6 +42,14 @@ Frame::~Frame() { } +void Frame::set_frame_thickness(int thickness) +{ + if (m_thickness == thickness) + return; + m_thickness = thickness; + set_content_margins({ thickness, thickness, thickness, thickness }); +} + void Frame::paint_event(PaintEvent& event) { if (m_shape == Gfx::FrameShape::NoFrame) diff --git a/Libraries/LibGUI/Frame.h b/Libraries/LibGUI/Frame.h index e31bf13052..10b48e1cae 100644 --- a/Libraries/LibGUI/Frame.h +++ b/Libraries/LibGUI/Frame.h @@ -37,7 +37,7 @@ public: virtual ~Frame() override; int frame_thickness() const { return m_thickness; } - void set_frame_thickness(int thickness) { m_thickness = thickness; } + void set_frame_thickness(int thickness); Gfx::FrameShadow frame_shadow() const { return m_shadow; } void set_frame_shadow(Gfx::FrameShadow shadow) { m_shadow = shadow; } diff --git a/Libraries/LibGUI/MultiView.cpp b/Libraries/LibGUI/MultiView.cpp index 9b542eb67f..d80536804b 100644 --- a/Libraries/LibGUI/MultiView.cpp +++ b/Libraries/LibGUI/MultiView.cpp @@ -39,6 +39,7 @@ namespace GUI { MultiView::MultiView() { set_active_widget(nullptr); + set_content_margins({ 2, 2, 2, 2 }); m_item_view = add<ItemView>(); m_table_view = add<TableView>(); diff --git a/Libraries/LibGUI/Splitter.cpp b/Libraries/LibGUI/Splitter.cpp index b58113f09b..8b1a86bf84 100644 --- a/Libraries/LibGUI/Splitter.cpp +++ b/Libraries/LibGUI/Splitter.cpp @@ -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(); diff --git a/Libraries/LibGUI/Widget.cpp b/Libraries/LibGUI/Widget.cpp index 00b107a5f4..ceee7e37f3 100644 --- a/Libraries/LibGUI/Widget.cpp +++ b/Libraries/LibGUI/Widget.cpp @@ -472,7 +472,7 @@ Widget* Widget::child_at(const Gfx::Point& point) const auto& child = Core::to<Widget>(children()[i]); if (!child.is_visible()) continue; - if (child.relative_rect().contains(point)) + if (child.content_rect().contains(point)) return const_cast<Widget*>(&child); } return nullptr; @@ -811,4 +811,21 @@ void Widget::did_end_inspection() update(); } +void Widget::set_content_margins(const Margins& margins) +{ + if (m_content_margins == margins) + return; + m_content_margins = margins; + invalidate_layout(); +} + +Gfx::Rect Widget::content_rect() const +{ + auto rect = relative_rect(); + rect.move_by(m_content_margins.left(), m_content_margins.top()); + rect.set_width(rect.width() - (m_content_margins.left() + m_content_margins.right())); + rect.set_height(rect.height() - (m_content_margins.top() + m_content_margins.bottom())); + return rect; +} + } diff --git a/Libraries/LibGUI/Widget.h b/Libraries/LibGUI/Widget.h index a90f28c850..8023558271 100644 --- a/Libraries/LibGUI/Widget.h +++ b/Libraries/LibGUI/Widget.h @@ -30,6 +30,7 @@ #include <LibCore/Object.h> #include <LibGUI/Event.h> #include <LibGUI/Forward.h> +#include <LibGUI/Margins.h> #include <LibGfx/Color.h> #include <LibGfx/Forward.h> #include <LibGfx/Orientation.h> @@ -266,6 +267,11 @@ public: Gfx::Palette palette() const; void set_palette(const Gfx::Palette&); + const Margins& content_margins() const { return m_content_margins; } + void set_content_margins(const Margins&); + + Gfx::Rect content_rect() const; + protected: Widget(); @@ -324,6 +330,7 @@ private: SizePolicy m_horizontal_size_policy { SizePolicy::Fill }; SizePolicy m_vertical_size_policy { SizePolicy::Fill }; Gfx::Size m_preferred_size; + Margins m_content_margins; bool m_fill_with_background_color { false }; bool m_visible { true }; |