248f1a6696db8852a4a2d5202762e76968dd3132
[pspp-builds.git] / lib / gtksheet / gtkiconlist.c
1 /* gtkiconlist - gtkiconlist widget for gtk+
2  * Copyright 1999-2001  Adrian E. Feiguin <feiguin@ifir.edu.ar>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 #include <config.h>
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <gtk/gtk.h>
26 #include <gdk/gdkkeysyms.h>
27 #include <pango/pango.h>
28 #include "gtkitementry.h"
29 #include "gtkiconlist.h"
30 #include "gtkextra-marshal.h"
31 #include <math.h>
32
33 #define DEFAULT_ROW_SPACING     4
34 #define DEFAULT_COL_SPACING     10      
35 #define DEFAULT_TEXT_SPACE      60
36 #define DEFAULT_ICON_BORDER     2
37 #define DEFAULT_WIDTH 150
38 #define DEFAULT_HEIGHT 120
39
40 #define EVENTS_MASK    (GDK_EXPOSURE_MASK |             \
41                        GDK_POINTER_MOTION_MASK |        \
42                        GDK_POINTER_MOTION_HINT_MASK |   \
43                        GDK_BUTTON_PRESS_MASK |          \
44                        GDK_BUTTON_RELEASE_MASK)
45
46 /* Signals */
47
48 extern void 
49 _gtkextra_signal_emit(GtkObject *object, guint signal_id, ...);
50
51 enum{
52       SELECT_ICON,                       
53       UNSELECT_ICON,                       
54       TEXT_CHANGED,                       
55       ACTIVATE_ICON,                       
56       DEACTIVATE_ICON,                       
57       CLICK_EVENT,                       
58       LAST_SIGNAL,
59 };
60
61 static guint signals[LAST_SIGNAL] = {0};
62
63 static void gtk_icon_list_class_init            (GtkIconListClass *class);
64 static void gtk_icon_list_init                  (GtkIconList *icon_list);
65 static void gtk_icon_list_destroy               (GtkObject *object);
66 static void gtk_icon_list_finalize              (GObject *object);
67
68 static void gtk_icon_list_size_allocate         (GtkWidget *widget,
69                                                  GtkAllocation *allocation);
70
71 static void gtk_icon_list_realize               (GtkWidget *widget);
72 static gint gtk_icon_list_expose                (GtkWidget *widget, 
73                                                  GdkEventExpose *event);
74 static gint gtk_icon_list_button_press          (GtkWidget *widget, 
75                                                  GdkEventButton *event);
76 static gint deactivate_entry                    (GtkIconList *iconlist);
77 static gint entry_in                            (GtkWidget *widget,
78                                                  GdkEventButton *event,
79                                                  gpointer data);
80 static gint entry_changed                       (GtkWidget *widget, 
81                                                  gpointer data);
82 static void select_icon                         (GtkIconList *iconlist, 
83                                                  GtkIconListItem *item,
84                                                  GdkEvent *event);
85 static void unselect_icon                       (GtkIconList *iconlist, 
86                                                  GtkIconListItem *item,
87                                                  GdkEvent *event);
88 static void unselect_all                        (GtkIconList *iconlist); 
89 static void set_labels                          (GtkIconList *iconlist, 
90                                                  GtkIconListItem *item, 
91                                                  const gchar *label); 
92 static GtkIconListItem *get_icon_from_entry     (GtkIconList *iconlist, 
93                                                  GtkWidget *widget);
94 static void reorder_icons                       (GtkIconList *iconlist);
95 static void item_size_request                   (GtkIconList *iconlist, 
96                                                  GtkIconListItem *item,
97                                                  GtkRequisition *requisition);
98 static void gtk_icon_list_move                  (GtkIconList *iconlist, 
99                                                  GtkIconListItem *icon, 
100                                                  guint x, guint y);
101 static GtkIconListItem *gtk_icon_list_real_add  (GtkIconList *iconualist,
102                                                  GdkPixmap *pixmap,
103                                                  GdkBitmap *mask,
104                                                  const gchar *label,
105                                                  gpointer data);
106 static GtkIconListItem *gtk_icon_list_put       (GtkIconList *iconlist, 
107                                                  guint x, guint y, 
108                                                  GdkPixmap *pixmap,
109                                                  GdkBitmap *mask,
110                                                  const gchar *label,
111                                                  gpointer data);
112 static gint icon_key_press                      (GtkWidget *widget, 
113                                                  GdkEventKey *key, 
114                                                  gpointer data);
115 static gint sort_list                           (gpointer a, gpointer b);
116 static void pixmap_destroy                      (GtkPixmap* pixmap);
117
118
119 static GtkFixedClass *parent_class = NULL;
120
121 static inline guint STRING_WIDTH(GtkWidget *widget,
122                                  PangoFontDescription *font, const gchar *text)
123 {
124   PangoRectangle rect;
125   PangoLayout *layout;
126
127   layout = gtk_widget_create_pango_layout (widget, text);
128   pango_layout_set_font_description (layout, font);
129
130   pango_layout_get_pixel_extents (layout, NULL, &rect);
131
132   g_object_unref(G_OBJECT(layout));
133   return rect.width;
134 }
135
136
137 GtkType
138 gtk_icon_list_get_type (void)
139 {
140   static GtkType icon_list_type = 0;
141
142   if (!icon_list_type)
143     {
144       static const GtkTypeInfo icon_list_info =
145       {
146         "GtkIconList",
147         sizeof (GtkIconList),
148         sizeof (GtkIconListClass),
149         (GtkClassInitFunc) gtk_icon_list_class_init,
150         (GtkObjectInitFunc) gtk_icon_list_init,
151         /* reserved 1*/ NULL,
152         /* reserved 2 */ NULL,
153         (GtkClassInitFunc) NULL,
154       };
155
156       icon_list_type = gtk_type_unique (GTK_TYPE_FIXED, &icon_list_info);
157     }
158   return icon_list_type;
159 }
160
161 static GtkIconListItem*
162 gtk_icon_list_item_copy (const GtkIconListItem *item)
163 {
164   GtkIconListItem *new_item;
165
166   g_return_val_if_fail (item != NULL, NULL);
167
168   new_item = g_new (GtkIconListItem, 1);
169
170   *new_item = *item;
171
172   return new_item;
173 }
174
175 static void
176 gtk_icon_list_item_free (GtkIconListItem *item)
177 {
178   g_return_if_fail (item != NULL);
179
180   g_free (item);
181 }
182
183
184 GType
185 gtk_icon_list_item_get_type (void)
186 {
187   static GType icon_list_item_type;
188
189   if(!icon_list_item_type)
190   {
191     icon_list_item_type = g_boxed_type_register_static("GtkIconListItem", (GBoxedCopyFunc)gtk_icon_list_item_copy, (GBoxedFreeFunc)gtk_icon_list_item_free);
192   }
193   return icon_list_item_type;
194 }
195  
196
197 static void
198 gtk_icon_list_class_init (GtkIconListClass *klass)
199 {
200   GtkObjectClass *object_class;
201   GObjectClass *gobject_class;
202   GtkWidgetClass *widget_class;
203
204   parent_class = gtk_type_class (GTK_TYPE_FIXED);
205
206   object_class = (GtkObjectClass *) klass;
207   gobject_class = (GObjectClass *) klass;
208   widget_class = (GtkWidgetClass *) klass;
209
210   object_class->destroy = gtk_icon_list_destroy;
211   gobject_class->finalize = gtk_icon_list_finalize;
212
213   widget_class->realize = gtk_icon_list_realize;
214
215   widget_class->size_allocate = gtk_icon_list_size_allocate;
216
217   widget_class->expose_event = gtk_icon_list_expose;
218   widget_class->button_press_event = gtk_icon_list_button_press;
219
220   signals[SELECT_ICON] =
221       gtk_signal_new("select_icon",
222                      GTK_RUN_LAST,
223                      GTK_CLASS_TYPE(object_class),
224                      GTK_SIGNAL_OFFSET(GtkIconListClass, select_icon),
225                      gtkextra_BOOLEAN__BOXED_BOXED,
226                      GTK_TYPE_BOOL, 2,
227                      GTK_TYPE_ICON_LIST_ITEM, GDK_TYPE_EVENT); 
228
229   signals[UNSELECT_ICON] =
230       gtk_signal_new("unselect_icon",
231                      GTK_RUN_FIRST,
232                      GTK_CLASS_TYPE(object_class),
233                      GTK_SIGNAL_OFFSET(GtkIconListClass, unselect_icon),
234                      gtkextra_VOID__BOXED_BOXED,
235                      GTK_TYPE_NONE, 2,
236                      GTK_TYPE_ICON_LIST_ITEM, GDK_TYPE_EVENT); 
237
238   signals[TEXT_CHANGED] =
239       gtk_signal_new("text_changed",
240                      GTK_RUN_LAST,
241                      GTK_CLASS_TYPE(object_class),
242                      GTK_SIGNAL_OFFSET(GtkIconListClass, text_changed),
243                      gtkextra_BOOLEAN__BOXED_STRING,
244                      GTK_TYPE_BOOL, 2,
245                      GTK_TYPE_ICON_LIST_ITEM, GTK_TYPE_STRING); 
246
247   signals[ACTIVATE_ICON] =
248       gtk_signal_new("activate_icon",
249                      GTK_RUN_LAST,
250                      GTK_CLASS_TYPE(object_class),
251                      GTK_SIGNAL_OFFSET(GtkIconListClass, activate_icon),
252                      gtkextra_BOOLEAN__BOXED,
253                      GTK_TYPE_BOOL, 1,
254                      GTK_TYPE_ICON_LIST_ITEM); 
255
256   signals[DEACTIVATE_ICON] =
257       gtk_signal_new("deactivate_icon",
258                      GTK_RUN_LAST,
259                      GTK_CLASS_TYPE(object_class),
260                      GTK_SIGNAL_OFFSET(GtkIconListClass, deactivate_icon),
261                      gtkextra_BOOLEAN__BOXED,
262                      GTK_TYPE_BOOL, 1,
263                      GTK_TYPE_ICON_LIST_ITEM); 
264
265   signals[CLICK_EVENT] =
266       gtk_signal_new("click_event",
267                      GTK_RUN_LAST,
268                      GTK_CLASS_TYPE(object_class),
269                      GTK_SIGNAL_OFFSET(GtkIconListClass, click_event),
270                      gtkextra_VOID__BOXED,
271                      GTK_TYPE_NONE, 1,
272                      GDK_TYPE_EVENT); 
273  
274 }
275
276 void
277 gtk_icon_list_freeze(GtkIconList *iconlist)
278 {
279  iconlist->freeze_count++;
280 }
281
282 void
283 gtk_icon_list_thaw(GtkIconList *iconlist)
284 {
285  if(iconlist->freeze_count == 0) return;
286  iconlist->freeze_count--;
287  if(iconlist->freeze_count == 0)
288                reorder_icons(iconlist);
289 }
290
291 void
292 gtk_icon_list_update(GtkIconList *iconlist)
293 {
294   reorder_icons(iconlist);
295 }
296
297 static void
298 reorder_icons(GtkIconList *iconlist)
299 {
300   GtkWidget *widget;
301   GtkIconListItem *item;
302   GtkRequisition req;
303   GList *icons;
304   gint hspace = 0;
305   gint vspace = 0;
306   gint x = 0;
307   gint y = 0;
308   gint old_width, old_height;
309
310   widget = GTK_WIDGET(iconlist);
311
312   if(iconlist->freeze_count > 0) return;
313
314 /*
315   gdk_threads_enter();
316 */
317
318   old_width = widget->allocation.width;
319   old_height = widget->allocation.height;
320   if(GTK_WIDGET_REALIZED(widget)){
321     if(GTK_IS_VIEWPORT(widget->parent))
322      gdk_window_get_size(GTK_VIEWPORT(widget->parent)->view_window, &old_width, &old_height);
323   }
324
325   y = iconlist->row_spacing;
326   x = iconlist->col_spacing;
327
328   icons = iconlist->icons;
329   while(icons){
330     item = (GtkIconListItem *) icons->data;
331
332     gtk_icon_list_move(iconlist, item, x, y);
333
334     item_size_request(iconlist, item, &req);
335  
336     vspace = req.height + iconlist->row_spacing;
337     hspace = req.width + iconlist->col_spacing;
338
339     switch(iconlist->mode){
340       case GTK_ICON_LIST_TEXT_RIGHT:
341         y += vspace;
342         if(y + vspace >= old_height - DEFAULT_COL_SPACING){
343                 x += hspace;
344                 y = iconlist->row_spacing;
345         }
346         break;
347       case GTK_ICON_LIST_TEXT_BELOW:
348       case GTK_ICON_LIST_ICON:
349       default:
350         x += hspace;
351         if(x + hspace >= old_width - DEFAULT_COL_SPACING){
352                 x = iconlist->col_spacing;
353                 y += vspace;
354         }
355         break;
356     }
357
358     icons = icons->next;
359
360    }
361 /*
362   gdk_threads_leave();
363 */
364 }
365
366
367 static void
368 gtk_icon_list_move(GtkIconList *iconlist, GtkIconListItem *icon, 
369                    guint x, guint y)
370 {
371   GtkRequisition req1, req2;
372   GtkRequisition req;
373   GtkAllocation a;
374   const gchar *text;
375   gint old_width, old_height, width, height;
376   gint old_x, old_y;
377   gint size;
378
379   old_x = icon->x;
380   old_y = icon->y;
381
382   icon->x = x;
383   icon->y = y;
384
385   if(x == old_x && y == old_y) return;
386
387   item_size_request(iconlist, icon, &req);
388   req1 = icon->pixmap->requisition;
389   req2 = icon->entry->requisition;
390   req2.width = iconlist->text_space;
391
392   req1.width += 2*iconlist->icon_border;
393   req1.height += 2*iconlist->icon_border;
394   if(iconlist->mode == GTK_ICON_LIST_TEXT_BELOW){
395      req1.width = MAX(req1.width, req.width);
396   }
397
398   if(iconlist->mode == GTK_ICON_LIST_ICON) 
399           req2.width = req2.height = 0;
400
401   old_width = width = GTK_WIDGET(iconlist)->allocation.width;
402   old_height = height = GTK_WIDGET(iconlist)->allocation.height;
403
404   gtk_fixed_move(GTK_FIXED(iconlist), icon->pixmap, 
405                  x + req1.width/2 - icon->pixmap->requisition.width/2, 
406                  y + iconlist->icon_border);
407
408   icon->pixmap->allocation.x += (x - old_x);
409   icon->pixmap->allocation.y += (y - old_y);
410   icon->entry->allocation.x += (x - old_x);
411   icon->entry->allocation.y += (y - old_y);
412   icon->entry->allocation.width = req2.width;
413
414
415   switch(iconlist->mode){
416    case GTK_ICON_LIST_TEXT_BELOW:
417         text = gtk_entry_get_text(GTK_ENTRY(icon->entry));
418         size = STRING_WIDTH(icon->entry, icon->entry->style->font_desc, text);
419         size = MIN(size, req2.width);
420
421         gtk_fixed_move(GTK_FIXED(iconlist), icon->entry, 
422                         x - req2.width/2 + req1.width/2, 
423                         y + req1.height + iconlist->icon_border);
424
425         if(y + req.height > height) 
426            height += req.height;
427         break;
428    case GTK_ICON_LIST_TEXT_RIGHT:
429         gtk_fixed_move(GTK_FIXED(iconlist), icon->entry, 
430                         x + req1.width + iconlist->icon_border, 
431                         y + req1.height/2 - req2.height/2); 
432
433         if(x + req.width > width) 
434             width += req.width;
435         break;
436    case GTK_ICON_LIST_ICON:
437    default: ;
438   }
439
440   a = icon->entry->allocation;
441
442   gtk_widget_size_allocate(icon->pixmap, &icon->pixmap->allocation);
443   if(icon->entry){
444     gtk_widget_size_allocate(icon->entry, &a);
445     gtk_widget_draw(icon->entry, NULL);
446   }
447
448 }
449
450
451 static void
452 gtk_icon_list_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
453 {
454   GtkAllocation *old = gtk_object_get_data(GTK_OBJECT(widget),"viewport");
455   GTK_WIDGET_CLASS(parent_class)->size_allocate(widget, allocation);
456   if(GTK_WIDGET_REALIZED(widget) && old){
457     gint new_width, new_height;
458     gdk_window_get_size(GTK_VIEWPORT(widget->parent)->view_window, &new_width, &new_height);
459     if(old->width != new_width || old->height != new_height)
460       reorder_icons(GTK_ICON_LIST(widget));
461     old->width = new_width; 
462     old->height = new_height; 
463   }
464 }
465
466
467 static void
468 gtk_icon_list_realize(GtkWidget *widget)
469 {
470   GList *icons;
471   GtkIconList *iconlist;
472   GtkIconListItem *item;
473   GtkStyle *style;
474   
475   GTK_WIDGET_CLASS(parent_class)->realize (widget);
476
477   iconlist = GTK_ICON_LIST(widget);
478
479   style = gtk_style_copy(widget->style);
480
481   style->bg[0] = iconlist->background;
482   gtk_widget_set_style(widget, style);
483   gtk_style_set_background(style, widget->window, GTK_STATE_NORMAL);
484   gtk_style_set_background(style, widget->window, GTK_STATE_ACTIVE);
485
486   icons = iconlist->icons;
487   while(icons){
488     item = (GtkIconListItem *) icons->data;
489     gtk_widget_draw(item->pixmap, NULL);
490     if(iconlist->mode != GTK_ICON_LIST_ICON){
491       GtkStyle *style;
492
493       gtk_widget_realize(item->entry);
494
495       style = gtk_style_copy(item->entry->style);
496       style->bg[GTK_STATE_ACTIVE] = iconlist->background;
497       style->bg[GTK_STATE_NORMAL] = iconlist->background;
498       gtk_widget_set_style(item->entry, style);
499       gtk_widget_show(item->entry);
500     }
501     if(item->entry) gtk_widget_draw(item->entry, NULL);
502     icons = icons->next;
503   }
504
505 /*  
506   if(GTK_IS_VIEWPORT(widget->parent) && GTK_WIDGET_REALIZED(widget->parent)){
507     GtkAllocation *allocation = gtk_object_get_data(GTK_OBJECT(widget),"viewport");
508     gdk_window_get_size(GTK_VIEWPORT(widget->parent)->view_window, &allocation->width, &allocation->height);
509   }
510   reorder_icons(iconlist);
511 */
512 }
513
514
515 static void
516 gtk_icon_list_init (GtkIconList *icon_list)
517 {
518   GtkWidget *widget;
519   widget = GTK_WIDGET(icon_list);
520
521   gtk_widget_ensure_style(widget);
522   gdk_color_black(gtk_widget_get_colormap(widget), &widget->style->black);
523   gdk_color_white(gtk_widget_get_colormap(widget), &widget->style->white);
524
525   gtk_fixed_set_has_window(GTK_FIXED(widget), TRUE);
526
527   gtk_widget_set_events (widget, gtk_widget_get_events(widget)|
528                          EVENTS_MASK);
529
530   icon_list->selection = NULL;
531   icon_list->is_editable = TRUE;
532
533   icon_list->num_icons = 0;
534   icon_list->background = widget->style->white;
535
536   icon_list->row_spacing = DEFAULT_ROW_SPACING;
537   icon_list->col_spacing = DEFAULT_COL_SPACING;
538   icon_list->text_space = DEFAULT_TEXT_SPACE;
539   icon_list->icon_border = DEFAULT_ICON_BORDER;
540
541   icon_list->active_icon = NULL;
542   icon_list->compare_func = (GCompareFunc)sort_list;
543 }
544
545 static gint 
546 sort_list(gpointer a, gpointer b)
547 {
548   GtkIconListItem *itema;
549   GtkIconListItem *itemb;
550
551   itema = (GtkIconListItem *)a;
552   itemb = (GtkIconListItem *)b;
553
554   return (strcmp(itema->label, itemb->label));
555 }
556
557 static gboolean
558 gtk_icon_list_expose (GtkWidget *widget, GdkEventExpose *event)
559 {
560   GtkIconList *icon_list;
561
562   icon_list = GTK_ICON_LIST(widget);
563
564   if(!GTK_WIDGET_DRAWABLE(widget)) return FALSE;
565
566   gtk_paint_flat_box (widget->style, widget->window, GTK_STATE_NORMAL,
567                       GTK_SHADOW_NONE, &event->area, widget, "base", 0, 0, -1, -1);
568
569   GTK_WIDGET_CLASS(parent_class)->expose_event(widget, event);
570
571   if(icon_list->active_icon && icon_list->active_icon->entry){
572         gdk_draw_rectangle(widget->window,
573                            widget->style->black_gc,
574                            FALSE,
575                            icon_list->active_icon->entry->allocation.x-2,
576                            icon_list->active_icon->entry->allocation.y-2,
577                            icon_list->active_icon->entry->allocation.width+4,
578                            icon_list->active_icon->entry->allocation.height+4);
579   }
580
581   return FALSE;
582 }
583
584 static gint
585 gtk_icon_list_button_press(GtkWidget *widget, GdkEventButton *event)
586 {
587   GtkIconList *iconlist;
588   GtkIconListItem *item;
589   gint x, y;
590   GtkAllocation *allocation;
591
592   if(!GTK_IS_ICON_LIST(widget)) return FALSE;
593
594   iconlist = GTK_ICON_LIST(widget);
595
596
597   gtk_widget_get_pointer(widget, &x, &y);
598   item = gtk_icon_list_get_icon_at(iconlist, x , y );
599
600   if(!item){ 
601      gtk_signal_emit(GTK_OBJECT(iconlist), signals[CLICK_EVENT],
602                      event);
603      return FALSE;
604   }
605
606   if(item->entry){
607     allocation = &item->entry->allocation;
608     if(x >= allocation->x &&
609        x <= allocation->x + allocation->width &&
610        y >= allocation->y &&
611        y <= allocation->y + allocation->height) return FALSE;
612   }
613
614   if(item)
615    switch(iconlist->selection_mode){
616      case GTK_SELECTION_SINGLE:
617      case GTK_SELECTION_BROWSE:
618         unselect_all(iconlist);
619      case GTK_SELECTION_MULTIPLE:
620         select_icon(iconlist, item, (GdkEvent *)event);
621      case GTK_SELECTION_NONE:
622         break;
623    }
624
625   return FALSE;
626 }
627
628
629 static gint 
630 deactivate_entry(GtkIconList *iconlist)
631 {
632   GdkGC *gc;
633   GtkEntry *entry;
634   gboolean veto = TRUE;
635
636   if(iconlist->active_icon) {
637      _gtkextra_signal_emit(GTK_OBJECT(iconlist), signals[DEACTIVATE_ICON], 
638                      iconlist->active_icon, &veto);
639      if(!veto) return FALSE;
640
641      entry = GTK_ENTRY(iconlist->active_icon->entry);
642
643      if(!entry || !GTK_WIDGET_REALIZED(entry)) return TRUE;
644      gtk_entry_set_editable(entry, FALSE);    
645      gtk_entry_select_region(entry, 0, 0);
646      gtk_item_entry_set_cursor_visible(GTK_ITEM_ENTRY(entry), FALSE);
647
648      switch(iconlist->mode){
649        case GTK_ICON_LIST_TEXT_RIGHT:
650          gtk_item_entry_set_text(GTK_ITEM_ENTRY(entry), 
651                                  iconlist->active_icon->entry_label,
652                                  GTK_JUSTIFY_LEFT);
653          break;
654        case GTK_ICON_LIST_TEXT_BELOW:
655          gtk_item_entry_set_text(GTK_ITEM_ENTRY(entry), 
656                                  iconlist->active_icon->entry_label,
657                                  GTK_JUSTIFY_CENTER);
658          break;
659        case GTK_ICON_LIST_ICON:
660        default:
661          break;
662      }
663
664      if(GTK_WIDGET_REALIZED(iconlist->active_icon->entry)){
665        gc = gdk_gc_new(GTK_WIDGET(iconlist)->window);
666        gdk_gc_set_foreground(gc, &iconlist->background);
667        gdk_draw_rectangle(GTK_WIDGET(iconlist)->window,
668                           gc,
669                           FALSE,
670                           GTK_WIDGET(entry)->allocation.x-2,
671                           GTK_WIDGET(entry)->allocation.y-2,
672                           GTK_WIDGET(entry)->allocation.width+4,
673                           GTK_WIDGET(entry)->allocation.height+4);
674        gdk_gc_unref(gc);
675      }
676
677      iconlist->active_icon->state = GTK_STATE_NORMAL;
678      iconlist->active_icon = NULL;
679   }
680
681   return TRUE;
682 }
683
684
685 static void
686 select_icon(GtkIconList *iconlist, GtkIconListItem *item, GdkEvent *event)
687 {
688   gboolean veto = TRUE;
689
690   if(item == NULL) return;
691
692   _gtkextra_signal_emit(GTK_OBJECT(iconlist), signals[SELECT_ICON], item, 
693                   event, &veto);                        
694
695   if(!veto) return;
696
697   if(iconlist->mode != GTK_ICON_LIST_ICON){ 
698     if(!deactivate_entry(iconlist)) return;
699
700     if(item->entry && GTK_WIDGET_REALIZED(item->entry)){
701       GtkStyle *style = gtk_style_copy(item->entry->style);
702       style->bg[GTK_STATE_ACTIVE] = style->base[GTK_STATE_SELECTED];
703       style->bg[GTK_STATE_NORMAL] = style->base[GTK_STATE_SELECTED];
704       style->text[GTK_STATE_ACTIVE] = style->text[GTK_STATE_SELECTED];
705       style->text[GTK_STATE_NORMAL] = style->text[GTK_STATE_SELECTED];
706       gtk_widget_set_style(item->entry, style);
707       gtk_style_unref(style);
708
709       switch(iconlist->mode){
710         case GTK_ICON_LIST_TEXT_RIGHT:
711           gtk_item_entry_set_text(GTK_ITEM_ENTRY(item->entry), 
712                                   item->label,
713                                   GTK_JUSTIFY_LEFT);
714           break;
715         case GTK_ICON_LIST_TEXT_BELOW:
716           gtk_item_entry_set_text(GTK_ITEM_ENTRY(item->entry), 
717                                   item->label,
718                                   GTK_JUSTIFY_CENTER);
719           break;
720         case GTK_ICON_LIST_ICON:
721         default:
722           break;
723       }
724     }
725   }
726   if(item->state == GTK_STATE_SELECTED) return;
727   iconlist->selection = g_list_append(iconlist->selection, item);
728
729   item->state = GTK_STATE_SELECTED;  
730   if(item->entry) gtk_widget_grab_focus(item->entry);
731 }
732
733 static void
734 unselect_icon(GtkIconList *iconlist, GtkIconListItem *item, GdkEvent *event)
735 {
736   GList *selection;
737   GtkIconListItem *icon;
738
739   if(!item) return;
740
741   if(item->state == GTK_STATE_NORMAL) return;
742
743   selection = iconlist->selection;
744   while(selection){
745     icon = (GtkIconListItem *)selection->data; 
746     if(item == icon) break;
747     selection = selection->next;
748   }
749
750   if(selection){
751        iconlist->selection = g_list_remove_link(iconlist->selection, selection);
752   }
753  
754   item->state = GTK_STATE_NORMAL;
755
756   if(iconlist->mode != GTK_ICON_LIST_ICON){
757    if(item->entry && GTK_WIDGET_REALIZED(item->entry)){
758      GtkStyle *style = gtk_style_copy(item->entry->style);
759
760      style->bg[GTK_STATE_ACTIVE] = iconlist->background;
761      style->bg[GTK_STATE_NORMAL] = iconlist->background;
762      style->text[GTK_STATE_ACTIVE] = GTK_WIDGET(iconlist)->style->text[GTK_STATE_ACTIVE];
763      style->text[GTK_STATE_NORMAL] = GTK_WIDGET(iconlist)->style->text[GTK_STATE_NORMAL];
764      gtk_widget_set_style(item->entry, style);
765      gtk_style_unref(style);
766
767      gtk_entry_select_region(GTK_ENTRY(item->entry), 0, 0);
768      gtk_entry_set_text(GTK_ENTRY(item->entry), item->entry_label);
769      gtk_entry_set_editable(GTK_ENTRY(item->entry), FALSE);
770      gtk_widget_draw(item->entry, NULL);
771
772    }
773   }
774
775   gtk_signal_emit(GTK_OBJECT(iconlist), signals[UNSELECT_ICON], item, event);                        
776 }
777
778 static void
779 unselect_all(GtkIconList *iconlist)
780 {
781   GList *selection;
782   GtkIconListItem *item;
783
784   selection = iconlist->selection;
785   while(selection){
786     item = (GtkIconListItem *)selection->data;
787     unselect_icon(iconlist, item, NULL);
788     selection = iconlist->selection;
789   }
790
791   g_list_free(iconlist->selection);
792   iconlist->selection = NULL;
793 }
794
795 GtkWidget*
796 gtk_icon_list_new (guint icon_width, GtkIconListMode mode)
797 {
798   GtkIconList *icon_list;
799   GtkAllocation *allocation;
800
801   icon_list = gtk_type_new (gtk_icon_list_get_type ());
802
803   gtk_icon_list_construct(icon_list, icon_width, mode);
804   allocation = g_new0(GtkAllocation, 1);
805   gtk_object_set_data(GTK_OBJECT(icon_list), "viewport", allocation);
806
807   return GTK_WIDGET (icon_list);
808 }
809
810 void
811 gtk_icon_list_construct (GtkIconList *icon_list, guint icon_width, GtkIconListMode mode)
812 {
813   icon_list->icon_width = icon_width;
814   icon_list->mode = mode;
815   icon_list->icons = NULL;
816   icon_list->selection = NULL;
817   icon_list->selection_mode = GTK_SELECTION_SINGLE;
818 }
819
820 void
821 gtk_icon_list_set_mode (GtkIconList *iconlist, GtkIconListMode mode)
822 {
823   GList *icons;
824
825   iconlist->mode = mode;
826
827   icons = iconlist->icons;
828   while(icons){
829     GtkIconListItem *item;
830
831     item = (GtkIconListItem *)icons->data;
832
833     switch(mode){
834       case GTK_ICON_LIST_TEXT_RIGHT:
835         gtk_item_entry_set_justification(GTK_ITEM_ENTRY(item->entry), 
836                                          GTK_JUSTIFY_LEFT);
837         break;
838       case GTK_ICON_LIST_TEXT_BELOW:
839         gtk_item_entry_set_justification(GTK_ITEM_ENTRY(item->entry), 
840                                          GTK_JUSTIFY_CENTER);
841         break;
842       case GTK_ICON_LIST_ICON:
843       default:
844         break;
845     }
846     
847     icons = icons->next;
848   }
849  
850   reorder_icons(iconlist); 
851 }
852
853 GtkIconListMode
854 gtk_icon_list_get_mode (GtkIconList *iconlist)
855 {
856   return(iconlist->mode);
857 }
858
859 void
860 gtk_icon_list_set_text_space (GtkIconList *iconlist, guint text_space)
861 {
862   GList *icons;
863
864   iconlist->text_space = text_space;
865
866   icons = iconlist->icons;
867   while(icons){
868     GtkIconListItem *item;
869
870     item = (GtkIconListItem *)icons->data;
871     
872     if(item->entry) GTK_ITEM_ENTRY(item->entry)->text_max_size = text_space;
873     
874     icons = icons->next;
875   }
876  
877   reorder_icons(iconlist); 
878 }
879
880
881 static void
882 gtk_icon_list_destroy (GtkObject *object)
883 {
884   GtkIconList *icon_list;
885
886   g_return_if_fail (object != NULL);
887   g_return_if_fail (GTK_IS_ICON_LIST (object));
888
889   icon_list = GTK_ICON_LIST (object);
890
891   gtk_icon_list_clear(icon_list);
892
893   if (GTK_OBJECT_CLASS (parent_class)->destroy)
894     (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
895 }
896
897 static void
898 gtk_icon_list_finalize (GObject *object)
899 {
900   GtkIconList *icon_list;
901   GtkAllocation *allocation;
902
903   icon_list = GTK_ICON_LIST (object);
904
905   allocation = gtk_object_get_data(GTK_OBJECT(icon_list), "viewport");
906   if(allocation) g_free(allocation);
907   gtk_object_set_data(GTK_OBJECT(icon_list), "viewport", NULL);
908
909   if (G_OBJECT_CLASS (parent_class)->finalize)
910     (*G_OBJECT_CLASS (parent_class)->finalize) (object);
911 }
912
913 void
914 gtk_icon_list_set_background (GtkIconList *iconlist, GdkColor *color)
915 {
916   GtkWidget *widget;
917   GtkStyle *style;
918   
919   g_return_if_fail (iconlist != NULL);
920   g_return_if_fail (GTK_IS_ICON_LIST (iconlist));
921
922   widget = GTK_WIDGET(iconlist);
923
924   iconlist->background = *color;
925
926   style = gtk_style_copy(widget->style);
927   style->bg[0] = iconlist->background;
928
929   gtk_widget_set_style(widget, style);
930   if(widget->window) gdk_window_set_background(widget->window, color);
931   gtk_style_unref(style);
932
933 }
934
935 static gint
936 entry_changed (GtkWidget *widget, gpointer data)
937 {
938   GtkIconList *iconlist;
939   GtkIconListItem *item;
940   gboolean veto = TRUE;
941   const gchar *text;
942
943   iconlist = GTK_ICON_LIST(data);
944   item = get_icon_from_entry(iconlist, widget);
945   text = gtk_entry_get_text(GTK_ENTRY(widget));
946
947   _gtkextra_signal_emit(GTK_OBJECT(data), signals[TEXT_CHANGED],
948                   item, text, &veto);
949
950   if(!veto) return veto; 
951
952   if(item->entry && gtk_editable_get_editable(GTK_EDITABLE(item->entry))){
953     if(item->label) g_free(item->label);
954     if(text) item->label = g_strdup(text); 
955     if(item->entry_label) g_free(item->entry_label);
956     set_labels(iconlist, item, text); 
957   }
958
959   return veto;
960
961                   
962 static gint
963 entry_in (GtkWidget *widget, GdkEventButton *event, gpointer data)
964 {
965   GtkIconList *iconlist;
966   GtkIconListItem *item;
967   gboolean veto = TRUE;
968
969   if(!GTK_IS_ENTRY(widget)) return FALSE;
970   iconlist = GTK_ICON_LIST(data);
971
972   item = get_icon_from_entry(iconlist, widget);
973   if(iconlist->active_icon && iconlist->active_icon->entry == widget) 
974           return FALSE;
975
976   _gtkextra_signal_emit(GTK_OBJECT(iconlist), signals[ACTIVATE_ICON], &item, &veto);
977
978   if(!veto) return FALSE; 
979   if(!deactivate_entry(iconlist)) return FALSE;
980
981   if(item->state == GTK_STATE_SELECTED){
982    if(iconlist->is_editable && !gtk_editable_get_editable(GTK_EDITABLE(widget))){
983      unselect_all(iconlist);
984
985      gtk_entry_set_editable(GTK_ENTRY(widget), TRUE);
986      gtk_item_entry_set_cursor_visible(GTK_ITEM_ENTRY(widget), TRUE);
987      if(item->label) gtk_entry_set_text(GTK_ENTRY(widget), item->label);
988      iconlist->active_icon = item;
989      item->state = GTK_STATE_NORMAL;
990
991      if(GTK_WIDGET_DRAWABLE(widget)) 
992        gdk_draw_rectangle(GTK_WIDGET(iconlist)->window,
993                           widget->style->black_gc,
994                           FALSE,
995                           iconlist->active_icon->entry->allocation.x-2,
996                           iconlist->active_icon->entry->allocation.y-2,
997                           iconlist->active_icon->entry->allocation.width+4,
998                           iconlist->active_icon->entry->allocation.height+4);
999    }else{
1000      gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "button_press_event"); 
1001      if(iconlist->selection_mode == GTK_SELECTION_SINGLE ||
1002         iconlist->selection_mode == GTK_SELECTION_BROWSE) 
1003           unselect_all(iconlist);
1004      select_icon(iconlist, item, (GdkEvent *)event);
1005    }
1006   }else{
1007      if(iconlist->selection_mode == GTK_SELECTION_SINGLE ||
1008         iconlist->selection_mode == GTK_SELECTION_BROWSE) 
1009           unselect_all(iconlist);
1010      select_icon(iconlist, item, (GdkEvent *)event);
1011   }
1012
1013   return FALSE;
1014 }
1015
1016 GtkIconListItem *
1017 gtk_icon_list_get_active_icon(GtkIconList *iconlist)
1018 {
1019   return iconlist->active_icon;
1020 }
1021
1022 static GtkIconListItem *
1023 get_icon_from_entry(GtkIconList *iconlist, GtkWidget *widget)
1024 {
1025   GList *icons;
1026   GtkIconListItem *item;
1027
1028   icons = iconlist->icons;
1029   while(icons){
1030     item = (GtkIconListItem *) icons->data;
1031     if(widget == item->entry) return item;
1032     icons = icons->next;
1033   }
1034
1035   return NULL;
1036 }
1037
1038 GtkIconListItem *
1039 gtk_icon_list_get_icon_at(GtkIconList *iconlist, gint x, gint y)
1040 {
1041   GList *icons;
1042   GtkIconListItem *item;
1043   GtkRequisition req;
1044
1045   icons = iconlist->icons;
1046   while(icons){
1047     item = (GtkIconListItem *) icons->data;
1048     item_size_request(iconlist, item, &req);
1049     if(x >= item->x && x <= item->x + req.width &&
1050        y >= item->y && y <= item->y + req.height) return item;
1051     icons = icons->next;
1052   }
1053
1054   return NULL;
1055 }
1056
1057 GtkIconListItem *
1058 gtk_icon_list_add (GtkIconList *iconlist, 
1059                    const gchar *file,
1060                    const gchar *label,
1061                    gpointer link)
1062 {
1063   GtkIconListItem *item;
1064   GdkColormap *colormap;
1065   GdkPixmap *pixmap;
1066   GdkBitmap *mask;
1067
1068   colormap = gdk_colormap_get_system();
1069   pixmap = gdk_pixmap_colormap_create_from_xpm(NULL, colormap, &mask, NULL, 
1070                                                file);
1071   item = gtk_icon_list_real_add(iconlist, pixmap, mask, label, link);
1072   return item;
1073 }
1074
1075 GtkIconListItem *
1076 gtk_icon_list_add_from_data (GtkIconList *iconlist, 
1077                              gchar **data,
1078                              const gchar *label,
1079                              gpointer link)
1080 {
1081   GtkIconListItem *item;
1082   GdkColormap *colormap;
1083   GdkPixmap *pixmap;
1084   GdkBitmap *mask;
1085
1086   colormap = gdk_colormap_get_system();
1087   pixmap = gdk_pixmap_colormap_create_from_xpm_d(NULL, colormap, &mask, NULL, 
1088                                                  data);
1089   item = gtk_icon_list_real_add(iconlist, pixmap, mask, label, link);
1090   return item;
1091 }
1092
1093 GtkIconListItem *
1094 gtk_icon_list_add_from_pixmap (GtkIconList *iconlist, 
1095                                GdkPixmap *pixmap,
1096                                GdkBitmap *mask,
1097                                const gchar *label,
1098                                gpointer link)
1099 {
1100   GtkIconListItem *item;
1101
1102   gdk_pixmap_ref(pixmap);
1103   if(mask) gdk_bitmap_ref(mask);
1104   item = gtk_icon_list_real_add(iconlist, pixmap, mask, label, link);
1105   return item;
1106 }
1107
1108
1109 static GtkIconListItem*
1110 gtk_icon_list_real_add (GtkIconList *iconlist, 
1111                         GdkPixmap *pixmap,
1112                         GdkBitmap *mask,
1113                         const gchar *label,
1114                         gpointer data)
1115 {
1116   GtkIconListItem *item;
1117   GtkRequisition requisition;
1118   gint hspace = 0;
1119   gint vspace = 0;
1120   gint x = 0;
1121   gint y = 0;
1122   gint width, height;
1123
1124   width = GTK_WIDGET(iconlist)->allocation.width;
1125   height = GTK_WIDGET(iconlist)->allocation.height;
1126
1127   if(iconlist->num_icons > 0){
1128     item = gtk_icon_list_get_nth(iconlist, iconlist->num_icons-1);
1129     x = item->x;
1130     y = item->y;
1131     item_size_request(iconlist, item, &requisition);
1132  
1133     vspace = requisition.height + iconlist->row_spacing;
1134     hspace = requisition.width + iconlist->col_spacing;
1135
1136     switch(iconlist->mode){
1137       case GTK_ICON_LIST_TEXT_RIGHT:
1138         y += vspace;
1139         if(y >= height){
1140                 x += hspace;
1141                 y = iconlist->row_spacing;
1142         }
1143         break;
1144       case GTK_ICON_LIST_TEXT_BELOW:
1145       case GTK_ICON_LIST_ICON:
1146       default:
1147         x += hspace;
1148         if(x >= width){
1149                 x = iconlist->col_spacing;
1150                 y += vspace;
1151         }
1152         break;
1153     }
1154   } else {
1155     y = iconlist->row_spacing;
1156     x = iconlist->col_spacing;
1157   }
1158
1159   item = gtk_icon_list_put(iconlist, x, y, pixmap, mask, label, data);
1160   return item;
1161 }
1162
1163 static GtkIconListItem *
1164 gtk_icon_list_put (GtkIconList *iconlist, 
1165                    guint x, guint y, 
1166                    GdkPixmap *pixmap,
1167                    GdkBitmap *mask,
1168                    const gchar *label,
1169                    gpointer data)
1170 {
1171   GtkIconListItem *icon;
1172   GtkIconListItem *active_icon;
1173   GtkWidget *widget;
1174   GtkRequisition req, req1, req2;
1175   gint text_width;
1176   gint width, height, old_width, old_height;
1177   GtkAllocation alloc;
1178
1179   widget = GTK_WIDGET(iconlist);
1180
1181   old_width = width = GTK_WIDGET(iconlist)->allocation.width;
1182   old_height = height = GTK_WIDGET(iconlist)->allocation.height;
1183
1184   active_icon = iconlist->active_icon;
1185   gtk_icon_list_set_active_icon(iconlist, NULL);
1186
1187   icon = g_new(GtkIconListItem, 1);
1188   icon->x = x;
1189   icon->y = y;
1190   icon->state = GTK_STATE_NORMAL;
1191   icon->label = NULL;
1192   icon->entry_label = NULL;
1193   if(label) icon->label = g_strdup(label);
1194   icon->entry = gtk_item_entry_new();
1195   icon->pixmap = gtk_pixmap_new(pixmap, mask);
1196   icon->link = data;
1197
1198   GTK_ITEM_ENTRY(icon->entry)->text_max_size = iconlist->text_space; 
1199   item_size_request(iconlist, icon, &req);
1200   req1 = icon->pixmap->requisition;
1201   req2 = icon->entry->requisition;
1202   req2.width = iconlist->text_space; 
1203
1204   req1.width += 2*iconlist->icon_border;
1205   req1.height += 2*iconlist->icon_border;
1206   if(iconlist->mode == GTK_ICON_LIST_TEXT_BELOW){
1207      req1.width = MAX(req1.width, req.width);
1208   }
1209
1210   if(iconlist->mode == GTK_ICON_LIST_ICON) 
1211           req2.width = req2.height = 0;
1212   else
1213           set_labels(iconlist, icon, label);
1214
1215   text_width = 0;
1216   if(label) text_width = STRING_WIDTH(icon->entry, icon->entry->style->font_desc, label);
1217
1218   gtk_fixed_put(GTK_FIXED(iconlist), icon->pixmap, 
1219                  x + req1.width/2 - icon->pixmap->requisition.width/2, 
1220                  y + iconlist->icon_border);
1221
1222   alloc.x = x + req1.width/2 - icon->pixmap->requisition.width/2; 
1223   alloc.y = y + iconlist->icon_border; 
1224   alloc.width =  req1.width;
1225   alloc.height =  req1.height;
1226   gtk_widget_size_allocate(icon->pixmap, &alloc);
1227
1228   switch(iconlist->mode){
1229    case GTK_ICON_LIST_TEXT_BELOW:
1230         gtk_item_entry_set_text(GTK_ITEM_ENTRY(icon->entry), icon->entry_label, 
1231                                 GTK_JUSTIFY_CENTER);
1232         gtk_fixed_put(GTK_FIXED(iconlist), icon->entry, 
1233                        x - req2.width/2 + req1.width/2, 
1234                        y + req1.height + iconlist->icon_border);
1235         alloc.x = x - req2.width/2 + req1.width/2; 
1236         alloc.y = y + req1.height + iconlist->icon_border;
1237         alloc.width = req2.width;
1238         alloc.height = req2.height;
1239         gtk_widget_size_allocate(icon->entry, &alloc);
1240
1241         if(y + req1.height + iconlist->icon_border + req2.height > height) 
1242            height += req1.height + iconlist->icon_border + req2.height;
1243         break;
1244    case GTK_ICON_LIST_TEXT_RIGHT:
1245         gtk_item_entry_set_text(GTK_ITEM_ENTRY(icon->entry), icon->entry_label, 
1246                                 GTK_JUSTIFY_LEFT);
1247         gtk_fixed_put(GTK_FIXED(iconlist), icon->entry, 
1248                        x + req1.width + iconlist->icon_border, 
1249                        y + req1.height/2 - req2.height/2); 
1250         alloc.x = x + req1.width + iconlist->icon_border; 
1251         alloc.y = y + req1.height/2 - req2.height/2; 
1252         alloc.width = req2.width;
1253         alloc.height = req2.height;
1254         gtk_widget_size_allocate(icon->entry, &alloc);
1255
1256         if(x + req1.width + iconlist->icon_border + text_width > width) 
1257             width += req1.width + iconlist->icon_border + text_width;
1258         break;
1259    case GTK_ICON_LIST_ICON:
1260    default: ;
1261   }
1262
1263   if(GTK_WIDGET_REALIZED(iconlist))
1264     if(iconlist->mode != GTK_ICON_LIST_ICON){
1265       GtkStyle *style = gtk_style_copy(icon->entry->style);
1266       style->bg[GTK_STATE_ACTIVE] = iconlist->background;
1267       style->bg[GTK_STATE_NORMAL] = iconlist->background;
1268       gtk_widget_set_style(icon->entry, style);
1269       gtk_style_unref(style);
1270       gtk_widget_show(icon->entry);
1271     }
1272
1273   gtk_widget_show(icon->pixmap);
1274
1275   if(iconlist->compare_func)
1276     iconlist->icons = g_list_insert_sorted(iconlist->icons, icon, iconlist->compare_func);
1277   else
1278     iconlist->icons = g_list_append(iconlist->icons, icon);
1279
1280   iconlist->num_icons++;
1281
1282   if(GTK_WIDGET_REALIZED(iconlist))
1283                 reorder_icons(iconlist);
1284
1285   gtk_entry_set_editable(GTK_ENTRY(icon->entry), FALSE);
1286
1287   gtk_signal_connect(GTK_OBJECT(icon->entry), "key_press_event",
1288                     (GtkSignalFunc)icon_key_press, iconlist);
1289   gtk_signal_connect(GTK_OBJECT(icon->entry), "button_press_event", 
1290                      (GtkSignalFunc)entry_in, iconlist);
1291   gtk_signal_connect(GTK_OBJECT(icon->entry), "changed", 
1292                      (GtkSignalFunc)entry_changed, iconlist);
1293
1294   gtk_icon_list_set_active_icon(iconlist, active_icon);
1295   return icon;
1296 }
1297
1298 static void 
1299 set_labels(GtkIconList *iconlist, GtkIconListItem *icon, const gchar *label)
1300 {
1301   gint text_width;
1302   gint point_width;
1303   gint max_width;
1304   gchar *entry_label = NULL;
1305   gint n, space;
1306
1307   if(!label) return;
1308
1309   entry_label = (gchar *)g_malloc(strlen(label) + 5);
1310   entry_label[0] = label[0];
1311   entry_label[1] = '\0';
1312
1313   text_width = STRING_WIDTH(icon->entry, icon->entry->style->font_desc, label);
1314   point_width = STRING_WIDTH(icon->entry, icon->entry->style->font_desc, "X");
1315
1316   max_width = iconlist->text_space;
1317
1318   for(n = 0; n < strlen(label); n++){
1319      space = strlen(label) - n + 1;
1320      if(space > 3 && 
1321         STRING_WIDTH(icon->entry, icon->entry->style->font_desc, entry_label) +
1322         3 * point_width > max_width) 
1323                                                    break;
1324      entry_label[n] = label[n];
1325      entry_label[n + 1] = '\0';
1326   }
1327
1328
1329   if(strlen(entry_label) < strlen(label))
1330       sprintf(entry_label,"%s...", entry_label);
1331
1332   icon->entry_label = g_strdup(entry_label);
1333
1334   g_free(entry_label);
1335 }
1336
1337 static gint
1338 icon_key_press(GtkWidget *widget, GdkEventKey *key, gpointer data)
1339 {
1340   GtkIconList *iconlist;
1341
1342   iconlist = GTK_ICON_LIST(data);
1343   if(key->keyval != GDK_Return) return FALSE;
1344
1345   if(iconlist->active_icon)
1346           select_icon(iconlist, iconlist->active_icon, NULL);
1347
1348   return FALSE;
1349 }
1350
1351 static void
1352 item_size_request(GtkIconList *iconlist, 
1353                   GtkIconListItem *item,
1354                   GtkRequisition *requisition)
1355 {
1356   GtkRequisition req2;
1357
1358   gtk_widget_size_request(item->entry, &req2);
1359   req2.width = iconlist->text_space;
1360
1361   gtk_widget_size_request(item->pixmap, requisition);
1362   requisition->width = MAX(iconlist->icon_width, requisition->width);
1363   requisition->width += 2*iconlist->icon_border;
1364   requisition->height += 2*iconlist->icon_border;
1365
1366   switch(iconlist->mode){
1367    case GTK_ICON_LIST_TEXT_BELOW:
1368         requisition->height += req2.height;
1369         requisition->width = MAX(requisition->width, req2.width);
1370         break;
1371    case GTK_ICON_LIST_TEXT_RIGHT:
1372         requisition->width += req2.width;
1373         break;
1374    case GTK_ICON_LIST_ICON:
1375    default: ;
1376   }
1377
1378 }
1379
1380                   
1381 void
1382 gtk_icon_list_set_editable (GtkIconList *iconlist, gboolean editable)
1383 {
1384   GList *icons;
1385   GtkIconListItem *item;
1386   
1387   icons = iconlist->icons;
1388   while(icons){
1389     item = (GtkIconListItem *) icons->data;
1390     gtk_entry_set_editable(GTK_ENTRY(item->entry), editable);
1391     icons = icons->next;
1392   }
1393
1394   iconlist->is_editable = editable;
1395
1396
1397 GtkIconListItem *
1398 gtk_icon_list_get_nth(GtkIconList *iconlist, guint n)
1399 {
1400   return (GtkIconListItem *)g_list_nth_data(iconlist->icons, n);
1401 }
1402
1403 gint
1404 gtk_icon_list_get_index(GtkIconList *iconlist, GtkIconListItem *item)
1405 {
1406   GList *icons;
1407   GtkIconListItem *icon;
1408   gint n = 0;
1409
1410   if(item == NULL) return -1;
1411  
1412   icons = iconlist->icons;
1413   while(icons){
1414     n++;
1415     icon = (GtkIconListItem *) icons->data;
1416     if(item == icon) break;
1417     icons = icons->next;
1418   }
1419
1420   if(icons) return n;
1421
1422   return -1;
1423 }
1424
1425 static void
1426 remove_from_fixed(GtkIconList *iconlist, GtkWidget *widget)
1427 {
1428   GtkFixed *fixed;
1429   GList *children;
1430
1431   fixed = GTK_FIXED(iconlist);
1432   children = fixed->children;
1433   while(children){
1434     GtkFixedChild *child;
1435
1436     child = children->data;
1437
1438     if(child->widget == widget){
1439       gtk_widget_unparent(widget);
1440       fixed->children = g_list_remove_link (fixed->children, children);
1441       g_list_free (children);
1442       g_free (child);
1443
1444       break;
1445     }
1446
1447     children = children->next;
1448   }
1449 }
1450
1451 static void
1452 pixmap_destroy(GtkPixmap* pixmap)
1453 {
1454   /* release pixmap */
1455   if (pixmap){
1456     GdkPixmap* pm = NULL;
1457     GdkBitmap* bm = NULL;
1458
1459     gtk_pixmap_get(pixmap, &pm, &bm);
1460
1461     /* HB: i don't know enough about Gtk+ to call this a design flaw, but it
1462      * appears the pixmaps need to be destroyed by hand ...
1463      */
1464     if (pm) gdk_pixmap_unref(pm);
1465     if (bm) gdk_pixmap_unref(bm);
1466   }
1467 }
1468   
1469 void
1470 gtk_icon_list_remove (GtkIconList *iconlist, GtkIconListItem *item)
1471 {
1472   GList *icons;
1473   GtkIconListItem *icon = 0;
1474
1475   if(item == NULL) return;
1476  
1477   icons = iconlist->icons;
1478   while(icons){
1479     icon = (GtkIconListItem *) icons->data;
1480     if(item == icon) break;
1481     icons = icons->next;
1482   }
1483
1484   if(icons){
1485      if(icon->state == GTK_STATE_SELECTED) unselect_icon(iconlist, icon, NULL);
1486      if(icon == iconlist->active_icon) deactivate_entry(iconlist);
1487      pixmap_destroy(GTK_PIXMAP(icon->pixmap));
1488      if(icon->entry && iconlist->mode != GTK_ICON_LIST_ICON){
1489        remove_from_fixed(iconlist, icon->entry);
1490        icon->entry = NULL;
1491      }
1492      if(icon->pixmap){
1493        remove_from_fixed(iconlist, icon->pixmap);
1494        icon->pixmap = NULL;
1495      }
1496      if(icon->label){
1497         g_free(icon->label);
1498         icon->label = NULL;
1499      }
1500      if(icon->entry_label){
1501         g_free(icon->entry_label);
1502         icon->entry_label = NULL;
1503      }
1504
1505      g_free(icon);
1506      iconlist->icons = g_list_remove_link(iconlist->icons, icons);
1507      g_list_free_1(icons);
1508      iconlist->num_icons--;
1509   }
1510
1511   if(iconlist->num_icons == 0){
1512       iconlist->icons = NULL;
1513       iconlist->selection = NULL;
1514   }
1515 }
1516
1517 void
1518 gtk_icon_list_remove_nth (GtkIconList *iconlist, guint n)
1519 {
1520   GtkIconListItem *item;
1521
1522   item = gtk_icon_list_get_nth(iconlist, n);
1523   gtk_icon_list_remove(iconlist, item);
1524 }
1525
1526 void
1527 gtk_icon_list_clear(GtkIconList *iconlist)
1528 {
1529   GList *icons;
1530   GtkIconListItem *icon;
1531
1532   if(iconlist->num_icons == 0) return;
1533   if(!deactivate_entry(iconlist)) return;
1534
1535   unselect_all(iconlist);
1536
1537   icons = iconlist->icons;
1538
1539   while(icons){
1540     icon = (GtkIconListItem *) icons->data;
1541     pixmap_destroy(GTK_PIXMAP(icon->pixmap));
1542     if(icon->entry && iconlist->mode != GTK_ICON_LIST_ICON){
1543       remove_from_fixed(iconlist, icon->entry);
1544       icon->entry = NULL;
1545     }
1546     if(icon->pixmap){
1547       gtk_widget_hide(icon->pixmap);
1548       remove_from_fixed(iconlist, icon->pixmap);
1549       icon->pixmap = NULL;
1550     }
1551     if(icon->label){
1552         g_free(icon->label);
1553         icon->label = NULL;
1554     }
1555     if(icon->entry_label){
1556         g_free(icon->entry_label);
1557         icon->entry_label = NULL;
1558     }
1559
1560     g_free(icon);
1561     icon = NULL;
1562
1563     iconlist->icons = g_list_remove_link(iconlist->icons, icons);
1564     g_list_free_1(icons);
1565     icons = iconlist->icons;
1566   }
1567
1568   iconlist->icons = NULL;
1569   iconlist->selection = NULL;
1570   iconlist->active_icon = NULL;
1571   iconlist->num_icons = 0;
1572 }    
1573
1574 void
1575 gtk_icon_list_link(GtkIconListItem *item, gpointer data)
1576 {
1577   item->link = data;
1578
1579
1580 gpointer
1581 gtk_icon_list_get_link(GtkIconListItem *item)
1582 {
1583   return item->link;
1584 }
1585
1586 GtkIconListItem *
1587 gtk_icon_list_get_icon_from_link(GtkIconList *iconlist, gpointer data)
1588 {
1589   GList *icons;
1590   GtkIconListItem *item;
1591
1592   icons = iconlist->icons;
1593   while(icons){
1594     item = (GtkIconListItem *) icons->data;
1595     if(data == item->link) return item;
1596     icons = icons->next;
1597   }
1598
1599   return NULL;
1600 }
1601
1602 GtkWidget *
1603 gtk_icon_list_get_entry(GtkIconListItem *item)
1604 {
1605   return item->entry;
1606 }
1607
1608 GtkWidget *
1609 gtk_icon_list_get_pixmap(GtkIconListItem *item)
1610 {
1611   return item->pixmap;
1612 }
1613
1614 void
1615 gtk_icon_list_set_pixmap(GtkIconListItem *item, 
1616                          GdkPixmap *pixmap, 
1617                          GdkBitmap *mask)
1618 {
1619
1620   if(item->pixmap) gtk_widget_destroy(item->pixmap);  
1621   item->pixmap = gtk_pixmap_new(pixmap, mask);
1622
1623 }
1624
1625 void 
1626 gtk_icon_list_set_label(GtkIconList *iconlist, GtkIconListItem *item, const gchar *label)
1627 {
1628   if(item->label){
1629       g_free(item->label);
1630       item->label = NULL;
1631   }
1632   if(item->entry_label){
1633       g_free(item->entry_label);
1634       item->entry_label = NULL;
1635   }
1636   if(label) item->label = g_strdup(label);
1637   gtk_entry_set_text(GTK_ENTRY(item->entry), label);
1638   set_labels(iconlist, item, label);
1639 }
1640  
1641 /**********************************
1642  * gtk_icon_list_set_icon_width
1643  * gtk_icon_list_set_row_spacing
1644  * gtk_icon_list_set_col_spacing
1645  * gtk_icon_list_set_text_space
1646  * gtk_icon_list_icon_border
1647  **********************************/
1648
1649 void
1650 gtk_icon_list_set_icon_width(GtkIconList *iconlist, guint width)
1651 {
1652   iconlist->icon_width = width;
1653   reorder_icons(iconlist);
1654 }
1655
1656 void
1657 gtk_icon_list_set_icon_border(GtkIconList *iconlist, guint border)
1658 {
1659   iconlist->icon_border = border;
1660   reorder_icons(iconlist);
1661 }
1662
1663 void
1664 gtk_icon_list_set_row_spacing(GtkIconList *iconlist, guint spacing)
1665 {
1666   iconlist->row_spacing = spacing;
1667   reorder_icons(iconlist);
1668 }
1669
1670 void
1671 gtk_icon_list_set_col_spacing(GtkIconList *iconlist, guint spacing)
1672 {
1673   iconlist->col_spacing = spacing;
1674   reorder_icons(iconlist);
1675 }
1676
1677
1678 /**********************************
1679  * gtk_icon_list_set_selection_mode
1680  * gtk_icon_list_select_icon
1681  * gtk_icon_list_unselect_icon
1682  * gtk_icon_list_unselect_all
1683  **********************************/
1684
1685 void
1686 gtk_icon_list_set_selection_mode(GtkIconList *iconlist, gint mode)
1687 {
1688   iconlist->selection_mode = mode;
1689 }
1690
1691 void
1692 gtk_icon_list_select_icon(GtkIconList *iconlist, GtkIconListItem *item)
1693 {
1694   select_icon(iconlist, item, NULL);
1695 }
1696
1697 void
1698 gtk_icon_list_unselect_icon(GtkIconList *iconlist, GtkIconListItem *item)
1699 {
1700   unselect_icon(iconlist, item, NULL);
1701 }
1702
1703 void
1704 gtk_icon_list_unselect_all(GtkIconList *iconlist)
1705 {
1706   unselect_all(iconlist);
1707 }
1708
1709 void
1710 gtk_icon_list_set_active_icon(GtkIconList *iconlist, GtkIconListItem *icon)
1711 {
1712   if(!icon){
1713     deactivate_entry(iconlist);
1714     unselect_all(iconlist);
1715     return;
1716   }
1717
1718   if(icon->entry){
1719     icon->state = GTK_STATE_SELECTED;
1720     entry_in(icon->entry, NULL, iconlist);
1721     gtk_widget_grab_focus(icon->entry);
1722   }
1723 }
1724
1725
1726 gboolean
1727 gtk_icon_list_is_editable       (GtkIconList *iconlist)
1728 {
1729   return (iconlist->is_editable);
1730 }
1731
1732 guint
1733 gtk_icon_list_get_row_spacing       (GtkIconList *iconlist)
1734 {
1735   return(iconlist->row_spacing);
1736 }
1737
1738 guint
1739 gtk_icon_list_get_col_spacing       (GtkIconList *iconlist)
1740 {
1741   return(iconlist->col_spacing);
1742 }
1743
1744 guint
1745 gtk_icon_list_get_text_space       (GtkIconList *iconlist)
1746 {
1747   return(iconlist->text_space);
1748 }
1749
1750 guint
1751 gtk_icon_list_get_icon_border       (GtkIconList *iconlist)
1752 {
1753   return(iconlist->icon_border);
1754 }
1755
1756 guint
1757 gtk_icon_list_get_icon_width       (GtkIconList *iconlist)
1758 {
1759   return(iconlist->icon_width);
1760 }
1761