mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 19:57:45 +00:00
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.
This commit is contained in:
parent
4d09b5c4ba
commit
517c03f920
6 changed files with 77 additions and 51 deletions
|
@ -5,9 +5,11 @@ serenity_component(
|
||||||
)
|
)
|
||||||
|
|
||||||
compile_gml(MinesweeperCustomGameWindow.gml MinesweeperCustomGameWindowGML.h minesweeper_custom_game_window_gml)
|
compile_gml(MinesweeperCustomGameWindow.gml MinesweeperCustomGameWindowGML.h minesweeper_custom_game_window_gml)
|
||||||
|
compile_gml(MinesweeperWindow.gml MinesweeperWindowGML.h minesweeper_window_gml)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
MinesweeperCustomGameWindowGML.h
|
MinesweeperCustomGameWindowGML.h
|
||||||
|
MinesweeperWindowGML.h
|
||||||
CustomGameDialog.cpp
|
CustomGameDialog.cpp
|
||||||
Field.cpp
|
Field.cpp
|
||||||
main.cpp
|
main.cpp
|
||||||
|
|
|
@ -42,8 +42,7 @@ void CustomGameDialog::set_max_mines()
|
||||||
CustomGameDialog::CustomGameDialog(Window* parent_window)
|
CustomGameDialog::CustomGameDialog(Window* parent_window)
|
||||||
: Dialog(parent_window)
|
: Dialog(parent_window)
|
||||||
{
|
{
|
||||||
resize(305, 90);
|
resize(300, 82);
|
||||||
center_on_screen();
|
|
||||||
set_resizable(false);
|
set_resizable(false);
|
||||||
set_title("Custom game");
|
set_title("Custom game");
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "Field.h"
|
#include "Field.h"
|
||||||
#include <AK/HashTable.h>
|
#include <AK/HashTable.h>
|
||||||
|
#include <AK/NumberFormat.h>
|
||||||
#include <AK/Queue.h>
|
#include <AK/Queue.h>
|
||||||
#include <AK/Random.h>
|
#include <AK/Random.h>
|
||||||
#include <LibConfig/Client.h>
|
#include <LibConfig/Client.h>
|
||||||
|
@ -115,7 +116,7 @@ Field::Field(GUI::Label& flag_label, GUI::Label& time_label, GUI::Button& face_b
|
||||||
m_timer = Core::Timer::create_repeating(
|
m_timer = Core::Timer::create_repeating(
|
||||||
1000, [this] {
|
1000, [this] {
|
||||||
++m_time_elapsed;
|
++m_time_elapsed;
|
||||||
m_time_label.set_text(String::number(m_time_elapsed));
|
m_time_label.set_text(human_readable_digital_time(m_time_elapsed));
|
||||||
},
|
},
|
||||||
this);
|
this);
|
||||||
m_mine_bitmap = Gfx::Bitmap::try_load_from_file("/res/icons/minesweeper/mine.png"sv).release_value_but_fixme_should_propagate_errors();
|
m_mine_bitmap = Gfx::Bitmap::try_load_from_file("/res/icons/minesweeper/mine.png"sv).release_value_but_fixme_should_propagate_errors();
|
||||||
|
@ -199,7 +200,7 @@ void Field::reset()
|
||||||
m_first_click = true;
|
m_first_click = true;
|
||||||
set_updates_enabled(false);
|
set_updates_enabled(false);
|
||||||
m_time_elapsed = 0;
|
m_time_elapsed = 0;
|
||||||
m_time_label.set_text("0");
|
m_time_label.set_text("00:00");
|
||||||
m_flags_left = m_mine_count;
|
m_flags_left = m_mine_count;
|
||||||
m_flag_label.set_text(String::number(m_flags_left));
|
m_flag_label.set_text(String::number(m_flags_left));
|
||||||
m_timer->stop();
|
m_timer->stop();
|
||||||
|
@ -520,7 +521,9 @@ void Field::set_field_size(Difficulty difficulty, size_t rows, size_t columns, s
|
||||||
m_mine_count = mine_count;
|
m_mine_count = mine_count;
|
||||||
set_fixed_size(frame_thickness() * 2 + m_columns * square_size(), frame_thickness() * 2 + m_rows * square_size());
|
set_fixed_size(frame_thickness() * 2 + m_columns * square_size(), frame_thickness() * 2 + m_rows * square_size());
|
||||||
reset();
|
reset();
|
||||||
|
deferred_invoke([this] {
|
||||||
m_on_size_changed(Gfx::IntSize(min_size()));
|
m_on_size_changed(Gfx::IntSize(min_size()));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Field::set_single_chording(bool enabled)
|
void Field::set_single_chording(bool enabled)
|
||||||
|
|
|
@ -2,13 +2,14 @@
|
||||||
fill_with_background_color: true
|
fill_with_background_color: true
|
||||||
layout: @GUI::VerticalBoxLayout {
|
layout: @GUI::VerticalBoxLayout {
|
||||||
margins: [4]
|
margins: [4]
|
||||||
|
spacing: 6
|
||||||
}
|
}
|
||||||
|
|
||||||
@GUI::GroupBox {
|
@GUI::GroupBox {
|
||||||
title: "Field"
|
title: "Field"
|
||||||
autosize: true
|
autosize: true
|
||||||
layout: @GUI::HorizontalBoxLayout {
|
layout: @GUI::HorizontalBoxLayout {
|
||||||
margins: [16, 6, 6]
|
margins: [6]
|
||||||
}
|
}
|
||||||
|
|
||||||
@GUI::Label {
|
@GUI::Label {
|
||||||
|
@ -23,7 +24,7 @@
|
||||||
fixed_width: 40
|
fixed_width: 40
|
||||||
}
|
}
|
||||||
|
|
||||||
@GUI::VerticalSeparator {}
|
@GUI::Layout::Spacer {}
|
||||||
|
|
||||||
@GUI::Label {
|
@GUI::Label {
|
||||||
text: "Rows: "
|
text: "Rows: "
|
||||||
|
@ -37,7 +38,7 @@
|
||||||
fixed_width: 40
|
fixed_width: 40
|
||||||
}
|
}
|
||||||
|
|
||||||
@GUI::VerticalSeparator {}
|
@GUI::Layout::Spacer {}
|
||||||
|
|
||||||
@GUI::Label {
|
@GUI::Label {
|
||||||
text: "Mines: "
|
text: "Mines: "
|
||||||
|
@ -53,8 +54,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@GUI::Widget {
|
@GUI::Widget {
|
||||||
max_height: 24
|
layout: @GUI::HorizontalBoxLayout {
|
||||||
layout: @GUI::HorizontalBoxLayout {}
|
spacing: 10
|
||||||
|
}
|
||||||
|
|
||||||
@GUI::Layout::Spacer {}
|
@GUI::Layout::Spacer {}
|
||||||
|
|
||||||
|
|
52
Userland/Games/Minesweeper/MinesweeperWindow.gml
Normal file
52
Userland/Games/Minesweeper/MinesweeperWindow.gml
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
@GUI::Widget {
|
||||||
|
fill_with_background_color: true
|
||||||
|
layout: @GUI::VerticalBoxLayout {
|
||||||
|
spacing: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::HorizontalSeparator {
|
||||||
|
name: "separator"
|
||||||
|
fixed_height: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Widget {
|
||||||
|
name: "container"
|
||||||
|
fixed_height: 36
|
||||||
|
layout: @GUI::HorizontalBoxLayout {}
|
||||||
|
|
||||||
|
@GUI::Layout::Spacer {}
|
||||||
|
|
||||||
|
@GUI::ImageWidget {
|
||||||
|
name: "flag_image"
|
||||||
|
bitmap: "/res/icons/minesweeper/flag.png"
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Label {
|
||||||
|
name: "flag_label"
|
||||||
|
autosize: true
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Layout::Spacer {}
|
||||||
|
|
||||||
|
@GUI::Button {
|
||||||
|
name: "face_button"
|
||||||
|
fixed_size: [36, 36]
|
||||||
|
focus_policy: "TabFocus"
|
||||||
|
button_style: "Coolbar"
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Layout::Spacer {}
|
||||||
|
|
||||||
|
@GUI::ImageWidget {
|
||||||
|
name: "time_image"
|
||||||
|
bitmap: "/res/icons/minesweeper/timer.png"
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Label {
|
||||||
|
name: "time_label"
|
||||||
|
autosize: true
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Layout::Spacer {}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@
|
||||||
#include "CustomGameDialog.h"
|
#include "CustomGameDialog.h"
|
||||||
#include "Field.h"
|
#include "Field.h"
|
||||||
#include <AK/URL.h>
|
#include <AK/URL.h>
|
||||||
|
#include <Games/Minesweeper/MinesweeperWindowGML.h>
|
||||||
#include <LibConfig/Client.h>
|
#include <LibConfig/Client.h>
|
||||||
#include <LibCore/System.h>
|
#include <LibCore/System.h>
|
||||||
#include <LibDesktop/Launcher.h>
|
#include <LibDesktop/Launcher.h>
|
||||||
|
@ -46,51 +47,18 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
auto window = TRY(GUI::Window::try_create());
|
auto window = TRY(GUI::Window::try_create());
|
||||||
window->set_resizable(false);
|
window->set_resizable(false);
|
||||||
window->set_title("Minesweeper");
|
window->set_title("Minesweeper");
|
||||||
window->resize(139, 175);
|
window->resize(139, 177);
|
||||||
|
|
||||||
auto widget = TRY(window->try_set_main_widget<GUI::Widget>());
|
auto widget = TRY(window->try_set_main_widget<GUI::Widget>());
|
||||||
(void)TRY(widget->try_set_layout<GUI::VerticalBoxLayout>());
|
widget->load_from_gml(minesweeper_window_gml);
|
||||||
widget->layout()->set_spacing(0);
|
|
||||||
|
|
||||||
auto top_line = TRY(widget->try_add<GUI::SeparatorWidget>(Gfx::Orientation::Horizontal));
|
|
||||||
top_line->set_fixed_height(2);
|
|
||||||
|
|
||||||
auto container = TRY(widget->try_add<GUI::Widget>());
|
|
||||||
container->set_fill_with_background_color(true);
|
|
||||||
container->set_fixed_height(36);
|
|
||||||
(void)TRY(container->try_set_layout<GUI::HorizontalBoxLayout>());
|
|
||||||
|
|
||||||
container->layout()->add_spacer();
|
|
||||||
|
|
||||||
auto flag_image = TRY(container->try_add<GUI::Label>());
|
|
||||||
flag_image->set_icon(Gfx::Bitmap::try_load_from_file("/res/icons/minesweeper/flag.png"sv).release_value_but_fixme_should_propagate_errors());
|
|
||||||
flag_image->set_fixed_width(16);
|
|
||||||
|
|
||||||
auto flag_label = TRY(container->try_add<GUI::Label>());
|
|
||||||
flag_label->set_autosize(true);
|
|
||||||
flag_label->set_text_alignment(Gfx::TextAlignment::CenterLeft);
|
|
||||||
|
|
||||||
container->layout()->add_spacer();
|
|
||||||
|
|
||||||
auto face_button = TRY(container->try_add<GUI::Button>());
|
|
||||||
face_button->set_focus_policy(GUI::FocusPolicy::TabFocus);
|
|
||||||
face_button->set_button_style(Gfx::ButtonStyle::Coolbar);
|
|
||||||
face_button->set_fixed_size(36, 36);
|
|
||||||
|
|
||||||
container->layout()->add_spacer();
|
|
||||||
|
|
||||||
auto time_image = TRY(container->try_add<GUI::Label>());
|
|
||||||
time_image->set_fixed_width(16);
|
|
||||||
time_image->set_icon(Gfx::Bitmap::try_load_from_file("/res/icons/minesweeper/timer.png"sv).release_value_but_fixme_should_propagate_errors());
|
|
||||||
|
|
||||||
auto time_label = TRY(container->try_add<GUI::Label>());
|
|
||||||
time_label->set_fixed_width(50);
|
|
||||||
time_label->set_text_alignment(Gfx::TextAlignment::CenterLeft);
|
|
||||||
|
|
||||||
container->layout()->add_spacer();
|
|
||||||
|
|
||||||
|
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) {
|
auto field = TRY(widget->try_add<Field>(flag_label, time_label, face_button, [&](auto size) {
|
||||||
size.set_height(size.height() + container->min_size().height().as_int());
|
size.set_height(size.height() + separator.height() + container.height());
|
||||||
window->resize(size);
|
window->resize(size);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue