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_append (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, clist->rows, text);
1699 gtk_clist_insert (GtkCList * clist,
1703 return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, row, text);
1707 real_insert_row (GtkCList * clist,
1712 GtkCListRow *clist_row;
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 /* return if out of bounds */
1719 if (row < 0 || row > clist->rows)
1722 /* create the row */
1723 clist_row = row_new (clist);
1725 /* set the text in the row's columns */
1726 for (i = 0; i < clist->columns; i++)
1728 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
1729 (clist, clist_row, i, GTK_CELL_TEXT, text[i], 0, NULL ,NULL);
1733 clist->row_list = g_list_append (clist->row_list, clist_row);
1734 clist->row_list_end = clist->row_list;
1738 if (GTK_CLIST_AUTO_SORT (clist)) /* override insertion pos */
1743 work = clist->row_list;
1745 if (clist->sort_type == GTK_SORT_ASCENDING)
1747 while (row < clist->rows &&
1748 clist->compare (clist, clist_row,
1749 GTK_CLIST_ROW (work)) > 0)
1757 while (row < clist->rows &&
1758 clist->compare (clist, clist_row,
1759 GTK_CLIST_ROW (work)) < 0)
1767 /* reset the row end pointer if we're inserting at the end of the list */
1768 if (row == clist->rows)
1769 clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
1771 clist->row_list = g_list_insert (clist->row_list, clist_row, row);
1776 if (row < ROW_FROM_YPIXEL (clist, 0))
1777 clist->voffset -= (clist->row_height + CELL_SPACING);
1779 /* syncronize the selection list */
1780 sync_selection (clist, row, SYNC_INSERT);
1782 /* redraw the list if it isn't frozen */
1783 if (!GTK_CLIST_FROZEN (clist))
1785 adjust_scrollbars (clist);
1787 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1788 draw_rows (clist, NULL);
1795 gtk_clist_remove (GtkCList * clist,
1798 GTK_CLIST_CLASS_FW (clist)->remove_row (clist, row);
1802 real_remove_row (GtkCList * clist,
1805 gint was_visible, was_selected;
1807 GtkCListRow *clist_row;
1809 g_return_if_fail (clist != NULL);
1810 g_return_if_fail (GTK_IS_CLIST (clist));
1812 /* return if out of bounds */
1813 if (row < 0 || row > (clist->rows - 1))
1816 was_visible = (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE);
1819 /* get the row we're going to delete */
1820 list = g_list_nth (clist->row_list, row);
1821 clist_row = list->data;
1823 /* if we're removing a selected row, we have to make sure
1824 * it's properly unselected, and then sync up the clist->selected
1825 * list to reflect the deincrimented indexies of rows after the
1827 if (clist_row->state == GTK_STATE_SELECTED)
1829 switch (clist->selection_mode)
1831 case GTK_SELECTION_SINGLE:
1832 case GTK_SELECTION_MULTIPLE:
1833 case GTK_SELECTION_EXTENDED:
1834 unselect_row (clist, row, -1, NULL);
1837 case GTK_SELECTION_BROWSE:
1838 select_row (clist, row - 1, -1, NULL);
1846 /* reset the row end pointer if we're removing at the
1847 * end of the list */
1848 if (row == clist->rows - 1)
1849 clist->row_list_end = list->prev;
1850 if (row >= clist->focus_row && clist->focus_row >=0)
1853 clist->row_list = g_list_remove (clist->row_list, clist_row);
1856 if (row < ROW_FROM_YPIXEL (clist, 0))
1857 clist->voffset += clist->row_height + CELL_SPACING;
1859 sync_selection (clist, row, SYNC_REMOVE);
1862 row_delete (clist, clist_row);
1864 /* redraw the row if it isn't frozen */
1865 if (!GTK_CLIST_FROZEN (clist))
1867 adjust_scrollbars (clist);
1870 draw_rows (clist, NULL);
1875 sync_selection (GtkCList * clist,
1882 if (mode == SYNC_INSERT)
1887 if (clist->focus_row >= row)
1889 clist->focus_row += d;
1890 if (clist->focus_row == -1 && clist->rows >= 1)
1891 clist->focus_row = 0;
1894 if (clist->selection_mode == GTK_SELECTION_BROWSE && clist->anchor != -1)
1895 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
1897 g_list_free (clist->undo_selection);
1898 g_list_free (clist->undo_unselection);
1899 clist->undo_selection = NULL;
1900 clist->undo_unselection = NULL;
1903 clist->drag_pos = -1;
1904 clist->undo_anchor = clist->focus_row;
1906 list = clist->selection;
1909 if (GPOINTER_TO_INT (list->data) >= row)
1910 list->data = ((gchar*) list->data) + d;
1916 gtk_clist_clear (GtkCList * clist)
1918 g_return_if_fail (clist != NULL);
1919 g_return_if_fail (GTK_IS_CLIST (clist));
1921 GTK_CLIST_CLASS_FW (clist)->clear (clist);
1925 real_clear (GtkCList * clist)
1929 g_return_if_fail (clist != NULL);
1930 g_return_if_fail (GTK_IS_CLIST (clist));
1932 /* remove all the rows */
1933 for (list = clist->row_list; list; list = list->next)
1934 row_delete (clist, GTK_CLIST_ROW (list));
1936 g_list_free (clist->row_list);
1938 /* free up the selection list */
1939 g_list_free (clist->selection);
1940 g_list_free (clist->undo_selection);
1941 g_list_free (clist->undo_unselection);
1943 clist->row_list = NULL;
1944 clist->row_list_end = NULL;
1945 clist->selection = NULL;
1946 clist->selection_end = NULL;
1947 clist->undo_selection = NULL;
1948 clist->undo_unselection = NULL;
1951 clist->focus_row = -1;
1953 clist->undo_anchor = -1;
1954 clist->anchor_state = GTK_STATE_SELECTED;
1955 clist->drag_pos = -1;
1957 /* zero-out the scrollbars */
1958 if (clist->vscrollbar)
1960 GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0;
1961 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
1963 if (!GTK_CLIST_FROZEN (clist))
1964 gtk_clist_thaw (clist);
1969 gtk_clist_swap_rows (GtkCList * clist,
1974 GList *list, *link1, *link2;
1977 g_return_if_fail (clist != NULL);
1978 g_return_if_fail (GTK_IS_CLIST (clist));
1980 if (GTK_CLIST_AUTO_SORT (clist))
1983 if (row1 < 0 || row1 > (clist->rows - 1))
1986 if (row2 < 0 || row2 > (clist->rows - 1))
1989 first = MIN (row1, row2);
1990 last = MAX (row1, row2);
1992 link1 = g_list_nth (clist->row_list, first);
1993 link2 = g_list_nth (link1, row2 - row1);
1996 link1->data = link2->data;
1999 list = clist->selection;
2002 if (GPOINTER_TO_INT (list->data) == row1)
2003 list->data = GINT_TO_POINTER (row2);
2005 if (GPOINTER_TO_INT (list->data) == row2)
2006 list->data = GINT_TO_POINTER (row1);
2011 if (!GTK_CLIST_FROZEN (clist))
2013 if (gtk_clist_row_is_visible (clist, row1) != GTK_VISIBILITY_NONE)
2014 GTK_CLIST_CLASS_FW (clist)->draw_row
2015 (clist, NULL, row1, GTK_CLIST_ROW (link2));
2017 if (gtk_clist_row_is_visible (clist, row2) != GTK_VISIBILITY_NONE)
2018 GTK_CLIST_CLASS_FW (clist)->draw_row
2019 (clist, NULL, row2, GTK_CLIST_ROW (link1));
2024 gtk_clist_set_row_data (GtkCList * clist,
2028 gtk_clist_set_row_data_full (clist, row, data, NULL);
2032 gtk_clist_set_row_data_full (GtkCList * clist,
2035 GtkDestroyNotify destroy)
2037 GtkCListRow *clist_row;
2039 g_return_if_fail (clist != NULL);
2040 g_return_if_fail (GTK_IS_CLIST (clist));
2042 if (row < 0 || row > (clist->rows - 1))
2045 clist_row = (g_list_nth (clist->row_list, row))->data;
2046 clist_row->data = data;
2047 clist_row->destroy = destroy;
2051 gtk_clist_get_row_data (GtkCList * clist,
2054 GtkCListRow *clist_row;
2056 g_return_val_if_fail (clist != NULL, NULL);
2057 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2059 if (row < 0 || row > (clist->rows - 1))
2062 clist_row = (g_list_nth (clist->row_list, row))->data;
2063 return clist_row->data;
2067 gtk_clist_find_row_from_data (GtkCList * clist,
2073 g_return_val_if_fail (clist != NULL, -1);
2074 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
2076 if (clist->rows < 1)
2077 return -1; /* is this an optimization or just worthless? */
2079 for (n = 0, list = clist->row_list; list; n++, list = list->next)
2080 if (GTK_CLIST_ROW (list)->data == data)
2087 gtk_clist_select_row (GtkCList * clist,
2091 g_return_if_fail (clist != NULL);
2092 g_return_if_fail (GTK_IS_CLIST (clist));
2094 if (row < 0 || row >= clist->rows)
2097 if (column < -1 || column >= clist->columns)
2100 select_row (clist, row, column, NULL);
2104 gtk_clist_unselect_row (GtkCList * clist,
2108 g_return_if_fail (clist != NULL);
2109 g_return_if_fail (GTK_IS_CLIST (clist));
2111 if (row < 0 || row >= clist->rows)
2114 if (column < -1 || column >= clist->columns)
2117 unselect_row (clist, row, column, NULL);
2121 gtk_clist_row_is_visible (GtkCList * clist,
2126 g_return_val_if_fail (clist != NULL, 0);
2127 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
2129 if (row < 0 || row >= clist->rows)
2130 return GTK_VISIBILITY_NONE;
2132 if (clist->row_height == 0)
2133 return GTK_VISIBILITY_NONE;
2135 if (row < ROW_FROM_YPIXEL (clist, 0))
2136 return GTK_VISIBILITY_NONE;
2138 if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height))
2139 return GTK_VISIBILITY_NONE;
2141 top = ROW_TOP_YPIXEL (clist, row);
2144 || ((top + clist->row_height) >= clist->clist_window_height))
2145 return GTK_VISIBILITY_PARTIAL;
2147 return GTK_VISIBILITY_FULL;
2151 static GtkAdjustment*
2152 gtk_clist_get_vadjustment (GtkCList * clist)
2154 g_return_val_if_fail (clist != NULL, NULL);
2155 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2157 return gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
2160 static GtkAdjustment*
2161 gtk_clist_get_hadjustment (GtkCList * clist)
2163 g_return_val_if_fail (clist != NULL, NULL);
2164 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2166 return gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
2171 gtk_clist_set_policy (GtkCList * clist,
2172 GtkPolicyType vscrollbar_policy,
2173 GtkPolicyType hscrollbar_policy)
2175 g_return_if_fail (clist != NULL);
2176 g_return_if_fail (GTK_IS_CLIST (clist));
2178 if (clist->vscrollbar_policy != vscrollbar_policy)
2180 clist->vscrollbar_policy = vscrollbar_policy;
2182 if (GTK_WIDGET (clist)->parent)
2183 gtk_widget_queue_resize (GTK_WIDGET (clist));
2186 if (clist->hscrollbar_policy != hscrollbar_policy)
2188 clist->hscrollbar_policy = hscrollbar_policy;
2190 if (GTK_WIDGET (clist)->parent)
2191 gtk_widget_queue_resize (GTK_WIDGET (clist));
2196 gtk_clist_undo_selection (GtkCList *clist)
2198 g_return_if_fail (clist != NULL);
2199 g_return_if_fail (GTK_IS_CLIST (clist));
2201 if (clist->selection_mode == GTK_SELECTION_EXTENDED &&
2202 (clist->undo_selection || clist->undo_unselection))
2203 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNDO_SELECTION]);
2207 real_undo_selection (GtkCList *clist)
2211 g_return_if_fail (clist != NULL);
2212 g_return_if_fail (GTK_IS_CLIST (clist));
2214 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
2215 clist->selection_mode != GTK_SELECTION_EXTENDED)
2218 if (clist->anchor >= 0)
2219 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
2221 if (!(clist->undo_selection || clist->undo_unselection))
2223 gtk_clist_unselect_all (clist);
2227 for (work = clist->undo_selection; work; work = work->next)
2228 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
2229 GPOINTER_TO_INT (work->data), -1, NULL);
2231 for (work = clist->undo_unselection; work; work = work->next)
2232 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
2233 GPOINTER_TO_INT (work->data), -1, NULL);
2235 if (GTK_WIDGET_HAS_FOCUS (clist) && clist->focus_row != clist->undo_anchor)
2237 gtk_clist_draw_focus (GTK_WIDGET (clist));
2238 clist->focus_row = clist->undo_anchor;
2239 gtk_clist_draw_focus (GTK_WIDGET (clist));
2242 clist->focus_row = clist->undo_anchor;
2244 clist->undo_anchor = -1;
2246 g_list_free (clist->undo_selection);
2247 g_list_free (clist->undo_unselection);
2248 clist->undo_selection = NULL;
2249 clist->undo_unselection = NULL;
2251 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
2252 clist->clist_window_height)
2253 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
2254 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
2255 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
2261 * gtk_clist_finalize
2264 gtk_clist_destroy (GtkObject * object)
2269 g_return_if_fail (object != NULL);
2270 g_return_if_fail (GTK_IS_CLIST (object));
2272 clist = GTK_CLIST (object);
2274 /* freeze the list */
2275 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2277 /* get rid of all the rows */
2278 gtk_clist_clear (clist);
2280 /* Since we don't have a _remove method, unparent the children
2281 * instead of destroying them so the focus will be unset properly.
2282 * (For other containers, the _remove method takes care of the
2283 * unparent) The destroy will happen when the refcount drops
2287 /* destroy the scrollbars */
2288 if (clist->vscrollbar)
2290 gtk_widget_unparent (clist->vscrollbar);
2291 clist->vscrollbar = NULL;
2293 if (clist->hscrollbar)
2295 gtk_widget_unparent (clist->hscrollbar);
2296 clist->hscrollbar = NULL;
2301 gtk_timeout_remove (clist->htimer);
2306 gtk_timeout_remove (clist->vtimer);
2310 /* destroy the column buttons */
2311 for (i = 0; i < clist->columns; i++)
2312 if (clist->column[i].button)
2314 gtk_widget_unparent (clist->column[i].button);
2315 clist->column[i].button = NULL;
2318 if (GTK_OBJECT_CLASS (parent_class)->destroy)
2319 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2323 gtk_clist_finalize (GtkObject * object)
2327 g_return_if_fail (object != NULL);
2328 g_return_if_fail (GTK_IS_CLIST (object));
2330 clist = GTK_CLIST (object);
2332 columns_delete (clist);
2334 g_mem_chunk_destroy (clist->cell_mem_chunk);
2335 g_mem_chunk_destroy (clist->row_mem_chunk);
2337 if (GTK_OBJECT_CLASS (parent_class)->finalize)
2338 (*GTK_OBJECT_CLASS (parent_class)->finalize) (object);
2344 * gtk_clist_unrealize
2349 * gtk_clist_button_press
2350 * gtk_clist_button_release
2352 * gtk_clist_size_request
2353 * gtk_clist_size_allocate
2356 gtk_clist_realize (GtkWidget * widget)
2360 GdkWindowAttr attributes;
2361 gint attributes_mask;
2365 g_return_if_fail (widget != NULL);
2366 g_return_if_fail (GTK_IS_CLIST (widget));
2368 clist = GTK_CLIST (widget);
2370 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2372 add_style_data (clist);
2374 border_width = GTK_CONTAINER (widget)->border_width;
2376 attributes.window_type = GDK_WINDOW_CHILD;
2377 attributes.x = widget->allocation.x + border_width;
2378 attributes.y = widget->allocation.y + border_width;
2379 attributes.width = widget->allocation.width - border_width * 2;
2380 attributes.height = widget->allocation.height - border_width * 2;
2381 attributes.wclass = GDK_INPUT_OUTPUT;
2382 attributes.visual = gtk_widget_get_visual (widget);
2383 attributes.colormap = gtk_widget_get_colormap (widget);
2384 attributes.event_mask = gtk_widget_get_events (widget);
2385 attributes.event_mask |= (GDK_EXPOSURE_MASK |
2386 GDK_BUTTON_PRESS_MASK |
2387 GDK_BUTTON_RELEASE_MASK |
2388 GDK_KEY_PRESS_MASK |
2389 GDK_KEY_RELEASE_MASK);
2390 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2393 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
2394 gdk_window_set_user_data (widget->window, clist);
2396 widget->style = gtk_style_attach (widget->style, widget->window);
2398 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
2400 /* column-title window */
2402 attributes.x = clist->column_title_area.x;
2403 attributes.y = clist->column_title_area.y;
2404 attributes.width = clist->column_title_area.width;
2405 attributes.height = clist->column_title_area.height;
2407 clist->title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2408 gdk_window_set_user_data (clist->title_window, clist);
2410 gtk_style_set_background (widget->style, clist->title_window, GTK_STATE_SELECTED);
2411 gdk_window_show (clist->title_window);
2413 /* set things up so column buttons are drawn in title window */
2414 for (i = 0; i < clist->columns; i++)
2415 if (clist->column[i].button)
2416 gtk_widget_set_parent_window (clist->column[i].button, clist->title_window);
2419 attributes.x = clist->internal_allocation.x + widget->style->klass->xthickness;
2420 attributes.y = clist->internal_allocation.y + widget->style->klass->ythickness +
2421 clist->column_title_area.height;
2422 attributes.width = clist->clist_window_width;
2423 attributes.height = clist->clist_window_height;
2425 clist->clist_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2426 gdk_window_set_user_data (clist->clist_window, clist);
2428 gdk_window_set_background (clist->clist_window, &widget->style->bg[GTK_STATE_PRELIGHT]);
2429 gdk_window_show (clist->clist_window);
2430 gdk_window_get_size (clist->clist_window, &clist->clist_window_width,
2431 &clist->clist_window_height);
2433 /* create resize windows */
2434 attributes.wclass = GDK_INPUT_ONLY;
2435 attributes.event_mask = (GDK_BUTTON_PRESS_MASK |
2436 GDK_BUTTON_RELEASE_MASK |
2437 GDK_POINTER_MOTION_MASK |
2438 GDK_POINTER_MOTION_HINT_MASK |
2439 GDK_KEY_PRESS_MASK);
2440 attributes.cursor = clist->cursor_drag = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
2441 attributes_mask = GDK_WA_CURSOR;
2443 for (i = 0; i < clist->columns; i++)
2445 clist->column[i].window = gdk_window_new (clist->title_window, &attributes, attributes_mask);
2446 gdk_window_set_user_data (clist->column[i].window, clist);
2449 /* This is slightly less efficient than creating them with the
2450 * right size to begin with, but easier
2452 size_allocate_title_buttons (clist);
2455 clist->fg_gc = gdk_gc_new (widget->window);
2456 clist->bg_gc = gdk_gc_new (widget->window);
2458 /* We'll use this gc to do scrolling as well */
2459 gdk_gc_set_exposures (clist->fg_gc, TRUE);
2461 values.foreground = widget->style->white;
2462 values.function = GDK_XOR;
2463 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
2464 clist->xor_gc = gdk_gc_new_with_values (widget->window,
2472 gtk_clist_unrealize (GtkWidget * widget)
2477 g_return_if_fail (widget != NULL);
2478 g_return_if_fail (GTK_IS_CLIST (widget));
2480 clist = GTK_CLIST (widget);
2482 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2484 gdk_cursor_destroy (clist->cursor_drag);
2485 gdk_gc_destroy (clist->xor_gc);
2486 gdk_gc_destroy (clist->fg_gc);
2487 gdk_gc_destroy (clist->bg_gc);
2489 for (i = 0; i < clist->columns; i++)
2490 if (clist->column[i].window)
2492 gdk_window_set_user_data (clist->column[i].window, NULL);
2493 gdk_window_destroy (clist->column[i].window);
2494 clist->column[i].window = NULL;
2497 gdk_window_set_user_data (clist->clist_window, NULL);
2498 gdk_window_destroy (clist->clist_window);
2499 clist->clist_window = NULL;
2501 gdk_window_set_user_data (clist->title_window, NULL);
2502 gdk_window_destroy (clist->title_window);
2503 clist->title_window = NULL;
2505 clist->cursor_drag = NULL;
2506 clist->xor_gc = NULL;
2507 clist->fg_gc = NULL;
2508 clist->bg_gc = NULL;
2510 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
2511 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2515 gtk_clist_map (GtkWidget * widget)
2520 g_return_if_fail (widget != NULL);
2521 g_return_if_fail (GTK_IS_CLIST (widget));
2523 clist = GTK_CLIST (widget);
2525 if (!GTK_WIDGET_MAPPED (widget))
2527 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
2529 gdk_window_show (widget->window);
2530 gdk_window_show (clist->title_window);
2531 gdk_window_show (clist->clist_window);
2533 /* map column buttons */
2534 for (i = 0; i < clist->columns; i++)
2535 if (clist->column[i].button &&
2536 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
2537 !GTK_WIDGET_MAPPED (clist->column[i].button))
2538 gtk_widget_map (clist->column[i].button);
2540 /* map resize windows AFTER column buttons (above) */
2541 for (i = 0; i < clist->columns; i++)
2542 if (clist->column[i].window && clist->column[i].button)
2543 gdk_window_show (clist->column[i].window);
2545 /* map vscrollbars */
2546 if (GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
2547 !GTK_WIDGET_MAPPED (clist->vscrollbar))
2548 gtk_widget_map (clist->vscrollbar);
2550 if (GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
2551 !GTK_WIDGET_MAPPED (clist->hscrollbar))
2552 gtk_widget_map (clist->hscrollbar);
2554 /* unfreeze the list */
2555 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
2560 gtk_clist_unmap (GtkWidget * widget)
2565 g_return_if_fail (widget != NULL);
2566 g_return_if_fail (GTK_IS_CLIST (widget));
2568 clist = GTK_CLIST (widget);
2570 if (GTK_WIDGET_MAPPED (widget))
2572 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
2574 for (i = 0; i < clist->columns; i++)
2575 if (clist->column[i].window)
2576 gdk_window_hide (clist->column[i].window);
2578 gdk_window_hide (clist->clist_window);
2579 gdk_window_hide (clist->title_window);
2580 gdk_window_hide (widget->window);
2582 /* unmap scrollbars */
2583 if (GTK_WIDGET_MAPPED (clist->vscrollbar))
2584 gtk_widget_unmap (clist->vscrollbar);
2586 if (GTK_WIDGET_MAPPED (clist->hscrollbar))
2587 gtk_widget_unmap (clist->hscrollbar);
2589 /* unmap column buttons */
2590 for (i = 0; i < clist->columns; i++)
2591 if (clist->column[i].button &&
2592 GTK_WIDGET_MAPPED (clist->column[i].button))
2593 gtk_widget_unmap (clist->column[i].button);
2595 /* freeze the list */
2596 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2601 gtk_clist_draw (GtkWidget * widget,
2602 GdkRectangle * area)
2606 GdkRectangle child_area;
2609 g_return_if_fail (widget != NULL);
2610 g_return_if_fail (GTK_IS_CLIST (widget));
2611 g_return_if_fail (area != NULL);
2613 if (GTK_WIDGET_DRAWABLE (widget))
2615 clist = GTK_CLIST (widget);
2616 border_width = GTK_CONTAINER (widget)->border_width;
2618 gdk_window_clear_area (widget->window,
2619 area->x - border_width,
2620 area->y - border_width,
2621 area->width, area->height);
2623 /* draw list shadow/border */
2624 gtk_draw_shadow (widget->style, widget->window,
2625 GTK_STATE_NORMAL, clist->shadow_type,
2627 clist->clist_window_width + (2 * widget->style->klass->xthickness),
2628 clist->clist_window_height + (2 * widget->style->klass->ythickness) +
2629 clist->column_title_area.height);
2631 gdk_window_clear_area (clist->clist_window,
2634 draw_rows (clist, NULL);
2636 for (i = 0; i < clist->columns; i++)
2638 if (gtk_widget_intersect (clist->column[i].button, area, &child_area))
2639 gtk_widget_draw (clist->column[i].button, &child_area);
2645 gtk_clist_expose (GtkWidget * widget,
2646 GdkEventExpose * event)
2650 g_return_val_if_fail (widget != NULL, FALSE);
2651 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2652 g_return_val_if_fail (event != NULL, FALSE);
2654 if (GTK_WIDGET_DRAWABLE (widget))
2656 clist = GTK_CLIST (widget);
2659 if (event->window == widget->window)
2660 gtk_draw_shadow (widget->style, widget->window,
2661 GTK_STATE_NORMAL, clist->shadow_type,
2663 clist->clist_window_width + (2 * widget->style->klass->xthickness),
2664 clist->clist_window_height + (2 * widget->style->klass->ythickness) +
2665 clist->column_title_area.height);
2667 /* exposure events on the list */
2668 if (event->window == clist->clist_window)
2669 draw_rows (clist, &event->area);
2676 gtk_clist_button_press (GtkWidget * widget,
2677 GdkEventButton * event)
2686 g_return_val_if_fail (widget != NULL, FALSE);
2687 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2688 g_return_val_if_fail (event != NULL, FALSE);
2690 clist = GTK_CLIST (widget);
2692 /* we don't handle button 2 and 3 */
2693 if (event->button != 1)
2696 /* selections on the list */
2697 if (event->window == clist->clist_window)
2702 if (get_selection_info (clist, x, y, &row, &column))
2704 gint old_row = clist->focus_row;
2706 if (clist->focus_row == -1)
2709 if (event->type == GDK_BUTTON_PRESS)
2711 GTK_CLIST_SET_FLAG (clist, CLIST_DRAG_SELECTION);
2712 gdk_pointer_grab (clist->clist_window, FALSE,
2713 GDK_POINTER_MOTION_HINT_MASK |
2714 GDK_BUTTON1_MOTION_MASK |
2715 GDK_BUTTON_RELEASE_MASK,
2716 NULL, NULL, event->time);
2717 gtk_grab_add (widget);
2719 else if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (widget))
2721 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
2722 gtk_grab_remove (widget);
2723 gdk_pointer_ungrab (event->time);
2726 if (GTK_CLIST_ADD_MODE (clist))
2728 GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
2729 if (GTK_WIDGET_HAS_FOCUS (widget))
2731 gtk_clist_draw_focus (widget);
2732 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2733 GDK_LINE_SOLID, 0, 0);
2734 clist->focus_row = row;
2735 gtk_clist_draw_focus (widget);
2739 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2740 GDK_LINE_SOLID, 0, 0);
2741 clist->focus_row = row;
2744 else if (row != clist->focus_row)
2746 if (GTK_WIDGET_HAS_FOCUS (widget))
2748 gtk_clist_draw_focus (widget);
2749 clist->focus_row = row;
2750 gtk_clist_draw_focus (widget);
2753 clist->focus_row = row;
2756 if (!GTK_WIDGET_HAS_FOCUS (widget))
2757 gtk_widget_grab_focus (widget);
2759 switch (clist->selection_mode)
2761 case GTK_SELECTION_SINGLE:
2762 case GTK_SELECTION_MULTIPLE:
2763 if (event->type != GDK_BUTTON_PRESS)
2764 select_row (clist, row, column, (GdkEvent *) event);
2766 clist->anchor = row;
2769 case GTK_SELECTION_BROWSE:
2770 select_row (clist, row, column, (GdkEvent *) event);
2773 case GTK_SELECTION_EXTENDED:
2774 if (event->type != GDK_BUTTON_PRESS)
2776 if (clist->anchor != -1)
2778 update_extended_selection (clist, clist->focus_row);
2779 GTK_CLIST_CLASS_FW (clist)->resync_selection
2780 (clist, (GdkEvent *) event);
2782 select_row (clist, row, column, (GdkEvent *) event);
2786 if (event->state & GDK_CONTROL_MASK)
2788 if (event->state & GDK_SHIFT_MASK)
2790 if (clist->anchor < 0)
2792 g_list_free (clist->undo_selection);
2793 g_list_free (clist->undo_unselection);
2794 clist->undo_selection = NULL;
2795 clist->undo_unselection = NULL;
2796 clist->anchor = old_row;
2797 clist->drag_pos = old_row;
2798 clist->undo_anchor = old_row;
2800 update_extended_selection (clist, clist->focus_row);
2804 if (clist->anchor == -1)
2805 set_anchor (clist, TRUE, row, old_row);
2807 update_extended_selection (clist, clist->focus_row);
2812 if (event->state & GDK_SHIFT_MASK)
2814 set_anchor (clist, FALSE, old_row, old_row);
2815 update_extended_selection (clist, clist->focus_row);
2819 if (clist->anchor == -1)
2820 set_anchor (clist, FALSE, row, old_row);
2822 update_extended_selection (clist, clist->focus_row);
2833 /* press on resize windows */
2834 for (i = 0; i < clist->columns; i++)
2835 if (clist->column[i].window && event->window == clist->column[i].window)
2837 gdk_pointer_grab (clist->column[i].window, FALSE,
2838 GDK_POINTER_MOTION_HINT_MASK |
2839 GDK_BUTTON1_MOTION_MASK |
2840 GDK_BUTTON_RELEASE_MASK,
2841 NULL, NULL, event->time);
2842 gtk_grab_add (widget);
2843 GTK_CLIST_SET_FLAG (clist, CLIST_IN_DRAG);
2845 if (!GTK_WIDGET_HAS_FOCUS (widget))
2846 gtk_widget_grab_focus (widget);
2848 clist->drag_pos = i;
2849 clist->x_drag = (COLUMN_LEFT_XPIXEL(clist, i) + COLUMN_INSET +
2850 clist->column[i].area.width + CELL_SPACING);
2852 if (GTK_CLIST_ADD_MODE (clist))
2853 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
2854 draw_xor_line (clist);
2863 gtk_clist_button_release (GtkWidget * widget,
2864 GdkEventButton * event)
2868 g_return_val_if_fail (widget != NULL, FALSE);
2869 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2870 g_return_val_if_fail (event != NULL, FALSE);
2872 clist = GTK_CLIST (widget);
2874 /* we don't handle button 2 and 3 */
2875 if (event->button != 1)
2878 /* release on resize windows */
2879 if (GTK_CLIST_IN_DRAG (clist))
2881 gint i, x, width, visible;
2883 i = clist->drag_pos;
2884 clist->drag_pos = -1;
2885 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
2886 gtk_widget_get_pointer (widget, &x, NULL);
2888 width = new_column_width (clist, i, &x, &visible);
2889 gtk_grab_remove (widget);
2890 gdk_pointer_ungrab (event->time);
2893 draw_xor_line (clist);
2895 if (GTK_CLIST_ADD_MODE (clist))
2897 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2898 GDK_LINE_ON_OFF_DASH, 0, 0);
2899 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
2902 resize_column (clist, i, width);
2906 if (GTK_CLIST_DRAG_SELECTION (clist))
2911 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
2912 gtk_grab_remove (widget);
2913 gdk_pointer_ungrab (event->time);
2916 gtk_timeout_remove (clist->htimer);
2921 gtk_timeout_remove (clist->vtimer);
2924 switch (clist->selection_mode)
2926 case GTK_SELECTION_EXTENDED:
2927 if (!(event->state & GDK_SHIFT_MASK) ||
2928 event->x < 0 || event->x >= clist->clist_window_width ||
2929 event->y < 0 || event->y >= clist->clist_window_height)
2930 GTK_CLIST_CLASS_FW (clist)->resync_selection
2931 (clist, (GdkEvent *) event);
2934 case GTK_SELECTION_SINGLE:
2935 case GTK_SELECTION_MULTIPLE:
2936 if (get_selection_info (clist, event->x, event->y, &row, &column))
2938 if (clist->anchor == clist->focus_row)
2939 toggle_row (clist, row, column, (GdkEvent *) event);
2953 horizontal_timeout (GtkCList *clist)
2956 GdkEventMotion event;
2957 GdkModifierType mask;
2959 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
2962 gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
2969 gtk_clist_motion (GTK_WIDGET (clist), &event);
2975 vertical_timeout (GtkCList *clist)
2978 GdkEventMotion event;
2979 GdkModifierType mask;
2981 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
2984 gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
2991 gtk_clist_motion (GTK_WIDGET (clist), &event);
2997 move_vertical (GtkCList *clist,
3004 adj = GTK_RANGE (clist->vscrollbar)->adjustment;
3006 y = ROW_TOP_YPIXEL (clist, row) - clist->voffset;
3008 y = y - align * (clist->clist_window_height - clist->row_height)
3009 + (2 * align - 1) * CELL_SPACING;
3011 if (y + adj->page_size > adj->upper)
3012 adj->value = adj->upper - adj->page_size;
3016 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
3020 move_horizontal (GtkCList *clist,
3026 adj = GTK_RANGE (clist->hscrollbar)->adjustment;
3030 upper = adj->upper - adj->page_size;
3031 adj->value = MIN (adj->value, upper);
3032 adj->value = MAX (adj->value, 0.0);
3034 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
3038 gtk_clist_motion (GtkWidget * widget,
3039 GdkEventMotion * event)
3047 g_return_val_if_fail (widget != NULL, FALSE);
3048 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
3050 clist = GTK_CLIST (widget);
3052 if (!(gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)))
3055 if (GTK_CLIST_IN_DRAG (clist))
3057 if (event->is_hint || event->window != widget->window)
3058 gtk_widget_get_pointer (widget, &x, NULL);
3062 new_width = new_column_width (clist, clist->drag_pos, &x, &visible);
3063 /* Welcome to my hack! I'm going to use a value of x_drag = -99999
3064 * to indicate that the xor line is already invisible */
3066 if (!visible && clist->x_drag != -99999)
3068 draw_xor_line (clist);
3069 clist->x_drag = -99999;
3072 if (x != clist->x_drag && visible)
3074 if (clist->x_drag != -99999)
3075 draw_xor_line (clist);
3078 draw_xor_line (clist);
3081 if (new_width <= COLUMN_MIN_WIDTH + 1)
3083 if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) && x < 0)
3084 gtk_clist_moveto (clist, -1, clist->drag_pos, 0, 0);
3090 if (event->is_hint || event->window != clist->clist_window)
3091 gdk_window_get_pointer (clist->clist_window, &x, &y, NULL);
3093 /* horizontal autoscrolling */
3094 if (LIST_WIDTH (clist) > clist->clist_window_width &&
3095 (x < 0 || x >= clist->clist_window_width))
3100 clist->htimer = gtk_timeout_add
3101 (SCROLL_TIME, (GtkFunction) horizontal_timeout, clist);
3103 if (!((x < 0 && GTK_RANGE (clist->hscrollbar)->adjustment->value == 0) ||
3104 (x >= clist->clist_window_width &&
3105 GTK_RANGE (clist->hscrollbar)->adjustment->value ==
3106 LIST_WIDTH (clist) - clist->clist_window_width)))
3109 move_horizontal (clist, -1 + (x/2));
3111 move_horizontal (clist, 1 + (x - clist->clist_window_width) / 2);
3115 if (GTK_CLIST_IN_DRAG (clist))
3118 /* vertical autoscrolling */
3119 row = ROW_FROM_YPIXEL (clist, y);
3121 /* don't scroll on last pixel row if it's a cell spacing */
3122 if (y == clist->clist_window_height-1 &&
3123 y == ROW_TOP_YPIXEL (clist, row-1) + clist->row_height)
3126 if (LIST_HEIGHT (clist) > clist->clist_window_height &&
3127 (y < 0 || y >= clist->clist_window_height))
3132 clist->vtimer = gtk_timeout_add (SCROLL_TIME,
3133 (GtkFunction) vertical_timeout, clist);
3135 if (GTK_CLIST_DRAG_SELECTION (clist))
3137 if ((y < 0 && clist->focus_row == 0) ||
3138 (y >= clist->clist_window_height &&
3139 clist->focus_row == clist->rows-1))
3144 row = CLAMP (row, 0, clist->rows - 1);
3146 if (GTK_CLIST_DRAG_SELECTION (clist))
3148 if (row == clist->focus_row)
3151 gtk_clist_draw_focus (widget);
3152 clist->focus_row = row;
3153 gtk_clist_draw_focus (widget);
3155 switch (clist->selection_mode)
3157 case GTK_SELECTION_BROWSE:
3158 select_row (clist, clist->focus_row, - 1, (GdkEvent *) event);
3161 case GTK_SELECTION_EXTENDED:
3162 update_extended_selection (clist, clist->focus_row);
3170 if (ROW_TOP_YPIXEL(clist, row) < 0)
3171 move_vertical (clist, row, 0);
3172 else if (ROW_TOP_YPIXEL(clist, row) + clist->row_height >
3173 clist->clist_window_height)
3174 move_vertical (clist, row, 1);
3180 gtk_clist_size_request (GtkWidget * widget,
3181 GtkRequisition * requisition)
3186 g_return_if_fail (widget != NULL);
3187 g_return_if_fail (GTK_IS_CLIST (widget));
3188 g_return_if_fail (requisition != NULL);
3190 clist = GTK_CLIST (widget);
3192 add_style_data (clist);
3194 requisition->width = 0;
3195 requisition->height = 0;
3197 /* compute the size of the column title (title) area */
3198 clist->column_title_area.height = 0;
3199 if (GTK_CLIST_SHOW_TITLES (clist))
3200 for (i = 0; i < clist->columns; i++)
3201 if (clist->column[i].button)
3203 gtk_widget_size_request (clist->column[i].button, &clist->column[i].button->requisition);
3204 clist->column_title_area.height = MAX (clist->column_title_area.height,
3205 clist->column[i].button->requisition.height);
3207 requisition->height += clist->column_title_area.height;
3209 /* add the vscrollbar space */
3210 if ((clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
3211 GTK_WIDGET_VISIBLE (clist->vscrollbar))
3213 gtk_widget_size_request (clist->vscrollbar, &clist->vscrollbar->requisition);
3215 requisition->width += clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist);
3216 requisition->height = MAX (requisition->height,
3217 clist->vscrollbar->requisition.height);
3220 /* add the hscrollbar space */
3221 if ((clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
3222 GTK_WIDGET_VISIBLE (clist->hscrollbar))
3224 gtk_widget_size_request (clist->hscrollbar, &clist->hscrollbar->requisition);
3226 requisition->height += clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist);
3227 requisition->width = MAX (clist->hscrollbar->requisition.width,
3228 requisition->width -
3229 clist->vscrollbar->requisition.width);
3233 requisition->width += widget->style->klass->xthickness * 2 +
3234 GTK_CONTAINER (widget)->border_width * 2;
3235 requisition->height += widget->style->klass->ythickness * 2 +
3236 GTK_CONTAINER (widget)->border_width * 2;
3240 gtk_clist_size_allocate (GtkWidget * widget,
3241 GtkAllocation * allocation)
3244 GtkAllocation clist_allocation;
3245 GtkAllocation child_allocation;
3246 gint i, vscrollbar_vis, hscrollbar_vis;
3248 g_return_if_fail (widget != NULL);
3249 g_return_if_fail (GTK_IS_CLIST (widget));
3250 g_return_if_fail (allocation != NULL);
3252 clist = GTK_CLIST (widget);
3253 widget->allocation = *allocation;
3255 if (GTK_WIDGET_REALIZED (widget))
3257 gdk_window_move_resize (widget->window,
3258 allocation->x + GTK_CONTAINER (widget)->border_width,
3259 allocation->y + GTK_CONTAINER (widget)->border_width,
3260 allocation->width - GTK_CONTAINER (widget)->border_width * 2,
3261 allocation->height - GTK_CONTAINER (widget)->border_width * 2);
3264 /* use internal allocation structure for all the math
3265 * because it's easier than always subtracting the container
3267 clist->internal_allocation.x = 0;
3268 clist->internal_allocation.y = 0;
3269 clist->internal_allocation.width = MAX (1, allocation->width -
3270 GTK_CONTAINER (widget)->border_width * 2);
3271 clist->internal_allocation.height = MAX (1, allocation->height -
3272 GTK_CONTAINER (widget)->border_width * 2);
3274 /* allocate clist window assuming no scrollbars */
3275 clist_allocation.x = clist->internal_allocation.x + widget->style->klass->xthickness;
3276 clist_allocation.y = clist->internal_allocation.y + widget->style->klass->ythickness +
3277 clist->column_title_area.height;
3278 clist_allocation.width = MAX (1, clist->internal_allocation.width -
3279 (2 * widget->style->klass->xthickness));
3280 clist_allocation.height = MAX (1, clist->internal_allocation.height -
3281 (2 * widget->style->klass->ythickness) -
3282 clist->column_title_area.height);
3285 * here's where we decide to show/not show the scrollbars
3290 for (i = 0; i <= 1; i++)
3292 if (LIST_HEIGHT (clist) <= clist_allocation.height &&
3293 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
3299 if (!vscrollbar_vis)
3302 clist_allocation.width = MAX (1, clist_allocation.width -
3303 (clist->vscrollbar->requisition.width +
3304 SCROLLBAR_SPACING (clist)));
3308 if (LIST_WIDTH (clist) <= clist_allocation.width &&
3309 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
3315 if (!hscrollbar_vis)
3318 clist_allocation.height = MAX (1, clist_allocation.height -
3319 (clist->hscrollbar->requisition.height +
3320 SCROLLBAR_SPACING (clist)));
3325 clist->clist_window_width = clist_allocation.width;
3326 clist->clist_window_height = clist_allocation.height;
3328 if (GTK_WIDGET_REALIZED (widget))
3330 gdk_window_move_resize (clist->clist_window,
3333 clist_allocation.width,
3334 clist_allocation.height);
3337 /* position the window which holds the column title buttons */
3338 clist->column_title_area.x = widget->style->klass->xthickness;
3339 clist->column_title_area.y = widget->style->klass->ythickness;
3340 clist->column_title_area.width = clist_allocation.width;
3342 if (GTK_WIDGET_REALIZED (widget))
3344 gdk_window_move_resize (clist->title_window,
3345 clist->column_title_area.x,
3346 clist->column_title_area.y,
3347 clist->column_title_area.width,
3348 clist->column_title_area.height);
3351 /* column button allocation */
3352 size_allocate_columns (clist);
3353 size_allocate_title_buttons (clist);
3355 adjust_scrollbars (clist);
3357 /* allocate the vscrollbar */
3360 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
3361 gtk_widget_show (clist->vscrollbar);
3363 child_allocation.x = clist->internal_allocation.x +
3364 clist->internal_allocation.width -
3365 clist->vscrollbar->requisition.width;
3366 child_allocation.y = clist->internal_allocation.y;
3367 child_allocation.width = clist->vscrollbar->requisition.width;
3368 child_allocation.height = MAX (1, clist->internal_allocation.height -
3369 (hscrollbar_vis ? (clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist)) : 0));
3371 gtk_widget_size_allocate (clist->vscrollbar, &child_allocation);
3375 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
3376 gtk_widget_hide (clist->vscrollbar);
3381 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
3382 gtk_widget_show (clist->hscrollbar);
3384 child_allocation.x = clist->internal_allocation.x;
3385 child_allocation.y = clist->internal_allocation.y +
3386 clist->internal_allocation.height -
3387 clist->hscrollbar->requisition.height;
3388 child_allocation.width = MAX (1, clist->internal_allocation.width -
3389 (vscrollbar_vis ? (clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist)) : 0));
3390 child_allocation.height = clist->hscrollbar->requisition.height;
3392 gtk_widget_size_allocate (clist->hscrollbar, &child_allocation);
3396 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
3397 gtk_widget_hide (clist->hscrollbar);
3400 /* set the vscrollbar adjustments */
3401 adjust_scrollbars (clist);
3409 gtk_clist_forall (GtkContainer *container,
3410 gboolean include_internals,
3411 GtkCallback callback,
3412 gpointer callback_data)
3416 g_return_if_fail (container != NULL);
3417 g_return_if_fail (GTK_IS_CLIST (container));
3418 g_return_if_fail (callback != NULL);
3420 clist = GTK_CLIST (container);
3422 if (include_internals)
3426 /* callback for the column buttons */
3427 for (i = 0; i < clist->columns; i++)
3428 if (clist->column[i].button)
3429 (*callback) (clist->column[i].button, callback_data);
3431 /* callbacks for the scrollbars */
3432 if (clist->vscrollbar)
3433 (*callback) (clist->vscrollbar, callback_data);
3434 if (clist->hscrollbar)
3435 (*callback) (clist->hscrollbar, callback_data);
3445 draw_row (GtkCList * clist,
3446 GdkRectangle * area,
3448 GtkCListRow * clist_row)
3451 GdkGC *fg_gc, *bg_gc;
3452 GdkRectangle row_rectangle, cell_rectangle, clip_rectangle, intersect_rectangle,
3454 gint i, offset = 0, width, height, pixmap_width = 0;
3455 gint xsrc, ysrc, xdest, ydest;
3457 g_return_if_fail (clist != NULL);
3459 /* bail now if we arn't drawable yet */
3460 if (!GTK_WIDGET_DRAWABLE (clist))
3463 if (row < 0 || row >= clist->rows)
3466 widget = GTK_WIDGET (clist);
3468 /* if the function is passed the pointer to the row instead of null,
3469 * it avoids this expensive lookup */
3471 clist_row = (g_list_nth (clist->row_list, row))->data;
3473 /* rectangle of the entire row */
3474 row_rectangle.x = 0;
3475 row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
3476 row_rectangle.width = clist->clist_window_width;
3477 row_rectangle.height = clist->row_height;
3479 /* rectangle of the cell spacing above the row */
3480 cell_rectangle.x = 0;
3481 cell_rectangle.y = row_rectangle.y - CELL_SPACING;
3482 cell_rectangle.width = row_rectangle.width;
3483 cell_rectangle.height = CELL_SPACING;
3485 /* rectangle used to clip drawing operations, it's y and height
3486 * positions only need to be set once, so we set them once here.
3487 * the x and width are set withing the drawing loop below once per
3489 clip_rectangle.y = row_rectangle.y;
3490 clip_rectangle.height = row_rectangle.height;
3492 /* select GC for background rectangle */
3493 if (clist_row->state == GTK_STATE_SELECTED)
3495 fg_gc = widget->style->fg_gc[GTK_STATE_SELECTED];
3496 bg_gc = widget->style->bg_gc[GTK_STATE_SELECTED];
3500 if (clist_row->fg_set)
3502 gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
3503 fg_gc = clist->fg_gc;
3506 fg_gc = widget->style->fg_gc[GTK_STATE_NORMAL];
3508 if (clist_row->bg_set)
3510 gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
3511 bg_gc = clist->bg_gc;
3514 bg_gc = widget->style->bg_gc[GTK_STATE_PRELIGHT];
3517 /* draw the cell borders and background */
3520 if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
3521 gdk_draw_rectangle (clist->clist_window,
3522 widget->style->base_gc[GTK_STATE_NORMAL],
3524 intersect_rectangle.x,
3525 intersect_rectangle.y,
3526 intersect_rectangle.width,
3527 intersect_rectangle.height);
3529 /* the last row has to clear it's bottom cell spacing too */
3530 if (clist_row == clist->row_list_end->data)
3532 cell_rectangle.y += clist->row_height + CELL_SPACING;
3534 if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
3535 gdk_draw_rectangle (clist->clist_window,
3536 widget->style->base_gc[GTK_STATE_NORMAL],
3538 intersect_rectangle.x,
3539 intersect_rectangle.y,
3540 intersect_rectangle.width,
3541 intersect_rectangle.height);
3544 if (!gdk_rectangle_intersect (area, &row_rectangle, &intersect_rectangle))
3547 if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
3548 gdk_draw_rectangle (clist->clist_window,
3551 intersect_rectangle.x,
3552 intersect_rectangle.y,
3553 intersect_rectangle.width,
3554 intersect_rectangle.height);
3556 gdk_window_clear_area (clist->clist_window,
3557 intersect_rectangle.x,
3558 intersect_rectangle.y,
3559 intersect_rectangle.width,
3560 intersect_rectangle.height);
3564 gdk_draw_rectangle (clist->clist_window,
3565 widget->style->base_gc[GTK_STATE_NORMAL],
3569 cell_rectangle.width,
3570 cell_rectangle.height);
3572 /* the last row has to clear it's bottom cell spacing too */
3573 if (clist_row == clist->row_list_end->data)
3575 cell_rectangle.y += clist->row_height + CELL_SPACING;
3577 gdk_draw_rectangle (clist->clist_window,
3578 widget->style->base_gc[GTK_STATE_NORMAL],
3582 cell_rectangle.width,
3583 cell_rectangle.height);
3586 if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
3587 gdk_draw_rectangle (clist->clist_window,
3592 row_rectangle.width,
3593 row_rectangle.height);
3595 gdk_window_clear_area (clist->clist_window,
3598 row_rectangle.width,
3599 row_rectangle.height);
3602 /* iterate and draw all the columns (row cells) and draw their contents */
3603 for (i = 0; i < clist->columns; i++)
3605 clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
3606 clip_rectangle.width = clist->column[i].area.width;
3608 /* calculate clipping region clipping region */
3611 rect = &clip_rectangle;
3615 if (!gdk_rectangle_intersect (area, &clip_rectangle,
3616 &intersect_rectangle))
3618 rect = &intersect_rectangle;
3621 /* calculate real width for column justification */
3622 switch (clist_row->cell[i].type)
3624 case GTK_CELL_EMPTY:
3629 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
3630 GTK_CELL_TEXT (clist_row->cell[i])->text);
3633 case GTK_CELL_PIXMAP:
3634 gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, &width, &height);
3635 pixmap_width = width;
3638 case GTK_CELL_PIXTEXT:
3639 gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, &width, &height);
3640 pixmap_width = width;
3641 width += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
3642 width += gdk_string_width (GTK_WIDGET (clist)->style->font,
3643 GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
3646 case GTK_CELL_WIDGET:
3656 switch (clist->column[i].justification)
3658 case GTK_JUSTIFY_LEFT:
3659 offset = clip_rectangle.x;
3662 case GTK_JUSTIFY_RIGHT:
3663 offset = (clip_rectangle.x + clip_rectangle.width) - width;
3666 case GTK_JUSTIFY_CENTER:
3667 offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
3670 case GTK_JUSTIFY_FILL:
3671 offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
3679 /* Draw Text or Pixmap */
3680 switch (clist_row->cell[i].type)
3682 case GTK_CELL_EMPTY:
3687 gdk_gc_set_clip_rectangle (fg_gc, rect);
3689 gdk_draw_string (clist->clist_window,
3690 widget->style->font,
3692 offset + clist_row->cell[i].horizontal,
3693 row_rectangle.y + clist->row_center_offset +
3694 clist_row->cell[i].vertical,
3695 GTK_CELL_TEXT (clist_row->cell[i])->text);
3697 gdk_gc_set_clip_rectangle (fg_gc, NULL);
3700 case GTK_CELL_PIXMAP:
3703 xdest = offset + clist_row->cell[i].horizontal;
3704 ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
3705 clist_row->cell[i].vertical;
3707 if (xdest < clip_rectangle.x)
3709 xsrc = clip_rectangle.x - xdest;
3710 pixmap_width -= xsrc;
3711 xdest = clip_rectangle.x;
3714 if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width)
3715 pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest;
3717 if (ydest < clip_rectangle.y)
3719 ysrc = clip_rectangle.y - ydest;
3721 ydest = clip_rectangle.y;
3724 if (ydest + height > clip_rectangle.y + clip_rectangle.height)
3725 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
3727 if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
3729 gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXMAP (clist_row->cell[i])->mask);
3730 gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
3732 gdk_draw_pixmap (clist->clist_window,
3734 GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
3737 pixmap_width, height);
3739 if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
3741 gdk_gc_set_clip_origin (fg_gc, 0, 0);
3742 gdk_gc_set_clip_mask (fg_gc, NULL);
3746 case GTK_CELL_PIXTEXT:
3747 /* draw the pixmap */
3750 xdest = offset + clist_row->cell[i].horizontal;
3751 ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
3752 clist_row->cell[i].vertical;
3754 if (xdest < clip_rectangle.x)
3756 xsrc = clip_rectangle.x - xdest;
3757 pixmap_width -= xsrc;
3758 xdest = clip_rectangle.x;
3761 if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width)
3762 pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest;
3764 if (ydest < clip_rectangle.y)
3766 ysrc = clip_rectangle.y - ydest;
3768 ydest = clip_rectangle.y;
3771 if (ydest + height > clip_rectangle.y + clip_rectangle.height)
3772 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
3774 if (GTK_CELL_PIXTEXT (clist_row->cell[i])->mask)
3776 gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXTEXT (clist_row->cell[i])->mask);
3777 gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
3780 gdk_draw_pixmap (clist->clist_window,
3782 GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
3786 pixmap_width, height);
3788 gdk_gc_set_clip_origin (fg_gc, 0, 0);
3790 offset += pixmap_width + GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
3792 /* draw the string */
3793 gdk_gc_set_clip_rectangle (fg_gc, rect);
3795 gdk_draw_string (clist->clist_window,
3796 widget->style->font,
3798 offset + clist_row->cell[i].horizontal,
3799 row_rectangle.y + clist->row_center_offset +
3800 clist_row->cell[i].vertical,
3801 GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
3803 gdk_gc_set_clip_rectangle (fg_gc, NULL);
3806 case GTK_CELL_WIDGET:
3816 if (clist->focus_row == row && GTK_WIDGET_HAS_FOCUS (widget))
3820 if (gdk_rectangle_intersect (area, &row_rectangle,
3821 &intersect_rectangle))
3823 gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle);
3824 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
3825 row_rectangle.x, row_rectangle.y,
3826 row_rectangle.width - 1,
3827 row_rectangle.height - 1);
3828 gdk_gc_set_clip_rectangle (clist->xor_gc, NULL);
3832 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
3833 row_rectangle.x, row_rectangle.y,
3834 row_rectangle.width - 1, row_rectangle.height - 1);
3839 draw_rows (GtkCList * clist,
3840 GdkRectangle * area)
3843 GtkCListRow *clist_row;
3844 int i, first_row, last_row;
3846 g_return_if_fail (clist != NULL);
3847 g_return_if_fail (GTK_IS_CLIST (clist));
3849 if (clist->row_height == 0 ||
3850 !GTK_WIDGET_DRAWABLE (clist))
3855 first_row = ROW_FROM_YPIXEL (clist, area->y);
3856 last_row = ROW_FROM_YPIXEL (clist, area->y + area->height);
3860 first_row = ROW_FROM_YPIXEL (clist, 0);
3861 last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height);
3864 /* this is a small special case which exposes the bottom cell line
3865 * on the last row -- it might go away if I change the wall the cell spacings
3867 if (clist->rows == first_row)
3870 list = g_list_nth (clist->row_list, first_row);
3874 clist_row = list->data;
3880 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, area, i, clist_row);
3885 gdk_window_clear_area (clist->clist_window, 0, ROW_TOP_YPIXEL (clist, i), -1, -1);
3890 * size_allocate_title_buttons
3891 * size_allocate_columns
3894 size_allocate_title_buttons (GtkCList * clist)
3896 gint i, last_button = 0;
3897 GtkAllocation button_allocation;
3899 if (!GTK_WIDGET_REALIZED (clist))
3902 button_allocation.x = clist->hoffset;
3903 button_allocation.y = 0;
3904 button_allocation.width = 0;
3905 button_allocation.height = clist->column_title_area.height;
3907 for (i = 0; i < clist->columns; i++)
3909 button_allocation.width += clist->column[i].area.width;
3911 if (i == clist->columns - 1)
3912 button_allocation.width += 2 * (CELL_SPACING + COLUMN_INSET);
3914 button_allocation.width += CELL_SPACING + (2 * COLUMN_INSET);
3916 if (i == (clist->columns - 1) || clist->column[i + 1].button)
3918 gtk_widget_size_allocate (clist->column[last_button].button, &button_allocation);
3919 button_allocation.x += button_allocation.width;
3920 button_allocation.width = 0;
3922 gdk_window_show (clist->column[last_button].window);
3923 gdk_window_move_resize (clist->column[last_button].window,
3924 button_allocation.x - (DRAG_WIDTH / 2),
3925 0, DRAG_WIDTH, clist->column_title_area.height);
3927 last_button = i + 1;
3931 gdk_window_hide (clist->column[i].window);
3937 size_allocate_columns (GtkCList * clist)
3939 gint i, xoffset = 0;
3941 for (i = 0; i < clist->columns; i++)
3943 clist->column[i].area.x = xoffset + CELL_SPACING + COLUMN_INSET;
3945 if (i == clist->columns - 1)
3949 if (clist->column[i].width_set)
3951 width = clist->column[i].width;
3955 if (clist->column[i].title)
3956 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
3957 clist->column[i].title);
3962 clist->column[i].area.width = MAX (width,
3963 clist->clist_window_width -
3964 xoffset - (2 * (CELL_SPACING + COLUMN_INSET)));
3969 clist->column[i].area.width = clist->column[i].width;
3972 xoffset += clist->column[i].area.width + CELL_SPACING + (2 * COLUMN_INSET);
3981 * get_selection_info
3984 toggle_row (GtkCList * clist,
3989 GtkCListRow *clist_row;
3991 switch (clist->selection_mode)
3993 case GTK_SELECTION_EXTENDED:
3994 case GTK_SELECTION_MULTIPLE:
3995 case GTK_SELECTION_SINGLE:
3997 clist_row = g_list_nth (clist->row_list, row)->data;
3998 if (clist_row->state == GTK_STATE_SELECTED)
4000 unselect_row (clist, row, column, event);
4004 case GTK_SELECTION_BROWSE:
4005 select_row (clist, row, column, event);
4011 select_row (GtkCList * clist,
4016 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
4017 row, column, event);
4021 unselect_row (GtkCList * clist,
4026 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
4027 row, column, event);
4031 real_select_row (GtkCList * clist,
4036 GtkCListRow *clist_row;
4039 gboolean row_selected;
4041 g_return_if_fail (clist != NULL);
4042 g_return_if_fail (GTK_IS_CLIST (clist));
4044 if (row < 0 || row > (clist->rows - 1))
4047 switch (clist->selection_mode)
4049 case GTK_SELECTION_SINGLE:
4050 case GTK_SELECTION_BROWSE:
4052 row_selected = FALSE;
4053 list = clist->selection;
4057 sel_row = GPOINTER_TO_INT (list->data);
4061 row_selected = TRUE;
4063 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
4064 sel_row, column, event);
4074 clist_row = (g_list_nth (clist->row_list, row))->data;
4076 if (clist_row->state != GTK_STATE_NORMAL || !clist_row->selectable)
4079 clist_row->state = GTK_STATE_SELECTED;
4080 if (!clist->selection)
4082 clist->selection = g_list_append (clist->selection,
4083 GINT_TO_POINTER (row));
4084 clist->selection_end = clist->selection;
4087 clist->selection_end =
4088 g_list_append (clist->selection_end, GINT_TO_POINTER (row))->next;
4090 if (!GTK_CLIST_FROZEN (clist)
4091 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
4092 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
4096 real_unselect_row (GtkCList * clist,
4101 GtkCListRow *clist_row;
4103 g_return_if_fail (clist != NULL);
4104 g_return_if_fail (GTK_IS_CLIST (clist));
4106 if (row < 0 || row > (clist->rows - 1))
4109 clist_row = (g_list_nth (clist->row_list, row))->data;
4111 if (clist_row->state == GTK_STATE_SELECTED)
4113 clist_row->state = GTK_STATE_NORMAL;
4115 if (clist->selection_end &&
4116 clist->selection_end->data == GINT_TO_POINTER (row))
4117 clist->selection_end = clist->selection_end->prev;
4119 clist->selection = g_list_remove (clist->selection,
4120 GINT_TO_POINTER (row));
4122 if (!GTK_CLIST_FROZEN (clist)
4123 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
4124 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
4129 get_selection_info (GtkCList * clist,
4137 g_return_val_if_fail (clist != NULL, 0);
4138 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
4140 /* bounds checking, return false if the user clicked
4141 * on a blank area */
4142 trow = ROW_FROM_YPIXEL (clist, y);
4143 if (trow >= clist->rows)
4149 tcol = COLUMN_FROM_XPIXEL (clist, x);
4150 if (tcol >= clist->columns)
4160 gtk_clist_get_selection_info (GtkCList *clist,
4166 g_return_val_if_fail (clist != NULL, 0);
4167 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
4168 return get_selection_info (clist, x, y, row, column);
4178 draw_xor_line (GtkCList * clist)
4182 g_return_if_fail (clist != NULL);
4184 widget = GTK_WIDGET (clist);
4186 gdk_draw_line (widget->window, clist->xor_gc,
4188 widget->style->klass->ythickness,
4190 clist->column_title_area.height + clist->clist_window_height + 1);
4193 /* this function returns the new width of the column being resized given
4194 * the column and x position of the cursor; the x cursor position is passed
4195 * in as a pointer and automagicly corrected if it's beyond min/max limits */
4197 new_column_width (GtkCList * clist,
4206 /* first translate the x position from widget->window
4207 * to clist->clist_window */
4208 cx -= GTK_WIDGET (clist)->style->klass->xthickness;
4210 /* rx is x from the list beginning */
4211 rx = cx - clist->hoffset;
4213 /* you can't shrink a column to less than its minimum width */
4214 if (cx < (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH))
4216 *x = cx = COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH +
4217 GTK_WIDGET (clist)->style->klass->xthickness;
4218 cx -= GTK_WIDGET (clist)->style->klass->xthickness;
4219 rx = cx - clist->hoffset;
4222 if (cx < 0 || cx > clist->clist_window_width)
4227 /* calculate new column width making sure it doesn't end up
4228 * less than the minimum width */
4229 width = (rx - COLUMN_LEFT (clist, column)) - COLUMN_INSET -
4230 ((clist->columns == (column - 1)) ? CELL_SPACING : 0);
4231 if (width < COLUMN_MIN_WIDTH)
4232 width = COLUMN_MIN_WIDTH;
4237 /* this will do more later */
4239 resize_column (GtkCList * clist,
4243 gtk_clist_set_column_width (clist, column, width);
4248 column_button_create (GtkCList * clist,
4253 button = clist->column[column].button = gtk_button_new ();
4254 if (GTK_WIDGET_REALIZED (clist) && clist->title_window)
4255 gtk_widget_set_parent_window (clist->column[column].button, clist->title_window);
4256 gtk_widget_set_parent (button, GTK_WIDGET (clist));
4258 gtk_signal_connect (GTK_OBJECT (button), "clicked",
4259 (GtkSignalFunc) column_button_clicked,
4262 gtk_widget_show (button);
4266 column_button_clicked (GtkWidget * widget,
4272 g_return_if_fail (widget != NULL);
4273 g_return_if_fail (GTK_IS_CLIST (data));
4275 clist = GTK_CLIST (data);
4277 /* find the column who's button was pressed */
4278 for (i = 0; i < clist->columns; i++)
4279 if (clist->column[i].button == widget)
4282 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i);
4291 * vadjustment_changed
4292 * hadjustment_changed
4293 * vadjustment_value_changed
4294 * hadjustment_value_changed
4297 create_scrollbars (GtkCList * clist)
4299 GtkAdjustment *adjustment;
4301 clist->vscrollbar = gtk_vscrollbar_new (NULL);
4303 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
4305 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
4306 (GtkSignalFunc) vadjustment_changed,
4309 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
4310 (GtkSignalFunc) vadjustment_value_changed,
4313 gtk_widget_set_parent (clist->vscrollbar, GTK_WIDGET (clist));
4314 gtk_widget_show (clist->vscrollbar);
4316 clist->hscrollbar = gtk_hscrollbar_new (NULL);
4318 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
4320 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
4321 (GtkSignalFunc) hadjustment_changed,
4324 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
4325 (GtkSignalFunc) hadjustment_value_changed,
4328 gtk_widget_set_parent (clist->hscrollbar, GTK_WIDGET (clist));
4329 gtk_widget_show (clist->hscrollbar);
4333 adjust_scrollbars (GtkCList * clist)
4335 GTK_RANGE (clist->vscrollbar)->adjustment->page_size = clist->clist_window_height;
4336 GTK_RANGE (clist->vscrollbar)->adjustment->page_increment = clist->clist_window_height / 2;
4337 GTK_RANGE (clist->vscrollbar)->adjustment->step_increment = 10;
4338 GTK_RANGE (clist->vscrollbar)->adjustment->lower = 0;
4339 GTK_RANGE (clist->vscrollbar)->adjustment->upper = LIST_HEIGHT (clist);
4341 if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist))
4343 GTK_RANGE (clist->vscrollbar)->adjustment->value = MAX (0, LIST_HEIGHT (clist) -
4344 clist->clist_window_height);
4345 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment),
4349 GTK_RANGE (clist->hscrollbar)->adjustment->page_size = clist->clist_window_width;
4350 GTK_RANGE (clist->hscrollbar)->adjustment->page_increment = clist->clist_window_width / 2;
4351 GTK_RANGE (clist->hscrollbar)->adjustment->step_increment = 10;
4352 GTK_RANGE (clist->hscrollbar)->adjustment->lower = 0;
4353 GTK_RANGE (clist->hscrollbar)->adjustment->upper = LIST_WIDTH (clist);
4355 if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist))
4357 GTK_RANGE (clist->hscrollbar)->adjustment->value = MAX (0, LIST_WIDTH (clist) -
4358 clist->clist_window_width);
4359 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment),
4363 if (LIST_HEIGHT (clist) <= clist->clist_window_height &&
4364 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
4366 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
4368 gtk_widget_hide (clist->vscrollbar);
4369 gtk_widget_size_allocate (GTK_WIDGET (clist),
4370 >K_WIDGET (clist)->allocation);
4375 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
4377 gtk_widget_show (clist->vscrollbar);
4378 gtk_widget_size_allocate (GTK_WIDGET (clist),
4379 >K_WIDGET (clist)->allocation);
4383 if (LIST_WIDTH (clist) <= clist->clist_window_width &&
4384 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
4386 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
4388 gtk_widget_hide (clist->hscrollbar);
4389 gtk_widget_size_allocate (GTK_WIDGET (clist),
4390 >K_WIDGET (clist)->allocation);
4395 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
4397 gtk_widget_show (clist->hscrollbar);
4398 gtk_widget_size_allocate (GTK_WIDGET (clist),
4399 >K_WIDGET (clist)->allocation);
4403 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
4404 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), "changed");
4408 vadjustment_changed (GtkAdjustment * adjustment,
4413 g_return_if_fail (adjustment != NULL);
4414 g_return_if_fail (data != NULL);
4416 clist = GTK_CLIST (data);
4420 hadjustment_changed (GtkAdjustment * adjustment,
4425 g_return_if_fail (adjustment != NULL);
4426 g_return_if_fail (data != NULL);
4428 clist = GTK_CLIST (data);
4432 check_exposures (GtkCList *clist)
4436 if (!GTK_WIDGET_REALIZED (clist))
4439 /* Make sure graphics expose events are processed before scrolling
4441 while ((event = gdk_event_get_graphics_expose (clist->clist_window)) != NULL)
4443 gtk_widget_event (GTK_WIDGET (clist), event);
4444 if (event->expose.count == 0)
4446 gdk_event_free (event);
4449 gdk_event_free (event);
4454 vadjustment_value_changed (GtkAdjustment * adjustment,
4461 g_return_if_fail (adjustment != NULL);
4462 g_return_if_fail (data != NULL);
4463 g_return_if_fail (GTK_IS_CLIST (data));
4465 clist = GTK_CLIST (data);
4467 if (!GTK_WIDGET_DRAWABLE (clist))
4470 value = adjustment->value;
4472 if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)))
4474 if (value > -clist->voffset)
4477 diff = value + clist->voffset;
4479 /* we have to re-draw the whole screen here... */
4480 if (diff >= clist->clist_window_height)
4482 clist->voffset = -value;
4483 draw_rows (clist, NULL);
4487 if ((diff != 0) && (diff != clist->clist_window_height))
4488 gdk_window_copy_area (clist->clist_window,
4491 clist->clist_window,
4494 clist->clist_window_width,
4495 clist->clist_window_height - diff);
4498 area.y = clist->clist_window_height - diff;
4499 area.width = clist->clist_window_width;
4505 diff = -clist->voffset - value;
4507 /* we have to re-draw the whole screen here... */
4508 if (diff >= clist->clist_window_height)
4510 clist->voffset = -value;
4511 draw_rows (clist, NULL);
4515 if ((diff != 0) && (diff != clist->clist_window_height))
4516 gdk_window_copy_area (clist->clist_window,
4519 clist->clist_window,
4522 clist->clist_window_width,
4523 clist->clist_window_height - diff);
4527 area.width = clist->clist_window_width;
4532 clist->voffset = -value;
4533 if ((diff != 0) && (diff != clist->clist_window_height))
4534 check_exposures (clist);
4537 draw_rows (clist, &area);
4541 hadjustment_value_changed (GtkAdjustment * adjustment,
4551 g_return_if_fail (adjustment != NULL);
4552 g_return_if_fail (data != NULL);
4553 g_return_if_fail (GTK_IS_CLIST (data));
4555 clist = GTK_CLIST (data);
4557 if (!GTK_WIDGET_DRAWABLE (clist) ||
4558 adjustment != gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)))
4561 value = adjustment->value;
4563 /* move the column buttons and resize windows */
4564 for (i = 0; i < clist->columns; i++)
4566 if (clist->column[i].button)
4568 clist->column[i].button->allocation.x -= value + clist->hoffset;
4570 if (clist->column[i].button->window)
4572 gdk_window_move (clist->column[i].button->window,
4573 clist->column[i].button->allocation.x,
4574 clist->column[i].button->allocation.y);
4576 if (clist->column[i].window)
4577 gdk_window_move (clist->column[i].window,
4578 clist->column[i].button->allocation.x +
4579 clist->column[i].button->allocation.width -
4580 (DRAG_WIDTH / 2), 0);
4585 if (value > -clist->hoffset)
4588 diff = value + clist->hoffset;
4590 clist->hoffset = -value;
4592 /* we have to re-draw the whole screen here... */
4593 if (diff >= clist->clist_window_width)
4595 draw_rows (clist, NULL);
4599 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
4600 GTK_CLIST_ADD_MODE (clist))
4602 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4604 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
4605 clist->clist_window_width - 1,
4606 clist->row_height - 1);
4608 gdk_window_copy_area (clist->clist_window,
4611 clist->clist_window,
4614 clist->clist_window_width - diff,
4615 clist->clist_window_height);
4617 area.x = clist->clist_window_width - diff;
4622 if (!(diff = -clist->hoffset - value))
4625 clist->hoffset = -value;
4627 /* we have to re-draw the whole screen here... */
4628 if (diff >= clist->clist_window_width)
4630 draw_rows (clist, NULL);
4634 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
4635 GTK_CLIST_ADD_MODE (clist))
4637 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4639 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
4640 clist->clist_window_width - 1,
4641 clist->row_height - 1);
4644 gdk_window_copy_area (clist->clist_window,
4647 clist->clist_window,
4650 clist->clist_window_width - diff,
4651 clist->clist_window_height);
4658 area.height = clist->clist_window_height;
4660 check_exposures (clist);
4662 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist))
4664 if (GTK_CLIST_ADD_MODE (clist))
4668 focus_row = clist->focus_row;
4669 clist->focus_row = -1;
4670 draw_rows (clist, &area);
4671 clist->focus_row = focus_row;
4673 gdk_draw_rectangle (clist->clist_window, clist->xor_gc,
4674 FALSE, 0, y, clist->clist_window_width - 1,
4675 clist->row_height - 1);
4685 x0 = clist->clist_window_width - 1;
4694 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4695 gdk_draw_line (clist->clist_window, clist->xor_gc,
4696 x0, y + 1, x0, y + clist->row_height - 2);
4697 gdk_draw_line (clist->clist_window, clist->xor_gc,
4698 x1, y + 1, x1, y + clist->row_height - 2);
4702 draw_rows (clist, &area);
4706 * Memory Allocation/Distruction Routines for GtkCList stuctures
4716 static GtkCListColumn *
4717 columns_new (GtkCList * clist)
4720 GtkCListColumn *column;
4722 column = g_new (GtkCListColumn, clist->columns);
4724 for (i = 0; i < clist->columns; i++)
4726 column[i].area.x = 0;
4727 column[i].area.y = 0;
4728 column[i].area.width = 0;
4729 column[i].area.height = 0;
4730 column[i].title = NULL;
4731 column[i].button = NULL;
4732 column[i].window = NULL;
4733 column[i].width = 0;
4734 column[i].width_set = FALSE;
4735 column[i].justification = GTK_JUSTIFY_LEFT;
4742 column_title_new (GtkCList *clist,
4746 if (clist->column[column].title)
4747 g_free (clist->column[column].title);
4749 clist->column[column].title = g_strdup (title);
4753 columns_delete (GtkCList * clist)
4757 for (i = 0; i < clist->columns; i++)
4758 if (clist->column[i].title)
4759 g_free (clist->column[i].title);
4761 g_free (clist->column);
4764 static GtkCListRow *
4765 row_new (GtkCList * clist)
4768 GtkCListRow *clist_row;
4770 clist_row = g_chunk_new (GtkCListRow, clist->row_mem_chunk);
4771 clist_row->cell = g_chunk_new (GtkCell, clist->cell_mem_chunk);
4773 for (i = 0; i < clist->columns; i++)
4775 clist_row->cell[i].type = GTK_CELL_EMPTY;
4776 clist_row->cell[i].vertical = 0;
4777 clist_row->cell[i].horizontal = 0;
4780 clist_row->fg_set = FALSE;
4781 clist_row->bg_set = FALSE;
4782 clist_row->selectable = TRUE;
4783 clist_row->state = GTK_STATE_NORMAL;
4784 clist_row->data = NULL;
4785 clist_row->destroy = NULL;
4791 row_delete (GtkCList * clist,
4792 GtkCListRow * clist_row)
4796 for (i = 0; i < clist->columns; i++)
4797 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
4798 (clist, clist_row, i, GTK_CELL_EMPTY, NULL, 0, NULL, NULL);
4800 if (clist_row->destroy)
4801 clist_row->destroy (clist_row->data);
4803 g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell);
4804 g_mem_chunk_free (clist->row_mem_chunk, clist_row);
4808 set_cell_contents (GtkCList *clist,
4809 GtkCListRow *clist_row,
4817 g_return_if_fail (clist_row != NULL);
4819 switch (clist_row->cell[column].type)
4821 case GTK_CELL_EMPTY:
4825 g_free (GTK_CELL_TEXT (clist_row->cell[column])->text);
4828 case GTK_CELL_PIXMAP:
4829 gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap);
4830 if (GTK_CELL_PIXMAP (clist_row->cell[column])->mask)
4831 gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask);
4834 case GTK_CELL_PIXTEXT:
4835 g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text);
4836 gdk_pixmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap);
4837 if (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask)
4838 gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask);
4841 case GTK_CELL_WIDGET:
4849 clist_row->cell[column].type = GTK_CELL_EMPTY;
4856 clist_row->cell[column].type = GTK_CELL_TEXT;
4857 GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
4861 case GTK_CELL_PIXMAP:
4864 clist_row->cell[column].type = GTK_CELL_PIXMAP;
4865 GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
4866 /* We set the mask even if it is NULL */
4867 GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask;
4871 case GTK_CELL_PIXTEXT:
4874 clist_row->cell[column].type = GTK_CELL_PIXTEXT;
4875 GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
4876 GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
4877 GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
4878 GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask;
4887 /* Fill in data after widget has correct style */
4890 add_style_data (GtkCList * clist)
4894 widget = GTK_WIDGET(clist);
4896 /* text properties */
4897 if (!GTK_CLIST_ROW_HEIGHT_SET (clist))
4899 clist->row_height = widget->style->font->ascent + widget->style->font->descent + 1;
4900 clist->row_center_offset = widget->style->font->ascent + 1.5;
4905 text_height = clist->row_height - (GTK_WIDGET (clist)->style->font->ascent +
4906 GTK_WIDGET (clist) ->style->font->descent + 1);
4907 clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
4914 /* focus functions */
4917 gtk_clist_draw_focus (GtkWidget *widget)
4921 g_return_if_fail (widget != NULL);
4922 g_return_if_fail (GTK_IS_CLIST (widget));
4924 if (!GTK_WIDGET_DRAWABLE (widget))
4927 clist = GTK_CLIST (widget);
4928 if (clist->focus_row >= 0)
4929 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
4930 0, ROW_TOP_YPIXEL(clist, clist->focus_row),
4931 clist->clist_window_width - 1,
4932 clist->row_height - 1);
4936 gtk_clist_set_focus_child (GtkContainer *container,
4939 g_return_if_fail (container != NULL);
4940 g_return_if_fail (GTK_IS_CLIST (container));
4944 g_return_if_fail (GTK_IS_WIDGET (child));
4945 GTK_CLIST_SET_FLAG (GTK_CLIST (container), CLIST_CHILD_HAS_FOCUS);
4948 parent_class->set_focus_child (container, child);
4952 gtk_clist_focus_in (GtkWidget *widget,
4953 GdkEventFocus *event)
4957 g_return_val_if_fail (widget != NULL, FALSE);
4958 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4959 g_return_val_if_fail (event != NULL, FALSE);
4961 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
4962 GTK_CLIST_UNSET_FLAG (widget, CLIST_CHILD_HAS_FOCUS);
4964 clist = GTK_CLIST (widget);
4966 if (clist->selection_mode == GTK_SELECTION_BROWSE &&
4967 clist->selection == NULL && clist->focus_row > -1)
4971 list = g_list_nth (clist->row_list, clist->focus_row);
4972 if (list && GTK_CLIST_ROW (list)->selectable)
4973 select_row (clist, clist->focus_row, -1, (GdkEvent *) event);
4975 gtk_widget_draw_focus (widget);
4978 gtk_widget_draw_focus (widget);
4984 gtk_clist_focus_out (GtkWidget *widget,
4985 GdkEventFocus *event)
4989 g_return_val_if_fail (widget != NULL, FALSE);
4990 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4991 g_return_val_if_fail (event != NULL, FALSE);
4993 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
4994 gtk_widget_draw_focus (widget);
4996 clist = GTK_CLIST (widget);
4998 if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
4999 GTK_CLIST_CLASS_FW (widget)->resync_selection (clist, (GdkEvent *) event);
5005 toggle_add_mode (GtkCList *clist)
5007 g_return_if_fail (clist != 0);
5008 g_return_if_fail (GTK_IS_CLIST (clist));
5010 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
5011 clist->selection_mode != GTK_SELECTION_EXTENDED)
5014 gtk_clist_draw_focus (GTK_WIDGET (clist));
5015 if (!GTK_CLIST_ADD_MODE (clist))
5017 GTK_CLIST_SET_FLAG (clist, CLIST_ADD_MODE);
5018 gdk_gc_set_line_attributes (clist->xor_gc, 1,
5019 GDK_LINE_ON_OFF_DASH, 0, 0);
5020 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
5024 GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
5025 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
5026 clist->anchor_state = GTK_STATE_SELECTED;
5028 gtk_clist_draw_focus (GTK_WIDGET (clist));
5032 toggle_focus_row (GtkCList *clist)
5034 g_return_if_fail (clist != 0);
5035 g_return_if_fail (GTK_IS_CLIST (clist));
5037 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
5038 clist->focus_row < 0 || clist->focus_row >= clist->rows)
5041 switch (clist->selection_mode)
5043 case GTK_SELECTION_SINGLE:
5044 case GTK_SELECTION_MULTIPLE:
5045 toggle_row (clist, clist->focus_row, 0, NULL);
5047 case GTK_SELECTION_EXTENDED:
5048 g_list_free (clist->undo_selection);
5049 g_list_free (clist->undo_unselection);
5050 clist->undo_selection = NULL;
5051 clist->undo_unselection = NULL;
5053 clist->anchor = clist->focus_row;
5054 clist->drag_pos = clist->focus_row;
5055 clist->undo_anchor = clist->focus_row;
5057 if (GTK_CLIST_ADD_MODE (clist))
5058 fake_toggle_row (clist, clist->focus_row);
5060 GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist,clist->focus_row);
5062 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
5070 move_focus_row (GtkCList *clist,
5071 GtkScrollType scroll_type,
5076 g_return_if_fail (clist != 0);
5077 g_return_if_fail (GTK_IS_CLIST (clist));
5079 widget = GTK_WIDGET (clist);
5081 switch (scroll_type)
5083 case GTK_SCROLL_STEP_BACKWARD:
5084 if (clist->focus_row <= 0)
5086 gtk_clist_draw_focus (widget);
5088 gtk_clist_draw_focus (widget);
5090 case GTK_SCROLL_STEP_FORWARD:
5091 if (clist->focus_row >= clist->rows - 1)
5093 gtk_clist_draw_focus (widget);
5095 gtk_clist_draw_focus (widget);
5097 case GTK_SCROLL_PAGE_BACKWARD:
5098 if (clist->focus_row <= 0)
5100 gtk_clist_draw_focus (widget);
5101 clist->focus_row = MAX (0, clist->focus_row -
5102 (2 * clist->clist_window_height -
5103 clist->row_height - CELL_SPACING) /
5104 (2 * (clist->row_height + CELL_SPACING)));
5105 gtk_clist_draw_focus (widget);
5107 case GTK_SCROLL_PAGE_FORWARD:
5108 if (clist->focus_row >= clist->rows - 1)
5110 gtk_clist_draw_focus (widget);
5111 clist->focus_row = MIN (clist->rows - 1, clist->focus_row +
5112 (2 * clist->clist_window_height -
5113 clist->row_height - CELL_SPACING) /
5114 (2 * (clist->row_height + CELL_SPACING)));
5115 gtk_clist_draw_focus (widget);
5117 case GTK_SCROLL_JUMP:
5118 if (position >= 0 && position <= 1)
5120 gtk_clist_draw_focus (widget);
5121 clist->focus_row = position * (clist->rows - 1);
5122 gtk_clist_draw_focus (widget);
5131 scroll_horizontal (GtkCList *clist,
5132 GtkScrollType scroll_type,
5137 g_return_if_fail (clist != 0);
5138 g_return_if_fail (GTK_IS_CLIST (clist));
5140 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5143 switch (scroll_type)
5145 case GTK_SCROLL_STEP_BACKWARD:
5146 column = COLUMN_FROM_XPIXEL (clist, 0);
5147 if (COLUMN_LEFT_XPIXEL (clist, column) - CELL_SPACING - COLUMN_INSET >= 0
5151 case GTK_SCROLL_STEP_FORWARD:
5152 column = COLUMN_FROM_XPIXEL (clist, clist->clist_window_width);
5155 if (COLUMN_LEFT_XPIXEL (clist, column) + clist->column[column].area.width
5156 + CELL_SPACING + COLUMN_INSET - 1 <= clist->clist_window_width &&
5157 column < clist->columns - 1)
5160 case GTK_SCROLL_PAGE_BACKWARD:
5161 case GTK_SCROLL_PAGE_FORWARD:
5163 case GTK_SCROLL_JUMP:
5164 if (position >= 0 && position <= 1)
5165 column = position * (clist->columns - 1);
5173 if (COLUMN_LEFT_XPIXEL (clist, column) < CELL_SPACING + COLUMN_INSET)
5174 gtk_clist_moveto (clist, -1, column, 0, 0);
5175 else if (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET - 1
5176 + clist->column[column].area.width > clist->clist_window_width)
5178 if (column == clist->columns - 1)
5179 gtk_clist_moveto (clist, -1, column, 0, 0);
5181 gtk_clist_moveto (clist, -1, column, 0, 1);
5186 scroll_vertical (GtkCList *clist,
5187 GtkScrollType scroll_type,
5192 g_return_if_fail (clist != NULL);
5193 g_return_if_fail (GTK_IS_CLIST (clist));
5195 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5198 switch (clist->selection_mode)
5200 case GTK_SELECTION_EXTENDED:
5201 if (clist->anchor >= 0)
5204 case GTK_SELECTION_BROWSE:
5206 old_focus_row = clist->focus_row;
5207 move_focus_row (clist, scroll_type, position);
5209 if (old_focus_row != clist->focus_row)
5211 if (clist->selection_mode == GTK_SELECTION_BROWSE)
5212 unselect_row (clist,old_focus_row, -1, NULL);
5213 else if (!GTK_CLIST_ADD_MODE (clist))
5215 gtk_clist_unselect_all (clist);
5216 clist->undo_anchor = old_focus_row;
5220 switch (gtk_clist_row_is_visible (clist, clist->focus_row))
5222 case GTK_VISIBILITY_NONE:
5223 if (old_focus_row != clist->focus_row &&
5224 !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
5225 GTK_CLIST_ADD_MODE (clist)))
5226 select_row (clist, clist->focus_row, -1, NULL);
5227 switch (scroll_type)
5229 case GTK_SCROLL_STEP_BACKWARD:
5230 case GTK_SCROLL_PAGE_BACKWARD:
5231 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5233 case GTK_SCROLL_STEP_FORWARD:
5234 case GTK_SCROLL_PAGE_FORWARD:
5235 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5237 case GTK_SCROLL_JUMP:
5238 gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
5245 case GTK_VISIBILITY_PARTIAL:
5246 switch (scroll_type)
5248 case GTK_SCROLL_STEP_BACKWARD:
5249 case GTK_SCROLL_PAGE_BACKWARD:
5250 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5252 case GTK_SCROLL_STEP_FORWARD:
5253 case GTK_SCROLL_PAGE_FORWARD:
5254 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5256 case GTK_SCROLL_JUMP:
5257 gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
5264 if (old_focus_row != clist->focus_row &&
5265 !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
5266 GTK_CLIST_ADD_MODE (clist)))
5267 select_row (clist, clist->focus_row, -1, NULL);
5273 move_focus_row (clist, scroll_type, position);
5275 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5276 clist->clist_window_height)
5277 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5278 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5279 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5285 set_anchor (GtkCList *clist,
5290 g_return_if_fail (clist != NULL);
5291 g_return_if_fail (GTK_IS_CLIST (clist));
5293 if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor >= 0)
5296 g_list_free (clist->undo_selection);
5297 g_list_free (clist->undo_unselection);
5298 clist->undo_selection = NULL;
5299 clist->undo_unselection = NULL;
5302 fake_toggle_row (clist, anchor);
5305 GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist, anchor);
5306 clist->anchor_state = GTK_STATE_SELECTED;
5309 clist->anchor = anchor;
5310 clist->drag_pos = anchor;
5311 clist->undo_anchor = undo_anchor;
5315 resync_selection (GtkCList *clist,
5321 gboolean thaw = FALSE;
5323 GtkCListRow *clist_row;
5325 if (clist->anchor < 0)
5328 if (!GTK_CLIST_FROZEN (clist))
5330 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
5334 i = MIN (clist->anchor, clist->drag_pos);
5335 e = MAX (clist->anchor, clist->drag_pos);
5337 if (clist->undo_selection)
5339 list = clist->selection;
5340 clist->selection = clist->undo_selection;
5341 clist->selection_end = g_list_last (clist->selection);
5342 clist->undo_selection = list;
5343 list = clist->selection;
5346 row = GPOINTER_TO_INT (list->data);
5348 if (row < i || row > e)
5350 clist_row = g_list_nth (clist->row_list, row)->data;
5351 if (clist_row->selectable)
5353 clist_row->state = GTK_STATE_SELECTED;
5354 unselect_row (clist, row, -1, event);
5355 clist->undo_selection = g_list_prepend
5356 (clist->undo_selection, GINT_TO_POINTER (row));
5362 for (list = g_list_nth (clist->row_list, i); i <= e; i++, list = list->next)
5363 if (GTK_CLIST_ROW (list)->selectable)
5365 if (g_list_find (clist->selection, GINT_TO_POINTER(i)))
5367 if (GTK_CLIST_ROW (list)->state == GTK_STATE_NORMAL)
5369 GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
5370 unselect_row (clist, i, -1, event);
5371 clist->undo_selection = g_list_prepend (clist->undo_selection,
5372 GINT_TO_POINTER (i));
5375 else if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
5377 GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
5378 clist->undo_unselection = g_list_prepend (clist->undo_unselection,
5379 GINT_TO_POINTER (i));
5383 for (list = clist->undo_unselection; list; list = list->next)
5384 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
5385 GPOINTER_TO_INT (list->data), -1, event);
5388 clist->drag_pos = -1;
5391 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
5395 update_extended_selection (GtkCList *clist,
5405 gint y1 = clist->clist_window_height;
5406 gint y2 = clist->clist_window_height;
5411 if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor == -1)
5416 if (row >= clist->rows)
5417 row = clist->rows - 1;
5419 /* extending downwards */
5420 if (row > clist->drag_pos && clist->anchor <= clist->drag_pos)
5422 s2 = clist->drag_pos + 1;
5425 /* extending upwards */
5426 else if (row < clist->drag_pos && clist->anchor >= clist->drag_pos)
5429 e2 = clist->drag_pos - 1;
5431 else if (row < clist->drag_pos && clist->anchor < clist->drag_pos)
5433 e1 = clist->drag_pos;
5434 /* row and drag_pos on different sides of anchor :
5435 take back the selection between anchor and drag_pos,
5436 select between anchor and row */
5437 if (row < clist->anchor)
5439 s1 = clist->anchor + 1;
5441 e2 = clist->anchor - 1;
5443 /* take back the selection between anchor and drag_pos */
5447 else if (row > clist->drag_pos && clist->anchor > clist->drag_pos)
5449 s1 = clist->drag_pos;
5450 /* row and drag_pos on different sides of anchor :
5451 take back the selection between anchor and drag_pos,
5452 select between anchor and row */
5453 if (row > clist->anchor)
5455 e1 = clist->anchor - 1;
5456 s2 = clist->anchor + 1;
5459 /* take back the selection between anchor and drag_pos */
5464 clist->drag_pos = row;
5467 area.width = clist->clist_window_width;
5469 /* restore the elements between s1 and e1 */
5472 for (i = s1, list = g_list_nth (clist->row_list, i); i <= e1;
5473 i++, list = list->next)
5474 if (GTK_CLIST_ROW (list)->selectable)
5476 if (GTK_CLIST_CLASS_FW (clist)->selection_find (clist, i, list))
5477 GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
5479 GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
5482 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
5484 if (top + clist->row_height <= 0)
5487 area.height = ROW_TOP_YPIXEL (clist, e1) + clist->row_height;
5488 draw_rows (clist, &area);
5489 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5491 else if (top >= clist->clist_window_height)
5493 area.y = ROW_TOP_YPIXEL (clist, s1);
5494 area.height = clist->clist_window_height - area.y;
5495 draw_rows (clist, &area);
5496 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5499 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5500 else if (top + clist->row_height > clist->clist_window_height)
5501 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5503 y1 = ROW_TOP_YPIXEL (clist, s1);
5504 h1 = (e1 - s1 + 1) * (clist->row_height + CELL_SPACING);
5507 /* extend the selection between s2 and e2 */
5510 for (i = s2, list = g_list_nth (clist->row_list, i); i <= e2;
5511 i++, list = list->next)
5512 if (GTK_CLIST_ROW (list)->selectable &&
5513 GTK_CLIST_ROW (list)->state != clist->anchor_state)
5514 GTK_CLIST_ROW (list)->state = clist->anchor_state;
5516 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
5518 if (top + clist->row_height <= 0)
5521 area.height = ROW_TOP_YPIXEL (clist, e2) + clist->row_height;
5522 draw_rows (clist, &area);
5523 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5525 else if (top >= clist->clist_window_height)
5527 area.y = ROW_TOP_YPIXEL (clist, s2);
5528 area.height = clist->clist_window_height - area.y;
5529 draw_rows (clist, &area);
5530 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5533 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5534 else if (top + clist->row_height > clist->clist_window_height)
5535 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5537 y2 = ROW_TOP_YPIXEL (clist, s2);
5538 h2 = (e2 - s2 + 1) * (clist->row_height + CELL_SPACING);
5541 area.y = MAX (0, MIN (y1, y2));
5542 if (area.y > clist->clist_window_height)
5544 area.height = MIN (clist->clist_window_height, h1 + h2);
5545 if (s1 >= 0 && s2 >= 0)
5546 area.height += (clist->row_height + CELL_SPACING);
5547 draw_rows (clist, &area);
5551 start_selection (GtkCList *clist)
5553 g_return_if_fail (clist != NULL);
5554 g_return_if_fail (GTK_IS_CLIST (clist));
5556 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5559 set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
5564 end_selection (GtkCList *clist)
5566 g_return_if_fail (clist != NULL);
5567 g_return_if_fail (GTK_IS_CLIST (clist));
5569 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist)) ||
5570 clist->anchor == -1)
5573 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
5577 extend_selection (GtkCList *clist,
5578 GtkScrollType scroll_type,
5580 gboolean auto_start_selection)
5582 g_return_if_fail (clist != NULL);
5583 g_return_if_fail (GTK_IS_CLIST (clist));
5585 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
5586 clist->selection_mode != GTK_SELECTION_EXTENDED)
5589 if (auto_start_selection)
5590 set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
5592 else if (clist->anchor == -1)
5595 move_focus_row (clist, scroll_type, position);
5597 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5598 clist->clist_window_height)
5599 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5600 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5601 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5603 update_extended_selection (clist, clist->focus_row);
5607 abort_column_resize (GtkCList *clist)
5609 g_return_if_fail (clist != NULL);
5610 g_return_if_fail (GTK_IS_CLIST (clist));
5612 if (!GTK_CLIST_IN_DRAG (clist))
5615 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
5616 gtk_grab_remove (GTK_WIDGET (clist));
5617 gdk_pointer_ungrab (GDK_CURRENT_TIME);
5618 clist->drag_pos = -1;
5620 if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1)
5621 draw_xor_line (clist);
5623 if (GTK_CLIST_ADD_MODE (clist))
5625 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_ON_OFF_DASH, 0,0);
5626 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
5631 gtk_clist_key_press (GtkWidget * widget,
5632 GdkEventKey * event)
5634 g_return_val_if_fail (widget != NULL, FALSE);
5635 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
5636 g_return_val_if_fail (event != NULL, FALSE);
5638 if (GTK_WIDGET_CLASS (parent_class)->key_press_event &&
5639 GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
5642 switch (event->keyval)
5645 case GDK_ISO_Left_Tab:
5646 if (event->state & GDK_SHIFT_MASK)
5647 return gtk_container_focus (GTK_CONTAINER (widget),
5648 GTK_DIR_TAB_BACKWARD);
5650 return gtk_container_focus (GTK_CONTAINER (widget),
5651 GTK_DIR_TAB_FORWARD);
5661 title_focus (GtkCList * clist,
5664 GtkWidget *focus_child;
5665 gboolean return_val = FALSE;
5670 if (!GTK_CLIST_SHOW_TITLES (clist))
5673 focus_child = GTK_CONTAINER (clist)->focus_child;
5677 case GTK_DIR_TAB_BACKWARD:
5679 if (!focus_child || focus_child == clist->hscrollbar ||
5680 focus_child == clist->hscrollbar ||
5681 !GTK_CLIST_CHILD_HAS_FOCUS (clist))
5683 if (dir == GTK_DIR_UP)
5684 i = COLUMN_FROM_XPIXEL (clist, 0);
5686 i = clist->columns - 1;
5687 focus_child = clist->column[i].button;
5688 dir = GTK_DIR_TAB_FORWARD;
5695 if (!focus_child || focus_child == clist->hscrollbar ||
5696 focus_child == clist->hscrollbar)
5698 i = clist->columns - 1;
5699 focus_child = clist->column[i].button;
5703 if (!focus_child || focus_child == clist->hscrollbar ||
5704 focus_child == clist->hscrollbar)
5707 focus_child = clist->column[i].button;
5713 while (i < clist->columns)
5715 if (clist->column[i].button == focus_child)
5717 if (clist->column[i].button &&
5718 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
5719 GTK_IS_CONTAINER (clist->column[i].button) &&
5720 !GTK_WIDGET_HAS_FOCUS (clist->column[i].button))
5721 if (gtk_container_focus
5722 (GTK_CONTAINER (clist->column[i].button), dir))
5727 if (!return_val && dir == GTK_DIR_UP)
5738 while (j >= 0 && j < clist->columns)
5740 if (clist->column[j].button &&
5741 GTK_WIDGET_VISIBLE (clist->column[j].button))
5743 if (GTK_IS_CONTAINER (clist->column[j].button) &&
5745 (GTK_CONTAINER (clist->column[j].button), dir))
5750 else if (GTK_WIDGET_CAN_FOCUS (clist->column[j].button))
5752 gtk_widget_grab_focus (clist->column[j].button);
5762 if (COLUMN_LEFT_XPIXEL (clist, j) < CELL_SPACING + COLUMN_INSET)
5763 gtk_clist_moveto (clist, -1, j, 0, 0);
5764 else if (COLUMN_LEFT_XPIXEL(clist, j) + clist->column[j].area.width >
5765 clist->clist_window_width)
5767 if (j == clist->columns-1)
5768 gtk_clist_moveto (clist, -1, j, 0, 0);
5770 gtk_clist_moveto (clist, -1, j, 0, 1);
5777 gtk_clist_focus (GtkContainer * container,
5778 GtkDirectionType direction)
5781 GtkWidget *focus_child;
5784 g_return_val_if_fail (container != NULL, FALSE);
5785 g_return_val_if_fail (GTK_IS_CLIST (container), FALSE);
5787 if (!GTK_WIDGET_SENSITIVE (container))
5790 clist = GTK_CLIST (container);
5791 focus_child = container->focus_child;
5792 old_row = clist->focus_row;
5798 if (GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5799 (!focus_child || (focus_child && focus_child != clist->vscrollbar &&
5800 focus_child != clist->hscrollbar)))
5802 if (title_focus (clist, direction))
5804 gtk_container_set_focus_child (container, NULL);
5807 gtk_widget_grab_focus (GTK_WIDGET (container));
5810 case GTK_DIR_TAB_FORWARD:
5811 if (GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5812 (!focus_child || (focus_child != clist->vscrollbar &&
5813 focus_child != clist->hscrollbar)))
5815 gboolean tf = FALSE;
5817 if (((focus_child && direction == GTK_DIR_DOWN) ||
5818 !(tf = title_focus (clist, GTK_DIR_TAB_FORWARD)))
5821 if (clist->focus_row < 0)
5823 clist->focus_row = 0;
5825 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
5826 clist->selection_mode == GTK_SELECTION_EXTENDED) &&
5828 select_row (clist, clist->focus_row, -1, NULL);
5830 gtk_widget_grab_focus (GTK_WIDGET (container));
5838 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
5840 if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child ||
5841 (focus_child != clist->vscrollbar &&
5842 focus_child != clist->hscrollbar)) &&
5843 GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
5844 GTK_WIDGET_CAN_FOCUS (clist->vscrollbar))
5846 gtk_widget_grab_focus (clist->vscrollbar);
5850 if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child ||
5851 focus_child != clist->hscrollbar) &&
5852 GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
5853 GTK_WIDGET_CAN_FOCUS (clist->hscrollbar))
5855 gtk_widget_grab_focus (clist->hscrollbar);
5860 case GTK_DIR_TAB_BACKWARD:
5861 if (!focus_child && GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5862 GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
5863 GTK_WIDGET_CAN_FOCUS (clist->hscrollbar))
5865 gtk_widget_grab_focus (clist->hscrollbar);
5869 if ((!focus_child || focus_child == clist->hscrollbar) &&
5870 GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5871 GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
5872 GTK_WIDGET_CAN_FOCUS (clist->vscrollbar))
5874 gtk_widget_grab_focus (clist->vscrollbar);
5878 if ((!focus_child || focus_child == clist->hscrollbar ||
5879 focus_child == clist->vscrollbar) &&
5880 GTK_CLIST_CHILD_HAS_FOCUS (clist) && clist->rows)
5882 if (clist->focus_row < 0)
5884 clist->focus_row = 0;
5885 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
5886 clist->selection_mode == GTK_SELECTION_EXTENDED) &&
5888 select_row (clist, clist->focus_row, -1, NULL);
5890 gtk_widget_grab_focus (GTK_WIDGET (container));
5894 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
5896 if (title_focus (clist, direction))
5905 gtk_container_set_focus_child (container, NULL);
5910 gtk_clist_unselect_all (GtkCList * clist)
5912 g_return_if_fail (clist != NULL);
5913 g_return_if_fail (GTK_IS_CLIST (clist));
5915 GTK_CLIST_CLASS_FW (clist)->unselect_all (clist);
5919 real_unselect_all (GtkCList * clist)
5924 g_return_if_fail (clist != NULL);
5925 g_return_if_fail (GTK_IS_CLIST (clist));
5927 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5930 switch (clist->selection_mode)
5932 case GTK_SELECTION_BROWSE:
5933 if (clist->focus_row >= 0)
5935 select_row (clist, clist->focus_row, -1, NULL);
5940 case GTK_SELECTION_EXTENDED:
5941 g_list_free (clist->undo_selection);
5942 g_list_free (clist->undo_unselection);
5943 clist->undo_selection = NULL;
5944 clist->undo_unselection = NULL;
5947 clist->drag_pos = -1;
5948 clist->undo_anchor = clist->focus_row;
5955 list = clist->selection;
5959 i = GPOINTER_TO_INT (list->data);
5961 unselect_row (clist, i, -1, NULL);
5966 gtk_clist_select_all (GtkCList * clist)
5968 g_return_if_fail (clist != NULL);
5969 g_return_if_fail (GTK_IS_CLIST (clist));
5971 GTK_CLIST_CLASS_FW (clist)->select_all (clist);
5975 real_select_all (GtkCList * clist)
5980 g_return_if_fail (clist != NULL);
5981 g_return_if_fail (GTK_IS_CLIST (clist));
5983 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5986 switch (clist->selection_mode)
5988 case GTK_SELECTION_SINGLE:
5989 case GTK_SELECTION_BROWSE:
5992 case GTK_SELECTION_EXTENDED:
5993 g_list_free (clist->undo_selection);
5994 g_list_free (clist->undo_unselection);
5995 clist->undo_selection = NULL;
5996 clist->undo_unselection = NULL;
5999 ((GtkCListRow *) (clist->row_list->data))->state !=
6001 fake_toggle_row (clist, 0);
6003 clist->anchor_state = GTK_STATE_SELECTED;
6005 clist->drag_pos = 0;
6006 clist->undo_anchor = clist->focus_row;
6007 update_extended_selection (clist, clist->rows);
6008 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
6011 case GTK_SELECTION_MULTIPLE:
6012 for (i = 0, list = clist->row_list; list; i++, list = list->next)
6014 if (((GtkCListRow *)(list->data))->state == GTK_STATE_NORMAL)
6015 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
6023 fake_unselect_all (GtkCList * clist,
6030 if (row >= 0 && (work = g_list_nth (clist->row_list, row)))
6032 if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL &&
6033 GTK_CLIST_ROW (work)->selectable)
6035 GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
6037 if (!GTK_CLIST_FROZEN (clist) &&
6038 gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
6039 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
6040 GTK_CLIST_ROW (work));
6044 clist->undo_selection = clist->selection;
6045 clist->selection = NULL;
6046 clist->selection_end = NULL;
6048 for (list = clist->undo_selection; list; list = list->next)
6050 if ((i = GPOINTER_TO_INT (list->data)) == row ||
6051 !(work = g_list_nth (clist->row_list, i)))
6054 GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
6055 if (!GTK_CLIST_FROZEN (clist) &&
6056 gtk_clist_row_is_visible (clist, i) != GTK_VISIBILITY_NONE)
6057 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, i,
6058 GTK_CLIST_ROW (work));
6063 fake_toggle_row (GtkCList *clist,
6068 if (!(work = g_list_nth (clist->row_list, row))||
6069 !GTK_CLIST_ROW (work)->selectable)
6072 if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL)
6073 clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
6075 clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
6077 if (!GTK_CLIST_FROZEN (clist) &&
6078 gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
6079 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
6080 GTK_CLIST_ROW (work));
6084 selection_find (GtkCList *clist,
6086 GList *row_list_element)
6088 return g_list_find (clist->selection, GINT_TO_POINTER (row_number));
6092 default_compare (GtkCList *clist,
6099 GtkCListRow *row1 = (GtkCListRow *) ptr1;
6100 GtkCListRow *row2 = (GtkCListRow *) ptr2;
6102 switch (row1->cell[clist->sort_column].type)
6105 text1 = GTK_CELL_TEXT (row1->cell[clist->sort_column])->text;
6107 case GTK_CELL_PIXTEXT:
6108 text1 = GTK_CELL_PIXTEXT (row1->cell[clist->sort_column])->text;
6114 switch (row2->cell[clist->sort_column].type)
6117 text2 = GTK_CELL_TEXT (row2->cell[clist->sort_column])->text;
6119 case GTK_CELL_PIXTEXT:
6120 text2 = GTK_CELL_PIXTEXT (row2->cell[clist->sort_column])->text;
6127 return (text1 != NULL);
6132 return strcmp (text1, text2);
6136 gtk_clist_set_compare_func (GtkCList *clist,
6137 GtkCListCompareFunc cmp_func)
6139 g_return_if_fail (clist != NULL);
6140 g_return_if_fail (GTK_IS_CLIST (clist));
6142 clist->compare = (cmp_func) ? cmp_func : default_compare;
6146 gtk_clist_set_auto_sort (GtkCList *clist,
6149 g_return_if_fail (clist != NULL);
6150 g_return_if_fail (GTK_IS_CLIST (clist));
6152 if (GTK_CLIST_AUTO_SORT (clist) && !auto_sort)
6153 GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_SORT);
6154 else if (!GTK_CLIST_AUTO_SORT (clist) && auto_sort)
6156 GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_SORT);
6157 gtk_clist_sort (clist);
6162 gtk_clist_set_sort_type (GtkCList *clist,
6163 GtkSortType sort_type)
6165 g_return_if_fail (clist != NULL);
6166 g_return_if_fail (GTK_IS_CLIST (clist));
6168 clist->sort_type = sort_type;
6172 gtk_clist_set_sort_column (GtkCList *clist,
6175 g_return_if_fail (clist != NULL);
6176 g_return_if_fail (GTK_IS_CLIST (clist));
6178 if (column < 0 || column >= clist->columns)
6181 clist->sort_column = column;
6185 gtk_clist_merge (GtkCList *clist,
6186 GList *a, /* first list to merge */
6187 GList *b) /* second list to merge */
6189 GList z = { 0 }; /* auxiliary node */
6215 cmp = clist->compare (clist, GTK_CLIST_ROW (a), GTK_CLIST_ROW (b));
6216 if ((cmp >= 0 && clist->sort_type == GTK_SORT_DESCENDING) ||
6217 (cmp <= 0 && clist->sort_type == GTK_SORT_ASCENDING) ||
6239 gtk_clist_mergesort (GtkCList *clist,
6240 GList *list, /* the list to sort */
6241 gint num) /* the list's length */
6252 /* move "half" to the middle */
6254 for (i = 0; i < num / 2; i++)
6257 /* cut the list in two */
6258 half->prev->next = NULL;
6261 /* recursively sort both lists */
6262 return gtk_clist_merge (clist,
6263 gtk_clist_mergesort (clist, list, num / 2),
6264 gtk_clist_mergesort (clist, half, num - num / 2));
6269 gtk_clist_sort (GtkCList *clist)
6271 g_return_if_fail (clist != NULL);
6272 g_return_if_fail (GTK_IS_CLIST (clist));
6274 GTK_CLIST_CLASS_FW (clist)->sort_list (clist);
6278 real_sort_list (GtkCList *clist)
6283 gboolean thaw = FALSE;
6285 g_return_if_fail (clist != NULL);
6286 g_return_if_fail (GTK_IS_CLIST (clist));
6288 if (clist->rows <= 1)
6291 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
6294 if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
6296 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
6297 g_list_free (clist->undo_selection);
6298 g_list_free (clist->undo_unselection);
6299 clist->undo_selection = NULL;
6300 clist->undo_unselection = NULL;
6303 if (!GTK_CLIST_FROZEN (clist))
6305 gtk_clist_freeze (clist);
6309 clist->row_list = gtk_clist_mergesort (clist, clist->row_list, clist->rows);
6311 work = clist->selection;
6313 for (i = 0, list = clist->row_list; i < clist->rows; i++, list = list->next)
6315 if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
6317 work->data = GINT_TO_POINTER (i);
6321 if (i == clist->rows - 1)
6322 clist->row_list_end = list;
6326 gtk_clist_thaw (clist);