Serenity Operating System
at master 163 lines 4.9 kB view raw
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 9#include "CardGame.h" 10#include <LibCards/CardPainter.h> 11#include <LibConfig/Client.h> 12#include <LibGUI/Action.h> 13#include <LibGUI/Process.h> 14#include <LibGUI/Window.h> 15#include <LibGfx/Palette.h> 16 17namespace Cards { 18 19ErrorOr<NonnullRefPtr<GUI::Action>> make_cards_settings_action(GUI::Window* parent) 20{ 21 auto action = GUI::Action::create( 22 "&Cards Settings", {}, TRY(Gfx::Bitmap::load_from_file("/res/icons/16x16/games.png"sv)), [parent](auto&) { 23 GUI::Process::spawn_or_show_error(parent, "/bin/GamesSettings"sv, Array { "--open-tab", "cards" }); 24 }, 25 parent); 26 action->set_status_tip("Open the Game Settings for Cards"); 27 return action; 28} 29 30CardGame::CardGame() 31{ 32 auto background_color = Gfx::Color::from_string(Config::read_string("Games"sv, "Cards"sv, "BackgroundColor"sv)); 33 set_background_color(background_color.value_or(Color::from_rgb(0x008000))); 34} 35 36void CardGame::mark_intersecting_stacks_dirty(Cards::Card const& intersecting_card) 37{ 38 for (auto& stack : stacks()) { 39 if (intersecting_card.rect().intersects(stack->bounding_box())) 40 update(stack->bounding_box()); 41 } 42 43 update(intersecting_card.rect()); 44} 45 46Gfx::IntRect CardGame::moving_cards_bounds() const 47{ 48 if (!is_moving_cards()) 49 return {}; 50 51 // Note: This assumes that the cards are arranged in a line. 52 return m_moving_cards.first()->rect().united(m_moving_cards.last()->rect()); 53} 54 55ErrorOr<void> CardGame::pick_up_cards_from_stack(Cards::CardStack& stack, Gfx::IntPoint click_location, CardStack::MovementRule movement_rule) 56{ 57 TRY(stack.add_all_grabbed_cards(click_location, m_moving_cards, movement_rule)); 58 m_moving_cards_source_stack = stack; 59 return {}; 60} 61 62RefPtr<CardStack> CardGame::find_stack_to_drop_on(CardStack::MovementRule movement_rule) 63{ 64 auto bounds_to_check = moving_cards_bounds(); 65 66 RefPtr<CardStack> closest_stack; 67 float closest_distance = FLT_MAX; 68 69 for (auto& stack : stacks()) { 70 if (stack == moving_cards_source_stack()) 71 continue; 72 73 if (stack->bounding_box().intersects(bounds_to_check) 74 && stack->is_allowed_to_push(moving_cards().at(0), moving_cards().size(), movement_rule)) { 75 76 auto distance = bounds_to_check.center().distance_from(stack->bounding_box().center()); 77 if (distance < closest_distance) { 78 closest_stack = stack; 79 closest_distance = distance; 80 } 81 } 82 } 83 84 return closest_stack; 85} 86 87ErrorOr<void> CardGame::drop_cards_on_stack(Cards::CardStack& stack, CardStack::MovementRule movement_rule) 88{ 89 VERIFY(stack.is_allowed_to_push(m_moving_cards.at(0), m_moving_cards.size(), movement_rule)); 90 for (auto& to_intersect : moving_cards()) { 91 mark_intersecting_stacks_dirty(to_intersect); 92 TRY(stack.push(to_intersect)); 93 (void)moving_cards_source_stack()->pop(); 94 } 95 96 update(moving_cards_source_stack()->bounding_box()); 97 update(stack.bounding_box()); 98 99 return {}; 100} 101 102void CardGame::clear_moving_cards() 103{ 104 m_moving_cards_source_stack.clear(); 105 m_moving_cards.clear(); 106} 107 108void CardGame::dump_layout() const 109{ 110 dbgln("------------------------------"); 111 for (auto const& stack : stacks()) 112 dbgln("{}", stack); 113} 114 115void CardGame::config_string_did_change(DeprecatedString const& domain, DeprecatedString const& group, DeprecatedString const& key, DeprecatedString const& value) 116{ 117 if (domain == "Games" && group == "Cards") { 118 if (key == "BackgroundColor") { 119 if (auto maybe_color = Gfx::Color::from_string(value); maybe_color.has_value()) 120 set_background_color(maybe_color.value()); 121 return; 122 } 123 if (key == "CardBackImage") { 124 CardPainter::the().set_background_image_path(value); 125 update(); 126 return; 127 } 128 } 129} 130 131Gfx::Color CardGame::background_color() const 132{ 133 return palette().color(background_role()); 134} 135 136void CardGame::set_background_color(Gfx::Color color) 137{ 138 auto new_palette = palette(); 139 new_palette.set_color(Gfx::ColorRole::Background, color); 140 set_palette(new_palette); 141 142 CardPainter::the().set_background_color(color); 143} 144 145void CardGame::preview_card(CardStack& stack, Gfx::IntPoint click_location) 146{ 147 if (!stack.preview_card(click_location)) 148 return; 149 150 m_previewed_card_stack = stack; 151 update(stack.bounding_box()); 152} 153 154void CardGame::clear_card_preview() 155{ 156 VERIFY(m_previewed_card_stack); 157 158 update(m_previewed_card_stack->bounding_box()); 159 m_previewed_card_stack->clear_card_preview(); 160 m_previewed_card_stack = nullptr; 161} 162 163}