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 Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include "../config.h"
23 /* the number rows memchunk expands at a time */
24 #define CLIST_OPTIMUM_SIZE 512
26 /* the width of the column resize windows */
29 /* minimum allowed width of a column */
30 #define COLUMN_MIN_WIDTH 5
32 /* this defigns the base grid spacing */
33 #define CELL_SPACING 1
35 /* added the horizontal space at the beginning and end of a row*/
36 #define COLUMN_INSET 3
38 /* scrollbar spacing class macro */
39 #define SCROLLBAR_SPACING(w) (GTK_CLIST_CLASS (GTK_OBJECT (w)->klass)->scrollbar_spacing)
41 /* gives the top pixel of the given row in context of
42 * the clist's voffset */
43 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
44 (((row) + 1) * CELL_SPACING) + \
47 /* returns the row index from a y pixel location in the
48 * context of the clist's voffset */
49 #define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \
50 ((clist)->row_height + CELL_SPACING))
52 /* gives the left pixel of the given column in context of
53 * the clist's hoffset */
54 #define COLUMN_LEFT_XPIXEL(clist, column) ((clist)->column[(column)].area.x + \
57 /* returns the column index from a x pixel location in the
58 * context of the clist's hoffset */
60 COLUMN_FROM_XPIXEL (GtkCList * clist,
65 for (i = 0; i < clist->columns; i++)
67 cx = clist->column[i].area.x + clist->hoffset;
69 if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
70 x <= (cx + clist->column[i].area.width + COLUMN_INSET))
78 /* returns the top pixel of the given row in the context of
80 #define ROW_TOP(clist, row) (((clist)->row_height + CELL_SPACING) * (row))
82 /* returns the left pixel of the given column in the context of
84 #define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x)
86 /* returns the total height of the list */
87 #define LIST_HEIGHT(clist) (((clist)->row_height * ((clist)->rows)) + \
88 (CELL_SPACING * ((clist)->rows + 1)))
90 /* returns the total width of the list */
91 #define LIST_WIDTH(clist) ((clist)->column[(clist)->columns - 1].area.x + \
92 (clist)->column[(clist)->columns - 1].area.width + \
93 COLUMN_INSET + CELL_SPACING)
106 typedef void (*GtkCListSignal1) (GtkObject * object,
112 typedef void (*GtkCListSignal2) (GtkObject * object,
117 /* GtkCList Methods */
118 static void gtk_clist_class_init (GtkCListClass * klass);
119 static void gtk_clist_init (GtkCList * clist);
121 /* GtkObject Methods */
122 static void gtk_clist_destroy (GtkObject * object);
123 static void gtk_clist_finalize (GtkObject * object);
126 /* GtkWidget Methods */
127 static void gtk_clist_realize (GtkWidget * widget);
128 static void gtk_clist_unrealize (GtkWidget * widget);
129 static void gtk_clist_map (GtkWidget * widget);
130 static void gtk_clist_unmap (GtkWidget * widget);
131 static void gtk_clist_draw (GtkWidget * widget,
132 GdkRectangle * area);
133 static gint gtk_clist_expose (GtkWidget * widget,
134 GdkEventExpose * event);
135 static gint gtk_clist_button_press (GtkWidget * widget,
136 GdkEventButton * event);
137 static gint gtk_clist_button_release (GtkWidget * widget,
138 GdkEventButton * event);
139 static gint gtk_clist_motion (GtkWidget * widget,
140 GdkEventMotion * event);
142 static void gtk_clist_size_request (GtkWidget * widget,
143 GtkRequisition * requisition);
144 static void gtk_clist_size_allocate (GtkWidget * widget,
145 GtkAllocation * allocation);
147 /* GtkContainer Methods */
148 static void gtk_clist_foreach (GtkContainer * container,
149 GtkCallback callback,
150 gpointer callback_data);
153 static void draw_row (GtkCList * clist,
156 GtkCListRow * clist_row);
157 static void draw_rows (GtkCList * clist,
158 GdkRectangle * area);
160 /* Size Allocation */
161 static void size_allocate_title_buttons (GtkCList * clist);
162 static void size_allocate_columns (GtkCList * clist);
165 static void real_select_row (GtkCList * clist,
169 static void real_unselect_row (GtkCList * clist,
173 static gint get_selection_info (GtkCList * clist,
180 static void draw_xor_line (GtkCList * clist);
181 static gint new_column_width (GtkCList * clist,
185 static void resize_column (GtkCList * clist,
190 static void column_button_create (GtkCList * clist,
192 static void column_button_clicked (GtkWidget * widget,
196 static void create_scrollbars (GtkCList * clist);
197 static void adjust_scrollbars (GtkCList * clist);
198 static void check_exposures (GtkCList * clist);
199 static void vadjustment_changed (GtkAdjustment * adjustment,
201 static void vadjustment_value_changed (GtkAdjustment * adjustment,
203 static void hadjustment_changed (GtkAdjustment * adjustment,
205 static void hadjustment_value_changed (GtkAdjustment * adjustment,
209 /* Memory Allocation/Distruction Routines */
210 static GtkCListColumn *columns_new (GtkCList * clist);
212 static void column_title_new (GtkCList * clist,
215 static void columns_delete (GtkCList * clist);
217 static GtkCListRow *row_new (GtkCList * clist);
219 static void row_delete (GtkCList * clist,
220 GtkCListRow * clist_row);
221 static void cell_empty (GtkCList * clist,
222 GtkCListRow * clist_row,
224 static void cell_set_text (GtkCList * clist,
225 GtkCListRow * clist_row,
228 static void cell_set_pixmap (GtkCList * clist,
229 GtkCListRow * clist_row,
233 static void cell_set_pixtext (GtkCList * clist,
234 GtkCListRow * clist_row,
242 static void gtk_clist_marshal_signal_1 (GtkObject * object,
246 static void gtk_clist_marshal_signal_2 (GtkObject * object,
251 /* Fill in data after widget is realized and has style */
252 static void add_style_data (GtkCList * clist);
254 static GtkContainerClass *parent_class = NULL;
255 static gint clist_signals[LAST_SIGNAL] = {0};
258 gtk_clist_get_type ()
260 static guint clist_type = 0;
264 GtkTypeInfo clist_info =
268 sizeof (GtkCListClass),
269 (GtkClassInitFunc) gtk_clist_class_init,
270 (GtkObjectInitFunc) gtk_clist_init,
271 (GtkArgSetFunc) NULL,
272 (GtkArgGetFunc) NULL,
275 clist_type = gtk_type_unique (gtk_container_get_type (), &clist_info);
282 gtk_clist_class_init (GtkCListClass * klass)
284 GtkObjectClass *object_class;
285 GtkWidgetClass *widget_class;
286 GtkContainerClass *container_class;
288 object_class = (GtkObjectClass *) klass;
289 widget_class = (GtkWidgetClass *) klass;
290 container_class = (GtkContainerClass *) klass;
292 parent_class = gtk_type_class (gtk_container_get_type ());
293 clist_signals[MOUSE_CLICK] =
294 gtk_signal_new ("mouse_click",
297 GTK_SIGNAL_OFFSET (GtkCListClass, mouse_click),
298 gtk_clist_marshal_signal_1,
299 GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_INT);
300 clist_signals[MOUSE_DOUBLE_CLICK] =
301 gtk_signal_new ("mouse_double_click",
304 GTK_SIGNAL_OFFSET (GtkCListClass, mouse_double_click),
305 gtk_clist_marshal_signal_1,
306 GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_INT);
307 clist_signals[SELECT_ROW] =
308 gtk_signal_new ("select_row",
311 GTK_SIGNAL_OFFSET (GtkCListClass, select_row),
312 gtk_clist_marshal_signal_1,
313 GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_INT);
314 clist_signals[UNSELECT_ROW] =
315 gtk_signal_new ("unselect_row",
318 GTK_SIGNAL_OFFSET (GtkCListClass, unselect_row),
319 gtk_clist_marshal_signal_1,
320 GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_INT);
321 clist_signals[CLICK_COLUMN] =
322 gtk_signal_new ("click_column",
325 GTK_SIGNAL_OFFSET (GtkCListClass, click_column),
326 gtk_clist_marshal_signal_2,
327 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
329 gtk_object_class_add_signals (object_class, clist_signals, LAST_SIGNAL);
331 object_class->destroy = gtk_clist_destroy;
332 object_class->finalize = gtk_clist_finalize;
334 widget_class->realize = gtk_clist_realize;
335 widget_class->unrealize = gtk_clist_unrealize;
336 widget_class->map = gtk_clist_map;
337 widget_class->unmap = gtk_clist_unmap;
338 widget_class->draw = gtk_clist_draw;
339 widget_class->button_press_event = gtk_clist_button_press;
340 widget_class->button_release_event = gtk_clist_button_release;
341 widget_class->motion_notify_event = gtk_clist_motion;
342 widget_class->expose_event = gtk_clist_expose;
343 widget_class->size_request = gtk_clist_size_request;
344 widget_class->size_allocate = gtk_clist_size_allocate;
346 container_class->add = NULL;
347 container_class->remove = NULL;
348 container_class->foreach = gtk_clist_foreach;
350 klass->mouse_click = NULL;
351 klass->mouse_double_click = NULL;
352 klass->select_row = real_select_row;
353 klass->unselect_row = real_unselect_row;
354 klass->click_column = NULL;
356 klass->scrollbar_spacing = 5;
360 gtk_clist_marshal_signal_1 (GtkObject * object,
365 GtkCListSignal1 rfunc;
367 rfunc = (GtkCListSignal1) func;
370 GTK_VALUE_INT (args[0]),
371 GTK_VALUE_INT (args[1]),
372 GTK_VALUE_INT (args[2]),
377 gtk_clist_marshal_signal_2 (GtkObject * object,
382 GtkCListSignal2 rfunc;
384 rfunc = (GtkCListSignal2) func;
387 GTK_VALUE_INT (args[0]),
392 gtk_clist_init (GtkCList * clist)
396 GTK_WIDGET_UNSET_FLAGS (clist, GTK_NO_WINDOW);
397 GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
400 clist->row_center_offset = 0;
401 clist->row_height = 0;
402 clist->row_list = NULL;
403 clist->row_list_end = NULL;
407 clist->title_window = NULL;
408 clist->column_title_area.x = 0;
409 clist->column_title_area.y = 0;
410 clist->column_title_area.width = 0;
411 clist->column_title_area.height = 0;
413 clist->clist_window = NULL;
414 clist->clist_window_width = 0;
415 clist->clist_window_height = 0;
420 clist->shadow_type = GTK_SHADOW_IN;
421 clist->hscrollbar_policy = GTK_POLICY_ALWAYS;
422 clist->vscrollbar_policy = GTK_POLICY_ALWAYS;
424 clist->cursor_drag = NULL;
425 clist->xor_gc = NULL;
430 clist->selection_mode = GTK_SELECTION_SINGLE;
431 clist->selection = NULL;
435 * GTKCLIST PUBLIC INTERFACE
436 * gtk_clist_new_with_titles
440 gtk_clist_new_with_titles (int columns,
450 widget = gtk_clist_new (columns);
454 clist = GTK_CLIST (widget);
456 /* set column titles */
457 GTK_CLIST_SET_FLAGS (clist, CLIST_SHOW_TITLES);
458 for (i = 0; i < columns; i++)
460 gtk_clist_set_column_title (clist, i, titles[i]);
467 gtk_clist_new (int columns)
475 clist = gtk_type_new (gtk_clist_get_type ());
476 GTK_CLIST_UNSET_FLAGS (clist, CLIST_SHOW_TITLES);
478 /* initalize memory chunks */
479 clist->row_mem_chunk = g_mem_chunk_new ("clist row mem chunk",
480 sizeof (GtkCListRow),
481 sizeof (GtkCListRow) * CLIST_OPTIMUM_SIZE,
484 clist->cell_mem_chunk = g_mem_chunk_new ("clist cell mem chunk",
485 sizeof (GtkCell) * columns,
486 sizeof (GtkCell) * columns * CLIST_OPTIMUM_SIZE,
489 /* set number of columns, allocate memory */
490 clist->columns = columns;
491 clist->column = columns_new (clist);
493 /* there needs to be at least one column button
494 * because there is alot of code that will break if it
496 column_button_create (clist, 0);
498 /* create scrollbars */
499 create_scrollbars (clist);
501 return GTK_WIDGET (clist);
505 gtk_clist_set_border (GtkCList * clist,
506 GtkShadowType border)
508 g_return_if_fail (clist != NULL);
510 clist->shadow_type = border;
512 if (GTK_WIDGET_VISIBLE (clist))
513 gtk_widget_queue_resize (GTK_WIDGET (clist));
517 gtk_clist_set_selection_mode (GtkCList * clist,
518 GtkSelectionMode mode)
520 g_return_if_fail (clist != NULL);
522 clist->selection_mode = mode;
526 gtk_clist_freeze (GtkCList * clist)
528 g_return_if_fail (clist != NULL);
530 GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
534 gtk_clist_thaw (GtkCList * clist)
536 g_return_if_fail (clist != NULL);
538 GTK_CLIST_UNSET_FLAGS (clist, CLIST_FROZEN);
540 adjust_scrollbars (clist);
541 draw_rows (clist, NULL);
545 gtk_clist_column_titles_show (GtkCList * clist)
547 g_return_if_fail (clist != NULL);
549 if (!GTK_CLIST_SHOW_TITLES (clist))
551 GTK_CLIST_SET_FLAGS (clist, CLIST_SHOW_TITLES);
552 gdk_window_show (clist->title_window);
553 gtk_widget_queue_resize (GTK_WIDGET (clist));
558 gtk_clist_column_titles_hide (GtkCList * clist)
560 g_return_if_fail (clist != NULL);
562 if (GTK_CLIST_SHOW_TITLES (clist))
564 GTK_CLIST_UNSET_FLAGS (clist, CLIST_SHOW_TITLES);
565 gdk_window_hide (clist->title_window);
566 gtk_widget_queue_resize (GTK_WIDGET (clist));
571 gtk_clist_column_title_active (GtkCList * clist,
574 g_return_if_fail (clist != NULL);
576 if (column < 0 || column >= clist->columns)
579 if (!GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
580 !GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
582 GTK_WIDGET_SET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS);
583 if (GTK_WIDGET_VISIBLE (clist))
584 gtk_widget_queue_draw (clist->column[column].button);
589 gtk_clist_column_title_passive (GtkCList * clist,
592 g_return_if_fail (clist != NULL);
594 if (column < 0 || column >= clist->columns)
597 if (GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
598 GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
600 GTK_WIDGET_UNSET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS);
601 if (GTK_WIDGET_VISIBLE (clist))
602 gtk_widget_queue_draw (clist->column[column].button);
607 gtk_clist_column_titles_active (GtkCList * clist)
611 g_return_if_fail (clist != NULL);
613 for (i = 0; i < clist->columns; i++)
614 if (clist->column[i].button)
615 gtk_clist_column_title_active (clist, i);
619 gtk_clist_column_titles_passive (GtkCList * clist)
623 g_return_if_fail (clist != NULL);
625 for (i = 0; i < clist->columns; i++)
626 if (clist->column[i].button)
627 gtk_clist_column_title_passive (clist, i);
631 gtk_clist_set_column_title (GtkCList * clist,
636 GtkWidget *old_widget;
637 GtkWidget *alignment = NULL;
640 g_return_if_fail (clist != NULL);
642 if (column < 0 || column >= clist->columns)
645 /* if the column button doesn't currently exist,
646 * it has to be created first */
647 if (!clist->column[column].button)
649 column_button_create (clist, column);
653 column_title_new (clist, column, title);
655 /* remove and destroy the old widget */
656 old_widget = GTK_BUTTON (clist->column[column].button)->child;
659 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
660 gtk_widget_destroy (old_widget);
663 /* create new alignment based no column justification */
664 switch (clist->column[column].justification)
666 case GTK_JUSTIFY_LEFT:
667 alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
670 case GTK_JUSTIFY_RIGHT:
671 alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
674 case GTK_JUSTIFY_CENTER:
675 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
678 case GTK_JUSTIFY_FILL:
679 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
683 label = gtk_label_new (clist->column[column].title);
684 gtk_container_add (GTK_CONTAINER (alignment), label);
685 gtk_container_add (GTK_CONTAINER (clist->column[column].button), alignment);
686 gtk_widget_show (label);
687 gtk_widget_show (alignment);
689 /* if this button didn't previously exist, then the
690 * column button positions have to be re-computed */
691 if (GTK_WIDGET_VISIBLE (clist) && new_button)
692 size_allocate_title_buttons (clist);
696 gtk_clist_set_column_widget (GtkCList * clist,
701 GtkWidget *old_widget;
703 g_return_if_fail (clist != NULL);
705 if (column < 0 || column >= clist->columns)
708 /* if the column button doesn't currently exist,
709 * it has to be created first */
710 if (!clist->column[column].button)
712 column_button_create (clist, column);
716 column_title_new (clist, column, NULL);
718 /* remove and destroy the old widget */
719 old_widget = GTK_BUTTON (clist->column[column].button)->child;
722 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
723 gtk_widget_destroy (old_widget);
726 /* add and show the widget */
729 gtk_container_add (GTK_CONTAINER (clist->column[column].button), widget);
730 gtk_widget_show (widget);
733 /* if this button didn't previously exist, then the
734 * column button positions have to be re-computed */
735 if (GTK_WIDGET_VISIBLE (clist) && new_button)
736 size_allocate_title_buttons (clist);
740 gtk_clist_set_column_justification (GtkCList * clist,
742 GtkJustification justification)
744 GtkWidget *alignment;
746 g_return_if_fail (clist != NULL);
748 if (column < 0 || column >= clist->columns)
751 clist->column[column].justification = justification;
753 /* change the alinment of the button title if it's not a
755 if (clist->column[column].title)
757 alignment = GTK_BUTTON (clist->column[column].button)->child;
759 switch (clist->column[column].justification)
761 case GTK_JUSTIFY_LEFT:
762 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.0, 0.5, 0.0, 0.0);
765 case GTK_JUSTIFY_RIGHT:
766 gtk_alignment_set (GTK_ALIGNMENT (alignment), 1.0, 0.5, 0.0, 0.0);
769 case GTK_JUSTIFY_CENTER:
770 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
773 case GTK_JUSTIFY_FILL:
774 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
782 if (!GTK_CLIST_FROZEN (clist))
783 draw_rows (clist, NULL);
787 gtk_clist_set_column_width (GtkCList * clist,
791 g_return_if_fail (clist != NULL);
793 if (column < 0 || column >= clist->columns)
796 clist->column[column].width = width;
797 clist->column[column].width_set = TRUE;
799 /* FIXME: this is quite expensive to do if the widget hasn't
800 * been size_allocated yet, and pointless. Should
803 size_allocate_columns (clist);
804 size_allocate_title_buttons (clist);
806 if (!GTK_CLIST_FROZEN (clist))
808 adjust_scrollbars (clist);
809 draw_rows (clist, NULL);
814 gtk_clist_set_row_height (GtkCList * clist,
819 g_return_if_fail (clist != NULL);
822 clist->row_height = height;
826 GTK_CLIST_SET_FLAGS (clist, CLIST_ROW_HEIGHT_SET);
828 if (GTK_WIDGET_REALIZED (clist))
830 text_height = height - (GTK_WIDGET (clist)->style->font->ascent +
831 GTK_WIDGET (clist)->style->font->descent + 1);
832 clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
835 if (!GTK_CLIST_FROZEN (clist))
837 adjust_scrollbars (clist);
838 draw_rows (clist, NULL);
843 gtk_clist_moveto (GtkCList * clist,
851 g_return_if_fail (clist != NULL);
853 if (row < -1 || row >= clist->rows)
855 if (column < -1 || column >= clist->columns)
858 /* adjust vertical scrollbar */
861 x = ROW_TOP (clist, row) - (row_align * (clist->clist_window_height -
862 (clist->row_height + 2 * CELL_SPACING)));
865 GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0;
866 else if (x > LIST_HEIGHT (clist) - clist->clist_window_height)
867 GTK_RANGE (clist->vscrollbar)->adjustment->value = LIST_HEIGHT (clist) -
868 clist->clist_window_height;
870 GTK_RANGE (clist->vscrollbar)->adjustment->value = x;
872 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment),
876 /* adjust horizontal scrollbar */
879 y = COLUMN_LEFT (clist, column) - (col_align * (clist->clist_window_width -
880 clist->column[column].area.width +
881 2 * (CELL_SPACING + COLUMN_INSET)));
884 GTK_RANGE (clist->hscrollbar)->adjustment->value = 0.0;
885 else if (y > LIST_WIDTH (clist) - clist->clist_window_width)
886 GTK_RANGE (clist->hscrollbar)->adjustment->value = LIST_WIDTH (clist) -
887 clist->clist_window_width;
889 GTK_RANGE (clist->hscrollbar)->adjustment->value = y;
891 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment),
897 gtk_clist_get_cell_type (GtkCList * clist,
901 GtkCListRow *clist_row;
903 g_return_val_if_fail (clist != NULL, -1);
905 if (row < 0 || row >= clist->rows)
907 if (column < 0 || column >= clist->columns)
910 clist_row = (g_list_nth (clist->row_list, row))->data;
912 return clist_row->cell[column].type;
916 gtk_clist_set_text (GtkCList * clist,
921 GtkCListRow *clist_row;
923 g_return_if_fail (clist != NULL);
925 if (row < 0 || row >= clist->rows)
927 if (column < 0 || column >= clist->columns)
930 clist_row = (g_list_nth (clist->row_list, row))->data;
932 /* if text is null, then the cell is empty */
934 cell_set_text (clist, clist_row, column, text);
936 cell_empty (clist, clist_row, column);
938 /* redraw the list if it's not frozen */
939 if (!GTK_CLIST_FROZEN (clist))
941 if (gtk_clist_row_isvisable (clist, row))
942 draw_row (clist, NULL, row, clist_row);
947 gtk_clist_get_text (GtkCList * clist,
952 GtkCListRow *clist_row;
954 g_return_val_if_fail (clist != NULL, 0);
956 if (row < 0 || row >= clist->rows)
958 if (column < 0 || column >= clist->columns)
961 clist_row = (g_list_nth (clist->row_list, row))->data;
963 if (clist_row->cell[column].type != GTK_CELL_TEXT)
967 *text = GTK_CELL_TEXT (clist_row->cell[column])->text;
973 gtk_clist_set_pixmap (GtkCList * clist,
979 GtkCListRow *clist_row;
981 g_return_if_fail (clist != NULL);
983 if (row < 0 || row >= clist->rows)
985 if (column < 0 || column >= clist->columns)
988 clist_row = (g_list_nth (clist->row_list, row))->data;
990 gdk_pixmap_ref (pixmap);
991 gdk_pixmap_ref (mask);
992 cell_set_pixmap (clist, clist_row, column, pixmap, mask);
994 /* redraw the list if it's not frozen */
995 if (!GTK_CLIST_FROZEN (clist))
997 if (gtk_clist_row_isvisable (clist, row))
998 draw_row (clist, NULL, row, clist_row);
1003 gtk_clist_get_pixmap (GtkCList * clist,
1006 GdkPixmap ** pixmap,
1009 GtkCListRow *clist_row;
1011 g_return_val_if_fail (clist != NULL, 0);
1013 if (row < 0 || row >= clist->rows)
1015 if (column < 0 || column >= clist->columns)
1018 clist_row = (g_list_nth (clist->row_list, row))->data;
1020 if (clist_row->cell[column].type != GTK_CELL_PIXMAP)
1024 *pixmap = GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap;
1026 *mask = GTK_CELL_PIXMAP (clist_row->cell[column])->mask;
1032 gtk_clist_set_pixtext (GtkCList * clist,
1040 GtkCListRow *clist_row;
1042 g_return_if_fail (clist != NULL);
1044 if (row < 0 || row >= clist->rows)
1046 if (column < 0 || column >= clist->columns)
1049 clist_row = (g_list_nth (clist->row_list, row))->data;
1051 gdk_pixmap_ref (pixmap);
1052 gdk_pixmap_ref (mask);
1053 cell_set_pixtext (clist, clist_row, column, text, spacing, pixmap, mask);
1055 /* redraw the list if it's not frozen */
1056 if (!GTK_CLIST_FROZEN (clist))
1058 if (gtk_clist_row_isvisable (clist, row))
1059 draw_row (clist, NULL, row, clist_row);
1064 gtk_clist_get_pixtext (GtkCList * clist,
1069 GdkPixmap ** pixmap,
1072 GtkCListRow *clist_row;
1074 g_return_val_if_fail (clist != NULL, 0);
1076 if (row < 0 || row >= clist->rows)
1078 if (column < 0 || column >= clist->columns)
1081 clist_row = (g_list_nth (clist->row_list, row))->data;
1083 if (clist_row->cell[column].type != GTK_CELL_PIXTEXT)
1087 *text = GTK_CELL_PIXTEXT (clist_row->cell[column])->text;
1089 *spacing = GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing;
1091 *pixmap = GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap;
1093 *mask = GTK_CELL_PIXTEXT (clist_row->cell[column])->mask;
1099 gtk_clist_set_foreground (GtkCList * clist,
1103 GtkCListRow *clist_row;
1105 g_return_if_fail (clist != NULL);
1106 g_return_if_fail (color != NULL);
1108 if (row < 0 || row >= clist->rows)
1111 clist_row = (g_list_nth (clist->row_list, row))->data;
1112 clist_row->foreground = *color;
1113 clist_row->fg_set = TRUE;
1115 if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
1116 draw_row (clist, NULL, row, clist_row);
1119 void gtk_clist_set_background (GtkCList * clist,
1123 GtkCListRow *clist_row;
1125 g_return_if_fail (clist != NULL);
1126 g_return_if_fail (color != NULL);
1128 if (row < 0 || row >= clist->rows)
1131 clist_row = (g_list_nth (clist->row_list, row))->data;
1132 clist_row->background = *color;
1133 clist_row->bg_set = TRUE;
1135 if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
1136 draw_row (clist, NULL, row, clist_row);
1140 gtk_clist_set_shift (GtkCList * clist,
1146 GtkCListRow *clist_row;
1148 g_return_if_fail (clist != NULL);
1150 if (row < 0 || row >= clist->rows)
1152 if (column < 0 || column >= clist->columns)
1155 clist_row = (g_list_nth (clist->row_list, row))->data;
1157 clist_row->cell[column].vertical = vertical;
1158 clist_row->cell[column].horizontal = horizontal;
1160 if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
1161 draw_row (clist, NULL, row, clist_row);
1165 gtk_clist_append (GtkCList * clist,
1169 GtkCListRow *clist_row;
1171 g_return_val_if_fail (clist != NULL, -1);
1173 clist_row = row_new (clist);
1176 /* set the text in the row's columns */
1178 for (i = 0; i < clist->columns; i++)
1180 cell_set_text (clist, clist_row, i, text[i]);
1182 /* keeps track of the end of the list so the list
1183 * doesn't have to be traversed every time a item is added */
1184 if (!clist->row_list)
1186 clist->row_list = g_list_append (clist->row_list, clist_row);
1187 clist->row_list_end = clist->row_list;
1189 /* check the selection mode to see if we should select
1190 * the first row automaticly */
1191 switch (clist->selection_mode)
1193 case GTK_SELECTION_BROWSE:
1194 gtk_clist_select_row (clist, 0, -1);
1202 clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
1204 /* redraw the list if it's not frozen */
1205 if (!GTK_CLIST_FROZEN (clist))
1207 adjust_scrollbars (clist);
1209 if (gtk_clist_row_isvisable (clist, clist->rows - 1))
1210 draw_rows (clist, NULL);
1213 /* return index of the row */
1214 return clist->rows - 1;
1218 gtk_clist_insert (GtkCList * clist,
1223 GtkCListRow *clist_row;
1225 g_return_if_fail (clist != NULL);
1226 g_return_if_fail (text != NULL);
1228 /* return if out of bounds */
1229 if (row < 0 || row > (clist->rows - 1))
1232 /* create the row */
1233 clist_row = row_new (clist);
1235 /* set the text in the row's columns */
1237 for (i = 0; i < clist->columns; i++)
1239 cell_set_text (clist, clist_row, i, text[i]);
1241 /* reset the row end pointer if we're inserting at the
1242 * end of the list */
1243 if (row == clist->rows)
1244 clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
1246 clist->row_list = g_list_insert (clist->row_list, clist_row, row);
1250 /* redraw the list if it isn't frozen */
1251 if (!GTK_CLIST_FROZEN (clist))
1253 adjust_scrollbars (clist);
1255 if (gtk_clist_row_isvisable (clist, row))
1256 draw_rows (clist, NULL);
1261 gtk_clist_remove (GtkCList * clist,
1266 GtkCListRow *clist_row;
1268 g_return_if_fail (clist != NULL);
1270 /* return if out of bounds */
1271 if (row < 0 || row > (clist->rows - 1))
1274 was_visible = gtk_clist_row_isvisable (clist, row);
1276 /* get the row we're going to delete */
1277 list = g_list_nth (clist->row_list, row);
1278 clist_row = list->data;
1280 /* reset the row end pointer if we're removing at the
1281 * end of the list */
1282 if (row == clist->rows - 1)
1283 clist->row_list_end = list->prev;
1285 clist->row_list = g_list_remove (clist->row_list, clist_row);
1288 /* redraw the row if it isn't frozen */
1289 if (!GTK_CLIST_FROZEN (clist))
1291 adjust_scrollbars (clist);
1294 draw_rows (clist, NULL);
1297 if (clist_row->state == GTK_STATE_SELECTED)
1299 switch (clist->selection_mode)
1301 case GTK_SELECTION_BROWSE:
1302 if (row >= clist->rows)
1304 gtk_clist_select_row (clist, row, -1);
1311 /* remove from selection list */
1312 clist->selection = g_list_remove (clist->selection, clist_row);
1315 row_delete (clist, clist_row);
1319 gtk_clist_clear (GtkCList * clist)
1322 GtkCListRow *clist_row;
1324 g_return_if_fail (clist != NULL);
1326 /* remove all the rows */
1327 list = clist->row_list;
1330 clist_row = list->data;
1333 row_delete (clist, clist_row);
1335 g_list_free (clist->row_list);
1337 /* free up the selection list */
1338 g_list_free (clist->selection);
1340 clist->row_list = NULL;
1341 clist->row_list_end = NULL;
1342 clist->selection = NULL;
1346 /* zero-out the scrollbars */
1347 if (clist->vscrollbar)
1349 GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0;
1350 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
1352 if (!GTK_CLIST_FROZEN (clist))
1354 adjust_scrollbars (clist);
1355 draw_rows (clist, NULL);
1361 gtk_clist_set_row_data (GtkCList * clist,
1365 GtkCListRow *clist_row;
1367 g_return_if_fail (clist != NULL);
1369 if (row < 0 || row > (clist->rows - 1))
1372 clist_row = (g_list_nth (clist->row_list, row))->data;
1373 clist_row->data = data;
1376 * re-send the selected signal if data is changed/added
1377 * so the application can respond to the new data --
1378 * this could be questionable behavior
1380 if (clist_row->state == GTK_STATE_SELECTED)
1381 gtk_clist_select_row (clist, 0, 0);
1385 gtk_clist_get_row_data (GtkCList * clist,
1388 GtkCListRow *clist_row;
1390 g_return_val_if_fail (clist != NULL, NULL);
1392 if (row < 0 || row > (clist->rows - 1))
1395 clist_row = (g_list_nth (clist->row_list, row))->data;
1396 return clist_row->data;
1400 gtk_clist_find_row_from_data (GtkCList * clist,
1406 g_return_val_if_fail (clist != NULL, -1);
1407 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1409 if (clist->rows < 1)
1410 return -1; /* is this an optimization or just worthless? */
1413 list = clist->row_list;
1416 GtkCListRow *clist_row;
1418 clist_row = list->data;
1419 if (clist_row->data == data)
1432 gtk_clist_select_row (GtkCList * clist,
1436 g_return_if_fail (clist != NULL);
1438 if (row < 0 || row >= clist->rows)
1441 if (column < -1 || column >= clist->columns)
1444 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], row, column, 0);
1448 gtk_clist_unselect_row (GtkCList * clist,
1452 g_return_if_fail (clist != NULL);
1454 if (row < 0 || row >= clist->rows)
1457 if (column < -1 || column >= clist->columns)
1460 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], row, column, 0);
1464 gtk_clist_row_isvisable (GtkCList * clist,
1467 g_return_val_if_fail (clist != NULL, 0);
1469 if (row < 0 || row >= clist->rows)
1472 if (clist->row_height == 0)
1475 if (row < ROW_FROM_YPIXEL (clist, 0))
1478 if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height))
1485 gtk_clist_get_vadjustment (GtkCList * clist)
1487 g_return_val_if_fail (clist != NULL, NULL);
1488 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
1490 return gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
1494 gtk_clist_get_hadjustment (GtkCList * clist)
1496 g_return_val_if_fail (clist != NULL, NULL);
1497 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
1499 return gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
1503 gtk_clist_set_policy (GtkCList * clist,
1504 GtkPolicyType vscrollbar_policy,
1505 GtkPolicyType hscrollbar_policy)
1507 g_return_if_fail (clist != NULL);
1508 g_return_if_fail (GTK_IS_CLIST (clist));
1510 if (clist->vscrollbar_policy != vscrollbar_policy)
1512 clist->vscrollbar_policy = vscrollbar_policy;
1514 if (GTK_WIDGET (clist)->parent)
1515 gtk_widget_queue_resize (GTK_WIDGET (clist));
1518 if (clist->hscrollbar_policy != hscrollbar_policy)
1520 clist->hscrollbar_policy = hscrollbar_policy;
1522 if (GTK_WIDGET (clist)->parent)
1523 gtk_widget_queue_resize (GTK_WIDGET (clist));
1530 * gtk_clist_finalize
1533 gtk_clist_destroy (GtkObject * object)
1538 g_return_if_fail (object != NULL);
1539 g_return_if_fail (GTK_IS_CLIST (object));
1541 clist = GTK_CLIST (object);
1543 /* freeze the list */
1544 GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
1546 /* get rid of all the rows */
1547 gtk_clist_clear (clist);
1549 /* Since we don't have a _remove method, unparent the children
1550 * instead of destroying them so the focus will be unset properly.
1551 * (For other containers, the _remove method takes care of the
1552 * unparent) The destroy will happen when the refcount drops
1556 /* destroy the scrollbars */
1557 if (clist->vscrollbar)
1559 gtk_widget_unparent (clist->vscrollbar);
1560 clist->vscrollbar = NULL;
1562 if (clist->hscrollbar)
1564 gtk_widget_unparent (clist->hscrollbar);
1565 clist->hscrollbar = NULL;
1568 /* destroy the column buttons */
1569 for (i = 0; i < clist->columns; i++)
1570 if (clist->column[i].button)
1572 gtk_widget_unparent (clist->column[i].button);
1573 clist->column[i].button = NULL;
1576 if (GTK_OBJECT_CLASS (parent_class)->destroy)
1577 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
1581 gtk_clist_finalize (GtkObject * object)
1585 g_return_if_fail (object != NULL);
1586 g_return_if_fail (GTK_IS_CLIST (object));
1588 clist = GTK_CLIST (object);
1590 columns_delete (clist);
1592 g_mem_chunk_destroy (clist->cell_mem_chunk);
1593 g_mem_chunk_destroy (clist->row_mem_chunk);
1595 if (GTK_OBJECT_CLASS (parent_class)->finalize)
1596 (*GTK_OBJECT_CLASS (parent_class)->finalize) (object);
1602 * gtk_clist_unrealize
1607 * gtk_clist_button_press
1608 * gtk_clist_button_release
1609 * gtk_clist_button_motion
1610 * gtk_clist_size_request
1611 * gtk_clist_size_allocate
1614 gtk_clist_realize (GtkWidget * widget)
1618 GdkWindowAttr attributes;
1619 gint attributes_mask;
1622 g_return_if_fail (widget != NULL);
1623 g_return_if_fail (GTK_IS_CLIST (widget));
1625 clist = GTK_CLIST (widget);
1627 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1629 attributes.window_type = GDK_WINDOW_CHILD;
1630 attributes.x = widget->allocation.x;
1631 attributes.y = widget->allocation.y;
1632 attributes.width = widget->allocation.width;
1633 attributes.height = widget->allocation.height;
1634 attributes.wclass = GDK_INPUT_OUTPUT;
1635 attributes.visual = gtk_widget_get_visual (widget);
1636 attributes.colormap = gtk_widget_get_colormap (widget);
1637 attributes.event_mask = gtk_widget_get_events (widget);
1638 attributes.event_mask |= (GDK_EXPOSURE_MASK |
1639 GDK_BUTTON_PRESS_MASK |
1640 GDK_BUTTON_RELEASE_MASK |
1641 GDK_KEY_PRESS_MASK);
1642 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1646 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
1647 gdk_window_set_user_data (widget->window, clist);
1649 widget->style = gtk_style_attach (widget->style, widget->window);
1651 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
1653 /* column-title window */
1654 clist->title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
1655 gdk_window_set_user_data (clist->title_window, clist);
1657 gtk_style_set_background (widget->style, clist->title_window, GTK_STATE_SELECTED);
1658 gdk_window_show (clist->title_window);
1660 /* set things up so column buttons are drawn in title window */
1661 for (i = 0; i < clist->columns; i++)
1662 if (clist->column[i].button)
1663 gtk_widget_set_parent_window (clist->column[i].button, clist->title_window);
1666 clist->clist_window = gdk_window_new (widget->window, &attributes, attributes_mask);
1667 gdk_window_set_user_data (clist->clist_window, clist);
1669 gdk_window_set_background (clist->clist_window, &widget->style->bg[GTK_STATE_PRELIGHT]);
1670 gdk_window_show (clist->clist_window);
1671 gdk_window_get_size (clist->clist_window, &clist->clist_window_width,
1672 &clist->clist_window_height);
1674 /* create resize windows */
1675 attributes.wclass = GDK_INPUT_ONLY;
1676 attributes.event_mask = (GDK_BUTTON_PRESS_MASK |
1677 GDK_BUTTON_RELEASE_MASK |
1678 GDK_POINTER_MOTION_MASK |
1679 GDK_POINTER_MOTION_HINT_MASK);
1680 attributes.cursor = clist->cursor_drag = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
1681 attributes_mask = GDK_WA_CURSOR;
1683 for (i = 0; i < clist->columns; i++)
1685 clist->column[i].window = gdk_window_new (clist->title_window, &attributes, attributes_mask);
1686 gdk_window_set_user_data (clist->column[i].window, clist);
1687 gdk_window_show (clist->column[i].window);
1691 clist->fg_gc = gdk_gc_new (widget->window);
1692 clist->bg_gc = gdk_gc_new (widget->window);
1694 /* We'll use this gc to do scrolling as well */
1695 gdk_gc_set_exposures (clist->fg_gc, TRUE);
1697 values.foreground = widget->style->white;
1698 values.function = GDK_XOR;
1699 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
1700 clist->xor_gc = gdk_gc_new_with_values (widget->window,
1706 add_style_data (clist);
1710 gtk_clist_unrealize (GtkWidget * widget)
1715 g_return_if_fail (widget != NULL);
1716 g_return_if_fail (GTK_IS_CLIST (widget));
1718 clist = GTK_CLIST (widget);
1720 GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
1722 gdk_cursor_destroy (clist->cursor_drag);
1723 gdk_gc_destroy (clist->xor_gc);
1724 gdk_gc_destroy (clist->fg_gc);
1725 gdk_gc_destroy (clist->bg_gc);
1727 for (i = 0; i < clist->columns; i++)
1728 if (clist->column[i].window)
1730 gdk_window_set_user_data (clist->column[i].window, NULL);
1731 gdk_window_destroy (clist->column[i].window);
1732 clist->column[i].window = NULL;
1735 gdk_window_set_user_data (clist->clist_window, NULL);
1736 gdk_window_destroy (clist->clist_window);
1737 clist->clist_window = NULL;
1739 gdk_window_set_user_data (clist->title_window, NULL);
1740 gdk_window_destroy (clist->title_window);
1741 clist->title_window = NULL;
1743 clist->cursor_drag = NULL;
1744 clist->xor_gc = NULL;
1745 clist->fg_gc = NULL;
1746 clist->bg_gc = NULL;
1748 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1749 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1753 gtk_clist_map (GtkWidget * widget)
1758 g_return_if_fail (widget != NULL);
1759 g_return_if_fail (GTK_IS_CLIST (widget));
1761 clist = GTK_CLIST (widget);
1763 if (!GTK_WIDGET_MAPPED (widget))
1765 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1767 gdk_window_show (widget->window);
1768 gdk_window_show (clist->title_window);
1769 gdk_window_show (clist->clist_window);
1771 /* map column buttons */
1772 for (i = 0; i < clist->columns; i++)
1773 if (clist->column[i].button &&
1774 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
1775 !GTK_WIDGET_MAPPED (clist->column[i].button))
1776 gtk_widget_map (clist->column[i].button);
1778 /* map resize windows AFTER column buttons (above) */
1779 for (i = 0; i < clist->columns; i++)
1780 if (clist->column[i].window && clist->column[i].button)
1781 gdk_window_show (clist->column[i].window);
1783 /* map vscrollbars */
1784 if (GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
1785 !GTK_WIDGET_MAPPED (clist->vscrollbar))
1786 gtk_widget_map (clist->vscrollbar);
1788 if (GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
1789 !GTK_WIDGET_MAPPED (clist->hscrollbar))
1790 gtk_widget_map (clist->hscrollbar);
1792 /* unfreeze the list */
1793 GTK_CLIST_UNSET_FLAGS (clist, CLIST_FROZEN);
1798 gtk_clist_unmap (GtkWidget * widget)
1803 g_return_if_fail (widget != NULL);
1804 g_return_if_fail (GTK_IS_CLIST (widget));
1806 clist = GTK_CLIST (widget);
1808 if (GTK_WIDGET_MAPPED (widget))
1810 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1812 for (i = 0; i < clist->columns; i++)
1813 if (clist->column[i].window)
1814 gdk_window_hide (clist->column[i].window);
1816 gdk_window_hide (clist->clist_window);
1817 gdk_window_hide (clist->title_window);
1818 gdk_window_hide (widget->window);
1820 /* unmap scrollbars */
1821 if (GTK_WIDGET_MAPPED (clist->vscrollbar))
1822 gtk_widget_unmap (clist->vscrollbar);
1824 if (GTK_WIDGET_MAPPED (clist->hscrollbar))
1825 gtk_widget_unmap (clist->hscrollbar);
1827 /* unmap column buttons */
1828 for (i = 0; i < clist->columns; i++)
1829 if (clist->column[i].button &&
1830 GTK_WIDGET_MAPPED (clist->column[i].button))
1831 gtk_widget_unmap (clist->column[i].button);
1833 /* freeze the list */
1834 GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
1839 gtk_clist_draw (GtkWidget * widget,
1840 GdkRectangle * area)
1844 g_return_if_fail (widget != NULL);
1845 g_return_if_fail (GTK_IS_CLIST (widget));
1846 g_return_if_fail (area != NULL);
1848 if (GTK_WIDGET_DRAWABLE (widget))
1850 clist = GTK_CLIST (widget);
1852 gdk_window_clear_area (widget->window,
1854 area->width, area->height);
1856 /* draw list shadow/border */
1857 gtk_draw_shadow (widget->style, widget->window,
1858 GTK_STATE_NORMAL, clist->shadow_type,
1860 clist->clist_window_width + (2 * widget->style->klass->xthickness),
1861 clist->clist_window_height + (2 * widget->style->klass->ythickness) +
1862 clist->column_title_area.height);
1864 gdk_window_clear_area (clist->clist_window,
1867 draw_rows (clist, NULL);
1872 gtk_clist_expose (GtkWidget * widget,
1873 GdkEventExpose * event)
1877 g_return_val_if_fail (widget != NULL, FALSE);
1878 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
1879 g_return_val_if_fail (event != NULL, FALSE);
1881 if (GTK_WIDGET_DRAWABLE (widget))
1883 clist = GTK_CLIST (widget);
1886 if (event->window == widget->window)
1887 gtk_draw_shadow (widget->style, widget->window,
1888 GTK_STATE_NORMAL, clist->shadow_type,
1890 clist->clist_window_width + (2 * widget->style->klass->xthickness),
1891 clist->clist_window_height + (2 * widget->style->klass->ythickness) +
1892 clist->column_title_area.height);
1894 /* exposure events on the list */
1895 if (event->window == clist->clist_window)
1896 draw_rows (clist, &event->area);
1903 gtk_clist_button_press (GtkWidget * widget,
1904 GdkEventButton * event)
1908 gint x, y, row, column;
1910 g_return_val_if_fail (widget != NULL, FALSE);
1911 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
1912 g_return_val_if_fail (event != NULL, FALSE);
1914 clist = GTK_CLIST (widget);
1916 /* selections on the list */
1917 if (event->window == clist->clist_window)
1922 if (get_selection_info (clist, x, y, &row, &column))
1924 switch (event->type)
1926 case GDK_BUTTON_PRESS:
1927 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[MOUSE_CLICK],
1928 row, column, event->button);
1929 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
1930 row, column, event->button);
1933 case GDK_2BUTTON_PRESS:
1934 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[MOUSE_DOUBLE_CLICK],
1935 row, column, event->button);
1946 /* press on resize windows */
1947 for (i = 0; i < clist->columns; i++)
1948 if (clist->column[i].window && event->window == clist->column[i].window)
1950 GTK_CLIST_SET_FLAGS (clist, CLIST_IN_DRAG);
1951 gtk_widget_get_pointer (widget, &clist->x_drag, NULL);
1953 gdk_pointer_grab (clist->column[i].window, FALSE,
1954 GDK_POINTER_MOTION_HINT_MASK |
1955 GDK_BUTTON1_MOTION_MASK |
1956 GDK_BUTTON_RELEASE_MASK,
1957 NULL, NULL, event->time);
1959 draw_xor_line (clist);
1967 gtk_clist_button_release (GtkWidget * widget,
1968 GdkEventButton * event)
1970 gint i, x, width, visible;
1973 g_return_val_if_fail (widget != NULL, FALSE);
1974 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
1975 g_return_val_if_fail (event != NULL, FALSE);
1977 clist = GTK_CLIST (widget);
1979 /* release on resize windows */
1980 if (GTK_CLIST_IN_DRAG (clist))
1981 for (i = 0; i < clist->columns; i++)
1982 if (clist->column[i].window && event->window == clist->column[i].window)
1984 GTK_CLIST_UNSET_FLAGS (clist, CLIST_IN_DRAG);
1985 gtk_widget_get_pointer (widget, &x, NULL);
1986 width = new_column_width (clist, i, &x, &visible);
1987 gdk_pointer_ungrab (event->time);
1990 draw_xor_line (clist);
1992 resize_column (clist, i, width);
2000 gtk_clist_motion (GtkWidget * widget,
2001 GdkEventMotion * event)
2006 g_return_val_if_fail (widget != NULL, FALSE);
2007 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2009 clist = GTK_CLIST (widget);
2011 if (GTK_CLIST_IN_DRAG (clist))
2012 for (i = 0; i < clist->columns; i++)
2013 if (clist->column[i].window && event->window == clist->column[i].window)
2015 if (event->is_hint || event->window != widget->window)
2016 gtk_widget_get_pointer (widget, &x, NULL);
2020 new_column_width (clist, i, &x, &visible);
2021 /* Welcome to my hack! I'm going to use a value of x_drage = -99999 to
2022 * indicate the the xor line is already no visible */
2023 if (!visible && clist->x_drag != -99999)
2025 draw_xor_line (clist);
2026 clist->x_drag = -99999;
2029 if (x != clist->x_drag && visible)
2031 if (clist->x_drag != -99999)
2032 draw_xor_line (clist);
2035 draw_xor_line (clist);
2043 gtk_clist_size_request (GtkWidget * widget,
2044 GtkRequisition * requisition)
2049 g_return_if_fail (widget != NULL);
2050 g_return_if_fail (GTK_IS_CLIST (widget));
2051 g_return_if_fail (requisition != NULL);
2053 clist = GTK_CLIST (widget);
2055 requisition->width = 0;
2056 requisition->height = 0;
2058 /* compute the size of the column title (title) area */
2059 clist->column_title_area.height = 0;
2060 if (GTK_CLIST_SHOW_TITLES (clist))
2061 for (i = 0; i < clist->columns; i++)
2062 if (clist->column[i].button)
2064 gtk_widget_size_request (clist->column[i].button, &clist->column[i].button->requisition);
2065 clist->column_title_area.height = MAX (clist->column_title_area.height,
2066 clist->column[i].button->requisition.height);
2068 requisition->height += clist->column_title_area.height;
2070 /* add the vscrollbar space */
2071 if ((clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
2072 GTK_WIDGET_VISIBLE (clist->vscrollbar))
2074 gtk_widget_size_request (clist->vscrollbar, &clist->vscrollbar->requisition);
2076 requisition->width += clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist);
2077 requisition->height = MAX (requisition->height,
2078 clist->vscrollbar->requisition.height);
2081 /* add the hscrollbar space */
2082 if ((clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
2083 GTK_WIDGET_VISIBLE (clist->hscrollbar))
2085 gtk_widget_size_request (clist->hscrollbar, &clist->hscrollbar->requisition);
2087 requisition->height += clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist);
2088 requisition->width = MAX (clist->hscrollbar->requisition.width,
2089 requisition->width -
2090 clist->vscrollbar->requisition.width);
2094 requisition->width += widget->style->klass->xthickness * 2 +
2095 GTK_CONTAINER (widget)->border_width * 2;
2096 requisition->height += widget->style->klass->ythickness * 2 +
2097 GTK_CONTAINER (widget)->border_width * 2;
2101 gtk_clist_size_allocate (GtkWidget * widget,
2102 GtkAllocation * allocation)
2105 GtkAllocation clist_allocation;
2106 GtkAllocation child_allocation;
2107 gint i, vscrollbar_vis, hscrollbar_vis;
2109 g_return_if_fail (widget != NULL);
2110 g_return_if_fail (GTK_IS_CLIST (widget));
2111 g_return_if_fail (allocation != NULL);
2113 clist = GTK_CLIST (widget);
2114 widget->allocation = *allocation;
2116 if (GTK_WIDGET_REALIZED (widget))
2118 gdk_window_move_resize (widget->window,
2119 allocation->x + GTK_CONTAINER (widget)->border_width,
2120 allocation->y + GTK_CONTAINER (widget)->border_width,
2121 allocation->width - GTK_CONTAINER (widget)->border_width * 2,
2122 allocation->height - GTK_CONTAINER (widget)->border_width * 2);
2124 /* use internal allocation structure for all the math
2125 * because it's easier than always subtracting the container
2127 clist->internal_allocation.x = 0;
2128 clist->internal_allocation.y = 0;
2129 clist->internal_allocation.width = allocation->width -
2130 GTK_CONTAINER (widget)->border_width * 2;
2131 clist->internal_allocation.height = allocation->height -
2132 GTK_CONTAINER (widget)->border_width * 2;
2134 /* allocate clist window assuming no scrollbars */
2135 clist_allocation.x = clist->internal_allocation.x + widget->style->klass->xthickness;
2136 clist_allocation.y = clist->internal_allocation.y + widget->style->klass->ythickness +
2137 clist->column_title_area.height;
2138 clist_allocation.width = clist->internal_allocation.width -
2139 (2 * widget->style->klass->xthickness);
2140 clist_allocation.height = clist->internal_allocation.height -
2141 (2 * widget->style->klass->xthickness) -
2142 clist->column_title_area.height;
2145 * here's where we decide to show/not show the scrollbars
2150 for (i = 0; i <= 1; i++)
2152 if (LIST_HEIGHT (clist) <= clist_allocation.height &&
2153 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
2159 if (!vscrollbar_vis)
2162 clist_allocation.width -= clist->vscrollbar->requisition.width +
2163 SCROLLBAR_SPACING (clist);
2167 if (LIST_WIDTH (clist) <= clist_allocation.width &&
2168 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
2174 if (!hscrollbar_vis)
2177 clist_allocation.height -= clist->hscrollbar->requisition.height +
2178 SCROLLBAR_SPACING (clist);
2183 clist->clist_window_width = clist_allocation.width;
2184 clist->clist_window_height = clist_allocation.height;
2186 gdk_window_move_resize (clist->clist_window,
2189 clist_allocation.width,
2190 clist_allocation.height);
2192 /* position the window which holds the column title buttons */
2193 clist->column_title_area.x = widget->style->klass->xthickness;
2194 clist->column_title_area.y = widget->style->klass->ythickness;
2195 clist->column_title_area.width = clist_allocation.width;
2197 gdk_window_move_resize (clist->title_window,
2198 clist->column_title_area.x,
2199 clist->column_title_area.y,
2200 clist->column_title_area.width,
2201 clist->column_title_area.height);
2203 /* column button allocation */
2204 size_allocate_columns (clist);
2205 size_allocate_title_buttons (clist);
2206 adjust_scrollbars (clist);
2208 /* allocate the vscrollbar */
2211 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
2212 gtk_widget_show (clist->vscrollbar);
2214 child_allocation.x = clist->internal_allocation.x +
2215 clist->internal_allocation.width -
2216 clist->vscrollbar->requisition.width;
2217 child_allocation.y = clist->internal_allocation.y;
2218 child_allocation.width = clist->vscrollbar->requisition.width;
2219 child_allocation.height = clist->internal_allocation.height -
2220 (hscrollbar_vis ? (clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist)) : 0);
2222 gtk_widget_size_allocate (clist->vscrollbar, &child_allocation);
2226 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
2227 gtk_widget_hide (clist->vscrollbar);
2232 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
2233 gtk_widget_show (clist->hscrollbar);
2235 child_allocation.x = clist->internal_allocation.x;
2236 child_allocation.y = clist->internal_allocation.y +
2237 clist->internal_allocation.height -
2238 clist->hscrollbar->requisition.height;
2239 child_allocation.width = clist->internal_allocation.width -
2240 (vscrollbar_vis ? (clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist)) : 0);
2241 child_allocation.height = clist->hscrollbar->requisition.height;
2243 gtk_widget_size_allocate (clist->hscrollbar, &child_allocation);
2247 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
2248 gtk_widget_hide (clist->hscrollbar);
2252 /* set the vscrollbar adjustments */
2253 adjust_scrollbars (clist);
2261 gtk_clist_foreach (GtkContainer * container,
2262 GtkCallback callback,
2263 gpointer callback_data)
2268 g_return_if_fail (container != NULL);
2269 g_return_if_fail (GTK_IS_CLIST (container));
2270 g_return_if_fail (callback != NULL);
2272 clist = GTK_CLIST (container);
2274 /* callback for the column buttons */
2275 for (i = 0; i < clist->columns; i++)
2276 if (clist->column[i].button)
2277 (*callback) (clist->column[i].button, callback_data);
2279 /* callbacks for the scrollbars */
2280 if (clist->vscrollbar)
2281 (*callback) (clist->vscrollbar, callback_data);
2282 if (clist->hscrollbar)
2283 (*callback) (clist->hscrollbar, callback_data);
2292 draw_row (GtkCList * clist,
2293 GdkRectangle * area,
2295 GtkCListRow * clist_row)
2298 GdkGC *fg_gc, *bg_gc;
2299 GdkRectangle row_rectangle, cell_rectangle, clip_rectangle, intersect_rectangle,
2301 gint i, offset = 0, width, height, pixmap_width = 0;
2302 gint xsrc, ysrc, xdest, ydest;
2304 g_return_if_fail (clist != NULL);
2306 /* bail now if we arn't drawable yet */
2307 if (!GTK_WIDGET_DRAWABLE (clist))
2310 if (row < 0 || row >= clist->rows)
2313 widget = GTK_WIDGET (clist);
2315 /* if the function is passed the pointer to the row instead of null,
2316 * it avoids this expensive lookup */
2318 clist_row = (g_list_nth (clist->row_list, row))->data;
2320 /* rectangle of the entire row */
2321 row_rectangle.x = 0;
2322 row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
2323 row_rectangle.width = clist->clist_window_width;
2324 row_rectangle.height = clist->row_height;
2326 /* rectangle of the cell spacing above the row */
2327 cell_rectangle.x = 0;
2328 cell_rectangle.y = row_rectangle.y - CELL_SPACING;
2329 cell_rectangle.width = row_rectangle.width;
2330 cell_rectangle.height = CELL_SPACING;
2332 /* rectangle used to clip drawing operations, it's y and height
2333 * positions only need to be set once, so we set them once here.
2334 * the x and width are set withing the drawing loop below once per
2336 clip_rectangle.y = row_rectangle.y;
2337 clip_rectangle.height = row_rectangle.height;
2339 /* select GC for background rectangle */
2340 if (clist_row->state == GTK_STATE_SELECTED)
2342 fg_gc = widget->style->fg_gc[GTK_STATE_SELECTED];
2343 bg_gc = widget->style->bg_gc[GTK_STATE_SELECTED];
2347 if (clist_row->fg_set)
2349 gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
2350 fg_gc = clist->fg_gc;
2353 fg_gc = widget->style->fg_gc[GTK_STATE_NORMAL];
2355 if (clist_row->bg_set)
2357 gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
2358 bg_gc = clist->bg_gc;
2361 bg_gc = widget->style->bg_gc[GTK_STATE_PRELIGHT];
2364 /* draw the cell borders and background */
2367 if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
2368 gdk_draw_rectangle (clist->clist_window,
2369 widget->style->white_gc,
2371 intersect_rectangle.x,
2372 intersect_rectangle.y,
2373 intersect_rectangle.width,
2374 intersect_rectangle.height);
2376 /* the last row has to clear it's bottom cell spacing too */
2377 if (clist_row == clist->row_list_end->data)
2379 cell_rectangle.y += clist->row_height + CELL_SPACING;
2381 if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
2382 gdk_draw_rectangle (clist->clist_window,
2383 widget->style->white_gc,
2385 intersect_rectangle.x,
2386 intersect_rectangle.y,
2387 intersect_rectangle.width,
2388 intersect_rectangle.height);
2391 if (!gdk_rectangle_intersect (area, &row_rectangle, &intersect_rectangle))
2394 if (clist_row->state == GTK_STATE_SELECTED || clist_row->fg_set)
2395 gdk_draw_rectangle (clist->clist_window,
2398 intersect_rectangle.x,
2399 intersect_rectangle.y,
2400 intersect_rectangle.width,
2401 intersect_rectangle.height);
2403 gdk_window_clear_area (clist->clist_window,
2404 intersect_rectangle.x,
2405 intersect_rectangle.y,
2406 intersect_rectangle.width,
2407 intersect_rectangle.height);
2411 gdk_draw_rectangle (clist->clist_window,
2412 widget->style->white_gc,
2416 cell_rectangle.width,
2417 cell_rectangle.height);
2419 /* the last row has to clear it's bottom cell spacing too */
2420 if (clist_row == clist->row_list_end->data)
2422 cell_rectangle.y += clist->row_height + CELL_SPACING;
2424 gdk_draw_rectangle (clist->clist_window,
2425 widget->style->white_gc,
2429 cell_rectangle.width,
2430 cell_rectangle.height);
2433 if (clist_row->state == GTK_STATE_SELECTED || clist_row->fg_set)
2434 gdk_draw_rectangle (clist->clist_window,
2439 row_rectangle.width,
2440 row_rectangle.height);
2442 gdk_window_clear_area (clist->clist_window,
2445 row_rectangle.width,
2446 row_rectangle.height);
2449 /* iterate and draw all the columns (row cells) and draw their contents */
2450 for (i = 0; i < clist->columns; i++)
2452 clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
2453 clip_rectangle.width = clist->column[i].area.width;
2455 /* calculate clipping region clipping region */
2458 rect = &clip_rectangle;
2462 if (!gdk_rectangle_intersect (area, &clip_rectangle, &intersect_rectangle))
2464 rect = &intersect_rectangle;
2467 /* calculate real width for column justification */
2468 switch (clist_row->cell[i].type)
2470 case GTK_CELL_EMPTY:
2475 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
2476 GTK_CELL_TEXT (clist_row->cell[i])->text);
2479 case GTK_CELL_PIXMAP:
2480 gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, &width, &height);
2481 pixmap_width = width;
2484 case GTK_CELL_PIXTEXT:
2485 gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, &width, &height);
2486 pixmap_width = width;
2487 width += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
2488 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
2489 GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
2492 case GTK_CELL_WIDGET:
2502 switch (clist->column[i].justification)
2504 case GTK_JUSTIFY_LEFT:
2505 offset = clip_rectangle.x;
2508 case GTK_JUSTIFY_RIGHT:
2509 offset = (clip_rectangle.x + clip_rectangle.width) - width;
2512 case GTK_JUSTIFY_CENTER:
2513 offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
2516 case GTK_JUSTIFY_FILL:
2517 offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
2525 /* Draw Text or Pixmap */
2526 switch (clist_row->cell[i].type)
2528 case GTK_CELL_EMPTY:
2533 gdk_gc_set_clip_rectangle (fg_gc, rect);
2535 gdk_draw_string (clist->clist_window,
2536 widget->style->font,
2538 offset + clist_row->cell[i].horizontal,
2539 row_rectangle.y + clist->row_center_offset +
2540 clist_row->cell[i].vertical,
2541 GTK_CELL_TEXT (clist_row->cell[i])->text);
2543 gdk_gc_set_clip_rectangle (fg_gc, NULL);
2546 case GTK_CELL_PIXMAP:
2549 xdest = offset + clist_row->cell[i].horizontal;
2550 ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
2551 clist_row->cell[i].vertical;
2553 gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXMAP (clist_row->cell[i])->mask);
2554 gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
2556 gdk_draw_pixmap (clist->clist_window,
2558 GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
2562 pixmap_width, height);
2564 gdk_gc_set_clip_origin (fg_gc, 0, 0);
2565 gdk_gc_set_clip_mask (fg_gc, NULL);
2568 case GTK_CELL_PIXTEXT:
2569 /* draw the pixmap */
2572 xdest = offset + clist_row->cell[i].horizontal;
2573 ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
2574 clist_row->cell[i].vertical;
2576 gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXTEXT (clist_row->cell[i])->mask);
2577 gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
2579 gdk_draw_pixmap (clist->clist_window,
2581 GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
2585 pixmap_width, height);
2587 gdk_gc_set_clip_origin (fg_gc, 0, 0);
2589 offset += pixmap_width + GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
2591 /* draw the string */
2592 gdk_gc_set_clip_rectangle (fg_gc, rect);
2594 gdk_draw_string (clist->clist_window,
2595 widget->style->font,
2597 offset + clist_row->cell[i].horizontal,
2598 row_rectangle.y + clist->row_center_offset +
2599 clist_row->cell[i].vertical,
2600 GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
2602 gdk_gc_set_clip_rectangle (fg_gc, NULL);
2606 case GTK_CELL_WIDGET:
2619 draw_rows (GtkCList * clist,
2620 GdkRectangle * area)
2623 GtkCListRow *clist_row;
2624 int i, first_row, last_row;
2626 g_return_if_fail (clist != NULL);
2627 g_return_if_fail (GTK_IS_CLIST (clist));
2629 if (clist->row_height == 0 ||
2630 !GTK_WIDGET_DRAWABLE (clist))
2635 first_row = ROW_FROM_YPIXEL (clist, area->y);
2636 last_row = ROW_FROM_YPIXEL (clist, area->y + area->height);
2640 first_row = ROW_FROM_YPIXEL (clist, 0);
2641 last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height);
2644 /* this is a small special case which exposes the bottom cell line
2645 * on the last row -- it might go away if I change the wall the cell spacings
2647 if (clist->rows == first_row)
2650 list = g_list_nth (clist->row_list, first_row);
2654 clist_row = list->data;
2660 draw_row (clist, area, i, clist_row);
2665 gdk_window_clear_area (clist->clist_window, 0, ROW_TOP_YPIXEL (clist, i), -1, -1);
2670 * size_allocate_title_buttons
2671 * size_allocate_columns
2674 size_allocate_title_buttons (GtkCList * clist)
2676 gint i, last_button = 0;
2677 GtkAllocation button_allocation;
2679 if (!GTK_WIDGET_REALIZED (clist))
2682 button_allocation.x = clist->hoffset;
2683 button_allocation.y = 0;
2684 button_allocation.width = 0;
2685 button_allocation.height = clist->column_title_area.height;
2687 for (i = 0; i < clist->columns; i++)
2689 button_allocation.width += clist->column[i].area.width;
2691 if (i == clist->columns - 1)
2692 button_allocation.width += 2 * (CELL_SPACING + COLUMN_INSET);
2694 button_allocation.width += CELL_SPACING + (2 * COLUMN_INSET);
2696 if (i == (clist->columns - 1) || clist->column[i + 1].button)
2698 gtk_widget_size_allocate (clist->column[last_button].button, &button_allocation);
2699 button_allocation.x += button_allocation.width;
2700 button_allocation.width = 0;
2702 gdk_window_show (clist->column[last_button].window);
2703 gdk_window_move_resize (clist->column[last_button].window,
2704 button_allocation.x - (DRAG_WIDTH / 2),
2705 0, DRAG_WIDTH, clist->column_title_area.height);
2707 last_button = i + 1;
2711 gdk_window_hide (clist->column[i].window);
2717 size_allocate_columns (GtkCList * clist)
2719 gint i, xoffset = 0;
2721 if (!GTK_WIDGET_REALIZED (clist))
2724 for (i = 0; i < clist->columns; i++)
2726 clist->column[i].area.x = xoffset + CELL_SPACING + COLUMN_INSET;
2728 if (i == clist->columns - 1)
2732 if (clist->column[i].width_set)
2733 width = clist->column[i].width;
2735 width = gdk_string_width (GTK_WIDGET (clist)->style->font, clist->column[i].title);
2736 clist->column[i].area.width = MAX (width,
2737 clist->clist_window_width -
2738 xoffset - (2 * (CELL_SPACING + COLUMN_INSET)));
2743 clist->column[i].area.width = clist->column[i].width;
2746 xoffset += clist->column[i].area.width + CELL_SPACING + (2 * COLUMN_INSET);
2754 * get_selection_info
2757 real_select_row (GtkCList * clist,
2764 GtkCListRow *clist_row;
2766 g_return_if_fail (clist != NULL);
2768 if (row < 0 || row >= clist->rows)
2771 switch (clist->selection_mode)
2773 case GTK_SELECTION_SINGLE:
2775 list = clist->row_list;
2778 clist_row = list->data;
2783 if (clist_row->state == GTK_STATE_SELECTED)
2785 clist_row->state = GTK_STATE_NORMAL;
2786 gtk_clist_unselect_row (clist, i, column);
2790 clist_row->state = GTK_STATE_SELECTED;
2791 clist->selection = g_list_append (clist->selection, clist_row);
2794 if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
2795 draw_row (clist, NULL, row, clist_row);
2797 else if (clist_row->state == GTK_STATE_SELECTED)
2799 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], i, column, button);
2806 case GTK_SELECTION_BROWSE:
2808 list = clist->row_list;
2811 clist_row = list->data;
2816 if (clist_row->state != GTK_STATE_SELECTED)
2818 clist_row->state = GTK_STATE_SELECTED;
2819 clist->selection = g_list_append (clist->selection, clist_row);
2821 if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
2822 draw_row (clist, NULL, row, clist_row);
2825 else if (clist_row->state == GTK_STATE_SELECTED)
2827 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], i, column, button);
2834 case GTK_SELECTION_MULTIPLE:
2836 list = clist->row_list;
2839 clist_row = list->data;
2844 if (clist_row->state == GTK_STATE_SELECTED)
2846 clist_row->state = GTK_STATE_NORMAL;
2847 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], i, column, button);
2851 clist->selection = g_list_append (clist->selection, clist_row);
2852 clist_row->state = GTK_STATE_SELECTED;
2855 if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
2856 draw_row (clist, NULL, row, clist_row);
2863 case GTK_SELECTION_EXTENDED:
2872 real_unselect_row (GtkCList * clist,
2877 GtkCListRow *clist_row;
2879 g_return_if_fail (clist != NULL);
2881 if (row < 0 || row > (clist->rows - 1))
2884 clist_row = (g_list_nth (clist->row_list, row))->data;
2885 clist_row->state = GTK_STATE_NORMAL;
2886 clist->selection = g_list_remove (clist->selection, clist_row);
2888 if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
2889 draw_row (clist, NULL, row, clist_row);
2893 get_selection_info (GtkCList * clist,
2901 g_return_val_if_fail (clist != NULL, 0);
2903 /* bounds checking, return false if the user clicked
2904 * on a blank area */
2905 trow = ROW_FROM_YPIXEL (clist, y);
2906 if (trow >= clist->rows)
2912 tcol = COLUMN_FROM_XPIXEL (clist, x);
2913 if (tcol >= clist->columns)
2929 draw_xor_line (GtkCList * clist)
2933 g_return_if_fail (clist != NULL);
2935 widget = GTK_WIDGET (clist);
2937 gdk_draw_line (widget->window, clist->xor_gc,
2939 widget->style->klass->ythickness,
2941 clist->column_title_area.height + clist->clist_window_height + 1);
2944 /* this function returns the new width of the column being resized given
2945 * the column and x position of the cursor; the x cursor position is passed
2946 * in as a pointer and automagicly corrected if it's beyond min/max limits */
2948 new_column_width (GtkCList * clist,
2957 /* first translate the x position from widget->window
2958 * to clist->clist_window */
2959 cx -= GTK_WIDGET (clist)->style->klass->xthickness;
2961 /* rx is x from the list beginning */
2962 rx = cx - clist->hoffset;
2964 /* you can't shrink a column to less than its minimum width */
2965 if (cx < (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH))
2967 *x = cx = COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH +
2968 GTK_WIDGET (clist)->style->klass->xthickness;
2969 cx -= GTK_WIDGET (clist)->style->klass->xthickness;
2970 rx = cx - clist->hoffset;
2973 if (cx > clist->clist_window_width)
2978 /* calculate new column width making sure it doesn't end up
2979 * less than the minimum width */
2980 width = (rx - COLUMN_LEFT (clist, column)) - COLUMN_INSET -
2981 ((clist->columns == (column - 1)) ? CELL_SPACING : 0);
2982 if (width < COLUMN_MIN_WIDTH)
2983 width = COLUMN_MIN_WIDTH;
2988 /* this will do more later */
2990 resize_column (GtkCList * clist,
2994 gtk_clist_set_column_width (clist, column, width);
2999 column_button_create (GtkCList * clist,
3004 button = clist->column[column].button = gtk_button_new ();
3005 gtk_widget_set_parent (button, GTK_WIDGET (clist));
3006 if (GTK_WIDGET_REALIZED (clist) && clist->title_window)
3007 gtk_widget_set_parent_window (clist->column[column].button, clist->title_window);
3009 gtk_signal_connect (GTK_OBJECT (button),
3011 (GtkSignalFunc) column_button_clicked,
3014 gtk_widget_show (button);
3018 column_button_clicked (GtkWidget * widget,
3024 g_return_if_fail (widget != NULL);
3025 g_return_if_fail (GTK_IS_CLIST (data));
3027 clist = GTK_CLIST (data);
3029 /* find the column who's button was pressed */
3030 for (i = 0; i < clist->columns; i++)
3031 if (clist->column[i].button == widget)
3034 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i);
3043 * vadjustment_changed
3044 * hadjustment_changed
3045 * vadjustment_value_changed
3046 * hadjustment_value_changed
3049 create_scrollbars (GtkCList * clist)
3051 GtkAdjustment *adjustment;
3053 clist->vscrollbar = gtk_vscrollbar_new (NULL);
3054 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
3056 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
3057 (GtkSignalFunc) vadjustment_changed,
3060 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
3061 (GtkSignalFunc) vadjustment_value_changed,
3064 gtk_widget_set_parent (clist->vscrollbar, GTK_WIDGET (clist));
3065 gtk_widget_show (clist->vscrollbar);
3067 clist->hscrollbar = gtk_hscrollbar_new (NULL);
3068 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
3070 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
3071 (GtkSignalFunc) hadjustment_changed,
3074 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
3075 (GtkSignalFunc) hadjustment_value_changed,
3078 gtk_widget_set_parent (clist->hscrollbar, GTK_WIDGET (clist));
3079 gtk_widget_show (clist->hscrollbar);
3083 adjust_scrollbars (GtkCList * clist)
3085 GTK_RANGE (clist->vscrollbar)->adjustment->page_size = clist->clist_window_height;
3086 GTK_RANGE (clist->vscrollbar)->adjustment->page_increment = clist->clist_window_height / 2;
3087 GTK_RANGE (clist->vscrollbar)->adjustment->step_increment = 10;
3088 GTK_RANGE (clist->vscrollbar)->adjustment->lower = 0;
3089 GTK_RANGE (clist->vscrollbar)->adjustment->upper = LIST_HEIGHT (clist);
3091 if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist))
3093 GTK_RANGE (clist->vscrollbar)->adjustment->value = LIST_HEIGHT (clist) -
3094 clist->clist_window_height;
3095 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment),
3099 GTK_RANGE (clist->hscrollbar)->adjustment->page_size = clist->clist_window_width;
3100 GTK_RANGE (clist->hscrollbar)->adjustment->page_increment = clist->clist_window_width / 2;
3101 GTK_RANGE (clist->hscrollbar)->adjustment->step_increment = 10;
3102 GTK_RANGE (clist->hscrollbar)->adjustment->lower = 0;
3103 GTK_RANGE (clist->hscrollbar)->adjustment->upper = LIST_WIDTH (clist);
3105 if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist))
3107 GTK_RANGE (clist->hscrollbar)->adjustment->value = LIST_WIDTH (clist) -
3108 clist->clist_window_width;
3109 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment),
3113 if (LIST_HEIGHT (clist) <= clist->clist_window_height &&
3114 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
3116 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
3118 gtk_widget_hide (clist->vscrollbar);
3119 gtk_widget_queue_resize (GTK_WIDGET (clist));
3124 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
3126 gtk_widget_show (clist->vscrollbar);
3127 gtk_widget_queue_resize (GTK_WIDGET (clist));
3131 if (LIST_WIDTH (clist) <= clist->clist_window_width &&
3132 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
3134 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
3136 gtk_widget_hide (clist->hscrollbar);
3137 gtk_widget_queue_resize (GTK_WIDGET (clist));
3142 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
3144 gtk_widget_show (clist->hscrollbar);
3145 gtk_widget_queue_resize (GTK_WIDGET (clist));
3149 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
3150 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), "changed");
3154 vadjustment_changed (GtkAdjustment * adjustment,
3159 g_return_if_fail (adjustment != NULL);
3160 g_return_if_fail (data != NULL);
3162 clist = GTK_CLIST (data);
3166 hadjustment_changed (GtkAdjustment * adjustment,
3171 g_return_if_fail (adjustment != NULL);
3172 g_return_if_fail (data != NULL);
3174 clist = GTK_CLIST (data);
3178 check_exposures (GtkCList *clist)
3182 if (!GTK_WIDGET_REALIZED (clist))
3185 /* Make sure graphics expose events are processed before scrolling
3187 while ((event = gdk_event_get_graphics_expose (clist->clist_window)) != NULL)
3189 gtk_widget_event (GTK_WIDGET (clist), event);
3190 if (event->expose.count == 0)
3192 gdk_event_free (event);
3195 gdk_event_free (event);
3200 vadjustment_value_changed (GtkAdjustment * adjustment,
3207 g_return_if_fail (adjustment != NULL);
3208 g_return_if_fail (data != NULL);
3209 g_return_if_fail (GTK_IS_CLIST (data));
3211 clist = GTK_CLIST (data);
3213 if (!GTK_WIDGET_DRAWABLE (clist))
3216 value = adjustment->value;
3218 if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)))
3220 if (value > -clist->voffset)
3223 diff = value + clist->voffset;
3225 /* we have to re-draw the whole screen here... */
3226 if (diff >= clist->clist_window_height)
3228 clist->voffset = -value;
3229 draw_rows (clist, NULL);
3233 if ((diff != 0) && (diff != clist->clist_window_height))
3234 gdk_window_copy_area (clist->clist_window,
3237 clist->clist_window,
3240 clist->clist_window_width,
3241 clist->clist_window_height - diff);
3244 area.y = clist->clist_window_height - diff;
3245 area.width = clist->clist_window_width;
3251 diff = -clist->voffset - value;
3253 /* we have to re-draw the whole screen here... */
3254 if (diff >= clist->clist_window_height)
3256 clist->voffset = -value;
3257 draw_rows (clist, NULL);
3261 if ((diff != 0) && (diff != clist->clist_window_height))
3262 gdk_window_copy_area (clist->clist_window,
3265 clist->clist_window,
3268 clist->clist_window_width,
3269 clist->clist_window_height - diff);
3273 area.width = clist->clist_window_width;
3278 clist->voffset = -value;
3279 if ((diff != 0) && (diff != clist->clist_window_height))
3280 check_exposures (clist);
3283 draw_rows (clist, &area);
3287 hadjustment_value_changed (GtkAdjustment * adjustment,
3292 gint i, diff, value;
3294 g_return_if_fail (adjustment != NULL);
3295 g_return_if_fail (data != NULL);
3296 g_return_if_fail (GTK_IS_CLIST (data));
3298 clist = GTK_CLIST (data);
3300 if (!GTK_WIDGET_DRAWABLE (clist))
3303 value = adjustment->value;
3305 if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)))
3307 /* move the column buttons and resize windows */
3308 for (i = 0; i < clist->columns; i++)
3310 if (clist->column[i].button)
3312 clist->column[i].button->allocation.x -= value + clist->hoffset;
3314 if (clist->column[i].button->window)
3316 gdk_window_move (clist->column[i].button->window,
3317 clist->column[i].button->allocation.x,
3318 clist->column[i].button->allocation.y);
3320 if (clist->column[i].window)
3321 gdk_window_move (clist->column[i].window,
3322 clist->column[i].button->allocation.x +
3323 clist->column[i].button->allocation.width -
3324 (DRAG_WIDTH / 2), 0);
3329 if (value > -clist->hoffset)
3332 diff = value + clist->hoffset;
3334 /* we have to re-draw the whole screen here... */
3335 if (diff >= clist->clist_window_width)
3337 clist->hoffset = -value;
3338 draw_rows (clist, NULL);
3342 if ((diff != 0) && (diff != clist->clist_window_width))
3343 gdk_window_copy_area (clist->clist_window,
3346 clist->clist_window,
3349 clist->clist_window_width - diff,
3350 clist->clist_window_height);
3352 area.x = clist->clist_window_width - diff;
3355 area.height = clist->clist_window_height;
3360 diff = -clist->hoffset - value;
3362 /* we have to re-draw the whole screen here... */
3363 if (diff >= clist->clist_window_width)
3365 clist->hoffset = -value;
3366 draw_rows (clist, NULL);
3370 if ((diff != 0) && (diff != clist->clist_window_width))
3371 gdk_window_copy_area (clist->clist_window,
3374 clist->clist_window,
3377 clist->clist_window_width - diff,
3378 clist->clist_window_height);
3383 area.height = clist->clist_window_height;
3386 clist->hoffset = -value;
3387 if ((diff != 0) && (diff != clist->clist_window_width))
3388 check_exposures (clist);
3391 draw_rows (clist, &area);
3395 * Memory Allocation/Distruction Routines for GtkCList stuctures
3407 static GtkCListColumn *
3408 columns_new (GtkCList * clist)
3411 GtkCListColumn *column;
3413 column = g_new (GtkCListColumn, clist->columns);
3415 for (i = 0; i < clist->columns; i++)
3417 column[i].area.x = 0;
3418 column[i].area.y = 0;
3419 column[i].area.width = 0;
3420 column[i].area.height = 0;
3421 column[i].title = NULL;
3422 column[i].button = NULL;
3423 column[i].window = NULL;
3424 column[i].width = 0;
3425 column[i].width_set = FALSE;
3426 column[i].justification = GTK_JUSTIFY_LEFT;
3433 column_title_new (GtkCList * clist,
3437 if (clist->column[column].title)
3438 g_free (clist->column[column].title);
3440 clist->column[column].title = g_strdup (title);
3444 columns_delete (GtkCList * clist)
3448 for (i = 0; i < clist->columns; i++)
3449 if (clist->column[i].title)
3450 g_free (clist->column[i].title);
3452 g_free (clist->column);
3455 static GtkCListRow *
3456 row_new (GtkCList * clist)
3459 GtkCListRow *clist_row;
3461 clist_row = g_chunk_new (GtkCListRow, clist->row_mem_chunk);
3462 clist_row->cell = g_chunk_new (GtkCell, clist->cell_mem_chunk);
3464 for (i = 0; i < clist->columns; i++)
3466 clist_row->cell[i].type = GTK_CELL_EMPTY;
3467 clist_row->cell[i].vertical = 0;
3468 clist_row->cell[i].horizontal = 0;
3471 clist_row->fg_set = FALSE;
3472 clist_row->bg_set = FALSE;
3473 clist_row->state = GTK_STATE_NORMAL;
3474 clist_row->data = NULL;
3480 row_delete (GtkCList * clist,
3481 GtkCListRow * clist_row)
3485 for (i = 0; i < clist->columns; i++)
3486 cell_empty (clist, clist_row, i);
3488 g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell);
3489 g_mem_chunk_free (clist->row_mem_chunk, clist_row);
3493 cell_empty (GtkCList * clist,
3494 GtkCListRow * clist_row,
3497 switch (clist_row->cell[column].type)
3499 case GTK_CELL_EMPTY:
3503 g_free (GTK_CELL_TEXT (clist_row->cell[column])->text);
3506 case GTK_CELL_PIXMAP:
3507 gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap);
3508 gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask);
3511 case GTK_CELL_PIXTEXT:
3512 g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text);
3513 gdk_pixmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap);
3514 gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask);
3517 case GTK_CELL_WIDGET:
3525 clist_row->cell[column].type = GTK_CELL_EMPTY;
3529 cell_set_text (GtkCList * clist,
3530 GtkCListRow * clist_row,
3534 cell_empty (clist, clist_row, column);
3538 clist_row->cell[column].type = GTK_CELL_TEXT;
3539 GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
3544 cell_set_pixmap (GtkCList * clist,
3545 GtkCListRow * clist_row,
3550 cell_empty (clist, clist_row, column);
3554 clist_row->cell[column].type = GTK_CELL_PIXMAP;
3555 GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
3556 GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask;
3561 cell_set_pixtext (GtkCList * clist,
3562 GtkCListRow * clist_row,
3569 cell_empty (clist, clist_row, column);
3571 if (text && pixmap && mask)
3573 clist_row->cell[column].type = GTK_CELL_PIXTEXT;
3574 GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
3575 GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
3576 GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
3577 GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask;
3581 /* Fill in data after widget is realized and has style */
3584 add_style_data (GtkCList * clist)
3588 widget = GTK_WIDGET(clist);
3590 /* text properties */
3591 if (!GTK_CLIST_ROW_HEIGHT_SET (clist))
3593 clist->row_height = widget->style->font->ascent + widget->style->font->descent + 1;
3594 clist->row_center_offset = widget->style->font->ascent + 1.5;
3599 text_height = clist->row_height - (GTK_WIDGET (clist)->style->font->ascent +
3600 GTK_WIDGET (clist) ->style->font->descent + 1);
3601 clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;