1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-06-15 20:12:08 +00:00
serenity/Userland/Games/Minesweeper/main.cpp
thankyouverycool 517c03f920 Minesweeper: Update GML and fix layout issues
Converts Minesweeper's main widget to GML, polishes the custom
game window, formats the clock as human readable digital time, and
defers invoking Field's callback until the main widget has finished
relayout. Fixes inability to downsize the main window when shrinking
field size.
2022-08-05 13:55:13 +02:00

136 lines
5.4 KiB
C++

/*
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "CustomGameDialog.h"
#include "Field.h"
#include <AK/URL.h>
#include <Games/Minesweeper/MinesweeperWindowGML.h>
#include <LibConfig/Client.h>
#include <LibCore/System.h>
#include <LibDesktop/Launcher.h>
#include <LibGUI/Action.h>
#include <LibGUI/ActionGroup.h>
#include <LibGUI/Application.h>
#include <LibGUI/BoxLayout.h>
#include <LibGUI/Button.h>
#include <LibGUI/Icon.h>
#include <LibGUI/Label.h>
#include <LibGUI/Menu.h>
#include <LibGUI/Menubar.h>
#include <LibGUI/SeparatorWidget.h>
#include <LibGUI/Window.h>
#include <LibMain/Main.h>
#include <stdio.h>
ErrorOr<int> serenity_main(Main::Arguments arguments)
{
TRY(Core::System::pledge("stdio rpath recvfd sendfd unix"));
auto app = TRY(GUI::Application::try_create(arguments));
Config::pledge_domain("Minesweeper");
TRY(Desktop::Launcher::add_allowed_handler_with_only_specific_urls("/bin/Help", { URL::create_with_file_protocol("/usr/share/man/man6/Minesweeper.md") }));
TRY(Desktop::Launcher::seal_allowlist());
TRY(Core::System::pledge("stdio rpath recvfd sendfd"));
TRY(Core::System::unveil("/res", "r"));
TRY(Core::System::unveil("/tmp/100/portal/launch", "rw"));
TRY(Core::System::unveil(nullptr, nullptr));
auto app_icon = TRY(GUI::Icon::try_create_default_icon("app-minesweeper"sv));
auto window = TRY(GUI::Window::try_create());
window->set_resizable(false);
window->set_title("Minesweeper");
window->resize(139, 177);
auto widget = TRY(window->try_set_main_widget<GUI::Widget>());
widget->load_from_gml(minesweeper_window_gml);
auto& separator = *widget->find_descendant_of_type_named<GUI::HorizontalSeparator>("separator");
auto& container = *widget->find_descendant_of_type_named<GUI::Widget>("container");
auto& flag_label = *widget->find_descendant_of_type_named<GUI::Label>("flag_label");
auto& time_label = *widget->find_descendant_of_type_named<GUI::Label>("time_label");
auto& face_button = *widget->find_descendant_of_type_named<GUI::Button>("face_button");
auto field = TRY(widget->try_add<Field>(flag_label, time_label, face_button, [&](auto size) {
size.set_height(size.height() + separator.height() + container.height());
window->resize(size);
}));
auto game_menu = TRY(window->try_add_menu("&Game"));
TRY(game_menu->try_add_action(GUI::Action::create("&New Game", { Mod_None, Key_F2 }, TRY(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/reload.png"sv)), [&](auto&) {
field->reset();
})));
TRY(game_menu->try_add_separator());
auto chord_toggler_action = GUI::Action::create_checkable("Single-click chording", [&](auto& action) {
field->set_single_chording(action.is_checked());
});
chord_toggler_action->set_checked(field->is_single_chording());
TRY(game_menu->try_add_action(*chord_toggler_action));
TRY(game_menu->try_add_separator());
TRY(game_menu->try_add_action(GUI::CommonActions::make_quit_action([](auto&) {
GUI::Application::the()->quit();
})));
auto difficulty_menu = TRY(window->try_add_menu("&Difficulty"));
GUI::ActionGroup difficulty_actions;
difficulty_actions.set_exclusive(true);
auto action = GUI::Action::create_checkable("&Beginner", { Mod_Ctrl, Key_B }, [&](auto&) {
field->set_field_difficulty(Field::Difficulty::Beginner);
});
action->set_checked(field->difficulty() == Field::Difficulty::Beginner);
TRY(difficulty_menu->try_add_action(action));
difficulty_actions.add_action(action);
action = GUI::Action::create_checkable("&Intermediate", { Mod_Ctrl, Key_I }, [&](auto&) {
field->set_field_difficulty(Field::Difficulty::Intermediate);
});
action->set_checked(field->difficulty() == Field::Difficulty::Intermediate);
TRY(difficulty_menu->try_add_action(action));
difficulty_actions.add_action(action);
action = GUI::Action::create_checkable("&Expert", { Mod_Ctrl, Key_E }, [&](auto&) {
field->set_field_difficulty(Field::Difficulty::Expert);
});
action->set_checked(field->difficulty() == Field::Difficulty::Expert);
TRY(difficulty_menu->try_add_action(action));
difficulty_actions.add_action(action);
action = GUI::Action::create_checkable("&Madwoman", { Mod_Ctrl, Key_M }, [&](auto&) {
field->set_field_difficulty(Field::Difficulty::Madwoman);
});
action->set_checked(field->difficulty() == Field::Difficulty::Madwoman);
TRY(difficulty_menu->try_add_action(action));
difficulty_actions.add_action(action);
TRY(difficulty_menu->try_add_separator());
action = GUI::Action::create_checkable("&Custom game...", { Mod_Ctrl, Key_C }, [&](auto&) {
CustomGameDialog::show(window, field);
});
action->set_checked(field->difficulty() == Field::Difficulty::Custom);
TRY(difficulty_menu->try_add_action(action));
difficulty_actions.add_action(action);
auto help_menu = TRY(window->try_add_menu("&Help"));
TRY(help_menu->try_add_action(GUI::CommonActions::make_help_action([](auto&) {
Desktop::Launcher::open(URL::create_with_file_protocol("/usr/share/man/man6/Minesweeper.md"), "/bin/Help");
})));
TRY(help_menu->try_add_action(GUI::CommonActions::make_about_action("Minesweeper", app_icon, window)));
window->show();
window->set_icon(app_icon.bitmap_for_size(16));
return app->exec();
}