1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald,
3 * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 #include "../config.h"
25 #include "gtkbindings.h"
26 #include <gdk/gdkkeysyms.h>
28 /* the number rows memchunk expands at a time */
29 #define CLIST_OPTIMUM_SIZE 512
31 /* the width of the column resize windows */
34 /* minimum allowed width of a column */
35 #define COLUMN_MIN_WIDTH 5
37 /* this defigns the base grid spacing */
38 #define CELL_SPACING 1
40 /* added the horizontal space at the beginning and end of a row*/
41 #define COLUMN_INSET 3
43 /* used for auto-scrolling */
44 #define SCROLL_TIME 100
46 /* scrollbar spacing class macro */
47 #define SCROLLBAR_SPACING(w) (GTK_CLIST_CLASS (GTK_OBJECT (w)->klass)->scrollbar_spacing)
49 /* gives the top pixel of the given row in context of
50 * the clist's voffset */
51 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
52 (((row) + 1) * CELL_SPACING) + \
55 /* returns the row index from a y pixel location in the
56 * context of the clist's voffset */
57 #define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \
58 ((clist)->row_height + CELL_SPACING))
60 /* gives the left pixel of the given column in context of
61 * the clist's hoffset */
62 #define COLUMN_LEFT_XPIXEL(clist, colnum) ((clist)->column[(colnum)].area.x + \
65 /* returns the column index from a x pixel location in the
66 * context of the clist's hoffset */
68 COLUMN_FROM_XPIXEL (GtkCList * clist,
73 for (i = 0; i < clist->columns; i++)
75 cx = clist->column[i].area.x + clist->hoffset;
77 if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
78 x <= (cx + clist->column[i].area.width + COLUMN_INSET))
86 /* returns the top pixel of the given row in the context of
88 #define ROW_TOP(clist, row) (((clist)->row_height + CELL_SPACING) * (row))
90 /* returns the left pixel of the given column in the context of
92 #define COLUMN_LEFT(clist, colnum) ((clist)->column[(colnum)].area.x)
94 /* returns the total height of the list */
95 #define LIST_HEIGHT(clist) (((clist)->row_height * ((clist)->rows)) + \
96 (CELL_SPACING * ((clist)->rows + 1)))
99 /* returns the total width of the list */
101 LIST_WIDTH (GtkCList * clist)
105 for (last_column = clist->columns - 1;
106 last_column >= 0 && !clist->column[last_column].visible; last_column--);
108 if (last_column >= 0)
109 return (clist->column[last_column].area.x +
110 clist->column[last_column].area.width +
111 COLUMN_INSET + CELL_SPACING);
116 #define GTK_CLIST_CLASS_FW(_widget_) GTK_CLIST_CLASS (GTK_OBJECT (_widget_)->klass)
147 typedef void (*GtkCListSignal1) (GtkObject * object,
153 typedef void (*GtkCListSignal2) (GtkObject *object,
156 typedef void (*GtkCListSignal3) (GtkObject * object,
159 typedef void (*GtkCListSignal4) (GtkObject * object,
163 typedef void (*GtkCListSignal5) (GtkObject * object,
170 static void sync_selection (GtkCList * clist,
174 /* GtkCList Methods */
175 static void gtk_clist_class_init (GtkCListClass * klass);
176 static void gtk_clist_init (GtkCList * clist);
177 static void real_clear (GtkCList * clist);
179 /* GtkObject Methods */
180 static void gtk_clist_destroy (GtkObject * object);
181 static void gtk_clist_finalize (GtkObject * object);
184 /* GtkWidget Methods */
185 static void gtk_clist_realize (GtkWidget * widget);
186 static void gtk_clist_unrealize (GtkWidget * widget);
187 static void gtk_clist_map (GtkWidget * widget);
188 static void gtk_clist_unmap (GtkWidget * widget);
189 static void gtk_clist_draw (GtkWidget * widget,
190 GdkRectangle * area);
191 static gint gtk_clist_expose (GtkWidget * widget,
192 GdkEventExpose * event);
193 static gint gtk_clist_button_press (GtkWidget * widget,
194 GdkEventButton * event);
195 static gint gtk_clist_button_release (GtkWidget * widget,
196 GdkEventButton * event);
197 static gint gtk_clist_motion (GtkWidget * widget,
198 GdkEventMotion * event);
199 static void gtk_clist_size_request (GtkWidget * widget,
200 GtkRequisition * requisition);
201 static void gtk_clist_size_allocate (GtkWidget * widget,
202 GtkAllocation * allocation);
203 static gint get_selection_info (GtkCList * clist,
209 /* GtkContainer Methods */
210 static void gtk_clist_forall (GtkContainer *container,
211 gboolean include_internals,
212 GtkCallback callback,
213 gpointer callback_data);
216 static void draw_row (GtkCList * clist,
219 GtkCListRow * clist_row);
220 static void draw_rows (GtkCList * clist,
221 GdkRectangle * area);
223 /* Size Allocation */
224 static void size_allocate_title_buttons (GtkCList * clist);
225 static void size_allocate_columns (GtkCList * clist);
228 static void toggle_row (GtkCList * clist,
232 static void select_row (GtkCList * clist,
236 static void unselect_row (GtkCList * clist,
240 static void real_select_row (GtkCList * clist,
244 static void real_unselect_row (GtkCList * clist,
248 static void update_extended_selection (GtkCList *clist,
250 static GList * selection_find (GtkCList *clist,
252 GList *row_list_element);
253 static void real_select_all (GtkCList * clist);
254 static void real_unselect_all (GtkCList * clist);
255 static void move_vertical (GtkCList *clist,
258 static void move_horizontal (GtkCList *clist,
260 static void real_undo_selection (GtkCList * clist);
261 static void fake_unselect_all (GtkCList *clist,
263 static void fake_toggle_row (GtkCList *clist,
265 static void resync_selection (GtkCList *clist,
269 static void draw_xor_line (GtkCList * clist);
270 static gint new_column_width (GtkCList * clist,
273 static void real_resize_column (GtkCList * clist,
276 static void resize_column (GtkCList * clist,
279 static void abort_column_resize (GtkCList *clist);
282 static void column_button_create (GtkCList * clist,
284 static void column_button_clicked (GtkWidget * widget,
288 static void create_scrollbars (GtkCList * clist);
289 static void adjust_scrollbars (GtkCList * clist);
290 static void check_exposures (GtkCList * clist);
291 static void vadjustment_changed (GtkAdjustment * adjustment,
293 static void vadjustment_value_changed (GtkAdjustment * adjustment,
295 static void hadjustment_changed (GtkAdjustment * adjustment,
297 static void hadjustment_value_changed (GtkAdjustment * adjustment,
300 /* Memory Allocation/Distruction Routines */
301 static GtkCListColumn *columns_new (GtkCList * clist);
303 static void column_title_new (GtkCList *clist,
306 static void columns_delete (GtkCList * clist);
308 static GtkCListRow *row_new (GtkCList * clist);
310 static void row_delete (GtkCList * clist,
311 GtkCListRow * clist_row);
312 static void set_cell_contents (GtkCList *clist,
313 GtkCListRow *clist_row,
320 static gint real_insert_row (GtkCList * clist,
323 static void real_remove_row (GtkCList * clist,
327 static void gtk_clist_draw_focus (GtkWidget *widget);
328 static gint gtk_clist_focus_in (GtkWidget *widget,
329 GdkEventFocus *event);
330 static gint gtk_clist_focus_out (GtkWidget *widget,
331 GdkEventFocus *event);
332 static gint gtk_clist_focus (GtkContainer *container,
333 GtkDirectionType direction);
334 static void gtk_clist_set_focus_child (GtkContainer *container,
336 static gint gtk_clist_key_press (GtkWidget *widget,
339 /* Selection handling */
340 static void set_anchor (GtkCList *clist,
344 static void start_selection (GtkCList *clist);
345 static void end_selection (GtkCList *clist);
347 static void toggle_add_mode (GtkCList *clist);
348 static void toggle_focus_row (GtkCList *clist);
349 static void move_focus_row (GtkCList *clist,
350 GtkScrollType scroll_type,
352 static void scroll_horizontal (GtkCList *clist,
353 GtkScrollType scroll_type,
355 static void scroll_vertical (GtkCList *clist,
356 GtkScrollType scroll_type,
358 static void extend_selection (GtkCList *clist,
359 GtkScrollType scroll_type,
361 gboolean auto_start_selection);
364 static gint default_compare (GtkCList *clist,
367 static GList * gtk_clist_merge (GtkCList *clist,
370 static GList * gtk_clist_mergesort (GtkCList *clist,
373 static void real_sort_list (GtkCList *clist);
375 /* Fill in data after widget is realized and has style */
377 static void add_style_data (GtkCList * clist);
379 static GtkContainerClass *parent_class = NULL;
380 static guint clist_signals[LAST_SIGNAL] = {0};
384 gtk_clist_get_type (void)
386 static GtkType clist_type = 0;
390 GtkTypeInfo clist_info =
394 sizeof (GtkCListClass),
395 (GtkClassInitFunc) gtk_clist_class_init,
396 (GtkObjectInitFunc) gtk_clist_init,
397 /* reserved_1 */ NULL,
398 /* reserved_2 */ NULL,
399 (GtkClassInitFunc) NULL,
402 clist_type = gtk_type_unique (GTK_TYPE_CONTAINER, &clist_info);
409 gtk_clist_class_init (GtkCListClass * klass)
411 GtkObjectClass *object_class;
412 GtkWidgetClass *widget_class;
413 GtkContainerClass *container_class;
415 object_class = (GtkObjectClass *) klass;
416 widget_class = (GtkWidgetClass *) klass;
417 container_class = (GtkContainerClass *) klass;
419 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
421 clist_signals[SELECT_ROW] =
422 gtk_signal_new ("select_row",
425 GTK_SIGNAL_OFFSET (GtkCListClass, select_row),
426 gtk_marshal_NONE__INT_INT_POINTER,
431 clist_signals[UNSELECT_ROW] =
432 gtk_signal_new ("unselect_row",
435 GTK_SIGNAL_OFFSET (GtkCListClass, unselect_row),
436 gtk_marshal_NONE__INT_INT_POINTER,
437 GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_GDK_EVENT);
438 clist_signals[CLICK_COLUMN] =
439 gtk_signal_new ("click_column",
442 GTK_SIGNAL_OFFSET (GtkCListClass, click_column),
443 gtk_marshal_NONE__INT,
444 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
445 clist_signals[RESIZE_COLUMN] =
446 gtk_signal_new ("resize_column",
449 GTK_SIGNAL_OFFSET (GtkCListClass, resize_column),
450 gtk_marshal_NONE__INT_INT,
451 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
453 clist_signals[TOGGLE_FOCUS_ROW] =
454 gtk_signal_new ("toggle_focus_row",
455 GTK_RUN_LAST | GTK_RUN_ACTION,
457 GTK_SIGNAL_OFFSET (GtkCListClass, toggle_focus_row),
458 gtk_marshal_NONE__NONE,
460 clist_signals[SELECT_ALL] =
461 gtk_signal_new ("select_all",
462 GTK_RUN_LAST | GTK_RUN_ACTION,
464 GTK_SIGNAL_OFFSET (GtkCListClass, select_all),
465 gtk_marshal_NONE__NONE,
467 clist_signals[UNSELECT_ALL] =
468 gtk_signal_new ("unselect_all",
469 GTK_RUN_LAST | GTK_RUN_ACTION,
471 GTK_SIGNAL_OFFSET (GtkCListClass, unselect_all),
472 gtk_marshal_NONE__NONE,
474 clist_signals[UNDO_SELECTION] =
475 gtk_signal_new ("undo_selection",
476 GTK_RUN_LAST | GTK_RUN_ACTION,
478 GTK_SIGNAL_OFFSET (GtkCListClass, undo_selection),
479 gtk_marshal_NONE__NONE,
481 clist_signals[START_SELECTION] =
482 gtk_signal_new ("start_selection",
483 GTK_RUN_LAST | GTK_RUN_ACTION,
485 GTK_SIGNAL_OFFSET (GtkCListClass, start_selection),
486 gtk_marshal_NONE__NONE,
488 clist_signals[END_SELECTION] =
489 gtk_signal_new ("end_selection",
490 GTK_RUN_LAST | GTK_RUN_ACTION,
492 GTK_SIGNAL_OFFSET (GtkCListClass, end_selection),
493 gtk_marshal_NONE__NONE,
495 clist_signals[TOGGLE_ADD_MODE] =
496 gtk_signal_new ("toggle_add_mode",
497 GTK_RUN_LAST | GTK_RUN_ACTION,
499 GTK_SIGNAL_OFFSET (GtkCListClass, toggle_add_mode),
500 gtk_marshal_NONE__NONE,
502 clist_signals[EXTEND_SELECTION] =
503 gtk_signal_new ("extend_selection",
504 GTK_RUN_LAST | GTK_RUN_ACTION,
506 GTK_SIGNAL_OFFSET (GtkCListClass, extend_selection),
507 gtk_marshal_NONE__ENUM_FLOAT_BOOL,
509 GTK_TYPE_SCROLL_TYPE, GTK_TYPE_FLOAT, GTK_TYPE_BOOL);
510 clist_signals[SCROLL_VERTICAL] =
511 gtk_signal_new ("scroll_vertical",
512 GTK_RUN_LAST | GTK_RUN_ACTION,
514 GTK_SIGNAL_OFFSET (GtkCListClass, scroll_vertical),
515 gtk_marshal_NONE__ENUM_FLOAT,
516 GTK_TYPE_NONE, 2, GTK_TYPE_SCROLL_TYPE, GTK_TYPE_FLOAT);
517 clist_signals[SCROLL_HORIZONTAL] =
518 gtk_signal_new ("scroll_horizontal",
519 GTK_RUN_LAST | GTK_RUN_ACTION,
521 GTK_SIGNAL_OFFSET (GtkCListClass, scroll_horizontal),
522 gtk_marshal_NONE__ENUM_FLOAT,
523 GTK_TYPE_NONE, 2, GTK_TYPE_SCROLL_TYPE, GTK_TYPE_FLOAT);
524 clist_signals[ABORT_COLUMN_RESIZE] =
525 gtk_signal_new ("abort_column_resize",
526 GTK_RUN_LAST | GTK_RUN_ACTION,
528 GTK_SIGNAL_OFFSET (GtkCListClass, abort_column_resize),
529 gtk_marshal_NONE__NONE,
533 gtk_object_class_add_signals (object_class, clist_signals, LAST_SIGNAL);
535 object_class->destroy = gtk_clist_destroy;
536 object_class->finalize = gtk_clist_finalize;
538 widget_class->realize = gtk_clist_realize;
539 widget_class->unrealize = gtk_clist_unrealize;
540 widget_class->map = gtk_clist_map;
541 widget_class->unmap = gtk_clist_unmap;
542 widget_class->draw = gtk_clist_draw;
543 widget_class->button_press_event = gtk_clist_button_press;
544 widget_class->button_release_event = gtk_clist_button_release;
545 widget_class->motion_notify_event = gtk_clist_motion;
546 widget_class->expose_event = gtk_clist_expose;
547 widget_class->size_request = gtk_clist_size_request;
548 widget_class->size_allocate = gtk_clist_size_allocate;
549 widget_class->key_press_event = gtk_clist_key_press;
550 widget_class->focus_in_event = gtk_clist_focus_in;
551 widget_class->focus_out_event = gtk_clist_focus_out;
552 widget_class->draw_focus = gtk_clist_draw_focus;
554 /* container_class->add = NULL; use the default GtkContainerClass warning */
555 /* container_class->remove = NULL; use the default GtkContainerClass warning */
556 container_class->forall = gtk_clist_forall;
557 container_class->focus = gtk_clist_focus;
558 container_class->set_focus_child = gtk_clist_set_focus_child;
560 klass->select_row = real_select_row;
561 klass->unselect_row = real_unselect_row;
562 klass->undo_selection = real_undo_selection;
563 klass->resync_selection = resync_selection;
564 klass->selection_find = selection_find;
565 klass->click_column = NULL;
566 klass->resize_column = real_resize_column;
567 klass->draw_row = draw_row;
568 klass->insert_row = real_insert_row;
569 klass->remove_row = real_remove_row;
570 klass->clear = real_clear;
571 klass->sort_list = real_sort_list;
572 klass->select_all = real_select_all;
573 klass->unselect_all = real_unselect_all;
574 klass->fake_unselect_all = fake_unselect_all;
575 klass->scroll_horizontal = scroll_horizontal;
576 klass->scroll_vertical = scroll_vertical;
577 klass->extend_selection = extend_selection;
578 klass->toggle_focus_row = toggle_focus_row;
579 klass->toggle_add_mode = toggle_add_mode;
580 klass->start_selection = start_selection;
581 klass->end_selection = end_selection;
582 klass->abort_column_resize = abort_column_resize;
583 klass->set_cell_contents = set_cell_contents;
585 klass->scrollbar_spacing = 5;
588 GtkBindingSet *binding_set;
590 binding_set = gtk_binding_set_by_class (klass);
591 gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
592 "scroll_vertical", 2,
593 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
594 GTK_TYPE_FLOAT, 0.0);
595 gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
596 "scroll_vertical", 2,
597 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
598 GTK_TYPE_FLOAT, 0.0);
599 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
600 "scroll_vertical", 2,
601 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
602 GTK_TYPE_FLOAT, 0.0);
603 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
604 "scroll_vertical", 2,
605 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
606 GTK_TYPE_FLOAT, 0.0);
607 gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
608 "scroll_vertical", 2,
609 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
610 GTK_TYPE_FLOAT, 0.0);
611 gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
612 "scroll_vertical", 2,
613 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
614 GTK_TYPE_FLOAT, 1.0);
616 gtk_binding_entry_add_signal (binding_set, GDK_Up, GDK_SHIFT_MASK,
617 "extend_selection", 3,
618 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
619 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
620 gtk_binding_entry_add_signal (binding_set, GDK_Down, GDK_SHIFT_MASK,
621 "extend_selection", 3,
622 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
623 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
624 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, GDK_SHIFT_MASK,
625 "extend_selection", 3,
626 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
627 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
628 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, GDK_SHIFT_MASK,
629 "extend_selection", 3,
630 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
631 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
632 gtk_binding_entry_add_signal (binding_set, GDK_Home,
633 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
634 "extend_selection", 3,
635 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
636 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
637 gtk_binding_entry_add_signal (binding_set, GDK_End,
638 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
639 "extend_selection", 3,
640 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
641 GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE);
644 gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
645 "scroll_horizontal", 2,
646 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
647 GTK_TYPE_FLOAT, 0.0);
648 gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
649 "scroll_horizontal", 2,
650 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
651 GTK_TYPE_FLOAT, 0.0);
652 gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
653 "scroll_horizontal", 2,
654 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
655 GTK_TYPE_FLOAT, 0.0);
656 gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
657 "scroll_horizontal", 2,
658 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
659 GTK_TYPE_FLOAT, 1.0);
662 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
663 "undo_selection", 0);
664 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
665 "abort_column_resize", 0);
666 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
667 "toggle_focus_row", 0);
668 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK,
669 "toggle_add_mode", 0);
670 gtk_binding_entry_add_signal (binding_set, '/', GDK_CONTROL_MASK,
672 gtk_binding_entry_add_signal (binding_set, '\\', GDK_CONTROL_MASK,
674 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
675 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
677 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
678 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
680 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
681 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
684 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
685 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
692 GtkBindingSet *binding_set;
694 binding_set = gtk_binding_set_by_class (klass);
695 gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
696 "scroll_vertical", 2,
697 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
698 GTK_TYPE_FLOAT, 0.0);
699 gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
700 "scroll_vertical", 2,
701 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
702 GTK_TYPE_FLOAT, 0.0);
703 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
704 "scroll_vertical", 2,
705 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
706 GTK_TYPE_FLOAT, 0.0);
707 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
708 "scroll_vertical", 2,
709 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
710 GTK_TYPE_FLOAT, 0.0);
711 gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
712 "scroll_vertical", 2,
713 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
714 GTK_TYPE_FLOAT, 0.0);
715 gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
716 "scroll_vertical", 2,
717 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
720 gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0,
721 "extend_selection", 3,
722 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
723 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
724 gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0,
725 "extend_selection", 3,
726 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
727 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
728 gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Up, 0,
729 "extend_selection", 3,
730 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
731 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
732 gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Down, 0,
733 "extend_selection", 3,
734 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
735 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
736 gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, 0,
737 "extend_selection", 3,
738 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
739 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
740 gtk_binding_entry_add_signal (binding_set, GDK_KP_End, 0,
741 "extend_selection", 3,
742 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
743 GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE);
745 gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
746 "scroll_horizontal", 2,
747 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
748 GTK_TYPE_FLOAT, 0.0);
749 gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0,
750 "scroll_horizontal", 2,
751 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
752 GTK_TYPE_FLOAT, 0.0);
753 gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
754 "scroll_horizontal", 2,
755 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
756 GTK_TYPE_FLOAT, 0.0);
757 gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0,
758 "scroll_horizontal", 2,
759 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
760 GTK_TYPE_FLOAT, 0.0);
761 gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
762 "scroll_horizontal", 2,
763 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
764 GTK_TYPE_FLOAT, 0.0);
765 gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
766 "sroll_horizontal", 2,
767 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
768 GTK_TYPE_FLOAT, 1.0);
770 gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, 0,
771 "undo_selection", 0);
772 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
773 "abort_column_resize", 0);
774 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
775 "toggle_focus_row", 0);
776 gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0,
777 "toggle_add_mode", 0);
778 gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0,
780 gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0,
782 gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0,
789 gtk_clist_init (GtkCList * clist)
793 GTK_WIDGET_UNSET_FLAGS (clist, GTK_NO_WINDOW);
794 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
796 clist->row_mem_chunk = NULL;
797 clist->cell_mem_chunk = NULL;
800 clist->row_center_offset = 0;
801 clist->row_height = 0;
802 clist->row_list = NULL;
803 clist->row_list_end = NULL;
807 clist->title_window = NULL;
808 clist->column_title_area.x = 0;
809 clist->column_title_area.y = 0;
810 clist->column_title_area.width = 1;
811 clist->column_title_area.height = 1;
813 clist->clist_window = NULL;
814 clist->clist_window_width = 1;
815 clist->clist_window_height = 1;
820 clist->shadow_type = GTK_SHADOW_IN;
821 clist->hscrollbar_policy = GTK_POLICY_ALWAYS;
822 clist->vscrollbar_policy = GTK_POLICY_ALWAYS;
824 clist->cursor_drag = NULL;
825 clist->xor_gc = NULL;
830 clist->selection_mode = GTK_SELECTION_SINGLE;
831 clist->selection = NULL;
832 clist->selection_end = NULL;
833 clist->undo_selection = NULL;
834 clist->undo_unselection = NULL;
836 GTK_WIDGET_SET_FLAGS (clist, GTK_CAN_FOCUS);
837 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
838 clist->focus_row = -1;
839 clist->undo_anchor = -1;
842 clist->anchor_state = GTK_STATE_SELECTED;
843 clist->drag_pos = -1;
847 clist->compare = default_compare;
848 clist->sort_type = GTK_SORT_ASCENDING;
849 clist->sort_column = 0;
854 gtk_clist_construct (GtkCList * clist,
860 g_return_if_fail (clist != NULL);
861 g_return_if_fail (GTK_IS_CLIST (clist));
862 g_return_if_fail (GTK_CLIST_CONSTRUCTED (clist) == FALSE);
864 GTK_CLIST_SET_FLAG (clist, CLIST_CONSTRUCTED);
866 /* initalize memory chunks, if this has not been done by any
867 * possibly derived widget
869 if (!clist->row_mem_chunk)
870 clist->row_mem_chunk = g_mem_chunk_new ("clist row mem chunk",
871 sizeof (GtkCListRow),
872 sizeof (GtkCListRow) * CLIST_OPTIMUM_SIZE,
875 if (!clist->cell_mem_chunk)
876 clist->cell_mem_chunk = g_mem_chunk_new ("clist cell mem chunk",
877 sizeof (GtkCell) * columns,
878 sizeof (GtkCell) * columns * CLIST_OPTIMUM_SIZE,
881 /* set number of columns, allocate memory */
882 clist->columns = columns;
883 clist->column = columns_new (clist);
885 /* there needs to be at least one column button
886 * because there is alot of code that will break if it
888 column_button_create (clist, 0);
890 /* create scrollbars */
891 create_scrollbars (clist);
895 GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES);
896 for (i = 0; i < columns; i++)
897 gtk_clist_set_column_title (clist, i, titles[i]);
901 GTK_CLIST_UNSET_FLAG (clist, CLIST_SHOW_TITLES);
906 * GTKCLIST PUBLIC INTERFACE
907 * gtk_clist_new_with_titles
911 gtk_clist_new_with_titles (gint columns,
916 g_return_val_if_fail (titles != NULL, NULL);
918 widget = gtk_type_new (GTK_TYPE_CLIST);
920 gtk_clist_construct (GTK_CLIST (widget), columns, titles);
926 gtk_clist_new (gint columns)
933 clist = gtk_type_new (GTK_TYPE_CLIST);
934 gtk_clist_construct (clist, columns, NULL);
935 return GTK_WIDGET (clist);
939 gtk_clist_set_border (GtkCList * clist,
940 GtkShadowType border)
942 g_return_if_fail (clist != NULL);
943 g_return_if_fail (GTK_IS_CLIST (clist));
945 clist->shadow_type = border;
947 if (GTK_WIDGET_VISIBLE (clist))
948 gtk_widget_queue_resize (GTK_WIDGET (clist));
952 gtk_clist_set_selection_mode (GtkCList * clist,
953 GtkSelectionMode mode)
955 g_return_if_fail (clist != NULL);
956 g_return_if_fail (GTK_IS_CLIST (clist));
958 if (mode == clist->selection_mode)
961 clist->selection_mode = mode;
963 clist->anchor_state = GTK_STATE_SELECTED;
964 clist->drag_pos = -1;
965 clist->undo_anchor = clist->focus_row;
967 g_list_free (clist->undo_selection);
968 g_list_free (clist->undo_unselection);
969 clist->undo_selection = NULL;
970 clist->undo_unselection = NULL;
974 case GTK_SELECTION_MULTIPLE:
975 case GTK_SELECTION_EXTENDED:
977 case GTK_SELECTION_BROWSE:
978 case GTK_SELECTION_SINGLE:
979 gtk_clist_unselect_all (clist);
985 gtk_clist_freeze (GtkCList * clist)
987 g_return_if_fail (clist != NULL);
988 g_return_if_fail (GTK_IS_CLIST (clist));
990 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
994 gtk_clist_thaw (GtkCList * clist)
996 g_return_if_fail (clist != NULL);
997 g_return_if_fail (GTK_IS_CLIST (clist));
999 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
1001 adjust_scrollbars (clist);
1002 draw_rows (clist, NULL);
1006 gtk_clist_column_titles_show (GtkCList * clist)
1008 g_return_if_fail (clist != NULL);
1009 g_return_if_fail (GTK_IS_CLIST (clist));
1011 if (!GTK_CLIST_SHOW_TITLES (clist))
1013 GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES);
1014 if (clist->title_window)
1015 gdk_window_show (clist->title_window);
1016 gtk_widget_queue_resize (GTK_WIDGET (clist));
1021 gtk_clist_column_titles_hide (GtkCList * clist)
1023 g_return_if_fail (clist != NULL);
1024 g_return_if_fail (GTK_IS_CLIST (clist));
1026 if (GTK_CLIST_SHOW_TITLES (clist))
1028 GTK_CLIST_UNSET_FLAG (clist, CLIST_SHOW_TITLES);
1029 if (clist->title_window)
1030 gdk_window_hide (clist->title_window);
1031 gtk_widget_queue_resize (GTK_WIDGET (clist));
1036 gtk_clist_set_column_visibility (GtkCList *clist,
1040 g_return_if_fail (clist != NULL);
1041 g_return_if_fail (GTK_IS_CLIST (clist));
1043 if (column < 0 || column >= clist->columns)
1045 if (clist->column[column].visible == visible)
1048 /* don't hide last visible column */
1052 gint vis_columns = 0;
1054 for (i = 0, vis_columns = 0; i < clist->columns && vis_columns < 2; i++)
1055 if (clist->column[i].visible)
1058 if (vis_columns < 2)
1062 clist->column[column].visible = visible;
1064 gtk_widget_show (clist->column[column].button);
1066 gtk_widget_hide (clist->column[column].button);
1070 gtk_clist_set_column_resizeable (GtkCList *clist,
1074 g_return_if_fail (clist != NULL);
1075 g_return_if_fail (GTK_IS_CLIST (clist));
1077 if (column < 0 || column >= clist->columns)
1079 if (clist->column[column].resizeable == resizeable)
1082 clist->column[column].resizeable = resizeable;
1086 gtk_clist_set_column_min_width (GtkCList *clist,
1090 g_return_if_fail (clist != NULL);
1091 g_return_if_fail (GTK_IS_CLIST (clist));
1093 if (column < 0 || column >= clist->columns)
1095 if (clist->column[column].min_width == min_width)
1098 if (clist->column[column].max_width >= 0 &&
1099 clist->column[column].max_width < min_width)
1100 clist->column[column].min_width = clist->column[column].max_width;
1102 clist->column[column].min_width = min_width;
1104 if (clist->column[column].area.width < clist->column[column].min_width)
1105 gtk_clist_set_column_width (clist, column,clist->column[column].min_width);
1109 gtk_clist_set_column_max_width (GtkCList * clist,
1113 g_return_if_fail (clist != NULL);
1114 g_return_if_fail (GTK_IS_CLIST (clist));
1116 if (column < 0 || column >= clist->columns)
1118 if (clist->column[column].max_width == max_width)
1121 if (clist->column[column].min_width >= 0 && max_width >= 0 &&
1122 clist->column[column].min_width > max_width)
1123 clist->column[column].max_width = clist->column[column].min_width;
1125 clist->column[column].max_width = max_width;
1127 if (clist->column[column].area.width > clist->column[column].max_width)
1128 gtk_clist_set_column_width (clist, column,clist->column[column].max_width);
1132 gtk_clist_column_title_active (GtkCList * clist,
1135 g_return_if_fail (clist != NULL);
1136 g_return_if_fail (GTK_IS_CLIST (clist));
1138 if (column < 0 || column >= clist->columns)
1141 if (!GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
1142 !GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
1144 GTK_WIDGET_SET_FLAGS (clist->column[column].button,
1145 GTK_SENSITIVE | GTK_CAN_FOCUS);
1146 if (GTK_WIDGET_VISIBLE (clist))
1147 gtk_widget_queue_draw (clist->column[column].button);
1152 gtk_clist_column_title_passive (GtkCList * clist,
1155 g_return_if_fail (clist != NULL);
1156 g_return_if_fail (GTK_IS_CLIST (clist));
1158 if (column < 0 || column >= clist->columns)
1161 if (GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
1162 GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
1164 GTK_WIDGET_UNSET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS);
1165 if (GTK_WIDGET_VISIBLE (clist))
1166 gtk_widget_queue_draw (clist->column[column].button);
1171 gtk_clist_column_titles_active (GtkCList * clist)
1175 g_return_if_fail (clist != NULL);
1176 g_return_if_fail (GTK_IS_CLIST (clist));
1178 for (i = 0; i < clist->columns; i++)
1179 if (clist->column[i].button)
1180 gtk_clist_column_title_active (clist, i);
1184 gtk_clist_column_titles_passive (GtkCList * clist)
1188 g_return_if_fail (clist != NULL);
1189 g_return_if_fail (GTK_IS_CLIST (clist));
1191 for (i = 0; i < clist->columns; i++)
1192 if (clist->column[i].button)
1193 gtk_clist_column_title_passive (clist, i);
1197 gtk_clist_set_column_title (GtkCList *clist,
1201 gint new_button = 0;
1202 GtkWidget *old_widget;
1203 GtkWidget *alignment = NULL;
1206 g_return_if_fail (clist != NULL);
1207 g_return_if_fail (GTK_IS_CLIST (clist));
1209 if (column < 0 || column >= clist->columns)
1212 /* if the column button doesn't currently exist,
1213 * it has to be created first */
1214 if (!clist->column[column].button)
1216 column_button_create (clist, column);
1220 column_title_new (clist, column, title);
1222 /* remove and destroy the old widget */
1223 old_widget = GTK_BIN (clist->column[column].button)->child;
1225 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
1227 /* create new alignment based no column justification */
1228 switch (clist->column[column].justification)
1230 case GTK_JUSTIFY_LEFT:
1231 alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
1234 case GTK_JUSTIFY_RIGHT:
1235 alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
1238 case GTK_JUSTIFY_CENTER:
1239 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1242 case GTK_JUSTIFY_FILL:
1243 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1247 label = gtk_label_new (clist->column[column].title);
1248 gtk_container_add (GTK_CONTAINER (alignment), label);
1249 gtk_container_add (GTK_CONTAINER (clist->column[column].button), alignment);
1250 gtk_widget_show (label);
1251 gtk_widget_show (alignment);
1253 /* if this button didn't previously exist, then the
1254 * column button positions have to be re-computed */
1255 if (GTK_WIDGET_VISIBLE (clist) && new_button)
1256 size_allocate_title_buttons (clist);
1260 gtk_clist_set_column_widget (GtkCList * clist,
1264 gint new_button = 0;
1265 GtkWidget *old_widget;
1267 g_return_if_fail (clist != NULL);
1268 g_return_if_fail (GTK_IS_CLIST (clist));
1270 if (column < 0 || column >= clist->columns)
1273 /* if the column button doesn't currently exist,
1274 * it has to be created first */
1275 if (!clist->column[column].button)
1277 column_button_create (clist, column);
1281 column_title_new (clist, column, NULL);
1283 /* remove and destroy the old widget */
1284 old_widget = GTK_BIN (clist->column[column].button)->child;
1286 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
1288 /* add and show the widget */
1291 gtk_container_add (GTK_CONTAINER (clist->column[column].button), widget);
1292 gtk_widget_show (widget);
1295 /* if this button didn't previously exist, then the
1296 * column button positions have to be re-computed */
1297 if (GTK_WIDGET_VISIBLE (clist) && new_button)
1298 size_allocate_title_buttons (clist);
1302 gtk_clist_set_column_justification (GtkCList * clist,
1304 GtkJustification justification)
1306 GtkWidget *alignment;
1308 g_return_if_fail (clist != NULL);
1309 g_return_if_fail (GTK_IS_CLIST (clist));
1311 if (column < 0 || column >= clist->columns)
1314 clist->column[column].justification = justification;
1316 /* change the alinment of the button title if it's not a
1318 if (clist->column[column].title)
1320 alignment = GTK_BIN (clist->column[column].button)->child;
1322 switch (clist->column[column].justification)
1324 case GTK_JUSTIFY_LEFT:
1325 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.0, 0.5, 0.0, 0.0);
1328 case GTK_JUSTIFY_RIGHT:
1329 gtk_alignment_set (GTK_ALIGNMENT (alignment), 1.0, 0.5, 0.0, 0.0);
1332 case GTK_JUSTIFY_CENTER:
1333 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
1336 case GTK_JUSTIFY_FILL:
1337 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
1345 if (!GTK_CLIST_FROZEN (clist))
1346 draw_rows (clist, NULL);
1350 real_resize_column (GtkCList * clist,
1354 g_return_if_fail (clist != NULL);
1355 g_return_if_fail (GTK_IS_CLIST (clist));
1357 if (column < 0 || column >= clist->columns)
1360 if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width))
1361 width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width);
1362 if (clist->column[column].max_width >= 0 &&
1363 width > clist->column[column].max_width)
1364 width = clist->column[column].max_width;
1366 clist->column[column].width = width;
1367 clist->column[column].width_set = TRUE;
1369 /* FIXME: this is quite expensive to do if the widget hasn't
1370 * been size_allocated yet, and pointless. Should
1373 size_allocate_columns (clist);
1374 size_allocate_title_buttons (clist);
1376 if (!GTK_CLIST_FROZEN (clist))
1378 adjust_scrollbars (clist);
1379 draw_rows (clist, NULL);
1384 gtk_clist_set_column_width (GtkCList * clist,
1388 g_return_if_fail (clist != NULL);
1389 g_return_if_fail (GTK_IS_CLIST (clist));
1391 if (column < 0 || column >= clist->columns)
1394 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[RESIZE_COLUMN],
1399 gtk_clist_set_row_height (GtkCList * clist,
1404 g_return_if_fail (clist != NULL);
1405 g_return_if_fail (GTK_IS_CLIST (clist));
1408 clist->row_height = height;
1412 GTK_CLIST_SET_FLAG (clist, CLIST_ROW_HEIGHT_SET);
1414 if (GTK_WIDGET_REALIZED (clist))
1416 text_height = height - (GTK_WIDGET (clist)->style->font->ascent +
1417 GTK_WIDGET (clist) ->style->font->descent + 1);
1418 clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
1421 if (!GTK_CLIST_FROZEN (clist))
1423 adjust_scrollbars (clist);
1424 draw_rows (clist, NULL);
1429 gtk_clist_moveto (GtkCList * clist,
1435 g_return_if_fail (clist != NULL);
1436 g_return_if_fail (GTK_IS_CLIST (clist));
1438 if (row < -1 || row >= clist->rows)
1440 if (column < -1 || column >= clist->columns)
1443 row_align = CLAMP (row_align, 0, 1);
1444 col_align = CLAMP (col_align, 0, 1);
1446 /* adjust horizontal scrollbar */
1452 adj = GTK_RANGE (clist->hscrollbar)->adjustment;
1454 x = COLUMN_LEFT (clist, column) - CELL_SPACING - COLUMN_INSET -
1455 (col_align * (clist->clist_window_width - 2 * COLUMN_INSET -
1456 CELL_SPACING - clist->column[column].area.width));
1458 gtk_adjustment_set_value (adj, 0.0);
1459 else if (x > LIST_WIDTH (clist) - clist->clist_window_width)
1460 gtk_adjustment_set_value
1461 (adj, LIST_WIDTH (clist) - clist->clist_window_width);
1463 gtk_adjustment_set_value (adj, x);
1466 /* adjust vertical scrollbar */
1468 move_vertical (clist, row, row_align);
1472 gtk_clist_get_cell_type (GtkCList * clist,
1476 GtkCListRow *clist_row;
1478 g_return_val_if_fail (clist != NULL, -1);
1479 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1481 if (row < 0 || row >= clist->rows)
1483 if (column < 0 || column >= clist->columns)
1486 clist_row = (g_list_nth (clist->row_list, row))->data;
1488 return clist_row->cell[column].type;
1492 gtk_clist_set_text (GtkCList *clist,
1497 GtkCListRow *clist_row;
1499 g_return_if_fail (clist != NULL);
1500 g_return_if_fail (GTK_IS_CLIST (clist));
1502 if (row < 0 || row >= clist->rows)
1504 if (column < 0 || column >= clist->columns)
1507 clist_row = (g_list_nth (clist->row_list, row))->data;
1509 /* if text is null, then the cell is empty */
1510 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
1511 (clist, clist_row, column, GTK_CELL_TEXT, text, 0, NULL, NULL);
1513 /* redraw the list if it's not frozen */
1514 if (!GTK_CLIST_FROZEN (clist))
1516 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1517 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1522 gtk_clist_get_text (GtkCList * clist,
1527 GtkCListRow *clist_row;
1529 g_return_val_if_fail (clist != NULL, 0);
1530 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
1532 if (row < 0 || row >= clist->rows)
1534 if (column < 0 || column >= clist->columns)
1537 clist_row = (g_list_nth (clist->row_list, row))->data;
1539 if (clist_row->cell[column].type != GTK_CELL_TEXT)
1543 *text = GTK_CELL_TEXT (clist_row->cell[column])->text;
1549 gtk_clist_set_pixmap (GtkCList * clist,
1555 GtkCListRow *clist_row;
1557 g_return_if_fail (clist != NULL);
1558 g_return_if_fail (GTK_IS_CLIST (clist));
1560 if (row < 0 || row >= clist->rows)
1562 if (column < 0 || column >= clist->columns)
1565 clist_row = (g_list_nth (clist->row_list, row))->data;
1567 gdk_pixmap_ref (pixmap);
1569 if (mask) gdk_pixmap_ref (mask);
1571 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
1572 (clist, clist_row, column, GTK_CELL_PIXMAP, NULL, 0, pixmap, mask);
1574 /* redraw the list if it's not frozen */
1575 if (!GTK_CLIST_FROZEN (clist))
1577 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1578 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1583 gtk_clist_get_pixmap (GtkCList * clist,
1586 GdkPixmap ** pixmap,
1589 GtkCListRow *clist_row;
1591 g_return_val_if_fail (clist != NULL, 0);
1592 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
1594 if (row < 0 || row >= clist->rows)
1596 if (column < 0 || column >= clist->columns)
1599 clist_row = (g_list_nth (clist->row_list, row))->data;
1601 if (clist_row->cell[column].type != GTK_CELL_PIXMAP)
1606 *pixmap = GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap;
1607 /* mask can be NULL */
1608 *mask = GTK_CELL_PIXMAP (clist_row->cell[column])->mask;
1615 gtk_clist_set_pixtext (GtkCList *clist,
1623 GtkCListRow *clist_row;
1625 g_return_if_fail (clist != NULL);
1626 g_return_if_fail (GTK_IS_CLIST (clist));
1628 if (row < 0 || row >= clist->rows)
1630 if (column < 0 || column >= clist->columns)
1633 clist_row = (g_list_nth (clist->row_list, row))->data;
1635 gdk_pixmap_ref (pixmap);
1636 if (mask) gdk_pixmap_ref (mask);
1637 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
1638 (clist, clist_row, column, GTK_CELL_PIXTEXT, text, spacing, pixmap, mask);
1640 /* redraw the list if it's not frozen */
1641 if (!GTK_CLIST_FROZEN (clist))
1643 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1644 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1649 gtk_clist_get_pixtext (GtkCList * clist,
1654 GdkPixmap ** pixmap,
1657 GtkCListRow *clist_row;
1659 g_return_val_if_fail (clist != NULL, 0);
1660 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
1662 if (row < 0 || row >= clist->rows)
1664 if (column < 0 || column >= clist->columns)
1667 clist_row = (g_list_nth (clist->row_list, row))->data;
1669 if (clist_row->cell[column].type != GTK_CELL_PIXTEXT)
1673 *text = GTK_CELL_PIXTEXT (clist_row->cell[column])->text;
1675 *spacing = GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing;
1677 *pixmap = GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap;
1679 /* mask can be NULL */
1680 *mask = GTK_CELL_PIXTEXT (clist_row->cell[column])->mask;
1686 gtk_clist_set_foreground (GtkCList * clist,
1690 GtkCListRow *clist_row;
1692 g_return_if_fail (clist != NULL);
1693 g_return_if_fail (GTK_IS_CLIST (clist));
1695 if (row < 0 || row >= clist->rows)
1698 clist_row = (g_list_nth (clist->row_list, row))->data;
1702 clist_row->foreground = *color;
1703 clist_row->fg_set = TRUE;
1706 clist_row->fg_set = FALSE;
1708 if (!GTK_CLIST_FROZEN (clist)
1709 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1710 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1714 gtk_clist_set_background (GtkCList * clist,
1718 GtkCListRow *clist_row;
1720 g_return_if_fail (clist != NULL);
1721 g_return_if_fail (GTK_IS_CLIST (clist));
1723 if (row < 0 || row >= clist->rows)
1726 clist_row = (g_list_nth (clist->row_list, row))->data;
1730 clist_row->background = *color;
1731 clist_row->bg_set = TRUE;
1734 clist_row->bg_set = FALSE;
1736 if (!GTK_CLIST_FROZEN (clist)
1737 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1738 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1742 gtk_clist_set_shift (GtkCList * clist,
1748 GtkCListRow *clist_row;
1750 g_return_if_fail (clist != NULL);
1751 g_return_if_fail (GTK_IS_CLIST (clist));
1753 if (row < 0 || row >= clist->rows)
1755 if (column < 0 || column >= clist->columns)
1758 clist_row = (g_list_nth (clist->row_list, row))->data;
1760 clist_row->cell[column].vertical = vertical;
1761 clist_row->cell[column].horizontal = horizontal;
1763 if (!GTK_CLIST_FROZEN (clist)
1764 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1765 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1769 gtk_clist_set_selectable (GtkCList *clist,
1771 gboolean selectable)
1773 GtkCListRow *clist_row;
1775 g_return_if_fail (clist != NULL);
1776 g_return_if_fail (GTK_IS_CLIST (clist));
1778 if (row < 0 || row >= clist->rows)
1781 clist_row = (g_list_nth (clist->row_list, row))->data;
1783 if (selectable == clist_row->selectable)
1786 clist_row->selectable = selectable;
1788 if (!selectable && clist_row->state == GTK_STATE_SELECTED)
1790 if (clist->anchor >= 0 &&
1791 clist->selection_mode == GTK_SELECTION_EXTENDED)
1793 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist)))
1795 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
1796 gtk_grab_remove (GTK_WIDGET (clist));
1797 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1800 gtk_timeout_remove (clist->htimer);
1805 gtk_timeout_remove (clist->vtimer);
1809 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
1811 unselect_row (clist, row, -1, NULL);
1816 gtk_clist_get_selectable (GtkCList *clist,
1819 g_return_val_if_fail (clist != NULL, FALSE);
1820 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
1822 if (row < 0 || row >= clist->rows)
1825 return GTK_CLIST_ROW (g_list_nth (clist->row_list, row))->selectable;
1829 gtk_clist_prepend (GtkCList *clist,
1832 g_return_val_if_fail (clist != NULL, -1);
1833 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1834 g_return_val_if_fail (text != NULL, -1);
1836 return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, 0, text);
1840 gtk_clist_append (GtkCList *clist,
1843 g_return_val_if_fail (clist != NULL, -1);
1844 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1845 g_return_val_if_fail (text != NULL, -1);
1847 return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, clist->rows, text);
1851 gtk_clist_insert (GtkCList *clist,
1855 g_return_val_if_fail (clist != NULL, -1);
1856 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1857 g_return_val_if_fail (text != NULL, -1);
1859 if (row < 0 || row > clist->rows)
1862 return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, row, text);
1866 real_insert_row (GtkCList *clist,
1871 GtkCListRow *clist_row;
1873 g_return_val_if_fail (clist != NULL, -1);
1874 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1875 g_return_val_if_fail (text != NULL, -1);
1877 /* return if out of bounds */
1878 if (row < 0 || row > clist->rows)
1881 /* create the row */
1882 clist_row = row_new (clist);
1884 /* set the text in the row's columns */
1885 for (i = 0; i < clist->columns; i++)
1887 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
1888 (clist, clist_row, i, GTK_CELL_TEXT, text[i], 0, NULL ,NULL);
1892 clist->row_list = g_list_append (clist->row_list, clist_row);
1893 clist->row_list_end = clist->row_list;
1897 if (GTK_CLIST_AUTO_SORT (clist)) /* override insertion pos */
1902 work = clist->row_list;
1904 if (clist->sort_type == GTK_SORT_ASCENDING)
1906 while (row < clist->rows &&
1907 clist->compare (clist, clist_row,
1908 GTK_CLIST_ROW (work)) > 0)
1916 while (row < clist->rows &&
1917 clist->compare (clist, clist_row,
1918 GTK_CLIST_ROW (work)) < 0)
1926 /* reset the row end pointer if we're inserting at the end of the list */
1927 if (row == clist->rows)
1928 clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
1930 clist->row_list = g_list_insert (clist->row_list, clist_row, row);
1935 if (row < ROW_FROM_YPIXEL (clist, 0))
1936 clist->voffset -= (clist->row_height + CELL_SPACING);
1938 /* syncronize the selection list */
1939 sync_selection (clist, row, SYNC_INSERT);
1941 /* redraw the list if it isn't frozen */
1942 if (!GTK_CLIST_FROZEN (clist))
1944 adjust_scrollbars (clist);
1946 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1947 draw_rows (clist, NULL);
1954 gtk_clist_remove (GtkCList * clist,
1957 GTK_CLIST_CLASS_FW (clist)->remove_row (clist, row);
1961 real_remove_row (GtkCList * clist,
1964 gint was_visible, was_selected;
1966 GtkCListRow *clist_row;
1968 g_return_if_fail (clist != NULL);
1969 g_return_if_fail (GTK_IS_CLIST (clist));
1971 /* return if out of bounds */
1972 if (row < 0 || row > (clist->rows - 1))
1975 was_visible = (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE);
1978 /* get the row we're going to delete */
1979 list = g_list_nth (clist->row_list, row);
1980 clist_row = list->data;
1982 /* if we're removing a selected row, we have to make sure
1983 * it's properly unselected, and then sync up the clist->selected
1984 * list to reflect the deincrimented indexies of rows after the
1986 if (clist_row->state == GTK_STATE_SELECTED)
1988 switch (clist->selection_mode)
1990 case GTK_SELECTION_SINGLE:
1991 case GTK_SELECTION_MULTIPLE:
1992 case GTK_SELECTION_EXTENDED:
1993 unselect_row (clist, row, -1, NULL);
1996 case GTK_SELECTION_BROWSE:
1997 select_row (clist, row - 1, -1, NULL);
2005 /* reset the row end pointer if we're removing at the
2006 * end of the list */
2007 if (row == clist->rows - 1)
2008 clist->row_list_end = list->prev;
2009 if (row >= clist->focus_row && clist->focus_row >=0)
2012 clist->row_list = g_list_remove (clist->row_list, clist_row);
2015 if (row < ROW_FROM_YPIXEL (clist, 0))
2016 clist->voffset += clist->row_height + CELL_SPACING;
2018 sync_selection (clist, row, SYNC_REMOVE);
2021 row_delete (clist, clist_row);
2023 /* redraw the row if it isn't frozen */
2024 if (!GTK_CLIST_FROZEN (clist))
2026 adjust_scrollbars (clist);
2029 draw_rows (clist, NULL);
2034 sync_selection (GtkCList * clist,
2041 if (mode == SYNC_INSERT)
2046 if (clist->focus_row >= row)
2048 clist->focus_row += d;
2049 if (clist->focus_row == -1 && clist->rows >= 1)
2050 clist->focus_row = 0;
2053 if (clist->selection_mode == GTK_SELECTION_BROWSE && clist->anchor != -1)
2054 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
2056 g_list_free (clist->undo_selection);
2057 g_list_free (clist->undo_unselection);
2058 clist->undo_selection = NULL;
2059 clist->undo_unselection = NULL;
2062 clist->drag_pos = -1;
2063 clist->undo_anchor = clist->focus_row;
2065 list = clist->selection;
2068 if (GPOINTER_TO_INT (list->data) >= row)
2069 list->data = ((gchar*) list->data) + d;
2075 gtk_clist_clear (GtkCList * clist)
2077 g_return_if_fail (clist != NULL);
2078 g_return_if_fail (GTK_IS_CLIST (clist));
2080 GTK_CLIST_CLASS_FW (clist)->clear (clist);
2084 real_clear (GtkCList * clist)
2086 GList *list, *free_list;
2088 g_return_if_fail (clist != NULL);
2089 g_return_if_fail (GTK_IS_CLIST (clist));
2091 /* free up the selection list */
2092 g_list_free (clist->selection);
2093 g_list_free (clist->undo_selection);
2094 g_list_free (clist->undo_unselection);
2096 clist->selection = NULL;
2097 clist->selection_end = NULL;
2098 clist->undo_selection = NULL;
2099 clist->undo_unselection = NULL;
2101 clist->focus_row = -1;
2103 clist->undo_anchor = -1;
2104 clist->anchor_state = GTK_STATE_SELECTED;
2105 clist->drag_pos = -1;
2107 /* remove all the rows */
2108 free_list = clist->row_list;
2109 clist->row_list = NULL;
2110 clist->row_list_end = NULL;
2112 for (list = free_list; list; list = list->next)
2113 row_delete (clist, GTK_CLIST_ROW (list));
2114 g_list_free (free_list);
2116 /* zero-out the scrollbars */
2117 if (clist->vscrollbar)
2119 GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0;
2120 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
2122 if (!GTK_CLIST_FROZEN (clist))
2123 gtk_clist_thaw (clist);
2128 gtk_clist_swap_rows (GtkCList * clist,
2133 GList *list, *link1, *link2;
2136 g_return_if_fail (clist != NULL);
2137 g_return_if_fail (GTK_IS_CLIST (clist));
2139 if (GTK_CLIST_AUTO_SORT (clist))
2142 if (row1 < 0 || row1 > (clist->rows - 1))
2145 if (row2 < 0 || row2 > (clist->rows - 1))
2148 first = MIN (row1, row2);
2149 last = MAX (row1, row2);
2151 link1 = g_list_nth (clist->row_list, first);
2152 link2 = g_list_nth (link1, row2 - row1);
2155 link1->data = link2->data;
2158 list = clist->selection;
2161 if (GPOINTER_TO_INT (list->data) == row1)
2162 list->data = GINT_TO_POINTER (row2);
2164 if (GPOINTER_TO_INT (list->data) == row2)
2165 list->data = GINT_TO_POINTER (row1);
2170 if (!GTK_CLIST_FROZEN (clist))
2172 if (gtk_clist_row_is_visible (clist, row1) != GTK_VISIBILITY_NONE)
2173 GTK_CLIST_CLASS_FW (clist)->draw_row
2174 (clist, NULL, row1, GTK_CLIST_ROW (link2));
2176 if (gtk_clist_row_is_visible (clist, row2) != GTK_VISIBILITY_NONE)
2177 GTK_CLIST_CLASS_FW (clist)->draw_row
2178 (clist, NULL, row2, GTK_CLIST_ROW (link1));
2183 gtk_clist_set_row_data (GtkCList * clist,
2187 gtk_clist_set_row_data_full (clist, row, data, NULL);
2191 gtk_clist_set_row_data_full (GtkCList * clist,
2194 GtkDestroyNotify destroy)
2196 GtkCListRow *clist_row;
2198 g_return_if_fail (clist != NULL);
2199 g_return_if_fail (GTK_IS_CLIST (clist));
2201 if (row < 0 || row > (clist->rows - 1))
2204 clist_row = (g_list_nth (clist->row_list, row))->data;
2205 clist_row->data = data;
2206 clist_row->destroy = destroy;
2210 gtk_clist_get_row_data (GtkCList * clist,
2213 GtkCListRow *clist_row;
2215 g_return_val_if_fail (clist != NULL, NULL);
2216 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2218 if (row < 0 || row > (clist->rows - 1))
2221 clist_row = (g_list_nth (clist->row_list, row))->data;
2222 return clist_row->data;
2226 gtk_clist_find_row_from_data (GtkCList * clist,
2232 g_return_val_if_fail (clist != NULL, -1);
2233 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
2235 if (clist->rows < 1)
2236 return -1; /* is this an optimization or just worthless? */
2238 for (n = 0, list = clist->row_list; list; n++, list = list->next)
2239 if (GTK_CLIST_ROW (list)->data == data)
2246 gtk_clist_select_row (GtkCList * clist,
2250 g_return_if_fail (clist != NULL);
2251 g_return_if_fail (GTK_IS_CLIST (clist));
2253 if (row < 0 || row >= clist->rows)
2256 if (column < -1 || column >= clist->columns)
2259 select_row (clist, row, column, NULL);
2263 gtk_clist_unselect_row (GtkCList * clist,
2267 g_return_if_fail (clist != NULL);
2268 g_return_if_fail (GTK_IS_CLIST (clist));
2270 if (row < 0 || row >= clist->rows)
2273 if (column < -1 || column >= clist->columns)
2276 unselect_row (clist, row, column, NULL);
2280 gtk_clist_row_is_visible (GtkCList * clist,
2285 g_return_val_if_fail (clist != NULL, 0);
2286 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
2288 if (row < 0 || row >= clist->rows)
2289 return GTK_VISIBILITY_NONE;
2291 if (clist->row_height == 0)
2292 return GTK_VISIBILITY_NONE;
2294 if (row < ROW_FROM_YPIXEL (clist, 0))
2295 return GTK_VISIBILITY_NONE;
2297 if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height))
2298 return GTK_VISIBILITY_NONE;
2300 top = ROW_TOP_YPIXEL (clist, row);
2303 || ((top + clist->row_height) >= clist->clist_window_height))
2304 return GTK_VISIBILITY_PARTIAL;
2306 return GTK_VISIBILITY_FULL;
2310 static GtkAdjustment*
2311 gtk_clist_get_vadjustment (GtkCList * clist)
2313 g_return_val_if_fail (clist != NULL, NULL);
2314 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2316 return gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
2319 static GtkAdjustment*
2320 gtk_clist_get_hadjustment (GtkCList * clist)
2322 g_return_val_if_fail (clist != NULL, NULL);
2323 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2325 return gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
2330 gtk_clist_set_policy (GtkCList * clist,
2331 GtkPolicyType vscrollbar_policy,
2332 GtkPolicyType hscrollbar_policy)
2334 g_return_if_fail (clist != NULL);
2335 g_return_if_fail (GTK_IS_CLIST (clist));
2337 if (clist->vscrollbar_policy != vscrollbar_policy)
2339 clist->vscrollbar_policy = vscrollbar_policy;
2341 if (GTK_WIDGET (clist)->parent)
2342 gtk_widget_queue_resize (GTK_WIDGET (clist));
2345 if (clist->hscrollbar_policy != hscrollbar_policy)
2347 clist->hscrollbar_policy = hscrollbar_policy;
2349 if (GTK_WIDGET (clist)->parent)
2350 gtk_widget_queue_resize (GTK_WIDGET (clist));
2355 gtk_clist_undo_selection (GtkCList *clist)
2357 g_return_if_fail (clist != NULL);
2358 g_return_if_fail (GTK_IS_CLIST (clist));
2360 if (clist->selection_mode == GTK_SELECTION_EXTENDED &&
2361 (clist->undo_selection || clist->undo_unselection))
2362 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNDO_SELECTION]);
2366 real_undo_selection (GtkCList *clist)
2370 g_return_if_fail (clist != NULL);
2371 g_return_if_fail (GTK_IS_CLIST (clist));
2373 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
2374 clist->selection_mode != GTK_SELECTION_EXTENDED)
2377 if (clist->anchor >= 0)
2378 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
2380 if (!(clist->undo_selection || clist->undo_unselection))
2382 gtk_clist_unselect_all (clist);
2386 for (work = clist->undo_selection; work; work = work->next)
2387 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
2388 GPOINTER_TO_INT (work->data), -1, NULL);
2390 for (work = clist->undo_unselection; work; work = work->next)
2391 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
2392 GPOINTER_TO_INT (work->data), -1, NULL);
2394 if (GTK_WIDGET_HAS_FOCUS (clist) && clist->focus_row != clist->undo_anchor)
2396 gtk_clist_draw_focus (GTK_WIDGET (clist));
2397 clist->focus_row = clist->undo_anchor;
2398 gtk_clist_draw_focus (GTK_WIDGET (clist));
2401 clist->focus_row = clist->undo_anchor;
2403 clist->undo_anchor = -1;
2405 g_list_free (clist->undo_selection);
2406 g_list_free (clist->undo_unselection);
2407 clist->undo_selection = NULL;
2408 clist->undo_unselection = NULL;
2410 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
2411 clist->clist_window_height)
2412 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
2413 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
2414 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
2420 * gtk_clist_finalize
2423 gtk_clist_destroy (GtkObject * object)
2428 g_return_if_fail (object != NULL);
2429 g_return_if_fail (GTK_IS_CLIST (object));
2431 clist = GTK_CLIST (object);
2433 /* freeze the list */
2434 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2436 /* get rid of all the rows */
2437 gtk_clist_clear (clist);
2439 /* Since we don't have a _remove method, unparent the children
2440 * instead of destroying them so the focus will be unset properly.
2441 * (For other containers, the _remove method takes care of the
2442 * unparent) The destroy will happen when the refcount drops
2446 /* destroy the scrollbars */
2447 if (clist->vscrollbar)
2449 gtk_widget_unparent (clist->vscrollbar);
2450 clist->vscrollbar = NULL;
2452 if (clist->hscrollbar)
2454 gtk_widget_unparent (clist->hscrollbar);
2455 clist->hscrollbar = NULL;
2460 gtk_timeout_remove (clist->htimer);
2465 gtk_timeout_remove (clist->vtimer);
2469 /* destroy the column buttons */
2470 for (i = 0; i < clist->columns; i++)
2471 if (clist->column[i].button)
2473 gtk_widget_unparent (clist->column[i].button);
2474 clist->column[i].button = NULL;
2477 if (GTK_OBJECT_CLASS (parent_class)->destroy)
2478 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2482 gtk_clist_finalize (GtkObject * object)
2486 g_return_if_fail (object != NULL);
2487 g_return_if_fail (GTK_IS_CLIST (object));
2489 clist = GTK_CLIST (object);
2491 columns_delete (clist);
2493 g_mem_chunk_destroy (clist->cell_mem_chunk);
2494 g_mem_chunk_destroy (clist->row_mem_chunk);
2496 if (GTK_OBJECT_CLASS (parent_class)->finalize)
2497 (*GTK_OBJECT_CLASS (parent_class)->finalize) (object);
2503 * gtk_clist_unrealize
2508 * gtk_clist_button_press
2509 * gtk_clist_button_release
2511 * gtk_clist_size_request
2512 * gtk_clist_size_allocate
2515 gtk_clist_realize (GtkWidget * widget)
2519 GdkWindowAttr attributes;
2520 gint attributes_mask;
2524 g_return_if_fail (widget != NULL);
2525 g_return_if_fail (GTK_IS_CLIST (widget));
2527 clist = GTK_CLIST (widget);
2529 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2531 add_style_data (clist);
2533 border_width = GTK_CONTAINER (widget)->border_width;
2535 attributes.window_type = GDK_WINDOW_CHILD;
2536 attributes.x = widget->allocation.x + border_width;
2537 attributes.y = widget->allocation.y + border_width;
2538 attributes.width = widget->allocation.width - border_width * 2;
2539 attributes.height = widget->allocation.height - border_width * 2;
2540 attributes.wclass = GDK_INPUT_OUTPUT;
2541 attributes.visual = gtk_widget_get_visual (widget);
2542 attributes.colormap = gtk_widget_get_colormap (widget);
2543 attributes.event_mask = gtk_widget_get_events (widget);
2544 attributes.event_mask |= (GDK_EXPOSURE_MASK |
2545 GDK_BUTTON_PRESS_MASK |
2546 GDK_BUTTON_RELEASE_MASK |
2547 GDK_KEY_PRESS_MASK |
2548 GDK_KEY_RELEASE_MASK);
2549 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2552 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
2553 gdk_window_set_user_data (widget->window, clist);
2555 widget->style = gtk_style_attach (widget->style, widget->window);
2557 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
2559 /* column-title window */
2561 attributes.x = clist->column_title_area.x;
2562 attributes.y = clist->column_title_area.y;
2563 attributes.width = clist->column_title_area.width;
2564 attributes.height = clist->column_title_area.height;
2566 clist->title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2567 gdk_window_set_user_data (clist->title_window, clist);
2569 gtk_style_set_background (widget->style, clist->title_window, GTK_STATE_SELECTED);
2570 gdk_window_show (clist->title_window);
2572 /* set things up so column buttons are drawn in title window */
2573 for (i = 0; i < clist->columns; i++)
2574 if (clist->column[i].button)
2575 gtk_widget_set_parent_window (clist->column[i].button, clist->title_window);
2578 attributes.x = clist->internal_allocation.x + widget->style->klass->xthickness;
2579 attributes.y = clist->internal_allocation.y + widget->style->klass->ythickness +
2580 clist->column_title_area.height;
2581 attributes.width = clist->clist_window_width;
2582 attributes.height = clist->clist_window_height;
2584 clist->clist_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2585 gdk_window_set_user_data (clist->clist_window, clist);
2587 gdk_window_set_background (clist->clist_window, &widget->style->bg[GTK_STATE_PRELIGHT]);
2588 gdk_window_show (clist->clist_window);
2589 gdk_window_get_size (clist->clist_window, &clist->clist_window_width,
2590 &clist->clist_window_height);
2592 /* create resize windows */
2593 attributes.wclass = GDK_INPUT_ONLY;
2594 attributes.event_mask = (GDK_BUTTON_PRESS_MASK |
2595 GDK_BUTTON_RELEASE_MASK |
2596 GDK_POINTER_MOTION_MASK |
2597 GDK_POINTER_MOTION_HINT_MASK |
2598 GDK_KEY_PRESS_MASK);
2599 attributes.cursor = clist->cursor_drag = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
2600 attributes_mask = GDK_WA_CURSOR;
2602 for (i = 0; i < clist->columns; i++)
2604 clist->column[i].window = gdk_window_new (clist->title_window, &attributes, attributes_mask);
2605 gdk_window_set_user_data (clist->column[i].window, clist);
2608 /* This is slightly less efficient than creating them with the
2609 * right size to begin with, but easier
2611 size_allocate_title_buttons (clist);
2614 clist->fg_gc = gdk_gc_new (widget->window);
2615 clist->bg_gc = gdk_gc_new (widget->window);
2617 /* We'll use this gc to do scrolling as well */
2618 gdk_gc_set_exposures (clist->fg_gc, TRUE);
2620 values.foreground = widget->style->white;
2621 values.function = GDK_XOR;
2622 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
2623 clist->xor_gc = gdk_gc_new_with_values (widget->window,
2631 gtk_clist_unrealize (GtkWidget * widget)
2636 g_return_if_fail (widget != NULL);
2637 g_return_if_fail (GTK_IS_CLIST (widget));
2639 clist = GTK_CLIST (widget);
2641 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2643 gdk_cursor_destroy (clist->cursor_drag);
2644 gdk_gc_destroy (clist->xor_gc);
2645 gdk_gc_destroy (clist->fg_gc);
2646 gdk_gc_destroy (clist->bg_gc);
2648 for (i = 0; i < clist->columns; i++)
2649 if (clist->column[i].window)
2651 gdk_window_set_user_data (clist->column[i].window, NULL);
2652 gdk_window_destroy (clist->column[i].window);
2653 clist->column[i].window = NULL;
2656 gdk_window_set_user_data (clist->clist_window, NULL);
2657 gdk_window_destroy (clist->clist_window);
2658 clist->clist_window = NULL;
2660 gdk_window_set_user_data (clist->title_window, NULL);
2661 gdk_window_destroy (clist->title_window);
2662 clist->title_window = NULL;
2664 clist->cursor_drag = NULL;
2665 clist->xor_gc = NULL;
2666 clist->fg_gc = NULL;
2667 clist->bg_gc = NULL;
2669 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
2670 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2674 gtk_clist_map (GtkWidget * widget)
2679 g_return_if_fail (widget != NULL);
2680 g_return_if_fail (GTK_IS_CLIST (widget));
2682 clist = GTK_CLIST (widget);
2684 if (!GTK_WIDGET_MAPPED (widget))
2686 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
2688 gdk_window_show (widget->window);
2689 gdk_window_show (clist->title_window);
2690 gdk_window_show (clist->clist_window);
2692 /* map column buttons */
2693 for (i = 0; i < clist->columns; i++)
2694 if (clist->column[i].button &&
2695 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
2696 !GTK_WIDGET_MAPPED (clist->column[i].button))
2697 gtk_widget_map (clist->column[i].button);
2699 /* map resize windows AFTER column buttons (above) */
2700 for (i = 0; i < clist->columns; i++)
2701 if (clist->column[i].window && clist->column[i].button)
2702 gdk_window_show (clist->column[i].window);
2704 /* map vscrollbars */
2705 if (GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
2706 !GTK_WIDGET_MAPPED (clist->vscrollbar))
2707 gtk_widget_map (clist->vscrollbar);
2709 if (GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
2710 !GTK_WIDGET_MAPPED (clist->hscrollbar))
2711 gtk_widget_map (clist->hscrollbar);
2713 /* unfreeze the list */
2714 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
2719 gtk_clist_unmap (GtkWidget * widget)
2724 g_return_if_fail (widget != NULL);
2725 g_return_if_fail (GTK_IS_CLIST (widget));
2727 clist = GTK_CLIST (widget);
2729 if (GTK_WIDGET_MAPPED (widget))
2731 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
2733 for (i = 0; i < clist->columns; i++)
2734 if (clist->column[i].window)
2735 gdk_window_hide (clist->column[i].window);
2737 gdk_window_hide (clist->clist_window);
2738 gdk_window_hide (clist->title_window);
2739 gdk_window_hide (widget->window);
2741 /* unmap scrollbars */
2742 if (GTK_WIDGET_MAPPED (clist->vscrollbar))
2743 gtk_widget_unmap (clist->vscrollbar);
2745 if (GTK_WIDGET_MAPPED (clist->hscrollbar))
2746 gtk_widget_unmap (clist->hscrollbar);
2748 /* unmap column buttons */
2749 for (i = 0; i < clist->columns; i++)
2750 if (clist->column[i].button &&
2751 GTK_WIDGET_MAPPED (clist->column[i].button))
2752 gtk_widget_unmap (clist->column[i].button);
2754 /* freeze the list */
2755 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2760 gtk_clist_draw (GtkWidget * widget,
2761 GdkRectangle * area)
2765 GdkRectangle child_area;
2768 g_return_if_fail (widget != NULL);
2769 g_return_if_fail (GTK_IS_CLIST (widget));
2770 g_return_if_fail (area != NULL);
2772 if (GTK_WIDGET_DRAWABLE (widget))
2774 clist = GTK_CLIST (widget);
2775 border_width = GTK_CONTAINER (widget)->border_width;
2777 gdk_window_clear_area (widget->window,
2778 area->x - border_width,
2779 area->y - border_width,
2780 area->width, area->height);
2782 /* draw list shadow/border */
2783 gtk_draw_shadow (widget->style, widget->window,
2784 GTK_STATE_NORMAL, clist->shadow_type,
2786 clist->clist_window_width + (2 * widget->style->klass->xthickness),
2787 clist->clist_window_height + (2 * widget->style->klass->ythickness) +
2788 clist->column_title_area.height);
2790 gdk_window_clear_area (clist->clist_window,
2793 draw_rows (clist, NULL);
2795 for (i = 0; i < clist->columns; i++)
2797 if (!clist->column[i].visible)
2799 if (gtk_widget_intersect (clist->column[i].button, area, &child_area))
2800 gtk_widget_draw (clist->column[i].button, &child_area);
2806 gtk_clist_expose (GtkWidget * widget,
2807 GdkEventExpose * event)
2811 g_return_val_if_fail (widget != NULL, FALSE);
2812 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2813 g_return_val_if_fail (event != NULL, FALSE);
2815 if (GTK_WIDGET_DRAWABLE (widget))
2817 clist = GTK_CLIST (widget);
2820 if (event->window == widget->window)
2821 gtk_draw_shadow (widget->style, widget->window,
2822 GTK_STATE_NORMAL, clist->shadow_type,
2824 clist->clist_window_width + (2 * widget->style->klass->xthickness),
2825 clist->clist_window_height + (2 * widget->style->klass->ythickness) +
2826 clist->column_title_area.height);
2828 /* exposure events on the list */
2829 if (event->window == clist->clist_window)
2830 draw_rows (clist, &event->area);
2837 gtk_clist_button_press (GtkWidget * widget,
2838 GdkEventButton * event)
2847 g_return_val_if_fail (widget != NULL, FALSE);
2848 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2849 g_return_val_if_fail (event != NULL, FALSE);
2851 clist = GTK_CLIST (widget);
2853 /* we don't handle button 2 and 3 */
2854 if (event->button != 1)
2857 /* selections on the list */
2858 if (event->window == clist->clist_window)
2863 if (get_selection_info (clist, x, y, &row, &column))
2865 gint old_row = clist->focus_row;
2867 if (clist->focus_row == -1)
2870 if (event->type == GDK_BUTTON_PRESS)
2872 GTK_CLIST_SET_FLAG (clist, CLIST_DRAG_SELECTION);
2873 gdk_pointer_grab (clist->clist_window, FALSE,
2874 GDK_POINTER_MOTION_HINT_MASK |
2875 GDK_BUTTON1_MOTION_MASK |
2876 GDK_BUTTON_RELEASE_MASK,
2877 NULL, NULL, event->time);
2878 gtk_grab_add (widget);
2880 else if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (widget))
2882 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
2883 gtk_grab_remove (widget);
2884 gdk_pointer_ungrab (event->time);
2887 if (GTK_CLIST_ADD_MODE (clist))
2889 GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
2890 if (GTK_WIDGET_HAS_FOCUS (widget))
2892 gtk_clist_draw_focus (widget);
2893 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2894 GDK_LINE_SOLID, 0, 0);
2895 clist->focus_row = row;
2896 gtk_clist_draw_focus (widget);
2900 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2901 GDK_LINE_SOLID, 0, 0);
2902 clist->focus_row = row;
2905 else if (row != clist->focus_row)
2907 if (GTK_WIDGET_HAS_FOCUS (widget))
2909 gtk_clist_draw_focus (widget);
2910 clist->focus_row = row;
2911 gtk_clist_draw_focus (widget);
2914 clist->focus_row = row;
2917 if (!GTK_WIDGET_HAS_FOCUS (widget))
2918 gtk_widget_grab_focus (widget);
2920 switch (clist->selection_mode)
2922 case GTK_SELECTION_SINGLE:
2923 case GTK_SELECTION_MULTIPLE:
2924 if (event->type != GDK_BUTTON_PRESS)
2925 select_row (clist, row, column, (GdkEvent *) event);
2927 clist->anchor = row;
2930 case GTK_SELECTION_BROWSE:
2931 select_row (clist, row, column, (GdkEvent *) event);
2934 case GTK_SELECTION_EXTENDED:
2935 if (event->type != GDK_BUTTON_PRESS)
2937 if (clist->anchor != -1)
2939 update_extended_selection (clist, clist->focus_row);
2940 GTK_CLIST_CLASS_FW (clist)->resync_selection
2941 (clist, (GdkEvent *) event);
2943 select_row (clist, row, column, (GdkEvent *) event);
2947 if (event->state & GDK_CONTROL_MASK)
2949 if (event->state & GDK_SHIFT_MASK)
2951 if (clist->anchor < 0)
2953 g_list_free (clist->undo_selection);
2954 g_list_free (clist->undo_unselection);
2955 clist->undo_selection = NULL;
2956 clist->undo_unselection = NULL;
2957 clist->anchor = old_row;
2958 clist->drag_pos = old_row;
2959 clist->undo_anchor = old_row;
2961 update_extended_selection (clist, clist->focus_row);
2965 if (clist->anchor == -1)
2966 set_anchor (clist, TRUE, row, old_row);
2968 update_extended_selection (clist, clist->focus_row);
2973 if (event->state & GDK_SHIFT_MASK)
2975 set_anchor (clist, FALSE, old_row, old_row);
2976 update_extended_selection (clist, clist->focus_row);
2980 if (clist->anchor == -1)
2981 set_anchor (clist, FALSE, row, old_row);
2983 update_extended_selection (clist, clist->focus_row);
2994 /* press on resize windows */
2995 for (i = 0; i < clist->columns; i++)
2996 if (clist->column[i].resizeable && clist->column[i].window &&
2997 event->window == clist->column[i].window)
2999 gdk_pointer_grab (clist->column[i].window, FALSE,
3000 GDK_POINTER_MOTION_HINT_MASK |
3001 GDK_BUTTON1_MOTION_MASK |
3002 GDK_BUTTON_RELEASE_MASK,
3003 NULL, NULL, event->time);
3004 gtk_grab_add (widget);
3005 GTK_CLIST_SET_FLAG (clist, CLIST_IN_DRAG);
3007 if (!GTK_WIDGET_HAS_FOCUS (widget))
3008 gtk_widget_grab_focus (widget);
3010 clist->drag_pos = i;
3011 clist->x_drag = (COLUMN_LEFT_XPIXEL(clist, i) + COLUMN_INSET +
3012 clist->column[i].area.width + CELL_SPACING);
3014 if (GTK_CLIST_ADD_MODE (clist))
3015 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
3016 draw_xor_line (clist);
3024 gtk_clist_button_release (GtkWidget * widget,
3025 GdkEventButton * event)
3029 g_return_val_if_fail (widget != NULL, FALSE);
3030 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
3031 g_return_val_if_fail (event != NULL, FALSE);
3033 clist = GTK_CLIST (widget);
3035 /* we don't handle button 2 and 3 */
3036 if (event->button != 1)
3039 /* release on resize windows */
3040 if (GTK_CLIST_IN_DRAG (clist))
3046 i = clist->drag_pos;
3047 clist->drag_pos = -1;
3049 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
3050 gtk_widget_get_pointer (widget, &x, NULL);
3051 gtk_grab_remove (widget);
3052 gdk_pointer_ungrab (event->time);
3054 if (clist->x_drag >= 0)
3055 draw_xor_line (clist);
3057 if (GTK_CLIST_ADD_MODE (clist))
3059 gdk_gc_set_line_attributes (clist->xor_gc, 1,
3060 GDK_LINE_ON_OFF_DASH, 0, 0);
3061 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
3064 width = new_column_width (clist, i, &x);
3065 resize_column (clist, i, width);
3069 if (GTK_CLIST_DRAG_SELECTION (clist))
3074 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
3075 gtk_grab_remove (widget);
3076 gdk_pointer_ungrab (event->time);
3079 gtk_timeout_remove (clist->htimer);
3084 gtk_timeout_remove (clist->vtimer);
3087 switch (clist->selection_mode)
3089 case GTK_SELECTION_EXTENDED:
3090 if (!(event->state & GDK_SHIFT_MASK) ||
3091 event->x < 0 || event->x >= clist->clist_window_width ||
3092 event->y < 0 || event->y >= clist->clist_window_height)
3093 GTK_CLIST_CLASS_FW (clist)->resync_selection
3094 (clist, (GdkEvent *) event);
3097 case GTK_SELECTION_SINGLE:
3098 case GTK_SELECTION_MULTIPLE:
3099 if (get_selection_info (clist, event->x, event->y, &row, &column))
3101 if (clist->anchor == clist->focus_row)
3102 toggle_row (clist, row, column, (GdkEvent *) event);
3116 horizontal_timeout (GtkCList *clist)
3119 GdkEventMotion event;
3120 GdkModifierType mask;
3122 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
3125 gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
3132 gtk_clist_motion (GTK_WIDGET (clist), &event);
3138 vertical_timeout (GtkCList *clist)
3141 GdkEventMotion event;
3142 GdkModifierType mask;
3144 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
3147 gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
3154 gtk_clist_motion (GTK_WIDGET (clist), &event);
3160 move_vertical (GtkCList *clist,
3167 adj = GTK_RANGE (clist->vscrollbar)->adjustment;
3169 y = ROW_TOP_YPIXEL (clist, row) - clist->voffset;
3171 y = y - align * (clist->clist_window_height - clist->row_height)
3172 + (2 * align - 1) * CELL_SPACING;
3174 if (y + adj->page_size > adj->upper)
3175 adj->value = adj->upper - adj->page_size;
3179 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
3183 move_horizontal (GtkCList *clist,
3189 adj = GTK_RANGE (clist->hscrollbar)->adjustment;
3193 upper = adj->upper - adj->page_size;
3194 adj->value = MIN (adj->value, upper);
3195 adj->value = MAX (adj->value, 0.0);
3197 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
3201 gtk_clist_motion (GtkWidget * widget,
3202 GdkEventMotion * event)
3210 g_return_val_if_fail (widget != NULL, FALSE);
3211 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
3213 clist = GTK_CLIST (widget);
3214 if (!(gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)))
3217 if (GTK_CLIST_IN_DRAG (clist))
3219 if (event->is_hint || event->window != widget->window)
3220 gtk_widget_get_pointer (widget, &x, NULL);
3224 new_width = new_column_width (clist, clist->drag_pos, &x);
3225 if (x != clist->x_drag)
3227 /* x_drag < 0 indicates that the xor line is already invisible */
3228 if (clist->x_drag >= 0)
3229 draw_xor_line (clist);
3233 if (clist->x_drag >= 0)
3234 draw_xor_line (clist);
3237 if (new_width <= MAX (COLUMN_MIN_WIDTH + 1,
3238 clist->column[clist->drag_pos].min_width + 1))
3240 if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) < 0 && x < 0)
3241 gtk_clist_moveto (clist, -1, clist->drag_pos, 0, 0);
3244 if (clist->column[clist->drag_pos].max_width >= COLUMN_MIN_WIDTH &&
3245 new_width >= clist->column[clist->drag_pos].max_width)
3247 if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) + new_width >
3248 clist->clist_window_width && x < 0)
3249 move_horizontal (clist,
3250 COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) +
3251 new_width - clist->clist_window_width +
3252 COLUMN_INSET + CELL_SPACING);
3257 if (event->is_hint || event->window != clist->clist_window)
3258 gdk_window_get_pointer (clist->clist_window, &x, &y, NULL);
3260 /* horizontal autoscrolling */
3261 if (LIST_WIDTH (clist) > clist->clist_window_width &&
3262 (x < 0 || x >= clist->clist_window_width))
3267 clist->htimer = gtk_timeout_add
3268 (SCROLL_TIME, (GtkFunction) horizontal_timeout, clist);
3270 if (!((x < 0 && GTK_RANGE (clist->hscrollbar)->adjustment->value == 0) ||
3271 (x >= clist->clist_window_width &&
3272 GTK_RANGE (clist->hscrollbar)->adjustment->value ==
3273 LIST_WIDTH (clist) - clist->clist_window_width)))
3276 move_horizontal (clist, -1 + (x/2));
3278 move_horizontal (clist, 1 + (x - clist->clist_window_width) / 2);
3282 if (GTK_CLIST_IN_DRAG (clist))
3285 /* vertical autoscrolling */
3286 row = ROW_FROM_YPIXEL (clist, y);
3288 /* don't scroll on last pixel row if it's a cell spacing */
3289 if (y == clist->clist_window_height-1 &&
3290 y == ROW_TOP_YPIXEL (clist, row-1) + clist->row_height)
3293 if (LIST_HEIGHT (clist) > clist->clist_window_height &&
3294 (y < 0 || y >= clist->clist_window_height))
3299 clist->vtimer = gtk_timeout_add (SCROLL_TIME,
3300 (GtkFunction) vertical_timeout, clist);
3302 if (GTK_CLIST_DRAG_SELECTION (clist))
3304 if ((y < 0 && clist->focus_row == 0) ||
3305 (y >= clist->clist_window_height &&
3306 clist->focus_row == clist->rows-1))
3311 row = CLAMP (row, 0, clist->rows - 1);
3313 if (GTK_CLIST_DRAG_SELECTION (clist))
3315 if (row == clist->focus_row)
3318 gtk_clist_draw_focus (widget);
3319 clist->focus_row = row;
3320 gtk_clist_draw_focus (widget);
3322 switch (clist->selection_mode)
3324 case GTK_SELECTION_BROWSE:
3325 select_row (clist, clist->focus_row, - 1, (GdkEvent *) event);
3328 case GTK_SELECTION_EXTENDED:
3329 update_extended_selection (clist, clist->focus_row);
3337 if (ROW_TOP_YPIXEL(clist, row) < 0)
3338 move_vertical (clist, row, 0);
3339 else if (ROW_TOP_YPIXEL(clist, row) + clist->row_height >
3340 clist->clist_window_height)
3341 move_vertical (clist, row, 1);
3347 gtk_clist_size_request (GtkWidget * widget,
3348 GtkRequisition * requisition)
3353 g_return_if_fail (widget != NULL);
3354 g_return_if_fail (GTK_IS_CLIST (widget));
3355 g_return_if_fail (requisition != NULL);
3357 clist = GTK_CLIST (widget);
3359 add_style_data (clist);
3361 requisition->width = 0;
3362 requisition->height = 0;
3364 /* compute the size of the column title (title) area */
3365 clist->column_title_area.height = 0;
3366 if (GTK_CLIST_SHOW_TITLES (clist))
3367 for (i = 0; i < clist->columns; i++)
3368 if (clist->column[i].button)
3370 gtk_widget_size_request (clist->column[i].button,
3371 &clist->column[i].button->requisition);
3372 clist->column_title_area.height =
3373 MAX (clist->column_title_area.height,
3374 clist->column[i].button->requisition.height);
3376 requisition->height += clist->column_title_area.height;
3378 /* add the vscrollbar space */
3379 if ((clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
3380 GTK_WIDGET_VISIBLE (clist->vscrollbar))
3382 gtk_widget_size_request (clist->vscrollbar,
3383 &clist->vscrollbar->requisition);
3385 requisition->width += (clist->vscrollbar->requisition.width +
3386 SCROLLBAR_SPACING (clist));
3387 requisition->height = MAX (requisition->height,
3388 clist->vscrollbar->requisition.height);
3391 /* add the hscrollbar space */
3392 if ((clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
3393 GTK_WIDGET_VISIBLE (clist->hscrollbar))
3395 gtk_widget_size_request (clist->hscrollbar,
3396 &clist->hscrollbar->requisition);
3398 requisition->height += (clist->hscrollbar->requisition.height +
3399 SCROLLBAR_SPACING (clist));
3400 requisition->width = MAX (clist->hscrollbar->requisition.width,
3401 requisition->width -
3402 clist->vscrollbar->requisition.width);
3406 requisition->width += (widget->style->klass->xthickness * 2 +
3407 GTK_CONTAINER (widget)->border_width * 2);
3408 requisition->height += (widget->style->klass->ythickness * 2 +
3409 GTK_CONTAINER (widget)->border_width * 2);
3413 gtk_clist_size_allocate (GtkWidget * widget,
3414 GtkAllocation * allocation)
3417 GtkAllocation clist_allocation;
3418 GtkAllocation child_allocation;
3419 gint i, vscrollbar_vis, hscrollbar_vis;
3422 g_return_if_fail (widget != NULL);
3423 g_return_if_fail (GTK_IS_CLIST (widget));
3424 g_return_if_fail (allocation != NULL);
3426 clist = GTK_CLIST (widget);
3427 widget->allocation = *allocation;
3428 border_width = GTK_CONTAINER (widget)->border_width;
3430 if (GTK_WIDGET_REALIZED (widget))
3432 gdk_window_move_resize (widget->window,
3433 allocation->x + border_width,
3434 allocation->y + border_width,
3435 allocation->width - border_width * 2,
3436 allocation->height - border_width * 2);
3439 /* use internal allocation structure for all the math
3440 * because it's easier than always subtracting the container
3442 clist->internal_allocation.x = 0;
3443 clist->internal_allocation.y = 0;
3444 clist->internal_allocation.width = MAX (1, allocation->width -
3446 clist->internal_allocation.height = MAX (1, allocation->height -
3449 /* allocate clist window assuming no scrollbars */
3450 clist_allocation.x = (clist->internal_allocation.x +
3451 widget->style->klass->xthickness);
3452 clist_allocation.y = (clist->internal_allocation.y +
3453 widget->style->klass->ythickness +
3454 clist->column_title_area.height);
3455 clist_allocation.width = MAX (1, clist->internal_allocation.width -
3456 (2 * widget->style->klass->xthickness));
3457 clist_allocation.height = MAX (1, clist->internal_allocation.height -
3458 (2 * widget->style->klass->ythickness) -
3459 clist->column_title_area.height);
3462 * here's where we decide to show/not show the scrollbars
3467 for (i = 0; i <= 1; i++)
3469 if (LIST_HEIGHT (clist) <= clist_allocation.height &&
3470 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
3474 else if (!vscrollbar_vis)
3477 clist_allocation.width = MAX (1, clist_allocation.width -
3478 (clist->vscrollbar->requisition.width +
3479 SCROLLBAR_SPACING (clist)));
3482 if (LIST_WIDTH (clist) <= clist_allocation.width &&
3483 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
3487 else if (!hscrollbar_vis)
3490 clist_allocation.height = MAX (1, clist_allocation.height -
3491 (clist->hscrollbar->requisition.height
3492 + SCROLLBAR_SPACING (clist)));
3496 clist->clist_window_width = clist_allocation.width;
3497 clist->clist_window_height = clist_allocation.height;
3499 if (GTK_WIDGET_REALIZED (widget))
3501 gdk_window_move_resize (clist->clist_window,
3504 clist_allocation.width,
3505 clist_allocation.height);
3508 /* position the window which holds the column title buttons */
3509 clist->column_title_area.x = widget->style->klass->xthickness;
3510 clist->column_title_area.y = widget->style->klass->ythickness;
3511 clist->column_title_area.width = clist_allocation.width;
3513 if (GTK_WIDGET_REALIZED (widget))
3515 gdk_window_move_resize (clist->title_window,
3516 clist->column_title_area.x,
3517 clist->column_title_area.y,
3518 clist->column_title_area.width,
3519 clist->column_title_area.height);
3522 /* column button allocation */
3523 size_allocate_columns (clist);
3524 size_allocate_title_buttons (clist);
3526 adjust_scrollbars (clist);
3528 /* allocate the vscrollbar */
3531 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
3532 gtk_widget_show (clist->vscrollbar);
3534 child_allocation.x = (clist->internal_allocation.x +
3535 clist->internal_allocation.width -
3536 clist->vscrollbar->requisition.width);
3537 child_allocation.y = clist->internal_allocation.y;
3538 child_allocation.width = clist->vscrollbar->requisition.width;
3539 child_allocation.height = MAX (1, clist->internal_allocation.height -
3541 (clist->hscrollbar->requisition.height +
3542 SCROLLBAR_SPACING (clist)) : 0));
3543 gtk_widget_size_allocate (clist->vscrollbar, &child_allocation);
3547 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
3548 gtk_widget_hide (clist->vscrollbar);
3553 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
3554 gtk_widget_show (clist->hscrollbar);
3556 child_allocation.x = clist->internal_allocation.x;
3557 child_allocation.y = (clist->internal_allocation.y +
3558 clist->internal_allocation.height -
3559 clist->hscrollbar->requisition.height);
3560 child_allocation.width = MAX (1, clist->internal_allocation.width -
3562 (clist->vscrollbar->requisition.width +
3563 SCROLLBAR_SPACING (clist)) : 0));
3564 child_allocation.height = clist->hscrollbar->requisition.height;
3566 gtk_widget_size_allocate (clist->hscrollbar, &child_allocation);
3570 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
3571 gtk_widget_hide (clist->hscrollbar);
3574 /* set the vscrollbar adjustments */
3575 adjust_scrollbars (clist);
3583 gtk_clist_forall (GtkContainer *container,
3584 gboolean include_internals,
3585 GtkCallback callback,
3586 gpointer callback_data)
3590 g_return_if_fail (container != NULL);
3591 g_return_if_fail (GTK_IS_CLIST (container));
3592 g_return_if_fail (callback != NULL);
3594 clist = GTK_CLIST (container);
3596 if (include_internals)
3600 /* callback for the column buttons */
3601 for (i = 0; i < clist->columns; i++)
3602 if (clist->column[i].button)
3603 (*callback) (clist->column[i].button, callback_data);
3605 /* callbacks for the scrollbars */
3606 if (clist->vscrollbar)
3607 (*callback) (clist->vscrollbar, callback_data);
3608 if (clist->hscrollbar)
3609 (*callback) (clist->hscrollbar, callback_data);
3619 draw_row (GtkCList * clist,
3620 GdkRectangle * area,
3622 GtkCListRow * clist_row)
3625 GdkGC *fg_gc, *bg_gc;
3626 GdkRectangle row_rectangle, cell_rectangle, clip_rectangle, intersect_rectangle,
3628 gint i, offset = 0, width, height, pixmap_width = 0;
3629 gint xsrc, ysrc, xdest, ydest;
3631 g_return_if_fail (clist != NULL);
3633 /* bail now if we arn't drawable yet */
3634 if (!GTK_WIDGET_DRAWABLE (clist))
3637 if (row < 0 || row >= clist->rows)
3640 widget = GTK_WIDGET (clist);
3642 /* if the function is passed the pointer to the row instead of null,
3643 * it avoids this expensive lookup */
3645 clist_row = (g_list_nth (clist->row_list, row))->data;
3647 /* rectangle of the entire row */
3648 row_rectangle.x = 0;
3649 row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
3650 row_rectangle.width = clist->clist_window_width;
3651 row_rectangle.height = clist->row_height;
3653 /* rectangle of the cell spacing above the row */
3654 cell_rectangle.x = 0;
3655 cell_rectangle.y = row_rectangle.y - CELL_SPACING;
3656 cell_rectangle.width = row_rectangle.width;
3657 cell_rectangle.height = CELL_SPACING;
3659 /* rectangle used to clip drawing operations, it's y and height
3660 * positions only need to be set once, so we set them once here.
3661 * the x and width are set withing the drawing loop below once per
3663 clip_rectangle.y = row_rectangle.y;
3664 clip_rectangle.height = row_rectangle.height;
3666 /* select GC for background rectangle */
3667 if (clist_row->state == GTK_STATE_SELECTED)
3669 fg_gc = widget->style->fg_gc[GTK_STATE_SELECTED];
3670 bg_gc = widget->style->bg_gc[GTK_STATE_SELECTED];
3674 if (clist_row->fg_set)
3676 gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
3677 fg_gc = clist->fg_gc;
3680 fg_gc = widget->style->fg_gc[GTK_STATE_NORMAL];
3682 if (clist_row->bg_set)
3684 gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
3685 bg_gc = clist->bg_gc;
3688 bg_gc = widget->style->bg_gc[GTK_STATE_PRELIGHT];
3691 /* draw the cell borders and background */
3694 if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
3695 gdk_draw_rectangle (clist->clist_window,
3696 widget->style->base_gc[GTK_STATE_NORMAL],
3698 intersect_rectangle.x,
3699 intersect_rectangle.y,
3700 intersect_rectangle.width,
3701 intersect_rectangle.height);
3703 /* the last row has to clear it's bottom cell spacing too */
3704 if (clist_row == clist->row_list_end->data)
3706 cell_rectangle.y += clist->row_height + CELL_SPACING;
3708 if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
3709 gdk_draw_rectangle (clist->clist_window,
3710 widget->style->base_gc[GTK_STATE_NORMAL],
3712 intersect_rectangle.x,
3713 intersect_rectangle.y,
3714 intersect_rectangle.width,
3715 intersect_rectangle.height);
3718 if (!gdk_rectangle_intersect (area, &row_rectangle, &intersect_rectangle))
3721 if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
3722 gdk_draw_rectangle (clist->clist_window,
3725 intersect_rectangle.x,
3726 intersect_rectangle.y,
3727 intersect_rectangle.width,
3728 intersect_rectangle.height);
3730 gdk_window_clear_area (clist->clist_window,
3731 intersect_rectangle.x,
3732 intersect_rectangle.y,
3733 intersect_rectangle.width,
3734 intersect_rectangle.height);
3738 gdk_draw_rectangle (clist->clist_window,
3739 widget->style->base_gc[GTK_STATE_NORMAL],
3743 cell_rectangle.width,
3744 cell_rectangle.height);
3746 /* the last row has to clear it's bottom cell spacing too */
3747 if (clist_row == clist->row_list_end->data)
3749 cell_rectangle.y += clist->row_height + CELL_SPACING;
3751 gdk_draw_rectangle (clist->clist_window,
3752 widget->style->base_gc[GTK_STATE_NORMAL],
3756 cell_rectangle.width,
3757 cell_rectangle.height);
3760 if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
3761 gdk_draw_rectangle (clist->clist_window,
3766 row_rectangle.width,
3767 row_rectangle.height);
3769 gdk_window_clear_area (clist->clist_window,
3772 row_rectangle.width,
3773 row_rectangle.height);
3776 /* iterate and draw all the columns (row cells) and draw their contents */
3777 for (i = 0; i < clist->columns; i++)
3779 if (!clist->column[i].visible)
3782 clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
3783 clip_rectangle.width = clist->column[i].area.width;
3785 /* calculate clipping region clipping region */
3788 rect = &clip_rectangle;
3792 if (!gdk_rectangle_intersect (area, &clip_rectangle,
3793 &intersect_rectangle))
3795 rect = &intersect_rectangle;
3798 /* calculate real width for column justification */
3799 switch (clist_row->cell[i].type)
3801 case GTK_CELL_EMPTY:
3806 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
3807 GTK_CELL_TEXT (clist_row->cell[i])->text);
3810 case GTK_CELL_PIXMAP:
3811 gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, &width, &height);
3812 pixmap_width = width;
3815 case GTK_CELL_PIXTEXT:
3816 gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, &width, &height);
3817 pixmap_width = width;
3818 width += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
3819 width += gdk_string_width (GTK_WIDGET (clist)->style->font,
3820 GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
3823 case GTK_CELL_WIDGET:
3833 switch (clist->column[i].justification)
3835 case GTK_JUSTIFY_LEFT:
3836 offset = clip_rectangle.x;
3839 case GTK_JUSTIFY_RIGHT:
3840 offset = (clip_rectangle.x + clip_rectangle.width) - width;
3843 case GTK_JUSTIFY_CENTER:
3844 offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
3847 case GTK_JUSTIFY_FILL:
3848 offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
3856 /* Draw Text or Pixmap */
3857 switch (clist_row->cell[i].type)
3859 case GTK_CELL_EMPTY:
3864 gdk_gc_set_clip_rectangle (fg_gc, rect);
3866 gdk_draw_string (clist->clist_window,
3867 widget->style->font,
3869 offset + clist_row->cell[i].horizontal,
3870 row_rectangle.y + clist->row_center_offset +
3871 clist_row->cell[i].vertical,
3872 GTK_CELL_TEXT (clist_row->cell[i])->text);
3874 gdk_gc_set_clip_rectangle (fg_gc, NULL);
3877 case GTK_CELL_PIXMAP:
3880 xdest = offset + clist_row->cell[i].horizontal;
3881 ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
3882 clist_row->cell[i].vertical;
3884 if (xdest < clip_rectangle.x)
3886 xsrc = clip_rectangle.x - xdest;
3887 pixmap_width -= xsrc;
3888 xdest = clip_rectangle.x;
3891 if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width)
3892 pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest;
3894 if (ydest < clip_rectangle.y)
3896 ysrc = clip_rectangle.y - ydest;
3898 ydest = clip_rectangle.y;
3901 if (ydest + height > clip_rectangle.y + clip_rectangle.height)
3902 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
3904 if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
3906 gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXMAP (clist_row->cell[i])->mask);
3907 gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
3909 gdk_draw_pixmap (clist->clist_window,
3911 GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
3914 pixmap_width, height);
3916 if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
3918 gdk_gc_set_clip_origin (fg_gc, 0, 0);
3919 gdk_gc_set_clip_mask (fg_gc, NULL);
3923 case GTK_CELL_PIXTEXT:
3924 /* draw the pixmap */
3927 xdest = offset + clist_row->cell[i].horizontal;
3928 ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
3929 clist_row->cell[i].vertical;
3931 if (xdest < clip_rectangle.x)
3933 xsrc = clip_rectangle.x - xdest;
3934 pixmap_width -= xsrc;
3935 xdest = clip_rectangle.x;
3938 if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width)
3939 pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest;
3941 if (ydest < clip_rectangle.y)
3943 ysrc = clip_rectangle.y - ydest;
3945 ydest = clip_rectangle.y;
3948 if (ydest + height > clip_rectangle.y + clip_rectangle.height)
3949 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
3951 if (GTK_CELL_PIXTEXT (clist_row->cell[i])->mask)
3953 gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXTEXT (clist_row->cell[i])->mask);
3954 gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
3957 gdk_draw_pixmap (clist->clist_window,
3959 GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
3963 pixmap_width, height);
3965 gdk_gc_set_clip_origin (fg_gc, 0, 0);
3967 offset += pixmap_width + GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
3969 /* draw the string */
3970 gdk_gc_set_clip_rectangle (fg_gc, rect);
3972 gdk_draw_string (clist->clist_window,
3973 widget->style->font,
3975 offset + clist_row->cell[i].horizontal,
3976 row_rectangle.y + clist->row_center_offset +
3977 clist_row->cell[i].vertical,
3978 GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
3980 gdk_gc_set_clip_rectangle (fg_gc, NULL);
3983 case GTK_CELL_WIDGET:
3993 if (clist->focus_row == row && GTK_WIDGET_HAS_FOCUS (widget))
3997 if (gdk_rectangle_intersect (area, &row_rectangle,
3998 &intersect_rectangle))
4000 gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle);
4001 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
4002 row_rectangle.x, row_rectangle.y,
4003 row_rectangle.width - 1,
4004 row_rectangle.height - 1);
4005 gdk_gc_set_clip_rectangle (clist->xor_gc, NULL);
4009 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
4010 row_rectangle.x, row_rectangle.y,
4011 row_rectangle.width - 1, row_rectangle.height - 1);
4016 draw_rows (GtkCList * clist,
4017 GdkRectangle * area)
4020 GtkCListRow *clist_row;
4021 int i, first_row, last_row;
4023 g_return_if_fail (clist != NULL);
4024 g_return_if_fail (GTK_IS_CLIST (clist));
4026 if (clist->row_height == 0 ||
4027 !GTK_WIDGET_DRAWABLE (clist))
4032 first_row = ROW_FROM_YPIXEL (clist, area->y);
4033 last_row = ROW_FROM_YPIXEL (clist, area->y + area->height);
4037 first_row = ROW_FROM_YPIXEL (clist, 0);
4038 last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height);
4041 /* this is a small special case which exposes the bottom cell line
4042 * on the last row -- it might go away if I change the wall the cell spacings
4044 if (clist->rows == first_row)
4047 list = g_list_nth (clist->row_list, first_row);
4051 clist_row = list->data;
4057 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, area, i, clist_row);
4062 gdk_window_clear_area (clist->clist_window, 0, ROW_TOP_YPIXEL (clist, i), -1, -1);
4067 * size_allocate_title_buttons
4068 * size_allocate_columns
4071 size_allocate_title_buttons (GtkCList * clist)
4073 GtkAllocation button_allocation;
4075 gint last_button = 0;
4078 if (!GTK_WIDGET_REALIZED (clist))
4081 button_allocation.x = clist->hoffset;
4082 button_allocation.y = 0;
4083 button_allocation.width = 0;
4084 button_allocation.height = clist->column_title_area.height;
4086 /* find last visible column */
4087 for (last_column = clist->columns - 1; last_column >= 0; last_column--)
4088 if (clist->column[last_column].visible)
4091 for (i = 0; i < last_column; i++)
4093 if (!clist->column[i].visible)
4095 last_button = i + 1;
4096 gdk_window_hide (clist->column[i].window);
4100 button_allocation.width += (clist->column[i].area.width +
4101 CELL_SPACING + 2 * COLUMN_INSET);
4103 if (!clist->column[i + 1].button)
4105 gdk_window_hide (clist->column[i].window);
4109 gtk_widget_size_allocate (clist->column[last_button].button,
4110 &button_allocation);
4111 button_allocation.x += button_allocation.width;
4112 button_allocation.width = 0;
4114 if (clist->column[last_button].resizeable)
4116 gdk_window_show (clist->column[last_button].window);
4117 gdk_window_move_resize (clist->column[last_button].window,
4118 button_allocation.x - (DRAG_WIDTH / 2),
4120 clist->column_title_area.height);
4123 gdk_window_hide (clist->column[last_button].window);
4125 last_button = i + 1;
4128 button_allocation.width += (clist->column[last_column].area.width +
4129 2 * (CELL_SPACING + COLUMN_INSET));
4130 gtk_widget_size_allocate (clist->column[last_button].button,
4131 &button_allocation);
4133 if (clist->column[last_button].resizeable)
4135 button_allocation.x += button_allocation.width;
4137 gdk_window_show (clist->column[last_button].window);
4138 gdk_window_move_resize (clist->column[last_button].window,
4139 button_allocation.x - (DRAG_WIDTH / 2),
4140 0, DRAG_WIDTH, clist->column_title_area.height);
4143 gdk_window_hide (clist->column[last_button].window);
4147 size_allocate_columns (GtkCList * clist)
4149 gint xoffset = CELL_SPACING + COLUMN_INSET;
4154 /* find last visible column and calculate correct column width */
4155 for (last_column = clist->columns - 1;
4156 last_column >= 0 && !clist->column[last_column].visible; last_column--);
4158 if (last_column < 0)
4161 for (i = 0; i < last_column; i++)
4163 if (!clist->column[i].visible)
4165 clist->column[i].area.x = xoffset;
4166 clist->column[i].area.width = clist->column[i].width;
4167 xoffset += clist->column[i].width + CELL_SPACING + (2 * COLUMN_INSET);
4170 if (clist->column[i].width_set)
4171 width = clist->column[i].width;
4172 else if (clist->column[i].title)
4173 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
4174 clist->column[i].title);
4176 clist->column[i].area.x = xoffset;
4177 clist->column[i].area.width = MAX (width,
4178 clist->clist_window_width - xoffset -
4179 (CELL_SPACING + COLUMN_INSET));
4187 * get_selection_info
4190 toggle_row (GtkCList * clist,
4195 GtkCListRow *clist_row;
4197 switch (clist->selection_mode)
4199 case GTK_SELECTION_EXTENDED:
4200 case GTK_SELECTION_MULTIPLE:
4201 case GTK_SELECTION_SINGLE:
4203 clist_row = g_list_nth (clist->row_list, row)->data;
4204 if (clist_row->state == GTK_STATE_SELECTED)
4206 unselect_row (clist, row, column, event);
4210 case GTK_SELECTION_BROWSE:
4211 select_row (clist, row, column, event);
4217 select_row (GtkCList * clist,
4222 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
4223 row, column, event);
4227 unselect_row (GtkCList * clist,
4232 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
4233 row, column, event);
4237 real_select_row (GtkCList * clist,
4242 GtkCListRow *clist_row;
4245 gboolean row_selected;
4247 g_return_if_fail (clist != NULL);
4248 g_return_if_fail (GTK_IS_CLIST (clist));
4250 if (row < 0 || row > (clist->rows - 1))
4253 switch (clist->selection_mode)
4255 case GTK_SELECTION_SINGLE:
4256 case GTK_SELECTION_BROWSE:
4258 row_selected = FALSE;
4259 list = clist->selection;
4263 sel_row = GPOINTER_TO_INT (list->data);
4267 row_selected = TRUE;
4269 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
4270 sel_row, column, event);
4280 clist_row = (g_list_nth (clist->row_list, row))->data;
4282 if (clist_row->state != GTK_STATE_NORMAL || !clist_row->selectable)
4285 clist_row->state = GTK_STATE_SELECTED;
4286 if (!clist->selection)
4288 clist->selection = g_list_append (clist->selection,
4289 GINT_TO_POINTER (row));
4290 clist->selection_end = clist->selection;
4293 clist->selection_end =
4294 g_list_append (clist->selection_end, GINT_TO_POINTER (row))->next;
4296 if (!GTK_CLIST_FROZEN (clist)
4297 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
4298 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
4302 real_unselect_row (GtkCList * clist,
4307 GtkCListRow *clist_row;
4309 g_return_if_fail (clist != NULL);
4310 g_return_if_fail (GTK_IS_CLIST (clist));
4312 if (row < 0 || row > (clist->rows - 1))
4315 clist_row = (g_list_nth (clist->row_list, row))->data;
4317 if (clist_row->state == GTK_STATE_SELECTED)
4319 clist_row->state = GTK_STATE_NORMAL;
4321 if (clist->selection_end &&
4322 clist->selection_end->data == GINT_TO_POINTER (row))
4323 clist->selection_end = clist->selection_end->prev;
4325 clist->selection = g_list_remove (clist->selection,
4326 GINT_TO_POINTER (row));
4328 if (!GTK_CLIST_FROZEN (clist)
4329 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
4330 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
4335 get_selection_info (GtkCList * clist,
4343 g_return_val_if_fail (clist != NULL, 0);
4344 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
4346 /* bounds checking, return false if the user clicked
4347 * on a blank area */
4348 trow = ROW_FROM_YPIXEL (clist, y);
4349 if (trow >= clist->rows)
4355 tcol = COLUMN_FROM_XPIXEL (clist, x);
4356 if (tcol >= clist->columns)
4366 gtk_clist_get_selection_info (GtkCList *clist,
4372 g_return_val_if_fail (clist != NULL, 0);
4373 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
4374 return get_selection_info (clist, x, y, row, column);
4384 draw_xor_line (GtkCList * clist)
4388 g_return_if_fail (clist != NULL);
4390 widget = GTK_WIDGET (clist);
4392 gdk_draw_line (widget->window, clist->xor_gc,
4394 widget->style->klass->ythickness,
4396 clist->column_title_area.height +
4397 clist->clist_window_height + 1);
4400 /* this function returns the new width of the column being resized given
4401 * the column and x position of the cursor; the x cursor position is passed
4402 * in as a pointer and automagicly corrected if it's beyond min/max limits */
4404 new_column_width (GtkCList *clist,
4408 gint xthickness = GTK_WIDGET (clist)->style->klass->xthickness;
4413 /* first translate the x position from widget->window
4414 * to clist->clist_window */
4415 cx = *x - xthickness;
4417 /* calculate new column width making sure it doesn't end up
4418 * less than the minimum width */
4419 dx = (COLUMN_LEFT_XPIXEL (clist, column) + COLUMN_INSET +
4420 (column < clist->columns - 1) * CELL_SPACING);
4423 if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width))
4425 width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width);
4427 *x = cx + xthickness;
4429 else if (clist->column[column].max_width >= COLUMN_MIN_WIDTH &&
4430 width > clist->column[column].max_width)
4432 width = clist->column[column].max_width;
4433 cx = dx + clist->column[column].max_width;
4434 *x = cx + xthickness;
4437 if (cx < 0 || cx > clist->clist_window_width)
4443 /* this will do more later */
4445 resize_column (GtkCList * clist,
4449 gtk_clist_set_column_width (clist, column, width);
4454 column_button_create (GtkCList * clist,
4459 button = clist->column[column].button = gtk_button_new ();
4460 if (GTK_WIDGET_REALIZED (clist) && clist->title_window)
4461 gtk_widget_set_parent_window (clist->column[column].button, clist->title_window);
4462 gtk_widget_set_parent (button, GTK_WIDGET (clist));
4464 gtk_signal_connect (GTK_OBJECT (button), "clicked",
4465 (GtkSignalFunc) column_button_clicked,
4468 gtk_widget_show (button);
4472 column_button_clicked (GtkWidget * widget,
4478 g_return_if_fail (widget != NULL);
4479 g_return_if_fail (GTK_IS_CLIST (data));
4481 clist = GTK_CLIST (data);
4483 /* find the column who's button was pressed */
4484 for (i = 0; i < clist->columns; i++)
4485 if (clist->column[i].button == widget)
4488 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i);
4497 * vadjustment_changed
4498 * hadjustment_changed
4499 * vadjustment_value_changed
4500 * hadjustment_value_changed
4503 create_scrollbars (GtkCList * clist)
4505 GtkAdjustment *adjustment;
4507 clist->vscrollbar = gtk_vscrollbar_new (NULL);
4509 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
4511 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
4512 (GtkSignalFunc) vadjustment_changed,
4515 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
4516 (GtkSignalFunc) vadjustment_value_changed,
4519 gtk_widget_set_parent (clist->vscrollbar, GTK_WIDGET (clist));
4520 gtk_widget_show (clist->vscrollbar);
4522 clist->hscrollbar = gtk_hscrollbar_new (NULL);
4524 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
4526 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
4527 (GtkSignalFunc) hadjustment_changed,
4530 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
4531 (GtkSignalFunc) hadjustment_value_changed,
4534 gtk_widget_set_parent (clist->hscrollbar, GTK_WIDGET (clist));
4535 gtk_widget_show (clist->hscrollbar);
4539 adjust_scrollbars (GtkCList * clist)
4541 GTK_RANGE (clist->vscrollbar)->adjustment->page_size = clist->clist_window_height;
4542 GTK_RANGE (clist->vscrollbar)->adjustment->page_increment = clist->clist_window_height / 2;
4543 GTK_RANGE (clist->vscrollbar)->adjustment->step_increment = 10;
4544 GTK_RANGE (clist->vscrollbar)->adjustment->lower = 0;
4545 GTK_RANGE (clist->vscrollbar)->adjustment->upper = LIST_HEIGHT (clist);
4547 if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist))
4549 GTK_RANGE (clist->vscrollbar)->adjustment->value = MAX (0, LIST_HEIGHT (clist) -
4550 clist->clist_window_height);
4551 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment),
4555 GTK_RANGE (clist->hscrollbar)->adjustment->page_size = clist->clist_window_width;
4556 GTK_RANGE (clist->hscrollbar)->adjustment->page_increment = clist->clist_window_width / 2;
4557 GTK_RANGE (clist->hscrollbar)->adjustment->step_increment = 10;
4558 GTK_RANGE (clist->hscrollbar)->adjustment->lower = 0;
4559 GTK_RANGE (clist->hscrollbar)->adjustment->upper = LIST_WIDTH (clist);
4561 if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist))
4563 GTK_RANGE (clist->hscrollbar)->adjustment->value = MAX (0, LIST_WIDTH (clist) -
4564 clist->clist_window_width);
4565 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment),
4569 if (LIST_HEIGHT (clist) <= clist->clist_window_height &&
4570 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
4572 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
4574 gtk_widget_hide (clist->vscrollbar);
4575 gtk_widget_size_allocate (GTK_WIDGET (clist),
4576 >K_WIDGET (clist)->allocation);
4581 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
4583 gtk_widget_show (clist->vscrollbar);
4584 gtk_widget_size_allocate (GTK_WIDGET (clist),
4585 >K_WIDGET (clist)->allocation);
4589 if (LIST_WIDTH (clist) <= clist->clist_window_width &&
4590 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
4592 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
4594 gtk_widget_hide (clist->hscrollbar);
4595 gtk_widget_size_allocate (GTK_WIDGET (clist),
4596 >K_WIDGET (clist)->allocation);
4601 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
4603 gtk_widget_show (clist->hscrollbar);
4604 gtk_widget_size_allocate (GTK_WIDGET (clist),
4605 >K_WIDGET (clist)->allocation);
4609 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
4610 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), "changed");
4614 vadjustment_changed (GtkAdjustment * adjustment,
4619 g_return_if_fail (adjustment != NULL);
4620 g_return_if_fail (data != NULL);
4622 clist = GTK_CLIST (data);
4626 hadjustment_changed (GtkAdjustment * adjustment,
4631 g_return_if_fail (adjustment != NULL);
4632 g_return_if_fail (data != NULL);
4634 clist = GTK_CLIST (data);
4638 check_exposures (GtkCList *clist)
4642 if (!GTK_WIDGET_REALIZED (clist))
4645 /* Make sure graphics expose events are processed before scrolling
4647 while ((event = gdk_event_get_graphics_expose (clist->clist_window)) != NULL)
4649 gtk_widget_event (GTK_WIDGET (clist), event);
4650 if (event->expose.count == 0)
4652 gdk_event_free (event);
4655 gdk_event_free (event);
4660 vadjustment_value_changed (GtkAdjustment * adjustment,
4667 g_return_if_fail (adjustment != NULL);
4668 g_return_if_fail (data != NULL);
4669 g_return_if_fail (GTK_IS_CLIST (data));
4671 clist = GTK_CLIST (data);
4673 if (!GTK_WIDGET_DRAWABLE (clist))
4676 value = adjustment->value;
4678 if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)))
4680 if (value > -clist->voffset)
4683 diff = value + clist->voffset;
4685 /* we have to re-draw the whole screen here... */
4686 if (diff >= clist->clist_window_height)
4688 clist->voffset = -value;
4689 draw_rows (clist, NULL);
4693 if ((diff != 0) && (diff != clist->clist_window_height))
4694 gdk_window_copy_area (clist->clist_window,
4697 clist->clist_window,
4700 clist->clist_window_width,
4701 clist->clist_window_height - diff);
4704 area.y = clist->clist_window_height - diff;
4705 area.width = clist->clist_window_width;
4711 diff = -clist->voffset - value;
4713 /* we have to re-draw the whole screen here... */
4714 if (diff >= clist->clist_window_height)
4716 clist->voffset = -value;
4717 draw_rows (clist, NULL);
4721 if ((diff != 0) && (diff != clist->clist_window_height))
4722 gdk_window_copy_area (clist->clist_window,
4725 clist->clist_window,
4728 clist->clist_window_width,
4729 clist->clist_window_height - diff);
4733 area.width = clist->clist_window_width;
4738 clist->voffset = -value;
4739 if ((diff != 0) && (diff != clist->clist_window_height))
4740 check_exposures (clist);
4743 draw_rows (clist, &area);
4747 hadjustment_value_changed (GtkAdjustment * adjustment,
4757 g_return_if_fail (adjustment != NULL);
4758 g_return_if_fail (data != NULL);
4759 g_return_if_fail (GTK_IS_CLIST (data));
4761 clist = GTK_CLIST (data);
4763 if (!GTK_WIDGET_DRAWABLE (clist) ||
4764 adjustment != gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)))
4767 value = adjustment->value;
4769 /* move the column buttons and resize windows */
4770 for (i = 0; i < clist->columns; i++)
4772 if (clist->column[i].button)
4774 clist->column[i].button->allocation.x -= value + clist->hoffset;
4776 if (clist->column[i].button->window)
4778 gdk_window_move (clist->column[i].button->window,
4779 clist->column[i].button->allocation.x,
4780 clist->column[i].button->allocation.y);
4782 if (clist->column[i].window)
4783 gdk_window_move (clist->column[i].window,
4784 clist->column[i].button->allocation.x +
4785 clist->column[i].button->allocation.width -
4786 (DRAG_WIDTH / 2), 0);
4791 if (value > -clist->hoffset)
4794 diff = value + clist->hoffset;
4796 clist->hoffset = -value;
4798 /* we have to re-draw the whole screen here... */
4799 if (diff >= clist->clist_window_width)
4801 draw_rows (clist, NULL);
4805 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
4806 GTK_CLIST_ADD_MODE (clist))
4808 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4810 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
4811 clist->clist_window_width - 1,
4812 clist->row_height - 1);
4814 gdk_window_copy_area (clist->clist_window,
4817 clist->clist_window,
4820 clist->clist_window_width - diff,
4821 clist->clist_window_height);
4823 area.x = clist->clist_window_width - diff;
4828 if (!(diff = -clist->hoffset - value))
4831 clist->hoffset = -value;
4833 /* we have to re-draw the whole screen here... */
4834 if (diff >= clist->clist_window_width)
4836 draw_rows (clist, NULL);
4840 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
4841 GTK_CLIST_ADD_MODE (clist))
4843 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4845 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
4846 clist->clist_window_width - 1,
4847 clist->row_height - 1);
4850 gdk_window_copy_area (clist->clist_window,
4853 clist->clist_window,
4856 clist->clist_window_width - diff,
4857 clist->clist_window_height);
4864 area.height = clist->clist_window_height;
4866 check_exposures (clist);
4868 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist))
4870 if (GTK_CLIST_ADD_MODE (clist))
4874 focus_row = clist->focus_row;
4875 clist->focus_row = -1;
4876 draw_rows (clist, &area);
4877 clist->focus_row = focus_row;
4879 gdk_draw_rectangle (clist->clist_window, clist->xor_gc,
4880 FALSE, 0, y, clist->clist_window_width - 1,
4881 clist->row_height - 1);
4891 x0 = clist->clist_window_width - 1;
4900 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4901 gdk_draw_line (clist->clist_window, clist->xor_gc,
4902 x0, y + 1, x0, y + clist->row_height - 2);
4903 gdk_draw_line (clist->clist_window, clist->xor_gc,
4904 x1, y + 1, x1, y + clist->row_height - 2);
4908 draw_rows (clist, &area);
4912 * Memory Allocation/Distruction Routines for GtkCList stuctures
4922 static GtkCListColumn *
4923 columns_new (GtkCList * clist)
4926 GtkCListColumn *column;
4928 column = g_new (GtkCListColumn, clist->columns);
4930 for (i = 0; i < clist->columns; i++)
4932 column[i].area.x = 0;
4933 column[i].area.y = 0;
4934 column[i].area.width = 0;
4935 column[i].area.height = 0;
4936 column[i].title = NULL;
4937 column[i].button = NULL;
4938 column[i].window = NULL;
4939 column[i].width = 0;
4940 column[i].min_width = -1;
4941 column[i].max_width = -1;
4942 column[i].visible = TRUE;
4943 column[i].width_set = FALSE;
4944 column[i].resizeable = TRUE;
4945 column[i].justification = GTK_JUSTIFY_LEFT;
4952 column_title_new (GtkCList *clist,
4956 if (clist->column[column].title)
4957 g_free (clist->column[column].title);
4959 clist->column[column].title = g_strdup (title);
4963 columns_delete (GtkCList * clist)
4967 for (i = 0; i < clist->columns; i++)
4968 if (clist->column[i].title)
4969 g_free (clist->column[i].title);
4971 g_free (clist->column);
4974 static GtkCListRow *
4975 row_new (GtkCList * clist)
4978 GtkCListRow *clist_row;
4980 clist_row = g_chunk_new (GtkCListRow, clist->row_mem_chunk);
4981 clist_row->cell = g_chunk_new (GtkCell, clist->cell_mem_chunk);
4983 for (i = 0; i < clist->columns; i++)
4985 clist_row->cell[i].type = GTK_CELL_EMPTY;
4986 clist_row->cell[i].vertical = 0;
4987 clist_row->cell[i].horizontal = 0;
4990 clist_row->fg_set = FALSE;
4991 clist_row->bg_set = FALSE;
4992 clist_row->selectable = TRUE;
4993 clist_row->state = GTK_STATE_NORMAL;
4994 clist_row->data = NULL;
4995 clist_row->destroy = NULL;
5001 row_delete (GtkCList * clist,
5002 GtkCListRow * clist_row)
5006 for (i = 0; i < clist->columns; i++)
5007 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
5008 (clist, clist_row, i, GTK_CELL_EMPTY, NULL, 0, NULL, NULL);
5010 if (clist_row->destroy)
5011 clist_row->destroy (clist_row->data);
5013 g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell);
5014 g_mem_chunk_free (clist->row_mem_chunk, clist_row);
5018 set_cell_contents (GtkCList *clist,
5019 GtkCListRow *clist_row,
5027 g_return_if_fail (clist_row != NULL);
5029 switch (clist_row->cell[column].type)
5031 case GTK_CELL_EMPTY:
5035 g_free (GTK_CELL_TEXT (clist_row->cell[column])->text);
5038 case GTK_CELL_PIXMAP:
5039 gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap);
5040 if (GTK_CELL_PIXMAP (clist_row->cell[column])->mask)
5041 gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask);
5044 case GTK_CELL_PIXTEXT:
5045 g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text);
5046 gdk_pixmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap);
5047 if (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask)
5048 gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask);
5051 case GTK_CELL_WIDGET:
5059 clist_row->cell[column].type = GTK_CELL_EMPTY;
5066 clist_row->cell[column].type = GTK_CELL_TEXT;
5067 GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
5071 case GTK_CELL_PIXMAP:
5074 clist_row->cell[column].type = GTK_CELL_PIXMAP;
5075 GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
5076 /* We set the mask even if it is NULL */
5077 GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask;
5081 case GTK_CELL_PIXTEXT:
5084 clist_row->cell[column].type = GTK_CELL_PIXTEXT;
5085 GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
5086 GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
5087 GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
5088 GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask;
5097 /* Fill in data after widget has correct style */
5100 add_style_data (GtkCList * clist)
5104 widget = GTK_WIDGET(clist);
5106 /* text properties */
5107 if (!GTK_CLIST_ROW_HEIGHT_SET (clist))
5109 clist->row_height = widget->style->font->ascent + widget->style->font->descent + 1;
5110 clist->row_center_offset = widget->style->font->ascent + 1.5;
5115 text_height = clist->row_height - (GTK_WIDGET (clist)->style->font->ascent +
5116 GTK_WIDGET (clist) ->style->font->descent + 1);
5117 clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
5124 /* focus functions */
5127 gtk_clist_draw_focus (GtkWidget *widget)
5131 g_return_if_fail (widget != NULL);
5132 g_return_if_fail (GTK_IS_CLIST (widget));
5134 if (!GTK_WIDGET_DRAWABLE (widget))
5137 clist = GTK_CLIST (widget);
5138 if (clist->focus_row >= 0)
5139 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
5140 0, ROW_TOP_YPIXEL(clist, clist->focus_row),
5141 clist->clist_window_width - 1,
5142 clist->row_height - 1);
5146 gtk_clist_set_focus_child (GtkContainer *container,
5149 g_return_if_fail (container != NULL);
5150 g_return_if_fail (GTK_IS_CLIST (container));
5154 g_return_if_fail (GTK_IS_WIDGET (child));
5155 GTK_CLIST_SET_FLAG (GTK_CLIST (container), CLIST_CHILD_HAS_FOCUS);
5158 parent_class->set_focus_child (container, child);
5162 gtk_clist_focus_in (GtkWidget *widget,
5163 GdkEventFocus *event)
5167 g_return_val_if_fail (widget != NULL, FALSE);
5168 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
5169 g_return_val_if_fail (event != NULL, FALSE);
5171 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
5172 GTK_CLIST_UNSET_FLAG (widget, CLIST_CHILD_HAS_FOCUS);
5174 clist = GTK_CLIST (widget);
5176 if (clist->selection_mode == GTK_SELECTION_BROWSE &&
5177 clist->selection == NULL && clist->focus_row > -1)
5181 list = g_list_nth (clist->row_list, clist->focus_row);
5182 if (list && GTK_CLIST_ROW (list)->selectable)
5183 select_row (clist, clist->focus_row, -1, (GdkEvent *) event);
5185 gtk_widget_draw_focus (widget);
5188 gtk_widget_draw_focus (widget);
5194 gtk_clist_focus_out (GtkWidget *widget,
5195 GdkEventFocus *event)
5199 g_return_val_if_fail (widget != NULL, FALSE);
5200 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
5201 g_return_val_if_fail (event != NULL, FALSE);
5203 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
5204 gtk_widget_draw_focus (widget);
5206 clist = GTK_CLIST (widget);
5208 if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
5209 GTK_CLIST_CLASS_FW (widget)->resync_selection (clist, (GdkEvent *) event);
5215 toggle_add_mode (GtkCList *clist)
5217 g_return_if_fail (clist != 0);
5218 g_return_if_fail (GTK_IS_CLIST (clist));
5220 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
5221 clist->selection_mode != GTK_SELECTION_EXTENDED)
5224 gtk_clist_draw_focus (GTK_WIDGET (clist));
5225 if (!GTK_CLIST_ADD_MODE (clist))
5227 GTK_CLIST_SET_FLAG (clist, CLIST_ADD_MODE);
5228 gdk_gc_set_line_attributes (clist->xor_gc, 1,
5229 GDK_LINE_ON_OFF_DASH, 0, 0);
5230 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
5234 GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
5235 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
5236 clist->anchor_state = GTK_STATE_SELECTED;
5238 gtk_clist_draw_focus (GTK_WIDGET (clist));
5242 toggle_focus_row (GtkCList *clist)
5244 g_return_if_fail (clist != 0);
5245 g_return_if_fail (GTK_IS_CLIST (clist));
5247 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
5248 clist->focus_row < 0 || clist->focus_row >= clist->rows)
5251 switch (clist->selection_mode)
5253 case GTK_SELECTION_SINGLE:
5254 case GTK_SELECTION_MULTIPLE:
5255 toggle_row (clist, clist->focus_row, 0, NULL);
5257 case GTK_SELECTION_EXTENDED:
5258 g_list_free (clist->undo_selection);
5259 g_list_free (clist->undo_unselection);
5260 clist->undo_selection = NULL;
5261 clist->undo_unselection = NULL;
5263 clist->anchor = clist->focus_row;
5264 clist->drag_pos = clist->focus_row;
5265 clist->undo_anchor = clist->focus_row;
5267 if (GTK_CLIST_ADD_MODE (clist))
5268 fake_toggle_row (clist, clist->focus_row);
5270 GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist,clist->focus_row);
5272 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
5280 move_focus_row (GtkCList *clist,
5281 GtkScrollType scroll_type,
5286 g_return_if_fail (clist != 0);
5287 g_return_if_fail (GTK_IS_CLIST (clist));
5289 widget = GTK_WIDGET (clist);
5291 switch (scroll_type)
5293 case GTK_SCROLL_STEP_BACKWARD:
5294 if (clist->focus_row <= 0)
5296 gtk_clist_draw_focus (widget);
5298 gtk_clist_draw_focus (widget);
5300 case GTK_SCROLL_STEP_FORWARD:
5301 if (clist->focus_row >= clist->rows - 1)
5303 gtk_clist_draw_focus (widget);
5305 gtk_clist_draw_focus (widget);
5307 case GTK_SCROLL_PAGE_BACKWARD:
5308 if (clist->focus_row <= 0)
5310 gtk_clist_draw_focus (widget);
5311 clist->focus_row = MAX (0, clist->focus_row -
5312 (2 * clist->clist_window_height -
5313 clist->row_height - CELL_SPACING) /
5314 (2 * (clist->row_height + CELL_SPACING)));
5315 gtk_clist_draw_focus (widget);
5317 case GTK_SCROLL_PAGE_FORWARD:
5318 if (clist->focus_row >= clist->rows - 1)
5320 gtk_clist_draw_focus (widget);
5321 clist->focus_row = MIN (clist->rows - 1, clist->focus_row +
5322 (2 * clist->clist_window_height -
5323 clist->row_height - CELL_SPACING) /
5324 (2 * (clist->row_height + CELL_SPACING)));
5325 gtk_clist_draw_focus (widget);
5327 case GTK_SCROLL_JUMP:
5328 if (position >= 0 && position <= 1)
5330 gtk_clist_draw_focus (widget);
5331 clist->focus_row = position * (clist->rows - 1);
5332 gtk_clist_draw_focus (widget);
5341 scroll_horizontal (GtkCList *clist,
5342 GtkScrollType scroll_type,
5347 g_return_if_fail (clist != 0);
5348 g_return_if_fail (GTK_IS_CLIST (clist));
5350 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5353 switch (scroll_type)
5355 case GTK_SCROLL_STEP_BACKWARD:
5356 column = COLUMN_FROM_XPIXEL (clist, 0);
5357 if (COLUMN_LEFT_XPIXEL (clist, column) - CELL_SPACING - COLUMN_INSET >= 0
5361 case GTK_SCROLL_STEP_FORWARD:
5362 column = COLUMN_FROM_XPIXEL (clist, clist->clist_window_width);
5365 if (COLUMN_LEFT_XPIXEL (clist, column) + clist->column[column].area.width
5366 + CELL_SPACING + COLUMN_INSET - 1 <= clist->clist_window_width &&
5367 column < clist->columns - 1)
5370 case GTK_SCROLL_PAGE_BACKWARD:
5371 case GTK_SCROLL_PAGE_FORWARD:
5373 case GTK_SCROLL_JUMP:
5374 if (position >= 0 && position <= 1)
5375 column = position * (clist->columns - 1);
5383 if (COLUMN_LEFT_XPIXEL (clist, column) < CELL_SPACING + COLUMN_INSET)
5384 gtk_clist_moveto (clist, -1, column, 0, 0);
5385 else if (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET - 1
5386 + clist->column[column].area.width > clist->clist_window_width)
5388 if (column == clist->columns - 1)
5389 gtk_clist_moveto (clist, -1, column, 0, 0);
5391 gtk_clist_moveto (clist, -1, column, 0, 1);
5396 scroll_vertical (GtkCList *clist,
5397 GtkScrollType scroll_type,
5402 g_return_if_fail (clist != NULL);
5403 g_return_if_fail (GTK_IS_CLIST (clist));
5405 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5408 switch (clist->selection_mode)
5410 case GTK_SELECTION_EXTENDED:
5411 if (clist->anchor >= 0)
5414 case GTK_SELECTION_BROWSE:
5416 old_focus_row = clist->focus_row;
5417 move_focus_row (clist, scroll_type, position);
5419 if (old_focus_row != clist->focus_row)
5421 if (clist->selection_mode == GTK_SELECTION_BROWSE)
5422 unselect_row (clist,old_focus_row, -1, NULL);
5423 else if (!GTK_CLIST_ADD_MODE (clist))
5425 gtk_clist_unselect_all (clist);
5426 clist->undo_anchor = old_focus_row;
5430 switch (gtk_clist_row_is_visible (clist, clist->focus_row))
5432 case GTK_VISIBILITY_NONE:
5433 if (old_focus_row != clist->focus_row &&
5434 !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
5435 GTK_CLIST_ADD_MODE (clist)))
5436 select_row (clist, clist->focus_row, -1, NULL);
5437 switch (scroll_type)
5439 case GTK_SCROLL_STEP_BACKWARD:
5440 case GTK_SCROLL_PAGE_BACKWARD:
5441 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5443 case GTK_SCROLL_STEP_FORWARD:
5444 case GTK_SCROLL_PAGE_FORWARD:
5445 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5447 case GTK_SCROLL_JUMP:
5448 gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
5455 case GTK_VISIBILITY_PARTIAL:
5456 switch (scroll_type)
5458 case GTK_SCROLL_STEP_BACKWARD:
5459 case GTK_SCROLL_PAGE_BACKWARD:
5460 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5462 case GTK_SCROLL_STEP_FORWARD:
5463 case GTK_SCROLL_PAGE_FORWARD:
5464 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5466 case GTK_SCROLL_JUMP:
5467 gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
5474 if (old_focus_row != clist->focus_row &&
5475 !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
5476 GTK_CLIST_ADD_MODE (clist)))
5477 select_row (clist, clist->focus_row, -1, NULL);
5483 move_focus_row (clist, scroll_type, position);
5485 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5486 clist->clist_window_height)
5487 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5488 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5489 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5495 set_anchor (GtkCList *clist,
5500 g_return_if_fail (clist != NULL);
5501 g_return_if_fail (GTK_IS_CLIST (clist));
5503 if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor >= 0)
5506 g_list_free (clist->undo_selection);
5507 g_list_free (clist->undo_unselection);
5508 clist->undo_selection = NULL;
5509 clist->undo_unselection = NULL;
5512 fake_toggle_row (clist, anchor);
5515 GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist, anchor);
5516 clist->anchor_state = GTK_STATE_SELECTED;
5519 clist->anchor = anchor;
5520 clist->drag_pos = anchor;
5521 clist->undo_anchor = undo_anchor;
5525 resync_selection (GtkCList *clist,
5531 gboolean thaw = FALSE;
5533 GtkCListRow *clist_row;
5535 if (clist->anchor < 0)
5538 if (!GTK_CLIST_FROZEN (clist))
5540 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
5544 i = MIN (clist->anchor, clist->drag_pos);
5545 e = MAX (clist->anchor, clist->drag_pos);
5547 if (clist->undo_selection)
5549 list = clist->selection;
5550 clist->selection = clist->undo_selection;
5551 clist->selection_end = g_list_last (clist->selection);
5552 clist->undo_selection = list;
5553 list = clist->selection;
5556 row = GPOINTER_TO_INT (list->data);
5558 if (row < i || row > e)
5560 clist_row = g_list_nth (clist->row_list, row)->data;
5561 if (clist_row->selectable)
5563 clist_row->state = GTK_STATE_SELECTED;
5564 unselect_row (clist, row, -1, event);
5565 clist->undo_selection = g_list_prepend
5566 (clist->undo_selection, GINT_TO_POINTER (row));
5572 for (list = g_list_nth (clist->row_list, i); i <= e; i++, list = list->next)
5573 if (GTK_CLIST_ROW (list)->selectable)
5575 if (g_list_find (clist->selection, GINT_TO_POINTER(i)))
5577 if (GTK_CLIST_ROW (list)->state == GTK_STATE_NORMAL)
5579 GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
5580 unselect_row (clist, i, -1, event);
5581 clist->undo_selection = g_list_prepend (clist->undo_selection,
5582 GINT_TO_POINTER (i));
5585 else if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
5587 GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
5588 clist->undo_unselection = g_list_prepend (clist->undo_unselection,
5589 GINT_TO_POINTER (i));
5593 for (list = clist->undo_unselection; list; list = list->next)
5594 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
5595 GPOINTER_TO_INT (list->data), -1, event);
5598 clist->drag_pos = -1;
5601 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
5605 update_extended_selection (GtkCList *clist,
5615 gint y1 = clist->clist_window_height;
5616 gint y2 = clist->clist_window_height;
5621 if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor == -1)
5626 if (row >= clist->rows)
5627 row = clist->rows - 1;
5629 /* extending downwards */
5630 if (row > clist->drag_pos && clist->anchor <= clist->drag_pos)
5632 s2 = clist->drag_pos + 1;
5635 /* extending upwards */
5636 else if (row < clist->drag_pos && clist->anchor >= clist->drag_pos)
5639 e2 = clist->drag_pos - 1;
5641 else if (row < clist->drag_pos && clist->anchor < clist->drag_pos)
5643 e1 = clist->drag_pos;
5644 /* row and drag_pos on different sides of anchor :
5645 take back the selection between anchor and drag_pos,
5646 select between anchor and row */
5647 if (row < clist->anchor)
5649 s1 = clist->anchor + 1;
5651 e2 = clist->anchor - 1;
5653 /* take back the selection between anchor and drag_pos */
5657 else if (row > clist->drag_pos && clist->anchor > clist->drag_pos)
5659 s1 = clist->drag_pos;
5660 /* row and drag_pos on different sides of anchor :
5661 take back the selection between anchor and drag_pos,
5662 select between anchor and row */
5663 if (row > clist->anchor)
5665 e1 = clist->anchor - 1;
5666 s2 = clist->anchor + 1;
5669 /* take back the selection between anchor and drag_pos */
5674 clist->drag_pos = row;
5677 area.width = clist->clist_window_width;
5679 /* restore the elements between s1 and e1 */
5682 for (i = s1, list = g_list_nth (clist->row_list, i); i <= e1;
5683 i++, list = list->next)
5684 if (GTK_CLIST_ROW (list)->selectable)
5686 if (GTK_CLIST_CLASS_FW (clist)->selection_find (clist, i, list))
5687 GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
5689 GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
5692 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
5694 if (top + clist->row_height <= 0)
5697 area.height = ROW_TOP_YPIXEL (clist, e1) + clist->row_height;
5698 draw_rows (clist, &area);
5699 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5701 else if (top >= clist->clist_window_height)
5703 area.y = ROW_TOP_YPIXEL (clist, s1);
5704 area.height = clist->clist_window_height - area.y;
5705 draw_rows (clist, &area);
5706 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5709 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5710 else if (top + clist->row_height > clist->clist_window_height)
5711 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5713 y1 = ROW_TOP_YPIXEL (clist, s1);
5714 h1 = (e1 - s1 + 1) * (clist->row_height + CELL_SPACING);
5717 /* extend the selection between s2 and e2 */
5720 for (i = s2, list = g_list_nth (clist->row_list, i); i <= e2;
5721 i++, list = list->next)
5722 if (GTK_CLIST_ROW (list)->selectable &&
5723 GTK_CLIST_ROW (list)->state != clist->anchor_state)
5724 GTK_CLIST_ROW (list)->state = clist->anchor_state;
5726 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
5728 if (top + clist->row_height <= 0)
5731 area.height = ROW_TOP_YPIXEL (clist, e2) + clist->row_height;
5732 draw_rows (clist, &area);
5733 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5735 else if (top >= clist->clist_window_height)
5737 area.y = ROW_TOP_YPIXEL (clist, s2);
5738 area.height = clist->clist_window_height - area.y;
5739 draw_rows (clist, &area);
5740 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5743 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5744 else if (top + clist->row_height > clist->clist_window_height)
5745 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5747 y2 = ROW_TOP_YPIXEL (clist, s2);
5748 h2 = (e2 - s2 + 1) * (clist->row_height + CELL_SPACING);
5751 area.y = MAX (0, MIN (y1, y2));
5752 if (area.y > clist->clist_window_height)
5754 area.height = MIN (clist->clist_window_height, h1 + h2);
5755 if (s1 >= 0 && s2 >= 0)
5756 area.height += (clist->row_height + CELL_SPACING);
5757 draw_rows (clist, &area);
5761 start_selection (GtkCList *clist)
5763 g_return_if_fail (clist != NULL);
5764 g_return_if_fail (GTK_IS_CLIST (clist));
5766 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5769 set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
5774 end_selection (GtkCList *clist)
5776 g_return_if_fail (clist != NULL);
5777 g_return_if_fail (GTK_IS_CLIST (clist));
5779 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist)) ||
5780 clist->anchor == -1)
5783 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
5787 extend_selection (GtkCList *clist,
5788 GtkScrollType scroll_type,
5790 gboolean auto_start_selection)
5792 g_return_if_fail (clist != NULL);
5793 g_return_if_fail (GTK_IS_CLIST (clist));
5795 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
5796 clist->selection_mode != GTK_SELECTION_EXTENDED)
5799 if (auto_start_selection)
5800 set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
5802 else if (clist->anchor == -1)
5805 move_focus_row (clist, scroll_type, position);
5807 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5808 clist->clist_window_height)
5809 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5810 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5811 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5813 update_extended_selection (clist, clist->focus_row);
5817 abort_column_resize (GtkCList *clist)
5819 g_return_if_fail (clist != NULL);
5820 g_return_if_fail (GTK_IS_CLIST (clist));
5822 if (!GTK_CLIST_IN_DRAG (clist))
5825 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
5826 gtk_grab_remove (GTK_WIDGET (clist));
5827 gdk_pointer_ungrab (GDK_CURRENT_TIME);
5828 clist->drag_pos = -1;
5830 if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1)
5831 draw_xor_line (clist);
5833 if (GTK_CLIST_ADD_MODE (clist))
5835 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_ON_OFF_DASH, 0,0);
5836 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
5841 gtk_clist_key_press (GtkWidget * widget,
5842 GdkEventKey * event)
5844 g_return_val_if_fail (widget != NULL, FALSE);
5845 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
5846 g_return_val_if_fail (event != NULL, FALSE);
5848 if (GTK_WIDGET_CLASS (parent_class)->key_press_event &&
5849 GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
5852 switch (event->keyval)
5855 case GDK_ISO_Left_Tab:
5856 if (event->state & GDK_SHIFT_MASK)
5857 return gtk_container_focus (GTK_CONTAINER (widget),
5858 GTK_DIR_TAB_BACKWARD);
5860 return gtk_container_focus (GTK_CONTAINER (widget),
5861 GTK_DIR_TAB_FORWARD);
5871 title_focus (GtkCList * clist,
5874 GtkWidget *focus_child;
5875 gboolean return_val = FALSE;
5880 if (!GTK_CLIST_SHOW_TITLES (clist))
5883 focus_child = GTK_CONTAINER (clist)->focus_child;
5887 case GTK_DIR_TAB_BACKWARD:
5889 if (!focus_child || focus_child == clist->hscrollbar ||
5890 focus_child == clist->hscrollbar ||
5891 !GTK_CLIST_CHILD_HAS_FOCUS (clist))
5893 if (dir == GTK_DIR_UP)
5894 i = COLUMN_FROM_XPIXEL (clist, 0);
5896 i = clist->columns - 1;
5897 focus_child = clist->column[i].button;
5898 dir = GTK_DIR_TAB_FORWARD;
5905 if (!focus_child || focus_child == clist->hscrollbar ||
5906 focus_child == clist->hscrollbar)
5908 i = clist->columns - 1;
5909 focus_child = clist->column[i].button;
5913 if (!focus_child || focus_child == clist->hscrollbar ||
5914 focus_child == clist->hscrollbar)
5917 focus_child = clist->column[i].button;
5923 while (i < clist->columns)
5925 if (clist->column[i].button == focus_child)
5927 if (clist->column[i].button &&
5928 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
5929 GTK_IS_CONTAINER (clist->column[i].button) &&
5930 !GTK_WIDGET_HAS_FOCUS (clist->column[i].button))
5931 if (gtk_container_focus
5932 (GTK_CONTAINER (clist->column[i].button), dir))
5937 if (!return_val && dir == GTK_DIR_UP)
5948 while (j >= 0 && j < clist->columns)
5950 if (clist->column[j].button &&
5951 GTK_WIDGET_VISIBLE (clist->column[j].button))
5953 if (GTK_IS_CONTAINER (clist->column[j].button) &&
5955 (GTK_CONTAINER (clist->column[j].button), dir))
5960 else if (GTK_WIDGET_CAN_FOCUS (clist->column[j].button))
5962 gtk_widget_grab_focus (clist->column[j].button);
5972 if (COLUMN_LEFT_XPIXEL (clist, j) < CELL_SPACING + COLUMN_INSET)
5973 gtk_clist_moveto (clist, -1, j, 0, 0);
5974 else if (COLUMN_LEFT_XPIXEL(clist, j) + clist->column[j].area.width >
5975 clist->clist_window_width)
5977 if (j == clist->columns-1)
5978 gtk_clist_moveto (clist, -1, j, 0, 0);
5980 gtk_clist_moveto (clist, -1, j, 0, 1);
5987 gtk_clist_focus (GtkContainer * container,
5988 GtkDirectionType direction)
5991 GtkWidget *focus_child;
5994 g_return_val_if_fail (container != NULL, FALSE);
5995 g_return_val_if_fail (GTK_IS_CLIST (container), FALSE);
5997 if (!GTK_WIDGET_SENSITIVE (container))
6000 clist = GTK_CLIST (container);
6001 focus_child = container->focus_child;
6002 old_row = clist->focus_row;
6008 if (GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
6009 (!focus_child || (focus_child && focus_child != clist->vscrollbar &&
6010 focus_child != clist->hscrollbar)))
6012 if (title_focus (clist, direction))
6014 gtk_container_set_focus_child (container, NULL);
6017 gtk_widget_grab_focus (GTK_WIDGET (container));
6020 case GTK_DIR_TAB_FORWARD:
6021 if (GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
6022 (!focus_child || (focus_child != clist->vscrollbar &&
6023 focus_child != clist->hscrollbar)))
6025 gboolean tf = FALSE;
6027 if (((focus_child && direction == GTK_DIR_DOWN) ||
6028 !(tf = title_focus (clist, GTK_DIR_TAB_FORWARD)))
6031 if (clist->focus_row < 0)
6033 clist->focus_row = 0;
6035 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
6036 clist->selection_mode == GTK_SELECTION_EXTENDED) &&
6038 select_row (clist, clist->focus_row, -1, NULL);
6040 gtk_widget_grab_focus (GTK_WIDGET (container));
6048 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
6050 if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child ||
6051 (focus_child != clist->vscrollbar &&
6052 focus_child != clist->hscrollbar)) &&
6053 GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
6054 GTK_WIDGET_CAN_FOCUS (clist->vscrollbar))
6056 gtk_widget_grab_focus (clist->vscrollbar);
6060 if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child ||
6061 focus_child != clist->hscrollbar) &&
6062 GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
6063 GTK_WIDGET_CAN_FOCUS (clist->hscrollbar))
6065 gtk_widget_grab_focus (clist->hscrollbar);
6070 case GTK_DIR_TAB_BACKWARD:
6071 if (!focus_child && GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
6072 GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
6073 GTK_WIDGET_CAN_FOCUS (clist->hscrollbar))
6075 gtk_widget_grab_focus (clist->hscrollbar);
6079 if ((!focus_child || focus_child == clist->hscrollbar) &&
6080 GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
6081 GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
6082 GTK_WIDGET_CAN_FOCUS (clist->vscrollbar))
6084 gtk_widget_grab_focus (clist->vscrollbar);
6088 if ((!focus_child || focus_child == clist->hscrollbar ||
6089 focus_child == clist->vscrollbar) &&
6090 GTK_CLIST_CHILD_HAS_FOCUS (clist) && clist->rows)
6092 if (clist->focus_row < 0)
6094 clist->focus_row = 0;
6095 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
6096 clist->selection_mode == GTK_SELECTION_EXTENDED) &&
6098 select_row (clist, clist->focus_row, -1, NULL);
6100 gtk_widget_grab_focus (GTK_WIDGET (container));
6104 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
6106 if (title_focus (clist, direction))
6115 gtk_container_set_focus_child (container, NULL);
6120 gtk_clist_unselect_all (GtkCList * clist)
6122 g_return_if_fail (clist != NULL);
6123 g_return_if_fail (GTK_IS_CLIST (clist));
6125 GTK_CLIST_CLASS_FW (clist)->unselect_all (clist);
6129 real_unselect_all (GtkCList * clist)
6134 g_return_if_fail (clist != NULL);
6135 g_return_if_fail (GTK_IS_CLIST (clist));
6137 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
6140 switch (clist->selection_mode)
6142 case GTK_SELECTION_BROWSE:
6143 if (clist->focus_row >= 0)
6145 select_row (clist, clist->focus_row, -1, NULL);
6150 case GTK_SELECTION_EXTENDED:
6151 g_list_free (clist->undo_selection);
6152 g_list_free (clist->undo_unselection);
6153 clist->undo_selection = NULL;
6154 clist->undo_unselection = NULL;
6157 clist->drag_pos = -1;
6158 clist->undo_anchor = clist->focus_row;
6165 list = clist->selection;
6169 i = GPOINTER_TO_INT (list->data);
6171 unselect_row (clist, i, -1, NULL);
6176 gtk_clist_select_all (GtkCList * clist)
6178 g_return_if_fail (clist != NULL);
6179 g_return_if_fail (GTK_IS_CLIST (clist));
6181 GTK_CLIST_CLASS_FW (clist)->select_all (clist);
6185 real_select_all (GtkCList * clist)
6190 g_return_if_fail (clist != NULL);
6191 g_return_if_fail (GTK_IS_CLIST (clist));
6193 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
6196 switch (clist->selection_mode)
6198 case GTK_SELECTION_SINGLE:
6199 case GTK_SELECTION_BROWSE:
6202 case GTK_SELECTION_EXTENDED:
6203 g_list_free (clist->undo_selection);
6204 g_list_free (clist->undo_unselection);
6205 clist->undo_selection = NULL;
6206 clist->undo_unselection = NULL;
6209 ((GtkCListRow *) (clist->row_list->data))->state !=
6211 fake_toggle_row (clist, 0);
6213 clist->anchor_state = GTK_STATE_SELECTED;
6215 clist->drag_pos = 0;
6216 clist->undo_anchor = clist->focus_row;
6217 update_extended_selection (clist, clist->rows);
6218 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
6221 case GTK_SELECTION_MULTIPLE:
6222 for (i = 0, list = clist->row_list; list; i++, list = list->next)
6224 if (((GtkCListRow *)(list->data))->state == GTK_STATE_NORMAL)
6225 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
6233 fake_unselect_all (GtkCList * clist,
6240 if (row >= 0 && (work = g_list_nth (clist->row_list, row)))
6242 if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL &&
6243 GTK_CLIST_ROW (work)->selectable)
6245 GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
6247 if (!GTK_CLIST_FROZEN (clist) &&
6248 gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
6249 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
6250 GTK_CLIST_ROW (work));
6254 clist->undo_selection = clist->selection;
6255 clist->selection = NULL;
6256 clist->selection_end = NULL;
6258 for (list = clist->undo_selection; list; list = list->next)
6260 if ((i = GPOINTER_TO_INT (list->data)) == row ||
6261 !(work = g_list_nth (clist->row_list, i)))
6264 GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
6265 if (!GTK_CLIST_FROZEN (clist) &&
6266 gtk_clist_row_is_visible (clist, i) != GTK_VISIBILITY_NONE)
6267 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, i,
6268 GTK_CLIST_ROW (work));
6273 fake_toggle_row (GtkCList *clist,
6278 if (!(work = g_list_nth (clist->row_list, row))||
6279 !GTK_CLIST_ROW (work)->selectable)
6282 if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL)
6283 clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
6285 clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
6287 if (!GTK_CLIST_FROZEN (clist) &&
6288 gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
6289 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
6290 GTK_CLIST_ROW (work));
6294 selection_find (GtkCList *clist,
6296 GList *row_list_element)
6298 return g_list_find (clist->selection, GINT_TO_POINTER (row_number));
6302 default_compare (GtkCList *clist,
6309 GtkCListRow *row1 = (GtkCListRow *) ptr1;
6310 GtkCListRow *row2 = (GtkCListRow *) ptr2;
6312 switch (row1->cell[clist->sort_column].type)
6315 text1 = GTK_CELL_TEXT (row1->cell[clist->sort_column])->text;
6317 case GTK_CELL_PIXTEXT:
6318 text1 = GTK_CELL_PIXTEXT (row1->cell[clist->sort_column])->text;
6324 switch (row2->cell[clist->sort_column].type)
6327 text2 = GTK_CELL_TEXT (row2->cell[clist->sort_column])->text;
6329 case GTK_CELL_PIXTEXT:
6330 text2 = GTK_CELL_PIXTEXT (row2->cell[clist->sort_column])->text;
6337 return (text1 != NULL);
6342 return strcmp (text1, text2);
6346 gtk_clist_set_compare_func (GtkCList *clist,
6347 GtkCListCompareFunc cmp_func)
6349 g_return_if_fail (clist != NULL);
6350 g_return_if_fail (GTK_IS_CLIST (clist));
6352 clist->compare = (cmp_func) ? cmp_func : default_compare;
6356 gtk_clist_set_auto_sort (GtkCList *clist,
6359 g_return_if_fail (clist != NULL);
6360 g_return_if_fail (GTK_IS_CLIST (clist));
6362 if (GTK_CLIST_AUTO_SORT (clist) && !auto_sort)
6363 GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_SORT);
6364 else if (!GTK_CLIST_AUTO_SORT (clist) && auto_sort)
6366 GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_SORT);
6367 gtk_clist_sort (clist);
6372 gtk_clist_set_sort_type (GtkCList *clist,
6373 GtkSortType sort_type)
6375 g_return_if_fail (clist != NULL);
6376 g_return_if_fail (GTK_IS_CLIST (clist));
6378 clist->sort_type = sort_type;
6382 gtk_clist_set_sort_column (GtkCList *clist,
6385 g_return_if_fail (clist != NULL);
6386 g_return_if_fail (GTK_IS_CLIST (clist));
6388 if (column < 0 || column >= clist->columns)
6391 clist->sort_column = column;
6395 gtk_clist_merge (GtkCList *clist,
6396 GList *a, /* first list to merge */
6397 GList *b) /* second list to merge */
6399 GList z = { 0 }; /* auxiliary node */
6425 cmp = clist->compare (clist, GTK_CLIST_ROW (a), GTK_CLIST_ROW (b));
6426 if ((cmp >= 0 && clist->sort_type == GTK_SORT_DESCENDING) ||
6427 (cmp <= 0 && clist->sort_type == GTK_SORT_ASCENDING) ||
6449 gtk_clist_mergesort (GtkCList *clist,
6450 GList *list, /* the list to sort */
6451 gint num) /* the list's length */
6462 /* move "half" to the middle */
6464 for (i = 0; i < num / 2; i++)
6467 /* cut the list in two */
6468 half->prev->next = NULL;
6471 /* recursively sort both lists */
6472 return gtk_clist_merge (clist,
6473 gtk_clist_mergesort (clist, list, num / 2),
6474 gtk_clist_mergesort (clist, half, num - num / 2));
6479 gtk_clist_sort (GtkCList *clist)
6481 g_return_if_fail (clist != NULL);
6482 g_return_if_fail (GTK_IS_CLIST (clist));
6484 GTK_CLIST_CLASS_FW (clist)->sort_list (clist);
6488 real_sort_list (GtkCList *clist)
6493 gboolean thaw = FALSE;
6495 g_return_if_fail (clist != NULL);
6496 g_return_if_fail (GTK_IS_CLIST (clist));
6498 if (clist->rows <= 1)
6501 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
6504 if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
6506 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
6507 g_list_free (clist->undo_selection);
6508 g_list_free (clist->undo_unselection);
6509 clist->undo_selection = NULL;
6510 clist->undo_unselection = NULL;
6513 if (!GTK_CLIST_FROZEN (clist))
6515 gtk_clist_freeze (clist);
6519 clist->row_list = gtk_clist_mergesort (clist, clist->row_list, clist->rows);
6521 work = clist->selection;
6523 for (i = 0, list = clist->row_list; i < clist->rows; i++, list = list->next)
6525 if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
6527 work->data = GINT_TO_POINTER (i);
6531 if (i == clist->rows - 1)
6532 clist->row_list_end = list;
6536 gtk_clist_thaw (clist);