summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-04-24 18:55:29 +0200
committerAndreas Kling <kling@serenityos.org>2020-04-24 19:05:02 +0200
commit42f0b2522b6e24e0269265597cebfda9f0b7b329 (patch)
treeccdabd18cf6bee50fde21912d2204cfff4394728
parent9badcff1bab051e0dfb50d6dd9c7775a4f1d3af3 (diff)
downloadserenity-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.cpp8
-rw-r--r--Libraries/LibGUI/Frame.h2
-rw-r--r--Libraries/LibGUI/MultiView.cpp1
-rw-r--r--Libraries/LibGUI/Splitter.cpp37
-rw-r--r--Libraries/LibGUI/Widget.cpp19
-rw-r--r--Libraries/LibGUI/Widget.h7
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 };