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.
21 #include "../config.h"
24 /* the number rows memchunk expands at a time */
25 #define CLIST_OPTIMUM_SIZE 512
27 /* the width of the column resize windows */
30 /* minimum allowed width of a column */
31 #define COLUMN_MIN_WIDTH 5
33 /* this defigns the base grid spacing */
34 #define CELL_SPACING 1
36 /* added the horizontal space at the beginning and end of a row*/
37 #define COLUMN_INSET 3
39 /* scrollbar spacing class macro */
40 #define SCROLLBAR_SPACING(w) (GTK_CLIST_CLASS (GTK_OBJECT (w)->klass)->scrollbar_spacing)
42 /* gives the top pixel of the given row in context of
43 * the clist's voffset */
44 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
45 (((row) + 1) * CELL_SPACING) + \
48 /* returns the row index from a y pixel location in the
49 * context of the clist's voffset */
50 #define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \
51 ((clist)->row_height + CELL_SPACING))
53 /* gives the left pixel of the given column in context of
54 * the clist's hoffset */
55 #define COLUMN_LEFT_XPIXEL(clist, column) ((clist)->column[(column)].area.x + \
58 /* returns the column index from a x pixel location in the
59 * context of the clist's hoffset */
61 COLUMN_FROM_XPIXEL (GtkCList * clist,
66 for (i = 0; i < clist->columns; i++)
68 cx = clist->column[i].area.x + clist->hoffset;
70 if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
71 x <= (cx + clist->column[i].area.width + COLUMN_INSET))
79 /* returns the top pixel of the given row in the context of
81 #define ROW_TOP(clist, row) (((clist)->row_height + CELL_SPACING) * (row))
83 /* returns the left pixel of the given column in the context of
85 #define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x)
87 /* returns the total height of the list */
88 #define LIST_HEIGHT(clist) (((clist)->row_height * ((clist)->rows)) + \
89 (CELL_SPACING * ((clist)->rows + 1)))
91 /* returns the total width of the list */
92 #define LIST_WIDTH(clist) ((clist)->column[(clist)->columns - 1].area.x + \
93 (clist)->column[(clist)->columns - 1].area.width + \
94 COLUMN_INSET + CELL_SPACING)
113 typedef void (*GtkCListSignal1) (GtkObject * object,
116 GdkEventButton * arg3,
119 typedef void (*GtkCListSignal2) (GtkObject * object,
124 static void sync_selection (GtkCList * clist,
128 /* GtkCList Methods */
129 static void gtk_clist_class_init (GtkCListClass * klass);
130 static void gtk_clist_init (GtkCList * clist);
132 /* GtkObject Methods */
133 static void gtk_clist_destroy (GtkObject * object);
134 static void gtk_clist_finalize (GtkObject * object);
137 /* GtkWidget Methods */
138 static void gtk_clist_realize (GtkWidget * widget);
139 static void gtk_clist_unrealize (GtkWidget * widget);
140 static void gtk_clist_map (GtkWidget * widget);
141 static void gtk_clist_unmap (GtkWidget * widget);
142 static void gtk_clist_draw (GtkWidget * widget,
143 GdkRectangle * area);
144 static gint gtk_clist_expose (GtkWidget * widget,
145 GdkEventExpose * event);
146 static gint gtk_clist_button_press (GtkWidget * widget,
147 GdkEventButton * event);
148 static gint gtk_clist_button_release (GtkWidget * widget,
149 GdkEventButton * event);
150 static gint gtk_clist_motion (GtkWidget * widget,
151 GdkEventMotion * event);
153 static void gtk_clist_size_request (GtkWidget * widget,
154 GtkRequisition * requisition);
155 static void gtk_clist_size_allocate (GtkWidget * widget,
156 GtkAllocation * allocation);
157 static gint get_selection_info (GtkCList * clist,
163 /* GtkContainer Methods */
164 static void gtk_clist_foreach (GtkContainer * container,
165 GtkCallback callback,
166 gpointer callback_data);
169 static void draw_row (GtkCList * clist,
172 GtkCListRow * clist_row);
173 static void draw_rows (GtkCList * clist,
174 GdkRectangle * area);
176 /* Size Allocation */
177 static void size_allocate_title_buttons (GtkCList * clist);
178 static void size_allocate_columns (GtkCList * clist);
181 static void toggle_row (GtkCList * clist,
184 GdkEventButton * event);
185 static void select_row (GtkCList * clist,
188 GdkEventButton * event);
189 static void unselect_row (GtkCList * clist,
192 GdkEventButton * event);
194 static void real_select_row (GtkCList * clist,
197 GdkEventButton * event);
198 static void real_unselect_row (GtkCList * clist,
201 GdkEventButton * event);
204 static void draw_xor_line (GtkCList * clist);
205 static gint new_column_width (GtkCList * clist,
209 static void resize_column (GtkCList * clist,
214 static void column_button_create (GtkCList * clist,
216 static void column_button_clicked (GtkWidget * widget,
220 static void create_scrollbars (GtkCList * clist);
221 static void adjust_scrollbars (GtkCList * clist);
222 static void check_exposures (GtkCList * clist);
223 static void vadjustment_changed (GtkAdjustment * adjustment,
225 static void vadjustment_value_changed (GtkAdjustment * adjustment,
227 static void hadjustment_changed (GtkAdjustment * adjustment,
229 static void hadjustment_value_changed (GtkAdjustment * adjustment,
233 /* Memory Allocation/Distruction Routines */
234 static GtkCListColumn *columns_new (GtkCList * clist);
236 static void column_title_new (GtkCList * clist,
239 static void columns_delete (GtkCList * clist);
241 static GtkCListRow *row_new (GtkCList * clist);
243 static void row_delete (GtkCList * clist,
244 GtkCListRow * clist_row);
245 static void cell_empty (GtkCList * clist,
246 GtkCListRow * clist_row,
248 static void cell_set_text (GtkCList * clist,
249 GtkCListRow * clist_row,
252 static void cell_set_pixmap (GtkCList * clist,
253 GtkCListRow * clist_row,
257 static void cell_set_pixtext (GtkCList * clist,
258 GtkCListRow * clist_row,
266 static void gtk_clist_marshal_signal_1 (GtkObject * object,
270 static void gtk_clist_marshal_signal_2 (GtkObject * object,
275 /* Fill in data after widget is realized and has style */
277 static void add_style_data (GtkCList * clist);
279 static GtkContainerClass *parent_class = NULL;
280 static guint clist_signals[LAST_SIGNAL] = {0};
284 gtk_clist_get_type (void)
286 static GtkType clist_type = 0;
290 GtkTypeInfo clist_info =
294 sizeof (GtkCListClass),
295 (GtkClassInitFunc) gtk_clist_class_init,
296 (GtkObjectInitFunc) gtk_clist_init,
297 (GtkArgSetFunc) NULL,
298 (GtkArgGetFunc) NULL,
301 clist_type = gtk_type_unique (gtk_container_get_type (), &clist_info);
308 gtk_clist_class_init (GtkCListClass * klass)
310 GtkObjectClass *object_class;
311 GtkWidgetClass *widget_class;
312 GtkContainerClass *container_class;
314 object_class = (GtkObjectClass *) klass;
315 widget_class = (GtkWidgetClass *) klass;
316 container_class = (GtkContainerClass *) klass;
318 parent_class = gtk_type_class (gtk_container_get_type ());
320 clist_signals[SELECT_ROW] =
321 gtk_signal_new ("select_row",
324 GTK_SIGNAL_OFFSET (GtkCListClass, select_row),
325 gtk_clist_marshal_signal_1,
326 GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_GDK_EVENT);
327 clist_signals[UNSELECT_ROW] =
328 gtk_signal_new ("unselect_row",
331 GTK_SIGNAL_OFFSET (GtkCListClass, unselect_row),
332 gtk_clist_marshal_signal_1,
333 GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_GDK_EVENT);
334 clist_signals[CLICK_COLUMN] =
335 gtk_signal_new ("click_column",
338 GTK_SIGNAL_OFFSET (GtkCListClass, click_column),
339 gtk_clist_marshal_signal_2,
340 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
342 gtk_object_class_add_signals (object_class, clist_signals, LAST_SIGNAL);
344 object_class->destroy = gtk_clist_destroy;
345 object_class->finalize = gtk_clist_finalize;
347 widget_class->realize = gtk_clist_realize;
348 widget_class->unrealize = gtk_clist_unrealize;
349 widget_class->map = gtk_clist_map;
350 widget_class->unmap = gtk_clist_unmap;
351 widget_class->draw = gtk_clist_draw;
352 widget_class->button_press_event = gtk_clist_button_press;
353 widget_class->button_release_event = gtk_clist_button_release;
354 widget_class->motion_notify_event = gtk_clist_motion;
355 widget_class->expose_event = gtk_clist_expose;
356 widget_class->size_request = gtk_clist_size_request;
357 widget_class->size_allocate = gtk_clist_size_allocate;
359 /* container_class->add = NULL; use the default GtkContainerClass warning */
360 /* container_class->remove = NULL; use the default GtkContainerClass warning */
361 container_class->foreach = gtk_clist_foreach;
363 klass->select_row = real_select_row;
364 klass->unselect_row = real_unselect_row;
365 klass->click_column = NULL;
367 klass->draw_row = draw_row;
369 klass->scrollbar_spacing = 5;
373 gtk_clist_marshal_signal_1 (GtkObject * object,
378 GtkCListSignal1 rfunc;
380 rfunc = (GtkCListSignal1) func;
382 (*rfunc) (object, GTK_VALUE_INT (args[0]),
383 GTK_VALUE_INT (args[1]),
384 GTK_VALUE_POINTER (args[2]),
389 gtk_clist_marshal_signal_2 (GtkObject * object,
394 GtkCListSignal2 rfunc;
396 rfunc = (GtkCListSignal2) func;
398 (*rfunc) (object, GTK_VALUE_INT (args[0]),
403 gtk_clist_init (GtkCList * clist)
407 GTK_WIDGET_UNSET_FLAGS (clist, GTK_NO_WINDOW);
408 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
410 clist->row_mem_chunk = NULL;
411 clist->cell_mem_chunk = NULL;
414 clist->row_center_offset = 0;
415 clist->row_height = 0;
416 clist->row_list = NULL;
417 clist->row_list_end = NULL;
421 clist->title_window = NULL;
422 clist->column_title_area.x = 0;
423 clist->column_title_area.y = 0;
424 clist->column_title_area.width = 1;
425 clist->column_title_area.height = 1;
427 clist->clist_window = NULL;
428 clist->clist_window_width = 1;
429 clist->clist_window_height = 1;
434 clist->shadow_type = GTK_SHADOW_IN;
435 clist->hscrollbar_policy = GTK_POLICY_ALWAYS;
436 clist->vscrollbar_policy = GTK_POLICY_ALWAYS;
438 clist->cursor_drag = NULL;
439 clist->xor_gc = NULL;
444 clist->selection_mode = GTK_SELECTION_SINGLE;
445 clist->selection = NULL;
450 gtk_clist_construct (GtkCList * clist,
456 g_return_if_fail (clist != NULL);
457 g_return_if_fail (GTK_IS_CLIST (clist));
458 g_return_if_fail (GTK_CLIST_CONSTRUCTED (clist) == FALSE);
460 GTK_CLIST_SET_FLAG (clist, CLIST_CONSTRUCTED);
462 /* initalize memory chunks, if this has not been done by any
463 * possibly derived widget
465 if (!clist->row_mem_chunk)
466 clist->row_mem_chunk = g_mem_chunk_new ("clist row mem chunk",
467 sizeof (GtkCListRow),
468 sizeof (GtkCListRow) * CLIST_OPTIMUM_SIZE,
471 if (!clist->cell_mem_chunk)
472 clist->cell_mem_chunk = g_mem_chunk_new ("clist cell mem chunk",
473 sizeof (GtkCell) * columns,
474 sizeof (GtkCell) * columns * CLIST_OPTIMUM_SIZE,
477 /* set number of columns, allocate memory */
478 clist->columns = columns;
479 clist->column = columns_new (clist);
481 /* there needs to be at least one column button
482 * because there is alot of code that will break if it
484 column_button_create (clist, 0);
486 /* create scrollbars */
487 create_scrollbars (clist);
491 GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES);
492 for (i = 0; i < columns; i++)
493 gtk_clist_set_column_title (clist, i, titles[i]);
497 GTK_CLIST_UNSET_FLAG (clist, CLIST_SHOW_TITLES);
502 * GTKCLIST PUBLIC INTERFACE
503 * gtk_clist_new_with_titles
507 gtk_clist_new_with_titles (gint columns,
512 g_return_val_if_fail (titles != NULL, NULL);
514 widget = gtk_type_new (gtk_clist_get_type ());
516 gtk_clist_construct (GTK_CLIST (widget), columns, titles);
522 gtk_clist_new (gint columns)
529 clist = gtk_type_new (gtk_clist_get_type ());
530 gtk_clist_construct (clist, columns, NULL);
531 return GTK_WIDGET (clist);
535 gtk_clist_set_border (GtkCList * clist,
536 GtkShadowType border)
538 g_return_if_fail (clist != NULL);
540 clist->shadow_type = border;
542 if (GTK_WIDGET_VISIBLE (clist))
543 gtk_widget_queue_resize (GTK_WIDGET (clist));
547 gtk_clist_set_selection_mode (GtkCList * clist,
548 GtkSelectionMode mode)
550 g_return_if_fail (clist != NULL);
552 clist->selection_mode = mode;
556 gtk_clist_freeze (GtkCList * clist)
558 g_return_if_fail (clist != NULL);
560 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
564 gtk_clist_thaw (GtkCList * clist)
566 g_return_if_fail (clist != NULL);
568 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
570 adjust_scrollbars (clist);
571 draw_rows (clist, NULL);
575 gtk_clist_column_titles_show (GtkCList * clist)
577 g_return_if_fail (clist != NULL);
579 if (!GTK_CLIST_SHOW_TITLES (clist))
581 GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES);
582 if (clist->title_window)
583 gdk_window_show (clist->title_window);
584 gtk_widget_queue_resize (GTK_WIDGET (clist));
589 gtk_clist_column_titles_hide (GtkCList * clist)
591 g_return_if_fail (clist != NULL);
593 if (GTK_CLIST_SHOW_TITLES (clist))
595 GTK_CLIST_UNSET_FLAG (clist, CLIST_SHOW_TITLES);
596 if (clist->title_window)
597 gdk_window_hide (clist->title_window);
598 gtk_widget_queue_resize (GTK_WIDGET (clist));
603 gtk_clist_column_title_active (GtkCList * clist,
606 g_return_if_fail (clist != NULL);
608 if (column < 0 || column >= clist->columns)
611 if (!GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
612 !GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
614 GTK_WIDGET_SET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS);
615 if (GTK_WIDGET_VISIBLE (clist))
616 gtk_widget_queue_draw (clist->column[column].button);
621 gtk_clist_column_title_passive (GtkCList * clist,
624 g_return_if_fail (clist != NULL);
626 if (column < 0 || column >= clist->columns)
629 if (GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
630 GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
632 GTK_WIDGET_UNSET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS);
633 if (GTK_WIDGET_VISIBLE (clist))
634 gtk_widget_queue_draw (clist->column[column].button);
639 gtk_clist_column_titles_active (GtkCList * clist)
643 g_return_if_fail (clist != NULL);
645 for (i = 0; i < clist->columns; i++)
646 if (clist->column[i].button)
647 gtk_clist_column_title_active (clist, i);
651 gtk_clist_column_titles_passive (GtkCList * clist)
655 g_return_if_fail (clist != NULL);
657 for (i = 0; i < clist->columns; i++)
658 if (clist->column[i].button)
659 gtk_clist_column_title_passive (clist, i);
663 gtk_clist_set_column_title (GtkCList * clist,
668 GtkWidget *old_widget;
669 GtkWidget *alignment = NULL;
672 g_return_if_fail (clist != NULL);
674 if (column < 0 || column >= clist->columns)
677 /* if the column button doesn't currently exist,
678 * it has to be created first */
679 if (!clist->column[column].button)
681 column_button_create (clist, column);
685 column_title_new (clist, column, title);
687 /* remove and destroy the old widget */
688 old_widget = GTK_BUTTON (clist->column[column].button)->child;
690 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
692 /* create new alignment based no column justification */
693 switch (clist->column[column].justification)
695 case GTK_JUSTIFY_LEFT:
696 alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
699 case GTK_JUSTIFY_RIGHT:
700 alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
703 case GTK_JUSTIFY_CENTER:
704 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
707 case GTK_JUSTIFY_FILL:
708 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
712 label = gtk_label_new (clist->column[column].title);
713 gtk_container_add (GTK_CONTAINER (alignment), label);
714 gtk_container_add (GTK_CONTAINER (clist->column[column].button), alignment);
715 gtk_widget_show (label);
716 gtk_widget_show (alignment);
718 /* if this button didn't previously exist, then the
719 * column button positions have to be re-computed */
720 if (GTK_WIDGET_VISIBLE (clist) && new_button)
721 size_allocate_title_buttons (clist);
725 gtk_clist_set_column_widget (GtkCList * clist,
730 GtkWidget *old_widget;
732 g_return_if_fail (clist != NULL);
734 if (column < 0 || column >= clist->columns)
737 /* if the column button doesn't currently exist,
738 * it has to be created first */
739 if (!clist->column[column].button)
741 column_button_create (clist, column);
745 column_title_new (clist, column, NULL);
747 /* remove and destroy the old widget */
748 old_widget = GTK_BUTTON (clist->column[column].button)->child;
750 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
752 /* add and show the widget */
755 gtk_container_add (GTK_CONTAINER (clist->column[column].button), widget);
756 gtk_widget_show (widget);
759 /* if this button didn't previously exist, then the
760 * column button positions have to be re-computed */
761 if (GTK_WIDGET_VISIBLE (clist) && new_button)
762 size_allocate_title_buttons (clist);
766 gtk_clist_set_column_justification (GtkCList * clist,
768 GtkJustification justification)
770 GtkWidget *alignment;
772 g_return_if_fail (clist != NULL);
774 if (column < 0 || column >= clist->columns)
777 clist->column[column].justification = justification;
779 /* change the alinment of the button title if it's not a
781 if (clist->column[column].title)
783 alignment = GTK_BUTTON (clist->column[column].button)->child;
785 switch (clist->column[column].justification)
787 case GTK_JUSTIFY_LEFT:
788 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.0, 0.5, 0.0, 0.0);
791 case GTK_JUSTIFY_RIGHT:
792 gtk_alignment_set (GTK_ALIGNMENT (alignment), 1.0, 0.5, 0.0, 0.0);
795 case GTK_JUSTIFY_CENTER:
796 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
799 case GTK_JUSTIFY_FILL:
800 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
808 if (!GTK_CLIST_FROZEN (clist))
809 draw_rows (clist, NULL);
813 gtk_clist_set_column_width (GtkCList * clist,
817 g_return_if_fail (clist != NULL);
819 if (column < 0 || column >= clist->columns)
822 clist->column[column].width = width;
823 clist->column[column].width_set = TRUE;
825 /* FIXME: this is quite expensive to do if the widget hasn't
826 * been size_allocated yet, and pointless. Should
829 size_allocate_columns (clist);
830 size_allocate_title_buttons (clist);
832 if (!GTK_CLIST_FROZEN (clist))
834 adjust_scrollbars (clist);
835 draw_rows (clist, NULL);
840 gtk_clist_set_row_height (GtkCList * clist,
845 g_return_if_fail (clist != NULL);
848 clist->row_height = height;
852 GTK_CLIST_SET_FLAG (clist, CLIST_ROW_HEIGHT_SET);
854 if (GTK_WIDGET_REALIZED (clist))
856 text_height = height - (GTK_WIDGET (clist)->style->font->ascent +
857 GTK_WIDGET (clist) ->style->font->descent + 1);
858 clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
861 if (!GTK_CLIST_FROZEN (clist))
863 adjust_scrollbars (clist);
864 draw_rows (clist, NULL);
869 gtk_clist_moveto (GtkCList * clist,
877 g_return_if_fail (clist != NULL);
879 if (row < -1 || row >= clist->rows)
881 if (column < -1 || column >= clist->columns)
884 /* adjust vertical scrollbar */
887 x = ROW_TOP (clist, row) - (row_align * (clist->clist_window_height -
888 (clist->row_height + 2 * CELL_SPACING)));
891 GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0;
892 else if (x > LIST_HEIGHT (clist) - clist->clist_window_height)
893 GTK_RANGE (clist->vscrollbar)->adjustment->value = LIST_HEIGHT (clist) -
894 clist->clist_window_height;
896 GTK_RANGE (clist->vscrollbar)->adjustment->value = x;
898 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment),
902 /* adjust horizontal scrollbar */
905 y = COLUMN_LEFT (clist, column) - (col_align * (clist->clist_window_width -
906 clist->column[column].area.width +
907 2 * (CELL_SPACING + COLUMN_INSET)));
910 GTK_RANGE (clist->hscrollbar)->adjustment->value = 0.0;
911 else if (y > LIST_WIDTH (clist) - clist->clist_window_width)
912 GTK_RANGE (clist->hscrollbar)->adjustment->value = LIST_WIDTH (clist) -
913 clist->clist_window_width;
915 GTK_RANGE (clist->hscrollbar)->adjustment->value = y;
917 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment),
923 gtk_clist_get_cell_type (GtkCList * clist,
927 GtkCListRow *clist_row;
929 g_return_val_if_fail (clist != NULL, -1);
931 if (row < 0 || row >= clist->rows)
933 if (column < 0 || column >= clist->columns)
936 clist_row = (g_list_nth (clist->row_list, row))->data;
938 return clist_row->cell[column].type;
942 gtk_clist_set_text (GtkCList * clist,
947 GtkCListRow *clist_row;
949 g_return_if_fail (clist != NULL);
951 if (row < 0 || row >= clist->rows)
953 if (column < 0 || column >= clist->columns)
956 clist_row = (g_list_nth (clist->row_list, row))->data;
958 /* if text is null, then the cell is empty */
960 cell_set_text (clist, clist_row, column, text);
962 cell_empty (clist, clist_row, column);
964 /* redraw the list if it's not frozen */
965 if (!GTK_CLIST_FROZEN (clist))
967 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
968 (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row)
969 (clist, NULL, row, clist_row);
974 gtk_clist_get_text (GtkCList * clist,
979 GtkCListRow *clist_row;
981 g_return_val_if_fail (clist != NULL, 0);
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 if (clist_row->cell[column].type != GTK_CELL_TEXT)
994 *text = GTK_CELL_TEXT (clist_row->cell[column])->text;
1000 gtk_clist_set_pixmap (GtkCList * clist,
1006 GtkCListRow *clist_row;
1008 g_return_if_fail (clist != NULL);
1010 if (row < 0 || row >= clist->rows)
1012 if (column < 0 || column >= clist->columns)
1015 clist_row = (g_list_nth (clist->row_list, row))->data;
1017 gdk_pixmap_ref (pixmap);
1019 if (mask) gdk_pixmap_ref (mask);
1021 cell_set_pixmap (clist, clist_row, column, pixmap, mask);
1023 /* redraw the list if it's not frozen */
1024 if (!GTK_CLIST_FROZEN (clist))
1026 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1027 (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row)
1028 (clist, NULL, row, clist_row);
1033 gtk_clist_get_pixmap (GtkCList * clist,
1036 GdkPixmap ** pixmap,
1039 GtkCListRow *clist_row;
1041 g_return_val_if_fail (clist != NULL, 0);
1043 if (row < 0 || row >= clist->rows)
1045 if (column < 0 || column >= clist->columns)
1048 clist_row = (g_list_nth (clist->row_list, row))->data;
1050 if (clist_row->cell[column].type != GTK_CELL_PIXMAP)
1055 *pixmap = GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap;
1056 /* mask can be NULL */
1057 *mask = GTK_CELL_PIXMAP (clist_row->cell[column])->mask;
1064 gtk_clist_set_pixtext (GtkCList * clist,
1072 GtkCListRow *clist_row;
1074 g_return_if_fail (clist != NULL);
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 gdk_pixmap_ref (pixmap);
1084 if (mask) gdk_pixmap_ref (mask);
1085 cell_set_pixtext (clist, clist_row, column, text, spacing, pixmap, mask);
1087 /* redraw the list if it's not frozen */
1088 if (!GTK_CLIST_FROZEN (clist))
1090 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1091 (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row)
1092 (clist, NULL, row, clist_row);
1097 gtk_clist_get_pixtext (GtkCList * clist,
1102 GdkPixmap ** pixmap,
1105 GtkCListRow *clist_row;
1107 g_return_val_if_fail (clist != NULL, 0);
1109 if (row < 0 || row >= clist->rows)
1111 if (column < 0 || column >= clist->columns)
1114 clist_row = (g_list_nth (clist->row_list, row))->data;
1116 if (clist_row->cell[column].type != GTK_CELL_PIXTEXT)
1120 *text = GTK_CELL_PIXTEXT (clist_row->cell[column])->text;
1122 *spacing = GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing;
1124 *pixmap = GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap;
1126 /* mask can be NULL */
1127 *mask = GTK_CELL_PIXTEXT (clist_row->cell[column])->mask;
1133 gtk_clist_set_foreground (GtkCList * clist,
1137 GtkCListRow *clist_row;
1139 g_return_if_fail (clist != NULL);
1141 if (row < 0 || row >= clist->rows)
1144 clist_row = (g_list_nth (clist->row_list, row))->data;
1148 clist_row->foreground = *color;
1149 clist_row->fg_set = TRUE;
1152 clist_row->fg_set = FALSE;
1154 if (!GTK_CLIST_FROZEN (clist)
1155 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1156 (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row)
1157 (clist, NULL, row, clist_row);
1161 gtk_clist_set_background (GtkCList * clist,
1165 GtkCListRow *clist_row;
1167 g_return_if_fail (clist != NULL);
1169 if (row < 0 || row >= clist->rows)
1172 clist_row = (g_list_nth (clist->row_list, row))->data;
1176 clist_row->background = *color;
1177 clist_row->bg_set = TRUE;
1180 clist_row->bg_set = FALSE;
1182 if (!GTK_CLIST_FROZEN (clist)
1183 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1184 (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row)
1185 (clist, NULL, row, clist_row);
1189 gtk_clist_set_shift (GtkCList * clist,
1195 GtkCListRow *clist_row;
1197 g_return_if_fail (clist != NULL);
1199 if (row < 0 || row >= clist->rows)
1201 if (column < 0 || column >= clist->columns)
1204 clist_row = (g_list_nth (clist->row_list, row))->data;
1206 clist_row->cell[column].vertical = vertical;
1207 clist_row->cell[column].horizontal = horizontal;
1209 if (!GTK_CLIST_FROZEN (clist)
1210 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
1211 (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row)
1212 (clist, NULL, row, clist_row);
1216 gtk_clist_append (GtkCList * clist,
1220 GtkCListRow *clist_row;
1222 g_return_val_if_fail (clist != NULL, -1);
1224 clist_row = row_new (clist);
1227 /* set the text in the row's columns */
1229 for (i = 0; i < clist->columns; i++)
1231 cell_set_text (clist, clist_row, i, text[i]);
1233 /* keeps track of the end of the list so the list
1234 * doesn't have to be traversed every time a item is added */
1235 if (!clist->row_list)
1237 clist->row_list = g_list_append (clist->row_list, clist_row);
1238 clist->row_list_end = clist->row_list;
1240 /* check the selection mode to see if we should select
1241 * the first row automaticly */
1242 switch (clist->selection_mode)
1244 case GTK_SELECTION_BROWSE:
1245 gtk_clist_select_row (clist, 0, -1);
1253 clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
1255 /* redraw the list if it's not frozen */
1256 if (!GTK_CLIST_FROZEN (clist))
1258 adjust_scrollbars (clist);
1260 if (gtk_clist_row_is_visible (clist, clist->rows - 1) != GTK_VISIBILITY_NONE)
1261 draw_rows (clist, NULL);
1264 /* return index of the row */
1265 return clist->rows - 1;
1269 gtk_clist_insert (GtkCList * clist,
1274 GtkCListRow *clist_row;
1276 g_return_if_fail (clist != NULL);
1277 g_return_if_fail (text != NULL);
1279 /* return if out of bounds */
1280 if (row < 0 || row > clist->rows)
1283 if (clist->rows == 0)
1284 gtk_clist_append (clist, text);
1287 /* create the row */
1288 clist_row = row_new (clist);
1290 /* set the text in the row's columns */
1292 for (i = 0; i < clist->columns; i++)
1294 cell_set_text (clist, clist_row, i, text[i]);
1296 /* reset the row end pointer if we're inserting at the
1297 * end of the list */
1298 if (row == clist->rows)
1299 clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
1301 clist->row_list = g_list_insert (clist->row_list, clist_row, row);
1305 /* syncronize the selection list */
1306 sync_selection (clist, row, SYNC_INSERT);
1309 /* redraw the list if it isn't frozen */
1310 if (!GTK_CLIST_FROZEN (clist))
1312 adjust_scrollbars (clist);
1314 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
1315 draw_rows (clist, NULL);
1320 gtk_clist_remove (GtkCList * clist,
1323 gint was_visible, was_selected;
1325 GtkCListRow *clist_row;
1327 g_return_if_fail (clist != NULL);
1329 /* return if out of bounds */
1330 if (row < 0 || row > (clist->rows - 1))
1333 was_visible = (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE);
1336 /* get the row we're going to delete */
1337 list = g_list_nth (clist->row_list, row);
1338 clist_row = list->data;
1340 /* if we're removing a selected row, we have to make sure
1341 * it's properly unselected, and then sync up the clist->selected
1342 * list to reflect the deincrimented indexies of rows after the
1344 if (clist_row->state == GTK_STATE_SELECTED)
1348 switch (clist->selection_mode)
1350 case GTK_SELECTION_SINGLE:
1351 case GTK_SELECTION_BROWSE:
1352 case GTK_SELECTION_MULTIPLE:
1353 gtk_clist_unselect_row (clist, row, -1);
1361 /* reset the row end pointer if we're removing at the
1362 * end of the list */
1363 if (row == clist->rows - 1)
1364 clist->row_list_end = list->prev;
1366 clist->row_list = g_list_remove (clist->row_list, clist_row);
1368 sync_selection (clist, row, SYNC_REMOVE);
1370 /* preform any selections required by the selection mode */
1373 switch (clist->selection_mode)
1375 case GTK_SELECTION_BROWSE:
1376 if (row == clist->rows)
1377 gtk_clist_select_row (clist, row - 1, -1);
1379 gtk_clist_select_row (clist, row, -1);
1388 row_delete (clist, clist_row);
1390 /* redraw the row if it isn't frozen */
1391 if (!GTK_CLIST_FROZEN (clist))
1393 adjust_scrollbars (clist);
1396 draw_rows (clist, NULL);
1401 sync_selection (GtkCList * clist,
1407 list = clist->selection;
1410 if (GPOINTER_TO_INT (list->data) >= row)
1414 list->data = ((gchar*) list->data) + 1;
1418 list->data = ((gchar*) list->data) - 1;
1430 gtk_clist_clear (GtkCList * clist)
1434 g_return_if_fail (clist != NULL);
1436 /* remove all the rows */
1437 for (list = clist->row_list; list; list = list->next)
1439 GtkCListRow *clist_row;
1441 clist_row = list->data;
1442 row_delete (clist, clist_row);
1444 g_list_free (clist->row_list);
1446 /* free up the selection list */
1447 g_list_free (clist->selection);
1449 clist->row_list = NULL;
1450 clist->row_list_end = NULL;
1451 clist->selection = NULL;
1455 /* zero-out the scrollbars */
1456 if (clist->vscrollbar)
1458 GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0;
1459 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
1461 if (!GTK_CLIST_FROZEN (clist))
1463 adjust_scrollbars (clist);
1464 draw_rows (clist, NULL);
1470 gtk_clist_swap_rows (GtkCList * clist,
1475 GList *list, *link1, *link2;
1478 g_return_if_fail (clist != NULL);
1480 if (row1 < 0 || row1 > (clist->rows - 1))
1483 if (row2 < 0 || row2 > (clist->rows - 1))
1486 first = MIN (row1, row2);
1487 last = MAX (row1, row2);
1489 link1 = g_list_nth (clist->row_list, first);
1490 link2 = g_list_nth (link1, row2 - row1);
1493 link1->data = link2->data;
1496 list = clist->selection;
1499 if (GPOINTER_TO_INT (list->data) == row1)
1500 GPOINTER_TO_INT (list->data) = row2;
1502 if (GPOINTER_TO_INT (list->data) == row2)
1503 GPOINTER_TO_INT (list->data) = row1;
1508 if (!GTK_CLIST_FROZEN (clist))
1510 if (gtk_clist_row_is_visible (clist, row1) != GTK_VISIBILITY_NONE)
1511 (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row)
1512 (clist, NULL, row1, (GtkCListRow *) link2->data);
1514 if (gtk_clist_row_is_visible (clist, row2) != GTK_VISIBILITY_NONE)
1515 (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row)
1516 (clist, NULL, row2, (GtkCListRow *) link1->data);
1521 gtk_clist_set_row_data (GtkCList * clist,
1525 gtk_clist_set_row_data_full (clist, row, data, NULL);
1529 gtk_clist_set_row_data_full (GtkCList * clist,
1532 GtkDestroyNotify destroy)
1534 GtkCListRow *clist_row;
1536 g_return_if_fail (clist != NULL);
1538 if (row < 0 || row > (clist->rows - 1))
1541 clist_row = (g_list_nth (clist->row_list, row))->data;
1542 clist_row->data = data;
1543 clist_row->destroy = destroy;
1545 /* re-send the selected signal if data is changed/added
1546 * so the application can respond to the new data --
1547 * this could be questionable behavior */
1548 if (clist_row->state == GTK_STATE_SELECTED)
1549 gtk_clist_select_row (clist, row, -1);
1553 gtk_clist_get_row_data (GtkCList * clist,
1556 GtkCListRow *clist_row;
1558 g_return_val_if_fail (clist != NULL, NULL);
1560 if (row < 0 || row > (clist->rows - 1))
1563 clist_row = (g_list_nth (clist->row_list, row))->data;
1564 return clist_row->data;
1568 gtk_clist_find_row_from_data (GtkCList * clist,
1574 g_return_val_if_fail (clist != NULL, -1);
1575 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1577 if (clist->rows < 1)
1578 return -1; /* is this an optimization or just worthless? */
1581 list = clist->row_list;
1584 GtkCListRow *clist_row;
1586 clist_row = list->data;
1587 if (clist_row->data == data)
1600 gtk_clist_select_row (GtkCList * clist,
1604 g_return_if_fail (clist != NULL);
1606 if (row < 0 || row >= clist->rows)
1609 if (column < -1 || column >= clist->columns)
1612 select_row (clist, row, column, NULL);
1616 gtk_clist_unselect_row (GtkCList * clist,
1620 g_return_if_fail (clist != NULL);
1622 if (row < 0 || row >= clist->rows)
1625 if (column < -1 || column >= clist->columns)
1628 unselect_row (clist, row, column, NULL);
1632 gtk_clist_row_is_visible (GtkCList * clist,
1637 g_return_val_if_fail (clist != NULL, 0);
1639 if (row < 0 || row >= clist->rows)
1640 return GTK_VISIBILITY_NONE;
1642 if (clist->row_height == 0)
1643 return GTK_VISIBILITY_NONE;
1645 if (row < ROW_FROM_YPIXEL (clist, 0))
1646 return GTK_VISIBILITY_NONE;
1648 if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height))
1649 return GTK_VISIBILITY_NONE;
1651 top = ROW_TOP_YPIXEL (clist, row);
1654 || ((top + clist->row_height) >= clist->clist_window_height))
1655 return GTK_VISIBILITY_PARTIAL;
1657 return GTK_VISIBILITY_FULL;
1661 gtk_clist_get_vadjustment (GtkCList * clist)
1663 g_return_val_if_fail (clist != NULL, NULL);
1664 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
1666 return gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
1670 gtk_clist_get_hadjustment (GtkCList * clist)
1672 g_return_val_if_fail (clist != NULL, NULL);
1673 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
1675 return gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
1679 gtk_clist_set_policy (GtkCList * clist,
1680 GtkPolicyType vscrollbar_policy,
1681 GtkPolicyType hscrollbar_policy)
1683 g_return_if_fail (clist != NULL);
1684 g_return_if_fail (GTK_IS_CLIST (clist));
1686 if (clist->vscrollbar_policy != vscrollbar_policy)
1688 clist->vscrollbar_policy = vscrollbar_policy;
1690 if (GTK_WIDGET (clist)->parent)
1691 gtk_widget_queue_resize (GTK_WIDGET (clist));
1694 if (clist->hscrollbar_policy != hscrollbar_policy)
1696 clist->hscrollbar_policy = hscrollbar_policy;
1698 if (GTK_WIDGET (clist)->parent)
1699 gtk_widget_queue_resize (GTK_WIDGET (clist));
1706 * gtk_clist_finalize
1709 gtk_clist_destroy (GtkObject * object)
1714 g_return_if_fail (object != NULL);
1715 g_return_if_fail (GTK_IS_CLIST (object));
1717 clist = GTK_CLIST (object);
1719 /* freeze the list */
1720 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
1722 /* get rid of all the rows */
1723 gtk_clist_clear (clist);
1725 /* Since we don't have a _remove method, unparent the children
1726 * instead of destroying them so the focus will be unset properly.
1727 * (For other containers, the _remove method takes care of the
1728 * unparent) The destroy will happen when the refcount drops
1732 /* destroy the scrollbars */
1733 if (clist->vscrollbar)
1735 gtk_widget_unparent (clist->vscrollbar);
1736 clist->vscrollbar = NULL;
1738 if (clist->hscrollbar)
1740 gtk_widget_unparent (clist->hscrollbar);
1741 clist->hscrollbar = NULL;
1744 /* destroy the column buttons */
1745 for (i = 0; i < clist->columns; i++)
1746 if (clist->column[i].button)
1748 gtk_widget_unparent (clist->column[i].button);
1749 clist->column[i].button = NULL;
1752 if (GTK_OBJECT_CLASS (parent_class)->destroy)
1753 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
1757 gtk_clist_finalize (GtkObject * object)
1761 g_return_if_fail (object != NULL);
1762 g_return_if_fail (GTK_IS_CLIST (object));
1764 clist = GTK_CLIST (object);
1766 columns_delete (clist);
1768 g_mem_chunk_destroy (clist->cell_mem_chunk);
1769 g_mem_chunk_destroy (clist->row_mem_chunk);
1771 if (GTK_OBJECT_CLASS (parent_class)->finalize)
1772 (*GTK_OBJECT_CLASS (parent_class)->finalize) (object);
1778 * gtk_clist_unrealize
1783 * gtk_clist_button_press
1784 * gtk_clist_button_release
1785 * gtk_clist_button_motion
1786 * gtk_clist_size_request
1787 * gtk_clist_size_allocate
1790 gtk_clist_realize (GtkWidget * widget)
1794 GdkWindowAttr attributes;
1795 gint attributes_mask;
1799 g_return_if_fail (widget != NULL);
1800 g_return_if_fail (GTK_IS_CLIST (widget));
1802 clist = GTK_CLIST (widget);
1804 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1806 add_style_data (clist);
1808 border_width = GTK_CONTAINER (widget)->border_width;
1810 attributes.window_type = GDK_WINDOW_CHILD;
1811 attributes.x = widget->allocation.x + border_width;
1812 attributes.y = widget->allocation.y + border_width;
1813 attributes.width = widget->allocation.width - border_width * 2;
1814 attributes.height = widget->allocation.height - border_width * 2;
1815 attributes.wclass = GDK_INPUT_OUTPUT;
1816 attributes.visual = gtk_widget_get_visual (widget);
1817 attributes.colormap = gtk_widget_get_colormap (widget);
1818 attributes.event_mask = gtk_widget_get_events (widget);
1819 attributes.event_mask |= (GDK_EXPOSURE_MASK |
1820 GDK_BUTTON_PRESS_MASK |
1821 GDK_BUTTON_RELEASE_MASK |
1822 GDK_KEY_PRESS_MASK);
1823 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1827 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
1828 gdk_window_set_user_data (widget->window, clist);
1830 widget->style = gtk_style_attach (widget->style, widget->window);
1832 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
1834 /* column-title window */
1836 attributes.x = clist->column_title_area.x;
1837 attributes.y = clist->column_title_area.y;
1838 attributes.width = clist->column_title_area.width;
1839 attributes.height = clist->column_title_area.height;
1841 clist->title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
1842 gdk_window_set_user_data (clist->title_window, clist);
1844 gtk_style_set_background (widget->style, clist->title_window, GTK_STATE_SELECTED);
1845 gdk_window_show (clist->title_window);
1847 /* set things up so column buttons are drawn in title window */
1848 for (i = 0; i < clist->columns; i++)
1849 if (clist->column[i].button)
1850 gtk_widget_set_parent_window (clist->column[i].button, clist->title_window);
1853 attributes.x = clist->internal_allocation.x + widget->style->klass->xthickness;
1854 attributes.y = clist->internal_allocation.y + widget->style->klass->ythickness +
1855 clist->column_title_area.height;
1856 attributes.width = clist->clist_window_width;
1857 attributes.height = clist->clist_window_height;
1859 clist->clist_window = gdk_window_new (widget->window, &attributes, attributes_mask);
1860 gdk_window_set_user_data (clist->clist_window, clist);
1862 gdk_window_set_background (clist->clist_window, &widget->style->bg[GTK_STATE_PRELIGHT]);
1863 gdk_window_show (clist->clist_window);
1864 gdk_window_get_size (clist->clist_window, &clist->clist_window_width,
1865 &clist->clist_window_height);
1867 /* create resize windows */
1868 attributes.wclass = GDK_INPUT_ONLY;
1869 attributes.event_mask = (GDK_BUTTON_PRESS_MASK |
1870 GDK_BUTTON_RELEASE_MASK |
1871 GDK_POINTER_MOTION_MASK |
1872 GDK_POINTER_MOTION_HINT_MASK);
1873 attributes.cursor = clist->cursor_drag = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
1874 attributes_mask = GDK_WA_CURSOR;
1876 for (i = 0; i < clist->columns; i++)
1878 clist->column[i].window = gdk_window_new (clist->title_window, &attributes, attributes_mask);
1879 gdk_window_set_user_data (clist->column[i].window, clist);
1882 /* This is slightly less efficient than creating them with the
1883 * right size to begin with, but easier
1885 size_allocate_title_buttons (clist);
1888 clist->fg_gc = gdk_gc_new (widget->window);
1889 clist->bg_gc = gdk_gc_new (widget->window);
1891 /* We'll use this gc to do scrolling as well */
1892 gdk_gc_set_exposures (clist->fg_gc, TRUE);
1894 values.foreground = widget->style->white;
1895 values.function = GDK_XOR;
1896 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
1897 clist->xor_gc = gdk_gc_new_with_values (widget->window,
1905 gtk_clist_unrealize (GtkWidget * widget)
1910 g_return_if_fail (widget != NULL);
1911 g_return_if_fail (GTK_IS_CLIST (widget));
1913 clist = GTK_CLIST (widget);
1915 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
1917 gdk_cursor_destroy (clist->cursor_drag);
1918 gdk_gc_destroy (clist->xor_gc);
1919 gdk_gc_destroy (clist->fg_gc);
1920 gdk_gc_destroy (clist->bg_gc);
1922 for (i = 0; i < clist->columns; i++)
1923 if (clist->column[i].window)
1925 gdk_window_set_user_data (clist->column[i].window, NULL);
1926 gdk_window_destroy (clist->column[i].window);
1927 clist->column[i].window = NULL;
1930 gdk_window_set_user_data (clist->clist_window, NULL);
1931 gdk_window_destroy (clist->clist_window);
1932 clist->clist_window = NULL;
1934 gdk_window_set_user_data (clist->title_window, NULL);
1935 gdk_window_destroy (clist->title_window);
1936 clist->title_window = NULL;
1938 clist->cursor_drag = NULL;
1939 clist->xor_gc = NULL;
1940 clist->fg_gc = NULL;
1941 clist->bg_gc = NULL;
1943 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1944 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1948 gtk_clist_map (GtkWidget * widget)
1953 g_return_if_fail (widget != NULL);
1954 g_return_if_fail (GTK_IS_CLIST (widget));
1956 clist = GTK_CLIST (widget);
1958 if (!GTK_WIDGET_MAPPED (widget))
1960 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1962 gdk_window_show (widget->window);
1963 gdk_window_show (clist->title_window);
1964 gdk_window_show (clist->clist_window);
1966 /* map column buttons */
1967 for (i = 0; i < clist->columns; i++)
1968 if (clist->column[i].button &&
1969 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
1970 !GTK_WIDGET_MAPPED (clist->column[i].button))
1971 gtk_widget_map (clist->column[i].button);
1973 /* map resize windows AFTER column buttons (above) */
1974 for (i = 0; i < clist->columns; i++)
1975 if (clist->column[i].window && clist->column[i].button)
1976 gdk_window_show (clist->column[i].window);
1978 /* map vscrollbars */
1979 if (GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
1980 !GTK_WIDGET_MAPPED (clist->vscrollbar))
1981 gtk_widget_map (clist->vscrollbar);
1983 if (GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
1984 !GTK_WIDGET_MAPPED (clist->hscrollbar))
1985 gtk_widget_map (clist->hscrollbar);
1987 /* unfreeze the list */
1988 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
1993 gtk_clist_unmap (GtkWidget * widget)
1998 g_return_if_fail (widget != NULL);
1999 g_return_if_fail (GTK_IS_CLIST (widget));
2001 clist = GTK_CLIST (widget);
2003 if (GTK_WIDGET_MAPPED (widget))
2005 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
2007 for (i = 0; i < clist->columns; i++)
2008 if (clist->column[i].window)
2009 gdk_window_hide (clist->column[i].window);
2011 gdk_window_hide (clist->clist_window);
2012 gdk_window_hide (clist->title_window);
2013 gdk_window_hide (widget->window);
2015 /* unmap scrollbars */
2016 if (GTK_WIDGET_MAPPED (clist->vscrollbar))
2017 gtk_widget_unmap (clist->vscrollbar);
2019 if (GTK_WIDGET_MAPPED (clist->hscrollbar))
2020 gtk_widget_unmap (clist->hscrollbar);
2022 /* unmap column buttons */
2023 for (i = 0; i < clist->columns; i++)
2024 if (clist->column[i].button &&
2025 GTK_WIDGET_MAPPED (clist->column[i].button))
2026 gtk_widget_unmap (clist->column[i].button);
2028 /* freeze the list */
2029 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
2034 gtk_clist_draw (GtkWidget * widget,
2035 GdkRectangle * area)
2040 g_return_if_fail (widget != NULL);
2041 g_return_if_fail (GTK_IS_CLIST (widget));
2042 g_return_if_fail (area != NULL);
2044 if (GTK_WIDGET_DRAWABLE (widget))
2046 clist = GTK_CLIST (widget);
2047 border_width = GTK_CONTAINER (widget)->border_width;
2049 gdk_window_clear_area (widget->window,
2050 area->x - border_width,
2051 area->y - border_width,
2052 area->width, area->height);
2054 /* draw list shadow/border */
2055 gtk_draw_shadow (widget->style, widget->window,
2056 GTK_STATE_NORMAL, clist->shadow_type,
2058 clist->clist_window_width + (2 * widget->style->klass->xthickness),
2059 clist->clist_window_height + (2 * widget->style->klass->ythickness) +
2060 clist->column_title_area.height);
2062 gdk_window_clear_area (clist->clist_window,
2065 draw_rows (clist, NULL);
2070 gtk_clist_expose (GtkWidget * widget,
2071 GdkEventExpose * event)
2075 g_return_val_if_fail (widget != NULL, FALSE);
2076 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2077 g_return_val_if_fail (event != NULL, FALSE);
2079 if (GTK_WIDGET_DRAWABLE (widget))
2081 clist = GTK_CLIST (widget);
2084 if (event->window == widget->window)
2085 gtk_draw_shadow (widget->style, widget->window,
2086 GTK_STATE_NORMAL, clist->shadow_type,
2088 clist->clist_window_width + (2 * widget->style->klass->xthickness),
2089 clist->clist_window_height + (2 * widget->style->klass->ythickness) +
2090 clist->column_title_area.height);
2092 /* exposure events on the list */
2093 if (event->window == clist->clist_window)
2094 draw_rows (clist, &event->area);
2101 gtk_clist_button_press (GtkWidget * widget,
2102 GdkEventButton * event)
2106 gint x, y, row, column;
2108 g_return_val_if_fail (widget != NULL, FALSE);
2109 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2110 g_return_val_if_fail (event != NULL, FALSE);
2112 clist = GTK_CLIST (widget);
2114 /* selections on the list */
2115 if (event->window == clist->clist_window)
2120 if (get_selection_info (clist, x, y, &row, &column))
2121 toggle_row (clist, row, column, event);
2126 /* press on resize windows */
2127 for (i = 0; i < clist->columns; i++)
2128 if (clist->column[i].window && event->window == clist->column[i].window)
2130 GTK_CLIST_SET_FLAG (clist, CLIST_IN_DRAG);
2131 gtk_widget_get_pointer (widget, &clist->x_drag, NULL);
2133 gdk_pointer_grab (clist->column[i].window, FALSE,
2134 GDK_POINTER_MOTION_HINT_MASK |
2135 GDK_BUTTON1_MOTION_MASK |
2136 GDK_BUTTON_RELEASE_MASK,
2137 NULL, NULL, event->time);
2139 draw_xor_line (clist);
2147 gtk_clist_button_release (GtkWidget * widget,
2148 GdkEventButton * event)
2150 gint i, x, width, visible;
2153 g_return_val_if_fail (widget != NULL, FALSE);
2154 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2155 g_return_val_if_fail (event != NULL, FALSE);
2157 clist = GTK_CLIST (widget);
2159 /* release on resize windows */
2160 if (GTK_CLIST_IN_DRAG (clist))
2161 for (i = 0; i < clist->columns; i++)
2162 if (clist->column[i].window && event->window == clist->column[i].window)
2164 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
2165 gtk_widget_get_pointer (widget, &x, NULL);
2166 width = new_column_width (clist, i, &x, &visible);
2167 gdk_pointer_ungrab (event->time);
2170 draw_xor_line (clist);
2172 resize_column (clist, i, width);
2180 gtk_clist_motion (GtkWidget * widget,
2181 GdkEventMotion * event)
2186 g_return_val_if_fail (widget != NULL, FALSE);
2187 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2189 clist = GTK_CLIST (widget);
2191 if (GTK_CLIST_IN_DRAG (clist))
2192 for (i = 0; i < clist->columns; i++)
2193 if (clist->column[i].window && event->window == clist->column[i].window)
2195 if (event->is_hint || event->window != widget->window)
2196 gtk_widget_get_pointer (widget, &x, NULL);
2200 new_column_width (clist, i, &x, &visible);
2201 /* Welcome to my hack! I'm going to use a value of x_drage = -99999 to
2202 * indicate the the xor line is already no visible */
2203 if (!visible && clist->x_drag != -99999)
2205 draw_xor_line (clist);
2206 clist->x_drag = -99999;
2209 if (x != clist->x_drag && visible)
2211 if (clist->x_drag != -99999)
2212 draw_xor_line (clist);
2215 draw_xor_line (clist);
2223 gtk_clist_size_request (GtkWidget * widget,
2224 GtkRequisition * requisition)
2229 g_return_if_fail (widget != NULL);
2230 g_return_if_fail (GTK_IS_CLIST (widget));
2231 g_return_if_fail (requisition != NULL);
2233 clist = GTK_CLIST (widget);
2235 add_style_data (clist);
2237 requisition->width = 0;
2238 requisition->height = 0;
2240 /* compute the size of the column title (title) area */
2241 clist->column_title_area.height = 0;
2242 if (GTK_CLIST_SHOW_TITLES (clist))
2243 for (i = 0; i < clist->columns; i++)
2244 if (clist->column[i].button)
2246 gtk_widget_size_request (clist->column[i].button, &clist->column[i].button->requisition);
2247 clist->column_title_area.height = MAX (clist->column_title_area.height,
2248 clist->column[i].button->requisition.height);
2250 requisition->height += clist->column_title_area.height;
2252 /* add the vscrollbar space */
2253 if ((clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
2254 GTK_WIDGET_VISIBLE (clist->vscrollbar))
2256 gtk_widget_size_request (clist->vscrollbar, &clist->vscrollbar->requisition);
2258 requisition->width += clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist);
2259 requisition->height = MAX (requisition->height,
2260 clist->vscrollbar->requisition.height);
2263 /* add the hscrollbar space */
2264 if ((clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
2265 GTK_WIDGET_VISIBLE (clist->hscrollbar))
2267 gtk_widget_size_request (clist->hscrollbar, &clist->hscrollbar->requisition);
2269 requisition->height += clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist);
2270 requisition->width = MAX (clist->hscrollbar->requisition.width,
2271 requisition->width -
2272 clist->vscrollbar->requisition.width);
2276 requisition->width += widget->style->klass->xthickness * 2 +
2277 GTK_CONTAINER (widget)->border_width * 2;
2278 requisition->height += widget->style->klass->ythickness * 2 +
2279 GTK_CONTAINER (widget)->border_width * 2;
2283 gtk_clist_size_allocate (GtkWidget * widget,
2284 GtkAllocation * allocation)
2287 GtkAllocation clist_allocation;
2288 GtkAllocation child_allocation;
2289 gint i, vscrollbar_vis, hscrollbar_vis;
2291 g_return_if_fail (widget != NULL);
2292 g_return_if_fail (GTK_IS_CLIST (widget));
2293 g_return_if_fail (allocation != NULL);
2295 clist = GTK_CLIST (widget);
2296 widget->allocation = *allocation;
2298 if (GTK_WIDGET_REALIZED (widget))
2300 gdk_window_move_resize (widget->window,
2301 allocation->x + GTK_CONTAINER (widget)->border_width,
2302 allocation->y + GTK_CONTAINER (widget)->border_width,
2303 allocation->width - GTK_CONTAINER (widget)->border_width * 2,
2304 allocation->height - GTK_CONTAINER (widget)->border_width * 2);
2307 /* use internal allocation structure for all the math
2308 * because it's easier than always subtracting the container
2310 clist->internal_allocation.x = 0;
2311 clist->internal_allocation.y = 0;
2312 clist->internal_allocation.width = MAX (1, allocation->width -
2313 GTK_CONTAINER (widget)->border_width * 2);
2314 clist->internal_allocation.height = MAX (1, allocation->height -
2315 GTK_CONTAINER (widget)->border_width * 2);
2317 /* allocate clist window assuming no scrollbars */
2318 clist_allocation.x = clist->internal_allocation.x + widget->style->klass->xthickness;
2319 clist_allocation.y = clist->internal_allocation.y + widget->style->klass->ythickness +
2320 clist->column_title_area.height;
2321 clist_allocation.width = MAX (1, clist->internal_allocation.width -
2322 (2 * widget->style->klass->xthickness));
2323 clist_allocation.height = MAX (1, clist->internal_allocation.height -
2324 (2 * widget->style->klass->ythickness) -
2325 clist->column_title_area.height);
2328 * here's where we decide to show/not show the scrollbars
2333 for (i = 0; i <= 1; i++)
2335 if (LIST_HEIGHT (clist) <= clist_allocation.height &&
2336 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
2342 if (!vscrollbar_vis)
2345 clist_allocation.width = MAX (1, clist_allocation.width -
2346 (clist->vscrollbar->requisition.width +
2347 SCROLLBAR_SPACING (clist)));
2351 if (LIST_WIDTH (clist) <= clist_allocation.width &&
2352 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
2358 if (!hscrollbar_vis)
2361 clist_allocation.height = MAX (1, clist_allocation.height -
2362 (clist->hscrollbar->requisition.height +
2363 SCROLLBAR_SPACING (clist)));
2368 clist->clist_window_width = clist_allocation.width;
2369 clist->clist_window_height = clist_allocation.height;
2371 if (GTK_WIDGET_REALIZED (widget))
2373 gdk_window_move_resize (clist->clist_window,
2376 clist_allocation.width,
2377 clist_allocation.height);
2380 /* position the window which holds the column title buttons */
2381 clist->column_title_area.x = widget->style->klass->xthickness;
2382 clist->column_title_area.y = widget->style->klass->ythickness;
2383 clist->column_title_area.width = clist_allocation.width;
2385 if (GTK_WIDGET_REALIZED (widget))
2387 gdk_window_move_resize (clist->title_window,
2388 clist->column_title_area.x,
2389 clist->column_title_area.y,
2390 clist->column_title_area.width,
2391 clist->column_title_area.height);
2394 /* column button allocation */
2395 size_allocate_columns (clist);
2397 if (GTK_WIDGET_REALIZED (widget))
2398 size_allocate_title_buttons (clist);
2400 adjust_scrollbars (clist);
2402 /* allocate the vscrollbar */
2405 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
2406 gtk_widget_show (clist->vscrollbar);
2408 child_allocation.x = clist->internal_allocation.x +
2409 clist->internal_allocation.width -
2410 clist->vscrollbar->requisition.width;
2411 child_allocation.y = clist->internal_allocation.y;
2412 child_allocation.width = clist->vscrollbar->requisition.width;
2413 child_allocation.height = MAX (1, clist->internal_allocation.height -
2414 (hscrollbar_vis ? (clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist)) : 0));
2416 gtk_widget_size_allocate (clist->vscrollbar, &child_allocation);
2420 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
2421 gtk_widget_hide (clist->vscrollbar);
2426 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
2427 gtk_widget_show (clist->hscrollbar);
2429 child_allocation.x = clist->internal_allocation.x;
2430 child_allocation.y = clist->internal_allocation.y +
2431 clist->internal_allocation.height -
2432 clist->hscrollbar->requisition.height;
2433 child_allocation.width = MAX (1, clist->internal_allocation.width -
2434 (vscrollbar_vis ? (clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist)) : 0));
2435 child_allocation.height = clist->hscrollbar->requisition.height;
2437 gtk_widget_size_allocate (clist->hscrollbar, &child_allocation);
2441 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
2442 gtk_widget_hide (clist->hscrollbar);
2445 /* set the vscrollbar adjustments */
2446 adjust_scrollbars (clist);
2454 gtk_clist_foreach (GtkContainer * container,
2455 GtkCallback callback,
2456 gpointer callback_data)
2461 g_return_if_fail (container != NULL);
2462 g_return_if_fail (GTK_IS_CLIST (container));
2463 g_return_if_fail (callback != NULL);
2465 clist = GTK_CLIST (container);
2467 /* callback for the column buttons */
2468 for (i = 0; i < clist->columns; i++)
2469 if (clist->column[i].button)
2470 (*callback) (clist->column[i].button, callback_data);
2472 /* callbacks for the scrollbars */
2473 if (clist->vscrollbar)
2474 (*callback) (clist->vscrollbar, callback_data);
2475 if (clist->hscrollbar)
2476 (*callback) (clist->hscrollbar, callback_data);
2485 draw_row (GtkCList * clist,
2486 GdkRectangle * area,
2488 GtkCListRow * clist_row)
2491 GdkGC *fg_gc, *bg_gc;
2492 GdkRectangle row_rectangle, cell_rectangle, clip_rectangle, intersect_rectangle,
2494 gint i, offset = 0, width, height, pixmap_width = 0;
2495 gint xsrc, ysrc, xdest, ydest;
2497 g_return_if_fail (clist != NULL);
2499 /* bail now if we arn't drawable yet */
2500 if (!GTK_WIDGET_DRAWABLE (clist))
2503 if (row < 0 || row >= clist->rows)
2506 widget = GTK_WIDGET (clist);
2508 /* if the function is passed the pointer to the row instead of null,
2509 * it avoids this expensive lookup */
2511 clist_row = (g_list_nth (clist->row_list, row))->data;
2513 /* rectangle of the entire row */
2514 row_rectangle.x = 0;
2515 row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
2516 row_rectangle.width = clist->clist_window_width;
2517 row_rectangle.height = clist->row_height;
2519 /* rectangle of the cell spacing above the row */
2520 cell_rectangle.x = 0;
2521 cell_rectangle.y = row_rectangle.y - CELL_SPACING;
2522 cell_rectangle.width = row_rectangle.width;
2523 cell_rectangle.height = CELL_SPACING;
2525 /* rectangle used to clip drawing operations, it's y and height
2526 * positions only need to be set once, so we set them once here.
2527 * the x and width are set withing the drawing loop below once per
2529 clip_rectangle.y = row_rectangle.y;
2530 clip_rectangle.height = row_rectangle.height;
2532 /* select GC for background rectangle */
2533 if (clist_row->state == GTK_STATE_SELECTED)
2535 fg_gc = widget->style->fg_gc[GTK_STATE_SELECTED];
2536 bg_gc = widget->style->bg_gc[GTK_STATE_SELECTED];
2540 if (clist_row->fg_set)
2542 gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
2543 fg_gc = clist->fg_gc;
2546 fg_gc = widget->style->fg_gc[GTK_STATE_NORMAL];
2548 if (clist_row->bg_set)
2550 gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
2551 bg_gc = clist->bg_gc;
2554 bg_gc = widget->style->bg_gc[GTK_STATE_PRELIGHT];
2557 /* draw the cell borders and background */
2560 if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
2561 gdk_draw_rectangle (clist->clist_window,
2562 widget->style->base_gc[GTK_STATE_NORMAL],
2564 intersect_rectangle.x,
2565 intersect_rectangle.y,
2566 intersect_rectangle.width,
2567 intersect_rectangle.height);
2569 /* the last row has to clear it's bottom cell spacing too */
2570 if (clist_row == clist->row_list_end->data)
2572 cell_rectangle.y += clist->row_height + CELL_SPACING;
2574 if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
2575 gdk_draw_rectangle (clist->clist_window,
2576 widget->style->base_gc[GTK_STATE_NORMAL],
2578 intersect_rectangle.x,
2579 intersect_rectangle.y,
2580 intersect_rectangle.width,
2581 intersect_rectangle.height);
2584 if (!gdk_rectangle_intersect (area, &row_rectangle, &intersect_rectangle))
2587 if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
2588 gdk_draw_rectangle (clist->clist_window,
2591 intersect_rectangle.x,
2592 intersect_rectangle.y,
2593 intersect_rectangle.width,
2594 intersect_rectangle.height);
2596 gdk_window_clear_area (clist->clist_window,
2597 intersect_rectangle.x,
2598 intersect_rectangle.y,
2599 intersect_rectangle.width,
2600 intersect_rectangle.height);
2604 gdk_draw_rectangle (clist->clist_window,
2605 widget->style->base_gc[GTK_STATE_NORMAL],
2609 cell_rectangle.width,
2610 cell_rectangle.height);
2612 /* the last row has to clear it's bottom cell spacing too */
2613 if (clist_row == clist->row_list_end->data)
2615 cell_rectangle.y += clist->row_height + CELL_SPACING;
2617 gdk_draw_rectangle (clist->clist_window,
2618 widget->style->base_gc[GTK_STATE_NORMAL],
2622 cell_rectangle.width,
2623 cell_rectangle.height);
2626 if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
2627 gdk_draw_rectangle (clist->clist_window,
2632 row_rectangle.width,
2633 row_rectangle.height);
2635 gdk_window_clear_area (clist->clist_window,
2638 row_rectangle.width,
2639 row_rectangle.height);
2642 /* iterate and draw all the columns (row cells) and draw their contents */
2643 for (i = 0; i < clist->columns; i++)
2645 clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
2646 clip_rectangle.width = clist->column[i].area.width;
2648 /* calculate clipping region clipping region */
2651 rect = &clip_rectangle;
2655 if (!gdk_rectangle_intersect (area, &clip_rectangle,
2656 &intersect_rectangle))
2658 rect = &intersect_rectangle;
2661 /* calculate real width for column justification */
2662 switch (clist_row->cell[i].type)
2664 case GTK_CELL_EMPTY:
2669 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
2670 GTK_CELL_TEXT (clist_row->cell[i])->text);
2673 case GTK_CELL_PIXMAP:
2674 gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, &width, &height);
2675 pixmap_width = width;
2678 case GTK_CELL_PIXTEXT:
2679 gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, &width, &height);
2680 pixmap_width = width;
2681 width += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
2682 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
2683 GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
2686 case GTK_CELL_WIDGET:
2696 switch (clist->column[i].justification)
2698 case GTK_JUSTIFY_LEFT:
2699 offset = clip_rectangle.x;
2702 case GTK_JUSTIFY_RIGHT:
2703 offset = (clip_rectangle.x + clip_rectangle.width) - width;
2706 case GTK_JUSTIFY_CENTER:
2707 offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
2710 case GTK_JUSTIFY_FILL:
2711 offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
2719 /* Draw Text or Pixmap */
2720 switch (clist_row->cell[i].type)
2722 case GTK_CELL_EMPTY:
2727 gdk_gc_set_clip_rectangle (fg_gc, rect);
2729 gdk_draw_string (clist->clist_window,
2730 widget->style->font,
2732 offset + clist_row->cell[i].horizontal,
2733 row_rectangle.y + clist->row_center_offset +
2734 clist_row->cell[i].vertical,
2735 GTK_CELL_TEXT (clist_row->cell[i])->text);
2737 gdk_gc_set_clip_rectangle (fg_gc, NULL);
2740 case GTK_CELL_PIXMAP:
2743 xdest = offset + clist_row->cell[i].horizontal;
2744 ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
2745 clist_row->cell[i].vertical;
2747 if (xdest < clip_rectangle.x)
2749 xsrc = clip_rectangle.x - xdest;
2750 pixmap_width -= xsrc;
2751 xdest = clip_rectangle.x;
2754 if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width)
2755 pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest;
2757 if (ydest < clip_rectangle.y)
2759 ysrc = clip_rectangle.y - ydest;
2761 ydest = clip_rectangle.y;
2764 if (ydest + height > clip_rectangle.y + clip_rectangle.height)
2765 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
2767 if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
2769 gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXMAP (clist_row->cell[i])->mask);
2770 gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
2772 gdk_draw_pixmap (clist->clist_window,
2774 GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
2777 pixmap_width, height);
2779 if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
2781 gdk_gc_set_clip_origin (fg_gc, 0, 0);
2782 gdk_gc_set_clip_mask (fg_gc, NULL);
2786 case GTK_CELL_PIXTEXT:
2787 /* draw the pixmap */
2790 xdest = offset + clist_row->cell[i].horizontal;
2791 ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
2792 clist_row->cell[i].vertical;
2794 if (xdest < clip_rectangle.x)
2796 xsrc = clip_rectangle.x - xdest;
2797 pixmap_width -= xsrc;
2798 xdest = clip_rectangle.x;
2801 if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width)
2802 pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest;
2804 if (ydest < clip_rectangle.y)
2806 ysrc = clip_rectangle.y - ydest;
2808 ydest = clip_rectangle.y;
2811 if (ydest + height > clip_rectangle.y + clip_rectangle.height)
2812 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
2814 if (GTK_CELL_PIXTEXT (clist_row->cell[i])->mask)
2816 gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXTEXT (clist_row->cell[i])->mask);
2817 gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
2820 gdk_draw_pixmap (clist->clist_window,
2822 GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
2826 pixmap_width, height);
2828 gdk_gc_set_clip_origin (fg_gc, 0, 0);
2830 offset += pixmap_width + GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
2832 /* draw the string */
2833 gdk_gc_set_clip_rectangle (fg_gc, rect);
2835 gdk_draw_string (clist->clist_window,
2836 widget->style->font,
2838 offset + clist_row->cell[i].horizontal,
2839 row_rectangle.y + clist->row_center_offset +
2840 clist_row->cell[i].vertical,
2841 GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
2843 gdk_gc_set_clip_rectangle (fg_gc, NULL);
2846 case GTK_CELL_WIDGET:
2859 draw_rows (GtkCList * clist,
2860 GdkRectangle * area)
2863 GtkCListRow *clist_row;
2864 int i, first_row, last_row;
2866 g_return_if_fail (clist != NULL);
2867 g_return_if_fail (GTK_IS_CLIST (clist));
2869 if (clist->row_height == 0 ||
2870 !GTK_WIDGET_DRAWABLE (clist))
2875 first_row = ROW_FROM_YPIXEL (clist, area->y);
2876 last_row = ROW_FROM_YPIXEL (clist, area->y + area->height);
2880 first_row = ROW_FROM_YPIXEL (clist, 0);
2881 last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height);
2884 /* this is a small special case which exposes the bottom cell line
2885 * on the last row -- it might go away if I change the wall the cell spacings
2887 if (clist->rows == first_row)
2890 list = g_list_nth (clist->row_list, first_row);
2894 clist_row = list->data;
2900 (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row)
2901 (clist, area, i, clist_row);
2906 gdk_window_clear_area (clist->clist_window, 0, ROW_TOP_YPIXEL (clist, i), -1, -1);
2911 * size_allocate_title_buttons
2912 * size_allocate_columns
2915 size_allocate_title_buttons (GtkCList * clist)
2917 gint i, last_button = 0;
2918 GtkAllocation button_allocation;
2920 if (!GTK_WIDGET_REALIZED (clist))
2923 button_allocation.x = clist->hoffset;
2924 button_allocation.y = 0;
2925 button_allocation.width = 0;
2926 button_allocation.height = clist->column_title_area.height;
2928 for (i = 0; i < clist->columns; i++)
2930 button_allocation.width += clist->column[i].area.width;
2932 if (i == clist->columns - 1)
2933 button_allocation.width += 2 * (CELL_SPACING + COLUMN_INSET);
2935 button_allocation.width += CELL_SPACING + (2 * COLUMN_INSET);
2937 if (i == (clist->columns - 1) || clist->column[i + 1].button)
2939 gtk_widget_size_allocate (clist->column[last_button].button, &button_allocation);
2940 button_allocation.x += button_allocation.width;
2941 button_allocation.width = 0;
2943 gdk_window_show (clist->column[last_button].window);
2944 gdk_window_move_resize (clist->column[last_button].window,
2945 button_allocation.x - (DRAG_WIDTH / 2),
2946 0, DRAG_WIDTH, clist->column_title_area.height);
2948 last_button = i + 1;
2952 gdk_window_hide (clist->column[i].window);
2958 size_allocate_columns (GtkCList * clist)
2960 gint i, xoffset = 0;
2962 for (i = 0; i < clist->columns; i++)
2964 clist->column[i].area.x = xoffset + CELL_SPACING + COLUMN_INSET;
2966 if (i == clist->columns - 1)
2970 if (clist->column[i].width_set)
2972 width = clist->column[i].width;
2976 if (clist->column[i].title)
2977 width = gdk_string_width (GTK_WIDGET (clist)->style->font,
2978 clist->column[i].title);
2983 clist->column[i].area.width = MAX (width,
2984 clist->clist_window_width -
2985 xoffset - (2 * (CELL_SPACING + COLUMN_INSET)));
2990 clist->column[i].area.width = clist->column[i].width;
2993 xoffset += clist->column[i].area.width + CELL_SPACING + (2 * COLUMN_INSET);
3002 * get_selection_info
3005 toggle_row (GtkCList * clist,
3008 GdkEventButton * event)
3012 GtkCListRow *clist_row, *selected_row;
3015 list = clist->row_list;
3016 selected_row = NULL;
3018 switch (clist->selection_mode)
3020 case GTK_SELECTION_SINGLE:
3023 clist_row = list->data;
3027 selected_row = clist_row;
3028 else if (clist_row->state == GTK_STATE_SELECTED)
3029 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3035 if (selected_row && selected_row->state == GTK_STATE_SELECTED)
3036 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3037 row, column, event);
3039 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
3040 row, column, event);
3044 case GTK_SELECTION_BROWSE:
3047 clist_row = list->data;
3050 if (i != row && clist_row->state == GTK_STATE_SELECTED)
3051 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3056 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
3057 row, column, event);
3061 case GTK_SELECTION_MULTIPLE:
3062 clist_row = (g_list_nth (clist->row_list, row))->data;
3064 if (clist_row->state == GTK_STATE_SELECTED)
3065 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3066 row, column, event);
3068 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
3069 row, column, event);
3073 case GTK_SELECTION_EXTENDED:
3082 select_row (GtkCList * clist,
3085 GdkEventButton * event)
3089 GtkCListRow *clist_row;
3091 switch (clist->selection_mode)
3093 case GTK_SELECTION_SINGLE:
3094 case GTK_SELECTION_BROWSE:
3096 list = clist->row_list;
3099 clist_row = list->data;
3102 if (row != i && clist_row->state == GTK_STATE_SELECTED)
3103 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3109 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
3110 row, column, event);
3113 case GTK_SELECTION_MULTIPLE:
3114 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
3115 row, column, event);
3119 case GTK_SELECTION_EXTENDED:
3128 unselect_row (GtkCList * clist,
3131 GdkEventButton * event)
3133 switch (clist->selection_mode)
3135 case GTK_SELECTION_SINGLE:
3136 case GTK_SELECTION_BROWSE:
3137 case GTK_SELECTION_MULTIPLE:
3138 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3139 row, column, event);
3142 case GTK_SELECTION_EXTENDED:
3151 real_select_row (GtkCList * clist,
3154 GdkEventButton * event)
3156 GtkCListRow *clist_row;
3158 g_return_if_fail (clist != NULL);
3160 if (row < 0 || row > (clist->rows - 1))
3163 clist_row = (g_list_nth (clist->row_list, row))->data;
3165 if (clist_row->state == GTK_STATE_NORMAL)
3167 clist_row->state = GTK_STATE_SELECTED;
3168 clist->selection = g_list_append (clist->selection, GINT_TO_POINTER (row));
3170 if (!GTK_CLIST_FROZEN (clist)
3171 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
3172 (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row)
3173 (clist, NULL, row, clist_row);
3178 real_unselect_row (GtkCList * clist,
3181 GdkEventButton * event)
3183 GtkCListRow *clist_row;
3185 g_return_if_fail (clist != NULL);
3187 if (row < 0 || row > (clist->rows - 1))
3190 clist_row = (g_list_nth (clist->row_list, row))->data;
3192 if (clist_row->state == GTK_STATE_SELECTED)
3194 clist_row->state = GTK_STATE_NORMAL;
3195 clist->selection = g_list_remove (clist->selection, GINT_TO_POINTER (row));
3197 if (!GTK_CLIST_FROZEN (clist)
3198 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
3199 (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row)
3200 (clist, NULL, row, clist_row);
3205 get_selection_info (GtkCList * clist,
3213 g_return_val_if_fail (clist != NULL, 0);
3215 /* bounds checking, return false if the user clicked
3216 * on a blank area */
3217 trow = ROW_FROM_YPIXEL (clist, y);
3218 if (trow >= clist->rows)
3224 tcol = COLUMN_FROM_XPIXEL (clist, x);
3225 if (tcol >= clist->columns)
3235 gtk_clist_get_selection_info (GtkCList *clist,
3241 g_return_val_if_fail (clist != NULL, 0);
3242 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
3243 return get_selection_info (clist, x, y, row, column);
3253 draw_xor_line (GtkCList * clist)
3257 g_return_if_fail (clist != NULL);
3259 widget = GTK_WIDGET (clist);
3261 gdk_draw_line (widget->window, clist->xor_gc,
3263 widget->style->klass->ythickness,
3265 clist->column_title_area.height + clist->clist_window_height + 1);
3268 /* this function returns the new width of the column being resized given
3269 * the column and x position of the cursor; the x cursor position is passed
3270 * in as a pointer and automagicly corrected if it's beyond min/max limits */
3272 new_column_width (GtkCList * clist,
3281 /* first translate the x position from widget->window
3282 * to clist->clist_window */
3283 cx -= GTK_WIDGET (clist)->style->klass->xthickness;
3285 /* rx is x from the list beginning */
3286 rx = cx - clist->hoffset;
3288 /* you can't shrink a column to less than its minimum width */
3289 if (cx < (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH))
3291 *x = cx = COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH +
3292 GTK_WIDGET (clist)->style->klass->xthickness;
3293 cx -= GTK_WIDGET (clist)->style->klass->xthickness;
3294 rx = cx - clist->hoffset;
3297 if (cx > clist->clist_window_width)
3302 /* calculate new column width making sure it doesn't end up
3303 * less than the minimum width */
3304 width = (rx - COLUMN_LEFT (clist, column)) - COLUMN_INSET -
3305 ((clist->columns == (column - 1)) ? CELL_SPACING : 0);
3306 if (width < COLUMN_MIN_WIDTH)
3307 width = COLUMN_MIN_WIDTH;
3312 /* this will do more later */
3314 resize_column (GtkCList * clist,
3318 gtk_clist_set_column_width (clist, column, width);
3323 column_button_create (GtkCList * clist,
3328 button = clist->column[column].button = gtk_button_new ();
3329 gtk_widget_set_parent (button, GTK_WIDGET (clist));
3330 if (GTK_WIDGET_REALIZED (clist) && clist->title_window)
3331 gtk_widget_set_parent_window (clist->column[column].button, clist->title_window);
3333 gtk_signal_connect (GTK_OBJECT (button),
3335 (GtkSignalFunc) column_button_clicked,
3338 gtk_widget_show (button);
3342 column_button_clicked (GtkWidget * widget,
3348 g_return_if_fail (widget != NULL);
3349 g_return_if_fail (GTK_IS_CLIST (data));
3351 clist = GTK_CLIST (data);
3353 /* find the column who's button was pressed */
3354 for (i = 0; i < clist->columns; i++)
3355 if (clist->column[i].button == widget)
3358 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i);
3367 * vadjustment_changed
3368 * hadjustment_changed
3369 * vadjustment_value_changed
3370 * hadjustment_value_changed
3373 create_scrollbars (GtkCList * clist)
3375 GtkAdjustment *adjustment;
3377 clist->vscrollbar = gtk_vscrollbar_new (NULL);
3378 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
3380 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
3381 (GtkSignalFunc) vadjustment_changed,
3384 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
3385 (GtkSignalFunc) vadjustment_value_changed,
3388 gtk_widget_set_parent (clist->vscrollbar, GTK_WIDGET (clist));
3389 gtk_widget_show (clist->vscrollbar);
3391 clist->hscrollbar = gtk_hscrollbar_new (NULL);
3392 adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
3394 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
3395 (GtkSignalFunc) hadjustment_changed,
3398 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
3399 (GtkSignalFunc) hadjustment_value_changed,
3402 gtk_widget_set_parent (clist->hscrollbar, GTK_WIDGET (clist));
3403 gtk_widget_show (clist->hscrollbar);
3407 adjust_scrollbars (GtkCList * clist)
3409 GTK_RANGE (clist->vscrollbar)->adjustment->page_size = clist->clist_window_height;
3410 GTK_RANGE (clist->vscrollbar)->adjustment->page_increment = clist->clist_window_height / 2;
3411 GTK_RANGE (clist->vscrollbar)->adjustment->step_increment = 10;
3412 GTK_RANGE (clist->vscrollbar)->adjustment->lower = 0;
3413 GTK_RANGE (clist->vscrollbar)->adjustment->upper = LIST_HEIGHT (clist);
3415 if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist))
3417 GTK_RANGE (clist->vscrollbar)->adjustment->value = MAX (0, LIST_HEIGHT (clist) -
3418 clist->clist_window_height);
3419 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment),
3423 GTK_RANGE (clist->hscrollbar)->adjustment->page_size = clist->clist_window_width;
3424 GTK_RANGE (clist->hscrollbar)->adjustment->page_increment = clist->clist_window_width / 2;
3425 GTK_RANGE (clist->hscrollbar)->adjustment->step_increment = 10;
3426 GTK_RANGE (clist->hscrollbar)->adjustment->lower = 0;
3427 GTK_RANGE (clist->hscrollbar)->adjustment->upper = LIST_WIDTH (clist);
3429 if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist))
3431 GTK_RANGE (clist->hscrollbar)->adjustment->value = MAX (0, LIST_WIDTH (clist) -
3432 clist->clist_window_width);
3433 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment),
3437 if (LIST_HEIGHT (clist) <= clist->clist_window_height &&
3438 clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
3440 if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
3442 gtk_widget_hide (clist->vscrollbar);
3443 gtk_widget_queue_resize (GTK_WIDGET (clist));
3448 if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
3450 gtk_widget_show (clist->vscrollbar);
3451 gtk_widget_queue_resize (GTK_WIDGET (clist));
3455 if (LIST_WIDTH (clist) <= clist->clist_window_width &&
3456 clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
3458 if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
3460 gtk_widget_hide (clist->hscrollbar);
3461 gtk_widget_queue_resize (GTK_WIDGET (clist));
3466 if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
3468 gtk_widget_show (clist->hscrollbar);
3469 gtk_widget_queue_resize (GTK_WIDGET (clist));
3473 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
3474 gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), "changed");
3478 vadjustment_changed (GtkAdjustment * adjustment,
3483 g_return_if_fail (adjustment != NULL);
3484 g_return_if_fail (data != NULL);
3486 clist = GTK_CLIST (data);
3490 hadjustment_changed (GtkAdjustment * adjustment,
3495 g_return_if_fail (adjustment != NULL);
3496 g_return_if_fail (data != NULL);
3498 clist = GTK_CLIST (data);
3502 check_exposures (GtkCList *clist)
3506 if (!GTK_WIDGET_REALIZED (clist))
3509 /* Make sure graphics expose events are processed before scrolling
3511 while ((event = gdk_event_get_graphics_expose (clist->clist_window)) != NULL)
3513 gtk_widget_event (GTK_WIDGET (clist), event);
3514 if (event->expose.count == 0)
3516 gdk_event_free (event);
3519 gdk_event_free (event);
3524 vadjustment_value_changed (GtkAdjustment * adjustment,
3531 g_return_if_fail (adjustment != NULL);
3532 g_return_if_fail (data != NULL);
3533 g_return_if_fail (GTK_IS_CLIST (data));
3535 clist = GTK_CLIST (data);
3537 if (!GTK_WIDGET_DRAWABLE (clist))
3540 value = adjustment->value;
3542 if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)))
3544 if (value > -clist->voffset)
3547 diff = value + clist->voffset;
3549 /* we have to re-draw the whole screen here... */
3550 if (diff >= clist->clist_window_height)
3552 clist->voffset = -value;
3553 draw_rows (clist, NULL);
3557 if ((diff != 0) && (diff != clist->clist_window_height))
3558 gdk_window_copy_area (clist->clist_window,
3561 clist->clist_window,
3564 clist->clist_window_width,
3565 clist->clist_window_height - diff);
3568 area.y = clist->clist_window_height - diff;
3569 area.width = clist->clist_window_width;
3575 diff = -clist->voffset - value;
3577 /* we have to re-draw the whole screen here... */
3578 if (diff >= clist->clist_window_height)
3580 clist->voffset = -value;
3581 draw_rows (clist, NULL);
3585 if ((diff != 0) && (diff != clist->clist_window_height))
3586 gdk_window_copy_area (clist->clist_window,
3589 clist->clist_window,
3592 clist->clist_window_width,
3593 clist->clist_window_height - diff);
3597 area.width = clist->clist_window_width;
3602 clist->voffset = -value;
3603 if ((diff != 0) && (diff != clist->clist_window_height))
3604 check_exposures (clist);
3607 draw_rows (clist, &area);
3611 hadjustment_value_changed (GtkAdjustment * adjustment,
3616 gint i, diff, value;
3618 g_return_if_fail (adjustment != NULL);
3619 g_return_if_fail (data != NULL);
3620 g_return_if_fail (GTK_IS_CLIST (data));
3622 clist = GTK_CLIST (data);
3624 if (!GTK_WIDGET_DRAWABLE (clist))
3627 value = adjustment->value;
3629 if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)))
3631 /* move the column buttons and resize windows */
3632 for (i = 0; i < clist->columns; i++)
3634 if (clist->column[i].button)
3636 clist->column[i].button->allocation.x -= value + clist->hoffset;
3638 if (clist->column[i].button->window)
3640 gdk_window_move (clist->column[i].button->window,
3641 clist->column[i].button->allocation.x,
3642 clist->column[i].button->allocation.y);
3644 if (clist->column[i].window)
3645 gdk_window_move (clist->column[i].window,
3646 clist->column[i].button->allocation.x +
3647 clist->column[i].button->allocation.width -
3648 (DRAG_WIDTH / 2), 0);
3653 if (value > -clist->hoffset)
3656 diff = value + clist->hoffset;
3658 /* we have to re-draw the whole screen here... */
3659 if (diff >= clist->clist_window_width)
3661 clist->hoffset = -value;
3662 draw_rows (clist, NULL);
3666 if ((diff != 0) && (diff != clist->clist_window_width))
3667 gdk_window_copy_area (clist->clist_window,
3670 clist->clist_window,
3673 clist->clist_window_width - diff,
3674 clist->clist_window_height);
3676 area.x = clist->clist_window_width - diff;
3679 area.height = clist->clist_window_height;
3684 diff = -clist->hoffset - value;
3686 /* we have to re-draw the whole screen here... */
3687 if (diff >= clist->clist_window_width)
3689 clist->hoffset = -value;
3690 draw_rows (clist, NULL);
3694 if ((diff != 0) && (diff != clist->clist_window_width))
3695 gdk_window_copy_area (clist->clist_window,
3698 clist->clist_window,
3701 clist->clist_window_width - diff,
3702 clist->clist_window_height);
3707 area.height = clist->clist_window_height;
3710 clist->hoffset = -value;
3711 if ((diff != 0) && (diff != clist->clist_window_width))
3712 check_exposures (clist);
3715 draw_rows (clist, &area);
3719 * Memory Allocation/Distruction Routines for GtkCList stuctures
3731 static GtkCListColumn *
3732 columns_new (GtkCList * clist)
3735 GtkCListColumn *column;
3737 column = g_new (GtkCListColumn, clist->columns);
3739 for (i = 0; i < clist->columns; i++)
3741 column[i].area.x = 0;
3742 column[i].area.y = 0;
3743 column[i].area.width = 0;
3744 column[i].area.height = 0;
3745 column[i].title = NULL;
3746 column[i].button = NULL;
3747 column[i].window = NULL;
3748 column[i].width = 0;
3749 column[i].width_set = FALSE;
3750 column[i].justification = GTK_JUSTIFY_LEFT;
3757 column_title_new (GtkCList * clist,
3761 if (clist->column[column].title)
3762 g_free (clist->column[column].title);
3764 clist->column[column].title = g_strdup (title);
3768 columns_delete (GtkCList * clist)
3772 for (i = 0; i < clist->columns; i++)
3773 if (clist->column[i].title)
3774 g_free (clist->column[i].title);
3776 g_free (clist->column);
3779 static GtkCListRow *
3780 row_new (GtkCList * clist)
3783 GtkCListRow *clist_row;
3785 clist_row = g_chunk_new (GtkCListRow, clist->row_mem_chunk);
3786 clist_row->cell = g_chunk_new (GtkCell, clist->cell_mem_chunk);
3788 for (i = 0; i < clist->columns; i++)
3790 clist_row->cell[i].type = GTK_CELL_EMPTY;
3791 clist_row->cell[i].vertical = 0;
3792 clist_row->cell[i].horizontal = 0;
3795 clist_row->fg_set = FALSE;
3796 clist_row->bg_set = FALSE;
3797 clist_row->state = GTK_STATE_NORMAL;
3798 clist_row->data = NULL;
3799 clist_row->destroy = NULL;
3805 row_delete (GtkCList * clist,
3806 GtkCListRow * clist_row)
3810 for (i = 0; i < clist->columns; i++)
3811 cell_empty (clist, clist_row, i);
3813 if (clist_row->destroy)
3814 clist_row->destroy (clist_row->data);
3816 g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell);
3817 g_mem_chunk_free (clist->row_mem_chunk, clist_row);
3821 cell_empty (GtkCList * clist,
3822 GtkCListRow * clist_row,
3825 switch (clist_row->cell[column].type)
3827 case GTK_CELL_EMPTY:
3831 g_free (GTK_CELL_TEXT (clist_row->cell[column])->text);
3834 case GTK_CELL_PIXMAP:
3835 gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap);
3836 if (GTK_CELL_PIXMAP (clist_row->cell[column])->mask)
3837 gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask);
3840 case GTK_CELL_PIXTEXT:
3841 g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text);
3842 gdk_pixmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap);
3843 if (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask)
3844 gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask);
3847 case GTK_CELL_WIDGET:
3855 clist_row->cell[column].type = GTK_CELL_EMPTY;
3859 cell_set_text (GtkCList * clist,
3860 GtkCListRow * clist_row,
3864 cell_empty (clist, clist_row, column);
3868 clist_row->cell[column].type = GTK_CELL_TEXT;
3869 GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
3874 cell_set_pixmap (GtkCList * clist,
3875 GtkCListRow * clist_row,
3880 cell_empty (clist, clist_row, column);
3884 clist_row->cell[column].type = GTK_CELL_PIXMAP;
3885 GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
3886 /* We set the mask even if it is NULL */
3887 GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask;
3892 cell_set_pixtext (GtkCList * clist,
3893 GtkCListRow * clist_row,
3900 cell_empty (clist, clist_row, column);
3904 clist_row->cell[column].type = GTK_CELL_PIXTEXT;
3905 GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
3906 GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
3907 GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
3908 GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask;
3912 /* Fill in data after widget has correct style */
3915 add_style_data (GtkCList * clist)
3919 widget = GTK_WIDGET(clist);
3921 /* text properties */
3922 if (!GTK_CLIST_ROW_HEIGHT_SET (clist))
3924 clist->row_height = widget->style->font->ascent + widget->style->font->descent + 1;
3925 clist->row_center_offset = widget->style->font->ascent + 1.5;
3930 text_height = clist->row_height - (GTK_WIDGET (clist)->style->font->ascent +
3931 GTK_WIDGET (clist) ->style->font->descent + 1);
3932 clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;