Loading...
Searching...
No Matches
Select.h
Go to the documentation of this file.
1//
2// Select.h
3//
4
5#ifndef MALENA_SELECT_H
6#define MALENA_SELECT_H
7
8#pragma once
9
12#include <Malena/Core/Core.h>
23#include <functional>
24#include <string>
25#include <vector>
26#include <memory>
27#include <optional>
28#include <type_traits>
29
30namespace ml
31{
33 {
34 public:
35 enum class Flag { OPEN };
36 enum class State { IDLE, HOVERED, OPEN }; // disabled is derived from ml::Flag::ENABLED
37 };
38
40 {
41 std::optional<sf::Color> color;
42 std::optional<sf::Color> bgColor;
43 std::optional<const sf::Font*> font;
44 std::optional<unsigned int> charSize;
45 std::optional<bool> bold;
46 std::optional<bool> italic;
47 std::string description;
48 std::optional<sf::Color> descColor;
49 std::optional<unsigned int> descCharSize;
50 const sf::Texture* iconTexture = nullptr;
52 sf::Vector2f iconSize = {0.f, 0.f};
53 };
54
56 {
57 std::string label;
58 std::string value;
60 bool enabled = true;
61 bool selected = false;
63
64 explicit SelectOption(const std::string& label,
65 const std::string& value = "",
66 const SelectOptionStyle& style = {})
67 : label(label), value(value.empty() ? label : value), style(style) {}
68
69 explicit SelectOption(ml::Core& component, const std::string& value = "")
70 : label(""), value(value), customComponent(&component) {}
71 };
72
82 class MALENA_API Select : public ComponentWith<SelectManifest>,
83 public SelectSettings,
84 public SelectTheme,
85 public Themeable
86 {
87 public:
90
91 private:
92 std::vector<SelectOption> _options;
93 int _selectedIndex = -1;
94
95 sf::RectangleShape _trigger;
96 sf::Text _triggerLabel;
97 sf::Text _arrow;
98 std::string _placeholder = "Select...";
99 sf::Vector2f _position = {0.f, 0.f};
100
101 sf::RectangleShape _panel;
102 float _scrollOffset = 0.f;
103 mutable sf::RenderTexture _panelCanvas;
104 mutable int _hoveredIndex = -1;
105 ml::Core* _prevExclusiveOwner = nullptr; // restored on close
106 ml::Core* _prevPopup = nullptr; // top-layer popup restored on close
107 mutable bool _openAbove = false;
108 bool _prevDown = false;
109
110 std::function<void(const std::string&, std::size_t)> _onSelectionChanged;
111 std::function<void()> _onOpen;
112 std::function<void()> _onClose;
113
114 void syncTrigger();
115 void syncTriggerColors();
116 void syncPanel();
117 void openPanel();
118 void closePanel();
119 void commitSelection(int index);
120 void resizePanelCanvas();
121
122 float panelHeight() const;
123 float panelY() const;
124
125 int hitTestPanel(const sf::Vector2f& worldPos) const;
126 void drawOption(sf::RenderTarget& target,
127 const sf::RenderStates& states,
128 const SelectOption& option,
129 float itemY, bool hovered, bool selected) const;
130
131 protected:
132 void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
133 void onEnabledChanged(bool enabled) override; // close dropdown + refresh colors
134 void onThemeApplied(const Theme& theme) override;
135
136 public:
138 ~Select() override;
139
140 // ── Apply ─────────────────────────────────────────────────────────────
141
142 template<typename S>
143 void applySettings(const S& s)
144 {
145 static_assert(std::is_base_of_v<SelectSettings, S>,
146 "applySettings() requires a type derived from SelectSettings");
147 static_cast<SelectSettings&>(*this) = s;
148 syncTrigger();
149 }
150
151 template<typename T>
152 void applyTheme(const T& t)
153 {
154 static_assert(std::is_base_of_v<SelectTheme, T>,
155 "applyTheme() requires a type derived from SelectTheme");
156 static_cast<SelectTheme&>(*this) = t;
157 syncTriggerColors();
158 }
159
160 template<typename St>
161 void applyStyle(const St& s)
162 {
163 static_assert(std::is_base_of_v<SelectSettings, St> &&
164 std::is_base_of_v<SelectTheme, St>,
165 "applyStyle() requires SelectSettings and SelectTheme");
166 static_cast<SelectSettings&>(*this) = s;
167 static_cast<SelectTheme&>(*this) = s;
168 syncTrigger();
169 }
170
171 // ── Adding options ────────────────────────────────────────────────────
172
173 void addOption(const std::string& label,
174 const std::string& value = "",
175 const SelectOptionStyle& style = {});
176 void add(ml::Core& component, const std::string& value = "");
178 [[nodiscard]] std::size_t optionCount() const;
179
180 // ── Selection ─────────────────────────────────────────────────────────
181
182 void selectIndex(std::size_t index);
183 void selectValue(const std::string& value);
185 [[nodiscard]] int getSelectedIndex() const;
186 [[nodiscard]] std::string getSelectedLabel() const;
187 [[nodiscard]] std::string getSelectedValue() const;
188
189 // ── Open / close ──────────────────────────────────────────────────────
190
191 void open();
192 void close();
193 [[nodiscard]] bool isOpen() const;
194
195 // ── Callback ─────────────────────────────────────────────────────────
196
198 std::function<void(const std::string&, std::size_t)> callback);
199
201 void onOpen(std::function<void()> callback);
202 void onClose(std::function<void()> callback);
203
204 // ── Misc ──────────────────────────────────────────────────────────────
205
206 void setPlaceholder(const std::string& text);
207 [[nodiscard]] std::string getPlaceholder() const;
208
209 void setOptionEnabled(std::size_t index, bool enabled);
210
211 void setFont(const sf::Font& f);
212 void setFont(const sf::Font&&) = delete;
213 [[nodiscard]] unsigned int getCharacterSize() const;
214
215 // ── Positionable ──────────────────────────────────────────────────────
216
217 void setPosition(const sf::Vector2f& position) override;
218 sf::Vector2f getPosition() const override;
220 };
221
222 template<typename MANIFEST>
223 class SelectWith : public Select, public Customizable<MANIFEST>
224 { public: using Select::Select; };
225
226} // namespace ml
227
228#endif // MALENA_SELECT_H
Virtual base class for all Malena framework objects.
Definition Core.h:97
static const sf::Font & getDefault()
Return the built-in Arial font.
Base class for all Malena manifests.
Definition Manifest.h:51
void onThemeApplied(const Theme &theme) override
Called by ThemeManager when the active theme changes.
void applySettings(const S &s)
Definition Select.h:143
void addOption(const std::string &label, const std::string &value="", const SelectOptionStyle &style={})
void draw(sf::RenderTarget &target, sf::RenderStates states) const override
void setPosition(const sf::Vector2f &position) override
void close()
void applyStyle(const St &s)
Definition Select.h:161
void selectValue(const std::string &value)
void clearOptions()
void onEnabledChanged(bool enabled) override
SelectManifest::State State
Definition Select.h:89
Select(const sf::Font &font=FontManager<>::getDefault())
std::string getSelectedValue() const
void clearSelection()
bool isOpen() const
~Select() override
sf::FloatRect getGlobalBounds() const override
SelectManifest::Flag Flag
Definition Select.h:88
void applyTheme(const T &t)
Definition Select.h:152
std::size_t optionCount() const
void onClose(std::function< void()> callback)
void open()
std::string getSelectedLabel() const
int getSelectedIndex() const
sf::Vector2f getPosition() const override
void selectIndex(std::size_t index)
void setPlaceholder(const std::string &text)
void onOpen(std::function< void()> callback)
void add(ml::Core &component, const std::string &value="")
void setFont(const sf::Font &f)
void setFont(const sf::Font &&)=delete
std::string getPlaceholder() const
unsigned int getCharacterSize() const
void onSelectionChanged(std::function< void(const std::string &, std::size_t)> callback)
void setOptionEnabled(std::size_t index, bool enabled)
Select(const sf::Font &font=FontManager<>::getDefault())
Component< M, Traits... > ComponentWith
Alias for Component<M, Traits...>.
Definition Component.h:323
@ HOVERED
Mouse is currently over this component (set by HoverableDispatcher).
Definition Flag.h:66
#define MALENA_API
Definition Animate.h:25
Rect< float > FloatRect
Rect< int > IntRect
Vector2< float > Vector2f
const sf::Font * font
SelectOption(const std::string &label, const std::string &value="", const SelectOptionStyle &style={})
Definition Select.h:64
std::string value
Definition Select.h:58
ml::Core * customComponent
Definition Select.h:62
SelectOption(ml::Core &component, const std::string &value="")
Definition Select.h:69
std::string label
Definition Select.h:57
SelectOptionStyle style
Definition Select.h:59
std::optional< unsigned int > charSize
Definition Select.h:44
std::string description
Definition Select.h:47
const sf::Texture * iconTexture
Definition Select.h:50
std::optional< sf::Color > color
Definition Select.h:41
std::optional< bool > italic
Definition Select.h:46
std::optional< bool > bold
Definition Select.h:45
std::optional< sf::Color > bgColor
Definition Select.h:42
sf::IntRect iconRect
Definition Select.h:51
sf::Vector2f iconSize
Definition Select.h:52
std::optional< sf::Color > descColor
Definition Select.h:48
std::optional< const sf::Font * > font
Definition Select.h:43
std::optional< unsigned int > descCharSize
Definition Select.h:49
Layout and behaviour settings for Select.
Color tokens for Select.
Definition SelectTheme.h:25
Universal design token set applied across all Themeable components.
Definition Theme.h:70