CalculatorWidget.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /*
  2. * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
  3. * Copyright (c) 2021, Glenford Williams <gw_dev@outlook.com>
  4. * Copyright (c) 2021, Max Wipfli <mail@maxwipfli.ch>
  5. * Copyright (c) 2022, the SerenityOS developers.
  6. *
  7. * SPDX-License-Identifier: BSD-2-Clause
  8. */
  9. #include "CalculatorWidget.h"
  10. #include "KeypadValue.h"
  11. #include <Applications/Calculator/CalculatorGML.h>
  12. #include <LibCore/Event.h>
  13. #include <LibGUI/Button.h>
  14. #include <LibGUI/Label.h>
  15. #include <LibGUI/TextBox.h>
  16. #include <LibGfx/Font/Font.h>
  17. #include <LibGfx/Palette.h>
  18. CalculatorWidget::CalculatorWidget()
  19. {
  20. load_from_gml(calculator_gml);
  21. m_entry = *find_descendant_of_type_named<GUI::TextBox>("entry_textbox");
  22. m_entry->set_relative_rect(5, 5, 244, 26);
  23. m_entry->set_text_alignment(Gfx::TextAlignment::CenterRight);
  24. m_label = *find_descendant_of_type_named<GUI::Label>("label");
  25. m_label->set_frame_shadow(Gfx::FrameShadow::Sunken);
  26. m_label->set_frame_shape(Gfx::FrameShape::Container);
  27. m_label->set_frame_thickness(2);
  28. for (int i = 0; i < 10; i++) {
  29. m_digit_button[i] = *find_descendant_of_type_named<GUI::Button>(String::formatted("{}_button", i));
  30. add_digit_button(*m_digit_button[i], i);
  31. }
  32. m_mem_add_button = *find_descendant_of_type_named<GUI::Button>("mem_add_button");
  33. add_operation_button(*m_mem_add_button, Calculator::Operation::MemAdd);
  34. m_mem_save_button = *find_descendant_of_type_named<GUI::Button>("mem_save_button");
  35. add_operation_button(*m_mem_save_button, Calculator::Operation::MemSave);
  36. m_mem_recall_button = *find_descendant_of_type_named<GUI::Button>("mem_recall_button");
  37. add_operation_button(*m_mem_recall_button, Calculator::Operation::MemRecall);
  38. m_mem_clear_button = *find_descendant_of_type_named<GUI::Button>("mem_clear_button");
  39. add_operation_button(*m_mem_clear_button, Calculator::Operation::MemClear);
  40. m_clear_button = *find_descendant_of_type_named<GUI::Button>("clear_button");
  41. m_clear_button->on_click = [this](auto) {
  42. m_keypad.set_value(0.0);
  43. m_calculator.clear_operation();
  44. update_display();
  45. };
  46. m_clear_error_button = *find_descendant_of_type_named<GUI::Button>("clear_error_button");
  47. m_clear_error_button->on_click = [this](auto) {
  48. m_keypad.set_value(0.0);
  49. update_display();
  50. };
  51. m_backspace_button = *find_descendant_of_type_named<GUI::Button>("backspace_button");
  52. m_backspace_button->on_click = [this](auto) {
  53. m_keypad.type_backspace();
  54. update_display();
  55. };
  56. m_decimal_point_button = *find_descendant_of_type_named<GUI::Button>("decimal_button");
  57. m_decimal_point_button->on_click = [this](auto) {
  58. m_keypad.type_decimal_point();
  59. update_display();
  60. };
  61. m_sign_button = *find_descendant_of_type_named<GUI::Button>("sign_button");
  62. add_operation_button(*m_sign_button, Calculator::Operation::ToggleSign);
  63. m_add_button = *find_descendant_of_type_named<GUI::Button>("add_button");
  64. add_operation_button(*m_add_button, Calculator::Operation::Add);
  65. m_subtract_button = *find_descendant_of_type_named<GUI::Button>("subtract_button");
  66. add_operation_button(*m_subtract_button, Calculator::Operation::Subtract);
  67. m_multiply_button = *find_descendant_of_type_named<GUI::Button>("multiply_button");
  68. add_operation_button(*m_multiply_button, Calculator::Operation::Multiply);
  69. m_divide_button = *find_descendant_of_type_named<GUI::Button>("divide_button");
  70. add_operation_button(*m_divide_button, Calculator::Operation::Divide);
  71. m_sqrt_button = *find_descendant_of_type_named<GUI::Button>("sqrt_button");
  72. add_operation_button(*m_sqrt_button, Calculator::Operation::Sqrt);
  73. m_inverse_button = *find_descendant_of_type_named<GUI::Button>("inverse_button");
  74. add_operation_button(*m_inverse_button, Calculator::Operation::Inverse);
  75. m_percent_button = *find_descendant_of_type_named<GUI::Button>("mod_button");
  76. add_operation_button(*m_percent_button, Calculator::Operation::Percent);
  77. m_equals_button = *find_descendant_of_type_named<GUI::Button>("equal_button");
  78. m_equals_button->on_click = [this](auto) {
  79. KeypadValue argument = m_keypad.value();
  80. KeypadValue res = m_calculator.finish_operation(argument);
  81. m_keypad.set_value(res);
  82. update_display();
  83. };
  84. }
  85. void CalculatorWidget::perform_operation(Calculator::Operation operation)
  86. {
  87. KeypadValue argument = m_keypad.value();
  88. KeypadValue res = m_calculator.begin_operation(operation, argument);
  89. m_keypad.set_value(res);
  90. update_display();
  91. }
  92. void CalculatorWidget::add_operation_button(GUI::Button& button, Calculator::Operation operation)
  93. {
  94. button.on_click = [this, operation](auto) {
  95. perform_operation(operation);
  96. };
  97. }
  98. void CalculatorWidget::add_digit_button(GUI::Button& button, int digit)
  99. {
  100. button.on_click = [this, digit](auto) {
  101. m_keypad.type_digit(digit);
  102. update_display();
  103. };
  104. }
  105. String CalculatorWidget::get_entry()
  106. {
  107. return m_entry->text();
  108. }
  109. void CalculatorWidget::set_entry(KeypadValue value)
  110. {
  111. m_keypad.set_value(value);
  112. update_display();
  113. }
  114. void CalculatorWidget::mimic_pressed_button(RefPtr<GUI::Button> button)
  115. {
  116. button->set_mimic_pressed(true);
  117. }
  118. void CalculatorWidget::update_display()
  119. {
  120. m_entry->set_text(m_keypad.to_string());
  121. if (m_calculator.has_error())
  122. m_label->set_text("E");
  123. else
  124. m_label->set_text("");
  125. }
  126. void CalculatorWidget::keydown_event(GUI::KeyEvent& event)
  127. {
  128. if (event.key() == KeyCode::Key_Return || event.key() == KeyCode::Key_Equal) {
  129. m_keypad.set_value(m_calculator.finish_operation(m_keypad.value()));
  130. mimic_pressed_button(m_equals_button);
  131. } else if (event.code_point() >= '0' && event.code_point() <= '9') {
  132. u32 digit = event.code_point() - '0';
  133. m_keypad.type_digit(digit);
  134. mimic_pressed_button(m_digit_button[digit]);
  135. } else if (event.code_point() == '.') {
  136. m_keypad.type_decimal_point();
  137. mimic_pressed_button(m_decimal_point_button);
  138. } else if (event.key() == KeyCode::Key_Escape || event.key() == KeyCode::Key_Delete) {
  139. m_keypad.set_value(0.0);
  140. m_calculator.clear_operation();
  141. mimic_pressed_button(m_clear_button);
  142. } else if (event.key() == KeyCode::Key_Backspace) {
  143. m_keypad.type_backspace();
  144. mimic_pressed_button(m_backspace_button);
  145. } else if (event.key() == KeyCode::Key_Backslash) {
  146. perform_operation(Calculator::Operation::ToggleSign);
  147. mimic_pressed_button(m_sign_button);
  148. } else if (event.key() == KeyCode::Key_S) {
  149. perform_operation(Calculator::Operation::Sqrt);
  150. mimic_pressed_button(m_sqrt_button);
  151. } else if (event.key() == KeyCode::Key_Percent) {
  152. perform_operation(Calculator::Operation::Percent);
  153. mimic_pressed_button(m_percent_button);
  154. } else if (event.key() == KeyCode::Key_I) {
  155. perform_operation(Calculator::Operation::Inverse);
  156. mimic_pressed_button(m_inverse_button);
  157. } else {
  158. Calculator::Operation operation;
  159. switch (event.code_point()) {
  160. case '+':
  161. operation = Calculator::Operation::Add;
  162. mimic_pressed_button(m_add_button);
  163. break;
  164. case '-':
  165. operation = Calculator::Operation::Subtract;
  166. mimic_pressed_button(m_subtract_button);
  167. break;
  168. case '*':
  169. operation = Calculator::Operation::Multiply;
  170. mimic_pressed_button(m_multiply_button);
  171. break;
  172. case '/':
  173. operation = Calculator::Operation::Divide;
  174. mimic_pressed_button(m_divide_button);
  175. break;
  176. case '%':
  177. operation = Calculator::Operation::Percent;
  178. mimic_pressed_button(m_percent_button);
  179. break;
  180. default:
  181. return;
  182. }
  183. m_keypad.set_value(m_calculator.begin_operation(operation, m_keypad.value()));
  184. }
  185. update_display();
  186. }