Skip to content

Commit

Permalink
Save Entires and Sort by Last Ran by default
Browse files Browse the repository at this point in the history
Also added "Sort By" Menu Added with "Last Ran", "Most Ran", and
"Least Ran" as options.
  • Loading branch information
iguessthislldo committed Apr 3, 2018
1 parent 03745b4 commit a179aab
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 28 deletions.
75 changes: 62 additions & 13 deletions Entry.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ void Entry_delete(Entry * entry) {
if (entry->event_box) g_object_unref(entry->event_box);
if (entry->exec) g_free(entry->exec);
if (entry->cd) g_free(entry->cd);
if (entry->last_ran) free(entry->last_ran);
free(entry);
}

Expand Down Expand Up @@ -63,6 +64,12 @@ void Entry_run(Entry * entry) {
if (debug) {
printf("Would run \"%s\": %s\n", entry->name, exec);
} else {
// Update Entry
entry->count++;
if (entry->last_ran) g_free(entry->last_ran);
entry->last_ran = get_time_string();
Entries_save(entries_file);

// execl wants a file to run AND what to set as argv[0]
execl("/bin/sh", "/bin/sh", "-c", exec, NULL);
// If we get here, execl had a problem running sh...
Expand Down Expand Up @@ -143,20 +150,27 @@ bool Entries_load(Entries * entries, const gchar * path) {
Entry_set_name(entry,
g_key_file_get_string(ini, groups[i], "name", NULL)
);

// count
entry->count = g_key_file_get_integer(ini, groups[i], "count", NULL);

// image_path
entry->image_path = g_key_file_get_string(ini, groups[i], "image", NULL);

// last_ran
if (g_key_file_has_key(ini, groups[i], "last_ran", NULL)) {
entry->last_ran = g_key_file_get_string(ini, groups[i], "last_ran", NULL);
}

// Run Information
if (g_key_file_has_key(ini, groups[i], "exec", NULL)) {
entry->exec = g_key_file_get_value(ini, groups[i], "exec", NULL);
entry->exec = g_key_file_get_string(ini, groups[i], "exec", NULL);
}
if (g_key_file_has_key(ini, groups[i], "cd", NULL)) {
entry->cd = g_key_file_get_value(ini, groups[i], "cd", NULL);
entry->cd = g_key_file_get_string(ini, groups[i], "cd", NULL);
}
if (g_key_file_has_key(ini, groups[i], "steam_id", NULL)) {
entry->steam_id = g_key_file_get_value(
entry->steam_id = g_key_file_get_string(
ini, groups[i], "steam_id", NULL
);
}
Expand Down Expand Up @@ -188,13 +202,34 @@ Entries * Entries_filter(Entries * entries, const char * filter) {
return filtered;
}

/*
* Return true if "a" goes first, else returns false.
*/
bool Entry_compare(Entry * a, Entry * b) {
// a is true, b is false
if (a->count > b->count) {
return true;
} else if (a->count < b->count) {
return false;
}
bool more_ran = a->count > b->count;
bool less_ran = a->count < b->count;
switch (sort_by) {
case LAST_RAN:
if (a->last_ran && !b->last_ran)
return true;
else if (!a->last_ran && b->last_ran)
return false;
else if (a->last_ran && b->last_ran)
compare_time_strings(a->last_ran, b->last_ran);
break;
case MOST_RAN:
if (more_ran)
return true;
else if (less_ran)
return false;
break;
case LEAST_RAN:
if (more_ran)
return false;
else if (less_ran)
return true;
break;
};
return g_utf8_collate(a->uc_name, b->uc_name) < 0;
}

Expand Down Expand Up @@ -296,19 +331,33 @@ void Entries_insert_steam() {

// Download
printf("%s -> %s\n", steam_header_url, header_path);
download(steam_header_url, update_bar, steam_header_url, header_path);
download(NULL, update_bar, steam_header_url, header_path);
free(steam_header_url);
g_free(header_path);
}
}
}

bool Entries_save(Entries * entries, const char * path) {
bool Entries_save(const char * path) {
bool had_error = false;
GKeyFile * ini = g_key_file_new();

for (Node * node = entries->head; node; node = node->next) {
/* g_ket_file_set_string(ini, */
g_key_file_set_integer(ini, "meta", "next_id", next_id);

for (Node * node = all_entries->head; node; node = node->next) {
Entry * e = node->entry;
g_key_file_set_string(ini, e->id, "name", e->name);
g_key_file_set_string(ini, e->id, "image", e->image_path);
g_key_file_set_integer(ini, e->id, "count", e->count);
g_key_file_set_boolean(ini, e->id, "favorite", e->favorite);
if (e->last_ran)
g_key_file_set_string(ini, e->id, "last_ran", e->last_ran);
if (e->exec)
g_key_file_set_string(ini, e->id, "exec", e->exec);
if (e->cd)
g_key_file_set_string(ini, e->id, "cd", e->cd);
if (e->steam_id)
g_key_file_set_string(ini, e->id, "steam_id", e->steam_id);
}

// Save entries to file
Expand Down
11 changes: 10 additions & 1 deletion Entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define ENTRY_HEADER

#include <stdbool.h>
#include <stdint.h>

#include <gtk/gtk.h>

Expand All @@ -18,8 +19,11 @@ struct Entry_struct {
char * name;
char * uc_name;
char * image_path;
unsigned count;

// Sort
unsigned count; // Number of times this Entry has been run
bool favorite;
char * last_ran; // As YYYYMMDDhhmmss

// Run through exec
char * exec;
Expand Down Expand Up @@ -119,4 +123,9 @@ void Entries_sort(Entries * entries);
*/
void Entries_insert_steam();

/*
* Save Entries to "path"
*/
bool Entries_save(const char * path);

#endif
2 changes: 2 additions & 0 deletions launcher.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ int main(int argc, char * argv[]) {
visable_entries = NULL;
steam_path = NULL;
include_steam_entries = false;
entries_changed = false;
sort_by = LAST_RAN;

steam_header_url_head = STEAM_HEADER_URL_HEAD;
steam_header_url_tail = STEAM_HEADER_URL_TAIL;
Expand Down
12 changes: 12 additions & 0 deletions launcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@
#define BANNER_HIGHT 215
#define GRID_WIDTH 3

// Sorting State
// How to sort displayed entries
enum _Sort_By {
LAST_RAN,
MOST_RAN,
LEAST_RAN
};
typedef enum _Sort_By Sort_By;
Sort_By sort_by;

bool entries_changed;

bool debug;
bool dev_mode;

Expand Down
72 changes: 58 additions & 14 deletions main_window.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#include <stdlib.h>
#include <string.h>

#include "main_window.h"

GtkWidget * window;
Expand All @@ -7,6 +10,8 @@ GtkWidget * scroll;
GtkWidget * grid;
GtkWidget * menu;

char * filter_string;

void entry_click(GtkWidget * widget, GdkEventButton * event, gpointer data) {
Entry * entry = (Entry *) data;
if (debug) printf(
Expand Down Expand Up @@ -38,22 +43,26 @@ void add_entries_to_grid(Entries * entries) {
}
}

void filter_changed(GtkEntryBuffer * b) {
const char * filter = gtk_entry_buffer_get_text(b);
if (debug) printf("Filter: %s\n", filter);
void update_displayed_entries() {
Entries_clear_container(GTK_CONTAINER(grid), visable_entries);
if (visable_entries != all_entries) {
Entries_delete(visable_entries);
}
if (filter[0]) {
visable_entries = Entries_filter(all_entries, filter);
if (filter_string && filter_string[0]) {
visable_entries = Entries_filter(all_entries, filter_string);
} else {
if (debug) printf(" <RESET>\n");
visable_entries = all_entries;
}
add_entries_to_grid(visable_entries);
}

void filter_changed(GtkEntryBuffer * b) {
if (filter_string) free(filter_string);
filter_string = strdup(gtk_entry_buffer_get_text(b));
if (debug) printf("Filter: %s\n", filter_string);
update_displayed_entries();
}

void init_entries_gui(Entries * entries) {
for (Node * node = entries->head; node; node = node->next) {
Entry * entry = node->entry;
Expand Down Expand Up @@ -90,21 +99,30 @@ void init_entries_gui(Entries * entries) {
gtk_container_add(GTK_CONTAINER(event_box), entry->image);

} else { // Create Error Entry GUI
g_warning("Could load image %s: \"%s\"\n",
full_image_path, error->message
char * error_message = g_strdup_printf(
"Could load image %s: \"%s\"\n",
full_image_path,
error->message
);
g_error_free(error);

GtkWidget * error_message = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add(GTK_CONTAINER(error_message),
if (debug) fprintf(stderr, error_message);

GtkWidget * error_message_box = gtk_box_new(
GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add(GTK_CONTAINER(error_message_box),
gtk_label_new(entry->name)
);
gtk_container_add(GTK_CONTAINER(error_message_box),
gtk_image_new_from_icon_name(
"image-missing", GTK_ICON_SIZE_DIALOG
)
);
gtk_container_add(GTK_CONTAINER(error_message),
gtk_label_new(entry->name)
gtk_container_add(GTK_CONTAINER(error_message_box),
gtk_label_new(error_message)
);
gtk_container_add(GTK_CONTAINER(event_box), error_message);
gtk_container_add(GTK_CONTAINER(event_box), error_message_box);
g_free(error_message);
}

}
Expand All @@ -122,6 +140,12 @@ static bool esc_close(GtkWindow * widget, GdkEventKey *event, gpointer data) {
return false;
}

void set_sort_by(void * value) {
sort_by = (Sort_By) value;
Entries_sort(all_entries);
update_displayed_entries();
}

void init_menu() {
menu = gtk_menu_new();

Expand All @@ -137,6 +161,24 @@ void init_menu() {
GtkWidget * add_item = gtk_menu_item_new_with_label("Add Game(s)");
gtk_menu_attach(GTK_MENU(menu), add_item, 0, 1, a++, b++);

// Sort Entries
GtkWidget * sort_by_item = gtk_menu_item_new_with_label("Sort By");
GtkWidget * sort_by_menu = gtk_menu_new();
char * names[3] = {"Last Ran", "Most Ran", "Least Ran"};
GSList * group = NULL;
for (unsigned i = 0; i < 3; i++) {
GtkWidget * item = gtk_radio_menu_item_new_with_label(group, names[i]);
if (!i) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), true);
group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item));
gtk_menu_attach(GTK_MENU(sort_by_menu), item, 0, 1, i, i+1);
g_signal_connect_swapped(
G_OBJECT(item), "activate",
G_CALLBACK(set_sort_by), (void *) (long unsigned) i
);
}
gtk_menu_item_set_submenu(GTK_MENU_ITEM(sort_by_item), sort_by_menu);
gtk_menu_attach(GTK_MENU(menu), sort_by_item, 0, 1, a++, b++);

GtkWidget * settings_item = gtk_menu_item_new_with_label("Settings");
gtk_menu_attach(GTK_MENU(menu), settings_item, 0, 1, a++, b++);

Expand All @@ -149,6 +191,8 @@ void init_menu() {
}

void init_main_window(GtkApplication * app, gpointer user_data) {
filter = NULL;

// Window
window = gtk_application_window_new(app);
gtk_window_set_resizable(GTK_WINDOW(window), false);
Expand Down Expand Up @@ -191,7 +235,7 @@ void init_main_window(GtkApplication * app, gpointer user_data) {
// Init Entry Elements and add them
init_entries_gui(all_entries);
visable_entries = all_entries;
add_entries_to_grid(visable_entries);
update_displayed_entries();

// Entry Context Menu
init_menu();
Expand Down
14 changes: 14 additions & 0 deletions util.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#include <string.h>
#include <errno.h>
#include <time.h>
#include <stdlib.h>

#include <curl/curl.h>
#include <glib.h>

#include "util.h"

Expand Down Expand Up @@ -67,3 +70,14 @@ bool starts_with(const char * string, const char * prefix) {
}
}

#define TIME_STRING_LEN 15
// 4 + 2+2+2+2+2+ 1 = 15
// YYYYMMDDhhmmss /0
char * get_time_string() {
char * string = g_malloc(TIME_STRING_LEN);
time_t epoch = time(NULL);
struct tm utc = *gmtime(&epoch);
strftime(string, TIME_STRING_LEN, "%Y%m%d%H%M%S", &utc);
return string;
}

29 changes: 29 additions & 0 deletions util.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,37 @@
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

/*
* Try to download a file from "url" to "destination" with "data"
* being passed to "callback".
*/
bool download(void * data,
int (*callback)(void*, double, double, double, double),
const char * url, const char * destination
);

/*
* Returns true if "string" starts with or is the same as "prefix".
*/
bool starts_with(const char * string, const char * prefix);

/* ======================================================================
* Time Functions
*
* Time is stored as a string, in a format similar to ISO 8601:
* YYYYMMDDhhmmss
* Ex: July 20, 1969 at 20:18:00 is "19690720201800"
*/

/*
* Return the current time in YYYYMMDDhhmmss format on the glib heap.
*/
char * get_time_string();

/*
* Compare 2 time strings, returns true if "a" is more recent than "b"
*/
//bool compare_time_strings(const char * a, const char * b)
#define compare_time_strings(a, b) (strcmp((a), (b)) < 0)

0 comments on commit a179aab

Please sign in to comment.