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);
355 static void gtk_clist_marshal_signal_1 (GtkObject * object,
359 static void gtk_clist_marshal_signal_2 (GtkObject * object,
363 static void gtk_clist_marshal_signal_3 (GtkObject * object,
367 static void gtk_clist_marshal_signal_4 (GtkObject * object,
371 static void gtk_clist_marshal_signal_5 (GtkObject * object,
378 /* Fill in data after widget is realized and has style */
380 static void add_style_data (GtkCList * clist);
382 static GtkContainerClass *parent_class = NULL;
383 static guint clist_signals[LAST_SIGNAL] = {0};
387 gtk_clist_get_type (void)
389 static GtkType clist_type = 0;
393 GtkTypeInfo clist_info =
397 sizeof (GtkCListClass),
398 (GtkClassInitFunc) gtk_clist_class_init,
399 (GtkObjectInitFunc) gtk_clist_init,
400 /* reserved_1 */ NULL,
401 /* reserved_2 */ NULL,
402 (GtkClassInitFunc) NULL,
405 clist_type = gtk_type_unique (GTK_TYPE_CONTAINER, &clist_info);
412 gtk_clist_class_init (GtkCListClass * klass)
414 GtkObjectClass *object_class;
415 GtkWidgetClass *widget_class;
416 GtkContainerClass *container_class;
418 object_class = (GtkObjectClass *) klass;
419 widget_class = (GtkWidgetClass *) klass;
420 container_class = (GtkContainerClass *) klass;
422 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
424 clist_signals[SELECT_ROW] =
425 gtk_signal_new ("select_row",
428 GTK_SIGNAL_OFFSET (GtkCListClass, select_row),
429 gtk_clist_marshal_signal_1,
430 GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_GDK_EVENT);
431 clist_signals[UNSELECT_ROW] =
432 gtk_signal_new ("unselect_row",
435 GTK_SIGNAL_OFFSET (GtkCListClass, unselect_row),
436 gtk_clist_marshal_signal_1,
437 GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_GDK_EVENT);
438 clist_signals[CLICK_COLUMN] =
439 gtk_signal_new ("click_column",
442 GTK_SIGNAL_OFFSET (GtkCListClass, click_column),
443 gtk_clist_marshal_signal_3,
444 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
446 clist_signals[TOGGLE_FOCUS_ROW] =
447 gtk_signal_new ("toggle_focus_row",
448 GTK_RUN_LAST | GTK_RUN_ACTION,
450 GTK_SIGNAL_OFFSET (GtkCListClass, toggle_focus_row),
451 gtk_clist_marshal_signal_2,
453 clist_signals[SELECT_ALL] =
454 gtk_signal_new ("select_all",
455 GTK_RUN_LAST | GTK_RUN_ACTION,
457 GTK_SIGNAL_OFFSET (GtkCListClass, select_all),
458 gtk_clist_marshal_signal_2,
460 clist_signals[UNSELECT_ALL] =
461 gtk_signal_new ("unselect_all",
462 GTK_RUN_LAST | GTK_RUN_ACTION,
464 GTK_SIGNAL_OFFSET (GtkCListClass, unselect_all),
465 gtk_clist_marshal_signal_2,
467 clist_signals[UNDO_SELECTION] =
468 gtk_signal_new ("undo_selection",
469 GTK_RUN_LAST | GTK_RUN_ACTION,
471 GTK_SIGNAL_OFFSET (GtkCListClass, undo_selection),
472 gtk_clist_marshal_signal_2,
474 clist_signals[START_SELECTION] =
475 gtk_signal_new ("start_selection",
476 GTK_RUN_LAST | GTK_RUN_ACTION,
478 GTK_SIGNAL_OFFSET (GtkCListClass, start_selection),
479 gtk_clist_marshal_signal_2,
481 clist_signals[END_SELECTION] =
482 gtk_signal_new ("end_selection",
483 GTK_RUN_LAST | GTK_RUN_ACTION,
485 GTK_SIGNAL_OFFSET (GtkCListClass, end_selection),
486 gtk_clist_marshal_signal_2,
488 clist_signals[TOGGLE_ADD_MODE] =
489 gtk_signal_new ("toggle_add_mode",
490 GTK_RUN_LAST | GTK_RUN_ACTION,
492 GTK_SIGNAL_OFFSET (GtkCListClass, toggle_add_mode),
493 gtk_clist_marshal_signal_2,
495 clist_signals[EXTEND_SELECTION] =
496 gtk_signal_new ("extend_selection",
497 GTK_RUN_LAST | GTK_RUN_ACTION,
499 GTK_SIGNAL_OFFSET (GtkCListClass, extend_selection),
500 gtk_clist_marshal_signal_5,
502 GTK_TYPE_ENUM, GTK_TYPE_FLOAT, GTK_TYPE_BOOL);
503 clist_signals[SCROLL_VERTICAL] =
504 gtk_signal_new ("scroll_vertical",
505 GTK_RUN_LAST | GTK_RUN_ACTION,
507 GTK_SIGNAL_OFFSET (GtkCListClass, scroll_vertical),
508 gtk_clist_marshal_signal_4,
509 GTK_TYPE_NONE, 2, GTK_TYPE_ENUM, GTK_TYPE_FLOAT);
510 clist_signals[SCROLL_HORIZONTAL] =
511 gtk_signal_new ("scroll_horizontal",
512 GTK_RUN_LAST | GTK_RUN_ACTION,
514 GTK_SIGNAL_OFFSET (GtkCListClass, scroll_horizontal),
515 gtk_clist_marshal_signal_4,
516 GTK_TYPE_NONE, 2, GTK_TYPE_ENUM, GTK_TYPE_FLOAT);
517 clist_signals[ABORT_COLUMN_RESIZE] =
518 gtk_signal_new ("abort_column_resize",
519 GTK_RUN_LAST | GTK_RUN_ACTION,
521 GTK_SIGNAL_OFFSET (GtkCListClass, abort_column_resize),
522 gtk_clist_marshal_signal_2,
526 gtk_object_class_add_signals (object_class, clist_signals, LAST_SIGNAL);
528 object_class->destroy = gtk_clist_destroy;
529 object_class->finalize = gtk_clist_finalize;
531 widget_class->realize = gtk_clist_realize;
532 widget_class->unrealize = gtk_clist_unrealize;
533 widget_class->map = gtk_clist_map;
534 widget_class->unmap = gtk_clist_unmap;
535 widget_class->draw = gtk_clist_draw;
536 widget_class->button_press_event = gtk_clist_button_press;
537 widget_class->button_release_event = gtk_clist_button_release;
538 widget_class->motion_notify_event = gtk_clist_motion;
539 widget_class->expose_event = gtk_clist_expose;
540 widget_class->size_request = gtk_clist_size_request;
541 widget_class->size_allocate = gtk_clist_size_allocate;
542 widget_class->key_press_event = gtk_clist_key_press;
543 widget_class->focus_in_event = gtk_clist_focus_in;
544 widget_class->focus_out_event = gtk_clist_focus_out;
545 widget_class->draw_focus = gtk_clist_draw_focus;
547 /* container_class->add = NULL; use the default GtkContainerClass warning */
548 /* container_class->remove = NULL; use the default GtkContainerClass warning */
549 container_class->foreach = gtk_clist_foreach;
550 container_class->focus = gtk_clist_focus;
551 container_class->set_focus_child = gtk_clist_set_focus_child;
553 klass->select_row = real_select_row;
554 klass->unselect_row = real_unselect_row;
555 klass->undo_selection = real_undo_selection;
556 klass->resync_selection = resync_selection;
557 klass->selection_find = selection_find;
558 klass->click_column = NULL;
559 klass->draw_row = draw_row;
560 klass->clear = real_clear;
561 klass->select_all = real_select_all;
562 klass->unselect_all = real_unselect_all;
563 klass->fake_unselect_all = fake_unselect_all;
564 klass->scroll_horizontal = scroll_horizontal;
565 klass->scroll_vertical = scroll_vertical;
566 klass->extend_selection = extend_selection;
567 klass->toggle_focus_row = toggle_focus_row;
568 klass->toggle_add_mode = toggle_add_mode;
569 klass->start_selection = start_selection;
570 klass->end_selection = end_selection;
571 klass->abort_column_resize = abort_column_resize;
573 klass->scrollbar_spacing = 5;
576 GtkBindingSet *binding_set;
578 binding_set = gtk_binding_set_by_class (klass);
579 gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
580 "scroll_vertical", 2,
581 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
582 GTK_TYPE_FLOAT, 0.0);
583 gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
584 "scroll_vertical", 2,
585 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
586 GTK_TYPE_FLOAT, 0.0);
587 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
588 "scroll_vertical", 2,
589 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
590 GTK_TYPE_FLOAT, 0.0);
591 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
592 "scroll_vertical", 2,
593 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
594 GTK_TYPE_FLOAT, 0.0);
595 gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
596 "scroll_vertical", 2,
597 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
598 GTK_TYPE_FLOAT, 0.0);
599 gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
600 "scroll_vertical", 2,
601 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
602 GTK_TYPE_FLOAT, 1.0);
604 gtk_binding_entry_add_signal (binding_set, GDK_Up, GDK_SHIFT_MASK,
605 "extend_selection", 3,
606 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
607 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
608 gtk_binding_entry_add_signal (binding_set, GDK_Down, GDK_SHIFT_MASK,
609 "extend_selection", 3,
610 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
611 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
612 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, GDK_SHIFT_MASK,
613 "extend_selection", 3,
614 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
615 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
616 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, GDK_SHIFT_MASK,
617 "extend_selection", 3,
618 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
619 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
620 gtk_binding_entry_add_signal (binding_set, GDK_Home,
621 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
622 "extend_selection", 3,
623 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
624 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
625 gtk_binding_entry_add_signal (binding_set, GDK_End,
626 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
627 "extend_selection", 3,
628 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
629 GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE);
632 gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
633 "scroll_horizontal", 2,
634 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
635 GTK_TYPE_FLOAT, 0.0);
636 gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
637 "scroll_horizontal", 2,
638 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
639 GTK_TYPE_FLOAT, 0.0);
640 gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
641 "scroll_horizontal", 2,
642 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
643 GTK_TYPE_FLOAT, 0.0);
644 gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
645 "scroll_horizontal", 2,
646 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
647 GTK_TYPE_FLOAT, 1.0);
650 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
651 "undo_selection", 0);
652 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
653 "abort_column_resize", 0);
654 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
655 "toggle_focus_row", 0);
656 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK,
657 "toggle_add_mode", 0);
658 gtk_binding_entry_add_signal (binding_set, '/', GDK_CONTROL_MASK,
660 gtk_binding_entry_add_signal (binding_set, '\\', GDK_CONTROL_MASK,
662 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
663 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
665 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
666 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
672 GtkBindingSet *binding_set;
674 binding_set = gtk_binding_set_by_class (klass);
675 gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
676 "scroll_vertical", 2,
677 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
678 GTK_TYPE_FLOAT, 0.0);
679 gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
680 "scroll_vertical", 2,
681 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
682 GTK_TYPE_FLOAT, 0.0);
683 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
684 "scroll_vertical", 2,
685 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
686 GTK_TYPE_FLOAT, 0.0);
687 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
688 "scroll_vertical", 2,
689 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
690 GTK_TYPE_FLOAT, 0.0);
691 gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
692 "scroll_vertical", 2,
693 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
694 GTK_TYPE_FLOAT, 0.0);
695 gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
696 "scroll_vertical", 2,
697 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
700 gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0,
701 "extend_selection", 3,
702 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
703 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
704 gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0,
705 "extend_selection", 3,
706 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
707 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
708 gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Up, 0,
709 "extend_selection", 3,
710 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
711 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
712 gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Down, 0,
713 "extend_selection", 3,
714 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
715 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
716 gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, 0,
717 "extend_selection", 3,
718 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
719 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
720 gtk_binding_entry_add_signal (binding_set, GDK_KP_End, 0,
721 "extend_selection", 3,
722 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
723 GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE);
725 gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
726 "scroll_horizontal", 2,
727 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
728 GTK_TYPE_FLOAT, 0.0);
729 gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0,
730 "scroll_horizontal", 2,
731 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
732 GTK_TYPE_FLOAT, 0.0);
733 gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
734 "scroll_horizontal", 2,
735 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
736 GTK_TYPE_FLOAT, 0.0);
737 gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0,
738 "scroll_horizontal", 2,
739 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
740 GTK_TYPE_FLOAT, 0.0);
741 gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
742 "scroll_horizontal", 2,
743 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
744 GTK_TYPE_FLOAT, 0.0);
745 gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
746 "sroll_horizontal", 2,
747 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
748 GTK_TYPE_FLOAT, 1.0);
750 gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, 0,
751 "undo_selection", 0);
752 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
753 "abort_column_resize", 0);
754 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
755 "toggle_focus_row", 0);
756 gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0,
757 "toggle_add_mode", 0);
758 gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0,
760 gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0,
762 gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0,
769 gtk_clist_marshal_signal_1 (GtkObject * object,
774 GtkCListSignal1 rfunc;
776 rfunc = (GtkCListSignal1) func;
778 (*rfunc) (object, GTK_VALUE_INT (args[0]),
779 GTK_VALUE_INT (args[1]),
780 GTK_VALUE_POINTER (args[2]),
785 gtk_clist_marshal_signal_2 (GtkObject * object,
790 GtkCListSignal2 rfunc;
792 rfunc = (GtkCListSignal2) func;
794 (*rfunc) (object, func_data);
798 gtk_clist_marshal_signal_3 (GtkObject * object,
803 GtkCListSignal3 rfunc;
805 rfunc = (GtkCListSignal3) func;
807 (*rfunc) (object, GTK_VALUE_INT (args[0]), func_data);
811 gtk_clist_marshal_signal_4 (GtkObject * object,
816 GtkCListSignal4 rfunc;
818 rfunc = (GtkCListSignal4) func;
820 (*rfunc) (object, GTK_VALUE_INT (args[0]),
821 GTK_VALUE_FLOAT (args[1]), func_data);
825 gtk_clist_marshal_signal_5 (GtkObject * object,
830 GtkCListSignal5 rfunc;
832 rfunc = (GtkCListSignal5) func;
834 (*rfunc) (object, GTK_VALUE_INT (args[0]), GTK_VALUE_FLOAT (args[1]),
835 GTK_VALUE_BOOL (args[2]), func_data);
839 gtk_clist_init (GtkCList * clist)
843 GTK_WIDGET_UNSET_FLAGS (clist, GTK_NO_WINDOW);
844 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
846 clist->row_mem_chunk = NULL;
847 clist->cell_mem_chunk = NULL;
850 clist->row_center_offset = 0;
851 clist->row_height = 0;
852 clist->row_list = NULL;
853 clist->row_list_end = NULL;
857 clist->title_window = NULL;
858 clist->column_title_area.x = 0;
859 clist->column_title_area.y = 0;
860 clist->column_title_area.width = 1;
861 clist->column_title_area.height = 1;
863 clist->clist_window = NULL;
864 clist->clist_window_width = 1;
865 clist->clist_window_height = 1;
870 clist->shadow_type = GTK_SHADOW_IN;
871 clist->hscrollbar_policy = GTK_POLICY_ALWAYS;
872 clist->vscrollbar_policy = GTK_POLICY_ALWAYS;
874 clist->cursor_drag = NULL;
875 clist->xor_gc = NULL;
880 clist->selection_mode = GTK_SELECTION_SINGLE;
881 clist->selection = NULL;
882 clist->selection_end = NULL;
883 clist->undo_selection = NULL;
884 clist->undo_unselection = NULL;
886 GTK_WIDGET_SET_FLAGS (clist, GTK_CAN_FOCUS);
887 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
888 clist->focus_row = -1;
889 clist->undo_anchor = -1;
892 clist->anchor_state = GTK_STATE_SELECTED;
893 clist->drag_pos = -1;
900 gtk_clist_construct (GtkCList * clist,
906 g_return_if_fail (clist != NULL);
907 g_return_if_fail (GTK_IS_CLIST (clist));
908 g_return_if_fail (GTK_CLIST_CONSTRUCTED (clist) == FALSE);
910 GTK_CLIST_SET_FLAG (clist, CLIST_CONSTRUCTED);
912 /* initalize memory chunks, if this has not been done by any
913 * possibly derived widget
915 if (!clist->row_mem_chunk)
916 clist->row_mem_chunk = g_mem_chunk_new ("clist row mem chunk",
917 sizeof (GtkCListRow),
918 sizeof (GtkCListRow) * CLIST_OPTIMUM_SIZE,
921 if (!clist->cell_mem_chunk)
922 clist->cell_mem_chunk = g_mem_chunk_new ("clist cell mem chunk",
923 sizeof (GtkCell) * columns,
924 sizeof (GtkCell) * columns * CLIST_OPTIMUM_SIZE,
927 /* set number of columns, allocate memory */
928 clist->columns = columns;
929 clist->column = columns_new (clist);
931 /* there needs to be at least one column button
932 * because there is alot of code that will break if it
934 column_button_create (clist, 0);
936 /* create scrollbars */
937 create_scrollbars (clist);
941 GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES);
942 for (i = 0; i < columns; i++)
943 gtk_clist_set_column_title (clist, i, titles[i]);
947 GTK_CLIST_UNSET_FLAG (clist, CLIST_SHOW_TITLES);
952 * GTKCLIST PUBLIC INTERFACE
953 * gtk_clist_new_with_titles
957 gtk_clist_new_with_titles (gint columns,
962 g_return_val_if_fail (titles != NULL, NULL);
964 widget = gtk_type_new (GTK_TYPE_CLIST);
966 gtk_clist_construct (GTK_CLIST (widget), columns, titles);
972 gtk_clist_new (gint columns)
979 clist = gtk_type_new (GTK_TYPE_CLIST);
980 gtk_clist_construct (clist, columns, NULL);
981 return GTK_WIDGET (clist);
985 gtk_clist_set_border (GtkCList * clist,
986 GtkShadowType border)
988 g_return_if_fail (clist != NULL);
989 g_return_if_fail (GTK_IS_CLIST (clist));
991 clist->shadow_type = border;
993 if (GTK_WIDGET_VISIBLE (clist))
994 gtk_widget_queue_resize (GTK_WIDGET (clist));
998 gtk_clist_set_selection_mode (GtkCList * clist,
999 GtkSelectionMode mode)
1001 g_return_if_fail (clist != NULL);
1002 g_return_if_fail (GTK_IS_CLIST (clist));
1004 if (mode == clist->selection_mode)
1007 clist->selection_mode = mode;
1009 clist->anchor_state = GTK_STATE_SELECTED;
1010 clist->drag_pos = -1;
1011 clist->undo_anchor = clist->focus_row;
1013 g_list_free (clist->undo_selection);
1014 g_list_free (clist->undo_unselection);
1015 clist->undo_selection = NULL;
1016 clist->undo_unselection = NULL;
1020 case GTK_SELECTION_MULTIPLE:
1021 case GTK_SELECTION_EXTENDED:
1023 case GTK_SELECTION_BROWSE:
1024 case GTK_SELECTION_SINGLE:
1025 gtk_clist_unselect_all (clist);
1031 gtk_clist_freeze (GtkCList * clist)
1033 g_return_if_fail (clist != NULL);
1034 g_return_if_fail (GTK_IS_CLIST (clist));
1036 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
1040 gtk_clist_thaw (GtkCList * clist)
1042 g_return_if_fail (clist != NULL);
1043 g_return_if_fail (GTK_IS_CLIST (clist));
1045 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
1047 adjust_scrollbars (clist);
1048 draw_rows (clist, NULL);
1052 gtk_clist_column_titles_show (GtkCList * clist)
1054 g_return_if_fail (clist != NULL);
1055 g_return_if_fail (GTK_IS_CLIST (clist));
1057 if (!GTK_CLIST_SHOW_TITLES (clist))
1059 GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES);
1060 if (clist->title_window)
1061 gdk_window_show (clist->title_window);
1062 gtk_widget_queue_resize (GTK_WIDGET (clist));
1067 gtk_clist_column_titles_hide (GtkCList * clist)
1069 g_return_if_fail (clist != NULL);
1070 g_return_if_fail (GTK_IS_CLIST (clist));
1072 if (GTK_CLIST_SHOW_TITLES (clist))
1074 GTK_CLIST_UNSET_FLAG (clist, CLIST_SHOW_TITLES);
1075 if (clist->title_window)
1076 gdk_window_hide (clist->title_window);
1077 gtk_widget_queue_resize (GTK_WIDGET (clist));
1082 gtk_clist_column_title_active (GtkCList * clist,
1085 g_return_if_fail (clist != NULL);
1086 g_return_if_fail (GTK_IS_CLIST (clist));
1088 if (column < 0 || column >= clist->columns)
1091 if (!GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
1092 !GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
1094 GTK_WIDGET_SET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS);
1095 if (GTK_WIDGET_VISIBLE (clist))
1096 gtk_widget_queue_draw (clist->column[column].button);
1101 gtk_clist_column_title_passive (GtkCList * clist,
1104 g_return_if_fail (clist != NULL);
1105 g_return_if_fail (GTK_IS_CLIST (clist));
1107 if (column < 0 || column >= clist->columns)
1110 if (GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
1111 GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
1113 GTK_WIDGET_UNSET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS);
1114 if (GTK_WIDGET_VISIBLE (clist))
1115 gtk_widget_queue_draw (clist->column[column].button);
1120 gtk_clist_column_titles_active (GtkCList * clist)
1124 g_return_if_fail (clist != NULL);
1125 g_return_if_fail (GTK_IS_CLIST (clist));
1127 for (i = 0; i < clist->columns; i++)
1128 if (clist->column[i].button)
1129 gtk_clist_column_title_active (clist, i);
1133 gtk_clist_column_titles_passive (GtkCList * clist)
1137 g_return_if_fail (clist != NULL);
1138 g_return_if_fail (GTK_IS_CLIST (clist));
1140 for (i = 0; i < clist->columns; i++)
1141 if (clist->column[i].button)
1142 gtk_clist_column_title_passive (clist, i);
1146 gtk_clist_set_column_title (GtkCList * clist,
1150 gint new_button = 0;
1151 GtkWidget *old_widget;
1152 GtkWidget *alignment = NULL;
1155 g_return_if_fail (clist != NULL);
1156 g_return_if_fail (GTK_IS_CLIST (clist));
1158 if (column < 0 || column >= clist->columns)
1161 /* if the column button doesn't currently exist,
1162 * it has to be created first */
1163 if (!clist->column[column].button)
1165 column_button_create (clist, column);
1169 column_title_new (clist, column, title);
1171 /* remove and destroy the old widget */
1172 old_widget = GTK_BIN (clist->column[column].button)->child;
1174 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
1176 /* create new alignment based no column justification */
1177 switch (clist->column[column].justification)
1179 case GTK_JUSTIFY_LEFT:
1180 alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
1183 case GTK_JUSTIFY_RIGHT:
1184 alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
1187 case GTK_JUSTIFY_CENTER:
1188 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1191 case GTK_JUSTIFY_FILL:
1192 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1196 label = gtk_label_new (clist->column[column].title);
1197 gtk_container_add (GTK_CONTAINER (alignment), label);
1198 gtk_container_add (GTK_CONTAINER (clist->column[column].button), alignment);
1199 gtk_widget_show (label);
1200 gtk_widget_show (alignment);
1202 /* if this button didn't previously exist, then the
1203 * column button positions have to be re-computed */
1204 if (GTK_WIDGET_VISIBLE (clist) && new_button)
1205 size_allocate_title_buttons (clist);
1209 gtk_clist_set_column_widget (GtkCList * clist,
1213 gint new_button = 0;
1214 GtkWidget *old_widget;
1216 g_return_if_fail (clist != NULL);
1217 g_return_if_fail (GTK_IS_CLIST (clist));
1219 if (column < 0 || column >= clist->columns)
1222 /* if the column button doesn't currently exist,
1223 * it has to be created first */
1224 if (!clist->column[column].button)
1226 column_button_create (clist, column);
1230 column_title_new (clist, column, NULL);
1232 /* remove and destroy the old widget */
1233 old_widget = GTK_BIN (clist->column[column].button)->child;
1235 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
1237 /* add and show the widget */
1240 gtk_container_add (GTK_CONTAINER (clist->column[column].button), widget);
1241 gtk_widget_show (widget);
1244 /* if this button didn't previously exist, then the
1245 * column button positions have to be re-computed */
1246 if (GTK_WIDGET_VISIBLE (clist) && new_button)
1247 size_allocate_title_buttons (clist);
1251 gtk_clist_set_column_justification (GtkCList * clist,
1253 GtkJustification justification)
1255 GtkWidget *alignment;
1257 g_return_if_fail (clist != NULL);
1258 g_return_if_fail (GTK_IS_CLIST (clist));
1260 if (column < 0 || column >= clist->columns)
1263 clist->column[column].justification = justification;
1265 /* change the alinment of the button title if it's not a
1267 if (clist->column[column].title)
1269 alignment = GTK_BIN (clist->column[column].button)->child;
1271 switch (clist->column[column].justification)
1273 case GTK_JUSTIFY_LEFT:
1274 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.0, 0.5, 0.0, 0.0);
1277 case GTK_JUSTIFY_RIGHT:
1278 gtk_alignment_set (GTK_ALIGNMENT (alignment), 1.0, 0.5, 0.0, 0.0);
1281 case GTK_JUSTIFY_CENTER:
1282 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
1285 case GTK_JUSTIFY_FILL:
1286 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
1294 if (!GTK_CLIST_FROZEN (clist))
1295 draw_rows (clist, NULL);
1299 gtk_clist_set_column_width (GtkCList * clist,
1303 g_return_if_fail (clist != NULL);
1304 g_return_if_fail (GTK_IS_CLIST (clist));
1306 if (column < 0 || column >= clist->columns)
1309 clist->column[column].width = width;
1310 clist->column[column].width_set = TRUE;
1312 /* FIXME: this is quite expensive to do if the widget hasn't
1313 * been size_allocated yet, and pointless. Should
1316 size_allocate_columns (clist);
1317 size_allocate_title_buttons (clist);
1319 if (!GTK_CLIST_FROZEN (clist))
1321 adjust_scrollbars (clist);
1322 draw_rows (clist, NULL);
1327 gtk_clist_set_row_height (GtkCList * clist,
1332 g_return_if_fail (clist != NULL);
1333 g_return_if_fail (GTK_IS_CLIST (clist));
1336 clist->row_height = height;
1340 GTK_CLIST_SET_FLAG (clist, CLIST_ROW_HEIGHT_SET);
1342 if (GTK_WIDGET_REALIZED (clist))
1344 text_height = height - (GTK_WIDGET (clist)->style->font->ascent +
1345 GTK_WIDGET (clist) ->style->font->descent + 1);
1346 clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
1349 if (!GTK_CLIST_FROZEN (clist))
1351 adjust_scrollbars (clist);
1352 draw_rows (clist, NULL);
1357 gtk_clist_moveto (GtkCList * clist,
1363 g_return_if_fail (clist != NULL);
1364 g_return_if_fail (GTK_IS_CLIST (clist));
1366 if (row < -1 || row >= clist->rows)
1368 if (column < -1 || column >= clist->columns)
1371 row_align = CLAMP (row_align, 0, 1);
1372 col_align = CLAMP (col_align, 0, 1);
1374 /* adjust horizontal scrollbar */
1380 adj = GTK_RANGE (clist->hscrollbar)->adjustment;
1382 x = COLUMN_LEFT (clist, column) - CELL_SPACING - COLUMN_INSET -
1383 (col_align * (clist->clist_window_width - 2 * COLUMN_INSET -
1384 CELL_SPACING - clist->column[column].area.width));
1386 gtk_adjustment_set_value (adj, 0.0);
1387 else if (x > LIST_WIDTH (clist) - clist->clist_window_width)
1388 gtk_adjustment_set_value
1389 (adj, LIST_WIDTH (clist) - clist->clist_window_width);
1391 gtk_adjustment_set_value (adj, x);
1394 /* adjust vertical scrollbar */
1396 move_vertical (clist, row, row_align);
1400 gtk_clist_get_cell_type (GtkCList * clist,
1404 GtkCListRow *clist_row;
1406 g_return_val_if_fail (clist != NULL, -1);
1407 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1409 if (row < 0 || row >= clist->rows)
1411 if (column < 0 || column >= clist->columns)
1414 clist_row = (g_list_nth (clist->row_list, row))->data;
1416 return clist_row->cell[column].type;
1420 gtk_clist_set_text (GtkCList * clist,
1425 GtkCListRow *clist_row;
1427 g_return_if_fail (clist != NULL);
1428 g_return_if_fail (GTK_IS_CLIST (clist));
1430 if (row < 0 || row >= clist->rows)
1432 if (column < 0 || column >= clist->columns)
1435 clist_row = (g_list_nth (clist->row_list, row))->data;
1437 /* if text is null, then the cell is empty */
1439 cell_set_text (clist, clist_row, column, text);
1441 cell_empty (clist, clist_row, column);
1443 /* redraw the list if it's not frozen */
1444 if (!GTK_CLIST_FROZEN (clist))
1446 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1447 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1452 gtk_clist_get_text (GtkCList * clist,
1457 GtkCListRow *clist_row;
1459 g_return_val_if_fail (clist != NULL, 0);
1460 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
1462 if (row < 0 || row >= clist->rows)
1464 if (column < 0 || column >= clist->columns)
1467 clist_row = (g_list_nth (clist->row_list, row))->data;
1469 if (clist_row->cell[column].type != GTK_CELL_TEXT)
1473 *text = GTK_CELL_TEXT (clist_row->cell[column])->text;
1479 gtk_clist_set_pixmap (GtkCList * clist,
1485 GtkCListRow *clist_row;
1487 g_return_if_fail (clist != NULL);
1488 g_return_if_fail (GTK_IS_CLIST (clist));
1490 if (row < 0 || row >= clist->rows)
1492 if (column < 0 || column >= clist->columns)
1495 clist_row = (g_list_nth (clist->row_list, row))->data;
1497 gdk_pixmap_ref (pixmap);
1499 if (mask) gdk_pixmap_ref (mask);
1501 cell_set_pixmap (clist, clist_row, column, pixmap, mask);
1503 /* redraw the list if it's not frozen */
1504 if (!GTK_CLIST_FROZEN (clist))
1506 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1507 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1512 gtk_clist_get_pixmap (GtkCList * clist,
1515 GdkPixmap ** pixmap,
1518 GtkCListRow *clist_row;
1520 g_return_val_if_fail (clist != NULL, 0);
1521 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
1523 if (row < 0 || row >= clist->rows)
1525 if (column < 0 || column >= clist->columns)
1528 clist_row = (g_list_nth (clist->row_list, row))->data;
1530 if (clist_row->cell[column].type != GTK_CELL_PIXMAP)
1535 *pixmap = GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap;
1536 /* mask can be NULL */
1537 *mask = GTK_CELL_PIXMAP (clist_row->cell[column])->mask;
1544 gtk_clist_set_pixtext (GtkCList * clist,
1552 GtkCListRow *clist_row;
1554 g_return_if_fail (clist != NULL);
1555 g_return_if_fail (GTK_IS_CLIST (clist));
1557 if (row < 0 || row >= clist->rows)
1559 if (column < 0 || column >= clist->columns)
1562 clist_row = (g_list_nth (clist->row_list, row))->data;
1564 gdk_pixmap_ref (pixmap);
1565 if (mask) gdk_pixmap_ref (mask);
1566 cell_set_pixtext (clist, clist_row, column, text, spacing, pixmap, mask);
1568 /* redraw the list if it's not frozen */
1569 if (!GTK_CLIST_FROZEN (clist))
1571 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1572 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1577 gtk_clist_get_pixtext (GtkCList * clist,
1582 GdkPixmap ** pixmap,
1585 GtkCListRow *clist_row;
1587 g_return_val_if_fail (clist != NULL, 0);
1588 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
1590 if (row < 0 || row >= clist->rows)
1592 if (column < 0 || column >= clist->columns)
1595 clist_row = (g_list_nth (clist->row_list, row))->data;
1597 if (clist_row->cell[column].type != GTK_CELL_PIXTEXT)
1601 *text = GTK_CELL_PIXTEXT (clist_row->cell[column])->text;
1603 *spacing = GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing;
1605 *pixmap = GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap;
1607 /* mask can be NULL */
1608 *mask = GTK_CELL_PIXTEXT (clist_row->cell[column])->mask;
1614 gtk_clist_set_foreground (GtkCList * clist,
1618 GtkCListRow *clist_row;
1620 g_return_if_fail (clist != NULL);
1621 g_return_if_fail (GTK_IS_CLIST (clist));
1623 if (row < 0 || row >= clist->rows)
1626 clist_row = (g_list_nth (clist->row_list, row))->data;
1630 clist_row->foreground = *color;
1631 clist_row->fg_set = TRUE;
1634 clist_row->fg_set = FALSE;
1636 if (!GTK_CLIST_FROZEN (clist)
1637 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1638 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1642 gtk_clist_set_background (GtkCList * clist,
1646 GtkCListRow *clist_row;
1648 g_return_if_fail (clist != NULL);
1649 g_return_if_fail (GTK_IS_CLIST (clist));
1651 if (row < 0 || row >= clist->rows)
1654 clist_row = (g_list_nth (clist->row_list, row))->data;
1658 clist_row->background = *color;
1659 clist_row->bg_set = TRUE;
1662 clist_row->bg_set = FALSE;
1664 if (!GTK_CLIST_FROZEN (clist)
1665 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1666 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1670 gtk_clist_set_shift (GtkCList * clist,
1676 GtkCListRow *clist_row;
1678 g_return_if_fail (clist != NULL);
1679 g_return_if_fail (GTK_IS_CLIST (clist));
1681 if (row < 0 || row >= clist->rows)
1683 if (column < 0 || column >= clist->columns)
1686 clist_row = (g_list_nth (clist->row_list, row))->data;
1688 clist_row->cell[column].vertical = vertical;
1689 clist_row->cell[column].horizontal = horizontal;
1691 if (!GTK_CLIST_FROZEN (clist)
1692 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1693 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
1697 gtk_clist_append (GtkCList * clist,
1701 GtkCListRow *clist_row;
1703 g_return_val_if_fail (clist != NULL, -1);
1704 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1706 clist_row = row_new (clist);
1709 /* set the text in the row's columns */
1711 for (i = 0; i < clist->columns; i++)
1713 cell_set_text (clist, clist_row, i, text[i]);
1715 /* keeps track of the end of the list so the list
1716 * doesn't have to be traversed every time a item is added */
1717 if (!clist->row_list)
1719 clist->row_list = g_list_append (clist->row_list, clist_row);
1720 clist->row_list_end = clist->row_list;
1722 /* check the selection mode to see if we should select
1723 * the first row automaticly */
1724 switch (clist->selection_mode)
1726 case GTK_SELECTION_BROWSE:
1727 select_row (clist, 0, -1, NULL);
1735 clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
1737 /* redraw the list if it's not frozen */
1738 if (!GTK_CLIST_FROZEN (clist))
1740 adjust_scrollbars (clist);
1742 if (gtk_clist_row_is_visible (clist, clist->rows - 1) != GTK_VISIBILITY_NONE)
1743 draw_rows (clist, NULL);
1746 /* return index of the row */
1747 return clist->rows - 1;
1751 gtk_clist_insert (GtkCList * clist,
1756 GtkCListRow *clist_row;
1758 g_return_if_fail (clist != NULL);
1759 g_return_if_fail (GTK_IS_CLIST (clist));
1760 g_return_if_fail (text != NULL);
1762 /* return if out of bounds */
1763 if (row < 0 || row > clist->rows)
1766 if (clist->rows == 0)
1767 gtk_clist_append (clist, text);
1770 /* create the row */
1771 clist_row = row_new (clist);
1773 /* set the text in the row's columns */
1775 for (i = 0; i < clist->columns; i++)
1777 cell_set_text (clist, clist_row, i, text[i]);
1779 /* reset the row end pointer if we're inserting at the
1780 * end of the list */
1781 if (row == clist->rows)
1782 clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
1784 clist->row_list = g_list_insert (clist->row_list, clist_row, row);
1788 if (row < ROW_FROM_YPIXEL (clist, 0))
1789 clist->voffset -= (clist->row_height + CELL_SPACING);
1791 /* syncronize the selection list */
1792 sync_selection (clist, row, SYNC_INSERT);
1795 /* redraw the list if it isn't frozen */
1796 if (!GTK_CLIST_FROZEN (clist))
1798 adjust_scrollbars (clist);
1800 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1801 draw_rows (clist, NULL);
1806 gtk_clist_remove (GtkCList * clist,
1809 gint was_visible, was_selected;
1811 GtkCListRow *clist_row;
1813 g_return_if_fail (clist != NULL);
1814 g_return_if_fail (GTK_IS_CLIST (clist));
1816 /* return if out of bounds */
1817 if (row < 0 || row > (clist->rows - 1))
1820 was_visible = (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE);
1823 /* get the row we're going to delete */
1824 list = g_list_nth (clist->row_list, row);
1825 clist_row = list->data;
1827 /* if we're removing a selected row, we have to make sure
1828 * it's properly unselected, and then sync up the clist->selected
1829 * list to reflect the deincrimented indexies of rows after the
1831 if (clist_row->state == GTK_STATE_SELECTED)
1833 switch (clist->selection_mode)
1835 case GTK_SELECTION_SINGLE:
1836 case GTK_SELECTION_MULTIPLE:
1837 case GTK_SELECTION_EXTENDED:
1838 unselect_row (clist, row, -1, NULL);
1841 case GTK_SELECTION_BROWSE:
1842 select_row (clist, row - 1, -1, NULL);
1850 /* reset the row end pointer if we're removing at the
1851 * end of the list */
1852 if (row == clist->rows - 1)
1853 clist->row_list_end = list->prev;
1854 if (row >= clist->focus_row && clist->focus_row >=0)
1857 clist->row_list = g_list_remove (clist->row_list, clist_row);
1860 if (row < ROW_FROM_YPIXEL (clist, 0))
1861 clist->voffset += clist->row_height + CELL_SPACING;
1863 sync_selection (clist, row, SYNC_REMOVE);
1866 row_delete (clist, clist_row);
1868 /* redraw the row if it isn't frozen */
1869 if (!GTK_CLIST_FROZEN (clist))
1871 adjust_scrollbars (clist);
1874 draw_rows (clist, NULL);
1879 sync_selection (GtkCList * clist,
1886 if (mode == SYNC_INSERT)
1891 if (clist->focus_row >= row)
1893 clist->focus_row += d;
1894 if (clist->focus_row == -1 && clist->rows >= 1)
1895 clist->focus_row = 0;
1898 if (clist->selection_mode == GTK_SELECTION_BROWSE && clist->anchor != -1)
1899 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
1901 g_list_free (clist->undo_selection);
1902 g_list_free (clist->undo_unselection);
1903 clist->undo_selection = NULL;
1904 clist->undo_unselection = NULL;
1907 clist->drag_pos = -1;
1908 clist->undo_anchor = clist->focus_row;
1910 list = clist->selection;
1913 if (GPOINTER_TO_INT (list->data) >= row)
1914 list->data = ((gchar*) list->data) + d;
1920 gtk_clist_clear (GtkCList * clist)
1922 GTK_CLIST_CLASS_FW (clist)->clear (clist);
1926 real_clear (GtkCList * clist)
1930 g_return_if_fail (clist != NULL);
1931 g_return_if_fail (GTK_IS_CLIST (clist));
1933 /* remove all the rows */
1934 for (list = clist->row_list; list; list = list->next)
1935 row_delete (clist, GTK_CLIST_ROW (list));
1937 g_list_free (clist->row_list);
1939 /* free up the selection list */
1940 g_list_free (clist->selection);
1941 g_list_free (clist->undo_selection);
1942 g_list_free (clist->undo_unselection);
1944 clist->row_list = NULL;
1945 clist->row_list_end = NULL;
1946 clist->selection = NULL;
1947 clist->selection_end = NULL;
1948 clist->undo_selection = NULL;
1949 clist->undo_unselection = NULL;
1952 clist->focus_row = -1;
1954 clist->undo_anchor = -1;
1955 clist->anchor_state = GTK_STATE_SELECTED;
1956 clist->drag_pos = -1;
1958 /* zero-out the scrollbars */
1959 if (clist->vscrollbar)
1961 GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0;
1962 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
1964 if (!GTK_CLIST_FROZEN (clist))
1965 gtk_clist_thaw (clist);
1970 gtk_clist_swap_rows (GtkCList * clist,
1975 GList *list, *link1, *link2;
1978 g_return_if_fail (clist != NULL);
1979 g_return_if_fail (GTK_IS_CLIST (clist));
1981 if (row1 < 0 || row1 > (clist->rows - 1))
1984 if (row2 < 0 || row2 > (clist->rows - 1))
1987 first = MIN (row1, row2);
1988 last = MAX (row1, row2);
1990 link1 = g_list_nth (clist->row_list, first);
1991 link2 = g_list_nth (link1, row2 - row1);
1994 link1->data = link2->data;
1997 list = clist->selection;
2000 if (GPOINTER_TO_INT (list->data) == row1)
2001 GPOINTER_TO_INT (list->data) = row2;
2003 if (GPOINTER_TO_INT (list->data) == row2)
2004 GPOINTER_TO_INT (list->data) = row1;
2009 if (!GTK_CLIST_FROZEN (clist))
2011 if (gtk_clist_row_is_visible (clist, row1) != GTK_VISIBILITY_NONE)
2012 GTK_CLIST_CLASS_FW (clist)->draw_row
2013 (clist, NULL, row1, GTK_CLIST_ROW (link2));
2015 if (gtk_clist_row_is_visible (clist, row2) != GTK_VISIBILITY_NONE)
2016 GTK_CLIST_CLASS_FW (clist)->draw_row
2017 (clist, NULL, row2, GTK_CLIST_ROW (link1));
2022 gtk_clist_set_row_data (GtkCList * clist,
2026 gtk_clist_set_row_data_full (clist, row, data, NULL);
2030 gtk_clist_set_row_data_full (GtkCList * clist,
2033 GtkDestroyNotify destroy)
2035 GtkCListRow *clist_row;
2037 g_return_if_fail (clist != NULL);
2038 g_return_if_fail (GTK_IS_CLIST (clist));
2040 if (row < 0 || row > (clist->rows - 1))
2043 clist_row = (g_list_nth (clist->row_list, row))->data;
2044 clist_row->data = data;
2045 clist_row->destroy = destroy;
2047 /* re-send the selected signal if data is changed/added
2048 * so the application can respond to the new data --
2049 * this could be questionable behavior */
2050 if (clist_row->state == GTK_STATE_SELECTED)
2051 select_row (clist, row, -1, NULL);
2055 gtk_clist_get_row_data (GtkCList * clist,
2058 GtkCListRow *clist_row;
2060 g_return_val_if_fail (clist != NULL, NULL);
2061 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2063 if (row < 0 || row > (clist->rows - 1))
2066 clist_row = (g_list_nth (clist->row_list, row))->data;
2067 return clist_row->data;
2071 gtk_clist_find_row_from_data (GtkCList * clist,
2077 g_return_val_if_fail (clist != NULL, -1);
2078 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
2080 if (clist->rows < 1)
2081 return -1; /* is this an optimization or just worthless? */
2083 for (n = 0, list = clist->row_list; list; n++, list = list->next)
2084 if (GTK_CLIST_ROW (list)->data == data)
2091 gtk_clist_select_row (GtkCList * clist,
2095 g_return_if_fail (clist != NULL);
2096 g_return_if_fail (GTK_IS_CLIST (clist));
2098 if (row < 0 || row >= clist->rows)
2101 if (column < -1 || column >= clist->columns)
2104 select_row (clist, row, column, NULL);
2108 gtk_clist_unselect_row (GtkCList * clist,
2112 g_return_if_fail (clist != NULL);
2113 g_return_if_fail (GTK_IS_CLIST (clist));
2115 if (row < 0 || row >= clist->rows)
2118 if (column < -1 || column >= clist->columns)
2121 unselect_row (clist, row, column, NULL);
2125 gtk_clist_row_is_visible (GtkCList * clist,
2130 g_return_val_if_fail (clist != NULL, 0);
2131 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
2133 if (row < 0 || row >= clist->rows)
2134 return GTK_VISIBILITY_NONE;
2136 if (clist->row_height == 0)
2137 return GTK_VISIBILITY_NONE;
2139 if (row < ROW_FROM_YPIXEL (clist, 0))
2140 return GTK_VISIBILITY_NONE;
2142 if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height))
2143 return GTK_VISIBILITY_NONE;
2145 top = ROW_TOP_YPIXEL (clist, row);
2148 || ((top + clist->row_height) >= clist->clist_window_height))
2149 return GTK_VISIBILITY_PARTIAL;
2151 return GTK_VISIBILITY_FULL;
2155 gtk_clist_get_vadjustment (GtkCList * clist)
2157 g_return_val_if_fail (clist != NULL, NULL);
2158 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2160 return gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
2164 gtk_clist_get_hadjustment (GtkCList * clist)
2166 g_return_val_if_fail (clist != NULL, NULL);
2167 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2169 return gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
2173 gtk_clist_set_policy (GtkCList * clist,
2174 GtkPolicyType vscrollbar_policy,
2175 GtkPolicyType hscrollbar_policy)
2177 g_return_if_fail (clist != NULL);
2178 g_return_if_fail (GTK_IS_CLIST (clist));
2180 if (clist->vscrollbar_policy != vscrollbar_policy)
2182 clist->vscrollbar_policy = vscrollbar_policy;
2184 if (GTK_WIDGET (clist)->parent)
2185 gtk_widget_queue_resize (GTK_WIDGET (clist));
2188 if (clist->hscrollbar_policy != hscrollbar_policy)
2190 clist->hscrollbar_policy = hscrollbar_policy;
2192 if (GTK_WIDGET (clist)->parent)
2193 gtk_widget_queue_resize (GTK_WIDGET (clist));
2198 gtk_clist_undo_selection (GtkCList *clist)
2200 g_return_if_fail (clist != NULL);
2201 g_return_if_fail (GTK_IS_CLIST (clist));
2203 if (clist->selection_mode == GTK_SELECTION_EXTENDED &&
2204 (clist->undo_selection || clist->undo_unselection))
2205 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNDO_SELECTION]);
2209 real_undo_selection (GtkCList *clist)
2213 g_return_if_fail (clist != NULL);
2214 g_return_if_fail (GTK_IS_CLIST (clist));
2216 if (gdk_pointer_is_grabbed () ||
2217 clist->selection_mode != GTK_SELECTION_EXTENDED)
2220 if (clist->anchor >= 0)
2221 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
2223 if (!(clist->undo_selection || clist->undo_unselection))
2225 gtk_clist_unselect_all (clist);
2229 for (work = clist->undo_selection; work; work = work->next)
2230 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
2231 GPOINTER_TO_INT (work->data), -1, NULL);
2233 for (work = clist->undo_unselection; work; work = work->next)
2234 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
2235 GPOINTER_TO_INT (work->data), -1, NULL);
2237 if (GTK_WIDGET_HAS_FOCUS (clist) && clist->focus_row != clist->undo_anchor)
2239 gtk_clist_draw_focus (GTK_WIDGET (clist));
2240 clist->focus_row = clist->undo_anchor;
2241 gtk_clist_draw_focus (GTK_WIDGET (clist));
2244 clist->focus_row = clist->undo_anchor;
2246 clist->undo_anchor = -1;
2248 g_list_free (clist->undo_selection);
2249 g_list_free (clist->undo_unselection);
2250 clist->undo_selection = NULL;
2251 clist->undo_unselection = NULL;
2253 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
2254 clist->clist_window_height)
2255 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
2256 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
2257 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
2263 * gtk_clist_finalize
2266 gtk_clist_destroy (GtkObject * object)
2271 g_return_if_fail (object != NULL);
2272 g_return_if_fail (GTK_IS_CLIST (object));
2274 clist = GTK_CLIST (object);
2276 /* freeze the list */
2277 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2279 /* get rid of all the rows */
2280 gtk_clist_clear (clist);
2282 /* Since we don't have a _remove method, unparent the children
2283 * instead of destroying them so the focus will be unset properly.
2284 * (For other containers, the _remove method takes care of the
2285 * unparent) The destroy will happen when the refcount drops
2289 /* destroy the scrollbars */
2290 if (clist->vscrollbar)
2292 gtk_widget_unparent (clist->vscrollbar);
2293 clist->vscrollbar = NULL;
2295 if (clist->hscrollbar)
2297 gtk_widget_unparent (clist->hscrollbar);
2298 clist->hscrollbar = NULL;
2303 gtk_timeout_remove (clist->htimer);
2308 gtk_timeout_remove (clist->vtimer);
2312 /* destroy the column buttons */
2313 for (i = 0; i < clist->columns; i++)
2314 if (clist->column[i].button)
2316 gtk_widget_unparent (clist->column[i].button);
2317 clist->column[i].button = NULL;
2320 if (GTK_OBJECT_CLASS (parent_class)->destroy)
2321 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2325 gtk_clist_finalize (GtkObject * object)
2329 g_return_if_fail (object != NULL);
2330 g_return_if_fail (GTK_IS_CLIST (object));
2332 clist = GTK_CLIST (object);
2334 columns_delete (clist);
2336 g_mem_chunk_destroy (clist->cell_mem_chunk);
2337 g_mem_chunk_destroy (clist->row_mem_chunk);
2339 if (GTK_OBJECT_CLASS (parent_class)->finalize)
2340 (*GTK_OBJECT_CLASS (parent_class)->finalize) (object);
2346 * gtk_clist_unrealize
2351 * gtk_clist_button_press
2352 * gtk_clist_button_release
2353 * gtk_clist_button_motion
2354 * gtk_clist_size_request
2355 * gtk_clist_size_allocate
2358 gtk_clist_realize (GtkWidget * widget)
2362 GdkWindowAttr attributes;
2363 gint attributes_mask;
2367 g_return_if_fail (widget != NULL);
2368 g_return_if_fail (GTK_IS_CLIST (widget));
2370 clist = GTK_CLIST (widget);
2372 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2374 add_style_data (clist);
2376 border_width = GTK_CONTAINER (widget)->border_width;
2378 attributes.window_type = GDK_WINDOW_CHILD;
2379 attributes.x = widget->allocation.x + border_width;
2380 attributes.y = widget->allocation.y + border_width;
2381 attributes.width = widget->allocation.width - border_width * 2;
2382 attributes.height = widget->allocation.height - border_width * 2;
2383 attributes.wclass = GDK_INPUT_OUTPUT;
2384 attributes.visual = gtk_widget_get_visual (widget);
2385 attributes.colormap = gtk_widget_get_colormap (widget);
2386 attributes.event_mask = gtk_widget_get_events (widget);
2387 attributes.event_mask |= (GDK_EXPOSURE_MASK |
2388 GDK_BUTTON_PRESS_MASK |
2389 GDK_BUTTON_RELEASE_MASK |
2390 GDK_KEY_PRESS_MASK |
2391 GDK_KEY_RELEASE_MASK);
2392 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2395 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
2396 gdk_window_set_user_data (widget->window, clist);
2398 widget->style = gtk_style_attach (widget->style, widget->window);
2400 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
2402 /* column-title window */
2404 attributes.x = clist->column_title_area.x;
2405 attributes.y = clist->column_title_area.y;
2406 attributes.width = clist->column_title_area.width;
2407 attributes.height = clist->column_title_area.height;
2409 clist->title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2410 gdk_window_set_user_data (clist->title_window, clist);
2412 gtk_style_set_background (widget->style, clist->title_window, GTK_STATE_SELECTED);
2413 gdk_window_show (clist->title_window);
2415 /* set things up so column buttons are drawn in title window */
2416 for (i = 0; i < clist->columns; i++)
2417 if (clist->column[i].button)
2418 gtk_widget_set_parent_window (clist->column[i].button, clist->title_window);
2421 attributes.x = clist->internal_allocation.x + widget->style->klass->xthickness;
2422 attributes.y = clist->internal_allocation.y + widget->style->klass->ythickness +
2423 clist->column_title_area.height;
2424 attributes.width = clist->clist_window_width;
2425 attributes.height = clist->clist_window_height;
2427 clist->clist_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2428 gdk_window_set_user_data (clist->clist_window, clist);
2430 gdk_window_set_background (clist->clist_window, &widget->style->bg[GTK_STATE_PRELIGHT]);
2431 gdk_window_show (clist->clist_window);
2432 gdk_window_get_size (clist->clist_window, &clist->clist_window_width,
2433 &clist->clist_window_height);
2435 /* create resize windows */
2436 attributes.wclass = GDK_INPUT_ONLY;
2437 attributes.event_mask = (GDK_BUTTON_PRESS_MASK |
2438 GDK_BUTTON_RELEASE_MASK |
2439 GDK_POINTER_MOTION_MASK |
2440 GDK_POINTER_MOTION_HINT_MASK |
2441 GDK_KEY_PRESS_MASK);
2442 attributes.cursor = clist->cursor_drag = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
2443 attributes_mask = GDK_WA_CURSOR;
2445 for (i = 0; i < clist->columns; i++)
2447 clist->column[i].window = gdk_window_new (clist->title_window, &attributes, attributes_mask);
2448 gdk_window_set_user_data (clist->column[i].window, clist);
2451 /* This is slightly less efficient than creating them with the
2452 * right size to begin with, but easier
2454 size_allocate_title_buttons (clist);
2457 clist->fg_gc = gdk_gc_new (widget->window);
2458 clist->bg_gc = gdk_gc_new (widget->window);
2460 /* We'll use this gc to do scrolling as well */
2461 gdk_gc_set_exposures (clist->fg_gc, TRUE);
2463 values.foreground = widget->style->white;
2464 values.function = GDK_XOR;
2465 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
2466 clist->xor_gc = gdk_gc_new_with_values (widget->window,
2474 gtk_clist_unrealize (GtkWidget * widget)
2479 g_return_if_fail (widget != NULL);
2480 g_return_if_fail (GTK_IS_CLIST (widget));
2482 clist = GTK_CLIST (widget);
2484 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2486 gdk_cursor_destroy (clist->cursor_drag);
2487 gdk_gc_destroy (clist->xor_gc);
2488 gdk_gc_destroy (clist->fg_gc);
2489 gdk_gc_destroy (clist->bg_gc);
2491 for (i = 0; i < clist->columns; i++)
2492 if (clist->column[i].window)
2494 gdk_window_set_user_data (clist->column[i].window, NULL);
2495 gdk_window_destroy (clist->column[i].window);
2496 clist->column[i].window = NULL;
2499 gdk_window_set_user_data (clist->clist_window, NULL);
2500 gdk_window_destroy (clist->clist_window);
2501 clist->clist_window = NULL;
2503 gdk_window_set_user_data (clist->title_window, NULL);
2504 gdk_window_destroy (clist->title_window);
2505 clist->title_window = NULL;
2507 clist->cursor_drag = NULL;
2508 clist->xor_gc = NULL;
2509 clist->fg_gc = NULL;
2510 clist->bg_gc = NULL;
2512 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
2513 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2517 gtk_clist_map (GtkWidget * widget)
2522 g_return_if_fail (widget != NULL);
2523 g_return_if_fail (GTK_IS_CLIST (widget));
2525 clist = GTK_CLIST (widget);
2527 if (!GTK_WIDGET_MAPPED (widget))
2529 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
2531 gdk_window_show (widget->window);
2532 gdk_window_show (clist->title_window);
2533 gdk_window_show (clist->clist_window);
2535 /* map column buttons */
2536 for (i = 0; i < clist->columns; i++)
2537 if (clist->column[i].button &&
2538 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
2539 !GTK_WIDGET_MAPPED (clist->column[i].button))
2540 gtk_widget_map (clist->column[i].button);
2542 /* map resize windows AFTER column buttons (above) */
2543 for (i = 0; i < clist->columns; i++)
2544 if (clist->column[i].window && clist->column[i].button)
2545 gdk_window_show (clist->column[i].window);
2547 /* map vscrollbars */
2548 if (GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
2549 !GTK_WIDGET_MAPPED (clist->vscrollbar))
2550 gtk_widget_map (clist->vscrollbar);
2552 if (GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
2553 !GTK_WIDGET_MAPPED (clist->hscrollbar))
2554 gtk_widget_map (clist->hscrollbar);
2556 /* unfreeze the list */
2557 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
2562 gtk_clist_unmap (GtkWidget * widget)
2567 g_return_if_fail (widget != NULL);
2568 g_return_if_fail (GTK_IS_CLIST (widget));
2570 clist = GTK_CLIST (widget);
2572 if (GTK_WIDGET_MAPPED (widget))
2574 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
2576 for (i = 0; i < clist->columns; i++)
2577 if (clist->column[i].window)
2578 gdk_window_hide (clist->column[i].window);
2580 gdk_window_hide (clist->clist_window);
2581 gdk_window_hide (clist->title_window);
2582 gdk_window_hide (widget->window);
2584 /* unmap scrollbars */
2585 if (GTK_WIDGET_MAPPED (clist->vscrollbar))
2586 gtk_widget_unmap (clist->vscrollbar);
2588 if (GTK_WIDGET_MAPPED (clist->hscrollbar))
2589 gtk_widget_unmap (clist->hscrollbar);
2591 /* unmap column buttons */
2592 for (i = 0; i < clist->columns; i++)
2593 if (clist->column[i].button &&
2594 GTK_WIDGET_MAPPED (clist->column[i].button))
2595 gtk_widget_unmap (clist->column[i].button);
2597 /* freeze the list */
2598 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2603 gtk_clist_draw (GtkWidget * widget,
2604 GdkRectangle * area)
2609 g_return_if_fail (widget != NULL);
2610 g_return_if_fail (GTK_IS_CLIST (widget));
2611 g_return_if_fail (area != NULL);
2613 if (GTK_WIDGET_DRAWABLE (widget))
2615 clist = GTK_CLIST (widget);
2616 border_width = GTK_CONTAINER (widget)->border_width;
2618 gdk_window_clear_area (widget->window,
2619 area->x - border_width,
2620 area->y - border_width,
2621 area->width, area->height);
2623 /* draw list shadow/border */
2624 gtk_draw_shadow (widget->style, widget->window,
2625 GTK_STATE_NORMAL, clist->shadow_type,
2627 clist->clist_window_width + (2 * widget->style->klass->xthickness),
2628 clist->clist_window_height + (2 * widget->style->klass->ythickness) +
2629 clist->column_title_area.height);
2631 gdk_window_clear_area (clist->clist_window,
2634 draw_rows (clist, NULL);
2639 gtk_clist_expose (GtkWidget * widget,
2640 GdkEventExpose * event)
2644 g_return_val_if_fail (widget != NULL, FALSE);
2645 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2646 g_return_val_if_fail (event != NULL, FALSE);
2648 if (GTK_WIDGET_DRAWABLE (widget))
2650 clist = GTK_CLIST (widget);
2653 if (event->window == widget->window)
2654 gtk_draw_shadow (widget->style, widget->window,
2655 GTK_STATE_NORMAL, clist->shadow_type,
2657 clist->clist_window_width + (2 * widget->style->klass->xthickness),
2658 clist->clist_window_height + (2 * widget->style->klass->ythickness) +
2659 clist->column_title_area.height);
2661 /* exposure events on the list */
2662 if (event->window == clist->clist_window)
2663 draw_rows (clist, &event->area);
2670 gtk_clist_button_press (GtkWidget * widget,
2671 GdkEventButton * event)
2680 g_return_val_if_fail (widget != NULL, FALSE);
2681 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2682 g_return_val_if_fail (event != NULL, FALSE);
2684 clist = GTK_CLIST (widget);
2686 /* we don't handle button 2 and 3 */
2687 if (event->button != 1)
2690 /* selections on the list */
2691 if (event->window == clist->clist_window)
2696 if (get_selection_info (clist, x, y, &row, &column))
2698 gint old_row = clist->focus_row;
2699 gboolean no_focus_row = FALSE;
2701 if (clist->focus_row == -1)
2704 no_focus_row = TRUE;
2707 if (event->type == GDK_BUTTON_PRESS)
2709 GTK_CLIST_SET_FLAG (clist, CLIST_DRAG_SELECTION);
2710 gdk_pointer_grab (clist->clist_window, FALSE,
2711 GDK_POINTER_MOTION_HINT_MASK |
2712 GDK_BUTTON1_MOTION_MASK |
2713 GDK_BUTTON_RELEASE_MASK,
2714 NULL, NULL, event->time);
2716 else if (gdk_pointer_is_grabbed ())
2718 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
2719 gdk_pointer_ungrab (event->time);
2722 if (GTK_CLIST_ADD_MODE (clist))
2724 GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
2725 if (GTK_WIDGET_HAS_FOCUS (widget))
2727 gtk_clist_draw_focus (widget);
2728 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2729 GDK_LINE_SOLID, 0, 0);
2730 clist->focus_row = row;
2731 gtk_clist_draw_focus (widget);
2735 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2736 GDK_LINE_SOLID, 0, 0);
2737 clist->focus_row = row;
2740 else if (row != clist->focus_row)
2742 if (GTK_WIDGET_HAS_FOCUS (widget))
2744 gtk_clist_draw_focus (widget);
2745 clist->focus_row = row;
2746 gtk_clist_draw_focus (widget);
2749 clist->focus_row = row;
2752 if (!GTK_WIDGET_HAS_FOCUS (widget))
2753 gtk_widget_grab_focus (widget);
2755 switch (clist->selection_mode)
2757 case GTK_SELECTION_SINGLE:
2758 case GTK_SELECTION_MULTIPLE:
2759 if (event->type != GDK_BUTTON_PRESS)
2760 select_row (clist, row, column, (GdkEvent *) event);
2762 clist->anchor = row;
2765 case GTK_SELECTION_BROWSE:
2766 select_row (clist, row, column, (GdkEvent *) event);
2769 case GTK_SELECTION_EXTENDED:
2770 if (event->type != GDK_BUTTON_PRESS)
2772 if (clist->anchor != -1)
2774 update_extended_selection (clist, clist->focus_row);
2775 GTK_CLIST_CLASS_FW (clist)->resync_selection
2776 (clist, (GdkEvent *) event);
2778 select_row (clist, row, column, (GdkEvent *) event);
2782 if (event->state & GDK_CONTROL_MASK)
2784 if (event->state & GDK_SHIFT_MASK)
2786 set_anchor (clist, TRUE, old_row, old_row);
2787 update_extended_selection (clist, clist->focus_row);
2791 if (clist->anchor == -1)
2792 set_anchor (clist, TRUE, row, old_row);
2794 update_extended_selection (clist, clist->focus_row);
2799 if (event->state & GDK_SHIFT_MASK)
2801 set_anchor (clist, FALSE, old_row, old_row);
2802 update_extended_selection (clist, clist->focus_row);
2806 if (clist->anchor == -1)
2807 set_anchor (clist, FALSE, row, old_row);
2809 update_extended_selection (clist, clist->focus_row);
2820 /* press on resize windows */
2821 for (i = 0; i < clist->columns; i++)
2822 if (clist->column[i].window && event->window == clist->column[i].window)
2824 GTK_CLIST_SET_FLAG (clist, CLIST_IN_DRAG);
2825 gtk_widget_get_pointer (widget, &clist->x_drag, NULL);
2827 gdk_pointer_grab (clist->column[i].window, FALSE,
2828 GDK_POINTER_MOTION_HINT_MASK |
2829 GDK_BUTTON1_MOTION_MASK |
2830 GDK_BUTTON_RELEASE_MASK,
2831 NULL, NULL, event->time);
2833 if (GTK_CLIST_ADD_MODE (clist))
2834 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
2836 draw_xor_line (clist);
2844 gtk_clist_button_release (GtkWidget * widget,
2845 GdkEventButton * event)
2847 gint i, x, width, visible;
2850 g_return_val_if_fail (widget != NULL, FALSE);
2851 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2852 g_return_val_if_fail (event != NULL, FALSE);
2854 clist = GTK_CLIST (widget);
2856 /* we don't handle button 2 and 3 */
2857 if (event->button != 1)
2860 /* release on resize windows */
2861 if (GTK_CLIST_IN_DRAG (clist))
2862 for (i = 0; i < clist->columns; i++)
2863 if (clist->column[i].window && event->window == clist->column[i].window)
2865 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
2866 gtk_widget_get_pointer (widget, &x, NULL);
2867 width = new_column_width (clist, i, &x, &visible);
2868 gdk_pointer_ungrab (event->time);
2871 draw_xor_line (clist);
2873 if (GTK_CLIST_ADD_MODE (clist))
2875 gdk_gc_set_line_attributes (clist->xor_gc, 1,
2876 GDK_LINE_ON_OFF_DASH, 0, 0);
2877 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
2880 resize_column (clist, i, width);
2884 if (GTK_CLIST_DRAG_SELECTION (clist))
2889 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
2890 gdk_pointer_ungrab (event->time);
2893 gtk_timeout_remove (clist->htimer);
2898 gtk_timeout_remove (clist->vtimer);
2901 switch (clist->selection_mode)
2903 case GTK_SELECTION_EXTENDED:
2904 if (!(event->state & GDK_SHIFT_MASK) ||
2905 event->x < 0 || event->x >= clist->clist_window_width ||
2906 event->y < 0 || event->y >= clist->clist_window_height)
2907 GTK_CLIST_CLASS_FW (clist)->resync_selection
2908 (clist, (GdkEvent *) event);
2911 case GTK_SELECTION_SINGLE:
2912 case GTK_SELECTION_MULTIPLE:
2913 if (get_selection_info (clist, event->x, event->y, &row, &column))
2915 if (clist->anchor == clist->focus_row)
2916 toggle_row (clist, row, column, (GdkEvent *) event);
2930 horizontal_timeout (GtkCList *clist)
2933 GdkEventMotion event;
2934 GdkModifierType mask;
2936 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
2939 gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
2946 gtk_clist_motion (GTK_WIDGET (clist), &event);
2952 vertical_timeout (GtkCList *clist)
2955 GdkEventMotion event;
2956 GdkModifierType mask;
2958 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
2961 gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
2968 gtk_clist_motion (GTK_WIDGET (clist), &event);
2974 move_vertical (GtkCList *clist,
2981 adj = GTK_RANGE (clist->vscrollbar)->adjustment;
2983 y = ROW_TOP_YPIXEL (clist, row) - clist->voffset;
2985 y = y - align * (clist->clist_window_height - clist->row_height)
2986 + (2 * align - 1) * CELL_SPACING;
2988 if (y + adj->page_size > adj->upper)
2989 adj->value = adj->upper - adj->page_size;
2993 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
2997 move_horizontal (GtkCList *clist,
3003 adj = GTK_RANGE (clist->hscrollbar)->adjustment;
3007 upper = adj->upper - adj->page_size;
3008 adj->value = MIN (adj->value, upper);
3009 adj->value = MAX (adj->value, 0.0);
3011 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
3015 gtk_clist_motion (GtkWidget * widget,
3016 GdkEventMotion * event)
3018 gint i, x, y, visible;
3021 g_return_val_if_fail (widget != NULL, FALSE);
3022 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
3024 clist = GTK_CLIST (widget);
3026 if (GTK_CLIST_IN_DRAG (clist))
3027 for (i = 0; i < clist->columns; i++)
3028 if (clist->column[i].window && event->window == clist->column[i].window)
3030 if (event->is_hint || event->window != widget->window)
3031 gtk_widget_get_pointer (widget, &x, NULL);
3035 new_column_width (clist, i, &x, &visible);
3036 /* Welcome to my hack! I'm going to use a value of x_drage = -99999 to
3037 * indicate the the xor line is already no visible */
3038 if (!visible && clist->x_drag != -99999)
3040 draw_xor_line (clist);
3041 clist->x_drag = -99999;
3044 if (x != clist->x_drag && visible)
3046 if (clist->x_drag != -99999)
3047 draw_xor_line (clist);
3050 draw_xor_line (clist);
3054 if (GTK_CLIST_DRAG_SELECTION (clist))
3058 if (event->is_hint || event->window != clist->clist_window)
3059 gdk_window_get_pointer (clist->clist_window, &x, &y, NULL);
3061 /* horizontal autoscrolling */
3062 if (LIST_WIDTH (clist) > clist->clist_window_width &&
3063 (x < 0 || x >= clist->clist_window_width))
3065 if (clist->htimer == 0)
3067 clist->htimer = gtk_timeout_add
3068 (SCROLL_TIME, (GtkFunction) horizontal_timeout, clist);
3070 if (!((x < 0 && GTK_RANGE (clist->hscrollbar)->adjustment->value
3071 == 0) || (x >= clist->clist_window_width &&
3072 GTK_RANGE (clist->hscrollbar)->adjustment->value ==
3073 LIST_WIDTH (clist) - clist->clist_window_width)))
3076 move_horizontal (clist, -1 + (x/2));
3078 move_horizontal (clist,
3079 1 + (x - clist->clist_window_width) / 2);
3086 row = ROW_FROM_YPIXEL (clist, y);
3088 /* don't scroll on last pixel row if it's a cell spacing */
3089 if (y == clist->clist_window_height-1 &&
3090 y == ROW_TOP_YPIXEL (clist, row-1) + clist->row_height)
3093 /* vertical autoscrolling */
3094 if (LIST_HEIGHT (clist) > clist->clist_window_height &&
3095 (y < 0 || y >= clist->clist_window_height))
3097 if (clist->vtimer == 0)
3099 clist->vtimer = gtk_timeout_add (SCROLL_TIME,
3100 (GtkFunction) vertical_timeout,
3103 if ((y < 0 && clist->focus_row == 0) ||
3104 (y >= clist->clist_window_height &&
3105 clist->focus_row == clist->rows-1))
3108 if (row < 0 && clist->focus_row > 0)
3110 gtk_clist_draw_focus (widget);
3111 clist->focus_row = 0;
3112 gtk_clist_draw_focus (widget);
3114 else if (row > clist->rows - 1 && clist->focus_row
3117 gtk_clist_draw_focus (widget);
3118 clist->focus_row = clist->rows - 1;
3119 gtk_clist_draw_focus (widget);
3121 else if (row >= 0 && row <= clist->rows - 1)
3123 gtk_clist_draw_focus (widget);
3124 clist->focus_row = row;
3125 gtk_clist_draw_focus (widget);
3130 switch (clist->selection_mode)
3132 case GTK_SELECTION_BROWSE:
3133 select_row (clist, clist->focus_row, -1, (GdkEvent *) event);
3136 case GTK_SELECTION_EXTENDED:
3137 update_extended_selection (clist, clist->focus_row);
3145 move_vertical (clist, row, 0);
3147 move_vertical (clist, row, 1);
3153 if (row == clist->focus_row)
3156 /* dragging inside clist_window */
3157 if (row < 0 && clist->focus_row > 0)
3159 gtk_clist_draw_focus (widget);
3160 clist->focus_row = 0;
3161 gtk_clist_draw_focus (widget);
3163 else if (row > clist->rows-1 && clist->focus_row < clist->rows-1)
3165 gtk_clist_draw_focus (widget);
3166 clist->focus_row = clist->rows-1;
3167 gtk_clist_draw_focus (widget);
3169 else if (row >= 0 && row <= clist->rows-1)
3171 gtk_clist_draw_focus (widget);
3172 clist->focus_row = row;
3173 gtk_clist_draw_focus (widget);
3178 switch (clist->selection_mode)
3180 case GTK_SELECTION_EXTENDED:
3181 update_extended_selection (clist, clist->focus_row);
3184 case GTK_SELECTION_BROWSE:
3185 select_row (clist, clist->focus_row, -1, (GdkEvent *) event);
3192 if (ROW_TOP_YPIXEL(clist, clist->focus_row) + clist->row_height <= 0)
3193 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
3194 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
3195 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
3196 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) >=
3197 clist->clist_window_height)
3198 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
3199 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
3200 clist->clist_window_height)
3201 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
3207 gtk_clist_size_request (GtkWidget * widget,
3208 GtkRequisition * requisition)
3213 g_return_if_fail (widget != NULL);
3214 g_return_if_fail (GTK_IS_CLIST (widget));
3215 g_return_if_fail (requisition != NULL);
3217 clist = GTK_CLIST (widget);
3219 add_style_data (clist);
3221 requisition->width = 0;
3222 requisition->height = 0;
3224 /* compute the size of the column title (title) area */
3225 clist->column_title_area.height = 0;
3226 if (GTK_CLIST_SHOW_TITLES (clist))
3227 for (i = 0; i < clist->columns; i++)
3228 if (clist->column[i].button)
3230 gtk_widget_size_request (clist->column[i].button, &clist->column[i].button->requisition);
3231 clist->column_title_area.height = MAX (clist->column_title_area.height,
3232 clist->column[i].button->requisition.height);
3234 requisition->height += clist->column_title_area.height;
3236 /* add the vscrollbar space */
3237 if ((clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
3238 GTK_WIDGET_VISIBLE (clist->vscrollbar))
3240 gtk_widget_size_request (clist->vscrollbar, &clist->vscrollbar->requisition);
3242 requisition->width += clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist);
3243 requisition->height = MAX (requisition->height,
3244 clist->vscrollbar->requisition.height);
3247 /* add the hscrollbar space */
3248 if ((clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
3249 GTK_WIDGET_VISIBLE (clist->hscrollbar))
3251 gtk_widget_size_request (clist->hscrollbar, &clist->hscrollbar->requisition);
3253 requisition->height += clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist);
3254 requisition->width = MAX (clist->hscrollbar->requisition.width,
3255 requisition->width -
3256 clist->vscrollbar->requisition.width);
3260 requisition->width += widget->style->klass->xthickness * 2 +
3261 GTK_CONTAINER (widget)->border_width * 2;
3262 requisition->height += widget->style->klass->ythickness * 2 +
3263 GTK_CONTAINER (widget)->border_width * 2;
3267 gtk_clist_size_allocate (GtkWidget * widget,
3268 GtkAllocation * allocation)
3271 GtkAllocation clist_allocation;
3272 GtkAllocation child_allocation;
3273 gint i, vscrollbar_vis, hscrollbar_vis;
3275 g_return_if_fail (widget != NULL);
3276 g_return_if_fail (GTK_IS_CLIST (widget));
3277 g_return_if_fail (allocation != NULL);
3279 clist = GTK_CLIST (widget);
3280 widget->allocation = *allocation;
3282 if (GTK_WIDGET_REALIZED (widget))
3284 gdk_window_move_resize (widget->window,
3285 allocation->x + GTK_CONTAINER (widget)->border_width,
3286 allocation->y + GTK_CONTAINER (widget)->border_width,
3287 allocation->width - GTK_CONTAINER (widget)->border_width * 2,
3288 allocation->height - GTK_CONTAINER (widget)->border_width * 2);
3291 /* use internal allocation structure for all the math
3292 * because it's easier than always subtracting the container
3294 clist->internal_allocation.x = 0;
3295 clist->internal_allocation.y = 0;
3296 clist->internal_allocation.width = MAX (1, allocation->width -
3297 GTK_CONTAINER (widget)->border_width * 2);
3298 clist->internal_allocation.height = MAX (1, allocation->height -
3299 GTK_CONTAINER (widget)->border_width * 2);
3301 /* allocate clist window assuming no scrollbars */
3302 clist_allocation.x = clist->internal_allocation.x + widget->style->klass->xthickness;
3303 clist_allocation.y = clist->internal_allocation.y + widget->style->klass->ythickness +
3304 clist->column_title_area.height;
3305 clist_allocation.width = MAX (1, clist->internal_allocation.width -
3306 (2 * widget->style->klass->xthickness));
3307 clist_allocation.height = MAX (1, clist->internal_allocation.height -
3308 (2 * widget->style->klass->ythickness) -
3309 clist->column_title_area.height);
3312 * here's where we decide to show/not show the scrollbars
3317 for (i = 0; i <= 1; i++)
3319 if (LIST_HEIGHT (clist) <= clist_allocation.height &&
3320 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
3326 if (!vscrollbar_vis)
3329 clist_allocation.width = MAX (1, clist_allocation.width -
3330 (clist->vscrollbar->requisition.width +
3331 SCROLLBAR_SPACING (clist)));
3335 if (LIST_WIDTH (clist) <= clist_allocation.width &&
3336 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
3342 if (!hscrollbar_vis)
3345 clist_allocation.height = MAX (1, clist_allocation.height -
3346 (clist->hscrollbar->requisition.height +
3347 SCROLLBAR_SPACING (clist)));
3352 clist->clist_window_width = clist_allocation.width;
3353 clist->clist_window_height = clist_allocation.height;
3355 if (GTK_WIDGET_REALIZED (widget))
3357 gdk_window_move_resize (clist->clist_window,
3360 clist_allocation.width,
3361 clist_allocation.height);
3364 /* position the window which holds the column title buttons */
3365 clist->column_title_area.x = widget->style->klass->xthickness;
3366 clist->column_title_area.y = widget->style->klass->ythickness;
3367 clist->column_title_area.width = clist_allocation.width;
3369 if (GTK_WIDGET_REALIZED (widget))
3371 gdk_window_move_resize (clist->title_window,
3372 clist->column_title_area.x,
3373 clist->column_title_area.y,
3374 clist->column_title_area.width,
3375 clist->column_title_area.height);
3378 /* column button allocation */
3379 size_allocate_columns (clist);
3381 if (GTK_WIDGET_REALIZED (widget))
3382 size_allocate_title_buttons (clist);
3384 adjust_scrollbars (clist);
3386 /* allocate the vscrollbar */
3389 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
3390 gtk_widget_show (clist->vscrollbar);
3392 child_allocation.x = clist->internal_allocation.x +
3393 clist->internal_allocation.width -
3394 clist->vscrollbar->requisition.width;
3395 child_allocation.y = clist->internal_allocation.y;
3396 child_allocation.width = clist->vscrollbar->requisition.width;
3397 child_allocation.height = MAX (1, clist->internal_allocation.height -
3398 (hscrollbar_vis ? (clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist)) : 0));
3400 gtk_widget_size_allocate (clist->vscrollbar, &child_allocation);
3404 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
3405 gtk_widget_hide (clist->vscrollbar);
3410 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
3411 gtk_widget_show (clist->hscrollbar);
3413 child_allocation.x = clist->internal_allocation.x;
3414 child_allocation.y = clist->internal_allocation.y +
3415 clist->internal_allocation.height -
3416 clist->hscrollbar->requisition.height;
3417 child_allocation.width = MAX (1, clist->internal_allocation.width -
3418 (vscrollbar_vis ? (clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist)) : 0));
3419 child_allocation.height = clist->hscrollbar->requisition.height;
3421 gtk_widget_size_allocate (clist->hscrollbar, &child_allocation);
3425 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
3426 gtk_widget_hide (clist->hscrollbar);
3429 /* set the vscrollbar adjustments */
3430 adjust_scrollbars (clist);
3438 gtk_clist_foreach (GtkContainer * container,
3439 GtkCallback callback,
3440 gpointer callback_data)
3445 g_return_if_fail (container != NULL);
3446 g_return_if_fail (GTK_IS_CLIST (container));
3447 g_return_if_fail (callback != NULL);
3449 clist = GTK_CLIST (container);
3451 /* callback for the column buttons */
3452 for (i = 0; i < clist->columns; i++)
3453 if (clist->column[i].button)
3454 (*callback) (clist->column[i].button, callback_data);
3456 /* callbacks for the scrollbars */
3457 if (clist->vscrollbar)
3458 (*callback) (clist->vscrollbar, callback_data);
3459 if (clist->hscrollbar)
3460 (*callback) (clist->hscrollbar, callback_data);
3469 draw_row (GtkCList * clist,
3470 GdkRectangle * area,
3472 GtkCListRow * clist_row)
3475 GdkGC *fg_gc, *bg_gc;
3476 GdkRectangle row_rectangle, cell_rectangle, clip_rectangle, intersect_rectangle,
3478 gint i, offset = 0, width, height, pixmap_width = 0;
3479 gint xsrc, ysrc, xdest, ydest;
3481 g_return_if_fail (clist != NULL);
3483 /* bail now if we arn't drawable yet */
3484 if (!GTK_WIDGET_DRAWABLE (clist))
3487 if (row < 0 || row >= clist->rows)
3490 widget = GTK_WIDGET (clist);
3492 /* if the function is passed the pointer to the row instead of null,
3493 * it avoids this expensive lookup */
3495 clist_row = (g_list_nth (clist->row_list, row))->data;
3497 /* rectangle of the entire row */
3498 row_rectangle.x = 0;
3499 row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
3500 row_rectangle.width = clist->clist_window_width;
3501 row_rectangle.height = clist->row_height;
3503 /* rectangle of the cell spacing above the row */
3504 cell_rectangle.x = 0;
3505 cell_rectangle.y = row_rectangle.y - CELL_SPACING;
3506 cell_rectangle.width = row_rectangle.width;
3507 cell_rectangle.height = CELL_SPACING;
3509 /* rectangle used to clip drawing operations, it's y and height
3510 * positions only need to be set once, so we set them once here.
3511 * the x and width are set withing the drawing loop below once per
3513 clip_rectangle.y = row_rectangle.y;
3514 clip_rectangle.height = row_rectangle.height;
3516 /* select GC for background rectangle */
3517 if (clist_row->state == GTK_STATE_SELECTED)
3519 fg_gc = widget->style->fg_gc[GTK_STATE_SELECTED];
3520 bg_gc = widget->style->bg_gc[GTK_STATE_SELECTED];
3524 if (clist_row->fg_set)
3526 gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
3527 fg_gc = clist->fg_gc;
3530 fg_gc = widget->style->fg_gc[GTK_STATE_NORMAL];
3532 if (clist_row->bg_set)
3534 gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
3535 bg_gc = clist->bg_gc;
3538 bg_gc = widget->style->bg_gc[GTK_STATE_PRELIGHT];
3541 /* draw the cell borders and background */
3544 if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
3545 gdk_draw_rectangle (clist->clist_window,
3546 widget->style->base_gc[GTK_STATE_NORMAL],
3548 intersect_rectangle.x,
3549 intersect_rectangle.y,
3550 intersect_rectangle.width,
3551 intersect_rectangle.height);
3553 /* the last row has to clear it's bottom cell spacing too */
3554 if (clist_row == clist->row_list_end->data)
3556 cell_rectangle.y += clist->row_height + CELL_SPACING;
3558 if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
3559 gdk_draw_rectangle (clist->clist_window,
3560 widget->style->base_gc[GTK_STATE_NORMAL],
3562 intersect_rectangle.x,
3563 intersect_rectangle.y,
3564 intersect_rectangle.width,
3565 intersect_rectangle.height);
3568 if (!gdk_rectangle_intersect (area, &row_rectangle, &intersect_rectangle))
3571 if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
3572 gdk_draw_rectangle (clist->clist_window,
3575 intersect_rectangle.x,
3576 intersect_rectangle.y,
3577 intersect_rectangle.width,
3578 intersect_rectangle.height);
3580 gdk_window_clear_area (clist->clist_window,
3581 intersect_rectangle.x,
3582 intersect_rectangle.y,
3583 intersect_rectangle.width,
3584 intersect_rectangle.height);
3588 gdk_draw_rectangle (clist->clist_window,
3589 widget->style->base_gc[GTK_STATE_NORMAL],
3593 cell_rectangle.width,
3594 cell_rectangle.height);
3596 /* the last row has to clear it's bottom cell spacing too */
3597 if (clist_row == clist->row_list_end->data)
3599 cell_rectangle.y += clist->row_height + CELL_SPACING;
3601 gdk_draw_rectangle (clist->clist_window,
3602 widget->style->base_gc[GTK_STATE_NORMAL],
3606 cell_rectangle.width,
3607 cell_rectangle.height);
3610 if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
3611 gdk_draw_rectangle (clist->clist_window,
3616 row_rectangle.width,
3617 row_rectangle.height);
3619 gdk_window_clear_area (clist->clist_window,
3622 row_rectangle.width,
3623 row_rectangle.height);
3626 /* iterate and draw all the columns (row cells) and draw their contents */
3627 for (i = 0; i < clist->columns; i++)
3629 clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
3630 clip_rectangle.width = clist->column[i].area.width;
3632 /* calculate clipping region clipping region */
3635 rect = &clip_rectangle;
3639 if (!gdk_rectangle_intersect (area, &clip_rectangle,
3640 &intersect_rectangle))
3642 rect = &intersect_rectangle;
3645 /* calculate real width for column justification */
3646 switch (clist_row->cell[i].type)
3648 case GTK_CELL_EMPTY:
3653 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
3654 GTK_CELL_TEXT (clist_row->cell[i])->text);
3657 case GTK_CELL_PIXMAP:
3658 gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, &width, &height);
3659 pixmap_width = width;
3662 case GTK_CELL_PIXTEXT:
3663 gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, &width, &height);
3664 pixmap_width = width;
3665 width += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
3666 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
3667 GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
3670 case GTK_CELL_WIDGET:
3680 switch (clist->column[i].justification)
3682 case GTK_JUSTIFY_LEFT:
3683 offset = clip_rectangle.x;
3686 case GTK_JUSTIFY_RIGHT:
3687 offset = (clip_rectangle.x + clip_rectangle.width) - width;
3690 case GTK_JUSTIFY_CENTER:
3691 offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
3694 case GTK_JUSTIFY_FILL:
3695 offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
3703 /* Draw Text or Pixmap */
3704 switch (clist_row->cell[i].type)
3706 case GTK_CELL_EMPTY:
3711 gdk_gc_set_clip_rectangle (fg_gc, rect);
3713 gdk_draw_string (clist->clist_window,
3714 widget->style->font,
3716 offset + clist_row->cell[i].horizontal,
3717 row_rectangle.y + clist->row_center_offset +
3718 clist_row->cell[i].vertical,
3719 GTK_CELL_TEXT (clist_row->cell[i])->text);
3721 gdk_gc_set_clip_rectangle (fg_gc, NULL);
3724 case GTK_CELL_PIXMAP:
3727 xdest = offset + clist_row->cell[i].horizontal;
3728 ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
3729 clist_row->cell[i].vertical;
3731 if (xdest < clip_rectangle.x)
3733 xsrc = clip_rectangle.x - xdest;
3734 pixmap_width -= xsrc;
3735 xdest = clip_rectangle.x;
3738 if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width)
3739 pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest;
3741 if (ydest < clip_rectangle.y)
3743 ysrc = clip_rectangle.y - ydest;
3745 ydest = clip_rectangle.y;
3748 if (ydest + height > clip_rectangle.y + clip_rectangle.height)
3749 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
3751 if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
3753 gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXMAP (clist_row->cell[i])->mask);
3754 gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
3756 gdk_draw_pixmap (clist->clist_window,
3758 GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
3761 pixmap_width, height);
3763 if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
3765 gdk_gc_set_clip_origin (fg_gc, 0, 0);
3766 gdk_gc_set_clip_mask (fg_gc, NULL);
3770 case GTK_CELL_PIXTEXT:
3771 /* draw the pixmap */
3774 xdest = offset + clist_row->cell[i].horizontal;
3775 ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
3776 clist_row->cell[i].vertical;
3778 if (xdest < clip_rectangle.x)
3780 xsrc = clip_rectangle.x - xdest;
3781 pixmap_width -= xsrc;
3782 xdest = clip_rectangle.x;
3785 if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width)
3786 pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest;
3788 if (ydest < clip_rectangle.y)
3790 ysrc = clip_rectangle.y - ydest;
3792 ydest = clip_rectangle.y;
3795 if (ydest + height > clip_rectangle.y + clip_rectangle.height)
3796 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
3798 if (GTK_CELL_PIXTEXT (clist_row->cell[i])->mask)
3800 gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXTEXT (clist_row->cell[i])->mask);
3801 gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
3804 gdk_draw_pixmap (clist->clist_window,
3806 GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
3810 pixmap_width, height);
3812 gdk_gc_set_clip_origin (fg_gc, 0, 0);
3814 offset += pixmap_width + GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
3816 /* draw the string */
3817 gdk_gc_set_clip_rectangle (fg_gc, rect);
3819 gdk_draw_string (clist->clist_window,
3820 widget->style->font,
3822 offset + clist_row->cell[i].horizontal,
3823 row_rectangle.y + clist->row_center_offset +
3824 clist_row->cell[i].vertical,
3825 GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
3827 gdk_gc_set_clip_rectangle (fg_gc, NULL);
3830 case GTK_CELL_WIDGET:
3840 if (clist->focus_row == row && GTK_WIDGET_HAS_FOCUS (widget))
3844 if (gdk_rectangle_intersect (area, &row_rectangle,
3845 &intersect_rectangle))
3847 gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle);
3848 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
3849 row_rectangle.x, row_rectangle.y,
3850 row_rectangle.width - 1,
3851 row_rectangle.height - 1);
3852 gdk_gc_set_clip_rectangle (clist->xor_gc, NULL);
3856 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
3857 row_rectangle.x, row_rectangle.y,
3858 row_rectangle.width - 1, row_rectangle.height - 1);
3863 draw_rows (GtkCList * clist,
3864 GdkRectangle * area)
3867 GtkCListRow *clist_row;
3868 int i, first_row, last_row;
3870 g_return_if_fail (clist != NULL);
3871 g_return_if_fail (GTK_IS_CLIST (clist));
3873 if (clist->row_height == 0 ||
3874 !GTK_WIDGET_DRAWABLE (clist))
3879 first_row = ROW_FROM_YPIXEL (clist, area->y);
3880 last_row = ROW_FROM_YPIXEL (clist, area->y + area->height);
3884 first_row = ROW_FROM_YPIXEL (clist, 0);
3885 last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height);
3888 /* this is a small special case which exposes the bottom cell line
3889 * on the last row -- it might go away if I change the wall the cell spacings
3891 if (clist->rows == first_row)
3894 list = g_list_nth (clist->row_list, first_row);
3898 clist_row = list->data;
3904 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, area, i, clist_row);
3909 gdk_window_clear_area (clist->clist_window, 0, ROW_TOP_YPIXEL (clist, i), -1, -1);
3914 * size_allocate_title_buttons
3915 * size_allocate_columns
3918 size_allocate_title_buttons (GtkCList * clist)
3920 gint i, last_button = 0;
3921 GtkAllocation button_allocation;
3923 if (!GTK_WIDGET_REALIZED (clist))
3926 button_allocation.x = clist->hoffset;
3927 button_allocation.y = 0;
3928 button_allocation.width = 0;
3929 button_allocation.height = clist->column_title_area.height;
3931 for (i = 0; i < clist->columns; i++)
3933 button_allocation.width += clist->column[i].area.width;
3935 if (i == clist->columns - 1)
3936 button_allocation.width += 2 * (CELL_SPACING + COLUMN_INSET);
3938 button_allocation.width += CELL_SPACING + (2 * COLUMN_INSET);
3940 if (i == (clist->columns - 1) || clist->column[i + 1].button)
3942 gtk_widget_size_allocate (clist->column[last_button].button, &button_allocation);
3943 button_allocation.x += button_allocation.width;
3944 button_allocation.width = 0;
3946 gdk_window_show (clist->column[last_button].window);
3947 gdk_window_move_resize (clist->column[last_button].window,
3948 button_allocation.x - (DRAG_WIDTH / 2),
3949 0, DRAG_WIDTH, clist->column_title_area.height);
3951 last_button = i + 1;
3955 gdk_window_hide (clist->column[i].window);
3961 size_allocate_columns (GtkCList * clist)
3963 gint i, xoffset = 0;
3965 for (i = 0; i < clist->columns; i++)
3967 clist->column[i].area.x = xoffset + CELL_SPACING + COLUMN_INSET;
3969 if (i == clist->columns - 1)
3973 if (clist->column[i].width_set)
3975 width = clist->column[i].width;
3979 if (clist->column[i].title)
3980 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
3981 clist->column[i].title);
3986 clist->column[i].area.width = MAX (width,
3987 clist->clist_window_width -
3988 xoffset - (2 * (CELL_SPACING + COLUMN_INSET)));
3993 clist->column[i].area.width = clist->column[i].width;
3996 xoffset += clist->column[i].area.width + CELL_SPACING + (2 * COLUMN_INSET);
4005 * get_selection_info
4008 toggle_row (GtkCList * clist,
4013 GtkCListRow *clist_row;
4015 switch (clist->selection_mode)
4017 case GTK_SELECTION_EXTENDED:
4018 case GTK_SELECTION_MULTIPLE:
4019 case GTK_SELECTION_SINGLE:
4021 clist_row = g_list_nth (clist->row_list, row)->data;
4022 if (clist_row->state == GTK_STATE_SELECTED)
4024 unselect_row (clist, row, column, event);
4028 case GTK_SELECTION_BROWSE:
4029 select_row (clist, row, column, event);
4035 select_row (GtkCList * clist,
4040 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
4041 row, column, event);
4045 unselect_row (GtkCList * clist,
4050 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
4051 row, column, event);
4055 real_select_row (GtkCList * clist,
4060 GtkCListRow *clist_row;
4063 gboolean row_selected;
4065 g_return_if_fail (clist != NULL);
4066 g_return_if_fail (GTK_IS_CLIST (clist));
4068 if (row < 0 || row > (clist->rows - 1))
4071 switch (clist->selection_mode)
4073 case GTK_SELECTION_SINGLE:
4074 case GTK_SELECTION_BROWSE:
4076 row_selected = FALSE;
4077 list = clist->selection;
4081 sel_row = GPOINTER_TO_INT (list->data);
4085 row_selected = TRUE;
4087 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
4088 sel_row, column, event);
4098 clist_row = (g_list_nth (clist->row_list, row))->data;
4100 if (clist_row->state != GTK_STATE_NORMAL)
4103 clist_row->state = GTK_STATE_SELECTED;
4104 if (!clist->selection)
4106 clist->selection = g_list_append (clist->selection,
4107 GINT_TO_POINTER (row));
4108 clist->selection_end = clist->selection;
4111 clist->selection_end =
4112 g_list_append (clist->selection_end, GINT_TO_POINTER (row))->next;
4114 if (!GTK_CLIST_FROZEN (clist)
4115 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
4116 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
4120 real_unselect_row (GtkCList * clist,
4125 GtkCListRow *clist_row;
4127 g_return_if_fail (clist != NULL);
4128 g_return_if_fail (GTK_IS_CLIST (clist));
4130 if (row < 0 || row > (clist->rows - 1))
4133 clist_row = (g_list_nth (clist->row_list, row))->data;
4135 if (clist_row->state == GTK_STATE_SELECTED)
4137 clist_row->state = GTK_STATE_NORMAL;
4139 if (clist->selection_end &&
4140 clist->selection_end->data == GINT_TO_POINTER (row))
4141 clist->selection_end = clist->selection_end->prev;
4143 clist->selection = g_list_remove (clist->selection,
4144 GINT_TO_POINTER (row));
4146 if (!GTK_CLIST_FROZEN (clist)
4147 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
4148 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
4153 get_selection_info (GtkCList * clist,
4161 g_return_val_if_fail (clist != NULL, 0);
4162 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
4164 /* bounds checking, return false if the user clicked
4165 * on a blank area */
4166 trow = ROW_FROM_YPIXEL (clist, y);
4167 if (trow >= clist->rows)
4173 tcol = COLUMN_FROM_XPIXEL (clist, x);
4174 if (tcol >= clist->columns)
4184 gtk_clist_get_selection_info (GtkCList *clist,
4190 g_return_val_if_fail (clist != NULL, 0);
4191 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
4192 return get_selection_info (clist, x, y, row, column);
4202 draw_xor_line (GtkCList * clist)
4206 g_return_if_fail (clist != NULL);
4208 widget = GTK_WIDGET (clist);
4210 gdk_draw_line (widget->window, clist->xor_gc,
4212 widget->style->klass->ythickness,
4214 clist->column_title_area.height + clist->clist_window_height + 1);
4217 /* this function returns the new width of the column being resized given
4218 * the column and x position of the cursor; the x cursor position is passed
4219 * in as a pointer and automagicly corrected if it's beyond min/max limits */
4221 new_column_width (GtkCList * clist,
4230 /* first translate the x position from widget->window
4231 * to clist->clist_window */
4232 cx -= GTK_WIDGET (clist)->style->klass->xthickness;
4234 /* rx is x from the list beginning */
4235 rx = cx - clist->hoffset;
4237 /* you can't shrink a column to less than its minimum width */
4238 if (cx < (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH))
4240 *x = cx = COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH +
4241 GTK_WIDGET (clist)->style->klass->xthickness;
4242 cx -= GTK_WIDGET (clist)->style->klass->xthickness;
4243 rx = cx - clist->hoffset;
4246 if (cx > clist->clist_window_width)
4251 /* calculate new column width making sure it doesn't end up
4252 * less than the minimum width */
4253 width = (rx - COLUMN_LEFT (clist, column)) - COLUMN_INSET -
4254 ((clist->columns == (column - 1)) ? CELL_SPACING : 0);
4255 if (width < COLUMN_MIN_WIDTH)
4256 width = COLUMN_MIN_WIDTH;
4261 /* this will do more later */
4263 resize_column (GtkCList * clist,
4267 gtk_clist_set_column_width (clist, column, width);
4272 column_button_create (GtkCList * clist,
4277 button = clist->column[column].button = gtk_button_new ();
4278 gtk_widget_set_parent (button, GTK_WIDGET (clist));
4279 if (GTK_WIDGET_REALIZED (clist) && clist->title_window)
4280 gtk_widget_set_parent_window (clist->column[column].button, clist->title_window);
4282 gtk_signal_connect (GTK_OBJECT (button), "clicked",
4283 (GtkSignalFunc) column_button_clicked,
4286 gtk_widget_show (button);
4290 column_button_clicked (GtkWidget * widget,
4296 g_return_if_fail (widget != NULL);
4297 g_return_if_fail (GTK_IS_CLIST (data));
4299 clist = GTK_CLIST (data);
4301 /* find the column who's button was pressed */
4302 for (i = 0; i < clist->columns; i++)
4303 if (clist->column[i].button == widget)
4306 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i);
4315 * vadjustment_changed
4316 * hadjustment_changed
4317 * vadjustment_value_changed
4318 * hadjustment_value_changed
4321 create_scrollbars (GtkCList * clist)
4323 GtkAdjustment *adjustment;
4325 clist->vscrollbar = gtk_vscrollbar_new (NULL);
4327 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
4329 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
4330 (GtkSignalFunc) vadjustment_changed,
4333 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
4334 (GtkSignalFunc) vadjustment_value_changed,
4337 gtk_widget_set_parent (clist->vscrollbar, GTK_WIDGET (clist));
4338 gtk_widget_show (clist->vscrollbar);
4340 clist->hscrollbar = gtk_hscrollbar_new (NULL);
4342 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
4344 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
4345 (GtkSignalFunc) hadjustment_changed,
4348 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
4349 (GtkSignalFunc) hadjustment_value_changed,
4352 gtk_widget_set_parent (clist->hscrollbar, GTK_WIDGET (clist));
4353 gtk_widget_show (clist->hscrollbar);
4357 adjust_scrollbars (GtkCList * clist)
4359 GTK_RANGE (clist->vscrollbar)->adjustment->page_size = clist->clist_window_height;
4360 GTK_RANGE (clist->vscrollbar)->adjustment->page_increment = clist->clist_window_height / 2;
4361 GTK_RANGE (clist->vscrollbar)->adjustment->step_increment = 10;
4362 GTK_RANGE (clist->vscrollbar)->adjustment->lower = 0;
4363 GTK_RANGE (clist->vscrollbar)->adjustment->upper = LIST_HEIGHT (clist);
4365 if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist))
4367 GTK_RANGE (clist->vscrollbar)->adjustment->value = MAX (0, LIST_HEIGHT (clist) -
4368 clist->clist_window_height);
4369 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment),
4373 GTK_RANGE (clist->hscrollbar)->adjustment->page_size = clist->clist_window_width;
4374 GTK_RANGE (clist->hscrollbar)->adjustment->page_increment = clist->clist_window_width / 2;
4375 GTK_RANGE (clist->hscrollbar)->adjustment->step_increment = 10;
4376 GTK_RANGE (clist->hscrollbar)->adjustment->lower = 0;
4377 GTK_RANGE (clist->hscrollbar)->adjustment->upper = LIST_WIDTH (clist);
4379 if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist))
4381 GTK_RANGE (clist->hscrollbar)->adjustment->value = MAX (0, LIST_WIDTH (clist) -
4382 clist->clist_window_width);
4383 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment),
4387 if (LIST_HEIGHT (clist) <= clist->clist_window_height &&
4388 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
4390 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
4392 gtk_widget_hide (clist->vscrollbar);
4393 gtk_widget_queue_resize (GTK_WIDGET (clist));
4398 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
4400 gtk_widget_show (clist->vscrollbar);
4401 gtk_widget_queue_resize (GTK_WIDGET (clist));
4405 if (LIST_WIDTH (clist) <= clist->clist_window_width &&
4406 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
4408 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
4410 gtk_widget_hide (clist->hscrollbar);
4411 gtk_widget_queue_resize (GTK_WIDGET (clist));
4416 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
4418 gtk_widget_show (clist->hscrollbar);
4419 gtk_widget_queue_resize (GTK_WIDGET (clist));
4423 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
4424 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), "changed");
4428 vadjustment_changed (GtkAdjustment * adjustment,
4433 g_return_if_fail (adjustment != NULL);
4434 g_return_if_fail (data != NULL);
4436 clist = GTK_CLIST (data);
4440 hadjustment_changed (GtkAdjustment * adjustment,
4445 g_return_if_fail (adjustment != NULL);
4446 g_return_if_fail (data != NULL);
4448 clist = GTK_CLIST (data);
4452 check_exposures (GtkCList *clist)
4456 if (!GTK_WIDGET_REALIZED (clist))
4459 /* Make sure graphics expose events are processed before scrolling
4461 while ((event = gdk_event_get_graphics_expose (clist->clist_window)) != NULL)
4463 gtk_widget_event (GTK_WIDGET (clist), event);
4464 if (event->expose.count == 0)
4466 gdk_event_free (event);
4469 gdk_event_free (event);
4474 vadjustment_value_changed (GtkAdjustment * adjustment,
4481 g_return_if_fail (adjustment != NULL);
4482 g_return_if_fail (data != NULL);
4483 g_return_if_fail (GTK_IS_CLIST (data));
4485 clist = GTK_CLIST (data);
4487 if (!GTK_WIDGET_DRAWABLE (clist))
4490 value = adjustment->value;
4492 if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)))
4494 if (value > -clist->voffset)
4497 diff = value + clist->voffset;
4499 /* we have to re-draw the whole screen here... */
4500 if (diff >= clist->clist_window_height)
4502 clist->voffset = -value;
4503 draw_rows (clist, NULL);
4507 if ((diff != 0) && (diff != clist->clist_window_height))
4508 gdk_window_copy_area (clist->clist_window,
4511 clist->clist_window,
4514 clist->clist_window_width,
4515 clist->clist_window_height - diff);
4518 area.y = clist->clist_window_height - diff;
4519 area.width = clist->clist_window_width;
4525 diff = -clist->voffset - value;
4527 /* we have to re-draw the whole screen here... */
4528 if (diff >= clist->clist_window_height)
4530 clist->voffset = -value;
4531 draw_rows (clist, NULL);
4535 if ((diff != 0) && (diff != clist->clist_window_height))
4536 gdk_window_copy_area (clist->clist_window,
4539 clist->clist_window,
4542 clist->clist_window_width,
4543 clist->clist_window_height - diff);
4547 area.width = clist->clist_window_width;
4552 clist->voffset = -value;
4553 if ((diff != 0) && (diff != clist->clist_window_height))
4554 check_exposures (clist);
4557 draw_rows (clist, &area);
4561 hadjustment_value_changed (GtkAdjustment * adjustment,
4571 g_return_if_fail (adjustment != NULL);
4572 g_return_if_fail (data != NULL);
4573 g_return_if_fail (GTK_IS_CLIST (data));
4575 clist = GTK_CLIST (data);
4577 if (!GTK_WIDGET_DRAWABLE (clist) ||
4578 adjustment != gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)))
4581 value = adjustment->value;
4583 /* move the column buttons and resize windows */
4584 for (i = 0; i < clist->columns; i++)
4586 if (clist->column[i].button)
4588 clist->column[i].button->allocation.x -= value + clist->hoffset;
4590 if (clist->column[i].button->window)
4592 gdk_window_move (clist->column[i].button->window,
4593 clist->column[i].button->allocation.x,
4594 clist->column[i].button->allocation.y);
4596 if (clist->column[i].window)
4597 gdk_window_move (clist->column[i].window,
4598 clist->column[i].button->allocation.x +
4599 clist->column[i].button->allocation.width -
4600 (DRAG_WIDTH / 2), 0);
4605 if (value > -clist->hoffset)
4608 diff = value + clist->hoffset;
4610 clist->hoffset = -value;
4612 /* we have to re-draw the whole screen here... */
4613 if (diff >= clist->clist_window_width)
4615 draw_rows (clist, NULL);
4619 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
4620 GTK_CLIST_ADD_MODE (clist))
4622 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4624 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
4625 clist->clist_window_width - 1,
4626 clist->row_height - 1);
4628 gdk_window_copy_area (clist->clist_window,
4631 clist->clist_window,
4634 clist->clist_window_width - diff,
4635 clist->clist_window_height);
4637 area.x = clist->clist_window_width - diff;
4642 if (!(diff = -clist->hoffset - value))
4645 clist->hoffset = -value;
4647 /* we have to re-draw the whole screen here... */
4648 if (diff >= clist->clist_window_width)
4650 draw_rows (clist, NULL);
4654 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
4655 GTK_CLIST_ADD_MODE (clist))
4657 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4659 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
4660 clist->clist_window_width - 1,
4661 clist->row_height - 1);
4664 gdk_window_copy_area (clist->clist_window,
4667 clist->clist_window,
4670 clist->clist_window_width - diff,
4671 clist->clist_window_height);
4678 area.height = clist->clist_window_height;
4680 check_exposures (clist);
4682 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist))
4684 if (GTK_CLIST_ADD_MODE (clist))
4688 focus_row = clist->focus_row;
4689 clist->focus_row = -1;
4690 draw_rows (clist, &area);
4691 clist->focus_row = focus_row;
4693 gdk_draw_rectangle (clist->clist_window, clist->xor_gc,
4694 FALSE, 0, y, clist->clist_window_width - 1,
4695 clist->row_height - 1);
4705 x0 = clist->clist_window_width - 1;
4714 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
4715 gdk_draw_line (clist->clist_window, clist->xor_gc,
4716 x0, y + 1, x0, y + clist->row_height - 2);
4717 gdk_draw_line (clist->clist_window, clist->xor_gc,
4718 x1, y + 1, x1, y + clist->row_height - 2);
4722 draw_rows (clist, &area);
4726 * Memory Allocation/Distruction Routines for GtkCList stuctures
4738 static GtkCListColumn *
4739 columns_new (GtkCList * clist)
4742 GtkCListColumn *column;
4744 column = g_new (GtkCListColumn, clist->columns);
4746 for (i = 0; i < clist->columns; i++)
4748 column[i].area.x = 0;
4749 column[i].area.y = 0;
4750 column[i].area.width = 0;
4751 column[i].area.height = 0;
4752 column[i].title = NULL;
4753 column[i].button = NULL;
4754 column[i].window = NULL;
4755 column[i].width = 0;
4756 column[i].width_set = FALSE;
4757 column[i].justification = GTK_JUSTIFY_LEFT;
4764 column_title_new (GtkCList * clist,
4768 if (clist->column[column].title)
4769 g_free (clist->column[column].title);
4771 clist->column[column].title = g_strdup (title);
4775 columns_delete (GtkCList * clist)
4779 for (i = 0; i < clist->columns; i++)
4780 if (clist->column[i].title)
4781 g_free (clist->column[i].title);
4783 g_free (clist->column);
4786 static GtkCListRow *
4787 row_new (GtkCList * clist)
4790 GtkCListRow *clist_row;
4792 clist_row = g_chunk_new (GtkCListRow, clist->row_mem_chunk);
4793 clist_row->cell = g_chunk_new (GtkCell, clist->cell_mem_chunk);
4795 for (i = 0; i < clist->columns; i++)
4797 clist_row->cell[i].type = GTK_CELL_EMPTY;
4798 clist_row->cell[i].vertical = 0;
4799 clist_row->cell[i].horizontal = 0;
4802 clist_row->fg_set = FALSE;
4803 clist_row->bg_set = FALSE;
4804 clist_row->state = GTK_STATE_NORMAL;
4805 clist_row->data = NULL;
4806 clist_row->destroy = NULL;
4812 row_delete (GtkCList * clist,
4813 GtkCListRow * clist_row)
4817 for (i = 0; i < clist->columns; i++)
4818 cell_empty (clist, clist_row, i);
4820 if (clist_row->destroy)
4821 clist_row->destroy (clist_row->data);
4823 g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell);
4824 g_mem_chunk_free (clist->row_mem_chunk, clist_row);
4828 cell_empty (GtkCList * clist,
4829 GtkCListRow * clist_row,
4832 switch (clist_row->cell[column].type)
4834 case GTK_CELL_EMPTY:
4838 g_free (GTK_CELL_TEXT (clist_row->cell[column])->text);
4841 case GTK_CELL_PIXMAP:
4842 gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap);
4843 if (GTK_CELL_PIXMAP (clist_row->cell[column])->mask)
4844 gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask);
4847 case GTK_CELL_PIXTEXT:
4848 g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text);
4849 gdk_pixmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap);
4850 if (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask)
4851 gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask);
4854 case GTK_CELL_WIDGET:
4862 clist_row->cell[column].type = GTK_CELL_EMPTY;
4866 cell_set_text (GtkCList * clist,
4867 GtkCListRow * clist_row,
4871 cell_empty (clist, clist_row, column);
4875 clist_row->cell[column].type = GTK_CELL_TEXT;
4876 GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
4881 cell_set_pixmap (GtkCList * clist,
4882 GtkCListRow * clist_row,
4887 cell_empty (clist, clist_row, column);
4891 clist_row->cell[column].type = GTK_CELL_PIXMAP;
4892 GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
4893 /* We set the mask even if it is NULL */
4894 GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask;
4899 cell_set_pixtext (GtkCList * clist,
4900 GtkCListRow * clist_row,
4907 cell_empty (clist, clist_row, column);
4911 clist_row->cell[column].type = GTK_CELL_PIXTEXT;
4912 GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
4913 GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
4914 GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
4915 GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask;
4919 /* Fill in data after widget has correct style */
4922 add_style_data (GtkCList * clist)
4926 widget = GTK_WIDGET(clist);
4928 /* text properties */
4929 if (!GTK_CLIST_ROW_HEIGHT_SET (clist))
4931 clist->row_height = widget->style->font->ascent + widget->style->font->descent + 1;
4932 clist->row_center_offset = widget->style->font->ascent + 1.5;
4937 text_height = clist->row_height - (GTK_WIDGET (clist)->style->font->ascent +
4938 GTK_WIDGET (clist) ->style->font->descent + 1);
4939 clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
4946 /* focus functions */
4949 gtk_clist_draw_focus (GtkWidget *widget)
4953 g_return_if_fail (widget != NULL);
4954 g_return_if_fail (GTK_IS_CLIST (widget));
4956 if (!GTK_WIDGET_DRAWABLE (widget))
4959 clist = GTK_CLIST (widget);
4960 if (clist->focus_row >= 0)
4961 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
4962 0, ROW_TOP_YPIXEL(clist, clist->focus_row),
4963 clist->clist_window_width - 1,
4964 clist->row_height - 1);
4968 gtk_clist_set_focus_child (GtkContainer *container,
4971 g_return_if_fail (container != NULL);
4972 g_return_if_fail (GTK_IS_CLIST (container));
4976 g_return_if_fail (GTK_IS_WIDGET (child));
4977 GTK_CLIST_SET_FLAG (GTK_CLIST (container), CLIST_CHILD_HAS_FOCUS);
4980 parent_class->set_focus_child (container, child);
4984 gtk_clist_focus_in (GtkWidget *widget,
4985 GdkEventFocus *event)
4989 g_return_val_if_fail (widget != NULL, FALSE);
4990 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4991 g_return_val_if_fail (event != NULL, FALSE);
4993 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
4994 GTK_CLIST_UNSET_FLAG (widget, CLIST_CHILD_HAS_FOCUS);
4996 clist = GTK_CLIST (widget);
4998 if (clist->selection_mode == GTK_SELECTION_BROWSE &&
4999 clist->selection == NULL && clist->focus_row > -1)
5000 select_row (clist, clist->focus_row, -1, (GdkEvent *) event);
5002 gtk_widget_draw_focus (widget);
5008 gtk_clist_focus_out (GtkWidget *widget,
5009 GdkEventFocus *event)
5013 g_return_val_if_fail (widget != NULL, FALSE);
5014 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
5015 g_return_val_if_fail (event != NULL, FALSE);
5017 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
5018 gtk_widget_draw_focus (widget);
5020 clist = GTK_CLIST (widget);
5022 if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
5023 GTK_CLIST_CLASS_FW (widget)->resync_selection (clist, (GdkEvent *) event);
5029 toggle_add_mode (GtkCList *clist)
5031 g_return_if_fail (clist != 0);
5032 g_return_if_fail (GTK_IS_CLIST (clist));
5034 if (gdk_pointer_is_grabbed () ||
5035 clist->selection_mode != GTK_SELECTION_EXTENDED)
5038 gtk_clist_draw_focus (GTK_WIDGET (clist));
5039 if (!GTK_CLIST_ADD_MODE (clist))
5041 GTK_CLIST_SET_FLAG (clist, CLIST_ADD_MODE);
5042 gdk_gc_set_line_attributes (clist->xor_gc, 1,
5043 GDK_LINE_ON_OFF_DASH, 0, 0);
5044 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
5048 GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
5049 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
5050 clist->anchor_state = GTK_STATE_SELECTED;
5052 gtk_clist_draw_focus (GTK_WIDGET (clist));
5056 toggle_focus_row (GtkCList *clist)
5058 g_return_if_fail (clist != 0);
5059 g_return_if_fail (GTK_IS_CLIST (clist));
5061 if (gdk_pointer_is_grabbed ())
5064 switch (clist->selection_mode)
5066 case GTK_SELECTION_SINGLE:
5067 case GTK_SELECTION_MULTIPLE:
5069 toggle_row (clist, clist->focus_row, 0, NULL);
5072 case GTK_SELECTION_EXTENDED:
5073 g_list_free (clist->undo_selection);
5074 g_list_free (clist->undo_unselection);
5075 clist->undo_selection = NULL;
5076 clist->undo_unselection = NULL;
5078 if (GTK_CLIST_ADD_MODE (clist))
5080 clist->anchor = clist->focus_row;
5081 clist->drag_pos = clist->focus_row;
5082 clist->undo_anchor = clist->focus_row;
5083 fake_toggle_row (clist, clist->focus_row);
5084 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
5088 clist->anchor = clist->focus_row;
5089 clist->drag_pos = clist->focus_row;
5090 clist->undo_anchor = clist->focus_row;
5091 GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist,
5093 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
5103 move_focus_row (GtkCList *clist,
5104 GtkScrollType scroll_type,
5109 g_return_if_fail (clist != 0);
5110 g_return_if_fail (GTK_IS_CLIST (clist));
5112 widget = GTK_WIDGET (clist);
5114 switch (scroll_type)
5116 case GTK_SCROLL_STEP_BACKWARD:
5117 if (clist->focus_row <= 0)
5119 gtk_clist_draw_focus (widget);
5121 gtk_clist_draw_focus (widget);
5123 case GTK_SCROLL_STEP_FORWARD:
5124 if (clist->focus_row >= clist->rows - 1)
5126 gtk_clist_draw_focus (widget);
5128 gtk_clist_draw_focus (widget);
5130 case GTK_SCROLL_PAGE_BACKWARD:
5131 if (clist->focus_row <= 0)
5133 gtk_clist_draw_focus (widget);
5134 clist->focus_row = MAX (0, clist->focus_row -
5135 (2 * clist->clist_window_height -
5136 clist->row_height - CELL_SPACING) /
5137 (2 * (clist->row_height + CELL_SPACING)));
5138 gtk_clist_draw_focus (widget);
5140 case GTK_SCROLL_PAGE_FORWARD:
5141 if (clist->focus_row >= clist->rows - 1)
5143 gtk_clist_draw_focus (widget);
5144 clist->focus_row = MIN (clist->rows - 1, clist->focus_row +
5145 (2 * clist->clist_window_height -
5146 clist->row_height - CELL_SPACING) /
5147 (2 * (clist->row_height + CELL_SPACING)));
5148 gtk_clist_draw_focus (widget);
5150 case GTK_SCROLL_JUMP:
5151 if (position >= 0 && position <= 1)
5153 gtk_clist_draw_focus (widget);
5154 clist->focus_row = position * (clist->rows - 1);
5155 gtk_clist_draw_focus (widget);
5164 scroll_horizontal (GtkCList *clist,
5165 GtkScrollType scroll_type,
5170 g_return_if_fail (clist != 0);
5171 g_return_if_fail (GTK_IS_CLIST (clist));
5173 if (gdk_pointer_is_grabbed ())
5176 switch (scroll_type)
5178 case GTK_SCROLL_STEP_BACKWARD:
5179 column = COLUMN_FROM_XPIXEL (clist, 0);
5180 if (COLUMN_LEFT_XPIXEL (clist, column) - CELL_SPACING - COLUMN_INSET >= 0
5184 case GTK_SCROLL_STEP_FORWARD:
5185 column = COLUMN_FROM_XPIXEL (clist, clist->clist_window_width);
5188 if (COLUMN_LEFT_XPIXEL (clist, column) + clist->column[column].area.width
5189 + CELL_SPACING + COLUMN_INSET - 1 <= clist->clist_window_width &&
5190 column < clist->columns - 1)
5193 case GTK_SCROLL_PAGE_BACKWARD:
5194 case GTK_SCROLL_PAGE_FORWARD:
5196 case GTK_SCROLL_JUMP:
5197 if (position >= 0 && position <= 1)
5198 column = position * (clist->columns - 1);
5206 if (COLUMN_LEFT_XPIXEL (clist, column) < CELL_SPACING + COLUMN_INSET)
5207 gtk_clist_moveto (clist, -1, column, 0, 0);
5208 else if (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET - 1
5209 + clist->column[column].area.width > clist->clist_window_width)
5211 if (column == clist->columns - 1)
5212 gtk_clist_moveto (clist, -1, column, 0, 0);
5214 gtk_clist_moveto (clist, -1, column, 0, 1);
5219 scroll_vertical (GtkCList *clist,
5220 GtkScrollType scroll_type,
5225 g_return_if_fail (clist != NULL);
5226 g_return_if_fail (GTK_IS_CLIST (clist));
5228 if (gdk_pointer_is_grabbed ())
5231 switch (clist->selection_mode)
5233 case GTK_SELECTION_EXTENDED:
5234 if (clist->anchor >= 0)
5237 case GTK_SELECTION_BROWSE:
5239 old_focus_row = clist->focus_row;
5240 move_focus_row (clist, scroll_type, position);
5242 if (old_focus_row != clist->focus_row)
5244 if (clist->selection_mode == GTK_SELECTION_BROWSE)
5245 unselect_row (clist,old_focus_row, -1, NULL);
5246 else if (!GTK_CLIST_ADD_MODE (clist))
5248 gtk_clist_unselect_all (clist);
5249 clist->undo_anchor = old_focus_row;
5253 if (clist->selection_mode == GTK_SELECTION_EXTENDED &&
5254 GTK_CLIST_ADD_MODE (clist))
5257 switch (gtk_clist_row_is_visible (clist, clist->focus_row))
5259 case GTK_VISIBILITY_NONE:
5260 if (old_focus_row != clist->focus_row)
5261 select_row (clist, clist->focus_row, -1, NULL);
5262 switch (scroll_type)
5264 case GTK_SCROLL_STEP_BACKWARD:
5265 case GTK_SCROLL_PAGE_BACKWARD:
5266 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5268 case GTK_SCROLL_STEP_FORWARD:
5269 case GTK_SCROLL_PAGE_FORWARD:
5270 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5272 case GTK_SCROLL_JUMP:
5273 gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
5280 case GTK_VISIBILITY_PARTIAL:
5281 switch (scroll_type)
5283 case GTK_SCROLL_STEP_BACKWARD:
5284 case GTK_SCROLL_PAGE_BACKWARD:
5285 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5287 case GTK_SCROLL_STEP_FORWARD:
5288 case GTK_SCROLL_PAGE_FORWARD:
5289 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5291 case GTK_SCROLL_JUMP:
5292 gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
5299 if (old_focus_row != clist->focus_row)
5300 select_row (clist, clist->focus_row, -1, NULL);
5306 move_focus_row (clist, scroll_type, position);
5308 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5309 clist->clist_window_height)
5310 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5311 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5312 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5318 set_anchor (GtkCList *clist,
5323 g_return_if_fail (clist != NULL);
5324 g_return_if_fail (GTK_IS_CLIST (clist));
5326 if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor >= 0)
5329 g_list_free (clist->undo_selection);
5330 g_list_free (clist->undo_unselection);
5331 clist->undo_selection = NULL;
5332 clist->undo_unselection = NULL;
5335 fake_toggle_row (clist, anchor);
5338 GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist, anchor);
5339 clist->anchor_state = GTK_STATE_SELECTED;
5342 clist->anchor = anchor;
5343 clist->drag_pos = anchor;
5344 clist->undo_anchor = undo_anchor;
5348 resync_selection (GtkCList *clist,
5354 gboolean thaw = FALSE;
5356 GtkCListRow *clist_row;
5358 if (clist->anchor < 0)
5361 if (!GTK_CLIST_FROZEN (clist))
5363 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
5367 i = MIN (clist->anchor, clist->drag_pos);
5368 e = MAX (clist->anchor, clist->drag_pos);
5370 if (clist->undo_selection)
5373 list = clist->selection;
5374 clist->selection = clist->undo_selection;
5375 clist->selection_end = g_list_last (clist->selection);
5376 clist->undo_selection = list;
5377 list = clist->selection;
5380 row = GPOINTER_TO_INT (list->data);
5382 if (row < i || row > e)
5384 clist_row = g_list_nth (clist->row_list, row)->data;
5385 clist_row->state = GTK_STATE_SELECTED;
5386 unselect_row (clist, row, -1, event);
5387 clist->undo_selection = g_list_prepend
5388 (clist->undo_selection, GINT_TO_POINTER (row));
5393 for (list = g_list_nth (clist->row_list, i); i <= e; i++, list = list->next)
5394 if (g_list_find (clist->selection, GINT_TO_POINTER(i)))
5396 if (GTK_CLIST_ROW (list)->state == GTK_STATE_NORMAL)
5398 GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
5399 unselect_row (clist, i, -1, event);
5400 clist->undo_selection = g_list_prepend (clist->undo_selection,
5401 GINT_TO_POINTER (i));
5404 else if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
5406 GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
5407 clist->undo_unselection = g_list_prepend (clist->undo_unselection,
5408 GINT_TO_POINTER (i));
5411 for (list = clist->undo_unselection; list; list = list->next)
5412 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
5413 GPOINTER_TO_INT (list->data), -1, event);
5416 clist->drag_pos = -1;
5419 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
5423 update_extended_selection (GtkCList *clist,
5433 gint y1 = clist->clist_window_height;
5434 gint y2 = clist->clist_window_height;
5439 if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor == -1)
5444 if (row >= clist->rows)
5445 row = clist->rows - 1;
5447 /* extending downwards */
5448 if (row > clist->drag_pos && clist->anchor <= clist->drag_pos)
5450 s2 = clist->drag_pos + 1;
5453 /* extending upwards */
5454 else if (row < clist->drag_pos && clist->anchor >= clist->drag_pos)
5457 e2 = clist->drag_pos - 1;
5459 else if (row < clist->drag_pos && clist->anchor < clist->drag_pos)
5461 e1 = clist->drag_pos;
5462 /* row and drag_pos on different sides of anchor :
5463 take back the selection between anchor and drag_pos,
5464 select between anchor and row */
5465 if (row < clist->anchor)
5467 s1 = clist->anchor + 1;
5469 e2 = clist->anchor - 1;
5471 /* take back the selection between anchor and drag_pos */
5475 else if (row > clist->drag_pos && clist->anchor > clist->drag_pos)
5477 s1 = clist->drag_pos;
5478 /* row and drag_pos on different sides of anchor :
5479 take back the selection between anchor and drag_pos,
5480 select between anchor and row */
5481 if (row > clist->anchor)
5483 e1 = clist->anchor - 1;
5484 s2 = clist->anchor + 1;
5487 /* take back the selection between anchor and drag_pos */
5492 clist->drag_pos = row;
5495 area.width = clist->clist_window_width;
5497 /* restore the elements between s1 and e1 */
5500 for (i = s1, list = g_list_nth (clist->row_list, i); i <= e1;
5501 i++, list = list->next)
5503 if (GTK_CLIST_CLASS_FW (clist)->selection_find (clist, i, list))
5504 GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
5506 GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
5509 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
5511 if (top + clist->row_height <= 0)
5514 area.height = ROW_TOP_YPIXEL (clist, e1) + clist->row_height;
5515 draw_rows (clist, &area);
5516 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5518 else if (top >= clist->clist_window_height)
5520 area.y = ROW_TOP_YPIXEL (clist, s1);
5521 area.height = clist->clist_window_height - area.y;
5522 draw_rows (clist, &area);
5523 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5526 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5527 else if (top + clist->row_height > clist->clist_window_height)
5528 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5530 y1 = ROW_TOP_YPIXEL (clist, s1);
5531 h1 = (e1 - s1 + 1) * (clist->row_height + CELL_SPACING);
5534 /* extend the selection between s2 and e2 */
5537 for (i = s2, list = g_list_nth (clist->row_list, i); i <= e2;
5538 i++, list = list->next)
5539 if (GTK_CLIST_ROW (list)->state != clist->anchor_state)
5540 GTK_CLIST_ROW (list)->state = clist->anchor_state;
5542 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
5544 if (top + clist->row_height <= 0)
5547 area.height = ROW_TOP_YPIXEL (clist, e2) + clist->row_height;
5548 draw_rows (clist, &area);
5549 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5551 else if (top >= clist->clist_window_height)
5553 area.y = ROW_TOP_YPIXEL (clist, s2);
5554 area.height = clist->clist_window_height - area.y;
5555 draw_rows (clist, &area);
5556 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5559 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5560 else if (top + clist->row_height > clist->clist_window_height)
5561 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5563 y2 = ROW_TOP_YPIXEL (clist, s2);
5564 h2 = (e2-s2+1) * (clist->row_height + CELL_SPACING);
5567 area.y = MAX (0, MIN (y1, y2));
5568 if (area.y > clist->clist_window_height)
5570 area.height = MIN (clist->clist_window_height, h1 + h2);
5571 if (s1 >= 0 && s2 >= 0)
5572 area.height += (clist->row_height + CELL_SPACING);
5573 draw_rows (clist, &area);
5577 start_selection (GtkCList *clist)
5579 g_return_if_fail (clist != NULL);
5580 g_return_if_fail (GTK_IS_CLIST (clist));
5582 if (gdk_pointer_is_grabbed ())
5585 set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
5590 end_selection (GtkCList *clist)
5592 g_return_if_fail (clist != NULL);
5593 g_return_if_fail (GTK_IS_CLIST (clist));
5595 if (gdk_pointer_is_grabbed () || clist->anchor == -1)
5598 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
5602 extend_selection (GtkCList *clist,
5603 GtkScrollType scroll_type,
5605 gboolean auto_start_selection)
5607 g_return_if_fail (clist != NULL);
5608 g_return_if_fail (GTK_IS_CLIST (clist));
5610 if (gdk_pointer_is_grabbed () ||
5611 clist->selection_mode != GTK_SELECTION_EXTENDED)
5614 if (auto_start_selection)
5615 set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
5617 else if (clist->anchor == -1)
5620 move_focus_row (clist, scroll_type, position);
5622 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5623 clist->clist_window_height)
5624 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5625 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5626 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5628 update_extended_selection (clist, clist->focus_row);
5632 abort_column_resize (GtkCList *clist)
5634 g_return_if_fail (clist != NULL);
5635 g_return_if_fail (GTK_IS_CLIST (clist));
5637 if (!GTK_CLIST_IN_DRAG (clist))
5640 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
5641 gdk_pointer_ungrab (gdk_time_get());
5643 if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1)
5644 draw_xor_line (clist);
5646 if (GTK_CLIST_ADD_MODE (clist))
5648 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_ON_OFF_DASH, 0,0);
5649 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
5654 gtk_clist_key_press (GtkWidget * widget,
5655 GdkEventKey * event)
5658 gboolean handled = FALSE;
5660 g_return_val_if_fail (widget != NULL, FALSE);
5661 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
5662 g_return_val_if_fail (event != NULL, FALSE);
5664 clist = GTK_CLIST (widget);
5667 if (event->keyval == GDK_Escape && GTK_CLIST_IN_DRAG (clist))
5669 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
5670 gdk_pointer_ungrab (event->time);
5672 if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1)
5673 draw_xor_line (clist);
5675 if (GTK_CLIST_ADD_MODE (clist))
5677 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_ON_OFF_DASH,
5679 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
5684 if (GTK_WIDGET_CLASS (parent_class)->key_press_event)
5685 handled = GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
5690 switch (event->keyval)
5693 case GDK_ISO_Left_Tab:
5694 if (event->state & GDK_SHIFT_MASK)
5695 return gtk_container_focus (GTK_CONTAINER (widget),
5696 GTK_DIR_TAB_BACKWARD);
5698 return gtk_container_focus (GTK_CONTAINER (widget),
5699 GTK_DIR_TAB_FORWARD);
5709 title_focus (GtkCList * clist,
5712 GtkWidget *focus_child;
5713 gboolean return_val = FALSE;
5718 if (!GTK_CLIST_SHOW_TITLES (clist))
5721 focus_child = GTK_CONTAINER (clist)->focus_child;
5725 case GTK_DIR_TAB_BACKWARD:
5727 if (!focus_child || focus_child == clist->hscrollbar ||
5728 focus_child == clist->hscrollbar ||
5729 !GTK_CLIST_CHILD_HAS_FOCUS (clist))
5731 if (dir == GTK_DIR_UP)
5732 i = COLUMN_FROM_XPIXEL (clist, 0);
5734 i = clist->columns - 1;
5735 focus_child = clist->column[i].button;
5736 dir = GTK_DIR_TAB_FORWARD;
5743 if (!focus_child || focus_child == clist->hscrollbar ||
5744 focus_child == clist->hscrollbar)
5746 i = clist->columns - 1;
5747 focus_child = clist->column[i].button;
5751 if (!focus_child || focus_child == clist->hscrollbar ||
5752 focus_child == clist->hscrollbar)
5755 focus_child = clist->column[i].button;
5761 while (i < clist->columns)
5763 if (clist->column[i].button == focus_child)
5765 if (clist->column[i].button &&
5766 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
5767 GTK_IS_CONTAINER (clist->column[i].button) &&
5768 !GTK_WIDGET_HAS_FOCUS (clist->column[i].button))
5769 if (gtk_container_focus
5770 (GTK_CONTAINER (clist->column[i].button), dir))
5775 if (!return_val && dir == GTK_DIR_UP)
5786 while (j >= 0 && j < clist->columns)
5788 if (clist->column[j].button &&
5789 GTK_WIDGET_VISIBLE (clist->column[j].button))
5791 if (GTK_IS_CONTAINER (clist->column[j].button) &&
5793 (GTK_CONTAINER (clist->column[j].button), dir))
5798 else if (GTK_WIDGET_CAN_FOCUS (clist->column[j].button))
5800 gtk_widget_grab_focus (clist->column[j].button);
5810 if (COLUMN_LEFT_XPIXEL (clist, j) < CELL_SPACING + COLUMN_INSET)
5811 gtk_clist_moveto (clist, -1, j, 0, 0);
5812 else if (COLUMN_LEFT_XPIXEL(clist, j) + clist->column[j].area.width >
5813 clist->clist_window_width)
5815 if (j == clist->columns-1)
5816 gtk_clist_moveto (clist, -1, j, 0, 0);
5818 gtk_clist_moveto (clist, -1, j, 0, 1);
5825 gtk_clist_focus (GtkContainer * container,
5826 GtkDirectionType direction)
5829 GtkWidget *focus_child;
5832 g_return_val_if_fail (container != NULL, FALSE);
5833 g_return_val_if_fail (GTK_IS_CLIST (container), FALSE);
5835 if (!GTK_WIDGET_SENSITIVE (container))
5838 clist = GTK_CLIST (container);
5839 focus_child = container->focus_child;
5840 old_row = clist->focus_row;
5846 if (GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5847 (!focus_child || (focus_child && focus_child != clist->vscrollbar &&
5848 focus_child != clist->hscrollbar)))
5850 if (title_focus (clist, direction))
5852 gtk_container_set_focus_child (container, NULL);
5855 gtk_widget_grab_focus (GTK_WIDGET (container));
5858 case GTK_DIR_TAB_FORWARD:
5859 if (GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5860 (!focus_child || (focus_child != clist->vscrollbar &&
5861 focus_child != clist->hscrollbar)))
5863 gboolean tf = FALSE;
5865 if (((focus_child && direction == GTK_DIR_DOWN) ||
5866 !(tf = title_focus (clist, GTK_DIR_TAB_FORWARD)))
5869 if (clist->focus_row < 0)
5871 clist->focus_row = 0;
5873 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
5874 clist->selection_mode == GTK_SELECTION_EXTENDED) &&
5876 select_row (clist, clist->focus_row, -1, NULL);
5878 gtk_widget_grab_focus (GTK_WIDGET (container));
5886 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
5888 if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child ||
5889 (focus_child != clist->vscrollbar &&
5890 focus_child != clist->hscrollbar)) &&
5891 GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
5892 GTK_WIDGET_CAN_FOCUS (clist->vscrollbar))
5894 gtk_widget_grab_focus (clist->vscrollbar);
5898 if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child ||
5899 focus_child != clist->hscrollbar) &&
5900 GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
5901 GTK_WIDGET_CAN_FOCUS (clist->hscrollbar))
5903 gtk_widget_grab_focus (clist->hscrollbar);
5908 case GTK_DIR_TAB_BACKWARD:
5909 if (!focus_child && GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5910 GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
5911 GTK_WIDGET_CAN_FOCUS (clist->hscrollbar))
5913 gtk_widget_grab_focus (clist->hscrollbar);
5917 if ((!focus_child || focus_child == clist->hscrollbar) &&
5918 GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5919 GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
5920 GTK_WIDGET_CAN_FOCUS (clist->vscrollbar))
5922 gtk_widget_grab_focus (clist->vscrollbar);
5926 if ((!focus_child || focus_child == clist->hscrollbar ||
5927 focus_child == clist->vscrollbar) &&
5928 GTK_CLIST_CHILD_HAS_FOCUS (clist) && clist->rows)
5930 if (clist->focus_row < 0)
5932 clist->focus_row = 0;
5933 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
5934 clist->selection_mode == GTK_SELECTION_EXTENDED) &&
5936 select_row (clist, clist->focus_row, -1, NULL);
5938 gtk_widget_grab_focus (GTK_WIDGET (container));
5942 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
5944 if (title_focus (clist, direction))
5953 gtk_container_set_focus_child (container, NULL);
5958 gtk_clist_unselect_all (GtkCList * clist)
5960 GTK_CLIST_CLASS_FW (clist)->unselect_all (clist);
5964 real_unselect_all (GtkCList * clist)
5969 g_return_if_fail (clist != NULL);
5970 g_return_if_fail (GTK_IS_CLIST (clist));
5972 if (gdk_pointer_is_grabbed ())
5975 switch (clist->selection_mode)
5977 case GTK_SELECTION_BROWSE:
5978 if (clist->focus_row >= 0)
5980 select_row (clist, clist->focus_row, -1, NULL);
5985 case GTK_SELECTION_EXTENDED:
5986 g_list_free (clist->undo_selection);
5987 g_list_free (clist->undo_unselection);
5988 clist->undo_selection = NULL;
5989 clist->undo_unselection = NULL;
5992 clist->drag_pos = -1;
5993 clist->undo_anchor = clist->focus_row;
6000 list = clist->selection;
6004 i = GPOINTER_TO_INT (list->data);
6006 unselect_row (clist, i, -1, NULL);
6011 gtk_clist_select_all (GtkCList * clist)
6013 GTK_CLIST_CLASS_FW (clist)->select_all (clist);
6017 real_select_all (GtkCList * clist)
6022 g_return_if_fail (clist != NULL);
6023 g_return_if_fail (GTK_IS_CLIST (clist));
6025 if (gdk_pointer_is_grabbed ())
6028 switch (clist->selection_mode)
6030 case GTK_SELECTION_SINGLE:
6031 case GTK_SELECTION_BROWSE:
6034 case GTK_SELECTION_EXTENDED:
6035 g_list_free (clist->undo_selection);
6036 g_list_free (clist->undo_unselection);
6037 clist->undo_selection = NULL;
6038 clist->undo_unselection = NULL;
6041 ((GtkCListRow *) (clist->row_list->data))->state !=
6043 fake_toggle_row (clist, 0);
6045 clist->anchor_state = GTK_STATE_SELECTED;
6047 clist->drag_pos = 0;
6048 clist->undo_anchor = clist->focus_row;
6049 update_extended_selection (clist, clist->rows);
6050 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
6053 case GTK_SELECTION_MULTIPLE:
6054 for (i = 0, list = clist->row_list; list; i++, list = list->next)
6056 if (((GtkCListRow *)(list->data))->state == GTK_STATE_NORMAL)
6057 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
6065 fake_unselect_all (GtkCList * clist,
6072 if (row >= 0 && (work = g_list_nth (clist->row_list, row)))
6074 if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL)
6076 GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
6078 if (!GTK_CLIST_FROZEN (clist) &&
6079 gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
6080 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
6081 GTK_CLIST_ROW (work));
6085 clist->undo_selection = clist->selection;
6086 clist->selection = NULL;
6087 clist->selection_end = NULL;
6089 for (list = clist->undo_selection; list; list = list->next)
6091 if ((i = GPOINTER_TO_INT (list->data)) == row ||
6092 !(work = g_list_nth (clist->row_list, i)))
6095 GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
6096 if (!GTK_CLIST_FROZEN (clist) &&
6097 gtk_clist_row_is_visible (clist, i) != GTK_VISIBILITY_NONE)
6098 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, i,
6099 GTK_CLIST_ROW (work));
6104 fake_toggle_row (GtkCList *clist,
6109 if (!(work = g_list_nth (clist->row_list, row)))
6112 if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL)
6113 clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
6115 clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
6117 if (!GTK_CLIST_FROZEN (clist) &&
6118 gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
6119 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
6120 GTK_CLIST_ROW (work));
6124 selection_find (GtkCList *clist,
6126 GList *row_list_element)
6128 return g_list_find (clist->selection, GINT_TO_POINTER (row_number));