CardGame.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /*
  2. * Copyright (c) 2020, Till Mayer <till.mayer@web.de>
  3. * Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
  4. * Copyright (c) 2022, the SerenityOS developers.
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #include "CardGame.h"
  9. #include <LibCards/CardPainter.h>
  10. #include <LibConfig/Client.h>
  11. #include <LibGUI/Action.h>
  12. #include <LibGUI/Process.h>
  13. #include <LibGUI/Window.h>
  14. #include <LibGfx/Palette.h>
  15. namespace Cards {
  16. ErrorOr<NonnullRefPtr<GUI::Action>> make_cards_settings_action(GUI::Window* parent)
  17. {
  18. auto action = GUI::Action::create(
  19. "&Cards Settings", {}, TRY(Gfx::Bitmap::load_from_file("/res/icons/16x16/games.png"sv)), [parent](auto&) {
  20. GUI::Process::spawn_or_show_error(parent, "/bin/GamesSettings"sv, Array { "--open-tab", "cards" });
  21. },
  22. parent);
  23. action->set_status_tip("Open the Game Settings for Cards");
  24. return action;
  25. }
  26. CardGame::CardGame()
  27. {
  28. auto background_color = Gfx::Color::from_string(Config::read_string("Games"sv, "Cards"sv, "BackgroundColor"sv));
  29. set_background_color(background_color.value_or(Color::from_rgb(0x008000)));
  30. }
  31. void CardGame::mark_intersecting_stacks_dirty(Cards::Card const& intersecting_card)
  32. {
  33. for (auto& stack : stacks()) {
  34. if (intersecting_card.rect().intersects(stack.bounding_box()))
  35. update(stack.bounding_box());
  36. }
  37. update(intersecting_card.rect());
  38. }
  39. Gfx::IntRect CardGame::moving_cards_bounds() const
  40. {
  41. if (!is_moving_cards())
  42. return {};
  43. // Note: This assumes that the cards are arranged in a line.
  44. return m_moving_cards.first().rect().united(m_moving_cards.last().rect());
  45. }
  46. ErrorOr<void> CardGame::pick_up_cards_from_stack(Cards::CardStack& stack, Gfx::IntPoint click_location, CardStack::MovementRule movement_rule)
  47. {
  48. TRY(stack.add_all_grabbed_cards(click_location, m_moving_cards, movement_rule));
  49. m_moving_cards_source_stack = stack;
  50. return {};
  51. }
  52. RefPtr<CardStack> CardGame::find_stack_to_drop_on(CardStack::MovementRule movement_rule)
  53. {
  54. auto bounds_to_check = moving_cards_bounds();
  55. RefPtr<CardStack> closest_stack;
  56. float closest_distance = FLT_MAX;
  57. for (auto& stack : stacks()) {
  58. if (stack == moving_cards_source_stack())
  59. continue;
  60. if (stack.bounding_box().intersects(bounds_to_check)
  61. && stack.is_allowed_to_push(moving_cards().at(0), moving_cards().size(), movement_rule)) {
  62. auto distance = bounds_to_check.center().distance_from(stack.bounding_box().center());
  63. if (distance < closest_distance) {
  64. closest_stack = stack;
  65. closest_distance = distance;
  66. }
  67. }
  68. }
  69. return closest_stack;
  70. }
  71. ErrorOr<void> CardGame::drop_cards_on_stack(Cards::CardStack& stack, CardStack::MovementRule movement_rule)
  72. {
  73. VERIFY(stack.is_allowed_to_push(m_moving_cards.at(0), m_moving_cards.size(), movement_rule));
  74. for (auto& to_intersect : moving_cards()) {
  75. mark_intersecting_stacks_dirty(to_intersect);
  76. TRY(stack.push(to_intersect));
  77. (void)moving_cards_source_stack()->pop();
  78. }
  79. update(moving_cards_source_stack()->bounding_box());
  80. update(stack.bounding_box());
  81. return {};
  82. }
  83. void CardGame::clear_moving_cards()
  84. {
  85. m_moving_cards_source_stack.clear();
  86. m_moving_cards.clear();
  87. }
  88. void CardGame::dump_layout() const
  89. {
  90. dbgln("------------------------------");
  91. for (auto const& stack : stacks())
  92. dbgln("{}", stack);
  93. }
  94. void CardGame::config_string_did_change(DeprecatedString const& domain, DeprecatedString const& group, DeprecatedString const& key, DeprecatedString const& value)
  95. {
  96. if (domain == "Games" && group == "Cards") {
  97. if (key == "BackgroundColor") {
  98. if (auto maybe_color = Gfx::Color::from_string(value); maybe_color.has_value())
  99. set_background_color(maybe_color.value());
  100. return;
  101. }
  102. if (key == "CardBackImage") {
  103. CardPainter::the().set_background_image_path(value);
  104. update();
  105. return;
  106. }
  107. }
  108. }
  109. Gfx::Color CardGame::background_color() const
  110. {
  111. return palette().color(background_role());
  112. }
  113. void CardGame::set_background_color(Gfx::Color color)
  114. {
  115. auto new_palette = palette();
  116. new_palette.set_color(Gfx::ColorRole::Background, color);
  117. set_palette(new_palette);
  118. CardPainter::the().set_background_color(color);
  119. }
  120. void CardGame::preview_card(CardStack& stack, Gfx::IntPoint click_location)
  121. {
  122. if (!stack.preview_card(click_location))
  123. return;
  124. m_previewed_card_stack = stack;
  125. update(stack.bounding_box());
  126. }
  127. void CardGame::clear_card_preview()
  128. {
  129. VERIFY(m_previewed_card_stack);
  130. update(m_previewed_card_stack->bounding_box());
  131. m_previewed_card_stack->clear_card_preview();
  132. m_previewed_card_stack = nullptr;
  133. }
  134. }