[aisleriot] Add recent items to the game select dialog
- From: William Jon McCann <mccann src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [aisleriot] Add recent items to the game select dialog
- Date: Mon, 4 Mar 2013 21:39:40 +0000 (UTC)
commit 3439a2e1285796b95a7e1aa066f52375c74a4404
Author: William Jon McCann <william jon mccann gmail com>
Date: Mon Mar 4 01:16:49 2013 -0500
Add recent items to the game select dialog
https://bugzilla.gnome.org/show_bug.cgi?id=695102
src/ar-game-chooser.c | 206 ++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 171 insertions(+), 35 deletions(-)
---
diff --git a/src/ar-game-chooser.c b/src/ar-game-chooser.c
index 240309f..686fb53 100644
--- a/src/ar-game-chooser.c
+++ b/src/ar-game-chooser.c
@@ -26,6 +26,7 @@
#include "ar-debug.h"
#include "ar-runtime.h"
#include "ar-string-utils.h"
+#include "conf.h"
struct _ArGameChooser
{
@@ -54,12 +55,14 @@ enum {
enum {
COL_NAME,
- COL_GAME_MODULE
+ COL_GAME_MODULE,
+ COL_RECENT_RANK
};
#define SELECT_GAME_DIALOG_MIN_WIDTH (300)
#define SELECT_GAME_DIALOG_MIN_HEIGHT (256)
#define SELECTED_PATH_DATA_KEY "selected-path"
+#define MAX_RECENT 5
/* private functions */
@@ -111,6 +114,154 @@ ar_game_chooser_init (ArGameChooser *chooser)
chooser->priv = G_TYPE_INSTANCE_GET_PRIVATE (chooser, AR_TYPE_GAME_CHOOSER, ArGameChooserPrivate);
}
+static void
+store_add_module (GtkListStore *store,
+ const char *game_module,
+ int recent_rank)
+{
+ char *game_name;
+ GtkTreeIter iter;
+
+ game_name = ar_filename_to_display_name (game_module);
+ gtk_list_store_insert_with_values (store, &iter,
+ -1,
+ COL_NAME, game_name,
+ COL_GAME_MODULE, game_module,
+ COL_RECENT_RANK, recent_rank,
+ -1);
+ g_free (game_name);
+}
+
+static void
+store_add_separator (GtkListStore *store)
+{
+ GtkTreeIter iter;
+
+ gtk_list_store_insert_with_values (store, &iter,
+ -1,
+ COL_NAME, NULL,
+ COL_GAME_MODULE, NULL,
+ COL_RECENT_RANK, 0,
+ -1);
+}
+
+static gboolean
+row_separator_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ gboolean ret;
+ char *game_module;
+
+ gtk_tree_model_get (model, iter,
+ COL_GAME_MODULE, &game_module,
+ -1);
+ ret = (game_module == NULL);
+ g_free (game_module);
+
+ return ret;
+}
+
+static char **
+get_unique_recent_modules (const char *current_module)
+{
+ char **recent_games, **new_recent;
+ gsize i;
+ gsize n_recent = 0;
+ gsize n_new_recent = 0;
+
+ recent_games = ar_conf_get_string_list (NULL, aisleriot_conf_get_key (CONF_RECENT_GAMES), &n_recent, NULL);
+
+ if (recent_games == NULL) {
+ new_recent = g_new (char *, 2);
+ new_recent[0] = g_strdup (current_module);
+ new_recent[1] = NULL;
+ n_new_recent = 1;
+ } else {
+ new_recent = g_new (char *, MIN (n_recent + 1, MAX_RECENT) + 1);
+ n_new_recent = 0;
+
+ new_recent[n_new_recent++] = g_strdup (current_module);
+
+ for (i = 0; i < n_recent && n_new_recent < MAX_RECENT; ++i) {
+ const char *module = recent_games[i];
+ gboolean found = FALSE;
+ gsize j;
+
+ for (j = 0; j < n_new_recent; j++) {
+ const char *existing = new_recent[j];
+
+ if (g_ascii_strcasecmp (existing, module) == 0) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found)
+ new_recent[n_new_recent++] = g_strdup (recent_games[i]);
+ }
+
+ /* NULL termination */
+ new_recent[n_new_recent] = NULL;
+
+ g_strfreev (recent_games);
+ }
+
+ return new_recent;
+}
+
+static void
+add_recent_items (ArGameChooser *chooser)
+{
+ ArGameChooserPrivate *priv = chooser->priv;
+ const char *current_game_module;
+ char **games;
+ int i;
+
+ current_game_module = aisleriot_window_get_game_module (priv->window);
+ games = get_unique_recent_modules (current_game_module);
+
+ for (i = 0; games[i] != NULL; ++i) {
+ store_add_module (priv->store, games[i], MAX_RECENT - i);
+ }
+
+ g_strfreev (games);
+
+ store_add_separator (priv->store);
+}
+
+static int
+sort_func (GtkTreeModel *model,
+ GtkTreeIter *iter_a,
+ GtkTreeIter *iter_b,
+ gpointer data)
+{
+ int ret;
+ int recent_a, recent_b;
+ char *name_a, *name_b;
+
+ gtk_tree_model_get (model, iter_a,
+ COL_NAME, &name_a,
+ COL_RECENT_RANK, &recent_a,
+ -1);
+ gtk_tree_model_get (model, iter_b,
+ COL_NAME, &name_b,
+ COL_RECENT_RANK, &recent_b,
+ -1);
+ if (recent_a < recent_b) {
+ ret = 1;
+ } else if (recent_a > recent_b) {
+ ret = -1;
+ } else {
+ ret = g_utf8_collate (name_a, name_b);
+ }
+
+ g_free (name_a);
+ g_free (name_b);
+
+ return ret;
+}
+
static GObject *
ar_game_chooser_constructor (GType type,
guint n_construct_properties,
@@ -127,9 +278,7 @@ ar_game_chooser_constructor (GType type,
GtkTreeViewColumn *column;
GtkCellRenderer *renderer;
GtkWidget *hbox;
- GtkTreeIter current_iter;
- gboolean current_iter_set = FALSE;
- const char *current_game_module;
+ GtkTreePath *path;
char **games;
int i;
GtkWidget *content_area;
@@ -144,32 +293,16 @@ ar_game_chooser_constructor (GType type,
g_assert (priv->window != NULL);
- priv->store = list = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+ priv->store = list = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
- current_game_module = aisleriot_window_get_game_module (priv->window);
+ add_recent_items (chooser);
games = ar_get_game_modules ();
if (games != NULL) {
for (i = 0; games[i]; ++i) {
const char *game_module = games[i];
- char *game_name;
- GtkTreeIter iter;
-
- game_name = ar_filename_to_display_name (game_module);
- gtk_list_store_insert_with_values (GTK_LIST_STORE (list), &iter,
- -1,
- COL_NAME, game_name,
- COL_GAME_MODULE, game_module,
- -1);
-
- if (current_game_module &&
- strcmp (current_game_module, game_module) == 0) {
- current_iter = iter;
- current_iter_set = TRUE;
- }
-
- g_free (game_name);
+ store_add_module (priv->store, game_module, -1);
}
}
@@ -204,8 +337,15 @@ ar_game_chooser_constructor (GType type,
g_signal_connect (list_view, "row-activated",
G_CALLBACK (row_activated_cb), chooser);
+ gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (list_view),
+ (GtkTreeViewRowSeparatorFunc)row_separator_func,
+ NULL, NULL);
+
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list),
0, GTK_SORT_ASCENDING);
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (list),
+ 0, (GtkTreeIterCompareFunc)sort_func,
+ NULL, NULL);
hbox = gtk_hbox_new (FALSE, 12);
gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
@@ -248,18 +388,14 @@ ar_game_chooser_constructor (GType type,
/* Select the row corresponding to the currently loaded game,
* and scroll to it.
*/
- if (current_iter_set) {
- GtkTreePath *path;
-
- gtk_tree_selection_select_iter (selection, ¤t_iter);
-
- /* Scroll view to the current item */
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (list), ¤t_iter);
- gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (list_view), path, NULL,
- TRUE,
- 0.5, 0.0);
- gtk_tree_path_free (path);
- }
+ path = gtk_tree_path_new_first ();
+ gtk_tree_selection_select_path (selection, path);
+
+ /* Scroll view to the current item */
+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (list_view), path, NULL,
+ TRUE,
+ 0.5, 0.0);
+ gtk_tree_path_free (path);
return object;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]