10#include "structure/container/spk_expected.hpp"
11#include "structure/math/spk_vector2.hpp"
12#include "structure/widget/spk_icon_button.hpp"
13#include "structure/widget/spk_linear_layout.hpp"
14#include "structure/widget/spk_text_edit.hpp"
15#include "structure/widget/spk_widget.hpp"
19 template <
typename TType>
32 static_assert(std::is_arithmetic_v<TType>,
"NumericSpinBox requires an arithmetic type.");
68 spk::HorizontalLayout _layout;
80 uint32_t _minimalTextEditSize = 0;
83 static bool _isEmptyOrSignOnly(
const std::wstring &p_text)
85 if (p_text.empty() ==
true)
90 if (p_text == L
"-" || p_text == L
"+")
95 if constexpr (std::is_floating_point_v<value_type>)
97 if (p_text == L
"." || p_text == L
"-." || p_text == L
"+.")
108 return (p_result.reportStatus().value() != ValidationState::Valid);
121 parsed.reportStatus().value(),
122 parsed.reportStatus().status());
125 static ParseResult _parseValue(
const std::wstring &p_text)
127 if (_isEmptyOrSignOnly(p_text) ==
true)
129 return _makeParseError(ValidationState::Undefined, L
"NumericSpinBox value is undefined.");
132 if constexpr (std::is_unsigned_v<value_type>)
134 if (p_text.empty() ==
false && p_text.front() == L
'-')
136 return _makeParseError(ValidationState::Invalid, L
"Unsigned NumericSpinBox does not accept negative values.");
141 if constexpr (std::is_integral_v<value_type>)
144 narrow.reserve(p_text.size());
145 for (
wchar_t c : p_text)
149 return _makeParseError(ValidationState::Invalid, L
"NumericSpinBox value contains invalid characters.");
151 narrow.push_back(
static_cast<char>(c));
155 const char *begin = narrow.data();
156 const char *end = narrow.data() + narrow.size();
158 auto [ptr, ec] = std::from_chars(begin, end, v, 10);
159 if (ec != std::errc() || ptr != end)
161 return _makeParseError(ValidationState::Invalid, L
"Failed to parse NumericSpinBox value.");
164 return ParseResult(v, ValidationState::Valid, L
"");
169 std::wistringstream stream(p_text);
173 if (stream.fail() ==
true)
175 return _makeParseError(ValidationState::Invalid, L
"Failed to parse NumericSpinBox value.");
179 if (stream.eof() ==
false)
181 return _makeParseError(ValidationState::Invalid, L
"NumericSpinBox value contains invalid characters.");
184 return ParseResult(v, ValidationState::Valid, L
"");
188 static std::wstring _formatValue(
const value_type &p_value)
191 return std::to_wstring(p_value);
194 void _syncValueFromTextIfValid()
196 const ParseResult parsed = _parseValue(_valueEdit.text());
197 if (_hasError(parsed) ==
false)
199 _value = parsed.value();
212 _layout.setGeometry(
geometry().atOrigin());
222 spk::
Widget(p_name, p_parent),
223 _valueEdit(p_name + L
"/TextEdit", this),
224 _raiseButton(p_name + L
"/RaiseButton", this),
225 _lowerButton(p_name + L
"/LowerButton", this)
227 _layout.addElement(&_valueEdit, spk::Layout::SizePolicy::Extend);
228 _layout.addElement(&_lowerButton, spk::Layout::SizePolicy::Desired);
229 _layout.addElement(&_raiseButton, spk::Layout::SizePolicy::Desired);
231 _valueEdit.activate();
232 _raiseButton.activate();
233 _lowerButton.activate();
238 _raiseButton.setIconSpriteID({5, 0});
239 _lowerButton.setIconSpriteID({4, 0});
241 _raiseButton.setIconPadding({2, 2});
242 _lowerButton.setIconPadding({2, 2});
244 _valueEdit.setValidationCallback([
this](
const std::wstring &p_text) {
245 return _validateTextForTextEdit(p_text);
248 _onTextEditionContract = _valueEdit.subscribeToEdition([
this](
const std::wstring &) {
249 _syncValueFromTextIfValid();
252 _raiseContract = _raiseButton.subscribe([
this]() {
255 _lowerContract = _lowerButton.subscribe([
this]() {
262 return _layout.sizeHint().minimal();
266 return _layout.sizeHint().maximal();
270 return _layout.sizeHint().desired();
281 return _value.onEdition().subscribe(p_job);
290 _valueEdit.sizeHint().release();
291 spk::Vector2UInt minimalTextSize = _valueEdit.sizeHint().minimal();
292 _valueEdit.sizeHint().setMinimal({std::max(minimalTextSize.
x, p_minimalTextEditSize), minimalTextSize.
y});
294 _layout.sizeHint().release();
307 _valueEdit.setText(_formatValue(_value));
309 _layout.sizeHint().release();
393 using FloatSpinBox = NumericSpinBox<float>;
394 using IntSpinBox = NumericSpinBox<int>;
395 using UnsignedIntSpinBox = NumericSpinBox<unsigned int>;
Carries a value alongside a task report status.
Definition spk_expected.hpp:24
static Expected generateReport(const ValidationState &p_reportStatusID, const std::wstring &p_reportStatusMessage)
Definition spk_expected.hpp:69
void increase()
Increases the value by the current step.
Definition spk_numeric_spin_box.hpp:343
spk::TextEdit::ValidationCallback ValidationCallback
Validation callback type for the text edit.
Definition spk_numeric_spin_box.hpp:51
void setValue(const value_type &p_value)
Sets the current numeric value.
Definition spk_numeric_spin_box.hpp:302
IconButton & lowerButton()
Returns the decrement button.
Definition spk_numeric_spin_box.hpp:387
spk::ObservableValue< value_type >::Contract EditionContract
Edition contract type for value changes.
Definition spk_numeric_spin_box.hpp:60
EditionContract subscribeToEdition(const EditionJob &p_job)
Subscribes to value edition notifications.
Definition spk_numeric_spin_box.hpp:279
TextEdit & valueEdit()
Returns the value text edit.
Definition spk_numeric_spin_box.hpp:360
spk::TextEdit::ValidationState ValidationState
Validation state type for the text edit.
Definition spk_numeric_spin_box.hpp:43
IconButton & raiseButton()
Returns the increment button.
Definition spk_numeric_spin_box.hpp:378
const TextEdit & valueEdit() const
Returns the value text edit.
Definition spk_numeric_spin_box.hpp:369
void _onGeometryChange() override
Updates layout geometry when size changes.
Definition spk_numeric_spin_box.hpp:207
void setMinimalTextEditSize(uint32_t p_minimalTextEditSize)
Sets the minimal width of the text edit field.
Definition spk_numeric_spin_box.hpp:288
void setStep(const value_type &p_step)
Sets the increment/decrement step.
Definition spk_numeric_spin_box.hpp:326
spk::TextEdit::ValidationStatus ValidationStatus
Validation status type for the text edit.
Definition spk_numeric_spin_box.hpp:47
const value_type & value() const
Returns the current numeric value.
Definition spk_numeric_spin_box.hpp:317
NumericSpinBox(const std::wstring &p_name, spk::Widget *p_parent)
Builds a numeric spin box widget.
Definition spk_numeric_spin_box.hpp:221
TType value_type
Underlying numeric value type.
Definition spk_numeric_spin_box.hpp:38
void decrease()
Decreases the value by the current step.
Definition spk_numeric_spin_box.hpp:351
const value_type & step() const
Returns the increment/decrement step.
Definition spk_numeric_spin_box.hpp:335
spk::ObservableValue< value_type >::Job EditionJob
Edition job type for value changes.
Definition spk_numeric_spin_box.hpp:56
spk::Expected< value_type, ValidationState > ParseResult
Parse result type for numeric text.
Definition spk_numeric_spin_box.hpp:65
Stores a value and notifies subscribers whenever it changes.
Definition spk_observable_value.hpp:22
spk::TContractProvider< TType >::Contract Contract
Contract type for subscriptions.
Definition spk_observable_value.hpp:27
spk::TContractProvider< TType >::Job Job
Job type dispatched on updates.
Definition spk_observable_value.hpp:31
void configureMaximalGenerator(Generator p_generator)
Configures the maximal size generator.
Definition spk_resizable_element.cpp:31
void configureDesiredGenerator(Generator p_generator)
Configures the desired size generator.
Definition spk_resizable_element.cpp:26
void release()
Releases all cached size hint values.
Definition spk_resizable_element.cpp:36
void configureMinimalGenerator(Generator p_generator)
Configures the minimal size generator.
Definition spk_resizable_element.cpp:21
SizeHint & sizeHint()
Returns mutable size hint data.
Definition spk_resizable_element.cpp:86
Editable text field with validation and cursor handling.
Definition spk_text_edit.hpp:29
spk::ObservableValue< std::wstring >::Contract EditionContract
Edition contract type for text changes.
Definition spk_text_edit.hpp:54
ValidationState
Validation state of the text content.
Definition spk_text_edit.hpp:36
spk::TaskResult< ValidationState > ValidationStatus
Validation status result type.
Definition spk_text_edit.hpp:44
std::function< ValidationStatus(const std::wstring &)> ValidationCallback
Validation callback signature.
Definition spk_text_edit.hpp:49
TType x
X component.
Definition spk_vector2.hpp:44
TType y
Y component.
Definition spk_vector2.hpp:48