Minesweeper: Fix lag when changing the field size.

Use a number of techniques to avoid freezing the UI for too long.

- Keep reusing the same widgets for the squares once they've been created.
- Temporarily disable widget updates.
- Avoid some redundant work on each run of reset().
This commit is contained in:
Andreas Kling 2019-05-02 04:21:21 +02:00
parent 49d0cdabac
commit 13b8c7eab8
Notes: sideshowbarker 2024-07-19 14:21:13 +09:00
2 changed files with 43 additions and 27 deletions

View file

@ -167,6 +167,7 @@ void Square::for_each_neighbor(Callback callback)
void Field::reset()
{
set_updates_enabled(false);
m_time_elapsed = 0;
m_time_label.set_text("0");
m_flags_left = m_mine_count;
@ -175,8 +176,14 @@ void Field::reset()
set_greedy_for_hits(false);
set_face(Face::Default);
srand(time(nullptr));
m_squares.clear();
m_squares.resize(rows() * columns());
m_squares.resize(max(m_squares.size(), rows() * columns()));
for (int i = rows() * columns(); i < m_squares.size(); ++i) {
auto& square = m_squares[i];
square->button->set_visible(false);
square->label->set_visible(false);
}
HashTable<int> mines;
while (mines.size() != m_mine_count) {
@ -188,7 +195,8 @@ void Field::reset()
int i = 0;
for (int r = 0; r < rows(); ++r) {
for (int c = 0; c < columns(); ++c) {
m_squares[i] = make<Square>();
if (!m_squares[i])
m_squares[i] = make<Square>();
Rect rect = { frame_thickness() + c * square_size(), frame_thickness() + r * square_size(), square_size(), square_size() };
auto& square = this->square(r, c);
square.field = this;
@ -198,35 +206,39 @@ void Field::reset()
square.has_flag = false;
square.is_considering = false;
square.is_swept = false;
if (!square.label)
if (!square.label) {
square.label = new SquareLabel(square, this);
square.label->set_background_color(Color::from_rgb(0xff4040));
}
square.label->set_fill_with_background_color(false);
square.label->set_relative_rect(rect);
square.label->set_visible(false);
square.label->set_icon(square.has_mine ? m_mine_bitmap : nullptr);
square.label->set_background_color(Color::from_rgb(0xff4040));
square.label->set_fill_with_background_color(false);
if (!square.button)
if (!square.button) {
square.button = new SquareButton(this);
square.button->set_checkable(true);
square.button->set_checkable(true);
square.button->on_click = [this, &square] (GButton&) {
on_square_clicked(square);
};
square.button->on_right_click = [this, &square] {
on_square_right_clicked(square);
};
square.button->on_middle_click = [this, &square] {
on_square_middle_clicked(square);
};
square.label->on_chord_click = [this, &square] {
on_square_chorded(square);
};
}
square.button->set_checked(false);
square.button->set_icon(nullptr);
square.button->set_relative_rect(rect);
square.button->set_visible(true);
square.button->on_click = [this, &square] (GButton&) {
on_square_clicked(square);
};
square.button->on_right_click = [this, &square] {
on_square_right_clicked(square);
};
square.button->on_middle_click = [this, &square] {
on_square_middle_clicked(square);
};
square.label->on_chord_click = [this, &square] {
on_square_chorded(square);
};
++i;
}
}
for (int r = 0; r < rows(); ++r) {
for (int c = 0; c < columns(); ++c) {
auto& square = this->square(r, c);
@ -243,8 +255,7 @@ void Field::reset()
}
m_unswept_empties = rows() * columns() - m_mine_count;
update();
set_updates_enabled(true);
}
void Field::flood_fill(Square& square)
@ -413,15 +424,17 @@ void Field::set_field_size(int rows, int columns, int mine_count)
{
if (m_rows == rows && m_columns == columns && m_mine_count == mine_count)
return;
auto config = CConfigFile::get_for_app("Minesweeper");
config->write_num_entry("Game", "MineCount", mine_count);
config->write_num_entry("Game", "Rows", rows);
config->write_num_entry("Game", "Columns", columns);
{
auto config = CConfigFile::get_for_app("Minesweeper");
config->write_num_entry("Game", "MineCount", mine_count);
config->write_num_entry("Game", "Rows", rows);
config->write_num_entry("Game", "Columns", columns);
}
m_rows = rows;
m_columns = columns;
m_mine_count = mine_count;
reset();
set_preferred_size({ frame_thickness() * 2 + m_columns * square_size(), frame_thickness() * 2 + m_rows * square_size() });
reset();
if (on_size_changed)
on_size_changed();
}

View file

@ -77,6 +77,9 @@ int main(int argc, char** argv)
game_menu->add_action(GAction::create("Expert", { Mod_Ctrl, Key_E }, [field] (const GAction&) {
field->set_field_size(16, 30, 99);
}));
game_menu->add_action(GAction::create("Madwoman", { Mod_Ctrl, Key_M }, [field] (const GAction&) {
field->set_field_size(32, 60, 350);
}));
menubar->add_menu(move(game_menu));
auto help_menu = make<GMenu>("Help");