Serenity Operating System
1/*
2 * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "Keypad.h"
28#include <AK/StringBuilder.h>
29#include <math.h>
30
31Keypad::Keypad()
32{
33}
34
35Keypad::~Keypad()
36{
37}
38
39void Keypad::type_digit(int digit)
40{
41 switch (m_state) {
42 case State::External:
43 m_state = State::TypingInteger;
44 m_negative = false;
45 m_int_value = digit;
46 m_frac_value = 0;
47 m_frac_length = 0;
48 break;
49 case State::TypingInteger:
50 ASSERT(m_frac_value == 0);
51 ASSERT(m_frac_length == 0);
52 m_int_value *= 10;
53 m_int_value += digit;
54 break;
55 case State::TypingDecimal:
56 if (m_frac_length > 6)
57 break;
58 m_frac_value *= 10;
59 m_frac_value += digit;
60 m_frac_length++;
61 break;
62 }
63}
64
65void Keypad::type_decimal_point()
66{
67 switch (m_state) {
68 case State::External:
69 m_negative = false;
70 m_int_value = 0;
71 m_frac_value = 0;
72 m_frac_length = 0;
73 break;
74 case State::TypingInteger:
75 ASSERT(m_frac_value == 0);
76 ASSERT(m_frac_length == 0);
77 m_state = State::TypingDecimal;
78 break;
79 case State::TypingDecimal:
80 // Ignore it.
81 break;
82 }
83}
84
85void Keypad::type_backspace()
86{
87 switch (m_state) {
88 case State::External:
89 m_negative = false;
90 m_int_value = 0;
91 m_frac_value = 0;
92 m_frac_length = 0;
93 break;
94 case State::TypingDecimal:
95 if (m_frac_length > 0) {
96 m_frac_value /= 10;
97 m_frac_length--;
98 break;
99 }
100 ASSERT(m_frac_value == 0);
101 m_state = State::TypingInteger;
102 [[fallthrough]];
103 case State::TypingInteger:
104 ASSERT(m_frac_value == 0);
105 ASSERT(m_frac_length == 0);
106 m_int_value /= 10;
107 if (m_int_value == 0)
108 m_negative = false;
109 break;
110 }
111}
112
113double Keypad::value() const
114{
115 double res = 0.0;
116
117 long frac = m_frac_value;
118 for (int i = 0; i < m_frac_length; i++) {
119 int digit = frac % 10;
120 res += digit;
121 res /= 10.0;
122 frac /= 10;
123 }
124
125 res += m_int_value;
126 if (m_negative)
127 res = -res;
128
129 return res;
130}
131
132void Keypad::set_value(double value)
133{
134 m_state = State::External;
135
136 if (value < 0.0) {
137 m_negative = true;
138 value = -value;
139 } else
140 m_negative = false;
141
142 m_int_value = value;
143 value -= m_int_value;
144
145 m_frac_value = 0;
146 m_frac_length = 0;
147 while (value != 0) {
148 value *= 10.0;
149 int digit = value;
150 m_frac_value *= 10;
151 m_frac_value += digit;
152 m_frac_length++;
153 value -= digit;
154
155 if (m_frac_length > 6)
156 break;
157 }
158}
159
160String Keypad::to_string() const
161{
162 StringBuilder builder;
163 if (m_negative)
164 builder.append("-");
165 builder.appendf("%ld.", m_int_value);
166
167 if (m_frac_length > 0)
168 builder.appendf("%0*ld", m_frac_length, m_frac_value);
169
170 return builder.to_string();
171}