digit_display.hpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. #ifndef TIME_DISPLAY_HPP
  2. #define TIME_DISPLAY_HPP
  3. #include <cassert>
  4. #include "digit_display.h"
  5. #include "utils.hpp"
  6. // what is integer exp that you don't have it, eh? c++, eh? -_-
  7. // TODO: add integer exp to simple::support i guess
  8. constexpr int int_pow(int i, int p)
  9. {
  10. int r = 1;
  11. while(p-->0)
  12. r *= i;
  13. return r;
  14. }
  15. template <size_t digit_count>
  16. digit_display<digit_count>::
  17. digit_display(int2 digit_size, int2 digit_spacing, graphical::color color) :
  18. digit_display(
  19. digit_size, digit_spacing, color, std::make_index_sequence<digit_count>())
  20. {}
  21. template <size_t digit_count>
  22. template <size_t... I>
  23. digit_display<digit_count>::digit_display(int2 digit_size, int2 digit_spacing, graphical::color color, std::index_sequence<I...>) :
  24. ui_element(layout),
  25. color(color),
  26. digits{ (void(I),
  27. digit_bitmap(digit[0], color, rect{digit_size})
  28. )...},
  29. layout({&digits[I]...}, digit_spacing),
  30. set_value(0),
  31. input_value(0),
  32. input(false)
  33. {
  34. layout.update();
  35. digits[0].align = -int2::i();
  36. digits[digit_count - 1].align = int2::i();
  37. }
  38. template <size_t digit_count>
  39. void digit_display<digit_count>::set(int value) noexcept
  40. {
  41. assert(0 <= value && value < int_pow(10, digit_count));
  42. set_value = value;
  43. for(size_t i = digit_count; i --> 0;)
  44. {
  45. digits[i].set_data(digit[value%10]);
  46. value /= 10;
  47. }
  48. }
  49. template <size_t digit_count>
  50. digit_display<digit_count>& digit_display<digit_count>::operator+=(const int2& offset)
  51. {
  52. layout += offset;
  53. return *this;
  54. }
  55. template <size_t digit_count>
  56. int2 digit_display<digit_count>::lower() const
  57. {
  58. return layout.lower();
  59. }
  60. template <size_t digit_count>
  61. int2 digit_display<digit_count>::upper() const
  62. {
  63. return layout.upper();
  64. }
  65. template <size_t digit_count>
  66. void digit_display<digit_count>::draw(const graphical::surface& target)
  67. {
  68. if(ui_element::focus())
  69. {
  70. lowlight(target, color, {lower(), upper()}, int2{3,3});
  71. graphical::fill(target, color, {upper() - (upper()-lower()) / int2{1, 40}, upper()});
  72. }
  73. for(auto&& digit : digits)
  74. digit.draw(target);
  75. }
  76. template <size_t digit_count>
  77. void digit_display<digit_count>::update(const interactive::event& event) noexcept
  78. {
  79. ui_element::update(event);
  80. if(current_state() == ui_element::state::disabled)
  81. return;
  82. if(ui_element::focus())
  83. {
  84. using namespace interactive;
  85. std::visit(support::overload
  86. {
  87. [this](const key_pressed& key_event)
  88. {
  89. int digit = -1;
  90. switch(key_event.data.keycode)
  91. {
  92. case keycode::_9:
  93. case keycode::kp_9:
  94. ++digit;
  95. [[fallthrough]]; // T_T
  96. case keycode::_8:
  97. case keycode::kp_8:
  98. ++digit;
  99. [[fallthrough]]; // T-T
  100. case keycode::_7:
  101. case keycode::kp_7:
  102. ++digit;
  103. [[fallthrough]]; // T-T
  104. case keycode::_6:
  105. case keycode::kp_6:
  106. ++digit;
  107. [[fallthrough]]; // ToT
  108. case keycode::_5:
  109. case keycode::kp_5:
  110. ++digit;
  111. [[fallthrough]]; // TOT
  112. case keycode::_4:
  113. case keycode::kp_4:
  114. ++digit;
  115. [[fallthrough]]; // ToT
  116. case keycode::_3:
  117. case keycode::kp_3:
  118. ++digit;
  119. [[fallthrough]]; // T-T
  120. case keycode::_2:
  121. case keycode::kp_2:
  122. ++digit;
  123. [[fallthrough]]; // T-T
  124. case keycode::_1:
  125. case keycode::kp_1:
  126. ++digit;
  127. [[fallthrough]]; // T_T
  128. case keycode::_0:
  129. case keycode::kp_0:
  130. ++digit;
  131. {
  132. if(!input)
  133. {
  134. input = true;
  135. input_value = 0;
  136. }
  137. if(input_value < int_pow(10, digit_count - 1))
  138. {
  139. input_value = input_value * 10 + digit;
  140. input_value %= int_pow(10, digit_count);
  141. }
  142. }
  143. break;
  144. case keycode::backspace:
  145. input_value /= 10;
  146. break;
  147. default: return;
  148. }
  149. if(input_value != set_value)
  150. {
  151. for(auto&& callback : on_input)
  152. callback(*this, set_value, input_value);
  153. set_value = input_value;
  154. }
  155. },
  156. [](auto&&){}
  157. }, event);
  158. }
  159. }
  160. template <size_t digit_count>
  161. void digit_display<digit_count>::drop_focus() noexcept
  162. {
  163. ui_element::drop_focus();
  164. input = false;
  165. input_value = 0;
  166. }
  167. #endif /* end of include guard */