Skip to content

Instantly share code, notes, and snippets.

@krofna
Last active January 1, 2016 15:09
Show Gist options
  • Select an option

  • Save krofna/8162728 to your computer and use it in GitHub Desktop.

Select an option

Save krofna/8162728 to your computer and use it in GitHub Desktop.
/*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://www.wtfpl.net/ for more details.
*/
#include <gtk/gtk.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
enum
{
COLUMN_DATE,
COLUMN_HERO,
COLUMN_WIN,
COLUMN_LOSE,
N_COLUMNS
};
enum
{
OUT_HERO,
OUT_AR,
OUT_WIN,
OUT_LOSE,
OUT_AVG,
N_OUTS
};
static const char* classes[] =
{
"Druid", "Hunter", "Mage",
"Paladin", "Priest", "Rogue",
"Shaman", "Warlock", "Warrior",
"<NULL>"
};
GtkWidget* window;
void append_entry(GtkListStore* liststore, gint8 hero, gint16 win, gint16 lose, gchar* date)
{
GtkTreeIter listiter;
gtk_list_store_append(liststore, &listiter);
gtk_list_store_set(liststore, &listiter, COLUMN_DATE, date, COLUMN_HERO, classes[hero], COLUMN_WIN, win, COLUMN_LOSE, lose, -1);
}
void new_button_clicked(GtkButton* button, gpointer data)
{
char tmp[50];
struct tm* info;
time_t ttime;
time(&ttime);
info = localtime(&ttime);
strftime(tmp, 100, "%d/%m/%y %H:%M", info);
append_entry((GtkListStore*)data, 9, 0, 0, tmp);
}
GtkListStore* in_liststore;
void init2(GtkListStore* liststore)
{
FILE* file = fopen("Arena Stats", "rb");
GtkTreeIter listiter;
guint16 num_entries, win, lose, datelen;
guint8 hero;
guint8 heroes[10];
guint8 wins[10];
guint8 loses[10];
if (!file)
return;
gtk_list_store_clear(liststore);
for (gint8 i = 0; i < 10; ++i)
wins[i] = loses[i] = heroes[i] = 0;
fread(&num_entries, sizeof(gint16), 1, file);
for (gint16 i = 0; i < num_entries; ++i)
{
fread(&datelen, sizeof(guint16), 1, file);
fseek(file, datelen, SEEK_CUR);
fread(&hero, sizeof(guint8), 1, file);
fread(&win, sizeof(guint16), 1, file);
fread(&lose, sizeof(guint16), 1, file);
heroes[hero] += 1;
wins[hero] += win;
loses[hero] += lose;
}
fclose(file);
for (gint16 i = 0; i < 9; ++i)
{
float avg_win = 0, avg_lose = 0;
if (heroes[i] > 0)
{
avg_win = wins[i] / (float)heroes[i];
avg_lose = loses[i] / (float)heroes[i];
}
char tmp[50] = { 0 };
sprintf(tmp, "%.2f / %.2f", avg_win, avg_lose);
gtk_list_store_append(liststore, &listiter);
gtk_list_store_set(liststore, &listiter, OUT_HERO, classes[i],
OUT_AR, heroes[i],
OUT_WIN, wins[i],
OUT_LOSE, loses[i],
OUT_AVG, tmp, -1);
}
}
void init(GtkListStore* liststore)
{
FILE* file = fopen("Arena Stats", "rb");
guint16 num_entries, win, lose, datelen;
guint8 hero;
if (!file)
return;
fread(&num_entries, sizeof(gint16), 1, file);
for (gint16 i = 0; i < num_entries; ++i)
{
char tmp[50] = {0};
fread(&datelen, sizeof(guint16), 1, file);
fread(tmp, datelen, 1, file);
fread(&hero, sizeof(gint8), 1, file);
fread(&win, sizeof(gint16), 1, file);
fread(&lose, sizeof(gint16), 1, file);
append_entry(liststore, hero, win, lose, tmp);
}
fclose(file);
}
void save(GtkListStore* list_store)
{
FILE* file = fopen("Arena Stats", "wb");
GtkTreeIter iter;
gboolean valid;
guint16 row_count = 0;
if (!file)
return;
fseek(file, sizeof(guint16), SEEK_SET);
for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list_store), &iter);
valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store), &iter))
{
gchar* hero_str, *date_str;
gint8 hero = 9;
gint win, lose;
gint16 win16, lose16, datelen;
gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter,
COLUMN_DATE, &date_str,
COLUMN_HERO, &hero_str,
COLUMN_WIN, &win,
COLUMN_LOSE, &lose,
-1);
for (int i = 0; i < 10; ++i)
if (strcmp(hero_str, classes[i]) == 0)
hero = i;
win16 = win;
lose16 = lose;
datelen = strlen(date_str);
fwrite(&datelen, sizeof(guint16), 1, file);
fwrite(date_str, datelen, 1, file);
fwrite(&hero, sizeof(gint8), 1, file);
fwrite(&win16, sizeof(guint16), 1, file);
fwrite(&lose16, sizeof(guint16), 1, file);
g_free(hero_str);
row_count++;
}
rewind(file);
fwrite(&row_count, sizeof(guint16), 1, file);
fclose(file);
}
GtkListStore* out_liststore;
void del_button_clicked(GtkButton* button, gpointer data)
{
GList* list = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(data)), NULL);
GtkTreePath* path = g_list_nth_data(list, 0);
GtkTreeIter listiter;
if (!path)
return;
gtk_tree_model_get_iter(GTK_TREE_MODEL(in_liststore), &listiter, path);
gtk_list_store_remove(in_liststore, &listiter);
g_list_foreach(list, (GFunc)gtk_tree_path_free, NULL);
g_list_free(list);
save(in_liststore);
init2(out_liststore);
}
void on_exit(GtkWindow* window, GtkListStore* liststore)
{
save(liststore);
gtk_main_quit();
}
void cell_edited(GtkCellRendererText* renderer, gchar* path, gchar* new_text, gpointer data)
{
GtkListStore* liststore = (GtkListStore*)data;
GtkTreePath* treepath = gtk_tree_path_new_from_string(path);
gint column = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(renderer), "column"));
GtkTreeIter listiter;
if (!new_text)
return;
gtk_tree_model_get_iter(GTK_TREE_MODEL(liststore), &listiter, treepath);
if (column == COLUMN_HERO)
gtk_list_store_set(liststore, &listiter, column, new_text, -1);
else
gtk_list_store_set(liststore, &listiter, column, atoi(new_text), -1);
gtk_tree_path_free(treepath);
save(liststore);
init2(out_liststore);
}
void init_input(GtkWidget* table_box)
{
GtkWidget* scroll_window;
GtkListStore* liststore, *heroliststore;
GtkWidget* treeview;
GtkTreeViewColumn* herocolumn, *wincolumn, *losecolumn, *datecolumn;
GtkCellRenderer* hero_renderer, *win_renderer, *lose_renderer, *date_renderer;
GtkTreeIter listiter;
GtkWidget* vbox, *button_box;
GtkWidget* new_button, *del_button;
GtkAdjustment* adjustment;
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
button_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
hero_renderer = gtk_cell_renderer_combo_new();
win_renderer = gtk_cell_renderer_spin_new();
lose_renderer = gtk_cell_renderer_spin_new();
date_renderer = gtk_cell_renderer_text_new();
g_object_set_data(G_OBJECT(hero_renderer), "column", GINT_TO_POINTER(COLUMN_HERO));
g_object_set_data(G_OBJECT(win_renderer), "column", GINT_TO_POINTER(COLUMN_WIN));
g_object_set_data(G_OBJECT(lose_renderer), "column", GINT_TO_POINTER(COLUMN_LOSE));
adjustment = gtk_adjustment_new(0, 0, 100, 1, 10, 0);
scroll_window = gtk_scrolled_window_new(NULL, NULL);
gtk_widget_set_size_request(scroll_window, 360, 150);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
liststore = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
heroliststore = gtk_list_store_new(1, G_TYPE_STRING);
treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(liststore));
datecolumn = gtk_tree_view_column_new_with_attributes("Date", date_renderer, "text", COLUMN_DATE, NULL);
herocolumn = gtk_tree_view_column_new_with_attributes("Hero", hero_renderer, "text", COLUMN_HERO, NULL);
wincolumn = gtk_tree_view_column_new_with_attributes(" Wins ", win_renderer, "text", COLUMN_WIN, NULL);
losecolumn = gtk_tree_view_column_new_with_attributes(" Loses ", lose_renderer, "text", COLUMN_LOSE, NULL);
new_button = gtk_button_new_with_label("+");
del_button = gtk_button_new_with_label("-");
g_signal_connect(new_button, "clicked", G_CALLBACK(new_button_clicked), liststore);
g_signal_connect(del_button, "clicked", G_CALLBACK(del_button_clicked), treeview);
g_signal_connect(hero_renderer, "edited", G_CALLBACK(cell_edited), liststore);
g_signal_connect(win_renderer, "edited", G_CALLBACK(cell_edited), liststore);
g_signal_connect(lose_renderer, "edited", G_CALLBACK(cell_edited), liststore);
for (int i = 0; i < 9; ++i)
{
gtk_list_store_append(heroliststore, &listiter);
gtk_list_store_set(heroliststore, &listiter, 0, classes[i], -1);
}
g_object_set(hero_renderer, "model", heroliststore,
"text-column", 0,
"has-entry", FALSE,
"editable", TRUE,
NULL);
GValue value = {0}, value2 = {0};
g_value_init(&value, G_TYPE_BOOLEAN);
g_value_init(&value2, G_TYPE_OBJECT);
g_value_set_boolean(&value, TRUE);
g_value_set_object(&value2, adjustment);
g_object_set_property(G_OBJECT(win_renderer), "editable", &value);
g_object_set_property(G_OBJECT(win_renderer), "adjustment", &value2);
g_object_set_property(G_OBJECT(lose_renderer), "editable", &value);
g_object_set_property(G_OBJECT(lose_renderer), "adjustment", &value2);
g_value_unset(&value);
g_value_unset(&value2);
init(liststore);
in_liststore = liststore;
gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), datecolumn);
gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), herocolumn);
gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), wincolumn);
gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), losecolumn);
gtk_container_add(GTK_CONTAINER(scroll_window), treeview);
gtk_box_pack_start(GTK_BOX(vbox), scroll_window, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(button_box), new_button, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(button_box), del_button, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox), button_box, FALSE, TRUE, 0);
gtk_container_add(GTK_CONTAINER(table_box), vbox);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(on_exit), liststore);
}
void add_column(GtkTreeView* treeview, const gchar* label, gint8 num)
{
GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes(label, renderer, "text", num, NULL);
gtk_tree_view_append_column(treeview, column);
if (num > 0 && num < 4)
gtk_tree_view_column_set_sort_column_id(column, num);
}
void init_output(GtkWidget* table_box)
{
static const gchar* labels[] = { "Hero", "Arena Runs", "Wins", "Loses", "Average" };
GtkListStore* liststore;
GtkWidget* treeview;
liststore = gtk_list_store_new(5, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING);
treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(liststore));
init2(liststore),
out_liststore = liststore;
for (int i = 0; i < 5; ++i)
add_column(GTK_TREE_VIEW(treeview), labels[i], i);
gtk_box_pack_start(GTK_BOX(table_box), treeview, TRUE, TRUE, 0);
}
int main(int argc, char** argv)
{
GtkWidget* table_box, *separator;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
table_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
separator = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
init_input(table_box);
gtk_box_pack_start(GTK_BOX(table_box), separator, FALSE, TRUE, 5);
init_output(table_box);
gtk_container_add(GTK_CONTAINER(window), table_box);
gtk_widget_show_all(window);
gtk_window_set_title(GTK_WINDOW(window), "Arena Stats");
gtk_main();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment