From 1f0ef0bc2e7d0b99feb05e57f1c15a5a739c48fa Mon Sep 17 00:00:00 2001 From: Jon Bergli Heier Date: Wed, 23 Dec 2009 17:10:39 +0100 Subject: Reworked the main window. Images are now placed in their own icon view. Folders are selected in the above tree view, while the icon view displays thumbnails of the images in the selected folder. The thumbnails are cached using the thumbnail specification (~/.thumbnails/). --- browse_model.c | 443 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ browse_model.h | 50 +++++++ thumbnails.c | 138 ++++++++++++++++++ thumbnails.h | 8 ++ walls.ui | 49 +++++-- window_main.c | 131 +++++++++++------ 6 files changed, 763 insertions(+), 56 deletions(-) create mode 100644 browse_model.c create mode 100644 browse_model.h create mode 100644 thumbnails.c create mode 100644 thumbnails.h diff --git a/browse_model.c b/browse_model.c new file mode 100644 index 0000000..72aac8a --- /dev/null +++ b/browse_model.c @@ -0,0 +1,443 @@ +#include "browse_model.h" + +static void browse_model_init(BrowseModel *browse_model); +static void browse_model_class_init(BrowseModelClass *klass); +static void browse_model_tree_model_init(GtkTreeModelIface *iface); +static void browse_model_finalize(GObject *object); +static GtkTreeModelFlags browse_model_get_flags(GtkTreeModel *tree_model); +static gint browse_model_get_n_columns(GtkTreeModel *tree_model); +static GType browse_model_get_column_type(GtkTreeModel *tree_model, gint index); +static gboolean browse_model_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path); +static GtkTreePath *browse_model_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter); +static void browse_model_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value); +static gboolean browse_model_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter); +static gboolean browse_model_iter_children(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent); +static gboolean browse_model_iter_has_child(GtkTreeModel *tree_model, GtkTreeIter *iter); +static gint browse_model_iter_n_children(GtkTreeModel *tree_model, GtkTreeIter *iter); +static gboolean browse_model_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n); +static gboolean browse_model_iter_parent(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child); + +static GObjectClass *parent_class = NULL; + +GType browse_model_get_type() { + static GType browse_model_type = 0; + if(browse_model_type == 0) { + static const GTypeInfo browse_model_info = { + sizeof(BrowseModelClass), + NULL, + NULL, + (GClassInitFunc) browse_model_class_init, + NULL, + NULL, + sizeof(BrowseModel), + 0, + (GInstanceInitFunc) browse_model_init + }; + static const GInterfaceInfo tree_model_info = { + (GInterfaceInitFunc) browse_model_tree_model_init, + NULL, + NULL + }; + browse_model_type = g_type_register_static(G_TYPE_OBJECT, "BrowseModel", &browse_model_info, (GTypeFlags)0); + g_type_add_interface_static(browse_model_type, GTK_TYPE_TREE_MODEL, &tree_model_info); + } + return browse_model_type; +} + +static void browse_model_class_init(BrowseModelClass *klass) { + GObjectClass *object_class; + + parent_class = (GObjectClass*)g_type_class_peek_parent(klass); + object_class = (GObjectClass*)klass; + + object_class->finalize = browse_model_finalize; +} + +static void browse_model_tree_model_init(GtkTreeModelIface *iface) { + iface->get_flags = browse_model_get_flags; + iface->get_n_columns = browse_model_get_n_columns; + iface->get_column_type = browse_model_get_column_type; + iface->get_iter = browse_model_get_iter; + iface->get_path = browse_model_get_path; + iface->get_value = browse_model_get_value; + iface->iter_next = browse_model_iter_next; + iface->iter_children = browse_model_iter_children; + iface->iter_has_child = browse_model_iter_has_child; + iface->iter_n_children = browse_model_iter_n_children; + iface->iter_nth_child = browse_model_iter_nth_child; + iface->iter_parent = browse_model_iter_parent; +} + +static void browse_model_init(BrowseModel *browse_model) { + BrowseModelRecord temp; + GArray *array; + browse_model->n_columns = BROWSE_MODEL_N_COLUMNS; + + browse_model->column_types[0] = G_TYPE_STRING; + + g_assert(BROWSE_MODEL_N_COLUMNS == 1); + + browse_model->num_rows = 0; + browse_model->rows = g_array_new(TRUE, FALSE, sizeof(BrowseModelRecord)); + browse_model->stamp = g_random_int(); + + if(db_get_top_level_directories(&array)) { + for(int i = 0; i < array->len; i++) { + struct directory_t *dir; + + dir = &g_array_index(array, struct directory_t, i); + + temp.dir.name = g_strdup(dir->name); + temp.dir.dirid = dir->dirid; + temp.parent = NULL; + temp.children = NULL; + temp.pos = i; + + g_free(dir->name); + + g_array_append_val(browse_model->rows, temp); + browse_model->num_rows++; + } + g_array_free(array, TRUE); + } +} + +static void finalize_recursive(BrowseModelRecord *record) { + if(!record->children) + return; + + for(int i = 0; i < record->children->len; i++) { + BrowseModelRecord *temp; + temp = &g_array_index(record->children, BrowseModelRecord, i); + g_free(temp->dir.name); + } +} + +static void browse_model_finalize(GObject *object) { + BrowseModel *browse_model; + + g_assert(MODEL_IS_BROWSE(object)); + + browse_model = BROWSE_MODEL(object); + + for(int i = 0; i < browse_model->rows->len; i++) { + BrowseModelRecord *temp; + temp = &g_array_index(browse_model->rows, BrowseModelRecord, i); + g_free(temp->dir.name); + finalize_recursive(temp); + } + + g_array_free(browse_model->rows, TRUE); +} + +static GtkTreeModelFlags browse_model_get_flags(GtkTreeModel *tree_model) { + g_return_val_if_fail(MODEL_IS_BROWSE(tree_model), (GtkTreeModelFlags)0); + + return GTK_TREE_MODEL_ITERS_PERSIST; +} + +static gint browse_model_get_n_columns(GtkTreeModel *tree_model) { + g_return_val_if_fail(MODEL_IS_BROWSE(tree_model), 0); + + return BROWSE_MODEL(tree_model)->n_columns; +} + +static GType browse_model_get_column_type(GtkTreeModel *tree_model, gint index) { + g_return_val_if_fail(MODEL_IS_BROWSE(tree_model), G_TYPE_INVALID); + g_return_val_if_fail(index < BROWSE_MODEL(tree_model)->n_columns && index >= 0, G_TYPE_INVALID); + + return BROWSE_MODEL(tree_model)->column_types[index]; +} + +inline static void fill_dir(BrowseModelRecord *record) { + GArray *array; + + record->children = g_array_new(FALSE, FALSE, sizeof(BrowseModelRecord)); + if(db_get_directories(record->dir.dirid, &array)) { + for(int i = 0; i < array->len; i++) { + BrowseModelRecord temp; + struct directory_t *dir; + + dir = &g_array_index(array, struct directory_t, i); + temp.dir.name = g_strdup(dir->name); + temp.dir.dirid = dir->dirid; + temp.parent = record; + temp.children = NULL; + temp.pos = i; + + g_array_append_val(record->children, temp); + + g_free(dir->name); + } + g_array_free(array, TRUE); + } +} + +#define BROWSE_MODEL_ENSURE_CHILDREN(obj) if(!(obj)->children) fill_dir((obj)) + +inline static BrowseModelRecord *browse_model_get_record_recursive(BrowseModel *browse_model, gint *indices, gint depth) { + BrowseModelRecord *temp; + if(depth == 1) { + return &g_array_index(browse_model->rows, BrowseModelRecord, indices[depth-1]); + } else { + temp = browse_model_get_record_recursive(browse_model, indices, depth-1); + BROWSE_MODEL_ENSURE_CHILDREN(temp); + return &g_array_index(temp->children, BrowseModelRecord, indices[depth-1]); + } +} + +static gboolean browse_model_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path) { + BrowseModel *browse_model; + BrowseModelRecord *record; + gint *indices, n, depth; + + g_assert(MODEL_IS_BROWSE(tree_model)); + g_assert(path != NULL); + + browse_model = BROWSE_MODEL(tree_model); + + indices = gtk_tree_path_get_indices(path); + depth = gtk_tree_path_get_depth(path); + + n = indices[depth-1]; + //if(n >= browse_model->num_rows || n < 0) + // return FALSE; + + //record = &g_array_index(browse_model->rows, BrowseModelRecord, n); + record = browse_model_get_record_recursive(browse_model, indices, depth); + + g_assert(record != NULL); + g_assert(record->pos == n); + + iter->stamp = browse_model->stamp; + iter->user_data = record; + iter->user_data2 = NULL; + iter->user_data3 = NULL; + + return TRUE; +} + +static GtkTreePath *browse_model_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter) { + GtkTreePath *path; + BrowseModelRecord *record; + BrowseModel *browse_model; + + g_return_val_if_fail(MODEL_IS_BROWSE(tree_model), NULL); + g_return_val_if_fail(iter != NULL, NULL); + g_return_val_if_fail(iter->user_data != NULL, NULL); + + browse_model = BROWSE_MODEL(tree_model); + + record = (BrowseModelRecord*)iter->user_data; + + path = gtk_tree_path_new(); + gtk_tree_path_append_index(path, record->pos); + + return path; +} + +static void browse_model_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value) { + BrowseModelRecord *record; + BrowseModel *browse_model; + + g_return_if_fail(MODEL_IS_BROWSE(tree_model)); + g_return_if_fail(iter != NULL); + g_return_if_fail(column < BROWSE_MODEL(tree_model)->n_columns); + + g_value_init(value, BROWSE_MODEL(tree_model)->column_types[column]); + + browse_model = BROWSE_MODEL(tree_model); + + record = (BrowseModelRecord*)iter->user_data; + + g_return_if_fail(record != NULL); + + //if(record->pos >= browse_model->num_rows) + // g_return_if_reached(); + + switch(column) { + case BROWSE_MODEL_COL_NAME: + g_value_set_string_take_ownership(value, (record->parent == NULL ? g_strdup(record->dir.name) : g_path_get_basename(record->dir.name))); + break; + } +} + +static gboolean browse_model_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter) { + BrowseModelRecord *record, *nextrecord; + BrowseModel *browse_model; + GArray *array; + + g_return_val_if_fail(MODEL_IS_BROWSE(tree_model), FALSE); + + if(iter == NULL || iter->user_data == NULL) + return FALSE; + + browse_model = BROWSE_MODEL(tree_model); + + record = (BrowseModelRecord*)iter->user_data; + + BROWSE_MODEL_ENSURE_CHILDREN(record); + + array = (record->parent ? record->parent->children : browse_model->rows); + + if((record->pos + 1) >= array->len) + return FALSE; + + nextrecord = &g_array_index(array, BrowseModelRecord, record->pos + 1); + + g_assert(nextrecord != NULL); + g_assert(nextrecord->pos == (record->pos + 1)); + + iter->stamp = browse_model->stamp; + iter->user_data = nextrecord; + + return TRUE; +} + +static gboolean browse_model_iter_children(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent) { + BrowseModel *browse_model; + BrowseModelRecord *parent_record; + + g_return_val_if_fail(MODEL_IS_BROWSE(tree_model), FALSE); + + browse_model = BROWSE_MODEL(tree_model); + + if(!parent) { + if(browse_model->num_rows == 0) + return FALSE; + iter->stamp = browse_model->stamp; + iter->user_data = &g_array_index(browse_model->rows, BrowseModelRecord, 0); + return TRUE; + } + + //g_return_val_if_fail(parent == NULL || parent->user_data != NULL, FALSE); + + parent_record = (BrowseModelRecord*)parent->user_data; + + BROWSE_MODEL_ENSURE_CHILDREN(parent_record); + + if(parent_record->children->len == 0) + return FALSE; + + iter->stamp = browse_model->stamp; + iter->user_data = &g_array_index(parent_record->children, BrowseModelRecord, 0); + + return TRUE; +} + +static gboolean browse_model_iter_has_child(GtkTreeModel *tree_model, GtkTreeIter *iter) { + BrowseModelRecord *record; + + g_return_val_if_fail(MODEL_IS_BROWSE(tree_model), FALSE); + + record = (BrowseModelRecord*)iter->user_data; + BROWSE_MODEL_ENSURE_CHILDREN(record); + + return (record->parent == NULL && BROWSE_MODEL(tree_model)->num_rows == 0 ? FALSE : (record->children->len > 0 ? TRUE : FALSE)); +} + +static gint browse_model_iter_n_children(GtkTreeModel *tree_model, GtkTreeIter *iter) { + BrowseModel *browse_model; + BrowseModelRecord *record; + GArray *array; + int n; + + g_return_val_if_fail(MODEL_IS_BROWSE(tree_model), -1); + g_return_val_if_fail(iter == NULL || iter->user_data != NULL, 0); + + browse_model = BROWSE_MODEL(tree_model); + + if(!iter) { + return browse_model->num_rows; + } + + record = (BrowseModelRecord*)iter->user_data; + + //array = NULL; + //g_return_val_if_fail(db_get_wallpapers(record->dir.dirid, &array), -1); + //for(n = 0; (&g_array_index(array, struct wallpaper_t, n))->filepath; n++); + + BROWSE_MODEL_ENSURE_CHILDREN(record); + + return record->children->len; + + return n; +} + +static gboolean browse_model_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n) { + BrowseModelRecord *record, *parent_record; + BrowseModel *browse_model; + + g_return_val_if_fail(MODEL_IS_BROWSE(tree_model), FALSE); + + browse_model = BROWSE_MODEL(tree_model); + + if(!parent) { + if(n >= browse_model->num_rows) + return FALSE; + record = &g_array_index(browse_model->rows, BrowseModelRecord, n); + + iter->stamp = browse_model->stamp; + iter->user_data = record; + + return TRUE; + } + + //if(n >= browse_model->num_rows) + // return FALSE; + + parent_record = parent->user_data; + + BROWSE_MODEL_ENSURE_CHILDREN(parent_record); + + if(n >= parent_record->children->len) + return FALSE; + + record = &g_array_index(parent_record->children, BrowseModelRecord, n); + + g_assert(record != NULL); + g_assert(record->pos == n); + + iter->stamp = browse_model->stamp; + iter->user_data = record; + + return TRUE; +} + +static gboolean browse_model_iter_parent(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child) { + BrowseModelRecord *record, *childrecord; + BrowseModel *browse_model; + + g_return_val_if_fail(MODEL_IS_BROWSE(tree_model), FALSE); + + browse_model = BROWSE_MODEL(tree_model); + + childrecord = (BrowseModelRecord*)child->user_data; + + iter->stamp = browse_model->stamp; + iter->user_data = childrecord->parent; + + return TRUE; +} + +BrowseModel *browse_model_new() { + BrowseModel *new_browse_model; + + new_browse_model = (BrowseModel*)g_object_new(MODEL_TYPE_BROWSE, NULL); + + g_assert(new_browse_model != NULL); + + return new_browse_model; +} + +void browse_model_get_dir_record(GtkTreeModel *tree_model, GtkTreeIter *iter, struct directory_t **dir) { + BrowseModel *browse_model; + BrowseModelRecord *record; + + g_assert(MODEL_IS_BROWSE(tree_model)); + g_assert(iter != NULL); + + browse_model = BROWSE_MODEL(tree_model); + record = (BrowseModelRecord*)iter->user_data; + *dir = &record->dir; +} diff --git a/browse_model.h b/browse_model.h new file mode 100644 index 0000000..1070d74 --- /dev/null +++ b/browse_model.h @@ -0,0 +1,50 @@ +#ifndef _BROWSE_MODEL_H_ +#define _BROWSE_MODEL_H_ + +#include +#include + +#include "db.h" + +#define MODEL_TYPE_BROWSE (browse_model_get_type()) +#define BROWSE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), MODEL_TYPE_BROWSE, BrowseModel)) +#define BROWSE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), MODEL_TYPE_BROWSE, BrowseModelClass)) +#define MODEL_IS_BROWSE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), MODEL_TYPE_BROWSE)) +#define MODEL_IS_BROWSE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), MODEL_TYPE_BROWSE)) +#define BROWSE_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), MODEL_TYPE_BROWSE, BrowseModelClass)) + +enum { + BROWSE_MODEL_COL_NAME = 0, + BROWSE_MODEL_N_COLUMNS, +}; + +typedef struct _BrowseModelRecord BrowseModelRecord; +typedef struct _BrowseModel BrowseModel; +typedef struct _BrowseModelClass BrowseModelClass; + +struct _BrowseModelRecord { + struct directory_t dir; + BrowseModelRecord *parent; + GArray *children; + guint pos; +}; + +struct _BrowseModel { + GObject parent; + + guint num_rows; + GArray *rows; + gint n_columns; + GType column_types[BROWSE_MODEL_N_COLUMNS]; + gint stamp; +}; + +struct _BrowseModelClass { + GObjectClass parent_class; +}; + +GType browse_model_get_type(); +BrowseModel *browse_model_new(); +void browse_model_get_dir_record(GtkTreeModel*, GtkTreeIter*, struct directory_t**); + +#endif diff --git a/thumbnails.c b/thumbnails.c new file mode 100644 index 0000000..18e2d9f --- /dev/null +++ b/thumbnails.c @@ -0,0 +1,138 @@ +#include +#include +#include + +#include +#include + +#include "db.h" +#include "thumbnails.h" + +inline static gchar *get_wall_thumb_name(const gchar *filepath) { + GChecksum *ck; + gchar *s; + gchar *cksum; + + ck = g_checksum_new(G_CHECKSUM_MD5); + s = g_strdup_printf("file://%s", filepath); + g_checksum_update(ck, s, -1); + g_free(s); + cksum = g_strdup_printf("%s/.thumbnails/normal/%s.png", g_get_home_dir(), g_checksum_get_string(ck)); + g_checksum_free(ck); + return cksum; +} + +inline static time_t get_mtime(const gchar *filepath) { + struct utimbuf times; + + if(g_utime(filepath, ×) == 0) { + return times.modtime; + } else { + return 0; + } +} + +GdkPixbuf *get_thumbnail(const gchar *filepath) { + GdkPixbuf *pb, *pb2; + gint win_width, win_height, img_width, img_height, width, height; + gdouble scalex, scaley, width_ratio, height_ratio, max_ratio; + GError *error = NULL; + gchar *thumbname; + + thumbname = get_wall_thumb_name(filepath); + + if(g_access(thumbname, F_OK) == 0) { + pb = gdk_pixbuf_new_from_file(thumbname, &error); + g_free(thumbname); + return pb; + } else { + pb = gdk_pixbuf_new_from_file(filepath, &error); + } + + if(!pb) { + g_warning("%s", error->message); + g_free(error); + return NULL; + } + + img_width = gdk_pixbuf_get_width(pb); + img_height = gdk_pixbuf_get_height(pb); + win_width = win_height = 128; + + width_ratio = (gdouble)img_width / (gdouble)win_width; + height_ratio = (gdouble)img_height / (gdouble)win_height; + if(width_ratio > height_ratio) { + width = win_width; + height = (gint)(1.0 / width_ratio * img_height); + } else { + height = win_height; + width = (gint)(1.0 / height_ratio * img_width); + } + scalex = (gdouble)width / (gdouble)img_width; + scaley = (gdouble)height / (gdouble)img_height; + + pb2 = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height); + gdk_pixbuf_scale(pb, pb2, 0, 0, width, height, 0, 0, scalex, scaley, GDK_INTERP_BILINEAR); + g_object_unref(pb); + + error = NULL; + if(!gdk_pixbuf_save(pb2, thumbname, "png", &error, + "tEXt::Thumb::URI", filepath, + "tEXt::Thumb::MTime", get_mtime(filepath), + "tEXt::Software", "walls", + NULL)) { + g_warning("%s", error->message); + g_free(error); + } + + g_free(thumbname); + + return pb2; +} + +static void fill_wall_list(GtkListStore *liststore, GArray *array) { + GtkTreeIter iter; + + for(int i = 0; i < array->len; i++) { + struct wallpaper_t *wall; + wall = &g_array_index(array, struct wallpaper_t, i); + + gtk_list_store_append(liststore, &iter); + gtk_list_store_set(liststore, &iter, 0, NULL, 1, wall->filepath, -1); + g_free(wall->filepath); + } + g_array_free(array, TRUE); +} + +gpointer add_thumbs_thread(gpointer data) { + GtkListStore *liststore; + GtkTreeIter iter; + int n; + GValue value; + GdkPixbuf *pb = NULL; + const gchar *filepath; + + liststore = GTK_LIST_STORE(data); + + if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(liststore), &iter)) { + return NULL; + } + + n = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(liststore), NULL); + + memset(&value, 0, sizeof(GValue)); + + for(int i = 0; i < n; i++) { + gtk_tree_model_get_value(GTK_TREE_MODEL(liststore), &iter, 1, &value); + printf("file: %s\n", g_value_get_string(&value)); + filepath = g_value_get_string(&value); + pb = get_thumbnail(filepath); + g_value_unset(&value); + if(pb) { + gtk_list_store_set(liststore, &iter, 0, pb, -1); + + g_object_unref(pb); + } + gtk_tree_model_iter_next(GTK_TREE_MODEL(liststore), &iter); + } +} diff --git a/thumbnails.h b/thumbnails.h new file mode 100644 index 0000000..d4ab69f --- /dev/null +++ b/thumbnails.h @@ -0,0 +1,8 @@ +#ifndef _THUMBNAILS_H_ +#define _THUMBNAILS_H_ + +#include + +gpointer add_thumbs_thread(gpointer data); + +#endif diff --git a/walls.ui b/walls.ui index bbc024b..67b227e 100644 --- a/walls.ui +++ b/walls.ui @@ -86,30 +86,61 @@ True - + True True + vertical - + True True - automatic - automatic - + True True + automatic + automatic + + + True + True + + + + + + + True + File Hierarchy + + False + + + False + True + - - + + True - File Hierarchy + True + automatic + automatic + + + True + True + horizontal + + + - False + True + True diff --git a/window_main.c b/window_main.c index cfc24c6..e84144f 100644 --- a/window_main.c +++ b/window_main.c @@ -1,12 +1,16 @@ +//#include #include +#include #include #include "window_main.h" #include "walls_ui.h" #include "db.h" +#include "browse_model.h" #include "walls_model.h" #include "wallpapers.h" +#include "thumbnails.h" GdkPixbuf *orig_pixbuf = NULL; gint last_width = 0, @@ -16,59 +20,37 @@ gint last_width = 0, GtkImage *image = NULL; GtkWidget *layout = NULL; GtkStatusbar *statusbar; +GtkIconView *thumbview; -GThread *add_thread = NULL; +GThread *add_thread = NULL, + *thumb_thread = NULL; -void on_filetree_selection_changed(GtkTreeSelection *treeselection, gpointer user_data); +void on_foldtree_selection_changed(GtkTreeSelection *treeselection, gpointer user_data); -inline static void filetree_create_model(GtkTreeView *filetree) { +inline static void foldtree_create_model(GtkTreeView *foldtree) { GtkTreeModel *tree_model; - tree_model = GTK_TREE_MODEL(walls_model_new()); - gtk_tree_view_set_model(filetree, GTK_TREE_MODEL(tree_model)); + tree_model = GTK_TREE_MODEL(browse_model_new()); + gtk_tree_view_set_model(foldtree, GTK_TREE_MODEL(tree_model)); } -inline static void filetree_init(GtkTreeView *filetree) { - GtkTreeViewColumn *col1, *col2, *col3, *col4; +inline static void foldtree_init(GtkTreeView *foldtree) { + GtkTreeViewColumn *col1; GtkCellRenderer *renderer; GtkTreeSelection *selection; col1 = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(col1, "Name"); - gtk_tree_view_append_column(filetree, col1); - - col2 = gtk_tree_view_column_new(); - gtk_tree_view_column_set_title(col2, "Size"); - gtk_tree_view_append_column(filetree, col2); - - col3 = gtk_tree_view_column_new(); - gtk_tree_view_column_set_title(col3, "Width"); - gtk_tree_view_append_column(filetree, col3); - - col4 = gtk_tree_view_column_new(); - gtk_tree_view_column_set_title(col4, "Height"); - gtk_tree_view_append_column(filetree, col4); + gtk_tree_view_append_column(foldtree, col1); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(col1, renderer, TRUE); gtk_tree_view_column_add_attribute(col1, renderer, "text", 0); - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(col2, renderer, TRUE); - gtk_tree_view_column_add_attribute(col2, renderer, "text", 1); - - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(col3, renderer, TRUE); - gtk_tree_view_column_add_attribute(col3, renderer, "text", 2); - - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(col4, renderer, TRUE); - gtk_tree_view_column_add_attribute(col4, renderer, "text", 3); - - filetree_create_model(filetree); + foldtree_create_model(foldtree); - selection = gtk_tree_view_get_selection(filetree); - g_signal_connect(selection, "changed", G_CALLBACK(on_filetree_selection_changed), filetree); + selection = gtk_tree_view_get_selection(foldtree); + g_signal_connect(selection, "changed", G_CALLBACK(on_foldtree_selection_changed), foldtree); } static void resize_pixbuf() { @@ -131,16 +113,14 @@ void on_window_hpane_resized(GObject *gobject, GParamSpec *pspec, gpointer user_ } } -static void load_pixbuf(struct wallpaper_t *wall) { +static void load_pixbuf(const gchar *filepath) { GdkPixbuf *pb; GError *error = NULL; GdkWindow *window; - gint win_width, win_height, img_width, img_height, width, height; - gdouble scalex, scaley, width_ratio, height_ratio, max_ratio; if(orig_pixbuf) g_object_unref(orig_pixbuf); - orig_pixbuf = gdk_pixbuf_new_from_file(wall->filepath, &error); + orig_pixbuf = gdk_pixbuf_new_from_file(filepath, &error); if(!orig_pixbuf) { g_warning("%s", error->message); g_free(error); @@ -150,16 +130,70 @@ static void load_pixbuf(struct wallpaper_t *wall) { resize_pixbuf(); } -void on_filetree_selection_changed(GtkTreeSelection *treeselection, gpointer user_data) { +static void fill_wall_list(GtkListStore *liststore, GArray *array) { + GtkTreeIter iter; + + for(int i = 0; i < array->len; i++) { + struct wallpaper_t *wall; + wall = &g_array_index(array, struct wallpaper_t, i); + + gtk_list_store_append(liststore, &iter); + gtk_list_store_set(liststore, &iter, 0, NULL, 1, wall->filepath, -1); + g_free(wall->filepath); + } + g_array_free(array, TRUE); +} + +void on_foldtree_selection_changed(GtkTreeSelection *treeselection, gpointer user_data) { GtkTreeModel *model; GtkTreeIter iter; - struct wallpaper_t *wall; + struct directory_t *dir; + GArray *array; + GtkListStore *liststore; + GError *error = NULL; if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) { - if(walls_model_get_record_type(model, &iter) == WALLS_MODEL_TYPE_WALL) { - walls_model_get_wall_record(model, &iter, &wall); - load_pixbuf(wall); + browse_model_get_dir_record(model, &iter, &dir); + + if(!db_get_wallpapers(dir->dirid, &array)) + return; + + liststore = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING); + fill_wall_list(liststore, array); + gtk_icon_view_set_model(thumbview, GTK_TREE_MODEL(liststore)); + + thumb_thread = g_thread_create(add_thumbs_thread, liststore, FALSE, &error); + + if(!thumb_thread) { + g_warning("%s", error->message); + g_free(error); + } + } +} + +void on_thumbview_selection_changed(GtkIconView *iconview, gpointer user_data) { + GList *list; + GValue value; + const gchar *filename; + GtkTreePath *path; + GtkTreeModel *model; + GtkTreeIter iter; + + list = gtk_icon_view_get_selected_items(iconview); + if(list) { + if(g_list_length(list) == 1) { + path = g_list_nth_data(list, 0); + model = gtk_icon_view_get_model(iconview); + gtk_tree_model_get_iter(model, &iter, path); + memset(&value, 0, sizeof(GValue)); + gtk_tree_model_get_value(model, &iter, 1, &value); + filename = g_value_get_string(&value); + load_pixbuf(filename); + g_value_unset(&value); } + + g_list_foreach(list, gtk_tree_path_free, NULL); + g_list_free(list); } } @@ -198,7 +232,7 @@ void on_add_dir_action_activate(GtkAction *action, gpointer user_data) { int gui_main(int argc, char **argv) { GtkWidget *window; - GtkWidget *filetree; + GtkWidget *foldtree; GtkWidget *window_hpane; GtkBuilder *builder ; GError *error = NULL; @@ -222,8 +256,11 @@ int gui_main(int argc, char **argv) { window = GTK_WIDGET(gtk_builder_get_object(builder, "window")); gtk_window_set_title(GTK_WINDOW(window), "walls"); - filetree = GTK_WIDGET(gtk_builder_get_object(builder, "filetree")); - filetree_init(GTK_TREE_VIEW(filetree)); + foldtree = GTK_WIDGET(gtk_builder_get_object(builder, "foldtree")); + foldtree_init(GTK_TREE_VIEW(foldtree)); + + thumbview = GTK_ICON_VIEW(gtk_builder_get_object(builder, "thumbview")); + gtk_icon_view_set_pixbuf_column(thumbview, 0); image = GTK_IMAGE(gtk_builder_get_object(builder, "image")); layout = GTK_WIDGET(gtk_builder_get_object(builder, "layout")); -- cgit v1.2.3