Keypad.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /*
  2. * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
  3. * Copyright (c) 2021, Max Wipfli <mail@maxwipfli.ch>
  4. * Copyright (c) 2022, the SerenityOS developers.
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #include "Keypad.h"
  9. #include "KeypadValue.h"
  10. #include <AK/IntegralMath.h>
  11. #include <AK/StringBuilder.h>
  12. void Keypad::type_digit(int digit)
  13. {
  14. u64 previous_value = 0;
  15. switch (m_state) {
  16. case State::External:
  17. m_state = State::TypingInteger;
  18. m_negative = false;
  19. m_int_value = digit;
  20. m_frac_value = 0;
  21. m_frac_length = 0;
  22. break;
  23. case State::TypingInteger:
  24. VERIFY(m_frac_value.value() == 0);
  25. VERIFY(m_frac_length == 0);
  26. previous_value = m_int_value.value();
  27. m_int_value *= 10;
  28. m_int_value += digit;
  29. if (m_int_value.has_overflow())
  30. m_int_value = previous_value;
  31. break;
  32. case State::TypingDecimal:
  33. previous_value = m_frac_value.value();
  34. m_frac_value *= 10;
  35. m_frac_value += digit;
  36. if (m_frac_value.has_overflow())
  37. m_frac_value = previous_value;
  38. else
  39. m_frac_length++;
  40. break;
  41. }
  42. }
  43. void Keypad::type_decimal_point()
  44. {
  45. switch (m_state) {
  46. case State::External:
  47. m_negative = false;
  48. m_int_value = 0;
  49. m_frac_value = 0;
  50. m_frac_length = 0;
  51. m_state = State::TypingDecimal;
  52. break;
  53. case State::TypingInteger:
  54. VERIFY(m_frac_value.value() == 0);
  55. VERIFY(m_frac_length == 0);
  56. m_state = State::TypingDecimal;
  57. break;
  58. case State::TypingDecimal:
  59. // Ignore it.
  60. break;
  61. }
  62. }
  63. void Keypad::type_backspace()
  64. {
  65. switch (m_state) {
  66. case State::External:
  67. m_negative = false;
  68. m_int_value = 0;
  69. m_frac_value = 0;
  70. m_frac_length = 0;
  71. break;
  72. case State::TypingDecimal:
  73. if (m_frac_length > 0) {
  74. m_frac_value /= 10;
  75. m_frac_length--;
  76. break;
  77. }
  78. VERIFY(m_frac_value.value() == 0);
  79. m_state = State::TypingInteger;
  80. [[fallthrough]];
  81. case State::TypingInteger:
  82. VERIFY(m_frac_value.value() == 0);
  83. VERIFY(m_frac_length == 0);
  84. m_int_value /= 10;
  85. if (m_int_value.value() == 0)
  86. m_negative = false;
  87. break;
  88. }
  89. }
  90. KeypadValue Keypad::value() const
  91. {
  92. KeypadValue frac_part = { (i64)m_frac_value.value(), m_frac_length };
  93. KeypadValue int_part = { (i64)m_int_value.value() };
  94. KeypadValue res = int_part + frac_part;
  95. if (m_negative)
  96. res = -res;
  97. return res;
  98. }
  99. void Keypad::set_value(KeypadValue value)
  100. {
  101. m_state = State::External;
  102. if (value.m_value < 0) {
  103. m_negative = true;
  104. value = -value;
  105. } else
  106. m_negative = false;
  107. m_int_value = value.m_value / AK::pow<u64>(10, value.m_decimal_places);
  108. m_frac_value = value.m_value % AK::pow<u64>(10, value.m_decimal_places);
  109. m_frac_length = value.m_decimal_places;
  110. }
  111. String Keypad::to_string() const
  112. {
  113. StringBuilder builder;
  114. if (m_negative)
  115. builder.append('-');
  116. builder.appendff("{}", m_int_value.value());
  117. // NOTE: This is so the decimal point appears on screen as soon as you type it.
  118. if (m_frac_length > 0 || m_state == State::TypingDecimal)
  119. builder.append('.');
  120. if (m_frac_length > 0) {
  121. // FIXME: This disables the compiletime format string check since we can't parse '}}' here correctly.
  122. // remove the 'StringView { }' when that's fixed.
  123. builder.appendff("{:0{}}"sv, m_frac_value.value(), m_frac_length);
  124. }
  125. return builder.to_string();
  126. }