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