diff options
Diffstat (limited to 'composer/e-icon-list.c')
-rw-r--r-- | composer/e-icon-list.c | 2667 |
1 files changed, 0 insertions, 2667 deletions
diff --git a/composer/e-icon-list.c b/composer/e-icon-list.c deleted file mode 100644 index d71ecc262f..0000000000 --- a/composer/e-icon-list.c +++ /dev/null @@ -1,2667 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 1998, 1999, 2000 Free Software Foundation - * All rights reserved. - * - * This file is part of the Gnome Library. - * - * The Gnome Library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * The Gnome Library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with the Gnome Library; see the file COPYING.LIB. If not, - * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ -/* - @NOTATION@ - */ - -/* - * GnomeIconList widget - scrollable icon list - * - * Authors: - * Federico Mena <federico@ximian.com> - * Miguel de Icaza <miguel@ximian.com> - * - * Rewrote from scratch from the code written by Federico Mena - * <federico@ximian.com> to be based on a GnomeCanvas, and - * to support banding selection and allow inline icon renaming. - * - * Redone somewhat by Elliot to support gdk-pixbuf, and to use GArray instead of - * GList for item storage. - */ - -#include <config.h> -#include <string.h> -#include <stdio.h> -#include <gtk/gtk.h> -#include "e-icon-list.h" -#include <libgnomeui/gnome-icon-item.h> -#include <libgnomeui/gnome-canvas-rect-ellipse.h> -#include <gdk-pixbuf/gnome-canvas-pixbuf.h> - -#include "bad-icon.xpm" - -/* Aliases to minimize screen use in my laptop */ -#define EIL(x) E_ICON_LIST(x) -#define EIL_CLASS(x) E_ICON_LIST_CLASS(x) -#define IS_EIL(x) E_IS_ICON_LIST(x) - -typedef EIconList Eil; -typedef EIconListClass EilClass; - - -/* default spacings */ -#define DEFAULT_ROW_SPACING 4 -#define DEFAULT_COL_SPACING 2 -#define DEFAULT_TEXT_SPACING 2 -#define DEFAULT_ICON_BORDER 2 - -/* Autoscroll timeout in milliseconds */ -#define SCROLL_TIMEOUT 30 - - -/* Signals */ -enum { - SELECT_ICON, - UNSELECT_ICON, - TEXT_CHANGED, - LAST_SIGNAL -}; - -typedef enum { - SYNC_INSERT, - SYNC_REMOVE -} SyncType; - -enum { - ARG_0, -}; - -static guint eil_signals[LAST_SIGNAL] = { 0 }; - - -static GnomeCanvasClass *parent_class; - - -/* Icon structure */ -typedef struct { - /* Icon image and text items */ - GnomeCanvasPixbuf *image; - GnomeIconTextItem *text; - - /* Filename of the icon file. */ - gchar *icon_filename; - - /* User data and destroy notify function */ - gpointer data; - GtkDestroyNotify destroy; - - /* ID for the text item's event signal handler */ - guint text_event_id; - - /* Whether the icon is selected, and temporary storage for rubberband - * selections. - */ - guint selected : 1; - guint tmp_selected : 1; -} Icon; - -/* A row of icons */ -typedef struct { - GList *line_icons; - gint16 y; - gint16 icon_height, text_height; -} IconLine; - -/* Private data of the EIconList structure */ -struct _EIconListPrivate { - /* List of icons */ - GArray *icon_list; - - /* List of rows of icons */ - GList *lines; - - /* Separators used to wrap the text below icons */ - char *separators; - - Icon *last_selected_icon; - - /* Rubberband rectangle */ - GnomeCanvasItem *sel_rect; - - /* Saved event for a pending selection */ - GdkEvent select_pending_event; - - /* Max of the height of all the icon rows and window height */ - int total_height; - - /* Selection mode */ - GtkSelectionMode selection_mode; - - /* A list of integers with the indices of the currently selected icons */ - GList *selection; - - /* Number of icons in the list */ - int icons; - - /* Freeze count */ - int frozen; - - /* Width allocated for icons */ - int icon_width; - - /* Spacing values */ - int row_spacing; - int col_spacing; - int text_spacing; - int icon_border; - - /* Index and pointer to last selected icon */ - int last_selected_idx; - - /* Timeout ID for autoscrolling */ - guint timer_tag; - - /* Change the adjustment value by this amount when autoscrolling */ - int value_diff; - - /* Mouse position for autoscrolling */ - int event_last_x; - int event_last_y; - - /* Selection start position */ - int sel_start_x; - int sel_start_y; - - /* Modifier state when the selection began */ - guint sel_state; - - /* Whether the icon texts are editable */ - guint is_editable : 1; - - /* Whether the icon texts need to be copied */ - guint static_text : 1; - - /* Whether the icons need to be laid out */ - guint dirty : 1; - - /* Whether the user is performing a rubberband selection */ - guint selecting : 1; - - /* Whether editing an icon is pending after a button press */ - guint edit_pending : 1; - - /* Whether selection is pending after a button press */ - guint select_pending : 1; - - /* Whether the icon that is pending selection was selected to begin with */ - guint select_pending_was_selected : 1; -}; - - -static inline int -icon_line_height (Eil *eil, IconLine *il) -{ - EIconListPrivate *priv; - - priv = eil->_priv; - - return il->icon_height + il->text_height + priv->row_spacing + priv->text_spacing; -} - -static void -icon_get_height (Icon *icon, int *icon_height, int *text_height) -{ - double d_icon_height; - gtk_object_get(GTK_OBJECT(icon->image), "height", &d_icon_height, NULL); - *icon_height = d_icon_height; - *text_height = icon->text->ti->height; -} - -static int -eil_get_items_per_line (Eil *eil) -{ - EIconListPrivate *priv; - int items_per_line; - - priv = eil->_priv; - - items_per_line = GTK_WIDGET (eil)->allocation.width / (priv->icon_width + priv->col_spacing); - if (items_per_line == 0) - items_per_line = 1; - - return items_per_line; -} - -/** - * e_icon_list_get_items_per_line: - * @eil: An icon list. - * - * Returns the number of icons that fit in a line or row. - */ -int -e_icon_list_get_items_per_line (EIconList *eil) -{ - g_return_val_if_fail (eil != NULL, 1); - g_return_val_if_fail (IS_EIL (eil), 1); - - return eil_get_items_per_line (eil); -} - -static void -eil_place_icon (Eil *eil, Icon *icon, int x, int y, int icon_height) -{ - EIconListPrivate *priv; - int x_offset, y_offset; - double d_icon_image_height; - double d_icon_image_width; - int icon_image_height; - int icon_image_width; - - priv = eil->_priv; - - gtk_object_get(GTK_OBJECT(icon->image), "height", &d_icon_image_height, NULL); - icon_image_height = d_icon_image_height; - g_assert(icon_image_height != 0); - if (icon_height > icon_image_height) - y_offset = (icon_height - icon_image_height) / 2; - else - y_offset = 0; - - gtk_object_get(GTK_OBJECT(icon->image), "width", &d_icon_image_width, NULL); - icon_image_width = d_icon_image_width; - g_assert(icon_image_width != 0); - if (priv->icon_width > icon_image_width) - x_offset = (priv->icon_width - icon_image_width) / 2; - else - x_offset = 0; - - gnome_canvas_item_set (GNOME_CANVAS_ITEM (icon->image), - "x", (double) (x + x_offset), - "y", (double) (y + y_offset), - NULL); - gnome_icon_text_item_setxy (icon->text, - x, - y + icon_height + priv->text_spacing); -} - -static void -eil_layout_line (Eil *eil, IconLine *il) -{ - EIconListPrivate *priv; - GList *l; - int x; - - priv = eil->_priv; - - x = 0; - for (l = il->line_icons; l; l = l->next) { - Icon *icon = l->data; - - eil_place_icon (eil, icon, x, il->y, il->icon_height); - x += priv->icon_width + priv->col_spacing; - } -} - -static void -eil_add_and_layout_line (Eil *eil, GList *line_icons, int y, - int icon_height, int text_height) -{ - EIconListPrivate *priv; - IconLine *il; - - priv = eil->_priv; - - il = g_new (IconLine, 1); - il->line_icons = line_icons; - il->y = y; - il->icon_height = icon_height; - il->text_height = text_height; - - eil_layout_line (eil, il); - priv->lines = g_list_append (priv->lines, il); -} - -static void -eil_relayout_icons_at (Eil *eil, int pos, int y) -{ - EIconListPrivate *priv; - int col, row, text_height, icon_height; - int items_per_line, n; - GList *line_icons; - - priv = eil->_priv; - items_per_line = eil_get_items_per_line (eil); - - col = row = text_height = icon_height = 0; - line_icons = NULL; - - for (n = pos; n < priv->icon_list->len; n++) { - Icon *icon = g_array_index(priv->icon_list, Icon*, n); - int ih, th; - - if (!(n % items_per_line)) { - if (line_icons) { - eil_add_and_layout_line (eil, line_icons, y, - icon_height, text_height); - line_icons = NULL; - - y += (icon_height + text_height - + priv->row_spacing + priv->text_spacing); - } - - icon_height = 0; - text_height = 0; - } - - icon_get_height (icon, &ih, &th); - - icon_height = MAX (ih, icon_height); - text_height = MAX (th, text_height); - - line_icons = g_list_append (line_icons, icon); - } - - if (line_icons) - eil_add_and_layout_line (eil, line_icons, y, icon_height, text_height); -} - -static void -eil_free_line_info (Eil *eil) -{ - EIconListPrivate *priv; - GList *l; - - priv = eil->_priv; - - for (l = priv->lines; l; l = l->next) { - IconLine *il = l->data; - - g_list_free (il->line_icons); - g_free (il); - } - - g_list_free (priv->lines); - priv->lines = NULL; - priv->total_height = 0; -} - -static void -eil_free_line_info_from (Eil *eil, int first_line) -{ - EIconListPrivate *priv; - GList *l, *ll; - - priv = eil->_priv; - ll = g_list_nth (priv->lines, first_line); - - for (l = ll; l; l = l->next) { - IconLine *il = l->data; - - g_list_free (il->line_icons); - g_free (il); - } - - if (priv->lines) { - if (ll->prev) - ll->prev->next = NULL; - else - priv->lines = NULL; - } - - g_list_free (ll); -} - -static void -eil_layout_from_line (Eil *eil, int line) -{ - EIconListPrivate *priv; - GList *l; - int height; - - priv = eil->_priv; - - eil_free_line_info_from (eil, line); - - height = 0; - for (l = priv->lines; l; l = l->next) { - IconLine *il = l->data; - - height += icon_line_height (eil, il); - } - - eil_relayout_icons_at (eil, line * eil_get_items_per_line (eil), height); -} - -static void -eil_layout_all_icons (Eil *eil) -{ - EIconListPrivate *priv; - - priv = eil->_priv; - - if (!GTK_WIDGET_REALIZED (eil)) - return; - - eil_free_line_info (eil); - eil_relayout_icons_at (eil, 0, 0); - priv->dirty = FALSE; -} - -static void -eil_scrollbar_adjust (Eil *eil) -{ - EIconListPrivate *priv; - GtkAdjustment *adj; - GList *l; - double wx, wy, wx1, wy1, wx2, wy2; - int height, step_increment; - - priv = eil->_priv; - - if (!GTK_WIDGET_REALIZED (eil)) - return; - - height = 0; - step_increment = 0; - for (l = priv->lines; l; l = l->next) { - IconLine *il = l->data; - - height += icon_line_height (eil, il); - - if (l == priv->lines) - step_increment = height; - } - - if (!step_increment) - step_increment = 10; - - priv->total_height = MAX (height, GTK_WIDGET (eil)->allocation.height); - - gnome_canvas_c2w (GNOME_CANVAS (eil), 0, 0, &wx1, &wy1); - gnome_canvas_c2w (GNOME_CANVAS (eil), - GTK_WIDGET (eil)->allocation.width, - priv->total_height, - &wx2, &wy2); - - gnome_canvas_set_scroll_region (GNOME_CANVAS (eil), - wx1, wy1, wx2, wy2); - - wx = wy = 0; - gnome_canvas_window_to_world (GNOME_CANVAS (eil), 0, 0, &wx, &wy); - - adj = gtk_layout_get_vadjustment (GTK_LAYOUT (eil)); - - adj->upper = priv->total_height; - adj->step_increment = step_increment; - adj->page_increment = GTK_WIDGET (eil)->allocation.height; - adj->page_size = GTK_WIDGET (eil)->allocation.height; - - if (wy > adj->upper - adj->page_size) - wy = adj->upper - adj->page_size; - - adj->value = wy; - - gtk_adjustment_changed (adj); -} - -/* Emits the select_icon or unselect_icon signals as appropriate */ -static void -emit_select (Eil *eil, int sel, int i, GdkEvent *event) -{ - gtk_signal_emit (GTK_OBJECT (eil), - eil_signals[sel ? SELECT_ICON : UNSELECT_ICON], - i, - event); -} - -static int -eil_unselect_all (EIconList *eil, GdkEvent *event, gpointer keep) -{ - EIconListPrivate *priv; - Icon *icon; - int i, idx = 0; - - g_return_val_if_fail (eil != NULL, 0); - g_return_val_if_fail (IS_EIL (eil), 0); - - priv = eil->_priv; - - for (i = 0; i < priv->icon_list->len; i++) { - icon = g_array_index(priv->icon_list, Icon*, i); - - if (icon == keep) - idx = i; - else if (icon->selected) - emit_select (eil, FALSE, i, event); - } - - return idx; -} - -/** - * e_icon_list_unselect_all: - * @eil: An icon list. - * - * Returns: the number of icons in the icon list - */ -int -e_icon_list_unselect_all (EIconList *eil) -{ - return eil_unselect_all (eil, NULL, NULL); -} - -static void -sync_selection (Eil *eil, int pos, SyncType type) -{ - GList *list; - - for (list = eil->_priv->selection; list; list = list->next) { - if (GPOINTER_TO_INT (list->data) >= pos) { - int i = GPOINTER_TO_INT (list->data); - - switch (type) { - case SYNC_INSERT: - list->data = GINT_TO_POINTER (i + 1); - break; - - case SYNC_REMOVE: - list->data = GINT_TO_POINTER (i - 1); - break; - - default: - g_assert_not_reached (); - } - } - } -} - -static int -eil_icon_to_index (Eil *eil, Icon *icon) -{ - EIconListPrivate *priv; - int n; - - priv = eil->_priv; - - for (n = 0; n < priv->icon_list->len; n++) - if (g_array_index(priv->icon_list, Icon*, n) == icon) - return n; - - g_assert_not_reached (); - return -1; /* Shut up the compiler */ -} - -/* Event handler for icons when we are in SINGLE or BROWSE mode */ -static gint -selection_one_icon_event (Eil *eil, Icon *icon, int idx, int on_text, GdkEvent *event) -{ - EIconListPrivate *priv; - GnomeIconTextItem *text; - int retval; - - priv = eil->_priv; - retval = FALSE; - - /* We use a separate variable and ref the object because it may be - * destroyed by one of the signal handlers. - */ - text = icon->text; - gtk_object_ref (GTK_OBJECT (text)); - - switch (event->type) { - case GDK_BUTTON_PRESS: - priv->edit_pending = FALSE; - priv->select_pending = FALSE; - - /* Ignore wheel mouse clicks for now */ - if (event->button.button > 3) - break; - - if (!icon->selected) { - eil_unselect_all (eil, NULL, NULL); - emit_select (eil, TRUE, idx, event); - } else { - if (priv->selection_mode == GTK_SELECTION_SINGLE - && (event->button.state & GDK_CONTROL_MASK)) - emit_select (eil, FALSE, idx, event); - else if (on_text && priv->is_editable && event->button.button == 1) - priv->edit_pending = TRUE; - else - emit_select (eil, TRUE, idx, event); - } - - retval = TRUE; - break; - - case GDK_2BUTTON_PRESS: - case GDK_3BUTTON_PRESS: - /* Ignore wheel mouse clicks for now */ - if (event->button.button > 3) - break; - - emit_select (eil, TRUE, idx, event); - retval = TRUE; - break; - - case GDK_BUTTON_RELEASE: - if (priv->edit_pending) { - gnome_icon_text_item_start_editing (text); - priv->edit_pending = FALSE; - } - - retval = TRUE; - break; - - default: - break; - } - - /* If the click was on the text and we actually did something, stop the - * icon text item's own handler from executing. - */ - if (on_text && retval) - gtk_signal_emit_stop_by_name (GTK_OBJECT (text), "event"); - - gtk_object_unref (GTK_OBJECT (text)); - - return retval; -} - -/* Handles range selections when clicking on an icon */ -static void -select_range (Eil *eil, Icon *icon, int idx, GdkEvent *event) -{ - EIconListPrivate *priv; - int a, b; - Icon *i; - - priv = eil->_priv; - - if (priv->last_selected_idx == -1) { - priv->last_selected_idx = idx; - priv->last_selected_icon = icon; - } - - if (idx < priv->last_selected_idx) { - a = idx; - b = priv->last_selected_idx; - } else { - a = priv->last_selected_idx; - b = idx; - } - - for (; a <= b; a++) { - i = g_array_index(priv->icon_list, Icon*, a); - - if (!i->selected) - emit_select (eil, TRUE, a, NULL); - } - - /* Actually notify the client of the event */ - emit_select (eil, TRUE, idx, event); -} - -/* Handles icon selection for MULTIPLE or EXTENDED selection modes */ -static void -do_select_many (Eil *eil, Icon *icon, int idx, GdkEvent *event, int use_event) -{ - EIconListPrivate *priv; - int range, additive; - - priv = eil->_priv; - - range = (event->button.state & GDK_SHIFT_MASK) != 0; - additive = (event->button.state & GDK_CONTROL_MASK) != 0; - - if (!additive) { - if (icon->selected) - eil_unselect_all (eil, NULL, icon); - else - eil_unselect_all (eil, NULL, NULL); - } - - if (!range) { - if (additive) - emit_select (eil, !icon->selected, idx, use_event ? event : NULL); - else - emit_select (eil, TRUE, idx, use_event ? event : NULL); - - priv->last_selected_idx = idx; - priv->last_selected_icon = icon; - } else - select_range (eil, icon, idx, use_event ? event : NULL); -} - -/* Event handler for icons when we are in MULTIPLE or EXTENDED mode */ -static gint -selection_many_icon_event (Eil *eil, Icon *icon, int idx, int on_text, GdkEvent *event) -{ - EIconListPrivate *priv; - GnomeIconTextItem *text; - int retval; - int additive, range; - int do_select; - - priv = eil->_priv; - retval = FALSE; - - /* We use a separate variable and ref the object because it may be - * destroyed by one of the signal handlers. - */ - text = icon->text; - gtk_object_ref (GTK_OBJECT (text)); - - range = (event->button.state & GDK_SHIFT_MASK) != 0; - additive = (event->button.state & GDK_CONTROL_MASK) != 0; - - switch (event->type) { - case GDK_BUTTON_PRESS: - priv->edit_pending = FALSE; - priv->select_pending = FALSE; - - /* Ignore wheel mouse clicks for now */ - if (event->button.button > 3) - break; - - do_select = TRUE; - - if (additive || range) { - if (additive && !range) { - priv->select_pending = TRUE; - priv->select_pending_event = *event; - priv->select_pending_was_selected = icon->selected; - - /* We have to emit this so that the client will - * know about the click. - */ - emit_select (eil, TRUE, idx, event); - do_select = FALSE; - } - } else if (icon->selected) { - priv->select_pending = TRUE; - priv->select_pending_event = *event; - priv->select_pending_was_selected = icon->selected; - - if (on_text && priv->is_editable && event->button.button == 1) - priv->edit_pending = TRUE; - - emit_select (eil, TRUE, idx, event); - do_select = FALSE; - } -#if 0 - } else if (icon->selected && on_text && priv->is_editable - && event->button.button == 1) { - priv->edit_pending = TRUE; - do_select = FALSE; - } -#endif - - if (do_select) - do_select_many (eil, icon, idx, event, TRUE); - - retval = TRUE; - break; - - case GDK_2BUTTON_PRESS: - case GDK_3BUTTON_PRESS: - /* Ignore wheel mouse clicks for now */ - if (event->button.button > 3) - break; - - emit_select (eil, TRUE, idx, event); - retval = TRUE; - break; - - case GDK_BUTTON_RELEASE: - if (priv->select_pending) { - icon->selected = priv->select_pending_was_selected; - do_select_many (eil, icon, idx, &priv->select_pending_event, FALSE); - priv->select_pending = FALSE; - retval = TRUE; - } - - if (priv->edit_pending) { - gnome_icon_text_item_start_editing (text); - priv->edit_pending = FALSE; - retval = TRUE; - } -#if 0 - if (priv->select_pending) { - icon->selected = priv->select_pending_was_selected; - do_select_many (eil, icon, idx, &priv->select_pending_event); - priv->select_pending = FALSE; - retval = TRUE; - } else if (priv->edit_pending) { - gnome_icon_text_item_start_editing (text); - priv->edit_pending = FALSE; - retval = TRUE; - } -#endif - - break; - - default: - break; - } - - /* If the click was on the text and we actually did something, stop the - * icon text item's own handler from executing. - */ - if (on_text && retval) - gtk_signal_emit_stop_by_name (GTK_OBJECT (text), "event"); - - gtk_object_unref (GTK_OBJECT (text)); - - return retval; -} - -/* Event handler for icons in the icon list */ -static gint -icon_event (GnomeCanvasItem *item, GdkEvent *event, gpointer data) -{ - Icon *icon; - Eil *eil; - EIconListPrivate *priv; - int idx; - int on_text; - - icon = data; - eil = EIL (item->canvas); - priv = eil->_priv; - idx = eil_icon_to_index (eil, icon); - on_text = item == GNOME_CANVAS_ITEM (icon->text); - - switch (priv->selection_mode) { - case GTK_SELECTION_SINGLE: - case GTK_SELECTION_BROWSE: - return selection_one_icon_event (eil, icon, idx, on_text, event); - - case GTK_SELECTION_MULTIPLE: - case GTK_SELECTION_EXTENDED: - return selection_many_icon_event (eil, icon, idx, on_text, event); - - default: - g_assert_not_reached (); - return FALSE; /* Shut up the compiler */ - } -} - -/* Handler for the editing_started signal of an icon text item. We block the - * event handler so that it will not be called while the text is being edited. - */ -static void -editing_started (GnomeIconTextItem *iti, gpointer data) -{ - Icon *icon; - - icon = data; - gtk_signal_handler_block (GTK_OBJECT (iti), icon->text_event_id); - eil_unselect_all (EIL (GNOME_CANVAS_ITEM (iti)->canvas), NULL, icon); -} - -/* Handler for the editing_stopped signal of an icon text item. We unblock the - * event handler so that we can get events from it again. - */ -static void -editing_stopped (GnomeIconTextItem *iti, gpointer data) -{ - Icon *icon; - - icon = data; - gtk_signal_handler_unblock (GTK_OBJECT (iti), icon->text_event_id); -} - -static gboolean -text_changed (GnomeCanvasItem *item, Icon *icon) -{ - Eil *eil; - gboolean accept; - int idx; - - eil = EIL (item->canvas); - accept = TRUE; - - idx = eil_icon_to_index (eil, icon); - gtk_signal_emit (GTK_OBJECT (eil), - eil_signals[TEXT_CHANGED], - idx, gnome_icon_text_item_get_text (icon->text), - &accept); - - return accept; -} - -static void -height_changed (GnomeCanvasItem *item, Icon *icon) -{ - Eil *eil; - EIconListPrivate *priv; - int n; - - eil = EIL (item->canvas); - priv = eil->_priv; - - if (!GTK_WIDGET_REALIZED (eil)) - return; - - if (priv->frozen) { - priv->dirty = TRUE; - return; - } - - n = eil_icon_to_index (eil, icon); - eil_layout_from_line (eil, n / eil_get_items_per_line (eil)); - eil_scrollbar_adjust (eil); -} - -static Icon * -icon_new_from_pixbuf (EIconList *eil, GdkPixbuf *im, - const char *icon_filename, const char *text) -{ - EIconListPrivate *priv; - GnomeCanvas *canvas; - GnomeCanvasGroup *group; - Icon *icon; - - priv = eil->_priv; - canvas = GNOME_CANVAS (eil); - group = GNOME_CANVAS_GROUP (canvas->root); - - icon = g_new0 (Icon, 1); - - if (icon_filename) - icon->icon_filename = g_strdup (icon_filename); - else - icon->icon_filename = NULL; - - if (im == NULL) - im = gdk_pixbuf_new_from_xpm_data ((const char**) bad_icon_xpm); - else - gdk_pixbuf_ref (im); - - icon->image = GNOME_CANVAS_PIXBUF (gnome_canvas_item_new ( - group, - gnome_canvas_pixbuf_get_type (), - "x", 0.0, - "y", 0.0, - "width", (double) gdk_pixbuf_get_width (im), - "height", (double) gdk_pixbuf_get_height (im), - "pixbuf", im, - NULL)); - gdk_pixbuf_unref (im); - - icon->text = GNOME_ICON_TEXT_ITEM (gnome_canvas_item_new ( - group, - gnome_icon_text_item_get_type (), - NULL)); - - gnome_canvas_item_set (GNOME_CANVAS_ITEM (icon->text), - "use_broken_event_handling", FALSE, - NULL); - - gnome_icon_text_item_configure (icon->text, - 0, 0, priv->icon_width, - "-adobe-helvetica-medium-r-normal-*-*-120-*-*-p-*-iso8859-1", - text, priv->is_editable, priv->static_text); - - gtk_signal_connect (GTK_OBJECT (icon->image), "event", - GTK_SIGNAL_FUNC (icon_event), - icon); - icon->text_event_id = gtk_signal_connect (GTK_OBJECT (icon->text), "event", - GTK_SIGNAL_FUNC (icon_event), - icon); - - gtk_signal_connect (GTK_OBJECT (icon->text), "editing_started", - GTK_SIGNAL_FUNC (editing_started), - icon); - gtk_signal_connect (GTK_OBJECT (icon->text), "editing_stopped", - GTK_SIGNAL_FUNC (editing_stopped), - icon); - - gtk_signal_connect (GTK_OBJECT (icon->text), "text_changed", - GTK_SIGNAL_FUNC (text_changed), - icon); - gtk_signal_connect (GTK_OBJECT (icon->text), "height_changed", - GTK_SIGNAL_FUNC (height_changed), - icon); - - return icon; -} - -static Icon * -icon_new (Eil *eil, const char *icon_filename, const char *text) -{ - GdkPixbuf *im; - Icon *retval; - - if (icon_filename) { - im = gdk_pixbuf_new_from_file (icon_filename); - - /* Bad icon image - Fixme. Need a better graphic. */ - if (im == NULL) - im = gdk_pixbuf_new_from_xpm_data ((const char**) bad_icon_xpm); - } else - im = NULL; - - retval = icon_new_from_pixbuf (eil, im, icon_filename, text); - - if(im) - gdk_pixbuf_unref(im); - - return retval; -} - -static int -icon_list_append (Eil *eil, Icon *icon) -{ - EIconListPrivate *priv; - int pos; - - priv = eil->_priv; - - pos = priv->icons++; - g_array_append_val(priv->icon_list, icon); - - switch (priv->selection_mode) { - case GTK_SELECTION_BROWSE: - e_icon_list_select_icon (eil, 0); - break; - - default: - break; - } - - if (!priv->frozen) { - /* FIXME: this should only layout the last line */ - eil_layout_all_icons (eil); - eil_scrollbar_adjust (eil); - } else - priv->dirty = TRUE; - - return priv->icons - 1; -} - -static void -icon_list_insert (Eil *eil, int pos, Icon *icon) -{ - EIconListPrivate *priv; - - priv = eil->_priv; - - if (pos == priv->icons) { - icon_list_append (eil, icon); - return; - } - - g_array_insert_val(priv->icon_list, pos, icon); - priv->icons++; - - switch (priv->selection_mode) { - case GTK_SELECTION_BROWSE: - e_icon_list_select_icon (eil, 0); - break; - - default: - break; - } - - if (!priv->frozen) { - /* FIXME: this should only layout the lines from then one - * containing the Icon to the end. - */ - eil_layout_all_icons (eil); - eil_scrollbar_adjust (eil); - } else - priv->dirty = TRUE; - - sync_selection (eil, pos, SYNC_INSERT); -} - -/** - * e_icon_list_insert_pixbuf: - * @eil: An icon list. - * @pos: Position at which the new icon should be inserted. - * @im: Pixbuf image with the icon image. - * @filename: Filename of the image file. - * @text: Text to be used for the icon's caption. - * - * Inserts an icon in the specified icon list. The icon is created from the - * specified Imlib image, and it is inserted at the @pos index. - */ -void -e_icon_list_insert_pixbuf (EIconList *eil, int pos, GdkPixbuf *im, - const char *icon_filename, const char *text) -{ - Icon *icon; - - g_return_if_fail (eil != NULL); - g_return_if_fail (IS_EIL (eil)); - - icon = icon_new_from_pixbuf (eil, im, icon_filename, text); - icon_list_insert (eil, pos, icon); - return; -} - -/** - * e_icon_list_insert: - * @eil: An icon list. - * @pos: Position at which the new icon should be inserted. - * @icon_filename: Name of the file that holds the icon's image. - * @text: Text to be used for the icon's caption. - * - * Inserts an icon in the specified icon list. The icon's image is loaded - * from the specified file, and it is inserted at the @pos index. - */ -void -e_icon_list_insert (EIconList *eil, int pos, const char *icon_filename, const char *text) -{ - Icon *icon; - - g_return_if_fail (eil != NULL); - g_return_if_fail (IS_EIL (eil)); - - icon = icon_new (eil, icon_filename, text); - icon_list_insert (eil, pos, icon); - return; -} - -/** - * e_icon_list_append_pixbuf: - * @eil: An icon list. - * @im: Pixbuf image with the icon image. - * @filename: Filename of the image file. - * @text: Text to be used for the icon's caption. - * - * Appends an icon to the specified icon list. The icon is created from - * the specified Imlib image. - */ -int -e_icon_list_append_pixbuf (EIconList *eil, GdkPixbuf *im, - const char *icon_filename, const char *text) -{ - Icon *icon; - - g_return_val_if_fail (eil != NULL, -1); - g_return_val_if_fail (IS_EIL (eil), -1); - - icon = icon_new_from_pixbuf (eil, im, icon_filename, text); - return icon_list_append (eil, icon); -} - -/** - * e_icon_list_append: - * @eil: An icon list. - * @icon_filename: Name of the file that holds the icon's image. - * @text: Text to be used for the icon's caption. - * - * Appends an icon to the specified icon list. The icon's image is loaded from - * the specified file, and it is inserted at the @pos index. - */ -int -e_icon_list_append (EIconList *eil, const char *icon_filename, - const char *text) -{ - Icon *icon; - - g_return_val_if_fail (eil != NULL, -1); - g_return_val_if_fail (IS_EIL (eil), -1); - - icon = icon_new (eil, icon_filename, text); - return icon_list_append (eil, icon); -} - -static void -icon_destroy (Icon *icon) -{ - if (icon->destroy) - (* icon->destroy) (icon->data); - - g_free (icon->icon_filename); - - gtk_object_destroy (GTK_OBJECT (icon->image)); - gtk_object_destroy (GTK_OBJECT (icon->text)); - g_free (icon); -} - -/** - * e_icon_list_remove: - * @eil: An icon list. - * @pos: Index of the icon that should be removed. - * - * Removes the icon at index position @pos. If a destroy handler was specified - * for that icon, it will be called with the appropriate data. - */ -void -e_icon_list_remove (EIconList *eil, int pos) -{ - EIconListPrivate *priv; - int was_selected; - Icon *icon; - - g_return_if_fail (eil != NULL); - g_return_if_fail (IS_EIL (eil)); - g_return_if_fail (pos >= 0 && pos < eil->_priv->icons); - - priv = eil->_priv; - - was_selected = FALSE; - - icon = g_array_index(priv->icon_list, Icon*, pos); - - if (icon->selected) { - was_selected = TRUE; - - switch (priv->selection_mode) { - case GTK_SELECTION_SINGLE: - case GTK_SELECTION_BROWSE: - case GTK_SELECTION_MULTIPLE: - case GTK_SELECTION_EXTENDED: - e_icon_list_unselect_icon (eil, pos); - break; - - default: - break; - } - } - - g_array_remove_index(priv->icon_list, pos); - priv->icons--; - - sync_selection (eil, pos, SYNC_REMOVE); - - if (was_selected) { - switch (priv->selection_mode) { - case GTK_SELECTION_BROWSE: - if (pos == priv->icons) - e_icon_list_select_icon (eil, pos - 1); - else - e_icon_list_select_icon (eil, pos); - - break; - - default: - break; - } - } - - if (priv->icons >= priv->last_selected_idx) - priv->last_selected_idx = -1; - - if (priv->last_selected_icon == icon) - priv->last_selected_icon = NULL; - - icon_destroy (icon); - - if (!priv->frozen) { - /* FIXME: Optimize, only re-layout from pos to end */ - eil_layout_all_icons (eil); - eil_scrollbar_adjust (eil); - } else - priv->dirty = TRUE; -} - -/** - * e_icon_list_clear: - * @eil: An icon list. - * - * Clears the contents for the icon list by removing all the icons. If destroy - * handlers were specified for any of the icons, they will be called with the - * appropriate data. - */ -void -e_icon_list_clear (EIconList *eil) -{ - EIconListPrivate *priv; - int i; - - g_return_if_fail (eil != NULL); - g_return_if_fail (IS_EIL (eil)); - - priv = eil->_priv; - - for (i = 0; i < priv->icon_list->len; i++) - icon_destroy (g_array_index (priv->icon_list, Icon*, i)); - - eil_free_line_info (eil); - - g_list_free (priv->selection); - priv->selection = NULL; - g_array_set_size(priv->icon_list, 0); - priv->icons = 0; - priv->last_selected_idx = -1; - priv->last_selected_icon = NULL; - - if (!priv->frozen) { - eil_layout_all_icons (eil); - eil_scrollbar_adjust (eil); - } else - priv->dirty = TRUE; -} - -static void -eil_destroy (GtkObject *object) -{ - Eil *eil; - - /* remember, destroy can be run multiple times! */ - - eil = EIL (object); - - g_free (eil->_priv->separators); - eil->_priv->separators = NULL; - - eil->_priv->frozen = 1; - eil->_priv->dirty = TRUE; - if(eil->_priv->icon_list) { - e_icon_list_clear (eil); - g_array_free(eil->_priv->icon_list, TRUE); - } - eil->_priv->icon_list = NULL; - - if (eil->_priv->timer_tag != 0) { - gtk_timeout_remove (eil->_priv->timer_tag); - eil->_priv->timer_tag = 0; - } - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (*GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} - -static void -eil_finalize (GtkObject *object) -{ - Eil *eil; - - eil = EIL (object); - - g_free (eil->_priv); - eil->_priv = NULL; - - if (GTK_OBJECT_CLASS (parent_class)->finalize) - (*GTK_OBJECT_CLASS (parent_class)->finalize) (object); -} - - -static void -select_icon (Eil *eil, int pos, GdkEvent *event) -{ - EIconListPrivate *priv; - gint i; - Icon *icon; - - priv = eil->_priv; - - switch (priv->selection_mode) { - case GTK_SELECTION_SINGLE: - case GTK_SELECTION_BROWSE: - i = 0; - - for (i = 0; i < priv->icon_list->len; i++) { - icon = g_array_index (priv->icon_list, Icon*, i); - - if (i != pos && icon->selected) - emit_select (eil, FALSE, i, event); - } - - emit_select (eil, TRUE, pos, event); - break; - - case GTK_SELECTION_MULTIPLE: - case GTK_SELECTION_EXTENDED: - emit_select (eil, TRUE, pos, event); - break; - - default: - break; - } -} - -/** - * e_icon_list_select_icon: - * @eil: An icon list. - * @pos: Index of the icon to be selected. - * - * Selects the icon at the index specified by @pos. - */ -void -e_icon_list_select_icon (EIconList *eil, int pos) -{ - g_return_if_fail (eil != NULL); - g_return_if_fail (IS_EIL (eil)); - g_return_if_fail (pos >= 0 && pos < eil->_priv->icons); - - select_icon (eil, pos, NULL); -} - -static void -unselect_icon (Eil *eil, int pos, GdkEvent *event) -{ - EIconListPrivate *priv; - - priv = eil->_priv; - - switch (priv->selection_mode) { - case GTK_SELECTION_SINGLE: - case GTK_SELECTION_BROWSE: - case GTK_SELECTION_MULTIPLE: - case GTK_SELECTION_EXTENDED: - emit_select (eil, FALSE, pos, event); - break; - - default: - break; - } -} - -/** - * e_icon_list_unselect_icon: - * @eil: An icon list. - * @pos: Index of the icon to be unselected. - * - * Unselects the icon at the index specified by @pos. - */ -void -e_icon_list_unselect_icon (EIconList *eil, int pos) -{ - g_return_if_fail (eil != NULL); - g_return_if_fail (IS_EIL (eil)); - g_return_if_fail (pos >= 0 && pos < eil->_priv->icons); - - unselect_icon (eil, pos, NULL); -} - -static void -eil_size_request (GtkWidget *widget, GtkRequisition *requisition) -{ - requisition->width = 1; - requisition->height = 1; -} - -static void -eil_size_allocate (GtkWidget *widget, GtkAllocation *allocation) -{ - Eil *eil; - EIconListPrivate *priv; - - eil = EIL (widget); - priv = eil->_priv; - - if (GTK_WIDGET_CLASS (parent_class)->size_allocate) - (* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation); - - if (priv->frozen) - return; - - eil_layout_all_icons (eil); -} - -static void -eil_realize (GtkWidget *widget) -{ - Eil *eil; - EIconListPrivate *priv; - GtkStyle *style; - - eil = EIL (widget); - priv = eil->_priv; - - priv->frozen++; - - if (GTK_WIDGET_CLASS (parent_class)->realize) - (* GTK_WIDGET_CLASS (parent_class)->realize) (widget); - - priv->frozen--; - - /* Change the style to use the base color as the background */ - - style = gtk_style_copy (gtk_widget_get_style (widget)); - style->bg[GTK_STATE_NORMAL] = style->base[GTK_STATE_NORMAL]; - gtk_widget_set_style (widget, style); - - gdk_window_set_background (GTK_LAYOUT (eil)->bin_window, - &widget->style->bg[GTK_STATE_NORMAL]); - - if (priv->frozen) - return; - - if (priv->dirty) { - eil_layout_all_icons (eil); - eil_scrollbar_adjust (eil); - } -} - -static void -real_select_icon (Eil *eil, gint num, GdkEvent *event) -{ - EIconListPrivate *priv; - Icon *icon; - - g_return_if_fail (eil != NULL); - g_return_if_fail (IS_EIL (eil)); - g_return_if_fail (num >= 0 && num < eil->_priv->icons); - - priv = eil->_priv; - - icon = g_array_index (priv->icon_list, Icon*, num); - - if (icon->selected) - return; - - icon->selected = TRUE; - gnome_icon_text_item_select (icon->text, TRUE); - priv->selection = g_list_append (priv->selection, GINT_TO_POINTER (num)); -} - -static void -real_unselect_icon (Eil *eil, gint num, GdkEvent *event) -{ - EIconListPrivate *priv; - Icon *icon; - - g_return_if_fail (eil != NULL); - g_return_if_fail (IS_EIL (eil)); - g_return_if_fail (num >= 0 && num < eil->_priv->icons); - - priv = eil->_priv; - - icon = g_array_index (priv->icon_list, Icon*, num); - - if (!icon->selected) - return; - - icon->selected = FALSE; - gnome_icon_text_item_select (icon->text, FALSE); - priv->selection = g_list_remove (priv->selection, GINT_TO_POINTER (num)); -} - -/* Saves the selection of the icon list to temporary storage */ -static void -store_temp_selection (Eil *eil) -{ - EIconListPrivate *priv; - int i; - Icon *icon; - - priv = eil->_priv; - - for (i = 0; i < priv->icon_list->len; i++) { - icon = g_array_index(priv->icon_list, Icon*, i); - - icon->tmp_selected = icon->selected; - } -} - -#define gray50_width 2 -#define gray50_height 2 -static const char gray50_bits[] = { - 0x02, 0x01, }; - -/* Button press handler for the icon list */ -static gint -eil_button_press (GtkWidget *widget, GdkEventButton *event) -{ - Eil *eil; - EIconListPrivate *priv; - int only_one; - GdkBitmap *stipple; - double tx, ty; - - eil = EIL (widget); - priv = eil->_priv; - - /* Invoke the canvas event handler and see if an item picks up the event */ - - if ((* GTK_WIDGET_CLASS (parent_class)->button_press_event) (widget, event)) - return TRUE; - - if (!(event->type == GDK_BUTTON_PRESS - && event->button == 1 - && priv->selection_mode != GTK_SELECTION_BROWSE)) - return FALSE; - - only_one = priv->selection_mode == GTK_SELECTION_SINGLE; - - if (only_one || (event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) == 0) - eil_unselect_all (eil, NULL, NULL); - - if (only_one) - return TRUE; - - if (priv->selecting) - return FALSE; - - gnome_canvas_window_to_world (GNOME_CANVAS (eil), event->x, event->y, &tx, &ty); - priv->sel_start_x = tx; - priv->sel_start_y = ty; - priv->sel_state = event->state; - priv->selecting = TRUE; - - store_temp_selection (eil); - - stipple = gdk_bitmap_create_from_data (NULL, gray50_bits, gray50_width, gray50_height); - priv->sel_rect = gnome_canvas_item_new (gnome_canvas_root (GNOME_CANVAS (eil)), - gnome_canvas_rect_get_type (), - "x1", tx, - "y1", ty, - "x2", tx, - "y2", ty, - "outline_color", "black", - "width_pixels", 1, - "outline_stipple", stipple, - NULL); - gdk_bitmap_unref (stipple); - - gnome_canvas_item_grab (priv->sel_rect, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, - NULL, event->time); - - return TRUE; -} - -/* Returns whether the specified icon is at least partially inside the specified - * rectangle. - */ -static int -icon_is_in_area (Icon *icon, int x1, int y1, int x2, int y2) -{ - double ix1, iy1, ix2, iy2; - - if (x1 == x2 && y1 == y2) - return FALSE; - - gnome_canvas_item_get_bounds (GNOME_CANVAS_ITEM (icon->image), &ix1, &iy1, &ix2, &iy2); - - if (ix1 <= x2 && iy1 <= y2 && ix2 >= x1 && iy2 >= y1) - return TRUE; - - gnome_canvas_item_get_bounds (GNOME_CANVAS_ITEM (icon->text), &ix1, &iy1, &ix2, &iy2); - - if (ix1 <= x2 && iy1 <= y2 && ix2 >= x1 && iy2 >= y1) - return TRUE; - - return FALSE; -} - -/* Updates the rubberband selection to the specified point */ -static void -update_drag_selection (Eil *eil, int x, int y) -{ - EIconListPrivate *priv; - int x1, x2, y1, y2; - int i; - Icon *icon; - int additive, invert; - - priv = eil->_priv; - - /* Update rubberband */ - - if (priv->sel_start_x < x) { - x1 = priv->sel_start_x; - x2 = x; - } else { - x1 = x; - x2 = priv->sel_start_x; - } - - if (priv->sel_start_y < y) { - y1 = priv->sel_start_y; - y2 = y; - } else { - y1 = y; - y2 = priv->sel_start_y; - } - - if (x1 < 0) - x1 = 0; - - if (y1 < 0) - y1 = 0; - - if (x2 >= GTK_WIDGET (eil)->allocation.width) - x2 = GTK_WIDGET (eil)->allocation.width - 1; - - if (y2 >= priv->total_height) - y2 = priv->total_height - 1; - - gnome_canvas_item_set (priv->sel_rect, - "x1", (double) x1, - "y1", (double) y1, - "x2", (double) x2, - "y2", (double) y2, - NULL); - - /* Select or unselect icons as appropriate */ - - additive = priv->sel_state & GDK_SHIFT_MASK; - invert = priv->sel_state & GDK_CONTROL_MASK; - - for (i = 0; i < priv->icon_list->len; i++) { - icon = g_array_index(priv->icon_list, Icon*, i); - - if (icon_is_in_area (icon, x1, y1, x2, y2)) { - if (invert) { - if (icon->selected == icon->tmp_selected) - emit_select (eil, !icon->selected, i, NULL); - } else if (additive) { - if (!icon->selected) - emit_select (eil, TRUE, i, NULL); - } else { - if (!icon->selected) - emit_select (eil, TRUE, i, NULL); - } - } else if (icon->selected != icon->tmp_selected) - emit_select (eil, icon->tmp_selected, i, NULL); - } -} - -/* Button release handler for the icon list */ -static gint -eil_button_release (GtkWidget *widget, GdkEventButton *event) -{ - Eil *eil; - EIconListPrivate *priv; - double x, y; - - eil = EIL (widget); - priv = eil->_priv; - - if (!priv->selecting) - return (* GTK_WIDGET_CLASS (parent_class)->button_release_event) (widget, event); - - if (event->button != 1) - return FALSE; - - gnome_canvas_window_to_world (GNOME_CANVAS (eil), event->x, event->y, &x, &y); - update_drag_selection (eil, x, y); - gnome_canvas_item_ungrab (priv->sel_rect, event->time); - - gtk_object_destroy (GTK_OBJECT (priv->sel_rect)); - priv->sel_rect = NULL; - priv->selecting = FALSE; - - if (priv->timer_tag != 0) { - gtk_timeout_remove (priv->timer_tag); - priv->timer_tag = 0; - } - - return TRUE; -} - -/* Autoscroll timeout handler for the icon list */ -static gint -scroll_timeout (gpointer data) -{ - Eil *eil; - EIconListPrivate *priv; - GtkAdjustment *adj; - double x, y; - int value; - - eil = data; - priv = eil->_priv; - - GDK_THREADS_ENTER (); - - adj = gtk_layout_get_vadjustment (GTK_LAYOUT (eil)); - - value = adj->value + priv->value_diff; - if (value > adj->upper - adj->page_size) - value = adj->upper - adj->page_size; - - gtk_adjustment_set_value (adj, value); - - gnome_canvas_window_to_world (GNOME_CANVAS (eil), - priv->event_last_x, priv->event_last_y, - &x, &y); - update_drag_selection (eil, x, y); - - GDK_THREADS_LEAVE(); - - return TRUE; -} - -/* Motion event handler for the icon list */ -static gint -eil_motion_notify (GtkWidget *widget, GdkEventMotion *event) -{ - Eil *eil; - EIconListPrivate *priv; - double x, y; - - eil = EIL (widget); - priv = eil->_priv; - - if (!priv->selecting) - return (* GTK_WIDGET_CLASS (parent_class)->motion_notify_event) (widget, event); - - gnome_canvas_window_to_world (GNOME_CANVAS (eil), event->x, event->y, &x, &y); - update_drag_selection (eil, x, y); - - /* If we are out of bounds, schedule a timeout that will do the scrolling */ - - if (event->y < 0 || event->y > widget->allocation.height) { - if (priv->timer_tag == 0) - priv->timer_tag = gtk_timeout_add (SCROLL_TIMEOUT, scroll_timeout, eil); - - if (event->y < 0) - priv->value_diff = event->y; - else - priv->value_diff = event->y - widget->allocation.height; - - priv->event_last_x = event->x; - priv->event_last_y = event->y; - - /* Make the steppings be relative to the mouse distance from the - * canvas. Also notice the timeout above is small to give a - * more smooth movement. - */ - priv->value_diff /= 5; - } else if (priv->timer_tag != 0) { - gtk_timeout_remove (priv->timer_tag); - priv->timer_tag = 0; - } - - return TRUE; -} - -typedef gboolean (*xGtkSignal_BOOL__INT_POINTER) (GtkObject * object, - gint arg1, - gpointer arg2, - gpointer user_data); -static void -xgtk_marshal_BOOL__INT_POINTER (GtkObject *object, GtkSignalFunc func, gpointer func_data, - GtkArg *args) -{ - xGtkSignal_BOOL__INT_POINTER rfunc; - gboolean *return_val; - - return_val = GTK_RETLOC_BOOL (args[2]); - rfunc = (xGtkSignal_BOOL__INT_POINTER) func; - *return_val = (*rfunc) (object, - GTK_VALUE_INT (args[0]), - GTK_VALUE_POINTER (args[1]), - func_data); -} - -static void -eil_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) -{ - EIconList *eil; - - eil = E_ICON_LIST (object); - - switch (arg_id) { - default: - break; - } -} - -static void -eil_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) -{ - EIconList *eil; - EIconListPrivate *priv; - - eil = E_ICON_LIST (object); - priv = eil->_priv; - - switch (arg_id) { - default: - arg->type = GTK_TYPE_INVALID; - break; - } -} - -static void -eil_class_init (EilClass *eil_class) -{ - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - GtkLayoutClass *layout_class; - GnomeCanvasClass *canvas_class; - - object_class = (GtkObjectClass *) eil_class; - widget_class = (GtkWidgetClass *) eil_class; - layout_class = (GtkLayoutClass *) eil_class; - canvas_class = (GnomeCanvasClass *) eil_class; - - parent_class = gtk_type_class (gnome_canvas_get_type ()); - - eil_signals[SELECT_ICON] = - gtk_signal_new ( - "select_icon", - GTK_RUN_FIRST, - object_class->type, - GTK_SIGNAL_OFFSET (EIconListClass, select_icon), - gtk_marshal_NONE__INT_POINTER, - GTK_TYPE_NONE, 2, - GTK_TYPE_INT, - GTK_TYPE_GDK_EVENT); - - eil_signals[UNSELECT_ICON] = - gtk_signal_new ( - "unselect_icon", - GTK_RUN_FIRST, - object_class->type, - GTK_SIGNAL_OFFSET (EIconListClass, unselect_icon), - gtk_marshal_NONE__INT_POINTER, - GTK_TYPE_NONE, 2, - GTK_TYPE_INT, - GTK_TYPE_GDK_EVENT); - - eil_signals[TEXT_CHANGED] = - gtk_signal_new ( - "text_changed", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (EIconListClass, text_changed), - xgtk_marshal_BOOL__INT_POINTER, - GTK_TYPE_BOOL, 2, - GTK_TYPE_INT, - GTK_TYPE_POINTER); - - gtk_object_class_add_signals (object_class, eil_signals, LAST_SIGNAL); - - object_class->destroy = eil_destroy; - object_class->finalize = eil_finalize; - object_class->set_arg = eil_set_arg; - object_class->get_arg = eil_get_arg; - - widget_class->size_request = eil_size_request; - widget_class->size_allocate = eil_size_allocate; - widget_class->realize = eil_realize; - widget_class->button_press_event = eil_button_press; - widget_class->button_release_event = eil_button_release; - widget_class->motion_notify_event = eil_motion_notify; - - eil_class->select_icon = real_select_icon; - eil_class->unselect_icon = real_unselect_icon; -} - -static void -eil_init (Eil *eil) -{ - eil->_priv = g_new0 (EIconListPrivate, 1); - - eil->_priv->icon_list = g_array_new(FALSE, FALSE, sizeof(gpointer)); - eil->_priv->row_spacing = DEFAULT_ROW_SPACING; - eil->_priv->col_spacing = DEFAULT_COL_SPACING; - eil->_priv->text_spacing = DEFAULT_TEXT_SPACING; - eil->_priv->icon_border = DEFAULT_ICON_BORDER; - eil->_priv->separators = g_strdup (" "); - - eil->_priv->selection_mode = GTK_SELECTION_SINGLE; - eil->_priv->dirty = TRUE; - - gnome_canvas_set_scroll_region (GNOME_CANVAS (eil), 0.0, 0.0, 1000000.0, 1000000.0); - gnome_canvas_scroll_to (GNOME_CANVAS (eil), 0, 0); -} - -/** - * e_icon_list_get_type: - * - * Registers the &EIconList class if necessary, and returns the type ID - * associated to it. - * - * Returns: The type ID of the &EIconList class. - */ -guint -e_icon_list_get_type (void) -{ - static guint eil_type = 0; - - if (!eil_type) { - GtkTypeInfo eil_info = { - "EIconList", - sizeof (EIconList), - sizeof (EIconListClass), - (GtkClassInitFunc) eil_class_init, - (GtkObjectInitFunc) eil_init, - NULL, - NULL, - NULL - }; - - eil_type = gtk_type_unique (gnome_canvas_get_type (), - &eil_info); - } - - return eil_type; -} - -/** - * e_icon_list_set_icon_width: - * @eil: An icon list. - * @w: New width for the icon columns. - * - * Sets the amount of horizontal space allocated to the icons, i.e. the column - * width of the icon list. - */ -void -e_icon_list_set_icon_width (EIconList *eil, int w) -{ - EIconListPrivate *priv; - - g_return_if_fail (eil != NULL); - g_return_if_fail (IS_EIL (eil)); - - priv = eil->_priv; - - priv->icon_width = w; - - if (priv->frozen) { - priv->dirty = TRUE; - return; - } - - eil_layout_all_icons (eil); - eil_scrollbar_adjust (eil); -} - - -/** - * e_icon_list_construct: - * @eil: An icon list. - * @icon_width: Width for the icon columns. - * @flags: A combination of %E_ICON_LIST_IS_EDITABLE and %E_ICON_LIST_STATIC_TEXT. - * - * Constructor for the icon list, to be used by derived classes. - **/ -void -e_icon_list_construct (EIconList *eil, guint icon_width, int flags) -{ - EIconListPrivate *priv; - - g_return_if_fail (eil != NULL); - g_return_if_fail (IS_EIL (eil)); - - priv = eil->_priv; - - e_icon_list_set_icon_width (eil, icon_width); - priv->is_editable = (flags & E_ICON_LIST_IS_EDITABLE) != 0; - priv->static_text = (flags & E_ICON_LIST_STATIC_TEXT) != 0; -} - - -/** - * e_icon_list_new: [constructor] - * @icon_width: Width for the icon columns. - * @flags: A combination of %E_ICON_LIST_IS_EDITABLE and %E_ICON_LIST_STATIC_TEXT. - * - * Creates a new icon list widget. The icon columns are allocated a width of - * @icon_width pixels. Icon captions will be word-wrapped to this width as - * well. - * - * If @flags has the %E_ICON_LIST_IS_EDITABLE flag set, then the user will be - * able to edit the text in the icon captions, and the "text_changed" signal - * will be emitted when an icon's text is changed. - * - * If @flags has the %E_ICON_LIST_STATIC_TEXT flags set, then the text - * for the icon captions will not be copied inside the icon list; it will only - * store the pointers to the original text strings specified by the application. - * This is intended to save memory. If this flag is not set, then the text - * strings will be copied and managed internally. - * - * Returns: a newly-created icon list widget - */ -GtkWidget * -e_icon_list_new (guint icon_width, int flags) -{ - Eil *eil; - - gtk_widget_push_colormap (gdk_rgb_get_cmap ()); - eil = EIL (gtk_type_new (e_icon_list_get_type ())); - gtk_widget_pop_colormap (); - - e_icon_list_construct (eil, icon_width, flags); - - return GTK_WIDGET (eil); -} - - -/** - * e_icon_list_freeze: - * @eil: An icon list. - * - * Freezes an icon list so that any changes made to it will not be - * reflected on the screen until it is thawed with e_icon_list_thaw(). - * It is recommended to freeze the icon list before inserting or deleting - * many icons, for example, so that the layout process will only be executed - * once, when the icon list is finally thawed. - * - * You can call this function multiple times, but it must be balanced with the - * same number of calls to e_icon_list_thaw() before the changes will take - * effect. - */ -void -e_icon_list_freeze (EIconList *eil) -{ - g_return_if_fail (eil != NULL); - g_return_if_fail (IS_EIL (eil)); - - eil->_priv->frozen++; - - /* We hide the root so that the user will not see any changes while the - * icon list is doing stuff. - */ - - if (eil->_priv->frozen == 1) - gnome_canvas_item_hide (GNOME_CANVAS (eil)->root); -} - -/** - * e_icon_list_thaw: - * @eil: An icon list. - * - * Thaws the icon list and performs any pending layout operations. This - * is to be used in conjunction with e_icon_list_freeze(). - */ -void -e_icon_list_thaw (EIconList *eil) -{ - g_return_if_fail (eil != NULL); - g_return_if_fail (IS_EIL (eil)); - g_return_if_fail (eil->_priv->frozen > 0); - - eil->_priv->frozen--; - - if (eil->_priv->dirty) { - eil_layout_all_icons (eil); - eil_scrollbar_adjust (eil); - } - - if (eil->_priv->frozen == 0) - gnome_canvas_item_show (GNOME_CANVAS (eil)->root); -} - -/** - * e_icon_list_set_selection_mode - * @eil: An icon list. - * @mode: New selection mode. - * - * Sets the selection mode for an icon list. The %GTK_SELECTION_MULTIPLE and - * %GTK_SELECTION_EXTENDED modes are considered equivalent. - */ -void -e_icon_list_set_selection_mode (EIconList *eil, GtkSelectionMode mode) -{ - g_return_if_fail (eil != NULL); - g_return_if_fail (IS_EIL (eil)); - - eil->_priv->selection_mode = mode; - eil->_priv->last_selected_idx = -1; - eil->_priv->last_selected_icon = NULL; -} - -/** - * e_icon_list_set_icon_data_full: - * @eil: An icon list. - * @pos: Index of an icon. - * @data: User data to set on the icon. - * @destroy: Destroy notification handler for the icon. - * - * Associates the @data pointer to the icon at the index specified by @pos. The - * @destroy argument points to a function that will be called when the icon is - * destroyed, or NULL if no function is to be called when this happens. - */ -void -e_icon_list_set_icon_data_full (EIconList *eil, - int pos, gpointer data, - GtkDestroyNotify destroy) -{ - Icon *icon; - - g_return_if_fail (eil != NULL); - g_return_if_fail (IS_EIL (eil)); - g_return_if_fail (pos >= 0 && pos < eil->_priv->icons); - - icon = g_array_index (eil->_priv->icon_list, Icon*, pos); - icon->data = data; - icon->destroy = destroy; -} - -/** - * e_icon_list_get_icon_data: - * @eil: An icon list. - * @pos: Index of an icon. - * @data: User data to set on the icon. - * - * Associates the @data pointer to the icon at the index specified by @pos. - */ -void -e_icon_list_set_icon_data (EIconList *eil, int pos, gpointer data) -{ - e_icon_list_set_icon_data_full (eil, pos, data, NULL); -} - -/** - * e_icon_list_get_icon_data: - * @eil: An icon list. - * @pos: Index of an icon. - * - * Returns the user data pointer associated to the icon at the index specified - * by @pos. - */ -gpointer -e_icon_list_get_icon_data (EIconList *eil, int pos) -{ - Icon *icon; - - g_return_val_if_fail (eil != NULL, NULL); - g_return_val_if_fail (IS_EIL (eil), NULL); - g_return_val_if_fail (pos >= 0 && pos < eil->_priv->icons, NULL); - - icon = g_array_index (eil->_priv->icon_list, Icon*, pos); - return icon->data; -} - -/** - * e_icon_list_find_icon_from_data: - * @eil: An icon list. - * @data: Data pointer associated to an icon. - * - * Returns the index of the icon whose user data has been set to @data, - * or -1 if no icon has this data associated to it. - */ -int -e_icon_list_find_icon_from_data (EIconList *eil, gpointer data) -{ - EIconListPrivate *priv; - int n; - Icon *icon; - - g_return_val_if_fail (eil != NULL, -1); - g_return_val_if_fail (IS_EIL (eil), -1); - - priv = eil->_priv; - - for (n = 0; n < priv->icon_list->len; n++) { - icon = g_array_index(priv->icon_list, Icon*, n); - if (icon->data == data) - return n; - } - - return -1; -} - -/* Sets an integer value in the private structure of the icon list, and updates it */ -static void -set_value (EIconList *eil, EIconListPrivate *priv, int *dest, int val) -{ - if (val == *dest) - return; - - *dest = val; - - if (!priv->frozen) { - eil_layout_all_icons (eil); - eil_scrollbar_adjust (eil); - } else - priv->dirty = TRUE; -} - -/** - * e_icon_list_set_row_spacing: - * @eil: An icon list. - * @pixels: Number of pixels for inter-row spacing. - * - * Sets the spacing to be used between rows of icons. - */ -void -e_icon_list_set_row_spacing (EIconList *eil, int pixels) -{ - EIconListPrivate *priv; - - g_return_if_fail (eil != NULL); - g_return_if_fail (IS_EIL (eil)); - - priv = eil->_priv; - set_value (eil, priv, &priv->row_spacing, pixels); -} - -/** - * e_icon_list_set_col_spacing: - * @eil: An icon list. - * @pixels: Number of pixels for inter-column spacing. - * - * Sets the spacing to be used between columns of icons. - */ -void -e_icon_list_set_col_spacing (EIconList *eil, int pixels) -{ - EIconListPrivate *priv; - - g_return_if_fail (eil != NULL); - g_return_if_fail (IS_EIL (eil)); - - priv = eil->_priv; - set_value (eil, priv, &priv->col_spacing, pixels); -} - -/** - * e_icon_list_set_text_spacing: - * @eil: An icon list. - * @pixels: Number of pixels between an icon's image and its caption. - * - * Sets the spacing to be used between an icon's image and its text caption. - */ -void -e_icon_list_set_text_spacing (EIconList *eil, int pixels) -{ - EIconListPrivate *priv; - - g_return_if_fail (eil != NULL); - g_return_if_fail (IS_EIL (eil)); - - priv = eil->_priv; - set_value (eil, priv, &priv->text_spacing, pixels); -} - -/** - * e_icon_list_set_icon_border: - * @eil: An icon list. - * @pixels: Number of border pixels to be used around an icon's image. - * - * Sets the width of the border to be displayed around an icon's image. This is - * currently not implemented. - */ -void -e_icon_list_set_icon_border (EIconList *eil, int pixels) -{ - EIconListPrivate *priv; - - g_return_if_fail (eil != NULL); - g_return_if_fail (IS_EIL (eil)); - - priv = eil->_priv; - set_value (eil, priv, &priv->icon_border, pixels); -} - -/** - * e_icon_list_set_separators: - * @eil: An icon list. - * @sep: String with characters to be used as word separators. - * - * Sets the characters that can be used as word separators when doing - * word-wrapping in the icon text captions. - */ -void -e_icon_list_set_separators (EIconList *eil, const char *sep) -{ - EIconListPrivate *priv; - - g_return_if_fail (eil != NULL); - g_return_if_fail (IS_EIL (eil)); - g_return_if_fail (sep != NULL); - - priv = eil->_priv; - - if (priv->separators) - g_free (priv->separators); - - priv->separators = g_strdup (sep); - - if (priv->frozen) { - priv->dirty = TRUE; - return; - } - - eil_layout_all_icons (eil); - eil_scrollbar_adjust (eil); -} - -/** - * e_icon_list_moveto: - * @eil: An icon list. - * @pos: Index of an icon. - * @yalign: Vertical alignment of the icon. - * - * Makes the icon whose index is @pos be visible on the screen. The icon list - * gets scrolled so that the icon is visible. An alignment of 0.0 represents - * the top of the visible part of the icon list, and 1.0 represents the bottom. - * An icon can be centered on the icon list. - */ -void -e_icon_list_moveto (EIconList *eil, int pos, double yalign) -{ - EIconListPrivate *priv; - GtkAdjustment *adj; - IconLine *il; - GList *l; - int i, y, uh, line; - - g_return_if_fail (eil != NULL); - g_return_if_fail (IS_EIL (eil)); - g_return_if_fail (pos >= 0 && pos < eil->_priv->icons); - g_return_if_fail (yalign >= 0.0 && yalign <= 1.0); - - priv = eil->_priv; - - g_return_if_fail (priv->lines != NULL); - - line = pos / eil_get_items_per_line (eil); - - y = 0; - for (i = 0, l = priv->lines; l && i < line; l = l->next, i++) { - il = l->data; - y += icon_line_height (eil, il); - } - - il = l->data; - - uh = GTK_WIDGET (eil)->allocation.height - icon_line_height (eil,il); - adj = gtk_layout_get_vadjustment (GTK_LAYOUT (eil)); - gtk_adjustment_set_value (adj, y - uh * yalign); -} - -/** - * e_icon_list_is_visible: - * @eil: An icon list. - * @pos: Index of an icon. - * - * Returns whether the icon at the index specified by @pos is visible. This - * will be %GTK_VISIBILITY_NONE if the icon is not visible at all, - * %GTK_VISIBILITY_PARTIAL if the icon is at least partially shown, and - * %GTK_VISIBILITY_FULL if the icon is fully visible. - */ -GtkVisibility -e_icon_list_icon_is_visible (EIconList *eil, int pos) -{ - EIconListPrivate *priv; - GtkAdjustment *adj; - IconLine *il; - GList *l; - int line, y1, y2, i; - - g_return_val_if_fail (eil != NULL, GTK_VISIBILITY_NONE); - g_return_val_if_fail (IS_EIL (eil), GTK_VISIBILITY_NONE); - g_return_val_if_fail (pos >= 0 && pos < eil->_priv->icons, - GTK_VISIBILITY_NONE); - - priv = eil->_priv; - - if (priv->lines == NULL) - return GTK_VISIBILITY_NONE; - - line = pos / eil_get_items_per_line (eil); - y1 = 0; - for (i = 0, l = priv->lines; l && i < line; l = l->next, i++) { - il = l->data; - y1 += icon_line_height (eil, il); - } - - y2 = y1 + icon_line_height (eil, (IconLine *) l->data); - - adj = gtk_layout_get_vadjustment (GTK_LAYOUT (eil)); - - if (y2 < adj->value) - return GTK_VISIBILITY_NONE; - - if (y1 > adj->value + GTK_WIDGET (eil)->allocation.height) - return GTK_VISIBILITY_NONE; - - if (y2 <= adj->value + GTK_WIDGET (eil)->allocation.height && - y1 >= adj->value) - return GTK_VISIBILITY_FULL; - - return GTK_VISIBILITY_PARTIAL; -} - -/** - * e_icon_list_get_icon_at: - * @eil: An icon list. - * @x: X position in the icon list window. - * @y: Y position in the icon list window. - * - * Returns the index of the icon that is under the specified coordinates, which - * are relative to the icon list's window. If there is no icon in that - * position, -1 is returned. - */ -int -e_icon_list_get_icon_at (EIconList *eil, int x, int y) -{ - EIconListPrivate *priv; - double wx, wy; - double dx, dy; - int cx, cy; - int n; - GnomeCanvasItem *item; - double dist; - - g_return_val_if_fail (eil != NULL, -1); - g_return_val_if_fail (IS_EIL (eil), -1); - - priv = eil->_priv; - - dx = x; - dy = y; - - gnome_canvas_window_to_world (GNOME_CANVAS (eil), dx, dy, &wx, &wy); - gnome_canvas_w2c (GNOME_CANVAS (eil), wx, wy, &cx, &cy); - - for (n = 0; n < priv->icon_list->len; n++) { - Icon *icon = g_array_index(priv->icon_list, Icon*, n); - GnomeCanvasItem *image = GNOME_CANVAS_ITEM (icon->image); - GnomeCanvasItem *text = GNOME_CANVAS_ITEM (icon->text); - - if (wx >= image->x1 && wx <= image->x2 && wy >= image->y1 && wy <= image->y2) { - dist = (* GNOME_CANVAS_ITEM_CLASS (GTK_OBJECT (image)->klass)->point) ( - image, - wx, wy, - cx, cy, - &item); - - if ((int) (dist * GNOME_CANVAS (eil)->pixels_per_unit + 0.5) - <= GNOME_CANVAS (eil)->close_enough) - return n; - } - - if (wx >= text->x1 && wx <= text->x2 && wy >= text->y1 && wy <= text->y2) { - dist = (* GNOME_CANVAS_ITEM_CLASS (GTK_OBJECT (text)->klass)->point) ( - text, - wx, wy, - cx, cy, - &item); - - if ((int) (dist * GNOME_CANVAS (eil)->pixels_per_unit + 0.5) - <= GNOME_CANVAS (eil)->close_enough) - return n; - } - } - - return -1; -} - - -/** - * e_icon_list_get_num_icons: - * @eil: An icon list. - * - * Returns the number of icons in the icon list. - */ -guint -e_icon_list_get_num_icons (EIconList *eil) -{ - g_return_val_if_fail (E_IS_ICON_LIST (eil), 0); - - return eil->_priv->icons; -} - - -/** - * e_icon_list_get_selection: - * @eil: An icon list. - * - * Returns a list of integers with the indices of the currently selected icons. - */ -GList * -e_icon_list_get_selection (EIconList *eil) -{ - g_return_val_if_fail (E_IS_ICON_LIST (eil), NULL); - - return eil->_priv->selection; -} - - -/** - * e_icon_list_get_selection: - * @eil: An icon list. - * @idx: Index of an @icon. - * - * Returns the filename of the icon with index @idx. - */ -gchar * -e_icon_list_get_icon_filename (EIconList *eil, int idx) -{ - Icon *icon; - - g_return_val_if_fail (eil != NULL, NULL); - g_return_val_if_fail (IS_EIL (eil), NULL); - g_return_val_if_fail (idx >= 0 && idx < eil->_priv->icons, NULL); - - icon = g_array_index (eil->_priv->icon_list, Icon*, idx); - return icon->icon_filename; -} - - -/** - * e_icon_list_find_icon_from_filename: - * @eil: An icon list. - * @filename: Filename of an icon. - * - * Returns the index of the icon whose filename is @filename or -1 if - * there is no icon with this filename. - */ -int -e_icon_list_find_icon_from_filename (EIconList *eil, - const gchar *filename) -{ - EIconListPrivate *priv; - int n; - Icon *icon; - - g_return_val_if_fail (eil != NULL, -1); - g_return_val_if_fail (IS_EIL (eil), -1); - g_return_val_if_fail (filename != NULL, -1); - - priv = eil->_priv; - - for (n = 0; n < priv->icon_list->len; n++) { - icon = g_array_index(priv->icon_list, Icon*, n); - if (!strcmp (icon->icon_filename, filename)) - return n; - } - - return -1; -} - |