Last active
January 1, 2016 15:09
-
-
Save krofna/8162728 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * 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