From 19dfdeeaecdccea97c1d51b0dc0949e32d44f5f8 Mon Sep 17 00:00:00 2001 From: Tim Ledbetter Date: Sat, 16 Sep 2023 14:19:32 +0100 Subject: [PATCH] GameOfLife: Add a tick counter to the status bar The counter is incremented after each new generation and reset whenever any cell on the board is toggled. Resizing the board does not reset the tick count. --- Userland/Games/GameOfLife/BoardWidget.cpp | 20 +++++++++++++ Userland/Games/GameOfLife/BoardWidget.h | 7 +++-- Userland/Games/GameOfLife/GameOfLife.gml | 1 + Userland/Games/GameOfLife/main.cpp | 35 ++++++++++++----------- 4 files changed, 45 insertions(+), 18 deletions(-) diff --git a/Userland/Games/GameOfLife/BoardWidget.cpp b/Userland/Games/GameOfLife/BoardWidget.cpp index 07ad23d2a1..b3ff7997c4 100644 --- a/Userland/Games/GameOfLife/BoardWidget.cpp +++ b/Userland/Games/GameOfLife/BoardWidget.cpp @@ -38,6 +38,12 @@ BoardWidget::BoardWidget(size_t rows, size_t columns) void BoardWidget::run_generation() { m_board->run_generation(); + if (!m_board->is_stalled()) + m_ticks++; + + if (on_tick) + on_tick(m_ticks); + update(); if (m_board->is_stalled()) { if (on_stall) @@ -91,6 +97,8 @@ void BoardWidget::toggle_cell(size_t row, size_t column) if (m_running || !m_toggling_cells || (m_last_cell_toggled.row == row && m_last_cell_toggled.column == column)) return; + m_ticks = 0; + m_last_cell_toggled = { row, column }; m_board->toggle_cell(row, column); @@ -100,6 +108,18 @@ void BoardWidget::toggle_cell(size_t row, size_t column) update(); } +void BoardWidget::clear_cells() +{ + m_ticks = 0; + m_board->clear(); +} + +void BoardWidget::randomize_cells() +{ + m_ticks = 0; + m_board->randomize(); +} + int BoardWidget::get_cell_size() const { int width = rect().width() / m_board->columns(); diff --git a/Userland/Games/GameOfLife/BoardWidget.h b/Userland/Games/GameOfLife/BoardWidget.h index 1bc8b0006d..1b3d5431f9 100644 --- a/Userland/Games/GameOfLife/BoardWidget.h +++ b/Userland/Games/GameOfLife/BoardWidget.h @@ -36,8 +36,8 @@ public: } void toggle_cell(size_t row, size_t column); - void clear_cells() { m_board->clear(); } - void randomize_cells() { m_board->randomize(); } + void clear_cells(); + void randomize_cells(); int get_cell_size() const; Gfx::IntSize get_board_offset() const; @@ -64,6 +64,7 @@ public: int running_timer_interval() const { return m_running_timer_interval; } void set_running_timer_interval(int interval); + Function on_tick; Function on_running_state_change; Function on_stall; Function on_pattern_selection_state_change; @@ -87,6 +88,8 @@ private: int m_running_timer_interval { 500 }; int m_running_pattern_preview_timer_interval { 100 }; + u64 m_ticks { 0 }; + RefPtr m_context_menu; RefPtr m_timer; diff --git a/Userland/Games/GameOfLife/GameOfLife.gml b/Userland/Games/GameOfLife/GameOfLife.gml index 77f5c0c3f7..b94d815872 100644 --- a/Userland/Games/GameOfLife/GameOfLife.gml +++ b/Userland/Games/GameOfLife/GameOfLife.gml @@ -61,5 +61,6 @@ @GUI::Statusbar { name: "statusbar" + segment_count: 2 } } diff --git a/Userland/Games/GameOfLife/main.cpp b/Userland/Games/GameOfLife/main.cpp index fbb57b8612..b4895a06d5 100644 --- a/Userland/Games/GameOfLife/main.cpp +++ b/Userland/Games/GameOfLife/main.cpp @@ -66,13 +66,9 @@ ErrorOr serenity_main(Main::Arguments arguments) board_widget->set_min_size(board_columns, board_rows); auto& statusbar = *main_widget->find_descendant_of_type_named("statusbar"); - statusbar.set_text(click_tip); - GUI::Application::the()->on_action_enter = [&statusbar](GUI::Action& action) { - statusbar.set_override_text(action.status_tip()); - }; - GUI::Application::the()->on_action_leave = [&statusbar](GUI::Action&) { - statusbar.set_override_text({}); - }; + auto width = board_widget->font().width("Ticks: 000,000,000"sv) + board_widget->font().max_glyph_width(); + statusbar.segment(1).set_fixed_width(ceil(width)); + statusbar.segment(0).set_text(click_tip); auto& columns_spinbox = *main_widget->find_descendant_of_type_named("columns_spinbox"); auto& rows_spinbox = *main_widget->find_descendant_of_type_named("rows_spinbox"); @@ -81,7 +77,7 @@ ErrorOr serenity_main(Main::Arguments arguments) rows_spinbox.set_value(board_rows); auto size_changed_function = [&] { - statusbar.set_text(click_tip); + statusbar.segment(0).set_text(click_tip); board_widget->resize_board(rows_spinbox.value(), columns_spinbox.value()); board_widget->update(); }; @@ -107,20 +103,22 @@ ErrorOr serenity_main(Main::Arguments arguments) main_toolbar.add_action(play_pause_action); auto run_one_generation_action = GUI::Action::create("Run &Next Generation", { Mod_Ctrl, Key_Equal }, TRY(Gfx::Bitmap::load_from_file("/res/icons/16x16/go-forward.png"sv)), [&](const GUI::Action&) { - statusbar.set_text(click_tip); + statusbar.segment(0).set_text(click_tip); board_widget->run_generation(); }); main_toolbar.add_action(run_one_generation_action); auto clear_board_action = GUI::Action::create("&Clear board", { Mod_Ctrl, Key_N }, TRY(Gfx::Bitmap::load_from_file("/res/icons/16x16/delete.png"sv)), [&](auto&) { - statusbar.set_text(click_tip); + statusbar.segment(0).set_text(click_tip); + statusbar.segment(1).set_text({}); board_widget->clear_cells(); board_widget->update(); }); main_toolbar.add_action(clear_board_action); auto randomize_cells_action = GUI::Action::create("&Randomize board", { Mod_Ctrl, Key_R }, TRY(Gfx::Bitmap::load_from_file("/res/icons/16x16/reload.png"sv)), [&](auto&) { - statusbar.set_text(click_tip); + statusbar.segment(0).set_text(click_tip); + statusbar.segment(1).set_text({}); board_widget->randomize_cells(); board_widget->update(); }); @@ -151,14 +149,18 @@ ErrorOr serenity_main(Main::Arguments arguments) })); help_menu->add_action(GUI::CommonActions::make_about_action("Game of Life"_string, app_icon, window)); + board_widget->on_tick = [&](u64 ticks) { + statusbar.segment(1).set_text(String::formatted("Ticks: {:'}", ticks).release_value_but_fixme_should_propagate_errors()); + }; + board_widget->on_running_state_change = [&]() { if (board_widget->is_running()) { - statusbar.set_text("Running..."_string); + statusbar.segment(0).set_text("Running..."_string); play_pause_action->set_icon(paused_icon); play_pause_action->set_text("&Pause"); main_widget->set_override_cursor(Gfx::StandardCursor::None); } else { - statusbar.set_text(click_tip); + statusbar.segment(0).set_text("Paused"_string); play_pause_action->set_icon(play_icon); play_pause_action->set_text("&Play"); main_widget->set_override_cursor(Gfx::StandardCursor::Drag); @@ -179,18 +181,19 @@ ErrorOr serenity_main(Main::Arguments arguments) board_widget->on_stall = [&] { play_pause_action->activate(); - statusbar.set_text("Stalled..."_string); + statusbar.segment(0).set_text("Stalled"_string); }; board_widget->on_cell_toggled = [&](auto, auto, auto) { - statusbar.set_text(click_tip); + statusbar.segment(0).set_text(click_tip); + statusbar.segment(1).set_text({}); }; board_widget->on_pattern_selection_state_change = [&] { rotate_pattern_action->set_enabled(board_widget->selected_pattern() != nullptr); }; - window->resize(500, 420); + window->resize(600, 500); window->show(); return app->exec();