Loading...
Searching...
No Matches
TabbedPanel.h
Go to the documentation of this file.
1//
2// TabbedPanel.h
3//
4
5#ifndef MALENA_TABBEDPANEL_H
6#define MALENA_TABBEDPANEL_H
7
8#pragma once
9
12#include <Malena/Core/Core.h>
22#include <functional>
23#include <memory>
24#include <string>
25#include <vector>
26#include <type_traits>
30
31namespace ml
32{
34 {
35 public:
36 enum class Flag {};
37 enum class State {};
38 };
39
79 class MALENA_API TabbedPanel : public ComponentWith<TabbedPanelManifest>,
81 public TabbedPanelTheme,
82 public Themeable
83 {
84 public:
88
89 private:
90
91 std::vector<Tab> _tabs;
92 int _activeIdx = -1;
93 int _hoveredIdx = -1;
94
95 sf::Vector2f _position = {0.f, 0.f};
96 sf::Vector2f _size = {400.f, 300.f};
97
98 // Content whose unique_ptr was transferred out during event dispatch is
99 // held here until the next onUpdate tick, preventing use-after-free when
100 // the EventManager's CLICK loop continues past a just-closed tab.
101 std::vector<std::unique_ptr<ml::Core>> _pendingDelete;
102
103 std::function<void(std::size_t, const std::string&)> _onTabChanged;
104 std::function<void(std::size_t, const std::string&)> _onTabClosed;
105
106 // ── Internal ──────────────────────────────────────────────────────────
107 void computeTabLayout();
108 int hitTestStrip(const sf::Vector2f& wp) const;
109 bool hitTestClose(int tabIdx, const sf::Vector2f& wp) const;
110
111 // Geometry helpers
112 sf::FloatRect stripRect() const;
113 sf::FloatRect contentRect() const;
114 sf::Vector2f stripAxis() const;
115
116 void drawStrip(sf::RenderTarget& target, const sf::RenderStates& states) const;
117 void drawTab(sf::RenderTarget& target, const sf::RenderStates& states,
118 int idx, bool active, bool hovered) const;
119
120 protected:
121 void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
122 void onThemeApplied(const Theme& theme) override;
123
124 public:
126
127 TabbedPanel(const TabbedPanel&) = delete;
129
130 // ── Apply ─────────────────────────────────────────────────────────────
131
132 template<typename S>
133 void applySettings(const S& s)
134 {
135 static_assert(std::is_base_of_v<TabbedPanelSettings, S>,
136 "applySettings() requires TabbedPanelSettings");
137 static_cast<TabbedPanelSettings&>(*this) = s;
138 computeTabLayout();
139 }
140
141 template<typename T>
142 void applyTheme(const T& t)
143 {
144 static_assert(std::is_base_of_v<TabbedPanelTheme, T>,
145 "applyTheme() requires TabbedPanelTheme");
146 static_cast<TabbedPanelTheme&>(*this) = t;
147 }
148
149 template<typename St>
150 void applyStyle(const St& s)
151 {
152 static_assert(std::is_base_of_v<TabbedPanelSettings, St> &&
153 std::is_base_of_v<TabbedPanelTheme, St>,
154 "applyStyle() requires TabbedPanelSettings and TabbedPanelTheme");
155 static_cast<TabbedPanelSettings&>(*this) = s;
156 static_cast<TabbedPanelTheme&>(*this) = s;
157 computeTabLayout();
158 }
159
160 // ── Tab management ────────────────────────────────────────────────────
161
168 void addTab(Tab tab);
169
185 template<typename T>
186 T& addTab(const std::string& label,
187 std::unique_ptr<T> content,
188 const sf::Texture* icon = nullptr,
189 bool closeable = false)
190 {
191 T* ptr = content.get();
192 addTab(Tab(label, std::move(content), icon, closeable));
193 return *ptr;
194 }
195
203 void removeTab(std::size_t index);
204
206 void selectTab(std::size_t index);
207
209 [[nodiscard]] int activeTab() const { return _activeIdx; }
210
212 [[nodiscard]] std::size_t tabCount() const { return _tabs.size(); }
213
226 [[nodiscard]] sf::Vector2f contentSize() const;
227
228 // ── Callbacks ─────────────────────────────────────────────────────────
229
231 void onTabChanged(std::function<void(std::size_t, const std::string&)> cb);
232
234 void onTabClosed(std::function<void(std::size_t, const std::string&)> cb);
235
236 // ── Size / position ───────────────────────────────────────────────────
237
238 void setSize(const sf::Vector2f& size);
239 [[nodiscard]] sf::Vector2f getSize() const { return _size; }
240
241 void setPosition(const sf::Vector2f& position) override;
242 sf::Vector2f getPosition() const override;
244
245 };
246
247 template<typename MANIFEST>
248 class TabbedPanelWith : public TabbedPanel, public Customizable<MANIFEST>
249 { public: using TabbedPanel::TabbedPanel; };
250
251} // namespace ml
252#endif // MALENA_TABBEDPANEL_H
static const sf::Font & getDefault()
Return the built-in Arial font.
Base class for all Malena manifests.
Definition Manifest.h:51
A single tab entry for TabbedPanel.
Definition Tab.h:40
T & addTab(const std::string &label, std::unique_ptr< T > content, const sf::Texture *icon=nullptr, bool closeable=false)
Convenience overload — constructs a Tab with owned content inline.
TabbedPanelSettings::TabPosition TabPosition
Definition TabbedPanel.h:87
sf::FloatRect getGlobalBounds() const override
TabbedPanel(const TabbedPanel &)=delete
void applySettings(const S &s)
void addTab(Tab tab)
Add a pre-built Tab.
TabbedPanel & operator=(const TabbedPanel &)=delete
sf::Vector2f contentSize() const
Return the content area size.
void draw(sf::RenderTarget &target, sf::RenderStates states) const override
TabbedPanel(const sf::Font &font=FontManager<>::getDefault())
TabbedPanelManifest::State State
Definition TabbedPanel.h:86
void onTabClosed(std::function< void(std::size_t, const std::string &)> cb)
Fired when a tab is closed via the × button.
void selectTab(std::size_t index)
Programmatically select a tab by index.
void applyStyle(const St &s)
TabbedPanelManifest::Flag Flag
Definition TabbedPanel.h:85
sf::Vector2f getPosition() const override
void onThemeApplied(const Theme &theme) override
Called by ThemeManager when the active theme changes.
int activeTab() const
Return the currently active tab index, or -1 if no tabs.
std::size_t tabCount() const
Return the number of tabs.
sf::Vector2f getSize() const
void setPosition(const sf::Vector2f &position) override
void setSize(const sf::Vector2f &size)
void onTabChanged(std::function< void(std::size_t, const std::string &)> cb)
Fired when the active tab changes.
void removeTab(std::size_t index)
Remove a tab by index.
void applyTheme(const T &t)
TabbedPanel(const sf::Font &font=FontManager<>::getDefault())
Component< M, Traits... > ComponentWith
Alias for Component<M, Traits...>.
Definition Component.h:316
#define MALENA_API
Definition Component.h:22
Rect< float > FloatRect
Vector2< float > Vector2f
const sf::Font * font
bool closeable
show × on all tabs by default
Universal design token set applied across all Themeable components.
Definition Theme.h:70