From 1fc887c5767cfced4df3af10d1f0d15685c1022f Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 11 Feb 2020 11:33:01 +0100 Subject: [PATCH] LibGUI: Only highlight grabbable area between a Splitter's children We were previously cheating by setting the entire splitter's background color to the hover highlight color. This looked goofy whenever there were transparent widgets inside a splitter, since the highlighted color would shine through when hovering. This was especially noticeable in SystemMonitor, which now looks much better. :^) --- Libraries/LibGUI/Splitter.cpp | 52 +++++++++++++++++++++++++++++++---- Libraries/LibGUI/Splitter.h | 6 ++++ 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/Libraries/LibGUI/Splitter.cpp b/Libraries/LibGUI/Splitter.cpp index 8783301267..5a7ca6dba8 100644 --- a/Libraries/LibGUI/Splitter.cpp +++ b/Libraries/LibGUI/Splitter.cpp @@ -24,10 +24,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include +#include #include #include +#include namespace GUI { @@ -45,19 +46,32 @@ Splitter::~Splitter() { } +void Splitter::paint_event(PaintEvent& event) +{ + Painter painter(*this); + painter.add_clip_rect(event.rect()); + painter.fill_rect(m_grabbable_rect, palette().hover_highlight()); +} + +void Splitter::resize_event(ResizeEvent& event) +{ + Frame::resize_event(event); + m_grabbable_rect = {}; +} + void Splitter::enter_event(Core::Event&) { - set_background_role(ColorRole::HoverHighlight); window()->set_override_cursor(m_orientation == Orientation::Horizontal ? StandardCursor::ResizeHorizontal : StandardCursor::ResizeVertical); - update(); } void Splitter::leave_event(Core::Event&) { - set_background_role(ColorRole::Button); if (!m_resizing) window()->set_override_cursor(StandardCursor::None); - update(); + if (!m_grabbable_rect.is_empty()) { + m_grabbable_rect = {}; + update(); + } } void Splitter::get_resize_candidates_at(const Gfx::Point& position, Widget*& first, Widget*& second) @@ -94,10 +108,30 @@ void Splitter::mousedown_event(MouseEvent& event) m_resize_origin = event.position(); } +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); + 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)); + if (m_grabbable_rect != rect) { + m_grabbable_rect = rect; + update(); + } +} + void Splitter::mousemove_event(MouseEvent& event) { - if (!m_resizing) + if (!m_resizing) { + Widget* first { nullptr }; + Widget* second { nullptr }; + get_resize_candidates_at(event.position(), first, second); + recompute_grabbable_rect(*first, *second); return; + } auto delta = event.position() - m_resize_origin; if (!m_first_resizee || !m_second_resizee) { // One or both of the resizees were deleted during an ongoing resize, screw this. @@ -130,6 +164,12 @@ void Splitter::mousemove_event(MouseEvent& event) invalidate_layout(); } +void Splitter::did_layout() +{ + if (m_first_resizee && m_second_resizee) + recompute_grabbable_rect(*m_first_resizee, *m_second_resizee); +} + void Splitter::mouseup_event(MouseEvent& event) { if (event.button() != MouseButton::Left) diff --git a/Libraries/LibGUI/Splitter.h b/Libraries/LibGUI/Splitter.h index 4cf876648c..1cf946b608 100644 --- a/Libraries/LibGUI/Splitter.h +++ b/Libraries/LibGUI/Splitter.h @@ -38,13 +38,18 @@ public: protected: Splitter(Orientation, Widget* parent); + virtual void paint_event(PaintEvent&) override; + virtual void resize_event(ResizeEvent&) override; virtual void mousedown_event(MouseEvent&) override; virtual void mousemove_event(MouseEvent&) override; virtual void mouseup_event(MouseEvent&) override; virtual void enter_event(Core::Event&) override; virtual void leave_event(Core::Event&) override; + virtual void did_layout() override; + private: + void recompute_grabbable_rect(const Widget&, const Widget&); void get_resize_candidates_at(const Gfx::Point&, Widget*&, Widget*&); Orientation m_orientation; @@ -54,6 +59,7 @@ private: WeakPtr m_second_resizee; Gfx::Size m_first_resizee_start_size; Gfx::Size m_second_resizee_start_size; + Gfx::Rect m_grabbable_rect; }; class VerticalSplitter final : public Splitter {