1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
20 #include "gtkbindings.h"
22 #include "gtklistitem.h"
24 #include "gtksignal.h"
25 #include <gdk/gdkkeysyms.h>
43 static void gtk_list_item_class_init (GtkListItemClass *klass);
44 static void gtk_list_item_init (GtkListItem *list_item);
45 static void gtk_list_item_realize (GtkWidget *widget);
46 static void gtk_list_item_size_request (GtkWidget *widget,
47 GtkRequisition *requisition);
48 static void gtk_list_item_size_allocate (GtkWidget *widget,
49 GtkAllocation *allocation);
50 static void gtk_list_item_style_set (GtkWidget *widget,
51 GtkStyle *previous_style);
52 static void gtk_list_item_draw (GtkWidget *widget,
54 static void gtk_list_item_draw_focus (GtkWidget *widget);
55 static gint gtk_list_item_button_press (GtkWidget *widget,
56 GdkEventButton *event);
57 static gint gtk_list_item_expose (GtkWidget *widget,
58 GdkEventExpose *event);
59 static gint gtk_list_item_focus_in (GtkWidget *widget,
60 GdkEventFocus *event);
61 static gint gtk_list_item_focus_out (GtkWidget *widget,
62 GdkEventFocus *event);
63 static void gtk_real_list_item_select (GtkItem *item);
64 static void gtk_real_list_item_deselect (GtkItem *item);
65 static void gtk_real_list_item_toggle (GtkItem *item);
68 static GtkItemClass *parent_class = NULL;
69 static guint list_item_signals[LAST_SIGNAL] = {0};
73 gtk_list_item_get_type (void)
75 static GtkType list_item_type = 0;
79 static const GtkTypeInfo list_item_info =
83 sizeof (GtkListItemClass),
84 (GtkClassInitFunc) gtk_list_item_class_init,
85 (GtkObjectInitFunc) gtk_list_item_init,
86 /* reserved_1 */ NULL,
87 /* reserved_2 */ NULL,
88 (GtkClassInitFunc) NULL,
91 list_item_type = gtk_type_unique (gtk_item_get_type (), &list_item_info);
94 return list_item_type;
98 gtk_list_item_class_init (GtkListItemClass *class)
100 GtkObjectClass *object_class;
101 GtkWidgetClass *widget_class;
102 GtkItemClass *item_class;
104 object_class = (GtkObjectClass*) class;
105 widget_class = (GtkWidgetClass*) class;
106 item_class = (GtkItemClass*) class;
108 parent_class = gtk_type_class (gtk_item_get_type ());
110 list_item_signals[TOGGLE_FOCUS_ROW] =
111 gtk_signal_new ("toggle_focus_row",
112 GTK_RUN_LAST | GTK_RUN_ACTION,
114 GTK_SIGNAL_OFFSET (GtkListItemClass, toggle_focus_row),
115 gtk_marshal_NONE__NONE,
117 list_item_signals[SELECT_ALL] =
118 gtk_signal_new ("select_all",
119 GTK_RUN_LAST | GTK_RUN_ACTION,
121 GTK_SIGNAL_OFFSET (GtkListItemClass, select_all),
122 gtk_marshal_NONE__NONE,
124 list_item_signals[UNSELECT_ALL] =
125 gtk_signal_new ("unselect_all",
126 GTK_RUN_LAST | GTK_RUN_ACTION,
128 GTK_SIGNAL_OFFSET (GtkListItemClass, unselect_all),
129 gtk_marshal_NONE__NONE,
131 list_item_signals[UNDO_SELECTION] =
132 gtk_signal_new ("undo_selection",
133 GTK_RUN_LAST | GTK_RUN_ACTION,
135 GTK_SIGNAL_OFFSET (GtkListItemClass, undo_selection),
136 gtk_marshal_NONE__NONE,
138 list_item_signals[START_SELECTION] =
139 gtk_signal_new ("start_selection",
140 GTK_RUN_LAST | GTK_RUN_ACTION,
142 GTK_SIGNAL_OFFSET (GtkListItemClass, start_selection),
143 gtk_marshal_NONE__NONE,
145 list_item_signals[END_SELECTION] =
146 gtk_signal_new ("end_selection",
147 GTK_RUN_LAST | GTK_RUN_ACTION,
149 GTK_SIGNAL_OFFSET (GtkListItemClass, end_selection),
150 gtk_marshal_NONE__NONE,
152 list_item_signals[TOGGLE_ADD_MODE] =
153 gtk_signal_new ("toggle_add_mode",
154 GTK_RUN_LAST | GTK_RUN_ACTION,
156 GTK_SIGNAL_OFFSET (GtkListItemClass, toggle_add_mode),
157 gtk_marshal_NONE__NONE,
159 list_item_signals[EXTEND_SELECTION] =
160 gtk_signal_new ("extend_selection",
161 GTK_RUN_LAST | GTK_RUN_ACTION,
163 GTK_SIGNAL_OFFSET (GtkListItemClass, extend_selection),
164 gtk_marshal_NONE__ENUM_FLOAT_BOOL,
166 GTK_TYPE_ENUM, GTK_TYPE_FLOAT, GTK_TYPE_BOOL);
167 list_item_signals[SCROLL_VERTICAL] =
168 gtk_signal_new ("scroll_vertical",
169 GTK_RUN_LAST | GTK_RUN_ACTION,
171 GTK_SIGNAL_OFFSET (GtkListItemClass, scroll_vertical),
172 gtk_marshal_NONE__ENUM_FLOAT,
173 GTK_TYPE_NONE, 2, GTK_TYPE_ENUM, GTK_TYPE_FLOAT);
174 list_item_signals[SCROLL_HORIZONTAL] =
175 gtk_signal_new ("scroll_horizontal",
176 GTK_RUN_LAST | GTK_RUN_ACTION,
178 GTK_SIGNAL_OFFSET (GtkListItemClass, scroll_horizontal),
179 gtk_marshal_NONE__ENUM_FLOAT,
180 GTK_TYPE_NONE, 2, GTK_TYPE_ENUM, GTK_TYPE_FLOAT);
182 gtk_object_class_add_signals (object_class, list_item_signals, LAST_SIGNAL);
184 widget_class->realize = gtk_list_item_realize;
185 widget_class->size_request = gtk_list_item_size_request;
186 widget_class->size_allocate = gtk_list_item_size_allocate;
187 widget_class->style_set = gtk_list_item_style_set;
188 widget_class->draw = gtk_list_item_draw;
189 widget_class->draw_focus = gtk_list_item_draw_focus;
190 widget_class->button_press_event = gtk_list_item_button_press;
191 widget_class->expose_event = gtk_list_item_expose;
192 widget_class->focus_in_event = gtk_list_item_focus_in;
193 widget_class->focus_out_event = gtk_list_item_focus_out;
195 item_class->select = gtk_real_list_item_select;
196 item_class->deselect = gtk_real_list_item_deselect;
197 item_class->toggle = gtk_real_list_item_toggle;
199 class->toggle_focus_row = NULL;
200 class->select_all = NULL;
201 class->unselect_all = NULL;
202 class->undo_selection = NULL;
203 class->start_selection = NULL;
204 class->end_selection = NULL;
205 class->extend_selection = NULL;
206 class->scroll_horizontal = NULL;
207 class->scroll_vertical = NULL;
208 class->toggle_add_mode = NULL;
211 GtkBindingSet *binding_set;
213 binding_set = gtk_binding_set_by_class (class);
214 gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
215 "scroll_vertical", 2,
216 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
217 GTK_TYPE_FLOAT, 0.0);
218 gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
219 "scroll_vertical", 2,
220 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
221 GTK_TYPE_FLOAT, 0.0);
222 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
223 "scroll_vertical", 2,
224 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
225 GTK_TYPE_FLOAT, 0.0);
226 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
227 "scroll_vertical", 2,
228 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
229 GTK_TYPE_FLOAT, 0.0);
230 gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
231 "scroll_vertical", 2,
232 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
233 GTK_TYPE_FLOAT, 0.0);
234 gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
235 "scroll_vertical", 2,
236 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
237 GTK_TYPE_FLOAT, 1.0);
239 gtk_binding_entry_add_signal (binding_set, GDK_Up, GDK_SHIFT_MASK,
240 "extend_selection", 3,
241 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
242 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
243 gtk_binding_entry_add_signal (binding_set, GDK_Down, GDK_SHIFT_MASK,
244 "extend_selection", 3,
245 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
246 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
247 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, GDK_SHIFT_MASK,
248 "extend_selection", 3,
249 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
250 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
251 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, GDK_SHIFT_MASK,
252 "extend_selection", 3,
253 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
254 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
255 gtk_binding_entry_add_signal (binding_set, GDK_Home,
256 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
257 "extend_selection", 3,
258 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
259 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
260 gtk_binding_entry_add_signal (binding_set, GDK_End,
261 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
262 "extend_selection", 3,
263 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
264 GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE);
267 gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
268 "scroll_horizontal", 2,
269 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
270 GTK_TYPE_FLOAT, 0.0);
271 gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
272 "scroll_horizontal", 2,
273 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
274 GTK_TYPE_FLOAT, 0.0);
275 gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
276 "scroll_horizontal", 2,
277 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
278 GTK_TYPE_FLOAT, 0.0);
279 gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
280 "scroll_horizontal", 2,
281 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
282 GTK_TYPE_FLOAT, 1.0);
285 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
286 "undo_selection", 0);
287 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
288 "toggle_focus_row", 0);
289 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK,
290 "toggle_add_mode", 0);
291 gtk_binding_entry_add_signal (binding_set, '/', GDK_CONTROL_MASK,
293 gtk_binding_entry_add_signal (binding_set, '\\', GDK_CONTROL_MASK,
295 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
296 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
298 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
299 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
301 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
302 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
310 gtk_list_item_init (GtkListItem *list_item)
312 GTK_WIDGET_SET_FLAGS (list_item, GTK_CAN_FOCUS);
316 gtk_list_item_new (void)
318 return GTK_WIDGET (gtk_type_new (gtk_list_item_get_type ()));
322 gtk_list_item_new_with_label (const gchar *label)
324 GtkWidget *list_item;
325 GtkWidget *label_widget;
327 list_item = gtk_list_item_new ();
328 label_widget = gtk_label_new (label);
329 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
331 gtk_container_add (GTK_CONTAINER (list_item), label_widget);
332 gtk_widget_show (label_widget);
338 gtk_list_item_select (GtkListItem *list_item)
340 gtk_item_select (GTK_ITEM (list_item));
344 gtk_list_item_deselect (GtkListItem *list_item)
346 gtk_item_deselect (GTK_ITEM (list_item));
351 gtk_list_item_realize (GtkWidget *widget)
353 GdkWindowAttr attributes;
354 gint attributes_mask;
356 /*if (GTK_WIDGET_CLASS (parent_class)->realize)
357 (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);*/
359 g_return_if_fail (widget != NULL);
360 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
362 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
364 attributes.x = widget->allocation.x;
365 attributes.y = widget->allocation.y;
366 attributes.width = widget->allocation.width;
367 attributes.height = widget->allocation.height;
368 attributes.window_type = GDK_WINDOW_CHILD;
369 attributes.wclass = GDK_INPUT_OUTPUT;
370 attributes.visual = gtk_widget_get_visual (widget);
371 attributes.colormap = gtk_widget_get_colormap (widget);
372 attributes.event_mask = (gtk_widget_get_events (widget) |
374 GDK_BUTTON_PRESS_MASK |
375 GDK_BUTTON_RELEASE_MASK |
377 GDK_KEY_RELEASE_MASK |
378 GDK_ENTER_NOTIFY_MASK |
379 GDK_LEAVE_NOTIFY_MASK);
381 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
382 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
383 gdk_window_set_user_data (widget->window, widget);
385 widget->style = gtk_style_attach (widget->style, widget->window);
386 gdk_window_set_background (widget->window,
387 &widget->style->base[GTK_STATE_NORMAL]);
391 gtk_list_item_size_request (GtkWidget *widget,
392 GtkRequisition *requisition)
396 g_return_if_fail (widget != NULL);
397 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
398 g_return_if_fail (requisition != NULL);
400 bin = GTK_BIN (widget);
402 requisition->width = (GTK_CONTAINER (widget)->border_width +
403 widget->style->klass->xthickness) * 2;
404 requisition->height = GTK_CONTAINER (widget)->border_width * 2;
406 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
408 gtk_widget_size_request (bin->child, &bin->child->requisition);
410 requisition->width += bin->child->requisition.width;
411 requisition->height += bin->child->requisition.height;
416 gtk_list_item_size_allocate (GtkWidget *widget,
417 GtkAllocation *allocation)
420 GtkAllocation child_allocation;
422 g_return_if_fail (widget != NULL);
423 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
424 g_return_if_fail (allocation != NULL);
426 widget->allocation = *allocation;
427 if (GTK_WIDGET_REALIZED (widget))
428 gdk_window_move_resize (widget->window,
429 allocation->x, allocation->y,
430 allocation->width, allocation->height);
432 bin = GTK_BIN (widget);
436 child_allocation.x = (GTK_CONTAINER (widget)->border_width +
437 widget->style->klass->xthickness);
438 child_allocation.y = GTK_CONTAINER (widget)->border_width;
439 child_allocation.width = allocation->width - child_allocation.x * 2;
440 child_allocation.height = allocation->height - child_allocation.y * 2;
442 gtk_widget_size_allocate (bin->child, &child_allocation);
447 gtk_list_item_style_set (GtkWidget *widget,
448 GtkStyle *previous_style)
450 g_return_if_fail (widget != NULL);
452 if (previous_style && GTK_WIDGET_REALIZED (widget))
453 gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
457 gtk_list_item_draw (GtkWidget *widget,
461 GdkRectangle child_area;
463 g_return_if_fail (widget != NULL);
464 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
465 g_return_if_fail (area != NULL);
467 if (GTK_WIDGET_DRAWABLE (widget))
469 bin = GTK_BIN (widget);
471 if (widget->state == GTK_STATE_NORMAL)
473 gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
474 gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height);
478 gtk_paint_flat_box(widget->style, widget->window,
479 widget->state, GTK_SHADOW_ETCHED_OUT,
480 area, widget, "listitem",
484 if (bin->child && gtk_widget_intersect (bin->child, area, &child_area))
485 gtk_widget_draw (bin->child, &child_area);
487 if (GTK_WIDGET_HAS_FOCUS (widget))
489 if (GTK_IS_LIST (widget->parent) && GTK_LIST (widget->parent)->add_mode)
490 gtk_paint_focus (widget->style, widget->window,
491 NULL, widget, "add-mode",
493 widget->allocation.width - 1,
494 widget->allocation.height - 1);
496 gtk_paint_focus (widget->style, widget->window,
499 widget->allocation.width - 1,
500 widget->allocation.height - 1);
506 gtk_list_item_draw_focus (GtkWidget *widget)
508 g_return_if_fail (widget != NULL);
509 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
511 gtk_widget_draw(widget, NULL);
515 gtk_list_item_button_press (GtkWidget *widget,
516 GdkEventButton *event)
518 g_return_val_if_fail (widget != NULL, FALSE);
519 g_return_val_if_fail (GTK_IS_LIST_ITEM (widget), FALSE);
520 g_return_val_if_fail (event != NULL, FALSE);
522 if (event->type == GDK_BUTTON_PRESS)
523 if (!GTK_WIDGET_HAS_FOCUS (widget))
524 gtk_widget_grab_focus (widget);
530 gtk_list_item_expose (GtkWidget *widget,
531 GdkEventExpose *event)
534 GdkEventExpose child_event;
536 g_return_val_if_fail (widget != NULL, FALSE);
537 g_return_val_if_fail (GTK_IS_LIST_ITEM (widget), FALSE);
538 g_return_val_if_fail (event != NULL, FALSE);
540 if (GTK_WIDGET_DRAWABLE (widget))
542 bin = GTK_BIN (widget);
544 if (!GTK_WIDGET_IS_SENSITIVE (widget))
545 gdk_window_set_background (widget->window, &widget->style->bg[GTK_STATE_INSENSITIVE]);
546 else if (widget->state == GTK_STATE_NORMAL)
547 gdk_window_set_background (widget->window, &widget->style->base[GTK_STATE_NORMAL]);
549 gdk_window_set_background (widget->window, &widget->style->bg[widget->state]);
551 gdk_window_clear_area (widget->window, event->area.x, event->area.y,
552 event->area.width, event->area.height);
556 child_event = *event;
558 if (GTK_WIDGET_NO_WINDOW (bin->child) &&
559 gtk_widget_intersect (bin->child, &event->area, &child_event.area))
560 gtk_widget_event (bin->child, (GdkEvent*) &child_event);
563 gtk_widget_draw_focus (widget);
570 gtk_list_item_focus_in (GtkWidget *widget,
571 GdkEventFocus *event)
573 g_return_val_if_fail (widget != NULL, FALSE);
574 g_return_val_if_fail (GTK_IS_LIST_ITEM (widget), FALSE);
575 g_return_val_if_fail (event != NULL, FALSE);
577 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
578 gtk_widget_draw_focus (widget);
584 gtk_list_item_focus_out (GtkWidget *widget,
585 GdkEventFocus *event)
587 g_return_val_if_fail (widget != NULL, FALSE);
588 g_return_val_if_fail (GTK_IS_LIST_ITEM (widget), FALSE);
589 g_return_val_if_fail (event != NULL, FALSE);
591 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
592 gtk_widget_draw_focus (widget);
598 gtk_real_list_item_select (GtkItem *item)
600 g_return_if_fail (item != NULL);
601 g_return_if_fail (GTK_IS_LIST_ITEM (item));
603 switch (GTK_WIDGET (item)->state)
605 case GTK_STATE_SELECTED:
606 case GTK_STATE_INSENSITIVE:
609 gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED);
615 gtk_real_list_item_deselect (GtkItem *item)
617 g_return_if_fail (item != NULL);
618 g_return_if_fail (GTK_IS_LIST_ITEM (item));
620 if (GTK_WIDGET (item)->state == GTK_STATE_SELECTED)
621 gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_NORMAL);
625 gtk_real_list_item_toggle (GtkItem *item)
627 g_return_if_fail (item != NULL);
628 g_return_if_fail (GTK_IS_LIST_ITEM (item));
630 switch (GTK_WIDGET (item)->state)
632 case GTK_STATE_SELECTED:
633 gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_NORMAL);
635 case GTK_STATE_INSENSITIVE:
638 gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED);