From cc5ea3aa4c09d8e617f51f554e8f452a2bf227b9 Mon Sep 17 00:00:00 2001 From: Arda Cinar Date: Thu, 8 Dec 2022 14:31:34 +0300 Subject: [PATCH] MasterWord: Display messages in a statusbar In the "inspiration" for this game, messages are displayed on top of the game area in case an invalid guess is inputted. After a few seconds, they disappear. In a similar fashion, a statusbar is created on the game window and similar messages are outputted there. --- Userland/Games/MasterWord/CMakeLists.txt | 6 ++++ Userland/Games/MasterWord/MasterWord.gml | 13 ++++++++ Userland/Games/MasterWord/WordGame.cpp | 39 +++++++++++++++++++--- Userland/Games/MasterWord/WordGame.h | 14 ++++++++ Userland/Games/MasterWord/main.cpp | 41 ++++++++++++++++-------- 5 files changed, 94 insertions(+), 19 deletions(-) create mode 100644 Userland/Games/MasterWord/MasterWord.gml diff --git a/Userland/Games/MasterWord/CMakeLists.txt b/Userland/Games/MasterWord/CMakeLists.txt index 30dd07c8b8..7a90f5824c 100644 --- a/Userland/Games/MasterWord/CMakeLists.txt +++ b/Userland/Games/MasterWord/CMakeLists.txt @@ -4,10 +4,16 @@ serenity_component( TARGETS MasterWord ) +compile_gml(MasterWord.gml MasterWordGML.h master_word_gml) + set(SOURCES main.cpp WordGame.cpp ) +set(GENERATED_SOURCES + MasterWordGML.h +) + serenity_app(MasterWord ICON app-masterword) target_link_libraries(MasterWord PRIVATE LibCore LibGfx LibGUI LibConfig LibMain LibDesktop) diff --git a/Userland/Games/MasterWord/MasterWord.gml b/Userland/Games/MasterWord/MasterWord.gml new file mode 100644 index 0000000000..4e2c44e37d --- /dev/null +++ b/Userland/Games/MasterWord/MasterWord.gml @@ -0,0 +1,13 @@ +@GUI::Widget { + layout: @GUI::VerticalBoxLayout { + spacing: 0 + } + + @MasterWord::WordGame { + name: "word_game" + } + + @GUI::Statusbar { + name: "statusbar" + } +} diff --git a/Userland/Games/MasterWord/WordGame.cpp b/Userland/Games/MasterWord/WordGame.cpp index a1df931350..681cdf638d 100644 --- a/Userland/Games/MasterWord/WordGame.cpp +++ b/Userland/Games/MasterWord/WordGame.cpp @@ -7,18 +7,25 @@ #include "WordGame.h" #include #include +#include #include #include +#include #include #include #include +#include #include #include #include +REGISTER_WIDGET(MasterWord, WordGame) + // TODO: Add stats +namespace MasterWord { WordGame::WordGame() + : m_clear_message_timer(Core::Timer::create_single_shot(5000, [this] { clear_message(); })) { read_words(); m_num_letters = Config::read_i32("MasterWord"sv, ""sv, "word_length"sv, 5); @@ -42,6 +49,7 @@ void WordGame::reset() reset(); } } + clear_message(); update(); } @@ -82,10 +90,17 @@ void WordGame::keydown_event(GUI::KeyEvent& event) m_current_guess = m_current_guess.substring(0, m_current_guess.length() - 1); m_last_word_not_in_dictionary = false; } - // If enough letters and return pressed - else if (m_current_guess.length() == m_num_letters && event.key() == KeyCode::Key_Return) { - if (is_in_dictionary(m_current_guess)) { + // If return pressed + else if (event.key() == KeyCode::Key_Return) { + if (m_current_guess.length() < m_num_letters) { + show_message("Not enough letters"sv); + } else if (!is_in_dictionary(m_current_guess)) { + show_message("Not in dictionary"sv); + m_last_word_not_in_dictionary = true; + } else { m_last_word_not_in_dictionary = false; + clear_message(); + add_guess(m_current_guess); auto won = m_current_guess == m_current_word; m_current_guess = {}; @@ -96,8 +111,6 @@ void WordGame::keydown_event(GUI::KeyEvent& event) GUI::MessageBox::show(window(), DeprecatedString::formatted("You lose!\nThe word was {}", m_current_word), "MasterWord"sv); reset(); } - } else { - m_last_word_not_in_dictionary = true; } } @@ -291,3 +304,19 @@ void WordGame::add_guess(AK::StringView guess) m_guesses.append({ guess, letter_states }); update(); } + +void WordGame::show_message(StringView message) const +{ + m_clear_message_timer->restart(); + if (on_message) + on_message(message); +} + +void WordGame::clear_message() const +{ + m_clear_message_timer->stop(); + if (on_message) + on_message({}); +} + +} diff --git a/Userland/Games/MasterWord/WordGame.h b/Userland/Games/MasterWord/WordGame.h index b7f723404d..7023e21865 100644 --- a/Userland/Games/MasterWord/WordGame.h +++ b/Userland/Games/MasterWord/WordGame.h @@ -7,10 +7,16 @@ #pragma once #include +#include +#include +#include #include +#include #include #include +namespace MasterWord { + class WordGame : public GUI::Frame { C_OBJECT(WordGame); @@ -32,9 +38,13 @@ public: void add_guess(AK::StringView guess); bool is_in_dictionary(AK::StringView guess); + Function)> on_message; + private: WordGame(); void read_words(); + void show_message(StringView message) const; + void clear_message() const; virtual void paint_event(GUI::PaintEvent&) override; virtual void keydown_event(GUI::KeyEvent&) override; @@ -76,4 +86,8 @@ private: AK::DeprecatedString m_current_word; HashMap> m_words; + + NonnullRefPtr m_clear_message_timer; }; + +} diff --git a/Userland/Games/MasterWord/main.cpp b/Userland/Games/MasterWord/main.cpp index 5b4ec79b3e..e377fd437f 100644 --- a/Userland/Games/MasterWord/main.cpp +++ b/Userland/Games/MasterWord/main.cpp @@ -6,6 +6,7 @@ #include "WordGame.h" #include +#include #include #include #include @@ -16,6 +17,7 @@ #include #include #include +#include #include #include @@ -44,20 +46,24 @@ ErrorOr serenity_main(Main::Arguments arguments) window->set_title("MasterWord"); window->set_resizable(false); - auto game = TRY(window->try_set_main_widget()); + auto main_widget = TRY(window->try_set_main_widget()); + main_widget->load_from_gml(master_word_gml); + auto& game = *main_widget->find_descendant_of_type_named("word_game"); + auto& statusbar = *main_widget->find_descendant_of_type_named("statusbar"); auto use_system_theme = Config::read_bool("MasterWord"sv, ""sv, "use_system_theme"sv, false); - game->set_use_system_theme(use_system_theme); + game.set_use_system_theme(use_system_theme); - auto shortest_word = game->shortest_word(); - auto longest_word = game->longest_word(); + auto shortest_word = game.shortest_word(); + auto longest_word = game.longest_word(); - window->resize(game->game_size()); + window->resize(game.game_size()); + window->set_focused_widget(&game); auto game_menu = TRY(window->try_add_menu("&Game")); TRY(game_menu->try_add_action(GUI::Action::create("&New Game", { Mod_None, Key_F2 }, [&](auto&) { - game->reset(); + game.reset(); }))); TRY(game_menu->try_add_separator()); @@ -79,8 +85,8 @@ ErrorOr serenity_main(Main::Arguments arguments) word_length = maybe_word_length.value(); Config::write_i32("MasterWord"sv, ""sv, "word_length"sv, word_length); - game->set_word_length(word_length); - window->resize(game->game_size()); + game.set_word_length(word_length); + window->resize(game.game_size()); } }))); TRY(settings_menu->try_add_action(GUI::Action::create("Set &Number Of Guesses", [&](auto&) { @@ -95,22 +101,22 @@ ErrorOr serenity_main(Main::Arguments arguments) max_guesses = maybe_max_guesses.value(); Config::write_i32("MasterWord"sv, ""sv, "max_guesses"sv, max_guesses); - game->set_max_guesses(max_guesses); - window->resize(game->game_size()); + game.set_max_guesses(max_guesses); + window->resize(game.game_size()); } }))); auto toggle_check_guesses = GUI::Action::create_checkable("Check &Guesses in dictionary", [&](auto& action) { auto checked = action.is_checked(); - game->set_check_guesses_in_dictionary(checked); + game.set_check_guesses_in_dictionary(checked); Config::write_bool("MasterWord"sv, ""sv, "check_guesses_in_dictionary"sv, checked); }); - toggle_check_guesses->set_checked(game->is_checking_guesses()); + toggle_check_guesses->set_checked(game.is_checking_guesses()); TRY(settings_menu->try_add_action(toggle_check_guesses)); auto theme_menu = TRY(window->try_add_menu("&Theme")); auto system_theme_action = GUI::Action::create("&System", [&](auto&) { - game->set_use_system_theme(true); + game.set_use_system_theme(true); Config::write_bool("MasterWord"sv, ""sv, "use_system_theme"sv, true); }); system_theme_action->set_checkable(true); @@ -118,7 +124,7 @@ ErrorOr serenity_main(Main::Arguments arguments) TRY(theme_menu->try_add_action(system_theme_action)); auto wordle_theme_action = GUI::Action::create("&Wordle", [&](auto&) { - game->set_use_system_theme(false); + game.set_use_system_theme(false); Config::write_bool("MasterWord"sv, ""sv, "use_system_theme"sv, false); }); wordle_theme_action->set_checkable(true); @@ -138,6 +144,13 @@ ErrorOr serenity_main(Main::Arguments arguments) }))); TRY(help_menu->try_add_action(GUI::CommonActions::make_about_action("MasterWord", app_icon, window))); + game.on_message = [&](auto message) { + if (!message.has_value()) + statusbar.set_text(""); + else + statusbar.set_text(*message); + }; + window->show(); window->set_icon(app_icon.bitmap_for_size(16));