1 /* gtkiconlist - gtkiconlist widget for gtk+
2 * Copyright 1999-2001 Adrian E. Feiguin <feiguin@ifir.edu.ar>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
24 #include <gdk/gdkkeysyms.h>
25 #include <pango/pango.h>
26 #include "gtkitementry.h"
27 #include "gtkiconlist.h"
28 #include "gtkextra-marshal.h"
31 #define DEFAULT_ROW_SPACING 4
32 #define DEFAULT_COL_SPACING 10
33 #define DEFAULT_TEXT_SPACE 60
34 #define DEFAULT_ICON_BORDER 2
35 #define DEFAULT_WIDTH 150
36 #define DEFAULT_HEIGHT 120
38 #define EVENTS_MASK (GDK_EXPOSURE_MASK | \
39 GDK_POINTER_MOTION_MASK | \
40 GDK_POINTER_MOTION_HINT_MASK | \
41 GDK_BUTTON_PRESS_MASK | \
42 GDK_BUTTON_RELEASE_MASK)
47 _gtkextra_signal_emit(GtkObject *object, guint signal_id, ...);
59 static guint signals[LAST_SIGNAL] = {0};
61 static void gtk_icon_list_class_init (GtkIconListClass *class);
62 static void gtk_icon_list_init (GtkIconList *icon_list);
63 static void gtk_icon_list_destroy (GtkObject *object);
64 static void gtk_icon_list_finalize (GObject *object);
66 static void gtk_icon_list_size_allocate (GtkWidget *widget,
67 GtkAllocation *allocation);
69 static void gtk_icon_list_realize (GtkWidget *widget);
70 static gint gtk_icon_list_expose (GtkWidget *widget,
71 GdkEventExpose *event);
72 static gint gtk_icon_list_button_press (GtkWidget *widget,
73 GdkEventButton *event);
74 static gint deactivate_entry (GtkIconList *iconlist);
75 static gint entry_in (GtkWidget *widget,
76 GdkEventButton *event,
78 static gint entry_changed (GtkWidget *widget,
80 static void select_icon (GtkIconList *iconlist,
81 GtkIconListItem *item,
83 static void unselect_icon (GtkIconList *iconlist,
84 GtkIconListItem *item,
86 static void unselect_all (GtkIconList *iconlist);
87 static void set_labels (GtkIconList *iconlist,
88 GtkIconListItem *item,
90 static GtkIconListItem *get_icon_from_entry (GtkIconList *iconlist,
92 static void reorder_icons (GtkIconList *iconlist);
93 static void item_size_request (GtkIconList *iconlist,
94 GtkIconListItem *item,
95 GtkRequisition *requisition);
96 static void gtk_icon_list_move (GtkIconList *iconlist,
97 GtkIconListItem *icon,
99 static GtkIconListItem *gtk_icon_list_real_add (GtkIconList *iconualist,
104 static GtkIconListItem *gtk_icon_list_put (GtkIconList *iconlist,
110 static gint icon_key_press (GtkWidget *widget,
113 static gint sort_list (gpointer a, gpointer b);
114 static void pixmap_destroy (GtkPixmap* pixmap);
117 static GtkFixedClass *parent_class = NULL;
119 static inline guint STRING_WIDTH(GtkWidget *widget,
120 PangoFontDescription *font, const gchar *text)
125 layout = gtk_widget_create_pango_layout (widget, text);
126 pango_layout_set_font_description (layout, font);
128 pango_layout_get_pixel_extents (layout, NULL, &rect);
130 g_object_unref(G_OBJECT(layout));
136 gtk_icon_list_get_type (void)
138 static GtkType icon_list_type = 0;
142 static const GtkTypeInfo icon_list_info =
145 sizeof (GtkIconList),
146 sizeof (GtkIconListClass),
147 (GtkClassInitFunc) gtk_icon_list_class_init,
148 (GtkObjectInitFunc) gtk_icon_list_init,
149 /* reserved 1*/ NULL,
150 /* reserved 2 */ NULL,
151 (GtkClassInitFunc) NULL,
154 icon_list_type = gtk_type_unique (GTK_TYPE_FIXED, &icon_list_info);
156 return icon_list_type;
159 static GtkIconListItem*
160 gtk_icon_list_item_copy (const GtkIconListItem *item)
162 GtkIconListItem *new_item;
164 g_return_val_if_fail (item != NULL, NULL);
166 new_item = g_new (GtkIconListItem, 1);
174 gtk_icon_list_item_free (GtkIconListItem *item)
176 g_return_if_fail (item != NULL);
183 gtk_icon_list_item_get_type (void)
185 static GType icon_list_item_type;
187 if(!icon_list_item_type)
189 icon_list_item_type = g_boxed_type_register_static("GtkIconListItem", (GBoxedCopyFunc)gtk_icon_list_item_copy, (GBoxedFreeFunc)gtk_icon_list_item_free);
191 return icon_list_item_type;
196 gtk_icon_list_class_init (GtkIconListClass *klass)
198 GtkObjectClass *object_class;
199 GObjectClass *gobject_class;
200 GtkWidgetClass *widget_class;
202 parent_class = gtk_type_class (GTK_TYPE_FIXED);
204 object_class = (GtkObjectClass *) klass;
205 gobject_class = (GObjectClass *) klass;
206 widget_class = (GtkWidgetClass *) klass;
208 object_class->destroy = gtk_icon_list_destroy;
209 gobject_class->finalize = gtk_icon_list_finalize;
211 widget_class->realize = gtk_icon_list_realize;
213 widget_class->size_allocate = gtk_icon_list_size_allocate;
215 widget_class->expose_event = gtk_icon_list_expose;
216 widget_class->button_press_event = gtk_icon_list_button_press;
218 signals[SELECT_ICON] =
219 gtk_signal_new("select_icon",
221 GTK_CLASS_TYPE(object_class),
222 GTK_SIGNAL_OFFSET(GtkIconListClass, select_icon),
223 gtkextra_BOOLEAN__BOXED_BOXED,
225 GTK_TYPE_ICON_LIST_ITEM, GDK_TYPE_EVENT);
227 signals[UNSELECT_ICON] =
228 gtk_signal_new("unselect_icon",
230 GTK_CLASS_TYPE(object_class),
231 GTK_SIGNAL_OFFSET(GtkIconListClass, unselect_icon),
232 gtkextra_VOID__BOXED_BOXED,
234 GTK_TYPE_ICON_LIST_ITEM, GDK_TYPE_EVENT);
236 signals[TEXT_CHANGED] =
237 gtk_signal_new("text_changed",
239 GTK_CLASS_TYPE(object_class),
240 GTK_SIGNAL_OFFSET(GtkIconListClass, text_changed),
241 gtkextra_BOOLEAN__BOXED_STRING,
243 GTK_TYPE_ICON_LIST_ITEM, GTK_TYPE_STRING);
245 signals[ACTIVATE_ICON] =
246 gtk_signal_new("activate_icon",
248 GTK_CLASS_TYPE(object_class),
249 GTK_SIGNAL_OFFSET(GtkIconListClass, activate_icon),
250 gtkextra_BOOLEAN__BOXED,
252 GTK_TYPE_ICON_LIST_ITEM);
254 signals[DEACTIVATE_ICON] =
255 gtk_signal_new("deactivate_icon",
257 GTK_CLASS_TYPE(object_class),
258 GTK_SIGNAL_OFFSET(GtkIconListClass, deactivate_icon),
259 gtkextra_BOOLEAN__BOXED,
261 GTK_TYPE_ICON_LIST_ITEM);
263 signals[CLICK_EVENT] =
264 gtk_signal_new("click_event",
266 GTK_CLASS_TYPE(object_class),
267 GTK_SIGNAL_OFFSET(GtkIconListClass, click_event),
268 gtkextra_VOID__BOXED,
275 gtk_icon_list_freeze(GtkIconList *iconlist)
277 iconlist->freeze_count++;
281 gtk_icon_list_thaw(GtkIconList *iconlist)
283 if(iconlist->freeze_count == 0) return;
284 iconlist->freeze_count--;
285 if(iconlist->freeze_count == 0)
286 reorder_icons(iconlist);
290 gtk_icon_list_update(GtkIconList *iconlist)
292 reorder_icons(iconlist);
296 reorder_icons(GtkIconList *iconlist)
299 GtkIconListItem *item;
306 gint old_width, old_height;
308 widget = GTK_WIDGET(iconlist);
310 if(iconlist->freeze_count > 0) return;
316 old_width = widget->allocation.width;
317 old_height = widget->allocation.height;
318 if(GTK_WIDGET_REALIZED(widget)){
319 if(GTK_IS_VIEWPORT(widget->parent))
320 gdk_window_get_size(GTK_VIEWPORT(widget->parent)->view_window, &old_width, &old_height);
323 y = iconlist->row_spacing;
324 x = iconlist->col_spacing;
326 icons = iconlist->icons;
328 item = (GtkIconListItem *) icons->data;
330 gtk_icon_list_move(iconlist, item, x, y);
332 item_size_request(iconlist, item, &req);
334 vspace = req.height + iconlist->row_spacing;
335 hspace = req.width + iconlist->col_spacing;
337 switch(iconlist->mode){
338 case GTK_ICON_LIST_TEXT_RIGHT:
340 if(y + vspace >= old_height - DEFAULT_COL_SPACING){
342 y = iconlist->row_spacing;
345 case GTK_ICON_LIST_TEXT_BELOW:
346 case GTK_ICON_LIST_ICON:
349 if(x + hspace >= old_width - DEFAULT_COL_SPACING){
350 x = iconlist->col_spacing;
366 gtk_icon_list_move(GtkIconList *iconlist, GtkIconListItem *icon,
369 GtkRequisition req1, req2;
373 gint old_width, old_height, width, height;
383 if(x == old_x && y == old_y) return;
385 item_size_request(iconlist, icon, &req);
386 req1 = icon->pixmap->requisition;
387 req2 = icon->entry->requisition;
388 req2.width = iconlist->text_space;
390 req1.width += 2*iconlist->icon_border;
391 req1.height += 2*iconlist->icon_border;
392 if(iconlist->mode == GTK_ICON_LIST_TEXT_BELOW){
393 req1.width = MAX(req1.width, req.width);
396 if(iconlist->mode == GTK_ICON_LIST_ICON)
397 req2.width = req2.height = 0;
399 old_width = width = GTK_WIDGET(iconlist)->allocation.width;
400 old_height = height = GTK_WIDGET(iconlist)->allocation.height;
402 gtk_fixed_move(GTK_FIXED(iconlist), icon->pixmap,
403 x + req1.width/2 - icon->pixmap->requisition.width/2,
404 y + iconlist->icon_border);
406 icon->pixmap->allocation.x += (x - old_x);
407 icon->pixmap->allocation.y += (y - old_y);
408 icon->entry->allocation.x += (x - old_x);
409 icon->entry->allocation.y += (y - old_y);
410 icon->entry->allocation.width = req2.width;
413 switch(iconlist->mode){
414 case GTK_ICON_LIST_TEXT_BELOW:
415 text = gtk_entry_get_text(GTK_ENTRY(icon->entry));
416 size = STRING_WIDTH(icon->entry, icon->entry->style->font_desc, text);
417 size = MIN(size, req2.width);
419 gtk_fixed_move(GTK_FIXED(iconlist), icon->entry,
420 x - req2.width/2 + req1.width/2,
421 y + req1.height + iconlist->icon_border);
423 if(y + req.height > height)
424 height += req.height;
426 case GTK_ICON_LIST_TEXT_RIGHT:
427 gtk_fixed_move(GTK_FIXED(iconlist), icon->entry,
428 x + req1.width + iconlist->icon_border,
429 y + req1.height/2 - req2.height/2);
431 if(x + req.width > width)
434 case GTK_ICON_LIST_ICON:
438 a = icon->entry->allocation;
440 gtk_widget_size_allocate(icon->pixmap, &icon->pixmap->allocation);
442 gtk_widget_size_allocate(icon->entry, &a);
443 gtk_widget_draw(icon->entry, NULL);
450 gtk_icon_list_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
452 GtkAllocation *old = gtk_object_get_data(GTK_OBJECT(widget),"viewport");
453 GTK_WIDGET_CLASS(parent_class)->size_allocate(widget, allocation);
454 if(GTK_WIDGET_REALIZED(widget) && old){
455 gint new_width, new_height;
456 gdk_window_get_size(GTK_VIEWPORT(widget->parent)->view_window, &new_width, &new_height);
457 if(old->width != new_width || old->height != new_height)
458 reorder_icons(GTK_ICON_LIST(widget));
459 old->width = new_width;
460 old->height = new_height;
466 gtk_icon_list_realize(GtkWidget *widget)
469 GtkIconList *iconlist;
470 GtkIconListItem *item;
473 GTK_WIDGET_CLASS(parent_class)->realize (widget);
475 iconlist = GTK_ICON_LIST(widget);
477 style = gtk_style_copy(widget->style);
479 style->bg[0] = iconlist->background;
480 gtk_widget_set_style(widget, style);
481 gtk_style_set_background(style, widget->window, GTK_STATE_NORMAL);
482 gtk_style_set_background(style, widget->window, GTK_STATE_ACTIVE);
484 icons = iconlist->icons;
486 item = (GtkIconListItem *) icons->data;
487 gtk_widget_draw(item->pixmap, NULL);
488 if(iconlist->mode != GTK_ICON_LIST_ICON){
491 gtk_widget_realize(item->entry);
493 style = gtk_style_copy(item->entry->style);
494 style->bg[GTK_STATE_ACTIVE] = iconlist->background;
495 style->bg[GTK_STATE_NORMAL] = iconlist->background;
496 gtk_widget_set_style(item->entry, style);
497 gtk_widget_show(item->entry);
499 if(item->entry) gtk_widget_draw(item->entry, NULL);
504 if(GTK_IS_VIEWPORT(widget->parent) && GTK_WIDGET_REALIZED(widget->parent)){
505 GtkAllocation *allocation = gtk_object_get_data(GTK_OBJECT(widget),"viewport");
506 gdk_window_get_size(GTK_VIEWPORT(widget->parent)->view_window, &allocation->width, &allocation->height);
508 reorder_icons(iconlist);
514 gtk_icon_list_init (GtkIconList *icon_list)
517 widget = GTK_WIDGET(icon_list);
519 gtk_widget_ensure_style(widget);
520 gdk_color_black(gtk_widget_get_colormap(widget), &widget->style->black);
521 gdk_color_white(gtk_widget_get_colormap(widget), &widget->style->white);
523 gtk_fixed_set_has_window(GTK_FIXED(widget), TRUE);
525 gtk_widget_set_events (widget, gtk_widget_get_events(widget)|
528 icon_list->selection = NULL;
529 icon_list->is_editable = TRUE;
531 icon_list->num_icons = 0;
532 icon_list->background = widget->style->white;
534 icon_list->row_spacing = DEFAULT_ROW_SPACING;
535 icon_list->col_spacing = DEFAULT_COL_SPACING;
536 icon_list->text_space = DEFAULT_TEXT_SPACE;
537 icon_list->icon_border = DEFAULT_ICON_BORDER;
539 icon_list->active_icon = NULL;
540 icon_list->compare_func = (GCompareFunc)sort_list;
544 sort_list(gpointer a, gpointer b)
546 GtkIconListItem *itema;
547 GtkIconListItem *itemb;
549 itema = (GtkIconListItem *)a;
550 itemb = (GtkIconListItem *)b;
552 return (strcmp(itema->label, itemb->label));
556 gtk_icon_list_expose (GtkWidget *widget, GdkEventExpose *event)
558 GtkIconList *icon_list;
560 icon_list = GTK_ICON_LIST(widget);
562 if(!GTK_WIDGET_DRAWABLE(widget)) return FALSE;
564 gtk_paint_flat_box (widget->style, widget->window, GTK_STATE_NORMAL,
565 GTK_SHADOW_NONE, &event->area, widget, "base", 0, 0, -1, -1);
567 GTK_WIDGET_CLASS(parent_class)->expose_event(widget, event);
569 if(icon_list->active_icon && icon_list->active_icon->entry){
570 gdk_draw_rectangle(widget->window,
571 widget->style->black_gc,
573 icon_list->active_icon->entry->allocation.x-2,
574 icon_list->active_icon->entry->allocation.y-2,
575 icon_list->active_icon->entry->allocation.width+4,
576 icon_list->active_icon->entry->allocation.height+4);
583 gtk_icon_list_button_press(GtkWidget *widget, GdkEventButton *event)
585 GtkIconList *iconlist;
586 GtkIconListItem *item;
588 GtkAllocation *allocation;
590 if(!GTK_IS_ICON_LIST(widget)) return FALSE;
592 iconlist = GTK_ICON_LIST(widget);
595 gtk_widget_get_pointer(widget, &x, &y);
596 item = gtk_icon_list_get_icon_at(iconlist, x , y );
599 gtk_signal_emit(GTK_OBJECT(iconlist), signals[CLICK_EVENT],
605 allocation = &item->entry->allocation;
606 if(x >= allocation->x &&
607 x <= allocation->x + allocation->width &&
608 y >= allocation->y &&
609 y <= allocation->y + allocation->height) return FALSE;
613 switch(iconlist->selection_mode){
614 case GTK_SELECTION_SINGLE:
615 case GTK_SELECTION_BROWSE:
616 unselect_all(iconlist);
617 case GTK_SELECTION_MULTIPLE:
618 select_icon(iconlist, item, (GdkEvent *)event);
619 case GTK_SELECTION_NONE:
628 deactivate_entry(GtkIconList *iconlist)
632 gboolean veto = TRUE;
634 if(iconlist->active_icon) {
635 _gtkextra_signal_emit(GTK_OBJECT(iconlist), signals[DEACTIVATE_ICON],
636 iconlist->active_icon, &veto);
637 if(!veto) return FALSE;
639 entry = GTK_ENTRY(iconlist->active_icon->entry);
641 if(!entry || !GTK_WIDGET_REALIZED(entry)) return TRUE;
642 gtk_entry_set_editable(entry, FALSE);
643 gtk_entry_select_region(entry, 0, 0);
644 gtk_item_entry_set_cursor_visible(GTK_ITEM_ENTRY(entry), FALSE);
646 switch(iconlist->mode){
647 case GTK_ICON_LIST_TEXT_RIGHT:
648 gtk_item_entry_set_text(GTK_ITEM_ENTRY(entry),
649 iconlist->active_icon->entry_label,
652 case GTK_ICON_LIST_TEXT_BELOW:
653 gtk_item_entry_set_text(GTK_ITEM_ENTRY(entry),
654 iconlist->active_icon->entry_label,
657 case GTK_ICON_LIST_ICON:
662 if(GTK_WIDGET_REALIZED(iconlist->active_icon->entry)){
663 gc = gdk_gc_new(GTK_WIDGET(iconlist)->window);
664 gdk_gc_set_foreground(gc, &iconlist->background);
665 gdk_draw_rectangle(GTK_WIDGET(iconlist)->window,
668 GTK_WIDGET(entry)->allocation.x-2,
669 GTK_WIDGET(entry)->allocation.y-2,
670 GTK_WIDGET(entry)->allocation.width+4,
671 GTK_WIDGET(entry)->allocation.height+4);
675 iconlist->active_icon->state = GTK_STATE_NORMAL;
676 iconlist->active_icon = NULL;
684 select_icon(GtkIconList *iconlist, GtkIconListItem *item, GdkEvent *event)
686 gboolean veto = TRUE;
688 if(item == NULL) return;
690 _gtkextra_signal_emit(GTK_OBJECT(iconlist), signals[SELECT_ICON], item,
695 if(iconlist->mode != GTK_ICON_LIST_ICON){
696 if(!deactivate_entry(iconlist)) return;
698 if(item->entry && GTK_WIDGET_REALIZED(item->entry)){
699 GtkStyle *style = gtk_style_copy(item->entry->style);
700 style->bg[GTK_STATE_ACTIVE] = style->base[GTK_STATE_SELECTED];
701 style->bg[GTK_STATE_NORMAL] = style->base[GTK_STATE_SELECTED];
702 style->text[GTK_STATE_ACTIVE] = style->text[GTK_STATE_SELECTED];
703 style->text[GTK_STATE_NORMAL] = style->text[GTK_STATE_SELECTED];
704 gtk_widget_set_style(item->entry, style);
705 gtk_style_unref(style);
707 switch(iconlist->mode){
708 case GTK_ICON_LIST_TEXT_RIGHT:
709 gtk_item_entry_set_text(GTK_ITEM_ENTRY(item->entry),
713 case GTK_ICON_LIST_TEXT_BELOW:
714 gtk_item_entry_set_text(GTK_ITEM_ENTRY(item->entry),
718 case GTK_ICON_LIST_ICON:
724 if(item->state == GTK_STATE_SELECTED) return;
725 iconlist->selection = g_list_append(iconlist->selection, item);
727 item->state = GTK_STATE_SELECTED;
728 if(item->entry) gtk_widget_grab_focus(item->entry);
732 unselect_icon(GtkIconList *iconlist, GtkIconListItem *item, GdkEvent *event)
735 GtkIconListItem *icon;
739 if(item->state == GTK_STATE_NORMAL) return;
741 selection = iconlist->selection;
743 icon = (GtkIconListItem *)selection->data;
744 if(item == icon) break;
745 selection = selection->next;
749 iconlist->selection = g_list_remove_link(iconlist->selection, selection);
752 item->state = GTK_STATE_NORMAL;
754 if(iconlist->mode != GTK_ICON_LIST_ICON){
755 if(item->entry && GTK_WIDGET_REALIZED(item->entry)){
756 GtkStyle *style = gtk_style_copy(item->entry->style);
758 style->bg[GTK_STATE_ACTIVE] = iconlist->background;
759 style->bg[GTK_STATE_NORMAL] = iconlist->background;
760 style->text[GTK_STATE_ACTIVE] = GTK_WIDGET(iconlist)->style->text[GTK_STATE_ACTIVE];
761 style->text[GTK_STATE_NORMAL] = GTK_WIDGET(iconlist)->style->text[GTK_STATE_NORMAL];
762 gtk_widget_set_style(item->entry, style);
763 gtk_style_unref(style);
765 gtk_entry_select_region(GTK_ENTRY(item->entry), 0, 0);
766 gtk_entry_set_text(GTK_ENTRY(item->entry), item->entry_label);
767 gtk_entry_set_editable(GTK_ENTRY(item->entry), FALSE);
768 gtk_widget_draw(item->entry, NULL);
773 gtk_signal_emit(GTK_OBJECT(iconlist), signals[UNSELECT_ICON], item, event);
777 unselect_all(GtkIconList *iconlist)
780 GtkIconListItem *item;
782 selection = iconlist->selection;
784 item = (GtkIconListItem *)selection->data;
785 unselect_icon(iconlist, item, NULL);
786 selection = iconlist->selection;
789 g_list_free(iconlist->selection);
790 iconlist->selection = NULL;
794 gtk_icon_list_new (guint icon_width, GtkIconListMode mode)
796 GtkIconList *icon_list;
797 GtkAllocation *allocation;
799 icon_list = gtk_type_new (gtk_icon_list_get_type ());
801 gtk_icon_list_construct(icon_list, icon_width, mode);
802 allocation = g_new0(GtkAllocation, 1);
803 gtk_object_set_data(GTK_OBJECT(icon_list), "viewport", allocation);
805 return GTK_WIDGET (icon_list);
809 gtk_icon_list_construct (GtkIconList *icon_list, guint icon_width, GtkIconListMode mode)
811 icon_list->icon_width = icon_width;
812 icon_list->mode = mode;
813 icon_list->icons = NULL;
814 icon_list->selection = NULL;
815 icon_list->selection_mode = GTK_SELECTION_SINGLE;
819 gtk_icon_list_set_mode (GtkIconList *iconlist, GtkIconListMode mode)
823 iconlist->mode = mode;
825 icons = iconlist->icons;
827 GtkIconListItem *item;
829 item = (GtkIconListItem *)icons->data;
832 case GTK_ICON_LIST_TEXT_RIGHT:
833 gtk_item_entry_set_justification(GTK_ITEM_ENTRY(item->entry),
836 case GTK_ICON_LIST_TEXT_BELOW:
837 gtk_item_entry_set_justification(GTK_ITEM_ENTRY(item->entry),
840 case GTK_ICON_LIST_ICON:
848 reorder_icons(iconlist);
852 gtk_icon_list_get_mode (GtkIconList *iconlist)
854 return(iconlist->mode);
858 gtk_icon_list_set_text_space (GtkIconList *iconlist, guint text_space)
862 iconlist->text_space = text_space;
864 icons = iconlist->icons;
866 GtkIconListItem *item;
868 item = (GtkIconListItem *)icons->data;
870 if(item->entry) GTK_ITEM_ENTRY(item->entry)->text_max_size = text_space;
875 reorder_icons(iconlist);
880 gtk_icon_list_destroy (GtkObject *object)
882 GtkIconList *icon_list;
884 g_return_if_fail (object != NULL);
885 g_return_if_fail (GTK_IS_ICON_LIST (object));
887 icon_list = GTK_ICON_LIST (object);
889 gtk_icon_list_clear(icon_list);
891 if (GTK_OBJECT_CLASS (parent_class)->destroy)
892 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
896 gtk_icon_list_finalize (GObject *object)
898 GtkIconList *icon_list;
899 GtkAllocation *allocation;
901 icon_list = GTK_ICON_LIST (object);
903 allocation = gtk_object_get_data(GTK_OBJECT(icon_list), "viewport");
904 if(allocation) g_free(allocation);
905 gtk_object_set_data(GTK_OBJECT(icon_list), "viewport", NULL);
907 if (G_OBJECT_CLASS (parent_class)->finalize)
908 (*G_OBJECT_CLASS (parent_class)->finalize) (object);
912 gtk_icon_list_set_background (GtkIconList *iconlist, GdkColor *color)
917 g_return_if_fail (iconlist != NULL);
918 g_return_if_fail (GTK_IS_ICON_LIST (iconlist));
920 widget = GTK_WIDGET(iconlist);
922 iconlist->background = *color;
924 style = gtk_style_copy(widget->style);
925 style->bg[0] = iconlist->background;
927 gtk_widget_set_style(widget, style);
928 if(widget->window) gdk_window_set_background(widget->window, color);
929 gtk_style_unref(style);
934 entry_changed (GtkWidget *widget, gpointer data)
936 GtkIconList *iconlist;
937 GtkIconListItem *item;
938 gboolean veto = TRUE;
941 iconlist = GTK_ICON_LIST(data);
942 item = get_icon_from_entry(iconlist, widget);
943 text = gtk_entry_get_text(GTK_ENTRY(widget));
945 _gtkextra_signal_emit(GTK_OBJECT(data), signals[TEXT_CHANGED],
948 if(!veto) return veto;
950 if(item->entry && gtk_editable_get_editable(GTK_EDITABLE(item->entry))){
951 if(item->label) g_free(item->label);
952 if(text) item->label = g_strdup(text);
953 if(item->entry_label) g_free(item->entry_label);
954 set_labels(iconlist, item, text);
961 entry_in (GtkWidget *widget, GdkEventButton *event, gpointer data)
963 GtkIconList *iconlist;
964 GtkIconListItem *item;
965 gboolean veto = TRUE;
967 if(!GTK_IS_ENTRY(widget)) return FALSE;
968 iconlist = GTK_ICON_LIST(data);
970 item = get_icon_from_entry(iconlist, widget);
971 if(iconlist->active_icon && iconlist->active_icon->entry == widget)
974 _gtkextra_signal_emit(GTK_OBJECT(iconlist), signals[ACTIVATE_ICON], &item, &veto);
976 if(!veto) return FALSE;
977 if(!deactivate_entry(iconlist)) return FALSE;
979 if(item->state == GTK_STATE_SELECTED){
980 if(iconlist->is_editable && !gtk_editable_get_editable(GTK_EDITABLE(widget))){
981 unselect_all(iconlist);
983 gtk_entry_set_editable(GTK_ENTRY(widget), TRUE);
984 gtk_item_entry_set_cursor_visible(GTK_ITEM_ENTRY(widget), TRUE);
985 if(item->label) gtk_entry_set_text(GTK_ENTRY(widget), item->label);
986 iconlist->active_icon = item;
987 item->state = GTK_STATE_NORMAL;
989 if(GTK_WIDGET_DRAWABLE(widget))
990 gdk_draw_rectangle(GTK_WIDGET(iconlist)->window,
991 widget->style->black_gc,
993 iconlist->active_icon->entry->allocation.x-2,
994 iconlist->active_icon->entry->allocation.y-2,
995 iconlist->active_icon->entry->allocation.width+4,
996 iconlist->active_icon->entry->allocation.height+4);
998 gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "button_press_event");
999 if(iconlist->selection_mode == GTK_SELECTION_SINGLE ||
1000 iconlist->selection_mode == GTK_SELECTION_BROWSE)
1001 unselect_all(iconlist);
1002 select_icon(iconlist, item, (GdkEvent *)event);
1005 if(iconlist->selection_mode == GTK_SELECTION_SINGLE ||
1006 iconlist->selection_mode == GTK_SELECTION_BROWSE)
1007 unselect_all(iconlist);
1008 select_icon(iconlist, item, (GdkEvent *)event);
1015 gtk_icon_list_get_active_icon(GtkIconList *iconlist)
1017 return iconlist->active_icon;
1020 static GtkIconListItem *
1021 get_icon_from_entry(GtkIconList *iconlist, GtkWidget *widget)
1024 GtkIconListItem *item;
1026 icons = iconlist->icons;
1028 item = (GtkIconListItem *) icons->data;
1029 if(widget == item->entry) return item;
1030 icons = icons->next;
1037 gtk_icon_list_get_icon_at(GtkIconList *iconlist, gint x, gint y)
1040 GtkIconListItem *item;
1043 icons = iconlist->icons;
1045 item = (GtkIconListItem *) icons->data;
1046 item_size_request(iconlist, item, &req);
1047 if(x >= item->x && x <= item->x + req.width &&
1048 y >= item->y && y <= item->y + req.height) return item;
1049 icons = icons->next;
1056 gtk_icon_list_add (GtkIconList *iconlist,
1061 GtkIconListItem *item;
1062 GdkColormap *colormap;
1066 colormap = gdk_colormap_get_system();
1067 pixmap = gdk_pixmap_colormap_create_from_xpm(NULL, colormap, &mask, NULL,
1069 item = gtk_icon_list_real_add(iconlist, pixmap, mask, label, link);
1074 gtk_icon_list_add_from_data (GtkIconList *iconlist,
1079 GtkIconListItem *item;
1080 GdkColormap *colormap;
1084 colormap = gdk_colormap_get_system();
1085 pixmap = gdk_pixmap_colormap_create_from_xpm_d(NULL, colormap, &mask, NULL,
1087 item = gtk_icon_list_real_add(iconlist, pixmap, mask, label, link);
1092 gtk_icon_list_add_from_pixmap (GtkIconList *iconlist,
1098 GtkIconListItem *item;
1100 gdk_pixmap_ref(pixmap);
1101 if(mask) gdk_bitmap_ref(mask);
1102 item = gtk_icon_list_real_add(iconlist, pixmap, mask, label, link);
1107 static GtkIconListItem*
1108 gtk_icon_list_real_add (GtkIconList *iconlist,
1114 GtkIconListItem *item;
1115 GtkRequisition requisition;
1122 width = GTK_WIDGET(iconlist)->allocation.width;
1123 height = GTK_WIDGET(iconlist)->allocation.height;
1125 if(iconlist->num_icons > 0){
1126 item = gtk_icon_list_get_nth(iconlist, iconlist->num_icons-1);
1129 item_size_request(iconlist, item, &requisition);
1131 vspace = requisition.height + iconlist->row_spacing;
1132 hspace = requisition.width + iconlist->col_spacing;
1134 switch(iconlist->mode){
1135 case GTK_ICON_LIST_TEXT_RIGHT:
1139 y = iconlist->row_spacing;
1142 case GTK_ICON_LIST_TEXT_BELOW:
1143 case GTK_ICON_LIST_ICON:
1147 x = iconlist->col_spacing;
1153 y = iconlist->row_spacing;
1154 x = iconlist->col_spacing;
1157 item = gtk_icon_list_put(iconlist, x, y, pixmap, mask, label, data);
1161 static GtkIconListItem *
1162 gtk_icon_list_put (GtkIconList *iconlist,
1169 GtkIconListItem *icon;
1170 GtkIconListItem *active_icon;
1172 GtkRequisition req, req1, req2;
1174 gint width, height, old_width, old_height;
1175 GtkAllocation alloc;
1177 widget = GTK_WIDGET(iconlist);
1179 old_width = width = GTK_WIDGET(iconlist)->allocation.width;
1180 old_height = height = GTK_WIDGET(iconlist)->allocation.height;
1182 active_icon = iconlist->active_icon;
1183 gtk_icon_list_set_active_icon(iconlist, NULL);
1185 icon = g_new(GtkIconListItem, 1);
1188 icon->state = GTK_STATE_NORMAL;
1190 icon->entry_label = NULL;
1191 if(label) icon->label = g_strdup(label);
1192 icon->entry = gtk_item_entry_new();
1193 icon->pixmap = gtk_pixmap_new(pixmap, mask);
1196 GTK_ITEM_ENTRY(icon->entry)->text_max_size = iconlist->text_space;
1197 item_size_request(iconlist, icon, &req);
1198 req1 = icon->pixmap->requisition;
1199 req2 = icon->entry->requisition;
1200 req2.width = iconlist->text_space;
1202 req1.width += 2*iconlist->icon_border;
1203 req1.height += 2*iconlist->icon_border;
1204 if(iconlist->mode == GTK_ICON_LIST_TEXT_BELOW){
1205 req1.width = MAX(req1.width, req.width);
1208 if(iconlist->mode == GTK_ICON_LIST_ICON)
1209 req2.width = req2.height = 0;
1211 set_labels(iconlist, icon, label);
1214 if(label) text_width = STRING_WIDTH(icon->entry, icon->entry->style->font_desc, label);
1216 gtk_fixed_put(GTK_FIXED(iconlist), icon->pixmap,
1217 x + req1.width/2 - icon->pixmap->requisition.width/2,
1218 y + iconlist->icon_border);
1220 alloc.x = x + req1.width/2 - icon->pixmap->requisition.width/2;
1221 alloc.y = y + iconlist->icon_border;
1222 alloc.width = req1.width;
1223 alloc.height = req1.height;
1224 gtk_widget_size_allocate(icon->pixmap, &alloc);
1226 switch(iconlist->mode){
1227 case GTK_ICON_LIST_TEXT_BELOW:
1228 gtk_item_entry_set_text(GTK_ITEM_ENTRY(icon->entry), icon->entry_label,
1229 GTK_JUSTIFY_CENTER);
1230 gtk_fixed_put(GTK_FIXED(iconlist), icon->entry,
1231 x - req2.width/2 + req1.width/2,
1232 y + req1.height + iconlist->icon_border);
1233 alloc.x = x - req2.width/2 + req1.width/2;
1234 alloc.y = y + req1.height + iconlist->icon_border;
1235 alloc.width = req2.width;
1236 alloc.height = req2.height;
1237 gtk_widget_size_allocate(icon->entry, &alloc);
1239 if(y + req1.height + iconlist->icon_border + req2.height > height)
1240 height += req1.height + iconlist->icon_border + req2.height;
1242 case GTK_ICON_LIST_TEXT_RIGHT:
1243 gtk_item_entry_set_text(GTK_ITEM_ENTRY(icon->entry), icon->entry_label,
1245 gtk_fixed_put(GTK_FIXED(iconlist), icon->entry,
1246 x + req1.width + iconlist->icon_border,
1247 y + req1.height/2 - req2.height/2);
1248 alloc.x = x + req1.width + iconlist->icon_border;
1249 alloc.y = y + req1.height/2 - req2.height/2;
1250 alloc.width = req2.width;
1251 alloc.height = req2.height;
1252 gtk_widget_size_allocate(icon->entry, &alloc);
1254 if(x + req1.width + iconlist->icon_border + text_width > width)
1255 width += req1.width + iconlist->icon_border + text_width;
1257 case GTK_ICON_LIST_ICON:
1261 if(GTK_WIDGET_REALIZED(iconlist))
1262 if(iconlist->mode != GTK_ICON_LIST_ICON){
1263 GtkStyle *style = gtk_style_copy(icon->entry->style);
1264 style->bg[GTK_STATE_ACTIVE] = iconlist->background;
1265 style->bg[GTK_STATE_NORMAL] = iconlist->background;
1266 gtk_widget_set_style(icon->entry, style);
1267 gtk_style_unref(style);
1268 gtk_widget_show(icon->entry);
1271 gtk_widget_show(icon->pixmap);
1273 if(iconlist->compare_func)
1274 iconlist->icons = g_list_insert_sorted(iconlist->icons, icon, iconlist->compare_func);
1276 iconlist->icons = g_list_append(iconlist->icons, icon);
1278 iconlist->num_icons++;
1280 if(GTK_WIDGET_REALIZED(iconlist))
1281 reorder_icons(iconlist);
1283 gtk_entry_set_editable(GTK_ENTRY(icon->entry), FALSE);
1285 gtk_signal_connect(GTK_OBJECT(icon->entry), "key_press_event",
1286 (GtkSignalFunc)icon_key_press, iconlist);
1287 gtk_signal_connect(GTK_OBJECT(icon->entry), "button_press_event",
1288 (GtkSignalFunc)entry_in, iconlist);
1289 gtk_signal_connect(GTK_OBJECT(icon->entry), "changed",
1290 (GtkSignalFunc)entry_changed, iconlist);
1292 gtk_icon_list_set_active_icon(iconlist, active_icon);
1297 set_labels(GtkIconList *iconlist, GtkIconListItem *icon, const gchar *label)
1302 gchar *entry_label = NULL;
1307 entry_label = (gchar *)g_malloc(strlen(label) + 5);
1308 entry_label[0] = label[0];
1309 entry_label[1] = '\0';
1311 text_width = STRING_WIDTH(icon->entry, icon->entry->style->font_desc, label);
1312 point_width = STRING_WIDTH(icon->entry, icon->entry->style->font_desc, "X");
1314 max_width = iconlist->text_space;
1316 for(n = 0; n < strlen(label); n++){
1317 space = strlen(label) - n + 1;
1319 STRING_WIDTH(icon->entry, icon->entry->style->font_desc, entry_label) +
1320 3 * point_width > max_width)
1322 entry_label[n] = label[n];
1323 entry_label[n + 1] = '\0';
1327 if(strlen(entry_label) < strlen(label))
1328 sprintf(entry_label,"%s...", entry_label);
1330 icon->entry_label = g_strdup(entry_label);
1332 g_free(entry_label);
1336 icon_key_press(GtkWidget *widget, GdkEventKey *key, gpointer data)
1338 GtkIconList *iconlist;
1340 iconlist = GTK_ICON_LIST(data);
1341 if(key->keyval != GDK_Return) return FALSE;
1343 if(iconlist->active_icon)
1344 select_icon(iconlist, iconlist->active_icon, NULL);
1350 item_size_request(GtkIconList *iconlist,
1351 GtkIconListItem *item,
1352 GtkRequisition *requisition)
1354 GtkRequisition req2;
1356 gtk_widget_size_request(item->entry, &req2);
1357 req2.width = iconlist->text_space;
1359 gtk_widget_size_request(item->pixmap, requisition);
1360 requisition->width = MAX(iconlist->icon_width, requisition->width);
1361 requisition->width += 2*iconlist->icon_border;
1362 requisition->height += 2*iconlist->icon_border;
1364 switch(iconlist->mode){
1365 case GTK_ICON_LIST_TEXT_BELOW:
1366 requisition->height += req2.height;
1367 requisition->width = MAX(requisition->width, req2.width);
1369 case GTK_ICON_LIST_TEXT_RIGHT:
1370 requisition->width += req2.width;
1372 case GTK_ICON_LIST_ICON:
1380 gtk_icon_list_set_editable (GtkIconList *iconlist, gboolean editable)
1383 GtkIconListItem *item;
1385 icons = iconlist->icons;
1387 item = (GtkIconListItem *) icons->data;
1388 gtk_entry_set_editable(GTK_ENTRY(item->entry), editable);
1389 icons = icons->next;
1392 iconlist->is_editable = editable;
1396 gtk_icon_list_get_nth(GtkIconList *iconlist, guint n)
1398 return (GtkIconListItem *)g_list_nth_data(iconlist->icons, n);
1402 gtk_icon_list_get_index(GtkIconList *iconlist, GtkIconListItem *item)
1405 GtkIconListItem *icon;
1408 if(item == NULL) return -1;
1410 icons = iconlist->icons;
1413 icon = (GtkIconListItem *) icons->data;
1414 if(item == icon) break;
1415 icons = icons->next;
1424 remove_from_fixed(GtkIconList *iconlist, GtkWidget *widget)
1429 fixed = GTK_FIXED(iconlist);
1430 children = fixed->children;
1432 GtkFixedChild *child;
1434 child = children->data;
1436 if(child->widget == widget){
1437 gtk_widget_unparent(widget);
1438 fixed->children = g_list_remove_link (fixed->children, children);
1439 g_list_free (children);
1445 children = children->next;
1450 pixmap_destroy(GtkPixmap* pixmap)
1452 /* release pixmap */
1454 GdkPixmap* pm = NULL;
1455 GdkBitmap* bm = NULL;
1457 gtk_pixmap_get(pixmap, &pm, &bm);
1459 /* HB: i don't know enough about Gtk+ to call this a design flaw, but it
1460 * appears the pixmaps need to be destroyed by hand ...
1462 if (pm) gdk_pixmap_unref(pm);
1463 if (bm) gdk_pixmap_unref(bm);
1468 gtk_icon_list_remove (GtkIconList *iconlist, GtkIconListItem *item)
1471 GtkIconListItem *icon = 0;
1473 if(item == NULL) return;
1475 icons = iconlist->icons;
1477 icon = (GtkIconListItem *) icons->data;
1478 if(item == icon) break;
1479 icons = icons->next;
1483 if(icon->state == GTK_STATE_SELECTED) unselect_icon(iconlist, icon, NULL);
1484 if(icon == iconlist->active_icon) deactivate_entry(iconlist);
1485 pixmap_destroy(GTK_PIXMAP(icon->pixmap));
1486 if(icon->entry && iconlist->mode != GTK_ICON_LIST_ICON){
1487 remove_from_fixed(iconlist, icon->entry);
1491 remove_from_fixed(iconlist, icon->pixmap);
1492 icon->pixmap = NULL;
1495 g_free(icon->label);
1498 if(icon->entry_label){
1499 g_free(icon->entry_label);
1500 icon->entry_label = NULL;
1504 iconlist->icons = g_list_remove_link(iconlist->icons, icons);
1505 g_list_free_1(icons);
1506 iconlist->num_icons--;
1509 if(iconlist->num_icons == 0){
1510 iconlist->icons = NULL;
1511 iconlist->selection = NULL;
1516 gtk_icon_list_remove_nth (GtkIconList *iconlist, guint n)
1518 GtkIconListItem *item;
1520 item = gtk_icon_list_get_nth(iconlist, n);
1521 gtk_icon_list_remove(iconlist, item);
1525 gtk_icon_list_clear(GtkIconList *iconlist)
1528 GtkIconListItem *icon;
1530 if(iconlist->num_icons == 0) return;
1531 if(!deactivate_entry(iconlist)) return;
1533 unselect_all(iconlist);
1535 icons = iconlist->icons;
1538 icon = (GtkIconListItem *) icons->data;
1539 pixmap_destroy(GTK_PIXMAP(icon->pixmap));
1540 if(icon->entry && iconlist->mode != GTK_ICON_LIST_ICON){
1541 remove_from_fixed(iconlist, icon->entry);
1545 gtk_widget_hide(icon->pixmap);
1546 remove_from_fixed(iconlist, icon->pixmap);
1547 icon->pixmap = NULL;
1550 g_free(icon->label);
1553 if(icon->entry_label){
1554 g_free(icon->entry_label);
1555 icon->entry_label = NULL;
1561 iconlist->icons = g_list_remove_link(iconlist->icons, icons);
1562 g_list_free_1(icons);
1563 icons = iconlist->icons;
1566 iconlist->icons = NULL;
1567 iconlist->selection = NULL;
1568 iconlist->active_icon = NULL;
1569 iconlist->num_icons = 0;
1573 gtk_icon_list_link(GtkIconListItem *item, gpointer data)
1579 gtk_icon_list_get_link(GtkIconListItem *item)
1585 gtk_icon_list_get_icon_from_link(GtkIconList *iconlist, gpointer data)
1588 GtkIconListItem *item;
1590 icons = iconlist->icons;
1592 item = (GtkIconListItem *) icons->data;
1593 if(data == item->link) return item;
1594 icons = icons->next;
1601 gtk_icon_list_get_entry(GtkIconListItem *item)
1607 gtk_icon_list_get_pixmap(GtkIconListItem *item)
1609 return item->pixmap;
1613 gtk_icon_list_set_pixmap(GtkIconListItem *item,
1618 if(item->pixmap) gtk_widget_destroy(item->pixmap);
1619 item->pixmap = gtk_pixmap_new(pixmap, mask);
1624 gtk_icon_list_set_label(GtkIconList *iconlist, GtkIconListItem *item, const gchar *label)
1627 g_free(item->label);
1630 if(item->entry_label){
1631 g_free(item->entry_label);
1632 item->entry_label = NULL;
1634 if(label) item->label = g_strdup(label);
1635 gtk_entry_set_text(GTK_ENTRY(item->entry), label);
1636 set_labels(iconlist, item, label);
1639 /**********************************
1640 * gtk_icon_list_set_icon_width
1641 * gtk_icon_list_set_row_spacing
1642 * gtk_icon_list_set_col_spacing
1643 * gtk_icon_list_set_text_space
1644 * gtk_icon_list_icon_border
1645 **********************************/
1648 gtk_icon_list_set_icon_width(GtkIconList *iconlist, guint width)
1650 iconlist->icon_width = width;
1651 reorder_icons(iconlist);
1655 gtk_icon_list_set_icon_border(GtkIconList *iconlist, guint border)
1657 iconlist->icon_border = border;
1658 reorder_icons(iconlist);
1662 gtk_icon_list_set_row_spacing(GtkIconList *iconlist, guint spacing)
1664 iconlist->row_spacing = spacing;
1665 reorder_icons(iconlist);
1669 gtk_icon_list_set_col_spacing(GtkIconList *iconlist, guint spacing)
1671 iconlist->col_spacing = spacing;
1672 reorder_icons(iconlist);
1676 /**********************************
1677 * gtk_icon_list_set_selection_mode
1678 * gtk_icon_list_select_icon
1679 * gtk_icon_list_unselect_icon
1680 * gtk_icon_list_unselect_all
1681 **********************************/
1684 gtk_icon_list_set_selection_mode(GtkIconList *iconlist, gint mode)
1686 iconlist->selection_mode = mode;
1690 gtk_icon_list_select_icon(GtkIconList *iconlist, GtkIconListItem *item)
1692 select_icon(iconlist, item, NULL);
1696 gtk_icon_list_unselect_icon(GtkIconList *iconlist, GtkIconListItem *item)
1698 unselect_icon(iconlist, item, NULL);
1702 gtk_icon_list_unselect_all(GtkIconList *iconlist)
1704 unselect_all(iconlist);
1708 gtk_icon_list_set_active_icon(GtkIconList *iconlist, GtkIconListItem *icon)
1711 deactivate_entry(iconlist);
1712 unselect_all(iconlist);
1717 icon->state = GTK_STATE_SELECTED;
1718 entry_in(icon->entry, NULL, iconlist);
1719 gtk_widget_grab_focus(icon->entry);
1725 gtk_icon_list_is_editable (GtkIconList *iconlist)
1727 return (iconlist->is_editable);
1731 gtk_icon_list_get_row_spacing (GtkIconList *iconlist)
1733 return(iconlist->row_spacing);
1737 gtk_icon_list_get_col_spacing (GtkIconList *iconlist)
1739 return(iconlist->col_spacing);
1743 gtk_icon_list_get_text_space (GtkIconList *iconlist)
1745 return(iconlist->text_space);
1749 gtk_icon_list_get_icon_border (GtkIconList *iconlist)
1751 return(iconlist->icon_border);
1755 gtk_icon_list_get_icon_width (GtkIconList *iconlist)
1757 return(iconlist->icon_width);