2020-01-18 08:38:21 +00:00
|
|
|
/*
|
2020-01-24 13:45:29 +00:00
|
|
|
* Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
|
2021-05-23 19:05:35 +00:00
|
|
|
* Copyright (c) 2021, Max Wipfli <mail@maxwipfli.ch>
|
2022-02-10 19:28:48 +00:00
|
|
|
* Copyright (c) 2022, the SerenityOS developers.
|
2020-01-18 08:38:21 +00:00
|
|
|
*
|
2021-04-22 08:24:48 +00:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2020-01-18 08:38:21 +00:00
|
|
|
*/
|
|
|
|
|
2019-08-09 10:55:20 +00:00
|
|
|
#include "Keypad.h"
|
|
|
|
#include <AK/StringBuilder.h>
|
2022-01-12 10:05:03 +00:00
|
|
|
#include <LibCrypto/BigFraction/BigFraction.h>
|
|
|
|
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
|
|
|
#include <LibCrypto/NumberTheory/ModularFunctions.h>
|
2019-08-09 10:55:20 +00:00
|
|
|
|
2022-12-26 16:07:00 +00:00
|
|
|
void Keypad::type_digit(int digit)
|
2019-08-09 10:55:20 +00:00
|
|
|
{
|
|
|
|
switch (m_state) {
|
|
|
|
case State::External:
|
2023-02-03 04:10:13 +00:00
|
|
|
case State::TypedExternal:
|
2019-08-09 10:55:20 +00:00
|
|
|
m_state = State::TypingInteger;
|
|
|
|
m_int_value = digit;
|
2022-01-12 10:05:03 +00:00
|
|
|
m_frac_value.set_to_0();
|
|
|
|
m_frac_length.set_to_0();
|
2019-08-09 10:55:20 +00:00
|
|
|
break;
|
|
|
|
case State::TypingInteger:
|
2022-01-12 10:05:03 +00:00
|
|
|
VERIFY(m_frac_value == 0);
|
2021-02-23 19:42:32 +00:00
|
|
|
VERIFY(m_frac_length == 0);
|
2022-01-12 10:05:03 +00:00
|
|
|
m_int_value.set_to(m_int_value.multiplied_by(10));
|
|
|
|
m_int_value.set_to(m_int_value.plus(digit));
|
2019-08-09 10:55:20 +00:00
|
|
|
break;
|
|
|
|
case State::TypingDecimal:
|
2022-01-12 10:05:03 +00:00
|
|
|
m_frac_value.set_to(m_frac_value.multiplied_by(10));
|
|
|
|
m_frac_value.set_to(m_frac_value.plus(digit));
|
|
|
|
|
|
|
|
m_frac_length.set_to(m_frac_length.plus(1));
|
2019-08-09 10:55:20 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Keypad::type_decimal_point()
|
|
|
|
{
|
|
|
|
switch (m_state) {
|
|
|
|
case State::External:
|
2023-02-03 04:10:13 +00:00
|
|
|
case State::TypedExternal:
|
2022-01-12 10:05:03 +00:00
|
|
|
m_int_value.set_to_0();
|
|
|
|
m_frac_value.set_to_0();
|
|
|
|
m_frac_length.set_to_0();
|
2021-05-23 19:27:32 +00:00
|
|
|
m_state = State::TypingDecimal;
|
2019-08-09 10:55:20 +00:00
|
|
|
break;
|
|
|
|
case State::TypingInteger:
|
2022-01-12 10:05:03 +00:00
|
|
|
VERIFY(m_frac_value == 0);
|
2021-02-23 19:42:32 +00:00
|
|
|
VERIFY(m_frac_length == 0);
|
2019-08-09 10:55:20 +00:00
|
|
|
m_state = State::TypingDecimal;
|
|
|
|
break;
|
|
|
|
case State::TypingDecimal:
|
|
|
|
// Ignore it.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Keypad::type_backspace()
|
|
|
|
{
|
|
|
|
switch (m_state) {
|
|
|
|
case State::External:
|
2023-02-03 04:10:13 +00:00
|
|
|
case State::TypedExternal:
|
2022-01-12 10:05:03 +00:00
|
|
|
m_int_value.set_to_0();
|
|
|
|
m_frac_value.set_to_0();
|
|
|
|
m_frac_length.set_to_0();
|
2019-08-09 10:55:20 +00:00
|
|
|
break;
|
|
|
|
case State::TypingDecimal:
|
|
|
|
if (m_frac_length > 0) {
|
2022-01-12 10:05:03 +00:00
|
|
|
m_frac_value.set_to(m_frac_value.divided_by(10).quotient);
|
|
|
|
m_frac_length.set_to(m_frac_length.minus(1));
|
2019-08-09 10:55:20 +00:00
|
|
|
break;
|
|
|
|
}
|
2022-01-12 10:05:03 +00:00
|
|
|
VERIFY(m_frac_value == 0);
|
2019-08-09 10:55:20 +00:00
|
|
|
m_state = State::TypingInteger;
|
|
|
|
[[fallthrough]];
|
|
|
|
case State::TypingInteger:
|
2022-01-12 10:05:03 +00:00
|
|
|
VERIFY(m_frac_value == 0);
|
2021-02-23 19:42:32 +00:00
|
|
|
VERIFY(m_frac_length == 0);
|
2022-01-12 10:05:03 +00:00
|
|
|
m_int_value.set_to(m_int_value.divided_by(10).quotient);
|
2019-08-09 10:55:20 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-12 10:05:03 +00:00
|
|
|
Crypto::BigFraction Keypad::value() const
|
2019-08-09 10:55:20 +00:00
|
|
|
{
|
2023-02-03 04:10:13 +00:00
|
|
|
if (m_state != State::External && m_state != State::TypedExternal) {
|
2022-01-12 10:05:03 +00:00
|
|
|
Crypto::SignedBigInteger sum { m_int_value.multiplied_by(Crypto::NumberTheory::Power("10"_bigint, m_frac_length)).plus(m_frac_value) };
|
|
|
|
Crypto::BigFraction res { move(sum), Crypto::NumberTheory::Power("10"_bigint, m_frac_length) };
|
|
|
|
|
|
|
|
m_internal_value = move(res);
|
|
|
|
}
|
|
|
|
|
|
|
|
return m_internal_value;
|
2019-08-09 10:55:20 +00:00
|
|
|
}
|
|
|
|
|
2022-01-12 10:05:03 +00:00
|
|
|
void Keypad::set_value(Crypto::BigFraction value)
|
2019-08-09 10:55:20 +00:00
|
|
|
{
|
|
|
|
m_state = State::External;
|
|
|
|
|
2022-01-12 10:05:03 +00:00
|
|
|
m_internal_value = move(value);
|
|
|
|
}
|
|
|
|
|
2023-02-03 04:10:13 +00:00
|
|
|
void Keypad::set_typed_value(Crypto::BigFraction value)
|
|
|
|
{
|
|
|
|
m_state = State::TypedExternal;
|
|
|
|
|
|
|
|
m_internal_value = move(value);
|
|
|
|
}
|
|
|
|
|
2022-01-12 10:05:03 +00:00
|
|
|
void Keypad::set_to_0()
|
|
|
|
{
|
|
|
|
m_int_value.set_to_0();
|
|
|
|
m_frac_value.set_to_0();
|
|
|
|
m_frac_length.set_to_0();
|
2019-08-09 10:55:20 +00:00
|
|
|
|
2022-01-12 10:05:03 +00:00
|
|
|
m_internal_value.set_to_0();
|
|
|
|
|
|
|
|
m_state = State::External;
|
2019-08-09 10:55:20 +00:00
|
|
|
}
|
|
|
|
|
2023-10-29 07:06:32 +00:00
|
|
|
ErrorOr<String> Keypad::to_string() const
|
2019-08-09 10:55:20 +00:00
|
|
|
{
|
2023-02-03 04:10:13 +00:00
|
|
|
if (m_state == State::External || m_state == State::TypedExternal)
|
2023-12-16 14:19:34 +00:00
|
|
|
return String::from_byte_string(m_internal_value.to_byte_string(m_displayed_fraction_length));
|
2022-01-12 10:05:03 +00:00
|
|
|
|
2019-08-09 10:55:20 +00:00
|
|
|
StringBuilder builder;
|
|
|
|
|
2023-12-16 14:19:34 +00:00
|
|
|
ByteString const integer_value = m_int_value.to_base_deprecated(10);
|
|
|
|
ByteString const frac_value = m_frac_value.to_base_deprecated(10);
|
2022-01-12 10:05:03 +00:00
|
|
|
unsigned const number_pre_zeros = m_frac_length.to_u64() - (frac_value.length() - 1) - (frac_value == "0" ? 0 : 1);
|
|
|
|
|
|
|
|
builder.append(integer_value);
|
2021-05-23 19:05:35 +00:00
|
|
|
|
2022-01-12 10:05:03 +00:00
|
|
|
// NOTE: We test for the state so the decimal point appears on screen as soon as you type it.
|
|
|
|
if (m_state == State::TypingDecimal) {
|
|
|
|
builder.append('.');
|
|
|
|
builder.append_repeated('0', number_pre_zeros);
|
|
|
|
if (frac_value != "0")
|
|
|
|
builder.append(frac_value);
|
2021-02-23 06:28:15 +00:00
|
|
|
}
|
2019-08-09 10:55:20 +00:00
|
|
|
|
2023-10-29 07:06:32 +00:00
|
|
|
return builder.to_string();
|
2019-08-09 10:55:20 +00:00
|
|
|
}
|
2022-09-22 14:54:46 +00:00
|
|
|
|
2022-12-26 16:12:46 +00:00
|
|
|
bool Keypad::in_typing_state() const
|
|
|
|
{
|
2023-02-03 04:10:13 +00:00
|
|
|
return m_state == State::TypedExternal || m_state == State::TypingDecimal || m_state == State::TypingInteger;
|
2022-12-26 16:12:46 +00:00
|
|
|
}
|
|
|
|
|
2022-09-22 14:54:46 +00:00
|
|
|
void Keypad::set_rounding_length(unsigned rounding_threshold)
|
|
|
|
{
|
|
|
|
m_displayed_fraction_length = rounding_threshold;
|
|
|
|
}
|
2022-09-22 14:55:04 +00:00
|
|
|
|
|
|
|
unsigned Keypad::rounding_length() const
|
|
|
|
{
|
|
|
|
return m_displayed_fraction_length;
|
|
|
|
}
|
2022-01-16 21:45:09 +00:00
|
|
|
|
|
|
|
void Keypad::shrink(unsigned shrink_threshold)
|
|
|
|
{
|
|
|
|
m_internal_value = m_internal_value.rounded(shrink_threshold);
|
|
|
|
}
|