Card.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*
  2. * Copyright (c) 2020, Till Mayer <till.mayer@web.de>
  3. * Copyright (c) 2022, the SerenityOS developers.
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include "Card.h"
  8. #include <LibGUI/Widget.h>
  9. #include <LibGfx/Font/Font.h>
  10. #include <LibGfx/Font/FontDatabase.h>
  11. namespace Cards {
  12. static constexpr Gfx::CharacterBitmap s_diamond {
  13. " # "
  14. " ### "
  15. " ##### "
  16. " ####### "
  17. "#########"
  18. " ####### "
  19. " ##### "
  20. " ### "
  21. " # "sv,
  22. 9, 9
  23. };
  24. static constexpr Gfx::CharacterBitmap s_heart {
  25. " # # "
  26. " ### ### "
  27. "#########"
  28. "#########"
  29. "#########"
  30. " ####### "
  31. " ##### "
  32. " ### "
  33. " # "sv,
  34. 9, 9
  35. };
  36. static constexpr Gfx::CharacterBitmap s_spade {
  37. " # "
  38. " ### "
  39. " ##### "
  40. " ####### "
  41. "#########"
  42. "#########"
  43. " ## # ## "
  44. " ### "
  45. " ### "sv,
  46. 9, 9
  47. };
  48. static constexpr Gfx::CharacterBitmap s_club {
  49. " ### "
  50. " ##### "
  51. " ##### "
  52. " ## ### ## "
  53. "###########"
  54. "###########"
  55. "#### # ####"
  56. " ## ### ## "
  57. " ### "sv,
  58. 11, 9
  59. };
  60. static RefPtr<Gfx::Bitmap> s_background;
  61. static RefPtr<Gfx::Bitmap> s_background_inverted;
  62. Card::Card(Suit suit, Rank rank)
  63. : m_rect(Gfx::IntRect({}, { width, height }))
  64. , m_front(Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, { width, height }).release_value_but_fixme_should_propagate_errors())
  65. , m_suit(suit)
  66. , m_rank(rank)
  67. {
  68. VERIFY(to_underlying(rank) < card_count);
  69. Gfx::IntRect paint_rect({ 0, 0 }, { width, height });
  70. if (s_background.is_null()) {
  71. s_background = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, { width, height }).release_value_but_fixme_should_propagate_errors();
  72. Gfx::Painter bg_painter(*s_background);
  73. auto image = Gfx::Bitmap::try_load_from_file("/res/icons/cards/buggie-deck.png"sv).release_value_but_fixme_should_propagate_errors();
  74. float aspect_ratio = image->width() / static_cast<float>(image->height());
  75. auto target_size = Gfx::IntSize(static_cast<int>(aspect_ratio * (height - 5)), height - 5);
  76. bg_painter.fill_rect_with_rounded_corners(paint_rect, Color::Black, card_radius);
  77. auto inner_paint_rect = paint_rect.shrunken(2, 2);
  78. bg_painter.fill_rect_with_rounded_corners(inner_paint_rect, Color::White, card_radius - 1);
  79. bg_painter.draw_scaled_bitmap(
  80. { { (width - target_size.width()) / 2, (height - target_size.height()) / 2 }, target_size },
  81. *image, image->rect());
  82. s_background_inverted = invert_bitmap(*s_background);
  83. }
  84. Gfx::Painter painter(m_front);
  85. auto& font = Gfx::FontDatabase::default_font().bold_variant();
  86. painter.fill_rect_with_rounded_corners(paint_rect, Color::Black, card_radius);
  87. paint_rect.shrink(2, 2);
  88. painter.fill_rect_with_rounded_corners(paint_rect, Color::White, card_radius - 1);
  89. paint_rect.set_height(paint_rect.height() / 2);
  90. paint_rect.shrink(10, 6);
  91. auto text_rect = Gfx::IntRect { 4, 6, font.width("10"sv), font.glyph_height() };
  92. painter.draw_text(text_rect, card_rank_label(m_rank), font, Gfx::TextAlignment::Center, color());
  93. auto const& symbol = [&]() -> Gfx::CharacterBitmap const& {
  94. switch (m_suit) {
  95. case Suit::Diamonds:
  96. return s_diamond;
  97. case Suit::Clubs:
  98. return s_club;
  99. break;
  100. case Suit::Spades:
  101. return s_spade;
  102. case Suit::Hearts:
  103. return s_heart;
  104. default:
  105. VERIFY_NOT_REACHED();
  106. }
  107. }();
  108. painter.draw_bitmap(
  109. { text_rect.x() + (text_rect.width() - symbol.size().width()) / 2, text_rect.bottom() + 5 },
  110. symbol, color());
  111. for (int y = height / 2; y < height; ++y) {
  112. for (int x = 0; x < width; ++x) {
  113. m_front->set_pixel(x, y, m_front->get_pixel(width - x - 1, height - y - 1));
  114. }
  115. }
  116. m_front_inverted = invert_bitmap(*m_front);
  117. }
  118. void Card::draw(GUI::Painter& painter) const
  119. {
  120. VERIFY(!s_background.is_null());
  121. if (m_inverted)
  122. painter.blit(position(), m_upside_down ? *s_background_inverted : *m_front_inverted, m_front_inverted->rect());
  123. else
  124. painter.blit(position(), m_upside_down ? *s_background : *m_front, m_front->rect());
  125. }
  126. void Card::clear(GUI::Painter& painter, Color const& background_color) const
  127. {
  128. painter.fill_rect({ old_position(), { width, height } }, background_color);
  129. }
  130. void Card::save_old_position()
  131. {
  132. m_old_position = m_rect.location();
  133. m_old_position_valid = true;
  134. }
  135. void Card::clear_and_draw(GUI::Painter& painter, Color const& background_color)
  136. {
  137. if (is_old_position_valid())
  138. clear(painter, background_color);
  139. draw(painter);
  140. save_old_position();
  141. }
  142. NonnullRefPtr<Gfx::Bitmap> Card::invert_bitmap(Gfx::Bitmap& bitmap)
  143. {
  144. auto inverted_bitmap = bitmap.clone().release_value_but_fixme_should_propagate_errors();
  145. for (int y = 0; y < inverted_bitmap->height(); y++) {
  146. for (int x = 0; x < inverted_bitmap->width(); x++) {
  147. inverted_bitmap->set_pixel(x, y, inverted_bitmap->get_pixel(x, y).inverted());
  148. }
  149. }
  150. return *inverted_bitmap;
  151. }
  152. }