Loading...
Searching...
No Matches
SplitPanel.h
Go to the documentation of this file.
1//
2// SplitPanel.h
3//
4
5#ifndef MALENA_SPLITPANEL_H
6#define MALENA_SPLITPANEL_H
7
8#pragma once
9
12#include <Malena/Core/Core.h>
20#include <functional>
21#include <memory>
22#include <vector>
23#include <type_traits>
26
27namespace ml
28{
30 {
31 public:
32 enum class Flag {};
33 enum class State { IDLE, DIVIDER_HOVER, DIVIDER_DRAG };
34 };
35
81 class MALENA_API SplitPanel : public ComponentWith<SplitPanelManifest>,
82 public SplitPanelSettings,
83 public SplitPanelTheme,
84 public Themeable
85 {
86 public:
91
92 private:
93 struct Pane
94 {
95 std::unique_ptr<ml::Core> content;
96 std::function<void(sf::Vector2f)> resizeFn;
97 float size = 0.f;
98 float minSize = 0.f;
99 float maxSize = 0.f;
100 };
101
102 std::vector<Pane> _panes;
103
104 sf::Vector2f _position = {0.f, 0.f};
105 sf::Vector2f _size = {400.f, 300.f};
106
107 int _hoveredDivider = -1;
108 int _draggingDiv = -1;
109 float _dragStartMouse = 0.f;
110 float _dragStartSizeA = 0.f;
111 float _dragStartSizeB = 0.f;
112 bool _prevMouseDown = false;
113
114 std::function<void(std::size_t, float)> _onDividerMoved;
115
116 // ── Internal ──────────────────────────────────────────────────────────
117 float totalAvailable() const;
118 float dividerPos(int divIdx) const;
119 int hitTestDivider(const sf::Vector2f& wp) const;
120 void layoutPanes();
121 void distributeSizes();
122 void drawDivider(sf::RenderTarget& target,
123 const sf::RenderStates& states,
124 int divIdx, bool hovered, bool dragging) const;
125
126 protected:
127 void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
128 void onThemeApplied(const Theme& theme) override;
129
130 public:
131 explicit SplitPanel(Orientation orientation = Orientation::HORIZONTAL,
133
134 SplitPanel(const SplitPanel&) = delete;
135 SplitPanel& operator=(const SplitPanel&) = delete;
136
137 // ── Apply ─────────────────────────────────────────────────────────────
138
139 template<typename S>
140 void applySettings(const S& s)
141 {
142 static_assert(std::is_base_of_v<SplitPanelSettings, S>,
143 "applySettings() requires SplitPanelSettings");
144 static_cast<SplitPanelSettings&>(*this) = s;
145 layoutPanes();
146 }
147
148 template<typename T>
149 void applyTheme(const T& t)
150 {
151 static_assert(std::is_base_of_v<SplitPanelTheme, T>,
152 "applyTheme() requires SplitPanelTheme");
153 static_cast<SplitPanelTheme&>(*this) = t;
154 }
155
156 template<typename St>
157 void applyStyle(const St& s)
158 {
159 static_assert(std::is_base_of_v<SplitPanelSettings, St> &&
160 std::is_base_of_v<SplitPanelTheme, St>,
161 "applyStyle() requires SplitPanelSettings and SplitPanelTheme");
162 static_cast<SplitPanelSettings&>(*this) = s;
163 static_cast<SplitPanelTheme&>(*this) = s;
164 layoutPanes();
165 }
166
167 // ── Pane management ───────────────────────────────────────────────────
168
182 template<typename T>
183 T& addPane(std::unique_ptr<T> content, float initialSize = 0.f)
184 {
185 static_assert(std::is_base_of_v<ml::Core, T>,
186 "addPane() content must derive from ml::Core");
187
188 T* ptr = content.get();
189
190 Pane pane;
191 pane.content = std::move(content);
192 pane.size = initialSize;
193
194 if constexpr (detail::has_setSize<T>::value)
195 pane.resizeFn = [ptr](sf::Vector2f sz){ ptr->setSize(sz); };
196
197 _panes.push_back(std::move(pane));
198 distributeSizes();
199 layoutPanes();
200
201 return *ptr;
202 }
203
205 void setPaneMinSize(std::size_t index, float minSize);
206
208 void setPaneMaxSize(std::size_t index, float maxSize);
209
211 void setDividerPosition(std::size_t dividerIndex, float position);
212
214 [[nodiscard]] std::size_t paneCount() const { return _panes.size(); }
215
216 // ── Callback ─────────────────────────────────────────────────────────
217
219 void onDividerMoved(std::function<void(std::size_t, float)> cb);
220
221 // ── Size / position ───────────────────────────────────────────────────
222
223 void setSize(const sf::Vector2f& size);
224 [[nodiscard]] sf::Vector2f getSize() const { return _size; }
225
226 void setPosition(const sf::Vector2f& position) override;
227 sf::Vector2f getPosition() const override;
229 };
230
231 template<typename MANIFEST>
232 class SplitPanelWith : public SplitPanel, public Customizable<MANIFEST>
233 { public: using SplitPanel::SplitPanel; };
234
235} // namespace ml
236#endif // MALENA_SPLITPANEL_H
static const sf::Font & getDefault()
Return the built-in Arial font.
Base class for all Malena manifests.
Definition Manifest.h:51
void setDividerPosition(std::size_t dividerIndex, float position)
Programmatically set a divider position.
SplitPanel(Orientation orientation=Orientation::HORIZONTAL, const sf::Font &font=FontManager<>::getDefault())
sf::Vector2f getSize() const
Definition SplitPanel.h:224
void setPosition(const sf::Vector2f &position) override
SplitPanelSettings::Orientation Orientation
Definition SplitPanel.h:89
SplitPanel(const SplitPanel &)=delete
void applyTheme(const T &t)
Definition SplitPanel.h:149
sf::Vector2f getPosition() const override
void draw(sf::RenderTarget &target, sf::RenderStates states) const override
void onDividerMoved(std::function< void(std::size_t, float)> cb)
Fired whenever a divider is moved (by drag or API).
void applyStyle(const St &s)
Definition SplitPanel.h:157
void setPaneMaxSize(std::size_t index, float maxSize)
Set the maximum size of a pane by index.
T & addPane(std::unique_ptr< T > content, float initialSize=0.f)
Add a pane with owned content.
Definition SplitPanel.h:183
SplitPanelManifest::State State
Definition SplitPanel.h:88
SplitPanelSettings::HandleStyle HandleStyle
Definition SplitPanel.h:90
void applySettings(const S &s)
Definition SplitPanel.h:140
SplitPanelManifest::Flag Flag
Definition SplitPanel.h:87
SplitPanel & operator=(const SplitPanel &)=delete
void setPaneMinSize(std::size_t index, float minSize)
Set the minimum size of a pane by index.
sf::FloatRect getGlobalBounds() const override
void setSize(const sf::Vector2f &size)
std::size_t paneCount() const
Return the number of panes.
Definition SplitPanel.h:214
void onThemeApplied(const Theme &theme) override
Called by ThemeManager when the active theme changes.
SplitPanel(Orientation orientation=Orientation::HORIZONTAL, const sf::Font &font=FontManager<>::getDefault())
Component< M, Traits... > ComponentWith
Alias for Component<M, Traits...>.
Definition Component.h:299
#define MALENA_API
Definition Component.h:22
Rect< float > FloatRect
Vector2< float > Vector2f
const sf::Font * font
Universal design token set applied across all Themeable components.
Definition Theme.h:70