ttx 0.1.0
Loading...
Searching...
No Matches
layout.h
Go to the documentation of this file.
1#pragma once
2
3#include "di/container/tree/tree_set.h"
4#include "di/reflect/prelude.h"
5#include "di/vocab/pointer/box.h"
6#include "direction.h"
7#include "dius/tty.h"
8#include "ttx/pane.h"
9
10namespace ttx {
11struct LayoutNode;
12class LayoutGroup;
13
14// Represents the layout result for a single pane. The row and col
15// coordinates are absolute.
17 u32 row { 0 };
18 u32 col { 0 };
19 dius::tty::WindowSize size;
20 LayoutNode* parent { nullptr };
21 Pane* pane { nullptr };
22
23 auto operator==(LayoutEntry const&) const -> bool = default;
24
25 constexpr friend auto tag_invoke(di::Tag<di::reflect>, di::InPlaceType<LayoutEntry>) {
26 return di::make_fields<"LayoutEntry">(di::field<"row", &LayoutEntry::row>, di::field<"col", &LayoutEntry::col>,
27 di::field<"size", &LayoutEntry::size>,
28 di::field<"parent", &LayoutEntry::parent>,
29 di::field<"pane", &LayoutEntry::pane>);
30 }
31};
32
33// Represents a full layout tree. This is created by calling
34// LayoutGroup::layout().
35struct LayoutNode {
36 u32 row { 0 };
37 u32 col { 0 };
38 dius::tty::WindowSize size;
39 di::Vector<di::Variant<di::Box<LayoutNode>, LayoutEntry>> children;
40 LayoutNode* parent { nullptr };
41 LayoutGroup* group { nullptr };
43
44 auto find_pane(Pane* pane) -> di::Optional<LayoutEntry&>;
45 auto hit_test(u32 row, u32 col) -> di::Optional<LayoutEntry&>;
46
47 auto hit_test_horizontal_line(u32 row, u32 col_start, u32 col_end) -> di::TreeSet<LayoutEntry*>;
48 auto hit_test_vertical_line(u32 col, u32 row_start, u32 row_end) -> di::TreeSet<LayoutEntry*>;
49
50 constexpr friend auto tag_invoke(di::Tag<di::reflect>, di::InPlaceType<LayoutNode>) {
51 return di::make_fields<"LayoutNode">(
52 di::field<"row", &LayoutNode::row>, di::field<"col", &LayoutNode::col>,
53 di::field<"size", &LayoutNode::size>, di::field<"children", &LayoutNode::children>,
54 di::field<"parent", &LayoutNode::parent>, di::field<"group", &LayoutNode::group>,
55 di::field<"direction", &LayoutNode::direction>);
56 }
57};
58
59// Pane sizes are computed in units of this number of precision, using fixed point arithemetic.
60constexpr inline auto max_layout_precision = i64(100'000);
61
62// Represents a pane in a layout group. This includes extra metadata
63// necessary for layout.
64struct LayoutPane {
65 di::Box<Pane> pane {};
67};
68
75
76constexpr auto tag_invoke(di::Tag<di::reflect>, di::InPlaceType<ResizeDirection>) {
77 using enum ResizeDirection;
78 return di::make_enumerators<"ResizeDirection">(di::enumerator<"Left", Left>, di::enumerator<"Right", Right>,
79 di::enumerator<"Top", Top>, di::enumerator<"Bottom", Bottom>);
80}
81
82// Represents a group of panes in a hierarchy. Instead of using a strict binary tree,
83// we allow multiple children on a single level so that by default, splits made in
84// the same direction share space evenly.
86public:
87 constexpr auto direction() const -> Direction { return m_direction; }
88 constexpr auto empty() const -> bool { return m_children.empty(); }
89 constexpr auto single() const -> bool { return m_children.size() == 1; }
90 constexpr auto relative_size() -> i64& { return m_relative_size; }
91
92 // NOTE: this method returns the correct size for the new pane, and a lvalue reference where
93 // the caller should store its newly created Pane. We need this akward API so that we can
94 // create a Pane with a sane initial size.
95 auto split(dius::tty::WindowSize const& size, u32 row_offset, u32 col_offset, Pane* reference, Direction direction)
96 -> di::Tuple<di::Box<LayoutNode>, di::Optional<LayoutEntry&>, di::Optional<di::Box<Pane>&>>;
97
98 // NOTE: after removing a pane, calling layout() is necessary as any previous LayoutNode's may become invalid.
99 auto remove_pane(Pane* pane) -> di::Box<Pane>;
100
101 // NOTE: after resizing a pane, caling layout() is necessary for the change to take effect. This functions
102 // returns true if any change occurred.
103 auto resize(LayoutNode& root, Pane* pane, ResizeDirection direction, i32 amount_in_cells) -> bool;
104
105 // NOTE: in addition to computing the layout tree, Pane::resize() is called to inform each Pane of its (potentially)
106 // new size.
107 auto layout(dius::tty::WindowSize const& size, u32 row_offset, u32 col_offset) -> di::Box<LayoutNode>;
108
109private:
111
112 void redistribute_space(di::Variant<di::Box<LayoutGroup>, di::Box<LayoutPane>>* new_child,
113 i64 original_size_available, i64 new_size_available);
114 void validate_layout();
115
116 di::Vector<di::Variant<di::Box<LayoutGroup>, di::Box<LayoutPane>>> m_children;
117 i64 m_relative_size { max_layout_precision };
118 Direction m_direction { Direction::None };
119};
120}
Definition layout.h:85
constexpr auto empty() const -> bool
Definition layout.h:88
auto resize(LayoutNode &root, Pane *pane, ResizeDirection direction, i32 amount_in_cells) -> bool
Definition layout.cpp:372
constexpr auto relative_size() -> i64 &
Definition layout.h:90
constexpr auto direction() const -> Direction
Definition layout.h:87
friend struct FindPaneInLayoutGroup
Definition layout.h:110
auto split(dius::tty::WindowSize const &size, u32 row_offset, u32 col_offset, Pane *reference, Direction direction) -> di::Tuple< di::Box< LayoutNode >, di::Optional< LayoutEntry & >, di::Optional< di::Box< Pane > & > >
Definition layout.cpp:205
auto remove_pane(Pane *pane) -> di::Box< Pane >
Definition layout.cpp:275
constexpr auto single() const -> bool
Definition layout.h:89
Definition pane.h:29
Definition test_layout.cpp:6
Definition cursor_style.h:5
Direction
Definition direction.h:7
@ None
Definition direction.h:8
@ Right
Definition key.h:70
@ Left
Definition key.h:69
constexpr auto tag_invoke(di::Tag< di::reflect >, di::InPlaceType< CursorStyle >)
Definition cursor_style.h:16
constexpr auto max_layout_precision
Definition layout.h:60
ResizeDirection
Definition layout.h:69
@ Bottom
Definition layout.h:73
@ Top
Definition layout.h:72
Definition layout.h:16
LayoutNode * parent
Definition layout.h:20
u32 row
Definition layout.h:17
auto operator==(LayoutEntry const &) const -> bool=default
Pane * pane
Definition layout.h:21
u32 col
Definition layout.h:18
constexpr friend auto tag_invoke(di::Tag< di::reflect >, di::InPlaceType< LayoutEntry >)
Definition layout.h:25
dius::tty::WindowSize size
Definition layout.h:19
Definition layout.h:35
Direction direction
Definition layout.h:42
auto hit_test_horizontal_line(u32 row, u32 col_start, u32 col_end) -> di::TreeSet< LayoutEntry * >
Definition layout.cpp:118
LayoutGroup * group
Definition layout.h:41
u32 row
Definition layout.h:36
dius::tty::WindowSize size
Definition layout.h:38
di::Vector< di::Variant< di::Box< LayoutNode >, LayoutEntry > > children
Definition layout.h:39
auto hit_test_vertical_line(u32 col, u32 row_start, u32 row_end) -> di::TreeSet< LayoutEntry * >
Definition layout.cpp:97
auto hit_test(u32 row, u32 col) -> di::Optional< LayoutEntry & >
Definition layout.cpp:73
LayoutNode * parent
Definition layout.h:40
constexpr friend auto tag_invoke(di::Tag< di::reflect >, di::InPlaceType< LayoutNode >)
Definition layout.h:50
u32 col
Definition layout.h:37
auto find_pane(Pane *pane) -> di::Optional< LayoutEntry & >
Definition layout.cpp:53
Definition layout.h:64
i64 relative_size
Definition layout.h:66
di::Box< Pane > pane
Definition layout.h:65