CardStack.h 3.6 KB

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