Fix code problems and add mine app code

This commit is contained in:
daleclack 2024-02-21 18:39:10 +08:00
parent e5bdcc39c5
commit 20e6524eb0
14 changed files with 409 additions and 716 deletions

View File

@ -29,7 +29,8 @@ set(SOURCES src/core/main.cpp src/core/MainWin.cpp src/core/MyStack.cpp
src/file_app/FileWindow.cpp src/game_app/GameApp.cpp src/calc_app/calc.cpp
src/calc_app/CalcApp.cpp src/run_app/RunApp.cpp src/draw_app/DrawApp.cpp
src/game24_app/Game24.cpp src/game24_app/Game24App.cpp src/text_app/TextEditor.cpp
src/text_app/MyInfoBar.cpp src/image_app/ImageApp.cpp src/image_app/MyImage.cpp)
src/text_app/MyInfoBar.cpp src/image_app/ImageApp.cpp src/image_app/MyImage.cpp
src/mine_app/MineSweeper.cpp src/mine_app/MineCell.cpp)
#Compile resources with GCR_CMake

View File

@ -0,0 +1,7 @@
#pragma once
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE(MineSweeper, mine_sweeper, MINE, SWEEPER, GtkApplicationWindow)
MineSweeper *mine_sweeper_new();

View File

@ -1,68 +0,0 @@
#pragma once
#include <gtkmm.h>
#include "InputBox.hh"
#include "ScoresWin.hh"
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
set_has_frame(false);
mines_around = 0;
}
};
class MineSweeper : public Gtk::ApplicationWindow
{
public:
MineSweeper();
~MineSweeper();
private:
// HeaderBar
Gtk::HeaderBar header;
Gtk::MenuButton menu_btn;
Gtk::Popover popover1;
// Child widgets
Gtk::Grid mine_grid;
Gtk::Label status_label;
Gtk::Box main_box, btn_box;
Gtk::Button btnstart, btnshow, btnexit;
// The cell to place mines
MineCell *cell;
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 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
};

View File

@ -1,89 +0,0 @@
#pragma once
#include <gtkmm.h>
// 4 Draw modes: default(free draw), circle, line, rectangle
enum class DrawMode{
Default,
Circle,
Line,
Rectangle
};
// Flage for process of drawing
enum class DrawProcess{
Begin, // The beginning of draw
Update, // The Process(Position update)
End // The end of draw
};
class Drawing : public Gtk::Window
{
// Drawing Mode
DrawMode drawing_mode;
// Child Widgets
Gtk::DrawingArea draw_area;
Gtk::ColorButton color_btn, fill_btn;
Gtk::CheckButton fill_check;
Gtk::Label main_label, size_label;
Gtk::Box left_box, main_box, btn_box;
Gtk::Button btn_clear, btn_save, btn_exit;
Gtk::RadioButton btn_free, btn_line, btn_circle, btn_rectangle;
Gtk::Scale scale;
// Color Setting
Gdk::RGBA m_color, fill_color;
Cairo::RefPtr<Cairo::ImageSurface> surface;
// Image Save Dialog
Glib::RefPtr<Gtk::FileChooserNative> dialog;
void dialog_response(int response_id);
// Draw Brush Settings
double brush_size;
double rel_x, rel_y;
bool begin = true;
// Gesture to draw
Glib::RefPtr<Gtk::GestureDrag> drag;
Glib::RefPtr<Gtk::GestureMultiPress> press;
Glib::RefPtr<Gtk::Adjustment> size_adj;
double start_x, start_y;
// Signal Handlers
// Part 1: Drawing signal handlers
bool draw_event(const Cairo::RefPtr<Cairo::Context> &context);
void draw_brush(double x, double y, DrawProcess process = DrawProcess::Update);
void draw_fill_color(const Cairo::RefPtr<Cairo::Context> &cr);
// Part 2: Signal handler for gestures
void button_press(int n_press, double x, double y);
void drag_begin(double x, double y);
void drag_progress(double x, double y);
void drag_end(double x, double y);
// Part 3: Signal Hanlders for normal buttons on the UI
void color_set();
void btnfree_clicked();
void btnline_clicked();
void btncircle_clicked();
void btnrectangle_clicked();
void btnclear_clicked();
void btnsave_clicked();
public:
Drawing();
};

View File

@ -1,99 +0,0 @@
#include "InputBox.hh"
InputBox::InputBox(BaseObjectType *cobject, const Glib::RefPtr<Gtk::Builder> &ref_Glade)
: Gtk::Dialog(cobject),
ref_builder(ref_Glade)
{
// Get Widgets
ref_builder->get_widget("entry_name", entry_name);
ref_builder->get_widget("check_scores", check_scores);
entry_name->signal_activate().connect(sigc::mem_fun(*this, &InputBox::entry_activated));
}
void InputBox::on_response(int response_id)
{
// Open a file to save json data
std::fstream outfile;
outfile.open("scores.json", std::ios_base::out);
if (outfile.is_open())
{
// Insert data to json
std::string name = std::string((entry_name->get_text()).c_str());
names.push_back(name);
times.push_back(game_time);
data["name"] = names;
data["time"] = times;
// Output data
outfile << data;
}
outfile.close();
if (response_id == Gtk::RESPONSE_OK)
{
read_scores(check_scores->get_active());
}
hide();
}
void InputBox::read_scores(bool show_scores_win)
{
// If show scores checkbutton is checked, show scores window
if (show_scores_win)
{
scores_win1->update_and_show();
}
}
void InputBox::set_game_time(int time)
{
// Try to open json file
std::fstream jsonfile;
jsonfile.open("scores.json", std::ios_base::in);
// If json file opened, read the data
if (jsonfile.is_open())
{
data = json::parse(jsonfile);
std::vector<std::string> names1 = data["name"];
std::vector<int> times1 = data["time"];
names = names1;
times = times1;
}
else
{
// Otherwist, create json data
data = json::parse(R"(
{
"name":[" "],
"time":[0]
}
)");
}
jsonfile.close();
// Initalize time
game_time = time;
}
void InputBox::entry_activated()
{
// Default response
response(Gtk::RESPONSE_OK);
}
void InputBox::set_scores_window(ScoresWin *win1)
{
// Bind Scores Window
scores_win1 = win1;
}
InputBox *InputBox::create()
{
// Create a inputbox object
auto builder = Gtk::Builder::create_from_resource("/org/gtk/daleclack/win_input.ui");
InputBox *dialog;
builder->get_widget_derived("dialog", dialog);
return dialog;
}

View File

@ -1,38 +0,0 @@
#pragma once
#include <gtkmm.h>
#include "jsonfile.hh"
#include "ScoresWin.hh"
class InputBox : public Gtk::Dialog{
public:
static InputBox *create();
InputBox(BaseObjectType *cobject, const Glib::RefPtr<Gtk::Builder> &ref_Glade);
void read_scores(bool show_scores_win = true);
void set_game_time(int time);
void set_scores_window(ScoresWin *win1);
protected:
void on_response(int response_id) override;
private:
int game_time;
// Data to write to json file
json data;
std::vector<std::string> names;
std::vector<int> times;
// Builder Object
Glib::RefPtr<Gtk::Builder> ref_builder;
// Child widget
Gtk::Entry *entry_name;
Gtk::CheckButton *check_scores;
// Scores Window
ScoresWin *scores_win1;
// Signal Handlers
void entry_activated();
};

View File

@ -0,0 +1,50 @@
#include "MineCell.h"
struct _MineCell
{
GtkButton parent_instance;
gboolean has_mine = FALSE;
gboolean cleared = FALSE;
int mines_around;
int x, y;
};
G_DEFINE_TYPE(MineCell, mine_cell, GTK_TYPE_BUTTON)
static void mine_cell_init(MineCell *self)
{
gtk_button_set_icon_name(GTK_BUTTON(self), "");
// gtk_button_set_has_frame(GTK_BUTTON(self), FALSE);
gtk_widget_set_size_request(GTK_WIDGET(self), 40, 40);
self->mines_around = 0;
self->has_mine = FALSE;
}
static void mine_cell_class_init(MineCellClass *klass)
{
}
void mine_cell_get_configs(MineCell *cell, gboolean &cell_has_mine, gboolean &cell_cleared,
int &cell_mines_around, int &cell_x, int &cell_y)
{
cell_has_mine = cell->has_mine;
cell_cleared = cell->cleared;
cell_mines_around = cell->mines_around;
cell_x = cell->x;
cell_y = cell->y;
}
void mine_cell_set_configs(MineCell *cell, gboolean cell_has_mine, gboolean cell_cleared,
int cell_mines_around, int cell_x, int cell_y)
{
cell->has_mine = cell_has_mine;
cell->cleared = cell_cleared;
cell->mines_around = cell_mines_around;
cell->x = cell_x;
cell->y = cell_y;
}
MineCell *mine_cell_new()
{
return Mine_Cell(g_object_new(mine_cell_get_type(), NULL));
}

View File

@ -0,0 +1,13 @@
#pragma once
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE(MineCell, mine_cell, Mine, Cell, GtkButton)
MineCell *mine_cell_new();
void mine_cell_get_configs(MineCell *cell, gboolean &cell_has_mine, gboolean &cell_cleared,
int &cell_mines_around, int &cell_x, int &cell_y);
void mine_cell_set_configs(MineCell *cell, gboolean cell_has_mine, gboolean cell_cleared,
int cell_mines_around, int cell_x, int cell_y);

View File

@ -1,295 +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
header.set_title("MineSweeper");
set_titlebar(header);
header.set_show_close_button();
header.set_decoration_layout("close,minimize,maximize:menu");
header.prepend(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("mine_menu");
auto gmenu = Glib::RefPtr<Gio::Menu>::cast_dynamic(object);
popover1.bind_model(gmenu);
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");
btnshow.set_label("Show All");
btnexit.set_label("Exit");
btn_box.append(btnstart);
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
add(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_relief(Gtk::RELIEF_HALF);
cell[i * 7 + j].set_image_from_icon_name("", Gtk::ICON_SIZE_LARGE_TOOLBAR);
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;
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_relief(Gtk::RELIEF_HALF);
cell[i * width + j].x = j;
cell[i * width + j].y = i;
cell[i * width + j].cleared = false;
}
}
mine_grid.show_all();
}
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::ICON_SIZE_LARGE_TOOLBAR);
}
}
}
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::ICON_SIZE_LARGE_TOOLBAR);
}
}
}
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_ended && !cell1->cleared)
{
//
// If get mine, the game will end now
if (cell1->has_mine)
{
// Set game to stop
winned = false;
cell1->cleared = true;
cell1->set_image_from_icon_name("exploded", Gtk::ICON_SIZE_LARGE_TOOLBAR);
// 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::ICON_SIZE_LARGE_TOOLBAR);
}
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::ICON_SIZE_LARGE_TOOLBAR);
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!");
winned = true;
game_ended = true;
mytimer.disconnect();
// Save the time of game
input_dialog->set_game_time(timer_count);
input_dialog->show_all();
}
}

View File

@ -0,0 +1,327 @@
#include "MineSweeper.h"
#include "MineCell.h"
#include <cstdlib>
#include <string>
// The status of the minesweeper game
typedef enum
{
Running,
Winned,
Ended,
Paused
} GameStatus;
struct _MineSweeper
{
GtkApplicationWindow parent_instance;
// Child widgets
GtkWidget *main_box, *btn_box;
GtkWidget *mine_grid;
GtkWidget *time_label, *status_label;
MineCell *cell[49];
GtkWidget *btn_start, *btn_show, *btn_exit;
// Tags for game status
int time_count;
gboolean started;
int mines_clear, mine_count;
GameStatus game_status;
};
G_DEFINE_TYPE(MineSweeper, mine_sweeper, GTK_TYPE_APPLICATION_WINDOW)
static void mine_sweeper_game_lost(MineSweeper *self, int explode_index)
{
gboolean has_mine, cleared;
int mines_around, x, y;
MineCell **cells = self->cell;
// Show all mines
for (int i = 0; i < 49; i++)
{
mine_cell_get_configs(cells[i], has_mine, cleared, mines_around, x, y);
if (has_mine && !cleared)
{
gtk_button_set_icon_name(GTK_BUTTON(cells[i]), "mine");
}
}
gtk_widget_set_sensitive(self->mine_grid, FALSE);
}
static void mine_sweeper_find_mines(int i, int j, MineCell **cell)
{
gboolean has_mine, cleared;
int mines_around, x, y;
int index1, index2;
int mines = 0;
// 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++)
{
mine_cell_get_configs(cell[index1 * 7 + index2], has_mine, cleared, mines_around, x, y);
if (has_mine)
{
// cell[i * 7 + j].mines_around++;
mines++;
}
}
}
// Update config of mine cell
mine_cell_get_configs(cell[i * 7 + j], has_mine, cleared, mines_around, x, y);
mine_cell_set_configs(cell[i * 7 + j], has_mine, cleared, mines, x, y);
}
static void mine_sweeper_reset(MineSweeper *self, int mines)
{
gboolean has_mine, cleared;
int mines_around, x, y;
// Reset mines status
self->mines_clear = 0;
self->mine_count = 0;
// Reset cell icons
MineCell **cells = self->cell;
for (int i = 0; i < 7; i++)
{
for (int j = 0; j < 7; j++)
{
gtk_button_set_icon_name(GTK_BUTTON(cells[i * 7 + j]), "");
gtk_button_set_has_frame(GTK_BUTTON(cells[i * 7 + j]), TRUE);
mine_cell_set_configs(cells[i * 7 + j], FALSE, FALSE, 0, j, i);
}
}
// Add mines
while (self->mine_count < mines)
{
int i = g_random_int_range(0, 49);
mine_cell_get_configs(cells[i], has_mine, cleared, mines_around, x, y);
if (!has_mine)
{
mine_cell_set_configs(cells[i], TRUE, FALSE, 0, x, y);
self->mine_count++;
}
}
// Calculate the mines around a cell
for (int i = 0; i < 7; i++)
{
for (int j = 0; j < 7; j++)
{
mine_sweeper_find_mines(i, j, cells);
}
}
}
static void mine_sweeper_check_mines(MineSweeper *self, int pos_x, int pos_y)
{
gboolean has_mine, cleared;
int mines_around, x, y;
MineCell **cells = self->cell;
if (pos_x >= 0 && pos_x <= 6 &&
pos_y >= 0 && pos_y <= 6)
{
mine_cell_get_configs(cells[pos_y * 7 + pos_x], has_mine, cleared, mines_around, x, y);
if (!has_mine && !cleared)
{
(self->mines_clear)++;
// Show the cell has no mines around
if (mines_around == 0)
{
gtk_button_set_icon_name(GTK_BUTTON(cells[pos_y * 7 + pos_x]), "");
}
else
{
// Show the numbers of mines around a cell
char *label = g_strdup_printf("%dmines", mines_around);
gtk_button_set_icon_name(GTK_BUTTON(cells[pos_y * 7 + pos_x]), label);
g_free(label);
}
// make the cell without mines cleared
gtk_button_set_has_frame(GTK_BUTTON(cells[pos_y * 7 + pos_x]), FALSE);
mine_cell_set_configs(cells[pos_y * 7 + pos_x], has_mine, TRUE, mines_around, x, y);
// Check the cells around a cell that has no mines
if (mines_around == 0)
{
mine_sweeper_check_mines(self, (pos_x - 1), (pos_y - 1));
mine_sweeper_check_mines(self, (pos_x + 1), (pos_y + 1));
mine_sweeper_check_mines(self, (pos_x - 1), (pos_y + 1));
mine_sweeper_check_mines(self, (pos_x + 1), (pos_y - 1));
mine_sweeper_check_mines(self, pos_x, (pos_y - 1));
mine_sweeper_check_mines(self, pos_x, (pos_y + 1));
mine_sweeper_check_mines(self, (pos_x + 1), pos_y);
mine_sweeper_check_mines(self, (pos_x - 1), pos_y);
}
}
}
// If all the mines has cleared, you has winned
if (self->mines_clear == 40)
{
// Stop the game
gtk_label_set_label(GTK_LABEL(self->status_label), "You winned!");
self->game_status = GameStatus::Winned;
self->started = FALSE;
// // Save the time of game
// input_dialog->set_game_time(timer_count);
// input_dialog->show();
}
}
static void mine_cell_clicked(MineCell *cell, MineSweeper *self)
{
gboolean has_mine, cleared;
int mines_around, x, y;
// Take all properties
mine_cell_get_configs(cell, has_mine, cleared, mines_around, x, y);
// Unset frame to show the cell opened
gtk_button_set_has_frame(GTK_BUTTON(cell), FALSE);
if (self->game_status == GameStatus::Running && !cleared)
{
// If get mine, the game will end now
if (has_mine)
{
// Clear the cell
mine_cell_set_configs(cell, has_mine, TRUE, mines_around, x, y);
// Set game to stop
// winned = false;
self->game_status = GameStatus::Ended;
gtk_button_set_icon_name(GTK_BUTTON(cell), "exploded");
// End the game
mine_sweeper_game_lost(self, y * 7 + x);
gtk_label_set_label(GTK_LABEL(self->status_label), "You lost!");
self->started = FALSE;
gtk_widget_set_sensitive(self->mine_grid, FALSE);
}
else
{
// If no mines, check the cell around
mine_sweeper_check_mines(self, x, y);
}
}
}
static void mine_sweeper_cells_init(MineSweeper *self, int width, int height)
{
// The mine sweeper will be 7x7
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
MineCell *cell = mine_cell_new();
(self->cell)[i * width + j] = cell;
g_signal_connect(cell, "clicked", G_CALLBACK(mine_cell_clicked), self);
}
}
// Append mines to grid
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
GtkWidget *widget = GTK_WIDGET((self->cell)[i * width + j]);
gtk_grid_attach(GTK_GRID(self->mine_grid), widget, j, i, 1, 1);
mine_cell_set_configs((self->cell)[i * width + j], FALSE, FALSE, 0, j, i);
}
}
gtk_widget_set_sensitive(self->mine_grid, FALSE);
}
static gboolean time_func(gpointer data)
{
MineSweeper *mine_app = MINE_SWEEPER(data);
char tmp[50];
(mine_app->time_count)++;
sprintf(tmp, "Time:%d", mine_app->time_count);
gtk_label_set_label(GTK_LABEL(mine_app->time_label), tmp);
return mine_app->started;
}
static void btnstart_clicked(GtkButton *btn, MineSweeper *self)
{
// Reset mine status
mine_sweeper_reset(self, 9);
// Start game
gtk_widget_set_sensitive(self->mine_grid, TRUE);
self->time_count = 0;
self->started = TRUE;
self->game_status = GameStatus::Running;
g_timeout_add(1000, time_func, self);
gtk_label_set_label(GTK_LABEL(self->status_label), "Started");
}
static void btnshow_clicked(GtkButton *btn, MineSweeper *self)
{
// Show all cells that has mine
gboolean has_mine, cleared;
int mines_around, x, y;
MineCell **cells = self->cell;
// Take all properties
for (int i = 0; i < 49; i++)
{
mine_cell_get_configs(cells[i], has_mine, cleared, mines_around, x, y);
// Show all buttons that has mine
if (has_mine)
{
gtk_button_set_icon_name(GTK_BUTTON(cells[i]), "mine");
}
}
}
static void mine_sweeper_init(MineSweeper *self)
{
// Initalize window
gtk_window_set_title(GTK_WINDOW(self), "MineSweeper");
// Create widgets
self->main_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
self->mine_grid = gtk_grid_new();
self->time_label = gtk_label_new("");
self->status_label = gtk_label_new("");
self->btn_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
self->btn_start = gtk_button_new_with_label("Start/Reset");
self->btn_show = gtk_button_new_with_label("Show All");
self->btn_exit = gtk_button_new_with_label("Exit");
g_signal_connect(self->btn_start, "clicked", G_CALLBACK(btnstart_clicked), self);
g_signal_connect(self->btn_show, "clicked", G_CALLBACK(btnshow_clicked), self);
g_signal_connect_swapped(self->btn_exit, "clicked", G_CALLBACK(gtk_window_close), self);
// Create mine cells
mine_sweeper_cells_init(self, 7, 7);
gtk_widget_set_halign(self->time_label, GTK_ALIGN_CENTER);
gtk_widget_set_halign(self->mine_grid, GTK_ALIGN_CENTER);
gtk_widget_set_halign(self->btn_box, GTK_ALIGN_CENTER);
gtk_box_append(GTK_BOX(self->main_box), self->status_label);
gtk_box_append(GTK_BOX(self->main_box), self->time_label);
gtk_box_append(GTK_BOX(self->main_box), self->mine_grid);
gtk_box_append(GTK_BOX(self->btn_box), self->btn_start);
gtk_box_append(GTK_BOX(self->btn_box), self->btn_show);
gtk_box_append(GTK_BOX(self->btn_box), self->btn_exit);
gtk_box_append(GTK_BOX(self->main_box), self->btn_box);
gtk_window_set_child(GTK_WINDOW(self), self->main_box);
}
static void mine_sweeper_class_init(MineSweeperClass *klass)
{
}
MineSweeper *mine_sweeper_new()
{
return MINE_SWEEPER(g_object_new(mine_sweeper_get_type(), NULL));
}

View File

@ -1,76 +0,0 @@
#include "ScoresWin.hh"
ScoresWin::ScoresWin(BaseObjectType *cobject, const Glib::RefPtr<Gtk::Builder> &ref_Glade)
: Gtk::Window(cobject),
ref_builder(ref_Glade)
{
// Get Widgets
ref_builder->get_widget("btnclose", btnclose);
ref_builder->get_widget("scores_view", tree_view);
btnclose->signal_clicked().connect(sigc::mem_fun(*this, &ScoresWin::hide));
// Create the list store
store = Gtk::ListStore::create(column1);
store->set_sort_func(column1.win_time, sigc::mem_fun(*this, &ScoresWin::sort_func));
store->set_sort_column(column1.win_time, Gtk::SortType::SORT_ASCENDING);
tree_view->set_model(store);
tree_view->append_column("name", column1.player_name);
tree_view->append_column("time", column1.win_time);
}
void ScoresWin::update_and_show()
{
std::fstream infile;
infile.open("scores.json", std::ios_base::in);
if (infile.is_open())
{
// Read data from json file
json data = json::parse(infile);
std::vector<std::string> name_vec = data["name"];
std::vector<int> time_vec = data["time"];
// Clear the store
store->clear();
// Append data to the store
for (int i = 0; i < name_vec.size(); i++)
{
auto row = *(store->append());
row[column1.player_name] = name_vec[i];
row[column1.win_time] = time_vec[i];
}
}
show_all();
}
int ScoresWin::sort_func(const Gtk::TreeModel::iterator &iter1, const Gtk::TreeModel::iterator &iter2)
{
// Sort by the game time
auto row1 = *iter1;
auto row2 = *iter2;
if (row1[column1.win_time] < row2[column1.win_time])
{
return -1;
}
if (row1[column1.win_time] == row2[column1.win_time])
{
return 0;
}
else
{
return 1;
}
}
ScoresWin *ScoresWin::create()
{
// Create a window
auto builder = Gtk::Builder::create_from_resource("/org/gtk/daleclack/scoreswin.ui");
ScoresWin *main_win;
builder->get_widget_derived("scores_win", main_win);
return main_win;
}

View File

@ -1,35 +0,0 @@
#pragma once
#include <gtkmm.h>
#include "jsonfile.hh"
class ScoresWin : public Gtk::Window{
public:
static ScoresWin *create();
ScoresWin(BaseObjectType *cobject, const Glib::RefPtr<Gtk::Builder> &ref_Glade);
void update_and_show();
private:
Glib::RefPtr<Gtk::Builder> ref_builder;
// Child widgets
Gtk::Button *btnclose;
Gtk::TreeView *tree_view;
// TreeView data
class ModelColumns : public Gtk::TreeModelColumnRecord{
public:
ModelColumns(){
add(player_name);
add(win_time);
}
Gtk::TreeModelColumn<std::string> player_name;
Gtk::TreeModelColumn<int> win_time;
};
ModelColumns column1;
Glib::RefPtr<Gtk::ListStore> store;
// Sort function
int sort_func(const Gtk::TreeModel::iterator &iter1, const Gtk::TreeModel::iterator &iter2);
};

View File

@ -1,7 +0,0 @@
#pragma once
#include "../json_nlohmann/json.hpp"
#include <fstream>
#include <vector>
using json = nlohmann::json;

View File

@ -9,6 +9,7 @@
#include "DrawApp.h"
#include "TextEditor.h"
#include "ImageApp.h"
#include "MineSweeper.h"
enum PadPage
{
@ -47,6 +48,7 @@ struct _MyDock
DrawApp *draw_win; // A Drawing App
TextEditor *edit_win; // Text Editor
ImageApp *image_app; // Image Viewer
MineSweeper *mine_app; // Mine Sweeper
};
G_DEFINE_TYPE(MyDock, my_dock, GTK_TYPE_BOX)
@ -166,7 +168,7 @@ static gboolean prefs_win_closed(GtkWidget *window, MyDock *dock)
}
// File Broswer control functions
static void padfiles_clicked(GtkWindow *window, MyDock *dock)
static void padfiles_clicked(GtkWidget *widget, MyDock *dock)
{
// When the window visible, unminimize it
if (gtk_widget_get_visible(GTK_WIDGET((dock->file_win))))
@ -183,7 +185,7 @@ static void padfiles_clicked(GtkWindow *window, MyDock *dock)
btnlaunch_clicked(NULL, dock);
}
static void btnfiles_clicked(GtkWindow *window, MyDock *dock)
static void btnfiles_clicked(GtkWidget *widget, MyDock *dock)
{
// When the window visible, control window state
if (gtk_widget_get_visible(GTK_WIDGET((dock->file_win))))
@ -208,7 +210,7 @@ static gboolean file_window_closed(GtkWidget *window, MyDock *dock)
}
// Guess Game control functions
static void padgame_clicked(GtkWindow *window, MyDock *dock)
static void padgame_clicked(GtkWidget *widget, MyDock *dock)
{
// When the window visible, unminimize it
if (gtk_widget_get_visible(GTK_WIDGET((dock->game_win))))
@ -250,7 +252,7 @@ static gboolean game_win_closed(GtkWidget *game_win, MyDock *dock)
}
// Calculator App control functions
static void padcalc_clicked(GtkWindow *window, MyDock *dock)
static void padcalc_clicked(GtkWidget *widget, MyDock *dock)
{
// When the window visible, unminimize it
if (gtk_widget_get_visible(GTK_WIDGET((dock->calc_win))))
@ -301,7 +303,7 @@ static void padrun_clicked(GtkWidget *widget, MyDock *dock)
}
// 24 Game control functions
static void padgame24_clicked(GtkWindow *window, MyDock *dock)
static void padgame24_clicked(GtkWidget *widget, MyDock *dock)
{
// When the window visible, unminimize it
if (gtk_widget_get_visible(GTK_WIDGET((dock->game24_win))))
@ -343,7 +345,7 @@ static gboolean game24_win_closed(GtkWidget *game24_win, MyDock *dock)
}
// Drawing App control functions
static void paddraw_clicked(GtkWindow *window, MyDock *dock)
static void paddraw_clicked(GtkWidget *widget, MyDock *dock)
{
// When the window visible, unminimize it
if (gtk_widget_get_visible(GTK_WIDGET((dock->draw_win))))
@ -385,7 +387,7 @@ static gboolean draw_win_closed(GtkWidget *draw_win, MyDock *dock)
}
// Text Editor control functions
static void padedit_clicked(GtkWindow *window, MyDock *dock)
static void padedit_clicked(GtkWidget *widget, MyDock *dock)
{
// When the window visible, unminimize it
if (gtk_widget_get_visible(GTK_WIDGET((dock->edit_win))))
@ -428,7 +430,7 @@ static gboolean edit_win_closed(GtkWidget *win, MyDock *dock)
}
// Image viewer control functions
static void padimage_clicked(GtkWindow *window, MyDock *dock)
static void padimage_clicked(GtkWidget *widget, MyDock *dock)
{
// When the window visible, unminimize it
if (gtk_widget_get_visible(GTK_WIDGET((dock->image_app))))