Serenity Operating System
1/*
2 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
3 * Copyright (c) 2022, the SerenityOS developers.
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#pragma once
9
10#include <LibGUI/Widget.h>
11
12namespace GUI {
13
14class Splitter : public Widget {
15 C_OBJECT(Splitter);
16
17public:
18 enum class OpportunisticResizee {
19 First,
20 Second
21 };
22
23 virtual ~Splitter() override = default;
24
25protected:
26 explicit Splitter(Gfx::Orientation);
27
28 virtual void paint_event(PaintEvent&) override;
29 virtual void resize_event(ResizeEvent&) override;
30 virtual void mousedown_event(MouseEvent&) override;
31 virtual void mousemove_event(MouseEvent&) override;
32 virtual void mouseup_event(MouseEvent&) override;
33 virtual void leave_event(Core::Event&) override;
34
35 virtual void did_layout() override;
36 virtual void custom_layout() override;
37
38 OpportunisticResizee opportunisitic_resizee() const { return m_opportunistic_resizee; }
39 void set_opportunisitic_resizee(OpportunisticResizee resizee) { m_opportunistic_resizee = resizee; }
40
41private:
42 void override_cursor(bool do_override);
43 Gfx::IntRect rect_between_widgets(GUI::Widget const& first_widget, GUI::Widget const& second_widget, bool honor_grabbable_margins) const;
44
45 Gfx::Orientation m_orientation;
46 bool m_resizing { false };
47 bool m_overriding_cursor { false };
48 Gfx::IntPoint m_resize_origin;
49 WeakPtr<Widget> m_first_resizee;
50 WeakPtr<Widget> m_second_resizee;
51 Gfx::IntSize m_first_resizee_start_size;
52 Gfx::IntSize m_second_resizee_start_size;
53 OpportunisticResizee m_opportunistic_resizee { OpportunisticResizee::Second };
54 size_t m_last_child_count { 0 };
55 int m_first_resizee_max_size { 0 };
56 int m_second_resizee_max_size { 0 };
57
58 void recompute_grabbables();
59
60 struct Grabbable {
61 // Index in m_grabbables, for convenience.
62 size_t index { 0 };
63
64 // The full grabbable rect, includes the content margin of adjacent elements.
65 Gfx::IntRect grabbable_rect;
66 // The rect used for painting. Does not include content margins.
67 Gfx::IntRect paint_rect;
68
69 WeakPtr<Widget> first_widget;
70 WeakPtr<Widget> second_widget;
71 };
72
73 Grabbable* grabbable_at(Gfx::IntPoint);
74 void set_hovered_grabbable(Grabbable*);
75
76 Vector<Grabbable> m_grabbables;
77 Optional<size_t> m_hovered_index;
78};
79
80class VerticalSplitter final : public Splitter {
81 C_OBJECT(VerticalSplitter)
82public:
83 virtual ~VerticalSplitter() override = default;
84
85private:
86 VerticalSplitter()
87 : Splitter(Gfx::Orientation::Vertical)
88 {
89 }
90};
91
92class HorizontalSplitter final : public Splitter {
93 C_OBJECT(HorizontalSplitter)
94public:
95 virtual ~HorizontalSplitter() override = default;
96
97private:
98 HorizontalSplitter()
99 : Splitter(Gfx::Orientation::Horizontal)
100 {
101 }
102};
103
104}