diff options
Diffstat (limited to 'Userland/Games/Solitaire/Card.cpp')
-rw-r--r-- | Userland/Games/Solitaire/Card.cpp | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/Userland/Games/Solitaire/Card.cpp b/Userland/Games/Solitaire/Card.cpp new file mode 100644 index 0000000000..23c3473632 --- /dev/null +++ b/Userland/Games/Solitaire/Card.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2020, Till Mayer <till.mayer@web.de> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Card.h" +#include <LibGUI/Widget.h> +#include <LibGfx/Font.h> +#include <LibGfx/FontDatabase.h> + +static const NonnullRefPtr<Gfx::CharacterBitmap> s_diamond = Gfx::CharacterBitmap::create_from_ascii( + " # " + " ### " + " ##### " + " ####### " + "#########" + " ####### " + " ##### " + " ### " + " # ", + 9, 9); + +static const NonnullRefPtr<Gfx::CharacterBitmap> s_heart = Gfx::CharacterBitmap::create_from_ascii( + " # # " + " ### ### " + "#########" + "#########" + "#########" + " ####### " + " ##### " + " ### " + " # ", + 9, 9); + +static const NonnullRefPtr<Gfx::CharacterBitmap> s_spade = Gfx::CharacterBitmap::create_from_ascii( + " # " + " ### " + " ##### " + " ####### " + "#########" + "#########" + " ## # ## " + " ### " + " ### ", + 9, 9); + +static const NonnullRefPtr<Gfx::CharacterBitmap> s_club = Gfx::CharacterBitmap::create_from_ascii( + " ### " + " ##### " + " ##### " + " ## ### ## " + "###########" + "###########" + "#### # ####" + " ## ### ## " + " ### ", + 11, 9); + +static RefPtr<Gfx::Bitmap> s_background; + +Card::Card(Type type, uint8_t value) + : m_rect(Gfx::IntRect({}, { width, height })) + , m_front(*Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, { width, height })) + , m_type(type) + , m_value(value) +{ + ASSERT(value < card_count); + Gfx::IntRect paint_rect({ 0, 0 }, { width, height }); + + if (s_background.is_null()) { + s_background = Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, { width, height }); + Gfx::Painter bg_painter(*s_background); + + s_background->fill(Color::White); + auto image = Gfx::Bitmap::load_from_file("/res/icons/solitaire/buggie-deck.png"); + ASSERT(!image.is_null()); + + float aspect_ratio = image->width() / static_cast<float>(image->height()); + auto target_size = Gfx::IntSize(static_cast<int>(aspect_ratio * (height - 5)), height - 5); + + bg_painter.draw_scaled_bitmap( + { { (width - target_size.width()) / 2, (height - target_size.height()) / 2 }, target_size }, + *image, image->rect()); + bg_painter.draw_rect(paint_rect, Color::Black); + } + + Gfx::Painter painter(m_front); + auto& font = Gfx::FontDatabase::default_bold_font(); + static const String labels[] = { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K" }; + + auto label = labels[value]; + m_front->fill(Color::White); + painter.draw_rect(paint_rect, Color::Black); + paint_rect.set_height(paint_rect.height() / 2); + paint_rect.shrink(10, 6); + + painter.draw_text(paint_rect, label, font, Gfx::TextAlignment::TopLeft, color()); + + NonnullRefPtr<Gfx::CharacterBitmap> symbol = s_diamond; + switch (m_type) { + case Diamonds: + symbol = s_diamond; + break; + case Clubs: + symbol = s_club; + break; + case Spades: + symbol = s_spade; + break; + case Hearts: + symbol = s_heart; + break; + default: + ASSERT_NOT_REACHED(); + } + + painter.draw_bitmap( + { paint_rect.x() + (font.width(label) - symbol->size().width()) / 2, font.glyph_height() + paint_rect.y() + 3 }, + symbol, color()); + + for (int y = height / 2; y < height; ++y) { + for (int x = 0; x < width; ++x) { + m_front->set_pixel(x, y, m_front->get_pixel(width - x - 1, height - y - 1)); + } + } +} + +Card::~Card() +{ +} + +void Card::draw(GUI::Painter& painter) const +{ + ASSERT(!s_background.is_null()); + painter.blit(position(), m_upside_down ? *s_background : *m_front, m_front->rect()); +} + +void Card::clear(GUI::Painter& painter, const Color& background_color) const +{ + painter.fill_rect({ old_positon(), { width, height } }, background_color); +} + +void Card::save_old_position() +{ + m_old_position = m_rect.location(); + m_old_position_valid = true; +} + +void Card::clear_and_draw(GUI::Painter& painter, const Color& background_color) +{ + if (is_old_position_valid()) + clear(painter, background_color); + + draw(painter); + save_old_position(); +} |