]> Pileus Git - ~andy/gtk/blob - gtk/gtklistitem.c
boy! did i really modify that many files?
[~andy/gtk] / gtk / gtklistitem.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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 #include "gtklabel.h"
20 #include "gtklistitem.h"
21 #include "gtklist.h"
22
23 static void gtk_list_item_class_init    (GtkListItemClass *klass);
24 static void gtk_list_item_init          (GtkListItem      *list_item);
25 static void gtk_list_item_realize       (GtkWidget        *widget);
26 static void gtk_list_item_size_request  (GtkWidget        *widget,
27                                          GtkRequisition   *requisition);
28 static void gtk_list_item_size_allocate (GtkWidget        *widget,
29                                          GtkAllocation    *allocation);
30 static void gtk_list_item_draw          (GtkWidget        *widget,
31                                          GdkRectangle     *area);
32 static void gtk_list_item_draw_focus    (GtkWidget        *widget);
33 static gint gtk_list_item_button_press  (GtkWidget        *widget,
34                                          GdkEventButton   *event);
35 static gint gtk_list_item_expose        (GtkWidget        *widget,
36                                          GdkEventExpose   *event);
37 static gint gtk_list_item_focus_in      (GtkWidget        *widget,
38                                          GdkEventFocus    *event);
39 static gint gtk_list_item_focus_out     (GtkWidget        *widget,
40                                          GdkEventFocus    *event);
41 static void gtk_real_list_item_select   (GtkItem          *item);
42 static void gtk_real_list_item_deselect (GtkItem          *item);
43 static void gtk_real_list_item_toggle   (GtkItem          *item);
44
45
46 static GtkItemClass *parent_class = NULL;
47
48
49 GtkType
50 gtk_list_item_get_type (void)
51 {
52   static GtkType list_item_type = 0;
53
54   if (!list_item_type)
55     {
56       GtkTypeInfo list_item_info =
57       {
58         "GtkListItem",
59         sizeof (GtkListItem),
60         sizeof (GtkListItemClass),
61         (GtkClassInitFunc) gtk_list_item_class_init,
62         (GtkObjectInitFunc) gtk_list_item_init,
63         (GtkArgSetFunc) NULL,
64         (GtkArgGetFunc) NULL,
65       };
66
67       list_item_type = gtk_type_unique (gtk_item_get_type (), &list_item_info);
68     }
69
70   return list_item_type;
71 }
72
73 static void
74 gtk_list_item_class_init (GtkListItemClass *class)
75 {
76   GtkWidgetClass *widget_class;
77   GtkItemClass *item_class;
78
79   widget_class = (GtkWidgetClass*) class;
80   item_class = (GtkItemClass*) class;
81
82   parent_class = gtk_type_class (gtk_item_get_type ());
83
84   widget_class->realize = gtk_list_item_realize;
85   widget_class->size_request = gtk_list_item_size_request;
86   widget_class->size_allocate = gtk_list_item_size_allocate;
87   widget_class->draw = gtk_list_item_draw;
88   widget_class->draw_focus = gtk_list_item_draw_focus;
89   widget_class->button_press_event = gtk_list_item_button_press;
90   widget_class->expose_event = gtk_list_item_expose;
91   widget_class->focus_in_event = gtk_list_item_focus_in;
92   widget_class->focus_out_event = gtk_list_item_focus_out;
93
94   item_class->select = gtk_real_list_item_select;
95   item_class->deselect = gtk_real_list_item_deselect;
96   item_class->toggle = gtk_real_list_item_toggle;
97 }
98
99 static void
100 gtk_list_item_init (GtkListItem *list_item)
101 {
102   GTK_WIDGET_SET_FLAGS (list_item, GTK_CAN_FOCUS);
103 }
104
105 GtkWidget*
106 gtk_list_item_new (void)
107 {
108   return GTK_WIDGET (gtk_type_new (gtk_list_item_get_type ()));
109 }
110
111 GtkWidget*
112 gtk_list_item_new_with_label (const gchar *label)
113 {
114   GtkWidget *list_item;
115   GtkWidget *label_widget;
116
117   list_item = gtk_list_item_new ();
118   label_widget = gtk_label_new (label);
119   gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
120
121   gtk_container_add (GTK_CONTAINER (list_item), label_widget);
122   gtk_widget_show (label_widget);
123
124   return list_item;
125 }
126
127 void
128 gtk_list_item_select (GtkListItem *list_item)
129 {
130   gtk_item_select (GTK_ITEM (list_item));
131 }
132
133 void
134 gtk_list_item_deselect (GtkListItem *list_item)
135 {
136   gtk_item_deselect (GTK_ITEM (list_item));
137 }
138
139
140 static void
141 gtk_list_item_realize (GtkWidget *widget)
142 {
143   g_return_if_fail (widget != NULL);
144   g_return_if_fail (GTK_IS_LIST_ITEM (widget));
145
146   if (GTK_WIDGET_CLASS (parent_class)->realize)
147     (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
148
149   gdk_window_set_background (widget->window, 
150                              &widget->style->base[GTK_STATE_NORMAL]);
151 }
152
153 static void
154 gtk_list_item_size_request (GtkWidget      *widget,
155                             GtkRequisition *requisition)
156 {
157   GtkBin *bin;
158
159   g_return_if_fail (widget != NULL);
160   g_return_if_fail (GTK_IS_LIST_ITEM (widget));
161   g_return_if_fail (requisition != NULL);
162
163   bin = GTK_BIN (widget);
164
165   requisition->width = (GTK_CONTAINER (widget)->border_width +
166                         widget->style->klass->xthickness) * 2;
167   requisition->height = GTK_CONTAINER (widget)->border_width * 2;
168
169   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
170     {
171       gtk_widget_size_request (bin->child, &bin->child->requisition);
172
173       requisition->width += bin->child->requisition.width;
174       requisition->height += bin->child->requisition.height;
175     }
176 }
177
178 static void
179 gtk_list_item_size_allocate (GtkWidget     *widget,
180                              GtkAllocation *allocation)
181 {
182   GtkBin *bin;
183   GtkAllocation child_allocation;
184
185   g_return_if_fail (widget != NULL);
186   g_return_if_fail (GTK_IS_LIST_ITEM (widget));
187   g_return_if_fail (allocation != NULL);
188
189   widget->allocation = *allocation;
190   if (GTK_WIDGET_REALIZED (widget))
191     gdk_window_move_resize (widget->window,
192                             allocation->x, allocation->y,
193                             allocation->width, allocation->height);
194
195   bin = GTK_BIN (widget);
196
197   if (bin->child)
198     {
199       child_allocation.x = (GTK_CONTAINER (widget)->border_width +
200                             widget->style->klass->xthickness);
201       child_allocation.y = GTK_CONTAINER (widget)->border_width;
202       child_allocation.width = allocation->width - child_allocation.x * 2;
203       child_allocation.height = allocation->height - child_allocation.y * 2;
204
205       gtk_widget_size_allocate (bin->child, &child_allocation);
206     }
207 }
208
209 static void
210 gtk_list_item_draw (GtkWidget    *widget,
211                     GdkRectangle *area)
212 {
213   GtkBin *bin;
214   GdkRectangle child_area;
215
216   g_return_if_fail (widget != NULL);
217   g_return_if_fail (GTK_IS_LIST_ITEM (widget));
218   g_return_if_fail (area != NULL);
219
220   if (GTK_WIDGET_DRAWABLE (widget))
221     {
222       bin = GTK_BIN (widget);
223
224       if (!GTK_WIDGET_IS_SENSITIVE (widget))
225         gtk_style_set_background (widget->style, widget->window, GTK_STATE_INSENSITIVE);
226       else if (widget->state == GTK_STATE_NORMAL)
227         gdk_window_set_background (widget->window, 
228                                    &widget->style->base[GTK_STATE_NORMAL]);
229       else
230         gtk_style_set_background (widget->style, widget->window, widget->state);
231
232       gdk_window_clear_area (widget->window, area->x, area->y,
233                              area->width, area->height);
234
235       if (bin->child && gtk_widget_intersect (bin->child, area, &child_area))
236         gtk_widget_draw (bin->child, &child_area);
237
238       gtk_widget_draw_focus (widget);
239     }
240 }
241
242 static void
243 gtk_list_item_draw_focus (GtkWidget *widget)
244 {
245   GdkGC *gc;
246
247   g_return_if_fail (widget != NULL);
248   g_return_if_fail (GTK_IS_LIST_ITEM (widget));
249
250   if (GTK_WIDGET_DRAWABLE (widget))
251     {
252       if (GTK_WIDGET_HAS_FOCUS (widget))
253         gc = widget->style->black_gc;
254       else if (!GTK_WIDGET_IS_SENSITIVE (widget))
255         gc = widget->style->bg_gc[GTK_STATE_INSENSITIVE];
256       else if (widget->state == GTK_STATE_NORMAL)
257         gc = widget->style->base_gc[GTK_STATE_NORMAL];
258       else
259         gc = widget->style->bg_gc[widget->state];
260
261       gdk_draw_rectangle (widget->window, gc, FALSE, 0, 0,
262                           widget->allocation.width - 1,
263                           widget->allocation.height - 1);
264     }
265 }
266
267 static gint
268 gtk_list_item_button_press (GtkWidget      *widget,
269                             GdkEventButton *event)
270 {
271   g_return_val_if_fail (widget != NULL, FALSE);
272   g_return_val_if_fail (GTK_IS_LIST_ITEM (widget), FALSE);
273   g_return_val_if_fail (event != NULL, FALSE);
274
275   if (event->type == GDK_BUTTON_PRESS)
276     if (!GTK_WIDGET_HAS_FOCUS (widget))
277       gtk_widget_grab_focus (widget);
278
279   return FALSE;
280 }
281
282 static gint
283 gtk_list_item_expose (GtkWidget      *widget,
284                       GdkEventExpose *event)
285 {
286   GtkBin *bin;
287   GdkEventExpose child_event;
288
289   g_return_val_if_fail (widget != NULL, FALSE);
290   g_return_val_if_fail (GTK_IS_LIST_ITEM (widget), FALSE);
291   g_return_val_if_fail (event != NULL, FALSE);
292
293   if (GTK_WIDGET_DRAWABLE (widget))
294     {
295       bin = GTK_BIN (widget);
296
297       if (!GTK_WIDGET_IS_SENSITIVE (widget))
298         gdk_window_set_background (widget->window, &widget->style->bg[GTK_STATE_INSENSITIVE]);
299       else if (widget->state == GTK_STATE_NORMAL)
300         gdk_window_set_background (widget->window, &widget->style->base[GTK_STATE_NORMAL]);
301       else
302         gdk_window_set_background (widget->window, &widget->style->bg[widget->state]);
303
304       gdk_window_clear_area (widget->window, event->area.x, event->area.y,
305                              event->area.width, event->area.height);
306
307       if (bin->child)
308         {
309           child_event = *event;
310
311           if (GTK_WIDGET_NO_WINDOW (bin->child) &&
312               gtk_widget_intersect (bin->child, &event->area, &child_event.area))
313             gtk_widget_event (bin->child, (GdkEvent*) &child_event);
314         }
315
316       gtk_widget_draw_focus (widget);
317     }
318
319   return FALSE;
320 }
321
322 static gint
323 gtk_list_item_focus_in (GtkWidget     *widget,
324                         GdkEventFocus *event)
325 {
326   g_return_val_if_fail (widget != NULL, FALSE);
327   g_return_val_if_fail (GTK_IS_LIST_ITEM (widget), FALSE);
328   g_return_val_if_fail (event != NULL, FALSE);
329
330   GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
331   gtk_widget_draw_focus (widget);
332
333   return FALSE;
334 }
335
336 static gint
337 gtk_list_item_focus_out (GtkWidget     *widget,
338                          GdkEventFocus *event)
339 {
340   g_return_val_if_fail (widget != NULL, FALSE);
341   g_return_val_if_fail (GTK_IS_LIST_ITEM (widget), FALSE);
342   g_return_val_if_fail (event != NULL, FALSE);
343
344   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
345   gtk_widget_draw_focus (widget);
346
347   return FALSE;
348 }
349
350 static void
351 gtk_real_list_item_select (GtkItem *item)
352 {
353   g_return_if_fail (item != NULL);
354   g_return_if_fail (GTK_IS_LIST_ITEM (item));
355
356   if (GTK_WIDGET (item)->state == GTK_STATE_SELECTED)
357     return;
358
359   gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED);
360   gtk_widget_queue_draw (GTK_WIDGET (item));
361 }
362
363 static void
364 gtk_real_list_item_deselect (GtkItem *item)
365 {
366   g_return_if_fail (item != NULL);
367   g_return_if_fail (GTK_IS_LIST_ITEM (item));
368
369   if (GTK_WIDGET (item)->state == GTK_STATE_NORMAL)
370     return;
371
372   gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_NORMAL);
373   gtk_widget_queue_draw (GTK_WIDGET (item));
374 }
375
376 static void
377 gtk_real_list_item_toggle (GtkItem *item)
378 {
379   g_return_if_fail (item != NULL);
380   g_return_if_fail (GTK_IS_LIST_ITEM (item));
381   
382   if (GTK_WIDGET (item)->parent && GTK_IS_LIST (GTK_WIDGET (item)->parent))
383     gtk_list_select_child (GTK_LIST (GTK_WIDGET (item)->parent),
384                            GTK_WIDGET (item));
385   else
386     {
387       /* Should we really bother with this bit? A listitem not in a list?
388        * -Johannes Keukelaar
389        * yes, always be on the save side!
390        * -timj
391        */
392       if (GTK_WIDGET (item)->state == GTK_STATE_SELECTED)
393         gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_NORMAL);
394       else
395         gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED);
396       gtk_widget_queue_draw (GTK_WIDGET (item));
397     }
398 }