Selaa lähdekoodia

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! :^)
Andreas Kling 5 vuotta sitten
vanhempi
commit
42f0b2522b

+ 8 - 0
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)

+ 1 - 1
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; }

+ 1 - 0
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>();
 

+ 22 - 15
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();

+ 18 - 1
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;
+}
+
 }

+ 7 - 0
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 };