1 #ifndef TERMOX_WIDGET_WIDGETS_NUMBER_EDIT_HPP
2 #define TERMOX_WIDGET_WIDGETS_NUMBER_EDIT_HPP
10 #include <signals_light/signal.hpp>
12 #include <termox/system/key.hpp>
13 #include <termox/system/mouse.hpp>
14 #include <termox/widget/align.hpp>
15 #include <termox/widget/pipe.hpp>
16 #include <termox/widget/widgets/detail/textline_base.hpp>
20 template <
typename Number_t>
24 Number_t min = Min_num;
25 Number_t max = Max_num;
31 Align alignment = Align::Left;
32 Action focus_in_action = Action::None;
33 Number_t increment = 1;
49 : Textline_base{std::to_string(
52 value_{std::clamp(initial,
range.min,
range.max)},
57 explicit Number_edit(Parameters p)
67 value_ = std::clamp(x, range_.min, range_.max);
68 core_.
set_text(std::to_string(value_));
73 [[nodiscard]]
auto value() const -> Number_t {
return value_; }
83 [[nodiscard]]
auto range() const ->
Range {
return range_; }
89 [[nodiscard]]
auto get_increment() const -> Number_t {
return increment_; }
95 Max_num - increment_ < value_
97 : std::clamp(value_ + increment_, range_.min, range_.max));
106 Min_num + increment_ > value_
108 : std::clamp(value_ - increment_, range_.min, range_.max));
117 case Key::Enter: this->validate_and_submit();
break;
118 case Key::Arrow_up: this->
increment();
break;
119 case Key::Arrow_down: this->
decrement();
break;
122 auto const c = key_to_char(k);
123 if (is_valid_input(c)) {
126 value_ = string_to_value(this->
text().str());
129 return Textline_base::key_press_event(k);
135 case Mouse::Button::ScrollUp: this->
increment();
break;
136 case Mouse::Button::ScrollDown: this->
decrement();
break;
139 return Textline_base::mouse_wheel_event(m);
144 this->validate_and_submit();
145 return Textline_base::focus_out_event();
153 static auto constexpr Min_num = std::numeric_limits<Number_t>::lowest();
154 static auto constexpr Max_num = std::numeric_limits<Number_t>::max();
158 [[nodiscard]]
static auto is_valid_input(
char c) ->
bool
160 bool is_separator = (c ==
',');
161 if constexpr (std::is_floating_point<Number_t>::value)
162 is_separator |= (c ==
'.');
163 bool is_sign = (c ==
'+');
164 if constexpr (!std::is_unsigned<Number_t>::value)
165 is_sign |= (c ==
'-');
166 return std::isdigit(c) || is_separator || is_sign;
170 [[nodiscard]]
auto string_to_value(std::string x) -> Number_t
173 auto ss = std::istringstream{x};
174 auto result = Number_t(0);
180 static void sanitize(std::string& s)
182 s.erase(std::remove(std::begin(s), std::end(s),
','), std::end(s));
186 void validate_and_submit()
188 auto const new_value = string_to_value(this->
text().str());
189 value_ = std::clamp(new_value, range_.min, range_.max);
190 if (value_ != new_value) {
191 core_.
set_text(std::to_string(value_));
194 submitted.emit(value_);
199 template <
typename Number_t>
200 [[nodiscard]]
auto number_edit(
201 Number_t initial = 0,
202 typename Number_edit<Number_t>::Range range = {},
203 Align alignment = Align::Left,
204 typename Number_edit<Number_t>::Action focus_in_action =
205 Number_edit<Number_t>::Action::None,
206 Number_t increment = 1) -> std::unique_ptr<Number_edit<Number_t>>
208 return std::make_unique<Number_edit<Number_t>>(initial, range, alignment,
209 focus_in_action, increment);
213 template <
typename Number_t>
214 [[nodiscard]]
auto number_edit(
typename Number_edit<Number_t>::Parameters p)
215 -> std::unique_ptr<Number_edit<Number_t>>
217 return std::make_unique<Number_edit<Number_t>>(std::move(p));
220 using Int_edit = Number_edit<int>;
223 [[nodiscard]]
inline auto int_edit(
225 Int_edit::Range range = {},
226 Align alignment = Align::Left,
227 Int_edit::Action focus_in_action = Int_edit::Action::None,
228 int increment = 1) -> std::unique_ptr<Int_edit>
230 return std::make_unique<Int_edit>(initial, range, alignment,
231 focus_in_action, increment);
235 [[nodiscard]]
inline auto int_edit(Int_edit::Parameters p)
236 -> std::unique_ptr<Int_edit>
238 return std::make_unique<Int_edit>(std::move(p));
241 using Unsigned_edit = Number_edit<unsigned int>;
244 [[nodiscard]]
inline auto unsigned_edit(
245 unsigned int initial = 0,
246 Unsigned_edit::Range range = {},
247 Align alignment = Align::Left,
248 Unsigned_edit::Action focus_in_action = Unsigned_edit::Action::None,
249 unsigned int increment = 1) -> std::unique_ptr<Unsigned_edit>
251 return std::make_unique<Unsigned_edit>(initial, range, alignment,
252 focus_in_action, increment);
256 [[nodiscard]]
inline auto unsigned_edit(Unsigned_edit::Parameters p)
257 -> std::unique_ptr<Unsigned_edit>
259 return std::make_unique<Unsigned_edit>(std::move(p));
262 using Double_edit = Number_edit<double>;
265 [[nodiscard]]
inline auto double_edit(
267 Double_edit::Range range = {},
268 Align alignment = Align::Left,
269 Double_edit::Action focus_in_action = Double_edit::Action::None,
270 double increment = 1) -> std::unique_ptr<Double_edit>
272 return std::make_unique<Double_edit>(initial, range, alignment,
273 focus_in_action, increment);
277 [[nodiscard]]
inline auto double_edit(Double_edit::Parameters p)
278 -> std::unique_ptr<Double_edit>
280 return std::make_unique<Double_edit>(std::move(p));
283 using Float_edit = Number_edit<float>;
286 [[nodiscard]]
inline auto float_edit(
288 Float_edit::Range range = {},
289 Align alignment = Align::Left,
290 Float_edit::Action focus_in_action = Float_edit::Action::None,
291 float increment = 1) -> std::unique_ptr<Float_edit>
293 return std::make_unique<Float_edit>(initial, range, alignment,
294 focus_in_action, increment);
298 [[nodiscard]]
inline auto float_edit(Float_edit::Parameters p)
299 -> std::unique_ptr<Float_edit>
301 return std::make_unique<Float_edit>(std::move(p));
Definition: number_edit.hpp:21
auto get_increment() const -> Number_t
Return the current increment/decrement value.
Definition: number_edit.hpp:89
void set_increment(Number_t x)
Set the value to increment/decrement by on arrow key/mouse wheel input.
Definition: number_edit.hpp:86
auto range() const -> Range
Get the currently set Range.
Definition: number_edit.hpp:83
sl::Signal< void(Number_t)> submitted
Emitted on Enter key press; sends along the current value.
Definition: number_edit.hpp:38
auto value() const -> Number_t
Get the current value of the Number_edit, defaults to zero if invalid.
Definition: number_edit.hpp:73
sl::Signal< void(Number_t)> value_modified
Emitted on key press and inc/decrement; sends along the current value.
Definition: number_edit.hpp:41
auto key_press_event(Key k) -> bool override
Handles Key_press_event objects.
Definition: number_edit.hpp:114
void set_range(Range x)
Set the accepted range of values.
Definition: number_edit.hpp:76
auto focus_out_event() -> bool override
Handles Focus_out_event objects.
Definition: number_edit.hpp:142
void increment()
Increment the current value by the set increment.
Definition: number_edit.hpp:92
auto mouse_wheel_event(Mouse const &m) -> bool override
Handles Mouse_wheel_event objects.
Definition: number_edit.hpp:132
void decrement()
Decrement the current value by the set increment.
Definition: number_edit.hpp:103
void set_value(Number_t x)
Set a new value to be displayed.
Definition: number_edit.hpp:65
Implements single line text Cursor navigation and deletion, no text input.
Definition: textline_base.hpp:14
auto text() const noexcept -> ox::Glyph_string const &
Return the full text contents.
Definition: textline_base.cpp:35
auto alignment() const noexcept -> ox::Align
Return the current alignment.
Definition: textline_base.cpp:46
auto focus_in_action() const noexcept -> Action
Return the currently used focus in event Action.
Definition: textline_base.cpp:57
void set_text(ox::Glyph_string x)
Clear and reset the text.
Definition: textline_core.cpp:24
void insert_at_cursor(ox::Glyph x)
Inserts x at the current cursor index.
Definition: textline_core.cpp:126
Definition: number_edit.hpp:28
Definition: number_edit.hpp:23
Holds [begin, end) half-open range of iterators and provides access.
Definition: range.hpp:7