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