Add Scores Window
This commit is contained in:
parent
311d1e1d21
commit
3a3b3fe59b
|
@ -26,7 +26,8 @@ link_directories (${GTK4_LIBRARY_DIRS})
|
||||||
# set(PO_DIR ${CMAKE_BINARY_DIR}/po/zh_CN/LC_MESSAGES)
|
# set(PO_DIR ${CMAKE_BINARY_DIR}/po/zh_CN/LC_MESSAGES)
|
||||||
|
|
||||||
#Source files
|
#Source files
|
||||||
set(SOURCE_FILE src/main.cpp src/MineSweeper.cpp src/MineCell.cpp src/InputBox.cpp)
|
set(SOURCE_FILE src/main.cpp src/MineSweeper.cpp src/MineCell.cpp
|
||||||
|
src/InputBox.cpp src/ScoresItem.cpp src/ScoresWin.cpp)
|
||||||
|
|
||||||
#Compile Resource
|
#Compile Resource
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include "InputBox.h"
|
#include "InputBox.h"
|
||||||
|
#include "ScoresWin.h"
|
||||||
#include "jsonfile.h"
|
#include "jsonfile.h"
|
||||||
|
|
||||||
struct _InputBox
|
struct _InputBox
|
||||||
|
@ -12,6 +13,9 @@ struct _InputBox
|
||||||
GtkWidget *scores_check;
|
GtkWidget *scores_check;
|
||||||
GtkWidget *btn_ok, *btn_cancel;
|
GtkWidget *btn_ok, *btn_cancel;
|
||||||
int game_time;
|
int game_time;
|
||||||
|
|
||||||
|
// Scores Window
|
||||||
|
ScoresWin *scores_win;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE(InputBox, input_box, GTK_TYPE_WINDOW)
|
G_DEFINE_TYPE(InputBox, input_box, GTK_TYPE_WINDOW)
|
||||||
|
@ -42,7 +46,10 @@ static void btnok_clicked(GtkButton *btn, InputBox *self)
|
||||||
outfile.close();
|
outfile.close();
|
||||||
|
|
||||||
// Show Scores window
|
// Show Scores window
|
||||||
|
if (gtk_check_button_get_active(GTK_CHECK_BUTTON(self->scores_check)))
|
||||||
|
{
|
||||||
|
scores_win_update_and_show(self->scores_win);
|
||||||
|
}
|
||||||
gtk_window_close(GTK_WINDOW(self));
|
gtk_window_close(GTK_WINDOW(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +64,7 @@ static void input_box_init(InputBox *self)
|
||||||
{
|
{
|
||||||
// Initalize window
|
// Initalize window
|
||||||
gtk_window_set_default_size(GTK_WINDOW(self), 300, 150);
|
gtk_window_set_default_size(GTK_WINDOW(self), 300, 150);
|
||||||
|
gtk_window_set_icon_name(GTK_WINDOW(self), "org.gtk.daleclack");
|
||||||
|
|
||||||
// Create widgets
|
// Create widgets
|
||||||
self->main_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
|
self->main_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
|
||||||
|
@ -66,6 +74,10 @@ static void input_box_init(InputBox *self)
|
||||||
self->btn_ok = gtk_button_new_with_label("OK");
|
self->btn_ok = gtk_button_new_with_label("OK");
|
||||||
self->btn_cancel = gtk_button_new_with_label("Cancel");
|
self->btn_cancel = gtk_button_new_with_label("Cancel");
|
||||||
|
|
||||||
|
// Create Scores Window
|
||||||
|
GtkWindow *window = gtk_window_get_transient_for(GTK_WINDOW(self));
|
||||||
|
self->scores_win = scores_win_new(window);
|
||||||
|
|
||||||
// Link signals
|
// Link signals
|
||||||
g_signal_connect(self->btn_ok, "clicked", G_CALLBACK(btnok_clicked), self);
|
g_signal_connect(self->btn_ok, "clicked", G_CALLBACK(btnok_clicked), self);
|
||||||
g_signal_connect(self, "close-request", G_CALLBACK(input_box_closed), self);
|
g_signal_connect(self, "close-request", G_CALLBACK(input_box_closed), self);
|
||||||
|
@ -133,3 +145,8 @@ void input_box_set_game_time(InputBox *self, int time)
|
||||||
// Set game time for input box
|
// Set game time for input box
|
||||||
self->game_time = time;
|
self->game_time = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void input_box_show_scores(InputBox *self)
|
||||||
|
{
|
||||||
|
scores_win_update_and_show(self->scores_win);
|
||||||
|
}
|
||||||
|
|
|
@ -9,3 +9,5 @@ InputBox *input_box_new(GtkWindow *parent);
|
||||||
void input_box_set_game_time(InputBox *self, int time);
|
void input_box_set_game_time(InputBox *self, int time);
|
||||||
|
|
||||||
void input_box_present(InputBox *self);
|
void input_box_present(InputBox *self);
|
||||||
|
|
||||||
|
void input_box_show_scores(InputBox *self);
|
||||||
|
|
|
@ -304,6 +304,8 @@ static void newgame_activated(GSimpleAction *action, GVariant *parmeter, gpointe
|
||||||
|
|
||||||
static void scores_activated(GSimpleAction *action, GVariant *parmeter, gpointer data)
|
static void scores_activated(GSimpleAction *action, GVariant *parmeter, gpointer data)
|
||||||
{
|
{
|
||||||
|
MineSweeper *app = MINE_SWEEPER(data);
|
||||||
|
input_box_show_scores(app->input_box);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void showmines_activated(GSimpleAction *action, GVariant *parmeter, gpointer data)
|
static void showmines_activated(GSimpleAction *action, GVariant *parmeter, gpointer data)
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
#include "ScoresItem.h"
|
||||||
|
|
||||||
|
struct _ScoresItem
|
||||||
|
{
|
||||||
|
GObject parent_instance;
|
||||||
|
char name[NAME_MAX];
|
||||||
|
int time;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(ScoresItem, scores_item, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
static void scores_item_init(ScoresItem *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scores_item_class_init(ScoresItemClass *klass)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ScoresItem *scores_item_new(const char *win_name, int win_time)
|
||||||
|
{
|
||||||
|
ScoresItem *item = Scores_Item(g_object_new(scores_item_get_type(), NULL));
|
||||||
|
strncpy(item->name, win_name, NAME_MAX);
|
||||||
|
item->time = win_time;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *scores_item_get_name(ScoresItem *item)
|
||||||
|
{
|
||||||
|
return item->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scores_item_set_name(ScoresItem *item, const char *win_name)
|
||||||
|
{
|
||||||
|
strncpy(item->name, win_name, NAME_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
int scores_item_get_time(ScoresItem *item)
|
||||||
|
{
|
||||||
|
return item->time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scores_item_set_time(ScoresItem *item, int win_time)
|
||||||
|
{
|
||||||
|
item->time = win_time;
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE(ScoresItem, scores_item, Scores, Item, GObject)
|
||||||
|
|
||||||
|
ScoresItem *scores_item_new(const char *win_name, int win_time);
|
||||||
|
|
||||||
|
const char *scores_item_get_name(ScoresItem *item);
|
||||||
|
|
||||||
|
void scores_item_set_name(ScoresItem *item, const char *win_name);
|
||||||
|
|
||||||
|
int scores_item_get_time(ScoresItem *item);
|
||||||
|
|
||||||
|
void scores_item_set_time(ScoresItem *item, int win_time);
|
|
@ -1,80 +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
|
|
||||||
btnclose = ref_builder->get_widget<Gtk::Button>("btnclose");
|
|
||||||
tree_view = ref_builder->get_widget<Gtk::TreeView>("scores_view");
|
|
||||||
btnclose->signal_clicked().connect(sigc::mem_fun(*this, &ScoresWin::hide));
|
|
||||||
|
|
||||||
// Create the list store
|
|
||||||
store = Gtk::ListStore::create(column1);
|
|
||||||
store->set_sort_column(column1.win_time, Gtk::SortType::ASCENDING);
|
|
||||||
store->set_sort_func(column1.win_time, sigc::mem_fun(*this, &ScoresWin::sort_func));
|
|
||||||
// store->set_default_sort_func(sigc::mem_fun(*this, &ScoresWin::sort_func));
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
int ScoresWin::sort_func(const Gtk::TreeModel::const_iterator &iter1, const Gtk::TreeModel::const_iterator &iter2)
|
|
||||||
{
|
|
||||||
// Sort by the game time
|
|
||||||
auto row1 = *iter1;
|
|
||||||
auto row2 = *iter2;
|
|
||||||
if (row1[column1.win_time] < row2[column1.win_time])
|
|
||||||
{
|
|
||||||
// g_print("test1\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (row1[column1.win_time] == row2[column1.win_time])
|
|
||||||
{
|
|
||||||
// g_print("test2\n");
|
|
||||||
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);
|
|
||||||
main_win = Gtk::Builder::get_widget_derived<ScoresWin>(builder, "scores_win");
|
|
||||||
|
|
||||||
return main_win;
|
|
||||||
}
|
|
|
@ -0,0 +1,178 @@
|
||||||
|
#include "jsonfile.h"
|
||||||
|
#include "ScoresWin.h"
|
||||||
|
#include "ScoresItem.h"
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
struct _ScoresWin
|
||||||
|
{
|
||||||
|
GtkWindow parent;
|
||||||
|
// Child widgets
|
||||||
|
GtkWidget *scrolled_win;
|
||||||
|
GtkWidget *main_box;
|
||||||
|
GtkWidget *btn_close;
|
||||||
|
|
||||||
|
// List widgets
|
||||||
|
GtkWidget *list_view;
|
||||||
|
GtkSingleSelection *selection;
|
||||||
|
GtkListItemFactory *factory_name, *factory_time;
|
||||||
|
GtkColumnViewColumn *column_name, *column_time;
|
||||||
|
GListStore *store;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(ScoresWin, scores_win, GTK_TYPE_WINDOW)
|
||||||
|
|
||||||
|
static gboolean scores_win_closed(GtkWidget *window, ScoresWin *self)
|
||||||
|
{
|
||||||
|
gtk_widget_set_visible(window, FALSE);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void btnclose_clicked(GtkButton *btn, GtkWindow *self)
|
||||||
|
{
|
||||||
|
gtk_window_close(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void name_factory_setup(GtkSignalListItemFactory *factory,
|
||||||
|
GtkListItem *item)
|
||||||
|
{
|
||||||
|
GtkWidget *label = gtk_label_new("");
|
||||||
|
gtk_list_item_set_child(item, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void name_factory_bind(GtkListItemFactory *factory,
|
||||||
|
GtkListItem *item)
|
||||||
|
{
|
||||||
|
// Get child
|
||||||
|
GtkWidget *label;
|
||||||
|
label = gtk_list_item_get_child(item);
|
||||||
|
|
||||||
|
// Get Item
|
||||||
|
ScoresItem *item1 = Scores_Item(gtk_list_item_get_item(item));
|
||||||
|
gtk_label_set_label(GTK_LABEL(label),
|
||||||
|
scores_item_get_name(item1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void time_factory_setup(GtkSignalListItemFactory *factory,
|
||||||
|
GtkListItem *item)
|
||||||
|
{
|
||||||
|
GtkWidget *label = gtk_label_new("");
|
||||||
|
gtk_list_item_set_child(item, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void time_factory_bind(GtkListItemFactory *factory,
|
||||||
|
GtkListItem *item)
|
||||||
|
{
|
||||||
|
// Get child
|
||||||
|
GtkWidget *label;
|
||||||
|
label = gtk_list_item_get_child(item);
|
||||||
|
|
||||||
|
// Get Item
|
||||||
|
ScoresItem *item1 = Scores_Item(gtk_list_item_get_item(item));
|
||||||
|
char *time_str = g_strdup_printf("%d", scores_item_get_time(item1));
|
||||||
|
gtk_label_set_label(GTK_LABEL(label), time_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint sort_func(gpointer a, gpointer b, gpointer user_data)
|
||||||
|
{
|
||||||
|
ScoresItem *item_a = Scores_Item(a);
|
||||||
|
ScoresItem *item_b = Scores_Item(b);
|
||||||
|
int time_a = scores_item_get_time(item_a);
|
||||||
|
int time_b = scores_item_get_time(item_b);
|
||||||
|
|
||||||
|
// Return result
|
||||||
|
if (time_a > time_b)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time_a == time_b)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time_a < time_b)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scores_win_init(ScoresWin *self)
|
||||||
|
{
|
||||||
|
// Initalize window
|
||||||
|
gtk_window_set_title(GTK_WINDOW(self), "Scores");
|
||||||
|
gtk_window_set_icon_name(GTK_WINDOW(self), "org.gtk.daleclack");
|
||||||
|
|
||||||
|
// Create widgets
|
||||||
|
self->main_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
|
||||||
|
self->scrolled_win = gtk_scrolled_window_new();
|
||||||
|
self->btn_close = gtk_button_new_with_label("Close");
|
||||||
|
g_signal_connect(self->btn_close, "clicked", G_CALLBACK(btnclose_clicked), self);
|
||||||
|
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(self->scrolled_win),
|
||||||
|
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||||||
|
gtk_widget_set_size_request(self->scrolled_win, 300, 400);
|
||||||
|
gtk_widget_set_halign(self->btn_close, GTK_ALIGN_CENTER);
|
||||||
|
|
||||||
|
// Create store
|
||||||
|
self->store = g_list_store_new(scores_item_get_type());
|
||||||
|
self->selection = gtk_single_selection_new(G_LIST_MODEL(self->store));
|
||||||
|
|
||||||
|
// Create Column View
|
||||||
|
self->list_view = gtk_column_view_new(GTK_SELECTION_MODEL(self->selection));
|
||||||
|
|
||||||
|
// Create factory for name
|
||||||
|
self->factory_name = gtk_signal_list_item_factory_new();
|
||||||
|
g_signal_connect(self->factory_name, "bind", G_CALLBACK(name_factory_bind), NULL);
|
||||||
|
g_signal_connect(self->factory_name, "setup", G_CALLBACK(name_factory_setup), NULL);
|
||||||
|
self->column_name = gtk_column_view_column_new("Name", self->factory_name);
|
||||||
|
gtk_column_view_append_column(GTK_COLUMN_VIEW(self->list_view), self->column_name);
|
||||||
|
|
||||||
|
// Create factory for time
|
||||||
|
self->factory_time = gtk_signal_list_item_factory_new();
|
||||||
|
g_signal_connect(self->factory_time, "bind", G_CALLBACK(time_factory_bind), NULL);
|
||||||
|
g_signal_connect(self->factory_time, "setup", G_CALLBACK(time_factory_setup), NULL);
|
||||||
|
self->column_time = gtk_column_view_column_new("Time", self->factory_time);
|
||||||
|
gtk_column_view_append_column(GTK_COLUMN_VIEW(self->list_view), self->column_time);
|
||||||
|
|
||||||
|
// Pack widgets
|
||||||
|
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(self->scrolled_win), self->list_view);
|
||||||
|
gtk_box_append(GTK_BOX(self->main_box), self->scrolled_win);
|
||||||
|
gtk_box_append(GTK_BOX(self->main_box), self->btn_close);
|
||||||
|
gtk_window_set_child(GTK_WINDOW(self), self->main_box);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scores_win_class_init(ScoresWinClass *klass)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ScoresWin *scores_win_new(GtkWindow *parent)
|
||||||
|
{
|
||||||
|
return Scores_Win(g_object_new(scores_win_get_type(),
|
||||||
|
"transient-for", parent, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
void scores_win_update_and_show(ScoresWin *self)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
g_list_store_remove_all(self->store);
|
||||||
|
|
||||||
|
// Append data to the store
|
||||||
|
for (int i = 0; i < name_vec.size(); i++)
|
||||||
|
{
|
||||||
|
g_list_store_append(self->store,
|
||||||
|
scores_item_new(name_vec[i].c_str(), time_vec[i]));
|
||||||
|
}
|
||||||
|
g_list_store_sort(self->store, (GCompareDataFunc)sort_func, NULL);
|
||||||
|
}
|
||||||
|
gtk_window_present(GTK_WINDOW(self));
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE(ScoresWin, scores_win, Scores, Win, GtkWindow)
|
||||||
|
|
||||||
|
ScoresWin *scores_win_new(GtkWindow *parent);
|
||||||
|
|
||||||
|
void scores_win_update_and_show(ScoresWin *self);
|
|
@ -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::const_iterator &iter1, const Gtk::TreeModel::const_iterator &iter2);
|
|
||||||
};
|
|
Loading…
Reference in New Issue