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 set_cell_contents (GtkCList * clist,
297 GtkCListRow * clist_row,
304 static gint real_insert_row (GtkCList * clist,
307 static void real_remove_row (GtkCList * clist,
311 static void gtk_clist_draw_focus (GtkWidget *widget);
312 static gint gtk_clist_focus_in (GtkWidget *widget,
313 GdkEventFocus *event);
314 static gint gtk_clist_focus_out (GtkWidget *widget,
315 GdkEventFocus *event);
316 static gint gtk_clist_focus (GtkContainer *container,
317 GtkDirectionType direction);
318 static void gtk_clist_set_focus_child (GtkContainer *container,
320 static gint gtk_clist_key_press (GtkWidget *widget,
323 /* Selection handling */
324 static void set_anchor (GtkCList *clist,
328 static void start_selection (GtkCList *clist);
329 static void end_selection (GtkCList *clist);
331 static void toggle_add_mode (GtkCList *clist);
332 static void toggle_focus_row (GtkCList *clist);
333 static void move_focus_row (GtkCList *clist,
334 GtkScrollType scroll_type,
336 static void scroll_horizontal (GtkCList *clist,
337 GtkScrollType scroll_type,
339 static void scroll_vertical (GtkCList *clist,
340 GtkScrollType scroll_type,
342 static void extend_selection (GtkCList *clist,
343 GtkScrollType scroll_type,
345 gboolean auto_start_selection);
348 static gint default_compare (GtkCList *clist,
351 static GList * gtk_clist_merge (GtkCList *clist,
354 static GList * gtk_clist_mergesort (GtkCList *clist,
357 static void real_sort_list (GtkCList *clist);
359 /* Fill in data after widget is realized and has style */
361 static void add_style_data (GtkCList * clist);
363 static GtkContainerClass *parent_class = NULL;
364 static guint clist_signals[LAST_SIGNAL] = {0};
368 gtk_clist_get_type (void)
370 static GtkType clist_type = 0;
374 GtkTypeInfo clist_info =
378 sizeof (GtkCListClass),
379 (GtkClassInitFunc) gtk_clist_class_init,
380 (GtkObjectInitFunc) gtk_clist_init,
381 /* reserved_1 */ NULL,
382 /* reserved_2 */ NULL,
383 (GtkClassInitFunc) NULL,
386 clist_type = gtk_type_unique (GTK_TYPE_CONTAINER, &clist_info);
393 gtk_clist_class_init (GtkCListClass * klass)
395 GtkObjectClass *object_class;
396 GtkWidgetClass *widget_class;
397 GtkContainerClass *container_class;
399 object_class = (GtkObjectClass *) klass;
400 widget_class = (GtkWidgetClass *) klass;
401 container_class = (GtkContainerClass *) klass;
403 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
405 clist_signals[SELECT_ROW] =
406 gtk_signal_new ("select_row",
409 GTK_SIGNAL_OFFSET (GtkCListClass, select_row),
410 gtk_marshal_NONE__INT_INT_POINTER,
415 clist_signals[UNSELECT_ROW] =
416 gtk_signal_new ("unselect_row",
419 GTK_SIGNAL_OFFSET (GtkCListClass, unselect_row),
420 gtk_marshal_NONE__INT_INT_POINTER,
421 GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_GDK_EVENT);
422 clist_signals[CLICK_COLUMN] =
423 gtk_signal_new ("click_column",
426 GTK_SIGNAL_OFFSET (GtkCListClass, click_column),
427 gtk_marshal_NONE__INT,
428 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
430 clist_signals[TOGGLE_FOCUS_ROW] =
431 gtk_signal_new ("toggle_focus_row",
432 GTK_RUN_LAST | GTK_RUN_ACTION,
434 GTK_SIGNAL_OFFSET (GtkCListClass, toggle_focus_row),
435 gtk_marshal_NONE__NONE,
437 clist_signals[SELECT_ALL] =
438 gtk_signal_new ("select_all",
439 GTK_RUN_LAST | GTK_RUN_ACTION,
441 GTK_SIGNAL_OFFSET (GtkCListClass, select_all),
442 gtk_marshal_NONE__NONE,
444 clist_signals[UNSELECT_ALL] =
445 gtk_signal_new ("unselect_all",
446 GTK_RUN_LAST | GTK_RUN_ACTION,
448 GTK_SIGNAL_OFFSET (GtkCListClass, unselect_all),
449 gtk_marshal_NONE__NONE,
451 clist_signals[UNDO_SELECTION] =
452 gtk_signal_new ("undo_selection",
453 GTK_RUN_LAST | GTK_RUN_ACTION,
455 GTK_SIGNAL_OFFSET (GtkCListClass, undo_selection),
456 gtk_marshal_NONE__NONE,
458 clist_signals[START_SELECTION] =
459 gtk_signal_new ("start_selection",
460 GTK_RUN_LAST | GTK_RUN_ACTION,
462 GTK_SIGNAL_OFFSET (GtkCListClass, start_selection),
463 gtk_marshal_NONE__NONE,
465 clist_signals[END_SELECTION] =
466 gtk_signal_new ("end_selection",
467 GTK_RUN_LAST | GTK_RUN_ACTION,
469 GTK_SIGNAL_OFFSET (GtkCListClass, end_selection),
470 gtk_marshal_NONE__NONE,
472 clist_signals[TOGGLE_ADD_MODE] =
473 gtk_signal_new ("toggle_add_mode",
474 GTK_RUN_LAST | GTK_RUN_ACTION,
476 GTK_SIGNAL_OFFSET (GtkCListClass, toggle_add_mode),
477 gtk_marshal_NONE__NONE,
479 clist_signals[EXTEND_SELECTION] =
480 gtk_signal_new ("extend_selection",
481 GTK_RUN_LAST | GTK_RUN_ACTION,
483 GTK_SIGNAL_OFFSET (GtkCListClass, extend_selection),
484 gtk_marshal_NONE__ENUM_FLOAT_BOOL,
486 GTK_TYPE_SCROLL_TYPE, GTK_TYPE_FLOAT, GTK_TYPE_BOOL);
487 clist_signals[SCROLL_VERTICAL] =
488 gtk_signal_new ("scroll_vertical",
489 GTK_RUN_LAST | GTK_RUN_ACTION,
491 GTK_SIGNAL_OFFSET (GtkCListClass, scroll_vertical),
492 gtk_marshal_NONE__ENUM_FLOAT,
493 GTK_TYPE_NONE, 2, GTK_TYPE_SCROLL_TYPE, GTK_TYPE_FLOAT);
494 clist_signals[SCROLL_HORIZONTAL] =
495 gtk_signal_new ("scroll_horizontal",
496 GTK_RUN_LAST | GTK_RUN_ACTION,
498 GTK_SIGNAL_OFFSET (GtkCListClass, scroll_horizontal),
499 gtk_marshal_NONE__ENUM_FLOAT,
500 GTK_TYPE_NONE, 2, GTK_TYPE_SCROLL_TYPE, GTK_TYPE_FLOAT);
501 clist_signals[ABORT_COLUMN_RESIZE] =
502 gtk_signal_new ("abort_column_resize",
503 GTK_RUN_LAST | GTK_RUN_ACTION,
505 GTK_SIGNAL_OFFSET (GtkCListClass, abort_column_resize),
506 gtk_marshal_NONE__NONE,
510 gtk_object_class_add_signals (object_class, clist_signals, LAST_SIGNAL);
512 object_class->destroy = gtk_clist_destroy;
513 object_class->finalize = gtk_clist_finalize;
515 widget_class->realize = gtk_clist_realize;
516 widget_class->unrealize = gtk_clist_unrealize;
517 widget_class->map = gtk_clist_map;
518 widget_class->unmap = gtk_clist_unmap;
519 widget_class->draw = gtk_clist_draw;
520 widget_class->button_press_event = gtk_clist_button_press;
521 widget_class->button_release_event = gtk_clist_button_release;
522 widget_class->motion_notify_event = gtk_clist_motion;
523 widget_class->expose_event = gtk_clist_expose;
524 widget_class->size_request = gtk_clist_size_request;
525 widget_class->size_allocate = gtk_clist_size_allocate;
526 widget_class->key_press_event = gtk_clist_key_press;
527 widget_class->focus_in_event = gtk_clist_focus_in;
528 widget_class->focus_out_event = gtk_clist_focus_out;
529 widget_class->draw_focus = gtk_clist_draw_focus;
531 /* container_class->add = NULL; use the default GtkContainerClass warning */
532 /* container_class->remove = NULL; use the default GtkContainerClass warning */
533 container_class->foreach = gtk_clist_foreach;
534 container_class->focus = gtk_clist_focus;
535 container_class->set_focus_child = gtk_clist_set_focus_child;
537 klass->select_row = real_select_row;
538 klass->unselect_row = real_unselect_row;
539 klass->undo_selection = real_undo_selection;
540 klass->resync_selection = resync_selection;
541 klass->selection_find = selection_find;
542 klass->click_column = NULL;
543 klass->draw_row = draw_row;
544 klass->insert_row = real_insert_row;
545 klass->remove_row = real_remove_row;
546 klass->clear = real_clear;
547 klass->sort_list = real_sort_list;
548 klass->select_all = real_select_all;
549 klass->unselect_all = real_unselect_all;
550 klass->fake_unselect_all = fake_unselect_all;
551 klass->scroll_horizontal = scroll_horizontal;
552 klass->scroll_vertical = scroll_vertical;
553 klass->extend_selection = extend_selection;
554 klass->toggle_focus_row = toggle_focus_row;
555 klass->toggle_add_mode = toggle_add_mode;
556 klass->start_selection = start_selection;
557 klass->end_selection = end_selection;
558 klass->abort_column_resize = abort_column_resize;
559 klass->set_cell_contents = set_cell_contents;
561 klass->scrollbar_spacing = 5;
564 GtkBindingSet *binding_set;
566 binding_set = gtk_binding_set_by_class (klass);
567 gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
568 "scroll_vertical", 2,
569 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
570 GTK_TYPE_FLOAT, 0.0);
571 gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
572 "scroll_vertical", 2,
573 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
574 GTK_TYPE_FLOAT, 0.0);
575 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
576 "scroll_vertical", 2,
577 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
578 GTK_TYPE_FLOAT, 0.0);
579 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
580 "scroll_vertical", 2,
581 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
582 GTK_TYPE_FLOAT, 0.0);
583 gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
584 "scroll_vertical", 2,
585 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
586 GTK_TYPE_FLOAT, 0.0);
587 gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
588 "scroll_vertical", 2,
589 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
590 GTK_TYPE_FLOAT, 1.0);
592 gtk_binding_entry_add_signal (binding_set, GDK_Up, GDK_SHIFT_MASK,
593 "extend_selection", 3,
594 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
595 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
596 gtk_binding_entry_add_signal (binding_set, GDK_Down, GDK_SHIFT_MASK,
597 "extend_selection", 3,
598 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
599 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
600 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, GDK_SHIFT_MASK,
601 "extend_selection", 3,
602 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
603 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
604 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, GDK_SHIFT_MASK,
605 "extend_selection", 3,
606 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
607 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
608 gtk_binding_entry_add_signal (binding_set, GDK_Home,
609 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
610 "extend_selection", 3,
611 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
612 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
613 gtk_binding_entry_add_signal (binding_set, GDK_End,
614 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
615 "extend_selection", 3,
616 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
617 GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE);
620 gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
621 "scroll_horizontal", 2,
622 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
623 GTK_TYPE_FLOAT, 0.0);
624 gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
625 "scroll_horizontal", 2,
626 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
627 GTK_TYPE_FLOAT, 0.0);
628 gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
629 "scroll_horizontal", 2,
630 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
631 GTK_TYPE_FLOAT, 0.0);
632 gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
633 "scroll_horizontal", 2,
634 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
635 GTK_TYPE_FLOAT, 1.0);
638 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
639 "undo_selection", 0);
640 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
641 "abort_column_resize", 0);
642 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
643 "toggle_focus_row", 0);
644 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK,
645 "toggle_add_mode", 0);
646 gtk_binding_entry_add_signal (binding_set, '/', GDK_CONTROL_MASK,
648 gtk_binding_entry_add_signal (binding_set, '\\', GDK_CONTROL_MASK,
650 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
651 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
653 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
654 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
656 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
657 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
660 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
661 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
668 GtkBindingSet *binding_set;
670 binding_set = gtk_binding_set_by_class (klass);
671 gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
672 "scroll_vertical", 2,
673 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
674 GTK_TYPE_FLOAT, 0.0);
675 gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
676 "scroll_vertical", 2,
677 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
678 GTK_TYPE_FLOAT, 0.0);
679 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
680 "scroll_vertical", 2,
681 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
682 GTK_TYPE_FLOAT, 0.0);
683 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
684 "scroll_vertical", 2,
685 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
686 GTK_TYPE_FLOAT, 0.0);
687 gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
688 "scroll_vertical", 2,
689 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
690 GTK_TYPE_FLOAT, 0.0);
691 gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
692 "scroll_vertical", 2,
693 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
696 gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0,
697 "extend_selection", 3,
698 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
699 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
700 gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0,
701 "extend_selection", 3,
702 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
703 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
704 gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Up, 0,
705 "extend_selection", 3,
706 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
707 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
708 gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Down, 0,
709 "extend_selection", 3,
710 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
711 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
712 gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, 0,
713 "extend_selection", 3,
714 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
715 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
716 gtk_binding_entry_add_signal (binding_set, GDK_KP_End, 0,
717 "extend_selection", 3,
718 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
719 GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE);
721 gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
722 "scroll_horizontal", 2,
723 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
724 GTK_TYPE_FLOAT, 0.0);
725 gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0,
726 "scroll_horizontal", 2,
727 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
728 GTK_TYPE_FLOAT, 0.0);
729 gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
730 "scroll_horizontal", 2,
731 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
732 GTK_TYPE_FLOAT, 0.0);
733 gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0,
734 "scroll_horizontal", 2,
735 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
736 GTK_TYPE_FLOAT, 0.0);
737 gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
738 "scroll_horizontal", 2,
739 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
740 GTK_TYPE_FLOAT, 0.0);
741 gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
742 "sroll_horizontal", 2,
743 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
744 GTK_TYPE_FLOAT, 1.0);
746 gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, 0,
747 "undo_selection", 0);
748 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
749 "abort_column_resize", 0);
750 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
751 "toggle_focus_row", 0);
752 gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0,
753 "toggle_add_mode", 0);
754 gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0,
756 gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0,
758 gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0,
765 gtk_clist_init (GtkCList * clist)
769 GTK_WIDGET_UNSET_FLAGS (clist, GTK_NO_WINDOW);
770 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
772 clist->row_mem_chunk = NULL;
773 clist->cell_mem_chunk = NULL;
776 clist->row_center_offset = 0;
777 clist->row_height = 0;
778 clist->row_list = NULL;
779 clist->row_list_end = NULL;
783 clist->title_window = NULL;
784 clist->column_title_area.x = 0;
785 clist->column_title_area.y = 0;
786 clist->column_title_area.width = 1;
787 clist->column_title_area.height = 1;
789 clist->clist_window = NULL;
790 clist->clist_window_width = 1;
791 clist->clist_window_height = 1;
796 clist->shadow_type = GTK_SHADOW_IN;
797 clist->hscrollbar_policy = GTK_POLICY_ALWAYS;
798 clist->vscrollbar_policy = GTK_POLICY_ALWAYS;
800 clist->cursor_drag = NULL;
801 clist->xor_gc = NULL;
806 clist->selection_mode = GTK_SELECTION_SINGLE;
807 clist->selection = NULL;
808 clist->selection_end = NULL;
809 clist->undo_selection = NULL;
810 clist->undo_unselection = NULL;
812 GTK_WIDGET_SET_FLAGS (clist, GTK_CAN_FOCUS);
813 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
814 clist->focus_row = -1;
815 clist->undo_anchor = -1;
818 clist->anchor_state = GTK_STATE_SELECTED;
819 clist->drag_pos = -1;
823 clist->compare = default_compare;
824 clist->sort_type = GTK_SORT_ASCENDING;
825 clist->sort_column = 0;
830 gtk_clist_construct (GtkCList * clist,
836 g_return_if_fail (clist != NULL);
837 g_return_if_fail (GTK_IS_CLIST (clist));
838 g_return_if_fail (GTK_CLIST_CONSTRUCTED (clist) == FALSE);
840 GTK_CLIST_SET_FLAG (clist, CLIST_CONSTRUCTED);
842 /* initalize memory chunks, if this has not been done by any
843 * possibly derived widget
845 if (!clist->row_mem_chunk)
846 clist->row_mem_chunk = g_mem_chunk_new ("clist row mem chunk",
847 sizeof (GtkCListRow),
848 sizeof (GtkCListRow) * CLIST_OPTIMUM_SIZE,
851 if (!clist->cell_mem_chunk)
852 clist->cell_mem_chunk = g_mem_chunk_new ("clist cell mem chunk",
853 sizeof (GtkCell) * columns,
854 sizeof (GtkCell) * columns * CLIST_OPTIMUM_SIZE,
857 /* set number of columns, allocate memory */
858 clist->columns = columns;
859 clist->column = columns_new (clist);
861 /* there needs to be at least one column button
862 * because there is alot of code that will break if it
864 column_button_create (clist, 0);
866 /* create scrollbars */
867 create_scrollbars (clist);
871 GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES);
872 for (i = 0; i < columns; i++)
873 gtk_clist_set_column_title (clist, i, titles[i]);
877 GTK_CLIST_UNSET_FLAG (clist, CLIST_SHOW_TITLES);
882 * GTKCLIST PUBLIC INTERFACE
883 * gtk_clist_new_with_titles
887 gtk_clist_new_with_titles (gint columns,
892 g_return_val_if_fail (titles != NULL, NULL);
894 widget = gtk_type_new (GTK_TYPE_CLIST);
896 gtk_clist_construct (GTK_CLIST (widget), columns, titles);
902 gtk_clist_new (gint columns)
909 clist = gtk_type_new (GTK_TYPE_CLIST);
910 gtk_clist_construct (clist, columns, NULL);
911 return GTK_WIDGET (clist);
915 gtk_clist_set_border (GtkCList * clist,
916 GtkShadowType border)
918 g_return_if_fail (clist != NULL);
919 g_return_if_fail (GTK_IS_CLIST (clist));
921 clist->shadow_type = border;
923 if (GTK_WIDGET_VISIBLE (clist))
924 gtk_widget_queue_resize (GTK_WIDGET (clist));
928 gtk_clist_set_selection_mode (GtkCList * clist,
929 GtkSelectionMode mode)
931 g_return_if_fail (clist != NULL);
932 g_return_if_fail (GTK_IS_CLIST (clist));
934 if (mode == clist->selection_mode)
937 clist->selection_mode = mode;
939 clist->anchor_state = GTK_STATE_SELECTED;
940 clist->drag_pos = -1;
941 clist->undo_anchor = clist->focus_row;
943 g_list_free (clist->undo_selection);
944 g_list_free (clist->undo_unselection);
945 clist->undo_selection = NULL;
946 clist->undo_unselection = NULL;
950 case GTK_SELECTION_MULTIPLE:
951 case GTK_SELECTION_EXTENDED:
953 case GTK_SELECTION_BROWSE:
954 case GTK_SELECTION_SINGLE:
955 gtk_clist_unselect_all (clist);
961 gtk_clist_freeze (GtkCList * clist)
963 g_return_if_fail (clist != NULL);
964 g_return_if_fail (GTK_IS_CLIST (clist));
966 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
970 gtk_clist_thaw (GtkCList * clist)
972 g_return_if_fail (clist != NULL);
973 g_return_if_fail (GTK_IS_CLIST (clist));
975 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
977 adjust_scrollbars (clist);
978 draw_rows (clist, NULL);
982 gtk_clist_column_titles_show (GtkCList * clist)
984 g_return_if_fail (clist != NULL);
985 g_return_if_fail (GTK_IS_CLIST (clist));
987 if (!GTK_CLIST_SHOW_TITLES (clist))
989 GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES);
990 if (clist->title_window)
991 gdk_window_show (clist->title_window);
992 gtk_widget_queue_resize (GTK_WIDGET (clist));
997 gtk_clist_column_titles_hide (GtkCList * clist)
999 g_return_if_fail (clist != NULL);
1000 g_return_if_fail (GTK_IS_CLIST (clist));
1002 if (GTK_CLIST_SHOW_TITLES (clist))
1004 GTK_CLIST_UNSET_FLAG (clist, CLIST_SHOW_TITLES);
1005 if (clist->title_window)
1006 gdk_window_hide (clist->title_window);
1007 gtk_widget_queue_resize (GTK_WIDGET (clist));
1012 gtk_clist_column_title_active (GtkCList * clist,
1015 g_return_if_fail (clist != NULL);
1016 g_return_if_fail (GTK_IS_CLIST (clist));
1018 if (column < 0 || column >= clist->columns)
1021 if (!GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
1022 !GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
1024 GTK_WIDGET_SET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS);
1025 if (GTK_WIDGET_VISIBLE (clist))
1026 gtk_widget_queue_draw (clist->column[column].button);
1031 gtk_clist_column_title_passive (GtkCList * clist,
1034 g_return_if_fail (clist != NULL);
1035 g_return_if_fail (GTK_IS_CLIST (clist));
1037 if (column < 0 || column >= clist->columns)
1040 if (GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
1041 GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
1043 GTK_WIDGET_UNSET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS);
1044 if (GTK_WIDGET_VISIBLE (clist))
1045 gtk_widget_queue_draw (clist->column[column].button);
1050 gtk_clist_column_titles_active (GtkCList * clist)
1054 g_return_if_fail (clist != NULL);
1055 g_return_if_fail (GTK_IS_CLIST (clist));
1057 for (i = 0; i < clist->columns; i++)
1058 if (clist->column[i].button)
1059 gtk_clist_column_title_active (clist, i);
1063 gtk_clist_column_titles_passive (GtkCList * clist)
1067 g_return_if_fail (clist != NULL);
1068 g_return_if_fail (GTK_IS_CLIST (clist));
1070 for (i = 0; i < clist->columns; i++)
1071 if (clist->column[i].button)
1072 gtk_clist_column_title_passive (clist, i);
1076 gtk_clist_set_column_title (GtkCList * clist,
1080 gint new_button = 0;
1081 GtkWidget *old_widget;
1082 GtkWidget *alignment = NULL;
1085 g_return_if_fail (clist != NULL);
1086 g_return_if_fail (GTK_IS_CLIST (clist));
1088 if (column < 0 || column >= clist->columns)
1091 /* if the column button doesn't currently exist,
1092 * it has to be created first */
1093 if (!clist->column[column].button)
1095 column_button_create (clist, column);
1099 column_title_new (clist, column, title);
1101 /* remove and destroy the old widget */
1102 old_widget = GTK_BIN (clist->column[column].button)->child;
1104 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
1106 /* create new alignment based no column justification */
1107 switch (clist->column[column].justification)
1109 case GTK_JUSTIFY_LEFT:
1110 alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
1113 case GTK_JUSTIFY_RIGHT:
1114 alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
1117 case GTK_JUSTIFY_CENTER:
1118 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1121 case GTK_JUSTIFY_FILL:
1122 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1126 label = gtk_label_new (clist->column[column].title);
1127 gtk_container_add (GTK_CONTAINER (alignment), label);
1128 gtk_container_add (GTK_CONTAINER (clist->column[column].button), alignment);
1129 gtk_widget_show (label);
1130 gtk_widget_show (alignment);
1132 /* if this button didn't previously exist, then the
1133 * column button positions have to be re-computed */
1134 if (GTK_WIDGET_VISIBLE (clist) && new_button)
1135 size_allocate_title_buttons (clist);
1139 gtk_clist_set_column_widget (GtkCList * clist,
1143 gint new_button = 0;
1144 GtkWidget *old_widget;
1146 g_return_if_fail (clist != NULL);
1147 g_return_if_fail (GTK_IS_CLIST (clist));
1149 if (column < 0 || column >= clist->columns)
1152 /* if the column button doesn't currently exist,
1153 * it has to be created first */
1154 if (!clist->column[column].button)
1156 column_button_create (clist, column);
1160 column_title_new (clist, column, NULL);
1162 /* remove and destroy the old widget */
1163 old_widget = GTK_BIN (clist->column[column].button)->child;
1165 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
1167 /* add and show the widget */
1170 gtk_container_add (GTK_CONTAINER (clist->column[column].button), widget);
1171 gtk_widget_show (widget);
1174 /* if this button didn't previously exist, then the
1175 * column button positions have to be re-computed */
1176 if (GTK_WIDGET_VISIBLE (clist) && new_button)
1177 size_allocate_title_buttons (clist);
1181 gtk_clist_set_column_justification (GtkCList * clist,
1183 GtkJustification justification)
1185 GtkWidget *alignment;
1187 g_return_if_fail (clist != NULL);
1188 g_return_if_fail (GTK_IS_CLIST (clist));
1190 if (column < 0 || column >= clist->columns)
1193 clist->column[column].justification = justification;
1195 /* change the alinment of the button title if it's not a
1197 if (clist->column[column].title)
1199 alignment = GTK_BIN (clist->column[column].button)->child;
1201 switch (clist->column[column].justification)
1203 case GTK_JUSTIFY_LEFT:
1204 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.0, 0.5, 0.0, 0.0);
1207 case GTK_JUSTIFY_RIGHT:
1208 gtk_alignment_set (GTK_ALIGNMENT (alignment), 1.0, 0.5, 0.0, 0.0);
1211 case GTK_JUSTIFY_CENTER:
1212 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
1215 case GTK_JUSTIFY_FILL:
1216 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
1224 if (!GTK_CLIST_FROZEN (clist))
1225 draw_rows (clist, NULL);
1229 gtk_clist_set_column_width (GtkCList * clist,
1233 g_return_if_fail (clist != NULL);
1234 g_return_if_fail (GTK_IS_CLIST (clist));
1236 if (column < 0 || column >= clist->columns)
1239 clist->column[column].width = width;
1240 clist->column[column].width_set = TRUE;
1242 /* FIXME: this is quite expensive to do if the widget hasn't
1243 * been size_allocated yet, and pointless. Should
1246 size_allocate_columns (clist);
1247 size_allocate_title_buttons (clist);
1249 if (!GTK_CLIST_FROZEN (clist))
1251 adjust_scrollbars (clist);
1252 draw_rows (clist, NULL);
1257 gtk_clist_set_row_height (GtkCList * clist,
1262 g_return_if_fail (clist != NULL);
1263 g_return_if_fail (GTK_IS_CLIST (clist));
1266 clist->row_height = height;
1270 GTK_CLIST_SET_FLAG (clist, CLIST_ROW_HEIGHT_SET);
1272 if (GTK_WIDGET_REALIZED (clist))
1274 text_height = height - (GTK_WIDGET (clist)->style->font->ascent +
1275 GTK_WIDGET (clist) ->style->font->descent + 1);
1276 clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
1279 if (!GTK_CLIST_FROZEN (clist))
1281 adjust_scrollbars (clist);
1282 draw_rows (clist, NULL);
1287 gtk_clist_moveto (GtkCList * clist,
1293 g_return_if_fail (clist != NULL);
1294 g_return_if_fail (GTK_IS_CLIST (clist));
1296 if (row < -1 || row >= clist->rows)
1298 if (column < -1 || column >= clist->columns)
1301 row_align = CLAMP (row_align, 0, 1);
1302 col_align = CLAMP (col_align, 0, 1);
1304 /* adjust horizontal scrollbar */
1310 adj = GTK_RANGE (clist->hscrollbar)->adjustment;
1312 x = COLUMN_LEFT (clist, column) - CELL_SPACING - COLUMN_INSET -
1313 (col_align * (clist->clist_window_width - 2 * COLUMN_INSET -
1314 CELL_SPACING - clist->column[column].area.width));
1316 gtk_adjustment_set_value (adj, 0.0);
1317 else if (x > LIST_WIDTH (clist) - clist->clist_window_width)
1318 gtk_adjustment_set_value
1319 (adj, LIST_WIDTH (clist) - clist->clist_window_width);
1321 gtk_adjustment_set_value (adj, x);
1324 /* adjust vertical scrollbar */
1326 move_vertical (clist, row, row_align);
1330 gtk_clist_get_cell_type (GtkCList * clist,
1334 GtkCListRow *clist_row;
1336 g_return_val_if_fail (clist != NULL, -1);
1337 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1339 if (row < 0 || row >= clist->rows)
1341 if (column < 0 || column >= clist->columns)
1344 clist_row = (g_list_nth (clist->row_list, row))->data;
1346 return clist_row->cell[column].type;
1350 gtk_clist_set_text (GtkCList * clist,
1355 GtkCListRow *clist_row;
1357 g_return_if_fail (clist != NULL);
1358 g_return_if_fail (GTK_IS_CLIST (clist));
1360 if (row < 0 || row >= clist->rows)
1362 if (column < 0 || column >= clist->columns)
1365 clist_row = (g_list_nth (clist->row_list, row))->data;
1367 /* if text is null, then the cell is empty */
1368 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
1369 (clist, clist_row, column, GTK_CELL_TEXT, text, 0, NULL, NULL);
1371 /* redraw the list if it's not frozen */
1372 if (!GTK_CLIST_FROZEN (clist))
1374 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1375 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1380 gtk_clist_get_text (GtkCList * clist,
1385 GtkCListRow *clist_row;
1387 g_return_val_if_fail (clist != NULL, 0);
1388 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
1390 if (row < 0 || row >= clist->rows)
1392 if (column < 0 || column >= clist->columns)
1395 clist_row = (g_list_nth (clist->row_list, row))->data;
1397 if (clist_row->cell[column].type != GTK_CELL_TEXT)
1401 *text = GTK_CELL_TEXT (clist_row->cell[column])->text;
1407 gtk_clist_set_pixmap (GtkCList * clist,
1413 GtkCListRow *clist_row;
1415 g_return_if_fail (clist != NULL);
1416 g_return_if_fail (GTK_IS_CLIST (clist));
1418 if (row < 0 || row >= clist->rows)
1420 if (column < 0 || column >= clist->columns)
1423 clist_row = (g_list_nth (clist->row_list, row))->data;
1425 gdk_pixmap_ref (pixmap);
1427 if (mask) gdk_pixmap_ref (mask);
1429 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
1430 (clist, clist_row, column, GTK_CELL_PIXMAP, NULL, 0, pixmap, mask);
1432 /* redraw the list if it's not frozen */
1433 if (!GTK_CLIST_FROZEN (clist))
1435 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1436 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1441 gtk_clist_get_pixmap (GtkCList * clist,
1444 GdkPixmap ** pixmap,
1447 GtkCListRow *clist_row;
1449 g_return_val_if_fail (clist != NULL, 0);
1450 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
1452 if (row < 0 || row >= clist->rows)
1454 if (column < 0 || column >= clist->columns)
1457 clist_row = (g_list_nth (clist->row_list, row))->data;
1459 if (clist_row->cell[column].type != GTK_CELL_PIXMAP)
1464 *pixmap = GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap;
1465 /* mask can be NULL */
1466 *mask = GTK_CELL_PIXMAP (clist_row->cell[column])->mask;
1473 gtk_clist_set_pixtext (GtkCList * clist,
1481 GtkCListRow *clist_row;
1483 g_return_if_fail (clist != NULL);
1484 g_return_if_fail (GTK_IS_CLIST (clist));
1486 if (row < 0 || row >= clist->rows)
1488 if (column < 0 || column >= clist->columns)
1491 clist_row = (g_list_nth (clist->row_list, row))->data;
1493 gdk_pixmap_ref (pixmap);
1494 if (mask) gdk_pixmap_ref (mask);
1495 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
1496 (clist, clist_row, column, GTK_CELL_PIXTEXT, text, spacing, pixmap, mask);
1498 /* redraw the list if it's not frozen */
1499 if (!GTK_CLIST_FROZEN (clist))
1501 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1502 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1507 gtk_clist_get_pixtext (GtkCList * clist,
1512 GdkPixmap ** pixmap,
1515 GtkCListRow *clist_row;
1517 g_return_val_if_fail (clist != NULL, 0);
1518 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
1520 if (row < 0 || row >= clist->rows)
1522 if (column < 0 || column >= clist->columns)
1525 clist_row = (g_list_nth (clist->row_list, row))->data;
1527 if (clist_row->cell[column].type != GTK_CELL_PIXTEXT)
1531 *text = GTK_CELL_PIXTEXT (clist_row->cell[column])->text;
1533 *spacing = GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing;
1535 *pixmap = GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap;
1537 /* mask can be NULL */
1538 *mask = GTK_CELL_PIXTEXT (clist_row->cell[column])->mask;
1544 gtk_clist_set_foreground (GtkCList * clist,
1548 GtkCListRow *clist_row;
1550 g_return_if_fail (clist != NULL);
1551 g_return_if_fail (GTK_IS_CLIST (clist));
1553 if (row < 0 || row >= clist->rows)
1556 clist_row = (g_list_nth (clist->row_list, row))->data;
1560 clist_row->foreground = *color;
1561 clist_row->fg_set = TRUE;
1564 clist_row->fg_set = FALSE;
1566 if (!GTK_CLIST_FROZEN (clist)
1567 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1568 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1572 gtk_clist_set_background (GtkCList * clist,
1576 GtkCListRow *clist_row;
1578 g_return_if_fail (clist != NULL);
1579 g_return_if_fail (GTK_IS_CLIST (clist));
1581 if (row < 0 || row >= clist->rows)
1584 clist_row = (g_list_nth (clist->row_list, row))->data;
1588 clist_row->background = *color;
1589 clist_row->bg_set = TRUE;
1592 clist_row->bg_set = FALSE;
1594 if (!GTK_CLIST_FROZEN (clist)
1595 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1596 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1600 gtk_clist_set_shift (GtkCList * clist,
1606 GtkCListRow *clist_row;
1608 g_return_if_fail (clist != NULL);
1609 g_return_if_fail (GTK_IS_CLIST (clist));
1611 if (row < 0 || row >= clist->rows)
1613 if (column < 0 || column >= clist->columns)
1616 clist_row = (g_list_nth (clist->row_list, row))->data;
1618 clist_row->cell[column].vertical = vertical;
1619 clist_row->cell[column].horizontal = horizontal;
1621 if (!GTK_CLIST_FROZEN (clist)
1622 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1623 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1627 gtk_clist_append (GtkCList * clist,
1630 g_return_val_if_fail (clist != NULL, -1);
1631 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1632 g_return_val_if_fail (text != NULL, -1);
1634 return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, clist->rows, text);
1638 gtk_clist_insert (GtkCList * clist,
1642 return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, row, text);
1646 real_insert_row (GtkCList * clist,
1651 GtkCListRow *clist_row;
1653 g_return_val_if_fail (clist != NULL, -1);
1654 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1655 g_return_val_if_fail (text != NULL, -1);
1657 /* return if out of bounds */
1658 if (row < 0 || row > clist->rows)
1661 /* create the row */
1662 clist_row = row_new (clist);
1664 /* set the text in the row's columns */
1665 for (i = 0; i < clist->columns; i++)
1667 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
1668 (clist, clist_row, i, GTK_CELL_TEXT, text[i], 0, NULL ,NULL);
1672 clist->row_list = g_list_append (clist->row_list, clist_row);
1673 clist->row_list_end = clist->row_list;
1677 if (GTK_CLIST_AUTO_SORT (clist)) /* override insertion pos */
1682 work = clist->row_list;
1684 if (clist->sort_type == GTK_SORT_ASCENDING)
1686 while (row < clist->rows &&
1687 clist->compare (clist, clist_row,
1688 GTK_CLIST_ROW (work)) > 0)
1696 while (row < clist->rows &&
1697 clist->compare (clist, clist_row,
1698 GTK_CLIST_ROW (work)) < 0)
1706 /* reset the row end pointer if we're inserting at the end of the list */
1707 if (row == clist->rows)
1708 clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
1710 clist->row_list = g_list_insert (clist->row_list, clist_row, row);
1715 if (row < ROW_FROM_YPIXEL (clist, 0))
1716 clist->voffset -= (clist->row_height + CELL_SPACING);
1718 /* syncronize the selection list */
1719 sync_selection (clist, row, SYNC_INSERT);
1721 /* redraw the list if it isn't frozen */
1722 if (!GTK_CLIST_FROZEN (clist))
1724 adjust_scrollbars (clist);
1726 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1727 draw_rows (clist, NULL);
1734 gtk_clist_remove (GtkCList * clist,
1737 GTK_CLIST_CLASS_FW (clist)->remove_row (clist, row);
1741 real_remove_row (GtkCList * clist,
1744 gint was_visible, was_selected;
1746 GtkCListRow *clist_row;
1748 g_return_if_fail (clist != NULL);
1749 g_return_if_fail (GTK_IS_CLIST (clist));
1751 /* return if out of bounds */
1752 if (row < 0 || row > (clist->rows - 1))
1755 was_visible = (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE);
1758 /* get the row we're going to delete */
1759 list = g_list_nth (clist->row_list, row);
1760 clist_row = list->data;
1762 /* if we're removing a selected row, we have to make sure
1763 * it's properly unselected, and then sync up the clist->selected
1764 * list to reflect the deincrimented indexies of rows after the
1766 if (clist_row->state == GTK_STATE_SELECTED)
1768 switch (clist->selection_mode)
1770 case GTK_SELECTION_SINGLE:
1771 case GTK_SELECTION_MULTIPLE:
1772 case GTK_SELECTION_EXTENDED:
1773 unselect_row (clist, row, -1, NULL);
1776 case GTK_SELECTION_BROWSE:
1777 select_row (clist, row - 1, -1, NULL);
1785 /* reset the row end pointer if we're removing at the
1786 * end of the list */
1787 if (row == clist->rows - 1)
1788 clist->row_list_end = list->prev;
1789 if (row >= clist->focus_row && clist->focus_row >=0)
1792 clist->row_list = g_list_remove (clist->row_list, clist_row);
1795 if (row < ROW_FROM_YPIXEL (clist, 0))
1796 clist->voffset += clist->row_height + CELL_SPACING;
1798 sync_selection (clist, row, SYNC_REMOVE);
1801 row_delete (clist, clist_row);
1803 /* redraw the row if it isn't frozen */
1804 if (!GTK_CLIST_FROZEN (clist))
1806 adjust_scrollbars (clist);
1809 draw_rows (clist, NULL);
1814 sync_selection (GtkCList * clist,
1821 if (mode == SYNC_INSERT)
1826 if (clist->focus_row >= row)
1828 clist->focus_row += d;
1829 if (clist->focus_row == -1 && clist->rows >= 1)
1830 clist->focus_row = 0;
1833 if (clist->selection_mode == GTK_SELECTION_BROWSE && clist->anchor != -1)
1834 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
1836 g_list_free (clist->undo_selection);
1837 g_list_free (clist->undo_unselection);
1838 clist->undo_selection = NULL;
1839 clist->undo_unselection = NULL;
1842 clist->drag_pos = -1;
1843 clist->undo_anchor = clist->focus_row;
1845 list = clist->selection;
1848 if (GPOINTER_TO_INT (list->data) >= row)
1849 list->data = ((gchar*) list->data) + d;
1855 gtk_clist_clear (GtkCList * clist)
1857 GTK_CLIST_CLASS_FW (clist)->clear (clist);
1861 real_clear (GtkCList * clist)
1865 g_return_if_fail (clist != NULL);
1866 g_return_if_fail (GTK_IS_CLIST (clist));
1868 /* remove all the rows */
1869 for (list = clist->row_list; list; list = list->next)
1870 row_delete (clist, GTK_CLIST_ROW (list));
1872 g_list_free (clist->row_list);
1874 /* free up the selection list */
1875 g_list_free (clist->selection);
1876 g_list_free (clist->undo_selection);
1877 g_list_free (clist->undo_unselection);
1879 clist->row_list = NULL;
1880 clist->row_list_end = NULL;
1881 clist->selection = NULL;
1882 clist->selection_end = NULL;
1883 clist->undo_selection = NULL;
1884 clist->undo_unselection = NULL;
1887 clist->focus_row = -1;
1889 clist->undo_anchor = -1;
1890 clist->anchor_state = GTK_STATE_SELECTED;
1891 clist->drag_pos = -1;
1893 /* zero-out the scrollbars */
1894 if (clist->vscrollbar)
1896 GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0;
1897 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
1899 if (!GTK_CLIST_FROZEN (clist))
1900 gtk_clist_thaw (clist);
1905 gtk_clist_swap_rows (GtkCList * clist,
1910 GList *list, *link1, *link2;
1913 g_return_if_fail (clist != NULL);
1914 g_return_if_fail (GTK_IS_CLIST (clist));
1916 if (GTK_CLIST_AUTO_SORT (clist))
1919 if (row1 < 0 || row1 > (clist->rows - 1))
1922 if (row2 < 0 || row2 > (clist->rows - 1))
1925 first = MIN (row1, row2);
1926 last = MAX (row1, row2);
1928 link1 = g_list_nth (clist->row_list, first);
1929 link2 = g_list_nth (link1, row2 - row1);
1932 link1->data = link2->data;
1935 list = clist->selection;
1938 if (GPOINTER_TO_INT (list->data) == row1)
1939 list->data = GINT_TO_POINTER (row2);
1941 if (GPOINTER_TO_INT (list->data) == row2)
1942 list->data = GINT_TO_POINTER (row1);
1947 if (!GTK_CLIST_FROZEN (clist))
1949 if (gtk_clist_row_is_visible (clist, row1) != GTK_VISIBILITY_NONE)
1950 GTK_CLIST_CLASS_FW (clist)->draw_row
1951 (clist, NULL, row1, GTK_CLIST_ROW (link2));
1953 if (gtk_clist_row_is_visible (clist, row2) != GTK_VISIBILITY_NONE)
1954 GTK_CLIST_CLASS_FW (clist)->draw_row
1955 (clist, NULL, row2, GTK_CLIST_ROW (link1));
1960 gtk_clist_set_row_data (GtkCList * clist,
1964 gtk_clist_set_row_data_full (clist, row, data, NULL);
1968 gtk_clist_set_row_data_full (GtkCList * clist,
1971 GtkDestroyNotify destroy)
1973 GtkCListRow *clist_row;
1975 g_return_if_fail (clist != NULL);
1976 g_return_if_fail (GTK_IS_CLIST (clist));
1978 if (row < 0 || row > (clist->rows - 1))
1981 clist_row = (g_list_nth (clist->row_list, row))->data;
1982 clist_row->data = data;
1983 clist_row->destroy = destroy;
1987 gtk_clist_get_row_data (GtkCList * clist,
1990 GtkCListRow *clist_row;
1992 g_return_val_if_fail (clist != NULL, NULL);
1993 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
1995 if (row < 0 || row > (clist->rows - 1))
1998 clist_row = (g_list_nth (clist->row_list, row))->data;
1999 return clist_row->data;
2003 gtk_clist_find_row_from_data (GtkCList * clist,
2009 g_return_val_if_fail (clist != NULL, -1);
2010 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
2012 if (clist->rows < 1)
2013 return -1; /* is this an optimization or just worthless? */
2015 for (n = 0, list = clist->row_list; list; n++, list = list->next)
2016 if (GTK_CLIST_ROW (list)->data == data)
2023 gtk_clist_select_row (GtkCList * clist,
2027 g_return_if_fail (clist != NULL);
2028 g_return_if_fail (GTK_IS_CLIST (clist));
2030 if (row < 0 || row >= clist->rows)
2033 if (column < -1 || column >= clist->columns)
2036 select_row (clist, row, column, NULL);
2040 gtk_clist_unselect_row (GtkCList * clist,
2044 g_return_if_fail (clist != NULL);
2045 g_return_if_fail (GTK_IS_CLIST (clist));
2047 if (row < 0 || row >= clist->rows)
2050 if (column < -1 || column >= clist->columns)
2053 unselect_row (clist, row, column, NULL);
2057 gtk_clist_row_is_visible (GtkCList * clist,
2062 g_return_val_if_fail (clist != NULL, 0);
2063 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
2065 if (row < 0 || row >= clist->rows)
2066 return GTK_VISIBILITY_NONE;
2068 if (clist->row_height == 0)
2069 return GTK_VISIBILITY_NONE;
2071 if (row < ROW_FROM_YPIXEL (clist, 0))
2072 return GTK_VISIBILITY_NONE;
2074 if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height))
2075 return GTK_VISIBILITY_NONE;
2077 top = ROW_TOP_YPIXEL (clist, row);
2080 || ((top + clist->row_height) >= clist->clist_window_height))
2081 return GTK_VISIBILITY_PARTIAL;
2083 return GTK_VISIBILITY_FULL;
2087 static GtkAdjustment*
2088 gtk_clist_get_vadjustment (GtkCList * clist)
2090 g_return_val_if_fail (clist != NULL, NULL);
2091 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2093 return gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
2096 static GtkAdjustment*
2097 gtk_clist_get_hadjustment (GtkCList * clist)
2099 g_return_val_if_fail (clist != NULL, NULL);
2100 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2102 return gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
2107 gtk_clist_set_policy (GtkCList * clist,
2108 GtkPolicyType vscrollbar_policy,
2109 GtkPolicyType hscrollbar_policy)
2111 g_return_if_fail (clist != NULL);
2112 g_return_if_fail (GTK_IS_CLIST (clist));
2114 if (clist->vscrollbar_policy != vscrollbar_policy)
2116 clist->vscrollbar_policy = vscrollbar_policy;
2118 if (GTK_WIDGET (clist)->parent)
2119 gtk_widget_queue_resize (GTK_WIDGET (clist));
2122 if (clist->hscrollbar_policy != hscrollbar_policy)
2124 clist->hscrollbar_policy = hscrollbar_policy;
2126 if (GTK_WIDGET (clist)->parent)
2127 gtk_widget_queue_resize (GTK_WIDGET (clist));
2132 gtk_clist_undo_selection (GtkCList *clist)
2134 g_return_if_fail (clist != NULL);
2135 g_return_if_fail (GTK_IS_CLIST (clist));
2137 if (clist->selection_mode == GTK_SELECTION_EXTENDED &&
2138 (clist->undo_selection || clist->undo_unselection))
2139 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNDO_SELECTION]);
2143 real_undo_selection (GtkCList *clist)
2147 g_return_if_fail (clist != NULL);
2148 g_return_if_fail (GTK_IS_CLIST (clist));
2150 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
2151 clist->selection_mode != GTK_SELECTION_EXTENDED)
2154 if (clist->anchor >= 0)
2155 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
2157 if (!(clist->undo_selection || clist->undo_unselection))
2159 gtk_clist_unselect_all (clist);
2163 for (work = clist->undo_selection; work; work = work->next)
2164 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
2165 GPOINTER_TO_INT (work->data), -1, NULL);
2167 for (work = clist->undo_unselection; work; work = work->next)
2168 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
2169 GPOINTER_TO_INT (work->data), -1, NULL);
2171 if (GTK_WIDGET_HAS_FOCUS (clist) && clist->focus_row != clist->undo_anchor)
2173 gtk_clist_draw_focus (GTK_WIDGET (clist));
2174 clist->focus_row = clist->undo_anchor;
2175 gtk_clist_draw_focus (GTK_WIDGET (clist));
2178 clist->focus_row = clist->undo_anchor;
2180 clist->undo_anchor = -1;
2182 g_list_free (clist->undo_selection);
2183 g_list_free (clist->undo_unselection);
2184 clist->undo_selection = NULL;
2185 clist->undo_unselection = NULL;
2187 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
2188 clist->clist_window_height)
2189 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
2190 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
2191 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
2197 * gtk_clist_finalize
2200 gtk_clist_destroy (GtkObject * object)
2205 g_return_if_fail (object != NULL);
2206 g_return_if_fail (GTK_IS_CLIST (object));
2208 clist = GTK_CLIST (object);
2210 /* freeze the list */
2211 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2213 /* get rid of all the rows */
2214 gtk_clist_clear (clist);
2216 /* Since we don't have a _remove method, unparent the children
2217 * instead of destroying them so the focus will be unset properly.
2218 * (For other containers, the _remove method takes care of the
2219 * unparent) The destroy will happen when the refcount drops
2223 /* destroy the scrollbars */
2224 if (clist->vscrollbar)
2226 gtk_widget_unparent (clist->vscrollbar);
2227 clist->vscrollbar = NULL;
2229 if (clist->hscrollbar)
2231 gtk_widget_unparent (clist->hscrollbar);
2232 clist->hscrollbar = NULL;
2237 gtk_timeout_remove (clist->htimer);
2242 gtk_timeout_remove (clist->vtimer);
2246 /* destroy the column buttons */
2247 for (i = 0; i < clist->columns; i++)
2248 if (clist->column[i].button)
2250 gtk_widget_unparent (clist->column[i].button);
2251 clist->column[i].button = NULL;
2254 if (GTK_OBJECT_CLASS (parent_class)->destroy)
2255 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2259 gtk_clist_finalize (GtkObject * object)
2263 g_return_if_fail (object != NULL);
2264 g_return_if_fail (GTK_IS_CLIST (object));
2266 clist = GTK_CLIST (object);
2268 columns_delete (clist);
2270 g_mem_chunk_destroy (clist->cell_mem_chunk);
2271 g_mem_chunk_destroy (clist->row_mem_chunk);
2273 if (GTK_OBJECT_CLASS (parent_class)->finalize)
2274 (*GTK_OBJECT_CLASS (parent_class)->finalize) (object);
2280 * gtk_clist_unrealize
2285 * gtk_clist_button_press
2286 * gtk_clist_button_release
2288 * gtk_clist_size_request
2289 * gtk_clist_size_allocate
2292 gtk_clist_realize (GtkWidget * widget)
2296 GdkWindowAttr attributes;
2297 gint attributes_mask;
2301 g_return_if_fail (widget != NULL);
2302 g_return_if_fail (GTK_IS_CLIST (widget));
2304 clist = GTK_CLIST (widget);
2306 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2308 add_style_data (clist);
2310 border_width = GTK_CONTAINER (widget)->border_width;
2312 attributes.window_type = GDK_WINDOW_CHILD;
2313 attributes.x = widget->allocation.x + border_width;
2314 attributes.y = widget->allocation.y + border_width;
2315 attributes.width = widget->allocation.width - border_width * 2;
2316 attributes.height = widget->allocation.height - border_width * 2;
2317 attributes.wclass = GDK_INPUT_OUTPUT;
2318 attributes.visual = gtk_widget_get_visual (widget);
2319 attributes.colormap = gtk_widget_get_colormap (widget);
2320 attributes.event_mask = gtk_widget_get_events (widget);
2321 attributes.event_mask |= (GDK_EXPOSURE_MASK |
2322 GDK_BUTTON_PRESS_MASK |
2323 GDK_BUTTON_RELEASE_MASK |
2324 GDK_KEY_PRESS_MASK |
2325 GDK_KEY_RELEASE_MASK);
2326 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2329 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
2330 gdk_window_set_user_data (widget->window, clist);
2332 widget->style = gtk_style_attach (widget->style, widget->window);
2334 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
2336 /* column-title window */
2338 attributes.x = clist->column_title_area.x;
2339 attributes.y = clist->column_title_area.y;
2340 attributes.width = clist->column_title_area.width;
2341 attributes.height = clist->column_title_area.height;
2343 clist->title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2344 gdk_window_set_user_data (clist->title_window, clist);
2346 gtk_style_set_background (widget->style, clist->title_window, GTK_STATE_SELECTED);
2347 gdk_window_show (clist->title_window);
2349 /* set things up so column buttons are drawn in title window */
2350 for (i = 0; i < clist->columns; i++)
2351 if (clist->column[i].button)
2352 gtk_widget_set_parent_window (clist->column[i].button, clist->title_window);
2355 attributes.x = clist->internal_allocation.x + widget->style->klass->xthickness;
2356 attributes.y = clist->internal_allocation.y + widget->style->klass->ythickness +
2357 clist->column_title_area.height;
2358 attributes.width = clist->clist_window_width;
2359 attributes.height = clist->clist_window_height;
2361 clist->clist_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2362 gdk_window_set_user_data (clist->clist_window, clist);
2364 gdk_window_set_background (clist->clist_window, &widget->style->bg[GTK_STATE_PRELIGHT]);
2365 gdk_window_show (clist->clist_window);
2366 gdk_window_get_size (clist->clist_window, &clist->clist_window_width,
2367 &clist->clist_window_height);
2369 /* create resize windows */
2370 attributes.wclass = GDK_INPUT_ONLY;
2371 attributes.event_mask = (GDK_BUTTON_PRESS_MASK |
2372 GDK_BUTTON_RELEASE_MASK |
2373 GDK_POINTER_MOTION_MASK |
2374 GDK_POINTER_MOTION_HINT_MASK |
2375 GDK_KEY_PRESS_MASK);
2376 attributes.cursor = clist->cursor_drag = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
2377 attributes_mask = GDK_WA_CURSOR;
2379 for (i = 0; i < clist->columns; i++)
2381 clist->column[i].window = gdk_window_new (clist->title_window, &attributes, attributes_mask);
2382 gdk_window_set_user_data (clist->column[i].window, clist);
2385 /* This is slightly less efficient than creating them with the
2386 * right size to begin with, but easier
2388 size_allocate_title_buttons (clist);
2391 clist->fg_gc = gdk_gc_new (widget->window);
2392 clist->bg_gc = gdk_gc_new (widget->window);
2394 /* We'll use this gc to do scrolling as well */
2395 gdk_gc_set_exposures (clist->fg_gc, TRUE);
2397 values.foreground = widget->style->white;
2398 values.function = GDK_XOR;
2399 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
2400 clist->xor_gc = gdk_gc_new_with_values (widget->window,
2408 gtk_clist_unrealize (GtkWidget * widget)
2413 g_return_if_fail (widget != NULL);
2414 g_return_if_fail (GTK_IS_CLIST (widget));
2416 clist = GTK_CLIST (widget);
2418 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2420 gdk_cursor_destroy (clist->cursor_drag);
2421 gdk_gc_destroy (clist->xor_gc);
2422 gdk_gc_destroy (clist->fg_gc);
2423 gdk_gc_destroy (clist->bg_gc);
2425 for (i = 0; i < clist->columns; i++)
2426 if (clist->column[i].window)
2428 gdk_window_set_user_data (clist->column[i].window, NULL);
2429 gdk_window_destroy (clist->column[i].window);
2430 clist->column[i].window = NULL;
2433 gdk_window_set_user_data (clist->clist_window, NULL);
2434 gdk_window_destroy (clist->clist_window);
2435 clist->clist_window = NULL;
2437 gdk_window_set_user_data (clist->title_window, NULL);
2438 gdk_window_destroy (clist->title_window);
2439 clist->title_window = NULL;
2441 clist->cursor_drag = NULL;
2442 clist->xor_gc = NULL;
2443 clist->fg_gc = NULL;
2444 clist->bg_gc = NULL;
2446 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
2447 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2451 gtk_clist_map (GtkWidget * widget)
2456 g_return_if_fail (widget != NULL);
2457 g_return_if_fail (GTK_IS_CLIST (widget));
2459 clist = GTK_CLIST (widget);
2461 if (!GTK_WIDGET_MAPPED (widget))
2463 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
2465 gdk_window_show (widget->window);
2466 gdk_window_show (clist->title_window);
2467 gdk_window_show (clist->clist_window);
2469 /* map column buttons */
2470 for (i = 0; i < clist->columns; i++)
2471 if (clist->column[i].button &&
2472 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
2473 !GTK_WIDGET_MAPPED (clist->column[i].button))
2474 gtk_widget_map (clist->column[i].button);
2476 /* map resize windows AFTER column buttons (above) */
2477 for (i = 0; i < clist->columns; i++)
2478 if (clist->column[i].window && clist->column[i].button)
2479 gdk_window_show (clist->column[i].window);
2481 /* map vscrollbars */
2482 if (GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
2483 !GTK_WIDGET_MAPPED (clist->vscrollbar))
2484 gtk_widget_map (clist->vscrollbar);
2486 if (GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
2487 !GTK_WIDGET_MAPPED (clist->hscrollbar))
2488 gtk_widget_map (clist->hscrollbar);
2490 /* unfreeze the list */
2491 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
2496 gtk_clist_unmap (GtkWidget * widget)
2501 g_return_if_fail (widget != NULL);
2502 g_return_if_fail (GTK_IS_CLIST (widget));
2504 clist = GTK_CLIST (widget);
2506 if (GTK_WIDGET_MAPPED (widget))
2508 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
2510 for (i = 0; i < clist->columns; i++)
2511 if (clist->column[i].window)
2512 gdk_window_hide (clist->column[i].window);
2514 gdk_window_hide (clist->clist_window);
2515 gdk_window_hide (clist->title_window);
2516 gdk_window_hide (widget->window);
2518 /* unmap scrollbars */
2519 if (GTK_WIDGET_MAPPED (clist->vscrollbar))
2520 gtk_widget_unmap (clist->vscrollbar);
2522 if (GTK_WIDGET_MAPPED (clist->hscrollbar))
2523 gtk_widget_unmap (clist->hscrollbar);
2525 /* unmap column buttons */
2526 for (i = 0; i < clist->columns; i++)
2527 if (clist->column[i].button &&
2528 GTK_WIDGET_MAPPED (clist->column[i].button))
2529 gtk_widget_unmap (clist->column[i].button);
2531 /* freeze the list */
2532 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2537 gtk_clist_draw (GtkWidget * widget,
2538 GdkRectangle * area)
2542 GdkRectangle child_area;
2545 g_return_if_fail (widget != NULL);
2546 g_return_if_fail (GTK_IS_CLIST (widget));
2547 g_return_if_fail (area != NULL);
2549 if (GTK_WIDGET_DRAWABLE (widget))
2551 clist = GTK_CLIST (widget);
2552 border_width = GTK_CONTAINER (widget)->border_width;
2554 gdk_window_clear_area (widget->window,
2555 area->x - border_width,
2556 area->y - border_width,
2557 area->width, area->height);
2559 /* draw list shadow/border */
2560 gtk_draw_shadow (widget->style, widget->window,
2561 GTK_STATE_NORMAL, clist->shadow_type,
2563 clist->clist_window_width + (2 * widget->style->klass->xthickness),
2564 clist->clist_window_height + (2 * widget->style->klass->ythickness) +
2565 clist->column_title_area.height);
2567 gdk_window_clear_area (clist->clist_window,
2570 draw_rows (clist, NULL);
2572 for (i = 0; i < clist->columns; i++)
2574 if (gtk_widget_intersect (clist->column[i].button, area, &child_area))
2575 gtk_widget_draw (clist->column[i].button, &child_area);
2581 gtk_clist_expose (GtkWidget * widget,
2582 GdkEventExpose * event)
2586 g_return_val_if_fail (widget != NULL, FALSE);
2587 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2588 g_return_val_if_fail (event != NULL, FALSE);
2590 if (GTK_WIDGET_DRAWABLE (widget))
2592 clist = GTK_CLIST (widget);
2595 if (event->window == widget->window)
2596 gtk_draw_shadow (widget->style, widget->window,
2597 GTK_STATE_NORMAL, clist->shadow_type,
2599 clist->clist_window_width + (2 * widget->style->klass->xthickness),
2600 clist->clist_window_height + (2 * widget->style->klass->ythickness) +
2601 clist->column_title_area.height);
2603 /* exposure events on the list */
2604 if (event->window == clist->clist_window)
2605 draw_rows (clist, &event->area);
2612 gtk_clist_button_press (GtkWidget * widget,
2613 GdkEventButton * event)
2622 g_return_val_if_fail (widget != NULL, FALSE);
2623 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2624 g_return_val_if_fail (event != NULL, FALSE);
2626 clist = GTK_CLIST (widget);
2628 /* we don't handle button 2 and 3 */
2629 if (event->button != 1)
2632 /* selections on the list */
2633 if (event->window == clist->clist_window)
2638 if (get_selection_info (clist, x, y, &row, &column))
2640 gint old_row = clist->focus_row;
2642 if (clist->focus_row == -1)
2645 if (event->type == GDK_BUTTON_PRESS)
2647 GTK_CLIST_SET_FLAG (clist, CLIST_DRAG_SELECTION);
2648 gdk_pointer_grab (clist->clist_window, FALSE,
2649 GDK_POINTER_MOTION_HINT_MASK |
2650 GDK_BUTTON1_MOTION_MASK |
2651 GDK_BUTTON_RELEASE_MASK,
2652 NULL, NULL, event->time);
2653 gtk_grab_add (widget);
2655 else if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (widget))
2657 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
2658 gtk_grab_remove (widget);
2659 gdk_pointer_ungrab (event->time);
2662 if (GTK_CLIST_ADD_MODE (clist))
2664 GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
2665 if (GTK_WIDGET_HAS_FOCUS (widget))
2667 gtk_clist_draw_focus (widget);
2668 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2669 GDK_LINE_SOLID, 0, 0);
2670 clist->focus_row = row;
2671 gtk_clist_draw_focus (widget);
2675 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2676 GDK_LINE_SOLID, 0, 0);
2677 clist->focus_row = row;
2680 else if (row != clist->focus_row)
2682 if (GTK_WIDGET_HAS_FOCUS (widget))
2684 gtk_clist_draw_focus (widget);
2685 clist->focus_row = row;
2686 gtk_clist_draw_focus (widget);
2689 clist->focus_row = row;
2692 if (!GTK_WIDGET_HAS_FOCUS (widget))
2693 gtk_widget_grab_focus (widget);
2695 switch (clist->selection_mode)
2697 case GTK_SELECTION_SINGLE:
2698 case GTK_SELECTION_MULTIPLE:
2699 if (event->type != GDK_BUTTON_PRESS)
2700 select_row (clist, row, column, (GdkEvent *) event);
2702 clist->anchor = row;
2705 case GTK_SELECTION_BROWSE:
2706 select_row (clist, row, column, (GdkEvent *) event);
2709 case GTK_SELECTION_EXTENDED:
2710 if (event->type != GDK_BUTTON_PRESS)
2712 if (clist->anchor != -1)
2714 update_extended_selection (clist, clist->focus_row);
2715 GTK_CLIST_CLASS_FW (clist)->resync_selection
2716 (clist, (GdkEvent *) event);
2718 select_row (clist, row, column, (GdkEvent *) event);
2722 if (event->state & GDK_CONTROL_MASK)
2724 if (event->state & GDK_SHIFT_MASK)
2726 if (clist->anchor < 0)
2728 g_list_free (clist->undo_selection);
2729 g_list_free (clist->undo_unselection);
2730 clist->undo_selection = NULL;
2731 clist->undo_unselection = NULL;
2732 clist->anchor = old_row;
2733 clist->drag_pos = old_row;
2734 clist->undo_anchor = old_row;
2736 update_extended_selection (clist, clist->focus_row);
2740 if (clist->anchor == -1)
2741 set_anchor (clist, TRUE, row, old_row);
2743 update_extended_selection (clist, clist->focus_row);
2748 if (event->state & GDK_SHIFT_MASK)
2750 set_anchor (clist, FALSE, old_row, old_row);
2751 update_extended_selection (clist, clist->focus_row);
2755 if (clist->anchor == -1)
2756 set_anchor (clist, FALSE, row, old_row);
2758 update_extended_selection (clist, clist->focus_row);
2769 /* press on resize windows */
2770 for (i = 0; i < clist->columns; i++)
2771 if (clist->column[i].window && event->window == clist->column[i].window)
2773 gdk_pointer_grab (clist->column[i].window, FALSE,
2774 GDK_POINTER_MOTION_HINT_MASK |
2775 GDK_BUTTON1_MOTION_MASK |
2776 GDK_BUTTON_RELEASE_MASK,
2777 NULL, NULL, event->time);
2778 gtk_grab_add (widget);
2779 GTK_CLIST_SET_FLAG (clist, CLIST_IN_DRAG);
2781 if (!GTK_WIDGET_HAS_FOCUS (widget))
2782 gtk_widget_grab_focus (widget);
2784 clist->drag_pos = i;
2785 clist->x_drag = (COLUMN_LEFT_XPIXEL(clist, i) + COLUMN_INSET +
2786 clist->column[i].area.width + CELL_SPACING);
2788 if (GTK_CLIST_ADD_MODE (clist))
2789 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
2790 draw_xor_line (clist);
2799 gtk_clist_button_release (GtkWidget * widget,
2800 GdkEventButton * event)
2804 g_return_val_if_fail (widget != NULL, FALSE);
2805 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2806 g_return_val_if_fail (event != NULL, FALSE);
2808 clist = GTK_CLIST (widget);
2810 /* we don't handle button 2 and 3 */
2811 if (event->button != 1)
2814 /* release on resize windows */
2815 if (GTK_CLIST_IN_DRAG (clist))
2817 gint i, x, width, visible;
2819 i = clist->drag_pos;
2820 clist->drag_pos = -1;
2821 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
2822 gtk_widget_get_pointer (widget, &x, NULL);
2824 width = new_column_width (clist, i, &x, &visible);
2825 gtk_grab_remove (widget);
2826 gdk_pointer_ungrab (event->time);
2829 draw_xor_line (clist);
2831 if (GTK_CLIST_ADD_MODE (clist))
2833 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2834 GDK_LINE_ON_OFF_DASH, 0, 0);
2835 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
2838 resize_column (clist, i, width);
2842 if (GTK_CLIST_DRAG_SELECTION (clist))
2847 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
2848 gtk_grab_remove (widget);
2849 gdk_pointer_ungrab (event->time);
2852 gtk_timeout_remove (clist->htimer);
2857 gtk_timeout_remove (clist->vtimer);
2860 switch (clist->selection_mode)
2862 case GTK_SELECTION_EXTENDED:
2863 if (!(event->state & GDK_SHIFT_MASK) ||
2864 event->x < 0 || event->x >= clist->clist_window_width ||
2865 event->y < 0 || event->y >= clist->clist_window_height)
2866 GTK_CLIST_CLASS_FW (clist)->resync_selection
2867 (clist, (GdkEvent *) event);
2870 case GTK_SELECTION_SINGLE:
2871 case GTK_SELECTION_MULTIPLE:
2872 if (get_selection_info (clist, event->x, event->y, &row, &column))
2874 if (clist->anchor == clist->focus_row)
2875 toggle_row (clist, row, column, (GdkEvent *) event);
2889 horizontal_timeout (GtkCList *clist)
2892 GdkEventMotion event;
2893 GdkModifierType mask;
2895 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
2898 gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
2905 gtk_clist_motion (GTK_WIDGET (clist), &event);
2911 vertical_timeout (GtkCList *clist)
2914 GdkEventMotion event;
2915 GdkModifierType mask;
2917 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
2920 gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
2927 gtk_clist_motion (GTK_WIDGET (clist), &event);
2933 move_vertical (GtkCList *clist,
2940 adj = GTK_RANGE (clist->vscrollbar)->adjustment;
2942 y = ROW_TOP_YPIXEL (clist, row) - clist->voffset;
2944 y = y - align * (clist->clist_window_height - clist->row_height)
2945 + (2 * align - 1) * CELL_SPACING;
2947 if (y + adj->page_size > adj->upper)
2948 adj->value = adj->upper - adj->page_size;
2952 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
2956 move_horizontal (GtkCList *clist,
2962 adj = GTK_RANGE (clist->hscrollbar)->adjustment;
2966 upper = adj->upper - adj->page_size;
2967 adj->value = MIN (adj->value, upper);
2968 adj->value = MAX (adj->value, 0.0);
2970 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
2974 gtk_clist_motion (GtkWidget * widget,
2975 GdkEventMotion * event)
2983 g_return_val_if_fail (widget != NULL, FALSE);
2984 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2986 clist = GTK_CLIST (widget);
2988 if (!(gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)))
2991 if (GTK_CLIST_IN_DRAG (clist))
2993 if (event->is_hint || event->window != widget->window)
2994 gtk_widget_get_pointer (widget, &x, NULL);
2998 new_width = new_column_width (clist, clist->drag_pos, &x, &visible);
2999 /* Welcome to my hack! I'm going to use a value of x_drag = -99999
3000 * to indicate that the xor line is already invisible */
3002 if (!visible && clist->x_drag != -99999)
3004 draw_xor_line (clist);
3005 clist->x_drag = -99999;
3008 if (x != clist->x_drag && visible)
3010 if (clist->x_drag != -99999)
3011 draw_xor_line (clist);
3014 draw_xor_line (clist);
3017 if (new_width <= COLUMN_MIN_WIDTH + 1)
3019 if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) && x < 0)
3020 gtk_clist_moveto (clist, -1, clist->drag_pos, 0, 0);
3026 if (event->is_hint || event->window != clist->clist_window)
3027 gdk_window_get_pointer (clist->clist_window, &x, &y, NULL);
3029 /* horizontal autoscrolling */
3030 if (LIST_WIDTH (clist) > clist->clist_window_width &&
3031 (x < 0 || x >= clist->clist_window_width))
3036 clist->htimer = gtk_timeout_add
3037 (SCROLL_TIME, (GtkFunction) horizontal_timeout, clist);
3039 if (!((x < 0 && GTK_RANGE (clist->hscrollbar)->adjustment->value == 0) ||
3040 (x >= clist->clist_window_width &&
3041 GTK_RANGE (clist->hscrollbar)->adjustment->value ==
3042 LIST_WIDTH (clist) - clist->clist_window_width)))
3045 move_horizontal (clist, -1 + (x/2));
3047 move_horizontal (clist, 1 + (x - clist->clist_window_width) / 2);
3051 if (GTK_CLIST_IN_DRAG (clist))
3054 /* vertical autoscrolling */
3055 row = ROW_FROM_YPIXEL (clist, y);
3057 /* don't scroll on last pixel row if it's a cell spacing */
3058 if (y == clist->clist_window_height-1 &&
3059 y == ROW_TOP_YPIXEL (clist, row-1) + clist->row_height)
3062 if (LIST_HEIGHT (clist) > clist->clist_window_height &&
3063 (y < 0 || y >= clist->clist_window_height))
3068 clist->vtimer = gtk_timeout_add (SCROLL_TIME,
3069 (GtkFunction) vertical_timeout, clist);
3071 if (GTK_CLIST_DRAG_SELECTION (clist))
3073 if ((y < 0 && clist->focus_row == 0) ||
3074 (y >= clist->clist_window_height &&
3075 clist->focus_row == clist->rows-1))
3080 row = CLAMP (row, 0, clist->rows - 1);
3082 if (GTK_CLIST_DRAG_SELECTION (clist))
3084 if (row == clist->focus_row)
3087 gtk_clist_draw_focus (widget);
3088 clist->focus_row = row;
3089 gtk_clist_draw_focus (widget);
3091 switch (clist->selection_mode)
3093 case GTK_SELECTION_BROWSE:
3094 select_row (clist, clist->focus_row, - 1, (GdkEvent *) event);
3097 case GTK_SELECTION_EXTENDED:
3098 update_extended_selection (clist, clist->focus_row);
3106 if (ROW_TOP_YPIXEL(clist, row) < 0)
3107 move_vertical (clist, row, 0);
3108 else if (ROW_TOP_YPIXEL(clist, row) + clist->row_height >
3109 clist->clist_window_height)
3110 move_vertical (clist, row, 1);
3116 gtk_clist_size_request (GtkWidget * widget,
3117 GtkRequisition * requisition)
3122 g_return_if_fail (widget != NULL);
3123 g_return_if_fail (GTK_IS_CLIST (widget));
3124 g_return_if_fail (requisition != NULL);
3126 clist = GTK_CLIST (widget);
3128 add_style_data (clist);
3130 requisition->width = 0;
3131 requisition->height = 0;
3133 /* compute the size of the column title (title) area */
3134 clist->column_title_area.height = 0;
3135 if (GTK_CLIST_SHOW_TITLES (clist))
3136 for (i = 0; i < clist->columns; i++)
3137 if (clist->column[i].button)
3139 gtk_widget_size_request (clist->column[i].button, &clist->column[i].button->requisition);
3140 clist->column_title_area.height = MAX (clist->column_title_area.height,
3141 clist->column[i].button->requisition.height);
3143 requisition->height += clist->column_title_area.height;
3145 /* add the vscrollbar space */
3146 if ((clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
3147 GTK_WIDGET_VISIBLE (clist->vscrollbar))
3149 gtk_widget_size_request (clist->vscrollbar, &clist->vscrollbar->requisition);
3151 requisition->width += clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist);
3152 requisition->height = MAX (requisition->height,
3153 clist->vscrollbar->requisition.height);
3156 /* add the hscrollbar space */
3157 if ((clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
3158 GTK_WIDGET_VISIBLE (clist->hscrollbar))
3160 gtk_widget_size_request (clist->hscrollbar, &clist->hscrollbar->requisition);
3162 requisition->height += clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist);
3163 requisition->width = MAX (clist->hscrollbar->requisition.width,
3164 requisition->width -
3165 clist->vscrollbar->requisition.width);
3169 requisition->width += widget->style->klass->xthickness * 2 +
3170 GTK_CONTAINER (widget)->border_width * 2;
3171 requisition->height += widget->style->klass->ythickness * 2 +
3172 GTK_CONTAINER (widget)->border_width * 2;
3176 gtk_clist_size_allocate (GtkWidget * widget,
3177 GtkAllocation * allocation)
3180 GtkAllocation clist_allocation;
3181 GtkAllocation child_allocation;
3182 gint i, vscrollbar_vis, hscrollbar_vis;
3184 g_return_if_fail (widget != NULL);
3185 g_return_if_fail (GTK_IS_CLIST (widget));
3186 g_return_if_fail (allocation != NULL);
3188 clist = GTK_CLIST (widget);
3189 widget->allocation = *allocation;
3191 if (GTK_WIDGET_REALIZED (widget))
3193 gdk_window_move_resize (widget->window,
3194 allocation->x + GTK_CONTAINER (widget)->border_width,
3195 allocation->y + GTK_CONTAINER (widget)->border_width,
3196 allocation->width - GTK_CONTAINER (widget)->border_width * 2,
3197 allocation->height - GTK_CONTAINER (widget)->border_width * 2);
3200 /* use internal allocation structure for all the math
3201 * because it's easier than always subtracting the container
3203 clist->internal_allocation.x = 0;
3204 clist->internal_allocation.y = 0;
3205 clist->internal_allocation.width = MAX (1, allocation->width -
3206 GTK_CONTAINER (widget)->border_width * 2);
3207 clist->internal_allocation.height = MAX (1, allocation->height -
3208 GTK_CONTAINER (widget)->border_width * 2);
3210 /* allocate clist window assuming no scrollbars */
3211 clist_allocation.x = clist->internal_allocation.x + widget->style->klass->xthickness;
3212 clist_allocation.y = clist->internal_allocation.y + widget->style->klass->ythickness +
3213 clist->column_title_area.height;
3214 clist_allocation.width = MAX (1, clist->internal_allocation.width -
3215 (2 * widget->style->klass->xthickness));
3216 clist_allocation.height = MAX (1, clist->internal_allocation.height -
3217 (2 * widget->style->klass->ythickness) -
3218 clist->column_title_area.height);
3221 * here's where we decide to show/not show the scrollbars
3226 for (i = 0; i <= 1; i++)
3228 if (LIST_HEIGHT (clist) <= clist_allocation.height &&
3229 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
3235 if (!vscrollbar_vis)
3238 clist_allocation.width = MAX (1, clist_allocation.width -
3239 (clist->vscrollbar->requisition.width +
3240 SCROLLBAR_SPACING (clist)));
3244 if (LIST_WIDTH (clist) <= clist_allocation.width &&
3245 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
3251 if (!hscrollbar_vis)
3254 clist_allocation.height = MAX (1, clist_allocation.height -
3255 (clist->hscrollbar->requisition.height +
3256 SCROLLBAR_SPACING (clist)));
3261 clist->clist_window_width = clist_allocation.width;
3262 clist->clist_window_height = clist_allocation.height;
3264 if (GTK_WIDGET_REALIZED (widget))
3266 gdk_window_move_resize (clist->clist_window,
3269 clist_allocation.width,
3270 clist_allocation.height);
3273 /* position the window which holds the column title buttons */
3274 clist->column_title_area.x = widget->style->klass->xthickness;
3275 clist->column_title_area.y = widget->style->klass->ythickness;
3276 clist->column_title_area.width = clist_allocation.width;
3278 if (GTK_WIDGET_REALIZED (widget))
3280 gdk_window_move_resize (clist->title_window,
3281 clist->column_title_area.x,
3282 clist->column_title_area.y,
3283 clist->column_title_area.width,
3284 clist->column_title_area.height);
3287 /* column button allocation */
3288 size_allocate_columns (clist);
3289 size_allocate_title_buttons (clist);
3291 adjust_scrollbars (clist);
3293 /* allocate the vscrollbar */
3296 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
3297 gtk_widget_show (clist->vscrollbar);
3299 child_allocation.x = clist->internal_allocation.x +
3300 clist->internal_allocation.width -
3301 clist->vscrollbar->requisition.width;
3302 child_allocation.y = clist->internal_allocation.y;
3303 child_allocation.width = clist->vscrollbar->requisition.width;
3304 child_allocation.height = MAX (1, clist->internal_allocation.height -
3305 (hscrollbar_vis ? (clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist)) : 0));
3307 gtk_widget_size_allocate (clist->vscrollbar, &child_allocation);
3311 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
3312 gtk_widget_hide (clist->vscrollbar);
3317 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
3318 gtk_widget_show (clist->hscrollbar);
3320 child_allocation.x = clist->internal_allocation.x;
3321 child_allocation.y = clist->internal_allocation.y +
3322 clist->internal_allocation.height -
3323 clist->hscrollbar->requisition.height;
3324 child_allocation.width = MAX (1, clist->internal_allocation.width -
3325 (vscrollbar_vis ? (clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist)) : 0));
3326 child_allocation.height = clist->hscrollbar->requisition.height;
3328 gtk_widget_size_allocate (clist->hscrollbar, &child_allocation);
3332 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
3333 gtk_widget_hide (clist->hscrollbar);
3336 /* set the vscrollbar adjustments */
3337 adjust_scrollbars (clist);
3345 gtk_clist_foreach (GtkContainer * container,
3346 GtkCallback callback,
3347 gpointer callback_data)
3352 g_return_if_fail (container != NULL);
3353 g_return_if_fail (GTK_IS_CLIST (container));
3354 g_return_if_fail (callback != NULL);
3356 clist = GTK_CLIST (container);
3358 /* callback for the column buttons */
3359 for (i = 0; i < clist->columns; i++)
3360 if (clist->column[i].button)
3361 (*callback) (clist->column[i].button, callback_data);
3363 /* callbacks for the scrollbars */
3364 if (clist->vscrollbar)
3365 (*callback) (clist->vscrollbar, callback_data);
3366 if (clist->hscrollbar)
3367 (*callback) (clist->hscrollbar, callback_data);
3376 draw_row (GtkCList * clist,
3377 GdkRectangle * area,
3379 GtkCListRow * clist_row)
3382 GdkGC *fg_gc, *bg_gc;
3383 GdkRectangle row_rectangle, cell_rectangle, clip_rectangle, intersect_rectangle,
3385 gint i, offset = 0, width, height, pixmap_width = 0;
3386 gint xsrc, ysrc, xdest, ydest;
3388 g_return_if_fail (clist != NULL);
3390 /* bail now if we arn't drawable yet */
3391 if (!GTK_WIDGET_DRAWABLE (clist))
3394 if (row < 0 || row >= clist->rows)
3397 widget = GTK_WIDGET (clist);
3399 /* if the function is passed the pointer to the row instead of null,
3400 * it avoids this expensive lookup */
3402 clist_row = (g_list_nth (clist->row_list, row))->data;
3404 /* rectangle of the entire row */
3405 row_rectangle.x = 0;
3406 row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
3407 row_rectangle.width = clist->clist_window_width;
3408 row_rectangle.height = clist->row_height;
3410 /* rectangle of the cell spacing above the row */
3411 cell_rectangle.x = 0;
3412 cell_rectangle.y = row_rectangle.y - CELL_SPACING;
3413 cell_rectangle.width = row_rectangle.width;
3414 cell_rectangle.height = CELL_SPACING;
3416 /* rectangle used to clip drawing operations, it's y and height
3417 * positions only need to be set once, so we set them once here.
3418 * the x and width are set withing the drawing loop below once per
3420 clip_rectangle.y = row_rectangle.y;
3421 clip_rectangle.height = row_rectangle.height;
3423 /* select GC for background rectangle */
3424 if (clist_row->state == GTK_STATE_SELECTED)
3426 fg_gc = widget->style->fg_gc[GTK_STATE_SELECTED];
3427 bg_gc = widget->style->bg_gc[GTK_STATE_SELECTED];
3431 if (clist_row->fg_set)
3433 gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
3434 fg_gc = clist->fg_gc;
3437 fg_gc = widget->style->fg_gc[GTK_STATE_NORMAL];
3439 if (clist_row->bg_set)
3441 gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
3442 bg_gc = clist->bg_gc;
3445 bg_gc = widget->style->bg_gc[GTK_STATE_PRELIGHT];
3448 /* draw the cell borders and background */
3451 if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
3452 gdk_draw_rectangle (clist->clist_window,
3453 widget->style->base_gc[GTK_STATE_NORMAL],
3455 intersect_rectangle.x,
3456 intersect_rectangle.y,
3457 intersect_rectangle.width,
3458 intersect_rectangle.height);
3460 /* the last row has to clear it's bottom cell spacing too */
3461 if (clist_row == clist->row_list_end->data)
3463 cell_rectangle.y += clist->row_height + CELL_SPACING;
3465 if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
3466 gdk_draw_rectangle (clist->clist_window,
3467 widget->style->base_gc[GTK_STATE_NORMAL],
3469 intersect_rectangle.x,
3470 intersect_rectangle.y,
3471 intersect_rectangle.width,
3472 intersect_rectangle.height);
3475 if (!gdk_rectangle_intersect (area, &row_rectangle, &intersect_rectangle))
3478 if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
3479 gdk_draw_rectangle (clist->clist_window,
3482 intersect_rectangle.x,
3483 intersect_rectangle.y,
3484 intersect_rectangle.width,
3485 intersect_rectangle.height);
3487 gdk_window_clear_area (clist->clist_window,
3488 intersect_rectangle.x,
3489 intersect_rectangle.y,
3490 intersect_rectangle.width,
3491 intersect_rectangle.height);
3495 gdk_draw_rectangle (clist->clist_window,
3496 widget->style->base_gc[GTK_STATE_NORMAL],
3500 cell_rectangle.width,
3501 cell_rectangle.height);
3503 /* the last row has to clear it's bottom cell spacing too */
3504 if (clist_row == clist->row_list_end->data)
3506 cell_rectangle.y += clist->row_height + CELL_SPACING;
3508 gdk_draw_rectangle (clist->clist_window,
3509 widget->style->base_gc[GTK_STATE_NORMAL],
3513 cell_rectangle.width,
3514 cell_rectangle.height);
3517 if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
3518 gdk_draw_rectangle (clist->clist_window,
3523 row_rectangle.width,
3524 row_rectangle.height);
3526 gdk_window_clear_area (clist->clist_window,
3529 row_rectangle.width,
3530 row_rectangle.height);
3533 /* iterate and draw all the columns (row cells) and draw their contents */
3534 for (i = 0; i < clist->columns; i++)
3536 clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
3537 clip_rectangle.width = clist->column[i].area.width;
3539 /* calculate clipping region clipping region */
3542 rect = &clip_rectangle;
3546 if (!gdk_rectangle_intersect (area, &clip_rectangle,
3547 &intersect_rectangle))
3549 rect = &intersect_rectangle;
3552 /* calculate real width for column justification */
3553 switch (clist_row->cell[i].type)
3555 case GTK_CELL_EMPTY:
3560 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
3561 GTK_CELL_TEXT (clist_row->cell[i])->text);
3564 case GTK_CELL_PIXMAP:
3565 gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, &width, &height);
3566 pixmap_width = width;
3569 case GTK_CELL_PIXTEXT:
3570 gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, &width, &height);
3571 pixmap_width = width;
3572 width += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
3573 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
3574 GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
3577 case GTK_CELL_WIDGET:
3587 switch (clist->column[i].justification)
3589 case GTK_JUSTIFY_LEFT:
3590 offset = clip_rectangle.x;
3593 case GTK_JUSTIFY_RIGHT:
3594 offset = (clip_rectangle.x + clip_rectangle.width) - width;
3597 case GTK_JUSTIFY_CENTER:
3598 offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
3601 case GTK_JUSTIFY_FILL:
3602 offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
3610 /* Draw Text or Pixmap */
3611 switch (clist_row->cell[i].type)
3613 case GTK_CELL_EMPTY:
3618 gdk_gc_set_clip_rectangle (fg_gc, rect);
3620 gdk_draw_string (clist->clist_window,
3621 widget->style->font,
3623 offset + clist_row->cell[i].horizontal,
3624 row_rectangle.y + clist->row_center_offset +
3625 clist_row->cell[i].vertical,
3626 GTK_CELL_TEXT (clist_row->cell[i])->text);
3628 gdk_gc_set_clip_rectangle (fg_gc, NULL);
3631 case GTK_CELL_PIXMAP:
3634 xdest = offset + clist_row->cell[i].horizontal;
3635 ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
3636 clist_row->cell[i].vertical;
3638 if (xdest < clip_rectangle.x)
3640 xsrc = clip_rectangle.x - xdest;
3641 pixmap_width -= xsrc;
3642 xdest = clip_rectangle.x;
3645 if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width)
3646 pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest;
3648 if (ydest < clip_rectangle.y)
3650 ysrc = clip_rectangle.y - ydest;
3652 ydest = clip_rectangle.y;
3655 if (ydest + height > clip_rectangle.y + clip_rectangle.height)
3656 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
3658 if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
3660 gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXMAP (clist_row->cell[i])->mask);
3661 gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
3663 gdk_draw_pixmap (clist->clist_window,
3665 GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
3668 pixmap_width, height);
3670 if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
3672 gdk_gc_set_clip_origin (fg_gc, 0, 0);
3673 gdk_gc_set_clip_mask (fg_gc, NULL);
3677 case GTK_CELL_PIXTEXT:
3678 /* draw the pixmap */
3681 xdest = offset + clist_row->cell[i].horizontal;
3682 ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
3683 clist_row->cell[i].vertical;
3685 if (xdest < clip_rectangle.x)
3687 xsrc = clip_rectangle.x - xdest;
3688 pixmap_width -= xsrc;
3689 xdest = clip_rectangle.x;
3692 if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width)
3693 pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest;
3695 if (ydest < clip_rectangle.y)
3697 ysrc = clip_rectangle.y - ydest;
3699 ydest = clip_rectangle.y;
3702 if (ydest + height > clip_rectangle.y + clip_rectangle.height)
3703 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
3705 if (GTK_CELL_PIXTEXT (clist_row->cell[i])->mask)
3707 gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXTEXT (clist_row->cell[i])->mask);
3708 gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
3711 gdk_draw_pixmap (clist->clist_window,
3713 GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
3717 pixmap_width, height);
3719 gdk_gc_set_clip_origin (fg_gc, 0, 0);
3721 offset += pixmap_width + GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
3723 /* draw the string */
3724 gdk_gc_set_clip_rectangle (fg_gc, rect);
3726 gdk_draw_string (clist->clist_window,
3727 widget->style->font,
3729 offset + clist_row->cell[i].horizontal,
3730 row_rectangle.y + clist->row_center_offset +
3731 clist_row->cell[i].vertical,
3732 GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
3734 gdk_gc_set_clip_rectangle (fg_gc, NULL);
3737 case GTK_CELL_WIDGET:
3747 if (clist->focus_row == row && GTK_WIDGET_HAS_FOCUS (widget))
3751 if (gdk_rectangle_intersect (area, &row_rectangle,
3752 &intersect_rectangle))
3754 gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle);
3755 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
3756 row_rectangle.x, row_rectangle.y,
3757 row_rectangle.width - 1,
3758 row_rectangle.height - 1);
3759 gdk_gc_set_clip_rectangle (clist->xor_gc, NULL);
3763 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
3764 row_rectangle.x, row_rectangle.y,
3765 row_rectangle.width - 1, row_rectangle.height - 1);
3770 draw_rows (GtkCList * clist,
3771 GdkRectangle * area)
3774 GtkCListRow *clist_row;
3775 int i, first_row, last_row;
3777 g_return_if_fail (clist != NULL);
3778 g_return_if_fail (GTK_IS_CLIST (clist));
3780 if (clist->row_height == 0 ||
3781 !GTK_WIDGET_DRAWABLE (clist))
3786 first_row = ROW_FROM_YPIXEL (clist, area->y);
3787 last_row = ROW_FROM_YPIXEL (clist, area->y + area->height);
3791 first_row = ROW_FROM_YPIXEL (clist, 0);
3792 last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height);
3795 /* this is a small special case which exposes the bottom cell line
3796 * on the last row -- it might go away if I change the wall the cell spacings
3798 if (clist->rows == first_row)
3801 list = g_list_nth (clist->row_list, first_row);
3805 clist_row = list->data;
3811 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, area, i, clist_row);
3816 gdk_window_clear_area (clist->clist_window, 0, ROW_TOP_YPIXEL (clist, i), -1, -1);
3821 * size_allocate_title_buttons
3822 * size_allocate_columns
3825 size_allocate_title_buttons (GtkCList * clist)
3827 gint i, last_button = 0;
3828 GtkAllocation button_allocation;
3830 if (!GTK_WIDGET_REALIZED (clist))
3833 button_allocation.x = clist->hoffset;
3834 button_allocation.y = 0;
3835 button_allocation.width = 0;
3836 button_allocation.height = clist->column_title_area.height;
3838 for (i = 0; i < clist->columns; i++)
3840 button_allocation.width += clist->column[i].area.width;
3842 if (i == clist->columns - 1)
3843 button_allocation.width += 2 * (CELL_SPACING + COLUMN_INSET);
3845 button_allocation.width += CELL_SPACING + (2 * COLUMN_INSET);
3847 if (i == (clist->columns - 1) || clist->column[i + 1].button)
3849 gtk_widget_size_allocate (clist->column[last_button].button, &button_allocation);
3850 button_allocation.x += button_allocation.width;
3851 button_allocation.width = 0;
3853 gdk_window_show (clist->column[last_button].window);
3854 gdk_window_move_resize (clist->column[last_button].window,
3855 button_allocation.x - (DRAG_WIDTH / 2),
3856 0, DRAG_WIDTH, clist->column_title_area.height);
3858 last_button = i + 1;
3862 gdk_window_hide (clist->column[i].window);
3868 size_allocate_columns (GtkCList * clist)
3870 gint i, xoffset = 0;
3872 for (i = 0; i < clist->columns; i++)
3874 clist->column[i].area.x = xoffset + CELL_SPACING + COLUMN_INSET;
3876 if (i == clist->columns - 1)
3880 if (clist->column[i].width_set)
3882 width = clist->column[i].width;
3886 if (clist->column[i].title)
3887 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
3888 clist->column[i].title);
3893 clist->column[i].area.width = MAX (width,
3894 clist->clist_window_width -
3895 xoffset - (2 * (CELL_SPACING + COLUMN_INSET)));
3900 clist->column[i].area.width = clist->column[i].width;
3903 xoffset += clist->column[i].area.width + CELL_SPACING + (2 * COLUMN_INSET);
3912 * get_selection_info
3915 toggle_row (GtkCList * clist,
3920 GtkCListRow *clist_row;
3922 switch (clist->selection_mode)
3924 case GTK_SELECTION_EXTENDED:
3925 case GTK_SELECTION_MULTIPLE:
3926 case GTK_SELECTION_SINGLE:
3928 clist_row = g_list_nth (clist->row_list, row)->data;
3929 if (clist_row->state == GTK_STATE_SELECTED)
3931 unselect_row (clist, row, column, event);
3935 case GTK_SELECTION_BROWSE:
3936 select_row (clist, row, column, event);
3942 select_row (GtkCList * clist,
3947 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
3948 row, column, event);
3952 unselect_row (GtkCList * clist,
3957 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3958 row, column, event);
3962 real_select_row (GtkCList * clist,
3967 GtkCListRow *clist_row;
3970 gboolean row_selected;
3972 g_return_if_fail (clist != NULL);
3973 g_return_if_fail (GTK_IS_CLIST (clist));
3975 if (row < 0 || row > (clist->rows - 1))
3978 switch (clist->selection_mode)
3980 case GTK_SELECTION_SINGLE:
3981 case GTK_SELECTION_BROWSE:
3983 row_selected = FALSE;
3984 list = clist->selection;
3988 sel_row = GPOINTER_TO_INT (list->data);
3992 row_selected = TRUE;
3994 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3995 sel_row, column, event);
4005 clist_row = (g_list_nth (clist->row_list, row))->data;
4007 if (clist_row->state != GTK_STATE_NORMAL)
4010 clist_row->state = GTK_STATE_SELECTED;
4011 if (!clist->selection)
4013 clist->selection = g_list_append (clist->selection,
4014 GINT_TO_POINTER (row));
4015 clist->selection_end = clist->selection;
4018 clist->selection_end =
4019 g_list_append (clist->selection_end, GINT_TO_POINTER (row))->next;
4021 if (!GTK_CLIST_FROZEN (clist)
4022 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
4023 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
4027 real_unselect_row (GtkCList * clist,
4032 GtkCListRow *clist_row;
4034 g_return_if_fail (clist != NULL);
4035 g_return_if_fail (GTK_IS_CLIST (clist));
4037 if (row < 0 || row > (clist->rows - 1))
4040 clist_row = (g_list_nth (clist->row_list, row))->data;
4042 if (clist_row->state == GTK_STATE_SELECTED)
4044 clist_row->state = GTK_STATE_NORMAL;
4046 if (clist->selection_end &&
4047 clist->selection_end->data == GINT_TO_POINTER (row))
4048 clist->selection_end = clist->selection_end->prev;
4050 clist->selection = g_list_remove (clist->selection,
4051 GINT_TO_POINTER (row));
4053 if (!GTK_CLIST_FROZEN (clist)
4054 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
4055 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
4060 get_selection_info (GtkCList * clist,
4068 g_return_val_if_fail (clist != NULL, 0);
4069 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
4071 /* bounds checking, return false if the user clicked
4072 * on a blank area */
4073 trow = ROW_FROM_YPIXEL (clist, y);
4074 if (trow >= clist->rows)
4080 tcol = COLUMN_FROM_XPIXEL (clist, x);
4081 if (tcol >= clist->columns)
4091 gtk_clist_get_selection_info (GtkCList *clist,
4097 g_return_val_if_fail (clist != NULL, 0);
4098 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
4099 return get_selection_info (clist, x, y, row, column);
4109 draw_xor_line (GtkCList * clist)
4113 g_return_if_fail (clist != NULL);
4115 widget = GTK_WIDGET (clist);
4117 gdk_draw_line (widget->window, clist->xor_gc,
4119 widget->style->klass->ythickness,
4121 clist->column_title_area.height + clist->clist_window_height + 1);
4124 /* this function returns the new width of the column being resized given
4125 * the column and x position of the cursor; the x cursor position is passed
4126 * in as a pointer and automagicly corrected if it's beyond min/max limits */
4128 new_column_width (GtkCList * clist,
4137 /* first translate the x position from widget->window
4138 * to clist->clist_window */
4139 cx -= GTK_WIDGET (clist)->style->klass->xthickness;
4141 /* rx is x from the list beginning */
4142 rx = cx - clist->hoffset;
4144 /* you can't shrink a column to less than its minimum width */
4145 if (cx < (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH))
4147 *x = cx = COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH +
4148 GTK_WIDGET (clist)->style->klass->xthickness;
4149 cx -= GTK_WIDGET (clist)->style->klass->xthickness;
4150 rx = cx - clist->hoffset;
4153 if (cx < 0 || cx > clist->clist_window_width)
4158 /* calculate new column width making sure it doesn't end up
4159 * less than the minimum width */
4160 width = (rx - COLUMN_LEFT (clist, column)) - COLUMN_INSET -
4161 ((clist->columns == (column - 1)) ? CELL_SPACING : 0);
4162 if (width < COLUMN_MIN_WIDTH)
4163 width = COLUMN_MIN_WIDTH;
4168 /* this will do more later */
4170 resize_column (GtkCList * clist,
4174 gtk_clist_set_column_width (clist, column, width);
4179 column_button_create (GtkCList * clist,
4184 button = clist->column[column].button = gtk_button_new ();
4185 gtk_widget_set_parent (button, GTK_WIDGET (clist));
4186 if (GTK_WIDGET_REALIZED (clist) && clist->title_window)
4187 gtk_widget_set_parent_window (clist->column[column].button, clist->title_window);
4189 gtk_signal_connect (GTK_OBJECT (button), "clicked",
4190 (GtkSignalFunc) column_button_clicked,
4193 gtk_widget_show (button);
4197 column_button_clicked (GtkWidget * widget,
4203 g_return_if_fail (widget != NULL);
4204 g_return_if_fail (GTK_IS_CLIST (data));
4206 clist = GTK_CLIST (data);
4208 /* find the column who's button was pressed */
4209 for (i = 0; i < clist->columns; i++)
4210 if (clist->column[i].button == widget)
4213 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i);
4222 * vadjustment_changed
4223 * hadjustment_changed
4224 * vadjustment_value_changed
4225 * hadjustment_value_changed
4228 create_scrollbars (GtkCList * clist)
4230 GtkAdjustment *adjustment;
4232 clist->vscrollbar = gtk_vscrollbar_new (NULL);
4234 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
4236 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
4237 (GtkSignalFunc) vadjustment_changed,
4240 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
4241 (GtkSignalFunc) vadjustment_value_changed,
4244 gtk_widget_set_parent (clist->vscrollbar, GTK_WIDGET (clist));
4245 gtk_widget_show (clist->vscrollbar);
4247 clist->hscrollbar = gtk_hscrollbar_new (NULL);
4249 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
4251 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
4252 (GtkSignalFunc) hadjustment_changed,
4255 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
4256 (GtkSignalFunc) hadjustment_value_changed,
4259 gtk_widget_set_parent (clist->hscrollbar, GTK_WIDGET (clist));
4260 gtk_widget_show (clist->hscrollbar);
4264 adjust_scrollbars (GtkCList * clist)
4266 GTK_RANGE (clist->vscrollbar)->adjustment->page_size = clist->clist_window_height;
4267 GTK_RANGE (clist->vscrollbar)->adjustment->page_increment = clist->clist_window_height / 2;
4268 GTK_RANGE (clist->vscrollbar)->adjustment->step_increment = 10;
4269 GTK_RANGE (clist->vscrollbar)->adjustment->lower = 0;
4270 GTK_RANGE (clist->vscrollbar)->adjustment->upper = LIST_HEIGHT (clist);
4272 if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist))
4274 GTK_RANGE (clist->vscrollbar)->adjustment->value = MAX (0, LIST_HEIGHT (clist) -
4275 clist->clist_window_height);
4276 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment),
4280 GTK_RANGE (clist->hscrollbar)->adjustment->page_size = clist->clist_window_width;
4281 GTK_RANGE (clist->hscrollbar)->adjustment->page_increment = clist->clist_window_width / 2;
4282 GTK_RANGE (clist->hscrollbar)->adjustment->step_increment = 10;
4283 GTK_RANGE (clist->hscrollbar)->adjustment->lower = 0;
4284 GTK_RANGE (clist->hscrollbar)->adjustment->upper = LIST_WIDTH (clist);
4286 if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist))
4288 GTK_RANGE (clist->hscrollbar)->adjustment->value = MAX (0, LIST_WIDTH (clist) -
4289 clist->clist_window_width);
4290 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment),
4294 if (LIST_HEIGHT (clist) <= clist->clist_window_height &&
4295 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
4297 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
4299 gtk_widget_hide (clist->vscrollbar);
4300 gtk_widget_size_allocate (GTK_WIDGET (clist),
4301 >K_WIDGET (clist)->allocation);
4306 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
4308 gtk_widget_show (clist->vscrollbar);
4309 gtk_widget_size_allocate (GTK_WIDGET (clist),
4310 >K_WIDGET (clist)->allocation);
4314 if (LIST_WIDTH (clist) <= clist->clist_window_width &&
4315 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
4317 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
4319 gtk_widget_hide (clist->hscrollbar);
4320 gtk_widget_size_allocate (GTK_WIDGET (clist),
4321 >K_WIDGET (clist)->allocation);
4326 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
4328 gtk_widget_show (clist->hscrollbar);
4329 gtk_widget_size_allocate (GTK_WIDGET (clist),
4330 >K_WIDGET (clist)->allocation);
4334 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
4335 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), "changed");
4339 vadjustment_changed (GtkAdjustment * adjustment,
4344 g_return_if_fail (adjustment != NULL);
4345 g_return_if_fail (data != NULL);
4347 clist = GTK_CLIST (data);
4351 hadjustment_changed (GtkAdjustment * adjustment,
4356 g_return_if_fail (adjustment != NULL);
4357 g_return_if_fail (data != NULL);
4359 clist = GTK_CLIST (data);
4363 check_exposures (GtkCList *clist)
4367 if (!GTK_WIDGET_REALIZED (clist))
4370 /* Make sure graphics expose events are processed before scrolling
4372 while ((event = gdk_event_get_graphics_expose (clist->clist_window)) != NULL)
4374 gtk_widget_event (GTK_WIDGET (clist), event);
4375 if (event->expose.count == 0)
4377 gdk_event_free (event);
4380 gdk_event_free (event);
4385 vadjustment_value_changed (GtkAdjustment * adjustment,
4392 g_return_if_fail (adjustment != NULL);
4393 g_return_if_fail (data != NULL);
4394 g_return_if_fail (GTK_IS_CLIST (data));
4396 clist = GTK_CLIST (data);
4398 if (!GTK_WIDGET_DRAWABLE (clist))
4401 value = adjustment->value;
4403 if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)))
4405 if (value > -clist->voffset)
4408 diff = value + clist->voffset;
4410 /* we have to re-draw the whole screen here... */
4411 if (diff >= clist->clist_window_height)
4413 clist->voffset = -value;
4414 draw_rows (clist, NULL);
4418 if ((diff != 0) && (diff != clist->clist_window_height))
4419 gdk_window_copy_area (clist->clist_window,
4422 clist->clist_window,
4425 clist->clist_window_width,
4426 clist->clist_window_height - diff);
4429 area.y = clist->clist_window_height - diff;
4430 area.width = clist->clist_window_width;
4436 diff = -clist->voffset - value;
4438 /* we have to re-draw the whole screen here... */
4439 if (diff >= clist->clist_window_height)
4441 clist->voffset = -value;
4442 draw_rows (clist, NULL);
4446 if ((diff != 0) && (diff != clist->clist_window_height))
4447 gdk_window_copy_area (clist->clist_window,
4450 clist->clist_window,
4453 clist->clist_window_width,
4454 clist->clist_window_height - diff);
4458 area.width = clist->clist_window_width;
4463 clist->voffset = -value;
4464 if ((diff != 0) && (diff != clist->clist_window_height))
4465 check_exposures (clist);
4468 draw_rows (clist, &area);
4472 hadjustment_value_changed (GtkAdjustment * adjustment,
4482 g_return_if_fail (adjustment != NULL);
4483 g_return_if_fail (data != NULL);
4484 g_return_if_fail (GTK_IS_CLIST (data));
4486 clist = GTK_CLIST (data);
4488 if (!GTK_WIDGET_DRAWABLE (clist) ||
4489 adjustment != gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)))
4492 value = adjustment->value;
4494 /* move the column buttons and resize windows */
4495 for (i = 0; i < clist->columns; i++)
4497 if (clist->column[i].button)
4499 clist->column[i].button->allocation.x -= value + clist->hoffset;
4501 if (clist->column[i].button->window)
4503 gdk_window_move (clist->column[i].button->window,
4504 clist->column[i].button->allocation.x,
4505 clist->column[i].button->allocation.y);
4507 if (clist->column[i].window)
4508 gdk_window_move (clist->column[i].window,
4509 clist->column[i].button->allocation.x +
4510 clist->column[i].button->allocation.width -
4511 (DRAG_WIDTH / 2), 0);
4516 if (value > -clist->hoffset)
4519 diff = value + clist->hoffset;
4521 clist->hoffset = -value;
4523 /* we have to re-draw the whole screen here... */
4524 if (diff >= clist->clist_window_width)
4526 draw_rows (clist, NULL);
4530 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
4531 GTK_CLIST_ADD_MODE (clist))
4533 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4535 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
4536 clist->clist_window_width - 1,
4537 clist->row_height - 1);
4539 gdk_window_copy_area (clist->clist_window,
4542 clist->clist_window,
4545 clist->clist_window_width - diff,
4546 clist->clist_window_height);
4548 area.x = clist->clist_window_width - diff;
4553 if (!(diff = -clist->hoffset - value))
4556 clist->hoffset = -value;
4558 /* we have to re-draw the whole screen here... */
4559 if (diff >= clist->clist_window_width)
4561 draw_rows (clist, NULL);
4565 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
4566 GTK_CLIST_ADD_MODE (clist))
4568 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4570 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
4571 clist->clist_window_width - 1,
4572 clist->row_height - 1);
4575 gdk_window_copy_area (clist->clist_window,
4578 clist->clist_window,
4581 clist->clist_window_width - diff,
4582 clist->clist_window_height);
4589 area.height = clist->clist_window_height;
4591 check_exposures (clist);
4593 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist))
4595 if (GTK_CLIST_ADD_MODE (clist))
4599 focus_row = clist->focus_row;
4600 clist->focus_row = -1;
4601 draw_rows (clist, &area);
4602 clist->focus_row = focus_row;
4604 gdk_draw_rectangle (clist->clist_window, clist->xor_gc,
4605 FALSE, 0, y, clist->clist_window_width - 1,
4606 clist->row_height - 1);
4616 x0 = clist->clist_window_width - 1;
4625 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4626 gdk_draw_line (clist->clist_window, clist->xor_gc,
4627 x0, y + 1, x0, y + clist->row_height - 2);
4628 gdk_draw_line (clist->clist_window, clist->xor_gc,
4629 x1, y + 1, x1, y + clist->row_height - 2);
4633 draw_rows (clist, &area);
4637 * Memory Allocation/Distruction Routines for GtkCList stuctures
4647 static GtkCListColumn *
4648 columns_new (GtkCList * clist)
4651 GtkCListColumn *column;
4653 column = g_new (GtkCListColumn, clist->columns);
4655 for (i = 0; i < clist->columns; i++)
4657 column[i].area.x = 0;
4658 column[i].area.y = 0;
4659 column[i].area.width = 0;
4660 column[i].area.height = 0;
4661 column[i].title = NULL;
4662 column[i].button = NULL;
4663 column[i].window = NULL;
4664 column[i].width = 0;
4665 column[i].width_set = FALSE;
4666 column[i].justification = GTK_JUSTIFY_LEFT;
4673 column_title_new (GtkCList * clist,
4677 if (clist->column[column].title)
4678 g_free (clist->column[column].title);
4680 clist->column[column].title = g_strdup (title);
4684 columns_delete (GtkCList * clist)
4688 for (i = 0; i < clist->columns; i++)
4689 if (clist->column[i].title)
4690 g_free (clist->column[i].title);
4692 g_free (clist->column);
4695 static GtkCListRow *
4696 row_new (GtkCList * clist)
4699 GtkCListRow *clist_row;
4701 clist_row = g_chunk_new (GtkCListRow, clist->row_mem_chunk);
4702 clist_row->cell = g_chunk_new (GtkCell, clist->cell_mem_chunk);
4704 for (i = 0; i < clist->columns; i++)
4706 clist_row->cell[i].type = GTK_CELL_EMPTY;
4707 clist_row->cell[i].vertical = 0;
4708 clist_row->cell[i].horizontal = 0;
4711 clist_row->fg_set = FALSE;
4712 clist_row->bg_set = FALSE;
4713 clist_row->state = GTK_STATE_NORMAL;
4714 clist_row->data = NULL;
4715 clist_row->destroy = NULL;
4721 row_delete (GtkCList * clist,
4722 GtkCListRow * clist_row)
4726 for (i = 0; i < clist->columns; i++)
4727 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
4728 (clist, clist_row, i, GTK_CELL_EMPTY, NULL, 0, NULL, NULL);
4730 if (clist_row->destroy)
4731 clist_row->destroy (clist_row->data);
4733 g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell);
4734 g_mem_chunk_free (clist->row_mem_chunk, clist_row);
4738 set_cell_contents (GtkCList * clist,
4739 GtkCListRow * clist_row,
4747 g_return_if_fail (clist_row != NULL);
4749 switch (clist_row->cell[column].type)
4751 case GTK_CELL_EMPTY:
4755 g_free (GTK_CELL_TEXT (clist_row->cell[column])->text);
4758 case GTK_CELL_PIXMAP:
4759 gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap);
4760 if (GTK_CELL_PIXMAP (clist_row->cell[column])->mask)
4761 gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask);
4764 case GTK_CELL_PIXTEXT:
4765 g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text);
4766 gdk_pixmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap);
4767 if (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask)
4768 gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask);
4771 case GTK_CELL_WIDGET:
4779 clist_row->cell[column].type = GTK_CELL_EMPTY;
4786 clist_row->cell[column].type = GTK_CELL_TEXT;
4787 GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
4791 case GTK_CELL_PIXMAP:
4794 clist_row->cell[column].type = GTK_CELL_PIXMAP;
4795 GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
4796 /* We set the mask even if it is NULL */
4797 GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask;
4801 case GTK_CELL_PIXTEXT:
4804 clist_row->cell[column].type = GTK_CELL_PIXTEXT;
4805 GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
4806 GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
4807 GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
4808 GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask;
4817 /* Fill in data after widget has correct style */
4820 add_style_data (GtkCList * clist)
4824 widget = GTK_WIDGET(clist);
4826 /* text properties */
4827 if (!GTK_CLIST_ROW_HEIGHT_SET (clist))
4829 clist->row_height = widget->style->font->ascent + widget->style->font->descent + 1;
4830 clist->row_center_offset = widget->style->font->ascent + 1.5;
4835 text_height = clist->row_height - (GTK_WIDGET (clist)->style->font->ascent +
4836 GTK_WIDGET (clist) ->style->font->descent + 1);
4837 clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
4844 /* focus functions */
4847 gtk_clist_draw_focus (GtkWidget *widget)
4851 g_return_if_fail (widget != NULL);
4852 g_return_if_fail (GTK_IS_CLIST (widget));
4854 if (!GTK_WIDGET_DRAWABLE (widget))
4857 clist = GTK_CLIST (widget);
4858 if (clist->focus_row >= 0)
4859 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
4860 0, ROW_TOP_YPIXEL(clist, clist->focus_row),
4861 clist->clist_window_width - 1,
4862 clist->row_height - 1);
4866 gtk_clist_set_focus_child (GtkContainer *container,
4869 g_return_if_fail (container != NULL);
4870 g_return_if_fail (GTK_IS_CLIST (container));
4874 g_return_if_fail (GTK_IS_WIDGET (child));
4875 GTK_CLIST_SET_FLAG (GTK_CLIST (container), CLIST_CHILD_HAS_FOCUS);
4878 parent_class->set_focus_child (container, child);
4882 gtk_clist_focus_in (GtkWidget *widget,
4883 GdkEventFocus *event)
4887 g_return_val_if_fail (widget != NULL, FALSE);
4888 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4889 g_return_val_if_fail (event != NULL, FALSE);
4891 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
4892 GTK_CLIST_UNSET_FLAG (widget, CLIST_CHILD_HAS_FOCUS);
4894 clist = GTK_CLIST (widget);
4896 if (clist->selection_mode == GTK_SELECTION_BROWSE &&
4897 clist->selection == NULL && clist->focus_row > -1)
4898 select_row (clist, clist->focus_row, -1, (GdkEvent *) event);
4900 gtk_widget_draw_focus (widget);
4906 gtk_clist_focus_out (GtkWidget *widget,
4907 GdkEventFocus *event)
4911 g_return_val_if_fail (widget != NULL, FALSE);
4912 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4913 g_return_val_if_fail (event != NULL, FALSE);
4915 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
4916 gtk_widget_draw_focus (widget);
4918 clist = GTK_CLIST (widget);
4920 if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
4921 GTK_CLIST_CLASS_FW (widget)->resync_selection (clist, (GdkEvent *) event);
4927 toggle_add_mode (GtkCList *clist)
4929 g_return_if_fail (clist != 0);
4930 g_return_if_fail (GTK_IS_CLIST (clist));
4932 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
4933 clist->selection_mode != GTK_SELECTION_EXTENDED)
4936 gtk_clist_draw_focus (GTK_WIDGET (clist));
4937 if (!GTK_CLIST_ADD_MODE (clist))
4939 GTK_CLIST_SET_FLAG (clist, CLIST_ADD_MODE);
4940 gdk_gc_set_line_attributes (clist->xor_gc, 1,
4941 GDK_LINE_ON_OFF_DASH, 0, 0);
4942 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
4946 GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
4947 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
4948 clist->anchor_state = GTK_STATE_SELECTED;
4950 gtk_clist_draw_focus (GTK_WIDGET (clist));
4954 toggle_focus_row (GtkCList *clist)
4956 g_return_if_fail (clist != 0);
4957 g_return_if_fail (GTK_IS_CLIST (clist));
4959 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
4960 clist->focus_row < 0 || clist->focus_row >= clist->rows)
4963 switch (clist->selection_mode)
4965 case GTK_SELECTION_SINGLE:
4966 case GTK_SELECTION_MULTIPLE:
4968 toggle_row (clist, clist->focus_row, 0, NULL);
4971 case GTK_SELECTION_EXTENDED:
4972 g_list_free (clist->undo_selection);
4973 g_list_free (clist->undo_unselection);
4974 clist->undo_selection = NULL;
4975 clist->undo_unselection = NULL;
4977 clist->anchor = clist->focus_row;
4978 clist->drag_pos = clist->focus_row;
4979 clist->undo_anchor = clist->focus_row;
4981 if (GTK_CLIST_ADD_MODE (clist))
4982 fake_toggle_row (clist, clist->focus_row);
4984 GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist,clist->focus_row);
4986 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
4995 move_focus_row (GtkCList *clist,
4996 GtkScrollType scroll_type,
5001 g_return_if_fail (clist != 0);
5002 g_return_if_fail (GTK_IS_CLIST (clist));
5004 widget = GTK_WIDGET (clist);
5006 switch (scroll_type)
5008 case GTK_SCROLL_STEP_BACKWARD:
5009 if (clist->focus_row <= 0)
5011 gtk_clist_draw_focus (widget);
5013 gtk_clist_draw_focus (widget);
5015 case GTK_SCROLL_STEP_FORWARD:
5016 if (clist->focus_row >= clist->rows - 1)
5018 gtk_clist_draw_focus (widget);
5020 gtk_clist_draw_focus (widget);
5022 case GTK_SCROLL_PAGE_BACKWARD:
5023 if (clist->focus_row <= 0)
5025 gtk_clist_draw_focus (widget);
5026 clist->focus_row = MAX (0, clist->focus_row -
5027 (2 * clist->clist_window_height -
5028 clist->row_height - CELL_SPACING) /
5029 (2 * (clist->row_height + CELL_SPACING)));
5030 gtk_clist_draw_focus (widget);
5032 case GTK_SCROLL_PAGE_FORWARD:
5033 if (clist->focus_row >= clist->rows - 1)
5035 gtk_clist_draw_focus (widget);
5036 clist->focus_row = MIN (clist->rows - 1, clist->focus_row +
5037 (2 * clist->clist_window_height -
5038 clist->row_height - CELL_SPACING) /
5039 (2 * (clist->row_height + CELL_SPACING)));
5040 gtk_clist_draw_focus (widget);
5042 case GTK_SCROLL_JUMP:
5043 if (position >= 0 && position <= 1)
5045 gtk_clist_draw_focus (widget);
5046 clist->focus_row = position * (clist->rows - 1);
5047 gtk_clist_draw_focus (widget);
5056 scroll_horizontal (GtkCList *clist,
5057 GtkScrollType scroll_type,
5062 g_return_if_fail (clist != 0);
5063 g_return_if_fail (GTK_IS_CLIST (clist));
5065 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5068 switch (scroll_type)
5070 case GTK_SCROLL_STEP_BACKWARD:
5071 column = COLUMN_FROM_XPIXEL (clist, 0);
5072 if (COLUMN_LEFT_XPIXEL (clist, column) - CELL_SPACING - COLUMN_INSET >= 0
5076 case GTK_SCROLL_STEP_FORWARD:
5077 column = COLUMN_FROM_XPIXEL (clist, clist->clist_window_width);
5080 if (COLUMN_LEFT_XPIXEL (clist, column) + clist->column[column].area.width
5081 + CELL_SPACING + COLUMN_INSET - 1 <= clist->clist_window_width &&
5082 column < clist->columns - 1)
5085 case GTK_SCROLL_PAGE_BACKWARD:
5086 case GTK_SCROLL_PAGE_FORWARD:
5088 case GTK_SCROLL_JUMP:
5089 if (position >= 0 && position <= 1)
5090 column = position * (clist->columns - 1);
5098 if (COLUMN_LEFT_XPIXEL (clist, column) < CELL_SPACING + COLUMN_INSET)
5099 gtk_clist_moveto (clist, -1, column, 0, 0);
5100 else if (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET - 1
5101 + clist->column[column].area.width > clist->clist_window_width)
5103 if (column == clist->columns - 1)
5104 gtk_clist_moveto (clist, -1, column, 0, 0);
5106 gtk_clist_moveto (clist, -1, column, 0, 1);
5111 scroll_vertical (GtkCList *clist,
5112 GtkScrollType scroll_type,
5117 g_return_if_fail (clist != NULL);
5118 g_return_if_fail (GTK_IS_CLIST (clist));
5120 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5123 switch (clist->selection_mode)
5125 case GTK_SELECTION_EXTENDED:
5126 if (clist->anchor >= 0)
5129 case GTK_SELECTION_BROWSE:
5131 old_focus_row = clist->focus_row;
5132 move_focus_row (clist, scroll_type, position);
5134 if (old_focus_row != clist->focus_row)
5136 if (clist->selection_mode == GTK_SELECTION_BROWSE)
5137 unselect_row (clist,old_focus_row, -1, NULL);
5138 else if (!GTK_CLIST_ADD_MODE (clist))
5140 gtk_clist_unselect_all (clist);
5141 clist->undo_anchor = old_focus_row;
5145 switch (gtk_clist_row_is_visible (clist, clist->focus_row))
5147 case GTK_VISIBILITY_NONE:
5148 if (old_focus_row != clist->focus_row &&
5149 !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
5150 GTK_CLIST_ADD_MODE (clist)))
5151 select_row (clist, clist->focus_row, -1, NULL);
5152 switch (scroll_type)
5154 case GTK_SCROLL_STEP_BACKWARD:
5155 case GTK_SCROLL_PAGE_BACKWARD:
5156 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5158 case GTK_SCROLL_STEP_FORWARD:
5159 case GTK_SCROLL_PAGE_FORWARD:
5160 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5162 case GTK_SCROLL_JUMP:
5163 gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
5170 case GTK_VISIBILITY_PARTIAL:
5171 switch (scroll_type)
5173 case GTK_SCROLL_STEP_BACKWARD:
5174 case GTK_SCROLL_PAGE_BACKWARD:
5175 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5177 case GTK_SCROLL_STEP_FORWARD:
5178 case GTK_SCROLL_PAGE_FORWARD:
5179 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5181 case GTK_SCROLL_JUMP:
5182 gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
5189 if (old_focus_row != clist->focus_row &&
5190 !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
5191 GTK_CLIST_ADD_MODE (clist)))
5192 select_row (clist, clist->focus_row, -1, NULL);
5198 move_focus_row (clist, scroll_type, position);
5200 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5201 clist->clist_window_height)
5202 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5203 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5204 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5210 set_anchor (GtkCList *clist,
5215 g_return_if_fail (clist != NULL);
5216 g_return_if_fail (GTK_IS_CLIST (clist));
5218 if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor >= 0)
5221 g_list_free (clist->undo_selection);
5222 g_list_free (clist->undo_unselection);
5223 clist->undo_selection = NULL;
5224 clist->undo_unselection = NULL;
5227 fake_toggle_row (clist, anchor);
5230 GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist, anchor);
5231 clist->anchor_state = GTK_STATE_SELECTED;
5234 clist->anchor = anchor;
5235 clist->drag_pos = anchor;
5236 clist->undo_anchor = undo_anchor;
5240 resync_selection (GtkCList *clist,
5246 gboolean thaw = FALSE;
5248 GtkCListRow *clist_row;
5250 if (clist->anchor < 0)
5253 if (!GTK_CLIST_FROZEN (clist))
5255 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
5259 i = MIN (clist->anchor, clist->drag_pos);
5260 e = MAX (clist->anchor, clist->drag_pos);
5262 if (clist->undo_selection)
5265 list = clist->selection;
5266 clist->selection = clist->undo_selection;
5267 clist->selection_end = g_list_last (clist->selection);
5268 clist->undo_selection = list;
5269 list = clist->selection;
5272 row = GPOINTER_TO_INT (list->data);
5274 if (row < i || row > e)
5276 clist_row = g_list_nth (clist->row_list, row)->data;
5277 clist_row->state = GTK_STATE_SELECTED;
5278 unselect_row (clist, row, -1, event);
5279 clist->undo_selection = g_list_prepend
5280 (clist->undo_selection, GINT_TO_POINTER (row));
5285 for (list = g_list_nth (clist->row_list, i); i <= e; i++, list = list->next)
5286 if (g_list_find (clist->selection, GINT_TO_POINTER(i)))
5288 if (GTK_CLIST_ROW (list)->state == GTK_STATE_NORMAL)
5290 GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
5291 unselect_row (clist, i, -1, event);
5292 clist->undo_selection = g_list_prepend (clist->undo_selection,
5293 GINT_TO_POINTER (i));
5296 else if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
5298 GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
5299 clist->undo_unselection = g_list_prepend (clist->undo_unselection,
5300 GINT_TO_POINTER (i));
5303 for (list = clist->undo_unselection; list; list = list->next)
5304 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
5305 GPOINTER_TO_INT (list->data), -1, event);
5308 clist->drag_pos = -1;
5311 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
5315 update_extended_selection (GtkCList *clist,
5325 gint y1 = clist->clist_window_height;
5326 gint y2 = clist->clist_window_height;
5331 if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor == -1)
5336 if (row >= clist->rows)
5337 row = clist->rows - 1;
5339 /* extending downwards */
5340 if (row > clist->drag_pos && clist->anchor <= clist->drag_pos)
5342 s2 = clist->drag_pos + 1;
5345 /* extending upwards */
5346 else if (row < clist->drag_pos && clist->anchor >= clist->drag_pos)
5349 e2 = clist->drag_pos - 1;
5351 else if (row < clist->drag_pos && clist->anchor < clist->drag_pos)
5353 e1 = clist->drag_pos;
5354 /* row and drag_pos on different sides of anchor :
5355 take back the selection between anchor and drag_pos,
5356 select between anchor and row */
5357 if (row < clist->anchor)
5359 s1 = clist->anchor + 1;
5361 e2 = clist->anchor - 1;
5363 /* take back the selection between anchor and drag_pos */
5367 else if (row > clist->drag_pos && clist->anchor > clist->drag_pos)
5369 s1 = clist->drag_pos;
5370 /* row and drag_pos on different sides of anchor :
5371 take back the selection between anchor and drag_pos,
5372 select between anchor and row */
5373 if (row > clist->anchor)
5375 e1 = clist->anchor - 1;
5376 s2 = clist->anchor + 1;
5379 /* take back the selection between anchor and drag_pos */
5384 clist->drag_pos = row;
5387 area.width = clist->clist_window_width;
5389 /* restore the elements between s1 and e1 */
5392 for (i = s1, list = g_list_nth (clist->row_list, i); i <= e1;
5393 i++, list = list->next)
5395 if (GTK_CLIST_CLASS_FW (clist)->selection_find (clist, i, list))
5396 GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
5398 GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
5401 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
5403 if (top + clist->row_height <= 0)
5406 area.height = ROW_TOP_YPIXEL (clist, e1) + clist->row_height;
5407 draw_rows (clist, &area);
5408 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5410 else if (top >= clist->clist_window_height)
5412 area.y = ROW_TOP_YPIXEL (clist, s1);
5413 area.height = clist->clist_window_height - area.y;
5414 draw_rows (clist, &area);
5415 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5418 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5419 else if (top + clist->row_height > clist->clist_window_height)
5420 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5422 y1 = ROW_TOP_YPIXEL (clist, s1);
5423 h1 = (e1 - s1 + 1) * (clist->row_height + CELL_SPACING);
5426 /* extend the selection between s2 and e2 */
5429 for (i = s2, list = g_list_nth (clist->row_list, i); i <= e2;
5430 i++, list = list->next)
5431 if (GTK_CLIST_ROW (list)->state != clist->anchor_state)
5432 GTK_CLIST_ROW (list)->state = clist->anchor_state;
5434 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
5436 if (top + clist->row_height <= 0)
5439 area.height = ROW_TOP_YPIXEL (clist, e2) + clist->row_height;
5440 draw_rows (clist, &area);
5441 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5443 else if (top >= clist->clist_window_height)
5445 area.y = ROW_TOP_YPIXEL (clist, s2);
5446 area.height = clist->clist_window_height - area.y;
5447 draw_rows (clist, &area);
5448 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5451 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5452 else if (top + clist->row_height > clist->clist_window_height)
5453 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5455 y2 = ROW_TOP_YPIXEL (clist, s2);
5456 h2 = (e2-s2+1) * (clist->row_height + CELL_SPACING);
5459 area.y = MAX (0, MIN (y1, y2));
5460 if (area.y > clist->clist_window_height)
5462 area.height = MIN (clist->clist_window_height, h1 + h2);
5463 if (s1 >= 0 && s2 >= 0)
5464 area.height += (clist->row_height + CELL_SPACING);
5465 draw_rows (clist, &area);
5469 start_selection (GtkCList *clist)
5471 g_return_if_fail (clist != NULL);
5472 g_return_if_fail (GTK_IS_CLIST (clist));
5474 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5477 set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
5482 end_selection (GtkCList *clist)
5484 g_return_if_fail (clist != NULL);
5485 g_return_if_fail (GTK_IS_CLIST (clist));
5487 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist)) ||
5488 clist->anchor == -1)
5491 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
5495 extend_selection (GtkCList *clist,
5496 GtkScrollType scroll_type,
5498 gboolean auto_start_selection)
5500 g_return_if_fail (clist != NULL);
5501 g_return_if_fail (GTK_IS_CLIST (clist));
5503 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
5504 clist->selection_mode != GTK_SELECTION_EXTENDED)
5507 if (auto_start_selection)
5508 set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
5510 else if (clist->anchor == -1)
5513 move_focus_row (clist, scroll_type, position);
5515 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5516 clist->clist_window_height)
5517 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5518 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5519 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5521 update_extended_selection (clist, clist->focus_row);
5525 abort_column_resize (GtkCList *clist)
5527 g_return_if_fail (clist != NULL);
5528 g_return_if_fail (GTK_IS_CLIST (clist));
5530 if (!GTK_CLIST_IN_DRAG (clist))
5533 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
5534 gtk_grab_remove (GTK_WIDGET (clist));
5535 gdk_pointer_ungrab (GDK_CURRENT_TIME);
5536 clist->drag_pos = -1;
5538 if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1)
5539 draw_xor_line (clist);
5541 if (GTK_CLIST_ADD_MODE (clist))
5543 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_ON_OFF_DASH, 0,0);
5544 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
5549 gtk_clist_key_press (GtkWidget * widget,
5550 GdkEventKey * event)
5552 g_return_val_if_fail (widget != NULL, FALSE);
5553 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
5554 g_return_val_if_fail (event != NULL, FALSE);
5556 if (GTK_WIDGET_CLASS (parent_class)->key_press_event &&
5557 GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
5560 switch (event->keyval)
5563 case GDK_ISO_Left_Tab:
5564 if (event->state & GDK_SHIFT_MASK)
5565 return gtk_container_focus (GTK_CONTAINER (widget),
5566 GTK_DIR_TAB_BACKWARD);
5568 return gtk_container_focus (GTK_CONTAINER (widget),
5569 GTK_DIR_TAB_FORWARD);
5579 title_focus (GtkCList * clist,
5582 GtkWidget *focus_child;
5583 gboolean return_val = FALSE;
5588 if (!GTK_CLIST_SHOW_TITLES (clist))
5591 focus_child = GTK_CONTAINER (clist)->focus_child;
5595 case GTK_DIR_TAB_BACKWARD:
5597 if (!focus_child || focus_child == clist->hscrollbar ||
5598 focus_child == clist->hscrollbar ||
5599 !GTK_CLIST_CHILD_HAS_FOCUS (clist))
5601 if (dir == GTK_DIR_UP)
5602 i = COLUMN_FROM_XPIXEL (clist, 0);
5604 i = clist->columns - 1;
5605 focus_child = clist->column[i].button;
5606 dir = GTK_DIR_TAB_FORWARD;
5613 if (!focus_child || focus_child == clist->hscrollbar ||
5614 focus_child == clist->hscrollbar)
5616 i = clist->columns - 1;
5617 focus_child = clist->column[i].button;
5621 if (!focus_child || focus_child == clist->hscrollbar ||
5622 focus_child == clist->hscrollbar)
5625 focus_child = clist->column[i].button;
5631 while (i < clist->columns)
5633 if (clist->column[i].button == focus_child)
5635 if (clist->column[i].button &&
5636 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
5637 GTK_IS_CONTAINER (clist->column[i].button) &&
5638 !GTK_WIDGET_HAS_FOCUS (clist->column[i].button))
5639 if (gtk_container_focus
5640 (GTK_CONTAINER (clist->column[i].button), dir))
5645 if (!return_val && dir == GTK_DIR_UP)
5656 while (j >= 0 && j < clist->columns)
5658 if (clist->column[j].button &&
5659 GTK_WIDGET_VISIBLE (clist->column[j].button))
5661 if (GTK_IS_CONTAINER (clist->column[j].button) &&
5663 (GTK_CONTAINER (clist->column[j].button), dir))
5668 else if (GTK_WIDGET_CAN_FOCUS (clist->column[j].button))
5670 gtk_widget_grab_focus (clist->column[j].button);
5680 if (COLUMN_LEFT_XPIXEL (clist, j) < CELL_SPACING + COLUMN_INSET)
5681 gtk_clist_moveto (clist, -1, j, 0, 0);
5682 else if (COLUMN_LEFT_XPIXEL(clist, j) + clist->column[j].area.width >
5683 clist->clist_window_width)
5685 if (j == clist->columns-1)
5686 gtk_clist_moveto (clist, -1, j, 0, 0);
5688 gtk_clist_moveto (clist, -1, j, 0, 1);
5695 gtk_clist_focus (GtkContainer * container,
5696 GtkDirectionType direction)
5699 GtkWidget *focus_child;
5702 g_return_val_if_fail (container != NULL, FALSE);
5703 g_return_val_if_fail (GTK_IS_CLIST (container), FALSE);
5705 if (!GTK_WIDGET_SENSITIVE (container))
5708 clist = GTK_CLIST (container);
5709 focus_child = container->focus_child;
5710 old_row = clist->focus_row;
5716 if (GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5717 (!focus_child || (focus_child && focus_child != clist->vscrollbar &&
5718 focus_child != clist->hscrollbar)))
5720 if (title_focus (clist, direction))
5722 gtk_container_set_focus_child (container, NULL);
5725 gtk_widget_grab_focus (GTK_WIDGET (container));
5728 case GTK_DIR_TAB_FORWARD:
5729 if (GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5730 (!focus_child || (focus_child != clist->vscrollbar &&
5731 focus_child != clist->hscrollbar)))
5733 gboolean tf = FALSE;
5735 if (((focus_child && direction == GTK_DIR_DOWN) ||
5736 !(tf = title_focus (clist, GTK_DIR_TAB_FORWARD)))
5739 if (clist->focus_row < 0)
5741 clist->focus_row = 0;
5743 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
5744 clist->selection_mode == GTK_SELECTION_EXTENDED) &&
5746 select_row (clist, clist->focus_row, -1, NULL);
5748 gtk_widget_grab_focus (GTK_WIDGET (container));
5756 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
5758 if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child ||
5759 (focus_child != clist->vscrollbar &&
5760 focus_child != clist->hscrollbar)) &&
5761 GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
5762 GTK_WIDGET_CAN_FOCUS (clist->vscrollbar))
5764 gtk_widget_grab_focus (clist->vscrollbar);
5768 if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child ||
5769 focus_child != clist->hscrollbar) &&
5770 GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
5771 GTK_WIDGET_CAN_FOCUS (clist->hscrollbar))
5773 gtk_widget_grab_focus (clist->hscrollbar);
5778 case GTK_DIR_TAB_BACKWARD:
5779 if (!focus_child && GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5780 GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
5781 GTK_WIDGET_CAN_FOCUS (clist->hscrollbar))
5783 gtk_widget_grab_focus (clist->hscrollbar);
5787 if ((!focus_child || focus_child == clist->hscrollbar) &&
5788 GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5789 GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
5790 GTK_WIDGET_CAN_FOCUS (clist->vscrollbar))
5792 gtk_widget_grab_focus (clist->vscrollbar);
5796 if ((!focus_child || focus_child == clist->hscrollbar ||
5797 focus_child == clist->vscrollbar) &&
5798 GTK_CLIST_CHILD_HAS_FOCUS (clist) && clist->rows)
5800 if (clist->focus_row < 0)
5802 clist->focus_row = 0;
5803 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
5804 clist->selection_mode == GTK_SELECTION_EXTENDED) &&
5806 select_row (clist, clist->focus_row, -1, NULL);
5808 gtk_widget_grab_focus (GTK_WIDGET (container));
5812 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
5814 if (title_focus (clist, direction))
5823 gtk_container_set_focus_child (container, NULL);
5828 gtk_clist_unselect_all (GtkCList * clist)
5830 GTK_CLIST_CLASS_FW (clist)->unselect_all (clist);
5834 real_unselect_all (GtkCList * clist)
5839 g_return_if_fail (clist != NULL);
5840 g_return_if_fail (GTK_IS_CLIST (clist));
5842 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5845 switch (clist->selection_mode)
5847 case GTK_SELECTION_BROWSE:
5848 if (clist->focus_row >= 0)
5850 select_row (clist, clist->focus_row, -1, NULL);
5855 case GTK_SELECTION_EXTENDED:
5856 g_list_free (clist->undo_selection);
5857 g_list_free (clist->undo_unselection);
5858 clist->undo_selection = NULL;
5859 clist->undo_unselection = NULL;
5862 clist->drag_pos = -1;
5863 clist->undo_anchor = clist->focus_row;
5870 list = clist->selection;
5874 i = GPOINTER_TO_INT (list->data);
5876 unselect_row (clist, i, -1, NULL);
5881 gtk_clist_select_all (GtkCList * clist)
5883 GTK_CLIST_CLASS_FW (clist)->select_all (clist);
5887 real_select_all (GtkCList * clist)
5892 g_return_if_fail (clist != NULL);
5893 g_return_if_fail (GTK_IS_CLIST (clist));
5895 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5898 switch (clist->selection_mode)
5900 case GTK_SELECTION_SINGLE:
5901 case GTK_SELECTION_BROWSE:
5904 case GTK_SELECTION_EXTENDED:
5905 g_list_free (clist->undo_selection);
5906 g_list_free (clist->undo_unselection);
5907 clist->undo_selection = NULL;
5908 clist->undo_unselection = NULL;
5911 ((GtkCListRow *) (clist->row_list->data))->state !=
5913 fake_toggle_row (clist, 0);
5915 clist->anchor_state = GTK_STATE_SELECTED;
5917 clist->drag_pos = 0;
5918 clist->undo_anchor = clist->focus_row;
5919 update_extended_selection (clist, clist->rows);
5920 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
5923 case GTK_SELECTION_MULTIPLE:
5924 for (i = 0, list = clist->row_list; list; i++, list = list->next)
5926 if (((GtkCListRow *)(list->data))->state == GTK_STATE_NORMAL)
5927 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
5935 fake_unselect_all (GtkCList * clist,
5942 if (row >= 0 && (work = g_list_nth (clist->row_list, row)))
5944 if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL)
5946 GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
5948 if (!GTK_CLIST_FROZEN (clist) &&
5949 gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
5950 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
5951 GTK_CLIST_ROW (work));
5955 clist->undo_selection = clist->selection;
5956 clist->selection = NULL;
5957 clist->selection_end = NULL;
5959 for (list = clist->undo_selection; list; list = list->next)
5961 if ((i = GPOINTER_TO_INT (list->data)) == row ||
5962 !(work = g_list_nth (clist->row_list, i)))
5965 GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
5966 if (!GTK_CLIST_FROZEN (clist) &&
5967 gtk_clist_row_is_visible (clist, i) != GTK_VISIBILITY_NONE)
5968 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, i,
5969 GTK_CLIST_ROW (work));
5974 fake_toggle_row (GtkCList *clist,
5979 if (!(work = g_list_nth (clist->row_list, row)))
5982 if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL)
5983 clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
5985 clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
5987 if (!GTK_CLIST_FROZEN (clist) &&
5988 gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
5989 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
5990 GTK_CLIST_ROW (work));
5994 selection_find (GtkCList *clist,
5996 GList *row_list_element)
5998 return g_list_find (clist->selection, GINT_TO_POINTER (row_number));
6002 default_compare (GtkCList *clist,
6009 GtkCListRow *row1 = (GtkCListRow *) ptr1;
6010 GtkCListRow *row2 = (GtkCListRow *) ptr2;
6012 switch (row1->cell[clist->sort_column].type)
6015 text1 = GTK_CELL_TEXT (row1->cell[clist->sort_column])->text;
6017 case GTK_CELL_PIXTEXT:
6018 text1 = GTK_CELL_PIXTEXT (row1->cell[clist->sort_column])->text;
6024 switch (row2->cell[clist->sort_column].type)
6027 text2 = GTK_CELL_TEXT (row2->cell[clist->sort_column])->text;
6029 case GTK_CELL_PIXTEXT:
6030 text2 = GTK_CELL_PIXTEXT (row2->cell[clist->sort_column])->text;
6037 return (text1 != NULL);
6042 return strcmp (text1, text2);
6046 gtk_clist_set_compare_func (GtkCList *clist,
6047 GtkCListCompareFunc cmp_func)
6049 g_return_if_fail (clist != NULL);
6050 g_return_if_fail (GTK_IS_CLIST (clist));
6052 clist->compare = (cmp_func) ? cmp_func : default_compare;
6056 gtk_clist_set_auto_sort (GtkCList *clist,
6059 g_return_if_fail (clist != NULL);
6060 g_return_if_fail (GTK_IS_CLIST (clist));
6062 if (GTK_CLIST_AUTO_SORT (clist) && !auto_sort)
6063 GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_SORT);
6064 else if (!GTK_CLIST_AUTO_SORT (clist) && auto_sort)
6066 GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_SORT);
6067 gtk_clist_sort (clist);
6072 gtk_clist_set_sort_type (GtkCList *clist,
6073 GtkSortType sort_type)
6075 g_return_if_fail (clist != NULL);
6076 g_return_if_fail (GTK_IS_CLIST (clist));
6078 clist->sort_type = sort_type;
6082 gtk_clist_set_sort_column (GtkCList *clist,
6085 g_return_if_fail (clist != NULL);
6086 g_return_if_fail (GTK_IS_CLIST (clist));
6088 if (column < 0 || column >= clist->columns)
6091 clist->sort_column = column;
6095 gtk_clist_merge (GtkCList *clist,
6096 GList *a, /* first list to merge */
6097 GList *b) /* second list to merge */
6099 GList z = { 0 }; /* auxiliary node */
6125 cmp = clist->compare (clist, GTK_CLIST_ROW (a), GTK_CLIST_ROW (b));
6126 if ((cmp >= 0 && clist->sort_type == GTK_SORT_DESCENDING) ||
6127 (cmp <= 0 && clist->sort_type == GTK_SORT_ASCENDING) ||
6149 gtk_clist_mergesort (GtkCList *clist,
6150 GList *list, /* the list to sort */
6151 gint num) /* the list's length */
6162 /* move "half" to the middle */
6164 for (i = 0; i < num / 2; i++)
6167 /* cut the list in two */
6168 half->prev->next = NULL;
6171 /* recursively sort both lists */
6172 return gtk_clist_merge (clist,
6173 gtk_clist_mergesort (clist, list, num / 2),
6174 gtk_clist_mergesort (clist, half, num - num / 2));
6179 gtk_clist_sort (GtkCList *clist)
6181 GTK_CLIST_CLASS_FW (clist)->sort_list (clist);
6185 real_sort_list (GtkCList *clist)
6190 gboolean thaw = FALSE;
6192 g_return_if_fail (clist != NULL);
6193 g_return_if_fail (GTK_IS_CLIST (clist));
6195 if (clist->rows <= 1)
6198 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
6201 if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
6203 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
6204 g_list_free (clist->undo_selection);
6205 g_list_free (clist->undo_unselection);
6206 clist->undo_selection = NULL;
6207 clist->undo_unselection = NULL;
6210 if (!GTK_CLIST_FROZEN (clist))
6212 gtk_clist_freeze (clist);
6216 clist->row_list = gtk_clist_mergesort (clist, clist->row_list, clist->rows);
6218 work = clist->selection;
6220 for (i = 0, list = clist->row_list; i < clist->rows; i++, list = list->next)
6222 if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
6224 work->data = GINT_TO_POINTER (i);
6228 if (i == clist->rows - 1)
6229 clist->row_list_end = list;
6233 gtk_clist_thaw (clist);