/* * image_list.c - things related to the image list widget in the UI */ #include #include "lodju.h" enum { FILENAME_COLUMN, THUMBNAIL_COLUMN, CAPTION_COLUMN, NUM_COLUMNS }; static GtkCList *image_list; static GList *selected_images = NULL; void image_list_set(GtkCList *clist) { gint i; image_list = clist; for (i = 0; i < NUM_COLUMNS; ++i) gtk_clist_column_title_passive(image_list, i); gtk_clist_set_row_height(image_list, THUMBNAIL_HEIGHT); } GtkCList *image_list_get(void) { return image_list; } static void image_list_clear_selected(void) { if (selected_images != NULL) g_list_free(selected_images); selected_images = NULL; } static void image_list_add_selected(Image *image) { if (image != NULL) selected_images = g_list_append(selected_images, image); } static void image_list_remove_selected(Image *image) { selected_images = g_list_remove(selected_images, image); } Image *image_list_get_selected(void) { if (selected_images == NULL || selected_images->next != NULL) return NULL; return selected_images->data; } static GList *image_list_get_all_selected(void) { return selected_images; } static gint image_list_get_row_for_image(Image *image) { return gtk_clist_find_row_from_data(image_list, image); } static void image_list_remove_row(gint row) { image_list_remove_selected(gtk_clist_get_row_data(image_list, row)); } static void image_list_add_row(gint row) { image_list_add_selected(gtk_clist_get_row_data(image_list, row)); } void image_list_clear(void) { image_list_clear_selected(); gtk_clist_clear(image_list); } void image_list_append_image(Image *image) { gchar *texts[NUM_COLUMNS]; gint row; gint i; texts[FILENAME_COLUMN] = g_strdup(g_basename(image_get_attribute(image, "filename"))); texts[THUMBNAIL_COLUMN] = g_strdup(""); texts[CAPTION_COLUMN] = g_strdup(image_get_attribute(image, "caption")); row = gtk_clist_append(image_list, texts); gtk_clist_set_row_data(image_list, row, image); for (i = 0; i < NUM_COLUMNS; ++i) g_free(texts[i]); /* * The image list selection mode is "browse", which means that if the * list is not empty, a row is always selected. If the list was empty * when we called gtk_clist_append above, it generated (and handled) * the "select_row" signal. We did not, however, have the time to * set the row data for the new row, which means that the meta data * information for the selected image (and the image loading) did * not yet start. Therefore, now that we have set the row data, we * send the signal again. * * This is a kludge. */ if (row == 0) gtk_clist_select_row(image_list, 0, 0); } void image_list_set_attribute(const gchar *name, const gchar *value) { GList *p; Image *image; for (p = image_list_get_all_selected(); p != NULL; p = p->next) { image = p->data; image_set_attribute(image, name, value); if (strcmp(name, "caption") == 0) { gtk_clist_set_text(image_list, image_list_get_row_for_image(image), CAPTION_COLUMN, value); } } } void image_list_draw_thumbnails(void) { GList *p; Image *image; GdkPixbuf *pixbuf; GdkPixmap *pixmap; GdkBitmap *mask; gint row; for (p = image_list_get_all_selected(); p != NULL; p = p->next) { image = p->data; pixbuf = pixbuf_get_from_image(image, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT); if (pixbuf != NULL) { gdk_pixbuf_render_pixmap_and_mask(pixbuf, &pixmap, &mask, 0); row = image_list_get_row_for_image(image); if (row != -1) gtk_clist_set_pixmap(image_list, row, THUMBNAIL_COLUMN, pixmap, mask); } } } void image_list_remove(void) { ImageFolder *folder; Image *image; gint row; GList *p; GList *list; folder = folder_tree_get_selected(); if (folder == NULL) return; list = g_list_copy(image_list_get_all_selected()); for (p = list; p != NULL; p = p->next) { image = p->data; image_list_remove_selected(image); row = image_list_get_row_for_image(image); if (row != -1) gtk_clist_remove(image_list, row); image_folder_remove_image(folder, image); } g_list_free(list); } static void select_and_make_visible(gint row) { gtk_clist_unselect_all(image_list_get()); gtk_clist_select_row(image_list_get(), row, 0); if (gtk_clist_row_is_visible(image_list, row) != GTK_VISIBILITY_FULL) gtk_clist_moveto(image_list, row, 0, 100.0, 100.0); } void on_next_activate(GtkMenuItem *menuitem, gpointer user_data) { GList *list; GList *p; gint p_row; gint row; list = image_list_get_all_selected(); if (list == NULL) row = 0; else if (list->next == NULL) row = image_list_get_row_for_image(list->data) + 1; else { row = -1; for (p = list; p != NULL; p = p->next) { p_row = image_list_get_row_for_image(p->data); if (row < p_row) row = p_row; } ++row; } list = image_folder_get_images(folder_tree_get_selected()); if (row >= g_list_length(list)) row = g_list_length(list) - 1; g_list_free(list); select_and_make_visible(row); } void on_previous_activate(GtkMenuItem *menuitem, gpointer user_data) { GList *list; GList *p; gint p_row; gint row; list = image_list_get_all_selected(); if (list == NULL) row = 0; else if (list->next == NULL) row = image_list_get_row_for_image(list->data) - 1; else { row = -1; for (p = list; p != NULL; p = p->next) { p_row = image_list_get_row_for_image(p->data); if (row == -1 || row > p_row) row = p_row; } --row; } if (row < 0) row = 0; select_and_make_visible(row); } void on_next_image_button_clicked(GtkButton *button, gpointer user_data) { on_next_activate(NULL, NULL); } void on_previous_image_button_clicked(GtkButton *button, gpointer user_data) { on_previous_activate(NULL, NULL); } static void update_image_in_meta_area(void) { Image *image; image = image_list_get_selected(); if (image != NULL) meta_fill(image); else meta_clear(); } void on_image_list_select_row(GtkCList *clist, gint row, gint column, GdkEventButton *event, gpointer user_data) { image_list_add_row(row); update_image_in_meta_area(); } void on_image_list_unselect_row(GtkCList *clist, gint row, gint column, GdkEventButton *event, gpointer user_data) { image_list_remove_row(row); update_image_in_meta_area(); } void on_image_list_drag_data_get(GtkWidget *widget, GdkDragContext *drag_context, GtkSelectionData *data, guint info, guint time, gpointer user_data) { const gchar *xml; Image *image; image = image_list_get_selected(); if (image != NULL) { xml = image_get_xml(image); gtk_selection_data_set(data, data->target, 8, xml, strlen(xml)); } } void on_image_list_drag_data_delete(GtkWidget *widget, GdkDragContext *drag_context, gpointer user_data) { image_list_remove(); } static gint normalize_angle(int angle) { while (angle < 0) angle += 360; while (angle >= 360) angle -= 360; g_assert(angle >= 0); g_assert(angle < 360); return angle; } static void rotate(gint angle) { GList *p; Image *image; gint rotation; gchar *buf; for (p = image_list_get_all_selected(); p != NULL; p = p->next) { image = p->data; rotation = atoi(image_get_attribute(image, "rotation")); rotation += angle; rotation = normalize_angle(rotation); buf = g_strdup_printf("%d", rotation); image_set_attribute(image, "rotation", buf); g_free(buf); } meta_draw_image(); } void on_rotate_left_activate(GtkMenuItem *menuitem, gpointer user_data) { rotate(-90); } void on_rotate_right_activate(GtkMenuItem *menuitem, gpointer user_data) { rotate(90); } void on_rotate_left_button_clicked(GtkButton *button, gpointer user_data) { rotate(-90); } void on_rotate_right_button_clicked(GtkButton *button, gpointer user_data) { rotate(90); }