Serenity Operating System
1/*
2 * Copyright (c) 2021, Matthew Olsson <mattco@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include "NumericInput.h"
8#include <ctype.h>
9
10NumericInput::NumericInput()
11{
12 set_text("0"sv);
13
14 on_change = [&] {
15 auto number_opt = text().to_int();
16 if (number_opt.has_value()) {
17 set_current_number(number_opt.value(), GUI::AllowCallback::No);
18 return;
19 }
20
21 StringBuilder builder;
22 bool first = true;
23 for (auto& ch : text()) {
24 if (isdigit(ch) || (first && ((ch == '-' && m_min_number < 0) || ch == '+')))
25 builder.append(ch);
26 first = false;
27 }
28
29 auto new_number_opt = builder.to_deprecated_string().to_int();
30 if (!new_number_opt.has_value()) {
31 m_needs_text_reset = true;
32 return;
33 } else {
34 m_needs_text_reset = false;
35 }
36
37 set_text(builder.to_deprecated_string());
38 set_current_number(new_number_opt.value(), GUI::AllowCallback::No);
39 };
40
41 on_up_pressed = [&] {
42 if (m_current_number < m_max_number)
43 set_current_number(m_current_number + 1);
44 };
45
46 on_down_pressed = [&] {
47 if (m_current_number > m_min_number)
48 set_current_number(m_current_number - 1);
49 };
50
51 on_focusout = [&] { on_focus_lost(); };
52 on_return_pressed = [&] { on_focus_lost(); };
53 on_escape_pressed = [&] { on_focus_lost(); };
54}
55
56void NumericInput::set_min_number(i32 number)
57{
58 m_min_number = number;
59 if (m_current_number < number)
60 set_current_number(number);
61}
62
63void NumericInput::set_max_number(i32 number)
64{
65 m_max_number = number;
66 if (m_current_number > number)
67 set_current_number(number);
68}
69
70void NumericInput::on_focus_lost()
71{
72 if (m_needs_text_reset) {
73 set_text(DeprecatedString::number(m_current_number));
74 m_needs_text_reset = false;
75 }
76 if (on_number_changed)
77 on_number_changed(m_current_number);
78}
79
80void NumericInput::set_current_number(i32 number, GUI::AllowCallback allow_callback)
81{
82 if (number == m_current_number)
83 return;
84
85 m_current_number = clamp(number, m_min_number, m_max_number);
86 set_text(DeprecatedString::number(m_current_number));
87 if (on_number_changed && allow_callback == GUI::AllowCallback::Yes)
88 on_number_changed(m_current_number);
89}