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