Serenity Operating System
1/*
2 * Copyright (c) 2020, Till Mayer <till.mayer@web.de>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "Card.h"
28#include <LibGUI/Widget.h>
29#include <LibGfx/Font.h>
30
31static const NonnullRefPtr<Gfx::CharacterBitmap> s_diamond = Gfx::CharacterBitmap::create_from_ascii(
32 " # "
33 " ### "
34 " ##### "
35 " ####### "
36 "#########"
37 " ####### "
38 " ##### "
39 " ### "
40 " # ",
41 9, 9);
42
43static const NonnullRefPtr<Gfx::CharacterBitmap> s_heart = Gfx::CharacterBitmap::create_from_ascii(
44 " # # "
45 " ### ### "
46 "#########"
47 "#########"
48 "#########"
49 " ####### "
50 " ##### "
51 " ### "
52 " # ",
53 9, 9);
54
55static const NonnullRefPtr<Gfx::CharacterBitmap> s_spade = Gfx::CharacterBitmap::create_from_ascii(
56 " # "
57 " ### "
58 " ##### "
59 " ####### "
60 "#########"
61 "#########"
62 " ## # ## "
63 " ### "
64 " ### ",
65 9, 9);
66
67static const NonnullRefPtr<Gfx::CharacterBitmap> s_club = Gfx::CharacterBitmap::create_from_ascii(
68 " ### "
69 " ##### "
70 " ##### "
71 " ## ### ## "
72 "###########"
73 "###########"
74 "#### # ####"
75 " ## ### ## "
76 " ### ",
77 11, 9);
78
79static RefPtr<Gfx::Bitmap> s_background;
80
81Card::Card(Type type, uint8_t value)
82 : m_rect(Gfx::Rect({}, { width, height }))
83 , m_front(Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, { width, height }))
84 , m_type(type)
85 , m_value(value)
86{
87 ASSERT(value < card_count);
88 Gfx::Rect paint_rect({ 0, 0 }, { width, height });
89
90 if (s_background.is_null()) {
91 s_background = Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, { width, height });
92 Gfx::Painter bg_painter(*s_background);
93
94 s_background->fill(Color::White);
95 auto image = Gfx::Bitmap::load_from_file("/res/icons/buggie.png");
96 ASSERT(!image.is_null());
97
98 float aspect_ratio = image->width() / static_cast<float>(image->height());
99 auto target_size = Gfx::Size(static_cast<int>(aspect_ratio * (height - 5)), height - 5);
100
101 bg_painter.draw_scaled_bitmap(
102 { { (width - target_size.width()) / 2, (height - target_size.height()) / 2 }, target_size },
103 *image, image->rect());
104 bg_painter.draw_rect(paint_rect, Color::Black);
105 }
106
107 Gfx::Painter painter(m_front);
108 auto& font = Gfx::Font::default_bold_font();
109 static const String labels[] = { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K" };
110
111 auto label = labels[value];
112 m_front->fill(Color::White);
113 painter.draw_rect(paint_rect, Color::Black);
114 paint_rect.set_height(paint_rect.height() / 2);
115 paint_rect.shrink(10, 6);
116
117 painter.draw_text(paint_rect, label, font, Gfx::TextAlignment::TopLeft, color());
118
119 NonnullRefPtr<Gfx::CharacterBitmap> symbol = s_diamond;
120 switch (m_type) {
121 case Diamonds:
122 symbol = s_diamond;
123 break;
124 case Clubs:
125 symbol = s_club;
126 break;
127 case Spades:
128 symbol = s_spade;
129 break;
130 case Hearts:
131 symbol = s_heart;
132 break;
133 default:
134 ASSERT_NOT_REACHED();
135 }
136
137 painter.draw_bitmap(
138 { paint_rect.x() + (font.width(label) - symbol->size().width()) / 2, font.glyph_height() + paint_rect.y() + 3 },
139 symbol, color());
140
141 for (int y = height / 2; y < height; ++y) {
142 for (int x = 0; x < width; ++x) {
143 m_front->set_pixel(x, y, m_front->get_pixel(width - x - 1, height - y - 1));
144 }
145 }
146}
147
148Card::~Card()
149{
150}
151
152void Card::draw(GUI::Painter& painter) const
153{
154 ASSERT(!s_background.is_null());
155 painter.blit(position(), m_upside_down ? *s_background : *m_front, m_front->rect());
156}
157
158void Card::clear(GUI::Painter& painter, const Color& background_color) const
159{
160 painter.fill_rect({ old_positon(), { width, height } }, background_color);
161}
162
163void Card::save_old_position()
164{
165 m_old_position = m_rect.location();
166 m_old_position_valid = true;
167}
168
169void Card::draw_complete(GUI::Painter& painter, const Color& background_color)
170{
171 if (is_old_position_valid())
172 clear(painter, background_color);
173
174 draw(painter);
175 save_old_position();
176}