Add Menu
This commit is contained in:
parent
39dc77884e
commit
d7aea43567
|
@ -26,7 +26,7 @@ link_directories (${GTK4_LIBRARY_DIRS})
|
|||
# set(PO_DIR ${CMAKE_BINARY_DIR}/po/zh_CN/LC_MESSAGES)
|
||||
|
||||
#Source files
|
||||
set(SOURCE_FILE src/main.cpp src/MineSweeper.cpp src/MineCell.cpp)
|
||||
set(SOURCE_FILE src/main.cpp src/MineSweeper.cpp src/MineCell.cpp src/InputBox.cpp)
|
||||
|
||||
#Compile Resource
|
||||
|
||||
|
|
|
@ -1,302 +0,0 @@
|
|||
#include "MineSweeper.hh"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
MineSweeper::MineSweeper()
|
||||
: main_box(Gtk::Orientation::VERTICAL, 5),
|
||||
btn_box(Gtk::Orientation::HORIZONTAL, 5),
|
||||
cell(nullptr)
|
||||
{
|
||||
// Initalize Window
|
||||
set_title("MineSweeper");
|
||||
set_titlebar(header);
|
||||
header.set_show_title_buttons();
|
||||
header.set_decoration_layout("close,minimize,maximize:menu");
|
||||
header.pack_end(menu_btn);
|
||||
set_icon_name("org.gtk.daleclack");
|
||||
|
||||
// Initalize Menu
|
||||
menu_builder = Gtk::Builder::create_from_resource("/org/gtk/daleclack/mine_menu.xml");
|
||||
auto object = menu_builder->get_object<Gio::MenuModel>("mine_menu");
|
||||
popover1.set_menu_model(object);
|
||||
// popover1.show();
|
||||
menu_btn.set_popover(popover1);
|
||||
|
||||
// Add Actions
|
||||
add_action("new_game", sigc::mem_fun(*this, &MineSweeper::new_game));
|
||||
add_action("scores", sigc::mem_fun(*this, &MineSweeper::show_scores));
|
||||
add_action("show_mines", sigc::mem_fun(*this, &MineSweeper::show_mines));
|
||||
add_action("quit", sigc::mem_fun(*this, &MineSweeper::hide));
|
||||
|
||||
// Default setting
|
||||
reset_game();
|
||||
|
||||
// Buttons
|
||||
btnstart.set_label("Start/Reset");
|
||||
btnpause.set_label("Pause");
|
||||
btnshow.set_label("Show All");
|
||||
btnexit.set_label("Exit");
|
||||
btn_box.append(btnstart);
|
||||
btn_box.append(btnpause);
|
||||
btn_box.append(btnshow);
|
||||
btn_box.append(btnexit);
|
||||
btnstart.signal_clicked().connect(sigc::mem_fun(*this, &MineSweeper::new_game));
|
||||
btnshow.signal_clicked().connect(sigc::mem_fun(*this, &MineSweeper::show_mines));
|
||||
btnexit.signal_clicked().connect(sigc::mem_fun(*this, &MineSweeper::hide));
|
||||
|
||||
// Pack widgets
|
||||
status_label.set_halign(Gtk::Align::CENTER);
|
||||
btn_box.set_halign(Gtk::Align::CENTER);
|
||||
mine_grid.set_halign(Gtk::Align::CENTER);
|
||||
main_box.append(status_label);
|
||||
main_box.append(mine_grid);
|
||||
main_box.append(btn_box);
|
||||
|
||||
// Create a dialog
|
||||
input_dialog = InputBox::create();
|
||||
|
||||
// Create Scores Window
|
||||
scores_win = ScoresWin::create();
|
||||
|
||||
// Bind windows
|
||||
input_dialog->set_transient_for(*this);
|
||||
scores_win->set_transient_for(*this);
|
||||
input_dialog->set_scores_window(scores_win);
|
||||
|
||||
// Show everything
|
||||
set_child(main_box);
|
||||
//show_all_children();
|
||||
}
|
||||
|
||||
MineSweeper::~MineSweeper(){
|
||||
// Delete all resources
|
||||
delete input_dialog;
|
||||
delete scores_win;
|
||||
if(cell != nullptr){
|
||||
delete[] cell;
|
||||
}
|
||||
}
|
||||
|
||||
void MineSweeper::new_game(){
|
||||
// New game = reset game
|
||||
reset_game();
|
||||
}
|
||||
|
||||
void MineSweeper::reset_game(int width, int height, int mines)
|
||||
{
|
||||
// Clear the cells
|
||||
if(cell != nullptr){
|
||||
delete[] cell;
|
||||
}
|
||||
|
||||
cell = new MineCell[width * height];
|
||||
// Reset timer
|
||||
mytimer.disconnect();
|
||||
timer_count = 0;
|
||||
mytimer = Glib::signal_timeout().connect(sigc::mem_fun(*this, &MineSweeper::timer_func), 1000);
|
||||
|
||||
mine_count = 0;
|
||||
mines_clear = 0;
|
||||
mine_grid.set_sensitive();
|
||||
// Reset all data
|
||||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
for (int j = 0; j < height; j++)
|
||||
{
|
||||
// Initalize cell
|
||||
cell[i * 7 + j].set_has_frame();
|
||||
cell[i * 7 + j].set_image_from_icon_name("", Gtk::IconSize::LARGE);
|
||||
// cell[i * 7 + j].set_always_show_image();
|
||||
cell[i * 7 + j].set_size_request(40, 40);
|
||||
cell[i * 7 + j].mines_around = 0;
|
||||
cell[i * 7 + j].has_mine = false;
|
||||
cell[i * 7 + j].cleared = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset mines
|
||||
while (mine_count < mines)
|
||||
{
|
||||
int index = g_random_int_range(0, width * height);
|
||||
if (!(cell[index].has_mine))
|
||||
{
|
||||
cell[index].has_mine = true;
|
||||
// cell[index].set_label("x");
|
||||
mine_count++;
|
||||
}
|
||||
}
|
||||
// std::cout << mine_count << std::endl;
|
||||
// game_ended = false;
|
||||
// winned = true;
|
||||
game_status = GameStatus::Running;
|
||||
status_label.set_label(" ");
|
||||
calc_mines();
|
||||
|
||||
// Append buttons to grid
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
for (int j = 0; j < width; j++)
|
||||
{
|
||||
// cell[i * 7 + j].set_label("?");
|
||||
cell[i * width + j].signal_clicked().connect(sigc::bind(
|
||||
sigc::mem_fun(*this, &MineSweeper::cell_clicked), &cell[i * width + j]));
|
||||
mine_grid.attach(cell[i * width + j], j, i);
|
||||
cell[i * width + j].set_has_frame();
|
||||
cell[i * width + j].x = j;
|
||||
cell[i * width + j].y = i;
|
||||
cell[i * width + j].cleared = false;
|
||||
}
|
||||
}
|
||||
|
||||
mine_grid.show();
|
||||
}
|
||||
|
||||
void MineSweeper::pause_game(){
|
||||
|
||||
}
|
||||
|
||||
void MineSweeper::calc_mines()
|
||||
{
|
||||
// Calculate the mines around a cell
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
for (int j = 0; j < 7; j++)
|
||||
{
|
||||
int index1, index2;
|
||||
// The Search cell should not over the grids
|
||||
for (index1 = MAX(0, i - 1); index1 < MIN(i + 1, 6) + 1; index1++)
|
||||
{
|
||||
for (index2 = MAX(0, j - 1); index2 < MIN(j + 1, 6) + 1; index2++)
|
||||
{
|
||||
if ((cell[index1 * 7 + index2].has_mine))
|
||||
{
|
||||
cell[i * 7 + j].mines_around++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MineSweeper::show_mines()
|
||||
{
|
||||
// Show all cell with a mine
|
||||
for (int i = 0; i < 49; i++)
|
||||
{
|
||||
if (cell[i].has_mine)
|
||||
{
|
||||
cell[i].set_image_from_icon_name("mine", Gtk::IconSize::LARGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MineSweeper::show_scores(){
|
||||
// Show Scores Window
|
||||
input_dialog->read_scores();
|
||||
}
|
||||
|
||||
void MineSweeper::game_lost(int explode_index){
|
||||
// When a cell with mine is clicked, show other mines
|
||||
for (int i = 0; i < 49; i++)
|
||||
{
|
||||
if (cell[i].has_mine && i != explode_index)
|
||||
{
|
||||
cell[i].set_image_from_icon_name("mine", Gtk::IconSize::LARGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MineSweeper::timer_func()
|
||||
{
|
||||
// Set timer
|
||||
char tmp[50];
|
||||
timer_count++;
|
||||
sprintf(tmp, "Time:%d", timer_count);
|
||||
status_label.set_label(tmp);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MineSweeper::cell_clicked(MineCell *cell1)
|
||||
{
|
||||
cell1->set_has_frame(false);
|
||||
if (game_status == GameStatus::Running && !cell1->cleared)
|
||||
{
|
||||
//
|
||||
// If get mine, the game will end now
|
||||
if (cell1->has_mine)
|
||||
{
|
||||
// Set game to stop
|
||||
// winned = false;
|
||||
game_status = GameStatus::Ended;
|
||||
cell1->cleared = true;
|
||||
cell1->set_image_from_icon_name("exploded", Gtk::IconSize::LARGE);
|
||||
|
||||
// End the game
|
||||
game_lost(cell1->y * 7 + cell1->x);
|
||||
status_label.set_label("You lost!");
|
||||
// game_ended = true;
|
||||
mytimer.disconnect();
|
||||
mine_grid.set_sensitive(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If no mines, check the cell around
|
||||
check_mines(cell1->x, cell1->y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MineSweeper::check_mines(int pos_x, int pos_y)
|
||||
{
|
||||
if (pos_x >= 0 && pos_x <= 6 &&
|
||||
pos_y >= 0 && pos_y <= 6)
|
||||
{
|
||||
if (!cell[pos_y * 7 + pos_x].has_mine &&
|
||||
!cell[pos_y * 7 + pos_x].cleared)
|
||||
{
|
||||
mines_clear++;
|
||||
// Show the cell has no mines around
|
||||
if (cell[pos_y * 7 + pos_x].mines_around == 0)
|
||||
{
|
||||
cell[pos_y * 7 + pos_x].set_image_from_icon_name("", Gtk::IconSize::LARGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show the numbers of mines around a cell
|
||||
char *label = g_strdup_printf("%dmines", cell[pos_y * 7 + pos_x].mines_around);
|
||||
cell[pos_y * 7 + pos_x].set_image_from_icon_name(label, Gtk::IconSize::LARGE);
|
||||
g_free(label);
|
||||
}
|
||||
|
||||
// make the cell without mines cleared
|
||||
cell[pos_y * 7 + pos_x].set_has_frame(false);
|
||||
cell[pos_y * 7 + pos_x].cleared = true;
|
||||
|
||||
// Check the cells around a cell that has no mines
|
||||
if (cell[pos_y * 7 + pos_x].mines_around == 0)
|
||||
{
|
||||
check_mines((pos_x - 1), (pos_y - 1));
|
||||
check_mines((pos_x + 1), (pos_y + 1));
|
||||
check_mines((pos_x - 1), (pos_y + 1));
|
||||
check_mines((pos_x + 1), (pos_y - 1));
|
||||
check_mines(pos_x, (pos_y - 1));
|
||||
check_mines(pos_x, (pos_y + 1));
|
||||
check_mines((pos_x + 1), pos_y);
|
||||
check_mines((pos_x - 1), pos_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If all the mines has cleared, you has winned
|
||||
if (mines_clear == 40)
|
||||
{
|
||||
// Stop the game
|
||||
status_label.set_label("You winned!");
|
||||
game_status = GameStatus::Winned;
|
||||
mytimer.disconnect();
|
||||
|
||||
// Save the time of game
|
||||
input_dialog->set_game_time(timer_count);
|
||||
input_dialog->show();
|
||||
}
|
||||
}
|
|
@ -16,6 +16,10 @@ struct _MineSweeper
|
|||
{
|
||||
GtkApplicationWindow parent_instance;
|
||||
|
||||
// Header widgets
|
||||
GtkWidget *header, *menu_btn;
|
||||
GtkBuilder *menu_builder;
|
||||
|
||||
// Child widgets
|
||||
GtkWidget *main_box, *btn_box;
|
||||
GtkWidget *mine_grid;
|
||||
|
@ -284,10 +288,55 @@ static void btnshow_clicked(GtkButton *btn, MineSweeper *self)
|
|||
}
|
||||
}
|
||||
|
||||
// Signal Handler for menus
|
||||
static void newgame_activated(GSimpleAction *action, GVariant *parmeter, gpointer data)
|
||||
{
|
||||
btnstart_clicked(NULL, MINE_SWEEPER(data));
|
||||
}
|
||||
|
||||
static void scores_activated(GSimpleAction *action, GVariant *parmeter, gpointer data)
|
||||
{
|
||||
}
|
||||
|
||||
static void showmines_activated(GSimpleAction *action, GVariant *parmeter, gpointer data)
|
||||
{
|
||||
btnshow_clicked(NULL, MINE_SWEEPER(data));
|
||||
}
|
||||
|
||||
static void quit_activated(GSimpleAction *action, GVariant *parmeter, gpointer data)
|
||||
{
|
||||
gtk_window_destroy(GTK_WINDOW(data));
|
||||
}
|
||||
|
||||
static void mine_sweeper_init(MineSweeper *self)
|
||||
{
|
||||
// Initalize window
|
||||
gtk_window_set_title(GTK_WINDOW(self), "MineSweeper");
|
||||
self->header = gtk_header_bar_new();
|
||||
gtk_window_set_titlebar(GTK_WINDOW(self), self->header);
|
||||
|
||||
// Add action for menu
|
||||
GActionEntry entries[] =
|
||||
{
|
||||
{"new_game", newgame_activated, NULL, NULL, NULL},
|
||||
{"scores", scores_activated, NULL, NULL, NULL},
|
||||
{"show_mines", showmines_activated, NULL, NULL, NULL},
|
||||
{"quit", quit_activated, NULL, NULL, NULL}};
|
||||
g_action_map_add_action_entries(G_ACTION_MAP(self), entries,
|
||||
G_N_ELEMENTS(entries), self);
|
||||
|
||||
// Create Menu and button
|
||||
self->menu_btn = gtk_menu_button_new();
|
||||
gtk_menu_button_set_icon_name(GTK_MENU_BUTTON(self->menu_btn), "open-menu");
|
||||
gtk_header_bar_pack_end(GTK_HEADER_BAR(self->header), self->menu_btn);
|
||||
|
||||
// Create Menu
|
||||
self->menu_builder = gtk_builder_new_from_resource("/org/gtk/daleclack/mine_menu.xml");
|
||||
GMenuModel *model = G_MENU_MODEL(gtk_builder_get_object(self->menu_builder, "mine_menu"));
|
||||
gtk_menu_button_set_menu_model(GTK_MENU_BUTTON(self->menu_btn), model);
|
||||
GtkPopover *popover = gtk_menu_button_get_popover(GTK_MENU_BUTTON(self->menu_btn));
|
||||
gtk_popover_set_has_arrow(popover, FALSE);
|
||||
gtk_widget_set_halign(GTK_WIDGET(popover), GTK_ALIGN_END);
|
||||
|
||||
// Create widgets
|
||||
self->main_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <gtkmm.h>
|
||||
#include "InputBox.hh"
|
||||
#include "ScoresWin.hh"
|
||||
|
||||
// The status of the minesweeper game
|
||||
enum class GameStatus
|
||||
{
|
||||
Running,
|
||||
Winned,
|
||||
Ended,
|
||||
Paused
|
||||
};
|
||||
|
||||
// The cell of the minesweeper game,
|
||||
// and the mines is under the cell
|
||||
class MineCell : public Gtk::Button
|
||||
{
|
||||
public:
|
||||
bool has_mine = false; // Whether the grid has mine
|
||||
bool cleared = false; // Whether the mine is cleared
|
||||
int mines_around; // The number near the grid
|
||||
int x, y; // The Position of the grid
|
||||
MineCell()
|
||||
{
|
||||
// Set button style
|
||||
mines_around = 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Main class
|
||||
class MineSweeper : public Gtk::ApplicationWindow
|
||||
{
|
||||
public:
|
||||
MineSweeper();
|
||||
~MineSweeper();
|
||||
|
||||
private:
|
||||
// HeaderBar
|
||||
Gtk::HeaderBar header;
|
||||
Gtk::MenuButton menu_btn;
|
||||
Gtk::PopoverMenu popover1;
|
||||
|
||||
// Child widgets
|
||||
Gtk::Grid mine_grid;
|
||||
Gtk::Label status_label;
|
||||
Gtk::Box main_box, btn_box;
|
||||
Gtk::Button btnstart, btnpause, btnshow, btnexit;
|
||||
|
||||
// The cell to place mines
|
||||
MineCell *cell;
|
||||
GameStatus game_status; // Use enum class for the status of game
|
||||
// bool winned, game_ended; // The status of game(win/end)
|
||||
int mines_clear, mine_count; // Whether the mine is cleared
|
||||
|
||||
// Menu
|
||||
Glib::RefPtr<Gtk::Builder> menu_builder;
|
||||
|
||||
// Timer
|
||||
int timer_count;
|
||||
sigc::connection mytimer;
|
||||
|
||||
// Input dialog
|
||||
InputBox *input_dialog;
|
||||
|
||||
// Scores Window
|
||||
ScoresWin *scores_win;
|
||||
|
||||
// Signal Handlers
|
||||
void new_game(); // "New Game" handler
|
||||
void reset_game(int width = 7, int height = 7, int mines = 9); // Reset all mines
|
||||
void pause_game(); // Pause or continue the game
|
||||
void calc_mines(); // Get the mines around
|
||||
void show_mines(); // Show all mines
|
||||
void show_scores(); // Show all scores
|
||||
void game_lost(int explode_index); // You lost the game
|
||||
void cell_clicked(MineCell *cell1); // Open a cell
|
||||
bool timer_func(); // Timer
|
||||
void check_mines(int pos_x, int pos_y); // Check if there is a mine
|
||||
};
|
Loading…
Reference in New Issue