1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald,
3 * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 #include "../config.h"
25 #include "gtkbindings.h"
26 #include <gdk/gdkkeysyms.h>
28 /* the number rows memchunk expands at a time */
29 #define CLIST_OPTIMUM_SIZE 512
31 /* the width of the column resize windows */
34 /* minimum allowed width of a column */
35 #define COLUMN_MIN_WIDTH 5
37 /* this defigns the base grid spacing */
38 #define CELL_SPACING 1
40 /* added the horizontal space at the beginning and end of a row*/
41 #define COLUMN_INSET 3
43 /* used for auto-scrolling */
44 #define SCROLL_TIME 100
46 /* scrollbar spacing class macro */
47 #define SCROLLBAR_SPACING(w) (GTK_CLIST_CLASS (GTK_OBJECT (w)->klass)->scrollbar_spacing)
49 /* gives the top pixel of the given row in context of
50 * the clist's voffset */
51 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
52 (((row) + 1) * CELL_SPACING) + \
55 /* returns the row index from a y pixel location in the
56 * context of the clist's voffset */
57 #define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \
58 ((clist)->row_height + CELL_SPACING))
60 /* gives the left pixel of the given column in context of
61 * the clist's hoffset */
62 #define COLUMN_LEFT_XPIXEL(clist, colnum) ((clist)->column[(colnum)].area.x + \
65 /* returns the column index from a x pixel location in the
66 * context of the clist's hoffset */
68 COLUMN_FROM_XPIXEL (GtkCList * clist,
73 for (i = 0; i < clist->columns; i++)
75 cx = clist->column[i].area.x + clist->hoffset;
77 if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
78 x <= (cx + clist->column[i].area.width + COLUMN_INSET))
86 /* returns the top pixel of the given row in the context of
88 #define ROW_TOP(clist, row) (((clist)->row_height + CELL_SPACING) * (row))
90 /* returns the left pixel of the given column in the context of
92 #define COLUMN_LEFT(clist, colnum) ((clist)->column[(colnum)].area.x)
94 /* returns the total height of the list */
95 #define LIST_HEIGHT(clist) (((clist)->row_height * ((clist)->rows)) + \
96 (CELL_SPACING * ((clist)->rows + 1)))
98 /* returns the total width of the list */
99 #define LIST_WIDTH(clist) ((clist)->column[(clist)->columns - 1].area.x + \
100 (clist)->column[(clist)->columns - 1].area.width + \
101 COLUMN_INSET + CELL_SPACING)
104 #define GTK_CLIST_CLASS_FW(_widget_) GTK_CLIST_CLASS (GTK_OBJECT (_widget_)->klass)
134 typedef void (*GtkCListSignal1) (GtkObject * object,
140 typedef void (*GtkCListSignal2) (GtkObject *object,
143 typedef void (*GtkCListSignal3) (GtkObject * object,
146 typedef void (*GtkCListSignal4) (GtkObject * object,
150 typedef void (*GtkCListSignal5) (GtkObject * object,
157 static void sync_selection (GtkCList * clist,
161 /* GtkCList Methods */
162 static void gtk_clist_class_init (GtkCListClass * klass);
163 static void gtk_clist_init (GtkCList * clist);
164 static void real_clear (GtkCList * clist);
166 /* GtkObject Methods */
167 static void gtk_clist_destroy (GtkObject * object);
168 static void gtk_clist_finalize (GtkObject * object);
171 /* GtkWidget Methods */
172 static void gtk_clist_realize (GtkWidget * widget);
173 static void gtk_clist_unrealize (GtkWidget * widget);
174 static void gtk_clist_map (GtkWidget * widget);
175 static void gtk_clist_unmap (GtkWidget * widget);
176 static void gtk_clist_draw (GtkWidget * widget,
177 GdkRectangle * area);
178 static gint gtk_clist_expose (GtkWidget * widget,
179 GdkEventExpose * event);
180 static gint gtk_clist_button_press (GtkWidget * widget,
181 GdkEventButton * event);
182 static gint gtk_clist_button_release (GtkWidget * widget,
183 GdkEventButton * event);
184 static gint gtk_clist_motion (GtkWidget * widget,
185 GdkEventMotion * event);
186 static void gtk_clist_size_request (GtkWidget * widget,
187 GtkRequisition * requisition);
188 static void gtk_clist_size_allocate (GtkWidget * widget,
189 GtkAllocation * allocation);
190 static gint get_selection_info (GtkCList * clist,
196 /* GtkContainer Methods */
197 static void gtk_clist_forall (GtkContainer *container,
198 gboolean include_internals,
199 GtkCallback callback,
200 gpointer callback_data);
203 static void draw_row (GtkCList * clist,
206 GtkCListRow * clist_row);
207 static void draw_rows (GtkCList * clist,
208 GdkRectangle * area);
210 /* Size Allocation */
211 static void size_allocate_title_buttons (GtkCList * clist);
212 static void size_allocate_columns (GtkCList * clist);
215 static void toggle_row (GtkCList * clist,
219 static void select_row (GtkCList * clist,
223 static void unselect_row (GtkCList * clist,
227 static void real_select_row (GtkCList * clist,
231 static void real_unselect_row (GtkCList * clist,
235 static void update_extended_selection (GtkCList *clist,
237 static GList * selection_find (GtkCList *clist,
239 GList *row_list_element);
240 static void real_select_all (GtkCList * clist);
241 static void real_unselect_all (GtkCList * clist);
242 static void move_vertical (GtkCList *clist,
245 static void move_horizontal (GtkCList *clist,
247 static void real_undo_selection (GtkCList * clist);
248 static void fake_unselect_all (GtkCList *clist,
250 static void fake_toggle_row (GtkCList *clist,
252 static void resync_selection (GtkCList *clist,
256 static void draw_xor_line (GtkCList * clist);
257 static gint new_column_width (GtkCList * clist,
261 static void resize_column (GtkCList * clist,
264 static void abort_column_resize (GtkCList *clist);
267 static void column_button_create (GtkCList * clist,
269 static void column_button_clicked (GtkWidget * widget,
273 static void create_scrollbars (GtkCList * clist);
274 static void adjust_scrollbars (GtkCList * clist);
275 static void check_exposures (GtkCList * clist);
276 static void vadjustment_changed (GtkAdjustment * adjustment,
278 static void vadjustment_value_changed (GtkAdjustment * adjustment,
280 static void hadjustment_changed (GtkAdjustment * adjustment,
282 static void hadjustment_value_changed (GtkAdjustment * adjustment,
285 /* Memory Allocation/Distruction Routines */
286 static GtkCListColumn *columns_new (GtkCList * clist);
288 static void column_title_new (GtkCList *clist,
291 static void columns_delete (GtkCList * clist);
293 static GtkCListRow *row_new (GtkCList * clist);
295 static void row_delete (GtkCList * clist,
296 GtkCListRow * clist_row);
297 static void set_cell_contents (GtkCList *clist,
298 GtkCListRow *clist_row,
305 static gint real_insert_row (GtkCList * clist,
308 static void real_remove_row (GtkCList * clist,
312 static void gtk_clist_draw_focus (GtkWidget *widget);
313 static gint gtk_clist_focus_in (GtkWidget *widget,
314 GdkEventFocus *event);
315 static gint gtk_clist_focus_out (GtkWidget *widget,
316 GdkEventFocus *event);
317 static gint gtk_clist_focus (GtkContainer *container,
318 GtkDirectionType direction);
319 static void gtk_clist_set_focus_child (GtkContainer *container,
321 static gint gtk_clist_key_press (GtkWidget *widget,
324 /* Selection handling */
325 static void set_anchor (GtkCList *clist,
329 static void start_selection (GtkCList *clist);
330 static void end_selection (GtkCList *clist);
332 static void toggle_add_mode (GtkCList *clist);
333 static void toggle_focus_row (GtkCList *clist);
334 static void move_focus_row (GtkCList *clist,
335 GtkScrollType scroll_type,
337 static void scroll_horizontal (GtkCList *clist,
338 GtkScrollType scroll_type,
340 static void scroll_vertical (GtkCList *clist,
341 GtkScrollType scroll_type,
343 static void extend_selection (GtkCList *clist,
344 GtkScrollType scroll_type,
346 gboolean auto_start_selection);
349 static gint default_compare (GtkCList *clist,
352 static GList * gtk_clist_merge (GtkCList *clist,
355 static GList * gtk_clist_mergesort (GtkCList *clist,
358 static void real_sort_list (GtkCList *clist);
360 /* Fill in data after widget is realized and has style */
362 static void add_style_data (GtkCList * clist);
364 static GtkContainerClass *parent_class = NULL;
365 static guint clist_signals[LAST_SIGNAL] = {0};
369 gtk_clist_get_type (void)
371 static GtkType clist_type = 0;
375 GtkTypeInfo clist_info =
379 sizeof (GtkCListClass),
380 (GtkClassInitFunc) gtk_clist_class_init,
381 (GtkObjectInitFunc) gtk_clist_init,
382 /* reserved_1 */ NULL,
383 /* reserved_2 */ NULL,
384 (GtkClassInitFunc) NULL,
387 clist_type = gtk_type_unique (GTK_TYPE_CONTAINER, &clist_info);
394 gtk_clist_class_init (GtkCListClass * klass)
396 GtkObjectClass *object_class;
397 GtkWidgetClass *widget_class;
398 GtkContainerClass *container_class;
400 object_class = (GtkObjectClass *) klass;
401 widget_class = (GtkWidgetClass *) klass;
402 container_class = (GtkContainerClass *) klass;
404 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
406 clist_signals[SELECT_ROW] =
407 gtk_signal_new ("select_row",
410 GTK_SIGNAL_OFFSET (GtkCListClass, select_row),
411 gtk_marshal_NONE__INT_INT_POINTER,
416 clist_signals[UNSELECT_ROW] =
417 gtk_signal_new ("unselect_row",
420 GTK_SIGNAL_OFFSET (GtkCListClass, unselect_row),
421 gtk_marshal_NONE__INT_INT_POINTER,
422 GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_GDK_EVENT);
423 clist_signals[CLICK_COLUMN] =
424 gtk_signal_new ("click_column",
427 GTK_SIGNAL_OFFSET (GtkCListClass, click_column),
428 gtk_marshal_NONE__INT,
429 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
431 clist_signals[TOGGLE_FOCUS_ROW] =
432 gtk_signal_new ("toggle_focus_row",
433 GTK_RUN_LAST | GTK_RUN_ACTION,
435 GTK_SIGNAL_OFFSET (GtkCListClass, toggle_focus_row),
436 gtk_marshal_NONE__NONE,
438 clist_signals[SELECT_ALL] =
439 gtk_signal_new ("select_all",
440 GTK_RUN_LAST | GTK_RUN_ACTION,
442 GTK_SIGNAL_OFFSET (GtkCListClass, select_all),
443 gtk_marshal_NONE__NONE,
445 clist_signals[UNSELECT_ALL] =
446 gtk_signal_new ("unselect_all",
447 GTK_RUN_LAST | GTK_RUN_ACTION,
449 GTK_SIGNAL_OFFSET (GtkCListClass, unselect_all),
450 gtk_marshal_NONE__NONE,
452 clist_signals[UNDO_SELECTION] =
453 gtk_signal_new ("undo_selection",
454 GTK_RUN_LAST | GTK_RUN_ACTION,
456 GTK_SIGNAL_OFFSET (GtkCListClass, undo_selection),
457 gtk_marshal_NONE__NONE,
459 clist_signals[START_SELECTION] =
460 gtk_signal_new ("start_selection",
461 GTK_RUN_LAST | GTK_RUN_ACTION,
463 GTK_SIGNAL_OFFSET (GtkCListClass, start_selection),
464 gtk_marshal_NONE__NONE,
466 clist_signals[END_SELECTION] =
467 gtk_signal_new ("end_selection",
468 GTK_RUN_LAST | GTK_RUN_ACTION,
470 GTK_SIGNAL_OFFSET (GtkCListClass, end_selection),
471 gtk_marshal_NONE__NONE,
473 clist_signals[TOGGLE_ADD_MODE] =
474 gtk_signal_new ("toggle_add_mode",
475 GTK_RUN_LAST | GTK_RUN_ACTION,
477 GTK_SIGNAL_OFFSET (GtkCListClass, toggle_add_mode),
478 gtk_marshal_NONE__NONE,
480 clist_signals[EXTEND_SELECTION] =
481 gtk_signal_new ("extend_selection",
482 GTK_RUN_LAST | GTK_RUN_ACTION,
484 GTK_SIGNAL_OFFSET (GtkCListClass, extend_selection),
485 gtk_marshal_NONE__ENUM_FLOAT_BOOL,
487 GTK_TYPE_SCROLL_TYPE, GTK_TYPE_FLOAT, GTK_TYPE_BOOL);
488 clist_signals[SCROLL_VERTICAL] =
489 gtk_signal_new ("scroll_vertical",
490 GTK_RUN_LAST | GTK_RUN_ACTION,
492 GTK_SIGNAL_OFFSET (GtkCListClass, scroll_vertical),
493 gtk_marshal_NONE__ENUM_FLOAT,
494 GTK_TYPE_NONE, 2, GTK_TYPE_SCROLL_TYPE, GTK_TYPE_FLOAT);
495 clist_signals[SCROLL_HORIZONTAL] =
496 gtk_signal_new ("scroll_horizontal",
497 GTK_RUN_LAST | GTK_RUN_ACTION,
499 GTK_SIGNAL_OFFSET (GtkCListClass, scroll_horizontal),
500 gtk_marshal_NONE__ENUM_FLOAT,
501 GTK_TYPE_NONE, 2, GTK_TYPE_SCROLL_TYPE, GTK_TYPE_FLOAT);
502 clist_signals[ABORT_COLUMN_RESIZE] =
503 gtk_signal_new ("abort_column_resize",
504 GTK_RUN_LAST | GTK_RUN_ACTION,
506 GTK_SIGNAL_OFFSET (GtkCListClass, abort_column_resize),
507 gtk_marshal_NONE__NONE,
511 gtk_object_class_add_signals (object_class, clist_signals, LAST_SIGNAL);
513 object_class->destroy = gtk_clist_destroy;
514 object_class->finalize = gtk_clist_finalize;
516 widget_class->realize = gtk_clist_realize;
517 widget_class->unrealize = gtk_clist_unrealize;
518 widget_class->map = gtk_clist_map;
519 widget_class->unmap = gtk_clist_unmap;
520 widget_class->draw = gtk_clist_draw;
521 widget_class->button_press_event = gtk_clist_button_press;
522 widget_class->button_release_event = gtk_clist_button_release;
523 widget_class->motion_notify_event = gtk_clist_motion;
524 widget_class->expose_event = gtk_clist_expose;
525 widget_class->size_request = gtk_clist_size_request;
526 widget_class->size_allocate = gtk_clist_size_allocate;
527 widget_class->key_press_event = gtk_clist_key_press;
528 widget_class->focus_in_event = gtk_clist_focus_in;
529 widget_class->focus_out_event = gtk_clist_focus_out;
530 widget_class->draw_focus = gtk_clist_draw_focus;
532 /* container_class->add = NULL; use the default GtkContainerClass warning */
533 /* container_class->remove = NULL; use the default GtkContainerClass warning */
534 container_class->forall = gtk_clist_forall;
535 container_class->focus = gtk_clist_focus;
536 container_class->set_focus_child = gtk_clist_set_focus_child;
538 klass->select_row = real_select_row;
539 klass->unselect_row = real_unselect_row;
540 klass->undo_selection = real_undo_selection;
541 klass->resync_selection = resync_selection;
542 klass->selection_find = selection_find;
543 klass->click_column = NULL;
544 klass->draw_row = draw_row;
545 klass->insert_row = real_insert_row;
546 klass->remove_row = real_remove_row;
547 klass->clear = real_clear;
548 klass->sort_list = real_sort_list;
549 klass->select_all = real_select_all;
550 klass->unselect_all = real_unselect_all;
551 klass->fake_unselect_all = fake_unselect_all;
552 klass->scroll_horizontal = scroll_horizontal;
553 klass->scroll_vertical = scroll_vertical;
554 klass->extend_selection = extend_selection;
555 klass->toggle_focus_row = toggle_focus_row;
556 klass->toggle_add_mode = toggle_add_mode;
557 klass->start_selection = start_selection;
558 klass->end_selection = end_selection;
559 klass->abort_column_resize = abort_column_resize;
560 klass->set_cell_contents = set_cell_contents;
562 klass->scrollbar_spacing = 5;
565 GtkBindingSet *binding_set;
567 binding_set = gtk_binding_set_by_class (klass);
568 gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
569 "scroll_vertical", 2,
570 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
571 GTK_TYPE_FLOAT, 0.0);
572 gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
573 "scroll_vertical", 2,
574 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
575 GTK_TYPE_FLOAT, 0.0);
576 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
577 "scroll_vertical", 2,
578 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
579 GTK_TYPE_FLOAT, 0.0);
580 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
581 "scroll_vertical", 2,
582 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
583 GTK_TYPE_FLOAT, 0.0);
584 gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
585 "scroll_vertical", 2,
586 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
587 GTK_TYPE_FLOAT, 0.0);
588 gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
589 "scroll_vertical", 2,
590 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
591 GTK_TYPE_FLOAT, 1.0);
593 gtk_binding_entry_add_signal (binding_set, GDK_Up, GDK_SHIFT_MASK,
594 "extend_selection", 3,
595 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
596 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
597 gtk_binding_entry_add_signal (binding_set, GDK_Down, GDK_SHIFT_MASK,
598 "extend_selection", 3,
599 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
600 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
601 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, GDK_SHIFT_MASK,
602 "extend_selection", 3,
603 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
604 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
605 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, GDK_SHIFT_MASK,
606 "extend_selection", 3,
607 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
608 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
609 gtk_binding_entry_add_signal (binding_set, GDK_Home,
610 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
611 "extend_selection", 3,
612 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
613 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
614 gtk_binding_entry_add_signal (binding_set, GDK_End,
615 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
616 "extend_selection", 3,
617 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
618 GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE);
621 gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
622 "scroll_horizontal", 2,
623 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
624 GTK_TYPE_FLOAT, 0.0);
625 gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
626 "scroll_horizontal", 2,
627 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
628 GTK_TYPE_FLOAT, 0.0);
629 gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
630 "scroll_horizontal", 2,
631 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
632 GTK_TYPE_FLOAT, 0.0);
633 gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
634 "scroll_horizontal", 2,
635 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
636 GTK_TYPE_FLOAT, 1.0);
639 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
640 "undo_selection", 0);
641 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
642 "abort_column_resize", 0);
643 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
644 "toggle_focus_row", 0);
645 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK,
646 "toggle_add_mode", 0);
647 gtk_binding_entry_add_signal (binding_set, '/', GDK_CONTROL_MASK,
649 gtk_binding_entry_add_signal (binding_set, '\\', GDK_CONTROL_MASK,
651 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
652 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
654 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
655 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
657 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
658 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
661 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
662 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
669 GtkBindingSet *binding_set;
671 binding_set = gtk_binding_set_by_class (klass);
672 gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
673 "scroll_vertical", 2,
674 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
675 GTK_TYPE_FLOAT, 0.0);
676 gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
677 "scroll_vertical", 2,
678 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
679 GTK_TYPE_FLOAT, 0.0);
680 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
681 "scroll_vertical", 2,
682 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
683 GTK_TYPE_FLOAT, 0.0);
684 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
685 "scroll_vertical", 2,
686 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
687 GTK_TYPE_FLOAT, 0.0);
688 gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
689 "scroll_vertical", 2,
690 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
691 GTK_TYPE_FLOAT, 0.0);
692 gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
693 "scroll_vertical", 2,
694 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
697 gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0,
698 "extend_selection", 3,
699 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
700 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
701 gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0,
702 "extend_selection", 3,
703 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
704 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
705 gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Up, 0,
706 "extend_selection", 3,
707 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
708 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
709 gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Down, 0,
710 "extend_selection", 3,
711 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
712 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
713 gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, 0,
714 "extend_selection", 3,
715 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
716 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
717 gtk_binding_entry_add_signal (binding_set, GDK_KP_End, 0,
718 "extend_selection", 3,
719 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
720 GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE);
722 gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
723 "scroll_horizontal", 2,
724 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
725 GTK_TYPE_FLOAT, 0.0);
726 gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0,
727 "scroll_horizontal", 2,
728 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
729 GTK_TYPE_FLOAT, 0.0);
730 gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
731 "scroll_horizontal", 2,
732 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
733 GTK_TYPE_FLOAT, 0.0);
734 gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0,
735 "scroll_horizontal", 2,
736 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
737 GTK_TYPE_FLOAT, 0.0);
738 gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
739 "scroll_horizontal", 2,
740 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
741 GTK_TYPE_FLOAT, 0.0);
742 gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
743 "sroll_horizontal", 2,
744 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
745 GTK_TYPE_FLOAT, 1.0);
747 gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, 0,
748 "undo_selection", 0);
749 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
750 "abort_column_resize", 0);
751 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
752 "toggle_focus_row", 0);
753 gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0,
754 "toggle_add_mode", 0);
755 gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0,
757 gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0,
759 gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0,
766 gtk_clist_init (GtkCList * clist)
770 GTK_WIDGET_UNSET_FLAGS (clist, GTK_NO_WINDOW);
771 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
773 clist->row_mem_chunk = NULL;
774 clist->cell_mem_chunk = NULL;
777 clist->row_center_offset = 0;
778 clist->row_height = 0;
779 clist->row_list = NULL;
780 clist->row_list_end = NULL;
784 clist->title_window = NULL;
785 clist->column_title_area.x = 0;
786 clist->column_title_area.y = 0;
787 clist->column_title_area.width = 1;
788 clist->column_title_area.height = 1;
790 clist->clist_window = NULL;
791 clist->clist_window_width = 1;
792 clist->clist_window_height = 1;
797 clist->shadow_type = GTK_SHADOW_IN;
798 clist->hscrollbar_policy = GTK_POLICY_ALWAYS;
799 clist->vscrollbar_policy = GTK_POLICY_ALWAYS;
801 clist->cursor_drag = NULL;
802 clist->xor_gc = NULL;
807 clist->selection_mode = GTK_SELECTION_SINGLE;
808 clist->selection = NULL;
809 clist->selection_end = NULL;
810 clist->undo_selection = NULL;
811 clist->undo_unselection = NULL;
813 GTK_WIDGET_SET_FLAGS (clist, GTK_CAN_FOCUS);
814 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
815 clist->focus_row = -1;
816 clist->undo_anchor = -1;
819 clist->anchor_state = GTK_STATE_SELECTED;
820 clist->drag_pos = -1;
824 clist->compare = default_compare;
825 clist->sort_type = GTK_SORT_ASCENDING;
826 clist->sort_column = 0;
831 gtk_clist_construct (GtkCList * clist,
837 g_return_if_fail (clist != NULL);
838 g_return_if_fail (GTK_IS_CLIST (clist));
839 g_return_if_fail (GTK_CLIST_CONSTRUCTED (clist) == FALSE);
841 GTK_CLIST_SET_FLAG (clist, CLIST_CONSTRUCTED);
843 /* initalize memory chunks, if this has not been done by any
844 * possibly derived widget
846 if (!clist->row_mem_chunk)
847 clist->row_mem_chunk = g_mem_chunk_new ("clist row mem chunk",
848 sizeof (GtkCListRow),
849 sizeof (GtkCListRow) * CLIST_OPTIMUM_SIZE,
852 if (!clist->cell_mem_chunk)
853 clist->cell_mem_chunk = g_mem_chunk_new ("clist cell mem chunk",
854 sizeof (GtkCell) * columns,
855 sizeof (GtkCell) * columns * CLIST_OPTIMUM_SIZE,
858 /* set number of columns, allocate memory */
859 clist->columns = columns;
860 clist->column = columns_new (clist);
862 /* there needs to be at least one column button
863 * because there is alot of code that will break if it
865 column_button_create (clist, 0);
867 /* create scrollbars */
868 create_scrollbars (clist);
872 GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES);
873 for (i = 0; i < columns; i++)
874 gtk_clist_set_column_title (clist, i, titles[i]);
878 GTK_CLIST_UNSET_FLAG (clist, CLIST_SHOW_TITLES);
883 * GTKCLIST PUBLIC INTERFACE
884 * gtk_clist_new_with_titles
888 gtk_clist_new_with_titles (gint columns,
893 g_return_val_if_fail (titles != NULL, NULL);
895 widget = gtk_type_new (GTK_TYPE_CLIST);
897 gtk_clist_construct (GTK_CLIST (widget), columns, titles);
903 gtk_clist_new (gint columns)
910 clist = gtk_type_new (GTK_TYPE_CLIST);
911 gtk_clist_construct (clist, columns, NULL);
912 return GTK_WIDGET (clist);
916 gtk_clist_set_border (GtkCList * clist,
917 GtkShadowType border)
919 g_return_if_fail (clist != NULL);
920 g_return_if_fail (GTK_IS_CLIST (clist));
922 clist->shadow_type = border;
924 if (GTK_WIDGET_VISIBLE (clist))
925 gtk_widget_queue_resize (GTK_WIDGET (clist));
929 gtk_clist_set_selection_mode (GtkCList * clist,
930 GtkSelectionMode mode)
932 g_return_if_fail (clist != NULL);
933 g_return_if_fail (GTK_IS_CLIST (clist));
935 if (mode == clist->selection_mode)
938 clist->selection_mode = mode;
940 clist->anchor_state = GTK_STATE_SELECTED;
941 clist->drag_pos = -1;
942 clist->undo_anchor = clist->focus_row;
944 g_list_free (clist->undo_selection);
945 g_list_free (clist->undo_unselection);
946 clist->undo_selection = NULL;
947 clist->undo_unselection = NULL;
951 case GTK_SELECTION_MULTIPLE:
952 case GTK_SELECTION_EXTENDED:
954 case GTK_SELECTION_BROWSE:
955 case GTK_SELECTION_SINGLE:
956 gtk_clist_unselect_all (clist);
962 gtk_clist_freeze (GtkCList * clist)
964 g_return_if_fail (clist != NULL);
965 g_return_if_fail (GTK_IS_CLIST (clist));
967 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
971 gtk_clist_thaw (GtkCList * clist)
973 g_return_if_fail (clist != NULL);
974 g_return_if_fail (GTK_IS_CLIST (clist));
976 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
978 adjust_scrollbars (clist);
979 draw_rows (clist, NULL);
983 gtk_clist_column_titles_show (GtkCList * clist)
985 g_return_if_fail (clist != NULL);
986 g_return_if_fail (GTK_IS_CLIST (clist));
988 if (!GTK_CLIST_SHOW_TITLES (clist))
990 GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES);
991 if (clist->title_window)
992 gdk_window_show (clist->title_window);
993 gtk_widget_queue_resize (GTK_WIDGET (clist));
998 gtk_clist_column_titles_hide (GtkCList * clist)
1000 g_return_if_fail (clist != NULL);
1001 g_return_if_fail (GTK_IS_CLIST (clist));
1003 if (GTK_CLIST_SHOW_TITLES (clist))
1005 GTK_CLIST_UNSET_FLAG (clist, CLIST_SHOW_TITLES);
1006 if (clist->title_window)
1007 gdk_window_hide (clist->title_window);
1008 gtk_widget_queue_resize (GTK_WIDGET (clist));
1013 gtk_clist_column_title_active (GtkCList * clist,
1016 g_return_if_fail (clist != NULL);
1017 g_return_if_fail (GTK_IS_CLIST (clist));
1019 if (column < 0 || column >= clist->columns)
1022 if (!GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
1023 !GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
1025 GTK_WIDGET_SET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS);
1026 if (GTK_WIDGET_VISIBLE (clist))
1027 gtk_widget_queue_draw (clist->column[column].button);
1032 gtk_clist_column_title_passive (GtkCList * clist,
1035 g_return_if_fail (clist != NULL);
1036 g_return_if_fail (GTK_IS_CLIST (clist));
1038 if (column < 0 || column >= clist->columns)
1041 if (GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
1042 GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
1044 GTK_WIDGET_UNSET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS);
1045 if (GTK_WIDGET_VISIBLE (clist))
1046 gtk_widget_queue_draw (clist->column[column].button);
1051 gtk_clist_column_titles_active (GtkCList * clist)
1055 g_return_if_fail (clist != NULL);
1056 g_return_if_fail (GTK_IS_CLIST (clist));
1058 for (i = 0; i < clist->columns; i++)
1059 if (clist->column[i].button)
1060 gtk_clist_column_title_active (clist, i);
1064 gtk_clist_column_titles_passive (GtkCList * clist)
1068 g_return_if_fail (clist != NULL);
1069 g_return_if_fail (GTK_IS_CLIST (clist));
1071 for (i = 0; i < clist->columns; i++)
1072 if (clist->column[i].button)
1073 gtk_clist_column_title_passive (clist, i);
1077 gtk_clist_set_column_title (GtkCList *clist,
1081 gint new_button = 0;
1082 GtkWidget *old_widget;
1083 GtkWidget *alignment = NULL;
1086 g_return_if_fail (clist != NULL);
1087 g_return_if_fail (GTK_IS_CLIST (clist));
1089 if (column < 0 || column >= clist->columns)
1092 /* if the column button doesn't currently exist,
1093 * it has to be created first */
1094 if (!clist->column[column].button)
1096 column_button_create (clist, column);
1100 column_title_new (clist, column, title);
1102 /* remove and destroy the old widget */
1103 old_widget = GTK_BIN (clist->column[column].button)->child;
1105 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
1107 /* create new alignment based no column justification */
1108 switch (clist->column[column].justification)
1110 case GTK_JUSTIFY_LEFT:
1111 alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
1114 case GTK_JUSTIFY_RIGHT:
1115 alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
1118 case GTK_JUSTIFY_CENTER:
1119 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1122 case GTK_JUSTIFY_FILL:
1123 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1127 label = gtk_label_new (clist->column[column].title);
1128 gtk_container_add (GTK_CONTAINER (alignment), label);
1129 gtk_container_add (GTK_CONTAINER (clist->column[column].button), alignment);
1130 gtk_widget_show (label);
1131 gtk_widget_show (alignment);
1133 /* if this button didn't previously exist, then the
1134 * column button positions have to be re-computed */
1135 if (GTK_WIDGET_VISIBLE (clist) && new_button)
1136 size_allocate_title_buttons (clist);
1140 gtk_clist_set_column_widget (GtkCList * clist,
1144 gint new_button = 0;
1145 GtkWidget *old_widget;
1147 g_return_if_fail (clist != NULL);
1148 g_return_if_fail (GTK_IS_CLIST (clist));
1150 if (column < 0 || column >= clist->columns)
1153 /* if the column button doesn't currently exist,
1154 * it has to be created first */
1155 if (!clist->column[column].button)
1157 column_button_create (clist, column);
1161 column_title_new (clist, column, NULL);
1163 /* remove and destroy the old widget */
1164 old_widget = GTK_BIN (clist->column[column].button)->child;
1166 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
1168 /* add and show the widget */
1171 gtk_container_add (GTK_CONTAINER (clist->column[column].button), widget);
1172 gtk_widget_show (widget);
1175 /* if this button didn't previously exist, then the
1176 * column button positions have to be re-computed */
1177 if (GTK_WIDGET_VISIBLE (clist) && new_button)
1178 size_allocate_title_buttons (clist);
1182 gtk_clist_set_column_justification (GtkCList * clist,
1184 GtkJustification justification)
1186 GtkWidget *alignment;
1188 g_return_if_fail (clist != NULL);
1189 g_return_if_fail (GTK_IS_CLIST (clist));
1191 if (column < 0 || column >= clist->columns)
1194 clist->column[column].justification = justification;
1196 /* change the alinment of the button title if it's not a
1198 if (clist->column[column].title)
1200 alignment = GTK_BIN (clist->column[column].button)->child;
1202 switch (clist->column[column].justification)
1204 case GTK_JUSTIFY_LEFT:
1205 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.0, 0.5, 0.0, 0.0);
1208 case GTK_JUSTIFY_RIGHT:
1209 gtk_alignment_set (GTK_ALIGNMENT (alignment), 1.0, 0.5, 0.0, 0.0);
1212 case GTK_JUSTIFY_CENTER:
1213 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
1216 case GTK_JUSTIFY_FILL:
1217 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
1225 if (!GTK_CLIST_FROZEN (clist))
1226 draw_rows (clist, NULL);
1230 gtk_clist_set_column_width (GtkCList * clist,
1234 g_return_if_fail (clist != NULL);
1235 g_return_if_fail (GTK_IS_CLIST (clist));
1237 if (column < 0 || column >= clist->columns)
1240 clist->column[column].width = width;
1241 clist->column[column].width_set = TRUE;
1243 /* FIXME: this is quite expensive to do if the widget hasn't
1244 * been size_allocated yet, and pointless. Should
1247 size_allocate_columns (clist);
1248 size_allocate_title_buttons (clist);
1250 if (!GTK_CLIST_FROZEN (clist))
1252 adjust_scrollbars (clist);
1253 draw_rows (clist, NULL);
1258 gtk_clist_set_row_height (GtkCList * clist,
1263 g_return_if_fail (clist != NULL);
1264 g_return_if_fail (GTK_IS_CLIST (clist));
1267 clist->row_height = height;
1271 GTK_CLIST_SET_FLAG (clist, CLIST_ROW_HEIGHT_SET);
1273 if (GTK_WIDGET_REALIZED (clist))
1275 text_height = height - (GTK_WIDGET (clist)->style->font->ascent +
1276 GTK_WIDGET (clist) ->style->font->descent + 1);
1277 clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
1280 if (!GTK_CLIST_FROZEN (clist))
1282 adjust_scrollbars (clist);
1283 draw_rows (clist, NULL);
1288 gtk_clist_moveto (GtkCList * clist,
1294 g_return_if_fail (clist != NULL);
1295 g_return_if_fail (GTK_IS_CLIST (clist));
1297 if (row < -1 || row >= clist->rows)
1299 if (column < -1 || column >= clist->columns)
1302 row_align = CLAMP (row_align, 0, 1);
1303 col_align = CLAMP (col_align, 0, 1);
1305 /* adjust horizontal scrollbar */
1311 adj = GTK_RANGE (clist->hscrollbar)->adjustment;
1313 x = COLUMN_LEFT (clist, column) - CELL_SPACING - COLUMN_INSET -
1314 (col_align * (clist->clist_window_width - 2 * COLUMN_INSET -
1315 CELL_SPACING - clist->column[column].area.width));
1317 gtk_adjustment_set_value (adj, 0.0);
1318 else if (x > LIST_WIDTH (clist) - clist->clist_window_width)
1319 gtk_adjustment_set_value
1320 (adj, LIST_WIDTH (clist) - clist->clist_window_width);
1322 gtk_adjustment_set_value (adj, x);
1325 /* adjust vertical scrollbar */
1327 move_vertical (clist, row, row_align);
1331 gtk_clist_get_cell_type (GtkCList * clist,
1335 GtkCListRow *clist_row;
1337 g_return_val_if_fail (clist != NULL, -1);
1338 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1340 if (row < 0 || row >= clist->rows)
1342 if (column < 0 || column >= clist->columns)
1345 clist_row = (g_list_nth (clist->row_list, row))->data;
1347 return clist_row->cell[column].type;
1351 gtk_clist_set_text (GtkCList *clist,
1356 GtkCListRow *clist_row;
1358 g_return_if_fail (clist != NULL);
1359 g_return_if_fail (GTK_IS_CLIST (clist));
1361 if (row < 0 || row >= clist->rows)
1363 if (column < 0 || column >= clist->columns)
1366 clist_row = (g_list_nth (clist->row_list, row))->data;
1368 /* if text is null, then the cell is empty */
1369 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
1370 (clist, clist_row, column, GTK_CELL_TEXT, text, 0, NULL, NULL);
1372 /* redraw the list if it's not frozen */
1373 if (!GTK_CLIST_FROZEN (clist))
1375 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1376 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1381 gtk_clist_get_text (GtkCList * clist,
1386 GtkCListRow *clist_row;
1388 g_return_val_if_fail (clist != NULL, 0);
1389 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
1391 if (row < 0 || row >= clist->rows)
1393 if (column < 0 || column >= clist->columns)
1396 clist_row = (g_list_nth (clist->row_list, row))->data;
1398 if (clist_row->cell[column].type != GTK_CELL_TEXT)
1402 *text = GTK_CELL_TEXT (clist_row->cell[column])->text;
1408 gtk_clist_set_pixmap (GtkCList * clist,
1414 GtkCListRow *clist_row;
1416 g_return_if_fail (clist != NULL);
1417 g_return_if_fail (GTK_IS_CLIST (clist));
1419 if (row < 0 || row >= clist->rows)
1421 if (column < 0 || column >= clist->columns)
1424 clist_row = (g_list_nth (clist->row_list, row))->data;
1426 gdk_pixmap_ref (pixmap);
1428 if (mask) gdk_pixmap_ref (mask);
1430 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
1431 (clist, clist_row, column, GTK_CELL_PIXMAP, NULL, 0, pixmap, mask);
1433 /* redraw the list if it's not frozen */
1434 if (!GTK_CLIST_FROZEN (clist))
1436 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1437 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1442 gtk_clist_get_pixmap (GtkCList * clist,
1445 GdkPixmap ** pixmap,
1448 GtkCListRow *clist_row;
1450 g_return_val_if_fail (clist != NULL, 0);
1451 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
1453 if (row < 0 || row >= clist->rows)
1455 if (column < 0 || column >= clist->columns)
1458 clist_row = (g_list_nth (clist->row_list, row))->data;
1460 if (clist_row->cell[column].type != GTK_CELL_PIXMAP)
1465 *pixmap = GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap;
1466 /* mask can be NULL */
1467 *mask = GTK_CELL_PIXMAP (clist_row->cell[column])->mask;
1474 gtk_clist_set_pixtext (GtkCList *clist,
1482 GtkCListRow *clist_row;
1484 g_return_if_fail (clist != NULL);
1485 g_return_if_fail (GTK_IS_CLIST (clist));
1487 if (row < 0 || row >= clist->rows)
1489 if (column < 0 || column >= clist->columns)
1492 clist_row = (g_list_nth (clist->row_list, row))->data;
1494 gdk_pixmap_ref (pixmap);
1495 if (mask) gdk_pixmap_ref (mask);
1496 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
1497 (clist, clist_row, column, GTK_CELL_PIXTEXT, text, spacing, pixmap, mask);
1499 /* redraw the list if it's not frozen */
1500 if (!GTK_CLIST_FROZEN (clist))
1502 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1503 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1508 gtk_clist_get_pixtext (GtkCList * clist,
1513 GdkPixmap ** pixmap,
1516 GtkCListRow *clist_row;
1518 g_return_val_if_fail (clist != NULL, 0);
1519 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
1521 if (row < 0 || row >= clist->rows)
1523 if (column < 0 || column >= clist->columns)
1526 clist_row = (g_list_nth (clist->row_list, row))->data;
1528 if (clist_row->cell[column].type != GTK_CELL_PIXTEXT)
1532 *text = GTK_CELL_PIXTEXT (clist_row->cell[column])->text;
1534 *spacing = GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing;
1536 *pixmap = GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap;
1538 /* mask can be NULL */
1539 *mask = GTK_CELL_PIXTEXT (clist_row->cell[column])->mask;
1545 gtk_clist_set_foreground (GtkCList * clist,
1549 GtkCListRow *clist_row;
1551 g_return_if_fail (clist != NULL);
1552 g_return_if_fail (GTK_IS_CLIST (clist));
1554 if (row < 0 || row >= clist->rows)
1557 clist_row = (g_list_nth (clist->row_list, row))->data;
1561 clist_row->foreground = *color;
1562 clist_row->fg_set = TRUE;
1565 clist_row->fg_set = FALSE;
1567 if (!GTK_CLIST_FROZEN (clist)
1568 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1569 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1573 gtk_clist_set_background (GtkCList * clist,
1577 GtkCListRow *clist_row;
1579 g_return_if_fail (clist != NULL);
1580 g_return_if_fail (GTK_IS_CLIST (clist));
1582 if (row < 0 || row >= clist->rows)
1585 clist_row = (g_list_nth (clist->row_list, row))->data;
1589 clist_row->background = *color;
1590 clist_row->bg_set = TRUE;
1593 clist_row->bg_set = FALSE;
1595 if (!GTK_CLIST_FROZEN (clist)
1596 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1597 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1601 gtk_clist_set_shift (GtkCList * clist,
1607 GtkCListRow *clist_row;
1609 g_return_if_fail (clist != NULL);
1610 g_return_if_fail (GTK_IS_CLIST (clist));
1612 if (row < 0 || row >= clist->rows)
1614 if (column < 0 || column >= clist->columns)
1617 clist_row = (g_list_nth (clist->row_list, row))->data;
1619 clist_row->cell[column].vertical = vertical;
1620 clist_row->cell[column].horizontal = horizontal;
1622 if (!GTK_CLIST_FROZEN (clist)
1623 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1624 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1628 gtk_clist_set_selectable (GtkCList *clist,
1630 gboolean selectable)
1632 GtkCListRow *clist_row;
1634 g_return_if_fail (clist != NULL);
1635 g_return_if_fail (GTK_IS_CLIST (clist));
1637 if (row < 0 || row >= clist->rows)
1640 clist_row = (g_list_nth (clist->row_list, row))->data;
1642 if (selectable == clist_row->selectable)
1645 clist_row->selectable = selectable;
1647 if (!selectable && clist_row->state == GTK_STATE_SELECTED)
1649 if (clist->anchor >= 0 &&
1650 clist->selection_mode == GTK_SELECTION_EXTENDED)
1652 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist)))
1654 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
1655 gtk_grab_remove (GTK_WIDGET (clist));
1656 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1659 gtk_timeout_remove (clist->htimer);
1664 gtk_timeout_remove (clist->vtimer);
1668 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
1670 unselect_row (clist, row, -1, NULL);
1675 gtk_clist_get_selectable (GtkCList *clist,
1678 g_return_val_if_fail (clist != NULL, FALSE);
1679 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
1681 if (row < 0 || row >= clist->rows)
1684 return GTK_CLIST_ROW (g_list_nth (clist->row_list, row))->selectable;
1688 gtk_clist_prepend (GtkCList *clist,
1691 g_return_val_if_fail (clist != NULL, -1);
1692 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1693 g_return_val_if_fail (text != NULL, -1);
1695 return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, 0, text);
1699 gtk_clist_append (GtkCList *clist,
1702 g_return_val_if_fail (clist != NULL, -1);
1703 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1704 g_return_val_if_fail (text != NULL, -1);
1706 return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, clist->rows, text);
1710 gtk_clist_insert (GtkCList *clist,
1714 g_return_val_if_fail (clist != NULL, -1);
1715 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1716 g_return_val_if_fail (text != NULL, -1);
1718 if (row < 0 || row > clist->rows)
1721 return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, row, text);
1725 real_insert_row (GtkCList *clist,
1730 GtkCListRow *clist_row;
1732 g_return_val_if_fail (clist != NULL, -1);
1733 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1734 g_return_val_if_fail (text != NULL, -1);
1736 /* return if out of bounds */
1737 if (row < 0 || row > clist->rows)
1740 /* create the row */
1741 clist_row = row_new (clist);
1743 /* set the text in the row's columns */
1744 for (i = 0; i < clist->columns; i++)
1746 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
1747 (clist, clist_row, i, GTK_CELL_TEXT, text[i], 0, NULL ,NULL);
1751 clist->row_list = g_list_append (clist->row_list, clist_row);
1752 clist->row_list_end = clist->row_list;
1756 if (GTK_CLIST_AUTO_SORT (clist)) /* override insertion pos */
1761 work = clist->row_list;
1763 if (clist->sort_type == GTK_SORT_ASCENDING)
1765 while (row < clist->rows &&
1766 clist->compare (clist, clist_row,
1767 GTK_CLIST_ROW (work)) > 0)
1775 while (row < clist->rows &&
1776 clist->compare (clist, clist_row,
1777 GTK_CLIST_ROW (work)) < 0)
1785 /* reset the row end pointer if we're inserting at the end of the list */
1786 if (row == clist->rows)
1787 clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
1789 clist->row_list = g_list_insert (clist->row_list, clist_row, row);
1794 if (row < ROW_FROM_YPIXEL (clist, 0))
1795 clist->voffset -= (clist->row_height + CELL_SPACING);
1797 /* syncronize the selection list */
1798 sync_selection (clist, row, SYNC_INSERT);
1800 /* redraw the list if it isn't frozen */
1801 if (!GTK_CLIST_FROZEN (clist))
1803 adjust_scrollbars (clist);
1805 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1806 draw_rows (clist, NULL);
1813 gtk_clist_remove (GtkCList * clist,
1816 GTK_CLIST_CLASS_FW (clist)->remove_row (clist, row);
1820 real_remove_row (GtkCList * clist,
1823 gint was_visible, was_selected;
1825 GtkCListRow *clist_row;
1827 g_return_if_fail (clist != NULL);
1828 g_return_if_fail (GTK_IS_CLIST (clist));
1830 /* return if out of bounds */
1831 if (row < 0 || row > (clist->rows - 1))
1834 was_visible = (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE);
1837 /* get the row we're going to delete */
1838 list = g_list_nth (clist->row_list, row);
1839 clist_row = list->data;
1841 /* if we're removing a selected row, we have to make sure
1842 * it's properly unselected, and then sync up the clist->selected
1843 * list to reflect the deincrimented indexies of rows after the
1845 if (clist_row->state == GTK_STATE_SELECTED)
1847 switch (clist->selection_mode)
1849 case GTK_SELECTION_SINGLE:
1850 case GTK_SELECTION_MULTIPLE:
1851 case GTK_SELECTION_EXTENDED:
1852 unselect_row (clist, row, -1, NULL);
1855 case GTK_SELECTION_BROWSE:
1856 select_row (clist, row - 1, -1, NULL);
1864 /* reset the row end pointer if we're removing at the
1865 * end of the list */
1866 if (row == clist->rows - 1)
1867 clist->row_list_end = list->prev;
1868 if (row >= clist->focus_row && clist->focus_row >=0)
1871 clist->row_list = g_list_remove (clist->row_list, clist_row);
1874 if (row < ROW_FROM_YPIXEL (clist, 0))
1875 clist->voffset += clist->row_height + CELL_SPACING;
1877 sync_selection (clist, row, SYNC_REMOVE);
1880 row_delete (clist, clist_row);
1882 /* redraw the row if it isn't frozen */
1883 if (!GTK_CLIST_FROZEN (clist))
1885 adjust_scrollbars (clist);
1888 draw_rows (clist, NULL);
1893 sync_selection (GtkCList * clist,
1900 if (mode == SYNC_INSERT)
1905 if (clist->focus_row >= row)
1907 clist->focus_row += d;
1908 if (clist->focus_row == -1 && clist->rows >= 1)
1909 clist->focus_row = 0;
1912 if (clist->selection_mode == GTK_SELECTION_BROWSE && clist->anchor != -1)
1913 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
1915 g_list_free (clist->undo_selection);
1916 g_list_free (clist->undo_unselection);
1917 clist->undo_selection = NULL;
1918 clist->undo_unselection = NULL;
1921 clist->drag_pos = -1;
1922 clist->undo_anchor = clist->focus_row;
1924 list = clist->selection;
1927 if (GPOINTER_TO_INT (list->data) >= row)
1928 list->data = ((gchar*) list->data) + d;
1934 gtk_clist_clear (GtkCList * clist)
1936 g_return_if_fail (clist != NULL);
1937 g_return_if_fail (GTK_IS_CLIST (clist));
1939 GTK_CLIST_CLASS_FW (clist)->clear (clist);
1943 real_clear (GtkCList * clist)
1945 GList *list, *free_list;
1947 g_return_if_fail (clist != NULL);
1948 g_return_if_fail (GTK_IS_CLIST (clist));
1950 /* free up the selection list */
1951 g_list_free (clist->selection);
1952 g_list_free (clist->undo_selection);
1953 g_list_free (clist->undo_unselection);
1955 clist->selection = NULL;
1956 clist->selection_end = NULL;
1957 clist->undo_selection = NULL;
1958 clist->undo_unselection = NULL;
1960 clist->focus_row = -1;
1962 clist->undo_anchor = -1;
1963 clist->anchor_state = GTK_STATE_SELECTED;
1964 clist->drag_pos = -1;
1966 /* remove all the rows */
1967 free_list = clist->row_list;
1968 clist->row_list = NULL;
1969 clist->row_list_end = NULL;
1971 for (list = free_list; list; list = list->next)
1972 row_delete (clist, GTK_CLIST_ROW (list));
1973 g_list_free (free_list);
1975 /* zero-out the scrollbars */
1976 if (clist->vscrollbar)
1978 GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0;
1979 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
1981 if (!GTK_CLIST_FROZEN (clist))
1982 gtk_clist_thaw (clist);
1987 gtk_clist_swap_rows (GtkCList * clist,
1992 GList *list, *link1, *link2;
1995 g_return_if_fail (clist != NULL);
1996 g_return_if_fail (GTK_IS_CLIST (clist));
1998 if (GTK_CLIST_AUTO_SORT (clist))
2001 if (row1 < 0 || row1 > (clist->rows - 1))
2004 if (row2 < 0 || row2 > (clist->rows - 1))
2007 first = MIN (row1, row2);
2008 last = MAX (row1, row2);
2010 link1 = g_list_nth (clist->row_list, first);
2011 link2 = g_list_nth (link1, row2 - row1);
2014 link1->data = link2->data;
2017 list = clist->selection;
2020 if (GPOINTER_TO_INT (list->data) == row1)
2021 list->data = GINT_TO_POINTER (row2);
2023 if (GPOINTER_TO_INT (list->data) == row2)
2024 list->data = GINT_TO_POINTER (row1);
2029 if (!GTK_CLIST_FROZEN (clist))
2031 if (gtk_clist_row_is_visible (clist, row1) != GTK_VISIBILITY_NONE)
2032 GTK_CLIST_CLASS_FW (clist)->draw_row
2033 (clist, NULL, row1, GTK_CLIST_ROW (link2));
2035 if (gtk_clist_row_is_visible (clist, row2) != GTK_VISIBILITY_NONE)
2036 GTK_CLIST_CLASS_FW (clist)->draw_row
2037 (clist, NULL, row2, GTK_CLIST_ROW (link1));
2042 gtk_clist_set_row_data (GtkCList * clist,
2046 gtk_clist_set_row_data_full (clist, row, data, NULL);
2050 gtk_clist_set_row_data_full (GtkCList * clist,
2053 GtkDestroyNotify destroy)
2055 GtkCListRow *clist_row;
2057 g_return_if_fail (clist != NULL);
2058 g_return_if_fail (GTK_IS_CLIST (clist));
2060 if (row < 0 || row > (clist->rows - 1))
2063 clist_row = (g_list_nth (clist->row_list, row))->data;
2064 clist_row->data = data;
2065 clist_row->destroy = destroy;
2069 gtk_clist_get_row_data (GtkCList * clist,
2072 GtkCListRow *clist_row;
2074 g_return_val_if_fail (clist != NULL, NULL);
2075 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2077 if (row < 0 || row > (clist->rows - 1))
2080 clist_row = (g_list_nth (clist->row_list, row))->data;
2081 return clist_row->data;
2085 gtk_clist_find_row_from_data (GtkCList * clist,
2091 g_return_val_if_fail (clist != NULL, -1);
2092 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
2094 if (clist->rows < 1)
2095 return -1; /* is this an optimization or just worthless? */
2097 for (n = 0, list = clist->row_list; list; n++, list = list->next)
2098 if (GTK_CLIST_ROW (list)->data == data)
2105 gtk_clist_select_row (GtkCList * clist,
2109 g_return_if_fail (clist != NULL);
2110 g_return_if_fail (GTK_IS_CLIST (clist));
2112 if (row < 0 || row >= clist->rows)
2115 if (column < -1 || column >= clist->columns)
2118 select_row (clist, row, column, NULL);
2122 gtk_clist_unselect_row (GtkCList * clist,
2126 g_return_if_fail (clist != NULL);
2127 g_return_if_fail (GTK_IS_CLIST (clist));
2129 if (row < 0 || row >= clist->rows)
2132 if (column < -1 || column >= clist->columns)
2135 unselect_row (clist, row, column, NULL);
2139 gtk_clist_row_is_visible (GtkCList * clist,
2144 g_return_val_if_fail (clist != NULL, 0);
2145 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
2147 if (row < 0 || row >= clist->rows)
2148 return GTK_VISIBILITY_NONE;
2150 if (clist->row_height == 0)
2151 return GTK_VISIBILITY_NONE;
2153 if (row < ROW_FROM_YPIXEL (clist, 0))
2154 return GTK_VISIBILITY_NONE;
2156 if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height))
2157 return GTK_VISIBILITY_NONE;
2159 top = ROW_TOP_YPIXEL (clist, row);
2162 || ((top + clist->row_height) >= clist->clist_window_height))
2163 return GTK_VISIBILITY_PARTIAL;
2165 return GTK_VISIBILITY_FULL;
2169 static GtkAdjustment*
2170 gtk_clist_get_vadjustment (GtkCList * clist)
2172 g_return_val_if_fail (clist != NULL, NULL);
2173 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2175 return gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
2178 static GtkAdjustment*
2179 gtk_clist_get_hadjustment (GtkCList * clist)
2181 g_return_val_if_fail (clist != NULL, NULL);
2182 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2184 return gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
2189 gtk_clist_set_policy (GtkCList * clist,
2190 GtkPolicyType vscrollbar_policy,
2191 GtkPolicyType hscrollbar_policy)
2193 g_return_if_fail (clist != NULL);
2194 g_return_if_fail (GTK_IS_CLIST (clist));
2196 if (clist->vscrollbar_policy != vscrollbar_policy)
2198 clist->vscrollbar_policy = vscrollbar_policy;
2200 if (GTK_WIDGET (clist)->parent)
2201 gtk_widget_queue_resize (GTK_WIDGET (clist));
2204 if (clist->hscrollbar_policy != hscrollbar_policy)
2206 clist->hscrollbar_policy = hscrollbar_policy;
2208 if (GTK_WIDGET (clist)->parent)
2209 gtk_widget_queue_resize (GTK_WIDGET (clist));
2214 gtk_clist_undo_selection (GtkCList *clist)
2216 g_return_if_fail (clist != NULL);
2217 g_return_if_fail (GTK_IS_CLIST (clist));
2219 if (clist->selection_mode == GTK_SELECTION_EXTENDED &&
2220 (clist->undo_selection || clist->undo_unselection))
2221 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNDO_SELECTION]);
2225 real_undo_selection (GtkCList *clist)
2229 g_return_if_fail (clist != NULL);
2230 g_return_if_fail (GTK_IS_CLIST (clist));
2232 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
2233 clist->selection_mode != GTK_SELECTION_EXTENDED)
2236 if (clist->anchor >= 0)
2237 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
2239 if (!(clist->undo_selection || clist->undo_unselection))
2241 gtk_clist_unselect_all (clist);
2245 for (work = clist->undo_selection; work; work = work->next)
2246 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
2247 GPOINTER_TO_INT (work->data), -1, NULL);
2249 for (work = clist->undo_unselection; work; work = work->next)
2250 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
2251 GPOINTER_TO_INT (work->data), -1, NULL);
2253 if (GTK_WIDGET_HAS_FOCUS (clist) && clist->focus_row != clist->undo_anchor)
2255 gtk_clist_draw_focus (GTK_WIDGET (clist));
2256 clist->focus_row = clist->undo_anchor;
2257 gtk_clist_draw_focus (GTK_WIDGET (clist));
2260 clist->focus_row = clist->undo_anchor;
2262 clist->undo_anchor = -1;
2264 g_list_free (clist->undo_selection);
2265 g_list_free (clist->undo_unselection);
2266 clist->undo_selection = NULL;
2267 clist->undo_unselection = NULL;
2269 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
2270 clist->clist_window_height)
2271 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
2272 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
2273 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
2279 * gtk_clist_finalize
2282 gtk_clist_destroy (GtkObject * object)
2287 g_return_if_fail (object != NULL);
2288 g_return_if_fail (GTK_IS_CLIST (object));
2290 clist = GTK_CLIST (object);
2292 /* freeze the list */
2293 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2295 /* get rid of all the rows */
2296 gtk_clist_clear (clist);
2298 /* Since we don't have a _remove method, unparent the children
2299 * instead of destroying them so the focus will be unset properly.
2300 * (For other containers, the _remove method takes care of the
2301 * unparent) The destroy will happen when the refcount drops
2305 /* destroy the scrollbars */
2306 if (clist->vscrollbar)
2308 gtk_widget_unparent (clist->vscrollbar);
2309 clist->vscrollbar = NULL;
2311 if (clist->hscrollbar)
2313 gtk_widget_unparent (clist->hscrollbar);
2314 clist->hscrollbar = NULL;
2319 gtk_timeout_remove (clist->htimer);
2324 gtk_timeout_remove (clist->vtimer);
2328 /* destroy the column buttons */
2329 for (i = 0; i < clist->columns; i++)
2330 if (clist->column[i].button)
2332 gtk_widget_unparent (clist->column[i].button);
2333 clist->column[i].button = NULL;
2336 if (GTK_OBJECT_CLASS (parent_class)->destroy)
2337 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2341 gtk_clist_finalize (GtkObject * object)
2345 g_return_if_fail (object != NULL);
2346 g_return_if_fail (GTK_IS_CLIST (object));
2348 clist = GTK_CLIST (object);
2350 columns_delete (clist);
2352 g_mem_chunk_destroy (clist->cell_mem_chunk);
2353 g_mem_chunk_destroy (clist->row_mem_chunk);
2355 if (GTK_OBJECT_CLASS (parent_class)->finalize)
2356 (*GTK_OBJECT_CLASS (parent_class)->finalize) (object);
2362 * gtk_clist_unrealize
2367 * gtk_clist_button_press
2368 * gtk_clist_button_release
2370 * gtk_clist_size_request
2371 * gtk_clist_size_allocate
2374 gtk_clist_realize (GtkWidget * widget)
2378 GdkWindowAttr attributes;
2379 gint attributes_mask;
2383 g_return_if_fail (widget != NULL);
2384 g_return_if_fail (GTK_IS_CLIST (widget));
2386 clist = GTK_CLIST (widget);
2388 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2390 add_style_data (clist);
2392 border_width = GTK_CONTAINER (widget)->border_width;
2394 attributes.window_type = GDK_WINDOW_CHILD;
2395 attributes.x = widget->allocation.x + border_width;
2396 attributes.y = widget->allocation.y + border_width;
2397 attributes.width = widget->allocation.width - border_width * 2;
2398 attributes.height = widget->allocation.height - border_width * 2;
2399 attributes.wclass = GDK_INPUT_OUTPUT;
2400 attributes.visual = gtk_widget_get_visual (widget);
2401 attributes.colormap = gtk_widget_get_colormap (widget);
2402 attributes.event_mask = gtk_widget_get_events (widget);
2403 attributes.event_mask |= (GDK_EXPOSURE_MASK |
2404 GDK_BUTTON_PRESS_MASK |
2405 GDK_BUTTON_RELEASE_MASK |
2406 GDK_KEY_PRESS_MASK |
2407 GDK_KEY_RELEASE_MASK);
2408 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2411 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
2412 gdk_window_set_user_data (widget->window, clist);
2414 widget->style = gtk_style_attach (widget->style, widget->window);
2416 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
2418 /* column-title window */
2420 attributes.x = clist->column_title_area.x;
2421 attributes.y = clist->column_title_area.y;
2422 attributes.width = clist->column_title_area.width;
2423 attributes.height = clist->column_title_area.height;
2425 clist->title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2426 gdk_window_set_user_data (clist->title_window, clist);
2428 gtk_style_set_background (widget->style, clist->title_window, GTK_STATE_SELECTED);
2429 gdk_window_show (clist->title_window);
2431 /* set things up so column buttons are drawn in title window */
2432 for (i = 0; i < clist->columns; i++)
2433 if (clist->column[i].button)
2434 gtk_widget_set_parent_window (clist->column[i].button, clist->title_window);
2437 attributes.x = clist->internal_allocation.x + widget->style->klass->xthickness;
2438 attributes.y = clist->internal_allocation.y + widget->style->klass->ythickness +
2439 clist->column_title_area.height;
2440 attributes.width = clist->clist_window_width;
2441 attributes.height = clist->clist_window_height;
2443 clist->clist_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2444 gdk_window_set_user_data (clist->clist_window, clist);
2446 gdk_window_set_background (clist->clist_window, &widget->style->bg[GTK_STATE_PRELIGHT]);
2447 gdk_window_show (clist->clist_window);
2448 gdk_window_get_size (clist->clist_window, &clist->clist_window_width,
2449 &clist->clist_window_height);
2451 /* create resize windows */
2452 attributes.wclass = GDK_INPUT_ONLY;
2453 attributes.event_mask = (GDK_BUTTON_PRESS_MASK |
2454 GDK_BUTTON_RELEASE_MASK |
2455 GDK_POINTER_MOTION_MASK |
2456 GDK_POINTER_MOTION_HINT_MASK |
2457 GDK_KEY_PRESS_MASK);
2458 attributes.cursor = clist->cursor_drag = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
2459 attributes_mask = GDK_WA_CURSOR;
2461 for (i = 0; i < clist->columns; i++)
2463 clist->column[i].window = gdk_window_new (clist->title_window, &attributes, attributes_mask);
2464 gdk_window_set_user_data (clist->column[i].window, clist);
2467 /* This is slightly less efficient than creating them with the
2468 * right size to begin with, but easier
2470 size_allocate_title_buttons (clist);
2473 clist->fg_gc = gdk_gc_new (widget->window);
2474 clist->bg_gc = gdk_gc_new (widget->window);
2476 /* We'll use this gc to do scrolling as well */
2477 gdk_gc_set_exposures (clist->fg_gc, TRUE);
2479 values.foreground = widget->style->white;
2480 values.function = GDK_XOR;
2481 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
2482 clist->xor_gc = gdk_gc_new_with_values (widget->window,
2490 gtk_clist_unrealize (GtkWidget * widget)
2495 g_return_if_fail (widget != NULL);
2496 g_return_if_fail (GTK_IS_CLIST (widget));
2498 clist = GTK_CLIST (widget);
2500 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2502 gdk_cursor_destroy (clist->cursor_drag);
2503 gdk_gc_destroy (clist->xor_gc);
2504 gdk_gc_destroy (clist->fg_gc);
2505 gdk_gc_destroy (clist->bg_gc);
2507 for (i = 0; i < clist->columns; i++)
2508 if (clist->column[i].window)
2510 gdk_window_set_user_data (clist->column[i].window, NULL);
2511 gdk_window_destroy (clist->column[i].window);
2512 clist->column[i].window = NULL;
2515 gdk_window_set_user_data (clist->clist_window, NULL);
2516 gdk_window_destroy (clist->clist_window);
2517 clist->clist_window = NULL;
2519 gdk_window_set_user_data (clist->title_window, NULL);
2520 gdk_window_destroy (clist->title_window);
2521 clist->title_window = NULL;
2523 clist->cursor_drag = NULL;
2524 clist->xor_gc = NULL;
2525 clist->fg_gc = NULL;
2526 clist->bg_gc = NULL;
2528 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
2529 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2533 gtk_clist_map (GtkWidget * widget)
2538 g_return_if_fail (widget != NULL);
2539 g_return_if_fail (GTK_IS_CLIST (widget));
2541 clist = GTK_CLIST (widget);
2543 if (!GTK_WIDGET_MAPPED (widget))
2545 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
2547 gdk_window_show (widget->window);
2548 gdk_window_show (clist->title_window);
2549 gdk_window_show (clist->clist_window);
2551 /* map column buttons */
2552 for (i = 0; i < clist->columns; i++)
2553 if (clist->column[i].button &&
2554 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
2555 !GTK_WIDGET_MAPPED (clist->column[i].button))
2556 gtk_widget_map (clist->column[i].button);
2558 /* map resize windows AFTER column buttons (above) */
2559 for (i = 0; i < clist->columns; i++)
2560 if (clist->column[i].window && clist->column[i].button)
2561 gdk_window_show (clist->column[i].window);
2563 /* map vscrollbars */
2564 if (GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
2565 !GTK_WIDGET_MAPPED (clist->vscrollbar))
2566 gtk_widget_map (clist->vscrollbar);
2568 if (GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
2569 !GTK_WIDGET_MAPPED (clist->hscrollbar))
2570 gtk_widget_map (clist->hscrollbar);
2572 /* unfreeze the list */
2573 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
2578 gtk_clist_unmap (GtkWidget * widget)
2583 g_return_if_fail (widget != NULL);
2584 g_return_if_fail (GTK_IS_CLIST (widget));
2586 clist = GTK_CLIST (widget);
2588 if (GTK_WIDGET_MAPPED (widget))
2590 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
2592 for (i = 0; i < clist->columns; i++)
2593 if (clist->column[i].window)
2594 gdk_window_hide (clist->column[i].window);
2596 gdk_window_hide (clist->clist_window);
2597 gdk_window_hide (clist->title_window);
2598 gdk_window_hide (widget->window);
2600 /* unmap scrollbars */
2601 if (GTK_WIDGET_MAPPED (clist->vscrollbar))
2602 gtk_widget_unmap (clist->vscrollbar);
2604 if (GTK_WIDGET_MAPPED (clist->hscrollbar))
2605 gtk_widget_unmap (clist->hscrollbar);
2607 /* unmap column buttons */
2608 for (i = 0; i < clist->columns; i++)
2609 if (clist->column[i].button &&
2610 GTK_WIDGET_MAPPED (clist->column[i].button))
2611 gtk_widget_unmap (clist->column[i].button);
2613 /* freeze the list */
2614 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2619 gtk_clist_draw (GtkWidget * widget,
2620 GdkRectangle * area)
2624 GdkRectangle child_area;
2627 g_return_if_fail (widget != NULL);
2628 g_return_if_fail (GTK_IS_CLIST (widget));
2629 g_return_if_fail (area != NULL);
2631 if (GTK_WIDGET_DRAWABLE (widget))
2633 clist = GTK_CLIST (widget);
2634 border_width = GTK_CONTAINER (widget)->border_width;
2636 gdk_window_clear_area (widget->window,
2637 area->x - border_width,
2638 area->y - border_width,
2639 area->width, area->height);
2641 /* draw list shadow/border */
2642 gtk_draw_shadow (widget->style, widget->window,
2643 GTK_STATE_NORMAL, clist->shadow_type,
2645 clist->clist_window_width + (2 * widget->style->klass->xthickness),
2646 clist->clist_window_height + (2 * widget->style->klass->ythickness) +
2647 clist->column_title_area.height);
2649 gdk_window_clear_area (clist->clist_window,
2652 draw_rows (clist, NULL);
2654 for (i = 0; i < clist->columns; i++)
2656 if (gtk_widget_intersect (clist->column[i].button, area, &child_area))
2657 gtk_widget_draw (clist->column[i].button, &child_area);
2663 gtk_clist_expose (GtkWidget * widget,
2664 GdkEventExpose * event)
2668 g_return_val_if_fail (widget != NULL, FALSE);
2669 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2670 g_return_val_if_fail (event != NULL, FALSE);
2672 if (GTK_WIDGET_DRAWABLE (widget))
2674 clist = GTK_CLIST (widget);
2677 if (event->window == widget->window)
2678 gtk_draw_shadow (widget->style, widget->window,
2679 GTK_STATE_NORMAL, clist->shadow_type,
2681 clist->clist_window_width + (2 * widget->style->klass->xthickness),
2682 clist->clist_window_height + (2 * widget->style->klass->ythickness) +
2683 clist->column_title_area.height);
2685 /* exposure events on the list */
2686 if (event->window == clist->clist_window)
2687 draw_rows (clist, &event->area);
2694 gtk_clist_button_press (GtkWidget * widget,
2695 GdkEventButton * event)
2704 g_return_val_if_fail (widget != NULL, FALSE);
2705 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2706 g_return_val_if_fail (event != NULL, FALSE);
2708 clist = GTK_CLIST (widget);
2710 /* we don't handle button 2 and 3 */
2711 if (event->button != 1)
2714 /* selections on the list */
2715 if (event->window == clist->clist_window)
2720 if (get_selection_info (clist, x, y, &row, &column))
2722 gint old_row = clist->focus_row;
2724 if (clist->focus_row == -1)
2727 if (event->type == GDK_BUTTON_PRESS)
2729 GTK_CLIST_SET_FLAG (clist, CLIST_DRAG_SELECTION);
2730 gdk_pointer_grab (clist->clist_window, FALSE,
2731 GDK_POINTER_MOTION_HINT_MASK |
2732 GDK_BUTTON1_MOTION_MASK |
2733 GDK_BUTTON_RELEASE_MASK,
2734 NULL, NULL, event->time);
2735 gtk_grab_add (widget);
2737 else if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (widget))
2739 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
2740 gtk_grab_remove (widget);
2741 gdk_pointer_ungrab (event->time);
2744 if (GTK_CLIST_ADD_MODE (clist))
2746 GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
2747 if (GTK_WIDGET_HAS_FOCUS (widget))
2749 gtk_clist_draw_focus (widget);
2750 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2751 GDK_LINE_SOLID, 0, 0);
2752 clist->focus_row = row;
2753 gtk_clist_draw_focus (widget);
2757 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2758 GDK_LINE_SOLID, 0, 0);
2759 clist->focus_row = row;
2762 else if (row != clist->focus_row)
2764 if (GTK_WIDGET_HAS_FOCUS (widget))
2766 gtk_clist_draw_focus (widget);
2767 clist->focus_row = row;
2768 gtk_clist_draw_focus (widget);
2771 clist->focus_row = row;
2774 if (!GTK_WIDGET_HAS_FOCUS (widget))
2775 gtk_widget_grab_focus (widget);
2777 switch (clist->selection_mode)
2779 case GTK_SELECTION_SINGLE:
2780 case GTK_SELECTION_MULTIPLE:
2781 if (event->type != GDK_BUTTON_PRESS)
2782 select_row (clist, row, column, (GdkEvent *) event);
2784 clist->anchor = row;
2787 case GTK_SELECTION_BROWSE:
2788 select_row (clist, row, column, (GdkEvent *) event);
2791 case GTK_SELECTION_EXTENDED:
2792 if (event->type != GDK_BUTTON_PRESS)
2794 if (clist->anchor != -1)
2796 update_extended_selection (clist, clist->focus_row);
2797 GTK_CLIST_CLASS_FW (clist)->resync_selection
2798 (clist, (GdkEvent *) event);
2800 select_row (clist, row, column, (GdkEvent *) event);
2804 if (event->state & GDK_CONTROL_MASK)
2806 if (event->state & GDK_SHIFT_MASK)
2808 if (clist->anchor < 0)
2810 g_list_free (clist->undo_selection);
2811 g_list_free (clist->undo_unselection);
2812 clist->undo_selection = NULL;
2813 clist->undo_unselection = NULL;
2814 clist->anchor = old_row;
2815 clist->drag_pos = old_row;
2816 clist->undo_anchor = old_row;
2818 update_extended_selection (clist, clist->focus_row);
2822 if (clist->anchor == -1)
2823 set_anchor (clist, TRUE, row, old_row);
2825 update_extended_selection (clist, clist->focus_row);
2830 if (event->state & GDK_SHIFT_MASK)
2832 set_anchor (clist, FALSE, old_row, old_row);
2833 update_extended_selection (clist, clist->focus_row);
2837 if (clist->anchor == -1)
2838 set_anchor (clist, FALSE, row, old_row);
2840 update_extended_selection (clist, clist->focus_row);
2851 /* press on resize windows */
2852 for (i = 0; i < clist->columns; i++)
2853 if (clist->column[i].window && event->window == clist->column[i].window)
2855 gdk_pointer_grab (clist->column[i].window, FALSE,
2856 GDK_POINTER_MOTION_HINT_MASK |
2857 GDK_BUTTON1_MOTION_MASK |
2858 GDK_BUTTON_RELEASE_MASK,
2859 NULL, NULL, event->time);
2860 gtk_grab_add (widget);
2861 GTK_CLIST_SET_FLAG (clist, CLIST_IN_DRAG);
2863 if (!GTK_WIDGET_HAS_FOCUS (widget))
2864 gtk_widget_grab_focus (widget);
2866 clist->drag_pos = i;
2867 clist->x_drag = (COLUMN_LEFT_XPIXEL(clist, i) + COLUMN_INSET +
2868 clist->column[i].area.width + CELL_SPACING);
2870 if (GTK_CLIST_ADD_MODE (clist))
2871 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
2872 draw_xor_line (clist);
2881 gtk_clist_button_release (GtkWidget * widget,
2882 GdkEventButton * event)
2886 g_return_val_if_fail (widget != NULL, FALSE);
2887 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2888 g_return_val_if_fail (event != NULL, FALSE);
2890 clist = GTK_CLIST (widget);
2892 /* we don't handle button 2 and 3 */
2893 if (event->button != 1)
2896 /* release on resize windows */
2897 if (GTK_CLIST_IN_DRAG (clist))
2899 gint i, x, width, visible;
2901 i = clist->drag_pos;
2902 clist->drag_pos = -1;
2903 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
2904 gtk_widget_get_pointer (widget, &x, NULL);
2906 width = new_column_width (clist, i, &x, &visible);
2907 gtk_grab_remove (widget);
2908 gdk_pointer_ungrab (event->time);
2911 draw_xor_line (clist);
2913 if (GTK_CLIST_ADD_MODE (clist))
2915 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2916 GDK_LINE_ON_OFF_DASH, 0, 0);
2917 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
2920 resize_column (clist, i, width);
2924 if (GTK_CLIST_DRAG_SELECTION (clist))
2929 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
2930 gtk_grab_remove (widget);
2931 gdk_pointer_ungrab (event->time);
2934 gtk_timeout_remove (clist->htimer);
2939 gtk_timeout_remove (clist->vtimer);
2942 switch (clist->selection_mode)
2944 case GTK_SELECTION_EXTENDED:
2945 if (!(event->state & GDK_SHIFT_MASK) ||
2946 event->x < 0 || event->x >= clist->clist_window_width ||
2947 event->y < 0 || event->y >= clist->clist_window_height)
2948 GTK_CLIST_CLASS_FW (clist)->resync_selection
2949 (clist, (GdkEvent *) event);
2952 case GTK_SELECTION_SINGLE:
2953 case GTK_SELECTION_MULTIPLE:
2954 if (get_selection_info (clist, event->x, event->y, &row, &column))
2956 if (clist->anchor == clist->focus_row)
2957 toggle_row (clist, row, column, (GdkEvent *) event);
2971 horizontal_timeout (GtkCList *clist)
2974 GdkEventMotion event;
2975 GdkModifierType mask;
2977 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
2980 gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
2987 gtk_clist_motion (GTK_WIDGET (clist), &event);
2993 vertical_timeout (GtkCList *clist)
2996 GdkEventMotion event;
2997 GdkModifierType mask;
2999 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
3002 gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
3009 gtk_clist_motion (GTK_WIDGET (clist), &event);
3015 move_vertical (GtkCList *clist,
3022 adj = GTK_RANGE (clist->vscrollbar)->adjustment;
3024 y = ROW_TOP_YPIXEL (clist, row) - clist->voffset;
3026 y = y - align * (clist->clist_window_height - clist->row_height)
3027 + (2 * align - 1) * CELL_SPACING;
3029 if (y + adj->page_size > adj->upper)
3030 adj->value = adj->upper - adj->page_size;
3034 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
3038 move_horizontal (GtkCList *clist,
3044 adj = GTK_RANGE (clist->hscrollbar)->adjustment;
3048 upper = adj->upper - adj->page_size;
3049 adj->value = MIN (adj->value, upper);
3050 adj->value = MAX (adj->value, 0.0);
3052 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
3056 gtk_clist_motion (GtkWidget * widget,
3057 GdkEventMotion * event)
3065 g_return_val_if_fail (widget != NULL, FALSE);
3066 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
3068 clist = GTK_CLIST (widget);
3070 if (!(gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)))
3073 if (GTK_CLIST_IN_DRAG (clist))
3075 if (event->is_hint || event->window != widget->window)
3076 gtk_widget_get_pointer (widget, &x, NULL);
3080 new_width = new_column_width (clist, clist->drag_pos, &x, &visible);
3081 /* Welcome to my hack! I'm going to use a value of x_drag = -99999
3082 * to indicate that the xor line is already invisible */
3084 if (!visible && clist->x_drag != -99999)
3086 draw_xor_line (clist);
3087 clist->x_drag = -99999;
3090 if (x != clist->x_drag && visible)
3092 if (clist->x_drag != -99999)
3093 draw_xor_line (clist);
3096 draw_xor_line (clist);
3099 if (new_width <= COLUMN_MIN_WIDTH + 1)
3101 if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) && x < 0)
3102 gtk_clist_moveto (clist, -1, clist->drag_pos, 0, 0);
3108 if (event->is_hint || event->window != clist->clist_window)
3109 gdk_window_get_pointer (clist->clist_window, &x, &y, NULL);
3111 /* horizontal autoscrolling */
3112 if (LIST_WIDTH (clist) > clist->clist_window_width &&
3113 (x < 0 || x >= clist->clist_window_width))
3118 clist->htimer = gtk_timeout_add
3119 (SCROLL_TIME, (GtkFunction) horizontal_timeout, clist);
3121 if (!((x < 0 && GTK_RANGE (clist->hscrollbar)->adjustment->value == 0) ||
3122 (x >= clist->clist_window_width &&
3123 GTK_RANGE (clist->hscrollbar)->adjustment->value ==
3124 LIST_WIDTH (clist) - clist->clist_window_width)))
3127 move_horizontal (clist, -1 + (x/2));
3129 move_horizontal (clist, 1 + (x - clist->clist_window_width) / 2);
3133 if (GTK_CLIST_IN_DRAG (clist))
3136 /* vertical autoscrolling */
3137 row = ROW_FROM_YPIXEL (clist, y);
3139 /* don't scroll on last pixel row if it's a cell spacing */
3140 if (y == clist->clist_window_height-1 &&
3141 y == ROW_TOP_YPIXEL (clist, row-1) + clist->row_height)
3144 if (LIST_HEIGHT (clist) > clist->clist_window_height &&
3145 (y < 0 || y >= clist->clist_window_height))
3150 clist->vtimer = gtk_timeout_add (SCROLL_TIME,
3151 (GtkFunction) vertical_timeout, clist);
3153 if (GTK_CLIST_DRAG_SELECTION (clist))
3155 if ((y < 0 && clist->focus_row == 0) ||
3156 (y >= clist->clist_window_height &&
3157 clist->focus_row == clist->rows-1))
3162 row = CLAMP (row, 0, clist->rows - 1);
3164 if (GTK_CLIST_DRAG_SELECTION (clist))
3166 if (row == clist->focus_row)
3169 gtk_clist_draw_focus (widget);
3170 clist->focus_row = row;
3171 gtk_clist_draw_focus (widget);
3173 switch (clist->selection_mode)
3175 case GTK_SELECTION_BROWSE:
3176 select_row (clist, clist->focus_row, - 1, (GdkEvent *) event);
3179 case GTK_SELECTION_EXTENDED:
3180 update_extended_selection (clist, clist->focus_row);
3188 if (ROW_TOP_YPIXEL(clist, row) < 0)
3189 move_vertical (clist, row, 0);
3190 else if (ROW_TOP_YPIXEL(clist, row) + clist->row_height >
3191 clist->clist_window_height)
3192 move_vertical (clist, row, 1);
3198 gtk_clist_size_request (GtkWidget * widget,
3199 GtkRequisition * requisition)
3204 g_return_if_fail (widget != NULL);
3205 g_return_if_fail (GTK_IS_CLIST (widget));
3206 g_return_if_fail (requisition != NULL);
3208 clist = GTK_CLIST (widget);
3210 add_style_data (clist);
3212 requisition->width = 0;
3213 requisition->height = 0;
3215 /* compute the size of the column title (title) area */
3216 clist->column_title_area.height = 0;
3217 if (GTK_CLIST_SHOW_TITLES (clist))
3218 for (i = 0; i < clist->columns; i++)
3219 if (clist->column[i].button)
3221 gtk_widget_size_request (clist->column[i].button, &clist->column[i].button->requisition);
3222 clist->column_title_area.height = MAX (clist->column_title_area.height,
3223 clist->column[i].button->requisition.height);
3225 requisition->height += clist->column_title_area.height;
3227 /* add the vscrollbar space */
3228 if ((clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
3229 GTK_WIDGET_VISIBLE (clist->vscrollbar))
3231 gtk_widget_size_request (clist->vscrollbar, &clist->vscrollbar->requisition);
3233 requisition->width += clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist);
3234 requisition->height = MAX (requisition->height,
3235 clist->vscrollbar->requisition.height);
3238 /* add the hscrollbar space */
3239 if ((clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
3240 GTK_WIDGET_VISIBLE (clist->hscrollbar))
3242 gtk_widget_size_request (clist->hscrollbar, &clist->hscrollbar->requisition);
3244 requisition->height += clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist);
3245 requisition->width = MAX (clist->hscrollbar->requisition.width,
3246 requisition->width -
3247 clist->vscrollbar->requisition.width);
3251 requisition->width += widget->style->klass->xthickness * 2 +
3252 GTK_CONTAINER (widget)->border_width * 2;
3253 requisition->height += widget->style->klass->ythickness * 2 +
3254 GTK_CONTAINER (widget)->border_width * 2;
3258 gtk_clist_size_allocate (GtkWidget * widget,
3259 GtkAllocation * allocation)
3262 GtkAllocation clist_allocation;
3263 GtkAllocation child_allocation;
3264 gint i, vscrollbar_vis, hscrollbar_vis;
3266 g_return_if_fail (widget != NULL);
3267 g_return_if_fail (GTK_IS_CLIST (widget));
3268 g_return_if_fail (allocation != NULL);
3270 clist = GTK_CLIST (widget);
3271 widget->allocation = *allocation;
3273 if (GTK_WIDGET_REALIZED (widget))
3275 gdk_window_move_resize (widget->window,
3276 allocation->x + GTK_CONTAINER (widget)->border_width,
3277 allocation->y + GTK_CONTAINER (widget)->border_width,
3278 allocation->width - GTK_CONTAINER (widget)->border_width * 2,
3279 allocation->height - GTK_CONTAINER (widget)->border_width * 2);
3282 /* use internal allocation structure for all the math
3283 * because it's easier than always subtracting the container
3285 clist->internal_allocation.x = 0;
3286 clist->internal_allocation.y = 0;
3287 clist->internal_allocation.width = MAX (1, allocation->width -
3288 GTK_CONTAINER (widget)->border_width * 2);
3289 clist->internal_allocation.height = MAX (1, allocation->height -
3290 GTK_CONTAINER (widget)->border_width * 2);
3292 /* allocate clist window assuming no scrollbars */
3293 clist_allocation.x = clist->internal_allocation.x + widget->style->klass->xthickness;
3294 clist_allocation.y = clist->internal_allocation.y + widget->style->klass->ythickness +
3295 clist->column_title_area.height;
3296 clist_allocation.width = MAX (1, clist->internal_allocation.width -
3297 (2 * widget->style->klass->xthickness));
3298 clist_allocation.height = MAX (1, clist->internal_allocation.height -
3299 (2 * widget->style->klass->ythickness) -
3300 clist->column_title_area.height);
3303 * here's where we decide to show/not show the scrollbars
3308 for (i = 0; i <= 1; i++)
3310 if (LIST_HEIGHT (clist) <= clist_allocation.height &&
3311 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
3317 if (!vscrollbar_vis)
3320 clist_allocation.width = MAX (1, clist_allocation.width -
3321 (clist->vscrollbar->requisition.width +
3322 SCROLLBAR_SPACING (clist)));
3326 if (LIST_WIDTH (clist) <= clist_allocation.width &&
3327 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
3333 if (!hscrollbar_vis)
3336 clist_allocation.height = MAX (1, clist_allocation.height -
3337 (clist->hscrollbar->requisition.height +
3338 SCROLLBAR_SPACING (clist)));
3343 clist->clist_window_width = clist_allocation.width;
3344 clist->clist_window_height = clist_allocation.height;
3346 if (GTK_WIDGET_REALIZED (widget))
3348 gdk_window_move_resize (clist->clist_window,
3351 clist_allocation.width,
3352 clist_allocation.height);
3355 /* position the window which holds the column title buttons */
3356 clist->column_title_area.x = widget->style->klass->xthickness;
3357 clist->column_title_area.y = widget->style->klass->ythickness;
3358 clist->column_title_area.width = clist_allocation.width;
3360 if (GTK_WIDGET_REALIZED (widget))
3362 gdk_window_move_resize (clist->title_window,
3363 clist->column_title_area.x,
3364 clist->column_title_area.y,
3365 clist->column_title_area.width,
3366 clist->column_title_area.height);
3369 /* column button allocation */
3370 size_allocate_columns (clist);
3371 size_allocate_title_buttons (clist);
3373 adjust_scrollbars (clist);
3375 /* allocate the vscrollbar */
3378 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
3379 gtk_widget_show (clist->vscrollbar);
3381 child_allocation.x = clist->internal_allocation.x +
3382 clist->internal_allocation.width -
3383 clist->vscrollbar->requisition.width;
3384 child_allocation.y = clist->internal_allocation.y;
3385 child_allocation.width = clist->vscrollbar->requisition.width;
3386 child_allocation.height = MAX (1, clist->internal_allocation.height -
3387 (hscrollbar_vis ? (clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist)) : 0));
3389 gtk_widget_size_allocate (clist->vscrollbar, &child_allocation);
3393 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
3394 gtk_widget_hide (clist->vscrollbar);
3399 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
3400 gtk_widget_show (clist->hscrollbar);
3402 child_allocation.x = clist->internal_allocation.x;
3403 child_allocation.y = clist->internal_allocation.y +
3404 clist->internal_allocation.height -
3405 clist->hscrollbar->requisition.height;
3406 child_allocation.width = MAX (1, clist->internal_allocation.width -
3407 (vscrollbar_vis ? (clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist)) : 0));
3408 child_allocation.height = clist->hscrollbar->requisition.height;
3410 gtk_widget_size_allocate (clist->hscrollbar, &child_allocation);
3414 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
3415 gtk_widget_hide (clist->hscrollbar);
3418 /* set the vscrollbar adjustments */
3419 adjust_scrollbars (clist);
3427 gtk_clist_forall (GtkContainer *container,
3428 gboolean include_internals,
3429 GtkCallback callback,
3430 gpointer callback_data)
3434 g_return_if_fail (container != NULL);
3435 g_return_if_fail (GTK_IS_CLIST (container));
3436 g_return_if_fail (callback != NULL);
3438 clist = GTK_CLIST (container);
3440 if (include_internals)
3444 /* callback for the column buttons */
3445 for (i = 0; i < clist->columns; i++)
3446 if (clist->column[i].button)
3447 (*callback) (clist->column[i].button, callback_data);
3449 /* callbacks for the scrollbars */
3450 if (clist->vscrollbar)
3451 (*callback) (clist->vscrollbar, callback_data);
3452 if (clist->hscrollbar)
3453 (*callback) (clist->hscrollbar, callback_data);
3463 draw_row (GtkCList * clist,
3464 GdkRectangle * area,
3466 GtkCListRow * clist_row)
3469 GdkGC *fg_gc, *bg_gc;
3470 GdkRectangle row_rectangle, cell_rectangle, clip_rectangle, intersect_rectangle,
3472 gint i, offset = 0, width, height, pixmap_width = 0;
3473 gint xsrc, ysrc, xdest, ydest;
3475 g_return_if_fail (clist != NULL);
3477 /* bail now if we arn't drawable yet */
3478 if (!GTK_WIDGET_DRAWABLE (clist))
3481 if (row < 0 || row >= clist->rows)
3484 widget = GTK_WIDGET (clist);
3486 /* if the function is passed the pointer to the row instead of null,
3487 * it avoids this expensive lookup */
3489 clist_row = (g_list_nth (clist->row_list, row))->data;
3491 /* rectangle of the entire row */
3492 row_rectangle.x = 0;
3493 row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
3494 row_rectangle.width = clist->clist_window_width;
3495 row_rectangle.height = clist->row_height;
3497 /* rectangle of the cell spacing above the row */
3498 cell_rectangle.x = 0;
3499 cell_rectangle.y = row_rectangle.y - CELL_SPACING;
3500 cell_rectangle.width = row_rectangle.width;
3501 cell_rectangle.height = CELL_SPACING;
3503 /* rectangle used to clip drawing operations, it's y and height
3504 * positions only need to be set once, so we set them once here.
3505 * the x and width are set withing the drawing loop below once per
3507 clip_rectangle.y = row_rectangle.y;
3508 clip_rectangle.height = row_rectangle.height;
3510 /* select GC for background rectangle */
3511 if (clist_row->state == GTK_STATE_SELECTED)
3513 fg_gc = widget->style->fg_gc[GTK_STATE_SELECTED];
3514 bg_gc = widget->style->bg_gc[GTK_STATE_SELECTED];
3518 if (clist_row->fg_set)
3520 gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
3521 fg_gc = clist->fg_gc;
3524 fg_gc = widget->style->fg_gc[GTK_STATE_NORMAL];
3526 if (clist_row->bg_set)
3528 gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
3529 bg_gc = clist->bg_gc;
3532 bg_gc = widget->style->bg_gc[GTK_STATE_PRELIGHT];
3535 /* draw the cell borders and background */
3538 if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
3539 gdk_draw_rectangle (clist->clist_window,
3540 widget->style->base_gc[GTK_STATE_NORMAL],
3542 intersect_rectangle.x,
3543 intersect_rectangle.y,
3544 intersect_rectangle.width,
3545 intersect_rectangle.height);
3547 /* the last row has to clear it's bottom cell spacing too */
3548 if (clist_row == clist->row_list_end->data)
3550 cell_rectangle.y += clist->row_height + CELL_SPACING;
3552 if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
3553 gdk_draw_rectangle (clist->clist_window,
3554 widget->style->base_gc[GTK_STATE_NORMAL],
3556 intersect_rectangle.x,
3557 intersect_rectangle.y,
3558 intersect_rectangle.width,
3559 intersect_rectangle.height);
3562 if (!gdk_rectangle_intersect (area, &row_rectangle, &intersect_rectangle))
3565 if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
3566 gdk_draw_rectangle (clist->clist_window,
3569 intersect_rectangle.x,
3570 intersect_rectangle.y,
3571 intersect_rectangle.width,
3572 intersect_rectangle.height);
3574 gdk_window_clear_area (clist->clist_window,
3575 intersect_rectangle.x,
3576 intersect_rectangle.y,
3577 intersect_rectangle.width,
3578 intersect_rectangle.height);
3582 gdk_draw_rectangle (clist->clist_window,
3583 widget->style->base_gc[GTK_STATE_NORMAL],
3587 cell_rectangle.width,
3588 cell_rectangle.height);
3590 /* the last row has to clear it's bottom cell spacing too */
3591 if (clist_row == clist->row_list_end->data)
3593 cell_rectangle.y += clist->row_height + CELL_SPACING;
3595 gdk_draw_rectangle (clist->clist_window,
3596 widget->style->base_gc[GTK_STATE_NORMAL],
3600 cell_rectangle.width,
3601 cell_rectangle.height);
3604 if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
3605 gdk_draw_rectangle (clist->clist_window,
3610 row_rectangle.width,
3611 row_rectangle.height);
3613 gdk_window_clear_area (clist->clist_window,
3616 row_rectangle.width,
3617 row_rectangle.height);
3620 /* iterate and draw all the columns (row cells) and draw their contents */
3621 for (i = 0; i < clist->columns; i++)
3623 clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
3624 clip_rectangle.width = clist->column[i].area.width;
3626 /* calculate clipping region clipping region */
3629 rect = &clip_rectangle;
3633 if (!gdk_rectangle_intersect (area, &clip_rectangle,
3634 &intersect_rectangle))
3636 rect = &intersect_rectangle;
3639 /* calculate real width for column justification */
3640 switch (clist_row->cell[i].type)
3642 case GTK_CELL_EMPTY:
3647 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
3648 GTK_CELL_TEXT (clist_row->cell[i])->text);
3651 case GTK_CELL_PIXMAP:
3652 gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, &width, &height);
3653 pixmap_width = width;
3656 case GTK_CELL_PIXTEXT:
3657 gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, &width, &height);
3658 pixmap_width = width;
3659 width += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
3660 width += gdk_string_width (GTK_WIDGET (clist)->style->font,
3661 GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
3664 case GTK_CELL_WIDGET:
3674 switch (clist->column[i].justification)
3676 case GTK_JUSTIFY_LEFT:
3677 offset = clip_rectangle.x;
3680 case GTK_JUSTIFY_RIGHT:
3681 offset = (clip_rectangle.x + clip_rectangle.width) - width;
3684 case GTK_JUSTIFY_CENTER:
3685 offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
3688 case GTK_JUSTIFY_FILL:
3689 offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
3697 /* Draw Text or Pixmap */
3698 switch (clist_row->cell[i].type)
3700 case GTK_CELL_EMPTY:
3705 gdk_gc_set_clip_rectangle (fg_gc, rect);
3707 gdk_draw_string (clist->clist_window,
3708 widget->style->font,
3710 offset + clist_row->cell[i].horizontal,
3711 row_rectangle.y + clist->row_center_offset +
3712 clist_row->cell[i].vertical,
3713 GTK_CELL_TEXT (clist_row->cell[i])->text);
3715 gdk_gc_set_clip_rectangle (fg_gc, NULL);
3718 case GTK_CELL_PIXMAP:
3721 xdest = offset + clist_row->cell[i].horizontal;
3722 ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
3723 clist_row->cell[i].vertical;
3725 if (xdest < clip_rectangle.x)
3727 xsrc = clip_rectangle.x - xdest;
3728 pixmap_width -= xsrc;
3729 xdest = clip_rectangle.x;
3732 if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width)
3733 pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest;
3735 if (ydest < clip_rectangle.y)
3737 ysrc = clip_rectangle.y - ydest;
3739 ydest = clip_rectangle.y;
3742 if (ydest + height > clip_rectangle.y + clip_rectangle.height)
3743 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
3745 if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
3747 gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXMAP (clist_row->cell[i])->mask);
3748 gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
3750 gdk_draw_pixmap (clist->clist_window,
3752 GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
3755 pixmap_width, height);
3757 if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
3759 gdk_gc_set_clip_origin (fg_gc, 0, 0);
3760 gdk_gc_set_clip_mask (fg_gc, NULL);
3764 case GTK_CELL_PIXTEXT:
3765 /* draw the pixmap */
3768 xdest = offset + clist_row->cell[i].horizontal;
3769 ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
3770 clist_row->cell[i].vertical;
3772 if (xdest < clip_rectangle.x)
3774 xsrc = clip_rectangle.x - xdest;
3775 pixmap_width -= xsrc;
3776 xdest = clip_rectangle.x;
3779 if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width)
3780 pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest;
3782 if (ydest < clip_rectangle.y)
3784 ysrc = clip_rectangle.y - ydest;
3786 ydest = clip_rectangle.y;
3789 if (ydest + height > clip_rectangle.y + clip_rectangle.height)
3790 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
3792 if (GTK_CELL_PIXTEXT (clist_row->cell[i])->mask)
3794 gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXTEXT (clist_row->cell[i])->mask);
3795 gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
3798 gdk_draw_pixmap (clist->clist_window,
3800 GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
3804 pixmap_width, height);
3806 gdk_gc_set_clip_origin (fg_gc, 0, 0);
3808 offset += pixmap_width + GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
3810 /* draw the string */
3811 gdk_gc_set_clip_rectangle (fg_gc, rect);
3813 gdk_draw_string (clist->clist_window,
3814 widget->style->font,
3816 offset + clist_row->cell[i].horizontal,
3817 row_rectangle.y + clist->row_center_offset +
3818 clist_row->cell[i].vertical,
3819 GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
3821 gdk_gc_set_clip_rectangle (fg_gc, NULL);
3824 case GTK_CELL_WIDGET:
3834 if (clist->focus_row == row && GTK_WIDGET_HAS_FOCUS (widget))
3838 if (gdk_rectangle_intersect (area, &row_rectangle,
3839 &intersect_rectangle))
3841 gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle);
3842 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
3843 row_rectangle.x, row_rectangle.y,
3844 row_rectangle.width - 1,
3845 row_rectangle.height - 1);
3846 gdk_gc_set_clip_rectangle (clist->xor_gc, NULL);
3850 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
3851 row_rectangle.x, row_rectangle.y,
3852 row_rectangle.width - 1, row_rectangle.height - 1);
3857 draw_rows (GtkCList * clist,
3858 GdkRectangle * area)
3861 GtkCListRow *clist_row;
3862 int i, first_row, last_row;
3864 g_return_if_fail (clist != NULL);
3865 g_return_if_fail (GTK_IS_CLIST (clist));
3867 if (clist->row_height == 0 ||
3868 !GTK_WIDGET_DRAWABLE (clist))
3873 first_row = ROW_FROM_YPIXEL (clist, area->y);
3874 last_row = ROW_FROM_YPIXEL (clist, area->y + area->height);
3878 first_row = ROW_FROM_YPIXEL (clist, 0);
3879 last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height);
3882 /* this is a small special case which exposes the bottom cell line
3883 * on the last row -- it might go away if I change the wall the cell spacings
3885 if (clist->rows == first_row)
3888 list = g_list_nth (clist->row_list, first_row);
3892 clist_row = list->data;
3898 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, area, i, clist_row);
3903 gdk_window_clear_area (clist->clist_window, 0, ROW_TOP_YPIXEL (clist, i), -1, -1);
3908 * size_allocate_title_buttons
3909 * size_allocate_columns
3912 size_allocate_title_buttons (GtkCList * clist)
3914 gint i, last_button = 0;
3915 GtkAllocation button_allocation;
3917 if (!GTK_WIDGET_REALIZED (clist))
3920 button_allocation.x = clist->hoffset;
3921 button_allocation.y = 0;
3922 button_allocation.width = 0;
3923 button_allocation.height = clist->column_title_area.height;
3925 for (i = 0; i < clist->columns; i++)
3927 button_allocation.width += clist->column[i].area.width;
3929 if (i == clist->columns - 1)
3930 button_allocation.width += 2 * (CELL_SPACING + COLUMN_INSET);
3932 button_allocation.width += CELL_SPACING + (2 * COLUMN_INSET);
3934 if (i == (clist->columns - 1) || clist->column[i + 1].button)
3936 gtk_widget_size_allocate (clist->column[last_button].button, &button_allocation);
3937 button_allocation.x += button_allocation.width;
3938 button_allocation.width = 0;
3940 gdk_window_show (clist->column[last_button].window);
3941 gdk_window_move_resize (clist->column[last_button].window,
3942 button_allocation.x - (DRAG_WIDTH / 2),
3943 0, DRAG_WIDTH, clist->column_title_area.height);
3945 last_button = i + 1;
3949 gdk_window_hide (clist->column[i].window);
3955 size_allocate_columns (GtkCList * clist)
3957 gint i, xoffset = 0;
3959 for (i = 0; i < clist->columns; i++)
3961 clist->column[i].area.x = xoffset + CELL_SPACING + COLUMN_INSET;
3963 if (i == clist->columns - 1)
3967 if (clist->column[i].width_set)
3969 width = clist->column[i].width;
3973 if (clist->column[i].title)
3974 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
3975 clist->column[i].title);
3980 clist->column[i].area.width = MAX (width,
3981 clist->clist_window_width -
3982 xoffset - (2 * (CELL_SPACING + COLUMN_INSET)));
3987 clist->column[i].area.width = clist->column[i].width;
3990 xoffset += clist->column[i].area.width + CELL_SPACING + (2 * COLUMN_INSET);
3999 * get_selection_info
4002 toggle_row (GtkCList * clist,
4007 GtkCListRow *clist_row;
4009 switch (clist->selection_mode)
4011 case GTK_SELECTION_EXTENDED:
4012 case GTK_SELECTION_MULTIPLE:
4013 case GTK_SELECTION_SINGLE:
4015 clist_row = g_list_nth (clist->row_list, row)->data;
4016 if (clist_row->state == GTK_STATE_SELECTED)
4018 unselect_row (clist, row, column, event);
4022 case GTK_SELECTION_BROWSE:
4023 select_row (clist, row, column, event);
4029 select_row (GtkCList * clist,
4034 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
4035 row, column, event);
4039 unselect_row (GtkCList * clist,
4044 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
4045 row, column, event);
4049 real_select_row (GtkCList * clist,
4054 GtkCListRow *clist_row;
4057 gboolean row_selected;
4059 g_return_if_fail (clist != NULL);
4060 g_return_if_fail (GTK_IS_CLIST (clist));
4062 if (row < 0 || row > (clist->rows - 1))
4065 switch (clist->selection_mode)
4067 case GTK_SELECTION_SINGLE:
4068 case GTK_SELECTION_BROWSE:
4070 row_selected = FALSE;
4071 list = clist->selection;
4075 sel_row = GPOINTER_TO_INT (list->data);
4079 row_selected = TRUE;
4081 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
4082 sel_row, column, event);
4092 clist_row = (g_list_nth (clist->row_list, row))->data;
4094 if (clist_row->state != GTK_STATE_NORMAL || !clist_row->selectable)
4097 clist_row->state = GTK_STATE_SELECTED;
4098 if (!clist->selection)
4100 clist->selection = g_list_append (clist->selection,
4101 GINT_TO_POINTER (row));
4102 clist->selection_end = clist->selection;
4105 clist->selection_end =
4106 g_list_append (clist->selection_end, GINT_TO_POINTER (row))->next;
4108 if (!GTK_CLIST_FROZEN (clist)
4109 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
4110 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
4114 real_unselect_row (GtkCList * clist,
4119 GtkCListRow *clist_row;
4121 g_return_if_fail (clist != NULL);
4122 g_return_if_fail (GTK_IS_CLIST (clist));
4124 if (row < 0 || row > (clist->rows - 1))
4127 clist_row = (g_list_nth (clist->row_list, row))->data;
4129 if (clist_row->state == GTK_STATE_SELECTED)
4131 clist_row->state = GTK_STATE_NORMAL;
4133 if (clist->selection_end &&
4134 clist->selection_end->data == GINT_TO_POINTER (row))
4135 clist->selection_end = clist->selection_end->prev;
4137 clist->selection = g_list_remove (clist->selection,
4138 GINT_TO_POINTER (row));
4140 if (!GTK_CLIST_FROZEN (clist)
4141 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
4142 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
4147 get_selection_info (GtkCList * clist,
4155 g_return_val_if_fail (clist != NULL, 0);
4156 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
4158 /* bounds checking, return false if the user clicked
4159 * on a blank area */
4160 trow = ROW_FROM_YPIXEL (clist, y);
4161 if (trow >= clist->rows)
4167 tcol = COLUMN_FROM_XPIXEL (clist, x);
4168 if (tcol >= clist->columns)
4178 gtk_clist_get_selection_info (GtkCList *clist,
4184 g_return_val_if_fail (clist != NULL, 0);
4185 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
4186 return get_selection_info (clist, x, y, row, column);
4196 draw_xor_line (GtkCList * clist)
4200 g_return_if_fail (clist != NULL);
4202 widget = GTK_WIDGET (clist);
4204 gdk_draw_line (widget->window, clist->xor_gc,
4206 widget->style->klass->ythickness,
4208 clist->column_title_area.height + clist->clist_window_height + 1);
4211 /* this function returns the new width of the column being resized given
4212 * the column and x position of the cursor; the x cursor position is passed
4213 * in as a pointer and automagicly corrected if it's beyond min/max limits */
4215 new_column_width (GtkCList * clist,
4224 /* first translate the x position from widget->window
4225 * to clist->clist_window */
4226 cx -= GTK_WIDGET (clist)->style->klass->xthickness;
4228 /* rx is x from the list beginning */
4229 rx = cx - clist->hoffset;
4231 /* you can't shrink a column to less than its minimum width */
4232 if (cx < (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH))
4234 *x = cx = COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH +
4235 GTK_WIDGET (clist)->style->klass->xthickness;
4236 cx -= GTK_WIDGET (clist)->style->klass->xthickness;
4237 rx = cx - clist->hoffset;
4240 if (cx < 0 || cx > clist->clist_window_width)
4245 /* calculate new column width making sure it doesn't end up
4246 * less than the minimum width */
4247 width = (rx - COLUMN_LEFT (clist, column)) - COLUMN_INSET -
4248 ((clist->columns == (column - 1)) ? CELL_SPACING : 0);
4249 if (width < COLUMN_MIN_WIDTH)
4250 width = COLUMN_MIN_WIDTH;
4255 /* this will do more later */
4257 resize_column (GtkCList * clist,
4261 gtk_clist_set_column_width (clist, column, width);
4266 column_button_create (GtkCList * clist,
4271 button = clist->column[column].button = gtk_button_new ();
4272 if (GTK_WIDGET_REALIZED (clist) && clist->title_window)
4273 gtk_widget_set_parent_window (clist->column[column].button, clist->title_window);
4274 gtk_widget_set_parent (button, GTK_WIDGET (clist));
4276 gtk_signal_connect (GTK_OBJECT (button), "clicked",
4277 (GtkSignalFunc) column_button_clicked,
4280 gtk_widget_show (button);
4284 column_button_clicked (GtkWidget * widget,
4290 g_return_if_fail (widget != NULL);
4291 g_return_if_fail (GTK_IS_CLIST (data));
4293 clist = GTK_CLIST (data);
4295 /* find the column who's button was pressed */
4296 for (i = 0; i < clist->columns; i++)
4297 if (clist->column[i].button == widget)
4300 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i);
4309 * vadjustment_changed
4310 * hadjustment_changed
4311 * vadjustment_value_changed
4312 * hadjustment_value_changed
4315 create_scrollbars (GtkCList * clist)
4317 GtkAdjustment *adjustment;
4319 clist->vscrollbar = gtk_vscrollbar_new (NULL);
4321 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
4323 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
4324 (GtkSignalFunc) vadjustment_changed,
4327 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
4328 (GtkSignalFunc) vadjustment_value_changed,
4331 gtk_widget_set_parent (clist->vscrollbar, GTK_WIDGET (clist));
4332 gtk_widget_show (clist->vscrollbar);
4334 clist->hscrollbar = gtk_hscrollbar_new (NULL);
4336 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
4338 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
4339 (GtkSignalFunc) hadjustment_changed,
4342 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
4343 (GtkSignalFunc) hadjustment_value_changed,
4346 gtk_widget_set_parent (clist->hscrollbar, GTK_WIDGET (clist));
4347 gtk_widget_show (clist->hscrollbar);
4351 adjust_scrollbars (GtkCList * clist)
4353 GTK_RANGE (clist->vscrollbar)->adjustment->page_size = clist->clist_window_height;
4354 GTK_RANGE (clist->vscrollbar)->adjustment->page_increment = clist->clist_window_height / 2;
4355 GTK_RANGE (clist->vscrollbar)->adjustment->step_increment = 10;
4356 GTK_RANGE (clist->vscrollbar)->adjustment->lower = 0;
4357 GTK_RANGE (clist->vscrollbar)->adjustment->upper = LIST_HEIGHT (clist);
4359 if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist))
4361 GTK_RANGE (clist->vscrollbar)->adjustment->value = MAX (0, LIST_HEIGHT (clist) -
4362 clist->clist_window_height);
4363 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment),
4367 GTK_RANGE (clist->hscrollbar)->adjustment->page_size = clist->clist_window_width;
4368 GTK_RANGE (clist->hscrollbar)->adjustment->page_increment = clist->clist_window_width / 2;
4369 GTK_RANGE (clist->hscrollbar)->adjustment->step_increment = 10;
4370 GTK_RANGE (clist->hscrollbar)->adjustment->lower = 0;
4371 GTK_RANGE (clist->hscrollbar)->adjustment->upper = LIST_WIDTH (clist);
4373 if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist))
4375 GTK_RANGE (clist->hscrollbar)->adjustment->value = MAX (0, LIST_WIDTH (clist) -
4376 clist->clist_window_width);
4377 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment),
4381 if (LIST_HEIGHT (clist) <= clist->clist_window_height &&
4382 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
4384 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
4386 gtk_widget_hide (clist->vscrollbar);
4387 gtk_widget_size_allocate (GTK_WIDGET (clist),
4388 >K_WIDGET (clist)->allocation);
4393 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
4395 gtk_widget_show (clist->vscrollbar);
4396 gtk_widget_size_allocate (GTK_WIDGET (clist),
4397 >K_WIDGET (clist)->allocation);
4401 if (LIST_WIDTH (clist) <= clist->clist_window_width &&
4402 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
4404 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
4406 gtk_widget_hide (clist->hscrollbar);
4407 gtk_widget_size_allocate (GTK_WIDGET (clist),
4408 >K_WIDGET (clist)->allocation);
4413 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
4415 gtk_widget_show (clist->hscrollbar);
4416 gtk_widget_size_allocate (GTK_WIDGET (clist),
4417 >K_WIDGET (clist)->allocation);
4421 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
4422 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), "changed");
4426 vadjustment_changed (GtkAdjustment * adjustment,
4431 g_return_if_fail (adjustment != NULL);
4432 g_return_if_fail (data != NULL);
4434 clist = GTK_CLIST (data);
4438 hadjustment_changed (GtkAdjustment * adjustment,
4443 g_return_if_fail (adjustment != NULL);
4444 g_return_if_fail (data != NULL);
4446 clist = GTK_CLIST (data);
4450 check_exposures (GtkCList *clist)
4454 if (!GTK_WIDGET_REALIZED (clist))
4457 /* Make sure graphics expose events are processed before scrolling
4459 while ((event = gdk_event_get_graphics_expose (clist->clist_window)) != NULL)
4461 gtk_widget_event (GTK_WIDGET (clist), event);
4462 if (event->expose.count == 0)
4464 gdk_event_free (event);
4467 gdk_event_free (event);
4472 vadjustment_value_changed (GtkAdjustment * adjustment,
4479 g_return_if_fail (adjustment != NULL);
4480 g_return_if_fail (data != NULL);
4481 g_return_if_fail (GTK_IS_CLIST (data));
4483 clist = GTK_CLIST (data);
4485 if (!GTK_WIDGET_DRAWABLE (clist))
4488 value = adjustment->value;
4490 if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)))
4492 if (value > -clist->voffset)
4495 diff = value + clist->voffset;
4497 /* we have to re-draw the whole screen here... */
4498 if (diff >= clist->clist_window_height)
4500 clist->voffset = -value;
4501 draw_rows (clist, NULL);
4505 if ((diff != 0) && (diff != clist->clist_window_height))
4506 gdk_window_copy_area (clist->clist_window,
4509 clist->clist_window,
4512 clist->clist_window_width,
4513 clist->clist_window_height - diff);
4516 area.y = clist->clist_window_height - diff;
4517 area.width = clist->clist_window_width;
4523 diff = -clist->voffset - value;
4525 /* we have to re-draw the whole screen here... */
4526 if (diff >= clist->clist_window_height)
4528 clist->voffset = -value;
4529 draw_rows (clist, NULL);
4533 if ((diff != 0) && (diff != clist->clist_window_height))
4534 gdk_window_copy_area (clist->clist_window,
4537 clist->clist_window,
4540 clist->clist_window_width,
4541 clist->clist_window_height - diff);
4545 area.width = clist->clist_window_width;
4550 clist->voffset = -value;
4551 if ((diff != 0) && (diff != clist->clist_window_height))
4552 check_exposures (clist);
4555 draw_rows (clist, &area);
4559 hadjustment_value_changed (GtkAdjustment * adjustment,
4569 g_return_if_fail (adjustment != NULL);
4570 g_return_if_fail (data != NULL);
4571 g_return_if_fail (GTK_IS_CLIST (data));
4573 clist = GTK_CLIST (data);
4575 if (!GTK_WIDGET_DRAWABLE (clist) ||
4576 adjustment != gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)))
4579 value = adjustment->value;
4581 /* move the column buttons and resize windows */
4582 for (i = 0; i < clist->columns; i++)
4584 if (clist->column[i].button)
4586 clist->column[i].button->allocation.x -= value + clist->hoffset;
4588 if (clist->column[i].button->window)
4590 gdk_window_move (clist->column[i].button->window,
4591 clist->column[i].button->allocation.x,
4592 clist->column[i].button->allocation.y);
4594 if (clist->column[i].window)
4595 gdk_window_move (clist->column[i].window,
4596 clist->column[i].button->allocation.x +
4597 clist->column[i].button->allocation.width -
4598 (DRAG_WIDTH / 2), 0);
4603 if (value > -clist->hoffset)
4606 diff = value + clist->hoffset;
4608 clist->hoffset = -value;
4610 /* we have to re-draw the whole screen here... */
4611 if (diff >= clist->clist_window_width)
4613 draw_rows (clist, NULL);
4617 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
4618 GTK_CLIST_ADD_MODE (clist))
4620 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4622 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
4623 clist->clist_window_width - 1,
4624 clist->row_height - 1);
4626 gdk_window_copy_area (clist->clist_window,
4629 clist->clist_window,
4632 clist->clist_window_width - diff,
4633 clist->clist_window_height);
4635 area.x = clist->clist_window_width - diff;
4640 if (!(diff = -clist->hoffset - value))
4643 clist->hoffset = -value;
4645 /* we have to re-draw the whole screen here... */
4646 if (diff >= clist->clist_window_width)
4648 draw_rows (clist, NULL);
4652 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
4653 GTK_CLIST_ADD_MODE (clist))
4655 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4657 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
4658 clist->clist_window_width - 1,
4659 clist->row_height - 1);
4662 gdk_window_copy_area (clist->clist_window,
4665 clist->clist_window,
4668 clist->clist_window_width - diff,
4669 clist->clist_window_height);
4676 area.height = clist->clist_window_height;
4678 check_exposures (clist);
4680 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist))
4682 if (GTK_CLIST_ADD_MODE (clist))
4686 focus_row = clist->focus_row;
4687 clist->focus_row = -1;
4688 draw_rows (clist, &area);
4689 clist->focus_row = focus_row;
4691 gdk_draw_rectangle (clist->clist_window, clist->xor_gc,
4692 FALSE, 0, y, clist->clist_window_width - 1,
4693 clist->row_height - 1);
4703 x0 = clist->clist_window_width - 1;
4712 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4713 gdk_draw_line (clist->clist_window, clist->xor_gc,
4714 x0, y + 1, x0, y + clist->row_height - 2);
4715 gdk_draw_line (clist->clist_window, clist->xor_gc,
4716 x1, y + 1, x1, y + clist->row_height - 2);
4720 draw_rows (clist, &area);
4724 * Memory Allocation/Distruction Routines for GtkCList stuctures
4734 static GtkCListColumn *
4735 columns_new (GtkCList * clist)
4738 GtkCListColumn *column;
4740 column = g_new (GtkCListColumn, clist->columns);
4742 for (i = 0; i < clist->columns; i++)
4744 column[i].area.x = 0;
4745 column[i].area.y = 0;
4746 column[i].area.width = 0;
4747 column[i].area.height = 0;
4748 column[i].title = NULL;
4749 column[i].button = NULL;
4750 column[i].window = NULL;
4751 column[i].width = 0;
4752 column[i].width_set = FALSE;
4753 column[i].justification = GTK_JUSTIFY_LEFT;
4760 column_title_new (GtkCList *clist,
4764 if (clist->column[column].title)
4765 g_free (clist->column[column].title);
4767 clist->column[column].title = g_strdup (title);
4771 columns_delete (GtkCList * clist)
4775 for (i = 0; i < clist->columns; i++)
4776 if (clist->column[i].title)
4777 g_free (clist->column[i].title);
4779 g_free (clist->column);
4782 static GtkCListRow *
4783 row_new (GtkCList * clist)
4786 GtkCListRow *clist_row;
4788 clist_row = g_chunk_new (GtkCListRow, clist->row_mem_chunk);
4789 clist_row->cell = g_chunk_new (GtkCell, clist->cell_mem_chunk);
4791 for (i = 0; i < clist->columns; i++)
4793 clist_row->cell[i].type = GTK_CELL_EMPTY;
4794 clist_row->cell[i].vertical = 0;
4795 clist_row->cell[i].horizontal = 0;
4798 clist_row->fg_set = FALSE;
4799 clist_row->bg_set = FALSE;
4800 clist_row->selectable = TRUE;
4801 clist_row->state = GTK_STATE_NORMAL;
4802 clist_row->data = NULL;
4803 clist_row->destroy = NULL;
4809 row_delete (GtkCList * clist,
4810 GtkCListRow * clist_row)
4814 for (i = 0; i < clist->columns; i++)
4815 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
4816 (clist, clist_row, i, GTK_CELL_EMPTY, NULL, 0, NULL, NULL);
4818 if (clist_row->destroy)
4819 clist_row->destroy (clist_row->data);
4821 g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell);
4822 g_mem_chunk_free (clist->row_mem_chunk, clist_row);
4826 set_cell_contents (GtkCList *clist,
4827 GtkCListRow *clist_row,
4835 g_return_if_fail (clist_row != NULL);
4837 switch (clist_row->cell[column].type)
4839 case GTK_CELL_EMPTY:
4843 g_free (GTK_CELL_TEXT (clist_row->cell[column])->text);
4846 case GTK_CELL_PIXMAP:
4847 gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap);
4848 if (GTK_CELL_PIXMAP (clist_row->cell[column])->mask)
4849 gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask);
4852 case GTK_CELL_PIXTEXT:
4853 g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text);
4854 gdk_pixmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap);
4855 if (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask)
4856 gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask);
4859 case GTK_CELL_WIDGET:
4867 clist_row->cell[column].type = GTK_CELL_EMPTY;
4874 clist_row->cell[column].type = GTK_CELL_TEXT;
4875 GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
4879 case GTK_CELL_PIXMAP:
4882 clist_row->cell[column].type = GTK_CELL_PIXMAP;
4883 GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
4884 /* We set the mask even if it is NULL */
4885 GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask;
4889 case GTK_CELL_PIXTEXT:
4892 clist_row->cell[column].type = GTK_CELL_PIXTEXT;
4893 GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
4894 GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
4895 GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
4896 GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask;
4905 /* Fill in data after widget has correct style */
4908 add_style_data (GtkCList * clist)
4912 widget = GTK_WIDGET(clist);
4914 /* text properties */
4915 if (!GTK_CLIST_ROW_HEIGHT_SET (clist))
4917 clist->row_height = widget->style->font->ascent + widget->style->font->descent + 1;
4918 clist->row_center_offset = widget->style->font->ascent + 1.5;
4923 text_height = clist->row_height - (GTK_WIDGET (clist)->style->font->ascent +
4924 GTK_WIDGET (clist) ->style->font->descent + 1);
4925 clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
4932 /* focus functions */
4935 gtk_clist_draw_focus (GtkWidget *widget)
4939 g_return_if_fail (widget != NULL);
4940 g_return_if_fail (GTK_IS_CLIST (widget));
4942 if (!GTK_WIDGET_DRAWABLE (widget))
4945 clist = GTK_CLIST (widget);
4946 if (clist->focus_row >= 0)
4947 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
4948 0, ROW_TOP_YPIXEL(clist, clist->focus_row),
4949 clist->clist_window_width - 1,
4950 clist->row_height - 1);
4954 gtk_clist_set_focus_child (GtkContainer *container,
4957 g_return_if_fail (container != NULL);
4958 g_return_if_fail (GTK_IS_CLIST (container));
4962 g_return_if_fail (GTK_IS_WIDGET (child));
4963 GTK_CLIST_SET_FLAG (GTK_CLIST (container), CLIST_CHILD_HAS_FOCUS);
4966 parent_class->set_focus_child (container, child);
4970 gtk_clist_focus_in (GtkWidget *widget,
4971 GdkEventFocus *event)
4975 g_return_val_if_fail (widget != NULL, FALSE);
4976 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4977 g_return_val_if_fail (event != NULL, FALSE);
4979 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
4980 GTK_CLIST_UNSET_FLAG (widget, CLIST_CHILD_HAS_FOCUS);
4982 clist = GTK_CLIST (widget);
4984 if (clist->selection_mode == GTK_SELECTION_BROWSE &&
4985 clist->selection == NULL && clist->focus_row > -1)
4989 list = g_list_nth (clist->row_list, clist->focus_row);
4990 if (list && GTK_CLIST_ROW (list)->selectable)
4991 select_row (clist, clist->focus_row, -1, (GdkEvent *) event);
4993 gtk_widget_draw_focus (widget);
4996 gtk_widget_draw_focus (widget);
5002 gtk_clist_focus_out (GtkWidget *widget,
5003 GdkEventFocus *event)
5007 g_return_val_if_fail (widget != NULL, FALSE);
5008 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
5009 g_return_val_if_fail (event != NULL, FALSE);
5011 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
5012 gtk_widget_draw_focus (widget);
5014 clist = GTK_CLIST (widget);
5016 if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
5017 GTK_CLIST_CLASS_FW (widget)->resync_selection (clist, (GdkEvent *) event);
5023 toggle_add_mode (GtkCList *clist)
5025 g_return_if_fail (clist != 0);
5026 g_return_if_fail (GTK_IS_CLIST (clist));
5028 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
5029 clist->selection_mode != GTK_SELECTION_EXTENDED)
5032 gtk_clist_draw_focus (GTK_WIDGET (clist));
5033 if (!GTK_CLIST_ADD_MODE (clist))
5035 GTK_CLIST_SET_FLAG (clist, CLIST_ADD_MODE);
5036 gdk_gc_set_line_attributes (clist->xor_gc, 1,
5037 GDK_LINE_ON_OFF_DASH, 0, 0);
5038 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
5042 GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
5043 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
5044 clist->anchor_state = GTK_STATE_SELECTED;
5046 gtk_clist_draw_focus (GTK_WIDGET (clist));
5050 toggle_focus_row (GtkCList *clist)
5052 g_return_if_fail (clist != 0);
5053 g_return_if_fail (GTK_IS_CLIST (clist));
5055 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
5056 clist->focus_row < 0 || clist->focus_row >= clist->rows)
5059 switch (clist->selection_mode)
5061 case GTK_SELECTION_SINGLE:
5062 case GTK_SELECTION_MULTIPLE:
5063 toggle_row (clist, clist->focus_row, 0, NULL);
5065 case GTK_SELECTION_EXTENDED:
5066 g_list_free (clist->undo_selection);
5067 g_list_free (clist->undo_unselection);
5068 clist->undo_selection = NULL;
5069 clist->undo_unselection = NULL;
5071 clist->anchor = clist->focus_row;
5072 clist->drag_pos = clist->focus_row;
5073 clist->undo_anchor = clist->focus_row;
5075 if (GTK_CLIST_ADD_MODE (clist))
5076 fake_toggle_row (clist, clist->focus_row);
5078 GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist,clist->focus_row);
5080 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
5088 move_focus_row (GtkCList *clist,
5089 GtkScrollType scroll_type,
5094 g_return_if_fail (clist != 0);
5095 g_return_if_fail (GTK_IS_CLIST (clist));
5097 widget = GTK_WIDGET (clist);
5099 switch (scroll_type)
5101 case GTK_SCROLL_STEP_BACKWARD:
5102 if (clist->focus_row <= 0)
5104 gtk_clist_draw_focus (widget);
5106 gtk_clist_draw_focus (widget);
5108 case GTK_SCROLL_STEP_FORWARD:
5109 if (clist->focus_row >= clist->rows - 1)
5111 gtk_clist_draw_focus (widget);
5113 gtk_clist_draw_focus (widget);
5115 case GTK_SCROLL_PAGE_BACKWARD:
5116 if (clist->focus_row <= 0)
5118 gtk_clist_draw_focus (widget);
5119 clist->focus_row = MAX (0, clist->focus_row -
5120 (2 * clist->clist_window_height -
5121 clist->row_height - CELL_SPACING) /
5122 (2 * (clist->row_height + CELL_SPACING)));
5123 gtk_clist_draw_focus (widget);
5125 case GTK_SCROLL_PAGE_FORWARD:
5126 if (clist->focus_row >= clist->rows - 1)
5128 gtk_clist_draw_focus (widget);
5129 clist->focus_row = MIN (clist->rows - 1, clist->focus_row +
5130 (2 * clist->clist_window_height -
5131 clist->row_height - CELL_SPACING) /
5132 (2 * (clist->row_height + CELL_SPACING)));
5133 gtk_clist_draw_focus (widget);
5135 case GTK_SCROLL_JUMP:
5136 if (position >= 0 && position <= 1)
5138 gtk_clist_draw_focus (widget);
5139 clist->focus_row = position * (clist->rows - 1);
5140 gtk_clist_draw_focus (widget);
5149 scroll_horizontal (GtkCList *clist,
5150 GtkScrollType scroll_type,
5155 g_return_if_fail (clist != 0);
5156 g_return_if_fail (GTK_IS_CLIST (clist));
5158 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5161 switch (scroll_type)
5163 case GTK_SCROLL_STEP_BACKWARD:
5164 column = COLUMN_FROM_XPIXEL (clist, 0);
5165 if (COLUMN_LEFT_XPIXEL (clist, column) - CELL_SPACING - COLUMN_INSET >= 0
5169 case GTK_SCROLL_STEP_FORWARD:
5170 column = COLUMN_FROM_XPIXEL (clist, clist->clist_window_width);
5173 if (COLUMN_LEFT_XPIXEL (clist, column) + clist->column[column].area.width
5174 + CELL_SPACING + COLUMN_INSET - 1 <= clist->clist_window_width &&
5175 column < clist->columns - 1)
5178 case GTK_SCROLL_PAGE_BACKWARD:
5179 case GTK_SCROLL_PAGE_FORWARD:
5181 case GTK_SCROLL_JUMP:
5182 if (position >= 0 && position <= 1)
5183 column = position * (clist->columns - 1);
5191 if (COLUMN_LEFT_XPIXEL (clist, column) < CELL_SPACING + COLUMN_INSET)
5192 gtk_clist_moveto (clist, -1, column, 0, 0);
5193 else if (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET - 1
5194 + clist->column[column].area.width > clist->clist_window_width)
5196 if (column == clist->columns - 1)
5197 gtk_clist_moveto (clist, -1, column, 0, 0);
5199 gtk_clist_moveto (clist, -1, column, 0, 1);
5204 scroll_vertical (GtkCList *clist,
5205 GtkScrollType scroll_type,
5210 g_return_if_fail (clist != NULL);
5211 g_return_if_fail (GTK_IS_CLIST (clist));
5213 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5216 switch (clist->selection_mode)
5218 case GTK_SELECTION_EXTENDED:
5219 if (clist->anchor >= 0)
5222 case GTK_SELECTION_BROWSE:
5224 old_focus_row = clist->focus_row;
5225 move_focus_row (clist, scroll_type, position);
5227 if (old_focus_row != clist->focus_row)
5229 if (clist->selection_mode == GTK_SELECTION_BROWSE)
5230 unselect_row (clist,old_focus_row, -1, NULL);
5231 else if (!GTK_CLIST_ADD_MODE (clist))
5233 gtk_clist_unselect_all (clist);
5234 clist->undo_anchor = old_focus_row;
5238 switch (gtk_clist_row_is_visible (clist, clist->focus_row))
5240 case GTK_VISIBILITY_NONE:
5241 if (old_focus_row != clist->focus_row &&
5242 !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
5243 GTK_CLIST_ADD_MODE (clist)))
5244 select_row (clist, clist->focus_row, -1, NULL);
5245 switch (scroll_type)
5247 case GTK_SCROLL_STEP_BACKWARD:
5248 case GTK_SCROLL_PAGE_BACKWARD:
5249 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5251 case GTK_SCROLL_STEP_FORWARD:
5252 case GTK_SCROLL_PAGE_FORWARD:
5253 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5255 case GTK_SCROLL_JUMP:
5256 gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
5263 case GTK_VISIBILITY_PARTIAL:
5264 switch (scroll_type)
5266 case GTK_SCROLL_STEP_BACKWARD:
5267 case GTK_SCROLL_PAGE_BACKWARD:
5268 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5270 case GTK_SCROLL_STEP_FORWARD:
5271 case GTK_SCROLL_PAGE_FORWARD:
5272 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5274 case GTK_SCROLL_JUMP:
5275 gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
5282 if (old_focus_row != clist->focus_row &&
5283 !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
5284 GTK_CLIST_ADD_MODE (clist)))
5285 select_row (clist, clist->focus_row, -1, NULL);
5291 move_focus_row (clist, scroll_type, position);
5293 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5294 clist->clist_window_height)
5295 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5296 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5297 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5303 set_anchor (GtkCList *clist,
5308 g_return_if_fail (clist != NULL);
5309 g_return_if_fail (GTK_IS_CLIST (clist));
5311 if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor >= 0)
5314 g_list_free (clist->undo_selection);
5315 g_list_free (clist->undo_unselection);
5316 clist->undo_selection = NULL;
5317 clist->undo_unselection = NULL;
5320 fake_toggle_row (clist, anchor);
5323 GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist, anchor);
5324 clist->anchor_state = GTK_STATE_SELECTED;
5327 clist->anchor = anchor;
5328 clist->drag_pos = anchor;
5329 clist->undo_anchor = undo_anchor;
5333 resync_selection (GtkCList *clist,
5339 gboolean thaw = FALSE;
5341 GtkCListRow *clist_row;
5343 if (clist->anchor < 0)
5346 if (!GTK_CLIST_FROZEN (clist))
5348 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
5352 i = MIN (clist->anchor, clist->drag_pos);
5353 e = MAX (clist->anchor, clist->drag_pos);
5355 if (clist->undo_selection)
5357 list = clist->selection;
5358 clist->selection = clist->undo_selection;
5359 clist->selection_end = g_list_last (clist->selection);
5360 clist->undo_selection = list;
5361 list = clist->selection;
5364 row = GPOINTER_TO_INT (list->data);
5366 if (row < i || row > e)
5368 clist_row = g_list_nth (clist->row_list, row)->data;
5369 if (clist_row->selectable)
5371 clist_row->state = GTK_STATE_SELECTED;
5372 unselect_row (clist, row, -1, event);
5373 clist->undo_selection = g_list_prepend
5374 (clist->undo_selection, GINT_TO_POINTER (row));
5380 for (list = g_list_nth (clist->row_list, i); i <= e; i++, list = list->next)
5381 if (GTK_CLIST_ROW (list)->selectable)
5383 if (g_list_find (clist->selection, GINT_TO_POINTER(i)))
5385 if (GTK_CLIST_ROW (list)->state == GTK_STATE_NORMAL)
5387 GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
5388 unselect_row (clist, i, -1, event);
5389 clist->undo_selection = g_list_prepend (clist->undo_selection,
5390 GINT_TO_POINTER (i));
5393 else if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
5395 GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
5396 clist->undo_unselection = g_list_prepend (clist->undo_unselection,
5397 GINT_TO_POINTER (i));
5401 for (list = clist->undo_unselection; list; list = list->next)
5402 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
5403 GPOINTER_TO_INT (list->data), -1, event);
5406 clist->drag_pos = -1;
5409 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
5413 update_extended_selection (GtkCList *clist,
5423 gint y1 = clist->clist_window_height;
5424 gint y2 = clist->clist_window_height;
5429 if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor == -1)
5434 if (row >= clist->rows)
5435 row = clist->rows - 1;
5437 /* extending downwards */
5438 if (row > clist->drag_pos && clist->anchor <= clist->drag_pos)
5440 s2 = clist->drag_pos + 1;
5443 /* extending upwards */
5444 else if (row < clist->drag_pos && clist->anchor >= clist->drag_pos)
5447 e2 = clist->drag_pos - 1;
5449 else if (row < clist->drag_pos && clist->anchor < clist->drag_pos)
5451 e1 = clist->drag_pos;
5452 /* row and drag_pos on different sides of anchor :
5453 take back the selection between anchor and drag_pos,
5454 select between anchor and row */
5455 if (row < clist->anchor)
5457 s1 = clist->anchor + 1;
5459 e2 = clist->anchor - 1;
5461 /* take back the selection between anchor and drag_pos */
5465 else if (row > clist->drag_pos && clist->anchor > clist->drag_pos)
5467 s1 = clist->drag_pos;
5468 /* row and drag_pos on different sides of anchor :
5469 take back the selection between anchor and drag_pos,
5470 select between anchor and row */
5471 if (row > clist->anchor)
5473 e1 = clist->anchor - 1;
5474 s2 = clist->anchor + 1;
5477 /* take back the selection between anchor and drag_pos */
5482 clist->drag_pos = row;
5485 area.width = clist->clist_window_width;
5487 /* restore the elements between s1 and e1 */
5490 for (i = s1, list = g_list_nth (clist->row_list, i); i <= e1;
5491 i++, list = list->next)
5492 if (GTK_CLIST_ROW (list)->selectable)
5494 if (GTK_CLIST_CLASS_FW (clist)->selection_find (clist, i, list))
5495 GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
5497 GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
5500 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
5502 if (top + clist->row_height <= 0)
5505 area.height = ROW_TOP_YPIXEL (clist, e1) + clist->row_height;
5506 draw_rows (clist, &area);
5507 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5509 else if (top >= clist->clist_window_height)
5511 area.y = ROW_TOP_YPIXEL (clist, s1);
5512 area.height = clist->clist_window_height - area.y;
5513 draw_rows (clist, &area);
5514 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5517 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5518 else if (top + clist->row_height > clist->clist_window_height)
5519 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5521 y1 = ROW_TOP_YPIXEL (clist, s1);
5522 h1 = (e1 - s1 + 1) * (clist->row_height + CELL_SPACING);
5525 /* extend the selection between s2 and e2 */
5528 for (i = s2, list = g_list_nth (clist->row_list, i); i <= e2;
5529 i++, list = list->next)
5530 if (GTK_CLIST_ROW (list)->selectable &&
5531 GTK_CLIST_ROW (list)->state != clist->anchor_state)
5532 GTK_CLIST_ROW (list)->state = clist->anchor_state;
5534 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
5536 if (top + clist->row_height <= 0)
5539 area.height = ROW_TOP_YPIXEL (clist, e2) + clist->row_height;
5540 draw_rows (clist, &area);
5541 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5543 else if (top >= clist->clist_window_height)
5545 area.y = ROW_TOP_YPIXEL (clist, s2);
5546 area.height = clist->clist_window_height - area.y;
5547 draw_rows (clist, &area);
5548 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5551 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5552 else if (top + clist->row_height > clist->clist_window_height)
5553 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5555 y2 = ROW_TOP_YPIXEL (clist, s2);
5556 h2 = (e2 - s2 + 1) * (clist->row_height + CELL_SPACING);
5559 area.y = MAX (0, MIN (y1, y2));
5560 if (area.y > clist->clist_window_height)
5562 area.height = MIN (clist->clist_window_height, h1 + h2);
5563 if (s1 >= 0 && s2 >= 0)
5564 area.height += (clist->row_height + CELL_SPACING);
5565 draw_rows (clist, &area);
5569 start_selection (GtkCList *clist)
5571 g_return_if_fail (clist != NULL);
5572 g_return_if_fail (GTK_IS_CLIST (clist));
5574 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5577 set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
5582 end_selection (GtkCList *clist)
5584 g_return_if_fail (clist != NULL);
5585 g_return_if_fail (GTK_IS_CLIST (clist));
5587 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist)) ||
5588 clist->anchor == -1)
5591 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
5595 extend_selection (GtkCList *clist,
5596 GtkScrollType scroll_type,
5598 gboolean auto_start_selection)
5600 g_return_if_fail (clist != NULL);
5601 g_return_if_fail (GTK_IS_CLIST (clist));
5603 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
5604 clist->selection_mode != GTK_SELECTION_EXTENDED)
5607 if (auto_start_selection)
5608 set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
5610 else if (clist->anchor == -1)
5613 move_focus_row (clist, scroll_type, position);
5615 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5616 clist->clist_window_height)
5617 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5618 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5619 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5621 update_extended_selection (clist, clist->focus_row);
5625 abort_column_resize (GtkCList *clist)
5627 g_return_if_fail (clist != NULL);
5628 g_return_if_fail (GTK_IS_CLIST (clist));
5630 if (!GTK_CLIST_IN_DRAG (clist))
5633 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
5634 gtk_grab_remove (GTK_WIDGET (clist));
5635 gdk_pointer_ungrab (GDK_CURRENT_TIME);
5636 clist->drag_pos = -1;
5638 if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1)
5639 draw_xor_line (clist);
5641 if (GTK_CLIST_ADD_MODE (clist))
5643 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_ON_OFF_DASH, 0,0);
5644 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
5649 gtk_clist_key_press (GtkWidget * widget,
5650 GdkEventKey * event)
5652 g_return_val_if_fail (widget != NULL, FALSE);
5653 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
5654 g_return_val_if_fail (event != NULL, FALSE);
5656 if (GTK_WIDGET_CLASS (parent_class)->key_press_event &&
5657 GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
5660 switch (event->keyval)
5663 case GDK_ISO_Left_Tab:
5664 if (event->state & GDK_SHIFT_MASK)
5665 return gtk_container_focus (GTK_CONTAINER (widget),
5666 GTK_DIR_TAB_BACKWARD);
5668 return gtk_container_focus (GTK_CONTAINER (widget),
5669 GTK_DIR_TAB_FORWARD);
5679 title_focus (GtkCList * clist,
5682 GtkWidget *focus_child;
5683 gboolean return_val = FALSE;
5688 if (!GTK_CLIST_SHOW_TITLES (clist))
5691 focus_child = GTK_CONTAINER (clist)->focus_child;
5695 case GTK_DIR_TAB_BACKWARD:
5697 if (!focus_child || focus_child == clist->hscrollbar ||
5698 focus_child == clist->hscrollbar ||
5699 !GTK_CLIST_CHILD_HAS_FOCUS (clist))
5701 if (dir == GTK_DIR_UP)
5702 i = COLUMN_FROM_XPIXEL (clist, 0);
5704 i = clist->columns - 1;
5705 focus_child = clist->column[i].button;
5706 dir = GTK_DIR_TAB_FORWARD;
5713 if (!focus_child || focus_child == clist->hscrollbar ||
5714 focus_child == clist->hscrollbar)
5716 i = clist->columns - 1;
5717 focus_child = clist->column[i].button;
5721 if (!focus_child || focus_child == clist->hscrollbar ||
5722 focus_child == clist->hscrollbar)
5725 focus_child = clist->column[i].button;
5731 while (i < clist->columns)
5733 if (clist->column[i].button == focus_child)
5735 if (clist->column[i].button &&
5736 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
5737 GTK_IS_CONTAINER (clist->column[i].button) &&
5738 !GTK_WIDGET_HAS_FOCUS (clist->column[i].button))
5739 if (gtk_container_focus
5740 (GTK_CONTAINER (clist->column[i].button), dir))
5745 if (!return_val && dir == GTK_DIR_UP)
5756 while (j >= 0 && j < clist->columns)
5758 if (clist->column[j].button &&
5759 GTK_WIDGET_VISIBLE (clist->column[j].button))
5761 if (GTK_IS_CONTAINER (clist->column[j].button) &&
5763 (GTK_CONTAINER (clist->column[j].button), dir))
5768 else if (GTK_WIDGET_CAN_FOCUS (clist->column[j].button))
5770 gtk_widget_grab_focus (clist->column[j].button);
5780 if (COLUMN_LEFT_XPIXEL (clist, j) < CELL_SPACING + COLUMN_INSET)
5781 gtk_clist_moveto (clist, -1, j, 0, 0);
5782 else if (COLUMN_LEFT_XPIXEL(clist, j) + clist->column[j].area.width >
5783 clist->clist_window_width)
5785 if (j == clist->columns-1)
5786 gtk_clist_moveto (clist, -1, j, 0, 0);
5788 gtk_clist_moveto (clist, -1, j, 0, 1);
5795 gtk_clist_focus (GtkContainer * container,
5796 GtkDirectionType direction)
5799 GtkWidget *focus_child;
5802 g_return_val_if_fail (container != NULL, FALSE);
5803 g_return_val_if_fail (GTK_IS_CLIST (container), FALSE);
5805 if (!GTK_WIDGET_SENSITIVE (container))
5808 clist = GTK_CLIST (container);
5809 focus_child = container->focus_child;
5810 old_row = clist->focus_row;
5816 if (GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5817 (!focus_child || (focus_child && focus_child != clist->vscrollbar &&
5818 focus_child != clist->hscrollbar)))
5820 if (title_focus (clist, direction))
5822 gtk_container_set_focus_child (container, NULL);
5825 gtk_widget_grab_focus (GTK_WIDGET (container));
5828 case GTK_DIR_TAB_FORWARD:
5829 if (GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5830 (!focus_child || (focus_child != clist->vscrollbar &&
5831 focus_child != clist->hscrollbar)))
5833 gboolean tf = FALSE;
5835 if (((focus_child && direction == GTK_DIR_DOWN) ||
5836 !(tf = title_focus (clist, GTK_DIR_TAB_FORWARD)))
5839 if (clist->focus_row < 0)
5841 clist->focus_row = 0;
5843 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
5844 clist->selection_mode == GTK_SELECTION_EXTENDED) &&
5846 select_row (clist, clist->focus_row, -1, NULL);
5848 gtk_widget_grab_focus (GTK_WIDGET (container));
5856 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
5858 if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child ||
5859 (focus_child != clist->vscrollbar &&
5860 focus_child != clist->hscrollbar)) &&
5861 GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
5862 GTK_WIDGET_CAN_FOCUS (clist->vscrollbar))
5864 gtk_widget_grab_focus (clist->vscrollbar);
5868 if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child ||
5869 focus_child != clist->hscrollbar) &&
5870 GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
5871 GTK_WIDGET_CAN_FOCUS (clist->hscrollbar))
5873 gtk_widget_grab_focus (clist->hscrollbar);
5878 case GTK_DIR_TAB_BACKWARD:
5879 if (!focus_child && GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5880 GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
5881 GTK_WIDGET_CAN_FOCUS (clist->hscrollbar))
5883 gtk_widget_grab_focus (clist->hscrollbar);
5887 if ((!focus_child || focus_child == clist->hscrollbar) &&
5888 GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5889 GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
5890 GTK_WIDGET_CAN_FOCUS (clist->vscrollbar))
5892 gtk_widget_grab_focus (clist->vscrollbar);
5896 if ((!focus_child || focus_child == clist->hscrollbar ||
5897 focus_child == clist->vscrollbar) &&
5898 GTK_CLIST_CHILD_HAS_FOCUS (clist) && clist->rows)
5900 if (clist->focus_row < 0)
5902 clist->focus_row = 0;
5903 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
5904 clist->selection_mode == GTK_SELECTION_EXTENDED) &&
5906 select_row (clist, clist->focus_row, -1, NULL);
5908 gtk_widget_grab_focus (GTK_WIDGET (container));
5912 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
5914 if (title_focus (clist, direction))
5923 gtk_container_set_focus_child (container, NULL);
5928 gtk_clist_unselect_all (GtkCList * clist)
5930 g_return_if_fail (clist != NULL);
5931 g_return_if_fail (GTK_IS_CLIST (clist));
5933 GTK_CLIST_CLASS_FW (clist)->unselect_all (clist);
5937 real_unselect_all (GtkCList * clist)
5942 g_return_if_fail (clist != NULL);
5943 g_return_if_fail (GTK_IS_CLIST (clist));
5945 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5948 switch (clist->selection_mode)
5950 case GTK_SELECTION_BROWSE:
5951 if (clist->focus_row >= 0)
5953 select_row (clist, clist->focus_row, -1, NULL);
5958 case GTK_SELECTION_EXTENDED:
5959 g_list_free (clist->undo_selection);
5960 g_list_free (clist->undo_unselection);
5961 clist->undo_selection = NULL;
5962 clist->undo_unselection = NULL;
5965 clist->drag_pos = -1;
5966 clist->undo_anchor = clist->focus_row;
5973 list = clist->selection;
5977 i = GPOINTER_TO_INT (list->data);
5979 unselect_row (clist, i, -1, NULL);
5984 gtk_clist_select_all (GtkCList * clist)
5986 g_return_if_fail (clist != NULL);
5987 g_return_if_fail (GTK_IS_CLIST (clist));
5989 GTK_CLIST_CLASS_FW (clist)->select_all (clist);
5993 real_select_all (GtkCList * clist)
5998 g_return_if_fail (clist != NULL);
5999 g_return_if_fail (GTK_IS_CLIST (clist));
6001 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
6004 switch (clist->selection_mode)
6006 case GTK_SELECTION_SINGLE:
6007 case GTK_SELECTION_BROWSE:
6010 case GTK_SELECTION_EXTENDED:
6011 g_list_free (clist->undo_selection);
6012 g_list_free (clist->undo_unselection);
6013 clist->undo_selection = NULL;
6014 clist->undo_unselection = NULL;
6017 ((GtkCListRow *) (clist->row_list->data))->state !=
6019 fake_toggle_row (clist, 0);
6021 clist->anchor_state = GTK_STATE_SELECTED;
6023 clist->drag_pos = 0;
6024 clist->undo_anchor = clist->focus_row;
6025 update_extended_selection (clist, clist->rows);
6026 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
6029 case GTK_SELECTION_MULTIPLE:
6030 for (i = 0, list = clist->row_list; list; i++, list = list->next)
6032 if (((GtkCListRow *)(list->data))->state == GTK_STATE_NORMAL)
6033 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
6041 fake_unselect_all (GtkCList * clist,
6048 if (row >= 0 && (work = g_list_nth (clist->row_list, row)))
6050 if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL &&
6051 GTK_CLIST_ROW (work)->selectable)
6053 GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
6055 if (!GTK_CLIST_FROZEN (clist) &&
6056 gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
6057 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
6058 GTK_CLIST_ROW (work));
6062 clist->undo_selection = clist->selection;
6063 clist->selection = NULL;
6064 clist->selection_end = NULL;
6066 for (list = clist->undo_selection; list; list = list->next)
6068 if ((i = GPOINTER_TO_INT (list->data)) == row ||
6069 !(work = g_list_nth (clist->row_list, i)))
6072 GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
6073 if (!GTK_CLIST_FROZEN (clist) &&
6074 gtk_clist_row_is_visible (clist, i) != GTK_VISIBILITY_NONE)
6075 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, i,
6076 GTK_CLIST_ROW (work));
6081 fake_toggle_row (GtkCList *clist,
6086 if (!(work = g_list_nth (clist->row_list, row))||
6087 !GTK_CLIST_ROW (work)->selectable)
6090 if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL)
6091 clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
6093 clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
6095 if (!GTK_CLIST_FROZEN (clist) &&
6096 gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
6097 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
6098 GTK_CLIST_ROW (work));
6102 selection_find (GtkCList *clist,
6104 GList *row_list_element)
6106 return g_list_find (clist->selection, GINT_TO_POINTER (row_number));
6110 default_compare (GtkCList *clist,
6117 GtkCListRow *row1 = (GtkCListRow *) ptr1;
6118 GtkCListRow *row2 = (GtkCListRow *) ptr2;
6120 switch (row1->cell[clist->sort_column].type)
6123 text1 = GTK_CELL_TEXT (row1->cell[clist->sort_column])->text;
6125 case GTK_CELL_PIXTEXT:
6126 text1 = GTK_CELL_PIXTEXT (row1->cell[clist->sort_column])->text;
6132 switch (row2->cell[clist->sort_column].type)
6135 text2 = GTK_CELL_TEXT (row2->cell[clist->sort_column])->text;
6137 case GTK_CELL_PIXTEXT:
6138 text2 = GTK_CELL_PIXTEXT (row2->cell[clist->sort_column])->text;
6145 return (text1 != NULL);
6150 return strcmp (text1, text2);
6154 gtk_clist_set_compare_func (GtkCList *clist,
6155 GtkCListCompareFunc cmp_func)
6157 g_return_if_fail (clist != NULL);
6158 g_return_if_fail (GTK_IS_CLIST (clist));
6160 clist->compare = (cmp_func) ? cmp_func : default_compare;
6164 gtk_clist_set_auto_sort (GtkCList *clist,
6167 g_return_if_fail (clist != NULL);
6168 g_return_if_fail (GTK_IS_CLIST (clist));
6170 if (GTK_CLIST_AUTO_SORT (clist) && !auto_sort)
6171 GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_SORT);
6172 else if (!GTK_CLIST_AUTO_SORT (clist) && auto_sort)
6174 GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_SORT);
6175 gtk_clist_sort (clist);
6180 gtk_clist_set_sort_type (GtkCList *clist,
6181 GtkSortType sort_type)
6183 g_return_if_fail (clist != NULL);
6184 g_return_if_fail (GTK_IS_CLIST (clist));
6186 clist->sort_type = sort_type;
6190 gtk_clist_set_sort_column (GtkCList *clist,
6193 g_return_if_fail (clist != NULL);
6194 g_return_if_fail (GTK_IS_CLIST (clist));
6196 if (column < 0 || column >= clist->columns)
6199 clist->sort_column = column;
6203 gtk_clist_merge (GtkCList *clist,
6204 GList *a, /* first list to merge */
6205 GList *b) /* second list to merge */
6207 GList z = { 0 }; /* auxiliary node */
6233 cmp = clist->compare (clist, GTK_CLIST_ROW (a), GTK_CLIST_ROW (b));
6234 if ((cmp >= 0 && clist->sort_type == GTK_SORT_DESCENDING) ||
6235 (cmp <= 0 && clist->sort_type == GTK_SORT_ASCENDING) ||
6257 gtk_clist_mergesort (GtkCList *clist,
6258 GList *list, /* the list to sort */
6259 gint num) /* the list's length */
6270 /* move "half" to the middle */
6272 for (i = 0; i < num / 2; i++)
6275 /* cut the list in two */
6276 half->prev->next = NULL;
6279 /* recursively sort both lists */
6280 return gtk_clist_merge (clist,
6281 gtk_clist_mergesort (clist, list, num / 2),
6282 gtk_clist_mergesort (clist, half, num - num / 2));
6287 gtk_clist_sort (GtkCList *clist)
6289 g_return_if_fail (clist != NULL);
6290 g_return_if_fail (GTK_IS_CLIST (clist));
6292 GTK_CLIST_CLASS_FW (clist)->sort_list (clist);
6296 real_sort_list (GtkCList *clist)
6301 gboolean thaw = FALSE;
6303 g_return_if_fail (clist != NULL);
6304 g_return_if_fail (GTK_IS_CLIST (clist));
6306 if (clist->rows <= 1)
6309 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
6312 if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
6314 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
6315 g_list_free (clist->undo_selection);
6316 g_list_free (clist->undo_unselection);
6317 clist->undo_selection = NULL;
6318 clist->undo_unselection = NULL;
6321 if (!GTK_CLIST_FROZEN (clist))
6323 gtk_clist_freeze (clist);
6327 clist->row_list = gtk_clist_mergesort (clist, clist->row_list, clist->rows);
6329 work = clist->selection;
6331 for (i = 0, list = clist->row_list; i < clist->rows; i++, list = list->next)
6333 if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
6335 work->data = GINT_TO_POINTER (i);
6339 if (i == clist->rows - 1)
6340 clist->row_list_end = list;
6344 gtk_clist_thaw (clist);