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 * gtk_clist_merge (GtkCList *clist,
360 static GList * gtk_clist_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 gdk_pointer_grab (clist->column[i].window, FALSE,
2763 GDK_POINTER_MOTION_HINT_MASK |
2764 GDK_BUTTON1_MOTION_MASK |
2765 GDK_BUTTON_RELEASE_MASK,
2766 NULL, NULL, event->time);
2767 gtk_grab_add (widget);
2768 GTK_CLIST_SET_FLAG (clist, CLIST_IN_DRAG);
2770 if (!GTK_WIDGET_HAS_FOCUS (widget))
2771 gtk_widget_grab_focus (widget);
2773 clist->drag_pos = i;
2774 clist->x_drag = (COLUMN_LEFT_XPIXEL(clist, i) + COLUMN_INSET +
2775 clist->column[i].area.width + CELL_SPACING);
2777 if (GTK_CLIST_ADD_MODE (clist))
2778 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
2779 draw_xor_line (clist);
2788 gtk_clist_button_release (GtkWidget * widget,
2789 GdkEventButton * event)
2793 g_return_val_if_fail (widget != NULL, FALSE);
2794 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2795 g_return_val_if_fail (event != NULL, FALSE);
2797 clist = GTK_CLIST (widget);
2799 /* we don't handle button 2 and 3 */
2800 if (event->button != 1)
2803 /* release on resize windows */
2804 if (GTK_CLIST_IN_DRAG (clist))
2806 gint i, x, width, visible;
2808 i = clist->drag_pos;
2809 clist->drag_pos = -1;
2810 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
2811 gtk_widget_get_pointer (widget, &x, NULL);
2813 width = new_column_width (clist, i, &x, &visible);
2814 gtk_grab_remove (widget);
2815 gdk_pointer_ungrab (event->time);
2818 draw_xor_line (clist);
2820 if (GTK_CLIST_ADD_MODE (clist))
2822 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2823 GDK_LINE_ON_OFF_DASH, 0, 0);
2824 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
2827 resize_column (clist, i, width);
2831 if (GTK_CLIST_DRAG_SELECTION (clist))
2836 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
2837 gtk_grab_remove (widget);
2838 gdk_pointer_ungrab (event->time);
2841 gtk_timeout_remove (clist->htimer);
2846 gtk_timeout_remove (clist->vtimer);
2849 switch (clist->selection_mode)
2851 case GTK_SELECTION_EXTENDED:
2852 if (!(event->state & GDK_SHIFT_MASK) ||
2853 event->x < 0 || event->x >= clist->clist_window_width ||
2854 event->y < 0 || event->y >= clist->clist_window_height)
2855 GTK_CLIST_CLASS_FW (clist)->resync_selection
2856 (clist, (GdkEvent *) event);
2859 case GTK_SELECTION_SINGLE:
2860 case GTK_SELECTION_MULTIPLE:
2861 if (get_selection_info (clist, event->x, event->y, &row, &column))
2863 if (clist->anchor == clist->focus_row)
2864 toggle_row (clist, row, column, (GdkEvent *) event);
2878 horizontal_timeout (GtkCList *clist)
2881 GdkEventMotion event;
2882 GdkModifierType mask;
2884 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
2887 gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
2894 gtk_clist_motion (GTK_WIDGET (clist), &event);
2900 vertical_timeout (GtkCList *clist)
2903 GdkEventMotion event;
2904 GdkModifierType mask;
2906 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
2909 gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
2916 gtk_clist_motion (GTK_WIDGET (clist), &event);
2922 move_vertical (GtkCList *clist,
2929 adj = GTK_RANGE (clist->vscrollbar)->adjustment;
2931 y = ROW_TOP_YPIXEL (clist, row) - clist->voffset;
2933 y = y - align * (clist->clist_window_height - clist->row_height)
2934 + (2 * align - 1) * CELL_SPACING;
2936 if (y + adj->page_size > adj->upper)
2937 adj->value = adj->upper - adj->page_size;
2941 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
2945 move_horizontal (GtkCList *clist,
2951 adj = GTK_RANGE (clist->hscrollbar)->adjustment;
2955 upper = adj->upper - adj->page_size;
2956 adj->value = MIN (adj->value, upper);
2957 adj->value = MAX (adj->value, 0.0);
2959 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
2963 gtk_clist_motion (GtkWidget * widget,
2964 GdkEventMotion * event)
2972 g_return_val_if_fail (widget != NULL, FALSE);
2973 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2975 clist = GTK_CLIST (widget);
2977 if (!(gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)))
2980 if (GTK_CLIST_IN_DRAG (clist))
2982 if (event->is_hint || event->window != widget->window)
2983 gtk_widget_get_pointer (widget, &x, NULL);
2987 new_width = new_column_width (clist, clist->drag_pos, &x, &visible);
2988 /* Welcome to my hack! I'm going to use a value of x_drag = -99999
2989 * to indicate that the xor line is already invisible */
2991 if (!visible && clist->x_drag != -99999)
2993 draw_xor_line (clist);
2994 clist->x_drag = -99999;
2997 if (x != clist->x_drag && visible)
2999 if (clist->x_drag != -99999)
3000 draw_xor_line (clist);
3003 draw_xor_line (clist);
3006 if (new_width <= COLUMN_MIN_WIDTH + 1)
3008 if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) && x < 0)
3009 gtk_clist_moveto (clist, -1, clist->drag_pos, 0, 0);
3015 if (event->is_hint || event->window != clist->clist_window)
3016 gdk_window_get_pointer (clist->clist_window, &x, &y, NULL);
3018 /* horizontal autoscrolling */
3019 if (LIST_WIDTH (clist) > clist->clist_window_width &&
3020 (x < 0 || x >= clist->clist_window_width))
3025 clist->htimer = gtk_timeout_add
3026 (SCROLL_TIME, (GtkFunction) horizontal_timeout, clist);
3028 if (!((x < 0 && GTK_RANGE (clist->hscrollbar)->adjustment->value == 0) ||
3029 (x >= clist->clist_window_width &&
3030 GTK_RANGE (clist->hscrollbar)->adjustment->value ==
3031 LIST_WIDTH (clist) - clist->clist_window_width)))
3034 move_horizontal (clist, -1 + (x/2));
3036 move_horizontal (clist, 1 + (x - clist->clist_window_width) / 2);
3040 if (GTK_CLIST_IN_DRAG (clist))
3043 /* vertical autoscrolling */
3044 row = ROW_FROM_YPIXEL (clist, y);
3046 /* don't scroll on last pixel row if it's a cell spacing */
3047 if (y == clist->clist_window_height-1 &&
3048 y == ROW_TOP_YPIXEL (clist, row-1) + clist->row_height)
3051 if (LIST_HEIGHT (clist) > clist->clist_window_height &&
3052 (y < 0 || y >= clist->clist_window_height))
3057 clist->vtimer = gtk_timeout_add (SCROLL_TIME,
3058 (GtkFunction) vertical_timeout, clist);
3060 if (GTK_CLIST_DRAG_SELECTION (clist))
3062 if ((y < 0 && clist->focus_row == 0) ||
3063 (y >= clist->clist_window_height &&
3064 clist->focus_row == clist->rows-1))
3069 row = CLAMP (row, 0, clist->rows - 1);
3071 if (GTK_CLIST_DRAG_SELECTION (clist))
3073 if (row == clist->focus_row)
3076 gtk_clist_draw_focus (widget);
3077 clist->focus_row = row;
3078 gtk_clist_draw_focus (widget);
3080 switch (clist->selection_mode)
3082 case GTK_SELECTION_BROWSE:
3083 select_row (clist, clist->focus_row, - 1, (GdkEvent *) event);
3086 case GTK_SELECTION_EXTENDED:
3087 update_extended_selection (clist, clist->focus_row);
3095 if (ROW_TOP_YPIXEL(clist, row) < 0)
3096 move_vertical (clist, row, 0);
3097 else if (ROW_TOP_YPIXEL(clist, row) + clist->row_height >
3098 clist->clist_window_height)
3099 move_vertical (clist, row, 1);
3105 gtk_clist_size_request (GtkWidget * widget,
3106 GtkRequisition * requisition)
3111 g_return_if_fail (widget != NULL);
3112 g_return_if_fail (GTK_IS_CLIST (widget));
3113 g_return_if_fail (requisition != NULL);
3115 clist = GTK_CLIST (widget);
3117 add_style_data (clist);
3119 requisition->width = 0;
3120 requisition->height = 0;
3122 /* compute the size of the column title (title) area */
3123 clist->column_title_area.height = 0;
3124 if (GTK_CLIST_SHOW_TITLES (clist))
3125 for (i = 0; i < clist->columns; i++)
3126 if (clist->column[i].button)
3128 gtk_widget_size_request (clist->column[i].button, &clist->column[i].button->requisition);
3129 clist->column_title_area.height = MAX (clist->column_title_area.height,
3130 clist->column[i].button->requisition.height);
3132 requisition->height += clist->column_title_area.height;
3134 /* add the vscrollbar space */
3135 if ((clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
3136 GTK_WIDGET_VISIBLE (clist->vscrollbar))
3138 gtk_widget_size_request (clist->vscrollbar, &clist->vscrollbar->requisition);
3140 requisition->width += clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist);
3141 requisition->height = MAX (requisition->height,
3142 clist->vscrollbar->requisition.height);
3145 /* add the hscrollbar space */
3146 if ((clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
3147 GTK_WIDGET_VISIBLE (clist->hscrollbar))
3149 gtk_widget_size_request (clist->hscrollbar, &clist->hscrollbar->requisition);
3151 requisition->height += clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist);
3152 requisition->width = MAX (clist->hscrollbar->requisition.width,
3153 requisition->width -
3154 clist->vscrollbar->requisition.width);
3158 requisition->width += widget->style->klass->xthickness * 2 +
3159 GTK_CONTAINER (widget)->border_width * 2;
3160 requisition->height += widget->style->klass->ythickness * 2 +
3161 GTK_CONTAINER (widget)->border_width * 2;
3165 gtk_clist_size_allocate (GtkWidget * widget,
3166 GtkAllocation * allocation)
3169 GtkAllocation clist_allocation;
3170 GtkAllocation child_allocation;
3171 gint i, vscrollbar_vis, hscrollbar_vis;
3173 g_return_if_fail (widget != NULL);
3174 g_return_if_fail (GTK_IS_CLIST (widget));
3175 g_return_if_fail (allocation != NULL);
3177 clist = GTK_CLIST (widget);
3178 widget->allocation = *allocation;
3180 if (GTK_WIDGET_REALIZED (widget))
3182 gdk_window_move_resize (widget->window,
3183 allocation->x + GTK_CONTAINER (widget)->border_width,
3184 allocation->y + GTK_CONTAINER (widget)->border_width,
3185 allocation->width - GTK_CONTAINER (widget)->border_width * 2,
3186 allocation->height - GTK_CONTAINER (widget)->border_width * 2);
3189 /* use internal allocation structure for all the math
3190 * because it's easier than always subtracting the container
3192 clist->internal_allocation.x = 0;
3193 clist->internal_allocation.y = 0;
3194 clist->internal_allocation.width = MAX (1, allocation->width -
3195 GTK_CONTAINER (widget)->border_width * 2);
3196 clist->internal_allocation.height = MAX (1, allocation->height -
3197 GTK_CONTAINER (widget)->border_width * 2);
3199 /* allocate clist window assuming no scrollbars */
3200 clist_allocation.x = clist->internal_allocation.x + widget->style->klass->xthickness;
3201 clist_allocation.y = clist->internal_allocation.y + widget->style->klass->ythickness +
3202 clist->column_title_area.height;
3203 clist_allocation.width = MAX (1, clist->internal_allocation.width -
3204 (2 * widget->style->klass->xthickness));
3205 clist_allocation.height = MAX (1, clist->internal_allocation.height -
3206 (2 * widget->style->klass->ythickness) -
3207 clist->column_title_area.height);
3210 * here's where we decide to show/not show the scrollbars
3215 for (i = 0; i <= 1; i++)
3217 if (LIST_HEIGHT (clist) <= clist_allocation.height &&
3218 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
3224 if (!vscrollbar_vis)
3227 clist_allocation.width = MAX (1, clist_allocation.width -
3228 (clist->vscrollbar->requisition.width +
3229 SCROLLBAR_SPACING (clist)));
3233 if (LIST_WIDTH (clist) <= clist_allocation.width &&
3234 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
3240 if (!hscrollbar_vis)
3243 clist_allocation.height = MAX (1, clist_allocation.height -
3244 (clist->hscrollbar->requisition.height +
3245 SCROLLBAR_SPACING (clist)));
3250 clist->clist_window_width = clist_allocation.width;
3251 clist->clist_window_height = clist_allocation.height;
3253 if (GTK_WIDGET_REALIZED (widget))
3255 gdk_window_move_resize (clist->clist_window,
3258 clist_allocation.width,
3259 clist_allocation.height);
3262 /* position the window which holds the column title buttons */
3263 clist->column_title_area.x = widget->style->klass->xthickness;
3264 clist->column_title_area.y = widget->style->klass->ythickness;
3265 clist->column_title_area.width = clist_allocation.width;
3267 if (GTK_WIDGET_REALIZED (widget))
3269 gdk_window_move_resize (clist->title_window,
3270 clist->column_title_area.x,
3271 clist->column_title_area.y,
3272 clist->column_title_area.width,
3273 clist->column_title_area.height);
3276 /* column button allocation */
3277 size_allocate_columns (clist);
3278 size_allocate_title_buttons (clist);
3280 adjust_scrollbars (clist);
3282 /* allocate the vscrollbar */
3285 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
3286 gtk_widget_show (clist->vscrollbar);
3288 child_allocation.x = clist->internal_allocation.x +
3289 clist->internal_allocation.width -
3290 clist->vscrollbar->requisition.width;
3291 child_allocation.y = clist->internal_allocation.y;
3292 child_allocation.width = clist->vscrollbar->requisition.width;
3293 child_allocation.height = MAX (1, clist->internal_allocation.height -
3294 (hscrollbar_vis ? (clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist)) : 0));
3296 gtk_widget_size_allocate (clist->vscrollbar, &child_allocation);
3300 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
3301 gtk_widget_hide (clist->vscrollbar);
3306 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
3307 gtk_widget_show (clist->hscrollbar);
3309 child_allocation.x = clist->internal_allocation.x;
3310 child_allocation.y = clist->internal_allocation.y +
3311 clist->internal_allocation.height -
3312 clist->hscrollbar->requisition.height;
3313 child_allocation.width = MAX (1, clist->internal_allocation.width -
3314 (vscrollbar_vis ? (clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist)) : 0));
3315 child_allocation.height = clist->hscrollbar->requisition.height;
3317 gtk_widget_size_allocate (clist->hscrollbar, &child_allocation);
3321 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
3322 gtk_widget_hide (clist->hscrollbar);
3325 /* set the vscrollbar adjustments */
3326 adjust_scrollbars (clist);
3334 gtk_clist_foreach (GtkContainer * container,
3335 GtkCallback callback,
3336 gpointer callback_data)
3341 g_return_if_fail (container != NULL);
3342 g_return_if_fail (GTK_IS_CLIST (container));
3343 g_return_if_fail (callback != NULL);
3345 clist = GTK_CLIST (container);
3347 /* callback for the column buttons */
3348 for (i = 0; i < clist->columns; i++)
3349 if (clist->column[i].button)
3350 (*callback) (clist->column[i].button, callback_data);
3352 /* callbacks for the scrollbars */
3353 if (clist->vscrollbar)
3354 (*callback) (clist->vscrollbar, callback_data);
3355 if (clist->hscrollbar)
3356 (*callback) (clist->hscrollbar, callback_data);
3365 draw_row (GtkCList * clist,
3366 GdkRectangle * area,
3368 GtkCListRow * clist_row)
3371 GdkGC *fg_gc, *bg_gc;
3372 GdkRectangle row_rectangle, cell_rectangle, clip_rectangle, intersect_rectangle,
3374 gint i, offset = 0, width, height, pixmap_width = 0;
3375 gint xsrc, ysrc, xdest, ydest;
3377 g_return_if_fail (clist != NULL);
3379 /* bail now if we arn't drawable yet */
3380 if (!GTK_WIDGET_DRAWABLE (clist))
3383 if (row < 0 || row >= clist->rows)
3386 widget = GTK_WIDGET (clist);
3388 /* if the function is passed the pointer to the row instead of null,
3389 * it avoids this expensive lookup */
3391 clist_row = (g_list_nth (clist->row_list, row))->data;
3393 /* rectangle of the entire row */
3394 row_rectangle.x = 0;
3395 row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
3396 row_rectangle.width = clist->clist_window_width;
3397 row_rectangle.height = clist->row_height;
3399 /* rectangle of the cell spacing above the row */
3400 cell_rectangle.x = 0;
3401 cell_rectangle.y = row_rectangle.y - CELL_SPACING;
3402 cell_rectangle.width = row_rectangle.width;
3403 cell_rectangle.height = CELL_SPACING;
3405 /* rectangle used to clip drawing operations, it's y and height
3406 * positions only need to be set once, so we set them once here.
3407 * the x and width are set withing the drawing loop below once per
3409 clip_rectangle.y = row_rectangle.y;
3410 clip_rectangle.height = row_rectangle.height;
3412 /* select GC for background rectangle */
3413 if (clist_row->state == GTK_STATE_SELECTED)
3415 fg_gc = widget->style->fg_gc[GTK_STATE_SELECTED];
3416 bg_gc = widget->style->bg_gc[GTK_STATE_SELECTED];
3420 if (clist_row->fg_set)
3422 gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
3423 fg_gc = clist->fg_gc;
3426 fg_gc = widget->style->fg_gc[GTK_STATE_NORMAL];
3428 if (clist_row->bg_set)
3430 gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
3431 bg_gc = clist->bg_gc;
3434 bg_gc = widget->style->bg_gc[GTK_STATE_PRELIGHT];
3437 /* draw the cell borders and background */
3440 if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
3441 gdk_draw_rectangle (clist->clist_window,
3442 widget->style->base_gc[GTK_STATE_NORMAL],
3444 intersect_rectangle.x,
3445 intersect_rectangle.y,
3446 intersect_rectangle.width,
3447 intersect_rectangle.height);
3449 /* the last row has to clear it's bottom cell spacing too */
3450 if (clist_row == clist->row_list_end->data)
3452 cell_rectangle.y += clist->row_height + CELL_SPACING;
3454 if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
3455 gdk_draw_rectangle (clist->clist_window,
3456 widget->style->base_gc[GTK_STATE_NORMAL],
3458 intersect_rectangle.x,
3459 intersect_rectangle.y,
3460 intersect_rectangle.width,
3461 intersect_rectangle.height);
3464 if (!gdk_rectangle_intersect (area, &row_rectangle, &intersect_rectangle))
3467 if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
3468 gdk_draw_rectangle (clist->clist_window,
3471 intersect_rectangle.x,
3472 intersect_rectangle.y,
3473 intersect_rectangle.width,
3474 intersect_rectangle.height);
3476 gdk_window_clear_area (clist->clist_window,
3477 intersect_rectangle.x,
3478 intersect_rectangle.y,
3479 intersect_rectangle.width,
3480 intersect_rectangle.height);
3484 gdk_draw_rectangle (clist->clist_window,
3485 widget->style->base_gc[GTK_STATE_NORMAL],
3489 cell_rectangle.width,
3490 cell_rectangle.height);
3492 /* the last row has to clear it's bottom cell spacing too */
3493 if (clist_row == clist->row_list_end->data)
3495 cell_rectangle.y += clist->row_height + CELL_SPACING;
3497 gdk_draw_rectangle (clist->clist_window,
3498 widget->style->base_gc[GTK_STATE_NORMAL],
3502 cell_rectangle.width,
3503 cell_rectangle.height);
3506 if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
3507 gdk_draw_rectangle (clist->clist_window,
3512 row_rectangle.width,
3513 row_rectangle.height);
3515 gdk_window_clear_area (clist->clist_window,
3518 row_rectangle.width,
3519 row_rectangle.height);
3522 /* iterate and draw all the columns (row cells) and draw their contents */
3523 for (i = 0; i < clist->columns; i++)
3525 clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
3526 clip_rectangle.width = clist->column[i].area.width;
3528 /* calculate clipping region clipping region */
3531 rect = &clip_rectangle;
3535 if (!gdk_rectangle_intersect (area, &clip_rectangle,
3536 &intersect_rectangle))
3538 rect = &intersect_rectangle;
3541 /* calculate real width for column justification */
3542 switch (clist_row->cell[i].type)
3544 case GTK_CELL_EMPTY:
3549 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
3550 GTK_CELL_TEXT (clist_row->cell[i])->text);
3553 case GTK_CELL_PIXMAP:
3554 gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, &width, &height);
3555 pixmap_width = width;
3558 case GTK_CELL_PIXTEXT:
3559 gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, &width, &height);
3560 pixmap_width = width;
3561 width += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
3562 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
3563 GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
3566 case GTK_CELL_WIDGET:
3576 switch (clist->column[i].justification)
3578 case GTK_JUSTIFY_LEFT:
3579 offset = clip_rectangle.x;
3582 case GTK_JUSTIFY_RIGHT:
3583 offset = (clip_rectangle.x + clip_rectangle.width) - width;
3586 case GTK_JUSTIFY_CENTER:
3587 offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
3590 case GTK_JUSTIFY_FILL:
3591 offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
3599 /* Draw Text or Pixmap */
3600 switch (clist_row->cell[i].type)
3602 case GTK_CELL_EMPTY:
3607 gdk_gc_set_clip_rectangle (fg_gc, rect);
3609 gdk_draw_string (clist->clist_window,
3610 widget->style->font,
3612 offset + clist_row->cell[i].horizontal,
3613 row_rectangle.y + clist->row_center_offset +
3614 clist_row->cell[i].vertical,
3615 GTK_CELL_TEXT (clist_row->cell[i])->text);
3617 gdk_gc_set_clip_rectangle (fg_gc, NULL);
3620 case GTK_CELL_PIXMAP:
3623 xdest = offset + clist_row->cell[i].horizontal;
3624 ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
3625 clist_row->cell[i].vertical;
3627 if (xdest < clip_rectangle.x)
3629 xsrc = clip_rectangle.x - xdest;
3630 pixmap_width -= xsrc;
3631 xdest = clip_rectangle.x;
3634 if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width)
3635 pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest;
3637 if (ydest < clip_rectangle.y)
3639 ysrc = clip_rectangle.y - ydest;
3641 ydest = clip_rectangle.y;
3644 if (ydest + height > clip_rectangle.y + clip_rectangle.height)
3645 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
3647 if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
3649 gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXMAP (clist_row->cell[i])->mask);
3650 gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
3652 gdk_draw_pixmap (clist->clist_window,
3654 GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
3657 pixmap_width, height);
3659 if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
3661 gdk_gc_set_clip_origin (fg_gc, 0, 0);
3662 gdk_gc_set_clip_mask (fg_gc, NULL);
3666 case GTK_CELL_PIXTEXT:
3667 /* draw the pixmap */
3670 xdest = offset + clist_row->cell[i].horizontal;
3671 ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
3672 clist_row->cell[i].vertical;
3674 if (xdest < clip_rectangle.x)
3676 xsrc = clip_rectangle.x - xdest;
3677 pixmap_width -= xsrc;
3678 xdest = clip_rectangle.x;
3681 if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width)
3682 pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest;
3684 if (ydest < clip_rectangle.y)
3686 ysrc = clip_rectangle.y - ydest;
3688 ydest = clip_rectangle.y;
3691 if (ydest + height > clip_rectangle.y + clip_rectangle.height)
3692 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
3694 if (GTK_CELL_PIXTEXT (clist_row->cell[i])->mask)
3696 gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXTEXT (clist_row->cell[i])->mask);
3697 gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
3700 gdk_draw_pixmap (clist->clist_window,
3702 GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
3706 pixmap_width, height);
3708 gdk_gc_set_clip_origin (fg_gc, 0, 0);
3710 offset += pixmap_width + GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
3712 /* draw the string */
3713 gdk_gc_set_clip_rectangle (fg_gc, rect);
3715 gdk_draw_string (clist->clist_window,
3716 widget->style->font,
3718 offset + clist_row->cell[i].horizontal,
3719 row_rectangle.y + clist->row_center_offset +
3720 clist_row->cell[i].vertical,
3721 GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
3723 gdk_gc_set_clip_rectangle (fg_gc, NULL);
3726 case GTK_CELL_WIDGET:
3736 if (clist->focus_row == row && GTK_WIDGET_HAS_FOCUS (widget))
3740 if (gdk_rectangle_intersect (area, &row_rectangle,
3741 &intersect_rectangle))
3743 gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle);
3744 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
3745 row_rectangle.x, row_rectangle.y,
3746 row_rectangle.width - 1,
3747 row_rectangle.height - 1);
3748 gdk_gc_set_clip_rectangle (clist->xor_gc, NULL);
3752 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
3753 row_rectangle.x, row_rectangle.y,
3754 row_rectangle.width - 1, row_rectangle.height - 1);
3759 draw_rows (GtkCList * clist,
3760 GdkRectangle * area)
3763 GtkCListRow *clist_row;
3764 int i, first_row, last_row;
3766 g_return_if_fail (clist != NULL);
3767 g_return_if_fail (GTK_IS_CLIST (clist));
3769 if (clist->row_height == 0 ||
3770 !GTK_WIDGET_DRAWABLE (clist))
3775 first_row = ROW_FROM_YPIXEL (clist, area->y);
3776 last_row = ROW_FROM_YPIXEL (clist, area->y + area->height);
3780 first_row = ROW_FROM_YPIXEL (clist, 0);
3781 last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height);
3784 /* this is a small special case which exposes the bottom cell line
3785 * on the last row -- it might go away if I change the wall the cell spacings
3787 if (clist->rows == first_row)
3790 list = g_list_nth (clist->row_list, first_row);
3794 clist_row = list->data;
3800 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, area, i, clist_row);
3805 gdk_window_clear_area (clist->clist_window, 0, ROW_TOP_YPIXEL (clist, i), -1, -1);
3810 * size_allocate_title_buttons
3811 * size_allocate_columns
3814 size_allocate_title_buttons (GtkCList * clist)
3816 gint i, last_button = 0;
3817 GtkAllocation button_allocation;
3819 if (!GTK_WIDGET_REALIZED (clist))
3822 button_allocation.x = clist->hoffset;
3823 button_allocation.y = 0;
3824 button_allocation.width = 0;
3825 button_allocation.height = clist->column_title_area.height;
3827 for (i = 0; i < clist->columns; i++)
3829 button_allocation.width += clist->column[i].area.width;
3831 if (i == clist->columns - 1)
3832 button_allocation.width += 2 * (CELL_SPACING + COLUMN_INSET);
3834 button_allocation.width += CELL_SPACING + (2 * COLUMN_INSET);
3836 if (i == (clist->columns - 1) || clist->column[i + 1].button)
3838 gtk_widget_size_allocate (clist->column[last_button].button, &button_allocation);
3839 button_allocation.x += button_allocation.width;
3840 button_allocation.width = 0;
3842 gdk_window_show (clist->column[last_button].window);
3843 gdk_window_move_resize (clist->column[last_button].window,
3844 button_allocation.x - (DRAG_WIDTH / 2),
3845 0, DRAG_WIDTH, clist->column_title_area.height);
3847 last_button = i + 1;
3851 gdk_window_hide (clist->column[i].window);
3857 size_allocate_columns (GtkCList * clist)
3859 gint i, xoffset = 0;
3861 for (i = 0; i < clist->columns; i++)
3863 clist->column[i].area.x = xoffset + CELL_SPACING + COLUMN_INSET;
3865 if (i == clist->columns - 1)
3869 if (clist->column[i].width_set)
3871 width = clist->column[i].width;
3875 if (clist->column[i].title)
3876 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
3877 clist->column[i].title);
3882 clist->column[i].area.width = MAX (width,
3883 clist->clist_window_width -
3884 xoffset - (2 * (CELL_SPACING + COLUMN_INSET)));
3889 clist->column[i].area.width = clist->column[i].width;
3892 xoffset += clist->column[i].area.width + CELL_SPACING + (2 * COLUMN_INSET);
3901 * get_selection_info
3904 toggle_row (GtkCList * clist,
3909 GtkCListRow *clist_row;
3911 switch (clist->selection_mode)
3913 case GTK_SELECTION_EXTENDED:
3914 case GTK_SELECTION_MULTIPLE:
3915 case GTK_SELECTION_SINGLE:
3917 clist_row = g_list_nth (clist->row_list, row)->data;
3918 if (clist_row->state == GTK_STATE_SELECTED)
3920 unselect_row (clist, row, column, event);
3924 case GTK_SELECTION_BROWSE:
3925 select_row (clist, row, column, event);
3931 select_row (GtkCList * clist,
3936 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
3937 row, column, event);
3941 unselect_row (GtkCList * clist,
3946 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3947 row, column, event);
3951 real_select_row (GtkCList * clist,
3956 GtkCListRow *clist_row;
3959 gboolean row_selected;
3961 g_return_if_fail (clist != NULL);
3962 g_return_if_fail (GTK_IS_CLIST (clist));
3964 if (row < 0 || row > (clist->rows - 1))
3967 switch (clist->selection_mode)
3969 case GTK_SELECTION_SINGLE:
3970 case GTK_SELECTION_BROWSE:
3972 row_selected = FALSE;
3973 list = clist->selection;
3977 sel_row = GPOINTER_TO_INT (list->data);
3981 row_selected = TRUE;
3983 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3984 sel_row, column, event);
3994 clist_row = (g_list_nth (clist->row_list, row))->data;
3996 if (clist_row->state != GTK_STATE_NORMAL)
3999 clist_row->state = GTK_STATE_SELECTED;
4000 if (!clist->selection)
4002 clist->selection = g_list_append (clist->selection,
4003 GINT_TO_POINTER (row));
4004 clist->selection_end = clist->selection;
4007 clist->selection_end =
4008 g_list_append (clist->selection_end, GINT_TO_POINTER (row))->next;
4010 if (!GTK_CLIST_FROZEN (clist)
4011 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
4012 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
4016 real_unselect_row (GtkCList * clist,
4021 GtkCListRow *clist_row;
4023 g_return_if_fail (clist != NULL);
4024 g_return_if_fail (GTK_IS_CLIST (clist));
4026 if (row < 0 || row > (clist->rows - 1))
4029 clist_row = (g_list_nth (clist->row_list, row))->data;
4031 if (clist_row->state == GTK_STATE_SELECTED)
4033 clist_row->state = GTK_STATE_NORMAL;
4035 if (clist->selection_end &&
4036 clist->selection_end->data == GINT_TO_POINTER (row))
4037 clist->selection_end = clist->selection_end->prev;
4039 clist->selection = g_list_remove (clist->selection,
4040 GINT_TO_POINTER (row));
4042 if (!GTK_CLIST_FROZEN (clist)
4043 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
4044 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
4049 get_selection_info (GtkCList * clist,
4057 g_return_val_if_fail (clist != NULL, 0);
4058 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
4060 /* bounds checking, return false if the user clicked
4061 * on a blank area */
4062 trow = ROW_FROM_YPIXEL (clist, y);
4063 if (trow >= clist->rows)
4069 tcol = COLUMN_FROM_XPIXEL (clist, x);
4070 if (tcol >= clist->columns)
4080 gtk_clist_get_selection_info (GtkCList *clist,
4086 g_return_val_if_fail (clist != NULL, 0);
4087 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
4088 return get_selection_info (clist, x, y, row, column);
4098 draw_xor_line (GtkCList * clist)
4102 g_return_if_fail (clist != NULL);
4104 widget = GTK_WIDGET (clist);
4106 gdk_draw_line (widget->window, clist->xor_gc,
4108 widget->style->klass->ythickness,
4110 clist->column_title_area.height + clist->clist_window_height + 1);
4113 /* this function returns the new width of the column being resized given
4114 * the column and x position of the cursor; the x cursor position is passed
4115 * in as a pointer and automagicly corrected if it's beyond min/max limits */
4117 new_column_width (GtkCList * clist,
4126 /* first translate the x position from widget->window
4127 * to clist->clist_window */
4128 cx -= GTK_WIDGET (clist)->style->klass->xthickness;
4130 /* rx is x from the list beginning */
4131 rx = cx - clist->hoffset;
4133 /* you can't shrink a column to less than its minimum width */
4134 if (cx < (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH))
4136 *x = cx = COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH +
4137 GTK_WIDGET (clist)->style->klass->xthickness;
4138 cx -= GTK_WIDGET (clist)->style->klass->xthickness;
4139 rx = cx - clist->hoffset;
4142 if (cx < 0 || cx > clist->clist_window_width)
4147 /* calculate new column width making sure it doesn't end up
4148 * less than the minimum width */
4149 width = (rx - COLUMN_LEFT (clist, column)) - COLUMN_INSET -
4150 ((clist->columns == (column - 1)) ? CELL_SPACING : 0);
4151 if (width < COLUMN_MIN_WIDTH)
4152 width = COLUMN_MIN_WIDTH;
4157 /* this will do more later */
4159 resize_column (GtkCList * clist,
4163 gtk_clist_set_column_width (clist, column, width);
4168 column_button_create (GtkCList * clist,
4173 button = clist->column[column].button = gtk_button_new ();
4174 gtk_widget_set_parent (button, GTK_WIDGET (clist));
4175 if (GTK_WIDGET_REALIZED (clist) && clist->title_window)
4176 gtk_widget_set_parent_window (clist->column[column].button, clist->title_window);
4178 gtk_signal_connect (GTK_OBJECT (button), "clicked",
4179 (GtkSignalFunc) column_button_clicked,
4182 gtk_widget_show (button);
4186 column_button_clicked (GtkWidget * widget,
4192 g_return_if_fail (widget != NULL);
4193 g_return_if_fail (GTK_IS_CLIST (data));
4195 clist = GTK_CLIST (data);
4197 /* find the column who's button was pressed */
4198 for (i = 0; i < clist->columns; i++)
4199 if (clist->column[i].button == widget)
4202 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i);
4211 * vadjustment_changed
4212 * hadjustment_changed
4213 * vadjustment_value_changed
4214 * hadjustment_value_changed
4217 create_scrollbars (GtkCList * clist)
4219 GtkAdjustment *adjustment;
4221 clist->vscrollbar = gtk_vscrollbar_new (NULL);
4223 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
4225 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
4226 (GtkSignalFunc) vadjustment_changed,
4229 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
4230 (GtkSignalFunc) vadjustment_value_changed,
4233 gtk_widget_set_parent (clist->vscrollbar, GTK_WIDGET (clist));
4234 gtk_widget_show (clist->vscrollbar);
4236 clist->hscrollbar = gtk_hscrollbar_new (NULL);
4238 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
4240 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
4241 (GtkSignalFunc) hadjustment_changed,
4244 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
4245 (GtkSignalFunc) hadjustment_value_changed,
4248 gtk_widget_set_parent (clist->hscrollbar, GTK_WIDGET (clist));
4249 gtk_widget_show (clist->hscrollbar);
4253 adjust_scrollbars (GtkCList * clist)
4255 GTK_RANGE (clist->vscrollbar)->adjustment->page_size = clist->clist_window_height;
4256 GTK_RANGE (clist->vscrollbar)->adjustment->page_increment = clist->clist_window_height / 2;
4257 GTK_RANGE (clist->vscrollbar)->adjustment->step_increment = 10;
4258 GTK_RANGE (clist->vscrollbar)->adjustment->lower = 0;
4259 GTK_RANGE (clist->vscrollbar)->adjustment->upper = LIST_HEIGHT (clist);
4261 if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist))
4263 GTK_RANGE (clist->vscrollbar)->adjustment->value = MAX (0, LIST_HEIGHT (clist) -
4264 clist->clist_window_height);
4265 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment),
4269 GTK_RANGE (clist->hscrollbar)->adjustment->page_size = clist->clist_window_width;
4270 GTK_RANGE (clist->hscrollbar)->adjustment->page_increment = clist->clist_window_width / 2;
4271 GTK_RANGE (clist->hscrollbar)->adjustment->step_increment = 10;
4272 GTK_RANGE (clist->hscrollbar)->adjustment->lower = 0;
4273 GTK_RANGE (clist->hscrollbar)->adjustment->upper = LIST_WIDTH (clist);
4275 if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist))
4277 GTK_RANGE (clist->hscrollbar)->adjustment->value = MAX (0, LIST_WIDTH (clist) -
4278 clist->clist_window_width);
4279 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment),
4283 if (LIST_HEIGHT (clist) <= clist->clist_window_height &&
4284 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
4286 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
4288 gtk_widget_hide (clist->vscrollbar);
4289 gtk_widget_size_allocate (GTK_WIDGET (clist),
4290 >K_WIDGET (clist)->allocation);
4295 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
4297 gtk_widget_show (clist->vscrollbar);
4298 gtk_widget_size_allocate (GTK_WIDGET (clist),
4299 >K_WIDGET (clist)->allocation);
4303 if (LIST_WIDTH (clist) <= clist->clist_window_width &&
4304 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
4306 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
4308 gtk_widget_hide (clist->hscrollbar);
4309 gtk_widget_size_allocate (GTK_WIDGET (clist),
4310 >K_WIDGET (clist)->allocation);
4315 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
4317 gtk_widget_show (clist->hscrollbar);
4318 gtk_widget_size_allocate (GTK_WIDGET (clist),
4319 >K_WIDGET (clist)->allocation);
4323 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
4324 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), "changed");
4328 vadjustment_changed (GtkAdjustment * adjustment,
4333 g_return_if_fail (adjustment != NULL);
4334 g_return_if_fail (data != NULL);
4336 clist = GTK_CLIST (data);
4340 hadjustment_changed (GtkAdjustment * adjustment,
4345 g_return_if_fail (adjustment != NULL);
4346 g_return_if_fail (data != NULL);
4348 clist = GTK_CLIST (data);
4352 check_exposures (GtkCList *clist)
4356 if (!GTK_WIDGET_REALIZED (clist))
4359 /* Make sure graphics expose events are processed before scrolling
4361 while ((event = gdk_event_get_graphics_expose (clist->clist_window)) != NULL)
4363 gtk_widget_event (GTK_WIDGET (clist), event);
4364 if (event->expose.count == 0)
4366 gdk_event_free (event);
4369 gdk_event_free (event);
4374 vadjustment_value_changed (GtkAdjustment * adjustment,
4381 g_return_if_fail (adjustment != NULL);
4382 g_return_if_fail (data != NULL);
4383 g_return_if_fail (GTK_IS_CLIST (data));
4385 clist = GTK_CLIST (data);
4387 if (!GTK_WIDGET_DRAWABLE (clist))
4390 value = adjustment->value;
4392 if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)))
4394 if (value > -clist->voffset)
4397 diff = value + clist->voffset;
4399 /* we have to re-draw the whole screen here... */
4400 if (diff >= clist->clist_window_height)
4402 clist->voffset = -value;
4403 draw_rows (clist, NULL);
4407 if ((diff != 0) && (diff != clist->clist_window_height))
4408 gdk_window_copy_area (clist->clist_window,
4411 clist->clist_window,
4414 clist->clist_window_width,
4415 clist->clist_window_height - diff);
4418 area.y = clist->clist_window_height - diff;
4419 area.width = clist->clist_window_width;
4425 diff = -clist->voffset - value;
4427 /* we have to re-draw the whole screen here... */
4428 if (diff >= clist->clist_window_height)
4430 clist->voffset = -value;
4431 draw_rows (clist, NULL);
4435 if ((diff != 0) && (diff != clist->clist_window_height))
4436 gdk_window_copy_area (clist->clist_window,
4439 clist->clist_window,
4442 clist->clist_window_width,
4443 clist->clist_window_height - diff);
4447 area.width = clist->clist_window_width;
4452 clist->voffset = -value;
4453 if ((diff != 0) && (diff != clist->clist_window_height))
4454 check_exposures (clist);
4457 draw_rows (clist, &area);
4461 hadjustment_value_changed (GtkAdjustment * adjustment,
4471 g_return_if_fail (adjustment != NULL);
4472 g_return_if_fail (data != NULL);
4473 g_return_if_fail (GTK_IS_CLIST (data));
4475 clist = GTK_CLIST (data);
4477 if (!GTK_WIDGET_DRAWABLE (clist) ||
4478 adjustment != gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)))
4481 value = adjustment->value;
4483 /* move the column buttons and resize windows */
4484 for (i = 0; i < clist->columns; i++)
4486 if (clist->column[i].button)
4488 clist->column[i].button->allocation.x -= value + clist->hoffset;
4490 if (clist->column[i].button->window)
4492 gdk_window_move (clist->column[i].button->window,
4493 clist->column[i].button->allocation.x,
4494 clist->column[i].button->allocation.y);
4496 if (clist->column[i].window)
4497 gdk_window_move (clist->column[i].window,
4498 clist->column[i].button->allocation.x +
4499 clist->column[i].button->allocation.width -
4500 (DRAG_WIDTH / 2), 0);
4505 if (value > -clist->hoffset)
4508 diff = value + clist->hoffset;
4510 clist->hoffset = -value;
4512 /* we have to re-draw the whole screen here... */
4513 if (diff >= clist->clist_window_width)
4515 draw_rows (clist, NULL);
4519 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
4520 GTK_CLIST_ADD_MODE (clist))
4522 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4524 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
4525 clist->clist_window_width - 1,
4526 clist->row_height - 1);
4528 gdk_window_copy_area (clist->clist_window,
4531 clist->clist_window,
4534 clist->clist_window_width - diff,
4535 clist->clist_window_height);
4537 area.x = clist->clist_window_width - diff;
4542 if (!(diff = -clist->hoffset - value))
4545 clist->hoffset = -value;
4547 /* we have to re-draw the whole screen here... */
4548 if (diff >= clist->clist_window_width)
4550 draw_rows (clist, NULL);
4554 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
4555 GTK_CLIST_ADD_MODE (clist))
4557 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4559 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
4560 clist->clist_window_width - 1,
4561 clist->row_height - 1);
4564 gdk_window_copy_area (clist->clist_window,
4567 clist->clist_window,
4570 clist->clist_window_width - diff,
4571 clist->clist_window_height);
4578 area.height = clist->clist_window_height;
4580 check_exposures (clist);
4582 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist))
4584 if (GTK_CLIST_ADD_MODE (clist))
4588 focus_row = clist->focus_row;
4589 clist->focus_row = -1;
4590 draw_rows (clist, &area);
4591 clist->focus_row = focus_row;
4593 gdk_draw_rectangle (clist->clist_window, clist->xor_gc,
4594 FALSE, 0, y, clist->clist_window_width - 1,
4595 clist->row_height - 1);
4605 x0 = clist->clist_window_width - 1;
4614 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4615 gdk_draw_line (clist->clist_window, clist->xor_gc,
4616 x0, y + 1, x0, y + clist->row_height - 2);
4617 gdk_draw_line (clist->clist_window, clist->xor_gc,
4618 x1, y + 1, x1, y + clist->row_height - 2);
4622 draw_rows (clist, &area);
4626 * Memory Allocation/Distruction Routines for GtkCList stuctures
4638 static GtkCListColumn *
4639 columns_new (GtkCList * clist)
4642 GtkCListColumn *column;
4644 column = g_new (GtkCListColumn, clist->columns);
4646 for (i = 0; i < clist->columns; i++)
4648 column[i].area.x = 0;
4649 column[i].area.y = 0;
4650 column[i].area.width = 0;
4651 column[i].area.height = 0;
4652 column[i].title = NULL;
4653 column[i].button = NULL;
4654 column[i].window = NULL;
4655 column[i].width = 0;
4656 column[i].width_set = FALSE;
4657 column[i].justification = GTK_JUSTIFY_LEFT;
4664 column_title_new (GtkCList * clist,
4668 if (clist->column[column].title)
4669 g_free (clist->column[column].title);
4671 clist->column[column].title = g_strdup (title);
4675 columns_delete (GtkCList * clist)
4679 for (i = 0; i < clist->columns; i++)
4680 if (clist->column[i].title)
4681 g_free (clist->column[i].title);
4683 g_free (clist->column);
4686 static GtkCListRow *
4687 row_new (GtkCList * clist)
4690 GtkCListRow *clist_row;
4692 clist_row = g_chunk_new (GtkCListRow, clist->row_mem_chunk);
4693 clist_row->cell = g_chunk_new (GtkCell, clist->cell_mem_chunk);
4695 for (i = 0; i < clist->columns; i++)
4697 clist_row->cell[i].type = GTK_CELL_EMPTY;
4698 clist_row->cell[i].vertical = 0;
4699 clist_row->cell[i].horizontal = 0;
4702 clist_row->fg_set = FALSE;
4703 clist_row->bg_set = FALSE;
4704 clist_row->state = GTK_STATE_NORMAL;
4705 clist_row->data = NULL;
4706 clist_row->destroy = NULL;
4712 row_delete (GtkCList * clist,
4713 GtkCListRow * clist_row)
4717 for (i = 0; i < clist->columns; i++)
4718 cell_empty (clist, clist_row, i);
4720 if (clist_row->destroy)
4721 clist_row->destroy (clist_row->data);
4723 g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell);
4724 g_mem_chunk_free (clist->row_mem_chunk, clist_row);
4728 cell_empty (GtkCList * clist,
4729 GtkCListRow * clist_row,
4732 switch (clist_row->cell[column].type)
4734 case GTK_CELL_EMPTY:
4738 g_free (GTK_CELL_TEXT (clist_row->cell[column])->text);
4741 case GTK_CELL_PIXMAP:
4742 gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap);
4743 if (GTK_CELL_PIXMAP (clist_row->cell[column])->mask)
4744 gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask);
4747 case GTK_CELL_PIXTEXT:
4748 g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text);
4749 gdk_pixmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap);
4750 if (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask)
4751 gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask);
4754 case GTK_CELL_WIDGET:
4762 clist_row->cell[column].type = GTK_CELL_EMPTY;
4766 cell_set_text (GtkCList * clist,
4767 GtkCListRow * clist_row,
4771 cell_empty (clist, clist_row, column);
4775 clist_row->cell[column].type = GTK_CELL_TEXT;
4776 GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
4781 cell_set_pixmap (GtkCList * clist,
4782 GtkCListRow * clist_row,
4787 cell_empty (clist, clist_row, column);
4791 clist_row->cell[column].type = GTK_CELL_PIXMAP;
4792 GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
4793 /* We set the mask even if it is NULL */
4794 GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask;
4799 cell_set_pixtext (GtkCList * clist,
4800 GtkCListRow * clist_row,
4807 cell_empty (clist, clist_row, column);
4811 clist_row->cell[column].type = GTK_CELL_PIXTEXT;
4812 GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
4813 GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
4814 GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
4815 GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask;
4819 /* Fill in data after widget has correct style */
4822 add_style_data (GtkCList * clist)
4826 widget = GTK_WIDGET(clist);
4828 /* text properties */
4829 if (!GTK_CLIST_ROW_HEIGHT_SET (clist))
4831 clist->row_height = widget->style->font->ascent + widget->style->font->descent + 1;
4832 clist->row_center_offset = widget->style->font->ascent + 1.5;
4837 text_height = clist->row_height - (GTK_WIDGET (clist)->style->font->ascent +
4838 GTK_WIDGET (clist) ->style->font->descent + 1);
4839 clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
4846 /* focus functions */
4849 gtk_clist_draw_focus (GtkWidget *widget)
4853 g_return_if_fail (widget != NULL);
4854 g_return_if_fail (GTK_IS_CLIST (widget));
4856 if (!GTK_WIDGET_DRAWABLE (widget))
4859 clist = GTK_CLIST (widget);
4860 if (clist->focus_row >= 0)
4861 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
4862 0, ROW_TOP_YPIXEL(clist, clist->focus_row),
4863 clist->clist_window_width - 1,
4864 clist->row_height - 1);
4868 gtk_clist_set_focus_child (GtkContainer *container,
4871 g_return_if_fail (container != NULL);
4872 g_return_if_fail (GTK_IS_CLIST (container));
4876 g_return_if_fail (GTK_IS_WIDGET (child));
4877 GTK_CLIST_SET_FLAG (GTK_CLIST (container), CLIST_CHILD_HAS_FOCUS);
4880 parent_class->set_focus_child (container, child);
4884 gtk_clist_focus_in (GtkWidget *widget,
4885 GdkEventFocus *event)
4889 g_return_val_if_fail (widget != NULL, FALSE);
4890 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4891 g_return_val_if_fail (event != NULL, FALSE);
4893 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
4894 GTK_CLIST_UNSET_FLAG (widget, CLIST_CHILD_HAS_FOCUS);
4896 clist = GTK_CLIST (widget);
4898 if (clist->selection_mode == GTK_SELECTION_BROWSE &&
4899 clist->selection == NULL && clist->focus_row > -1)
4900 select_row (clist, clist->focus_row, -1, (GdkEvent *) event);
4902 gtk_widget_draw_focus (widget);
4908 gtk_clist_focus_out (GtkWidget *widget,
4909 GdkEventFocus *event)
4913 g_return_val_if_fail (widget != NULL, FALSE);
4914 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4915 g_return_val_if_fail (event != NULL, FALSE);
4917 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
4918 gtk_widget_draw_focus (widget);
4920 clist = GTK_CLIST (widget);
4922 if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
4923 GTK_CLIST_CLASS_FW (widget)->resync_selection (clist, (GdkEvent *) event);
4929 toggle_add_mode (GtkCList *clist)
4931 g_return_if_fail (clist != 0);
4932 g_return_if_fail (GTK_IS_CLIST (clist));
4934 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
4935 clist->selection_mode != GTK_SELECTION_EXTENDED)
4938 gtk_clist_draw_focus (GTK_WIDGET (clist));
4939 if (!GTK_CLIST_ADD_MODE (clist))
4941 GTK_CLIST_SET_FLAG (clist, CLIST_ADD_MODE);
4942 gdk_gc_set_line_attributes (clist->xor_gc, 1,
4943 GDK_LINE_ON_OFF_DASH, 0, 0);
4944 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
4948 GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
4949 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
4950 clist->anchor_state = GTK_STATE_SELECTED;
4952 gtk_clist_draw_focus (GTK_WIDGET (clist));
4956 toggle_focus_row (GtkCList *clist)
4958 g_return_if_fail (clist != 0);
4959 g_return_if_fail (GTK_IS_CLIST (clist));
4961 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
4962 clist->focus_row < 0 || clist->focus_row >= clist->rows)
4965 switch (clist->selection_mode)
4967 case GTK_SELECTION_SINGLE:
4968 case GTK_SELECTION_MULTIPLE:
4970 toggle_row (clist, clist->focus_row, 0, NULL);
4973 case GTK_SELECTION_EXTENDED:
4974 g_list_free (clist->undo_selection);
4975 g_list_free (clist->undo_unselection);
4976 clist->undo_selection = NULL;
4977 clist->undo_unselection = NULL;
4979 clist->anchor = clist->focus_row;
4980 clist->drag_pos = clist->focus_row;
4981 clist->undo_anchor = clist->focus_row;
4983 if (GTK_CLIST_ADD_MODE (clist))
4984 fake_toggle_row (clist, clist->focus_row);
4986 GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist,clist->focus_row);
4988 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
4997 move_focus_row (GtkCList *clist,
4998 GtkScrollType scroll_type,
5003 g_return_if_fail (clist != 0);
5004 g_return_if_fail (GTK_IS_CLIST (clist));
5006 widget = GTK_WIDGET (clist);
5008 switch (scroll_type)
5010 case GTK_SCROLL_STEP_BACKWARD:
5011 if (clist->focus_row <= 0)
5013 gtk_clist_draw_focus (widget);
5015 gtk_clist_draw_focus (widget);
5017 case GTK_SCROLL_STEP_FORWARD:
5018 if (clist->focus_row >= clist->rows - 1)
5020 gtk_clist_draw_focus (widget);
5022 gtk_clist_draw_focus (widget);
5024 case GTK_SCROLL_PAGE_BACKWARD:
5025 if (clist->focus_row <= 0)
5027 gtk_clist_draw_focus (widget);
5028 clist->focus_row = MAX (0, clist->focus_row -
5029 (2 * clist->clist_window_height -
5030 clist->row_height - CELL_SPACING) /
5031 (2 * (clist->row_height + CELL_SPACING)));
5032 gtk_clist_draw_focus (widget);
5034 case GTK_SCROLL_PAGE_FORWARD:
5035 if (clist->focus_row >= clist->rows - 1)
5037 gtk_clist_draw_focus (widget);
5038 clist->focus_row = MIN (clist->rows - 1, clist->focus_row +
5039 (2 * clist->clist_window_height -
5040 clist->row_height - CELL_SPACING) /
5041 (2 * (clist->row_height + CELL_SPACING)));
5042 gtk_clist_draw_focus (widget);
5044 case GTK_SCROLL_JUMP:
5045 if (position >= 0 && position <= 1)
5047 gtk_clist_draw_focus (widget);
5048 clist->focus_row = position * (clist->rows - 1);
5049 gtk_clist_draw_focus (widget);
5058 scroll_horizontal (GtkCList *clist,
5059 GtkScrollType scroll_type,
5064 g_return_if_fail (clist != 0);
5065 g_return_if_fail (GTK_IS_CLIST (clist));
5067 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5070 switch (scroll_type)
5072 case GTK_SCROLL_STEP_BACKWARD:
5073 column = COLUMN_FROM_XPIXEL (clist, 0);
5074 if (COLUMN_LEFT_XPIXEL (clist, column) - CELL_SPACING - COLUMN_INSET >= 0
5078 case GTK_SCROLL_STEP_FORWARD:
5079 column = COLUMN_FROM_XPIXEL (clist, clist->clist_window_width);
5082 if (COLUMN_LEFT_XPIXEL (clist, column) + clist->column[column].area.width
5083 + CELL_SPACING + COLUMN_INSET - 1 <= clist->clist_window_width &&
5084 column < clist->columns - 1)
5087 case GTK_SCROLL_PAGE_BACKWARD:
5088 case GTK_SCROLL_PAGE_FORWARD:
5090 case GTK_SCROLL_JUMP:
5091 if (position >= 0 && position <= 1)
5092 column = position * (clist->columns - 1);
5100 if (COLUMN_LEFT_XPIXEL (clist, column) < CELL_SPACING + COLUMN_INSET)
5101 gtk_clist_moveto (clist, -1, column, 0, 0);
5102 else if (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET - 1
5103 + clist->column[column].area.width > clist->clist_window_width)
5105 if (column == clist->columns - 1)
5106 gtk_clist_moveto (clist, -1, column, 0, 0);
5108 gtk_clist_moveto (clist, -1, column, 0, 1);
5113 scroll_vertical (GtkCList *clist,
5114 GtkScrollType scroll_type,
5119 g_return_if_fail (clist != NULL);
5120 g_return_if_fail (GTK_IS_CLIST (clist));
5122 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5125 switch (clist->selection_mode)
5127 case GTK_SELECTION_EXTENDED:
5128 if (clist->anchor >= 0)
5131 case GTK_SELECTION_BROWSE:
5133 old_focus_row = clist->focus_row;
5134 move_focus_row (clist, scroll_type, position);
5136 if (old_focus_row != clist->focus_row)
5138 if (clist->selection_mode == GTK_SELECTION_BROWSE)
5139 unselect_row (clist,old_focus_row, -1, NULL);
5140 else if (!GTK_CLIST_ADD_MODE (clist))
5142 gtk_clist_unselect_all (clist);
5143 clist->undo_anchor = old_focus_row;
5147 switch (gtk_clist_row_is_visible (clist, clist->focus_row))
5149 case GTK_VISIBILITY_NONE:
5150 if (old_focus_row != clist->focus_row &&
5151 !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
5152 GTK_CLIST_ADD_MODE (clist)))
5153 select_row (clist, clist->focus_row, -1, NULL);
5154 switch (scroll_type)
5156 case GTK_SCROLL_STEP_BACKWARD:
5157 case GTK_SCROLL_PAGE_BACKWARD:
5158 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5160 case GTK_SCROLL_STEP_FORWARD:
5161 case GTK_SCROLL_PAGE_FORWARD:
5162 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5164 case GTK_SCROLL_JUMP:
5165 gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
5172 case GTK_VISIBILITY_PARTIAL:
5173 switch (scroll_type)
5175 case GTK_SCROLL_STEP_BACKWARD:
5176 case GTK_SCROLL_PAGE_BACKWARD:
5177 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5179 case GTK_SCROLL_STEP_FORWARD:
5180 case GTK_SCROLL_PAGE_FORWARD:
5181 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5183 case GTK_SCROLL_JUMP:
5184 gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
5191 if (old_focus_row != clist->focus_row &&
5192 !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
5193 GTK_CLIST_ADD_MODE (clist)))
5194 select_row (clist, clist->focus_row, -1, NULL);
5200 move_focus_row (clist, scroll_type, position);
5202 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5203 clist->clist_window_height)
5204 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5205 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5206 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5212 set_anchor (GtkCList *clist,
5217 g_return_if_fail (clist != NULL);
5218 g_return_if_fail (GTK_IS_CLIST (clist));
5220 if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor >= 0)
5223 g_list_free (clist->undo_selection);
5224 g_list_free (clist->undo_unselection);
5225 clist->undo_selection = NULL;
5226 clist->undo_unselection = NULL;
5229 fake_toggle_row (clist, anchor);
5232 GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist, anchor);
5233 clist->anchor_state = GTK_STATE_SELECTED;
5236 clist->anchor = anchor;
5237 clist->drag_pos = anchor;
5238 clist->undo_anchor = undo_anchor;
5242 resync_selection (GtkCList *clist,
5248 gboolean thaw = FALSE;
5250 GtkCListRow *clist_row;
5252 if (clist->anchor < 0)
5255 if (!GTK_CLIST_FROZEN (clist))
5257 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
5261 i = MIN (clist->anchor, clist->drag_pos);
5262 e = MAX (clist->anchor, clist->drag_pos);
5264 if (clist->undo_selection)
5267 list = clist->selection;
5268 clist->selection = clist->undo_selection;
5269 clist->selection_end = g_list_last (clist->selection);
5270 clist->undo_selection = list;
5271 list = clist->selection;
5274 row = GPOINTER_TO_INT (list->data);
5276 if (row < i || row > e)
5278 clist_row = g_list_nth (clist->row_list, row)->data;
5279 clist_row->state = GTK_STATE_SELECTED;
5280 unselect_row (clist, row, -1, event);
5281 clist->undo_selection = g_list_prepend
5282 (clist->undo_selection, GINT_TO_POINTER (row));
5287 for (list = g_list_nth (clist->row_list, i); i <= e; i++, list = list->next)
5288 if (g_list_find (clist->selection, GINT_TO_POINTER(i)))
5290 if (GTK_CLIST_ROW (list)->state == GTK_STATE_NORMAL)
5292 GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
5293 unselect_row (clist, i, -1, event);
5294 clist->undo_selection = g_list_prepend (clist->undo_selection,
5295 GINT_TO_POINTER (i));
5298 else if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
5300 GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
5301 clist->undo_unselection = g_list_prepend (clist->undo_unselection,
5302 GINT_TO_POINTER (i));
5305 for (list = clist->undo_unselection; list; list = list->next)
5306 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
5307 GPOINTER_TO_INT (list->data), -1, event);
5310 clist->drag_pos = -1;
5313 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
5317 update_extended_selection (GtkCList *clist,
5327 gint y1 = clist->clist_window_height;
5328 gint y2 = clist->clist_window_height;
5333 if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor == -1)
5338 if (row >= clist->rows)
5339 row = clist->rows - 1;
5341 /* extending downwards */
5342 if (row > clist->drag_pos && clist->anchor <= clist->drag_pos)
5344 s2 = clist->drag_pos + 1;
5347 /* extending upwards */
5348 else if (row < clist->drag_pos && clist->anchor >= clist->drag_pos)
5351 e2 = clist->drag_pos - 1;
5353 else if (row < clist->drag_pos && clist->anchor < clist->drag_pos)
5355 e1 = clist->drag_pos;
5356 /* row and drag_pos on different sides of anchor :
5357 take back the selection between anchor and drag_pos,
5358 select between anchor and row */
5359 if (row < clist->anchor)
5361 s1 = clist->anchor + 1;
5363 e2 = clist->anchor - 1;
5365 /* take back the selection between anchor and drag_pos */
5369 else if (row > clist->drag_pos && clist->anchor > clist->drag_pos)
5371 s1 = clist->drag_pos;
5372 /* row and drag_pos on different sides of anchor :
5373 take back the selection between anchor and drag_pos,
5374 select between anchor and row */
5375 if (row > clist->anchor)
5377 e1 = clist->anchor - 1;
5378 s2 = clist->anchor + 1;
5381 /* take back the selection between anchor and drag_pos */
5386 clist->drag_pos = row;
5389 area.width = clist->clist_window_width;
5391 /* restore the elements between s1 and e1 */
5394 for (i = s1, list = g_list_nth (clist->row_list, i); i <= e1;
5395 i++, list = list->next)
5397 if (GTK_CLIST_CLASS_FW (clist)->selection_find (clist, i, list))
5398 GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
5400 GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
5403 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
5405 if (top + clist->row_height <= 0)
5408 area.height = ROW_TOP_YPIXEL (clist, e1) + clist->row_height;
5409 draw_rows (clist, &area);
5410 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5412 else if (top >= clist->clist_window_height)
5414 area.y = ROW_TOP_YPIXEL (clist, s1);
5415 area.height = clist->clist_window_height - area.y;
5416 draw_rows (clist, &area);
5417 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5420 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5421 else if (top + clist->row_height > clist->clist_window_height)
5422 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5424 y1 = ROW_TOP_YPIXEL (clist, s1);
5425 h1 = (e1 - s1 + 1) * (clist->row_height + CELL_SPACING);
5428 /* extend the selection between s2 and e2 */
5431 for (i = s2, list = g_list_nth (clist->row_list, i); i <= e2;
5432 i++, list = list->next)
5433 if (GTK_CLIST_ROW (list)->state != clist->anchor_state)
5434 GTK_CLIST_ROW (list)->state = clist->anchor_state;
5436 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
5438 if (top + clist->row_height <= 0)
5441 area.height = ROW_TOP_YPIXEL (clist, e2) + clist->row_height;
5442 draw_rows (clist, &area);
5443 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5445 else if (top >= clist->clist_window_height)
5447 area.y = ROW_TOP_YPIXEL (clist, s2);
5448 area.height = clist->clist_window_height - area.y;
5449 draw_rows (clist, &area);
5450 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5453 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5454 else if (top + clist->row_height > clist->clist_window_height)
5455 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5457 y2 = ROW_TOP_YPIXEL (clist, s2);
5458 h2 = (e2-s2+1) * (clist->row_height + CELL_SPACING);
5461 area.y = MAX (0, MIN (y1, y2));
5462 if (area.y > clist->clist_window_height)
5464 area.height = MIN (clist->clist_window_height, h1 + h2);
5465 if (s1 >= 0 && s2 >= 0)
5466 area.height += (clist->row_height + CELL_SPACING);
5467 draw_rows (clist, &area);
5471 start_selection (GtkCList *clist)
5473 g_return_if_fail (clist != NULL);
5474 g_return_if_fail (GTK_IS_CLIST (clist));
5476 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5479 set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
5484 end_selection (GtkCList *clist)
5486 g_return_if_fail (clist != NULL);
5487 g_return_if_fail (GTK_IS_CLIST (clist));
5489 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist)) ||
5490 clist->anchor == -1)
5493 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
5497 extend_selection (GtkCList *clist,
5498 GtkScrollType scroll_type,
5500 gboolean auto_start_selection)
5502 g_return_if_fail (clist != NULL);
5503 g_return_if_fail (GTK_IS_CLIST (clist));
5505 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
5506 clist->selection_mode != GTK_SELECTION_EXTENDED)
5509 if (auto_start_selection)
5510 set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
5512 else if (clist->anchor == -1)
5515 move_focus_row (clist, scroll_type, position);
5517 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5518 clist->clist_window_height)
5519 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5520 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5521 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5523 update_extended_selection (clist, clist->focus_row);
5527 abort_column_resize (GtkCList *clist)
5529 g_return_if_fail (clist != NULL);
5530 g_return_if_fail (GTK_IS_CLIST (clist));
5532 if (!GTK_CLIST_IN_DRAG (clist))
5535 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
5536 gtk_grab_remove (GTK_WIDGET (clist));
5537 gdk_pointer_ungrab (GDK_CURRENT_TIME);
5538 clist->drag_pos = -1;
5540 if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1)
5541 draw_xor_line (clist);
5543 if (GTK_CLIST_ADD_MODE (clist))
5545 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_ON_OFF_DASH, 0,0);
5546 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
5551 gtk_clist_key_press (GtkWidget * widget,
5552 GdkEventKey * event)
5554 g_return_val_if_fail (widget != NULL, FALSE);
5555 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
5556 g_return_val_if_fail (event != NULL, FALSE);
5558 if (GTK_WIDGET_CLASS (parent_class)->key_press_event &&
5559 GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
5562 switch (event->keyval)
5565 case GDK_ISO_Left_Tab:
5566 if (event->state & GDK_SHIFT_MASK)
5567 return gtk_container_focus (GTK_CONTAINER (widget),
5568 GTK_DIR_TAB_BACKWARD);
5570 return gtk_container_focus (GTK_CONTAINER (widget),
5571 GTK_DIR_TAB_FORWARD);
5581 title_focus (GtkCList * clist,
5584 GtkWidget *focus_child;
5585 gboolean return_val = FALSE;
5590 if (!GTK_CLIST_SHOW_TITLES (clist))
5593 focus_child = GTK_CONTAINER (clist)->focus_child;
5597 case GTK_DIR_TAB_BACKWARD:
5599 if (!focus_child || focus_child == clist->hscrollbar ||
5600 focus_child == clist->hscrollbar ||
5601 !GTK_CLIST_CHILD_HAS_FOCUS (clist))
5603 if (dir == GTK_DIR_UP)
5604 i = COLUMN_FROM_XPIXEL (clist, 0);
5606 i = clist->columns - 1;
5607 focus_child = clist->column[i].button;
5608 dir = GTK_DIR_TAB_FORWARD;
5615 if (!focus_child || focus_child == clist->hscrollbar ||
5616 focus_child == clist->hscrollbar)
5618 i = clist->columns - 1;
5619 focus_child = clist->column[i].button;
5623 if (!focus_child || focus_child == clist->hscrollbar ||
5624 focus_child == clist->hscrollbar)
5627 focus_child = clist->column[i].button;
5633 while (i < clist->columns)
5635 if (clist->column[i].button == focus_child)
5637 if (clist->column[i].button &&
5638 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
5639 GTK_IS_CONTAINER (clist->column[i].button) &&
5640 !GTK_WIDGET_HAS_FOCUS (clist->column[i].button))
5641 if (gtk_container_focus
5642 (GTK_CONTAINER (clist->column[i].button), dir))
5647 if (!return_val && dir == GTK_DIR_UP)
5658 while (j >= 0 && j < clist->columns)
5660 if (clist->column[j].button &&
5661 GTK_WIDGET_VISIBLE (clist->column[j].button))
5663 if (GTK_IS_CONTAINER (clist->column[j].button) &&
5665 (GTK_CONTAINER (clist->column[j].button), dir))
5670 else if (GTK_WIDGET_CAN_FOCUS (clist->column[j].button))
5672 gtk_widget_grab_focus (clist->column[j].button);
5682 if (COLUMN_LEFT_XPIXEL (clist, j) < CELL_SPACING + COLUMN_INSET)
5683 gtk_clist_moveto (clist, -1, j, 0, 0);
5684 else if (COLUMN_LEFT_XPIXEL(clist, j) + clist->column[j].area.width >
5685 clist->clist_window_width)
5687 if (j == clist->columns-1)
5688 gtk_clist_moveto (clist, -1, j, 0, 0);
5690 gtk_clist_moveto (clist, -1, j, 0, 1);
5697 gtk_clist_focus (GtkContainer * container,
5698 GtkDirectionType direction)
5701 GtkWidget *focus_child;
5704 g_return_val_if_fail (container != NULL, FALSE);
5705 g_return_val_if_fail (GTK_IS_CLIST (container), FALSE);
5707 if (!GTK_WIDGET_SENSITIVE (container))
5710 clist = GTK_CLIST (container);
5711 focus_child = container->focus_child;
5712 old_row = clist->focus_row;
5718 if (GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5719 (!focus_child || (focus_child && focus_child != clist->vscrollbar &&
5720 focus_child != clist->hscrollbar)))
5722 if (title_focus (clist, direction))
5724 gtk_container_set_focus_child (container, NULL);
5727 gtk_widget_grab_focus (GTK_WIDGET (container));
5730 case GTK_DIR_TAB_FORWARD:
5731 if (GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5732 (!focus_child || (focus_child != clist->vscrollbar &&
5733 focus_child != clist->hscrollbar)))
5735 gboolean tf = FALSE;
5737 if (((focus_child && direction == GTK_DIR_DOWN) ||
5738 !(tf = title_focus (clist, GTK_DIR_TAB_FORWARD)))
5741 if (clist->focus_row < 0)
5743 clist->focus_row = 0;
5745 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
5746 clist->selection_mode == GTK_SELECTION_EXTENDED) &&
5748 select_row (clist, clist->focus_row, -1, NULL);
5750 gtk_widget_grab_focus (GTK_WIDGET (container));
5758 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
5760 if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child ||
5761 (focus_child != clist->vscrollbar &&
5762 focus_child != clist->hscrollbar)) &&
5763 GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
5764 GTK_WIDGET_CAN_FOCUS (clist->vscrollbar))
5766 gtk_widget_grab_focus (clist->vscrollbar);
5770 if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child ||
5771 focus_child != clist->hscrollbar) &&
5772 GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
5773 GTK_WIDGET_CAN_FOCUS (clist->hscrollbar))
5775 gtk_widget_grab_focus (clist->hscrollbar);
5780 case GTK_DIR_TAB_BACKWARD:
5781 if (!focus_child && GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5782 GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
5783 GTK_WIDGET_CAN_FOCUS (clist->hscrollbar))
5785 gtk_widget_grab_focus (clist->hscrollbar);
5789 if ((!focus_child || focus_child == clist->hscrollbar) &&
5790 GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5791 GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
5792 GTK_WIDGET_CAN_FOCUS (clist->vscrollbar))
5794 gtk_widget_grab_focus (clist->vscrollbar);
5798 if ((!focus_child || focus_child == clist->hscrollbar ||
5799 focus_child == clist->vscrollbar) &&
5800 GTK_CLIST_CHILD_HAS_FOCUS (clist) && clist->rows)
5802 if (clist->focus_row < 0)
5804 clist->focus_row = 0;
5805 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
5806 clist->selection_mode == GTK_SELECTION_EXTENDED) &&
5808 select_row (clist, clist->focus_row, -1, NULL);
5810 gtk_widget_grab_focus (GTK_WIDGET (container));
5814 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
5816 if (title_focus (clist, direction))
5825 gtk_container_set_focus_child (container, NULL);
5830 gtk_clist_unselect_all (GtkCList * clist)
5832 GTK_CLIST_CLASS_FW (clist)->unselect_all (clist);
5836 real_unselect_all (GtkCList * clist)
5841 g_return_if_fail (clist != NULL);
5842 g_return_if_fail (GTK_IS_CLIST (clist));
5844 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5847 switch (clist->selection_mode)
5849 case GTK_SELECTION_BROWSE:
5850 if (clist->focus_row >= 0)
5852 select_row (clist, clist->focus_row, -1, NULL);
5857 case GTK_SELECTION_EXTENDED:
5858 g_list_free (clist->undo_selection);
5859 g_list_free (clist->undo_unselection);
5860 clist->undo_selection = NULL;
5861 clist->undo_unselection = NULL;
5864 clist->drag_pos = -1;
5865 clist->undo_anchor = clist->focus_row;
5872 list = clist->selection;
5876 i = GPOINTER_TO_INT (list->data);
5878 unselect_row (clist, i, -1, NULL);
5883 gtk_clist_select_all (GtkCList * clist)
5885 GTK_CLIST_CLASS_FW (clist)->select_all (clist);
5889 real_select_all (GtkCList * clist)
5894 g_return_if_fail (clist != NULL);
5895 g_return_if_fail (GTK_IS_CLIST (clist));
5897 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5900 switch (clist->selection_mode)
5902 case GTK_SELECTION_SINGLE:
5903 case GTK_SELECTION_BROWSE:
5906 case GTK_SELECTION_EXTENDED:
5907 g_list_free (clist->undo_selection);
5908 g_list_free (clist->undo_unselection);
5909 clist->undo_selection = NULL;
5910 clist->undo_unselection = NULL;
5913 ((GtkCListRow *) (clist->row_list->data))->state !=
5915 fake_toggle_row (clist, 0);
5917 clist->anchor_state = GTK_STATE_SELECTED;
5919 clist->drag_pos = 0;
5920 clist->undo_anchor = clist->focus_row;
5921 update_extended_selection (clist, clist->rows);
5922 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
5925 case GTK_SELECTION_MULTIPLE:
5926 for (i = 0, list = clist->row_list; list; i++, list = list->next)
5928 if (((GtkCListRow *)(list->data))->state == GTK_STATE_NORMAL)
5929 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
5937 fake_unselect_all (GtkCList * clist,
5944 if (row >= 0 && (work = g_list_nth (clist->row_list, row)))
5946 if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL)
5948 GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
5950 if (!GTK_CLIST_FROZEN (clist) &&
5951 gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
5952 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
5953 GTK_CLIST_ROW (work));
5957 clist->undo_selection = clist->selection;
5958 clist->selection = NULL;
5959 clist->selection_end = NULL;
5961 for (list = clist->undo_selection; list; list = list->next)
5963 if ((i = GPOINTER_TO_INT (list->data)) == row ||
5964 !(work = g_list_nth (clist->row_list, i)))
5967 GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
5968 if (!GTK_CLIST_FROZEN (clist) &&
5969 gtk_clist_row_is_visible (clist, i) != GTK_VISIBILITY_NONE)
5970 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, i,
5971 GTK_CLIST_ROW (work));
5976 fake_toggle_row (GtkCList *clist,
5981 if (!(work = g_list_nth (clist->row_list, row)))
5984 if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL)
5985 clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
5987 clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
5989 if (!GTK_CLIST_FROZEN (clist) &&
5990 gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
5991 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
5992 GTK_CLIST_ROW (work));
5996 selection_find (GtkCList *clist,
5998 GList *row_list_element)
6000 return g_list_find (clist->selection, GINT_TO_POINTER (row_number));
6004 default_compare (GtkCList *clist,
6008 GtkCListRow *row1 = (GtkCListRow *) ptr1;
6009 GtkCListRow *row2 = (GtkCListRow *) ptr2;
6013 text1 = GTK_CELL_TEXT (row1->cell[clist->sort_column])->text;
6014 text2 = GTK_CELL_TEXT (row2->cell[clist->sort_column])->text;
6016 return strcmp (text1, text2);
6020 gtk_clist_set_compare_func (GtkCList *clist,
6021 GtkCListCompareFunc cmp_func)
6023 g_return_if_fail (clist != NULL);
6024 g_return_if_fail (GTK_IS_CLIST (clist));
6026 clist->compare = (cmp_func) ? cmp_func : default_compare;
6030 gtk_clist_set_auto_sort (GtkCList *clist,
6033 g_return_if_fail (clist != NULL);
6034 g_return_if_fail (GTK_IS_CLIST (clist));
6036 if (GTK_CLIST_AUTO_SORT (clist) && !auto_sort)
6037 GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_SORT);
6038 else if (!GTK_CLIST_AUTO_SORT (clist) && auto_sort)
6040 GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_SORT);
6041 gtk_clist_sort (clist);
6046 gtk_clist_set_sort_type (GtkCList *clist,
6047 GtkSortType sort_type)
6049 g_return_if_fail (clist != NULL);
6050 g_return_if_fail (GTK_IS_CLIST (clist));
6052 clist->sort_type = sort_type;
6056 gtk_clist_set_sort_column (GtkCList *clist,
6059 g_return_if_fail (clist != NULL);
6060 g_return_if_fail (GTK_IS_CLIST (clist));
6062 if (column < 0 || column >= clist->columns)
6065 clist->sort_column = column;
6069 gtk_clist_merge (GtkCList *clist,
6070 GList *a, /* first list to merge */
6071 GList *b) /* second list to merge */
6073 GList z = { 0 }; /* auxiliary node */
6099 cmp = clist->compare (clist, GTK_CLIST_ROW (a), GTK_CLIST_ROW (b));
6100 if ((cmp >= 0 && clist->sort_type == GTK_SORT_DESCENDING) ||
6101 (cmp <= 0 && clist->sort_type == GTK_SORT_ASCENDING) ||
6123 gtk_clist_mergesort (GtkCList *clist,
6124 GList *list, /* the list to sort */
6125 gint num) /* the list's length */
6136 /* move "half" to the middle */
6138 for (i = 0; i < num / 2; i++)
6141 /* cut the list in two */
6142 half->prev->next = NULL;
6145 /* recursively sort both lists */
6146 return gtk_clist_merge (clist,
6147 gtk_clist_mergesort (clist, list, num / 2),
6148 gtk_clist_mergesort (clist, half, num - num / 2));
6153 gtk_clist_sort (GtkCList *clist)
6158 gboolean thaw = FALSE;
6160 g_return_if_fail (clist != NULL);
6161 g_return_if_fail (GTK_IS_CLIST (clist));
6163 if (clist->rows <= 1)
6166 if (GTK_WIDGET_HAS_GRAB (GTK_WIDGET (clist)))
6169 if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
6171 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
6172 g_list_free (clist->undo_selection);
6173 g_list_free (clist->undo_unselection);
6174 clist->undo_selection = NULL;
6175 clist->undo_unselection = NULL;
6178 if (!GTK_CLIST_FROZEN (clist))
6180 gtk_clist_freeze (clist);
6184 clist->row_list = gtk_clist_mergesort (clist, clist->row_list, clist->rows);
6186 work = clist->selection;
6188 for (i = 0, list = clist->row_list; i < clist->rows; i++, list = list->next)
6190 if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
6192 work->data = GINT_TO_POINTER (i);
6196 if (i == clist->rows - 1)
6197 clist->row_list_end = list;
6201 gtk_clist_thaw (clist);