CardStack.h 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /*
  2. * Copyright (c) 2020, Till Mayer <till.mayer@web.de>
  3. * Copyright (c) 2023, David Ganz <david.g.ganz@gmail.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #pragma once
  8. #include "Card.h"
  9. #include <AK/Format.h>
  10. #include <AK/RefCounted.h>
  11. #include <AK/Vector.h>
  12. namespace Cards {
  13. class CardStack final : public RefCounted<CardStack> {
  14. public:
  15. enum class Type {
  16. Invalid,
  17. Stock,
  18. Normal,
  19. Waste,
  20. Play,
  21. Foundation
  22. };
  23. enum class MovementRule {
  24. Alternating,
  25. Same,
  26. Any,
  27. };
  28. CardStack();
  29. CardStack(Gfx::IntPoint position, Type type, RefPtr<CardStack> covered_stack = nullptr);
  30. bool is_empty() const { return m_stack.is_empty(); }
  31. Type type() const { return m_type; }
  32. Vector<NonnullRefPtr<Card>> const& stack() const { return m_stack; }
  33. size_t count() const { return m_stack.size(); }
  34. Card const& peek() const { return m_stack.last(); }
  35. Card& peek() { return m_stack.last(); }
  36. Gfx::IntRect const& bounding_box() const { return m_bounding_box; }
  37. bool make_top_card_visible(); // Returns true if the card was flipped.
  38. ErrorOr<void> push(NonnullRefPtr<Card>);
  39. NonnullRefPtr<Card> pop();
  40. ErrorOr<void> take_all(CardStack&);
  41. void rebound_cards();
  42. bool is_allowed_to_push(Card const&, size_t stack_size = 1, MovementRule movement_rule = MovementRule::Alternating) const;
  43. ErrorOr<void> add_all_grabbed_cards(Gfx::IntPoint click_location, Vector<NonnullRefPtr<Card>>& grabbed, MovementRule movement_rule = MovementRule::Alternating);
  44. void update_disabled_cards(MovementRule);
  45. bool preview_card(Gfx::IntPoint click_location);
  46. void clear_card_preview();
  47. void paint(GUI::Painter&, Gfx::Color background_color);
  48. void clear();
  49. void set_highlighted(bool highlighted) { m_highlighted = highlighted; }
  50. private:
  51. struct StackRules {
  52. uint8_t shift_x { 0 };
  53. uint8_t shift_y { 0 };
  54. uint8_t step { 1 };
  55. uint8_t shift_y_upside_down { 0 };
  56. };
  57. static constexpr StackRules rules_for_type(Type stack_type)
  58. {
  59. switch (stack_type) {
  60. case Type::Foundation:
  61. return { 2, 1, 4, 1 };
  62. case Type::Normal:
  63. return { 0, 20, 1, 3 };
  64. case Type::Stock:
  65. return { 2, 1, 8, 1 };
  66. case Type::Waste:
  67. return { 0, 0, 1, 0 };
  68. case Type::Play:
  69. return { 15, 0, 1, 0 };
  70. default:
  71. return {};
  72. }
  73. }
  74. void calculate_bounding_box();
  75. // An optional stack that this stack is painted on top of.
  76. // eg, in Solitaire the Play stack is positioned over the Waste stack.
  77. RefPtr<CardStack> m_covered_stack;
  78. Vector<NonnullRefPtr<Card>> m_stack;
  79. Vector<Gfx::IntPoint> m_stack_positions;
  80. Gfx::IntPoint m_position;
  81. Gfx::IntRect m_bounding_box;
  82. Type m_type { Type::Invalid };
  83. StackRules m_rules;
  84. Gfx::IntRect m_base;
  85. bool m_highlighted { false };
  86. };
  87. }
  88. template<>
  89. struct AK::Formatter<Cards::CardStack> : Formatter<FormatString> {
  90. ErrorOr<void> format(FormatBuilder& builder, Cards::CardStack const& stack)
  91. {
  92. StringView type;
  93. switch (stack.type()) {
  94. case Cards::CardStack::Type::Stock:
  95. type = "Stock"sv;
  96. break;
  97. case Cards::CardStack::Type::Normal:
  98. type = "Normal"sv;
  99. break;
  100. case Cards::CardStack::Type::Foundation:
  101. type = "Foundation"sv;
  102. break;
  103. case Cards::CardStack::Type::Waste:
  104. type = "Waste"sv;
  105. break;
  106. case Cards::CardStack::Type::Play:
  107. type = "Play"sv;
  108. break;
  109. default:
  110. VERIFY_NOT_REACHED();
  111. }
  112. StringBuilder cards;
  113. bool first_card = true;
  114. for (auto const& card : stack.stack()) {
  115. cards.appendff("{}{}", (first_card ? "" : " "), card);
  116. first_card = false;
  117. }
  118. return Formatter<FormatString>::format(builder, "{:<10} {:>16}: {}"sv, type, stack.bounding_box(), cards.to_byte_string());
  119. }
  120. };