LineInput.cxx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. #include "LineInput.hxx"
  2. #include <cassert>
  3. namespace {
  4. SDL_Rect const TEXTURE_RECTS[] = {
  5. {.x = 0, .y = 0, .w = 8, .h = 8}, // UPPER_LEFT
  6. {.x = 8, .y = 0, .w = 179, .h = 8}, // UPPER_EDGE
  7. {.x = 187, .y = 0, .w = 8, .h = 8}, // UPPER_RIGHT
  8. {.x = 0, .y = 8, .w = 8, .h = 34}, // LEFT_EDGE
  9. {.x = 8, .y = 8, .w = 179, .h = 34}, // CENTER
  10. {.x = 187, .y = 8, .w = 8, .h = 34}, // RIGHT_EDGE
  11. {.x = 0, .y = 42, .w = 8, .h = 7}, // LOWER_LEFT
  12. {.x = 8, .y = 42, .w = 179, .h = 7}, // LOWER_EDGE
  13. {.x = 187, .y = 42, .w = 8, .h = 7}, // LOWER_RIGHT
  14. };
  15. SDL_Rect calculate_text_rect(SDL_Rect const& area, SDL_Texture* texture)
  16. {
  17. int text_w, text_h;
  18. SDL_QueryTexture(texture, nullptr, nullptr, &text_w, &text_h);
  19. int const w = std::min(text_w, area.w-LineInput::MIN_WIDTH-8);
  20. int const h = std::min(text_h, area.h-LineInput::MIN_HEIGHT-8);
  21. return {
  22. .x = area.x+12,
  23. .y = area.y+(area.h-h)/2,
  24. .w = area.w>=(w+LineInput::MIN_WIDTH+8) ? w : 0,
  25. .h = area.h>=(h+LineInput::MIN_HEIGHT+8) ? h : 0,
  26. };
  27. }
  28. }
  29. LineInput::LineInput(int const x, int const y, int const w, int const h, std::string value)
  30. :value_{std::move(value)}, x_{x}, y_{y}, w_{w}, h_{h}, focus_{false},
  31. texture_{"line_input.png"},
  32. font_{"kenney_pixel.ttf"}
  33. {
  34. assert(w_>=MIN_WIDTH);
  35. assert(h_>=MIN_HEIGHT);
  36. }
  37. void LineInput::move(int const x, int const y)
  38. {
  39. x_ = x;
  40. y_ = y;
  41. }
  42. void LineInput::resize(int const w, int const h)
  43. {
  44. assert(w>=MIN_WIDTH);
  45. assert(h>=MIN_HEIGHT);
  46. w_ = w;
  47. h_ = h;
  48. }
  49. SDL_Rect LineInput::get_bounding_box() const
  50. {
  51. return {x_, y_, w_, h_};
  52. }
  53. void LineInput::set_focus(bool const focus)
  54. {
  55. focus_ = focus;
  56. }
  57. bool LineInput::has_focus() const
  58. {
  59. return focus_;
  60. }
  61. void LineInput::update(std::chrono::milliseconds const delta_time)
  62. {
  63. blink_timer_ = (blink_timer_+delta_time)%1'000u;
  64. }
  65. void LineInput::render(SDLRenderer& renderer)
  66. {
  67. using namespace std::chrono_literals;
  68. SDL_Texture* const background = texture_;
  69. SDL_Rect const target_rects[9] = {
  70. {.x = x_, .y = y_, .w = 8, .h = 8},
  71. {.x = x_+8, .y = y_, .w = w_-16, .h = 8},
  72. {.x = x_+w_-8, .y = y_, .w = 8, .h = 8},
  73. {.x = x_, .y = y_+8, .w = 8, .h = h_-15},
  74. {.x = x_+8, .y = y_+8, .w = w_-16, .h = h_-15},
  75. {.x = x_+w_-8, .y = y_+8, .w = 8, .h = h_-15},
  76. {.x = x_, .y = y_+h_-7, .w = 8, .h = 7},
  77. {.x = x_+8, .y = y_+h_-7, .w = w_-16, .h = 7},
  78. {.x = x_+w_-8, .y = y_+h_-7, .w = 8, .h = 7},
  79. };
  80. for (int n = 0; n<9; ++n)
  81. SDL_RenderCopy(renderer, background, ::TEXTURE_RECTS+n, target_rects+n);
  82. auto const text = TTF_RenderUTF8_Solid(font_, value_.c_str(), {0, 0, 0, SDL_ALPHA_OPAQUE});
  83. auto const text_ure = SDL_CreateTextureFromSurface(renderer, text);
  84. SDL_FreeSurface(text);
  85. auto const text_rect = ::calculate_text_rect(target_rects[4], text_ure);
  86. SDL_Rect const text_texture_rect{
  87. .x = 0, .y = 0, .w = text_rect.w, .h = text_rect.h,
  88. };
  89. SDL_RenderCopy(renderer, text_ure, &text_texture_rect, &text_rect);
  90. SDL_DestroyTexture(text_ure);
  91. if(focus_) {
  92. SDL_Rect cursor_rect{
  93. .x = text_rect.x + text_rect.w + 1, .y = text_rect.y, .w = 2, .h = text_rect.h,
  94. };
  95. SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
  96. if(blink_timer_ < 500ms) {
  97. SDL_RenderFillRect(renderer, &cursor_rect);
  98. }
  99. SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE);
  100. }
  101. }