Serenity Operating System
at master 159 lines 6.8 kB view raw
1/* 2 * Copyright (c) 2022, Joe Petrus <joe@petrus.io> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include "WordGame.h" 8#include <AK/URL.h> 9#include <Games/MasterWord/MasterWordGML.h> 10#include <LibConfig/Client.h> 11#include <LibCore/System.h> 12#include <LibDesktop/Launcher.h> 13#include <LibGUI/Action.h> 14#include <LibGUI/ActionGroup.h> 15#include <LibGUI/Application.h> 16#include <LibGUI/Icon.h> 17#include <LibGUI/InputBox.h> 18#include <LibGUI/Menubar.h> 19#include <LibGUI/MessageBox.h> 20#include <LibGUI/Statusbar.h> 21#include <LibGUI/Window.h> 22#include <LibMain/Main.h> 23 24ErrorOr<int> serenity_main(Main::Arguments arguments) 25{ 26 TRY(Core::System::pledge("stdio rpath recvfd sendfd unix")); 27 28 auto app = TRY(GUI::Application::try_create(arguments)); 29 30 Config::pledge_domain("MasterWord"); 31 32 TRY(Desktop::Launcher::add_allowed_handler_with_only_specific_urls("/bin/Help", { URL::create_with_file_scheme("/usr/share/man/man6/MasterWord.md") })); 33 TRY(Desktop::Launcher::seal_allowlist()); 34 35 TRY(Core::System::pledge("stdio rpath recvfd sendfd")); 36 37 TRY(Core::System::unveil("/tmp/session/%sid/portal/launch", "rw")); 38 TRY(Core::System::unveil("/res", "r")); 39 TRY(Core::System::unveil(nullptr, nullptr)); 40 41 auto app_icon = TRY(GUI::Icon::try_create_default_icon("app-masterword"sv)); 42 43 auto window = TRY(GUI::Window::try_create()); 44 45 window->set_double_buffering_enabled(false); 46 window->set_title("MasterWord"); 47 window->set_resizable(false); 48 49 auto main_widget = TRY(window->set_main_widget<GUI::Widget>()); 50 TRY(main_widget->load_from_gml(master_word_gml)); 51 auto& game = *main_widget->find_descendant_of_type_named<MasterWord::WordGame>("word_game"); 52 auto& statusbar = *main_widget->find_descendant_of_type_named<GUI::Statusbar>("statusbar"); 53 54 auto use_system_theme = Config::read_bool("MasterWord"sv, ""sv, "use_system_theme"sv, false); 55 game.set_use_system_theme(use_system_theme); 56 57 auto shortest_word = game.shortest_word(); 58 auto longest_word = game.longest_word(); 59 60 window->resize(game.game_size()); 61 window->set_focused_widget(&game); 62 63 auto game_menu = TRY(window->try_add_menu("&Game")); 64 65 TRY(game_menu->try_add_action(GUI::Action::create("&New Game", { Mod_None, Key_F2 }, [&](auto&) { 66 game.reset(); 67 }))); 68 69 TRY(game_menu->try_add_separator()); 70 TRY(game_menu->try_add_action(GUI::CommonActions::make_quit_action([](auto&) { 71 GUI::Application::the()->quit(); 72 }))); 73 74 auto settings_menu = TRY(window->try_add_menu("&Settings")); 75 76 TRY(settings_menu->try_add_action(GUI::Action::create("Set &Word Length", [&](auto&) { 77 auto word_length = Config::read_i32("MasterWord"sv, ""sv, "word_length"sv, 5); 78 auto word_length_string = DeprecatedString::number(word_length); 79 if (GUI::InputBox::show(window, word_length_string, "Word length:"sv, "MasterWord"sv, GUI::InputType::NonemptyText) == GUI::InputBox::ExecResult::OK) { 80 auto maybe_word_length = word_length_string.template to_uint(); 81 if (!maybe_word_length.has_value() || maybe_word_length.value() < shortest_word || maybe_word_length.value() > longest_word) { 82 GUI::MessageBox::show(window, DeprecatedString::formatted("Please enter a number between {} and {}.", shortest_word, longest_word), "MasterWord"sv); 83 return; 84 } 85 86 word_length = maybe_word_length.value(); 87 Config::write_i32("MasterWord"sv, ""sv, "word_length"sv, word_length); 88 game.set_word_length(word_length); 89 window->resize(game.game_size()); 90 } 91 }))); 92 TRY(settings_menu->try_add_action(GUI::Action::create("Set &Number Of Guesses", [&](auto&) { 93 auto max_guesses = Config::read_i32("MasterWord"sv, ""sv, "max_guesses"sv, 5); 94 auto max_guesses_string = DeprecatedString::number(max_guesses); 95 if (GUI::InputBox::show(window, max_guesses_string, "Maximum number of guesses:"sv, "MasterWord"sv, GUI::InputType::NonemptyText) == GUI::InputBox::ExecResult::OK) { 96 auto maybe_max_guesses = max_guesses_string.template to_uint(); 97 if (!maybe_max_guesses.has_value() || maybe_max_guesses.value() < 1 || maybe_max_guesses.value() > 20) { 98 GUI::MessageBox::show(window, "Please enter a number between 1 and 20."sv, "MasterWord"sv); 99 return; 100 } 101 102 max_guesses = maybe_max_guesses.value(); 103 Config::write_i32("MasterWord"sv, ""sv, "max_guesses"sv, max_guesses); 104 game.set_max_guesses(max_guesses); 105 window->resize(game.game_size()); 106 } 107 }))); 108 109 auto toggle_check_guesses = GUI::Action::create_checkable("Check &Guesses in dictionary", [&](auto& action) { 110 auto checked = action.is_checked(); 111 game.set_check_guesses_in_dictionary(checked); 112 Config::write_bool("MasterWord"sv, ""sv, "check_guesses_in_dictionary"sv, checked); 113 }); 114 toggle_check_guesses->set_checked(game.is_checking_guesses()); 115 TRY(settings_menu->try_add_action(toggle_check_guesses)); 116 117 auto theme_menu = TRY(window->try_add_menu("&Theme")); 118 auto system_theme_action = GUI::Action::create("&System", [&](auto&) { 119 game.set_use_system_theme(true); 120 Config::write_bool("MasterWord"sv, ""sv, "use_system_theme"sv, true); 121 }); 122 system_theme_action->set_checkable(true); 123 system_theme_action->set_checked(use_system_theme); 124 TRY(theme_menu->try_add_action(system_theme_action)); 125 126 auto wordle_theme_action = GUI::Action::create("&Wordle", [&](auto&) { 127 game.set_use_system_theme(false); 128 Config::write_bool("MasterWord"sv, ""sv, "use_system_theme"sv, false); 129 }); 130 wordle_theme_action->set_checkable(true); 131 wordle_theme_action->set_checked(!use_system_theme); 132 TRY(theme_menu->try_add_action(wordle_theme_action)); 133 134 GUI::ActionGroup theme_actions; 135 theme_actions.set_exclusive(true); 136 theme_actions.set_unchecking_allowed(false); 137 theme_actions.add_action(system_theme_action); 138 theme_actions.add_action(wordle_theme_action); 139 140 auto help_menu = TRY(window->try_add_menu("&Help")); 141 TRY(help_menu->try_add_action(GUI::CommonActions::make_command_palette_action(window))); 142 TRY(help_menu->try_add_action(GUI::CommonActions::make_help_action([](auto&) { 143 Desktop::Launcher::open(URL::create_with_file_scheme("/usr/share/man/man6/MasterWord.md"), "/bin/Help"); 144 }))); 145 TRY(help_menu->try_add_action(GUI::CommonActions::make_about_action("MasterWord", app_icon, window))); 146 147 game.on_message = [&](auto message) { 148 if (!message.has_value()) 149 statusbar.set_text(""); 150 else 151 statusbar.set_text(*message); 152 }; 153 154 window->show(); 155 156 window->set_icon(app_icon.bitmap_for_size(16)); 157 158 return app->exec(); 159}