ladybird/Userland/Libraries/LibCards/Card.cpp
2022-04-01 21:24:45 +01:00

183 lines
5.1 KiB
C++

/*
* Copyright (c) 2020, Till Mayer <till.mayer@web.de>
* Copyright (c) 2022, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "Card.h"
#include <LibGUI/Widget.h>
#include <LibGfx/Font.h>
#include <LibGfx/FontDatabase.h>
namespace Cards {
static constexpr Gfx::CharacterBitmap s_diamond {
" # "
" ### "
" ##### "
" ####### "
"#########"
" ####### "
" ##### "
" ### "
" # ",
9, 9
};
static constexpr Gfx::CharacterBitmap s_heart {
" # # "
" ### ### "
"#########"
"#########"
"#########"
" ####### "
" ##### "
" ### "
" # ",
9, 9
};
static constexpr Gfx::CharacterBitmap s_spade {
" # "
" ### "
" ##### "
" ####### "
"#########"
"#########"
" ## # ## "
" ### "
" ### ",
9, 9
};
static constexpr Gfx::CharacterBitmap s_club {
" ### "
" ##### "
" ##### "
" ## ### ## "
"###########"
"###########"
"#### # ####"
" ## ### ## "
" ### ",
11, 9
};
static RefPtr<Gfx::Bitmap> s_background;
static RefPtr<Gfx::Bitmap> s_background_inverted;
Card::Card(Suit suit, uint8_t value)
: m_rect(Gfx::IntRect({}, { width, height }))
, m_front(Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, { width, height }).release_value_but_fixme_should_propagate_errors())
, m_suit(suit)
, m_value(value)
{
VERIFY(value < card_count);
Gfx::IntRect paint_rect({ 0, 0 }, { width, height });
if (s_background.is_null()) {
s_background = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, { width, height }).release_value_but_fixme_should_propagate_errors();
Gfx::Painter bg_painter(*s_background);
auto image = Gfx::Bitmap::try_load_from_file("/res/icons/cards/buggie-deck.png").release_value_but_fixme_should_propagate_errors();
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.fill_rect_with_rounded_corners(paint_rect, Color::Black, card_radius);
auto inner_paint_rect = paint_rect.shrunken(2, 2);
bg_painter.fill_rect_with_rounded_corners(inner_paint_rect, Color::White, card_radius - 1);
bg_painter.draw_scaled_bitmap(
{ { (width - target_size.width()) / 2, (height - target_size.height()) / 2 }, target_size },
*image, image->rect());
s_background_inverted = invert_bitmap(*s_background);
}
Gfx::Painter painter(m_front);
auto& font = Gfx::FontDatabase::default_font().bold_variant();
auto label = labels[value];
painter.fill_rect_with_rounded_corners(paint_rect, Color::Black, card_radius);
paint_rect.shrink(2, 2);
painter.fill_rect_with_rounded_corners(paint_rect, Color::White, card_radius - 1);
paint_rect.set_height(paint_rect.height() / 2);
paint_rect.shrink(10, 6);
auto text_rect = Gfx::IntRect { 4, 6, font.width("10"), font.glyph_height() };
painter.draw_text(text_rect, label, font, Gfx::TextAlignment::Center, color());
auto const& symbol = [&]() -> Gfx::CharacterBitmap const& {
switch (m_suit) {
case Suit::Diamonds:
return s_diamond;
case Suit::Clubs:
return s_club;
break;
case Suit::Spades:
return s_spade;
case Suit::Hearts:
return s_heart;
default:
VERIFY_NOT_REACHED();
}
}();
painter.draw_bitmap(
{ text_rect.x() + (text_rect.width() - symbol.size().width()) / 2, text_rect.bottom() + 5 },
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));
}
}
m_front_inverted = invert_bitmap(*m_front);
}
void Card::draw(GUI::Painter& painter) const
{
VERIFY(!s_background.is_null());
if (m_inverted)
painter.blit(position(), m_upside_down ? *s_background_inverted : *m_front_inverted, m_front_inverted->rect());
else
painter.blit(position(), m_upside_down ? *s_background : *m_front, m_front->rect());
}
void Card::clear(GUI::Painter& painter, Color const& background_color) const
{
painter.fill_rect({ old_position(), { 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, Color const& background_color)
{
if (is_old_position_valid())
clear(painter, background_color);
draw(painter);
save_old_position();
}
NonnullRefPtr<Gfx::Bitmap> Card::invert_bitmap(Gfx::Bitmap& bitmap)
{
auto inverted_bitmap = bitmap.clone().release_value_but_fixme_should_propagate_errors();
for (int y = 0; y < inverted_bitmap->height(); y++) {
for (int x = 0; x < inverted_bitmap->width(); x++) {
inverted_bitmap->set_pixel(x, y, inverted_bitmap->get_pixel(x, y).inverted());
}
}
return *inverted_bitmap;
}
}