1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald,
3 * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 #include "../config.h"
25 #include "gtkbindings.h"
26 #include <gdk/gdkkeysyms.h>
28 /* the number rows memchunk expands at a time */
29 #define CLIST_OPTIMUM_SIZE 512
31 /* the width of the column resize windows */
34 /* minimum allowed width of a column */
35 #define COLUMN_MIN_WIDTH 5
37 /* this defigns the base grid spacing */
38 #define CELL_SPACING 1
40 /* added the horizontal space at the beginning and end of a row*/
41 #define COLUMN_INSET 3
43 /* used for auto-scrolling */
44 #define SCROLL_TIME 100
46 /* scrollbar spacing class macro */
47 #define SCROLLBAR_SPACING(w) (GTK_CLIST_CLASS (GTK_OBJECT (w)->klass)->scrollbar_spacing)
49 /* gives the top pixel of the given row in context of
50 * the clist's voffset */
51 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
52 (((row) + 1) * CELL_SPACING) + \
55 /* returns the row index from a y pixel location in the
56 * context of the clist's voffset */
57 #define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \
58 ((clist)->row_height + CELL_SPACING))
60 /* gives the left pixel of the given column in context of
61 * the clist's hoffset */
62 #define COLUMN_LEFT_XPIXEL(clist, colnum) ((clist)->column[(colnum)].area.x + \
65 /* returns the column index from a x pixel location in the
66 * context of the clist's hoffset */
68 COLUMN_FROM_XPIXEL (GtkCList * clist,
73 for (i = 0; i < clist->columns; i++)
75 cx = clist->column[i].area.x + clist->hoffset;
77 if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
78 x <= (cx + clist->column[i].area.width + COLUMN_INSET))
86 /* returns the top pixel of the given row in the context of
88 #define ROW_TOP(clist, row) (((clist)->row_height + CELL_SPACING) * (row))
90 /* returns the left pixel of the given column in the context of
92 #define COLUMN_LEFT(clist, colnum) ((clist)->column[(colnum)].area.x)
94 /* returns the total height of the list */
95 #define LIST_HEIGHT(clist) (((clist)->row_height * ((clist)->rows)) + \
96 (CELL_SPACING * ((clist)->rows + 1)))
98 /* returns the total width of the list */
99 #define LIST_WIDTH(clist) ((clist)->column[(clist)->columns - 1].area.x + \
100 (clist)->column[(clist)->columns - 1].area.width + \
101 COLUMN_INSET + CELL_SPACING)
104 #define GTK_CLIST_CLASS_FW(_widget_) GTK_CLIST_CLASS (GTK_OBJECT (_widget_)->klass)
134 typedef void (*GtkCListSignal1) (GtkObject * object,
140 typedef void (*GtkCListSignal2) (GtkObject *object,
143 typedef void (*GtkCListSignal3) (GtkObject * object,
146 typedef void (*GtkCListSignal4) (GtkObject * object,
150 typedef void (*GtkCListSignal5) (GtkObject * object,
157 static void sync_selection (GtkCList * clist,
161 /* GtkCList Methods */
162 static void gtk_clist_class_init (GtkCListClass * klass);
163 static void gtk_clist_init (GtkCList * clist);
164 static void real_clear (GtkCList * clist);
166 /* GtkObject Methods */
167 static void gtk_clist_destroy (GtkObject * object);
168 static void gtk_clist_finalize (GtkObject * object);
171 /* GtkWidget Methods */
172 static void gtk_clist_realize (GtkWidget * widget);
173 static void gtk_clist_unrealize (GtkWidget * widget);
174 static void gtk_clist_map (GtkWidget * widget);
175 static void gtk_clist_unmap (GtkWidget * widget);
176 static void gtk_clist_draw (GtkWidget * widget,
177 GdkRectangle * area);
178 static gint gtk_clist_expose (GtkWidget * widget,
179 GdkEventExpose * event);
180 static gint gtk_clist_button_press (GtkWidget * widget,
181 GdkEventButton * event);
182 static gint gtk_clist_button_release (GtkWidget * widget,
183 GdkEventButton * event);
184 static gint gtk_clist_motion (GtkWidget * widget,
185 GdkEventMotion * event);
186 static void gtk_clist_size_request (GtkWidget * widget,
187 GtkRequisition * requisition);
188 static void gtk_clist_size_allocate (GtkWidget * widget,
189 GtkAllocation * allocation);
190 static gint get_selection_info (GtkCList * clist,
196 /* GtkContainer Methods */
197 static void gtk_clist_foreach (GtkContainer * container,
198 GtkCallback callback,
199 gpointer callback_data);
202 static void draw_row (GtkCList * clist,
205 GtkCListRow * clist_row);
206 static void draw_rows (GtkCList * clist,
207 GdkRectangle * area);
209 /* Size Allocation */
210 static void size_allocate_title_buttons (GtkCList * clist);
211 static void size_allocate_columns (GtkCList * clist);
214 static void toggle_row (GtkCList * clist,
218 static void select_row (GtkCList * clist,
222 static void unselect_row (GtkCList * clist,
226 static void real_select_row (GtkCList * clist,
230 static void real_unselect_row (GtkCList * clist,
234 static void update_extended_selection (GtkCList *clist,
236 static GList * selection_find (GtkCList *clist,
238 GList *row_list_element);
239 static void real_select_all (GtkCList * clist);
240 static void real_unselect_all (GtkCList * clist);
241 static void move_vertical (GtkCList *clist,
244 static void move_horizontal (GtkCList *clist,
246 static void real_undo_selection (GtkCList * clist);
247 static void fake_unselect_all (GtkCList *clist,
249 static void fake_toggle_row (GtkCList *clist,
251 static void resync_selection (GtkCList *clist,
255 static void draw_xor_line (GtkCList * clist);
256 static gint new_column_width (GtkCList * clist,
260 static void resize_column (GtkCList * clist,
263 static void abort_column_resize (GtkCList *clist);
266 static void column_button_create (GtkCList * clist,
268 static void column_button_clicked (GtkWidget * widget,
272 static void create_scrollbars (GtkCList * clist);
273 static void adjust_scrollbars (GtkCList * clist);
274 static void check_exposures (GtkCList * clist);
275 static void vadjustment_changed (GtkAdjustment * adjustment,
277 static void vadjustment_value_changed (GtkAdjustment * adjustment,
279 static void hadjustment_changed (GtkAdjustment * adjustment,
281 static void hadjustment_value_changed (GtkAdjustment * adjustment,
284 /* Memory Allocation/Distruction Routines */
285 static GtkCListColumn *columns_new (GtkCList * clist);
287 static void column_title_new (GtkCList * clist,
290 static void columns_delete (GtkCList * clist);
292 static GtkCListRow *row_new (GtkCList * clist);
294 static void row_delete (GtkCList * clist,
295 GtkCListRow * clist_row);
296 static void cell_empty (GtkCList * clist,
297 GtkCListRow * clist_row,
299 static void cell_set_text (GtkCList * clist,
300 GtkCListRow * clist_row,
303 static void cell_set_pixmap (GtkCList * clist,
304 GtkCListRow * clist_row,
308 static void cell_set_pixtext (GtkCList * clist,
309 GtkCListRow * clist_row,
317 static void gtk_clist_draw_focus (GtkWidget *widget);
318 static gint gtk_clist_focus_in (GtkWidget *widget,
319 GdkEventFocus *event);
320 static gint gtk_clist_focus_out (GtkWidget *widget,
321 GdkEventFocus *event);
322 static gint gtk_clist_focus (GtkContainer *container,
323 GtkDirectionType direction);
324 static void gtk_clist_set_focus_child (GtkContainer *container,
326 static gint gtk_clist_key_press (GtkWidget *widget,
329 /* Selection handling */
330 static void set_anchor (GtkCList *clist,
334 static void start_selection (GtkCList *clist);
335 static void end_selection (GtkCList *clist);
337 static void toggle_add_mode (GtkCList *clist);
338 static void toggle_focus_row (GtkCList *clist);
339 static void move_focus_row (GtkCList *clist,
340 GtkScrollType scroll_type,
342 static void scroll_horizontal (GtkCList *clist,
343 GtkScrollType scroll_type,
345 static void scroll_vertical (GtkCList *clist,
346 GtkScrollType scroll_type,
348 static void extend_selection (GtkCList *clist,
349 GtkScrollType scroll_type,
351 gboolean auto_start_selection);
354 static gint default_compare (GtkCList *clist,
357 static GList * my_merge (GtkCList *clist,
360 static GList * my_mergesort (GtkCList *clist,
364 /* Fill in data after widget is realized and has style */
366 static void add_style_data (GtkCList * clist);
368 static GtkContainerClass *parent_class = NULL;
369 static guint clist_signals[LAST_SIGNAL] = {0};
373 gtk_clist_get_type (void)
375 static GtkType clist_type = 0;
379 GtkTypeInfo clist_info =
383 sizeof (GtkCListClass),
384 (GtkClassInitFunc) gtk_clist_class_init,
385 (GtkObjectInitFunc) gtk_clist_init,
386 /* reserved_1 */ NULL,
387 /* reserved_2 */ NULL,
388 (GtkClassInitFunc) NULL,
391 clist_type = gtk_type_unique (GTK_TYPE_CONTAINER, &clist_info);
398 gtk_clist_class_init (GtkCListClass * klass)
400 GtkObjectClass *object_class;
401 GtkWidgetClass *widget_class;
402 GtkContainerClass *container_class;
404 object_class = (GtkObjectClass *) klass;
405 widget_class = (GtkWidgetClass *) klass;
406 container_class = (GtkContainerClass *) klass;
408 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
410 clist_signals[SELECT_ROW] =
411 gtk_signal_new ("select_row",
414 GTK_SIGNAL_OFFSET (GtkCListClass, select_row),
415 gtk_marshal_NONE__INT_INT_POINTER,
420 clist_signals[UNSELECT_ROW] =
421 gtk_signal_new ("unselect_row",
424 GTK_SIGNAL_OFFSET (GtkCListClass, unselect_row),
425 gtk_marshal_NONE__INT_INT_POINTER,
426 GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_GDK_EVENT);
427 clist_signals[CLICK_COLUMN] =
428 gtk_signal_new ("click_column",
431 GTK_SIGNAL_OFFSET (GtkCListClass, click_column),
432 gtk_marshal_NONE__INT,
433 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
435 clist_signals[TOGGLE_FOCUS_ROW] =
436 gtk_signal_new ("toggle_focus_row",
437 GTK_RUN_LAST | GTK_RUN_ACTION,
439 GTK_SIGNAL_OFFSET (GtkCListClass, toggle_focus_row),
440 gtk_marshal_NONE__NONE,
442 clist_signals[SELECT_ALL] =
443 gtk_signal_new ("select_all",
444 GTK_RUN_LAST | GTK_RUN_ACTION,
446 GTK_SIGNAL_OFFSET (GtkCListClass, select_all),
447 gtk_marshal_NONE__NONE,
449 clist_signals[UNSELECT_ALL] =
450 gtk_signal_new ("unselect_all",
451 GTK_RUN_LAST | GTK_RUN_ACTION,
453 GTK_SIGNAL_OFFSET (GtkCListClass, unselect_all),
454 gtk_marshal_NONE__NONE,
456 clist_signals[UNDO_SELECTION] =
457 gtk_signal_new ("undo_selection",
458 GTK_RUN_LAST | GTK_RUN_ACTION,
460 GTK_SIGNAL_OFFSET (GtkCListClass, undo_selection),
461 gtk_marshal_NONE__NONE,
463 clist_signals[START_SELECTION] =
464 gtk_signal_new ("start_selection",
465 GTK_RUN_LAST | GTK_RUN_ACTION,
467 GTK_SIGNAL_OFFSET (GtkCListClass, start_selection),
468 gtk_marshal_NONE__NONE,
470 clist_signals[END_SELECTION] =
471 gtk_signal_new ("end_selection",
472 GTK_RUN_LAST | GTK_RUN_ACTION,
474 GTK_SIGNAL_OFFSET (GtkCListClass, end_selection),
475 gtk_marshal_NONE__NONE,
477 clist_signals[TOGGLE_ADD_MODE] =
478 gtk_signal_new ("toggle_add_mode",
479 GTK_RUN_LAST | GTK_RUN_ACTION,
481 GTK_SIGNAL_OFFSET (GtkCListClass, toggle_add_mode),
482 gtk_marshal_NONE__NONE,
484 clist_signals[EXTEND_SELECTION] =
485 gtk_signal_new ("extend_selection",
486 GTK_RUN_LAST | GTK_RUN_ACTION,
488 GTK_SIGNAL_OFFSET (GtkCListClass, extend_selection),
489 gtk_marshal_NONE__ENUM_FLOAT_BOOL,
491 GTK_TYPE_SCROLL_TYPE, GTK_TYPE_FLOAT, GTK_TYPE_BOOL);
492 clist_signals[SCROLL_VERTICAL] =
493 gtk_signal_new ("scroll_vertical",
494 GTK_RUN_LAST | GTK_RUN_ACTION,
496 GTK_SIGNAL_OFFSET (GtkCListClass, scroll_vertical),
497 gtk_marshal_NONE__ENUM_FLOAT,
498 GTK_TYPE_NONE, 2, GTK_TYPE_SCROLL_TYPE, GTK_TYPE_FLOAT);
499 clist_signals[SCROLL_HORIZONTAL] =
500 gtk_signal_new ("scroll_horizontal",
501 GTK_RUN_LAST | GTK_RUN_ACTION,
503 GTK_SIGNAL_OFFSET (GtkCListClass, scroll_horizontal),
504 gtk_marshal_NONE__ENUM_FLOAT,
505 GTK_TYPE_NONE, 2, GTK_TYPE_SCROLL_TYPE, GTK_TYPE_FLOAT);
506 clist_signals[ABORT_COLUMN_RESIZE] =
507 gtk_signal_new ("abort_column_resize",
508 GTK_RUN_LAST | GTK_RUN_ACTION,
510 GTK_SIGNAL_OFFSET (GtkCListClass, abort_column_resize),
511 gtk_marshal_NONE__NONE,
515 gtk_object_class_add_signals (object_class, clist_signals, LAST_SIGNAL);
517 object_class->destroy = gtk_clist_destroy;
518 object_class->finalize = gtk_clist_finalize;
520 widget_class->realize = gtk_clist_realize;
521 widget_class->unrealize = gtk_clist_unrealize;
522 widget_class->map = gtk_clist_map;
523 widget_class->unmap = gtk_clist_unmap;
524 widget_class->draw = gtk_clist_draw;
525 widget_class->button_press_event = gtk_clist_button_press;
526 widget_class->button_release_event = gtk_clist_button_release;
527 widget_class->motion_notify_event = gtk_clist_motion;
528 widget_class->expose_event = gtk_clist_expose;
529 widget_class->size_request = gtk_clist_size_request;
530 widget_class->size_allocate = gtk_clist_size_allocate;
531 widget_class->key_press_event = gtk_clist_key_press;
532 widget_class->focus_in_event = gtk_clist_focus_in;
533 widget_class->focus_out_event = gtk_clist_focus_out;
534 widget_class->draw_focus = gtk_clist_draw_focus;
536 /* container_class->add = NULL; use the default GtkContainerClass warning */
537 /* container_class->remove = NULL; use the default GtkContainerClass warning */
538 container_class->foreach = gtk_clist_foreach;
539 container_class->focus = gtk_clist_focus;
540 container_class->set_focus_child = gtk_clist_set_focus_child;
542 klass->select_row = real_select_row;
543 klass->unselect_row = real_unselect_row;
544 klass->undo_selection = real_undo_selection;
545 klass->resync_selection = resync_selection;
546 klass->selection_find = selection_find;
547 klass->click_column = NULL;
548 klass->draw_row = draw_row;
549 klass->clear = real_clear;
550 klass->select_all = real_select_all;
551 klass->unselect_all = real_unselect_all;
552 klass->fake_unselect_all = fake_unselect_all;
553 klass->scroll_horizontal = scroll_horizontal;
554 klass->scroll_vertical = scroll_vertical;
555 klass->extend_selection = extend_selection;
556 klass->toggle_focus_row = toggle_focus_row;
557 klass->toggle_add_mode = toggle_add_mode;
558 klass->start_selection = start_selection;
559 klass->end_selection = end_selection;
560 klass->abort_column_resize = abort_column_resize;
562 klass->scrollbar_spacing = 5;
565 GtkBindingSet *binding_set;
567 binding_set = gtk_binding_set_by_class (klass);
568 gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
569 "scroll_vertical", 2,
570 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
571 GTK_TYPE_FLOAT, 0.0);
572 gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
573 "scroll_vertical", 2,
574 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
575 GTK_TYPE_FLOAT, 0.0);
576 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
577 "scroll_vertical", 2,
578 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
579 GTK_TYPE_FLOAT, 0.0);
580 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
581 "scroll_vertical", 2,
582 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
583 GTK_TYPE_FLOAT, 0.0);
584 gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
585 "scroll_vertical", 2,
586 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
587 GTK_TYPE_FLOAT, 0.0);
588 gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
589 "scroll_vertical", 2,
590 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
591 GTK_TYPE_FLOAT, 1.0);
593 gtk_binding_entry_add_signal (binding_set, GDK_Up, GDK_SHIFT_MASK,
594 "extend_selection", 3,
595 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
596 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
597 gtk_binding_entry_add_signal (binding_set, GDK_Down, GDK_SHIFT_MASK,
598 "extend_selection", 3,
599 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
600 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
601 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, GDK_SHIFT_MASK,
602 "extend_selection", 3,
603 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
604 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
605 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, GDK_SHIFT_MASK,
606 "extend_selection", 3,
607 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
608 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
609 gtk_binding_entry_add_signal (binding_set, GDK_Home,
610 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
611 "extend_selection", 3,
612 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
613 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
614 gtk_binding_entry_add_signal (binding_set, GDK_End,
615 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
616 "extend_selection", 3,
617 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
618 GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE);
621 gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
622 "scroll_horizontal", 2,
623 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
624 GTK_TYPE_FLOAT, 0.0);
625 gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
626 "scroll_horizontal", 2,
627 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
628 GTK_TYPE_FLOAT, 0.0);
629 gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
630 "scroll_horizontal", 2,
631 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
632 GTK_TYPE_FLOAT, 0.0);
633 gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
634 "scroll_horizontal", 2,
635 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
636 GTK_TYPE_FLOAT, 1.0);
639 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
640 "undo_selection", 0);
641 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
642 "abort_column_resize", 0);
643 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
644 "toggle_focus_row", 0);
645 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK,
646 "toggle_add_mode", 0);
647 gtk_binding_entry_add_signal (binding_set, '/', GDK_CONTROL_MASK,
649 gtk_binding_entry_add_signal (binding_set, '\\', GDK_CONTROL_MASK,
651 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
652 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
654 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
655 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
657 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
658 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
661 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
662 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
669 GtkBindingSet *binding_set;
671 binding_set = gtk_binding_set_by_class (klass);
672 gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
673 "scroll_vertical", 2,
674 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
675 GTK_TYPE_FLOAT, 0.0);
676 gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
677 "scroll_vertical", 2,
678 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
679 GTK_TYPE_FLOAT, 0.0);
680 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
681 "scroll_vertical", 2,
682 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
683 GTK_TYPE_FLOAT, 0.0);
684 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
685 "scroll_vertical", 2,
686 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
687 GTK_TYPE_FLOAT, 0.0);
688 gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
689 "scroll_vertical", 2,
690 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
691 GTK_TYPE_FLOAT, 0.0);
692 gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
693 "scroll_vertical", 2,
694 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
697 gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0,
698 "extend_selection", 3,
699 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
700 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
701 gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0,
702 "extend_selection", 3,
703 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
704 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
705 gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Up, 0,
706 "extend_selection", 3,
707 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
708 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
709 gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Down, 0,
710 "extend_selection", 3,
711 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
712 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
713 gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, 0,
714 "extend_selection", 3,
715 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
716 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
717 gtk_binding_entry_add_signal (binding_set, GDK_KP_End, 0,
718 "extend_selection", 3,
719 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
720 GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE);
722 gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
723 "scroll_horizontal", 2,
724 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
725 GTK_TYPE_FLOAT, 0.0);
726 gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0,
727 "scroll_horizontal", 2,
728 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
729 GTK_TYPE_FLOAT, 0.0);
730 gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
731 "scroll_horizontal", 2,
732 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
733 GTK_TYPE_FLOAT, 0.0);
734 gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0,
735 "scroll_horizontal", 2,
736 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
737 GTK_TYPE_FLOAT, 0.0);
738 gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
739 "scroll_horizontal", 2,
740 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
741 GTK_TYPE_FLOAT, 0.0);
742 gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
743 "sroll_horizontal", 2,
744 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
745 GTK_TYPE_FLOAT, 1.0);
747 gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, 0,
748 "undo_selection", 0);
749 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
750 "abort_column_resize", 0);
751 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
752 "toggle_focus_row", 0);
753 gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0,
754 "toggle_add_mode", 0);
755 gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0,
757 gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0,
759 gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0,
766 gtk_clist_init (GtkCList * clist)
770 GTK_WIDGET_UNSET_FLAGS (clist, GTK_NO_WINDOW);
771 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
773 clist->row_mem_chunk = NULL;
774 clist->cell_mem_chunk = NULL;
777 clist->row_center_offset = 0;
778 clist->row_height = 0;
779 clist->row_list = NULL;
780 clist->row_list_end = NULL;
784 clist->title_window = NULL;
785 clist->column_title_area.x = 0;
786 clist->column_title_area.y = 0;
787 clist->column_title_area.width = 1;
788 clist->column_title_area.height = 1;
790 clist->clist_window = NULL;
791 clist->clist_window_width = 1;
792 clist->clist_window_height = 1;
797 clist->shadow_type = GTK_SHADOW_IN;
798 clist->hscrollbar_policy = GTK_POLICY_ALWAYS;
799 clist->vscrollbar_policy = GTK_POLICY_ALWAYS;
801 clist->cursor_drag = NULL;
802 clist->xor_gc = NULL;
807 clist->selection_mode = GTK_SELECTION_SINGLE;
808 clist->selection = NULL;
809 clist->selection_end = NULL;
810 clist->undo_selection = NULL;
811 clist->undo_unselection = NULL;
813 GTK_WIDGET_SET_FLAGS (clist, GTK_CAN_FOCUS);
814 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
815 clist->focus_row = -1;
816 clist->undo_anchor = -1;
819 clist->anchor_state = GTK_STATE_SELECTED;
820 clist->drag_pos = -1;
824 clist->compare = default_compare;
825 clist->sort_type = GTK_SORT_ASCENDING;
826 clist->sort_column = 0;
831 gtk_clist_construct (GtkCList * clist,
837 g_return_if_fail (clist != NULL);
838 g_return_if_fail (GTK_IS_CLIST (clist));
839 g_return_if_fail (GTK_CLIST_CONSTRUCTED (clist) == FALSE);
841 GTK_CLIST_SET_FLAG (clist, CLIST_CONSTRUCTED);
843 /* initalize memory chunks, if this has not been done by any
844 * possibly derived widget
846 if (!clist->row_mem_chunk)
847 clist->row_mem_chunk = g_mem_chunk_new ("clist row mem chunk",
848 sizeof (GtkCListRow),
849 sizeof (GtkCListRow) * CLIST_OPTIMUM_SIZE,
852 if (!clist->cell_mem_chunk)
853 clist->cell_mem_chunk = g_mem_chunk_new ("clist cell mem chunk",
854 sizeof (GtkCell) * columns,
855 sizeof (GtkCell) * columns * CLIST_OPTIMUM_SIZE,
858 /* set number of columns, allocate memory */
859 clist->columns = columns;
860 clist->column = columns_new (clist);
862 /* there needs to be at least one column button
863 * because there is alot of code that will break if it
865 column_button_create (clist, 0);
867 /* create scrollbars */
868 create_scrollbars (clist);
872 GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES);
873 for (i = 0; i < columns; i++)
874 gtk_clist_set_column_title (clist, i, titles[i]);
878 GTK_CLIST_UNSET_FLAG (clist, CLIST_SHOW_TITLES);
883 * GTKCLIST PUBLIC INTERFACE
884 * gtk_clist_new_with_titles
888 gtk_clist_new_with_titles (gint columns,
893 g_return_val_if_fail (titles != NULL, NULL);
895 widget = gtk_type_new (GTK_TYPE_CLIST);
897 gtk_clist_construct (GTK_CLIST (widget), columns, titles);
903 gtk_clist_new (gint columns)
910 clist = gtk_type_new (GTK_TYPE_CLIST);
911 gtk_clist_construct (clist, columns, NULL);
912 return GTK_WIDGET (clist);
916 gtk_clist_set_border (GtkCList * clist,
917 GtkShadowType border)
919 g_return_if_fail (clist != NULL);
920 g_return_if_fail (GTK_IS_CLIST (clist));
922 clist->shadow_type = border;
924 if (GTK_WIDGET_VISIBLE (clist))
925 gtk_widget_queue_resize (GTK_WIDGET (clist));
929 gtk_clist_set_selection_mode (GtkCList * clist,
930 GtkSelectionMode mode)
932 g_return_if_fail (clist != NULL);
933 g_return_if_fail (GTK_IS_CLIST (clist));
935 if (mode == clist->selection_mode)
938 clist->selection_mode = mode;
940 clist->anchor_state = GTK_STATE_SELECTED;
941 clist->drag_pos = -1;
942 clist->undo_anchor = clist->focus_row;
944 g_list_free (clist->undo_selection);
945 g_list_free (clist->undo_unselection);
946 clist->undo_selection = NULL;
947 clist->undo_unselection = NULL;
951 case GTK_SELECTION_MULTIPLE:
952 case GTK_SELECTION_EXTENDED:
954 case GTK_SELECTION_BROWSE:
955 case GTK_SELECTION_SINGLE:
956 gtk_clist_unselect_all (clist);
962 gtk_clist_freeze (GtkCList * clist)
964 g_return_if_fail (clist != NULL);
965 g_return_if_fail (GTK_IS_CLIST (clist));
967 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
971 gtk_clist_thaw (GtkCList * clist)
973 g_return_if_fail (clist != NULL);
974 g_return_if_fail (GTK_IS_CLIST (clist));
976 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
978 adjust_scrollbars (clist);
979 draw_rows (clist, NULL);
983 gtk_clist_column_titles_show (GtkCList * clist)
985 g_return_if_fail (clist != NULL);
986 g_return_if_fail (GTK_IS_CLIST (clist));
988 if (!GTK_CLIST_SHOW_TITLES (clist))
990 GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES);
991 if (clist->title_window)
992 gdk_window_show (clist->title_window);
993 gtk_widget_queue_resize (GTK_WIDGET (clist));
998 gtk_clist_column_titles_hide (GtkCList * clist)
1000 g_return_if_fail (clist != NULL);
1001 g_return_if_fail (GTK_IS_CLIST (clist));
1003 if (GTK_CLIST_SHOW_TITLES (clist))
1005 GTK_CLIST_UNSET_FLAG (clist, CLIST_SHOW_TITLES);
1006 if (clist->title_window)
1007 gdk_window_hide (clist->title_window);
1008 gtk_widget_queue_resize (GTK_WIDGET (clist));
1013 gtk_clist_column_title_active (GtkCList * clist,
1016 g_return_if_fail (clist != NULL);
1017 g_return_if_fail (GTK_IS_CLIST (clist));
1019 if (column < 0 || column >= clist->columns)
1022 if (!GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
1023 !GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
1025 GTK_WIDGET_SET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS);
1026 if (GTK_WIDGET_VISIBLE (clist))
1027 gtk_widget_queue_draw (clist->column[column].button);
1032 gtk_clist_column_title_passive (GtkCList * clist,
1035 g_return_if_fail (clist != NULL);
1036 g_return_if_fail (GTK_IS_CLIST (clist));
1038 if (column < 0 || column >= clist->columns)
1041 if (GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
1042 GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
1044 GTK_WIDGET_UNSET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS);
1045 if (GTK_WIDGET_VISIBLE (clist))
1046 gtk_widget_queue_draw (clist->column[column].button);
1051 gtk_clist_column_titles_active (GtkCList * clist)
1055 g_return_if_fail (clist != NULL);
1056 g_return_if_fail (GTK_IS_CLIST (clist));
1058 for (i = 0; i < clist->columns; i++)
1059 if (clist->column[i].button)
1060 gtk_clist_column_title_active (clist, i);
1064 gtk_clist_column_titles_passive (GtkCList * clist)
1068 g_return_if_fail (clist != NULL);
1069 g_return_if_fail (GTK_IS_CLIST (clist));
1071 for (i = 0; i < clist->columns; i++)
1072 if (clist->column[i].button)
1073 gtk_clist_column_title_passive (clist, i);
1077 gtk_clist_set_column_title (GtkCList * clist,
1081 gint new_button = 0;
1082 GtkWidget *old_widget;
1083 GtkWidget *alignment = NULL;
1086 g_return_if_fail (clist != NULL);
1087 g_return_if_fail (GTK_IS_CLIST (clist));
1089 if (column < 0 || column >= clist->columns)
1092 /* if the column button doesn't currently exist,
1093 * it has to be created first */
1094 if (!clist->column[column].button)
1096 column_button_create (clist, column);
1100 column_title_new (clist, column, title);
1102 /* remove and destroy the old widget */
1103 old_widget = GTK_BIN (clist->column[column].button)->child;
1105 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
1107 /* create new alignment based no column justification */
1108 switch (clist->column[column].justification)
1110 case GTK_JUSTIFY_LEFT:
1111 alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
1114 case GTK_JUSTIFY_RIGHT:
1115 alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
1118 case GTK_JUSTIFY_CENTER:
1119 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1122 case GTK_JUSTIFY_FILL:
1123 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1127 label = gtk_label_new (clist->column[column].title);
1128 gtk_container_add (GTK_CONTAINER (alignment), label);
1129 gtk_container_add (GTK_CONTAINER (clist->column[column].button), alignment);
1130 gtk_widget_show (label);
1131 gtk_widget_show (alignment);
1133 /* if this button didn't previously exist, then the
1134 * column button positions have to be re-computed */
1135 if (GTK_WIDGET_VISIBLE (clist) && new_button)
1136 size_allocate_title_buttons (clist);
1140 gtk_clist_set_column_widget (GtkCList * clist,
1144 gint new_button = 0;
1145 GtkWidget *old_widget;
1147 g_return_if_fail (clist != NULL);
1148 g_return_if_fail (GTK_IS_CLIST (clist));
1150 if (column < 0 || column >= clist->columns)
1153 /* if the column button doesn't currently exist,
1154 * it has to be created first */
1155 if (!clist->column[column].button)
1157 column_button_create (clist, column);
1161 column_title_new (clist, column, NULL);
1163 /* remove and destroy the old widget */
1164 old_widget = GTK_BIN (clist->column[column].button)->child;
1166 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
1168 /* add and show the widget */
1171 gtk_container_add (GTK_CONTAINER (clist->column[column].button), widget);
1172 gtk_widget_show (widget);
1175 /* if this button didn't previously exist, then the
1176 * column button positions have to be re-computed */
1177 if (GTK_WIDGET_VISIBLE (clist) && new_button)
1178 size_allocate_title_buttons (clist);
1182 gtk_clist_set_column_justification (GtkCList * clist,
1184 GtkJustification justification)
1186 GtkWidget *alignment;
1188 g_return_if_fail (clist != NULL);
1189 g_return_if_fail (GTK_IS_CLIST (clist));
1191 if (column < 0 || column >= clist->columns)
1194 clist->column[column].justification = justification;
1196 /* change the alinment of the button title if it's not a
1198 if (clist->column[column].title)
1200 alignment = GTK_BIN (clist->column[column].button)->child;
1202 switch (clist->column[column].justification)
1204 case GTK_JUSTIFY_LEFT:
1205 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.0, 0.5, 0.0, 0.0);
1208 case GTK_JUSTIFY_RIGHT:
1209 gtk_alignment_set (GTK_ALIGNMENT (alignment), 1.0, 0.5, 0.0, 0.0);
1212 case GTK_JUSTIFY_CENTER:
1213 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
1216 case GTK_JUSTIFY_FILL:
1217 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
1225 if (!GTK_CLIST_FROZEN (clist))
1226 draw_rows (clist, NULL);
1230 gtk_clist_set_column_width (GtkCList * clist,
1234 g_return_if_fail (clist != NULL);
1235 g_return_if_fail (GTK_IS_CLIST (clist));
1237 if (column < 0 || column >= clist->columns)
1240 clist->column[column].width = width;
1241 clist->column[column].width_set = TRUE;
1243 /* FIXME: this is quite expensive to do if the widget hasn't
1244 * been size_allocated yet, and pointless. Should
1247 size_allocate_columns (clist);
1248 size_allocate_title_buttons (clist);
1250 if (!GTK_CLIST_FROZEN (clist))
1252 adjust_scrollbars (clist);
1253 draw_rows (clist, NULL);
1258 gtk_clist_set_row_height (GtkCList * clist,
1263 g_return_if_fail (clist != NULL);
1264 g_return_if_fail (GTK_IS_CLIST (clist));
1267 clist->row_height = height;
1271 GTK_CLIST_SET_FLAG (clist, CLIST_ROW_HEIGHT_SET);
1273 if (GTK_WIDGET_REALIZED (clist))
1275 text_height = height - (GTK_WIDGET (clist)->style->font->ascent +
1276 GTK_WIDGET (clist) ->style->font->descent + 1);
1277 clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
1280 if (!GTK_CLIST_FROZEN (clist))
1282 adjust_scrollbars (clist);
1283 draw_rows (clist, NULL);
1288 gtk_clist_moveto (GtkCList * clist,
1294 g_return_if_fail (clist != NULL);
1295 g_return_if_fail (GTK_IS_CLIST (clist));
1297 if (row < -1 || row >= clist->rows)
1299 if (column < -1 || column >= clist->columns)
1302 row_align = CLAMP (row_align, 0, 1);
1303 col_align = CLAMP (col_align, 0, 1);
1305 /* adjust horizontal scrollbar */
1311 adj = GTK_RANGE (clist->hscrollbar)->adjustment;
1313 x = COLUMN_LEFT (clist, column) - CELL_SPACING - COLUMN_INSET -
1314 (col_align * (clist->clist_window_width - 2 * COLUMN_INSET -
1315 CELL_SPACING - clist->column[column].area.width));
1317 gtk_adjustment_set_value (adj, 0.0);
1318 else if (x > LIST_WIDTH (clist) - clist->clist_window_width)
1319 gtk_adjustment_set_value
1320 (adj, LIST_WIDTH (clist) - clist->clist_window_width);
1322 gtk_adjustment_set_value (adj, x);
1325 /* adjust vertical scrollbar */
1327 move_vertical (clist, row, row_align);
1331 gtk_clist_get_cell_type (GtkCList * clist,
1335 GtkCListRow *clist_row;
1337 g_return_val_if_fail (clist != NULL, -1);
1338 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1340 if (row < 0 || row >= clist->rows)
1342 if (column < 0 || column >= clist->columns)
1345 clist_row = (g_list_nth (clist->row_list, row))->data;
1347 return clist_row->cell[column].type;
1351 gtk_clist_set_text (GtkCList * clist,
1356 GtkCListRow *clist_row;
1358 g_return_if_fail (clist != NULL);
1359 g_return_if_fail (GTK_IS_CLIST (clist));
1361 if (row < 0 || row >= clist->rows)
1363 if (column < 0 || column >= clist->columns)
1366 clist_row = (g_list_nth (clist->row_list, row))->data;
1368 /* if text is null, then the cell is empty */
1370 cell_set_text (clist, clist_row, column, text);
1372 cell_empty (clist, clist_row, column);
1374 /* redraw the list if it's not frozen */
1375 if (!GTK_CLIST_FROZEN (clist))
1377 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1378 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1383 gtk_clist_get_text (GtkCList * clist,
1388 GtkCListRow *clist_row;
1390 g_return_val_if_fail (clist != NULL, 0);
1391 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
1393 if (row < 0 || row >= clist->rows)
1395 if (column < 0 || column >= clist->columns)
1398 clist_row = (g_list_nth (clist->row_list, row))->data;
1400 if (clist_row->cell[column].type != GTK_CELL_TEXT)
1404 *text = GTK_CELL_TEXT (clist_row->cell[column])->text;
1410 gtk_clist_set_pixmap (GtkCList * clist,
1416 GtkCListRow *clist_row;
1418 g_return_if_fail (clist != NULL);
1419 g_return_if_fail (GTK_IS_CLIST (clist));
1421 if (row < 0 || row >= clist->rows)
1423 if (column < 0 || column >= clist->columns)
1426 clist_row = (g_list_nth (clist->row_list, row))->data;
1428 gdk_pixmap_ref (pixmap);
1430 if (mask) gdk_pixmap_ref (mask);
1432 cell_set_pixmap (clist, clist_row, column, pixmap, mask);
1434 /* redraw the list if it's not frozen */
1435 if (!GTK_CLIST_FROZEN (clist))
1437 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1438 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1443 gtk_clist_get_pixmap (GtkCList * clist,
1446 GdkPixmap ** pixmap,
1449 GtkCListRow *clist_row;
1451 g_return_val_if_fail (clist != NULL, 0);
1452 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
1454 if (row < 0 || row >= clist->rows)
1456 if (column < 0 || column >= clist->columns)
1459 clist_row = (g_list_nth (clist->row_list, row))->data;
1461 if (clist_row->cell[column].type != GTK_CELL_PIXMAP)
1466 *pixmap = GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap;
1467 /* mask can be NULL */
1468 *mask = GTK_CELL_PIXMAP (clist_row->cell[column])->mask;
1475 gtk_clist_set_pixtext (GtkCList * clist,
1483 GtkCListRow *clist_row;
1485 g_return_if_fail (clist != NULL);
1486 g_return_if_fail (GTK_IS_CLIST (clist));
1488 if (row < 0 || row >= clist->rows)
1490 if (column < 0 || column >= clist->columns)
1493 clist_row = (g_list_nth (clist->row_list, row))->data;
1495 gdk_pixmap_ref (pixmap);
1496 if (mask) gdk_pixmap_ref (mask);
1497 cell_set_pixtext (clist, clist_row, column, text, spacing, pixmap, mask);
1499 /* redraw the list if it's not frozen */
1500 if (!GTK_CLIST_FROZEN (clist))
1502 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1503 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1508 gtk_clist_get_pixtext (GtkCList * clist,
1513 GdkPixmap ** pixmap,
1516 GtkCListRow *clist_row;
1518 g_return_val_if_fail (clist != NULL, 0);
1519 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
1521 if (row < 0 || row >= clist->rows)
1523 if (column < 0 || column >= clist->columns)
1526 clist_row = (g_list_nth (clist->row_list, row))->data;
1528 if (clist_row->cell[column].type != GTK_CELL_PIXTEXT)
1532 *text = GTK_CELL_PIXTEXT (clist_row->cell[column])->text;
1534 *spacing = GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing;
1536 *pixmap = GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap;
1538 /* mask can be NULL */
1539 *mask = GTK_CELL_PIXTEXT (clist_row->cell[column])->mask;
1545 gtk_clist_set_foreground (GtkCList * clist,
1549 GtkCListRow *clist_row;
1551 g_return_if_fail (clist != NULL);
1552 g_return_if_fail (GTK_IS_CLIST (clist));
1554 if (row < 0 || row >= clist->rows)
1557 clist_row = (g_list_nth (clist->row_list, row))->data;
1561 clist_row->foreground = *color;
1562 clist_row->fg_set = TRUE;
1565 clist_row->fg_set = FALSE;
1567 if (!GTK_CLIST_FROZEN (clist)
1568 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1569 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1573 gtk_clist_set_background (GtkCList * clist,
1577 GtkCListRow *clist_row;
1579 g_return_if_fail (clist != NULL);
1580 g_return_if_fail (GTK_IS_CLIST (clist));
1582 if (row < 0 || row >= clist->rows)
1585 clist_row = (g_list_nth (clist->row_list, row))->data;
1589 clist_row->background = *color;
1590 clist_row->bg_set = TRUE;
1593 clist_row->bg_set = FALSE;
1595 if (!GTK_CLIST_FROZEN (clist)
1596 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1597 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1601 gtk_clist_set_shift (GtkCList * clist,
1607 GtkCListRow *clist_row;
1609 g_return_if_fail (clist != NULL);
1610 g_return_if_fail (GTK_IS_CLIST (clist));
1612 if (row < 0 || row >= clist->rows)
1614 if (column < 0 || column >= clist->columns)
1617 clist_row = (g_list_nth (clist->row_list, row))->data;
1619 clist_row->cell[column].vertical = vertical;
1620 clist_row->cell[column].horizontal = horizontal;
1622 if (!GTK_CLIST_FROZEN (clist)
1623 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1624 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1628 gtk_clist_append (GtkCList * clist,
1631 g_return_val_if_fail (clist != NULL, -1);
1632 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1633 g_return_val_if_fail (text != NULL, -1);
1635 return gtk_clist_insert (clist, clist->rows, text);
1639 gtk_clist_insert (GtkCList * clist,
1644 GtkCListRow *clist_row;
1646 g_return_val_if_fail (clist != NULL, -1);
1647 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1648 g_return_val_if_fail (text != NULL, -1);
1650 /* return if out of bounds */
1651 if (row < 0 || row > clist->rows)
1654 /* create the row */
1655 clist_row = row_new (clist);
1657 /* set the text in the row's columns */
1658 for (i = 0; i < clist->columns; i++)
1660 cell_set_text (clist, clist_row, i, text[i]);
1664 clist->row_list = g_list_append (clist->row_list, clist_row);
1665 clist->row_list_end = clist->row_list;
1669 if (GTK_CLIST_AUTO_SORT (clist)) /* override insertion pos */
1674 work = clist->row_list;
1676 if (clist->sort_type == GTK_SORT_ASCENDING)
1678 while (row < clist->rows &&
1679 clist->compare (clist, clist_row,
1680 GTK_CLIST_ROW (work)) > 0)
1688 while (row < clist->rows &&
1689 clist->compare (clist, clist_row,
1690 GTK_CLIST_ROW (work)) < 0)
1698 /* reset the row end pointer if we're inserting at the end of the list */
1699 if (row == clist->rows)
1700 clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
1702 clist->row_list = g_list_insert (clist->row_list, clist_row, row);
1707 if (row < ROW_FROM_YPIXEL (clist, 0))
1708 clist->voffset -= (clist->row_height + CELL_SPACING);
1710 /* syncronize the selection list */
1711 sync_selection (clist, row, SYNC_INSERT);
1713 /* redraw the list if it isn't frozen */
1714 if (!GTK_CLIST_FROZEN (clist))
1716 adjust_scrollbars (clist);
1718 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1719 draw_rows (clist, NULL);
1726 gtk_clist_remove (GtkCList * clist,
1729 gint was_visible, was_selected;
1731 GtkCListRow *clist_row;
1733 g_return_if_fail (clist != NULL);
1734 g_return_if_fail (GTK_IS_CLIST (clist));
1736 /* return if out of bounds */
1737 if (row < 0 || row > (clist->rows - 1))
1740 was_visible = (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE);
1743 /* get the row we're going to delete */
1744 list = g_list_nth (clist->row_list, row);
1745 clist_row = list->data;
1747 /* if we're removing a selected row, we have to make sure
1748 * it's properly unselected, and then sync up the clist->selected
1749 * list to reflect the deincrimented indexies of rows after the
1751 if (clist_row->state == GTK_STATE_SELECTED)
1753 switch (clist->selection_mode)
1755 case GTK_SELECTION_SINGLE:
1756 case GTK_SELECTION_MULTIPLE:
1757 case GTK_SELECTION_EXTENDED:
1758 unselect_row (clist, row, -1, NULL);
1761 case GTK_SELECTION_BROWSE:
1762 select_row (clist, row - 1, -1, NULL);
1770 /* reset the row end pointer if we're removing at the
1771 * end of the list */
1772 if (row == clist->rows - 1)
1773 clist->row_list_end = list->prev;
1774 if (row >= clist->focus_row && clist->focus_row >=0)
1777 clist->row_list = g_list_remove (clist->row_list, clist_row);
1780 if (row < ROW_FROM_YPIXEL (clist, 0))
1781 clist->voffset += clist->row_height + CELL_SPACING;
1783 sync_selection (clist, row, SYNC_REMOVE);
1786 row_delete (clist, clist_row);
1788 /* redraw the row if it isn't frozen */
1789 if (!GTK_CLIST_FROZEN (clist))
1791 adjust_scrollbars (clist);
1794 draw_rows (clist, NULL);
1799 sync_selection (GtkCList * clist,
1806 if (mode == SYNC_INSERT)
1811 if (clist->focus_row >= row)
1813 clist->focus_row += d;
1814 if (clist->focus_row == -1 && clist->rows >= 1)
1815 clist->focus_row = 0;
1818 if (clist->selection_mode == GTK_SELECTION_BROWSE && clist->anchor != -1)
1819 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
1821 g_list_free (clist->undo_selection);
1822 g_list_free (clist->undo_unselection);
1823 clist->undo_selection = NULL;
1824 clist->undo_unselection = NULL;
1827 clist->drag_pos = -1;
1828 clist->undo_anchor = clist->focus_row;
1830 list = clist->selection;
1833 if (GPOINTER_TO_INT (list->data) >= row)
1834 list->data = ((gchar*) list->data) + d;
1840 gtk_clist_clear (GtkCList * clist)
1842 GTK_CLIST_CLASS_FW (clist)->clear (clist);
1846 real_clear (GtkCList * clist)
1850 g_return_if_fail (clist != NULL);
1851 g_return_if_fail (GTK_IS_CLIST (clist));
1853 /* remove all the rows */
1854 for (list = clist->row_list; list; list = list->next)
1855 row_delete (clist, GTK_CLIST_ROW (list));
1857 g_list_free (clist->row_list);
1859 /* free up the selection list */
1860 g_list_free (clist->selection);
1861 g_list_free (clist->undo_selection);
1862 g_list_free (clist->undo_unselection);
1864 clist->row_list = NULL;
1865 clist->row_list_end = NULL;
1866 clist->selection = NULL;
1867 clist->selection_end = NULL;
1868 clist->undo_selection = NULL;
1869 clist->undo_unselection = NULL;
1872 clist->focus_row = -1;
1874 clist->undo_anchor = -1;
1875 clist->anchor_state = GTK_STATE_SELECTED;
1876 clist->drag_pos = -1;
1878 /* zero-out the scrollbars */
1879 if (clist->vscrollbar)
1881 GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0;
1882 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
1884 if (!GTK_CLIST_FROZEN (clist))
1885 gtk_clist_thaw (clist);
1890 gtk_clist_swap_rows (GtkCList * clist,
1895 GList *list, *link1, *link2;
1898 g_return_if_fail (clist != NULL);
1899 g_return_if_fail (GTK_IS_CLIST (clist));
1901 if (GTK_CLIST_AUTO_SORT (clist))
1904 if (row1 < 0 || row1 > (clist->rows - 1))
1907 if (row2 < 0 || row2 > (clist->rows - 1))
1910 first = MIN (row1, row2);
1911 last = MAX (row1, row2);
1913 link1 = g_list_nth (clist->row_list, first);
1914 link2 = g_list_nth (link1, row2 - row1);
1917 link1->data = link2->data;
1920 list = clist->selection;
1923 if (GPOINTER_TO_INT (list->data) == row1)
1924 GPOINTER_TO_INT (list->data) = row2;
1926 if (GPOINTER_TO_INT (list->data) == row2)
1927 GPOINTER_TO_INT (list->data) = row1;
1932 if (!GTK_CLIST_FROZEN (clist))
1934 if (gtk_clist_row_is_visible (clist, row1) != GTK_VISIBILITY_NONE)
1935 GTK_CLIST_CLASS_FW (clist)->draw_row
1936 (clist, NULL, row1, GTK_CLIST_ROW (link2));
1938 if (gtk_clist_row_is_visible (clist, row2) != GTK_VISIBILITY_NONE)
1939 GTK_CLIST_CLASS_FW (clist)->draw_row
1940 (clist, NULL, row2, GTK_CLIST_ROW (link1));
1945 gtk_clist_set_row_data (GtkCList * clist,
1949 gtk_clist_set_row_data_full (clist, row, data, NULL);
1953 gtk_clist_set_row_data_full (GtkCList * clist,
1956 GtkDestroyNotify destroy)
1958 GtkCListRow *clist_row;
1960 g_return_if_fail (clist != NULL);
1961 g_return_if_fail (GTK_IS_CLIST (clist));
1963 if (row < 0 || row > (clist->rows - 1))
1966 clist_row = (g_list_nth (clist->row_list, row))->data;
1967 clist_row->data = data;
1968 clist_row->destroy = destroy;
1970 /* re-send the selected signal if data is changed/added
1971 * so the application can respond to the new data --
1972 * this could be questionable behavior */
1973 if (clist_row->state == GTK_STATE_SELECTED)
1974 select_row (clist, row, -1, NULL);
1978 gtk_clist_get_row_data (GtkCList * clist,
1981 GtkCListRow *clist_row;
1983 g_return_val_if_fail (clist != NULL, NULL);
1984 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
1986 if (row < 0 || row > (clist->rows - 1))
1989 clist_row = (g_list_nth (clist->row_list, row))->data;
1990 return clist_row->data;
1994 gtk_clist_find_row_from_data (GtkCList * clist,
2000 g_return_val_if_fail (clist != NULL, -1);
2001 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
2003 if (clist->rows < 1)
2004 return -1; /* is this an optimization or just worthless? */
2006 for (n = 0, list = clist->row_list; list; n++, list = list->next)
2007 if (GTK_CLIST_ROW (list)->data == data)
2014 gtk_clist_select_row (GtkCList * clist,
2018 g_return_if_fail (clist != NULL);
2019 g_return_if_fail (GTK_IS_CLIST (clist));
2021 if (row < 0 || row >= clist->rows)
2024 if (column < -1 || column >= clist->columns)
2027 select_row (clist, row, column, NULL);
2031 gtk_clist_unselect_row (GtkCList * clist,
2035 g_return_if_fail (clist != NULL);
2036 g_return_if_fail (GTK_IS_CLIST (clist));
2038 if (row < 0 || row >= clist->rows)
2041 if (column < -1 || column >= clist->columns)
2044 unselect_row (clist, row, column, NULL);
2048 gtk_clist_row_is_visible (GtkCList * clist,
2053 g_return_val_if_fail (clist != NULL, 0);
2054 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
2056 if (row < 0 || row >= clist->rows)
2057 return GTK_VISIBILITY_NONE;
2059 if (clist->row_height == 0)
2060 return GTK_VISIBILITY_NONE;
2062 if (row < ROW_FROM_YPIXEL (clist, 0))
2063 return GTK_VISIBILITY_NONE;
2065 if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height))
2066 return GTK_VISIBILITY_NONE;
2068 top = ROW_TOP_YPIXEL (clist, row);
2071 || ((top + clist->row_height) >= clist->clist_window_height))
2072 return GTK_VISIBILITY_PARTIAL;
2074 return GTK_VISIBILITY_FULL;
2078 gtk_clist_get_vadjustment (GtkCList * clist)
2080 g_return_val_if_fail (clist != NULL, NULL);
2081 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2083 return gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
2087 gtk_clist_get_hadjustment (GtkCList * clist)
2089 g_return_val_if_fail (clist != NULL, NULL);
2090 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2092 return gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
2096 gtk_clist_set_policy (GtkCList * clist,
2097 GtkPolicyType vscrollbar_policy,
2098 GtkPolicyType hscrollbar_policy)
2100 g_return_if_fail (clist != NULL);
2101 g_return_if_fail (GTK_IS_CLIST (clist));
2103 if (clist->vscrollbar_policy != vscrollbar_policy)
2105 clist->vscrollbar_policy = vscrollbar_policy;
2107 if (GTK_WIDGET (clist)->parent)
2108 gtk_widget_queue_resize (GTK_WIDGET (clist));
2111 if (clist->hscrollbar_policy != hscrollbar_policy)
2113 clist->hscrollbar_policy = hscrollbar_policy;
2115 if (GTK_WIDGET (clist)->parent)
2116 gtk_widget_queue_resize (GTK_WIDGET (clist));
2121 gtk_clist_undo_selection (GtkCList *clist)
2123 g_return_if_fail (clist != NULL);
2124 g_return_if_fail (GTK_IS_CLIST (clist));
2126 if (clist->selection_mode == GTK_SELECTION_EXTENDED &&
2127 (clist->undo_selection || clist->undo_unselection))
2128 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNDO_SELECTION]);
2132 real_undo_selection (GtkCList *clist)
2136 g_return_if_fail (clist != NULL);
2137 g_return_if_fail (GTK_IS_CLIST (clist));
2139 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
2140 clist->selection_mode != GTK_SELECTION_EXTENDED)
2143 if (clist->anchor >= 0)
2144 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
2146 if (!(clist->undo_selection || clist->undo_unselection))
2148 gtk_clist_unselect_all (clist);
2152 for (work = clist->undo_selection; work; work = work->next)
2153 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
2154 GPOINTER_TO_INT (work->data), -1, NULL);
2156 for (work = clist->undo_unselection; work; work = work->next)
2157 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
2158 GPOINTER_TO_INT (work->data), -1, NULL);
2160 if (GTK_WIDGET_HAS_FOCUS (clist) && clist->focus_row != clist->undo_anchor)
2162 gtk_clist_draw_focus (GTK_WIDGET (clist));
2163 clist->focus_row = clist->undo_anchor;
2164 gtk_clist_draw_focus (GTK_WIDGET (clist));
2167 clist->focus_row = clist->undo_anchor;
2169 clist->undo_anchor = -1;
2171 g_list_free (clist->undo_selection);
2172 g_list_free (clist->undo_unselection);
2173 clist->undo_selection = NULL;
2174 clist->undo_unselection = NULL;
2176 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
2177 clist->clist_window_height)
2178 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
2179 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
2180 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
2186 * gtk_clist_finalize
2189 gtk_clist_destroy (GtkObject * object)
2194 g_return_if_fail (object != NULL);
2195 g_return_if_fail (GTK_IS_CLIST (object));
2197 clist = GTK_CLIST (object);
2199 /* freeze the list */
2200 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2202 /* get rid of all the rows */
2203 gtk_clist_clear (clist);
2205 /* Since we don't have a _remove method, unparent the children
2206 * instead of destroying them so the focus will be unset properly.
2207 * (For other containers, the _remove method takes care of the
2208 * unparent) The destroy will happen when the refcount drops
2212 /* destroy the scrollbars */
2213 if (clist->vscrollbar)
2215 gtk_widget_unparent (clist->vscrollbar);
2216 clist->vscrollbar = NULL;
2218 if (clist->hscrollbar)
2220 gtk_widget_unparent (clist->hscrollbar);
2221 clist->hscrollbar = NULL;
2226 gtk_timeout_remove (clist->htimer);
2231 gtk_timeout_remove (clist->vtimer);
2235 /* destroy the column buttons */
2236 for (i = 0; i < clist->columns; i++)
2237 if (clist->column[i].button)
2239 gtk_widget_unparent (clist->column[i].button);
2240 clist->column[i].button = NULL;
2243 if (GTK_OBJECT_CLASS (parent_class)->destroy)
2244 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2248 gtk_clist_finalize (GtkObject * object)
2252 g_return_if_fail (object != NULL);
2253 g_return_if_fail (GTK_IS_CLIST (object));
2255 clist = GTK_CLIST (object);
2257 columns_delete (clist);
2259 g_mem_chunk_destroy (clist->cell_mem_chunk);
2260 g_mem_chunk_destroy (clist->row_mem_chunk);
2262 if (GTK_OBJECT_CLASS (parent_class)->finalize)
2263 (*GTK_OBJECT_CLASS (parent_class)->finalize) (object);
2269 * gtk_clist_unrealize
2274 * gtk_clist_button_press
2275 * gtk_clist_button_release
2277 * gtk_clist_size_request
2278 * gtk_clist_size_allocate
2281 gtk_clist_realize (GtkWidget * widget)
2285 GdkWindowAttr attributes;
2286 gint attributes_mask;
2290 g_return_if_fail (widget != NULL);
2291 g_return_if_fail (GTK_IS_CLIST (widget));
2293 clist = GTK_CLIST (widget);
2295 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2297 add_style_data (clist);
2299 border_width = GTK_CONTAINER (widget)->border_width;
2301 attributes.window_type = GDK_WINDOW_CHILD;
2302 attributes.x = widget->allocation.x + border_width;
2303 attributes.y = widget->allocation.y + border_width;
2304 attributes.width = widget->allocation.width - border_width * 2;
2305 attributes.height = widget->allocation.height - border_width * 2;
2306 attributes.wclass = GDK_INPUT_OUTPUT;
2307 attributes.visual = gtk_widget_get_visual (widget);
2308 attributes.colormap = gtk_widget_get_colormap (widget);
2309 attributes.event_mask = gtk_widget_get_events (widget);
2310 attributes.event_mask |= (GDK_EXPOSURE_MASK |
2311 GDK_BUTTON_PRESS_MASK |
2312 GDK_BUTTON_RELEASE_MASK |
2313 GDK_KEY_PRESS_MASK |
2314 GDK_KEY_RELEASE_MASK);
2315 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2318 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
2319 gdk_window_set_user_data (widget->window, clist);
2321 widget->style = gtk_style_attach (widget->style, widget->window);
2323 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
2325 /* column-title window */
2327 attributes.x = clist->column_title_area.x;
2328 attributes.y = clist->column_title_area.y;
2329 attributes.width = clist->column_title_area.width;
2330 attributes.height = clist->column_title_area.height;
2332 clist->title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2333 gdk_window_set_user_data (clist->title_window, clist);
2335 gtk_style_set_background (widget->style, clist->title_window, GTK_STATE_SELECTED);
2336 gdk_window_show (clist->title_window);
2338 /* set things up so column buttons are drawn in title window */
2339 for (i = 0; i < clist->columns; i++)
2340 if (clist->column[i].button)
2341 gtk_widget_set_parent_window (clist->column[i].button, clist->title_window);
2344 attributes.x = clist->internal_allocation.x + widget->style->klass->xthickness;
2345 attributes.y = clist->internal_allocation.y + widget->style->klass->ythickness +
2346 clist->column_title_area.height;
2347 attributes.width = clist->clist_window_width;
2348 attributes.height = clist->clist_window_height;
2350 clist->clist_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2351 gdk_window_set_user_data (clist->clist_window, clist);
2353 gdk_window_set_background (clist->clist_window, &widget->style->bg[GTK_STATE_PRELIGHT]);
2354 gdk_window_show (clist->clist_window);
2355 gdk_window_get_size (clist->clist_window, &clist->clist_window_width,
2356 &clist->clist_window_height);
2358 /* create resize windows */
2359 attributes.wclass = GDK_INPUT_ONLY;
2360 attributes.event_mask = (GDK_BUTTON_PRESS_MASK |
2361 GDK_BUTTON_RELEASE_MASK |
2362 GDK_POINTER_MOTION_MASK |
2363 GDK_POINTER_MOTION_HINT_MASK |
2364 GDK_KEY_PRESS_MASK);
2365 attributes.cursor = clist->cursor_drag = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
2366 attributes_mask = GDK_WA_CURSOR;
2368 for (i = 0; i < clist->columns; i++)
2370 clist->column[i].window = gdk_window_new (clist->title_window, &attributes, attributes_mask);
2371 gdk_window_set_user_data (clist->column[i].window, clist);
2374 /* This is slightly less efficient than creating them with the
2375 * right size to begin with, but easier
2377 size_allocate_title_buttons (clist);
2380 clist->fg_gc = gdk_gc_new (widget->window);
2381 clist->bg_gc = gdk_gc_new (widget->window);
2383 /* We'll use this gc to do scrolling as well */
2384 gdk_gc_set_exposures (clist->fg_gc, TRUE);
2386 values.foreground = widget->style->white;
2387 values.function = GDK_XOR;
2388 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
2389 clist->xor_gc = gdk_gc_new_with_values (widget->window,
2397 gtk_clist_unrealize (GtkWidget * widget)
2402 g_return_if_fail (widget != NULL);
2403 g_return_if_fail (GTK_IS_CLIST (widget));
2405 clist = GTK_CLIST (widget);
2407 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2409 gdk_cursor_destroy (clist->cursor_drag);
2410 gdk_gc_destroy (clist->xor_gc);
2411 gdk_gc_destroy (clist->fg_gc);
2412 gdk_gc_destroy (clist->bg_gc);
2414 for (i = 0; i < clist->columns; i++)
2415 if (clist->column[i].window)
2417 gdk_window_set_user_data (clist->column[i].window, NULL);
2418 gdk_window_destroy (clist->column[i].window);
2419 clist->column[i].window = NULL;
2422 gdk_window_set_user_data (clist->clist_window, NULL);
2423 gdk_window_destroy (clist->clist_window);
2424 clist->clist_window = NULL;
2426 gdk_window_set_user_data (clist->title_window, NULL);
2427 gdk_window_destroy (clist->title_window);
2428 clist->title_window = NULL;
2430 clist->cursor_drag = NULL;
2431 clist->xor_gc = NULL;
2432 clist->fg_gc = NULL;
2433 clist->bg_gc = NULL;
2435 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
2436 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2440 gtk_clist_map (GtkWidget * widget)
2445 g_return_if_fail (widget != NULL);
2446 g_return_if_fail (GTK_IS_CLIST (widget));
2448 clist = GTK_CLIST (widget);
2450 if (!GTK_WIDGET_MAPPED (widget))
2452 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
2454 gdk_window_show (widget->window);
2455 gdk_window_show (clist->title_window);
2456 gdk_window_show (clist->clist_window);
2458 /* map column buttons */
2459 for (i = 0; i < clist->columns; i++)
2460 if (clist->column[i].button &&
2461 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
2462 !GTK_WIDGET_MAPPED (clist->column[i].button))
2463 gtk_widget_map (clist->column[i].button);
2465 /* map resize windows AFTER column buttons (above) */
2466 for (i = 0; i < clist->columns; i++)
2467 if (clist->column[i].window && clist->column[i].button)
2468 gdk_window_show (clist->column[i].window);
2470 /* map vscrollbars */
2471 if (GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
2472 !GTK_WIDGET_MAPPED (clist->vscrollbar))
2473 gtk_widget_map (clist->vscrollbar);
2475 if (GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
2476 !GTK_WIDGET_MAPPED (clist->hscrollbar))
2477 gtk_widget_map (clist->hscrollbar);
2479 /* unfreeze the list */
2480 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
2485 gtk_clist_unmap (GtkWidget * widget)
2490 g_return_if_fail (widget != NULL);
2491 g_return_if_fail (GTK_IS_CLIST (widget));
2493 clist = GTK_CLIST (widget);
2495 if (GTK_WIDGET_MAPPED (widget))
2497 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
2499 for (i = 0; i < clist->columns; i++)
2500 if (clist->column[i].window)
2501 gdk_window_hide (clist->column[i].window);
2503 gdk_window_hide (clist->clist_window);
2504 gdk_window_hide (clist->title_window);
2505 gdk_window_hide (widget->window);
2507 /* unmap scrollbars */
2508 if (GTK_WIDGET_MAPPED (clist->vscrollbar))
2509 gtk_widget_unmap (clist->vscrollbar);
2511 if (GTK_WIDGET_MAPPED (clist->hscrollbar))
2512 gtk_widget_unmap (clist->hscrollbar);
2514 /* unmap column buttons */
2515 for (i = 0; i < clist->columns; i++)
2516 if (clist->column[i].button &&
2517 GTK_WIDGET_MAPPED (clist->column[i].button))
2518 gtk_widget_unmap (clist->column[i].button);
2520 /* freeze the list */
2521 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2526 gtk_clist_draw (GtkWidget * widget,
2527 GdkRectangle * area)
2531 GdkRectangle child_area;
2534 g_return_if_fail (widget != NULL);
2535 g_return_if_fail (GTK_IS_CLIST (widget));
2536 g_return_if_fail (area != NULL);
2538 if (GTK_WIDGET_DRAWABLE (widget))
2540 clist = GTK_CLIST (widget);
2541 border_width = GTK_CONTAINER (widget)->border_width;
2543 gdk_window_clear_area (widget->window,
2544 area->x - border_width,
2545 area->y - border_width,
2546 area->width, area->height);
2548 /* draw list shadow/border */
2549 gtk_draw_shadow (widget->style, widget->window,
2550 GTK_STATE_NORMAL, clist->shadow_type,
2552 clist->clist_window_width + (2 * widget->style->klass->xthickness),
2553 clist->clist_window_height + (2 * widget->style->klass->ythickness) +
2554 clist->column_title_area.height);
2556 gdk_window_clear_area (clist->clist_window,
2559 draw_rows (clist, NULL);
2561 for (i = 0; i < clist->columns; i++)
2563 if (gtk_widget_intersect (clist->column[i].button, area, &child_area))
2564 gtk_widget_draw (clist->column[i].button, &child_area);
2570 gtk_clist_expose (GtkWidget * widget,
2571 GdkEventExpose * event)
2575 g_return_val_if_fail (widget != NULL, FALSE);
2576 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2577 g_return_val_if_fail (event != NULL, FALSE);
2579 if (GTK_WIDGET_DRAWABLE (widget))
2581 clist = GTK_CLIST (widget);
2584 if (event->window == widget->window)
2585 gtk_draw_shadow (widget->style, widget->window,
2586 GTK_STATE_NORMAL, clist->shadow_type,
2588 clist->clist_window_width + (2 * widget->style->klass->xthickness),
2589 clist->clist_window_height + (2 * widget->style->klass->ythickness) +
2590 clist->column_title_area.height);
2592 /* exposure events on the list */
2593 if (event->window == clist->clist_window)
2594 draw_rows (clist, &event->area);
2601 gtk_clist_button_press (GtkWidget * widget,
2602 GdkEventButton * event)
2611 g_return_val_if_fail (widget != NULL, FALSE);
2612 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2613 g_return_val_if_fail (event != NULL, FALSE);
2615 clist = GTK_CLIST (widget);
2617 /* we don't handle button 2 and 3 */
2618 if (event->button != 1)
2621 /* selections on the list */
2622 if (event->window == clist->clist_window)
2627 if (get_selection_info (clist, x, y, &row, &column))
2629 gint old_row = clist->focus_row;
2631 if (clist->focus_row == -1)
2634 if (event->type == GDK_BUTTON_PRESS)
2636 GTK_CLIST_SET_FLAG (clist, CLIST_DRAG_SELECTION);
2637 gdk_pointer_grab (clist->clist_window, FALSE,
2638 GDK_POINTER_MOTION_HINT_MASK |
2639 GDK_BUTTON1_MOTION_MASK |
2640 GDK_BUTTON_RELEASE_MASK,
2641 NULL, NULL, event->time);
2642 gtk_grab_add (widget);
2644 else if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (widget))
2646 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
2647 gtk_grab_remove (widget);
2648 gdk_pointer_ungrab (event->time);
2651 if (GTK_CLIST_ADD_MODE (clist))
2653 GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
2654 if (GTK_WIDGET_HAS_FOCUS (widget))
2656 gtk_clist_draw_focus (widget);
2657 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2658 GDK_LINE_SOLID, 0, 0);
2659 clist->focus_row = row;
2660 gtk_clist_draw_focus (widget);
2664 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2665 GDK_LINE_SOLID, 0, 0);
2666 clist->focus_row = row;
2669 else if (row != clist->focus_row)
2671 if (GTK_WIDGET_HAS_FOCUS (widget))
2673 gtk_clist_draw_focus (widget);
2674 clist->focus_row = row;
2675 gtk_clist_draw_focus (widget);
2678 clist->focus_row = row;
2681 if (!GTK_WIDGET_HAS_FOCUS (widget))
2682 gtk_widget_grab_focus (widget);
2684 switch (clist->selection_mode)
2686 case GTK_SELECTION_SINGLE:
2687 case GTK_SELECTION_MULTIPLE:
2688 if (event->type != GDK_BUTTON_PRESS)
2689 select_row (clist, row, column, (GdkEvent *) event);
2691 clist->anchor = row;
2694 case GTK_SELECTION_BROWSE:
2695 select_row (clist, row, column, (GdkEvent *) event);
2698 case GTK_SELECTION_EXTENDED:
2699 if (event->type != GDK_BUTTON_PRESS)
2701 if (clist->anchor != -1)
2703 update_extended_selection (clist, clist->focus_row);
2704 GTK_CLIST_CLASS_FW (clist)->resync_selection
2705 (clist, (GdkEvent *) event);
2707 select_row (clist, row, column, (GdkEvent *) event);
2711 if (event->state & GDK_CONTROL_MASK)
2713 if (event->state & GDK_SHIFT_MASK)
2715 if (clist->anchor < 0)
2717 g_list_free (clist->undo_selection);
2718 g_list_free (clist->undo_unselection);
2719 clist->undo_selection = NULL;
2720 clist->undo_unselection = NULL;
2721 clist->anchor = old_row;
2722 clist->drag_pos = old_row;
2723 clist->undo_anchor = old_row;
2725 update_extended_selection (clist, clist->focus_row);
2729 if (clist->anchor == -1)
2730 set_anchor (clist, TRUE, row, old_row);
2732 update_extended_selection (clist, clist->focus_row);
2737 if (event->state & GDK_SHIFT_MASK)
2739 set_anchor (clist, FALSE, old_row, old_row);
2740 update_extended_selection (clist, clist->focus_row);
2744 if (clist->anchor == -1)
2745 set_anchor (clist, FALSE, row, old_row);
2747 update_extended_selection (clist, clist->focus_row);
2758 /* press on resize windows */
2759 for (i = 0; i < clist->columns; i++)
2760 if (clist->column[i].window && event->window == clist->column[i].window)
2762 if (!GTK_WIDGET_HAS_FOCUS (widget))
2763 gtk_widget_grab_focus (widget);
2765 GTK_CLIST_SET_FLAG (clist, CLIST_IN_DRAG);
2766 gtk_widget_get_pointer (widget, &clist->x_drag, NULL);
2768 gdk_pointer_grab (clist->column[i].window, FALSE,
2769 GDK_POINTER_MOTION_HINT_MASK |
2770 GDK_BUTTON1_MOTION_MASK |
2771 GDK_BUTTON_RELEASE_MASK,
2772 NULL, NULL, event->time);
2773 gtk_grab_add (widget);
2775 if (GTK_CLIST_ADD_MODE (clist))
2776 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
2778 draw_xor_line (clist);
2779 clist->drag_pos = i;
2787 gtk_clist_button_release (GtkWidget * widget,
2788 GdkEventButton * event)
2792 g_return_val_if_fail (widget != NULL, FALSE);
2793 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2794 g_return_val_if_fail (event != NULL, FALSE);
2796 clist = GTK_CLIST (widget);
2798 /* we don't handle button 2 and 3 */
2799 if (event->button != 1)
2802 /* release on resize windows */
2803 if (GTK_CLIST_IN_DRAG (clist))
2805 gint i, x, width, visible;
2807 i = clist->drag_pos;
2808 clist->drag_pos = -1;
2809 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
2810 gtk_widget_get_pointer (widget, &x, NULL);
2812 width = new_column_width (clist, i, &x, &visible);
2813 gtk_grab_remove (widget);
2814 gdk_pointer_ungrab (event->time);
2817 draw_xor_line (clist);
2819 if (GTK_CLIST_ADD_MODE (clist))
2821 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2822 GDK_LINE_ON_OFF_DASH, 0, 0);
2823 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
2826 resize_column (clist, i, width);
2830 if (GTK_CLIST_DRAG_SELECTION (clist))
2835 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
2836 gtk_grab_remove (widget);
2837 gdk_pointer_ungrab (event->time);
2840 gtk_timeout_remove (clist->htimer);
2845 gtk_timeout_remove (clist->vtimer);
2848 switch (clist->selection_mode)
2850 case GTK_SELECTION_EXTENDED:
2851 if (!(event->state & GDK_SHIFT_MASK) ||
2852 event->x < 0 || event->x >= clist->clist_window_width ||
2853 event->y < 0 || event->y >= clist->clist_window_height)
2854 GTK_CLIST_CLASS_FW (clist)->resync_selection
2855 (clist, (GdkEvent *) event);
2858 case GTK_SELECTION_SINGLE:
2859 case GTK_SELECTION_MULTIPLE:
2860 if (get_selection_info (clist, event->x, event->y, &row, &column))
2862 if (clist->anchor == clist->focus_row)
2863 toggle_row (clist, row, column, (GdkEvent *) event);
2877 horizontal_timeout (GtkCList *clist)
2880 GdkEventMotion event;
2881 GdkModifierType mask;
2883 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
2886 gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
2893 gtk_clist_motion (GTK_WIDGET (clist), &event);
2899 vertical_timeout (GtkCList *clist)
2902 GdkEventMotion event;
2903 GdkModifierType mask;
2905 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
2908 gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
2915 gtk_clist_motion (GTK_WIDGET (clist), &event);
2921 move_vertical (GtkCList *clist,
2928 adj = GTK_RANGE (clist->vscrollbar)->adjustment;
2930 y = ROW_TOP_YPIXEL (clist, row) - clist->voffset;
2932 y = y - align * (clist->clist_window_height - clist->row_height)
2933 + (2 * align - 1) * CELL_SPACING;
2935 if (y + adj->page_size > adj->upper)
2936 adj->value = adj->upper - adj->page_size;
2940 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
2944 move_horizontal (GtkCList *clist,
2950 adj = GTK_RANGE (clist->hscrollbar)->adjustment;
2954 upper = adj->upper - adj->page_size;
2955 adj->value = MIN (adj->value, upper);
2956 adj->value = MAX (adj->value, 0.0);
2958 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
2962 gtk_clist_motion (GtkWidget * widget,
2963 GdkEventMotion * event)
2971 g_return_val_if_fail (widget != NULL, FALSE);
2972 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2974 clist = GTK_CLIST (widget);
2976 if (!(gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)))
2979 if (GTK_CLIST_IN_DRAG (clist))
2981 if (event->is_hint || event->window != widget->window)
2982 gtk_widget_get_pointer (widget, &x, NULL);
2986 new_width = new_column_width (clist, clist->drag_pos, &x, &visible);
2987 /* Welcome to my hack! I'm going to use a value of x_drag = -99999
2988 * to indicate that the xor line is already invisible */
2990 if (!visible && clist->x_drag != -99999)
2992 draw_xor_line (clist);
2993 clist->x_drag = -99999;
2996 if (x != clist->x_drag && visible)
2998 if (clist->x_drag != -99999)
2999 draw_xor_line (clist);
3002 draw_xor_line (clist);
3005 if (new_width <= COLUMN_MIN_WIDTH + 1)
3007 if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) && x < 0)
3008 gtk_clist_moveto (clist, -1, clist->drag_pos, 0, 0);
3014 if (event->is_hint || event->window != clist->clist_window)
3015 gdk_window_get_pointer (clist->clist_window, &x, &y, NULL);
3017 /* horizontal autoscrolling */
3018 if (LIST_WIDTH (clist) > clist->clist_window_width &&
3019 (x < 0 || x >= clist->clist_window_width))
3024 clist->htimer = gtk_timeout_add
3025 (SCROLL_TIME, (GtkFunction) horizontal_timeout, clist);
3027 if (!((x < 0 && GTK_RANGE (clist->hscrollbar)->adjustment->value == 0) ||
3028 (x >= clist->clist_window_width &&
3029 GTK_RANGE (clist->hscrollbar)->adjustment->value ==
3030 LIST_WIDTH (clist) - clist->clist_window_width)))
3033 move_horizontal (clist, -1 + (x/2));
3035 move_horizontal (clist, 1 + (x - clist->clist_window_width) / 2);
3039 if (GTK_CLIST_IN_DRAG (clist))
3042 /* vertical autoscrolling */
3043 row = ROW_FROM_YPIXEL (clist, y);
3045 /* don't scroll on last pixel row if it's a cell spacing */
3046 if (y == clist->clist_window_height-1 &&
3047 y == ROW_TOP_YPIXEL (clist, row-1) + clist->row_height)
3050 if (LIST_HEIGHT (clist) > clist->clist_window_height &&
3051 (y < 0 || y >= clist->clist_window_height))
3056 clist->vtimer = gtk_timeout_add (SCROLL_TIME,
3057 (GtkFunction) vertical_timeout, clist);
3059 if (GTK_CLIST_DRAG_SELECTION (clist))
3061 if ((y < 0 && clist->focus_row == 0) ||
3062 (y >= clist->clist_window_height &&
3063 clist->focus_row == clist->rows-1))
3068 row = CLAMP (row, 0, clist->rows - 1);
3070 if (GTK_CLIST_DRAG_SELECTION (clist))
3072 if (row == clist->focus_row)
3075 gtk_clist_draw_focus (widget);
3076 clist->focus_row = row;
3077 gtk_clist_draw_focus (widget);
3079 switch (clist->selection_mode)
3081 case GTK_SELECTION_BROWSE:
3082 select_row (clist, clist->focus_row, - 1, (GdkEvent *) event);
3085 case GTK_SELECTION_EXTENDED:
3086 update_extended_selection (clist, clist->focus_row);
3094 if (ROW_TOP_YPIXEL(clist, row) < 0)
3095 move_vertical (clist, row, 0);
3096 else if (ROW_TOP_YPIXEL(clist, row) + clist->row_height >
3097 clist->clist_window_height)
3098 move_vertical (clist, row, 1);
3104 gtk_clist_size_request (GtkWidget * widget,
3105 GtkRequisition * requisition)
3110 g_return_if_fail (widget != NULL);
3111 g_return_if_fail (GTK_IS_CLIST (widget));
3112 g_return_if_fail (requisition != NULL);
3114 clist = GTK_CLIST (widget);
3116 add_style_data (clist);
3118 requisition->width = 0;
3119 requisition->height = 0;
3121 /* compute the size of the column title (title) area */
3122 clist->column_title_area.height = 0;
3123 if (GTK_CLIST_SHOW_TITLES (clist))
3124 for (i = 0; i < clist->columns; i++)
3125 if (clist->column[i].button)
3127 gtk_widget_size_request (clist->column[i].button, &clist->column[i].button->requisition);
3128 clist->column_title_area.height = MAX (clist->column_title_area.height,
3129 clist->column[i].button->requisition.height);
3131 requisition->height += clist->column_title_area.height;
3133 /* add the vscrollbar space */
3134 if ((clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
3135 GTK_WIDGET_VISIBLE (clist->vscrollbar))
3137 gtk_widget_size_request (clist->vscrollbar, &clist->vscrollbar->requisition);
3139 requisition->width += clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist);
3140 requisition->height = MAX (requisition->height,
3141 clist->vscrollbar->requisition.height);
3144 /* add the hscrollbar space */
3145 if ((clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
3146 GTK_WIDGET_VISIBLE (clist->hscrollbar))
3148 gtk_widget_size_request (clist->hscrollbar, &clist->hscrollbar->requisition);
3150 requisition->height += clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist);
3151 requisition->width = MAX (clist->hscrollbar->requisition.width,
3152 requisition->width -
3153 clist->vscrollbar->requisition.width);
3157 requisition->width += widget->style->klass->xthickness * 2 +
3158 GTK_CONTAINER (widget)->border_width * 2;
3159 requisition->height += widget->style->klass->ythickness * 2 +
3160 GTK_CONTAINER (widget)->border_width * 2;
3164 gtk_clist_size_allocate (GtkWidget * widget,
3165 GtkAllocation * allocation)
3168 GtkAllocation clist_allocation;
3169 GtkAllocation child_allocation;
3170 gint i, vscrollbar_vis, hscrollbar_vis;
3172 g_return_if_fail (widget != NULL);
3173 g_return_if_fail (GTK_IS_CLIST (widget));
3174 g_return_if_fail (allocation != NULL);
3176 clist = GTK_CLIST (widget);
3177 widget->allocation = *allocation;
3179 if (GTK_WIDGET_REALIZED (widget))
3181 gdk_window_move_resize (widget->window,
3182 allocation->x + GTK_CONTAINER (widget)->border_width,
3183 allocation->y + GTK_CONTAINER (widget)->border_width,
3184 allocation->width - GTK_CONTAINER (widget)->border_width * 2,
3185 allocation->height - GTK_CONTAINER (widget)->border_width * 2);
3188 /* use internal allocation structure for all the math
3189 * because it's easier than always subtracting the container
3191 clist->internal_allocation.x = 0;
3192 clist->internal_allocation.y = 0;
3193 clist->internal_allocation.width = MAX (1, allocation->width -
3194 GTK_CONTAINER (widget)->border_width * 2);
3195 clist->internal_allocation.height = MAX (1, allocation->height -
3196 GTK_CONTAINER (widget)->border_width * 2);
3198 /* allocate clist window assuming no scrollbars */
3199 clist_allocation.x = clist->internal_allocation.x + widget->style->klass->xthickness;
3200 clist_allocation.y = clist->internal_allocation.y + widget->style->klass->ythickness +
3201 clist->column_title_area.height;
3202 clist_allocation.width = MAX (1, clist->internal_allocation.width -
3203 (2 * widget->style->klass->xthickness));
3204 clist_allocation.height = MAX (1, clist->internal_allocation.height -
3205 (2 * widget->style->klass->ythickness) -
3206 clist->column_title_area.height);
3209 * here's where we decide to show/not show the scrollbars
3214 for (i = 0; i <= 1; i++)
3216 if (LIST_HEIGHT (clist) <= clist_allocation.height &&
3217 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
3223 if (!vscrollbar_vis)
3226 clist_allocation.width = MAX (1, clist_allocation.width -
3227 (clist->vscrollbar->requisition.width +
3228 SCROLLBAR_SPACING (clist)));
3232 if (LIST_WIDTH (clist) <= clist_allocation.width &&
3233 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
3239 if (!hscrollbar_vis)
3242 clist_allocation.height = MAX (1, clist_allocation.height -
3243 (clist->hscrollbar->requisition.height +
3244 SCROLLBAR_SPACING (clist)));
3249 clist->clist_window_width = clist_allocation.width;
3250 clist->clist_window_height = clist_allocation.height;
3252 if (GTK_WIDGET_REALIZED (widget))
3254 gdk_window_move_resize (clist->clist_window,
3257 clist_allocation.width,
3258 clist_allocation.height);
3261 /* position the window which holds the column title buttons */
3262 clist->column_title_area.x = widget->style->klass->xthickness;
3263 clist->column_title_area.y = widget->style->klass->ythickness;
3264 clist->column_title_area.width = clist_allocation.width;
3266 if (GTK_WIDGET_REALIZED (widget))
3268 gdk_window_move_resize (clist->title_window,
3269 clist->column_title_area.x,
3270 clist->column_title_area.y,
3271 clist->column_title_area.width,
3272 clist->column_title_area.height);
3275 /* column button allocation */
3276 size_allocate_columns (clist);
3278 if (GTK_WIDGET_REALIZED (widget))
3279 size_allocate_title_buttons (clist);
3281 adjust_scrollbars (clist);
3283 /* allocate the vscrollbar */
3286 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
3287 gtk_widget_show (clist->vscrollbar);
3289 child_allocation.x = clist->internal_allocation.x +
3290 clist->internal_allocation.width -
3291 clist->vscrollbar->requisition.width;
3292 child_allocation.y = clist->internal_allocation.y;
3293 child_allocation.width = clist->vscrollbar->requisition.width;
3294 child_allocation.height = MAX (1, clist->internal_allocation.height -
3295 (hscrollbar_vis ? (clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist)) : 0));
3297 gtk_widget_size_allocate (clist->vscrollbar, &child_allocation);
3301 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
3302 gtk_widget_hide (clist->vscrollbar);
3307 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
3308 gtk_widget_show (clist->hscrollbar);
3310 child_allocation.x = clist->internal_allocation.x;
3311 child_allocation.y = clist->internal_allocation.y +
3312 clist->internal_allocation.height -
3313 clist->hscrollbar->requisition.height;
3314 child_allocation.width = MAX (1, clist->internal_allocation.width -
3315 (vscrollbar_vis ? (clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist)) : 0));
3316 child_allocation.height = clist->hscrollbar->requisition.height;
3318 gtk_widget_size_allocate (clist->hscrollbar, &child_allocation);
3322 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
3323 gtk_widget_hide (clist->hscrollbar);
3326 /* set the vscrollbar adjustments */
3327 adjust_scrollbars (clist);
3335 gtk_clist_foreach (GtkContainer * container,
3336 GtkCallback callback,
3337 gpointer callback_data)
3342 g_return_if_fail (container != NULL);
3343 g_return_if_fail (GTK_IS_CLIST (container));
3344 g_return_if_fail (callback != NULL);
3346 clist = GTK_CLIST (container);
3348 /* callback for the column buttons */
3349 for (i = 0; i < clist->columns; i++)
3350 if (clist->column[i].button)
3351 (*callback) (clist->column[i].button, callback_data);
3353 /* callbacks for the scrollbars */
3354 if (clist->vscrollbar)
3355 (*callback) (clist->vscrollbar, callback_data);
3356 if (clist->hscrollbar)
3357 (*callback) (clist->hscrollbar, callback_data);
3366 draw_row (GtkCList * clist,
3367 GdkRectangle * area,
3369 GtkCListRow * clist_row)
3372 GdkGC *fg_gc, *bg_gc;
3373 GdkRectangle row_rectangle, cell_rectangle, clip_rectangle, intersect_rectangle,
3375 gint i, offset = 0, width, height, pixmap_width = 0;
3376 gint xsrc, ysrc, xdest, ydest;
3378 g_return_if_fail (clist != NULL);
3380 /* bail now if we arn't drawable yet */
3381 if (!GTK_WIDGET_DRAWABLE (clist))
3384 if (row < 0 || row >= clist->rows)
3387 widget = GTK_WIDGET (clist);
3389 /* if the function is passed the pointer to the row instead of null,
3390 * it avoids this expensive lookup */
3392 clist_row = (g_list_nth (clist->row_list, row))->data;
3394 /* rectangle of the entire row */
3395 row_rectangle.x = 0;
3396 row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
3397 row_rectangle.width = clist->clist_window_width;
3398 row_rectangle.height = clist->row_height;
3400 /* rectangle of the cell spacing above the row */
3401 cell_rectangle.x = 0;
3402 cell_rectangle.y = row_rectangle.y - CELL_SPACING;
3403 cell_rectangle.width = row_rectangle.width;
3404 cell_rectangle.height = CELL_SPACING;
3406 /* rectangle used to clip drawing operations, it's y and height
3407 * positions only need to be set once, so we set them once here.
3408 * the x and width are set withing the drawing loop below once per
3410 clip_rectangle.y = row_rectangle.y;
3411 clip_rectangle.height = row_rectangle.height;
3413 /* select GC for background rectangle */
3414 if (clist_row->state == GTK_STATE_SELECTED)
3416 fg_gc = widget->style->fg_gc[GTK_STATE_SELECTED];
3417 bg_gc = widget->style->bg_gc[GTK_STATE_SELECTED];
3421 if (clist_row->fg_set)
3423 gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
3424 fg_gc = clist->fg_gc;
3427 fg_gc = widget->style->fg_gc[GTK_STATE_NORMAL];
3429 if (clist_row->bg_set)
3431 gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
3432 bg_gc = clist->bg_gc;
3435 bg_gc = widget->style->bg_gc[GTK_STATE_PRELIGHT];
3438 /* draw the cell borders and background */
3441 if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
3442 gdk_draw_rectangle (clist->clist_window,
3443 widget->style->base_gc[GTK_STATE_NORMAL],
3445 intersect_rectangle.x,
3446 intersect_rectangle.y,
3447 intersect_rectangle.width,
3448 intersect_rectangle.height);
3450 /* the last row has to clear it's bottom cell spacing too */
3451 if (clist_row == clist->row_list_end->data)
3453 cell_rectangle.y += clist->row_height + CELL_SPACING;
3455 if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
3456 gdk_draw_rectangle (clist->clist_window,
3457 widget->style->base_gc[GTK_STATE_NORMAL],
3459 intersect_rectangle.x,
3460 intersect_rectangle.y,
3461 intersect_rectangle.width,
3462 intersect_rectangle.height);
3465 if (!gdk_rectangle_intersect (area, &row_rectangle, &intersect_rectangle))
3468 if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
3469 gdk_draw_rectangle (clist->clist_window,
3472 intersect_rectangle.x,
3473 intersect_rectangle.y,
3474 intersect_rectangle.width,
3475 intersect_rectangle.height);
3477 gdk_window_clear_area (clist->clist_window,
3478 intersect_rectangle.x,
3479 intersect_rectangle.y,
3480 intersect_rectangle.width,
3481 intersect_rectangle.height);
3485 gdk_draw_rectangle (clist->clist_window,
3486 widget->style->base_gc[GTK_STATE_NORMAL],
3490 cell_rectangle.width,
3491 cell_rectangle.height);
3493 /* the last row has to clear it's bottom cell spacing too */
3494 if (clist_row == clist->row_list_end->data)
3496 cell_rectangle.y += clist->row_height + CELL_SPACING;
3498 gdk_draw_rectangle (clist->clist_window,
3499 widget->style->base_gc[GTK_STATE_NORMAL],
3503 cell_rectangle.width,
3504 cell_rectangle.height);
3507 if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
3508 gdk_draw_rectangle (clist->clist_window,
3513 row_rectangle.width,
3514 row_rectangle.height);
3516 gdk_window_clear_area (clist->clist_window,
3519 row_rectangle.width,
3520 row_rectangle.height);
3523 /* iterate and draw all the columns (row cells) and draw their contents */
3524 for (i = 0; i < clist->columns; i++)
3526 clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
3527 clip_rectangle.width = clist->column[i].area.width;
3529 /* calculate clipping region clipping region */
3532 rect = &clip_rectangle;
3536 if (!gdk_rectangle_intersect (area, &clip_rectangle,
3537 &intersect_rectangle))
3539 rect = &intersect_rectangle;
3542 /* calculate real width for column justification */
3543 switch (clist_row->cell[i].type)
3545 case GTK_CELL_EMPTY:
3550 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
3551 GTK_CELL_TEXT (clist_row->cell[i])->text);
3554 case GTK_CELL_PIXMAP:
3555 gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, &width, &height);
3556 pixmap_width = width;
3559 case GTK_CELL_PIXTEXT:
3560 gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, &width, &height);
3561 pixmap_width = width;
3562 width += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
3563 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
3564 GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
3567 case GTK_CELL_WIDGET:
3577 switch (clist->column[i].justification)
3579 case GTK_JUSTIFY_LEFT:
3580 offset = clip_rectangle.x;
3583 case GTK_JUSTIFY_RIGHT:
3584 offset = (clip_rectangle.x + clip_rectangle.width) - width;
3587 case GTK_JUSTIFY_CENTER:
3588 offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
3591 case GTK_JUSTIFY_FILL:
3592 offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
3600 /* Draw Text or Pixmap */
3601 switch (clist_row->cell[i].type)
3603 case GTK_CELL_EMPTY:
3608 gdk_gc_set_clip_rectangle (fg_gc, rect);
3610 gdk_draw_string (clist->clist_window,
3611 widget->style->font,
3613 offset + clist_row->cell[i].horizontal,
3614 row_rectangle.y + clist->row_center_offset +
3615 clist_row->cell[i].vertical,
3616 GTK_CELL_TEXT (clist_row->cell[i])->text);
3618 gdk_gc_set_clip_rectangle (fg_gc, NULL);
3621 case GTK_CELL_PIXMAP:
3624 xdest = offset + clist_row->cell[i].horizontal;
3625 ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
3626 clist_row->cell[i].vertical;
3628 if (xdest < clip_rectangle.x)
3630 xsrc = clip_rectangle.x - xdest;
3631 pixmap_width -= xsrc;
3632 xdest = clip_rectangle.x;
3635 if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width)
3636 pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest;
3638 if (ydest < clip_rectangle.y)
3640 ysrc = clip_rectangle.y - ydest;
3642 ydest = clip_rectangle.y;
3645 if (ydest + height > clip_rectangle.y + clip_rectangle.height)
3646 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
3648 if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
3650 gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXMAP (clist_row->cell[i])->mask);
3651 gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
3653 gdk_draw_pixmap (clist->clist_window,
3655 GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
3658 pixmap_width, height);
3660 if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
3662 gdk_gc_set_clip_origin (fg_gc, 0, 0);
3663 gdk_gc_set_clip_mask (fg_gc, NULL);
3667 case GTK_CELL_PIXTEXT:
3668 /* draw the pixmap */
3671 xdest = offset + clist_row->cell[i].horizontal;
3672 ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
3673 clist_row->cell[i].vertical;
3675 if (xdest < clip_rectangle.x)
3677 xsrc = clip_rectangle.x - xdest;
3678 pixmap_width -= xsrc;
3679 xdest = clip_rectangle.x;
3682 if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width)
3683 pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest;
3685 if (ydest < clip_rectangle.y)
3687 ysrc = clip_rectangle.y - ydest;
3689 ydest = clip_rectangle.y;
3692 if (ydest + height > clip_rectangle.y + clip_rectangle.height)
3693 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
3695 if (GTK_CELL_PIXTEXT (clist_row->cell[i])->mask)
3697 gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXTEXT (clist_row->cell[i])->mask);
3698 gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
3701 gdk_draw_pixmap (clist->clist_window,
3703 GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
3707 pixmap_width, height);
3709 gdk_gc_set_clip_origin (fg_gc, 0, 0);
3711 offset += pixmap_width + GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
3713 /* draw the string */
3714 gdk_gc_set_clip_rectangle (fg_gc, rect);
3716 gdk_draw_string (clist->clist_window,
3717 widget->style->font,
3719 offset + clist_row->cell[i].horizontal,
3720 row_rectangle.y + clist->row_center_offset +
3721 clist_row->cell[i].vertical,
3722 GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
3724 gdk_gc_set_clip_rectangle (fg_gc, NULL);
3727 case GTK_CELL_WIDGET:
3737 if (clist->focus_row == row && GTK_WIDGET_HAS_FOCUS (widget))
3741 if (gdk_rectangle_intersect (area, &row_rectangle,
3742 &intersect_rectangle))
3744 gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle);
3745 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
3746 row_rectangle.x, row_rectangle.y,
3747 row_rectangle.width - 1,
3748 row_rectangle.height - 1);
3749 gdk_gc_set_clip_rectangle (clist->xor_gc, NULL);
3753 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
3754 row_rectangle.x, row_rectangle.y,
3755 row_rectangle.width - 1, row_rectangle.height - 1);
3760 draw_rows (GtkCList * clist,
3761 GdkRectangle * area)
3764 GtkCListRow *clist_row;
3765 int i, first_row, last_row;
3767 g_return_if_fail (clist != NULL);
3768 g_return_if_fail (GTK_IS_CLIST (clist));
3770 if (clist->row_height == 0 ||
3771 !GTK_WIDGET_DRAWABLE (clist))
3776 first_row = ROW_FROM_YPIXEL (clist, area->y);
3777 last_row = ROW_FROM_YPIXEL (clist, area->y + area->height);
3781 first_row = ROW_FROM_YPIXEL (clist, 0);
3782 last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height);
3785 /* this is a small special case which exposes the bottom cell line
3786 * on the last row -- it might go away if I change the wall the cell spacings
3788 if (clist->rows == first_row)
3791 list = g_list_nth (clist->row_list, first_row);
3795 clist_row = list->data;
3801 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, area, i, clist_row);
3806 gdk_window_clear_area (clist->clist_window, 0, ROW_TOP_YPIXEL (clist, i), -1, -1);
3811 * size_allocate_title_buttons
3812 * size_allocate_columns
3815 size_allocate_title_buttons (GtkCList * clist)
3817 gint i, last_button = 0;
3818 GtkAllocation button_allocation;
3820 if (!GTK_WIDGET_REALIZED (clist))
3823 button_allocation.x = clist->hoffset;
3824 button_allocation.y = 0;
3825 button_allocation.width = 0;
3826 button_allocation.height = clist->column_title_area.height;
3828 for (i = 0; i < clist->columns; i++)
3830 button_allocation.width += clist->column[i].area.width;
3832 if (i == clist->columns - 1)
3833 button_allocation.width += 2 * (CELL_SPACING + COLUMN_INSET);
3835 button_allocation.width += CELL_SPACING + (2 * COLUMN_INSET);
3837 if (i == (clist->columns - 1) || clist->column[i + 1].button)
3839 gtk_widget_size_allocate (clist->column[last_button].button, &button_allocation);
3840 button_allocation.x += button_allocation.width;
3841 button_allocation.width = 0;
3843 gdk_window_show (clist->column[last_button].window);
3844 gdk_window_move_resize (clist->column[last_button].window,
3845 button_allocation.x - (DRAG_WIDTH / 2),
3846 0, DRAG_WIDTH, clist->column_title_area.height);
3848 last_button = i + 1;
3852 gdk_window_hide (clist->column[i].window);
3858 size_allocate_columns (GtkCList * clist)
3860 gint i, xoffset = 0;
3862 for (i = 0; i < clist->columns; i++)
3864 clist->column[i].area.x = xoffset + CELL_SPACING + COLUMN_INSET;
3866 if (i == clist->columns - 1)
3870 if (clist->column[i].width_set)
3872 width = clist->column[i].width;
3876 if (clist->column[i].title)
3877 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
3878 clist->column[i].title);
3883 clist->column[i].area.width = MAX (width,
3884 clist->clist_window_width -
3885 xoffset - (2 * (CELL_SPACING + COLUMN_INSET)));
3890 clist->column[i].area.width = clist->column[i].width;
3893 xoffset += clist->column[i].area.width + CELL_SPACING + (2 * COLUMN_INSET);
3902 * get_selection_info
3905 toggle_row (GtkCList * clist,
3910 GtkCListRow *clist_row;
3912 switch (clist->selection_mode)
3914 case GTK_SELECTION_EXTENDED:
3915 case GTK_SELECTION_MULTIPLE:
3916 case GTK_SELECTION_SINGLE:
3918 clist_row = g_list_nth (clist->row_list, row)->data;
3919 if (clist_row->state == GTK_STATE_SELECTED)
3921 unselect_row (clist, row, column, event);
3925 case GTK_SELECTION_BROWSE:
3926 select_row (clist, row, column, event);
3932 select_row (GtkCList * clist,
3937 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
3938 row, column, event);
3942 unselect_row (GtkCList * clist,
3947 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3948 row, column, event);
3952 real_select_row (GtkCList * clist,
3957 GtkCListRow *clist_row;
3960 gboolean row_selected;
3962 g_return_if_fail (clist != NULL);
3963 g_return_if_fail (GTK_IS_CLIST (clist));
3965 if (row < 0 || row > (clist->rows - 1))
3968 switch (clist->selection_mode)
3970 case GTK_SELECTION_SINGLE:
3971 case GTK_SELECTION_BROWSE:
3973 row_selected = FALSE;
3974 list = clist->selection;
3978 sel_row = GPOINTER_TO_INT (list->data);
3982 row_selected = TRUE;
3984 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3985 sel_row, column, event);
3995 clist_row = (g_list_nth (clist->row_list, row))->data;
3997 if (clist_row->state != GTK_STATE_NORMAL)
4000 clist_row->state = GTK_STATE_SELECTED;
4001 if (!clist->selection)
4003 clist->selection = g_list_append (clist->selection,
4004 GINT_TO_POINTER (row));
4005 clist->selection_end = clist->selection;
4008 clist->selection_end =
4009 g_list_append (clist->selection_end, GINT_TO_POINTER (row))->next;
4011 if (!GTK_CLIST_FROZEN (clist)
4012 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
4013 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
4017 real_unselect_row (GtkCList * clist,
4022 GtkCListRow *clist_row;
4024 g_return_if_fail (clist != NULL);
4025 g_return_if_fail (GTK_IS_CLIST (clist));
4027 if (row < 0 || row > (clist->rows - 1))
4030 clist_row = (g_list_nth (clist->row_list, row))->data;
4032 if (clist_row->state == GTK_STATE_SELECTED)
4034 clist_row->state = GTK_STATE_NORMAL;
4036 if (clist->selection_end &&
4037 clist->selection_end->data == GINT_TO_POINTER (row))
4038 clist->selection_end = clist->selection_end->prev;
4040 clist->selection = g_list_remove (clist->selection,
4041 GINT_TO_POINTER (row));
4043 if (!GTK_CLIST_FROZEN (clist)
4044 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
4045 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
4050 get_selection_info (GtkCList * clist,
4058 g_return_val_if_fail (clist != NULL, 0);
4059 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
4061 /* bounds checking, return false if the user clicked
4062 * on a blank area */
4063 trow = ROW_FROM_YPIXEL (clist, y);
4064 if (trow >= clist->rows)
4070 tcol = COLUMN_FROM_XPIXEL (clist, x);
4071 if (tcol >= clist->columns)
4081 gtk_clist_get_selection_info (GtkCList *clist,
4087 g_return_val_if_fail (clist != NULL, 0);
4088 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
4089 return get_selection_info (clist, x, y, row, column);
4099 draw_xor_line (GtkCList * clist)
4103 g_return_if_fail (clist != NULL);
4105 widget = GTK_WIDGET (clist);
4107 gdk_draw_line (widget->window, clist->xor_gc,
4109 widget->style->klass->ythickness,
4111 clist->column_title_area.height + clist->clist_window_height + 1);
4114 /* this function returns the new width of the column being resized given
4115 * the column and x position of the cursor; the x cursor position is passed
4116 * in as a pointer and automagicly corrected if it's beyond min/max limits */
4118 new_column_width (GtkCList * clist,
4127 /* first translate the x position from widget->window
4128 * to clist->clist_window */
4129 cx -= GTK_WIDGET (clist)->style->klass->xthickness;
4131 /* rx is x from the list beginning */
4132 rx = cx - clist->hoffset;
4134 /* you can't shrink a column to less than its minimum width */
4135 if (cx < (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH))
4137 *x = cx = COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH +
4138 GTK_WIDGET (clist)->style->klass->xthickness;
4139 cx -= GTK_WIDGET (clist)->style->klass->xthickness;
4140 rx = cx - clist->hoffset;
4143 if (cx < 0 || cx > clist->clist_window_width)
4148 /* calculate new column width making sure it doesn't end up
4149 * less than the minimum width */
4150 width = (rx - COLUMN_LEFT (clist, column)) - COLUMN_INSET -
4151 ((clist->columns == (column - 1)) ? CELL_SPACING : 0);
4152 if (width < COLUMN_MIN_WIDTH)
4153 width = COLUMN_MIN_WIDTH;
4158 /* this will do more later */
4160 resize_column (GtkCList * clist,
4164 gtk_clist_set_column_width (clist, column, width);
4169 column_button_create (GtkCList * clist,
4174 button = clist->column[column].button = gtk_button_new ();
4175 gtk_widget_set_parent (button, GTK_WIDGET (clist));
4176 if (GTK_WIDGET_REALIZED (clist) && clist->title_window)
4177 gtk_widget_set_parent_window (clist->column[column].button, clist->title_window);
4179 gtk_signal_connect (GTK_OBJECT (button), "clicked",
4180 (GtkSignalFunc) column_button_clicked,
4183 gtk_widget_show (button);
4187 column_button_clicked (GtkWidget * widget,
4193 g_return_if_fail (widget != NULL);
4194 g_return_if_fail (GTK_IS_CLIST (data));
4196 clist = GTK_CLIST (data);
4198 /* find the column who's button was pressed */
4199 for (i = 0; i < clist->columns; i++)
4200 if (clist->column[i].button == widget)
4203 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i);
4212 * vadjustment_changed
4213 * hadjustment_changed
4214 * vadjustment_value_changed
4215 * hadjustment_value_changed
4218 create_scrollbars (GtkCList * clist)
4220 GtkAdjustment *adjustment;
4222 clist->vscrollbar = gtk_vscrollbar_new (NULL);
4224 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
4226 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
4227 (GtkSignalFunc) vadjustment_changed,
4230 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
4231 (GtkSignalFunc) vadjustment_value_changed,
4234 gtk_widget_set_parent (clist->vscrollbar, GTK_WIDGET (clist));
4235 gtk_widget_show (clist->vscrollbar);
4237 clist->hscrollbar = gtk_hscrollbar_new (NULL);
4239 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
4241 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
4242 (GtkSignalFunc) hadjustment_changed,
4245 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
4246 (GtkSignalFunc) hadjustment_value_changed,
4249 gtk_widget_set_parent (clist->hscrollbar, GTK_WIDGET (clist));
4250 gtk_widget_show (clist->hscrollbar);
4254 adjust_scrollbars (GtkCList * clist)
4256 GTK_RANGE (clist->vscrollbar)->adjustment->page_size = clist->clist_window_height;
4257 GTK_RANGE (clist->vscrollbar)->adjustment->page_increment = clist->clist_window_height / 2;
4258 GTK_RANGE (clist->vscrollbar)->adjustment->step_increment = 10;
4259 GTK_RANGE (clist->vscrollbar)->adjustment->lower = 0;
4260 GTK_RANGE (clist->vscrollbar)->adjustment->upper = LIST_HEIGHT (clist);
4262 if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist))
4264 GTK_RANGE (clist->vscrollbar)->adjustment->value = MAX (0, LIST_HEIGHT (clist) -
4265 clist->clist_window_height);
4266 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment),
4270 GTK_RANGE (clist->hscrollbar)->adjustment->page_size = clist->clist_window_width;
4271 GTK_RANGE (clist->hscrollbar)->adjustment->page_increment = clist->clist_window_width / 2;
4272 GTK_RANGE (clist->hscrollbar)->adjustment->step_increment = 10;
4273 GTK_RANGE (clist->hscrollbar)->adjustment->lower = 0;
4274 GTK_RANGE (clist->hscrollbar)->adjustment->upper = LIST_WIDTH (clist);
4276 if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist))
4278 GTK_RANGE (clist->hscrollbar)->adjustment->value = MAX (0, LIST_WIDTH (clist) -
4279 clist->clist_window_width);
4280 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment),
4284 if (LIST_HEIGHT (clist) <= clist->clist_window_height &&
4285 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
4287 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
4289 gtk_widget_hide (clist->vscrollbar);
4290 gtk_widget_queue_resize (GTK_WIDGET (clist));
4295 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
4297 gtk_widget_show (clist->vscrollbar);
4298 gtk_widget_queue_resize (GTK_WIDGET (clist));
4302 if (LIST_WIDTH (clist) <= clist->clist_window_width &&
4303 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
4305 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
4307 gtk_widget_hide (clist->hscrollbar);
4308 gtk_widget_queue_resize (GTK_WIDGET (clist));
4313 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
4315 gtk_widget_show (clist->hscrollbar);
4316 gtk_widget_queue_resize (GTK_WIDGET (clist));
4320 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
4321 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), "changed");
4325 vadjustment_changed (GtkAdjustment * adjustment,
4330 g_return_if_fail (adjustment != NULL);
4331 g_return_if_fail (data != NULL);
4333 clist = GTK_CLIST (data);
4337 hadjustment_changed (GtkAdjustment * adjustment,
4342 g_return_if_fail (adjustment != NULL);
4343 g_return_if_fail (data != NULL);
4345 clist = GTK_CLIST (data);
4349 check_exposures (GtkCList *clist)
4353 if (!GTK_WIDGET_REALIZED (clist))
4356 /* Make sure graphics expose events are processed before scrolling
4358 while ((event = gdk_event_get_graphics_expose (clist->clist_window)) != NULL)
4360 gtk_widget_event (GTK_WIDGET (clist), event);
4361 if (event->expose.count == 0)
4363 gdk_event_free (event);
4366 gdk_event_free (event);
4371 vadjustment_value_changed (GtkAdjustment * adjustment,
4378 g_return_if_fail (adjustment != NULL);
4379 g_return_if_fail (data != NULL);
4380 g_return_if_fail (GTK_IS_CLIST (data));
4382 clist = GTK_CLIST (data);
4384 if (!GTK_WIDGET_DRAWABLE (clist))
4387 value = adjustment->value;
4389 if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)))
4391 if (value > -clist->voffset)
4394 diff = value + clist->voffset;
4396 /* we have to re-draw the whole screen here... */
4397 if (diff >= clist->clist_window_height)
4399 clist->voffset = -value;
4400 draw_rows (clist, NULL);
4404 if ((diff != 0) && (diff != clist->clist_window_height))
4405 gdk_window_copy_area (clist->clist_window,
4408 clist->clist_window,
4411 clist->clist_window_width,
4412 clist->clist_window_height - diff);
4415 area.y = clist->clist_window_height - diff;
4416 area.width = clist->clist_window_width;
4422 diff = -clist->voffset - value;
4424 /* we have to re-draw the whole screen here... */
4425 if (diff >= clist->clist_window_height)
4427 clist->voffset = -value;
4428 draw_rows (clist, NULL);
4432 if ((diff != 0) && (diff != clist->clist_window_height))
4433 gdk_window_copy_area (clist->clist_window,
4436 clist->clist_window,
4439 clist->clist_window_width,
4440 clist->clist_window_height - diff);
4444 area.width = clist->clist_window_width;
4449 clist->voffset = -value;
4450 if ((diff != 0) && (diff != clist->clist_window_height))
4451 check_exposures (clist);
4454 draw_rows (clist, &area);
4458 hadjustment_value_changed (GtkAdjustment * adjustment,
4468 g_return_if_fail (adjustment != NULL);
4469 g_return_if_fail (data != NULL);
4470 g_return_if_fail (GTK_IS_CLIST (data));
4472 clist = GTK_CLIST (data);
4474 if (!GTK_WIDGET_DRAWABLE (clist) ||
4475 adjustment != gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)))
4478 value = adjustment->value;
4480 /* move the column buttons and resize windows */
4481 for (i = 0; i < clist->columns; i++)
4483 if (clist->column[i].button)
4485 clist->column[i].button->allocation.x -= value + clist->hoffset;
4487 if (clist->column[i].button->window)
4489 gdk_window_move (clist->column[i].button->window,
4490 clist->column[i].button->allocation.x,
4491 clist->column[i].button->allocation.y);
4493 if (clist->column[i].window)
4494 gdk_window_move (clist->column[i].window,
4495 clist->column[i].button->allocation.x +
4496 clist->column[i].button->allocation.width -
4497 (DRAG_WIDTH / 2), 0);
4502 if (value > -clist->hoffset)
4505 diff = value + clist->hoffset;
4507 clist->hoffset = -value;
4509 /* we have to re-draw the whole screen here... */
4510 if (diff >= clist->clist_window_width)
4512 draw_rows (clist, NULL);
4516 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
4517 GTK_CLIST_ADD_MODE (clist))
4519 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4521 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
4522 clist->clist_window_width - 1,
4523 clist->row_height - 1);
4525 gdk_window_copy_area (clist->clist_window,
4528 clist->clist_window,
4531 clist->clist_window_width - diff,
4532 clist->clist_window_height);
4534 area.x = clist->clist_window_width - diff;
4539 if (!(diff = -clist->hoffset - value))
4542 clist->hoffset = -value;
4544 /* we have to re-draw the whole screen here... */
4545 if (diff >= clist->clist_window_width)
4547 draw_rows (clist, NULL);
4551 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
4552 GTK_CLIST_ADD_MODE (clist))
4554 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4556 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
4557 clist->clist_window_width - 1,
4558 clist->row_height - 1);
4561 gdk_window_copy_area (clist->clist_window,
4564 clist->clist_window,
4567 clist->clist_window_width - diff,
4568 clist->clist_window_height);
4575 area.height = clist->clist_window_height;
4577 check_exposures (clist);
4579 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist))
4581 if (GTK_CLIST_ADD_MODE (clist))
4585 focus_row = clist->focus_row;
4586 clist->focus_row = -1;
4587 draw_rows (clist, &area);
4588 clist->focus_row = focus_row;
4590 gdk_draw_rectangle (clist->clist_window, clist->xor_gc,
4591 FALSE, 0, y, clist->clist_window_width - 1,
4592 clist->row_height - 1);
4602 x0 = clist->clist_window_width - 1;
4611 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4612 gdk_draw_line (clist->clist_window, clist->xor_gc,
4613 x0, y + 1, x0, y + clist->row_height - 2);
4614 gdk_draw_line (clist->clist_window, clist->xor_gc,
4615 x1, y + 1, x1, y + clist->row_height - 2);
4619 draw_rows (clist, &area);
4623 * Memory Allocation/Distruction Routines for GtkCList stuctures
4635 static GtkCListColumn *
4636 columns_new (GtkCList * clist)
4639 GtkCListColumn *column;
4641 column = g_new (GtkCListColumn, clist->columns);
4643 for (i = 0; i < clist->columns; i++)
4645 column[i].area.x = 0;
4646 column[i].area.y = 0;
4647 column[i].area.width = 0;
4648 column[i].area.height = 0;
4649 column[i].title = NULL;
4650 column[i].button = NULL;
4651 column[i].window = NULL;
4652 column[i].width = 0;
4653 column[i].width_set = FALSE;
4654 column[i].justification = GTK_JUSTIFY_LEFT;
4661 column_title_new (GtkCList * clist,
4665 if (clist->column[column].title)
4666 g_free (clist->column[column].title);
4668 clist->column[column].title = g_strdup (title);
4672 columns_delete (GtkCList * clist)
4676 for (i = 0; i < clist->columns; i++)
4677 if (clist->column[i].title)
4678 g_free (clist->column[i].title);
4680 g_free (clist->column);
4683 static GtkCListRow *
4684 row_new (GtkCList * clist)
4687 GtkCListRow *clist_row;
4689 clist_row = g_chunk_new (GtkCListRow, clist->row_mem_chunk);
4690 clist_row->cell = g_chunk_new (GtkCell, clist->cell_mem_chunk);
4692 for (i = 0; i < clist->columns; i++)
4694 clist_row->cell[i].type = GTK_CELL_EMPTY;
4695 clist_row->cell[i].vertical = 0;
4696 clist_row->cell[i].horizontal = 0;
4699 clist_row->fg_set = FALSE;
4700 clist_row->bg_set = FALSE;
4701 clist_row->state = GTK_STATE_NORMAL;
4702 clist_row->data = NULL;
4703 clist_row->destroy = NULL;
4709 row_delete (GtkCList * clist,
4710 GtkCListRow * clist_row)
4714 for (i = 0; i < clist->columns; i++)
4715 cell_empty (clist, clist_row, i);
4717 if (clist_row->destroy)
4718 clist_row->destroy (clist_row->data);
4720 g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell);
4721 g_mem_chunk_free (clist->row_mem_chunk, clist_row);
4725 cell_empty (GtkCList * clist,
4726 GtkCListRow * clist_row,
4729 switch (clist_row->cell[column].type)
4731 case GTK_CELL_EMPTY:
4735 g_free (GTK_CELL_TEXT (clist_row->cell[column])->text);
4738 case GTK_CELL_PIXMAP:
4739 gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap);
4740 if (GTK_CELL_PIXMAP (clist_row->cell[column])->mask)
4741 gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask);
4744 case GTK_CELL_PIXTEXT:
4745 g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text);
4746 gdk_pixmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap);
4747 if (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask)
4748 gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask);
4751 case GTK_CELL_WIDGET:
4759 clist_row->cell[column].type = GTK_CELL_EMPTY;
4763 cell_set_text (GtkCList * clist,
4764 GtkCListRow * clist_row,
4768 cell_empty (clist, clist_row, column);
4772 clist_row->cell[column].type = GTK_CELL_TEXT;
4773 GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
4778 cell_set_pixmap (GtkCList * clist,
4779 GtkCListRow * clist_row,
4784 cell_empty (clist, clist_row, column);
4788 clist_row->cell[column].type = GTK_CELL_PIXMAP;
4789 GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
4790 /* We set the mask even if it is NULL */
4791 GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask;
4796 cell_set_pixtext (GtkCList * clist,
4797 GtkCListRow * clist_row,
4804 cell_empty (clist, clist_row, column);
4808 clist_row->cell[column].type = GTK_CELL_PIXTEXT;
4809 GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
4810 GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
4811 GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
4812 GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask;
4816 /* Fill in data after widget has correct style */
4819 add_style_data (GtkCList * clist)
4823 widget = GTK_WIDGET(clist);
4825 /* text properties */
4826 if (!GTK_CLIST_ROW_HEIGHT_SET (clist))
4828 clist->row_height = widget->style->font->ascent + widget->style->font->descent + 1;
4829 clist->row_center_offset = widget->style->font->ascent + 1.5;
4834 text_height = clist->row_height - (GTK_WIDGET (clist)->style->font->ascent +
4835 GTK_WIDGET (clist) ->style->font->descent + 1);
4836 clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
4843 /* focus functions */
4846 gtk_clist_draw_focus (GtkWidget *widget)
4850 g_return_if_fail (widget != NULL);
4851 g_return_if_fail (GTK_IS_CLIST (widget));
4853 if (!GTK_WIDGET_DRAWABLE (widget))
4856 clist = GTK_CLIST (widget);
4857 if (clist->focus_row >= 0)
4858 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
4859 0, ROW_TOP_YPIXEL(clist, clist->focus_row),
4860 clist->clist_window_width - 1,
4861 clist->row_height - 1);
4865 gtk_clist_set_focus_child (GtkContainer *container,
4868 g_return_if_fail (container != NULL);
4869 g_return_if_fail (GTK_IS_CLIST (container));
4873 g_return_if_fail (GTK_IS_WIDGET (child));
4874 GTK_CLIST_SET_FLAG (GTK_CLIST (container), CLIST_CHILD_HAS_FOCUS);
4877 parent_class->set_focus_child (container, child);
4881 gtk_clist_focus_in (GtkWidget *widget,
4882 GdkEventFocus *event)
4886 g_return_val_if_fail (widget != NULL, FALSE);
4887 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4888 g_return_val_if_fail (event != NULL, FALSE);
4890 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
4891 GTK_CLIST_UNSET_FLAG (widget, CLIST_CHILD_HAS_FOCUS);
4893 clist = GTK_CLIST (widget);
4895 if (clist->selection_mode == GTK_SELECTION_BROWSE &&
4896 clist->selection == NULL && clist->focus_row > -1)
4897 select_row (clist, clist->focus_row, -1, (GdkEvent *) event);
4899 gtk_widget_draw_focus (widget);
4905 gtk_clist_focus_out (GtkWidget *widget,
4906 GdkEventFocus *event)
4910 g_return_val_if_fail (widget != NULL, FALSE);
4911 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4912 g_return_val_if_fail (event != NULL, FALSE);
4914 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
4915 gtk_widget_draw_focus (widget);
4917 clist = GTK_CLIST (widget);
4919 if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
4920 GTK_CLIST_CLASS_FW (widget)->resync_selection (clist, (GdkEvent *) event);
4926 toggle_add_mode (GtkCList *clist)
4928 g_return_if_fail (clist != 0);
4929 g_return_if_fail (GTK_IS_CLIST (clist));
4931 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
4932 clist->selection_mode != GTK_SELECTION_EXTENDED)
4935 gtk_clist_draw_focus (GTK_WIDGET (clist));
4936 if (!GTK_CLIST_ADD_MODE (clist))
4938 GTK_CLIST_SET_FLAG (clist, CLIST_ADD_MODE);
4939 gdk_gc_set_line_attributes (clist->xor_gc, 1,
4940 GDK_LINE_ON_OFF_DASH, 0, 0);
4941 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
4945 GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
4946 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
4947 clist->anchor_state = GTK_STATE_SELECTED;
4949 gtk_clist_draw_focus (GTK_WIDGET (clist));
4953 toggle_focus_row (GtkCList *clist)
4955 g_return_if_fail (clist != 0);
4956 g_return_if_fail (GTK_IS_CLIST (clist));
4958 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
4959 clist->focus_row < 0 || clist->focus_row >= clist->rows)
4962 switch (clist->selection_mode)
4964 case GTK_SELECTION_SINGLE:
4965 case GTK_SELECTION_MULTIPLE:
4967 toggle_row (clist, clist->focus_row, 0, NULL);
4970 case GTK_SELECTION_EXTENDED:
4971 g_list_free (clist->undo_selection);
4972 g_list_free (clist->undo_unselection);
4973 clist->undo_selection = NULL;
4974 clist->undo_unselection = NULL;
4976 clist->anchor = clist->focus_row;
4977 clist->drag_pos = clist->focus_row;
4978 clist->undo_anchor = clist->focus_row;
4980 if (GTK_CLIST_ADD_MODE (clist))
4981 fake_toggle_row (clist, clist->focus_row);
4983 GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist,clist->focus_row);
4985 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
4994 move_focus_row (GtkCList *clist,
4995 GtkScrollType scroll_type,
5000 g_return_if_fail (clist != 0);
5001 g_return_if_fail (GTK_IS_CLIST (clist));
5003 widget = GTK_WIDGET (clist);
5005 switch (scroll_type)
5007 case GTK_SCROLL_STEP_BACKWARD:
5008 if (clist->focus_row <= 0)
5010 gtk_clist_draw_focus (widget);
5012 gtk_clist_draw_focus (widget);
5014 case GTK_SCROLL_STEP_FORWARD:
5015 if (clist->focus_row >= clist->rows - 1)
5017 gtk_clist_draw_focus (widget);
5019 gtk_clist_draw_focus (widget);
5021 case GTK_SCROLL_PAGE_BACKWARD:
5022 if (clist->focus_row <= 0)
5024 gtk_clist_draw_focus (widget);
5025 clist->focus_row = MAX (0, clist->focus_row -
5026 (2 * clist->clist_window_height -
5027 clist->row_height - CELL_SPACING) /
5028 (2 * (clist->row_height + CELL_SPACING)));
5029 gtk_clist_draw_focus (widget);
5031 case GTK_SCROLL_PAGE_FORWARD:
5032 if (clist->focus_row >= clist->rows - 1)
5034 gtk_clist_draw_focus (widget);
5035 clist->focus_row = MIN (clist->rows - 1, clist->focus_row +
5036 (2 * clist->clist_window_height -
5037 clist->row_height - CELL_SPACING) /
5038 (2 * (clist->row_height + CELL_SPACING)));
5039 gtk_clist_draw_focus (widget);
5041 case GTK_SCROLL_JUMP:
5042 if (position >= 0 && position <= 1)
5044 gtk_clist_draw_focus (widget);
5045 clist->focus_row = position * (clist->rows - 1);
5046 gtk_clist_draw_focus (widget);
5055 scroll_horizontal (GtkCList *clist,
5056 GtkScrollType scroll_type,
5061 g_return_if_fail (clist != 0);
5062 g_return_if_fail (GTK_IS_CLIST (clist));
5064 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5067 switch (scroll_type)
5069 case GTK_SCROLL_STEP_BACKWARD:
5070 column = COLUMN_FROM_XPIXEL (clist, 0);
5071 if (COLUMN_LEFT_XPIXEL (clist, column) - CELL_SPACING - COLUMN_INSET >= 0
5075 case GTK_SCROLL_STEP_FORWARD:
5076 column = COLUMN_FROM_XPIXEL (clist, clist->clist_window_width);
5079 if (COLUMN_LEFT_XPIXEL (clist, column) + clist->column[column].area.width
5080 + CELL_SPACING + COLUMN_INSET - 1 <= clist->clist_window_width &&
5081 column < clist->columns - 1)
5084 case GTK_SCROLL_PAGE_BACKWARD:
5085 case GTK_SCROLL_PAGE_FORWARD:
5087 case GTK_SCROLL_JUMP:
5088 if (position >= 0 && position <= 1)
5089 column = position * (clist->columns - 1);
5097 if (COLUMN_LEFT_XPIXEL (clist, column) < CELL_SPACING + COLUMN_INSET)
5098 gtk_clist_moveto (clist, -1, column, 0, 0);
5099 else if (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET - 1
5100 + clist->column[column].area.width > clist->clist_window_width)
5102 if (column == clist->columns - 1)
5103 gtk_clist_moveto (clist, -1, column, 0, 0);
5105 gtk_clist_moveto (clist, -1, column, 0, 1);
5110 scroll_vertical (GtkCList *clist,
5111 GtkScrollType scroll_type,
5116 g_return_if_fail (clist != NULL);
5117 g_return_if_fail (GTK_IS_CLIST (clist));
5119 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5122 switch (clist->selection_mode)
5124 case GTK_SELECTION_EXTENDED:
5125 if (clist->anchor >= 0)
5128 case GTK_SELECTION_BROWSE:
5130 old_focus_row = clist->focus_row;
5131 move_focus_row (clist, scroll_type, position);
5133 if (old_focus_row != clist->focus_row)
5135 if (clist->selection_mode == GTK_SELECTION_BROWSE)
5136 unselect_row (clist,old_focus_row, -1, NULL);
5137 else if (!GTK_CLIST_ADD_MODE (clist))
5139 gtk_clist_unselect_all (clist);
5140 clist->undo_anchor = old_focus_row;
5144 switch (gtk_clist_row_is_visible (clist, clist->focus_row))
5146 case GTK_VISIBILITY_NONE:
5147 if (old_focus_row != clist->focus_row &&
5148 !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
5149 GTK_CLIST_ADD_MODE (clist)))
5150 select_row (clist, clist->focus_row, -1, NULL);
5151 switch (scroll_type)
5153 case GTK_SCROLL_STEP_BACKWARD:
5154 case GTK_SCROLL_PAGE_BACKWARD:
5155 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5157 case GTK_SCROLL_STEP_FORWARD:
5158 case GTK_SCROLL_PAGE_FORWARD:
5159 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5161 case GTK_SCROLL_JUMP:
5162 gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
5169 case GTK_VISIBILITY_PARTIAL:
5170 switch (scroll_type)
5172 case GTK_SCROLL_STEP_BACKWARD:
5173 case GTK_SCROLL_PAGE_BACKWARD:
5174 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5176 case GTK_SCROLL_STEP_FORWARD:
5177 case GTK_SCROLL_PAGE_FORWARD:
5178 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5180 case GTK_SCROLL_JUMP:
5181 gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
5188 if (old_focus_row != clist->focus_row &&
5189 !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
5190 GTK_CLIST_ADD_MODE (clist)))
5191 select_row (clist, clist->focus_row, -1, NULL);
5197 move_focus_row (clist, scroll_type, position);
5199 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5200 clist->clist_window_height)
5201 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5202 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5203 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5209 set_anchor (GtkCList *clist,
5214 g_return_if_fail (clist != NULL);
5215 g_return_if_fail (GTK_IS_CLIST (clist));
5217 if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor >= 0)
5220 g_list_free (clist->undo_selection);
5221 g_list_free (clist->undo_unselection);
5222 clist->undo_selection = NULL;
5223 clist->undo_unselection = NULL;
5226 fake_toggle_row (clist, anchor);
5229 GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist, anchor);
5230 clist->anchor_state = GTK_STATE_SELECTED;
5233 clist->anchor = anchor;
5234 clist->drag_pos = anchor;
5235 clist->undo_anchor = undo_anchor;
5239 resync_selection (GtkCList *clist,
5245 gboolean thaw = FALSE;
5247 GtkCListRow *clist_row;
5249 if (clist->anchor < 0)
5252 if (!GTK_CLIST_FROZEN (clist))
5254 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
5258 i = MIN (clist->anchor, clist->drag_pos);
5259 e = MAX (clist->anchor, clist->drag_pos);
5261 if (clist->undo_selection)
5264 list = clist->selection;
5265 clist->selection = clist->undo_selection;
5266 clist->selection_end = g_list_last (clist->selection);
5267 clist->undo_selection = list;
5268 list = clist->selection;
5271 row = GPOINTER_TO_INT (list->data);
5273 if (row < i || row > e)
5275 clist_row = g_list_nth (clist->row_list, row)->data;
5276 clist_row->state = GTK_STATE_SELECTED;
5277 unselect_row (clist, row, -1, event);
5278 clist->undo_selection = g_list_prepend
5279 (clist->undo_selection, GINT_TO_POINTER (row));
5284 for (list = g_list_nth (clist->row_list, i); i <= e; i++, list = list->next)
5285 if (g_list_find (clist->selection, GINT_TO_POINTER(i)))
5287 if (GTK_CLIST_ROW (list)->state == GTK_STATE_NORMAL)
5289 GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
5290 unselect_row (clist, i, -1, event);
5291 clist->undo_selection = g_list_prepend (clist->undo_selection,
5292 GINT_TO_POINTER (i));
5295 else if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
5297 GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
5298 clist->undo_unselection = g_list_prepend (clist->undo_unselection,
5299 GINT_TO_POINTER (i));
5302 for (list = clist->undo_unselection; list; list = list->next)
5303 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
5304 GPOINTER_TO_INT (list->data), -1, event);
5307 clist->drag_pos = -1;
5310 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
5314 update_extended_selection (GtkCList *clist,
5324 gint y1 = clist->clist_window_height;
5325 gint y2 = clist->clist_window_height;
5330 if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor == -1)
5335 if (row >= clist->rows)
5336 row = clist->rows - 1;
5338 /* extending downwards */
5339 if (row > clist->drag_pos && clist->anchor <= clist->drag_pos)
5341 s2 = clist->drag_pos + 1;
5344 /* extending upwards */
5345 else if (row < clist->drag_pos && clist->anchor >= clist->drag_pos)
5348 e2 = clist->drag_pos - 1;
5350 else if (row < clist->drag_pos && clist->anchor < clist->drag_pos)
5352 e1 = clist->drag_pos;
5353 /* row and drag_pos on different sides of anchor :
5354 take back the selection between anchor and drag_pos,
5355 select between anchor and row */
5356 if (row < clist->anchor)
5358 s1 = clist->anchor + 1;
5360 e2 = clist->anchor - 1;
5362 /* take back the selection between anchor and drag_pos */
5366 else if (row > clist->drag_pos && clist->anchor > clist->drag_pos)
5368 s1 = clist->drag_pos;
5369 /* row and drag_pos on different sides of anchor :
5370 take back the selection between anchor and drag_pos,
5371 select between anchor and row */
5372 if (row > clist->anchor)
5374 e1 = clist->anchor - 1;
5375 s2 = clist->anchor + 1;
5378 /* take back the selection between anchor and drag_pos */
5383 clist->drag_pos = row;
5386 area.width = clist->clist_window_width;
5388 /* restore the elements between s1 and e1 */
5391 for (i = s1, list = g_list_nth (clist->row_list, i); i <= e1;
5392 i++, list = list->next)
5394 if (GTK_CLIST_CLASS_FW (clist)->selection_find (clist, i, list))
5395 GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
5397 GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
5400 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
5402 if (top + clist->row_height <= 0)
5405 area.height = ROW_TOP_YPIXEL (clist, e1) + clist->row_height;
5406 draw_rows (clist, &area);
5407 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5409 else if (top >= clist->clist_window_height)
5411 area.y = ROW_TOP_YPIXEL (clist, s1);
5412 area.height = clist->clist_window_height - area.y;
5413 draw_rows (clist, &area);
5414 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5417 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5418 else if (top + clist->row_height > clist->clist_window_height)
5419 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5421 y1 = ROW_TOP_YPIXEL (clist, s1);
5422 h1 = (e1 - s1 + 1) * (clist->row_height + CELL_SPACING);
5425 /* extend the selection between s2 and e2 */
5428 for (i = s2, list = g_list_nth (clist->row_list, i); i <= e2;
5429 i++, list = list->next)
5430 if (GTK_CLIST_ROW (list)->state != clist->anchor_state)
5431 GTK_CLIST_ROW (list)->state = clist->anchor_state;
5433 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
5435 if (top + clist->row_height <= 0)
5438 area.height = ROW_TOP_YPIXEL (clist, e2) + clist->row_height;
5439 draw_rows (clist, &area);
5440 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5442 else if (top >= clist->clist_window_height)
5444 area.y = ROW_TOP_YPIXEL (clist, s2);
5445 area.height = clist->clist_window_height - area.y;
5446 draw_rows (clist, &area);
5447 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5450 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5451 else if (top + clist->row_height > clist->clist_window_height)
5452 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5454 y2 = ROW_TOP_YPIXEL (clist, s2);
5455 h2 = (e2-s2+1) * (clist->row_height + CELL_SPACING);
5458 area.y = MAX (0, MIN (y1, y2));
5459 if (area.y > clist->clist_window_height)
5461 area.height = MIN (clist->clist_window_height, h1 + h2);
5462 if (s1 >= 0 && s2 >= 0)
5463 area.height += (clist->row_height + CELL_SPACING);
5464 draw_rows (clist, &area);
5468 start_selection (GtkCList *clist)
5470 g_return_if_fail (clist != NULL);
5471 g_return_if_fail (GTK_IS_CLIST (clist));
5473 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5476 set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
5481 end_selection (GtkCList *clist)
5483 g_return_if_fail (clist != NULL);
5484 g_return_if_fail (GTK_IS_CLIST (clist));
5486 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist)) ||
5487 clist->anchor == -1)
5490 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
5494 extend_selection (GtkCList *clist,
5495 GtkScrollType scroll_type,
5497 gboolean auto_start_selection)
5499 g_return_if_fail (clist != NULL);
5500 g_return_if_fail (GTK_IS_CLIST (clist));
5502 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
5503 clist->selection_mode != GTK_SELECTION_EXTENDED)
5506 if (auto_start_selection)
5507 set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
5509 else if (clist->anchor == -1)
5512 move_focus_row (clist, scroll_type, position);
5514 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5515 clist->clist_window_height)
5516 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5517 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5518 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5520 update_extended_selection (clist, clist->focus_row);
5524 abort_column_resize (GtkCList *clist)
5526 g_return_if_fail (clist != NULL);
5527 g_return_if_fail (GTK_IS_CLIST (clist));
5529 if (!GTK_CLIST_IN_DRAG (clist))
5532 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
5533 gtk_grab_remove (GTK_WIDGET (clist));
5534 gdk_pointer_ungrab (GDK_CURRENT_TIME);
5535 clist->drag_pos = -1;
5537 if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1)
5538 draw_xor_line (clist);
5540 if (GTK_CLIST_ADD_MODE (clist))
5542 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_ON_OFF_DASH, 0,0);
5543 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
5548 gtk_clist_key_press (GtkWidget * widget,
5549 GdkEventKey * event)
5551 g_return_val_if_fail (widget != NULL, FALSE);
5552 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
5553 g_return_val_if_fail (event != NULL, FALSE);
5555 if (GTK_WIDGET_CLASS (parent_class)->key_press_event &&
5556 GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
5559 switch (event->keyval)
5562 case GDK_ISO_Left_Tab:
5563 if (event->state & GDK_SHIFT_MASK)
5564 return gtk_container_focus (GTK_CONTAINER (widget),
5565 GTK_DIR_TAB_BACKWARD);
5567 return gtk_container_focus (GTK_CONTAINER (widget),
5568 GTK_DIR_TAB_FORWARD);
5578 title_focus (GtkCList * clist,
5581 GtkWidget *focus_child;
5582 gboolean return_val = FALSE;
5587 if (!GTK_CLIST_SHOW_TITLES (clist))
5590 focus_child = GTK_CONTAINER (clist)->focus_child;
5594 case GTK_DIR_TAB_BACKWARD:
5596 if (!focus_child || focus_child == clist->hscrollbar ||
5597 focus_child == clist->hscrollbar ||
5598 !GTK_CLIST_CHILD_HAS_FOCUS (clist))
5600 if (dir == GTK_DIR_UP)
5601 i = COLUMN_FROM_XPIXEL (clist, 0);
5603 i = clist->columns - 1;
5604 focus_child = clist->column[i].button;
5605 dir = GTK_DIR_TAB_FORWARD;
5612 if (!focus_child || focus_child == clist->hscrollbar ||
5613 focus_child == clist->hscrollbar)
5615 i = clist->columns - 1;
5616 focus_child = clist->column[i].button;
5620 if (!focus_child || focus_child == clist->hscrollbar ||
5621 focus_child == clist->hscrollbar)
5624 focus_child = clist->column[i].button;
5630 while (i < clist->columns)
5632 if (clist->column[i].button == focus_child)
5634 if (clist->column[i].button &&
5635 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
5636 GTK_IS_CONTAINER (clist->column[i].button) &&
5637 !GTK_WIDGET_HAS_FOCUS (clist->column[i].button))
5638 if (gtk_container_focus
5639 (GTK_CONTAINER (clist->column[i].button), dir))
5644 if (!return_val && dir == GTK_DIR_UP)
5655 while (j >= 0 && j < clist->columns)
5657 if (clist->column[j].button &&
5658 GTK_WIDGET_VISIBLE (clist->column[j].button))
5660 if (GTK_IS_CONTAINER (clist->column[j].button) &&
5662 (GTK_CONTAINER (clist->column[j].button), dir))
5667 else if (GTK_WIDGET_CAN_FOCUS (clist->column[j].button))
5669 gtk_widget_grab_focus (clist->column[j].button);
5679 if (COLUMN_LEFT_XPIXEL (clist, j) < CELL_SPACING + COLUMN_INSET)
5680 gtk_clist_moveto (clist, -1, j, 0, 0);
5681 else if (COLUMN_LEFT_XPIXEL(clist, j) + clist->column[j].area.width >
5682 clist->clist_window_width)
5684 if (j == clist->columns-1)
5685 gtk_clist_moveto (clist, -1, j, 0, 0);
5687 gtk_clist_moveto (clist, -1, j, 0, 1);
5694 gtk_clist_focus (GtkContainer * container,
5695 GtkDirectionType direction)
5698 GtkWidget *focus_child;
5701 g_return_val_if_fail (container != NULL, FALSE);
5702 g_return_val_if_fail (GTK_IS_CLIST (container), FALSE);
5704 if (!GTK_WIDGET_SENSITIVE (container))
5707 clist = GTK_CLIST (container);
5708 focus_child = container->focus_child;
5709 old_row = clist->focus_row;
5715 if (GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5716 (!focus_child || (focus_child && focus_child != clist->vscrollbar &&
5717 focus_child != clist->hscrollbar)))
5719 if (title_focus (clist, direction))
5721 gtk_container_set_focus_child (container, NULL);
5724 gtk_widget_grab_focus (GTK_WIDGET (container));
5727 case GTK_DIR_TAB_FORWARD:
5728 if (GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5729 (!focus_child || (focus_child != clist->vscrollbar &&
5730 focus_child != clist->hscrollbar)))
5732 gboolean tf = FALSE;
5734 if (((focus_child && direction == GTK_DIR_DOWN) ||
5735 !(tf = title_focus (clist, GTK_DIR_TAB_FORWARD)))
5738 if (clist->focus_row < 0)
5740 clist->focus_row = 0;
5742 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
5743 clist->selection_mode == GTK_SELECTION_EXTENDED) &&
5745 select_row (clist, clist->focus_row, -1, NULL);
5747 gtk_widget_grab_focus (GTK_WIDGET (container));
5755 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
5757 if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child ||
5758 (focus_child != clist->vscrollbar &&
5759 focus_child != clist->hscrollbar)) &&
5760 GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
5761 GTK_WIDGET_CAN_FOCUS (clist->vscrollbar))
5763 gtk_widget_grab_focus (clist->vscrollbar);
5767 if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child ||
5768 focus_child != clist->hscrollbar) &&
5769 GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
5770 GTK_WIDGET_CAN_FOCUS (clist->hscrollbar))
5772 gtk_widget_grab_focus (clist->hscrollbar);
5777 case GTK_DIR_TAB_BACKWARD:
5778 if (!focus_child && GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5779 GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
5780 GTK_WIDGET_CAN_FOCUS (clist->hscrollbar))
5782 gtk_widget_grab_focus (clist->hscrollbar);
5786 if ((!focus_child || focus_child == clist->hscrollbar) &&
5787 GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5788 GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
5789 GTK_WIDGET_CAN_FOCUS (clist->vscrollbar))
5791 gtk_widget_grab_focus (clist->vscrollbar);
5795 if ((!focus_child || focus_child == clist->hscrollbar ||
5796 focus_child == clist->vscrollbar) &&
5797 GTK_CLIST_CHILD_HAS_FOCUS (clist) && clist->rows)
5799 if (clist->focus_row < 0)
5801 clist->focus_row = 0;
5802 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
5803 clist->selection_mode == GTK_SELECTION_EXTENDED) &&
5805 select_row (clist, clist->focus_row, -1, NULL);
5807 gtk_widget_grab_focus (GTK_WIDGET (container));
5811 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
5813 if (title_focus (clist, direction))
5822 gtk_container_set_focus_child (container, NULL);
5827 gtk_clist_unselect_all (GtkCList * clist)
5829 GTK_CLIST_CLASS_FW (clist)->unselect_all (clist);
5833 real_unselect_all (GtkCList * clist)
5838 g_return_if_fail (clist != NULL);
5839 g_return_if_fail (GTK_IS_CLIST (clist));
5841 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5844 switch (clist->selection_mode)
5846 case GTK_SELECTION_BROWSE:
5847 if (clist->focus_row >= 0)
5849 select_row (clist, clist->focus_row, -1, NULL);
5854 case GTK_SELECTION_EXTENDED:
5855 g_list_free (clist->undo_selection);
5856 g_list_free (clist->undo_unselection);
5857 clist->undo_selection = NULL;
5858 clist->undo_unselection = NULL;
5861 clist->drag_pos = -1;
5862 clist->undo_anchor = clist->focus_row;
5869 list = clist->selection;
5873 i = GPOINTER_TO_INT (list->data);
5875 unselect_row (clist, i, -1, NULL);
5880 gtk_clist_select_all (GtkCList * clist)
5882 GTK_CLIST_CLASS_FW (clist)->select_all (clist);
5886 real_select_all (GtkCList * clist)
5891 g_return_if_fail (clist != NULL);
5892 g_return_if_fail (GTK_IS_CLIST (clist));
5894 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5897 switch (clist->selection_mode)
5899 case GTK_SELECTION_SINGLE:
5900 case GTK_SELECTION_BROWSE:
5903 case GTK_SELECTION_EXTENDED:
5904 g_list_free (clist->undo_selection);
5905 g_list_free (clist->undo_unselection);
5906 clist->undo_selection = NULL;
5907 clist->undo_unselection = NULL;
5910 ((GtkCListRow *) (clist->row_list->data))->state !=
5912 fake_toggle_row (clist, 0);
5914 clist->anchor_state = GTK_STATE_SELECTED;
5916 clist->drag_pos = 0;
5917 clist->undo_anchor = clist->focus_row;
5918 update_extended_selection (clist, clist->rows);
5919 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
5922 case GTK_SELECTION_MULTIPLE:
5923 for (i = 0, list = clist->row_list; list; i++, list = list->next)
5925 if (((GtkCListRow *)(list->data))->state == GTK_STATE_NORMAL)
5926 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
5934 fake_unselect_all (GtkCList * clist,
5941 if (row >= 0 && (work = g_list_nth (clist->row_list, row)))
5943 if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL)
5945 GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
5947 if (!GTK_CLIST_FROZEN (clist) &&
5948 gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
5949 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
5950 GTK_CLIST_ROW (work));
5954 clist->undo_selection = clist->selection;
5955 clist->selection = NULL;
5956 clist->selection_end = NULL;
5958 for (list = clist->undo_selection; list; list = list->next)
5960 if ((i = GPOINTER_TO_INT (list->data)) == row ||
5961 !(work = g_list_nth (clist->row_list, i)))
5964 GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
5965 if (!GTK_CLIST_FROZEN (clist) &&
5966 gtk_clist_row_is_visible (clist, i) != GTK_VISIBILITY_NONE)
5967 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, i,
5968 GTK_CLIST_ROW (work));
5973 fake_toggle_row (GtkCList *clist,
5978 if (!(work = g_list_nth (clist->row_list, row)))
5981 if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL)
5982 clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
5984 clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
5986 if (!GTK_CLIST_FROZEN (clist) &&
5987 gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
5988 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
5989 GTK_CLIST_ROW (work));
5993 selection_find (GtkCList *clist,
5995 GList *row_list_element)
5997 return g_list_find (clist->selection, GINT_TO_POINTER (row_number));
6001 default_compare (GtkCList *clist,
6005 GtkCListRow *row1 = (GtkCListRow *) ptr1;
6006 GtkCListRow *row2 = (GtkCListRow *) ptr2;
6010 text1 = GTK_CELL_TEXT (row1->cell[clist->sort_column])->text;
6011 text2 = GTK_CELL_TEXT (row2->cell[clist->sort_column])->text;
6013 return strcmp (text1, text2);
6017 gtk_clist_set_compare_func (GtkCList *clist,
6018 GtkCListCompareFunc cmp_func)
6020 g_return_if_fail (clist != NULL);
6021 g_return_if_fail (GTK_IS_CLIST (clist));
6023 clist->compare = (cmp_func) ? cmp_func : default_compare;
6027 gtk_clist_set_auto_sort (GtkCList *clist,
6030 g_return_if_fail (clist != NULL);
6031 g_return_if_fail (GTK_IS_CLIST (clist));
6033 if (GTK_CLIST_AUTO_SORT (clist) && !auto_sort)
6034 GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_SORT);
6035 else if (!GTK_CLIST_AUTO_SORT (clist) && auto_sort)
6037 GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_SORT);
6038 gtk_clist_sort (clist);
6043 gtk_clist_set_sort_type (GtkCList *clist,
6044 GtkSortType sort_type)
6046 g_return_if_fail (clist != NULL);
6047 g_return_if_fail (GTK_IS_CLIST (clist));
6049 clist->sort_type = sort_type;
6053 gtk_clist_set_sort_column (GtkCList *clist,
6056 g_return_if_fail (clist != NULL);
6057 g_return_if_fail (GTK_IS_CLIST (clist));
6059 if (column < 0 || column >= clist->columns)
6062 clist->sort_column = column;
6066 my_merge (GtkCList *clist,
6067 GList *a, /* first list to merge */
6068 GList *b) /* second list to merge */
6070 GList z = { 0 }; /* auxiliary node */
6096 cmp = clist->compare (clist, GTK_CLIST_ROW (a), GTK_CLIST_ROW (b));
6097 if ((cmp >= 0 && clist->sort_type == GTK_SORT_DESCENDING) ||
6098 (cmp <= 0 && clist->sort_type == GTK_SORT_ASCENDING) ||
6120 my_mergesort (GtkCList *clist,
6121 GList *list, /* the list to sort */
6122 gint num) /* the list's length */
6133 /* move "half" to the middle */
6135 for (i = 0; i < num / 2; i++)
6138 /* cut the list in two */
6139 half->prev->next = NULL;
6142 /* recursively sort both lists */
6143 return my_merge (clist,
6144 my_mergesort (clist, list, num / 2),
6145 my_mergesort (clist, half, num - num / 2));
6150 gtk_clist_sort (GtkCList *clist)
6155 gboolean thaw = FALSE;
6157 g_return_if_fail (clist != NULL);
6158 g_return_if_fail (GTK_IS_CLIST (clist));
6160 if (clist->rows <= 1)
6163 if (GTK_WIDGET_HAS_GRAB (GTK_WIDGET (clist)))
6166 if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
6168 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
6169 g_list_free (clist->undo_selection);
6170 g_list_free (clist->undo_unselection);
6171 clist->undo_selection = NULL;
6172 clist->undo_unselection = NULL;
6175 if (!GTK_CLIST_FROZEN (clist))
6177 gtk_clist_freeze (clist);
6181 clist->row_list = my_mergesort (clist, clist->row_list, clist->rows);
6183 work = clist->selection;
6185 for (i = 0, list = clist->row_list; i < clist->rows; i++, list = list->next)
6187 if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
6189 work->data = GINT_TO_POINTER (i);
6193 if (i == clist->rows - 1)
6194 clist->row_list_end = list;
6198 gtk_clist_thaw (clist);