1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald,
3 * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 #include "../config.h"
25 #include "gtkbindings.h"
26 #include <gdk/gdkkeysyms.h>
28 /* the number rows memchunk expands at a time */
29 #define CLIST_OPTIMUM_SIZE 512
31 /* the width of the column resize windows */
34 /* minimum allowed width of a column */
35 #define COLUMN_MIN_WIDTH 5
37 /* this defigns the base grid spacing */
38 #define CELL_SPACING 1
40 /* added the horizontal space at the beginning and end of a row*/
41 #define COLUMN_INSET 3
43 /* used for auto-scrolling */
44 #define SCROLL_TIME 100
46 /* scrollbar spacing class macro */
47 #define SCROLLBAR_SPACING(w) (GTK_CLIST_CLASS (GTK_OBJECT (w)->klass)->scrollbar_spacing)
49 /* gives the top pixel of the given row in context of
50 * the clist's voffset */
51 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
52 (((row) + 1) * CELL_SPACING) + \
55 /* returns the row index from a y pixel location in the
56 * context of the clist's voffset */
57 #define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \
58 ((clist)->row_height + CELL_SPACING))
60 /* gives the left pixel of the given column in context of
61 * the clist's hoffset */
62 #define COLUMN_LEFT_XPIXEL(clist, colnum) ((clist)->column[(colnum)].area.x + \
65 /* returns the column index from a x pixel location in the
66 * context of the clist's hoffset */
68 COLUMN_FROM_XPIXEL (GtkCList * clist,
73 for (i = 0; i < clist->columns; i++)
75 cx = clist->column[i].area.x + clist->hoffset;
77 if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
78 x <= (cx + clist->column[i].area.width + COLUMN_INSET))
86 /* returns the top pixel of the given row in the context of
88 #define ROW_TOP(clist, row) (((clist)->row_height + CELL_SPACING) * (row))
90 /* returns the left pixel of the given column in the context of
92 #define COLUMN_LEFT(clist, colnum) ((clist)->column[(colnum)].area.x)
94 /* returns the total height of the list */
95 #define LIST_HEIGHT(clist) (((clist)->row_height * ((clist)->rows)) + \
96 (CELL_SPACING * ((clist)->rows + 1)))
98 /* returns the total width of the list */
99 #define LIST_WIDTH(clist) ((clist)->column[(clist)->columns - 1].area.x + \
100 (clist)->column[(clist)->columns - 1].area.width + \
101 COLUMN_INSET + CELL_SPACING)
104 #define GTK_CLIST_CLASS_FW(_widget_) GTK_CLIST_CLASS (GTK_OBJECT (_widget_)->klass)
134 typedef void (*GtkCListSignal1) (GtkObject * object,
140 typedef void (*GtkCListSignal2) (GtkObject *object,
143 typedef void (*GtkCListSignal3) (GtkObject * object,
146 typedef void (*GtkCListSignal4) (GtkObject * object,
150 typedef void (*GtkCListSignal5) (GtkObject * object,
157 static void sync_selection (GtkCList * clist,
161 /* GtkCList Methods */
162 static void gtk_clist_class_init (GtkCListClass * klass);
163 static void gtk_clist_init (GtkCList * clist);
164 static void real_clear (GtkCList * clist);
166 /* GtkObject Methods */
167 static void gtk_clist_destroy (GtkObject * object);
168 static void gtk_clist_finalize (GtkObject * object);
171 /* GtkWidget Methods */
172 static void gtk_clist_realize (GtkWidget * widget);
173 static void gtk_clist_unrealize (GtkWidget * widget);
174 static void gtk_clist_map (GtkWidget * widget);
175 static void gtk_clist_unmap (GtkWidget * widget);
176 static void gtk_clist_draw (GtkWidget * widget,
177 GdkRectangle * area);
178 static gint gtk_clist_expose (GtkWidget * widget,
179 GdkEventExpose * event);
180 static gint gtk_clist_button_press (GtkWidget * widget,
181 GdkEventButton * event);
182 static gint gtk_clist_button_release (GtkWidget * widget,
183 GdkEventButton * event);
184 static gint gtk_clist_motion (GtkWidget * widget,
185 GdkEventMotion * event);
186 static void gtk_clist_size_request (GtkWidget * widget,
187 GtkRequisition * requisition);
188 static void gtk_clist_size_allocate (GtkWidget * widget,
189 GtkAllocation * allocation);
190 static gint get_selection_info (GtkCList * clist,
196 /* GtkContainer Methods */
197 static void gtk_clist_foreach (GtkContainer * container,
198 GtkCallback callback,
199 gpointer callback_data);
202 static void draw_row (GtkCList * clist,
205 GtkCListRow * clist_row);
206 static void draw_rows (GtkCList * clist,
207 GdkRectangle * area);
209 /* Size Allocation */
210 static void size_allocate_title_buttons (GtkCList * clist);
211 static void size_allocate_columns (GtkCList * clist);
214 static void toggle_row (GtkCList * clist,
218 static void select_row (GtkCList * clist,
222 static void unselect_row (GtkCList * clist,
226 static void real_select_row (GtkCList * clist,
230 static void real_unselect_row (GtkCList * clist,
234 static void update_extended_selection (GtkCList *clist,
236 static GList * selection_find (GtkCList *clist,
238 GList *row_list_element);
239 static void real_select_all (GtkCList * clist);
240 static void real_unselect_all (GtkCList * clist);
241 static void move_vertical (GtkCList *clist,
244 static void move_horizontal (GtkCList *clist,
246 static void real_undo_selection (GtkCList * clist);
247 static void fake_unselect_all (GtkCList *clist,
249 static void fake_toggle_row (GtkCList *clist,
251 static void resync_selection (GtkCList *clist,
255 static void draw_xor_line (GtkCList * clist);
256 static gint new_column_width (GtkCList * clist,
260 static void resize_column (GtkCList * clist,
263 static void abort_column_resize (GtkCList *clist);
266 static void column_button_create (GtkCList * clist,
268 static void column_button_clicked (GtkWidget * widget,
272 static void create_scrollbars (GtkCList * clist);
273 static void adjust_scrollbars (GtkCList * clist);
274 static void check_exposures (GtkCList * clist);
275 static void vadjustment_changed (GtkAdjustment * adjustment,
277 static void vadjustment_value_changed (GtkAdjustment * adjustment,
279 static void hadjustment_changed (GtkAdjustment * adjustment,
281 static void hadjustment_value_changed (GtkAdjustment * adjustment,
284 /* Memory Allocation/Distruction Routines */
285 static GtkCListColumn *columns_new (GtkCList * clist);
287 static void column_title_new (GtkCList * clist,
290 static void columns_delete (GtkCList * clist);
292 static GtkCListRow *row_new (GtkCList * clist);
294 static void row_delete (GtkCList * clist,
295 GtkCListRow * clist_row);
296 static void cell_empty (GtkCList * clist,
297 GtkCListRow * clist_row,
299 static void cell_set_text (GtkCList * clist,
300 GtkCListRow * clist_row,
303 static void cell_set_pixmap (GtkCList * clist,
304 GtkCListRow * clist_row,
308 static void cell_set_pixtext (GtkCList * clist,
309 GtkCListRow * clist_row,
317 static void gtk_clist_draw_focus (GtkWidget *widget);
318 static gint gtk_clist_focus_in (GtkWidget *widget,
319 GdkEventFocus *event);
320 static gint gtk_clist_focus_out (GtkWidget *widget,
321 GdkEventFocus *event);
322 static gint gtk_clist_focus (GtkContainer *container,
323 GtkDirectionType direction);
324 static void gtk_clist_set_focus_child (GtkContainer *container,
326 static gint gtk_clist_key_press (GtkWidget *widget,
329 /* Selection handling */
330 static void set_anchor (GtkCList *clist,
334 static void start_selection (GtkCList *clist);
335 static void end_selection (GtkCList *clist);
337 static void toggle_add_mode (GtkCList *clist);
338 static void toggle_focus_row (GtkCList *clist);
339 static void move_focus_row (GtkCList *clist,
340 GtkScrollType scroll_type,
342 static void scroll_horizontal (GtkCList *clist,
343 GtkScrollType scroll_type,
345 static void scroll_vertical (GtkCList *clist,
346 GtkScrollType scroll_type,
348 static void extend_selection (GtkCList *clist,
349 GtkScrollType scroll_type,
351 gboolean auto_start_selection);
353 /* Fill in data after widget is realized and has style */
355 static void add_style_data (GtkCList * clist);
357 static GtkContainerClass *parent_class = NULL;
358 static guint clist_signals[LAST_SIGNAL] = {0};
362 gtk_clist_get_type (void)
364 static GtkType clist_type = 0;
368 GtkTypeInfo clist_info =
372 sizeof (GtkCListClass),
373 (GtkClassInitFunc) gtk_clist_class_init,
374 (GtkObjectInitFunc) gtk_clist_init,
375 /* reserved_1 */ NULL,
376 /* reserved_2 */ NULL,
377 (GtkClassInitFunc) NULL,
380 clist_type = gtk_type_unique (GTK_TYPE_CONTAINER, &clist_info);
387 gtk_clist_class_init (GtkCListClass * klass)
389 GtkObjectClass *object_class;
390 GtkWidgetClass *widget_class;
391 GtkContainerClass *container_class;
393 object_class = (GtkObjectClass *) klass;
394 widget_class = (GtkWidgetClass *) klass;
395 container_class = (GtkContainerClass *) klass;
397 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
399 clist_signals[SELECT_ROW] =
400 gtk_signal_new ("select_row",
403 GTK_SIGNAL_OFFSET (GtkCListClass, select_row),
404 gtk_marshal_NONE__INT_INT_POINTER,
409 clist_signals[UNSELECT_ROW] =
410 gtk_signal_new ("unselect_row",
413 GTK_SIGNAL_OFFSET (GtkCListClass, unselect_row),
414 gtk_marshal_NONE__INT_INT_POINTER,
415 GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_GDK_EVENT);
416 clist_signals[CLICK_COLUMN] =
417 gtk_signal_new ("click_column",
420 GTK_SIGNAL_OFFSET (GtkCListClass, click_column),
421 gtk_marshal_NONE__INT,
422 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
424 clist_signals[TOGGLE_FOCUS_ROW] =
425 gtk_signal_new ("toggle_focus_row",
426 GTK_RUN_LAST | GTK_RUN_ACTION,
428 GTK_SIGNAL_OFFSET (GtkCListClass, toggle_focus_row),
429 gtk_marshal_NONE__NONE,
431 clist_signals[SELECT_ALL] =
432 gtk_signal_new ("select_all",
433 GTK_RUN_LAST | GTK_RUN_ACTION,
435 GTK_SIGNAL_OFFSET (GtkCListClass, select_all),
436 gtk_marshal_NONE__NONE,
438 clist_signals[UNSELECT_ALL] =
439 gtk_signal_new ("unselect_all",
440 GTK_RUN_LAST | GTK_RUN_ACTION,
442 GTK_SIGNAL_OFFSET (GtkCListClass, unselect_all),
443 gtk_marshal_NONE__NONE,
445 clist_signals[UNDO_SELECTION] =
446 gtk_signal_new ("undo_selection",
447 GTK_RUN_LAST | GTK_RUN_ACTION,
449 GTK_SIGNAL_OFFSET (GtkCListClass, undo_selection),
450 gtk_marshal_NONE__NONE,
452 clist_signals[START_SELECTION] =
453 gtk_signal_new ("start_selection",
454 GTK_RUN_LAST | GTK_RUN_ACTION,
456 GTK_SIGNAL_OFFSET (GtkCListClass, start_selection),
457 gtk_marshal_NONE__NONE,
459 clist_signals[END_SELECTION] =
460 gtk_signal_new ("end_selection",
461 GTK_RUN_LAST | GTK_RUN_ACTION,
463 GTK_SIGNAL_OFFSET (GtkCListClass, end_selection),
464 gtk_marshal_NONE__NONE,
466 clist_signals[TOGGLE_ADD_MODE] =
467 gtk_signal_new ("toggle_add_mode",
468 GTK_RUN_LAST | GTK_RUN_ACTION,
470 GTK_SIGNAL_OFFSET (GtkCListClass, toggle_add_mode),
471 gtk_marshal_NONE__NONE,
473 clist_signals[EXTEND_SELECTION] =
474 gtk_signal_new ("extend_selection",
475 GTK_RUN_LAST | GTK_RUN_ACTION,
477 GTK_SIGNAL_OFFSET (GtkCListClass, extend_selection),
478 gtk_marshal_NONE__ENUM_FLOAT_BOOL,
480 GTK_TYPE_ENUM, GTK_TYPE_FLOAT, GTK_TYPE_BOOL);
481 clist_signals[SCROLL_VERTICAL] =
482 gtk_signal_new ("scroll_vertical",
483 GTK_RUN_LAST | GTK_RUN_ACTION,
485 GTK_SIGNAL_OFFSET (GtkCListClass, scroll_vertical),
486 gtk_marshal_NONE__ENUM_FLOAT,
487 GTK_TYPE_NONE, 2, GTK_TYPE_ENUM, GTK_TYPE_FLOAT);
488 clist_signals[SCROLL_HORIZONTAL] =
489 gtk_signal_new ("scroll_horizontal",
490 GTK_RUN_LAST | GTK_RUN_ACTION,
492 GTK_SIGNAL_OFFSET (GtkCListClass, scroll_horizontal),
493 gtk_marshal_NONE__ENUM_FLOAT,
494 GTK_TYPE_NONE, 2, GTK_TYPE_ENUM, GTK_TYPE_FLOAT);
495 clist_signals[ABORT_COLUMN_RESIZE] =
496 gtk_signal_new ("abort_column_resize",
497 GTK_RUN_LAST | GTK_RUN_ACTION,
499 GTK_SIGNAL_OFFSET (GtkCListClass, abort_column_resize),
500 gtk_marshal_NONE__NONE,
504 gtk_object_class_add_signals (object_class, clist_signals, LAST_SIGNAL);
506 object_class->destroy = gtk_clist_destroy;
507 object_class->finalize = gtk_clist_finalize;
509 widget_class->realize = gtk_clist_realize;
510 widget_class->unrealize = gtk_clist_unrealize;
511 widget_class->map = gtk_clist_map;
512 widget_class->unmap = gtk_clist_unmap;
513 widget_class->draw = gtk_clist_draw;
514 widget_class->button_press_event = gtk_clist_button_press;
515 widget_class->button_release_event = gtk_clist_button_release;
516 widget_class->motion_notify_event = gtk_clist_motion;
517 widget_class->expose_event = gtk_clist_expose;
518 widget_class->size_request = gtk_clist_size_request;
519 widget_class->size_allocate = gtk_clist_size_allocate;
520 widget_class->key_press_event = gtk_clist_key_press;
521 widget_class->focus_in_event = gtk_clist_focus_in;
522 widget_class->focus_out_event = gtk_clist_focus_out;
523 widget_class->draw_focus = gtk_clist_draw_focus;
525 /* container_class->add = NULL; use the default GtkContainerClass warning */
526 /* container_class->remove = NULL; use the default GtkContainerClass warning */
527 container_class->foreach = gtk_clist_foreach;
528 container_class->focus = gtk_clist_focus;
529 container_class->set_focus_child = gtk_clist_set_focus_child;
531 klass->select_row = real_select_row;
532 klass->unselect_row = real_unselect_row;
533 klass->undo_selection = real_undo_selection;
534 klass->resync_selection = resync_selection;
535 klass->selection_find = selection_find;
536 klass->click_column = NULL;
537 klass->draw_row = draw_row;
538 klass->clear = real_clear;
539 klass->select_all = real_select_all;
540 klass->unselect_all = real_unselect_all;
541 klass->fake_unselect_all = fake_unselect_all;
542 klass->scroll_horizontal = scroll_horizontal;
543 klass->scroll_vertical = scroll_vertical;
544 klass->extend_selection = extend_selection;
545 klass->toggle_focus_row = toggle_focus_row;
546 klass->toggle_add_mode = toggle_add_mode;
547 klass->start_selection = start_selection;
548 klass->end_selection = end_selection;
549 klass->abort_column_resize = abort_column_resize;
551 klass->scrollbar_spacing = 5;
554 GtkBindingSet *binding_set;
556 binding_set = gtk_binding_set_by_class (klass);
557 gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
558 "scroll_vertical", 2,
559 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
560 GTK_TYPE_FLOAT, 0.0);
561 gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
562 "scroll_vertical", 2,
563 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
564 GTK_TYPE_FLOAT, 0.0);
565 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
566 "scroll_vertical", 2,
567 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
568 GTK_TYPE_FLOAT, 0.0);
569 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
570 "scroll_vertical", 2,
571 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
572 GTK_TYPE_FLOAT, 0.0);
573 gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
574 "scroll_vertical", 2,
575 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
576 GTK_TYPE_FLOAT, 0.0);
577 gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
578 "scroll_vertical", 2,
579 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
580 GTK_TYPE_FLOAT, 1.0);
582 gtk_binding_entry_add_signal (binding_set, GDK_Up, GDK_SHIFT_MASK,
583 "extend_selection", 3,
584 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
585 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
586 gtk_binding_entry_add_signal (binding_set, GDK_Down, GDK_SHIFT_MASK,
587 "extend_selection", 3,
588 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
589 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
590 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, GDK_SHIFT_MASK,
591 "extend_selection", 3,
592 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
593 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
594 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, GDK_SHIFT_MASK,
595 "extend_selection", 3,
596 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
597 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
598 gtk_binding_entry_add_signal (binding_set, GDK_Home,
599 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
600 "extend_selection", 3,
601 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
602 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
603 gtk_binding_entry_add_signal (binding_set, GDK_End,
604 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
605 "extend_selection", 3,
606 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
607 GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE);
610 gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
611 "scroll_horizontal", 2,
612 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
613 GTK_TYPE_FLOAT, 0.0);
614 gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
615 "scroll_horizontal", 2,
616 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
617 GTK_TYPE_FLOAT, 0.0);
618 gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
619 "scroll_horizontal", 2,
620 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
621 GTK_TYPE_FLOAT, 0.0);
622 gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
623 "scroll_horizontal", 2,
624 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
625 GTK_TYPE_FLOAT, 1.0);
628 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
629 "undo_selection", 0);
630 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
631 "abort_column_resize", 0);
632 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
633 "toggle_focus_row", 0);
634 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK,
635 "toggle_add_mode", 0);
636 gtk_binding_entry_add_signal (binding_set, '/', GDK_CONTROL_MASK,
638 gtk_binding_entry_add_signal (binding_set, '\\', GDK_CONTROL_MASK,
640 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
641 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
643 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
644 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
646 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
647 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
650 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
651 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
658 GtkBindingSet *binding_set;
660 binding_set = gtk_binding_set_by_class (klass);
661 gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
662 "scroll_vertical", 2,
663 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
664 GTK_TYPE_FLOAT, 0.0);
665 gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
666 "scroll_vertical", 2,
667 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
668 GTK_TYPE_FLOAT, 0.0);
669 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
670 "scroll_vertical", 2,
671 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
672 GTK_TYPE_FLOAT, 0.0);
673 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
674 "scroll_vertical", 2,
675 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
676 GTK_TYPE_FLOAT, 0.0);
677 gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
678 "scroll_vertical", 2,
679 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
680 GTK_TYPE_FLOAT, 0.0);
681 gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
682 "scroll_vertical", 2,
683 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
686 gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0,
687 "extend_selection", 3,
688 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
689 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
690 gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0,
691 "extend_selection", 3,
692 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
693 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
694 gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Up, 0,
695 "extend_selection", 3,
696 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
697 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
698 gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Down, 0,
699 "extend_selection", 3,
700 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
701 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
702 gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, 0,
703 "extend_selection", 3,
704 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
705 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
706 gtk_binding_entry_add_signal (binding_set, GDK_KP_End, 0,
707 "extend_selection", 3,
708 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
709 GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE);
711 gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
712 "scroll_horizontal", 2,
713 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
714 GTK_TYPE_FLOAT, 0.0);
715 gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0,
716 "scroll_horizontal", 2,
717 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
718 GTK_TYPE_FLOAT, 0.0);
719 gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
720 "scroll_horizontal", 2,
721 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
722 GTK_TYPE_FLOAT, 0.0);
723 gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0,
724 "scroll_horizontal", 2,
725 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
726 GTK_TYPE_FLOAT, 0.0);
727 gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
728 "scroll_horizontal", 2,
729 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
730 GTK_TYPE_FLOAT, 0.0);
731 gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
732 "sroll_horizontal", 2,
733 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
734 GTK_TYPE_FLOAT, 1.0);
736 gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, 0,
737 "undo_selection", 0);
738 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
739 "abort_column_resize", 0);
740 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
741 "toggle_focus_row", 0);
742 gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0,
743 "toggle_add_mode", 0);
744 gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0,
746 gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0,
748 gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0,
755 gtk_clist_init (GtkCList * clist)
759 GTK_WIDGET_UNSET_FLAGS (clist, GTK_NO_WINDOW);
760 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
762 clist->row_mem_chunk = NULL;
763 clist->cell_mem_chunk = NULL;
766 clist->row_center_offset = 0;
767 clist->row_height = 0;
768 clist->row_list = NULL;
769 clist->row_list_end = NULL;
773 clist->title_window = NULL;
774 clist->column_title_area.x = 0;
775 clist->column_title_area.y = 0;
776 clist->column_title_area.width = 1;
777 clist->column_title_area.height = 1;
779 clist->clist_window = NULL;
780 clist->clist_window_width = 1;
781 clist->clist_window_height = 1;
786 clist->shadow_type = GTK_SHADOW_IN;
787 clist->hscrollbar_policy = GTK_POLICY_ALWAYS;
788 clist->vscrollbar_policy = GTK_POLICY_ALWAYS;
790 clist->cursor_drag = NULL;
791 clist->xor_gc = NULL;
796 clist->selection_mode = GTK_SELECTION_SINGLE;
797 clist->selection = NULL;
798 clist->selection_end = NULL;
799 clist->undo_selection = NULL;
800 clist->undo_unselection = NULL;
802 GTK_WIDGET_SET_FLAGS (clist, GTK_CAN_FOCUS);
803 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
804 clist->focus_row = -1;
805 clist->undo_anchor = -1;
808 clist->anchor_state = GTK_STATE_SELECTED;
809 clist->drag_pos = -1;
816 gtk_clist_construct (GtkCList * clist,
822 g_return_if_fail (clist != NULL);
823 g_return_if_fail (GTK_IS_CLIST (clist));
824 g_return_if_fail (GTK_CLIST_CONSTRUCTED (clist) == FALSE);
826 GTK_CLIST_SET_FLAG (clist, CLIST_CONSTRUCTED);
828 /* initalize memory chunks, if this has not been done by any
829 * possibly derived widget
831 if (!clist->row_mem_chunk)
832 clist->row_mem_chunk = g_mem_chunk_new ("clist row mem chunk",
833 sizeof (GtkCListRow),
834 sizeof (GtkCListRow) * CLIST_OPTIMUM_SIZE,
837 if (!clist->cell_mem_chunk)
838 clist->cell_mem_chunk = g_mem_chunk_new ("clist cell mem chunk",
839 sizeof (GtkCell) * columns,
840 sizeof (GtkCell) * columns * CLIST_OPTIMUM_SIZE,
843 /* set number of columns, allocate memory */
844 clist->columns = columns;
845 clist->column = columns_new (clist);
847 /* there needs to be at least one column button
848 * because there is alot of code that will break if it
850 column_button_create (clist, 0);
852 /* create scrollbars */
853 create_scrollbars (clist);
857 GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES);
858 for (i = 0; i < columns; i++)
859 gtk_clist_set_column_title (clist, i, titles[i]);
863 GTK_CLIST_UNSET_FLAG (clist, CLIST_SHOW_TITLES);
868 * GTKCLIST PUBLIC INTERFACE
869 * gtk_clist_new_with_titles
873 gtk_clist_new_with_titles (gint columns,
878 g_return_val_if_fail (titles != NULL, NULL);
880 widget = gtk_type_new (GTK_TYPE_CLIST);
882 gtk_clist_construct (GTK_CLIST (widget), columns, titles);
888 gtk_clist_new (gint columns)
895 clist = gtk_type_new (GTK_TYPE_CLIST);
896 gtk_clist_construct (clist, columns, NULL);
897 return GTK_WIDGET (clist);
901 gtk_clist_set_border (GtkCList * clist,
902 GtkShadowType border)
904 g_return_if_fail (clist != NULL);
905 g_return_if_fail (GTK_IS_CLIST (clist));
907 clist->shadow_type = border;
909 if (GTK_WIDGET_VISIBLE (clist))
910 gtk_widget_queue_resize (GTK_WIDGET (clist));
914 gtk_clist_set_selection_mode (GtkCList * clist,
915 GtkSelectionMode mode)
917 g_return_if_fail (clist != NULL);
918 g_return_if_fail (GTK_IS_CLIST (clist));
920 if (mode == clist->selection_mode)
923 clist->selection_mode = mode;
925 clist->anchor_state = GTK_STATE_SELECTED;
926 clist->drag_pos = -1;
927 clist->undo_anchor = clist->focus_row;
929 g_list_free (clist->undo_selection);
930 g_list_free (clist->undo_unselection);
931 clist->undo_selection = NULL;
932 clist->undo_unselection = NULL;
936 case GTK_SELECTION_MULTIPLE:
937 case GTK_SELECTION_EXTENDED:
939 case GTK_SELECTION_BROWSE:
940 case GTK_SELECTION_SINGLE:
941 gtk_clist_unselect_all (clist);
947 gtk_clist_freeze (GtkCList * clist)
949 g_return_if_fail (clist != NULL);
950 g_return_if_fail (GTK_IS_CLIST (clist));
952 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
956 gtk_clist_thaw (GtkCList * clist)
958 g_return_if_fail (clist != NULL);
959 g_return_if_fail (GTK_IS_CLIST (clist));
961 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
963 adjust_scrollbars (clist);
964 draw_rows (clist, NULL);
968 gtk_clist_column_titles_show (GtkCList * clist)
970 g_return_if_fail (clist != NULL);
971 g_return_if_fail (GTK_IS_CLIST (clist));
973 if (!GTK_CLIST_SHOW_TITLES (clist))
975 GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES);
976 if (clist->title_window)
977 gdk_window_show (clist->title_window);
978 gtk_widget_queue_resize (GTK_WIDGET (clist));
983 gtk_clist_column_titles_hide (GtkCList * clist)
985 g_return_if_fail (clist != NULL);
986 g_return_if_fail (GTK_IS_CLIST (clist));
988 if (GTK_CLIST_SHOW_TITLES (clist))
990 GTK_CLIST_UNSET_FLAG (clist, CLIST_SHOW_TITLES);
991 if (clist->title_window)
992 gdk_window_hide (clist->title_window);
993 gtk_widget_queue_resize (GTK_WIDGET (clist));
998 gtk_clist_column_title_active (GtkCList * clist,
1001 g_return_if_fail (clist != NULL);
1002 g_return_if_fail (GTK_IS_CLIST (clist));
1004 if (column < 0 || column >= clist->columns)
1007 if (!GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
1008 !GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
1010 GTK_WIDGET_SET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS);
1011 if (GTK_WIDGET_VISIBLE (clist))
1012 gtk_widget_queue_draw (clist->column[column].button);
1017 gtk_clist_column_title_passive (GtkCList * clist,
1020 g_return_if_fail (clist != NULL);
1021 g_return_if_fail (GTK_IS_CLIST (clist));
1023 if (column < 0 || column >= clist->columns)
1026 if (GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
1027 GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
1029 GTK_WIDGET_UNSET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS);
1030 if (GTK_WIDGET_VISIBLE (clist))
1031 gtk_widget_queue_draw (clist->column[column].button);
1036 gtk_clist_column_titles_active (GtkCList * clist)
1040 g_return_if_fail (clist != NULL);
1041 g_return_if_fail (GTK_IS_CLIST (clist));
1043 for (i = 0; i < clist->columns; i++)
1044 if (clist->column[i].button)
1045 gtk_clist_column_title_active (clist, i);
1049 gtk_clist_column_titles_passive (GtkCList * clist)
1053 g_return_if_fail (clist != NULL);
1054 g_return_if_fail (GTK_IS_CLIST (clist));
1056 for (i = 0; i < clist->columns; i++)
1057 if (clist->column[i].button)
1058 gtk_clist_column_title_passive (clist, i);
1062 gtk_clist_set_column_title (GtkCList * clist,
1066 gint new_button = 0;
1067 GtkWidget *old_widget;
1068 GtkWidget *alignment = NULL;
1071 g_return_if_fail (clist != NULL);
1072 g_return_if_fail (GTK_IS_CLIST (clist));
1074 if (column < 0 || column >= clist->columns)
1077 /* if the column button doesn't currently exist,
1078 * it has to be created first */
1079 if (!clist->column[column].button)
1081 column_button_create (clist, column);
1085 column_title_new (clist, column, title);
1087 /* remove and destroy the old widget */
1088 old_widget = GTK_BIN (clist->column[column].button)->child;
1090 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
1092 /* create new alignment based no column justification */
1093 switch (clist->column[column].justification)
1095 case GTK_JUSTIFY_LEFT:
1096 alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
1099 case GTK_JUSTIFY_RIGHT:
1100 alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
1103 case GTK_JUSTIFY_CENTER:
1104 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1107 case GTK_JUSTIFY_FILL:
1108 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1112 label = gtk_label_new (clist->column[column].title);
1113 gtk_container_add (GTK_CONTAINER (alignment), label);
1114 gtk_container_add (GTK_CONTAINER (clist->column[column].button), alignment);
1115 gtk_widget_show (label);
1116 gtk_widget_show (alignment);
1118 /* if this button didn't previously exist, then the
1119 * column button positions have to be re-computed */
1120 if (GTK_WIDGET_VISIBLE (clist) && new_button)
1121 size_allocate_title_buttons (clist);
1125 gtk_clist_set_column_widget (GtkCList * clist,
1129 gint new_button = 0;
1130 GtkWidget *old_widget;
1132 g_return_if_fail (clist != NULL);
1133 g_return_if_fail (GTK_IS_CLIST (clist));
1135 if (column < 0 || column >= clist->columns)
1138 /* if the column button doesn't currently exist,
1139 * it has to be created first */
1140 if (!clist->column[column].button)
1142 column_button_create (clist, column);
1146 column_title_new (clist, column, NULL);
1148 /* remove and destroy the old widget */
1149 old_widget = GTK_BIN (clist->column[column].button)->child;
1151 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
1153 /* add and show the widget */
1156 gtk_container_add (GTK_CONTAINER (clist->column[column].button), widget);
1157 gtk_widget_show (widget);
1160 /* if this button didn't previously exist, then the
1161 * column button positions have to be re-computed */
1162 if (GTK_WIDGET_VISIBLE (clist) && new_button)
1163 size_allocate_title_buttons (clist);
1167 gtk_clist_set_column_justification (GtkCList * clist,
1169 GtkJustification justification)
1171 GtkWidget *alignment;
1173 g_return_if_fail (clist != NULL);
1174 g_return_if_fail (GTK_IS_CLIST (clist));
1176 if (column < 0 || column >= clist->columns)
1179 clist->column[column].justification = justification;
1181 /* change the alinment of the button title if it's not a
1183 if (clist->column[column].title)
1185 alignment = GTK_BIN (clist->column[column].button)->child;
1187 switch (clist->column[column].justification)
1189 case GTK_JUSTIFY_LEFT:
1190 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.0, 0.5, 0.0, 0.0);
1193 case GTK_JUSTIFY_RIGHT:
1194 gtk_alignment_set (GTK_ALIGNMENT (alignment), 1.0, 0.5, 0.0, 0.0);
1197 case GTK_JUSTIFY_CENTER:
1198 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
1201 case GTK_JUSTIFY_FILL:
1202 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
1210 if (!GTK_CLIST_FROZEN (clist))
1211 draw_rows (clist, NULL);
1215 gtk_clist_set_column_width (GtkCList * clist,
1219 g_return_if_fail (clist != NULL);
1220 g_return_if_fail (GTK_IS_CLIST (clist));
1222 if (column < 0 || column >= clist->columns)
1225 clist->column[column].width = width;
1226 clist->column[column].width_set = TRUE;
1228 /* FIXME: this is quite expensive to do if the widget hasn't
1229 * been size_allocated yet, and pointless. Should
1232 size_allocate_columns (clist);
1233 size_allocate_title_buttons (clist);
1235 if (!GTK_CLIST_FROZEN (clist))
1237 adjust_scrollbars (clist);
1238 draw_rows (clist, NULL);
1243 gtk_clist_set_row_height (GtkCList * clist,
1248 g_return_if_fail (clist != NULL);
1249 g_return_if_fail (GTK_IS_CLIST (clist));
1252 clist->row_height = height;
1256 GTK_CLIST_SET_FLAG (clist, CLIST_ROW_HEIGHT_SET);
1258 if (GTK_WIDGET_REALIZED (clist))
1260 text_height = height - (GTK_WIDGET (clist)->style->font->ascent +
1261 GTK_WIDGET (clist) ->style->font->descent + 1);
1262 clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
1265 if (!GTK_CLIST_FROZEN (clist))
1267 adjust_scrollbars (clist);
1268 draw_rows (clist, NULL);
1273 gtk_clist_moveto (GtkCList * clist,
1279 g_return_if_fail (clist != NULL);
1280 g_return_if_fail (GTK_IS_CLIST (clist));
1282 if (row < -1 || row >= clist->rows)
1284 if (column < -1 || column >= clist->columns)
1287 row_align = CLAMP (row_align, 0, 1);
1288 col_align = CLAMP (col_align, 0, 1);
1290 /* adjust horizontal scrollbar */
1296 adj = GTK_RANGE (clist->hscrollbar)->adjustment;
1298 x = COLUMN_LEFT (clist, column) - CELL_SPACING - COLUMN_INSET -
1299 (col_align * (clist->clist_window_width - 2 * COLUMN_INSET -
1300 CELL_SPACING - clist->column[column].area.width));
1302 gtk_adjustment_set_value (adj, 0.0);
1303 else if (x > LIST_WIDTH (clist) - clist->clist_window_width)
1304 gtk_adjustment_set_value
1305 (adj, LIST_WIDTH (clist) - clist->clist_window_width);
1307 gtk_adjustment_set_value (adj, x);
1310 /* adjust vertical scrollbar */
1312 move_vertical (clist, row, row_align);
1316 gtk_clist_get_cell_type (GtkCList * clist,
1320 GtkCListRow *clist_row;
1322 g_return_val_if_fail (clist != NULL, -1);
1323 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1325 if (row < 0 || row >= clist->rows)
1327 if (column < 0 || column >= clist->columns)
1330 clist_row = (g_list_nth (clist->row_list, row))->data;
1332 return clist_row->cell[column].type;
1336 gtk_clist_set_text (GtkCList * clist,
1341 GtkCListRow *clist_row;
1343 g_return_if_fail (clist != NULL);
1344 g_return_if_fail (GTK_IS_CLIST (clist));
1346 if (row < 0 || row >= clist->rows)
1348 if (column < 0 || column >= clist->columns)
1351 clist_row = (g_list_nth (clist->row_list, row))->data;
1353 /* if text is null, then the cell is empty */
1355 cell_set_text (clist, clist_row, column, text);
1357 cell_empty (clist, clist_row, column);
1359 /* redraw the list if it's not frozen */
1360 if (!GTK_CLIST_FROZEN (clist))
1362 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1363 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1368 gtk_clist_get_text (GtkCList * clist,
1373 GtkCListRow *clist_row;
1375 g_return_val_if_fail (clist != NULL, 0);
1376 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
1378 if (row < 0 || row >= clist->rows)
1380 if (column < 0 || column >= clist->columns)
1383 clist_row = (g_list_nth (clist->row_list, row))->data;
1385 if (clist_row->cell[column].type != GTK_CELL_TEXT)
1389 *text = GTK_CELL_TEXT (clist_row->cell[column])->text;
1395 gtk_clist_set_pixmap (GtkCList * clist,
1401 GtkCListRow *clist_row;
1403 g_return_if_fail (clist != NULL);
1404 g_return_if_fail (GTK_IS_CLIST (clist));
1406 if (row < 0 || row >= clist->rows)
1408 if (column < 0 || column >= clist->columns)
1411 clist_row = (g_list_nth (clist->row_list, row))->data;
1413 gdk_pixmap_ref (pixmap);
1415 if (mask) gdk_pixmap_ref (mask);
1417 cell_set_pixmap (clist, clist_row, column, pixmap, mask);
1419 /* redraw the list if it's not frozen */
1420 if (!GTK_CLIST_FROZEN (clist))
1422 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1423 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1428 gtk_clist_get_pixmap (GtkCList * clist,
1431 GdkPixmap ** pixmap,
1434 GtkCListRow *clist_row;
1436 g_return_val_if_fail (clist != NULL, 0);
1437 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
1439 if (row < 0 || row >= clist->rows)
1441 if (column < 0 || column >= clist->columns)
1444 clist_row = (g_list_nth (clist->row_list, row))->data;
1446 if (clist_row->cell[column].type != GTK_CELL_PIXMAP)
1451 *pixmap = GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap;
1452 /* mask can be NULL */
1453 *mask = GTK_CELL_PIXMAP (clist_row->cell[column])->mask;
1460 gtk_clist_set_pixtext (GtkCList * clist,
1468 GtkCListRow *clist_row;
1470 g_return_if_fail (clist != NULL);
1471 g_return_if_fail (GTK_IS_CLIST (clist));
1473 if (row < 0 || row >= clist->rows)
1475 if (column < 0 || column >= clist->columns)
1478 clist_row = (g_list_nth (clist->row_list, row))->data;
1480 gdk_pixmap_ref (pixmap);
1481 if (mask) gdk_pixmap_ref (mask);
1482 cell_set_pixtext (clist, clist_row, column, text, spacing, pixmap, mask);
1484 /* redraw the list if it's not frozen */
1485 if (!GTK_CLIST_FROZEN (clist))
1487 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1488 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1493 gtk_clist_get_pixtext (GtkCList * clist,
1498 GdkPixmap ** pixmap,
1501 GtkCListRow *clist_row;
1503 g_return_val_if_fail (clist != NULL, 0);
1504 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
1506 if (row < 0 || row >= clist->rows)
1508 if (column < 0 || column >= clist->columns)
1511 clist_row = (g_list_nth (clist->row_list, row))->data;
1513 if (clist_row->cell[column].type != GTK_CELL_PIXTEXT)
1517 *text = GTK_CELL_PIXTEXT (clist_row->cell[column])->text;
1519 *spacing = GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing;
1521 *pixmap = GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap;
1523 /* mask can be NULL */
1524 *mask = GTK_CELL_PIXTEXT (clist_row->cell[column])->mask;
1530 gtk_clist_set_foreground (GtkCList * clist,
1534 GtkCListRow *clist_row;
1536 g_return_if_fail (clist != NULL);
1537 g_return_if_fail (GTK_IS_CLIST (clist));
1539 if (row < 0 || row >= clist->rows)
1542 clist_row = (g_list_nth (clist->row_list, row))->data;
1546 clist_row->foreground = *color;
1547 clist_row->fg_set = TRUE;
1550 clist_row->fg_set = FALSE;
1552 if (!GTK_CLIST_FROZEN (clist)
1553 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1554 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1558 gtk_clist_set_background (GtkCList * clist,
1562 GtkCListRow *clist_row;
1564 g_return_if_fail (clist != NULL);
1565 g_return_if_fail (GTK_IS_CLIST (clist));
1567 if (row < 0 || row >= clist->rows)
1570 clist_row = (g_list_nth (clist->row_list, row))->data;
1574 clist_row->background = *color;
1575 clist_row->bg_set = TRUE;
1578 clist_row->bg_set = FALSE;
1580 if (!GTK_CLIST_FROZEN (clist)
1581 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1582 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1586 gtk_clist_set_shift (GtkCList * clist,
1592 GtkCListRow *clist_row;
1594 g_return_if_fail (clist != NULL);
1595 g_return_if_fail (GTK_IS_CLIST (clist));
1597 if (row < 0 || row >= clist->rows)
1599 if (column < 0 || column >= clist->columns)
1602 clist_row = (g_list_nth (clist->row_list, row))->data;
1604 clist_row->cell[column].vertical = vertical;
1605 clist_row->cell[column].horizontal = horizontal;
1607 if (!GTK_CLIST_FROZEN (clist)
1608 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1609 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1613 gtk_clist_append (GtkCList * clist,
1617 GtkCListRow *clist_row;
1619 g_return_val_if_fail (clist != NULL, -1);
1620 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1622 clist_row = row_new (clist);
1625 /* set the text in the row's columns */
1627 for (i = 0; i < clist->columns; i++)
1629 cell_set_text (clist, clist_row, i, text[i]);
1631 /* keeps track of the end of the list so the list
1632 * doesn't have to be traversed every time a item is added */
1633 if (!clist->row_list)
1635 clist->row_list = g_list_append (clist->row_list, clist_row);
1636 clist->row_list_end = clist->row_list;
1638 /* check the selection mode to see if we should select
1639 * the first row automaticly */
1640 switch (clist->selection_mode)
1642 case GTK_SELECTION_BROWSE:
1643 select_row (clist, 0, -1, NULL);
1651 clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
1653 /* redraw the list if it's not frozen */
1654 if (!GTK_CLIST_FROZEN (clist))
1656 adjust_scrollbars (clist);
1658 if (gtk_clist_row_is_visible (clist, clist->rows - 1) != GTK_VISIBILITY_NONE)
1659 draw_rows (clist, NULL);
1662 /* return index of the row */
1663 return clist->rows - 1;
1667 gtk_clist_insert (GtkCList * clist,
1672 GtkCListRow *clist_row;
1674 g_return_if_fail (clist != NULL);
1675 g_return_if_fail (GTK_IS_CLIST (clist));
1676 g_return_if_fail (text != NULL);
1678 /* return if out of bounds */
1679 if (row < 0 || row > clist->rows)
1682 if (clist->rows == 0)
1683 gtk_clist_append (clist, text);
1686 /* create the row */
1687 clist_row = row_new (clist);
1689 /* set the text in the row's columns */
1691 for (i = 0; i < clist->columns; i++)
1693 cell_set_text (clist, clist_row, i, text[i]);
1695 /* reset the row end pointer if we're inserting at the
1696 * end of the list */
1697 if (row == clist->rows)
1698 clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
1700 clist->row_list = g_list_insert (clist->row_list, clist_row, row);
1704 if (row < ROW_FROM_YPIXEL (clist, 0))
1705 clist->voffset -= (clist->row_height + CELL_SPACING);
1707 /* syncronize the selection list */
1708 sync_selection (clist, row, SYNC_INSERT);
1711 /* redraw the list if it isn't frozen */
1712 if (!GTK_CLIST_FROZEN (clist))
1714 adjust_scrollbars (clist);
1716 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1717 draw_rows (clist, NULL);
1722 gtk_clist_remove (GtkCList * clist,
1725 gint was_visible, was_selected;
1727 GtkCListRow *clist_row;
1729 g_return_if_fail (clist != NULL);
1730 g_return_if_fail (GTK_IS_CLIST (clist));
1732 /* return if out of bounds */
1733 if (row < 0 || row > (clist->rows - 1))
1736 was_visible = (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE);
1739 /* get the row we're going to delete */
1740 list = g_list_nth (clist->row_list, row);
1741 clist_row = list->data;
1743 /* if we're removing a selected row, we have to make sure
1744 * it's properly unselected, and then sync up the clist->selected
1745 * list to reflect the deincrimented indexies of rows after the
1747 if (clist_row->state == GTK_STATE_SELECTED)
1749 switch (clist->selection_mode)
1751 case GTK_SELECTION_SINGLE:
1752 case GTK_SELECTION_MULTIPLE:
1753 case GTK_SELECTION_EXTENDED:
1754 unselect_row (clist, row, -1, NULL);
1757 case GTK_SELECTION_BROWSE:
1758 select_row (clist, row - 1, -1, NULL);
1766 /* reset the row end pointer if we're removing at the
1767 * end of the list */
1768 if (row == clist->rows - 1)
1769 clist->row_list_end = list->prev;
1770 if (row >= clist->focus_row && clist->focus_row >=0)
1773 clist->row_list = g_list_remove (clist->row_list, clist_row);
1776 if (row < ROW_FROM_YPIXEL (clist, 0))
1777 clist->voffset += clist->row_height + CELL_SPACING;
1779 sync_selection (clist, row, SYNC_REMOVE);
1782 row_delete (clist, clist_row);
1784 /* redraw the row if it isn't frozen */
1785 if (!GTK_CLIST_FROZEN (clist))
1787 adjust_scrollbars (clist);
1790 draw_rows (clist, NULL);
1795 sync_selection (GtkCList * clist,
1802 if (mode == SYNC_INSERT)
1807 if (clist->focus_row >= row)
1809 clist->focus_row += d;
1810 if (clist->focus_row == -1 && clist->rows >= 1)
1811 clist->focus_row = 0;
1814 if (clist->selection_mode == GTK_SELECTION_BROWSE && clist->anchor != -1)
1815 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
1817 g_list_free (clist->undo_selection);
1818 g_list_free (clist->undo_unselection);
1819 clist->undo_selection = NULL;
1820 clist->undo_unselection = NULL;
1823 clist->drag_pos = -1;
1824 clist->undo_anchor = clist->focus_row;
1826 list = clist->selection;
1829 if (GPOINTER_TO_INT (list->data) >= row)
1830 list->data = ((gchar*) list->data) + d;
1836 gtk_clist_clear (GtkCList * clist)
1838 GTK_CLIST_CLASS_FW (clist)->clear (clist);
1842 real_clear (GtkCList * clist)
1846 g_return_if_fail (clist != NULL);
1847 g_return_if_fail (GTK_IS_CLIST (clist));
1849 /* remove all the rows */
1850 for (list = clist->row_list; list; list = list->next)
1851 row_delete (clist, GTK_CLIST_ROW (list));
1853 g_list_free (clist->row_list);
1855 /* free up the selection list */
1856 g_list_free (clist->selection);
1857 g_list_free (clist->undo_selection);
1858 g_list_free (clist->undo_unselection);
1860 clist->row_list = NULL;
1861 clist->row_list_end = NULL;
1862 clist->selection = NULL;
1863 clist->selection_end = NULL;
1864 clist->undo_selection = NULL;
1865 clist->undo_unselection = NULL;
1868 clist->focus_row = -1;
1870 clist->undo_anchor = -1;
1871 clist->anchor_state = GTK_STATE_SELECTED;
1872 clist->drag_pos = -1;
1874 /* zero-out the scrollbars */
1875 if (clist->vscrollbar)
1877 GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0;
1878 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
1880 if (!GTK_CLIST_FROZEN (clist))
1881 gtk_clist_thaw (clist);
1886 gtk_clist_swap_rows (GtkCList * clist,
1891 GList *list, *link1, *link2;
1894 g_return_if_fail (clist != NULL);
1895 g_return_if_fail (GTK_IS_CLIST (clist));
1897 if (row1 < 0 || row1 > (clist->rows - 1))
1900 if (row2 < 0 || row2 > (clist->rows - 1))
1903 first = MIN (row1, row2);
1904 last = MAX (row1, row2);
1906 link1 = g_list_nth (clist->row_list, first);
1907 link2 = g_list_nth (link1, row2 - row1);
1910 link1->data = link2->data;
1913 list = clist->selection;
1916 if (GPOINTER_TO_INT (list->data) == row1)
1917 GPOINTER_TO_INT (list->data) = row2;
1919 if (GPOINTER_TO_INT (list->data) == row2)
1920 GPOINTER_TO_INT (list->data) = row1;
1925 if (!GTK_CLIST_FROZEN (clist))
1927 if (gtk_clist_row_is_visible (clist, row1) != GTK_VISIBILITY_NONE)
1928 GTK_CLIST_CLASS_FW (clist)->draw_row
1929 (clist, NULL, row1, GTK_CLIST_ROW (link2));
1931 if (gtk_clist_row_is_visible (clist, row2) != GTK_VISIBILITY_NONE)
1932 GTK_CLIST_CLASS_FW (clist)->draw_row
1933 (clist, NULL, row2, GTK_CLIST_ROW (link1));
1938 gtk_clist_set_row_data (GtkCList * clist,
1942 gtk_clist_set_row_data_full (clist, row, data, NULL);
1946 gtk_clist_set_row_data_full (GtkCList * clist,
1949 GtkDestroyNotify destroy)
1951 GtkCListRow *clist_row;
1953 g_return_if_fail (clist != NULL);
1954 g_return_if_fail (GTK_IS_CLIST (clist));
1956 if (row < 0 || row > (clist->rows - 1))
1959 clist_row = (g_list_nth (clist->row_list, row))->data;
1960 clist_row->data = data;
1961 clist_row->destroy = destroy;
1963 /* re-send the selected signal if data is changed/added
1964 * so the application can respond to the new data --
1965 * this could be questionable behavior */
1966 if (clist_row->state == GTK_STATE_SELECTED)
1967 select_row (clist, row, -1, NULL);
1971 gtk_clist_get_row_data (GtkCList * clist,
1974 GtkCListRow *clist_row;
1976 g_return_val_if_fail (clist != NULL, NULL);
1977 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
1979 if (row < 0 || row > (clist->rows - 1))
1982 clist_row = (g_list_nth (clist->row_list, row))->data;
1983 return clist_row->data;
1987 gtk_clist_find_row_from_data (GtkCList * clist,
1993 g_return_val_if_fail (clist != NULL, -1);
1994 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1996 if (clist->rows < 1)
1997 return -1; /* is this an optimization or just worthless? */
1999 for (n = 0, list = clist->row_list; list; n++, list = list->next)
2000 if (GTK_CLIST_ROW (list)->data == data)
2007 gtk_clist_select_row (GtkCList * clist,
2011 g_return_if_fail (clist != NULL);
2012 g_return_if_fail (GTK_IS_CLIST (clist));
2014 if (row < 0 || row >= clist->rows)
2017 if (column < -1 || column >= clist->columns)
2020 select_row (clist, row, column, NULL);
2024 gtk_clist_unselect_row (GtkCList * clist,
2028 g_return_if_fail (clist != NULL);
2029 g_return_if_fail (GTK_IS_CLIST (clist));
2031 if (row < 0 || row >= clist->rows)
2034 if (column < -1 || column >= clist->columns)
2037 unselect_row (clist, row, column, NULL);
2041 gtk_clist_row_is_visible (GtkCList * clist,
2046 g_return_val_if_fail (clist != NULL, 0);
2047 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
2049 if (row < 0 || row >= clist->rows)
2050 return GTK_VISIBILITY_NONE;
2052 if (clist->row_height == 0)
2053 return GTK_VISIBILITY_NONE;
2055 if (row < ROW_FROM_YPIXEL (clist, 0))
2056 return GTK_VISIBILITY_NONE;
2058 if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height))
2059 return GTK_VISIBILITY_NONE;
2061 top = ROW_TOP_YPIXEL (clist, row);
2064 || ((top + clist->row_height) >= clist->clist_window_height))
2065 return GTK_VISIBILITY_PARTIAL;
2067 return GTK_VISIBILITY_FULL;
2071 gtk_clist_get_vadjustment (GtkCList * clist)
2073 g_return_val_if_fail (clist != NULL, NULL);
2074 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2076 return gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
2080 gtk_clist_get_hadjustment (GtkCList * clist)
2082 g_return_val_if_fail (clist != NULL, NULL);
2083 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2085 return gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
2089 gtk_clist_set_policy (GtkCList * clist,
2090 GtkPolicyType vscrollbar_policy,
2091 GtkPolicyType hscrollbar_policy)
2093 g_return_if_fail (clist != NULL);
2094 g_return_if_fail (GTK_IS_CLIST (clist));
2096 if (clist->vscrollbar_policy != vscrollbar_policy)
2098 clist->vscrollbar_policy = vscrollbar_policy;
2100 if (GTK_WIDGET (clist)->parent)
2101 gtk_widget_queue_resize (GTK_WIDGET (clist));
2104 if (clist->hscrollbar_policy != hscrollbar_policy)
2106 clist->hscrollbar_policy = hscrollbar_policy;
2108 if (GTK_WIDGET (clist)->parent)
2109 gtk_widget_queue_resize (GTK_WIDGET (clist));
2114 gtk_clist_undo_selection (GtkCList *clist)
2116 g_return_if_fail (clist != NULL);
2117 g_return_if_fail (GTK_IS_CLIST (clist));
2119 if (clist->selection_mode == GTK_SELECTION_EXTENDED &&
2120 (clist->undo_selection || clist->undo_unselection))
2121 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNDO_SELECTION]);
2125 real_undo_selection (GtkCList *clist)
2129 g_return_if_fail (clist != NULL);
2130 g_return_if_fail (GTK_IS_CLIST (clist));
2132 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
2133 clist->selection_mode != GTK_SELECTION_EXTENDED)
2136 if (clist->anchor >= 0)
2137 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
2139 if (!(clist->undo_selection || clist->undo_unselection))
2141 gtk_clist_unselect_all (clist);
2145 for (work = clist->undo_selection; work; work = work->next)
2146 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
2147 GPOINTER_TO_INT (work->data), -1, NULL);
2149 for (work = clist->undo_unselection; work; work = work->next)
2150 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
2151 GPOINTER_TO_INT (work->data), -1, NULL);
2153 if (GTK_WIDGET_HAS_FOCUS (clist) && clist->focus_row != clist->undo_anchor)
2155 gtk_clist_draw_focus (GTK_WIDGET (clist));
2156 clist->focus_row = clist->undo_anchor;
2157 gtk_clist_draw_focus (GTK_WIDGET (clist));
2160 clist->focus_row = clist->undo_anchor;
2162 clist->undo_anchor = -1;
2164 g_list_free (clist->undo_selection);
2165 g_list_free (clist->undo_unselection);
2166 clist->undo_selection = NULL;
2167 clist->undo_unselection = NULL;
2169 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
2170 clist->clist_window_height)
2171 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
2172 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
2173 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
2179 * gtk_clist_finalize
2182 gtk_clist_destroy (GtkObject * object)
2187 g_return_if_fail (object != NULL);
2188 g_return_if_fail (GTK_IS_CLIST (object));
2190 clist = GTK_CLIST (object);
2192 /* freeze the list */
2193 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2195 /* get rid of all the rows */
2196 gtk_clist_clear (clist);
2198 /* Since we don't have a _remove method, unparent the children
2199 * instead of destroying them so the focus will be unset properly.
2200 * (For other containers, the _remove method takes care of the
2201 * unparent) The destroy will happen when the refcount drops
2205 /* destroy the scrollbars */
2206 if (clist->vscrollbar)
2208 gtk_widget_unparent (clist->vscrollbar);
2209 clist->vscrollbar = NULL;
2211 if (clist->hscrollbar)
2213 gtk_widget_unparent (clist->hscrollbar);
2214 clist->hscrollbar = NULL;
2219 gtk_timeout_remove (clist->htimer);
2224 gtk_timeout_remove (clist->vtimer);
2228 /* destroy the column buttons */
2229 for (i = 0; i < clist->columns; i++)
2230 if (clist->column[i].button)
2232 gtk_widget_unparent (clist->column[i].button);
2233 clist->column[i].button = NULL;
2236 if (GTK_OBJECT_CLASS (parent_class)->destroy)
2237 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2241 gtk_clist_finalize (GtkObject * object)
2245 g_return_if_fail (object != NULL);
2246 g_return_if_fail (GTK_IS_CLIST (object));
2248 clist = GTK_CLIST (object);
2250 columns_delete (clist);
2252 g_mem_chunk_destroy (clist->cell_mem_chunk);
2253 g_mem_chunk_destroy (clist->row_mem_chunk);
2255 if (GTK_OBJECT_CLASS (parent_class)->finalize)
2256 (*GTK_OBJECT_CLASS (parent_class)->finalize) (object);
2262 * gtk_clist_unrealize
2267 * gtk_clist_button_press
2268 * gtk_clist_button_release
2269 * gtk_clist_button_motion
2270 * gtk_clist_size_request
2271 * gtk_clist_size_allocate
2274 gtk_clist_realize (GtkWidget * widget)
2278 GdkWindowAttr attributes;
2279 gint attributes_mask;
2283 g_return_if_fail (widget != NULL);
2284 g_return_if_fail (GTK_IS_CLIST (widget));
2286 clist = GTK_CLIST (widget);
2288 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2290 add_style_data (clist);
2292 border_width = GTK_CONTAINER (widget)->border_width;
2294 attributes.window_type = GDK_WINDOW_CHILD;
2295 attributes.x = widget->allocation.x + border_width;
2296 attributes.y = widget->allocation.y + border_width;
2297 attributes.width = widget->allocation.width - border_width * 2;
2298 attributes.height = widget->allocation.height - border_width * 2;
2299 attributes.wclass = GDK_INPUT_OUTPUT;
2300 attributes.visual = gtk_widget_get_visual (widget);
2301 attributes.colormap = gtk_widget_get_colormap (widget);
2302 attributes.event_mask = gtk_widget_get_events (widget);
2303 attributes.event_mask |= (GDK_EXPOSURE_MASK |
2304 GDK_BUTTON_PRESS_MASK |
2305 GDK_BUTTON_RELEASE_MASK |
2306 GDK_KEY_PRESS_MASK |
2307 GDK_KEY_RELEASE_MASK);
2308 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2311 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
2312 gdk_window_set_user_data (widget->window, clist);
2314 widget->style = gtk_style_attach (widget->style, widget->window);
2316 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
2318 /* column-title window */
2320 attributes.x = clist->column_title_area.x;
2321 attributes.y = clist->column_title_area.y;
2322 attributes.width = clist->column_title_area.width;
2323 attributes.height = clist->column_title_area.height;
2325 clist->title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2326 gdk_window_set_user_data (clist->title_window, clist);
2328 gtk_style_set_background (widget->style, clist->title_window, GTK_STATE_SELECTED);
2329 gdk_window_show (clist->title_window);
2331 /* set things up so column buttons are drawn in title window */
2332 for (i = 0; i < clist->columns; i++)
2333 if (clist->column[i].button)
2334 gtk_widget_set_parent_window (clist->column[i].button, clist->title_window);
2337 attributes.x = clist->internal_allocation.x + widget->style->klass->xthickness;
2338 attributes.y = clist->internal_allocation.y + widget->style->klass->ythickness +
2339 clist->column_title_area.height;
2340 attributes.width = clist->clist_window_width;
2341 attributes.height = clist->clist_window_height;
2343 clist->clist_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2344 gdk_window_set_user_data (clist->clist_window, clist);
2346 gdk_window_set_background (clist->clist_window, &widget->style->bg[GTK_STATE_PRELIGHT]);
2347 gdk_window_show (clist->clist_window);
2348 gdk_window_get_size (clist->clist_window, &clist->clist_window_width,
2349 &clist->clist_window_height);
2351 /* create resize windows */
2352 attributes.wclass = GDK_INPUT_ONLY;
2353 attributes.event_mask = (GDK_BUTTON_PRESS_MASK |
2354 GDK_BUTTON_RELEASE_MASK |
2355 GDK_POINTER_MOTION_MASK |
2356 GDK_POINTER_MOTION_HINT_MASK |
2357 GDK_KEY_PRESS_MASK);
2358 attributes.cursor = clist->cursor_drag = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
2359 attributes_mask = GDK_WA_CURSOR;
2361 for (i = 0; i < clist->columns; i++)
2363 clist->column[i].window = gdk_window_new (clist->title_window, &attributes, attributes_mask);
2364 gdk_window_set_user_data (clist->column[i].window, clist);
2367 /* This is slightly less efficient than creating them with the
2368 * right size to begin with, but easier
2370 size_allocate_title_buttons (clist);
2373 clist->fg_gc = gdk_gc_new (widget->window);
2374 clist->bg_gc = gdk_gc_new (widget->window);
2376 /* We'll use this gc to do scrolling as well */
2377 gdk_gc_set_exposures (clist->fg_gc, TRUE);
2379 values.foreground = widget->style->white;
2380 values.function = GDK_XOR;
2381 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
2382 clist->xor_gc = gdk_gc_new_with_values (widget->window,
2390 gtk_clist_unrealize (GtkWidget * widget)
2395 g_return_if_fail (widget != NULL);
2396 g_return_if_fail (GTK_IS_CLIST (widget));
2398 clist = GTK_CLIST (widget);
2400 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2402 gdk_cursor_destroy (clist->cursor_drag);
2403 gdk_gc_destroy (clist->xor_gc);
2404 gdk_gc_destroy (clist->fg_gc);
2405 gdk_gc_destroy (clist->bg_gc);
2407 for (i = 0; i < clist->columns; i++)
2408 if (clist->column[i].window)
2410 gdk_window_set_user_data (clist->column[i].window, NULL);
2411 gdk_window_destroy (clist->column[i].window);
2412 clist->column[i].window = NULL;
2415 gdk_window_set_user_data (clist->clist_window, NULL);
2416 gdk_window_destroy (clist->clist_window);
2417 clist->clist_window = NULL;
2419 gdk_window_set_user_data (clist->title_window, NULL);
2420 gdk_window_destroy (clist->title_window);
2421 clist->title_window = NULL;
2423 clist->cursor_drag = NULL;
2424 clist->xor_gc = NULL;
2425 clist->fg_gc = NULL;
2426 clist->bg_gc = NULL;
2428 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
2429 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2433 gtk_clist_map (GtkWidget * widget)
2438 g_return_if_fail (widget != NULL);
2439 g_return_if_fail (GTK_IS_CLIST (widget));
2441 clist = GTK_CLIST (widget);
2443 if (!GTK_WIDGET_MAPPED (widget))
2445 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
2447 gdk_window_show (widget->window);
2448 gdk_window_show (clist->title_window);
2449 gdk_window_show (clist->clist_window);
2451 /* map column buttons */
2452 for (i = 0; i < clist->columns; i++)
2453 if (clist->column[i].button &&
2454 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
2455 !GTK_WIDGET_MAPPED (clist->column[i].button))
2456 gtk_widget_map (clist->column[i].button);
2458 /* map resize windows AFTER column buttons (above) */
2459 for (i = 0; i < clist->columns; i++)
2460 if (clist->column[i].window && clist->column[i].button)
2461 gdk_window_show (clist->column[i].window);
2463 /* map vscrollbars */
2464 if (GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
2465 !GTK_WIDGET_MAPPED (clist->vscrollbar))
2466 gtk_widget_map (clist->vscrollbar);
2468 if (GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
2469 !GTK_WIDGET_MAPPED (clist->hscrollbar))
2470 gtk_widget_map (clist->hscrollbar);
2472 /* unfreeze the list */
2473 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
2478 gtk_clist_unmap (GtkWidget * widget)
2483 g_return_if_fail (widget != NULL);
2484 g_return_if_fail (GTK_IS_CLIST (widget));
2486 clist = GTK_CLIST (widget);
2488 if (GTK_WIDGET_MAPPED (widget))
2490 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
2492 for (i = 0; i < clist->columns; i++)
2493 if (clist->column[i].window)
2494 gdk_window_hide (clist->column[i].window);
2496 gdk_window_hide (clist->clist_window);
2497 gdk_window_hide (clist->title_window);
2498 gdk_window_hide (widget->window);
2500 /* unmap scrollbars */
2501 if (GTK_WIDGET_MAPPED (clist->vscrollbar))
2502 gtk_widget_unmap (clist->vscrollbar);
2504 if (GTK_WIDGET_MAPPED (clist->hscrollbar))
2505 gtk_widget_unmap (clist->hscrollbar);
2507 /* unmap column buttons */
2508 for (i = 0; i < clist->columns; i++)
2509 if (clist->column[i].button &&
2510 GTK_WIDGET_MAPPED (clist->column[i].button))
2511 gtk_widget_unmap (clist->column[i].button);
2513 /* freeze the list */
2514 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2519 gtk_clist_draw (GtkWidget * widget,
2520 GdkRectangle * area)
2525 g_return_if_fail (widget != NULL);
2526 g_return_if_fail (GTK_IS_CLIST (widget));
2527 g_return_if_fail (area != NULL);
2529 if (GTK_WIDGET_DRAWABLE (widget))
2531 clist = GTK_CLIST (widget);
2532 border_width = GTK_CONTAINER (widget)->border_width;
2534 gdk_window_clear_area (widget->window,
2535 area->x - border_width,
2536 area->y - border_width,
2537 area->width, area->height);
2539 /* draw list shadow/border */
2540 gtk_draw_shadow (widget->style, widget->window,
2541 GTK_STATE_NORMAL, clist->shadow_type,
2543 clist->clist_window_width + (2 * widget->style->klass->xthickness),
2544 clist->clist_window_height + (2 * widget->style->klass->ythickness) +
2545 clist->column_title_area.height);
2547 gdk_window_clear_area (clist->clist_window,
2550 draw_rows (clist, NULL);
2555 gtk_clist_expose (GtkWidget * widget,
2556 GdkEventExpose * event)
2560 g_return_val_if_fail (widget != NULL, FALSE);
2561 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2562 g_return_val_if_fail (event != NULL, FALSE);
2564 if (GTK_WIDGET_DRAWABLE (widget))
2566 clist = GTK_CLIST (widget);
2569 if (event->window == widget->window)
2570 gtk_draw_shadow (widget->style, widget->window,
2571 GTK_STATE_NORMAL, clist->shadow_type,
2573 clist->clist_window_width + (2 * widget->style->klass->xthickness),
2574 clist->clist_window_height + (2 * widget->style->klass->ythickness) +
2575 clist->column_title_area.height);
2577 /* exposure events on the list */
2578 if (event->window == clist->clist_window)
2579 draw_rows (clist, &event->area);
2586 gtk_clist_button_press (GtkWidget * widget,
2587 GdkEventButton * event)
2596 g_return_val_if_fail (widget != NULL, FALSE);
2597 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2598 g_return_val_if_fail (event != NULL, FALSE);
2600 clist = GTK_CLIST (widget);
2602 /* we don't handle button 2 and 3 */
2603 if (event->button != 1)
2606 /* selections on the list */
2607 if (event->window == clist->clist_window)
2612 if (get_selection_info (clist, x, y, &row, &column))
2614 gint old_row = clist->focus_row;
2616 if (clist->focus_row == -1)
2619 if (event->type == GDK_BUTTON_PRESS)
2621 GTK_CLIST_SET_FLAG (clist, CLIST_DRAG_SELECTION);
2622 gdk_pointer_grab (clist->clist_window, FALSE,
2623 GDK_POINTER_MOTION_HINT_MASK |
2624 GDK_BUTTON1_MOTION_MASK |
2625 GDK_BUTTON_RELEASE_MASK,
2626 NULL, NULL, event->time);
2627 gtk_grab_add (widget);
2629 else if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (widget))
2631 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
2632 gtk_grab_remove (widget);
2633 gdk_pointer_ungrab (event->time);
2636 if (GTK_CLIST_ADD_MODE (clist))
2638 GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
2639 if (GTK_WIDGET_HAS_FOCUS (widget))
2641 gtk_clist_draw_focus (widget);
2642 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2643 GDK_LINE_SOLID, 0, 0);
2644 clist->focus_row = row;
2645 gtk_clist_draw_focus (widget);
2649 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2650 GDK_LINE_SOLID, 0, 0);
2651 clist->focus_row = row;
2654 else if (row != clist->focus_row)
2656 if (GTK_WIDGET_HAS_FOCUS (widget))
2658 gtk_clist_draw_focus (widget);
2659 clist->focus_row = row;
2660 gtk_clist_draw_focus (widget);
2663 clist->focus_row = row;
2666 if (!GTK_WIDGET_HAS_FOCUS (widget))
2667 gtk_widget_grab_focus (widget);
2669 switch (clist->selection_mode)
2671 case GTK_SELECTION_SINGLE:
2672 case GTK_SELECTION_MULTIPLE:
2673 if (event->type != GDK_BUTTON_PRESS)
2674 select_row (clist, row, column, (GdkEvent *) event);
2676 clist->anchor = row;
2679 case GTK_SELECTION_BROWSE:
2680 select_row (clist, row, column, (GdkEvent *) event);
2683 case GTK_SELECTION_EXTENDED:
2684 if (event->type != GDK_BUTTON_PRESS)
2686 if (clist->anchor != -1)
2688 update_extended_selection (clist, clist->focus_row);
2689 GTK_CLIST_CLASS_FW (clist)->resync_selection
2690 (clist, (GdkEvent *) event);
2692 select_row (clist, row, column, (GdkEvent *) event);
2696 if (event->state & GDK_CONTROL_MASK)
2698 if (event->state & GDK_SHIFT_MASK)
2700 if (clist->anchor < 0)
2702 g_list_free (clist->undo_selection);
2703 g_list_free (clist->undo_unselection);
2704 clist->undo_selection = NULL;
2705 clist->undo_unselection = NULL;
2706 clist->anchor = old_row;
2707 clist->drag_pos = old_row;
2708 clist->undo_anchor = old_row;
2710 update_extended_selection (clist, clist->focus_row);
2714 if (clist->anchor == -1)
2715 set_anchor (clist, TRUE, row, old_row);
2717 update_extended_selection (clist, clist->focus_row);
2722 if (event->state & GDK_SHIFT_MASK)
2724 set_anchor (clist, FALSE, old_row, old_row);
2725 update_extended_selection (clist, clist->focus_row);
2729 if (clist->anchor == -1)
2730 set_anchor (clist, FALSE, row, old_row);
2732 update_extended_selection (clist, clist->focus_row);
2743 /* press on resize windows */
2744 for (i = 0; i < clist->columns; i++)
2745 if (clist->column[i].window && event->window == clist->column[i].window)
2747 GTK_CLIST_SET_FLAG (clist, CLIST_IN_DRAG);
2748 gtk_widget_get_pointer (widget, &clist->x_drag, NULL);
2750 gdk_pointer_grab (clist->column[i].window, FALSE,
2751 GDK_POINTER_MOTION_HINT_MASK |
2752 GDK_BUTTON1_MOTION_MASK |
2753 GDK_BUTTON_RELEASE_MASK,
2754 NULL, NULL, event->time);
2755 gtk_grab_add (widget);
2757 if (GTK_CLIST_ADD_MODE (clist))
2758 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
2760 draw_xor_line (clist);
2768 gtk_clist_button_release (GtkWidget * widget,
2769 GdkEventButton * event)
2771 gint i, x, width, visible;
2774 g_return_val_if_fail (widget != NULL, FALSE);
2775 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2776 g_return_val_if_fail (event != NULL, FALSE);
2778 clist = GTK_CLIST (widget);
2780 /* we don't handle button 2 and 3 */
2781 if (event->button != 1)
2784 /* release on resize windows */
2785 if (GTK_CLIST_IN_DRAG (clist))
2786 for (i = 0; i < clist->columns; i++)
2787 if (clist->column[i].window && event->window == clist->column[i].window)
2789 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
2790 gtk_widget_get_pointer (widget, &x, NULL);
2791 width = new_column_width (clist, i, &x, &visible);
2793 gtk_grab_remove (widget);
2794 gdk_pointer_ungrab (event->time);
2797 draw_xor_line (clist);
2799 if (GTK_CLIST_ADD_MODE (clist))
2801 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2802 GDK_LINE_ON_OFF_DASH, 0, 0);
2803 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
2806 resize_column (clist, i, width);
2810 if (GTK_CLIST_DRAG_SELECTION (clist))
2815 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
2816 gtk_grab_remove (widget);
2817 gdk_pointer_ungrab (event->time);
2820 gtk_timeout_remove (clist->htimer);
2825 gtk_timeout_remove (clist->vtimer);
2828 switch (clist->selection_mode)
2830 case GTK_SELECTION_EXTENDED:
2831 if (!(event->state & GDK_SHIFT_MASK) ||
2832 event->x < 0 || event->x >= clist->clist_window_width ||
2833 event->y < 0 || event->y >= clist->clist_window_height)
2834 GTK_CLIST_CLASS_FW (clist)->resync_selection
2835 (clist, (GdkEvent *) event);
2838 case GTK_SELECTION_SINGLE:
2839 case GTK_SELECTION_MULTIPLE:
2840 if (get_selection_info (clist, event->x, event->y, &row, &column))
2842 if (clist->anchor == clist->focus_row)
2843 toggle_row (clist, row, column, (GdkEvent *) event);
2857 horizontal_timeout (GtkCList *clist)
2860 GdkEventMotion event;
2861 GdkModifierType mask;
2863 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
2866 gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
2873 gtk_clist_motion (GTK_WIDGET (clist), &event);
2879 vertical_timeout (GtkCList *clist)
2882 GdkEventMotion event;
2883 GdkModifierType mask;
2885 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
2888 gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
2895 gtk_clist_motion (GTK_WIDGET (clist), &event);
2901 move_vertical (GtkCList *clist,
2908 adj = GTK_RANGE (clist->vscrollbar)->adjustment;
2910 y = ROW_TOP_YPIXEL (clist, row) - clist->voffset;
2912 y = y - align * (clist->clist_window_height - clist->row_height)
2913 + (2 * align - 1) * CELL_SPACING;
2915 if (y + adj->page_size > adj->upper)
2916 adj->value = adj->upper - adj->page_size;
2920 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
2924 move_horizontal (GtkCList *clist,
2930 adj = GTK_RANGE (clist->hscrollbar)->adjustment;
2934 upper = adj->upper - adj->page_size;
2935 adj->value = MIN (adj->value, upper);
2936 adj->value = MAX (adj->value, 0.0);
2938 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
2942 gtk_clist_motion (GtkWidget * widget,
2943 GdkEventMotion * event)
2945 gint i, x, y, visible;
2948 g_return_val_if_fail (widget != NULL, FALSE);
2949 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2951 clist = GTK_CLIST (widget);
2953 if (GTK_CLIST_IN_DRAG (clist))
2954 for (i = 0; i < clist->columns; i++)
2955 if (clist->column[i].window && event->window == clist->column[i].window)
2957 if (event->is_hint || event->window != widget->window)
2958 gtk_widget_get_pointer (widget, &x, NULL);
2962 new_column_width (clist, i, &x, &visible);
2963 /* Welcome to my hack! I'm going to use a value of x_drage = -99999 to
2964 * indicate the the xor line is already no visible */
2965 if (!visible && clist->x_drag != -99999)
2967 draw_xor_line (clist);
2968 clist->x_drag = -99999;
2971 if (x != clist->x_drag && visible)
2973 if (clist->x_drag != -99999)
2974 draw_xor_line (clist);
2977 draw_xor_line (clist);
2981 if (GTK_CLIST_DRAG_SELECTION (clist))
2985 if (event->is_hint || event->window != clist->clist_window)
2986 gdk_window_get_pointer (clist->clist_window, &x, &y, NULL);
2988 /* horizontal autoscrolling */
2989 if (LIST_WIDTH (clist) > clist->clist_window_width &&
2990 (x < 0 || x >= clist->clist_window_width))
2992 if (clist->htimer == 0)
2994 clist->htimer = gtk_timeout_add
2995 (SCROLL_TIME, (GtkFunction) horizontal_timeout, clist);
2997 if (!((x < 0 && GTK_RANGE (clist->hscrollbar)->adjustment->value
2998 == 0) || (x >= clist->clist_window_width &&
2999 GTK_RANGE (clist->hscrollbar)->adjustment->value ==
3000 LIST_WIDTH (clist) - clist->clist_window_width)))
3003 move_horizontal (clist, -1 + (x/2));
3005 move_horizontal (clist,
3006 1 + (x - clist->clist_window_width) / 2);
3013 row = ROW_FROM_YPIXEL (clist, y);
3015 /* don't scroll on last pixel row if it's a cell spacing */
3016 if (y == clist->clist_window_height-1 &&
3017 y == ROW_TOP_YPIXEL (clist, row-1) + clist->row_height)
3020 /* vertical autoscrolling */
3021 if (LIST_HEIGHT (clist) > clist->clist_window_height &&
3022 (y < 0 || y >= clist->clist_window_height))
3024 if (clist->vtimer == 0)
3026 clist->vtimer = gtk_timeout_add (SCROLL_TIME,
3027 (GtkFunction) vertical_timeout,
3030 if ((y < 0 && clist->focus_row == 0) ||
3031 (y >= clist->clist_window_height &&
3032 clist->focus_row == clist->rows-1))
3035 if (row < 0 && clist->focus_row > 0)
3037 gtk_clist_draw_focus (widget);
3038 clist->focus_row = 0;
3039 gtk_clist_draw_focus (widget);
3041 else if (row > clist->rows - 1 && clist->focus_row
3044 gtk_clist_draw_focus (widget);
3045 clist->focus_row = clist->rows - 1;
3046 gtk_clist_draw_focus (widget);
3048 else if (row >= 0 && row <= clist->rows - 1)
3050 gtk_clist_draw_focus (widget);
3051 clist->focus_row = row;
3052 gtk_clist_draw_focus (widget);
3057 switch (clist->selection_mode)
3059 case GTK_SELECTION_BROWSE:
3060 select_row (clist, clist->focus_row, -1, (GdkEvent *) event);
3063 case GTK_SELECTION_EXTENDED:
3064 update_extended_selection (clist, clist->focus_row);
3072 move_vertical (clist, row, 0);
3074 move_vertical (clist, row, 1);
3080 if (row == clist->focus_row)
3083 /* dragging inside clist_window */
3084 if (row < 0 && clist->focus_row > 0)
3086 gtk_clist_draw_focus (widget);
3087 clist->focus_row = 0;
3088 gtk_clist_draw_focus (widget);
3090 else if (row > clist->rows-1 && clist->focus_row < clist->rows-1)
3092 gtk_clist_draw_focus (widget);
3093 clist->focus_row = clist->rows-1;
3094 gtk_clist_draw_focus (widget);
3096 else if (row >= 0 && row <= clist->rows-1)
3098 gtk_clist_draw_focus (widget);
3099 clist->focus_row = row;
3100 gtk_clist_draw_focus (widget);
3105 switch (clist->selection_mode)
3107 case GTK_SELECTION_EXTENDED:
3108 update_extended_selection (clist, clist->focus_row);
3111 case GTK_SELECTION_BROWSE:
3112 select_row (clist, clist->focus_row, -1, (GdkEvent *) event);
3119 if (ROW_TOP_YPIXEL(clist, clist->focus_row) + clist->row_height <= 0)
3120 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
3121 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
3122 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
3123 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) >=
3124 clist->clist_window_height)
3125 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
3126 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
3127 clist->clist_window_height)
3128 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
3134 gtk_clist_size_request (GtkWidget * widget,
3135 GtkRequisition * requisition)
3140 g_return_if_fail (widget != NULL);
3141 g_return_if_fail (GTK_IS_CLIST (widget));
3142 g_return_if_fail (requisition != NULL);
3144 clist = GTK_CLIST (widget);
3146 add_style_data (clist);
3148 requisition->width = 0;
3149 requisition->height = 0;
3151 /* compute the size of the column title (title) area */
3152 clist->column_title_area.height = 0;
3153 if (GTK_CLIST_SHOW_TITLES (clist))
3154 for (i = 0; i < clist->columns; i++)
3155 if (clist->column[i].button)
3157 gtk_widget_size_request (clist->column[i].button, &clist->column[i].button->requisition);
3158 clist->column_title_area.height = MAX (clist->column_title_area.height,
3159 clist->column[i].button->requisition.height);
3161 requisition->height += clist->column_title_area.height;
3163 /* add the vscrollbar space */
3164 if ((clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
3165 GTK_WIDGET_VISIBLE (clist->vscrollbar))
3167 gtk_widget_size_request (clist->vscrollbar, &clist->vscrollbar->requisition);
3169 requisition->width += clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist);
3170 requisition->height = MAX (requisition->height,
3171 clist->vscrollbar->requisition.height);
3174 /* add the hscrollbar space */
3175 if ((clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
3176 GTK_WIDGET_VISIBLE (clist->hscrollbar))
3178 gtk_widget_size_request (clist->hscrollbar, &clist->hscrollbar->requisition);
3180 requisition->height += clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist);
3181 requisition->width = MAX (clist->hscrollbar->requisition.width,
3182 requisition->width -
3183 clist->vscrollbar->requisition.width);
3187 requisition->width += widget->style->klass->xthickness * 2 +
3188 GTK_CONTAINER (widget)->border_width * 2;
3189 requisition->height += widget->style->klass->ythickness * 2 +
3190 GTK_CONTAINER (widget)->border_width * 2;
3194 gtk_clist_size_allocate (GtkWidget * widget,
3195 GtkAllocation * allocation)
3198 GtkAllocation clist_allocation;
3199 GtkAllocation child_allocation;
3200 gint i, vscrollbar_vis, hscrollbar_vis;
3202 g_return_if_fail (widget != NULL);
3203 g_return_if_fail (GTK_IS_CLIST (widget));
3204 g_return_if_fail (allocation != NULL);
3206 clist = GTK_CLIST (widget);
3207 widget->allocation = *allocation;
3209 if (GTK_WIDGET_REALIZED (widget))
3211 gdk_window_move_resize (widget->window,
3212 allocation->x + GTK_CONTAINER (widget)->border_width,
3213 allocation->y + GTK_CONTAINER (widget)->border_width,
3214 allocation->width - GTK_CONTAINER (widget)->border_width * 2,
3215 allocation->height - GTK_CONTAINER (widget)->border_width * 2);
3218 /* use internal allocation structure for all the math
3219 * because it's easier than always subtracting the container
3221 clist->internal_allocation.x = 0;
3222 clist->internal_allocation.y = 0;
3223 clist->internal_allocation.width = MAX (1, allocation->width -
3224 GTK_CONTAINER (widget)->border_width * 2);
3225 clist->internal_allocation.height = MAX (1, allocation->height -
3226 GTK_CONTAINER (widget)->border_width * 2);
3228 /* allocate clist window assuming no scrollbars */
3229 clist_allocation.x = clist->internal_allocation.x + widget->style->klass->xthickness;
3230 clist_allocation.y = clist->internal_allocation.y + widget->style->klass->ythickness +
3231 clist->column_title_area.height;
3232 clist_allocation.width = MAX (1, clist->internal_allocation.width -
3233 (2 * widget->style->klass->xthickness));
3234 clist_allocation.height = MAX (1, clist->internal_allocation.height -
3235 (2 * widget->style->klass->ythickness) -
3236 clist->column_title_area.height);
3239 * here's where we decide to show/not show the scrollbars
3244 for (i = 0; i <= 1; i++)
3246 if (LIST_HEIGHT (clist) <= clist_allocation.height &&
3247 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
3253 if (!vscrollbar_vis)
3256 clist_allocation.width = MAX (1, clist_allocation.width -
3257 (clist->vscrollbar->requisition.width +
3258 SCROLLBAR_SPACING (clist)));
3262 if (LIST_WIDTH (clist) <= clist_allocation.width &&
3263 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
3269 if (!hscrollbar_vis)
3272 clist_allocation.height = MAX (1, clist_allocation.height -
3273 (clist->hscrollbar->requisition.height +
3274 SCROLLBAR_SPACING (clist)));
3279 clist->clist_window_width = clist_allocation.width;
3280 clist->clist_window_height = clist_allocation.height;
3282 if (GTK_WIDGET_REALIZED (widget))
3284 gdk_window_move_resize (clist->clist_window,
3287 clist_allocation.width,
3288 clist_allocation.height);
3291 /* position the window which holds the column title buttons */
3292 clist->column_title_area.x = widget->style->klass->xthickness;
3293 clist->column_title_area.y = widget->style->klass->ythickness;
3294 clist->column_title_area.width = clist_allocation.width;
3296 if (GTK_WIDGET_REALIZED (widget))
3298 gdk_window_move_resize (clist->title_window,
3299 clist->column_title_area.x,
3300 clist->column_title_area.y,
3301 clist->column_title_area.width,
3302 clist->column_title_area.height);
3305 /* column button allocation */
3306 size_allocate_columns (clist);
3308 if (GTK_WIDGET_REALIZED (widget))
3309 size_allocate_title_buttons (clist);
3311 adjust_scrollbars (clist);
3313 /* allocate the vscrollbar */
3316 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
3317 gtk_widget_show (clist->vscrollbar);
3319 child_allocation.x = clist->internal_allocation.x +
3320 clist->internal_allocation.width -
3321 clist->vscrollbar->requisition.width;
3322 child_allocation.y = clist->internal_allocation.y;
3323 child_allocation.width = clist->vscrollbar->requisition.width;
3324 child_allocation.height = MAX (1, clist->internal_allocation.height -
3325 (hscrollbar_vis ? (clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist)) : 0));
3327 gtk_widget_size_allocate (clist->vscrollbar, &child_allocation);
3331 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
3332 gtk_widget_hide (clist->vscrollbar);
3337 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
3338 gtk_widget_show (clist->hscrollbar);
3340 child_allocation.x = clist->internal_allocation.x;
3341 child_allocation.y = clist->internal_allocation.y +
3342 clist->internal_allocation.height -
3343 clist->hscrollbar->requisition.height;
3344 child_allocation.width = MAX (1, clist->internal_allocation.width -
3345 (vscrollbar_vis ? (clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist)) : 0));
3346 child_allocation.height = clist->hscrollbar->requisition.height;
3348 gtk_widget_size_allocate (clist->hscrollbar, &child_allocation);
3352 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
3353 gtk_widget_hide (clist->hscrollbar);
3356 /* set the vscrollbar adjustments */
3357 adjust_scrollbars (clist);
3365 gtk_clist_foreach (GtkContainer * container,
3366 GtkCallback callback,
3367 gpointer callback_data)
3372 g_return_if_fail (container != NULL);
3373 g_return_if_fail (GTK_IS_CLIST (container));
3374 g_return_if_fail (callback != NULL);
3376 clist = GTK_CLIST (container);
3378 /* callback for the column buttons */
3379 for (i = 0; i < clist->columns; i++)
3380 if (clist->column[i].button)
3381 (*callback) (clist->column[i].button, callback_data);
3383 /* callbacks for the scrollbars */
3384 if (clist->vscrollbar)
3385 (*callback) (clist->vscrollbar, callback_data);
3386 if (clist->hscrollbar)
3387 (*callback) (clist->hscrollbar, callback_data);
3396 draw_row (GtkCList * clist,
3397 GdkRectangle * area,
3399 GtkCListRow * clist_row)
3402 GdkGC *fg_gc, *bg_gc;
3403 GdkRectangle row_rectangle, cell_rectangle, clip_rectangle, intersect_rectangle,
3405 gint i, offset = 0, width, height, pixmap_width = 0;
3406 gint xsrc, ysrc, xdest, ydest;
3408 g_return_if_fail (clist != NULL);
3410 /* bail now if we arn't drawable yet */
3411 if (!GTK_WIDGET_DRAWABLE (clist))
3414 if (row < 0 || row >= clist->rows)
3417 widget = GTK_WIDGET (clist);
3419 /* if the function is passed the pointer to the row instead of null,
3420 * it avoids this expensive lookup */
3422 clist_row = (g_list_nth (clist->row_list, row))->data;
3424 /* rectangle of the entire row */
3425 row_rectangle.x = 0;
3426 row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
3427 row_rectangle.width = clist->clist_window_width;
3428 row_rectangle.height = clist->row_height;
3430 /* rectangle of the cell spacing above the row */
3431 cell_rectangle.x = 0;
3432 cell_rectangle.y = row_rectangle.y - CELL_SPACING;
3433 cell_rectangle.width = row_rectangle.width;
3434 cell_rectangle.height = CELL_SPACING;
3436 /* rectangle used to clip drawing operations, it's y and height
3437 * positions only need to be set once, so we set them once here.
3438 * the x and width are set withing the drawing loop below once per
3440 clip_rectangle.y = row_rectangle.y;
3441 clip_rectangle.height = row_rectangle.height;
3443 /* select GC for background rectangle */
3444 if (clist_row->state == GTK_STATE_SELECTED)
3446 fg_gc = widget->style->fg_gc[GTK_STATE_SELECTED];
3447 bg_gc = widget->style->bg_gc[GTK_STATE_SELECTED];
3451 if (clist_row->fg_set)
3453 gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
3454 fg_gc = clist->fg_gc;
3457 fg_gc = widget->style->fg_gc[GTK_STATE_NORMAL];
3459 if (clist_row->bg_set)
3461 gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
3462 bg_gc = clist->bg_gc;
3465 bg_gc = widget->style->bg_gc[GTK_STATE_PRELIGHT];
3468 /* draw the cell borders and background */
3471 if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
3472 gdk_draw_rectangle (clist->clist_window,
3473 widget->style->base_gc[GTK_STATE_NORMAL],
3475 intersect_rectangle.x,
3476 intersect_rectangle.y,
3477 intersect_rectangle.width,
3478 intersect_rectangle.height);
3480 /* the last row has to clear it's bottom cell spacing too */
3481 if (clist_row == clist->row_list_end->data)
3483 cell_rectangle.y += clist->row_height + CELL_SPACING;
3485 if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
3486 gdk_draw_rectangle (clist->clist_window,
3487 widget->style->base_gc[GTK_STATE_NORMAL],
3489 intersect_rectangle.x,
3490 intersect_rectangle.y,
3491 intersect_rectangle.width,
3492 intersect_rectangle.height);
3495 if (!gdk_rectangle_intersect (area, &row_rectangle, &intersect_rectangle))
3498 if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
3499 gdk_draw_rectangle (clist->clist_window,
3502 intersect_rectangle.x,
3503 intersect_rectangle.y,
3504 intersect_rectangle.width,
3505 intersect_rectangle.height);
3507 gdk_window_clear_area (clist->clist_window,
3508 intersect_rectangle.x,
3509 intersect_rectangle.y,
3510 intersect_rectangle.width,
3511 intersect_rectangle.height);
3515 gdk_draw_rectangle (clist->clist_window,
3516 widget->style->base_gc[GTK_STATE_NORMAL],
3520 cell_rectangle.width,
3521 cell_rectangle.height);
3523 /* the last row has to clear it's bottom cell spacing too */
3524 if (clist_row == clist->row_list_end->data)
3526 cell_rectangle.y += clist->row_height + CELL_SPACING;
3528 gdk_draw_rectangle (clist->clist_window,
3529 widget->style->base_gc[GTK_STATE_NORMAL],
3533 cell_rectangle.width,
3534 cell_rectangle.height);
3537 if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
3538 gdk_draw_rectangle (clist->clist_window,
3543 row_rectangle.width,
3544 row_rectangle.height);
3546 gdk_window_clear_area (clist->clist_window,
3549 row_rectangle.width,
3550 row_rectangle.height);
3553 /* iterate and draw all the columns (row cells) and draw their contents */
3554 for (i = 0; i < clist->columns; i++)
3556 clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
3557 clip_rectangle.width = clist->column[i].area.width;
3559 /* calculate clipping region clipping region */
3562 rect = &clip_rectangle;
3566 if (!gdk_rectangle_intersect (area, &clip_rectangle,
3567 &intersect_rectangle))
3569 rect = &intersect_rectangle;
3572 /* calculate real width for column justification */
3573 switch (clist_row->cell[i].type)
3575 case GTK_CELL_EMPTY:
3580 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
3581 GTK_CELL_TEXT (clist_row->cell[i])->text);
3584 case GTK_CELL_PIXMAP:
3585 gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, &width, &height);
3586 pixmap_width = width;
3589 case GTK_CELL_PIXTEXT:
3590 gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, &width, &height);
3591 pixmap_width = width;
3592 width += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
3593 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
3594 GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
3597 case GTK_CELL_WIDGET:
3607 switch (clist->column[i].justification)
3609 case GTK_JUSTIFY_LEFT:
3610 offset = clip_rectangle.x;
3613 case GTK_JUSTIFY_RIGHT:
3614 offset = (clip_rectangle.x + clip_rectangle.width) - width;
3617 case GTK_JUSTIFY_CENTER:
3618 offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
3621 case GTK_JUSTIFY_FILL:
3622 offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
3630 /* Draw Text or Pixmap */
3631 switch (clist_row->cell[i].type)
3633 case GTK_CELL_EMPTY:
3638 gdk_gc_set_clip_rectangle (fg_gc, rect);
3640 gdk_draw_string (clist->clist_window,
3641 widget->style->font,
3643 offset + clist_row->cell[i].horizontal,
3644 row_rectangle.y + clist->row_center_offset +
3645 clist_row->cell[i].vertical,
3646 GTK_CELL_TEXT (clist_row->cell[i])->text);
3648 gdk_gc_set_clip_rectangle (fg_gc, NULL);
3651 case GTK_CELL_PIXMAP:
3654 xdest = offset + clist_row->cell[i].horizontal;
3655 ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
3656 clist_row->cell[i].vertical;
3658 if (xdest < clip_rectangle.x)
3660 xsrc = clip_rectangle.x - xdest;
3661 pixmap_width -= xsrc;
3662 xdest = clip_rectangle.x;
3665 if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width)
3666 pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest;
3668 if (ydest < clip_rectangle.y)
3670 ysrc = clip_rectangle.y - ydest;
3672 ydest = clip_rectangle.y;
3675 if (ydest + height > clip_rectangle.y + clip_rectangle.height)
3676 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
3678 if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
3680 gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXMAP (clist_row->cell[i])->mask);
3681 gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
3683 gdk_draw_pixmap (clist->clist_window,
3685 GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
3688 pixmap_width, height);
3690 if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
3692 gdk_gc_set_clip_origin (fg_gc, 0, 0);
3693 gdk_gc_set_clip_mask (fg_gc, NULL);
3697 case GTK_CELL_PIXTEXT:
3698 /* draw the pixmap */
3701 xdest = offset + clist_row->cell[i].horizontal;
3702 ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
3703 clist_row->cell[i].vertical;
3705 if (xdest < clip_rectangle.x)
3707 xsrc = clip_rectangle.x - xdest;
3708 pixmap_width -= xsrc;
3709 xdest = clip_rectangle.x;
3712 if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width)
3713 pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest;
3715 if (ydest < clip_rectangle.y)
3717 ysrc = clip_rectangle.y - ydest;
3719 ydest = clip_rectangle.y;
3722 if (ydest + height > clip_rectangle.y + clip_rectangle.height)
3723 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
3725 if (GTK_CELL_PIXTEXT (clist_row->cell[i])->mask)
3727 gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXTEXT (clist_row->cell[i])->mask);
3728 gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
3731 gdk_draw_pixmap (clist->clist_window,
3733 GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
3737 pixmap_width, height);
3739 gdk_gc_set_clip_origin (fg_gc, 0, 0);
3741 offset += pixmap_width + GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
3743 /* draw the string */
3744 gdk_gc_set_clip_rectangle (fg_gc, rect);
3746 gdk_draw_string (clist->clist_window,
3747 widget->style->font,
3749 offset + clist_row->cell[i].horizontal,
3750 row_rectangle.y + clist->row_center_offset +
3751 clist_row->cell[i].vertical,
3752 GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
3754 gdk_gc_set_clip_rectangle (fg_gc, NULL);
3757 case GTK_CELL_WIDGET:
3767 if (clist->focus_row == row && GTK_WIDGET_HAS_FOCUS (widget))
3771 if (gdk_rectangle_intersect (area, &row_rectangle,
3772 &intersect_rectangle))
3774 gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle);
3775 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
3776 row_rectangle.x, row_rectangle.y,
3777 row_rectangle.width - 1,
3778 row_rectangle.height - 1);
3779 gdk_gc_set_clip_rectangle (clist->xor_gc, NULL);
3783 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
3784 row_rectangle.x, row_rectangle.y,
3785 row_rectangle.width - 1, row_rectangle.height - 1);
3790 draw_rows (GtkCList * clist,
3791 GdkRectangle * area)
3794 GtkCListRow *clist_row;
3795 int i, first_row, last_row;
3797 g_return_if_fail (clist != NULL);
3798 g_return_if_fail (GTK_IS_CLIST (clist));
3800 if (clist->row_height == 0 ||
3801 !GTK_WIDGET_DRAWABLE (clist))
3806 first_row = ROW_FROM_YPIXEL (clist, area->y);
3807 last_row = ROW_FROM_YPIXEL (clist, area->y + area->height);
3811 first_row = ROW_FROM_YPIXEL (clist, 0);
3812 last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height);
3815 /* this is a small special case which exposes the bottom cell line
3816 * on the last row -- it might go away if I change the wall the cell spacings
3818 if (clist->rows == first_row)
3821 list = g_list_nth (clist->row_list, first_row);
3825 clist_row = list->data;
3831 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, area, i, clist_row);
3836 gdk_window_clear_area (clist->clist_window, 0, ROW_TOP_YPIXEL (clist, i), -1, -1);
3841 * size_allocate_title_buttons
3842 * size_allocate_columns
3845 size_allocate_title_buttons (GtkCList * clist)
3847 gint i, last_button = 0;
3848 GtkAllocation button_allocation;
3850 if (!GTK_WIDGET_REALIZED (clist))
3853 button_allocation.x = clist->hoffset;
3854 button_allocation.y = 0;
3855 button_allocation.width = 0;
3856 button_allocation.height = clist->column_title_area.height;
3858 for (i = 0; i < clist->columns; i++)
3860 button_allocation.width += clist->column[i].area.width;
3862 if (i == clist->columns - 1)
3863 button_allocation.width += 2 * (CELL_SPACING + COLUMN_INSET);
3865 button_allocation.width += CELL_SPACING + (2 * COLUMN_INSET);
3867 if (i == (clist->columns - 1) || clist->column[i + 1].button)
3869 gtk_widget_size_allocate (clist->column[last_button].button, &button_allocation);
3870 button_allocation.x += button_allocation.width;
3871 button_allocation.width = 0;
3873 gdk_window_show (clist->column[last_button].window);
3874 gdk_window_move_resize (clist->column[last_button].window,
3875 button_allocation.x - (DRAG_WIDTH / 2),
3876 0, DRAG_WIDTH, clist->column_title_area.height);
3878 last_button = i + 1;
3882 gdk_window_hide (clist->column[i].window);
3888 size_allocate_columns (GtkCList * clist)
3890 gint i, xoffset = 0;
3892 for (i = 0; i < clist->columns; i++)
3894 clist->column[i].area.x = xoffset + CELL_SPACING + COLUMN_INSET;
3896 if (i == clist->columns - 1)
3900 if (clist->column[i].width_set)
3902 width = clist->column[i].width;
3906 if (clist->column[i].title)
3907 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
3908 clist->column[i].title);
3913 clist->column[i].area.width = MAX (width,
3914 clist->clist_window_width -
3915 xoffset - (2 * (CELL_SPACING + COLUMN_INSET)));
3920 clist->column[i].area.width = clist->column[i].width;
3923 xoffset += clist->column[i].area.width + CELL_SPACING + (2 * COLUMN_INSET);
3932 * get_selection_info
3935 toggle_row (GtkCList * clist,
3940 GtkCListRow *clist_row;
3942 switch (clist->selection_mode)
3944 case GTK_SELECTION_EXTENDED:
3945 case GTK_SELECTION_MULTIPLE:
3946 case GTK_SELECTION_SINGLE:
3948 clist_row = g_list_nth (clist->row_list, row)->data;
3949 if (clist_row->state == GTK_STATE_SELECTED)
3951 unselect_row (clist, row, column, event);
3955 case GTK_SELECTION_BROWSE:
3956 select_row (clist, row, column, event);
3962 select_row (GtkCList * clist,
3967 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
3968 row, column, event);
3972 unselect_row (GtkCList * clist,
3977 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3978 row, column, event);
3982 real_select_row (GtkCList * clist,
3987 GtkCListRow *clist_row;
3990 gboolean row_selected;
3992 g_return_if_fail (clist != NULL);
3993 g_return_if_fail (GTK_IS_CLIST (clist));
3995 if (row < 0 || row > (clist->rows - 1))
3998 switch (clist->selection_mode)
4000 case GTK_SELECTION_SINGLE:
4001 case GTK_SELECTION_BROWSE:
4003 row_selected = FALSE;
4004 list = clist->selection;
4008 sel_row = GPOINTER_TO_INT (list->data);
4012 row_selected = TRUE;
4014 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
4015 sel_row, column, event);
4025 clist_row = (g_list_nth (clist->row_list, row))->data;
4027 if (clist_row->state != GTK_STATE_NORMAL)
4030 clist_row->state = GTK_STATE_SELECTED;
4031 if (!clist->selection)
4033 clist->selection = g_list_append (clist->selection,
4034 GINT_TO_POINTER (row));
4035 clist->selection_end = clist->selection;
4038 clist->selection_end =
4039 g_list_append (clist->selection_end, GINT_TO_POINTER (row))->next;
4041 if (!GTK_CLIST_FROZEN (clist)
4042 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
4043 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
4047 real_unselect_row (GtkCList * clist,
4052 GtkCListRow *clist_row;
4054 g_return_if_fail (clist != NULL);
4055 g_return_if_fail (GTK_IS_CLIST (clist));
4057 if (row < 0 || row > (clist->rows - 1))
4060 clist_row = (g_list_nth (clist->row_list, row))->data;
4062 if (clist_row->state == GTK_STATE_SELECTED)
4064 clist_row->state = GTK_STATE_NORMAL;
4066 if (clist->selection_end &&
4067 clist->selection_end->data == GINT_TO_POINTER (row))
4068 clist->selection_end = clist->selection_end->prev;
4070 clist->selection = g_list_remove (clist->selection,
4071 GINT_TO_POINTER (row));
4073 if (!GTK_CLIST_FROZEN (clist)
4074 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
4075 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
4080 get_selection_info (GtkCList * clist,
4088 g_return_val_if_fail (clist != NULL, 0);
4089 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
4091 /* bounds checking, return false if the user clicked
4092 * on a blank area */
4093 trow = ROW_FROM_YPIXEL (clist, y);
4094 if (trow >= clist->rows)
4100 tcol = COLUMN_FROM_XPIXEL (clist, x);
4101 if (tcol >= clist->columns)
4111 gtk_clist_get_selection_info (GtkCList *clist,
4117 g_return_val_if_fail (clist != NULL, 0);
4118 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
4119 return get_selection_info (clist, x, y, row, column);
4129 draw_xor_line (GtkCList * clist)
4133 g_return_if_fail (clist != NULL);
4135 widget = GTK_WIDGET (clist);
4137 gdk_draw_line (widget->window, clist->xor_gc,
4139 widget->style->klass->ythickness,
4141 clist->column_title_area.height + clist->clist_window_height + 1);
4144 /* this function returns the new width of the column being resized given
4145 * the column and x position of the cursor; the x cursor position is passed
4146 * in as a pointer and automagicly corrected if it's beyond min/max limits */
4148 new_column_width (GtkCList * clist,
4157 /* first translate the x position from widget->window
4158 * to clist->clist_window */
4159 cx -= GTK_WIDGET (clist)->style->klass->xthickness;
4161 /* rx is x from the list beginning */
4162 rx = cx - clist->hoffset;
4164 /* you can't shrink a column to less than its minimum width */
4165 if (cx < (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH))
4167 *x = cx = COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH +
4168 GTK_WIDGET (clist)->style->klass->xthickness;
4169 cx -= GTK_WIDGET (clist)->style->klass->xthickness;
4170 rx = cx - clist->hoffset;
4173 if (cx > clist->clist_window_width)
4178 /* calculate new column width making sure it doesn't end up
4179 * less than the minimum width */
4180 width = (rx - COLUMN_LEFT (clist, column)) - COLUMN_INSET -
4181 ((clist->columns == (column - 1)) ? CELL_SPACING : 0);
4182 if (width < COLUMN_MIN_WIDTH)
4183 width = COLUMN_MIN_WIDTH;
4188 /* this will do more later */
4190 resize_column (GtkCList * clist,
4194 gtk_clist_set_column_width (clist, column, width);
4199 column_button_create (GtkCList * clist,
4204 button = clist->column[column].button = gtk_button_new ();
4205 gtk_widget_set_parent (button, GTK_WIDGET (clist));
4206 if (GTK_WIDGET_REALIZED (clist) && clist->title_window)
4207 gtk_widget_set_parent_window (clist->column[column].button, clist->title_window);
4209 gtk_signal_connect (GTK_OBJECT (button), "clicked",
4210 (GtkSignalFunc) column_button_clicked,
4213 gtk_widget_show (button);
4217 column_button_clicked (GtkWidget * widget,
4223 g_return_if_fail (widget != NULL);
4224 g_return_if_fail (GTK_IS_CLIST (data));
4226 clist = GTK_CLIST (data);
4228 /* find the column who's button was pressed */
4229 for (i = 0; i < clist->columns; i++)
4230 if (clist->column[i].button == widget)
4233 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i);
4242 * vadjustment_changed
4243 * hadjustment_changed
4244 * vadjustment_value_changed
4245 * hadjustment_value_changed
4248 create_scrollbars (GtkCList * clist)
4250 GtkAdjustment *adjustment;
4252 clist->vscrollbar = gtk_vscrollbar_new (NULL);
4254 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
4256 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
4257 (GtkSignalFunc) vadjustment_changed,
4260 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
4261 (GtkSignalFunc) vadjustment_value_changed,
4264 gtk_widget_set_parent (clist->vscrollbar, GTK_WIDGET (clist));
4265 gtk_widget_show (clist->vscrollbar);
4267 clist->hscrollbar = gtk_hscrollbar_new (NULL);
4269 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
4271 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
4272 (GtkSignalFunc) hadjustment_changed,
4275 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
4276 (GtkSignalFunc) hadjustment_value_changed,
4279 gtk_widget_set_parent (clist->hscrollbar, GTK_WIDGET (clist));
4280 gtk_widget_show (clist->hscrollbar);
4284 adjust_scrollbars (GtkCList * clist)
4286 GTK_RANGE (clist->vscrollbar)->adjustment->page_size = clist->clist_window_height;
4287 GTK_RANGE (clist->vscrollbar)->adjustment->page_increment = clist->clist_window_height / 2;
4288 GTK_RANGE (clist->vscrollbar)->adjustment->step_increment = 10;
4289 GTK_RANGE (clist->vscrollbar)->adjustment->lower = 0;
4290 GTK_RANGE (clist->vscrollbar)->adjustment->upper = LIST_HEIGHT (clist);
4292 if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist))
4294 GTK_RANGE (clist->vscrollbar)->adjustment->value = MAX (0, LIST_HEIGHT (clist) -
4295 clist->clist_window_height);
4296 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment),
4300 GTK_RANGE (clist->hscrollbar)->adjustment->page_size = clist->clist_window_width;
4301 GTK_RANGE (clist->hscrollbar)->adjustment->page_increment = clist->clist_window_width / 2;
4302 GTK_RANGE (clist->hscrollbar)->adjustment->step_increment = 10;
4303 GTK_RANGE (clist->hscrollbar)->adjustment->lower = 0;
4304 GTK_RANGE (clist->hscrollbar)->adjustment->upper = LIST_WIDTH (clist);
4306 if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist))
4308 GTK_RANGE (clist->hscrollbar)->adjustment->value = MAX (0, LIST_WIDTH (clist) -
4309 clist->clist_window_width);
4310 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment),
4314 if (LIST_HEIGHT (clist) <= clist->clist_window_height &&
4315 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
4317 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
4319 gtk_widget_hide (clist->vscrollbar);
4320 gtk_widget_queue_resize (GTK_WIDGET (clist));
4325 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
4327 gtk_widget_show (clist->vscrollbar);
4328 gtk_widget_queue_resize (GTK_WIDGET (clist));
4332 if (LIST_WIDTH (clist) <= clist->clist_window_width &&
4333 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
4335 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
4337 gtk_widget_hide (clist->hscrollbar);
4338 gtk_widget_queue_resize (GTK_WIDGET (clist));
4343 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
4345 gtk_widget_show (clist->hscrollbar);
4346 gtk_widget_queue_resize (GTK_WIDGET (clist));
4350 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
4351 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), "changed");
4355 vadjustment_changed (GtkAdjustment * adjustment,
4360 g_return_if_fail (adjustment != NULL);
4361 g_return_if_fail (data != NULL);
4363 clist = GTK_CLIST (data);
4367 hadjustment_changed (GtkAdjustment * adjustment,
4372 g_return_if_fail (adjustment != NULL);
4373 g_return_if_fail (data != NULL);
4375 clist = GTK_CLIST (data);
4379 check_exposures (GtkCList *clist)
4383 if (!GTK_WIDGET_REALIZED (clist))
4386 /* Make sure graphics expose events are processed before scrolling
4388 while ((event = gdk_event_get_graphics_expose (clist->clist_window)) != NULL)
4390 gtk_widget_event (GTK_WIDGET (clist), event);
4391 if (event->expose.count == 0)
4393 gdk_event_free (event);
4396 gdk_event_free (event);
4401 vadjustment_value_changed (GtkAdjustment * adjustment,
4408 g_return_if_fail (adjustment != NULL);
4409 g_return_if_fail (data != NULL);
4410 g_return_if_fail (GTK_IS_CLIST (data));
4412 clist = GTK_CLIST (data);
4414 if (!GTK_WIDGET_DRAWABLE (clist))
4417 value = adjustment->value;
4419 if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)))
4421 if (value > -clist->voffset)
4424 diff = value + clist->voffset;
4426 /* we have to re-draw the whole screen here... */
4427 if (diff >= clist->clist_window_height)
4429 clist->voffset = -value;
4430 draw_rows (clist, NULL);
4434 if ((diff != 0) && (diff != clist->clist_window_height))
4435 gdk_window_copy_area (clist->clist_window,
4438 clist->clist_window,
4441 clist->clist_window_width,
4442 clist->clist_window_height - diff);
4445 area.y = clist->clist_window_height - diff;
4446 area.width = clist->clist_window_width;
4452 diff = -clist->voffset - value;
4454 /* we have to re-draw the whole screen here... */
4455 if (diff >= clist->clist_window_height)
4457 clist->voffset = -value;
4458 draw_rows (clist, NULL);
4462 if ((diff != 0) && (diff != clist->clist_window_height))
4463 gdk_window_copy_area (clist->clist_window,
4466 clist->clist_window,
4469 clist->clist_window_width,
4470 clist->clist_window_height - diff);
4474 area.width = clist->clist_window_width;
4479 clist->voffset = -value;
4480 if ((diff != 0) && (diff != clist->clist_window_height))
4481 check_exposures (clist);
4484 draw_rows (clist, &area);
4488 hadjustment_value_changed (GtkAdjustment * adjustment,
4498 g_return_if_fail (adjustment != NULL);
4499 g_return_if_fail (data != NULL);
4500 g_return_if_fail (GTK_IS_CLIST (data));
4502 clist = GTK_CLIST (data);
4504 if (!GTK_WIDGET_DRAWABLE (clist) ||
4505 adjustment != gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)))
4508 value = adjustment->value;
4510 /* move the column buttons and resize windows */
4511 for (i = 0; i < clist->columns; i++)
4513 if (clist->column[i].button)
4515 clist->column[i].button->allocation.x -= value + clist->hoffset;
4517 if (clist->column[i].button->window)
4519 gdk_window_move (clist->column[i].button->window,
4520 clist->column[i].button->allocation.x,
4521 clist->column[i].button->allocation.y);
4523 if (clist->column[i].window)
4524 gdk_window_move (clist->column[i].window,
4525 clist->column[i].button->allocation.x +
4526 clist->column[i].button->allocation.width -
4527 (DRAG_WIDTH / 2), 0);
4532 if (value > -clist->hoffset)
4535 diff = value + clist->hoffset;
4537 clist->hoffset = -value;
4539 /* we have to re-draw the whole screen here... */
4540 if (diff >= clist->clist_window_width)
4542 draw_rows (clist, NULL);
4546 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
4547 GTK_CLIST_ADD_MODE (clist))
4549 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4551 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
4552 clist->clist_window_width - 1,
4553 clist->row_height - 1);
4555 gdk_window_copy_area (clist->clist_window,
4558 clist->clist_window,
4561 clist->clist_window_width - diff,
4562 clist->clist_window_height);
4564 area.x = clist->clist_window_width - diff;
4569 if (!(diff = -clist->hoffset - value))
4572 clist->hoffset = -value;
4574 /* we have to re-draw the whole screen here... */
4575 if (diff >= clist->clist_window_width)
4577 draw_rows (clist, NULL);
4581 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
4582 GTK_CLIST_ADD_MODE (clist))
4584 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4586 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
4587 clist->clist_window_width - 1,
4588 clist->row_height - 1);
4591 gdk_window_copy_area (clist->clist_window,
4594 clist->clist_window,
4597 clist->clist_window_width - diff,
4598 clist->clist_window_height);
4605 area.height = clist->clist_window_height;
4607 check_exposures (clist);
4609 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist))
4611 if (GTK_CLIST_ADD_MODE (clist))
4615 focus_row = clist->focus_row;
4616 clist->focus_row = -1;
4617 draw_rows (clist, &area);
4618 clist->focus_row = focus_row;
4620 gdk_draw_rectangle (clist->clist_window, clist->xor_gc,
4621 FALSE, 0, y, clist->clist_window_width - 1,
4622 clist->row_height - 1);
4632 x0 = clist->clist_window_width - 1;
4641 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4642 gdk_draw_line (clist->clist_window, clist->xor_gc,
4643 x0, y + 1, x0, y + clist->row_height - 2);
4644 gdk_draw_line (clist->clist_window, clist->xor_gc,
4645 x1, y + 1, x1, y + clist->row_height - 2);
4649 draw_rows (clist, &area);
4653 * Memory Allocation/Distruction Routines for GtkCList stuctures
4665 static GtkCListColumn *
4666 columns_new (GtkCList * clist)
4669 GtkCListColumn *column;
4671 column = g_new (GtkCListColumn, clist->columns);
4673 for (i = 0; i < clist->columns; i++)
4675 column[i].area.x = 0;
4676 column[i].area.y = 0;
4677 column[i].area.width = 0;
4678 column[i].area.height = 0;
4679 column[i].title = NULL;
4680 column[i].button = NULL;
4681 column[i].window = NULL;
4682 column[i].width = 0;
4683 column[i].width_set = FALSE;
4684 column[i].justification = GTK_JUSTIFY_LEFT;
4691 column_title_new (GtkCList * clist,
4695 if (clist->column[column].title)
4696 g_free (clist->column[column].title);
4698 clist->column[column].title = g_strdup (title);
4702 columns_delete (GtkCList * clist)
4706 for (i = 0; i < clist->columns; i++)
4707 if (clist->column[i].title)
4708 g_free (clist->column[i].title);
4710 g_free (clist->column);
4713 static GtkCListRow *
4714 row_new (GtkCList * clist)
4717 GtkCListRow *clist_row;
4719 clist_row = g_chunk_new (GtkCListRow, clist->row_mem_chunk);
4720 clist_row->cell = g_chunk_new (GtkCell, clist->cell_mem_chunk);
4722 for (i = 0; i < clist->columns; i++)
4724 clist_row->cell[i].type = GTK_CELL_EMPTY;
4725 clist_row->cell[i].vertical = 0;
4726 clist_row->cell[i].horizontal = 0;
4729 clist_row->fg_set = FALSE;
4730 clist_row->bg_set = FALSE;
4731 clist_row->state = GTK_STATE_NORMAL;
4732 clist_row->data = NULL;
4733 clist_row->destroy = NULL;
4739 row_delete (GtkCList * clist,
4740 GtkCListRow * clist_row)
4744 for (i = 0; i < clist->columns; i++)
4745 cell_empty (clist, clist_row, i);
4747 if (clist_row->destroy)
4748 clist_row->destroy (clist_row->data);
4750 g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell);
4751 g_mem_chunk_free (clist->row_mem_chunk, clist_row);
4755 cell_empty (GtkCList * clist,
4756 GtkCListRow * clist_row,
4759 switch (clist_row->cell[column].type)
4761 case GTK_CELL_EMPTY:
4765 g_free (GTK_CELL_TEXT (clist_row->cell[column])->text);
4768 case GTK_CELL_PIXMAP:
4769 gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap);
4770 if (GTK_CELL_PIXMAP (clist_row->cell[column])->mask)
4771 gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask);
4774 case GTK_CELL_PIXTEXT:
4775 g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text);
4776 gdk_pixmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap);
4777 if (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask)
4778 gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask);
4781 case GTK_CELL_WIDGET:
4789 clist_row->cell[column].type = GTK_CELL_EMPTY;
4793 cell_set_text (GtkCList * clist,
4794 GtkCListRow * clist_row,
4798 cell_empty (clist, clist_row, column);
4802 clist_row->cell[column].type = GTK_CELL_TEXT;
4803 GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
4808 cell_set_pixmap (GtkCList * clist,
4809 GtkCListRow * clist_row,
4814 cell_empty (clist, clist_row, column);
4818 clist_row->cell[column].type = GTK_CELL_PIXMAP;
4819 GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
4820 /* We set the mask even if it is NULL */
4821 GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask;
4826 cell_set_pixtext (GtkCList * clist,
4827 GtkCListRow * clist_row,
4834 cell_empty (clist, clist_row, column);
4838 clist_row->cell[column].type = GTK_CELL_PIXTEXT;
4839 GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
4840 GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
4841 GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
4842 GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask;
4846 /* Fill in data after widget has correct style */
4849 add_style_data (GtkCList * clist)
4853 widget = GTK_WIDGET(clist);
4855 /* text properties */
4856 if (!GTK_CLIST_ROW_HEIGHT_SET (clist))
4858 clist->row_height = widget->style->font->ascent + widget->style->font->descent + 1;
4859 clist->row_center_offset = widget->style->font->ascent + 1.5;
4864 text_height = clist->row_height - (GTK_WIDGET (clist)->style->font->ascent +
4865 GTK_WIDGET (clist) ->style->font->descent + 1);
4866 clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
4873 /* focus functions */
4876 gtk_clist_draw_focus (GtkWidget *widget)
4880 g_return_if_fail (widget != NULL);
4881 g_return_if_fail (GTK_IS_CLIST (widget));
4883 if (!GTK_WIDGET_DRAWABLE (widget))
4886 clist = GTK_CLIST (widget);
4887 if (clist->focus_row >= 0)
4888 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
4889 0, ROW_TOP_YPIXEL(clist, clist->focus_row),
4890 clist->clist_window_width - 1,
4891 clist->row_height - 1);
4895 gtk_clist_set_focus_child (GtkContainer *container,
4898 g_return_if_fail (container != NULL);
4899 g_return_if_fail (GTK_IS_CLIST (container));
4903 g_return_if_fail (GTK_IS_WIDGET (child));
4904 GTK_CLIST_SET_FLAG (GTK_CLIST (container), CLIST_CHILD_HAS_FOCUS);
4907 parent_class->set_focus_child (container, child);
4911 gtk_clist_focus_in (GtkWidget *widget,
4912 GdkEventFocus *event)
4916 g_return_val_if_fail (widget != NULL, FALSE);
4917 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4918 g_return_val_if_fail (event != NULL, FALSE);
4920 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
4921 GTK_CLIST_UNSET_FLAG (widget, CLIST_CHILD_HAS_FOCUS);
4923 clist = GTK_CLIST (widget);
4925 if (clist->selection_mode == GTK_SELECTION_BROWSE &&
4926 clist->selection == NULL && clist->focus_row > -1)
4927 select_row (clist, clist->focus_row, -1, (GdkEvent *) event);
4929 gtk_widget_draw_focus (widget);
4935 gtk_clist_focus_out (GtkWidget *widget,
4936 GdkEventFocus *event)
4940 g_return_val_if_fail (widget != NULL, FALSE);
4941 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4942 g_return_val_if_fail (event != NULL, FALSE);
4944 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
4945 gtk_widget_draw_focus (widget);
4947 clist = GTK_CLIST (widget);
4949 if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
4950 GTK_CLIST_CLASS_FW (widget)->resync_selection (clist, (GdkEvent *) event);
4956 toggle_add_mode (GtkCList *clist)
4958 g_return_if_fail (clist != 0);
4959 g_return_if_fail (GTK_IS_CLIST (clist));
4961 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
4962 clist->selection_mode != GTK_SELECTION_EXTENDED)
4965 gtk_clist_draw_focus (GTK_WIDGET (clist));
4966 if (!GTK_CLIST_ADD_MODE (clist))
4968 GTK_CLIST_SET_FLAG (clist, CLIST_ADD_MODE);
4969 gdk_gc_set_line_attributes (clist->xor_gc, 1,
4970 GDK_LINE_ON_OFF_DASH, 0, 0);
4971 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
4975 GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
4976 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
4977 clist->anchor_state = GTK_STATE_SELECTED;
4979 gtk_clist_draw_focus (GTK_WIDGET (clist));
4983 toggle_focus_row (GtkCList *clist)
4985 g_return_if_fail (clist != 0);
4986 g_return_if_fail (GTK_IS_CLIST (clist));
4988 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
4989 clist->focus_row < 0 || clist->focus_row >= clist->rows)
4992 switch (clist->selection_mode)
4994 case GTK_SELECTION_SINGLE:
4995 case GTK_SELECTION_MULTIPLE:
4997 toggle_row (clist, clist->focus_row, 0, NULL);
5000 case GTK_SELECTION_EXTENDED:
5001 g_list_free (clist->undo_selection);
5002 g_list_free (clist->undo_unselection);
5003 clist->undo_selection = NULL;
5004 clist->undo_unselection = NULL;
5006 clist->anchor = clist->focus_row;
5007 clist->drag_pos = clist->focus_row;
5008 clist->undo_anchor = clist->focus_row;
5010 if (GTK_CLIST_ADD_MODE (clist))
5011 fake_toggle_row (clist, clist->focus_row);
5013 GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist,clist->focus_row);
5015 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
5024 move_focus_row (GtkCList *clist,
5025 GtkScrollType scroll_type,
5030 g_return_if_fail (clist != 0);
5031 g_return_if_fail (GTK_IS_CLIST (clist));
5033 widget = GTK_WIDGET (clist);
5035 switch (scroll_type)
5037 case GTK_SCROLL_STEP_BACKWARD:
5038 if (clist->focus_row <= 0)
5040 gtk_clist_draw_focus (widget);
5042 gtk_clist_draw_focus (widget);
5044 case GTK_SCROLL_STEP_FORWARD:
5045 if (clist->focus_row >= clist->rows - 1)
5047 gtk_clist_draw_focus (widget);
5049 gtk_clist_draw_focus (widget);
5051 case GTK_SCROLL_PAGE_BACKWARD:
5052 if (clist->focus_row <= 0)
5054 gtk_clist_draw_focus (widget);
5055 clist->focus_row = MAX (0, clist->focus_row -
5056 (2 * clist->clist_window_height -
5057 clist->row_height - CELL_SPACING) /
5058 (2 * (clist->row_height + CELL_SPACING)));
5059 gtk_clist_draw_focus (widget);
5061 case GTK_SCROLL_PAGE_FORWARD:
5062 if (clist->focus_row >= clist->rows - 1)
5064 gtk_clist_draw_focus (widget);
5065 clist->focus_row = MIN (clist->rows - 1, clist->focus_row +
5066 (2 * clist->clist_window_height -
5067 clist->row_height - CELL_SPACING) /
5068 (2 * (clist->row_height + CELL_SPACING)));
5069 gtk_clist_draw_focus (widget);
5071 case GTK_SCROLL_JUMP:
5072 if (position >= 0 && position <= 1)
5074 gtk_clist_draw_focus (widget);
5075 clist->focus_row = position * (clist->rows - 1);
5076 gtk_clist_draw_focus (widget);
5085 scroll_horizontal (GtkCList *clist,
5086 GtkScrollType scroll_type,
5091 g_return_if_fail (clist != 0);
5092 g_return_if_fail (GTK_IS_CLIST (clist));
5094 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5097 switch (scroll_type)
5099 case GTK_SCROLL_STEP_BACKWARD:
5100 column = COLUMN_FROM_XPIXEL (clist, 0);
5101 if (COLUMN_LEFT_XPIXEL (clist, column) - CELL_SPACING - COLUMN_INSET >= 0
5105 case GTK_SCROLL_STEP_FORWARD:
5106 column = COLUMN_FROM_XPIXEL (clist, clist->clist_window_width);
5109 if (COLUMN_LEFT_XPIXEL (clist, column) + clist->column[column].area.width
5110 + CELL_SPACING + COLUMN_INSET - 1 <= clist->clist_window_width &&
5111 column < clist->columns - 1)
5114 case GTK_SCROLL_PAGE_BACKWARD:
5115 case GTK_SCROLL_PAGE_FORWARD:
5117 case GTK_SCROLL_JUMP:
5118 if (position >= 0 && position <= 1)
5119 column = position * (clist->columns - 1);
5127 if (COLUMN_LEFT_XPIXEL (clist, column) < CELL_SPACING + COLUMN_INSET)
5128 gtk_clist_moveto (clist, -1, column, 0, 0);
5129 else if (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET - 1
5130 + clist->column[column].area.width > clist->clist_window_width)
5132 if (column == clist->columns - 1)
5133 gtk_clist_moveto (clist, -1, column, 0, 0);
5135 gtk_clist_moveto (clist, -1, column, 0, 1);
5140 scroll_vertical (GtkCList *clist,
5141 GtkScrollType scroll_type,
5146 g_return_if_fail (clist != NULL);
5147 g_return_if_fail (GTK_IS_CLIST (clist));
5149 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5152 switch (clist->selection_mode)
5154 case GTK_SELECTION_EXTENDED:
5155 if (clist->anchor >= 0)
5158 case GTK_SELECTION_BROWSE:
5160 old_focus_row = clist->focus_row;
5161 move_focus_row (clist, scroll_type, position);
5163 if (old_focus_row != clist->focus_row)
5165 if (clist->selection_mode == GTK_SELECTION_BROWSE)
5166 unselect_row (clist,old_focus_row, -1, NULL);
5167 else if (!GTK_CLIST_ADD_MODE (clist))
5169 gtk_clist_unselect_all (clist);
5170 clist->undo_anchor = old_focus_row;
5174 switch (gtk_clist_row_is_visible (clist, clist->focus_row))
5176 case GTK_VISIBILITY_NONE:
5177 if (old_focus_row != clist->focus_row &&
5178 !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
5179 GTK_CLIST_ADD_MODE (clist)))
5180 select_row (clist, clist->focus_row, -1, NULL);
5181 switch (scroll_type)
5183 case GTK_SCROLL_STEP_BACKWARD:
5184 case GTK_SCROLL_PAGE_BACKWARD:
5185 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5187 case GTK_SCROLL_STEP_FORWARD:
5188 case GTK_SCROLL_PAGE_FORWARD:
5189 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5191 case GTK_SCROLL_JUMP:
5192 gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
5199 case GTK_VISIBILITY_PARTIAL:
5200 switch (scroll_type)
5202 case GTK_SCROLL_STEP_BACKWARD:
5203 case GTK_SCROLL_PAGE_BACKWARD:
5204 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5206 case GTK_SCROLL_STEP_FORWARD:
5207 case GTK_SCROLL_PAGE_FORWARD:
5208 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5210 case GTK_SCROLL_JUMP:
5211 gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
5218 if (old_focus_row != clist->focus_row &&
5219 !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
5220 GTK_CLIST_ADD_MODE (clist)))
5221 select_row (clist, clist->focus_row, -1, NULL);
5227 move_focus_row (clist, scroll_type, position);
5229 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5230 clist->clist_window_height)
5231 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5232 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5233 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5239 set_anchor (GtkCList *clist,
5244 g_return_if_fail (clist != NULL);
5245 g_return_if_fail (GTK_IS_CLIST (clist));
5247 if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor >= 0)
5250 g_list_free (clist->undo_selection);
5251 g_list_free (clist->undo_unselection);
5252 clist->undo_selection = NULL;
5253 clist->undo_unselection = NULL;
5256 fake_toggle_row (clist, anchor);
5259 GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist, anchor);
5260 clist->anchor_state = GTK_STATE_SELECTED;
5263 clist->anchor = anchor;
5264 clist->drag_pos = anchor;
5265 clist->undo_anchor = undo_anchor;
5269 resync_selection (GtkCList *clist,
5275 gboolean thaw = FALSE;
5277 GtkCListRow *clist_row;
5279 if (clist->anchor < 0)
5282 if (!GTK_CLIST_FROZEN (clist))
5284 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
5288 i = MIN (clist->anchor, clist->drag_pos);
5289 e = MAX (clist->anchor, clist->drag_pos);
5291 if (clist->undo_selection)
5294 list = clist->selection;
5295 clist->selection = clist->undo_selection;
5296 clist->selection_end = g_list_last (clist->selection);
5297 clist->undo_selection = list;
5298 list = clist->selection;
5301 row = GPOINTER_TO_INT (list->data);
5303 if (row < i || row > e)
5305 clist_row = g_list_nth (clist->row_list, row)->data;
5306 clist_row->state = GTK_STATE_SELECTED;
5307 unselect_row (clist, row, -1, event);
5308 clist->undo_selection = g_list_prepend
5309 (clist->undo_selection, GINT_TO_POINTER (row));
5314 for (list = g_list_nth (clist->row_list, i); i <= e; i++, list = list->next)
5315 if (g_list_find (clist->selection, GINT_TO_POINTER(i)))
5317 if (GTK_CLIST_ROW (list)->state == GTK_STATE_NORMAL)
5319 GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
5320 unselect_row (clist, i, -1, event);
5321 clist->undo_selection = g_list_prepend (clist->undo_selection,
5322 GINT_TO_POINTER (i));
5325 else if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
5327 GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
5328 clist->undo_unselection = g_list_prepend (clist->undo_unselection,
5329 GINT_TO_POINTER (i));
5332 for (list = clist->undo_unselection; list; list = list->next)
5333 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
5334 GPOINTER_TO_INT (list->data), -1, event);
5337 clist->drag_pos = -1;
5340 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
5344 update_extended_selection (GtkCList *clist,
5354 gint y1 = clist->clist_window_height;
5355 gint y2 = clist->clist_window_height;
5360 if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor == -1)
5365 if (row >= clist->rows)
5366 row = clist->rows - 1;
5368 /* extending downwards */
5369 if (row > clist->drag_pos && clist->anchor <= clist->drag_pos)
5371 s2 = clist->drag_pos + 1;
5374 /* extending upwards */
5375 else if (row < clist->drag_pos && clist->anchor >= clist->drag_pos)
5378 e2 = clist->drag_pos - 1;
5380 else if (row < clist->drag_pos && clist->anchor < clist->drag_pos)
5382 e1 = clist->drag_pos;
5383 /* row and drag_pos on different sides of anchor :
5384 take back the selection between anchor and drag_pos,
5385 select between anchor and row */
5386 if (row < clist->anchor)
5388 s1 = clist->anchor + 1;
5390 e2 = clist->anchor - 1;
5392 /* take back the selection between anchor and drag_pos */
5396 else if (row > clist->drag_pos && clist->anchor > clist->drag_pos)
5398 s1 = clist->drag_pos;
5399 /* row and drag_pos on different sides of anchor :
5400 take back the selection between anchor and drag_pos,
5401 select between anchor and row */
5402 if (row > clist->anchor)
5404 e1 = clist->anchor - 1;
5405 s2 = clist->anchor + 1;
5408 /* take back the selection between anchor and drag_pos */
5413 clist->drag_pos = row;
5416 area.width = clist->clist_window_width;
5418 /* restore the elements between s1 and e1 */
5421 for (i = s1, list = g_list_nth (clist->row_list, i); i <= e1;
5422 i++, list = list->next)
5424 if (GTK_CLIST_CLASS_FW (clist)->selection_find (clist, i, list))
5425 GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
5427 GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
5430 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
5432 if (top + clist->row_height <= 0)
5435 area.height = ROW_TOP_YPIXEL (clist, e1) + clist->row_height;
5436 draw_rows (clist, &area);
5437 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5439 else if (top >= clist->clist_window_height)
5441 area.y = ROW_TOP_YPIXEL (clist, s1);
5442 area.height = clist->clist_window_height - area.y;
5443 draw_rows (clist, &area);
5444 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5447 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5448 else if (top + clist->row_height > clist->clist_window_height)
5449 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5451 y1 = ROW_TOP_YPIXEL (clist, s1);
5452 h1 = (e1 - s1 + 1) * (clist->row_height + CELL_SPACING);
5455 /* extend the selection between s2 and e2 */
5458 for (i = s2, list = g_list_nth (clist->row_list, i); i <= e2;
5459 i++, list = list->next)
5460 if (GTK_CLIST_ROW (list)->state != clist->anchor_state)
5461 GTK_CLIST_ROW (list)->state = clist->anchor_state;
5463 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
5465 if (top + clist->row_height <= 0)
5468 area.height = ROW_TOP_YPIXEL (clist, e2) + clist->row_height;
5469 draw_rows (clist, &area);
5470 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5472 else if (top >= clist->clist_window_height)
5474 area.y = ROW_TOP_YPIXEL (clist, s2);
5475 area.height = clist->clist_window_height - area.y;
5476 draw_rows (clist, &area);
5477 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5480 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5481 else if (top + clist->row_height > clist->clist_window_height)
5482 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5484 y2 = ROW_TOP_YPIXEL (clist, s2);
5485 h2 = (e2-s2+1) * (clist->row_height + CELL_SPACING);
5488 area.y = MAX (0, MIN (y1, y2));
5489 if (area.y > clist->clist_window_height)
5491 area.height = MIN (clist->clist_window_height, h1 + h2);
5492 if (s1 >= 0 && s2 >= 0)
5493 area.height += (clist->row_height + CELL_SPACING);
5494 draw_rows (clist, &area);
5498 start_selection (GtkCList *clist)
5500 g_return_if_fail (clist != NULL);
5501 g_return_if_fail (GTK_IS_CLIST (clist));
5503 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5506 set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
5511 end_selection (GtkCList *clist)
5513 g_return_if_fail (clist != NULL);
5514 g_return_if_fail (GTK_IS_CLIST (clist));
5516 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist)) ||
5517 clist->anchor == -1)
5520 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
5524 extend_selection (GtkCList *clist,
5525 GtkScrollType scroll_type,
5527 gboolean auto_start_selection)
5529 g_return_if_fail (clist != NULL);
5530 g_return_if_fail (GTK_IS_CLIST (clist));
5532 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
5533 clist->selection_mode != GTK_SELECTION_EXTENDED)
5536 if (auto_start_selection)
5537 set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
5539 else if (clist->anchor == -1)
5542 move_focus_row (clist, scroll_type, position);
5544 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5545 clist->clist_window_height)
5546 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5547 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5548 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5550 update_extended_selection (clist, clist->focus_row);
5554 abort_column_resize (GtkCList *clist)
5556 g_return_if_fail (clist != NULL);
5557 g_return_if_fail (GTK_IS_CLIST (clist));
5559 if (!GTK_CLIST_IN_DRAG (clist))
5562 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
5563 gtk_grab_remove (clist);
5564 gdk_pointer_ungrab (gdk_time_get());
5566 if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1)
5567 draw_xor_line (clist);
5569 if (GTK_CLIST_ADD_MODE (clist))
5571 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_ON_OFF_DASH, 0,0);
5572 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
5577 gtk_clist_key_press (GtkWidget * widget,
5578 GdkEventKey * event)
5581 gboolean handled = FALSE;
5583 g_return_val_if_fail (widget != NULL, FALSE);
5584 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
5585 g_return_val_if_fail (event != NULL, FALSE);
5587 clist = GTK_CLIST (widget);
5590 if (event->keyval == GDK_Escape && GTK_CLIST_IN_DRAG (clist))
5592 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
5593 gtk_grab_remove (widget);
5594 gdk_pointer_ungrab (event->time);
5596 if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1)
5597 draw_xor_line (clist);
5599 if (GTK_CLIST_ADD_MODE (clist))
5601 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_ON_OFF_DASH,
5603 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
5608 if (GTK_WIDGET_CLASS (parent_class)->key_press_event)
5609 handled = GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
5614 switch (event->keyval)
5617 case GDK_ISO_Left_Tab:
5618 if (event->state & GDK_SHIFT_MASK)
5619 return gtk_container_focus (GTK_CONTAINER (widget),
5620 GTK_DIR_TAB_BACKWARD);
5622 return gtk_container_focus (GTK_CONTAINER (widget),
5623 GTK_DIR_TAB_FORWARD);
5633 title_focus (GtkCList * clist,
5636 GtkWidget *focus_child;
5637 gboolean return_val = FALSE;
5642 if (!GTK_CLIST_SHOW_TITLES (clist))
5645 focus_child = GTK_CONTAINER (clist)->focus_child;
5649 case GTK_DIR_TAB_BACKWARD:
5651 if (!focus_child || focus_child == clist->hscrollbar ||
5652 focus_child == clist->hscrollbar ||
5653 !GTK_CLIST_CHILD_HAS_FOCUS (clist))
5655 if (dir == GTK_DIR_UP)
5656 i = COLUMN_FROM_XPIXEL (clist, 0);
5658 i = clist->columns - 1;
5659 focus_child = clist->column[i].button;
5660 dir = GTK_DIR_TAB_FORWARD;
5667 if (!focus_child || focus_child == clist->hscrollbar ||
5668 focus_child == clist->hscrollbar)
5670 i = clist->columns - 1;
5671 focus_child = clist->column[i].button;
5675 if (!focus_child || focus_child == clist->hscrollbar ||
5676 focus_child == clist->hscrollbar)
5679 focus_child = clist->column[i].button;
5685 while (i < clist->columns)
5687 if (clist->column[i].button == focus_child)
5689 if (clist->column[i].button &&
5690 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
5691 GTK_IS_CONTAINER (clist->column[i].button) &&
5692 !GTK_WIDGET_HAS_FOCUS (clist->column[i].button))
5693 if (gtk_container_focus
5694 (GTK_CONTAINER (clist->column[i].button), dir))
5699 if (!return_val && dir == GTK_DIR_UP)
5710 while (j >= 0 && j < clist->columns)
5712 if (clist->column[j].button &&
5713 GTK_WIDGET_VISIBLE (clist->column[j].button))
5715 if (GTK_IS_CONTAINER (clist->column[j].button) &&
5717 (GTK_CONTAINER (clist->column[j].button), dir))
5722 else if (GTK_WIDGET_CAN_FOCUS (clist->column[j].button))
5724 gtk_widget_grab_focus (clist->column[j].button);
5734 if (COLUMN_LEFT_XPIXEL (clist, j) < CELL_SPACING + COLUMN_INSET)
5735 gtk_clist_moveto (clist, -1, j, 0, 0);
5736 else if (COLUMN_LEFT_XPIXEL(clist, j) + clist->column[j].area.width >
5737 clist->clist_window_width)
5739 if (j == clist->columns-1)
5740 gtk_clist_moveto (clist, -1, j, 0, 0);
5742 gtk_clist_moveto (clist, -1, j, 0, 1);
5749 gtk_clist_focus (GtkContainer * container,
5750 GtkDirectionType direction)
5753 GtkWidget *focus_child;
5756 g_return_val_if_fail (container != NULL, FALSE);
5757 g_return_val_if_fail (GTK_IS_CLIST (container), FALSE);
5759 if (!GTK_WIDGET_SENSITIVE (container))
5762 clist = GTK_CLIST (container);
5763 focus_child = container->focus_child;
5764 old_row = clist->focus_row;
5770 if (GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5771 (!focus_child || (focus_child && focus_child != clist->vscrollbar &&
5772 focus_child != clist->hscrollbar)))
5774 if (title_focus (clist, direction))
5776 gtk_container_set_focus_child (container, NULL);
5779 gtk_widget_grab_focus (GTK_WIDGET (container));
5782 case GTK_DIR_TAB_FORWARD:
5783 if (GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5784 (!focus_child || (focus_child != clist->vscrollbar &&
5785 focus_child != clist->hscrollbar)))
5787 gboolean tf = FALSE;
5789 if (((focus_child && direction == GTK_DIR_DOWN) ||
5790 !(tf = title_focus (clist, GTK_DIR_TAB_FORWARD)))
5793 if (clist->focus_row < 0)
5795 clist->focus_row = 0;
5797 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
5798 clist->selection_mode == GTK_SELECTION_EXTENDED) &&
5800 select_row (clist, clist->focus_row, -1, NULL);
5802 gtk_widget_grab_focus (GTK_WIDGET (container));
5810 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
5812 if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child ||
5813 (focus_child != clist->vscrollbar &&
5814 focus_child != clist->hscrollbar)) &&
5815 GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
5816 GTK_WIDGET_CAN_FOCUS (clist->vscrollbar))
5818 gtk_widget_grab_focus (clist->vscrollbar);
5822 if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child ||
5823 focus_child != clist->hscrollbar) &&
5824 GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
5825 GTK_WIDGET_CAN_FOCUS (clist->hscrollbar))
5827 gtk_widget_grab_focus (clist->hscrollbar);
5832 case GTK_DIR_TAB_BACKWARD:
5833 if (!focus_child && GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5834 GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
5835 GTK_WIDGET_CAN_FOCUS (clist->hscrollbar))
5837 gtk_widget_grab_focus (clist->hscrollbar);
5841 if ((!focus_child || focus_child == clist->hscrollbar) &&
5842 GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5843 GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
5844 GTK_WIDGET_CAN_FOCUS (clist->vscrollbar))
5846 gtk_widget_grab_focus (clist->vscrollbar);
5850 if ((!focus_child || focus_child == clist->hscrollbar ||
5851 focus_child == clist->vscrollbar) &&
5852 GTK_CLIST_CHILD_HAS_FOCUS (clist) && clist->rows)
5854 if (clist->focus_row < 0)
5856 clist->focus_row = 0;
5857 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
5858 clist->selection_mode == GTK_SELECTION_EXTENDED) &&
5860 select_row (clist, clist->focus_row, -1, NULL);
5862 gtk_widget_grab_focus (GTK_WIDGET (container));
5866 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
5868 if (title_focus (clist, direction))
5877 gtk_container_set_focus_child (container, NULL);
5882 gtk_clist_unselect_all (GtkCList * clist)
5884 GTK_CLIST_CLASS_FW (clist)->unselect_all (clist);
5888 real_unselect_all (GtkCList * clist)
5893 g_return_if_fail (clist != NULL);
5894 g_return_if_fail (GTK_IS_CLIST (clist));
5896 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5899 switch (clist->selection_mode)
5901 case GTK_SELECTION_BROWSE:
5902 if (clist->focus_row >= 0)
5904 select_row (clist, clist->focus_row, -1, NULL);
5909 case GTK_SELECTION_EXTENDED:
5910 g_list_free (clist->undo_selection);
5911 g_list_free (clist->undo_unselection);
5912 clist->undo_selection = NULL;
5913 clist->undo_unselection = NULL;
5916 clist->drag_pos = -1;
5917 clist->undo_anchor = clist->focus_row;
5924 list = clist->selection;
5928 i = GPOINTER_TO_INT (list->data);
5930 unselect_row (clist, i, -1, NULL);
5935 gtk_clist_select_all (GtkCList * clist)
5937 GTK_CLIST_CLASS_FW (clist)->select_all (clist);
5941 real_select_all (GtkCList * clist)
5946 g_return_if_fail (clist != NULL);
5947 g_return_if_fail (GTK_IS_CLIST (clist));
5949 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
5952 switch (clist->selection_mode)
5954 case GTK_SELECTION_SINGLE:
5955 case GTK_SELECTION_BROWSE:
5958 case GTK_SELECTION_EXTENDED:
5959 g_list_free (clist->undo_selection);
5960 g_list_free (clist->undo_unselection);
5961 clist->undo_selection = NULL;
5962 clist->undo_unselection = NULL;
5965 ((GtkCListRow *) (clist->row_list->data))->state !=
5967 fake_toggle_row (clist, 0);
5969 clist->anchor_state = GTK_STATE_SELECTED;
5971 clist->drag_pos = 0;
5972 clist->undo_anchor = clist->focus_row;
5973 update_extended_selection (clist, clist->rows);
5974 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
5977 case GTK_SELECTION_MULTIPLE:
5978 for (i = 0, list = clist->row_list; list; i++, list = list->next)
5980 if (((GtkCListRow *)(list->data))->state == GTK_STATE_NORMAL)
5981 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
5989 fake_unselect_all (GtkCList * clist,
5996 if (row >= 0 && (work = g_list_nth (clist->row_list, row)))
5998 if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL)
6000 GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
6002 if (!GTK_CLIST_FROZEN (clist) &&
6003 gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
6004 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
6005 GTK_CLIST_ROW (work));
6009 clist->undo_selection = clist->selection;
6010 clist->selection = NULL;
6011 clist->selection_end = NULL;
6013 for (list = clist->undo_selection; list; list = list->next)
6015 if ((i = GPOINTER_TO_INT (list->data)) == row ||
6016 !(work = g_list_nth (clist->row_list, i)))
6019 GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
6020 if (!GTK_CLIST_FROZEN (clist) &&
6021 gtk_clist_row_is_visible (clist, i) != GTK_VISIBILITY_NONE)
6022 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, i,
6023 GTK_CLIST_ROW (work));
6028 fake_toggle_row (GtkCList *clist,
6033 if (!(work = g_list_nth (clist->row_list, row)))
6036 if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL)
6037 clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
6039 clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
6041 if (!GTK_CLIST_FROZEN (clist) &&
6042 gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
6043 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
6044 GTK_CLIST_ROW (work));
6048 selection_find (GtkCList *clist,
6050 GList *row_list_element)
6052 return g_list_find (clist->selection, GINT_TO_POINTER (row_number));