123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- /*
- * Copyright (c) 2020, the SerenityOS developers.
- * Copyright (c) 2022, the SerenityOS developers.
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include "BoardView.h"
- #include <LibGUI/Painter.h>
- #include <LibGfx/Font/Font.h>
- #include <LibGfx/Font/FontDatabase.h>
- #include <LibGfx/Palette.h>
- BoardView::BoardView(Game::Board const* board)
- : m_board(board)
- {
- }
- void BoardView::set_board(Game::Board const* board)
- {
- if (has_timer())
- stop_timer();
- slide_animation_frame = 0;
- pop_in_animation_frame = 0;
- start_timer(frame_duration_ms);
- if (m_board == board)
- return;
- if (!board) {
- m_board = nullptr;
- return;
- }
- bool must_resize = !m_board || m_board->tiles().size() != board->tiles().size();
- m_board = board;
- if (must_resize)
- resize();
- update();
- }
- void BoardView::pick_font()
- {
- String best_font_name;
- int best_font_size = -1;
- auto& font_database = Gfx::FontDatabase::the();
- font_database.for_each_font([&](Gfx::Font const& font) {
- if (font.family() != "Liza" || font.weight() != 700)
- return;
- auto size = font.glyph_height();
- if (size * 2 <= m_cell_size && size > best_font_size) {
- best_font_name = font.qualified_name();
- best_font_size = size;
- }
- });
- auto font = font_database.get_by_name(best_font_name);
- set_font(font);
- m_min_cell_size = best_font_size;
- }
- size_t BoardView::rows() const
- {
- if (!m_board)
- return 0;
- return m_board->tiles().size();
- }
- size_t BoardView::columns() const
- {
- if (!m_board)
- return 0;
- if (m_board->tiles().is_empty())
- return 0;
- return m_board->tiles()[0].size();
- }
- void BoardView::resize_event(GUI::ResizeEvent&)
- {
- resize();
- }
- void BoardView::resize()
- {
- constexpr float padding_ratio = 7;
- m_padding = min(
- width() / (columns() * (padding_ratio + 1) + 1),
- height() / (rows() * (padding_ratio + 1) + 1));
- m_cell_size = m_padding * padding_ratio;
- pick_font();
- }
- void BoardView::keydown_event(GUI::KeyEvent& event)
- {
- if (!on_move)
- return;
- switch (event.key()) {
- case KeyCode::Key_A:
- case KeyCode::Key_Left:
- on_move(Game::Direction::Left);
- break;
- case KeyCode::Key_D:
- case KeyCode::Key_Right:
- on_move(Game::Direction::Right);
- break;
- case KeyCode::Key_W:
- case KeyCode::Key_Up:
- on_move(Game::Direction::Up);
- break;
- case KeyCode::Key_S:
- case KeyCode::Key_Down:
- on_move(Game::Direction::Down);
- break;
- default:
- return;
- }
- }
- Gfx::Color BoardView::background_color_for_cell(u32 value)
- {
- switch (value) {
- case 0:
- return Color::from_rgb(0xcdc1b4);
- case 2:
- return Color::from_rgb(0xeee4da);
- case 4:
- return Color::from_rgb(0xede0c8);
- case 8:
- return Color::from_rgb(0xf2b179);
- case 16:
- return Color::from_rgb(0xf59563);
- case 32:
- return Color::from_rgb(0xf67c5f);
- case 64:
- return Color::from_rgb(0xf65e3b);
- case 128:
- return Color::from_rgb(0xedcf72);
- case 256:
- return Color::from_rgb(0xedcc61);
- case 512:
- return Color::from_rgb(0xedc850);
- case 1024:
- return Color::from_rgb(0xedc53f);
- case 2048:
- return Color::from_rgb(0xedc22e);
- default:
- VERIFY(value > 2048);
- return Color::from_rgb(0x3c3a32);
- }
- }
- Gfx::Color BoardView::text_color_for_cell(u32 value)
- {
- if (value <= 4)
- return Color::from_rgb(0x776e65);
- return Color::from_rgb(0xf9f6f2);
- }
- void BoardView::timer_event(Core::TimerEvent&)
- {
- if (slide_animation_frame < animation_duration) {
- slide_animation_frame++;
- update();
- } else if (pop_in_animation_frame < animation_duration) {
- pop_in_animation_frame++;
- update();
- if (pop_in_animation_frame == animation_duration)
- stop_timer();
- }
- }
- void BoardView::paint_event(GUI::PaintEvent& event)
- {
- Frame::paint_event(event);
- Color background_color = Color::from_rgb(0xbbada0);
- GUI::Painter painter(*this);
- painter.add_clip_rect(event.rect());
- painter.add_clip_rect(frame_inner_rect());
- painter.translate(frame_thickness(), frame_thickness());
- if (!m_board) {
- painter.fill_rect(rect(), background_color);
- return;
- }
- auto& tiles = m_board->tiles();
- Gfx::IntRect field_rect {
- 0,
- 0,
- static_cast<int>(m_padding + (m_cell_size + m_padding) * columns()),
- static_cast<int>(m_padding + (m_cell_size + m_padding) * rows())
- };
- field_rect.center_within(rect());
- painter.fill_rect(field_rect, background_color);
- auto tile_center = [&](size_t row, size_t column) {
- return Gfx::IntPoint {
- field_rect.x() + m_padding + (m_cell_size + m_padding) * column + m_cell_size / 2,
- field_rect.y() + m_padding + (m_cell_size + m_padding) * row + m_cell_size / 2,
- };
- };
- if (slide_animation_frame < animation_duration) {
- // background
- for (size_t column = 0; column < columns(); ++column) {
- for (size_t row = 0; row < rows(); ++row) {
- auto center = tile_center(row, column);
- auto tile_size = Gfx::IntSize { m_cell_size, m_cell_size };
- auto rect = Gfx::IntRect::centered_on(center, tile_size);
- painter.fill_rect(rect, background_color_for_cell(0));
- }
- }
- for (auto& sliding_tile : m_board->sliding_tiles()) {
- auto center_from = tile_center(sliding_tile.row_from, sliding_tile.column_from);
- auto center_to = tile_center(sliding_tile.row_to, sliding_tile.column_to);
- auto offset = Gfx::FloatPoint(center_to - center_from);
- auto center = center_from + Gfx::IntPoint(offset * (slide_animation_frame / (float)animation_duration));
- auto tile_size = Gfx::IntSize { m_cell_size, m_cell_size };
- auto rect = Gfx::IntRect::centered_on(center, tile_size);
- painter.fill_rect(rect, background_color_for_cell(sliding_tile.value_from));
- painter.draw_text(rect, String::number(sliding_tile.value_from), font(), Gfx::TextAlignment::Center, text_color_for_cell(sliding_tile.value_from));
- }
- } else {
- for (size_t column = 0; column < columns(); ++column) {
- for (size_t row = 0; row < rows(); ++row) {
- auto center = tile_center(row, column);
- auto tile_size = Gfx::IntSize { m_cell_size, m_cell_size };
- if (pop_in_animation_frame < animation_duration && Game::Board::Position { row, column } == m_board->last_added_position()) {
- float pop_in_size = m_min_cell_size + (m_cell_size - m_min_cell_size) * (pop_in_animation_frame / (float)animation_duration);
- tile_size = Gfx::IntSize { pop_in_size, pop_in_size };
- }
- auto rect = Gfx::IntRect::centered_on(center, tile_size);
- auto entry = tiles[row][column];
- painter.fill_rect(rect, background_color_for_cell(entry));
- if (entry > 0)
- painter.draw_text(rect, String::number(entry), font(), Gfx::TextAlignment::Center, text_color_for_cell(entry));
- }
- }
- }
- }
|