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)))
99 /* returns the total width of the list */
101 LIST_WIDTH (GtkCList * clist)
105 for (last_column = clist->columns - 1;
106 last_column >= 0 && !clist->column[last_column].visible; last_column--);
108 if (last_column >= 0)
109 return (clist->column[last_column].area.x +
110 clist->column[last_column].area.width +
111 COLUMN_INSET + CELL_SPACING);
116 #define GTK_CLIST_CLASS_FW(_widget_) GTK_CLIST_CLASS (GTK_OBJECT (_widget_)->klass)
146 static void sync_selection (GtkCList * clist,
150 /* GtkCList Methods */
151 static void gtk_clist_class_init (GtkCListClass *klass);
152 static void gtk_clist_init (GtkCList *clist);
154 /* GtkObject Methods */
155 static void gtk_clist_destroy (GtkObject *object);
156 static void gtk_clist_finalize (GtkObject *object);
158 /* GtkWidget Methods */
159 static void gtk_clist_realize (GtkWidget *widget);
160 static void gtk_clist_unrealize (GtkWidget *widget);
161 static void gtk_clist_map (GtkWidget *widget);
162 static void gtk_clist_unmap (GtkWidget *widget);
163 static void gtk_clist_draw (GtkWidget *widget,
165 static gint gtk_clist_expose (GtkWidget *widget,
166 GdkEventExpose *event);
167 static gint gtk_clist_key_press (GtkWidget *widget,
169 static gint gtk_clist_button_press (GtkWidget *widget,
170 GdkEventButton *event);
171 static gint gtk_clist_button_release (GtkWidget *widget,
172 GdkEventButton *event);
173 static gint gtk_clist_motion (GtkWidget *widget,
174 GdkEventMotion *event);
175 static void gtk_clist_size_request (GtkWidget *widget,
176 GtkRequisition *requisition);
177 static void gtk_clist_size_allocate (GtkWidget *widget,
178 GtkAllocation *allocation);
179 static void gtk_clist_draw_focus (GtkWidget *widget);
180 static gint gtk_clist_focus_in (GtkWidget *widget,
181 GdkEventFocus *event);
182 static gint gtk_clist_focus_out (GtkWidget *widget,
183 GdkEventFocus *event);
184 static gint gtk_clist_focus (GtkContainer *container,
185 GtkDirectionType direction);
186 static void gtk_clist_style_set (GtkWidget *widget,
187 GtkStyle *previous_style);
189 /* GtkContainer Methods */
190 static void gtk_clist_set_focus_child (GtkContainer *container,
192 static void gtk_clist_forall (GtkContainer *container,
193 gboolean include_internals,
194 GtkCallback callback,
195 gpointer callback_data);
198 static void toggle_row (GtkCList *clist,
202 static void real_select_row (GtkCList *clist,
206 static void real_unselect_row (GtkCList *clist,
210 static void update_extended_selection (GtkCList *clist,
212 static GList *selection_find (GtkCList *clist,
214 GList *row_list_element);
215 static void real_select_all (GtkCList *clist);
216 static void real_unselect_all (GtkCList *clist);
217 static void move_vertical (GtkCList *clist,
220 static void move_horizontal (GtkCList *clist,
222 static void real_undo_selection (GtkCList *clist);
223 static void fake_unselect_all (GtkCList *clist,
225 static void fake_toggle_row (GtkCList *clist,
227 static void resync_selection (GtkCList *clist,
229 static void sync_selection (GtkCList *clist,
232 static void set_anchor (GtkCList *clist,
236 static void start_selection (GtkCList *clist);
237 static void end_selection (GtkCList *clist);
238 static void toggle_add_mode (GtkCList *clist);
239 static void toggle_focus_row (GtkCList *clist);
240 static void move_focus_row (GtkCList *clist,
241 GtkScrollType scroll_type,
243 static void scroll_horizontal (GtkCList *clist,
244 GtkScrollType scroll_type,
246 static void scroll_vertical (GtkCList *clist,
247 GtkScrollType scroll_type,
249 static void extend_selection (GtkCList *clist,
250 GtkScrollType scroll_type,
252 gboolean auto_start_selection);
253 static gint get_selection_info (GtkCList *clist,
260 static void draw_xor_line (GtkCList *clist);
261 static gint new_column_width (GtkCList *clist,
264 static void column_auto_resize (GtkCList *clist,
265 GtkCListRow *clist_row,
268 static void real_resize_column (GtkCList *clist,
271 static void abort_column_resize (GtkCList *clist);
272 static void cell_size_request (GtkCList *clist,
273 GtkCListRow *clist_row,
275 GtkRequisition *requisition);
278 static void column_button_create (GtkCList *clist,
280 static void column_button_clicked (GtkWidget *widget,
284 static void create_scrollbars (GtkCList *clist);
285 static void adjust_scrollbars (GtkCList *clist);
286 static void check_exposures (GtkCList *clist);
287 static void vadjustment_changed (GtkAdjustment *adjustment,
289 static void vadjustment_value_changed (GtkAdjustment *adjustment,
291 static void hadjustment_changed (GtkAdjustment *adjustment,
293 static void hadjustment_value_changed (GtkAdjustment *adjustment,
297 static void get_cell_style (GtkCList *clist,
298 GtkCListRow *clist_row,
304 static gint draw_cell_pixmap (GdkWindow *window,
305 GdkRectangle *clip_rectangle,
313 static void draw_row (GtkCList *clist,
316 GtkCListRow *clist_row);
317 static void draw_rows (GtkCList *clist,
320 /* Size Allocation */
321 static void size_allocate_title_buttons (GtkCList *clist);
322 static void size_allocate_columns (GtkCList *clist);
324 /* Memory Allocation/Distruction Routines */
325 static GtkCListColumn *columns_new (GtkCList *clist);
326 static void column_title_new (GtkCList *clist,
329 static void columns_delete (GtkCList *clist);
330 static GtkCListRow *row_new (GtkCList *clist);
331 static void row_delete (GtkCList *clist,
332 GtkCListRow *clist_row);
333 static void set_cell_contents (GtkCList *clist,
334 GtkCListRow *clist_row,
341 static gint real_insert_row (GtkCList *clist,
344 static void real_remove_row (GtkCList *clist,
346 static void real_clear (GtkCList *clist);
349 static gint default_compare (GtkCList *clist,
352 static void real_sort_list (GtkCList *clist);
353 static GList *gtk_clist_merge (GtkCList *clist,
356 static GList *gtk_clist_mergesort (GtkCList *clist,
360 static gboolean title_focus (GtkCList *clist,
363 static GtkContainerClass *parent_class = NULL;
364 static guint clist_signals[LAST_SIGNAL] = {0};
368 gtk_clist_get_type (void)
370 static GtkType clist_type = 0;
374 GtkTypeInfo clist_info =
378 sizeof (GtkCListClass),
379 (GtkClassInitFunc) gtk_clist_class_init,
380 (GtkObjectInitFunc) gtk_clist_init,
381 /* reserved_1 */ NULL,
382 /* reserved_2 */ NULL,
383 (GtkClassInitFunc) NULL,
386 clist_type = gtk_type_unique (GTK_TYPE_CONTAINER, &clist_info);
393 gtk_clist_class_init (GtkCListClass *klass)
395 GtkObjectClass *object_class;
396 GtkWidgetClass *widget_class;
397 GtkContainerClass *container_class;
399 object_class = (GtkObjectClass *) klass;
400 widget_class = (GtkWidgetClass *) klass;
401 container_class = (GtkContainerClass *) klass;
403 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
405 clist_signals[SELECT_ROW] =
406 gtk_signal_new ("select_row",
409 GTK_SIGNAL_OFFSET (GtkCListClass, select_row),
410 gtk_marshal_NONE__INT_INT_POINTER,
415 clist_signals[UNSELECT_ROW] =
416 gtk_signal_new ("unselect_row",
419 GTK_SIGNAL_OFFSET (GtkCListClass, unselect_row),
420 gtk_marshal_NONE__INT_INT_POINTER,
421 GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_GDK_EVENT);
422 clist_signals[CLICK_COLUMN] =
423 gtk_signal_new ("click_column",
426 GTK_SIGNAL_OFFSET (GtkCListClass, click_column),
427 gtk_marshal_NONE__INT,
428 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
429 clist_signals[RESIZE_COLUMN] =
430 gtk_signal_new ("resize_column",
433 GTK_SIGNAL_OFFSET (GtkCListClass, resize_column),
434 gtk_marshal_NONE__INT_INT,
435 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
437 clist_signals[TOGGLE_FOCUS_ROW] =
438 gtk_signal_new ("toggle_focus_row",
439 GTK_RUN_LAST | GTK_RUN_ACTION,
441 GTK_SIGNAL_OFFSET (GtkCListClass, toggle_focus_row),
442 gtk_marshal_NONE__NONE,
444 clist_signals[SELECT_ALL] =
445 gtk_signal_new ("select_all",
446 GTK_RUN_LAST | GTK_RUN_ACTION,
448 GTK_SIGNAL_OFFSET (GtkCListClass, select_all),
449 gtk_marshal_NONE__NONE,
451 clist_signals[UNSELECT_ALL] =
452 gtk_signal_new ("unselect_all",
453 GTK_RUN_LAST | GTK_RUN_ACTION,
455 GTK_SIGNAL_OFFSET (GtkCListClass, unselect_all),
456 gtk_marshal_NONE__NONE,
458 clist_signals[UNDO_SELECTION] =
459 gtk_signal_new ("undo_selection",
460 GTK_RUN_LAST | GTK_RUN_ACTION,
462 GTK_SIGNAL_OFFSET (GtkCListClass, undo_selection),
463 gtk_marshal_NONE__NONE,
465 clist_signals[START_SELECTION] =
466 gtk_signal_new ("start_selection",
467 GTK_RUN_LAST | GTK_RUN_ACTION,
469 GTK_SIGNAL_OFFSET (GtkCListClass, start_selection),
470 gtk_marshal_NONE__NONE,
472 clist_signals[END_SELECTION] =
473 gtk_signal_new ("end_selection",
474 GTK_RUN_LAST | GTK_RUN_ACTION,
476 GTK_SIGNAL_OFFSET (GtkCListClass, end_selection),
477 gtk_marshal_NONE__NONE,
479 clist_signals[TOGGLE_ADD_MODE] =
480 gtk_signal_new ("toggle_add_mode",
481 GTK_RUN_LAST | GTK_RUN_ACTION,
483 GTK_SIGNAL_OFFSET (GtkCListClass, toggle_add_mode),
484 gtk_marshal_NONE__NONE,
486 clist_signals[EXTEND_SELECTION] =
487 gtk_signal_new ("extend_selection",
488 GTK_RUN_LAST | GTK_RUN_ACTION,
490 GTK_SIGNAL_OFFSET (GtkCListClass, extend_selection),
491 gtk_marshal_NONE__ENUM_FLOAT_BOOL,
493 GTK_TYPE_SCROLL_TYPE, GTK_TYPE_FLOAT, GTK_TYPE_BOOL);
494 clist_signals[SCROLL_VERTICAL] =
495 gtk_signal_new ("scroll_vertical",
496 GTK_RUN_LAST | GTK_RUN_ACTION,
498 GTK_SIGNAL_OFFSET (GtkCListClass, scroll_vertical),
499 gtk_marshal_NONE__ENUM_FLOAT,
500 GTK_TYPE_NONE, 2, GTK_TYPE_SCROLL_TYPE, GTK_TYPE_FLOAT);
501 clist_signals[SCROLL_HORIZONTAL] =
502 gtk_signal_new ("scroll_horizontal",
503 GTK_RUN_LAST | GTK_RUN_ACTION,
505 GTK_SIGNAL_OFFSET (GtkCListClass, scroll_horizontal),
506 gtk_marshal_NONE__ENUM_FLOAT,
507 GTK_TYPE_NONE, 2, GTK_TYPE_SCROLL_TYPE, GTK_TYPE_FLOAT);
508 clist_signals[ABORT_COLUMN_RESIZE] =
509 gtk_signal_new ("abort_column_resize",
510 GTK_RUN_LAST | GTK_RUN_ACTION,
512 GTK_SIGNAL_OFFSET (GtkCListClass, abort_column_resize),
513 gtk_marshal_NONE__NONE,
517 gtk_object_class_add_signals (object_class, clist_signals, LAST_SIGNAL);
519 object_class->destroy = gtk_clist_destroy;
520 object_class->finalize = gtk_clist_finalize;
522 widget_class->realize = gtk_clist_realize;
523 widget_class->unrealize = gtk_clist_unrealize;
524 widget_class->map = gtk_clist_map;
525 widget_class->unmap = gtk_clist_unmap;
526 widget_class->draw = gtk_clist_draw;
527 widget_class->button_press_event = gtk_clist_button_press;
528 widget_class->button_release_event = gtk_clist_button_release;
529 widget_class->motion_notify_event = gtk_clist_motion;
530 widget_class->expose_event = gtk_clist_expose;
531 widget_class->size_request = gtk_clist_size_request;
532 widget_class->size_allocate = gtk_clist_size_allocate;
533 widget_class->key_press_event = gtk_clist_key_press;
534 widget_class->focus_in_event = gtk_clist_focus_in;
535 widget_class->focus_out_event = gtk_clist_focus_out;
536 widget_class->draw_focus = gtk_clist_draw_focus;
537 widget_class->style_set = gtk_clist_style_set;
539 /* container_class->add = NULL; use the default GtkContainerClass warning */
540 /* container_class->remove=NULL; use the default GtkContainerClass warning */
542 container_class->forall = gtk_clist_forall;
543 container_class->focus = gtk_clist_focus;
544 container_class->set_focus_child = gtk_clist_set_focus_child;
546 klass->select_row = real_select_row;
547 klass->unselect_row = real_unselect_row;
548 klass->undo_selection = real_undo_selection;
549 klass->resync_selection = resync_selection;
550 klass->selection_find = selection_find;
551 klass->click_column = NULL;
552 klass->resize_column = real_resize_column;
553 klass->draw_row = draw_row;
554 klass->insert_row = real_insert_row;
555 klass->remove_row = real_remove_row;
556 klass->clear = real_clear;
557 klass->sort_list = real_sort_list;
558 klass->select_all = real_select_all;
559 klass->unselect_all = real_unselect_all;
560 klass->fake_unselect_all = fake_unselect_all;
561 klass->scroll_horizontal = scroll_horizontal;
562 klass->scroll_vertical = scroll_vertical;
563 klass->extend_selection = extend_selection;
564 klass->toggle_focus_row = toggle_focus_row;
565 klass->toggle_add_mode = toggle_add_mode;
566 klass->start_selection = start_selection;
567 klass->end_selection = end_selection;
568 klass->abort_column_resize = abort_column_resize;
569 klass->set_cell_contents = set_cell_contents;
570 klass->cell_size_request = cell_size_request;
572 klass->scrollbar_spacing = 5;
575 GtkBindingSet *binding_set;
577 binding_set = gtk_binding_set_by_class (klass);
578 gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
579 "scroll_vertical", 2,
580 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
581 GTK_TYPE_FLOAT, 0.0);
582 gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
583 "scroll_vertical", 2,
584 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
585 GTK_TYPE_FLOAT, 0.0);
586 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
587 "scroll_vertical", 2,
588 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
589 GTK_TYPE_FLOAT, 0.0);
590 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
591 "scroll_vertical", 2,
592 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
593 GTK_TYPE_FLOAT, 0.0);
594 gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
595 "scroll_vertical", 2,
596 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
597 GTK_TYPE_FLOAT, 0.0);
598 gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
599 "scroll_vertical", 2,
600 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
601 GTK_TYPE_FLOAT, 1.0);
603 gtk_binding_entry_add_signal (binding_set, GDK_Up, GDK_SHIFT_MASK,
604 "extend_selection", 3,
605 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
606 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
607 gtk_binding_entry_add_signal (binding_set, GDK_Down, GDK_SHIFT_MASK,
608 "extend_selection", 3,
609 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
610 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
611 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, GDK_SHIFT_MASK,
612 "extend_selection", 3,
613 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
614 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
615 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, GDK_SHIFT_MASK,
616 "extend_selection", 3,
617 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
618 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
619 gtk_binding_entry_add_signal (binding_set, GDK_Home,
620 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
621 "extend_selection", 3,
622 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
623 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
624 gtk_binding_entry_add_signal (binding_set, GDK_End,
625 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
626 "extend_selection", 3,
627 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
628 GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE);
631 gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
632 "scroll_horizontal", 2,
633 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
634 GTK_TYPE_FLOAT, 0.0);
635 gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
636 "scroll_horizontal", 2,
637 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
638 GTK_TYPE_FLOAT, 0.0);
639 gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
640 "scroll_horizontal", 2,
641 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
642 GTK_TYPE_FLOAT, 0.0);
643 gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
644 "scroll_horizontal", 2,
645 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
646 GTK_TYPE_FLOAT, 1.0);
649 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
650 "undo_selection", 0);
651 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
652 "abort_column_resize", 0);
653 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
654 "toggle_focus_row", 0);
655 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK,
656 "toggle_add_mode", 0);
657 gtk_binding_entry_add_signal (binding_set, '/', GDK_CONTROL_MASK,
659 gtk_binding_entry_add_signal (binding_set, '\\', GDK_CONTROL_MASK,
661 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
662 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
664 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
665 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
667 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
668 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
671 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
672 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
679 GtkBindingSet *binding_set;
681 binding_set = gtk_binding_set_by_class (klass);
682 gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
683 "scroll_vertical", 2,
684 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
685 GTK_TYPE_FLOAT, 0.0);
686 gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
687 "scroll_vertical", 2,
688 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
689 GTK_TYPE_FLOAT, 0.0);
690 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
691 "scroll_vertical", 2,
692 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
693 GTK_TYPE_FLOAT, 0.0);
694 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
695 "scroll_vertical", 2,
696 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
697 GTK_TYPE_FLOAT, 0.0);
698 gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
699 "scroll_vertical", 2,
700 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
701 GTK_TYPE_FLOAT, 0.0);
702 gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
703 "scroll_vertical", 2,
704 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
707 gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0,
708 "extend_selection", 3,
709 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
710 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
711 gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0,
712 "extend_selection", 3,
713 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
714 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
715 gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Up, 0,
716 "extend_selection", 3,
717 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
718 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
719 gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Down, 0,
720 "extend_selection", 3,
721 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
722 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
723 gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, 0,
724 "extend_selection", 3,
725 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
726 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
727 gtk_binding_entry_add_signal (binding_set, GDK_KP_End, 0,
728 "extend_selection", 3,
729 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
730 GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE);
732 gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
733 "scroll_horizontal", 2,
734 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
735 GTK_TYPE_FLOAT, 0.0);
736 gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0,
737 "scroll_horizontal", 2,
738 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
739 GTK_TYPE_FLOAT, 0.0);
740 gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
741 "scroll_horizontal", 2,
742 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
743 GTK_TYPE_FLOAT, 0.0);
744 gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0,
745 "scroll_horizontal", 2,
746 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
747 GTK_TYPE_FLOAT, 0.0);
748 gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
749 "scroll_horizontal", 2,
750 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
751 GTK_TYPE_FLOAT, 0.0);
752 gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
753 "sroll_horizontal", 2,
754 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
755 GTK_TYPE_FLOAT, 1.0);
757 gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, 0,
758 "undo_selection", 0);
759 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
760 "abort_column_resize", 0);
761 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
762 "toggle_focus_row", 0);
763 gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0,
764 "toggle_add_mode", 0);
765 gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0,
767 gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0,
769 gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0,
776 gtk_clist_init (GtkCList *clist)
780 GTK_WIDGET_UNSET_FLAGS (clist, GTK_NO_WINDOW);
781 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
783 clist->row_mem_chunk = NULL;
784 clist->cell_mem_chunk = NULL;
787 clist->row_center_offset = 0;
788 clist->row_height = 0;
789 clist->row_list = NULL;
790 clist->row_list_end = NULL;
794 clist->title_window = NULL;
795 clist->column_title_area.x = 0;
796 clist->column_title_area.y = 0;
797 clist->column_title_area.width = 1;
798 clist->column_title_area.height = 1;
800 clist->clist_window = NULL;
801 clist->clist_window_width = 1;
802 clist->clist_window_height = 1;
807 clist->shadow_type = GTK_SHADOW_IN;
808 clist->hscrollbar_policy = GTK_POLICY_ALWAYS;
809 clist->vscrollbar_policy = GTK_POLICY_ALWAYS;
811 clist->cursor_drag = NULL;
812 clist->xor_gc = NULL;
817 clist->selection_mode = GTK_SELECTION_SINGLE;
818 clist->selection = NULL;
819 clist->selection_end = NULL;
820 clist->undo_selection = NULL;
821 clist->undo_unselection = NULL;
823 GTK_WIDGET_SET_FLAGS (clist, GTK_CAN_FOCUS);
824 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
825 clist->focus_row = -1;
826 clist->undo_anchor = -1;
829 clist->anchor_state = GTK_STATE_SELECTED;
830 clist->drag_pos = -1;
834 clist->compare = default_compare;
835 clist->sort_type = GTK_SORT_ASCENDING;
836 clist->sort_column = 0;
841 gtk_clist_construct (GtkCList *clist,
847 g_return_if_fail (clist != NULL);
848 g_return_if_fail (GTK_IS_CLIST (clist));
849 g_return_if_fail (GTK_CLIST_CONSTRUCTED (clist) == FALSE);
851 GTK_CLIST_SET_FLAG (clist, CLIST_CONSTRUCTED);
853 /* initalize memory chunks, if this has not been done by any
854 * possibly derived widget
856 if (!clist->row_mem_chunk)
857 clist->row_mem_chunk = g_mem_chunk_new ("clist row mem chunk",
858 sizeof (GtkCListRow),
859 sizeof (GtkCListRow) *
863 if (!clist->cell_mem_chunk)
864 clist->cell_mem_chunk = g_mem_chunk_new ("clist cell mem chunk",
865 sizeof (GtkCell) * columns,
866 sizeof (GtkCell) * columns *
870 /* set number of columns, allocate memory */
871 clist->columns = columns;
872 clist->column = columns_new (clist);
874 /* there needs to be at least one column button
875 * because there is alot of code that will break if it
877 column_button_create (clist, 0);
879 /* create scrollbars */
880 create_scrollbars (clist);
884 GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES);
885 for (i = 0; i < columns; i++)
886 gtk_clist_set_column_title (clist, i, titles[i]);
890 GTK_CLIST_UNSET_FLAG (clist, CLIST_SHOW_TITLES);
894 /* GTKCLIST PUBLIC INTERFACE
896 * gtk_clist_new_with_titles
897 * gtk_clist_set_shadow_type
898 * gtk_clist_set_border *** deprecated function ***
899 * gtk_clist_set_selection_mode
900 * gtk_clist_set_policy
905 gtk_clist_new (gint columns)
912 clist = gtk_type_new (GTK_TYPE_CLIST);
913 gtk_clist_construct (clist, columns, NULL);
914 return GTK_WIDGET (clist);
918 gtk_clist_new_with_titles (gint columns,
923 g_return_val_if_fail (titles != NULL, NULL);
925 widget = gtk_type_new (GTK_TYPE_CLIST);
927 gtk_clist_construct (GTK_CLIST (widget), columns, titles);
933 gtk_clist_set_shadow_type (GtkCList *clist,
936 g_return_if_fail (clist != NULL);
937 g_return_if_fail (GTK_IS_CLIST (clist));
939 clist->shadow_type = type;
941 if (GTK_WIDGET_VISIBLE (clist))
942 gtk_widget_queue_resize (GTK_WIDGET (clist));
945 /* deprecated function, use gtk_clist_set_shadow_type instead. */
947 gtk_clist_set_border (GtkCList *clist,
948 GtkShadowType border)
950 gtk_clist_set_shadow_type (clist, border);
954 gtk_clist_set_selection_mode (GtkCList *clist,
955 GtkSelectionMode mode)
957 g_return_if_fail (clist != NULL);
958 g_return_if_fail (GTK_IS_CLIST (clist));
960 if (mode == clist->selection_mode)
963 clist->selection_mode = mode;
965 clist->anchor_state = GTK_STATE_SELECTED;
966 clist->drag_pos = -1;
967 clist->undo_anchor = clist->focus_row;
969 g_list_free (clist->undo_selection);
970 g_list_free (clist->undo_unselection);
971 clist->undo_selection = NULL;
972 clist->undo_unselection = NULL;
976 case GTK_SELECTION_MULTIPLE:
977 case GTK_SELECTION_EXTENDED:
979 case GTK_SELECTION_BROWSE:
980 case GTK_SELECTION_SINGLE:
981 gtk_clist_unselect_all (clist);
987 gtk_clist_set_policy (GtkCList *clist,
988 GtkPolicyType vscrollbar_policy,
989 GtkPolicyType hscrollbar_policy)
991 g_return_if_fail (clist != NULL);
992 g_return_if_fail (GTK_IS_CLIST (clist));
994 if (clist->vscrollbar_policy != vscrollbar_policy)
996 clist->vscrollbar_policy = vscrollbar_policy;
998 if (GTK_WIDGET (clist)->parent)
999 gtk_widget_queue_resize (GTK_WIDGET (clist));
1002 if (clist->hscrollbar_policy != hscrollbar_policy)
1004 clist->hscrollbar_policy = hscrollbar_policy;
1006 if (GTK_WIDGET (clist)->parent)
1007 gtk_widget_queue_resize (GTK_WIDGET (clist));
1012 gtk_clist_freeze (GtkCList *clist)
1014 g_return_if_fail (clist != NULL);
1015 g_return_if_fail (GTK_IS_CLIST (clist));
1017 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
1021 gtk_clist_thaw (GtkCList *clist)
1023 g_return_if_fail (clist != NULL);
1024 g_return_if_fail (GTK_IS_CLIST (clist));
1026 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
1028 adjust_scrollbars (clist);
1029 draw_rows (clist, NULL);
1032 /* PUBLIC COLUMN FUNCTIONS
1033 * gtk_clist_column_titles_show
1034 * gtk_clist_column_titles_hide
1035 * gtk_clist_column_title_active
1036 * gtk_clist_column_title_passive
1037 * gtk_clist_column_titles_active
1038 * gtk_clist_column_titles_passive
1039 * gtk_clist_set_column_title
1040 * gtk_clist_set_column_widget
1041 * gtk_clist_set_column_justification
1042 * gtk_clist_set_column_visibility
1043 * gtk_clist_set_column_resizeable
1044 * gtk_clist_set_column_auto_resize
1045 * gtk_clist_optimal_column_width
1046 * gtk_clist_set_column_width
1047 * gtk_clist_set_column_min_width
1048 * gtk_clist_set_column_max_width
1051 gtk_clist_column_titles_show (GtkCList *clist)
1053 g_return_if_fail (clist != NULL);
1054 g_return_if_fail (GTK_IS_CLIST (clist));
1056 if (!GTK_CLIST_SHOW_TITLES (clist))
1058 GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES);
1059 if (clist->title_window)
1060 gdk_window_show (clist->title_window);
1061 gtk_widget_queue_resize (GTK_WIDGET (clist));
1066 gtk_clist_column_titles_hide (GtkCList *clist)
1068 g_return_if_fail (clist != NULL);
1069 g_return_if_fail (GTK_IS_CLIST (clist));
1071 if (GTK_CLIST_SHOW_TITLES (clist))
1073 GTK_CLIST_UNSET_FLAG (clist, CLIST_SHOW_TITLES);
1074 if (clist->title_window)
1075 gdk_window_hide (clist->title_window);
1076 gtk_widget_queue_resize (GTK_WIDGET (clist));
1081 gtk_clist_column_title_active (GtkCList *clist,
1084 g_return_if_fail (clist != NULL);
1085 g_return_if_fail (GTK_IS_CLIST (clist));
1087 if (column < 0 || column >= clist->columns)
1090 if (!GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
1091 !GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
1093 GTK_WIDGET_SET_FLAGS (clist->column[column].button,
1094 GTK_SENSITIVE | GTK_CAN_FOCUS);
1095 if (GTK_WIDGET_VISIBLE (clist))
1096 gtk_widget_queue_draw (clist->column[column].button);
1101 gtk_clist_column_title_passive (GtkCList *clist,
1104 g_return_if_fail (clist != NULL);
1105 g_return_if_fail (GTK_IS_CLIST (clist));
1107 if (column < 0 || column >= clist->columns)
1110 if (GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
1111 GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
1113 GTK_WIDGET_UNSET_FLAGS (clist->column[column].button,
1114 GTK_SENSITIVE | GTK_CAN_FOCUS);
1115 if (GTK_WIDGET_VISIBLE (clist))
1116 gtk_widget_queue_draw (clist->column[column].button);
1121 gtk_clist_column_titles_active (GtkCList *clist)
1125 g_return_if_fail (clist != NULL);
1126 g_return_if_fail (GTK_IS_CLIST (clist));
1128 for (i = 0; i < clist->columns; i++)
1129 if (clist->column[i].button)
1130 gtk_clist_column_title_active (clist, i);
1134 gtk_clist_column_titles_passive (GtkCList *clist)
1138 g_return_if_fail (clist != NULL);
1139 g_return_if_fail (GTK_IS_CLIST (clist));
1141 for (i = 0; i < clist->columns; i++)
1142 if (clist->column[i].button)
1143 gtk_clist_column_title_passive (clist, i);
1147 gtk_clist_set_column_title (GtkCList *clist,
1151 gint new_button = 0;
1152 GtkWidget *old_widget;
1153 GtkWidget *alignment = NULL;
1156 g_return_if_fail (clist != NULL);
1157 g_return_if_fail (GTK_IS_CLIST (clist));
1159 if (column < 0 || column >= clist->columns)
1162 /* if the column button doesn't currently exist,
1163 * it has to be created first */
1164 if (!clist->column[column].button)
1166 column_button_create (clist, column);
1170 column_title_new (clist, column, title);
1172 /* remove and destroy the old widget */
1173 old_widget = GTK_BIN (clist->column[column].button)->child;
1175 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
1177 /* create new alignment based no column justification */
1178 switch (clist->column[column].justification)
1180 case GTK_JUSTIFY_LEFT:
1181 alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
1184 case GTK_JUSTIFY_RIGHT:
1185 alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
1188 case GTK_JUSTIFY_CENTER:
1189 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1192 case GTK_JUSTIFY_FILL:
1193 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1197 label = gtk_label_new (clist->column[column].title);
1198 gtk_container_add (GTK_CONTAINER (alignment), label);
1199 gtk_container_add (GTK_CONTAINER (clist->column[column].button), alignment);
1200 gtk_widget_show (label);
1201 gtk_widget_show (alignment);
1203 /* if this button didn't previously exist, then the
1204 * column button positions have to be re-computed */
1205 if (GTK_WIDGET_VISIBLE (clist) && new_button)
1206 size_allocate_title_buttons (clist);
1210 gtk_clist_set_column_widget (GtkCList *clist,
1214 gint new_button = 0;
1215 GtkWidget *old_widget;
1217 g_return_if_fail (clist != NULL);
1218 g_return_if_fail (GTK_IS_CLIST (clist));
1220 if (column < 0 || column >= clist->columns)
1223 /* if the column button doesn't currently exist,
1224 * it has to be created first */
1225 if (!clist->column[column].button)
1227 column_button_create (clist, column);
1231 column_title_new (clist, column, NULL);
1233 /* remove and destroy the old widget */
1234 old_widget = GTK_BIN (clist->column[column].button)->child;
1236 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
1238 /* add and show the widget */
1241 gtk_container_add (GTK_CONTAINER (clist->column[column].button), widget);
1242 gtk_widget_show (widget);
1245 /* if this button didn't previously exist, then the
1246 * column button positions have to be re-computed */
1247 if (GTK_WIDGET_VISIBLE (clist) && new_button)
1248 size_allocate_title_buttons (clist);
1252 gtk_clist_set_column_justification (GtkCList *clist,
1254 GtkJustification justification)
1256 GtkWidget *alignment;
1258 g_return_if_fail (clist != NULL);
1259 g_return_if_fail (GTK_IS_CLIST (clist));
1261 if (column < 0 || column >= clist->columns)
1264 clist->column[column].justification = justification;
1266 /* change the alinment of the button title if it's not a
1268 if (clist->column[column].title)
1270 alignment = GTK_BIN (clist->column[column].button)->child;
1272 switch (clist->column[column].justification)
1274 case GTK_JUSTIFY_LEFT:
1275 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.0, 0.5, 0.0, 0.0);
1278 case GTK_JUSTIFY_RIGHT:
1279 gtk_alignment_set (GTK_ALIGNMENT (alignment), 1.0, 0.5, 0.0, 0.0);
1282 case GTK_JUSTIFY_CENTER:
1283 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
1286 case GTK_JUSTIFY_FILL:
1287 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
1295 if (!GTK_CLIST_FROZEN (clist))
1296 draw_rows (clist, NULL);
1300 gtk_clist_set_column_visibility (GtkCList *clist,
1304 g_return_if_fail (clist != NULL);
1305 g_return_if_fail (GTK_IS_CLIST (clist));
1307 if (column < 0 || column >= clist->columns)
1309 if (clist->column[column].visible == visible)
1312 /* don't hide last visible column */
1316 gint vis_columns = 0;
1318 for (i = 0, vis_columns = 0; i < clist->columns && vis_columns < 2; i++)
1319 if (clist->column[i].visible)
1322 if (vis_columns < 2)
1326 clist->column[column].visible = visible;
1328 gtk_widget_show (clist->column[column].button);
1330 gtk_widget_hide (clist->column[column].button);
1334 gtk_clist_set_column_resizeable (GtkCList *clist,
1338 g_return_if_fail (clist != NULL);
1339 g_return_if_fail (GTK_IS_CLIST (clist));
1341 if (column < 0 || column >= clist->columns)
1343 if (clist->column[column].resizeable == resizeable)
1346 clist->column[column].resizeable = resizeable;
1348 clist->column[column].auto_resize = FALSE;
1350 if (GTK_WIDGET_VISIBLE (clist))
1351 size_allocate_title_buttons (clist);
1355 gtk_clist_set_column_auto_resize (GtkCList *clist,
1357 gboolean auto_resize)
1359 g_return_if_fail (clist != NULL);
1360 g_return_if_fail (GTK_IS_CLIST (clist));
1362 if (column < 0 || column >= clist->columns)
1364 if (clist->column[column].auto_resize == auto_resize)
1367 clist->column[column].auto_resize = auto_resize;
1370 clist->column[column].resizeable = FALSE;
1371 if (!GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
1375 width = gtk_clist_optimal_column_width (clist, column);
1376 gtk_clist_set_column_width (clist, column, width);
1380 if (GTK_WIDGET_VISIBLE (clist))
1381 size_allocate_title_buttons (clist);
1385 gtk_clist_optimal_column_width (GtkCList *clist,
1388 GtkRequisition requisition;
1392 g_return_val_if_fail (clist != NULL, 0);
1393 g_return_val_if_fail (GTK_CLIST (clist), 0);
1395 if (column < 0 || column > clist->columns)
1398 for (list = clist->row_list; list; list = list->next)
1400 GTK_CLIST_CLASS_FW (clist)->cell_size_request
1401 (clist, GTK_CLIST_ROW (list), column, &requisition);
1402 width = MAX (width, requisition.width);
1409 gtk_clist_set_column_width (GtkCList *clist,
1413 g_return_if_fail (clist != NULL);
1414 g_return_if_fail (GTK_IS_CLIST (clist));
1416 if (column < 0 || column >= clist->columns)
1419 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[RESIZE_COLUMN],
1424 gtk_clist_set_column_min_width (GtkCList *clist,
1428 g_return_if_fail (clist != NULL);
1429 g_return_if_fail (GTK_IS_CLIST (clist));
1431 if (column < 0 || column >= clist->columns)
1433 if (clist->column[column].min_width == min_width)
1436 if (clist->column[column].max_width >= 0 &&
1437 clist->column[column].max_width < min_width)
1438 clist->column[column].min_width = clist->column[column].max_width;
1440 clist->column[column].min_width = min_width;
1442 if (clist->column[column].area.width < clist->column[column].min_width)
1443 gtk_clist_set_column_width (clist, column,clist->column[column].min_width);
1447 gtk_clist_set_column_max_width (GtkCList *clist,
1451 g_return_if_fail (clist != NULL);
1452 g_return_if_fail (GTK_IS_CLIST (clist));
1454 if (column < 0 || column >= clist->columns)
1456 if (clist->column[column].max_width == max_width)
1459 if (clist->column[column].min_width >= 0 && max_width >= 0 &&
1460 clist->column[column].min_width > max_width)
1461 clist->column[column].max_width = clist->column[column].min_width;
1463 clist->column[column].max_width = max_width;
1465 if (clist->column[column].area.width > clist->column[column].max_width)
1466 gtk_clist_set_column_width (clist, column,clist->column[column].max_width);
1469 /* PRIVATE COLUMN FUNCTIONS
1470 * column_auto_resize
1471 * real_resize_column
1472 * abort_column_resize
1473 * size_allocate_title_buttons
1474 * size_allocate_columns
1476 * column_button_create
1477 * column_button_clicked
1480 column_auto_resize (GtkCList *clist,
1481 GtkCListRow *clist_row,
1485 /* resize column if needed for auto_resize */
1486 GtkRequisition requisition;
1488 if (!clist->column[column].auto_resize ||
1489 GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
1492 GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row,
1493 column, &requisition);
1495 if (requisition.width > clist->column[column].width)
1497 if (clist->column[column].max_width < 0)
1498 gtk_clist_set_column_width (clist, column, requisition.width);
1499 else if (clist->column[column].max_width >
1500 clist->column[column].width)
1501 gtk_clist_set_column_width (clist, column,
1502 MIN (requisition.width,
1503 clist->column[column].max_width));
1505 else if (requisition.width < old_width &&
1506 old_width == clist->column[column].width)
1511 /* run a "gtk_clist_optimal_column_width" but break, if
1512 * the column doesn't shrink */
1514 for (list = clist->row_list; list; list = list->next)
1516 GTK_CLIST_CLASS_FW (clist)->cell_size_request
1517 (clist, GTK_CLIST_ROW (list), column, &requisition);
1518 new_width = MAX (new_width, requisition.width);
1519 if (new_width == clist->column[column].width)
1522 if (new_width < clist->column[column].width)
1523 gtk_clist_set_column_width
1524 (clist, column, MAX (new_width, clist->column[column].min_width));
1529 real_resize_column (GtkCList *clist,
1533 g_return_if_fail (clist != NULL);
1534 g_return_if_fail (GTK_IS_CLIST (clist));
1536 if (column < 0 || column >= clist->columns)
1539 if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width))
1540 width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width);
1541 if (clist->column[column].max_width >= 0 &&
1542 width > clist->column[column].max_width)
1543 width = clist->column[column].max_width;
1545 clist->column[column].width = width;
1546 clist->column[column].width_set = TRUE;
1548 /* FIXME: this is quite expensive to do if the widget hasn't
1549 * been size_allocated yet, and pointless. Should
1552 size_allocate_columns (clist);
1553 size_allocate_title_buttons (clist);
1555 if (!GTK_CLIST_FROZEN (clist))
1557 adjust_scrollbars (clist);
1558 draw_rows (clist, NULL);
1563 abort_column_resize (GtkCList *clist)
1565 g_return_if_fail (clist != NULL);
1566 g_return_if_fail (GTK_IS_CLIST (clist));
1568 if (!GTK_CLIST_IN_DRAG (clist))
1571 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
1572 gtk_grab_remove (GTK_WIDGET (clist));
1573 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1574 clist->drag_pos = -1;
1576 if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1)
1577 draw_xor_line (clist);
1579 if (GTK_CLIST_ADD_MODE (clist))
1581 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_ON_OFF_DASH, 0,0);
1582 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
1587 size_allocate_title_buttons (GtkCList *clist)
1589 GtkAllocation button_allocation;
1591 gint last_button = 0;
1594 if (!GTK_WIDGET_REALIZED (clist))
1597 button_allocation.x = clist->hoffset;
1598 button_allocation.y = 0;
1599 button_allocation.width = 0;
1600 button_allocation.height = clist->column_title_area.height;
1602 /* find last visible column */
1603 for (last_column = clist->columns - 1; last_column >= 0; last_column--)
1604 if (clist->column[last_column].visible)
1607 for (i = 0; i < last_column; i++)
1609 if (!clist->column[i].visible)
1611 last_button = i + 1;
1612 gdk_window_hide (clist->column[i].window);
1616 button_allocation.width += (clist->column[i].area.width +
1617 CELL_SPACING + 2 * COLUMN_INSET);
1619 if (!clist->column[i + 1].button)
1621 gdk_window_hide (clist->column[i].window);
1625 gtk_widget_size_allocate (clist->column[last_button].button,
1626 &button_allocation);
1627 button_allocation.x += button_allocation.width;
1628 button_allocation.width = 0;
1630 if (clist->column[last_button].resizeable)
1632 gdk_window_show (clist->column[last_button].window);
1633 gdk_window_move_resize (clist->column[last_button].window,
1634 button_allocation.x - (DRAG_WIDTH / 2),
1636 clist->column_title_area.height);
1639 gdk_window_hide (clist->column[last_button].window);
1641 last_button = i + 1;
1644 button_allocation.width += (clist->column[last_column].area.width +
1645 2 * (CELL_SPACING + COLUMN_INSET));
1646 gtk_widget_size_allocate (clist->column[last_button].button,
1647 &button_allocation);
1649 if (clist->column[last_button].resizeable)
1651 button_allocation.x += button_allocation.width;
1653 gdk_window_show (clist->column[last_button].window);
1654 gdk_window_move_resize (clist->column[last_button].window,
1655 button_allocation.x - (DRAG_WIDTH / 2),
1656 0, DRAG_WIDTH, clist->column_title_area.height);
1659 gdk_window_hide (clist->column[last_button].window);
1663 size_allocate_columns (GtkCList *clist)
1665 gint xoffset = CELL_SPACING + COLUMN_INSET;
1670 /* find last visible column and calculate correct column width */
1671 for (last_column = clist->columns - 1;
1672 last_column >= 0 && !clist->column[last_column].visible; last_column--);
1674 if (last_column < 0)
1677 for (i = 0; i < last_column; i++)
1679 if (!clist->column[i].visible)
1681 clist->column[i].area.x = xoffset;
1682 clist->column[i].area.width = clist->column[i].width;
1683 xoffset += clist->column[i].width + CELL_SPACING + (2 * COLUMN_INSET);
1686 if (clist->column[i].width_set)
1687 width = clist->column[i].width;
1688 else if (clist->column[i].title)
1689 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
1690 clist->column[i].title);
1692 clist->column[i].area.x = xoffset;
1693 clist->column[i].area.width = MAX (width,
1694 clist->clist_window_width - xoffset -
1695 (CELL_SPACING + COLUMN_INSET));
1698 /* this function returns the new width of the column being resized given
1699 * the column and x position of the cursor; the x cursor position is passed
1700 * in as a pointer and automagicly corrected if it's beyond min/max limits */
1702 new_column_width (GtkCList *clist,
1706 gint xthickness = GTK_WIDGET (clist)->style->klass->xthickness;
1711 /* first translate the x position from widget->window
1712 * to clist->clist_window */
1713 cx = *x - xthickness;
1715 /* calculate new column width making sure it doesn't end up
1716 * less than the minimum width */
1717 dx = (COLUMN_LEFT_XPIXEL (clist, column) + COLUMN_INSET +
1718 (column < clist->columns - 1) * CELL_SPACING);
1721 if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width))
1723 width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width);
1725 *x = cx + xthickness;
1727 else if (clist->column[column].max_width >= COLUMN_MIN_WIDTH &&
1728 width > clist->column[column].max_width)
1730 width = clist->column[column].max_width;
1731 cx = dx + clist->column[column].max_width;
1732 *x = cx + xthickness;
1735 if (cx < 0 || cx > clist->clist_window_width)
1742 column_button_create (GtkCList *clist,
1747 button = clist->column[column].button = gtk_button_new ();
1748 if (GTK_WIDGET_REALIZED (clist) && clist->title_window)
1749 gtk_widget_set_parent_window (clist->column[column].button, clist->title_window);
1750 gtk_widget_set_parent (button, GTK_WIDGET (clist));
1752 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1753 (GtkSignalFunc) column_button_clicked,
1756 gtk_widget_show (button);
1760 column_button_clicked (GtkWidget *widget,
1766 g_return_if_fail (widget != NULL);
1767 g_return_if_fail (GTK_IS_CLIST (data));
1769 clist = GTK_CLIST (data);
1771 /* find the column who's button was pressed */
1772 for (i = 0; i < clist->columns; i++)
1773 if (clist->column[i].button == widget)
1776 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i);
1780 gtk_clist_set_row_height (GtkCList *clist,
1783 g_return_if_fail (clist != NULL);
1784 g_return_if_fail (GTK_IS_CLIST (clist));
1787 clist->row_height = height;
1791 GTK_CLIST_SET_FLAG (clist, CLIST_ROW_HEIGHT_SET);
1793 if (GTK_WIDGET_REALIZED (clist))
1797 font = GTK_WIDGET (clist)->style->font;
1798 clist->row_center_offset = (((height + font->ascent - font->descent - 1)
1802 if (!GTK_CLIST_FROZEN (clist))
1804 adjust_scrollbars (clist);
1805 draw_rows (clist, NULL);
1810 gtk_clist_moveto (GtkCList *clist,
1816 g_return_if_fail (clist != NULL);
1817 g_return_if_fail (GTK_IS_CLIST (clist));
1819 if (row < -1 || row >= clist->rows)
1821 if (column < -1 || column >= clist->columns)
1824 row_align = CLAMP (row_align, 0, 1);
1825 col_align = CLAMP (col_align, 0, 1);
1827 /* adjust horizontal scrollbar */
1833 adj = GTK_RANGE (clist->hscrollbar)->adjustment;
1835 x = (COLUMN_LEFT (clist, column) - CELL_SPACING - COLUMN_INSET -
1836 (col_align * (clist->clist_window_width - 2 * COLUMN_INSET -
1837 CELL_SPACING - clist->column[column].area.width)));
1839 gtk_adjustment_set_value (adj, 0.0);
1840 else if (x > LIST_WIDTH (clist) - clist->clist_window_width)
1841 gtk_adjustment_set_value
1842 (adj, LIST_WIDTH (clist) - clist->clist_window_width);
1844 gtk_adjustment_set_value (adj, x);
1847 /* adjust vertical scrollbar */
1849 move_vertical (clist, row, row_align);
1852 /* PUBLIC CELL FUNCTIONS
1853 * gtk_clist_get_cell_type
1854 * gtk_clist_set_text
1855 * gtk_clist_get_text
1856 * gtk_clist_set_pixmap
1857 * gtk_clist_get_pixmap
1858 * gtk_clist_set_pixtext
1859 * gtk_clist_get_pixtext
1860 * gtk_clist_set_shift
1863 gtk_clist_get_cell_type (GtkCList *clist,
1867 GtkCListRow *clist_row;
1869 g_return_val_if_fail (clist != NULL, -1);
1870 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1872 if (row < 0 || row >= clist->rows)
1874 if (column < 0 || column >= clist->columns)
1877 clist_row = (g_list_nth (clist->row_list, row))->data;
1879 return clist_row->cell[column].type;
1883 gtk_clist_set_text (GtkCList *clist,
1888 GtkCListRow *clist_row;
1890 g_return_if_fail (clist != NULL);
1891 g_return_if_fail (GTK_IS_CLIST (clist));
1893 if (row < 0 || row >= clist->rows)
1895 if (column < 0 || column >= clist->columns)
1898 clist_row = (g_list_nth (clist->row_list, row))->data;
1900 /* if text is null, then the cell is empty */
1901 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
1902 (clist, clist_row, column, GTK_CELL_TEXT, text, 0, NULL, NULL);
1904 /* redraw the list if it's not frozen */
1905 if (!GTK_CLIST_FROZEN (clist))
1907 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1908 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1913 gtk_clist_get_text (GtkCList *clist,
1918 GtkCListRow *clist_row;
1920 g_return_val_if_fail (clist != NULL, 0);
1921 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
1923 if (row < 0 || row >= clist->rows)
1925 if (column < 0 || column >= clist->columns)
1928 clist_row = (g_list_nth (clist->row_list, row))->data;
1930 if (clist_row->cell[column].type != GTK_CELL_TEXT)
1934 *text = GTK_CELL_TEXT (clist_row->cell[column])->text;
1940 gtk_clist_set_pixmap (GtkCList *clist,
1946 GtkCListRow *clist_row;
1948 g_return_if_fail (clist != NULL);
1949 g_return_if_fail (GTK_IS_CLIST (clist));
1951 if (row < 0 || row >= clist->rows)
1953 if (column < 0 || column >= clist->columns)
1956 clist_row = (g_list_nth (clist->row_list, row))->data;
1958 gdk_pixmap_ref (pixmap);
1960 if (mask) gdk_pixmap_ref (mask);
1962 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
1963 (clist, clist_row, column, GTK_CELL_PIXMAP, NULL, 0, pixmap, mask);
1965 /* redraw the list if it's not frozen */
1966 if (!GTK_CLIST_FROZEN (clist))
1968 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1969 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1974 gtk_clist_get_pixmap (GtkCList *clist,
1980 GtkCListRow *clist_row;
1982 g_return_val_if_fail (clist != NULL, 0);
1983 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
1985 if (row < 0 || row >= clist->rows)
1987 if (column < 0 || column >= clist->columns)
1990 clist_row = (g_list_nth (clist->row_list, row))->data;
1992 if (clist_row->cell[column].type != GTK_CELL_PIXMAP)
1997 *pixmap = GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap;
1998 /* mask can be NULL */
1999 *mask = GTK_CELL_PIXMAP (clist_row->cell[column])->mask;
2006 gtk_clist_set_pixtext (GtkCList *clist,
2014 GtkCListRow *clist_row;
2016 g_return_if_fail (clist != NULL);
2017 g_return_if_fail (GTK_IS_CLIST (clist));
2019 if (row < 0 || row >= clist->rows)
2021 if (column < 0 || column >= clist->columns)
2024 clist_row = (g_list_nth (clist->row_list, row))->data;
2026 gdk_pixmap_ref (pixmap);
2027 if (mask) gdk_pixmap_ref (mask);
2028 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
2029 (clist, clist_row, column, GTK_CELL_PIXTEXT, text, spacing, pixmap, mask);
2031 /* redraw the list if it's not frozen */
2032 if (!GTK_CLIST_FROZEN (clist))
2034 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
2035 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
2040 gtk_clist_get_pixtext (GtkCList *clist,
2048 GtkCListRow *clist_row;
2050 g_return_val_if_fail (clist != NULL, 0);
2051 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
2053 if (row < 0 || row >= clist->rows)
2055 if (column < 0 || column >= clist->columns)
2058 clist_row = (g_list_nth (clist->row_list, row))->data;
2060 if (clist_row->cell[column].type != GTK_CELL_PIXTEXT)
2064 *text = GTK_CELL_PIXTEXT (clist_row->cell[column])->text;
2066 *spacing = GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing;
2068 *pixmap = GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap;
2070 /* mask can be NULL */
2071 *mask = GTK_CELL_PIXTEXT (clist_row->cell[column])->mask;
2077 gtk_clist_set_shift (GtkCList *clist,
2083 GtkRequisition requisition;
2084 GtkCListRow *clist_row;
2086 g_return_if_fail (clist != NULL);
2087 g_return_if_fail (GTK_IS_CLIST (clist));
2089 if (row < 0 || row >= clist->rows)
2091 if (column < 0 || column >= clist->columns)
2094 clist_row = (g_list_nth (clist->row_list, row))->data;
2096 if (clist->column[column].auto_resize &&
2097 !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
2098 GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row,
2099 column, &requisition);
2101 clist_row->cell[column].vertical = vertical;
2102 clist_row->cell[column].horizontal = horizontal;
2104 column_auto_resize (clist, clist_row, column, requisition.width);
2106 if (!GTK_CLIST_FROZEN (clist)
2107 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
2108 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
2111 /* PRIVATE CELL FUNCTIONS
2116 set_cell_contents (GtkCList *clist,
2117 GtkCListRow *clist_row,
2125 GtkRequisition requisition;
2127 g_return_if_fail (clist != NULL);
2128 g_return_if_fail (GTK_IS_CLIST (clist));
2129 g_return_if_fail (clist_row != NULL);
2131 if (clist->column[column].auto_resize &&
2132 !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
2133 GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row,
2134 column, &requisition);
2136 switch (clist_row->cell[column].type)
2138 case GTK_CELL_EMPTY:
2141 g_free (GTK_CELL_TEXT (clist_row->cell[column])->text);
2143 case GTK_CELL_PIXMAP:
2144 gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap);
2145 if (GTK_CELL_PIXMAP (clist_row->cell[column])->mask)
2146 gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask);
2148 case GTK_CELL_PIXTEXT:
2149 g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text);
2150 gdk_pixmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap);
2151 if (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask)
2152 gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask);
2154 case GTK_CELL_WIDGET:
2161 clist_row->cell[column].type = GTK_CELL_EMPTY;
2168 clist_row->cell[column].type = GTK_CELL_TEXT;
2169 GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
2172 case GTK_CELL_PIXMAP:
2175 clist_row->cell[column].type = GTK_CELL_PIXMAP;
2176 GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
2177 /* We set the mask even if it is NULL */
2178 GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask;
2181 case GTK_CELL_PIXTEXT:
2184 clist_row->cell[column].type = GTK_CELL_PIXTEXT;
2185 GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
2186 GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
2187 GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
2188 GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask;
2195 column_auto_resize (clist, clist_row, column, requisition.width);
2199 cell_size_request (GtkCList *clist,
2200 GtkCListRow *clist_row,
2202 GtkRequisition *requisition)
2208 g_return_if_fail (clist != NULL);
2209 g_return_if_fail (GTK_IS_CLIST (clist));
2210 g_return_if_fail (requisition != NULL);
2212 get_cell_style (clist, clist_row, GTK_STATE_PRELIGHT, column, &style,
2215 switch (clist_row->cell[column].type)
2218 requisition->width =
2219 gdk_string_width (style->font,
2220 GTK_CELL_TEXT (clist_row->cell[column])->text);
2221 requisition->height = style->font->ascent + style->font->descent;
2223 case GTK_CELL_PIXTEXT:
2224 gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap,
2226 requisition->width = width +
2227 GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing +
2228 gdk_string_width (style->font,
2229 GTK_CELL_TEXT (clist_row->cell[column])->text);
2231 requisition->height = MAX (style->font->ascent + style->font->descent,
2234 case GTK_CELL_PIXMAP:
2235 gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap,
2237 requisition->width = width;
2238 requisition->height = height;
2241 requisition->width = 0;
2242 requisition->height = 0;
2246 requisition->width += clist_row->cell[column].horizontal;
2247 requisition->height += clist_row->cell[column].vertical;
2250 /* PUBLIC INSERT/REMOVE ROW FUNCTIONS
2258 gtk_clist_prepend (GtkCList *clist,
2261 g_return_val_if_fail (clist != NULL, -1);
2262 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
2263 g_return_val_if_fail (text != NULL, -1);
2265 return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, 0, text);
2269 gtk_clist_append (GtkCList *clist,
2272 g_return_val_if_fail (clist != NULL, -1);
2273 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
2274 g_return_val_if_fail (text != NULL, -1);
2276 return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, clist->rows, text);
2280 gtk_clist_insert (GtkCList *clist,
2284 g_return_val_if_fail (clist != NULL, -1);
2285 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
2286 g_return_val_if_fail (text != NULL, -1);
2288 if (row < 0 || row > clist->rows)
2291 return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, row, text);
2295 gtk_clist_remove (GtkCList *clist,
2298 GTK_CLIST_CLASS_FW (clist)->remove_row (clist, row);
2302 gtk_clist_clear (GtkCList *clist)
2304 g_return_if_fail (clist != NULL);
2305 g_return_if_fail (GTK_IS_CLIST (clist));
2307 GTK_CLIST_CLASS_FW (clist)->clear (clist);
2310 /* PRIVATE INSERT/REMOVE ROW FUNCTIONS
2317 real_insert_row (GtkCList *clist,
2322 GtkCListRow *clist_row;
2324 g_return_val_if_fail (clist != NULL, -1);
2325 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
2326 g_return_val_if_fail (text != NULL, -1);
2328 /* return if out of bounds */
2329 if (row < 0 || row > clist->rows)
2332 /* create the row */
2333 clist_row = row_new (clist);
2335 /* set the text in the row's columns */
2336 for (i = 0; i < clist->columns; i++)
2338 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
2339 (clist, clist_row, i, GTK_CELL_TEXT, text[i], 0, NULL ,NULL);
2343 clist->row_list = g_list_append (clist->row_list, clist_row);
2344 clist->row_list_end = clist->row_list;
2348 if (GTK_CLIST_AUTO_SORT (clist)) /* override insertion pos */
2353 work = clist->row_list;
2355 if (clist->sort_type == GTK_SORT_ASCENDING)
2357 while (row < clist->rows &&
2358 clist->compare (clist, clist_row,
2359 GTK_CLIST_ROW (work)) > 0)
2367 while (row < clist->rows &&
2368 clist->compare (clist, clist_row,
2369 GTK_CLIST_ROW (work)) < 0)
2377 /* reset the row end pointer if we're inserting at the end of the list */
2378 if (row == clist->rows)
2379 clist->row_list_end = (g_list_append (clist->row_list_end,
2382 clist->row_list = g_list_insert (clist->row_list, clist_row, row);
2387 if (row < ROW_FROM_YPIXEL (clist, 0))
2388 clist->voffset -= (clist->row_height + CELL_SPACING);
2390 /* syncronize the selection list */
2391 sync_selection (clist, row, SYNC_INSERT);
2393 /* redraw the list if it isn't frozen */
2394 if (!GTK_CLIST_FROZEN (clist))
2396 adjust_scrollbars (clist);
2398 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
2399 draw_rows (clist, NULL);
2406 real_remove_row (GtkCList *clist,
2409 gint was_visible, was_selected;
2411 GtkCListRow *clist_row;
2413 g_return_if_fail (clist != NULL);
2414 g_return_if_fail (GTK_IS_CLIST (clist));
2416 /* return if out of bounds */
2417 if (row < 0 || row > (clist->rows - 1))
2420 was_visible = (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE);
2423 /* get the row we're going to delete */
2424 list = g_list_nth (clist->row_list, row);
2425 clist_row = list->data;
2427 /* if we're removing a selected row, we have to make sure
2428 * it's properly unselected, and then sync up the clist->selected
2429 * list to reflect the deincrimented indexies of rows after the
2431 if (clist_row->state == GTK_STATE_SELECTED)
2433 switch (clist->selection_mode)
2435 case GTK_SELECTION_SINGLE:
2436 case GTK_SELECTION_MULTIPLE:
2437 case GTK_SELECTION_EXTENDED:
2438 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
2441 case GTK_SELECTION_BROWSE:
2442 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
2450 /* reset the row end pointer if we're removing at the
2451 * end of the list */
2452 if (row == clist->rows - 1)
2453 clist->row_list_end = list->prev;
2454 if (row >= clist->focus_row && clist->focus_row >=0)
2457 clist->row_list = g_list_remove (clist->row_list, clist_row);
2460 if (row < ROW_FROM_YPIXEL (clist, 0))
2461 clist->voffset += clist->row_height + CELL_SPACING;
2463 sync_selection (clist, row, SYNC_REMOVE);
2466 row_delete (clist, clist_row);
2468 /* redraw the row if it isn't frozen */
2469 if (!GTK_CLIST_FROZEN (clist))
2471 adjust_scrollbars (clist);
2474 draw_rows (clist, NULL);
2479 real_clear (GtkCList *clist)
2485 g_return_if_fail (clist != NULL);
2486 g_return_if_fail (GTK_IS_CLIST (clist));
2488 /* free up the selection list */
2489 g_list_free (clist->selection);
2490 g_list_free (clist->undo_selection);
2491 g_list_free (clist->undo_unselection);
2493 clist->selection = NULL;
2494 clist->selection_end = NULL;
2495 clist->undo_selection = NULL;
2496 clist->undo_unselection = NULL;
2498 clist->focus_row = -1;
2500 clist->undo_anchor = -1;
2501 clist->anchor_state = GTK_STATE_SELECTED;
2502 clist->drag_pos = -1;
2504 /* remove all the rows */
2505 GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED);
2506 free_list = clist->row_list;
2507 clist->row_list = NULL;
2508 clist->row_list_end = NULL;
2510 for (list = free_list; list; list = list->next)
2511 row_delete (clist, GTK_CLIST_ROW (list));
2512 g_list_free (free_list);
2513 GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED);
2514 for (i = 0; i < clist->columns; i++)
2515 if (clist->column[i].auto_resize && clist->column[i].width > 0)
2516 gtk_clist_set_column_width (clist, i, 0);
2518 /* zero-out the scrollbars */
2519 if (clist->vscrollbar)
2521 GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0;
2522 gtk_signal_emit_by_name
2523 (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
2524 if (!GTK_CLIST_FROZEN (clist))
2525 gtk_clist_thaw (clist);
2529 /* PUBLIC ROW FUNCTIONS
2530 * gtk_clist_set_row_data
2531 * gtk_clist_set_row_data_full
2532 * gtk_clist_get_row_data
2533 * gtk_clist_find_row_from_data
2534 * gtk_clist_swap_rows
2535 * gtk_clist_row_is_visible
2536 * gtk_clist_set_foreground
2537 * gtk_clist_set_background
2540 gtk_clist_set_row_data (GtkCList *clist,
2544 gtk_clist_set_row_data_full (clist, row, data, NULL);
2548 gtk_clist_set_row_data_full (GtkCList *clist,
2551 GtkDestroyNotify destroy)
2553 GtkCListRow *clist_row;
2555 g_return_if_fail (clist != NULL);
2556 g_return_if_fail (GTK_IS_CLIST (clist));
2558 if (row < 0 || row > (clist->rows - 1))
2561 clist_row = (g_list_nth (clist->row_list, row))->data;
2562 clist_row->data = data;
2563 clist_row->destroy = destroy;
2567 gtk_clist_get_row_data (GtkCList *clist,
2570 GtkCListRow *clist_row;
2572 g_return_val_if_fail (clist != NULL, NULL);
2573 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2575 if (row < 0 || row > (clist->rows - 1))
2578 clist_row = (g_list_nth (clist->row_list, row))->data;
2579 return clist_row->data;
2583 gtk_clist_find_row_from_data (GtkCList *clist,
2589 g_return_val_if_fail (clist != NULL, -1);
2590 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
2592 for (n = 0, list = clist->row_list; list; n++, list = list->next)
2593 if (GTK_CLIST_ROW (list)->data == data)
2600 gtk_clist_swap_rows (GtkCList *clist,
2605 GList *list, *link1, *link2;
2608 g_return_if_fail (clist != NULL);
2609 g_return_if_fail (GTK_IS_CLIST (clist));
2611 if (GTK_CLIST_AUTO_SORT (clist))
2614 if (row1 < 0 || row1 > (clist->rows - 1))
2617 if (row2 < 0 || row2 > (clist->rows - 1))
2620 first = MIN (row1, row2);
2621 last = MAX (row1, row2);
2623 link1 = g_list_nth (clist->row_list, first);
2624 link2 = g_list_nth (link1, row2 - row1);
2627 link1->data = link2->data;
2630 list = clist->selection;
2633 if (GPOINTER_TO_INT (list->data) == row1)
2634 list->data = GINT_TO_POINTER (row2);
2636 if (GPOINTER_TO_INT (list->data) == row2)
2637 list->data = GINT_TO_POINTER (row1);
2642 if (!GTK_CLIST_FROZEN (clist))
2644 if (gtk_clist_row_is_visible (clist, row1) != GTK_VISIBILITY_NONE)
2645 GTK_CLIST_CLASS_FW (clist)->draw_row
2646 (clist, NULL, row1, GTK_CLIST_ROW (link2));
2648 if (gtk_clist_row_is_visible (clist, row2) != GTK_VISIBILITY_NONE)
2649 GTK_CLIST_CLASS_FW (clist)->draw_row
2650 (clist, NULL, row2, GTK_CLIST_ROW (link1));
2655 gtk_clist_row_is_visible (GtkCList *clist,
2660 g_return_val_if_fail (clist != NULL, 0);
2661 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
2663 if (row < 0 || row >= clist->rows)
2664 return GTK_VISIBILITY_NONE;
2666 if (clist->row_height == 0)
2667 return GTK_VISIBILITY_NONE;
2669 if (row < ROW_FROM_YPIXEL (clist, 0))
2670 return GTK_VISIBILITY_NONE;
2672 if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height))
2673 return GTK_VISIBILITY_NONE;
2675 top = ROW_TOP_YPIXEL (clist, row);
2678 || ((top + clist->row_height) >= clist->clist_window_height))
2679 return GTK_VISIBILITY_PARTIAL;
2681 return GTK_VISIBILITY_FULL;
2685 gtk_clist_set_foreground (GtkCList *clist,
2689 GtkCListRow *clist_row;
2691 g_return_if_fail (clist != NULL);
2692 g_return_if_fail (GTK_IS_CLIST (clist));
2694 if (row < 0 || row >= clist->rows)
2697 clist_row = (g_list_nth (clist->row_list, row))->data;
2701 clist_row->foreground = *color;
2702 clist_row->fg_set = TRUE;
2703 if (GTK_WIDGET_REALIZED (clist))
2704 gdk_color_alloc (gtk_widget_get_colormap (GTK_WIDGET (clist)),
2705 &clist_row->foreground);
2708 clist_row->fg_set = FALSE;
2710 if (!GTK_CLIST_FROZEN (clist)
2711 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
2712 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
2716 gtk_clist_set_background (GtkCList *clist,
2720 GtkCListRow *clist_row;
2722 g_return_if_fail (clist != NULL);
2723 g_return_if_fail (GTK_IS_CLIST (clist));
2725 if (row < 0 || row >= clist->rows)
2728 clist_row = (g_list_nth (clist->row_list, row))->data;
2732 clist_row->background = *color;
2733 clist_row->bg_set = TRUE;
2734 if (GTK_WIDGET_REALIZED (clist))
2735 gdk_color_alloc (gtk_widget_get_colormap (GTK_WIDGET (clist)),
2736 &clist_row->background);
2739 clist_row->bg_set = FALSE;
2741 if (!GTK_CLIST_FROZEN (clist)
2742 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
2743 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
2746 /* PUBLIC ROW/CELL STYLE FUNCTIONS
2747 * gtk_clist_set_cell_style
2748 * gtk_clist_get_cell_style
2749 * gtk_clist_set_row_style
2750 * gtk_clist_get_row_style
2753 gtk_clist_set_cell_style (GtkCList *clist,
2758 GtkRequisition requisition;
2759 GtkCListRow *clist_row;
2761 g_return_if_fail (clist != NULL);
2762 g_return_if_fail (GTK_IS_CLIST (clist));
2764 if (row < 0 || row >= clist->rows)
2766 if (column < 0 || column >= clist->columns)
2769 clist_row = (g_list_nth (clist->row_list, row))->data;
2771 if (clist_row->cell[column].style == style)
2774 if (clist->column[column].auto_resize &&
2775 !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
2776 GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row,
2777 column, &requisition);
2779 if (clist_row->cell[column].style)
2781 if (GTK_WIDGET_REALIZED (clist))
2782 gtk_style_detach (clist_row->cell[column].style);
2783 gtk_style_unref (clist_row->cell[column].style);
2786 clist_row->cell[column].style = style;
2788 if (clist_row->cell[column].style)
2790 gtk_style_ref (clist_row->cell[column].style);
2792 if (GTK_WIDGET_REALIZED (clist))
2793 clist_row->cell[column].style =
2794 gtk_style_attach (clist_row->cell[column].style,
2795 clist->clist_window);
2798 column_auto_resize (clist, clist_row, column, requisition.width);
2800 /* redraw the list if it's not frozen */
2801 if (!GTK_CLIST_FROZEN (clist))
2803 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
2804 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
2809 gtk_clist_get_cell_style (GtkCList *clist,
2813 GtkCListRow *clist_row;
2815 g_return_val_if_fail (clist != NULL, NULL);
2816 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2818 if (row < 0 || row >= clist->rows || column < 0 || column >= clist->columns)
2821 clist_row = (g_list_nth (clist->row_list, row))->data;
2823 return clist_row->cell[column].style;
2827 gtk_clist_set_row_style (GtkCList *clist,
2831 GtkRequisition requisition;
2832 GtkCListRow *clist_row;
2836 g_return_if_fail (clist != NULL);
2837 g_return_if_fail (GTK_IS_CLIST (clist));
2839 if (row < 0 || row >= clist->rows)
2842 clist_row = (g_list_nth (clist->row_list, row))->data;
2844 if (clist_row->style == style)
2847 old_width = g_new (gint, clist->columns);
2849 if (!GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
2851 for (i = 0; i < clist->columns; i++)
2852 if (clist->column[i].auto_resize)
2854 GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row,
2856 old_width[i] = requisition.width;
2860 if (clist_row->style)
2862 if (GTK_WIDGET_REALIZED (clist))
2863 gtk_style_detach (clist_row->style);
2864 gtk_style_unref (clist_row->style);
2867 clist_row->style = style;
2869 if (clist_row->style)
2871 gtk_style_ref (clist_row->style);
2873 if (GTK_WIDGET_REALIZED (clist))
2874 clist_row->style = gtk_style_attach (clist_row->style,
2875 clist->clist_window);
2878 if (GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
2880 for (i = 0; i < clist->columns; i++)
2881 if (clist->column[i].auto_resize)
2882 column_auto_resize (clist, clist_row, i, old_width[i]);
2887 /* redraw the list if it's not frozen */
2888 if (!GTK_CLIST_FROZEN (clist))
2890 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
2891 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
2896 gtk_clist_get_row_style (GtkCList *clist,
2899 GtkCListRow *clist_row;
2901 g_return_val_if_fail (clist != NULL, NULL);
2902 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2904 if (row < 0 || row >= clist->rows)
2907 clist_row = (g_list_nth (clist->row_list, row))->data;
2909 return clist_row->style;
2912 /* PUBLIC SELECTION FUNCTIONS
2913 * gtk_clist_set_selectable
2914 * gtk_clist_get_selectable
2915 * gtk_clist_select_row
2916 * gtk_clist_unselect_row
2917 * gtk_clist_select_all
2918 * gtk_clist_unselect_all
2919 * gtk_clist_undo_selection
2922 gtk_clist_set_selectable (GtkCList *clist,
2924 gboolean selectable)
2926 GtkCListRow *clist_row;
2928 g_return_if_fail (clist != NULL);
2929 g_return_if_fail (GTK_IS_CLIST (clist));
2931 if (row < 0 || row >= clist->rows)
2934 clist_row = (g_list_nth (clist->row_list, row))->data;
2936 if (selectable == clist_row->selectable)
2939 clist_row->selectable = selectable;
2941 if (!selectable && clist_row->state == GTK_STATE_SELECTED)
2943 if (clist->anchor >= 0 &&
2944 clist->selection_mode == GTK_SELECTION_EXTENDED)
2946 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist)))
2948 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
2949 gtk_grab_remove (GTK_WIDGET (clist));
2950 gdk_pointer_ungrab (GDK_CURRENT_TIME);
2953 gtk_timeout_remove (clist->htimer);
2958 gtk_timeout_remove (clist->vtimer);
2962 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
2964 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
2970 gtk_clist_get_selectable (GtkCList *clist,
2973 g_return_val_if_fail (clist != NULL, FALSE);
2974 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
2976 if (row < 0 || row >= clist->rows)
2979 return GTK_CLIST_ROW (g_list_nth (clist->row_list, row))->selectable;
2983 gtk_clist_select_row (GtkCList *clist,
2987 g_return_if_fail (clist != NULL);
2988 g_return_if_fail (GTK_IS_CLIST (clist));
2990 if (row < 0 || row >= clist->rows)
2992 if (column < -1 || column >= clist->columns)
2995 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
3000 gtk_clist_unselect_row (GtkCList *clist,
3004 g_return_if_fail (clist != NULL);
3005 g_return_if_fail (GTK_IS_CLIST (clist));
3007 if (row < 0 || row >= clist->rows)
3009 if (column < -1 || column >= clist->columns)
3012 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3017 gtk_clist_select_all (GtkCList *clist)
3019 g_return_if_fail (clist != NULL);
3020 g_return_if_fail (GTK_IS_CLIST (clist));
3022 GTK_CLIST_CLASS_FW (clist)->select_all (clist);
3026 gtk_clist_unselect_all (GtkCList *clist)
3028 g_return_if_fail (clist != NULL);
3029 g_return_if_fail (GTK_IS_CLIST (clist));
3031 GTK_CLIST_CLASS_FW (clist)->unselect_all (clist);
3035 gtk_clist_undo_selection (GtkCList *clist)
3037 g_return_if_fail (clist != NULL);
3038 g_return_if_fail (GTK_IS_CLIST (clist));
3040 if (clist->selection_mode == GTK_SELECTION_EXTENDED &&
3041 (clist->undo_selection || clist->undo_unselection))
3042 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNDO_SELECTION]);
3045 /* PRIVATE SELECTION FUNCTIONS
3056 * real_undo_selection
3059 * update_extended_selection
3066 selection_find (GtkCList *clist,
3068 GList *row_list_element)
3070 return g_list_find (clist->selection, GINT_TO_POINTER (row_number));
3074 toggle_row (GtkCList *clist,
3079 GtkCListRow *clist_row;
3081 switch (clist->selection_mode)
3083 case GTK_SELECTION_EXTENDED:
3084 case GTK_SELECTION_MULTIPLE:
3085 case GTK_SELECTION_SINGLE:
3086 clist_row = g_list_nth (clist->row_list, row)->data;
3087 if (clist_row->state == GTK_STATE_SELECTED)
3089 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3090 row, column, event);
3093 case GTK_SELECTION_BROWSE:
3094 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
3095 row, column, event);
3101 fake_toggle_row (GtkCList *clist,
3106 if (!(work = g_list_nth (clist->row_list, row))||
3107 !GTK_CLIST_ROW (work)->selectable)
3110 if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL)
3111 clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
3113 clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
3115 if (!GTK_CLIST_FROZEN (clist) &&
3116 gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
3117 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
3118 GTK_CLIST_ROW (work));
3122 toggle_focus_row (GtkCList *clist)
3124 g_return_if_fail (clist != 0);
3125 g_return_if_fail (GTK_IS_CLIST (clist));
3127 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
3128 clist->focus_row < 0 || clist->focus_row >= clist->rows)
3131 switch (clist->selection_mode)
3133 case GTK_SELECTION_SINGLE:
3134 case GTK_SELECTION_MULTIPLE:
3135 toggle_row (clist, clist->focus_row, 0, NULL);
3137 case GTK_SELECTION_EXTENDED:
3138 g_list_free (clist->undo_selection);
3139 g_list_free (clist->undo_unselection);
3140 clist->undo_selection = NULL;
3141 clist->undo_unselection = NULL;
3143 clist->anchor = clist->focus_row;
3144 clist->drag_pos = clist->focus_row;
3145 clist->undo_anchor = clist->focus_row;
3147 if (GTK_CLIST_ADD_MODE (clist))
3148 fake_toggle_row (clist, clist->focus_row);
3150 GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist,clist->focus_row);
3152 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
3160 toggle_add_mode (GtkCList *clist)
3162 g_return_if_fail (clist != 0);
3163 g_return_if_fail (GTK_IS_CLIST (clist));
3165 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
3166 clist->selection_mode != GTK_SELECTION_EXTENDED)
3169 gtk_clist_draw_focus (GTK_WIDGET (clist));
3170 if (!GTK_CLIST_ADD_MODE (clist))
3172 GTK_CLIST_SET_FLAG (clist, CLIST_ADD_MODE);
3173 gdk_gc_set_line_attributes (clist->xor_gc, 1,
3174 GDK_LINE_ON_OFF_DASH, 0, 0);
3175 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
3179 GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
3180 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
3181 clist->anchor_state = GTK_STATE_SELECTED;
3183 gtk_clist_draw_focus (GTK_WIDGET (clist));
3187 real_select_row (GtkCList *clist,
3192 GtkCListRow *clist_row;
3195 gboolean row_selected;
3197 g_return_if_fail (clist != NULL);
3198 g_return_if_fail (GTK_IS_CLIST (clist));
3200 if (row < 0 || row > (clist->rows - 1))
3203 switch (clist->selection_mode)
3205 case GTK_SELECTION_SINGLE:
3206 case GTK_SELECTION_BROWSE:
3208 row_selected = FALSE;
3209 list = clist->selection;
3213 sel_row = GPOINTER_TO_INT (list->data);
3217 row_selected = TRUE;
3219 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3220 sel_row, column, event);
3230 clist_row = (g_list_nth (clist->row_list, row))->data;
3232 if (clist_row->state != GTK_STATE_NORMAL || !clist_row->selectable)
3235 clist_row->state = GTK_STATE_SELECTED;
3236 if (!clist->selection)
3238 clist->selection = g_list_append (clist->selection,
3239 GINT_TO_POINTER (row));
3240 clist->selection_end = clist->selection;
3243 clist->selection_end =
3244 g_list_append (clist->selection_end, GINT_TO_POINTER (row))->next;
3246 if (!GTK_CLIST_FROZEN (clist)
3247 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
3248 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
3252 real_unselect_row (GtkCList *clist,
3257 GtkCListRow *clist_row;
3259 g_return_if_fail (clist != NULL);
3260 g_return_if_fail (GTK_IS_CLIST (clist));
3262 if (row < 0 || row > (clist->rows - 1))
3265 clist_row = (g_list_nth (clist->row_list, row))->data;
3267 if (clist_row->state == GTK_STATE_SELECTED)
3269 clist_row->state = GTK_STATE_NORMAL;
3271 if (clist->selection_end &&
3272 clist->selection_end->data == GINT_TO_POINTER (row))
3273 clist->selection_end = clist->selection_end->prev;
3275 clist->selection = g_list_remove (clist->selection,
3276 GINT_TO_POINTER (row));
3278 if (!GTK_CLIST_FROZEN (clist)
3279 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
3280 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
3285 real_select_all (GtkCList *clist)
3290 g_return_if_fail (clist != NULL);
3291 g_return_if_fail (GTK_IS_CLIST (clist));
3293 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
3296 switch (clist->selection_mode)
3298 case GTK_SELECTION_SINGLE:
3299 case GTK_SELECTION_BROWSE:
3302 case GTK_SELECTION_EXTENDED:
3303 g_list_free (clist->undo_selection);
3304 g_list_free (clist->undo_unselection);
3305 clist->undo_selection = NULL;
3306 clist->undo_unselection = NULL;
3309 ((GtkCListRow *) (clist->row_list->data))->state !=
3311 fake_toggle_row (clist, 0);
3313 clist->anchor_state = GTK_STATE_SELECTED;
3315 clist->drag_pos = 0;
3316 clist->undo_anchor = clist->focus_row;
3317 update_extended_selection (clist, clist->rows);
3318 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
3321 case GTK_SELECTION_MULTIPLE:
3322 for (i = 0, list = clist->row_list; list; i++, list = list->next)
3324 if (((GtkCListRow *)(list->data))->state == GTK_STATE_NORMAL)
3325 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
3333 real_unselect_all (GtkCList *clist)
3338 g_return_if_fail (clist != NULL);
3339 g_return_if_fail (GTK_IS_CLIST (clist));
3341 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
3344 switch (clist->selection_mode)
3346 case GTK_SELECTION_BROWSE:
3347 if (clist->focus_row >= 0)
3349 gtk_signal_emit (GTK_OBJECT (clist),
3350 clist_signals[SELECT_ROW],
3351 clist->focus_row, -1, NULL);
3355 case GTK_SELECTION_EXTENDED:
3356 g_list_free (clist->undo_selection);
3357 g_list_free (clist->undo_unselection);
3358 clist->undo_selection = NULL;
3359 clist->undo_unselection = NULL;
3362 clist->drag_pos = -1;
3363 clist->undo_anchor = clist->focus_row;
3369 list = clist->selection;
3372 i = GPOINTER_TO_INT (list->data);
3374 gtk_signal_emit (GTK_OBJECT (clist),
3375 clist_signals[UNSELECT_ROW], i, -1, NULL);
3380 fake_unselect_all (GtkCList *clist,
3387 if (row >= 0 && (work = g_list_nth (clist->row_list, row)))
3389 if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL &&
3390 GTK_CLIST_ROW (work)->selectable)
3392 GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
3394 if (!GTK_CLIST_FROZEN (clist) &&
3395 gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
3396 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
3397 GTK_CLIST_ROW (work));
3401 clist->undo_selection = clist->selection;
3402 clist->selection = NULL;
3403 clist->selection_end = NULL;
3405 for (list = clist->undo_selection; list; list = list->next)
3407 if ((i = GPOINTER_TO_INT (list->data)) == row ||
3408 !(work = g_list_nth (clist->row_list, i)))
3411 GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
3412 if (!GTK_CLIST_FROZEN (clist) &&
3413 gtk_clist_row_is_visible (clist, i) != GTK_VISIBILITY_NONE)
3414 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, i,
3415 GTK_CLIST_ROW (work));
3420 real_undo_selection (GtkCList *clist)
3424 g_return_if_fail (clist != NULL);
3425 g_return_if_fail (GTK_IS_CLIST (clist));
3427 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
3428 clist->selection_mode != GTK_SELECTION_EXTENDED)
3431 if (clist->anchor >= 0)
3432 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
3434 if (!(clist->undo_selection || clist->undo_unselection))
3436 gtk_clist_unselect_all (clist);
3440 for (work = clist->undo_selection; work; work = work->next)
3441 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
3442 GPOINTER_TO_INT (work->data), -1, NULL);
3444 for (work = clist->undo_unselection; work; work = work->next)
3445 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3446 GPOINTER_TO_INT (work->data), -1, NULL);
3448 if (GTK_WIDGET_HAS_FOCUS (clist) && clist->focus_row != clist->undo_anchor)
3450 gtk_clist_draw_focus (GTK_WIDGET (clist));
3451 clist->focus_row = clist->undo_anchor;
3452 gtk_clist_draw_focus (GTK_WIDGET (clist));
3455 clist->focus_row = clist->undo_anchor;
3457 clist->undo_anchor = -1;
3459 g_list_free (clist->undo_selection);
3460 g_list_free (clist->undo_unselection);
3461 clist->undo_selection = NULL;
3462 clist->undo_unselection = NULL;
3464 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
3465 clist->clist_window_height)
3466 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
3467 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
3468 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
3472 set_anchor (GtkCList *clist,
3477 g_return_if_fail (clist != NULL);
3478 g_return_if_fail (GTK_IS_CLIST (clist));
3480 if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor >= 0)
3483 g_list_free (clist->undo_selection);
3484 g_list_free (clist->undo_unselection);
3485 clist->undo_selection = NULL;
3486 clist->undo_unselection = NULL;
3489 fake_toggle_row (clist, anchor);
3492 GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist, anchor);
3493 clist->anchor_state = GTK_STATE_SELECTED;
3496 clist->anchor = anchor;
3497 clist->drag_pos = anchor;
3498 clist->undo_anchor = undo_anchor;
3502 resync_selection (GtkCList *clist,
3508 gboolean thaw = FALSE;
3510 GtkCListRow *clist_row;
3512 if (clist->anchor < 0)
3515 if (!GTK_CLIST_FROZEN (clist))
3517 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
3521 i = MIN (clist->anchor, clist->drag_pos);
3522 e = MAX (clist->anchor, clist->drag_pos);
3524 if (clist->undo_selection)
3526 list = clist->selection;
3527 clist->selection = clist->undo_selection;
3528 clist->selection_end = g_list_last (clist->selection);
3529 clist->undo_selection = list;
3530 list = clist->selection;
3533 row = GPOINTER_TO_INT (list->data);
3535 if (row < i || row > e)
3537 clist_row = g_list_nth (clist->row_list, row)->data;
3538 if (clist_row->selectable)
3540 clist_row->state = GTK_STATE_SELECTED;
3541 gtk_signal_emit (GTK_OBJECT (clist),
3542 clist_signals[UNSELECT_ROW],
3544 clist->undo_selection = g_list_prepend
3545 (clist->undo_selection, GINT_TO_POINTER (row));
3551 for (list = g_list_nth (clist->row_list, i); i <= e; i++, list = list->next)
3552 if (GTK_CLIST_ROW (list)->selectable)
3554 if (g_list_find (clist->selection, GINT_TO_POINTER(i)))
3556 if (GTK_CLIST_ROW (list)->state == GTK_STATE_NORMAL)
3558 GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
3559 gtk_signal_emit (GTK_OBJECT (clist),
3560 clist_signals[UNSELECT_ROW], i, -1, event);
3561 clist->undo_selection = g_list_prepend (clist->undo_selection,
3562 GINT_TO_POINTER (i));
3565 else if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
3567 GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
3568 clist->undo_unselection = g_list_prepend (clist->undo_unselection,
3569 GINT_TO_POINTER (i));
3573 for (list = clist->undo_unselection; list; list = list->next)
3574 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
3575 GPOINTER_TO_INT (list->data), -1, event);
3578 clist->drag_pos = -1;
3581 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
3585 update_extended_selection (GtkCList *clist,
3595 gint y1 = clist->clist_window_height;
3596 gint y2 = clist->clist_window_height;
3601 if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor == -1)
3606 if (row >= clist->rows)
3607 row = clist->rows - 1;
3609 /* extending downwards */
3610 if (row > clist->drag_pos && clist->anchor <= clist->drag_pos)
3612 s2 = clist->drag_pos + 1;
3615 /* extending upwards */
3616 else if (row < clist->drag_pos && clist->anchor >= clist->drag_pos)
3619 e2 = clist->drag_pos - 1;
3621 else if (row < clist->drag_pos && clist->anchor < clist->drag_pos)
3623 e1 = clist->drag_pos;
3624 /* row and drag_pos on different sides of anchor :
3625 take back the selection between anchor and drag_pos,
3626 select between anchor and row */
3627 if (row < clist->anchor)
3629 s1 = clist->anchor + 1;
3631 e2 = clist->anchor - 1;
3633 /* take back the selection between anchor and drag_pos */
3637 else if (row > clist->drag_pos && clist->anchor > clist->drag_pos)
3639 s1 = clist->drag_pos;
3640 /* row and drag_pos on different sides of anchor :
3641 take back the selection between anchor and drag_pos,
3642 select between anchor and row */
3643 if (row > clist->anchor)
3645 e1 = clist->anchor - 1;
3646 s2 = clist->anchor + 1;
3649 /* take back the selection between anchor and drag_pos */
3654 clist->drag_pos = row;
3657 area.width = clist->clist_window_width;
3659 /* restore the elements between s1 and e1 */
3662 for (i = s1, list = g_list_nth (clist->row_list, i); i <= e1;
3663 i++, list = list->next)
3664 if (GTK_CLIST_ROW (list)->selectable)
3666 if (GTK_CLIST_CLASS_FW (clist)->selection_find (clist, i, list))
3667 GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
3669 GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
3672 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
3674 if (top + clist->row_height <= 0)
3677 area.height = ROW_TOP_YPIXEL (clist, e1) + clist->row_height;
3678 draw_rows (clist, &area);
3679 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
3681 else if (top >= clist->clist_window_height)
3683 area.y = ROW_TOP_YPIXEL (clist, s1) - 1;
3684 area.height = clist->clist_window_height - area.y;
3685 draw_rows (clist, &area);
3686 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
3689 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
3690 else if (top + clist->row_height > clist->clist_window_height)
3691 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
3693 y1 = ROW_TOP_YPIXEL (clist, s1) - 1;
3694 h1 = (e1 - s1 + 1) * (clist->row_height + CELL_SPACING);
3697 /* extend the selection between s2 and e2 */
3700 for (i = s2, list = g_list_nth (clist->row_list, i); i <= e2;
3701 i++, list = list->next)
3702 if (GTK_CLIST_ROW (list)->selectable &&
3703 GTK_CLIST_ROW (list)->state != clist->anchor_state)
3704 GTK_CLIST_ROW (list)->state = clist->anchor_state;
3706 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
3708 if (top + clist->row_height <= 0)
3711 area.height = ROW_TOP_YPIXEL (clist, e2) + clist->row_height;
3712 draw_rows (clist, &area);
3713 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
3715 else if (top >= clist->clist_window_height)
3717 area.y = ROW_TOP_YPIXEL (clist, s2) - 1;
3718 area.height = clist->clist_window_height - area.y;
3719 draw_rows (clist, &area);
3720 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
3723 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
3724 else if (top + clist->row_height > clist->clist_window_height)
3725 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
3727 y2 = ROW_TOP_YPIXEL (clist, s2) - 1;
3728 h2 = (e2 - s2 + 1) * (clist->row_height + CELL_SPACING);
3731 area.y = MAX (0, MIN (y1, y2));
3732 if (area.y > clist->clist_window_height)
3734 area.height = MIN (clist->clist_window_height, h1 + h2);
3735 if (s1 >= 0 && s2 >= 0)
3736 area.height += (clist->row_height + CELL_SPACING);
3737 draw_rows (clist, &area);
3741 start_selection (GtkCList *clist)
3743 g_return_if_fail (clist != NULL);
3744 g_return_if_fail (GTK_IS_CLIST (clist));
3746 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
3749 set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
3754 end_selection (GtkCList *clist)
3756 g_return_if_fail (clist != NULL);
3757 g_return_if_fail (GTK_IS_CLIST (clist));
3759 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist)) ||
3760 clist->anchor == -1)
3763 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
3767 extend_selection (GtkCList *clist,
3768 GtkScrollType scroll_type,
3770 gboolean auto_start_selection)
3772 g_return_if_fail (clist != NULL);
3773 g_return_if_fail (GTK_IS_CLIST (clist));
3775 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
3776 clist->selection_mode != GTK_SELECTION_EXTENDED)
3779 if (auto_start_selection)
3780 set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
3782 else if (clist->anchor == -1)
3785 move_focus_row (clist, scroll_type, position);
3787 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
3788 clist->clist_window_height)
3789 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
3790 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
3791 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
3793 update_extended_selection (clist, clist->focus_row);
3797 sync_selection (GtkCList *clist,
3804 if (mode == SYNC_INSERT)
3809 if (clist->focus_row >= row)
3811 clist->focus_row += d;
3812 if (clist->focus_row == -1 && clist->rows >= 1)
3813 clist->focus_row = 0;
3816 if (clist->selection_mode == GTK_SELECTION_BROWSE && clist->anchor != -1)
3817 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
3819 g_list_free (clist->undo_selection);
3820 g_list_free (clist->undo_unselection);
3821 clist->undo_selection = NULL;
3822 clist->undo_unselection = NULL;
3825 clist->drag_pos = -1;
3826 clist->undo_anchor = clist->focus_row;
3828 list = clist->selection;
3831 if (GPOINTER_TO_INT (list->data) >= row)
3832 list->data = ((gchar*) list->data) + d;
3839 * gtk_clist_finalize
3842 gtk_clist_destroy (GtkObject *object)
3847 g_return_if_fail (object != NULL);
3848 g_return_if_fail (GTK_IS_CLIST (object));
3850 clist = GTK_CLIST (object);
3852 /* freeze the list */
3853 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
3855 /* get rid of all the rows */
3856 gtk_clist_clear (clist);
3858 /* Since we don't have a _remove method, unparent the children
3859 * instead of destroying them so the focus will be unset properly.
3860 * (For other containers, the _remove method takes care of the
3861 * unparent) The destroy will happen when the refcount drops
3865 /* destroy the scrollbars */
3866 if (clist->vscrollbar)
3868 gtk_widget_unparent (clist->vscrollbar);
3869 clist->vscrollbar = NULL;
3871 if (clist->hscrollbar)
3873 gtk_widget_unparent (clist->hscrollbar);
3874 clist->hscrollbar = NULL;
3879 gtk_timeout_remove (clist->htimer);
3884 gtk_timeout_remove (clist->vtimer);
3888 /* destroy the column buttons */
3889 for (i = 0; i < clist->columns; i++)
3890 if (clist->column[i].button)
3892 gtk_widget_unparent (clist->column[i].button);
3893 clist->column[i].button = NULL;
3896 if (GTK_OBJECT_CLASS (parent_class)->destroy)
3897 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
3901 gtk_clist_finalize (GtkObject *object)
3905 g_return_if_fail (object != NULL);
3906 g_return_if_fail (GTK_IS_CLIST (object));
3908 clist = GTK_CLIST (object);
3910 columns_delete (clist);
3912 g_mem_chunk_destroy (clist->cell_mem_chunk);
3913 g_mem_chunk_destroy (clist->row_mem_chunk);
3915 if (GTK_OBJECT_CLASS (parent_class)->finalize)
3916 (*GTK_OBJECT_CLASS (parent_class)->finalize) (object);
3921 * gtk_clist_unrealize
3926 * gtk_clist_style_set
3927 * gtk_clist_key_press
3928 * gtk_clist_button_press
3929 * gtk_clist_button_release
3931 * gtk_clist_size_request
3932 * gtk_clist_size_allocate
3935 gtk_clist_realize (GtkWidget *widget)
3938 GdkWindowAttr attributes;
3940 GtkCListRow *clist_row;
3942 gint attributes_mask;
3947 g_return_if_fail (widget != NULL);
3948 g_return_if_fail (GTK_IS_CLIST (widget));
3950 clist = GTK_CLIST (widget);
3952 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
3954 border_width = GTK_CONTAINER (widget)->border_width;
3956 attributes.window_type = GDK_WINDOW_CHILD;
3957 attributes.x = widget->allocation.x + border_width;
3958 attributes.y = widget->allocation.y + border_width;
3959 attributes.width = widget->allocation.width - border_width * 2;
3960 attributes.height = widget->allocation.height - border_width * 2;
3961 attributes.wclass = GDK_INPUT_OUTPUT;
3962 attributes.visual = gtk_widget_get_visual (widget);
3963 attributes.colormap = gtk_widget_get_colormap (widget);
3964 attributes.event_mask = gtk_widget_get_events (widget);
3965 attributes.event_mask |= (GDK_EXPOSURE_MASK |
3966 GDK_BUTTON_PRESS_MASK |
3967 GDK_BUTTON_RELEASE_MASK |
3968 GDK_KEY_PRESS_MASK |
3969 GDK_KEY_RELEASE_MASK);
3970 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3973 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
3974 &attributes, attributes_mask);
3975 gdk_window_set_user_data (widget->window, clist);
3977 widget->style = gtk_style_attach (widget->style, widget->window);
3979 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
3981 /* column-title window */
3983 attributes.x = clist->column_title_area.x;
3984 attributes.y = clist->column_title_area.y;
3985 attributes.width = clist->column_title_area.width;
3986 attributes.height = clist->column_title_area.height;
3988 clist->title_window = gdk_window_new (widget->window, &attributes,
3990 gdk_window_set_user_data (clist->title_window, clist);
3992 gtk_style_set_background (widget->style, clist->title_window,
3993 GTK_STATE_SELECTED);
3994 gdk_window_show (clist->title_window);
3996 /* set things up so column buttons are drawn in title window */
3997 for (i = 0; i < clist->columns; i++)
3998 if (clist->column[i].button)
3999 gtk_widget_set_parent_window (clist->column[i].button,
4000 clist->title_window);
4003 attributes.x = (clist->internal_allocation.x +
4004 widget->style->klass->xthickness);
4005 attributes.y = (clist->internal_allocation.y +
4006 widget->style->klass->ythickness +
4007 clist->column_title_area.height);
4008 attributes.width = clist->clist_window_width;
4009 attributes.height = clist->clist_window_height;
4011 clist->clist_window = gdk_window_new (widget->window, &attributes,
4013 gdk_window_set_user_data (clist->clist_window, clist);
4015 gdk_window_set_background (clist->clist_window,
4016 &widget->style->bg[GTK_STATE_PRELIGHT]);
4017 gdk_window_show (clist->clist_window);
4018 gdk_window_get_size (clist->clist_window, &clist->clist_window_width,
4019 &clist->clist_window_height);
4021 /* create resize windows */
4022 attributes.wclass = GDK_INPUT_ONLY;
4023 attributes.event_mask = (GDK_BUTTON_PRESS_MASK |
4024 GDK_BUTTON_RELEASE_MASK |
4025 GDK_POINTER_MOTION_MASK |
4026 GDK_POINTER_MOTION_HINT_MASK |
4027 GDK_KEY_PRESS_MASK);
4028 attributes_mask = GDK_WA_CURSOR;
4029 attributes.cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
4030 clist->cursor_drag = attributes.cursor;
4032 attributes.x = LIST_WIDTH (clist) + 1;
4034 attributes.width = 0;
4035 attributes.height = 0;
4037 for (i = 0; i < clist->columns; i++)
4039 clist->column[i].window = gdk_window_new (clist->title_window,
4040 &attributes, attributes_mask);
4041 gdk_window_set_user_data (clist->column[i].window, clist);
4044 /* This is slightly less efficient than creating them with the
4045 * right size to begin with, but easier
4047 size_allocate_title_buttons (clist);
4050 clist->fg_gc = gdk_gc_new (widget->window);
4051 clist->bg_gc = gdk_gc_new (widget->window);
4053 /* We'll use this gc to do scrolling as well */
4054 gdk_gc_set_exposures (clist->fg_gc, TRUE);
4056 values.foreground = widget->style->white;
4057 values.function = GDK_XOR;
4058 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
4059 clist->xor_gc = gdk_gc_new_with_values (widget->window,
4065 /* attach optional row/cell styles, allocate foreground/background colors */
4066 list = clist->row_list;
4067 for (i = 0; i < clist->rows; i++)
4069 clist_row = list->data;
4072 if (clist_row->style)
4073 clist_row->style = gtk_style_attach (clist_row->style,
4074 clist->clist_window);
4076 if (clist_row->fg_set || clist_row->bg_set)
4078 GdkColormap *colormap;
4080 colormap = gtk_widget_get_colormap (widget);
4081 if (clist_row->fg_set)
4082 gdk_color_alloc (colormap, &clist_row->foreground);
4083 if (clist_row->bg_set)
4084 gdk_color_alloc (colormap, &clist_row->background);
4087 for (j = 0; j < clist->columns; j++)
4088 if (clist_row->cell[j].style)
4089 clist_row->cell[j].style =
4090 gtk_style_attach (clist_row->cell[j].style, clist->clist_window);
4095 gtk_clist_unrealize (GtkWidget *widget)
4100 g_return_if_fail (widget != NULL);
4101 g_return_if_fail (GTK_IS_CLIST (widget));
4103 clist = GTK_CLIST (widget);
4105 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
4107 /* detach optional row/cell styles */
4109 if (GTK_WIDGET_REALIZED (widget))
4111 GtkCListRow *clist_row;
4115 list = clist->row_list;
4116 for (i = 0; i < clist->rows; i++)
4118 clist_row = list->data;
4121 if (clist_row->style)
4122 gtk_style_detach (clist_row->style);
4123 for (j = 0; j < clist->columns; j++)
4124 if (clist_row->cell[j].style)
4125 gtk_style_detach (clist_row->cell[j].style);
4129 gdk_cursor_destroy (clist->cursor_drag);
4130 gdk_gc_destroy (clist->xor_gc);
4131 gdk_gc_destroy (clist->fg_gc);
4132 gdk_gc_destroy (clist->bg_gc);
4134 for (i = 0; i < clist->columns; i++)
4135 if (clist->column[i].window)
4137 gdk_window_set_user_data (clist->column[i].window, NULL);
4138 gdk_window_destroy (clist->column[i].window);
4139 clist->column[i].window = NULL;
4142 gdk_window_set_user_data (clist->clist_window, NULL);
4143 gdk_window_destroy (clist->clist_window);
4144 clist->clist_window = NULL;
4146 gdk_window_set_user_data (clist->title_window, NULL);
4147 gdk_window_destroy (clist->title_window);
4148 clist->title_window = NULL;
4150 clist->cursor_drag = NULL;
4151 clist->xor_gc = NULL;
4152 clist->fg_gc = NULL;
4153 clist->bg_gc = NULL;
4155 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
4156 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
4160 gtk_clist_map (GtkWidget *widget)
4165 g_return_if_fail (widget != NULL);
4166 g_return_if_fail (GTK_IS_CLIST (widget));
4168 clist = GTK_CLIST (widget);
4170 if (!GTK_WIDGET_MAPPED (widget))
4172 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
4174 gdk_window_show (widget->window);
4175 gdk_window_show (clist->title_window);
4176 gdk_window_show (clist->clist_window);
4178 /* map column buttons */
4179 for (i = 0; i < clist->columns; i++)
4180 if (clist->column[i].button &&
4181 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
4182 !GTK_WIDGET_MAPPED (clist->column[i].button))
4183 gtk_widget_map (clist->column[i].button);
4185 /* map resize windows AFTER column buttons (above) */
4186 for (i = 0; i < clist->columns; i++)
4187 if (clist->column[i].window && clist->column[i].button)
4188 gdk_window_show (clist->column[i].window);
4190 /* map vscrollbars */
4191 if (GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
4192 !GTK_WIDGET_MAPPED (clist->vscrollbar))
4193 gtk_widget_map (clist->vscrollbar);
4195 if (GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
4196 !GTK_WIDGET_MAPPED (clist->hscrollbar))
4197 gtk_widget_map (clist->hscrollbar);
4199 /* unfreeze the list */
4200 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
4205 gtk_clist_unmap (GtkWidget *widget)
4210 g_return_if_fail (widget != NULL);
4211 g_return_if_fail (GTK_IS_CLIST (widget));
4213 clist = GTK_CLIST (widget);
4215 if (GTK_WIDGET_MAPPED (widget))
4217 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
4219 for (i = 0; i < clist->columns; i++)
4220 if (clist->column[i].window)
4221 gdk_window_hide (clist->column[i].window);
4223 gdk_window_hide (clist->clist_window);
4224 gdk_window_hide (clist->title_window);
4225 gdk_window_hide (widget->window);
4227 /* unmap scrollbars */
4228 if (GTK_WIDGET_MAPPED (clist->vscrollbar))
4229 gtk_widget_unmap (clist->vscrollbar);
4231 if (GTK_WIDGET_MAPPED (clist->hscrollbar))
4232 gtk_widget_unmap (clist->hscrollbar);
4234 /* unmap column buttons */
4235 for (i = 0; i < clist->columns; i++)
4236 if (clist->column[i].button &&
4237 GTK_WIDGET_MAPPED (clist->column[i].button))
4238 gtk_widget_unmap (clist->column[i].button);
4240 /* freeze the list */
4241 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
4246 gtk_clist_draw (GtkWidget *widget,
4251 GdkRectangle child_area;
4254 g_return_if_fail (widget != NULL);
4255 g_return_if_fail (GTK_IS_CLIST (widget));
4256 g_return_if_fail (area != NULL);
4258 if (GTK_WIDGET_DRAWABLE (widget))
4260 clist = GTK_CLIST (widget);
4261 border_width = GTK_CONTAINER (widget)->border_width;
4263 gdk_window_clear_area (widget->window,
4264 area->x - border_width,
4265 area->y - border_width,
4266 area->width, area->height);
4268 /* draw list shadow/border */
4269 gtk_draw_shadow (widget->style, widget->window,
4270 GTK_STATE_NORMAL, clist->shadow_type,
4272 clist->clist_window_width +
4273 (2 * widget->style->klass->xthickness),
4274 clist->clist_window_height +
4275 (2 * widget->style->klass->ythickness) +
4276 clist->column_title_area.height);
4278 gdk_window_clear_area (clist->clist_window, 0, 0, -1, -1);
4279 draw_rows (clist, NULL);
4281 for (i = 0; i < clist->columns; i++)
4283 if (!clist->column[i].visible)
4285 if (gtk_widget_intersect(clist->column[i].button, area, &child_area))
4286 gtk_widget_draw (clist->column[i].button, &child_area);
4292 gtk_clist_expose (GtkWidget *widget,
4293 GdkEventExpose *event)
4297 g_return_val_if_fail (widget != NULL, FALSE);
4298 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4299 g_return_val_if_fail (event != NULL, FALSE);
4301 if (GTK_WIDGET_DRAWABLE (widget))
4303 clist = GTK_CLIST (widget);
4306 if (event->window == widget->window)
4307 gtk_draw_shadow (widget->style, widget->window,
4308 GTK_STATE_NORMAL, clist->shadow_type,
4310 clist->clist_window_width +
4311 (2 * widget->style->klass->xthickness),
4312 clist->clist_window_height +
4313 (2 * widget->style->klass->ythickness) +
4314 clist->column_title_area.height);
4316 /* exposure events on the list */
4317 if (event->window == clist->clist_window)
4318 draw_rows (clist, &event->area);
4325 gtk_clist_style_set (GtkWidget *widget,
4326 GtkStyle *previous_style)
4330 g_return_if_fail (widget != NULL);
4331 g_return_if_fail (GTK_IS_CLIST (widget));
4333 if (GTK_WIDGET_CLASS (parent_class)->style_set)
4334 (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style);
4336 clist = GTK_CLIST (widget);
4338 /* Fill in data after widget has correct style */
4340 /* text properties */
4341 if (!GTK_CLIST_ROW_HEIGHT_SET (clist))
4343 clist->row_height = (widget->style->font->ascent +
4344 widget->style->font->descent + 1);
4345 clist->row_center_offset = widget->style->font->ascent + 1.5;
4348 clist->row_center_offset = 1.5 + (clist->row_height +
4349 widget->style->font->ascent -
4350 widget->style->font->descent - 1) / 2;
4353 if (!GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
4358 for (i = 0; i < clist->columns; i++)
4359 if (clist->column[i].auto_resize)
4361 width = gtk_clist_optimal_column_width (clist, i);
4362 if (width != clist->column[i].width)
4363 gtk_clist_set_column_width (clist, i, width);
4369 gtk_clist_key_press (GtkWidget *widget,
4372 g_return_val_if_fail (widget != NULL, FALSE);
4373 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4374 g_return_val_if_fail (event != NULL, FALSE);
4376 if (GTK_WIDGET_CLASS (parent_class)->key_press_event &&
4377 GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
4380 switch (event->keyval)
4383 case GDK_ISO_Left_Tab:
4384 if (event->state & GDK_SHIFT_MASK)
4385 return gtk_container_focus (GTK_CONTAINER (widget),
4386 GTK_DIR_TAB_BACKWARD);
4388 return gtk_container_focus (GTK_CONTAINER (widget),
4389 GTK_DIR_TAB_FORWARD);
4397 gtk_clist_button_press (GtkWidget *widget,
4398 GdkEventButton *event)
4407 g_return_val_if_fail (widget != NULL, FALSE);
4408 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4409 g_return_val_if_fail (event != NULL, FALSE);
4411 clist = GTK_CLIST (widget);
4413 /* we don't handle button 2 and 3 */
4414 if (event->button != 1)
4417 /* selections on the list */
4418 if (event->window == clist->clist_window)
4423 if (get_selection_info (clist, x, y, &row, &column))
4425 gint old_row = clist->focus_row;
4427 if (clist->focus_row == -1)
4430 if (event->type == GDK_BUTTON_PRESS)
4432 GTK_CLIST_SET_FLAG (clist, CLIST_DRAG_SELECTION);
4433 gdk_pointer_grab (clist->clist_window, FALSE,
4434 GDK_POINTER_MOTION_HINT_MASK |
4435 GDK_BUTTON1_MOTION_MASK |
4436 GDK_BUTTON_RELEASE_MASK,
4437 NULL, NULL, event->time);
4438 gtk_grab_add (widget);
4440 else if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (widget))
4442 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
4443 gtk_grab_remove (widget);
4444 gdk_pointer_ungrab (event->time);
4447 if (GTK_CLIST_ADD_MODE (clist))
4449 GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
4450 if (GTK_WIDGET_HAS_FOCUS (widget))
4452 gtk_clist_draw_focus (widget);
4453 gdk_gc_set_line_attributes (clist->xor_gc, 1,
4454 GDK_LINE_SOLID, 0, 0);
4455 clist->focus_row = row;
4456 gtk_clist_draw_focus (widget);
4460 gdk_gc_set_line_attributes (clist->xor_gc, 1,
4461 GDK_LINE_SOLID, 0, 0);
4462 clist->focus_row = row;
4465 else if (row != clist->focus_row)
4467 if (GTK_WIDGET_HAS_FOCUS (widget))
4469 gtk_clist_draw_focus (widget);
4470 clist->focus_row = row;
4471 gtk_clist_draw_focus (widget);
4474 clist->focus_row = row;
4477 if (!GTK_WIDGET_HAS_FOCUS (widget))
4478 gtk_widget_grab_focus (widget);
4480 switch (clist->selection_mode)
4482 case GTK_SELECTION_SINGLE:
4483 case GTK_SELECTION_MULTIPLE:
4484 if (event->type != GDK_BUTTON_PRESS)
4485 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
4486 row, column, event);
4488 clist->anchor = row;
4490 case GTK_SELECTION_BROWSE:
4491 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
4492 row, column, event);
4494 case GTK_SELECTION_EXTENDED:
4495 if (event->type != GDK_BUTTON_PRESS)
4497 if (clist->anchor != -1)
4499 update_extended_selection (clist, clist->focus_row);
4500 GTK_CLIST_CLASS_FW (clist)->resync_selection
4501 (clist, (GdkEvent *) event);
4503 gtk_signal_emit (GTK_OBJECT (clist),
4504 clist_signals[SELECT_ROW],
4505 row, column, event);
4509 if (event->state & GDK_CONTROL_MASK)
4511 if (event->state & GDK_SHIFT_MASK)
4513 if (clist->anchor < 0)
4515 g_list_free (clist->undo_selection);
4516 g_list_free (clist->undo_unselection);
4517 clist->undo_selection = NULL;
4518 clist->undo_unselection = NULL;
4519 clist->anchor = old_row;
4520 clist->drag_pos = old_row;
4521 clist->undo_anchor = old_row;
4523 update_extended_selection (clist, clist->focus_row);
4527 if (clist->anchor == -1)
4528 set_anchor (clist, TRUE, row, old_row);
4530 update_extended_selection (clist, clist->focus_row);
4535 if (event->state & GDK_SHIFT_MASK)
4537 set_anchor (clist, FALSE, old_row, old_row);
4538 update_extended_selection (clist, clist->focus_row);
4542 if (clist->anchor == -1)
4543 set_anchor (clist, FALSE, row, old_row);
4545 update_extended_selection (clist, clist->focus_row);
4555 /* press on resize windows */
4556 for (i = 0; i < clist->columns; i++)
4557 if (clist->column[i].resizeable && clist->column[i].window &&
4558 event->window == clist->column[i].window)
4560 gdk_pointer_grab (clist->column[i].window, FALSE,
4561 GDK_POINTER_MOTION_HINT_MASK |
4562 GDK_BUTTON1_MOTION_MASK |
4563 GDK_BUTTON_RELEASE_MASK,
4564 NULL, NULL, event->time);
4565 gtk_grab_add (widget);
4566 GTK_CLIST_SET_FLAG (clist, CLIST_IN_DRAG);
4568 if (!GTK_WIDGET_HAS_FOCUS (widget))
4569 gtk_widget_grab_focus (widget);
4571 clist->drag_pos = i;
4572 clist->x_drag = (COLUMN_LEFT_XPIXEL(clist, i) + COLUMN_INSET +
4573 clist->column[i].area.width + CELL_SPACING);
4575 if (GTK_CLIST_ADD_MODE (clist))
4576 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
4577 draw_xor_line (clist);
4585 gtk_clist_button_release (GtkWidget *widget,
4586 GdkEventButton *event)
4590 g_return_val_if_fail (widget != NULL, FALSE);
4591 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4592 g_return_val_if_fail (event != NULL, FALSE);
4594 clist = GTK_CLIST (widget);
4596 /* we don't handle button 2 and 3 */
4597 if (event->button != 1)
4600 /* release on resize windows */
4601 if (GTK_CLIST_IN_DRAG (clist))
4607 i = clist->drag_pos;
4608 clist->drag_pos = -1;
4610 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
4611 gtk_widget_get_pointer (widget, &x, NULL);
4612 gtk_grab_remove (widget);
4613 gdk_pointer_ungrab (event->time);
4615 if (clist->x_drag >= 0)
4616 draw_xor_line (clist);
4618 if (GTK_CLIST_ADD_MODE (clist))
4620 gdk_gc_set_line_attributes (clist->xor_gc, 1,
4621 GDK_LINE_ON_OFF_DASH, 0, 0);
4622 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
4625 width = new_column_width (clist, i, &x);
4626 gtk_clist_set_column_width (clist, i, width);
4630 if (GTK_CLIST_DRAG_SELECTION (clist))
4635 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
4636 gtk_grab_remove (widget);
4637 gdk_pointer_ungrab (event->time);
4640 gtk_timeout_remove (clist->htimer);
4645 gtk_timeout_remove (clist->vtimer);
4648 switch (clist->selection_mode)
4650 case GTK_SELECTION_EXTENDED:
4651 if (!(event->state & GDK_SHIFT_MASK) ||
4652 event->x < 0 || event->x >= clist->clist_window_width ||
4653 event->y < 0 || event->y >= clist->clist_window_height)
4654 GTK_CLIST_CLASS_FW (clist)->resync_selection
4655 (clist, (GdkEvent *) event);
4658 case GTK_SELECTION_SINGLE:
4659 case GTK_SELECTION_MULTIPLE:
4660 if (get_selection_info (clist, event->x, event->y, &row, &column))
4662 if (clist->anchor == clist->focus_row)
4663 toggle_row (clist, row, column, (GdkEvent *) event);
4677 horizontal_timeout (GtkCList *clist)
4680 GdkEventMotion event;
4681 GdkModifierType mask;
4683 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
4686 gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
4693 gtk_clist_motion (GTK_WIDGET (clist), &event);
4699 vertical_timeout (GtkCList *clist)
4702 GdkEventMotion event;
4703 GdkModifierType mask;
4705 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
4708 gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
4715 gtk_clist_motion (GTK_WIDGET (clist), &event);
4721 move_vertical (GtkCList *clist,
4728 adj = GTK_RANGE (clist->vscrollbar)->adjustment;
4730 y = ROW_TOP_YPIXEL (clist, row) - clist->voffset;
4732 y = y - align * (clist->clist_window_height - clist->row_height)
4733 + (2 * align - 1) * CELL_SPACING;
4735 if (y + adj->page_size > adj->upper)
4736 adj->value = adj->upper - adj->page_size;
4740 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
4744 move_horizontal (GtkCList *clist,
4750 adj = GTK_RANGE (clist->hscrollbar)->adjustment;
4754 upper = adj->upper - adj->page_size;
4755 adj->value = MIN (adj->value, upper);
4756 adj->value = MAX (adj->value, 0.0);
4758 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
4762 gtk_clist_motion (GtkWidget *widget,
4763 GdkEventMotion *event)
4771 g_return_val_if_fail (widget != NULL, FALSE);
4772 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4774 clist = GTK_CLIST (widget);
4775 if (!(gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)))
4778 if (GTK_CLIST_IN_DRAG (clist))
4780 if (event->is_hint || event->window != widget->window)
4781 gtk_widget_get_pointer (widget, &x, NULL);
4785 new_width = new_column_width (clist, clist->drag_pos, &x);
4786 if (x != clist->x_drag)
4788 /* x_drag < 0 indicates that the xor line is already invisible */
4789 if (clist->x_drag >= 0)
4790 draw_xor_line (clist);
4794 if (clist->x_drag >= 0)
4795 draw_xor_line (clist);
4798 if (new_width <= MAX (COLUMN_MIN_WIDTH + 1,
4799 clist->column[clist->drag_pos].min_width + 1))
4801 if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) < 0 && x < 0)
4802 gtk_clist_moveto (clist, -1, clist->drag_pos, 0, 0);
4805 if (clist->column[clist->drag_pos].max_width >= COLUMN_MIN_WIDTH &&
4806 new_width >= clist->column[clist->drag_pos].max_width)
4808 if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) + new_width >
4809 clist->clist_window_width && x < 0)
4810 move_horizontal (clist,
4811 COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) +
4812 new_width - clist->clist_window_width +
4813 COLUMN_INSET + CELL_SPACING);
4818 if (event->is_hint || event->window != clist->clist_window)
4819 gdk_window_get_pointer (clist->clist_window, &x, &y, NULL);
4821 /* horizontal autoscrolling */
4822 if (LIST_WIDTH (clist) > clist->clist_window_width &&
4823 (x < 0 || x >= clist->clist_window_width))
4828 clist->htimer = gtk_timeout_add
4829 (SCROLL_TIME, (GtkFunction) horizontal_timeout, clist);
4831 if (!((x < 0 && GTK_RANGE (clist->hscrollbar)->adjustment->value == 0) ||
4832 (x >= clist->clist_window_width &&
4833 GTK_RANGE (clist->hscrollbar)->adjustment->value ==
4834 LIST_WIDTH (clist) - clist->clist_window_width)))
4837 move_horizontal (clist, -1 + (x/2));
4839 move_horizontal (clist, 1 + (x - clist->clist_window_width) / 2);
4843 if (GTK_CLIST_IN_DRAG (clist))
4846 /* vertical autoscrolling */
4847 row = ROW_FROM_YPIXEL (clist, y);
4849 /* don't scroll on last pixel row if it's a cell spacing */
4850 if (y == clist->clist_window_height-1 &&
4851 y == ROW_TOP_YPIXEL (clist, row-1) + clist->row_height)
4854 if (LIST_HEIGHT (clist) > clist->clist_window_height &&
4855 (y < 0 || y >= clist->clist_window_height))
4860 clist->vtimer = gtk_timeout_add (SCROLL_TIME,
4861 (GtkFunction) vertical_timeout, clist);
4863 if (GTK_CLIST_DRAG_SELECTION (clist))
4865 if ((y < 0 && clist->focus_row == 0) ||
4866 (y >= clist->clist_window_height &&
4867 clist->focus_row == clist->rows-1))
4872 row = CLAMP (row, 0, clist->rows - 1);
4874 if (GTK_CLIST_DRAG_SELECTION (clist))
4876 if (row == clist->focus_row)
4879 gtk_clist_draw_focus (widget);
4880 clist->focus_row = row;
4881 gtk_clist_draw_focus (widget);
4883 switch (clist->selection_mode)
4885 case GTK_SELECTION_BROWSE:
4886 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
4887 clist->focus_row, -1, event);
4889 case GTK_SELECTION_EXTENDED:
4890 update_extended_selection (clist, clist->focus_row);
4897 if (ROW_TOP_YPIXEL(clist, row) < 0)
4898 move_vertical (clist, row, 0);
4899 else if (ROW_TOP_YPIXEL(clist, row) + clist->row_height >
4900 clist->clist_window_height)
4901 move_vertical (clist, row, 1);
4907 gtk_clist_size_request (GtkWidget *widget,
4908 GtkRequisition *requisition)
4913 g_return_if_fail (widget != NULL);
4914 g_return_if_fail (GTK_IS_CLIST (widget));
4915 g_return_if_fail (requisition != NULL);
4917 clist = GTK_CLIST (widget);
4919 requisition->width = 0;
4920 requisition->height = 0;
4922 /* compute the size of the column title (title) area */
4923 clist->column_title_area.height = 0;
4924 if (GTK_CLIST_SHOW_TITLES (clist))
4925 for (i = 0; i < clist->columns; i++)
4926 if (clist->column[i].button)
4928 gtk_widget_size_request (clist->column[i].button,
4929 &clist->column[i].button->requisition);
4930 clist->column_title_area.height =
4931 MAX (clist->column_title_area.height,
4932 clist->column[i].button->requisition.height);
4934 requisition->height += clist->column_title_area.height;
4936 /* add the vscrollbar space */
4937 if ((clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
4938 GTK_WIDGET_VISIBLE (clist->vscrollbar))
4940 gtk_widget_size_request (clist->vscrollbar,
4941 &clist->vscrollbar->requisition);
4943 requisition->width += (clist->vscrollbar->requisition.width +
4944 SCROLLBAR_SPACING (clist));
4945 requisition->height = MAX (requisition->height,
4946 clist->vscrollbar->requisition.height);
4949 /* add the hscrollbar space */
4950 if ((clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
4951 GTK_WIDGET_VISIBLE (clist->hscrollbar))
4953 gtk_widget_size_request (clist->hscrollbar,
4954 &clist->hscrollbar->requisition);
4956 requisition->height += (clist->hscrollbar->requisition.height +
4957 SCROLLBAR_SPACING (clist));
4958 requisition->width = MAX (clist->hscrollbar->requisition.width,
4959 requisition->width -
4960 clist->vscrollbar->requisition.width);
4964 requisition->width += (widget->style->klass->xthickness +
4965 GTK_CONTAINER (widget)->border_width) * 2;
4966 requisition->height += (widget->style->klass->ythickness +
4967 GTK_CONTAINER (widget)->border_width) * 2;
4971 gtk_clist_size_allocate (GtkWidget *widget,
4972 GtkAllocation *allocation)
4975 GtkAllocation clist_allocation;
4976 GtkAllocation child_allocation;
4977 gint i, vscrollbar_vis, hscrollbar_vis;
4980 g_return_if_fail (widget != NULL);
4981 g_return_if_fail (GTK_IS_CLIST (widget));
4982 g_return_if_fail (allocation != NULL);
4984 clist = GTK_CLIST (widget);
4985 widget->allocation = *allocation;
4986 border_width = GTK_CONTAINER (widget)->border_width;
4988 if (GTK_WIDGET_REALIZED (widget))
4990 gdk_window_move_resize (widget->window,
4991 allocation->x + border_width,
4992 allocation->y + border_width,
4993 allocation->width - border_width * 2,
4994 allocation->height - border_width * 2);
4997 /* use internal allocation structure for all the math
4998 * because it's easier than always subtracting the container
5000 clist->internal_allocation.x = 0;
5001 clist->internal_allocation.y = 0;
5002 clist->internal_allocation.width = MAX (1, allocation->width -
5004 clist->internal_allocation.height = MAX (1, allocation->height -
5007 /* allocate clist window assuming no scrollbars */
5008 clist_allocation.x = (clist->internal_allocation.x +
5009 widget->style->klass->xthickness);
5010 clist_allocation.y = (clist->internal_allocation.y +
5011 widget->style->klass->ythickness +
5012 clist->column_title_area.height);
5013 clist_allocation.width = MAX (1, clist->internal_allocation.width -
5014 (2 * widget->style->klass->xthickness));
5015 clist_allocation.height = MAX (1, clist->internal_allocation.height -
5016 (2 * widget->style->klass->ythickness) -
5017 clist->column_title_area.height);
5020 * here's where we decide to show/not show the scrollbars
5025 for (i = 0; i <= 1; i++)
5027 if (LIST_HEIGHT (clist) <= clist_allocation.height &&
5028 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
5032 else if (!vscrollbar_vis)
5035 clist_allocation.width = MAX (1, clist_allocation.width -
5036 (clist->vscrollbar->requisition.width +
5037 SCROLLBAR_SPACING (clist)));
5040 if (LIST_WIDTH (clist) <= clist_allocation.width &&
5041 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
5045 else if (!hscrollbar_vis)
5048 clist_allocation.height = MAX (1, clist_allocation.height -
5049 (clist->hscrollbar->requisition.height
5050 + SCROLLBAR_SPACING (clist)));
5054 clist->clist_window_width = clist_allocation.width;
5055 clist->clist_window_height = clist_allocation.height;
5057 if (GTK_WIDGET_REALIZED (widget))
5059 gdk_window_move_resize (clist->clist_window,
5062 clist_allocation.width,
5063 clist_allocation.height);
5066 /* position the window which holds the column title buttons */
5067 clist->column_title_area.x = widget->style->klass->xthickness;
5068 clist->column_title_area.y = widget->style->klass->ythickness;
5069 clist->column_title_area.width = clist_allocation.width;
5071 if (GTK_WIDGET_REALIZED (widget))
5073 gdk_window_move_resize (clist->title_window,
5074 clist->column_title_area.x,
5075 clist->column_title_area.y,
5076 clist->column_title_area.width,
5077 clist->column_title_area.height);
5080 /* column button allocation */
5081 size_allocate_columns (clist);
5082 size_allocate_title_buttons (clist);
5084 adjust_scrollbars (clist);
5086 /* allocate the vscrollbar */
5089 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
5090 gtk_widget_show (clist->vscrollbar);
5092 child_allocation.x = (clist->internal_allocation.x +
5093 clist->internal_allocation.width -
5094 clist->vscrollbar->requisition.width);
5095 child_allocation.y = clist->internal_allocation.y;
5096 child_allocation.width = clist->vscrollbar->requisition.width;
5097 child_allocation.height = MAX (1, clist->internal_allocation.height -
5099 (clist->hscrollbar->requisition.height +
5100 SCROLLBAR_SPACING (clist)) : 0));
5101 gtk_widget_size_allocate (clist->vscrollbar, &child_allocation);
5105 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
5106 gtk_widget_hide (clist->vscrollbar);
5111 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
5112 gtk_widget_show (clist->hscrollbar);
5114 child_allocation.x = clist->internal_allocation.x;
5115 child_allocation.y = (clist->internal_allocation.y +
5116 clist->internal_allocation.height -
5117 clist->hscrollbar->requisition.height);
5118 child_allocation.width = MAX (1, clist->internal_allocation.width -
5120 (clist->vscrollbar->requisition.width +
5121 SCROLLBAR_SPACING (clist)) : 0));
5122 child_allocation.height = clist->hscrollbar->requisition.height;
5124 gtk_widget_size_allocate (clist->hscrollbar, &child_allocation);
5128 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
5129 gtk_widget_hide (clist->hscrollbar);
5132 /* set the vscrollbar adjustments */
5133 adjust_scrollbars (clist);
5140 gtk_clist_forall (GtkContainer *container,
5141 gboolean include_internals,
5142 GtkCallback callback,
5143 gpointer callback_data)
5147 g_return_if_fail (container != NULL);
5148 g_return_if_fail (GTK_IS_CLIST (container));
5149 g_return_if_fail (callback != NULL);
5151 clist = GTK_CLIST (container);
5153 if (include_internals)
5157 /* callback for the column buttons */
5158 for (i = 0; i < clist->columns; i++)
5159 if (clist->column[i].button)
5160 (*callback) (clist->column[i].button, callback_data);
5162 /* callbacks for the scrollbars */
5163 if (clist->vscrollbar)
5164 (*callback) (clist->vscrollbar, callback_data);
5165 if (clist->hscrollbar)
5166 (*callback) (clist->hscrollbar, callback_data);
5170 /* PRIVATE DRAWING FUNCTIONS
5178 get_cell_style (GtkCList *clist,
5179 GtkCListRow *clist_row,
5186 if (clist_row->cell[column].style)
5189 *style = clist_row->cell[column].style;
5191 *fg_gc = clist_row->cell[column].style->fg_gc[state];
5193 *bg_gc = clist_row->cell[column].style->bg_gc[state];
5195 else if (clist_row->style)
5198 *style = clist_row->style;
5200 *fg_gc = clist_row->style->fg_gc[state];
5202 *bg_gc = clist_row->style->bg_gc[state];
5207 *style = GTK_WIDGET (clist)->style;
5209 *fg_gc = GTK_WIDGET (clist)->style->fg_gc[state];
5211 *bg_gc = GTK_WIDGET (clist)->style->bg_gc[state];
5213 if (state != GTK_STATE_SELECTED)
5215 if (fg_gc && clist_row->fg_set)
5216 *fg_gc = clist->fg_gc;
5217 if (bg_gc && clist_row->bg_set)
5218 *bg_gc = clist->bg_gc;
5224 draw_cell_pixmap (GdkWindow *window,
5225 GdkRectangle *clip_rectangle,
5239 gdk_gc_set_clip_mask (fg_gc, mask);
5240 gdk_gc_set_clip_origin (fg_gc, x, y);
5243 if (x < clip_rectangle->x)
5245 xsrc = clip_rectangle->x - x;
5247 x = clip_rectangle->x;
5249 if (x + width > clip_rectangle->x + clip_rectangle->width)
5250 width = clip_rectangle->x + clip_rectangle->width - x;
5252 if (y < clip_rectangle->y)
5254 ysrc = clip_rectangle->y - y;
5256 y = clip_rectangle->y;
5258 if (y + height > clip_rectangle->y + clip_rectangle->height)
5259 height = clip_rectangle->y + clip_rectangle->height - y;
5261 gdk_draw_pixmap (window, fg_gc, pixmap, xsrc, ysrc, x, y, width, height);
5262 gdk_gc_set_clip_origin (fg_gc, 0, 0);
5264 return x + MAX (width, 0);
5268 draw_row (GtkCList *clist,
5271 GtkCListRow *clist_row)
5275 GdkRectangle row_rectangle;
5276 GdkRectangle cell_rectangle;
5277 GdkRectangle clip_rectangle;
5278 GdkRectangle intersect_rectangle;
5282 g_return_if_fail (clist != NULL);
5284 /* bail now if we arn't drawable yet */
5285 if (!GTK_WIDGET_DRAWABLE (clist) || row < 0 || row >= clist->rows)
5288 widget = GTK_WIDGET (clist);
5290 /* if the function is passed the pointer to the row instead of null,
5291 * it avoids this expensive lookup */
5293 clist_row = (g_list_nth (clist->row_list, row))->data;
5295 /* rectangle of the entire row */
5296 row_rectangle.x = 0;
5297 row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
5298 row_rectangle.width = clist->clist_window_width;
5299 row_rectangle.height = clist->row_height;
5301 /* rectangle of the cell spacing above the row */
5302 cell_rectangle.x = 0;
5303 cell_rectangle.y = row_rectangle.y - CELL_SPACING;
5304 cell_rectangle.width = row_rectangle.width;
5305 cell_rectangle.height = CELL_SPACING;
5307 /* rectangle used to clip drawing operations, it's y and height
5308 * positions only need to be set once, so we set them once here.
5309 * the x and width are set withing the drawing loop below once per
5311 clip_rectangle.y = row_rectangle.y;
5312 clip_rectangle.height = row_rectangle.height;
5314 if (clist_row->state == GTK_STATE_NORMAL)
5316 state = GTK_STATE_PRELIGHT;
5317 if (clist_row->fg_set)
5318 gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
5319 if (clist_row->bg_set)
5320 gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
5323 state = clist_row->state;
5325 /* draw the cell borders and background */
5328 rect = &intersect_rectangle;
5329 if (gdk_rectangle_intersect (area, &cell_rectangle,
5330 &intersect_rectangle))
5331 gdk_draw_rectangle (clist->clist_window,
5332 widget->style->base_gc[GTK_STATE_NORMAL],
5334 intersect_rectangle.x,
5335 intersect_rectangle.y,
5336 intersect_rectangle.width,
5337 intersect_rectangle.height);
5339 /* the last row has to clear it's bottom cell spacing too */
5340 if (clist_row == clist->row_list_end->data)
5342 cell_rectangle.y += clist->row_height + CELL_SPACING;
5344 if (gdk_rectangle_intersect (area, &cell_rectangle,
5345 &intersect_rectangle))
5346 gdk_draw_rectangle (clist->clist_window,
5347 widget->style->base_gc[GTK_STATE_NORMAL],
5349 intersect_rectangle.x,
5350 intersect_rectangle.y,
5351 intersect_rectangle.width,
5352 intersect_rectangle.height);
5355 if (!gdk_rectangle_intersect (area, &row_rectangle,&intersect_rectangle))
5361 rect = &clip_rectangle;
5362 gdk_draw_rectangle (clist->clist_window,
5363 widget->style->base_gc[GTK_STATE_NORMAL],
5367 cell_rectangle.width,
5368 cell_rectangle.height);
5370 /* the last row has to clear it's bottom cell spacing too */
5371 if (clist_row == clist->row_list_end->data)
5373 cell_rectangle.y += clist->row_height + CELL_SPACING;
5375 gdk_draw_rectangle (clist->clist_window,
5376 widget->style->base_gc[GTK_STATE_NORMAL],
5380 cell_rectangle.width,
5381 cell_rectangle.height);
5385 /* iterate and draw all the columns (row cells) and draw their contents */
5386 for (i = 0; i < clist->columns; i++)
5396 gint row_center_offset;
5398 if (!clist->column[i].visible)
5401 get_cell_style (clist, clist_row, state, i, &style, &fg_gc, &bg_gc);
5403 clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
5404 clip_rectangle.width = clist->column[i].area.width;
5406 /* calculate clipping region clipping region */
5407 clip_rectangle.x -= COLUMN_INSET + CELL_SPACING;
5408 clip_rectangle.width += (2 * COLUMN_INSET + CELL_SPACING +
5409 (i + 1 == clist->columns) * CELL_SPACING);
5411 if (area && !gdk_rectangle_intersect (area, &clip_rectangle,
5412 &intersect_rectangle))
5415 gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE,
5416 rect->x, rect->y, rect->width, rect->height);
5418 clip_rectangle.x += COLUMN_INSET + CELL_SPACING;
5419 clip_rectangle.width -= (2 * COLUMN_INSET + CELL_SPACING +
5420 (i + 1 == clist->columns) * CELL_SPACING);
5422 /* calculate real width for column justification */
5425 switch (clist_row->cell[i].type)
5428 width = gdk_string_width (style->font,
5429 GTK_CELL_TEXT (clist_row->cell[i])->text);
5431 case GTK_CELL_PIXMAP:
5432 gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
5433 &pixmap_width, &height);
5434 width = pixmap_width;
5436 case GTK_CELL_PIXTEXT:
5437 gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
5438 &pixmap_width, &height);
5439 width = (pixmap_width +
5440 GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing +
5441 gdk_string_width (style->font,
5443 (clist_row->cell[i])->text));
5450 switch (clist->column[i].justification)
5452 case GTK_JUSTIFY_LEFT:
5453 offset = clip_rectangle.x + clist_row->cell[i].horizontal;
5455 case GTK_JUSTIFY_RIGHT:
5456 offset = (clip_rectangle.x + clist_row->cell[i].horizontal +
5457 clip_rectangle.width - width);
5459 case GTK_JUSTIFY_CENTER:
5460 case GTK_JUSTIFY_FILL:
5461 offset = (clip_rectangle.x + clist_row->cell[i].horizontal +
5462 (clip_rectangle.width / 2) - (width / 2));
5466 /* Draw Text and/or Pixmap */
5467 switch (clist_row->cell[i].type)
5469 case GTK_CELL_PIXMAP:
5470 draw_cell_pixmap (clist->clist_window, &clip_rectangle, fg_gc,
5471 GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
5472 GTK_CELL_PIXMAP (clist_row->cell[i])->mask,
5474 clip_rectangle.y + clist_row->cell[i].vertical +
5475 (clip_rectangle.height - height) / 2,
5476 pixmap_width, height);
5478 case GTK_CELL_PIXTEXT:
5480 draw_cell_pixmap (clist->clist_window, &clip_rectangle, fg_gc,
5481 GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
5482 GTK_CELL_PIXTEXT (clist_row->cell[i])->mask,
5484 clip_rectangle.y + clist_row->cell[i].vertical+
5485 (clip_rectangle.height - height) / 2,
5486 pixmap_width, height);
5487 offset += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
5489 if (style != GTK_WIDGET (clist)->style)
5490 row_center_offset = (((clist->row_height - style->font->ascent -
5491 style->font->descent - 1) / 2) + 1.5 +
5492 style->font->ascent);
5494 row_center_offset = clist->row_center_offset;
5496 gdk_gc_set_clip_rectangle (fg_gc, &clip_rectangle);
5497 gdk_draw_string (clist->clist_window, style->font, fg_gc,
5499 row_rectangle.y + row_center_offset +
5500 clist_row->cell[i].vertical,
5501 (clist_row->cell[i].type == GTK_CELL_PIXTEXT) ?
5502 GTK_CELL_PIXTEXT (clist_row->cell[i])->text :
5503 GTK_CELL_TEXT (clist_row->cell[i])->text);
5504 gdk_gc_set_clip_rectangle (fg_gc, NULL);
5511 /* draw focus rectangle */
5512 if (clist->focus_row == row && GTK_WIDGET_HAS_FOCUS (widget))
5515 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
5516 row_rectangle.x, row_rectangle.y,
5517 row_rectangle.width - 1, row_rectangle.height - 1);
5518 else if (gdk_rectangle_intersect (area, &row_rectangle,
5519 &intersect_rectangle))
5521 gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle);
5522 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
5523 row_rectangle.x, row_rectangle.y,
5524 row_rectangle.width - 1,
5525 row_rectangle.height - 1);
5526 gdk_gc_set_clip_rectangle (clist->xor_gc, NULL);
5532 draw_rows (GtkCList *clist,
5536 GtkCListRow *clist_row;
5541 g_return_if_fail (clist != NULL);
5542 g_return_if_fail (GTK_IS_CLIST (clist));
5544 if (clist->row_height == 0 ||
5545 !GTK_WIDGET_DRAWABLE (clist))
5550 first_row = ROW_FROM_YPIXEL (clist, area->y);
5551 last_row = ROW_FROM_YPIXEL (clist, area->y + area->height);
5555 first_row = ROW_FROM_YPIXEL (clist, 0);
5556 last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height);
5559 /* this is a small special case which exposes the bottom cell line
5560 * on the last row -- it might go away if I change the wall the cell
5561 * spacings are drawn
5563 if (clist->rows == first_row)
5566 list = g_list_nth (clist->row_list, first_row);
5570 clist_row = list->data;
5576 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, area, i, clist_row);
5581 gdk_window_clear_area (clist->clist_window,
5582 0, ROW_TOP_YPIXEL (clist, i), -1, -1);
5586 draw_xor_line (GtkCList *clist)
5590 g_return_if_fail (clist != NULL);
5592 widget = GTK_WIDGET (clist);
5594 gdk_draw_line (widget->window, clist->xor_gc,
5596 widget->style->klass->ythickness,
5598 clist->column_title_area.height +
5599 clist->clist_window_height + 1);
5602 /* get cell from coordinates
5603 * get_selection_info
5604 * gtk_clist_get_selection_info
5607 get_selection_info (GtkCList *clist,
5615 g_return_val_if_fail (clist != NULL, 0);
5616 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
5618 /* bounds checking, return false if the user clicked
5619 * on a blank area */
5620 trow = ROW_FROM_YPIXEL (clist, y);
5621 if (trow >= clist->rows)
5627 tcol = COLUMN_FROM_XPIXEL (clist, x);
5628 if (tcol >= clist->columns)
5638 gtk_clist_get_selection_info (GtkCList *clist,
5644 g_return_val_if_fail (clist != NULL, 0);
5645 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
5646 return get_selection_info (clist, x, y, row, column);
5655 * vadjustment_changed
5656 * hadjustment_changed
5657 * vadjustment_value_changed
5658 * hadjustment_value_changed
5662 create_scrollbars (GtkCList *clist)
5664 GtkAdjustment *adjustment;
5666 clist->vscrollbar = gtk_vscrollbar_new (NULL);
5668 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
5670 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
5671 (GtkSignalFunc) vadjustment_changed,
5674 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
5675 (GtkSignalFunc) vadjustment_value_changed,
5678 gtk_widget_set_parent (clist->vscrollbar, GTK_WIDGET (clist));
5679 gtk_widget_show (clist->vscrollbar);
5681 clist->hscrollbar = gtk_hscrollbar_new (NULL);
5683 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
5685 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
5686 (GtkSignalFunc) hadjustment_changed,
5689 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
5690 (GtkSignalFunc) hadjustment_value_changed,
5693 gtk_widget_set_parent (clist->hscrollbar, GTK_WIDGET (clist));
5694 gtk_widget_show (clist->hscrollbar);
5698 adjust_scrollbars (GtkCList * clist)
5700 GtkRange *vscrollbar;
5701 GtkRange *hscrollbar;
5703 vscrollbar = GTK_RANGE (clist->vscrollbar);
5704 vscrollbar->adjustment->page_size = clist->clist_window_height;
5705 vscrollbar->adjustment->page_increment = clist->clist_window_height / 2;
5706 vscrollbar->adjustment->step_increment = 10;
5707 vscrollbar->adjustment->lower = 0;
5708 vscrollbar->adjustment->upper = LIST_HEIGHT (clist);
5710 if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist))
5712 vscrollbar->adjustment->value = MAX (0, LIST_HEIGHT (clist) -
5713 clist->clist_window_height);
5714 gtk_signal_emit_by_name (GTK_OBJECT (vscrollbar->adjustment),
5718 hscrollbar = GTK_RANGE (clist->hscrollbar);
5719 hscrollbar->adjustment->page_size = clist->clist_window_width;
5720 hscrollbar->adjustment->page_increment = clist->clist_window_width / 2;
5721 hscrollbar->adjustment->step_increment = 10;
5722 hscrollbar->adjustment->lower = 0;
5723 hscrollbar->adjustment->upper = LIST_WIDTH (clist);
5725 if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist))
5727 hscrollbar->adjustment->value = MAX (0, LIST_WIDTH (clist) -
5728 clist->clist_window_width);
5729 gtk_signal_emit_by_name (GTK_OBJECT (hscrollbar->adjustment),
5733 if (LIST_HEIGHT (clist) <= clist->clist_window_height &&
5734 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
5736 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
5738 gtk_widget_hide (clist->vscrollbar);
5739 gtk_widget_size_allocate (GTK_WIDGET (clist),
5740 >K_WIDGET (clist)->allocation);
5745 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
5747 gtk_widget_show (clist->vscrollbar);
5748 gtk_widget_size_allocate (GTK_WIDGET (clist),
5749 >K_WIDGET (clist)->allocation);
5753 if (LIST_WIDTH (clist) <= clist->clist_window_width &&
5754 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
5756 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
5758 gtk_widget_hide (clist->hscrollbar);
5759 gtk_widget_size_allocate (GTK_WIDGET (clist),
5760 >K_WIDGET (clist)->allocation);
5765 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
5767 gtk_widget_show (clist->hscrollbar);
5768 gtk_widget_size_allocate (GTK_WIDGET (clist),
5769 >K_WIDGET (clist)->allocation);
5773 gtk_signal_emit_by_name (GTK_OBJECT (vscrollbar->adjustment), "changed");
5774 gtk_signal_emit_by_name (GTK_OBJECT (hscrollbar->adjustment), "changed");
5778 vadjustment_changed (GtkAdjustment *adjustment,
5783 g_return_if_fail (adjustment != NULL);
5784 g_return_if_fail (data != NULL);
5786 clist = GTK_CLIST (data);
5790 hadjustment_changed (GtkAdjustment *adjustment,
5795 g_return_if_fail (adjustment != NULL);
5796 g_return_if_fail (data != NULL);
5798 clist = GTK_CLIST (data);
5802 vadjustment_value_changed (GtkAdjustment *adjustment,
5809 g_return_if_fail (adjustment != NULL);
5810 g_return_if_fail (data != NULL);
5811 g_return_if_fail (GTK_IS_CLIST (data));
5813 clist = GTK_CLIST (data);
5815 if (!GTK_WIDGET_DRAWABLE (clist))
5818 value = adjustment->value;
5820 if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)))
5822 if (value > -clist->voffset)
5825 diff = value + clist->voffset;
5827 /* we have to re-draw the whole screen here... */
5828 if (diff >= clist->clist_window_height)
5830 clist->voffset = -value;
5831 draw_rows (clist, NULL);
5835 if ((diff != 0) && (diff != clist->clist_window_height))
5836 gdk_window_copy_area (clist->clist_window,
5839 clist->clist_window,
5842 clist->clist_window_width,
5843 clist->clist_window_height - diff);
5846 area.y = clist->clist_window_height - diff;
5847 area.width = clist->clist_window_width;
5853 diff = -clist->voffset - value;
5855 /* we have to re-draw the whole screen here... */
5856 if (diff >= clist->clist_window_height)
5858 clist->voffset = -value;
5859 draw_rows (clist, NULL);
5863 if ((diff != 0) && (diff != clist->clist_window_height))
5864 gdk_window_copy_area (clist->clist_window,
5867 clist->clist_window,
5870 clist->clist_window_width,
5871 clist->clist_window_height - diff);
5875 area.width = clist->clist_window_width;
5880 clist->voffset = -value;
5881 if ((diff != 0) && (diff != clist->clist_window_height))
5882 check_exposures (clist);
5885 draw_rows (clist, &area);
5889 hadjustment_value_changed (GtkAdjustment *adjustment,
5899 g_return_if_fail (adjustment != NULL);
5900 g_return_if_fail (data != NULL);
5901 g_return_if_fail (GTK_IS_CLIST (data));
5903 clist = GTK_CLIST (data);
5905 if (!GTK_WIDGET_DRAWABLE (clist) ||
5906 adjustment != gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)))
5909 value = adjustment->value;
5911 /* move the column buttons and resize windows */
5912 for (i = 0; i < clist->columns; i++)
5914 if (clist->column[i].button)
5916 clist->column[i].button->allocation.x -= value + clist->hoffset;
5918 if (clist->column[i].button->window)
5920 gdk_window_move (clist->column[i].button->window,
5921 clist->column[i].button->allocation.x,
5922 clist->column[i].button->allocation.y);
5924 if (clist->column[i].window)
5925 gdk_window_move (clist->column[i].window,
5926 clist->column[i].button->allocation.x +
5927 clist->column[i].button->allocation.width -
5928 (DRAG_WIDTH / 2), 0);
5933 if (value > -clist->hoffset)
5936 diff = value + clist->hoffset;
5938 clist->hoffset = -value;
5940 /* we have to re-draw the whole screen here... */
5941 if (diff >= clist->clist_window_width)
5943 draw_rows (clist, NULL);
5947 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5948 GTK_CLIST_ADD_MODE (clist))
5950 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
5952 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
5953 clist->clist_window_width - 1,
5954 clist->row_height - 1);
5956 gdk_window_copy_area (clist->clist_window,
5959 clist->clist_window,
5962 clist->clist_window_width - diff,
5963 clist->clist_window_height);
5965 area.x = clist->clist_window_width - diff;
5970 if (!(diff = -clist->hoffset - value))
5973 clist->hoffset = -value;
5975 /* we have to re-draw the whole screen here... */
5976 if (diff >= clist->clist_window_width)
5978 draw_rows (clist, NULL);
5982 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5983 GTK_CLIST_ADD_MODE (clist))
5985 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
5987 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
5988 clist->clist_window_width - 1,
5989 clist->row_height - 1);
5992 gdk_window_copy_area (clist->clist_window,
5995 clist->clist_window,
5998 clist->clist_window_width - diff,
5999 clist->clist_window_height);
6006 area.height = clist->clist_window_height;
6008 check_exposures (clist);
6010 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist))
6012 if (GTK_CLIST_ADD_MODE (clist))
6016 focus_row = clist->focus_row;
6017 clist->focus_row = -1;
6018 draw_rows (clist, &area);
6019 clist->focus_row = focus_row;
6021 gdk_draw_rectangle (clist->clist_window, clist->xor_gc,
6022 FALSE, 0, y, clist->clist_window_width - 1,
6023 clist->row_height - 1);
6033 x0 = clist->clist_window_width - 1;
6042 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
6043 gdk_draw_line (clist->clist_window, clist->xor_gc,
6044 x0, y + 1, x0, y + clist->row_height - 2);
6045 gdk_draw_line (clist->clist_window, clist->xor_gc,
6046 x1, y + 1, x1, y + clist->row_height - 2);
6050 draw_rows (clist, &area);
6054 check_exposures (GtkCList *clist)
6058 if (!GTK_WIDGET_REALIZED (clist))
6061 /* Make sure graphics expose events are processed before scrolling
6063 while ((event = gdk_event_get_graphics_expose (clist->clist_window)) != NULL)
6065 gtk_widget_event (GTK_WIDGET (clist), event);
6066 if (event->expose.count == 0)
6068 gdk_event_free (event);
6071 gdk_event_free (event);
6076 * Memory Allocation/Distruction Routines for GtkCList stuctures
6085 static GtkCListColumn *
6086 columns_new (GtkCList *clist)
6088 GtkCListColumn *column;
6091 column = g_new (GtkCListColumn, clist->columns);
6093 for (i = 0; i < clist->columns; i++)
6095 column[i].area.x = 0;
6096 column[i].area.y = 0;
6097 column[i].area.width = 0;
6098 column[i].area.height = 0;
6099 column[i].title = NULL;
6100 column[i].button = NULL;
6101 column[i].window = NULL;
6102 column[i].width = 0;
6103 column[i].min_width = -1;
6104 column[i].max_width = -1;
6105 column[i].visible = TRUE;
6106 column[i].width_set = FALSE;
6107 column[i].resizeable = TRUE;
6108 column[i].auto_resize = FALSE;
6109 column[i].justification = GTK_JUSTIFY_LEFT;
6116 column_title_new (GtkCList *clist,
6120 if (clist->column[column].title)
6121 g_free (clist->column[column].title);
6123 clist->column[column].title = g_strdup (title);
6127 columns_delete (GtkCList *clist)
6131 for (i = 0; i < clist->columns; i++)
6132 if (clist->column[i].title)
6133 g_free (clist->column[i].title);
6135 g_free (clist->column);
6138 static GtkCListRow *
6139 row_new (GtkCList *clist)
6142 GtkCListRow *clist_row;
6144 clist_row = g_chunk_new (GtkCListRow, clist->row_mem_chunk);
6145 clist_row->cell = g_chunk_new (GtkCell, clist->cell_mem_chunk);
6147 for (i = 0; i < clist->columns; i++)
6149 clist_row->cell[i].type = GTK_CELL_EMPTY;
6150 clist_row->cell[i].vertical = 0;
6151 clist_row->cell[i].horizontal = 0;
6152 clist_row->cell[i].style = NULL;
6155 clist_row->fg_set = FALSE;
6156 clist_row->bg_set = FALSE;
6157 clist_row->style = NULL;
6158 clist_row->selectable = TRUE;
6159 clist_row->state = GTK_STATE_NORMAL;
6160 clist_row->data = NULL;
6161 clist_row->destroy = NULL;
6167 row_delete (GtkCList *clist,
6168 GtkCListRow *clist_row)
6172 for (i = 0; i < clist->columns; i++)
6174 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
6175 (clist, clist_row, i, GTK_CELL_EMPTY, NULL, 0, NULL, NULL);
6176 if (clist_row->cell[i].style)
6178 if (GTK_WIDGET_REALIZED (clist))
6179 gtk_style_detach (clist_row->cell[i].style);
6180 gtk_style_unref (clist_row->cell[i].style);
6184 if (clist_row->style)
6186 if (GTK_WIDGET_REALIZED (clist))
6187 gtk_style_detach (clist_row->style);
6188 gtk_style_unref (clist_row->style);
6191 if (clist_row->destroy)
6192 clist_row->destroy (clist_row->data);
6194 g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell);
6195 g_mem_chunk_free (clist->row_mem_chunk, clist_row);
6200 * gtk_clist_draw_focus
6201 * gtk_clist_focus_in
6202 * gtk_clist_focus_out
6203 * gtk_clist_set_focus_child
6207 gtk_clist_focus (GtkContainer *container,
6208 GtkDirectionType direction)
6211 GtkWidget *focus_child;
6214 g_return_val_if_fail (container != NULL, FALSE);
6215 g_return_val_if_fail (GTK_IS_CLIST (container), FALSE);
6217 if (!GTK_WIDGET_SENSITIVE (container))
6220 clist = GTK_CLIST (container);
6221 focus_child = container->focus_child;
6222 old_row = clist->focus_row;
6228 if (GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
6229 (!focus_child || (focus_child && focus_child != clist->vscrollbar &&
6230 focus_child != clist->hscrollbar)))
6232 if (title_focus (clist, direction))
6234 gtk_container_set_focus_child (container, NULL);
6237 gtk_widget_grab_focus (GTK_WIDGET (container));
6240 case GTK_DIR_TAB_FORWARD:
6241 if (GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
6242 (!focus_child || (focus_child != clist->vscrollbar &&
6243 focus_child != clist->hscrollbar)))
6245 gboolean tf = FALSE;
6247 if (((focus_child && direction == GTK_DIR_DOWN) ||
6248 !(tf = title_focus (clist, GTK_DIR_TAB_FORWARD)))
6251 if (clist->focus_row < 0)
6253 clist->focus_row = 0;
6255 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
6256 clist->selection_mode == GTK_SELECTION_EXTENDED) &&
6258 gtk_signal_emit (GTK_OBJECT (clist),
6259 clist_signals[SELECT_ROW],
6260 clist->focus_row, -1, NULL);
6262 gtk_widget_grab_focus (GTK_WIDGET (container));
6270 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
6272 if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child ||
6273 (focus_child != clist->vscrollbar &&
6274 focus_child != clist->hscrollbar)) &&
6275 GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
6276 GTK_WIDGET_CAN_FOCUS (clist->vscrollbar))
6278 gtk_widget_grab_focus (clist->vscrollbar);
6282 if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child ||
6283 focus_child != clist->hscrollbar) &&
6284 GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
6285 GTK_WIDGET_CAN_FOCUS (clist->hscrollbar))
6287 gtk_widget_grab_focus (clist->hscrollbar);
6292 case GTK_DIR_TAB_BACKWARD:
6293 if (!focus_child && GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
6294 GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
6295 GTK_WIDGET_CAN_FOCUS (clist->hscrollbar))
6297 gtk_widget_grab_focus (clist->hscrollbar);
6301 if ((!focus_child || focus_child == clist->hscrollbar) &&
6302 GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
6303 GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
6304 GTK_WIDGET_CAN_FOCUS (clist->vscrollbar))
6306 gtk_widget_grab_focus (clist->vscrollbar);
6310 if ((!focus_child || focus_child == clist->hscrollbar ||
6311 focus_child == clist->vscrollbar) &&
6312 GTK_CLIST_CHILD_HAS_FOCUS (clist) && clist->rows)
6314 if (clist->focus_row < 0)
6316 clist->focus_row = 0;
6317 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
6318 clist->selection_mode == GTK_SELECTION_EXTENDED) &&
6320 gtk_signal_emit (GTK_OBJECT (clist),
6321 clist_signals[SELECT_ROW],
6322 clist->focus_row, -1, NULL);
6324 gtk_widget_grab_focus (GTK_WIDGET (container));
6328 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
6330 if (title_focus (clist, direction))
6338 gtk_container_set_focus_child (container, NULL);
6343 gtk_clist_draw_focus (GtkWidget *widget)
6347 g_return_if_fail (widget != NULL);
6348 g_return_if_fail (GTK_IS_CLIST (widget));
6350 if (!GTK_WIDGET_DRAWABLE (widget))
6353 clist = GTK_CLIST (widget);
6354 if (clist->focus_row >= 0)
6355 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
6356 0, ROW_TOP_YPIXEL(clist, clist->focus_row),
6357 clist->clist_window_width - 1,
6358 clist->row_height - 1);
6362 gtk_clist_focus_in (GtkWidget *widget,
6363 GdkEventFocus *event)
6367 g_return_val_if_fail (widget != NULL, FALSE);
6368 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
6369 g_return_val_if_fail (event != NULL, FALSE);
6371 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
6372 GTK_CLIST_UNSET_FLAG (widget, CLIST_CHILD_HAS_FOCUS);
6374 clist = GTK_CLIST (widget);
6376 if (clist->selection_mode == GTK_SELECTION_BROWSE &&
6377 clist->selection == NULL && clist->focus_row > -1)
6381 list = g_list_nth (clist->row_list, clist->focus_row);
6382 if (list && GTK_CLIST_ROW (list)->selectable)
6383 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
6384 clist->focus_row, -1, event);
6386 gtk_widget_draw_focus (widget);
6389 gtk_widget_draw_focus (widget);
6395 gtk_clist_focus_out (GtkWidget *widget,
6396 GdkEventFocus *event)
6400 g_return_val_if_fail (widget != NULL, FALSE);
6401 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
6402 g_return_val_if_fail (event != NULL, FALSE);
6404 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
6405 gtk_widget_draw_focus (widget);
6407 clist = GTK_CLIST (widget);
6409 if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
6410 GTK_CLIST_CLASS_FW (widget)->resync_selection (clist, (GdkEvent *) event);
6416 gtk_clist_set_focus_child (GtkContainer *container,
6419 g_return_if_fail (container != NULL);
6420 g_return_if_fail (GTK_IS_CLIST (container));
6424 g_return_if_fail (GTK_IS_WIDGET (child));
6425 GTK_CLIST_SET_FLAG (GTK_CLIST (container), CLIST_CHILD_HAS_FOCUS);
6428 parent_class->set_focus_child (container, child);
6432 title_focus (GtkCList *clist,
6435 GtkWidget *focus_child;
6436 gboolean return_val = FALSE;
6441 if (!GTK_CLIST_SHOW_TITLES (clist))
6444 focus_child = GTK_CONTAINER (clist)->focus_child;
6448 case GTK_DIR_TAB_BACKWARD:
6450 if (!focus_child || focus_child == clist->hscrollbar ||
6451 focus_child == clist->hscrollbar ||
6452 !GTK_CLIST_CHILD_HAS_FOCUS (clist))
6454 if (dir == GTK_DIR_UP)
6455 i = COLUMN_FROM_XPIXEL (clist, 0);
6457 i = clist->columns - 1;
6458 focus_child = clist->column[i].button;
6459 dir = GTK_DIR_TAB_FORWARD;
6466 if (!focus_child || focus_child == clist->hscrollbar ||
6467 focus_child == clist->hscrollbar)
6469 i = clist->columns - 1;
6470 focus_child = clist->column[i].button;
6474 if (!focus_child || focus_child == clist->hscrollbar ||
6475 focus_child == clist->hscrollbar)
6478 focus_child = clist->column[i].button;
6484 while (i < clist->columns)
6486 if (clist->column[i].button == focus_child)
6488 if (clist->column[i].button &&
6489 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
6490 GTK_IS_CONTAINER (clist->column[i].button) &&
6491 !GTK_WIDGET_HAS_FOCUS (clist->column[i].button))
6492 if (gtk_container_focus
6493 (GTK_CONTAINER (clist->column[i].button), dir))
6498 if (!return_val && dir == GTK_DIR_UP)
6509 while (j >= 0 && j < clist->columns)
6511 if (clist->column[j].button &&
6512 GTK_WIDGET_VISIBLE (clist->column[j].button))
6514 if (GTK_IS_CONTAINER (clist->column[j].button) &&
6516 (GTK_CONTAINER (clist->column[j].button), dir))
6521 else if (GTK_WIDGET_CAN_FOCUS (clist->column[j].button))
6523 gtk_widget_grab_focus (clist->column[j].button);
6533 if (COLUMN_LEFT_XPIXEL (clist, j) < CELL_SPACING + COLUMN_INSET)
6534 gtk_clist_moveto (clist, -1, j, 0, 0);
6535 else if (COLUMN_LEFT_XPIXEL(clist, j) + clist->column[j].area.width >
6536 clist->clist_window_width)
6538 if (j == clist->columns-1)
6539 gtk_clist_moveto (clist, -1, j, 0, 0);
6541 gtk_clist_moveto (clist, -1, j, 0, 1);
6547 /* SCROLLING FUNCTIONS
6553 move_focus_row (GtkCList *clist,
6554 GtkScrollType scroll_type,
6559 g_return_if_fail (clist != 0);
6560 g_return_if_fail (GTK_IS_CLIST (clist));
6562 widget = GTK_WIDGET (clist);
6564 switch (scroll_type)
6566 case GTK_SCROLL_STEP_BACKWARD:
6567 if (clist->focus_row <= 0)
6569 gtk_clist_draw_focus (widget);
6571 gtk_clist_draw_focus (widget);
6573 case GTK_SCROLL_STEP_FORWARD:
6574 if (clist->focus_row >= clist->rows - 1)
6576 gtk_clist_draw_focus (widget);
6578 gtk_clist_draw_focus (widget);
6580 case GTK_SCROLL_PAGE_BACKWARD:
6581 if (clist->focus_row <= 0)
6583 gtk_clist_draw_focus (widget);
6584 clist->focus_row = MAX (0, clist->focus_row -
6585 (2 * clist->clist_window_height -
6586 clist->row_height - CELL_SPACING) /
6587 (2 * (clist->row_height + CELL_SPACING)));
6588 gtk_clist_draw_focus (widget);
6590 case GTK_SCROLL_PAGE_FORWARD:
6591 if (clist->focus_row >= clist->rows - 1)
6593 gtk_clist_draw_focus (widget);
6594 clist->focus_row = MIN (clist->rows - 1, clist->focus_row +
6595 (2 * clist->clist_window_height -
6596 clist->row_height - CELL_SPACING) /
6597 (2 * (clist->row_height + CELL_SPACING)));
6598 gtk_clist_draw_focus (widget);
6600 case GTK_SCROLL_JUMP:
6601 if (position >= 0 && position <= 1)
6603 gtk_clist_draw_focus (widget);
6604 clist->focus_row = position * (clist->rows - 1);
6605 gtk_clist_draw_focus (widget);
6614 scroll_horizontal (GtkCList *clist,
6615 GtkScrollType scroll_type,
6620 g_return_if_fail (clist != 0);
6621 g_return_if_fail (GTK_IS_CLIST (clist));
6623 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
6626 switch (scroll_type)
6628 case GTK_SCROLL_STEP_BACKWARD:
6629 column = COLUMN_FROM_XPIXEL (clist, 0);
6630 if (COLUMN_LEFT_XPIXEL (clist, column) - CELL_SPACING - COLUMN_INSET >= 0
6634 case GTK_SCROLL_STEP_FORWARD:
6635 column = COLUMN_FROM_XPIXEL (clist, clist->clist_window_width);
6638 if (COLUMN_LEFT_XPIXEL (clist, column) + clist->column[column].area.width
6639 + CELL_SPACING + COLUMN_INSET - 1 <= clist->clist_window_width &&
6640 column < clist->columns - 1)
6643 case GTK_SCROLL_PAGE_BACKWARD:
6644 case GTK_SCROLL_PAGE_FORWARD:
6646 case GTK_SCROLL_JUMP:
6647 if (position >= 0 && position <= 1)
6648 column = position * (clist->columns - 1);
6656 if (COLUMN_LEFT_XPIXEL (clist, column) < CELL_SPACING + COLUMN_INSET)
6657 gtk_clist_moveto (clist, -1, column, 0, 0);
6658 else if (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET - 1
6659 + clist->column[column].area.width > clist->clist_window_width)
6661 if (column == clist->columns - 1)
6662 gtk_clist_moveto (clist, -1, column, 0, 0);
6664 gtk_clist_moveto (clist, -1, column, 0, 1);
6669 scroll_vertical (GtkCList *clist,
6670 GtkScrollType scroll_type,
6675 g_return_if_fail (clist != NULL);
6676 g_return_if_fail (GTK_IS_CLIST (clist));
6678 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
6681 switch (clist->selection_mode)
6683 case GTK_SELECTION_EXTENDED:
6684 if (clist->anchor >= 0)
6686 case GTK_SELECTION_BROWSE:
6688 old_focus_row = clist->focus_row;
6689 move_focus_row (clist, scroll_type, position);
6691 if (old_focus_row != clist->focus_row)
6693 if (clist->selection_mode == GTK_SELECTION_BROWSE)
6694 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
6695 old_focus_row, -1, NULL);
6696 else if (!GTK_CLIST_ADD_MODE (clist))
6698 gtk_clist_unselect_all (clist);
6699 clist->undo_anchor = old_focus_row;
6703 switch (gtk_clist_row_is_visible (clist, clist->focus_row))
6705 case GTK_VISIBILITY_NONE:
6706 if (old_focus_row != clist->focus_row &&
6707 !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
6708 GTK_CLIST_ADD_MODE (clist)))
6709 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
6710 clist->focus_row, -1, NULL);
6711 switch (scroll_type)
6713 case GTK_SCROLL_STEP_BACKWARD:
6714 case GTK_SCROLL_PAGE_BACKWARD:
6715 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
6717 case GTK_SCROLL_STEP_FORWARD:
6718 case GTK_SCROLL_PAGE_FORWARD:
6719 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
6721 case GTK_SCROLL_JUMP:
6722 gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
6728 case GTK_VISIBILITY_PARTIAL:
6729 switch (scroll_type)
6731 case GTK_SCROLL_STEP_BACKWARD:
6732 case GTK_SCROLL_PAGE_BACKWARD:
6733 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
6735 case GTK_SCROLL_STEP_FORWARD:
6736 case GTK_SCROLL_PAGE_FORWARD:
6737 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
6739 case GTK_SCROLL_JUMP:
6740 gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
6746 if (old_focus_row != clist->focus_row &&
6747 !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
6748 GTK_CLIST_ADD_MODE (clist)))
6749 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
6750 clist->focus_row, -1, NULL);
6755 move_focus_row (clist, scroll_type, position);
6757 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
6758 clist->clist_window_height)
6759 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
6760 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
6761 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
6766 /* PUBLIC SORTING FUNCTIONS
6768 * gtk_clist_set_compare_func
6769 * gtk_clist_set_auto_sort
6770 * gtk_clist_set_sort_type
6771 * gtk_clist_set_sort_column
6774 gtk_clist_sort (GtkCList *clist)
6776 g_return_if_fail (clist != NULL);
6777 g_return_if_fail (GTK_IS_CLIST (clist));
6779 GTK_CLIST_CLASS_FW (clist)->sort_list (clist);
6783 gtk_clist_set_compare_func (GtkCList *clist,
6784 GtkCListCompareFunc cmp_func)
6786 g_return_if_fail (clist != NULL);
6787 g_return_if_fail (GTK_IS_CLIST (clist));
6789 clist->compare = (cmp_func) ? cmp_func : default_compare;
6793 gtk_clist_set_auto_sort (GtkCList *clist,
6796 g_return_if_fail (clist != NULL);
6797 g_return_if_fail (GTK_IS_CLIST (clist));
6799 if (GTK_CLIST_AUTO_SORT (clist) && !auto_sort)
6800 GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_SORT);
6801 else if (!GTK_CLIST_AUTO_SORT (clist) && auto_sort)
6803 GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_SORT);
6804 gtk_clist_sort (clist);
6809 gtk_clist_set_sort_type (GtkCList *clist,
6810 GtkSortType sort_type)
6812 g_return_if_fail (clist != NULL);
6813 g_return_if_fail (GTK_IS_CLIST (clist));
6815 clist->sort_type = sort_type;
6819 gtk_clist_set_sort_column (GtkCList *clist,
6822 g_return_if_fail (clist != NULL);
6823 g_return_if_fail (GTK_IS_CLIST (clist));
6825 if (column < 0 || column >= clist->columns)
6828 clist->sort_column = column;
6831 /* PRIVATE SORTING FUNCTIONS
6835 * gtk_clist_mergesort
6838 default_compare (GtkCList *clist,
6845 GtkCListRow *row1 = (GtkCListRow *) ptr1;
6846 GtkCListRow *row2 = (GtkCListRow *) ptr2;
6848 switch (row1->cell[clist->sort_column].type)
6851 text1 = GTK_CELL_TEXT (row1->cell[clist->sort_column])->text;
6853 case GTK_CELL_PIXTEXT:
6854 text1 = GTK_CELL_PIXTEXT (row1->cell[clist->sort_column])->text;
6860 switch (row2->cell[clist->sort_column].type)
6863 text2 = GTK_CELL_TEXT (row2->cell[clist->sort_column])->text;
6865 case GTK_CELL_PIXTEXT:
6866 text2 = GTK_CELL_PIXTEXT (row2->cell[clist->sort_column])->text;
6873 return (text1 != NULL);
6878 return strcmp (text1, text2);
6882 real_sort_list (GtkCList *clist)
6887 gboolean thaw = FALSE;
6889 g_return_if_fail (clist != NULL);
6890 g_return_if_fail (GTK_IS_CLIST (clist));
6892 if (clist->rows <= 1)
6895 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
6898 if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
6900 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
6901 g_list_free (clist->undo_selection);
6902 g_list_free (clist->undo_unselection);
6903 clist->undo_selection = NULL;
6904 clist->undo_unselection = NULL;
6907 if (!GTK_CLIST_FROZEN (clist))
6909 gtk_clist_freeze (clist);
6913 clist->row_list = gtk_clist_mergesort (clist, clist->row_list, clist->rows);
6915 work = clist->selection;
6917 for (i = 0, list = clist->row_list; i < clist->rows; i++, list = list->next)
6919 if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
6921 work->data = GINT_TO_POINTER (i);
6925 if (i == clist->rows - 1)
6926 clist->row_list_end = list;
6930 gtk_clist_thaw (clist);
6934 gtk_clist_merge (GtkCList *clist,
6935 GList *a, /* first list to merge */
6936 GList *b) /* second list to merge */
6938 GList z = { 0 }; /* auxiliary node */
6964 cmp = clist->compare (clist, GTK_CLIST_ROW (a), GTK_CLIST_ROW (b));
6965 if ((cmp >= 0 && clist->sort_type == GTK_SORT_DESCENDING) ||
6966 (cmp <= 0 && clist->sort_type == GTK_SORT_ASCENDING) ||
6988 gtk_clist_mergesort (GtkCList *clist,
6989 GList *list, /* the list to sort */
6990 gint num) /* the list's length */
7001 /* move "half" to the middle */
7003 for (i = 0; i < num / 2; i++)
7006 /* cut the list in two */
7007 half->prev->next = NULL;
7010 /* recursively sort both lists */
7011 return gtk_clist_merge (clist,
7012 gtk_clist_mergesort (clist, list, num / 2),
7013 gtk_clist_mergesort (clist, half, num - num / 2));