diff options
author | Jay Painter <jpaint@src.gnome.org> | 1998-01-03 03:31:03 +0000 |
---|---|---|
committer | Jay Painter <jpaint@src.gnome.org> | 1998-01-03 03:31:03 +0000 |
commit | 948a3620cf9d11a00610b4f90d90b27a7f5ba712 (patch) | |
tree | 9bab2f579af78e8aaa1788c828f9a23b3902e222 | |
parent | 303c8f03a8a2386d38941cfc3c9601c33c3ebc8b (diff) | |
download | gdk-pixbuf-948a3620cf9d11a00610b4f90d90b27a7f5ba712.tar.gz |
Added column list widget GtkCList. -Jay Painter
-rw-r--r-- | gtk/Makefile.am | 2 | ||||
-rw-r--r-- | gtk/gtk.h | 1 | ||||
-rw-r--r-- | gtk/gtkclist.c | 2817 | ||||
-rw-r--r-- | gtk/gtkclist.h | 405 | ||||
-rw-r--r-- | gtk/testgtk.c | 103 | ||||
-rw-r--r-- | gtk/testgtkrc | 6 | ||||
-rw-r--r-- | tests/testgtk.c | 103 | ||||
-rw-r--r-- | tests/testgtkrc | 6 |
8 files changed, 3437 insertions, 6 deletions
diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 5b1018b6f..ff0c18e2b 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -16,6 +16,7 @@ libgtk_la_SOURCES = \ gtkbutton.c \ gtkcheckbutton.c \ gtkcheckmenuitem.c \ + gtkclist.c \ gtkcolorsel.c \ gtkcontainer.c \ gtkcurve.c \ @@ -103,6 +104,7 @@ gtkinclude_HEADERS = \ gtkbutton.h \ gtkcheckbutton.h \ gtkcheckmenuitem.h \ + gtkclist.h \ gtkcolorsel.h \ gtkcontainer.h \ gtkcurve.h \ @@ -31,6 +31,7 @@ #include <gtk/gtkbutton.h> #include <gtk/gtkcheckbutton.h> #include <gtk/gtkcheckmenuitem.h> +#include <gtk/gtkclist.h> #include <gtk/gtkcolorsel.h> #include <gtk/gtkcontainer.h> #include <gtk/gtkcurve.h> diff --git a/gtk/gtkclist.c b/gtk/gtkclist.c new file mode 100644 index 000000000..e5b06ee1d --- /dev/null +++ b/gtk/gtkclist.c @@ -0,0 +1,2817 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald, + * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <stdlib.h> +#include "gtkclist.h" + +/* the width of the column resize windows */ +#define DRAG_WIDTH 5 + +/* minimum allowed width of a column */ +#define COLUMN_MIN_WIDTH 5 + +/* this defigns the base grid spacing */ +#define CELL_SPACING 1 + +/* added the horizontal space at the beginning and end of a row*/ +#define COLUMN_INSET 3 + + +/* gives the top pixel of the given row in context of + * the clist's voffset */ +#define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * row) + \ + ((row + 1) * CELL_SPACING) + \ + (clist)->voffset) + +/* returns the row index from a y pixel location in the + * context of the clist's voffset */ +#define ROW_FROM_YPIXEL(clist, y) ((y - (clist)->voffset) / \ + ((clist)->row_height + CELL_SPACING)) + +/* gives the left pixel of the given column in context of + * the clist's hoffset */ +#define COLUMN_LEFT_YPIXEL(clist, column) ((clist)->column[(column)].area.x + \ + (clist)->hoffset) + +/* returns the column index from a x pixel location in the + * context of the clist's hoffset */ +static inline gint +COLUMN_FROM_XPIXEL (GtkCList * clist, + gint x) +{ + gint i, cx; + + for (i = 0; i < clist->columns; i++) + { + cx = clist->column[i].area.x + clist->hoffset; + + if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) && + x <= (cx + clist->column[i].area.width + COLUMN_INSET)) + return i; + } + + /* no match */ + return -1; +} + +/* returns the top pixel of the given row in the context of + * the list height */ +#define ROW_TOP(clist, row) (((clist)->row_height + CELL_SPACING) * (row)) + +/* returns the left pixel of the given column in the context of + * the list width */ +#define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x) + +/* returns the total height of the list */ +#define LIST_HEIGHT(clist) (((clist)->row_height * ((clist)->rows)) + \ + (CELL_SPACING * ((clist)->rows + 1))) + +/* returns the total width of the list */ +#define LIST_WIDTH(clist) ((clist)->column[(clist)->columns - 1].area.x + \ + (clist)->column[(clist)->columns - 1].area.width + \ + COLUMN_INSET + CELL_SPACING) + + +/* Signals */ +enum +{ + SELECT_ROW, + UNSELECT_ROW, + CLICK_COLUMN, + LAST_SIGNAL +}; + +typedef void (*GtkCListSignal1) (GtkObject * object, + gint arg1, + gint arg2, + GdkEventButton * arg3, + gpointer data); + +typedef void (*GtkCListSignal2) (GtkObject * object, + gint arg1, + gpointer data); + + +/* GtkCList Methods */ +static void gtk_clist_class_init (GtkCListClass * klass); +static void gtk_clist_init (GtkCList * clist); + +static gint gtk_clist_row_isvisable (GtkCList * clist, + gint row); + +static void gtk_clist_draw_row (GtkCList * clist, + GdkRectangle * area, + gint row, + GtkCListRow * clist_row); + +static void gtk_clist_draw_rows (GtkCList * clist, + GdkRectangle * area); + +static gint gtk_clist_get_selection_info (GtkCList * clist, + gint x, + gint y, + gint * row, + gint * column); + +static void gtk_clist_real_select_row (GtkCList * clist, + gint row, + gint column, + GdkEventButton * event); +static void gtk_clist_real_unselect_row (GtkCList * clist, + gint row, + gint column, + GdkEventButton * event); + +static void gtk_clist_size_allocate_title_buttons (GtkCList * clist); +static void gtk_clist_size_allocate_columns (GtkCList * clist); + + +/* GtkObject Methods */ +static void gtk_clist_destroy (GtkObject * object); + + +/* GtkWidget Methods */ +static void gtk_clist_realize (GtkWidget * widget); +static void gtk_clist_unrealize (GtkWidget * widget); +static void gtk_clist_map (GtkWidget * widget); +static void gtk_clist_unmap (GtkWidget * widget); +static void gtk_clist_draw (GtkWidget * widget, + GdkRectangle * area); +static gint gtk_clist_expose (GtkWidget * widget, + GdkEventExpose * event); +static gint gtk_clist_button_press (GtkWidget * widget, + GdkEventButton * event); + +static void gtk_clist_size_request (GtkWidget * widget, + GtkRequisition * requisition); +static void gtk_clist_size_allocate (GtkWidget * widget, + GtkAllocation * allocation); + + +/* GtkContainer Methods */ +static void gtk_clist_foreach (GtkContainer * container, + GtkCallback callback, + gpointer callback_data); + + +/* Buttons */ +static void gtk_clist_column_button_realize (GtkWidget * widget, + gpointer data); +static void gtk_clist_column_button_clicked (GtkWidget * widget, + gpointer data); + + +/* Scrollbars */ +static void gtk_clist_adjust_scrollbars (GtkCList * clist); +static void gtk_clist_vadjustment_changed (GtkAdjustment * adjustment, + gpointer data); +static void gtk_clist_vadjustment_value_changed (GtkAdjustment * adjustment, + gpointer data); +static void gtk_clist_hadjustment_changed (GtkAdjustment * adjustment, + gpointer data); +static void gtk_clist_hadjustment_value_changed (GtkAdjustment * adjustment, + gpointer data); + + +/* Memory Allocation/Distruction Routines */ +static GtkCListColumn *gtk_clist_columns_new (GtkCList * clist); + +static void gtk_clist_column_title_new (GtkCList * clist, + gint column, + gchar * title); +static void gtk_clist_columns_delete (GtkCList * clist); + +static GtkCListRow *gtk_clist_row_new (GtkCList * clist); + +static void gtk_clist_row_delete (GtkCList * clist, + GtkCListRow * clist_row); +static void gtk_clist_cell_empty (GtkCList * clist, + GtkCListRow * clist_row, + gint column); +static void gtk_clist_cell_set_text (GtkCList * clist, + GtkCListRow * clist_row, + gint column, + gchar * text); +static void gtk_clist_cell_set_pixmap (GtkCList * clist, + GtkCListRow * clist_row, + gint column, + GdkPixmap * pixmap, + GdkBitmap * mask); +static void gtk_clist_cell_set_pixtext (GtkCList * clist, + GtkCListRow * clist_row, + gint column, + gchar * text, + guint8 spacing, + GdkPixmap * pixmap, + GdkBitmap * mask); + +/* Signals */ +static void gtk_clist_marshal_signal_1 (GtkObject * object, + GtkSignalFunc func, + gpointer func_data, + GtkArg * args); +static void gtk_clist_marshal_signal_2 (GtkObject * object, + GtkSignalFunc func, + gpointer func_data, + GtkArg * args); + + +static GtkContainerClass *parent_class = NULL; +static gint clist_signals[LAST_SIGNAL] = {0}; + + +guint +gtk_clist_get_type () +{ + static guint clist_type = 0; + + if (!clist_type) + { + GtkTypeInfo clist_info = + { + "GtkCList", + sizeof (GtkCList), + sizeof (GtkCListClass), + (GtkClassInitFunc) gtk_clist_class_init, + (GtkObjectInitFunc) gtk_clist_init, + (GtkArgFunc) NULL, + }; + + clist_type = gtk_type_unique (gtk_container_get_type (), &clist_info); + } + + return clist_type; +} + +static void +gtk_clist_class_init (GtkCListClass * klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass *) klass; + widget_class = (GtkWidgetClass *) klass; + container_class = (GtkContainerClass *) klass; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + clist_signals[SELECT_ROW] = + gtk_signal_new ("select_row", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkCListClass, select_row), + gtk_clist_marshal_signal_1, + GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_POINTER); + clist_signals[UNSELECT_ROW] = + gtk_signal_new ("unselect_row", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkCListClass, unselect_row), + gtk_clist_marshal_signal_1, + GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_POINTER); + clist_signals[CLICK_COLUMN] = + gtk_signal_new ("click_column", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkCListClass, click_column), + gtk_clist_marshal_signal_2, + GTK_TYPE_NONE, 1, GTK_TYPE_INT); + + gtk_object_class_add_signals (object_class, clist_signals, LAST_SIGNAL); + + object_class->destroy = gtk_clist_destroy; + + widget_class->realize = gtk_clist_realize; + widget_class->unrealize = gtk_clist_unrealize; + widget_class->map = gtk_clist_map; + widget_class->unmap = gtk_clist_unmap; + widget_class->draw = gtk_clist_draw; + widget_class->button_press_event = gtk_clist_button_press; + widget_class->expose_event = gtk_clist_expose; + widget_class->size_request = gtk_clist_size_request; + widget_class->size_allocate = gtk_clist_size_allocate; + + container_class->add = NULL; + container_class->remove = NULL; + container_class->foreach = gtk_clist_foreach; + + klass->select_row = gtk_clist_real_select_row; + klass->unselect_row = gtk_clist_real_unselect_row; + klass->click_column = NULL; +} + +static void +gtk_clist_marshal_signal_1 (GtkObject * object, + GtkSignalFunc func, + gpointer func_data, + GtkArg * args) +{ + GtkCListSignal1 rfunc; + + rfunc = (GtkCListSignal1) func; + + (*rfunc) (object, GTK_VALUE_INT (args[0]), + GTK_VALUE_INT (args[1]), + GTK_VALUE_POINTER (args[2]), + func_data); +} + +static void +gtk_clist_marshal_signal_2 (GtkObject * object, + GtkSignalFunc func, + gpointer func_data, + GtkArg * args) +{ + GtkCListSignal2 rfunc; + + rfunc = (GtkCListSignal2) func; + + (*rfunc) (object, GTK_VALUE_INT (args[0]), + func_data); +} + +static void +gtk_clist_init (GtkCList * clist) +{ + clist->flags = 0; + + GTK_WIDGET_UNSET_FLAGS (clist, GTK_NO_WINDOW); + GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN); + + clist->rows = 0; + clist->row_center_offset = 0; + clist->row_height = 0; + clist->row_list = NULL; + clist->row_list_end = NULL; + + clist->columns = 0; + + clist->column_title_area.x = 0; + clist->column_title_area.y = 0; + clist->column_title_area.width = 0; + clist->column_title_area.height = 0; + + clist->clist_window = NULL; + clist->clist_window_width = 0; + clist->clist_window_height = 0; + + clist->hoffset = 0; + clist->voffset = 0; + + clist->shadow_type = GTK_SHADOW_IN; + clist->hscrollbar_policy = GTK_POLICY_ALWAYS; + clist->vscrollbar_policy = GTK_POLICY_ALWAYS; + + clist->cursor_drag = NULL; + clist->xor_gc = NULL; + clist->fg_gc = NULL; + clist->bg_gc = NULL; + clist->x_drag = 0; + + clist->selection_mode = GTK_SELECTION_SINGLE; +} + +GtkWidget * +gtk_clist_new (int columns, + gchar * titles[]) +{ + int i; + GtkCList *clist; + GtkAdjustment *adjustment; + + /* sanity check */ + if (columns < 1 || titles == NULL) + return NULL; + + clist = gtk_type_new (gtk_clist_get_type ()); + + /* initalize memory chunks */ + clist->row_mem_chunk = g_mem_chunk_new ("clist row mem chunk", + sizeof (GtkCListRow), + 1024, G_ALLOC_AND_FREE); + clist->cell_mem_chunk = g_mem_chunk_new ("clist cell mem chunk", + sizeof (GtkCell) * columns, + 1024, G_ALLOC_AND_FREE); + + /* set number of columns, allocate memory */ + clist->columns = columns; + clist->column = gtk_clist_columns_new (clist); + + /* create column button and connect signals */ + for (i = 0; i < columns; i++) + { + clist->column[i].button = gtk_button_new (); + gtk_widget_set_parent (clist->column[i].button, GTK_WIDGET (clist)); + + gtk_signal_connect_after (GTK_OBJECT (clist->column[i].button), + "realize", + (GtkSignalFunc) gtk_clist_column_button_realize, + (gpointer) clist); + + gtk_signal_connect (GTK_OBJECT (clist->column[i].button), + "clicked", + (GtkSignalFunc) gtk_clist_column_button_clicked, + (gpointer) clist); + + /* set column title */ + gtk_clist_set_column_title (clist, i, titles[i]); + + clist->column[i].width = + gdk_string_width (GTK_WIDGET (clist)->style->font, clist->column[i].title); + + gtk_widget_show (clist->column[i].button); + } + + + /* create and connect scrollbars */ + clist->vscrollbar = gtk_vscrollbar_new (NULL); + adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)); + + gtk_signal_connect (GTK_OBJECT (adjustment), "changed", + (GtkSignalFunc) gtk_clist_vadjustment_changed, + (gpointer) clist); + + gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", + (GtkSignalFunc) gtk_clist_vadjustment_value_changed, + (gpointer) clist); + + gtk_widget_set_parent (clist->vscrollbar, GTK_WIDGET (clist)); + gtk_widget_show (clist->vscrollbar); + + clist->hscrollbar = gtk_hscrollbar_new (NULL); + adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)); + + gtk_signal_connect (GTK_OBJECT (adjustment), "changed", + (GtkSignalFunc) gtk_clist_hadjustment_changed, + (gpointer) clist); + + gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", + (GtkSignalFunc) gtk_clist_hadjustment_value_changed, + (gpointer) clist); + + gtk_widget_set_parent (clist->hscrollbar, GTK_WIDGET (clist)); + gtk_widget_show (clist->hscrollbar); + + return GTK_WIDGET (clist); +} + +void +gtk_clist_set_border (GtkCList * clist, + GtkShadowType border) +{ + g_return_if_fail (clist != NULL); + + clist->shadow_type = border; + + if (GTK_WIDGET_VISIBLE (clist)) + gtk_widget_queue_resize (GTK_WIDGET (clist)); +} + +void +gtk_clist_set_selection_mode (GtkCList * clist, + GtkSelectionMode mode) +{ + g_return_if_fail (clist != NULL); + + clist->selection_mode = mode; +} + +void +gtk_clist_freeze (GtkCList * clist) +{ + g_return_if_fail (clist != NULL); + + GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN); +} + +void +gtk_clist_thaw (GtkCList * clist) +{ + g_return_if_fail (clist != NULL); + + GTK_CLIST_UNSET_FLAGS (clist, CLIST_FROZEN); + + gtk_clist_adjust_scrollbars (clist); + gtk_clist_draw_rows (clist, NULL); +} + + +void +gtk_clist_set_column_title (GtkCList * clist, + gint column, + gchar * title) +{ + GtkWidget *old_widget; + GtkWidget *alignment; + GtkWidget *label; + + g_return_if_fail (clist != NULL); + + if (column < 0 || column >= clist->columns) + return; + + gtk_clist_column_title_new (clist, column, title); + + /* remove and destroy the old widget */ + old_widget = GTK_BUTTON (clist->column[column].button)->child; + if (old_widget) + { + gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget); + gtk_widget_destroy (old_widget); + } + + switch (clist->column[column].justification) + { + case GTK_JUSTIFY_LEFT: + alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0); + break; + + case GTK_JUSTIFY_RIGHT: + alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0); + break; + + case GTK_JUSTIFY_CENTER: + alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); + break; + + case GTK_JUSTIFY_FILL: + alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); + break; + + default: + break; + } + + if (alignment) + { + label = gtk_label_new (clist->column[column].title); + gtk_container_add (GTK_CONTAINER (alignment), label); + gtk_container_add (GTK_CONTAINER (clist->column[column].button), alignment); + gtk_widget_show (label); + gtk_widget_show (alignment); + } +} + +void +gtk_clist_set_column_widget (GtkCList * clist, + gint column, + GtkWidget * widget) +{ + GtkWidget *old_widget; + + g_return_if_fail (clist != NULL); + + if (column < 0 || column >= clist->columns) + return; + + gtk_clist_column_title_new (clist, column, NULL); + + /* remove and destroy the old widget */ + old_widget = GTK_BUTTON (clist->column[column].button)->child; + if (old_widget) + { + gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget); + gtk_widget_destroy (old_widget); + } + + /* add and show the widget */ + if (widget) + { + gtk_container_add (GTK_CONTAINER (clist->column[column].button), widget); + gtk_widget_show (widget); + } +} + +void +gtk_clist_set_column_justification (GtkCList * clist, + gint column, + GtkJustification justification) +{ + GtkWidget *alignment; + + g_return_if_fail (clist != NULL); + + if (column < 0 || column >= clist->columns) + return; + + clist->column[column].justification = justification; + + /* change the alinment of the button title if it's not a + * custom widget */ + if (clist->column[column].title) + { + alignment = GTK_BUTTON (clist->column[column].button)->child; + + switch (clist->column[column].justification) + { + case GTK_JUSTIFY_LEFT: + gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.0, 0.5, 0.0, 0.0); + break; + + case GTK_JUSTIFY_RIGHT: + gtk_alignment_set (GTK_ALIGNMENT (alignment), 1.0, 0.5, 0.0, 0.0); + break; + + case GTK_JUSTIFY_CENTER: + gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0); + break; + + case GTK_JUSTIFY_FILL: + gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0); + break; + + default: + break; + } + } + + if (!GTK_CLIST_FROZEN (clist)) + gtk_clist_draw_rows (clist, NULL); +} + +void +gtk_clist_set_column_width (GtkCList * clist, + gint column, + gint width) +{ + g_return_if_fail (clist != NULL); + + if (column < 0 || column >= clist->columns) + return; + + clist->column[column].width = width; + + gtk_clist_size_allocate_title_buttons (clist); + + if (!GTK_CLIST_FROZEN (clist)) + { + gtk_clist_adjust_scrollbars (clist); + gtk_clist_draw_rows (clist, NULL); + } +} + +void +gtk_clist_set_row_height (GtkCList * clist, + gint height) +{ + gint text_height; + + g_return_if_fail (clist != NULL); + + if (height > 0) + clist->row_height = height; + else + return; + + GTK_CLIST_SET_FLAGS (clist, CLIST_ROW_HEIGHT_SET); + + text_height = height - (GTK_WIDGET (clist)->style->font->ascent + + GTK_WIDGET (clist) ->style->font->descent + 1); + clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5; + + if (!GTK_CLIST_FROZEN (clist)) + { + gtk_clist_adjust_scrollbars (clist); + gtk_clist_draw_rows (clist, NULL); + } +} + +void +gtk_clist_moveto (GtkCList * clist, + gint row, + gint column, + gfloat row_align, + gfloat col_align) +{ + gint x, y; + + g_return_if_fail (clist != NULL); + + if (row < 0 || row >= clist->rows) + return; + if (column < 0 || column >= clist->columns) + return; + + /* adjust vertical scrollbar */ + x = ROW_TOP (clist, row) - (row_align * (clist->clist_window_height - + (clist->row_height + 2 * CELL_SPACING))); + + if (x < 0) + GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0; + else if (x > LIST_HEIGHT (clist) - clist->clist_window_height) + GTK_RANGE (clist->vscrollbar)->adjustment->value = LIST_HEIGHT (clist) - + clist->clist_window_height; + else + GTK_RANGE (clist->vscrollbar)->adjustment->value = x; + + gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), + "value_changed"); + + /* adjust horizontal scrollbar */ + y = COLUMN_LEFT (clist, column) - (col_align * (clist->clist_window_width - + clist->column[column].area.width + + 2 * (CELL_SPACING + COLUMN_INSET))); + + if (y < 0) + GTK_RANGE (clist->hscrollbar)->adjustment->value = 0.0; + else if (y > LIST_WIDTH (clist) - clist->clist_window_width) + GTK_RANGE (clist->hscrollbar)->adjustment->value = LIST_WIDTH (clist) - + clist->clist_window_width; + else + GTK_RANGE (clist->hscrollbar)->adjustment->value = y; + + gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), + "value_changed"); + +} + +void +gtk_clist_set_text (GtkCList * clist, + gint row, + gint column, + gchar * text) +{ + GtkCListRow *clist_row; + + g_return_if_fail (clist != NULL); + + if (row < 0 || row >= clist->rows) + return; + if (column < 0 || column >= clist->columns) + return; + + clist_row = (g_list_nth (clist->row_list, row))->data; + + /* if text is null, then the cell is empty */ + if (text) + gtk_clist_cell_set_text (clist, clist_row, column, text); + else + gtk_clist_cell_empty (clist, clist_row, column); + + /* redraw the list if it's not frozen */ + if (!GTK_CLIST_FROZEN (clist)) + { + if (gtk_clist_row_isvisable (clist, row)) + gtk_clist_draw_row (clist, NULL, row, clist_row); + } +} + +void +gtk_clist_set_pixmap (GtkCList * clist, + gint row, + gint column, + GdkPixmap * pixmap, + GdkBitmap * mask) +{ + GtkCListRow *clist_row; + + g_return_if_fail (clist != NULL); + + if (row < 0 || row >= clist->rows) + return; + if (column < 0 || column >= clist->columns) + return; + + clist_row = (g_list_nth (clist->row_list, row))->data; + + gdk_pixmap_ref (pixmap); + gdk_pixmap_ref (mask); + gtk_clist_cell_set_pixmap (clist, clist_row, column, pixmap, mask); + + /* redraw the list if it's not frozen */ + if (!GTK_CLIST_FROZEN (clist)) + { + if (gtk_clist_row_isvisable (clist, row)) + gtk_clist_draw_row (clist, NULL, row, clist_row); + } +} + +void +gtk_clist_set_pixtext (GtkCList * clist, + gint row, + gint column, + gchar * text, + guint8 spacing, + GdkPixmap * pixmap, + GdkBitmap * mask) +{ + GtkCListRow *clist_row; + + g_return_if_fail (clist != NULL); + + if (row < 0 || row >= clist->rows) + return; + if (column < 0 || column >= clist->columns) + return; + + clist_row = (g_list_nth (clist->row_list, row))->data; + + gdk_pixmap_ref (pixmap); + gdk_pixmap_ref (mask); + gtk_clist_cell_set_pixtext (clist, clist_row, column, text, spacing, pixmap, mask); + + /* redraw the list if it's not frozen */ + if (!GTK_CLIST_FROZEN (clist)) + { + if (gtk_clist_row_isvisable (clist, row)) + gtk_clist_draw_row (clist, NULL, row, clist_row); + } +} + +void +gtk_clist_set_foreground (GtkCList * clist, + gint row, + GdkColor * color) +{ + GtkCListRow *clist_row; + + g_return_if_fail (clist != NULL); + g_return_if_fail (color != NULL); + + if (row < 0 || row >= clist->rows) + return; + + clist_row = (g_list_nth (clist->row_list, row))->data; + clist_row->foreground = *color; + + if (!GTK_CLIST_FROZEN (clist)) + if (gtk_clist_row_isvisable (clist, row)) + gtk_clist_draw_row (clist, NULL, row, clist_row); +} + +void gtk_clist_set_background (GtkCList * clist, + gint row, + GdkColor * color) +{ + GtkCListRow *clist_row; + + g_return_if_fail (clist != NULL); + g_return_if_fail (color != NULL); + + if (row < 0 || row >= clist->rows) + return; + + clist_row = (g_list_nth (clist->row_list, row))->data; + clist_row->background = *color; + + if (!GTK_CLIST_FROZEN (clist)) + if (gtk_clist_row_isvisable (clist, row)) + gtk_clist_draw_row (clist, NULL, row, clist_row); +} + +void +gtk_clist_set_shift (GtkCList * clist, + gint row, + gint column, + gint verticle, + gint horizontal) +{ + GtkCListRow *clist_row; + + g_return_if_fail (clist != NULL); + + if (row < 0 || row >= clist->rows) + return; + if (column < 0 || column >= clist->columns) + return; + + clist_row = (g_list_nth (clist->row_list, row))->data; + + clist_row->cell[column].verticle = verticle; + clist_row->cell[column].horizontal = horizontal; + + if (!GTK_CLIST_FROZEN (clist)) + if (gtk_clist_row_isvisable (clist, row)) + gtk_clist_draw_row (clist, NULL, row, clist_row); +} + +gint +gtk_clist_append (GtkCList * clist, + gchar * text[]) +{ + gint i; + GtkCListRow *clist_row; + + g_return_val_if_fail (clist != NULL, -1); + + clist_row = gtk_clist_row_new (clist); + clist->rows++; + + /* keeps track of the end of the list so the list + * doesn't have to be traversed every time a item is added */ + if (!clist->row_list) + { + clist->row_list = g_list_append (clist->row_list, clist_row); + clist->row_list_end = clist->row_list; + + /* check the selection mode to see if we should select + * the first row automaticly */ + switch (clist->selection_mode) + { + case GTK_SELECTION_BROWSE: + gtk_clist_select_row (clist, 0, -1); + break; + + default: + break; + } + } + else + clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next; + + /* set the text in the row's columns */ + for (i = 0; i < clist->columns; i++) + if (text[i]) + gtk_clist_cell_set_text (clist, clist_row, i, text[i]); + + /* redraw the list if it's not frozen */ + if (!GTK_CLIST_FROZEN (clist)) + { + gtk_clist_adjust_scrollbars (clist); + + if (gtk_clist_row_isvisable (clist, clist->rows - 1)) + gtk_clist_draw_rows (clist, NULL); + } + + /* return index of the row */ + return clist->rows - 1; +} + +void +gtk_clist_insert (GtkCList * clist, + gint row, + gchar * text[]) +{ + gint i; + GtkCListRow *clist_row; + + g_return_if_fail (clist != NULL); + g_return_if_fail (text != NULL); + + /* + * return if out of bounds + */ + if (row < 0 || row > (clist->rows - 1)) + return; + + /* create the row */ + clist_row = gtk_clist_row_new (clist); + + /* reset the row end pointer if we're inserting at the + * end of the list */ + if (row == clist->rows) + clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next; + else + clist->row_list = g_list_insert (clist->row_list, clist_row, row); + + clist->rows++; + + /* set the text in the row's columns */ + for (i = 0; i < clist->columns; i++) + if (text[i]) + gtk_clist_cell_set_text (clist, clist_row, i, text[i]); + + /* redraw the list if it isn't frozen */ + if (!GTK_CLIST_FROZEN (clist)) + { + gtk_clist_adjust_scrollbars (clist); + + if (gtk_clist_row_isvisable (clist, row)) + gtk_clist_draw_rows (clist, NULL); + } +} + +void +gtk_clist_remove (GtkCList * clist, + gint row) +{ + GList *list; + GtkCListRow *clist_row; + + g_return_if_fail (clist != NULL); + + /* return if out of bounds */ + if (row < 0 || row > (clist->rows - 1)) + return; + + /* get the row we're going to delete */ + list = g_list_nth (clist->row_list, row); + clist_row = list->data; + + /* reset the row end pointer if we're removing at the + * end of the list */ + if (row == clist->rows - 1) + clist->row_list_end = list->prev; + + clist->row_list = g_list_remove (clist->row_list, clist_row); + clist->rows--; + gtk_clist_row_delete (clist, clist_row); + + /* redraw the row if it isn't frozen */ + if (!GTK_CLIST_FROZEN (clist)) + { + gtk_clist_adjust_scrollbars (clist); + + if (gtk_clist_row_isvisable (clist, row)) + gtk_clist_draw_rows (clist, NULL); + } +} + +void +gtk_clist_clear (GtkCList * clist) +{ + GList *list; + GtkCListRow *clist_row; + + g_return_if_fail (clist != NULL); + + list = clist->row_list; + while (list) + { + clist_row = list->data; + list = list->next; + + gtk_clist_row_delete (clist, clist_row); + } + g_list_free (clist->row_list); + + clist->row_list = NULL; + clist->row_list_end = NULL; + clist->voffset = 0; + clist->rows = 0; + + /* zero-out the scrollbars */ + GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0; + gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed"); + + if (!GTK_CLIST_FROZEN (clist)) + { + gtk_clist_adjust_scrollbars (clist); + gtk_clist_draw_rows (clist, NULL); + } +} + +void +gtk_clist_set_row_data (GtkCList * clist, + gint row, + gpointer data) +{ + GtkCListRow *clist_row; + + g_return_if_fail (clist != NULL); + + if (row < 0 || row > (clist->rows - 1)) + return; + + clist_row = (g_list_nth (clist->row_list, row))->data; + clist_row->data = data; + + /* + * re-send the selected signal if data is changed/added + * so the application can respond to the new data -- + * this could be questionable behavior + */ + if (clist_row->state == GTK_STATE_SELECTED) + gtk_clist_select_row (clist, 0, 0); +} + +gpointer +gtk_clist_get_row_data (GtkCList * clist, + gint row) +{ + GtkCListRow *clist_row; + + g_return_val_if_fail (clist != NULL, NULL); + + if (row < 0 || row > (clist->rows - 1)) + return NULL; + + clist_row = (g_list_nth (clist->row_list, row))->data; + return clist_row->data; +} + +void +gtk_clist_select_row (GtkCList * clist, + gint row, + gint column) +{ + g_return_if_fail (clist != NULL); + + if (row < 0 || row >= clist->rows) + return; + + if (column < -1 || column >= clist->columns) + return; + + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], row, column, NULL); +} + +void +gtk_clist_unselect_row (GtkCList * clist, + gint row, + gint column) +{ + g_return_if_fail (clist != NULL); + + if (row < 0 || row >= clist->rows) + return; + + if (column < -1 || column >= clist->columns) + return; + + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], row, column, NULL); +} + +static gint +gtk_clist_row_isvisable (GtkCList * clist, + gint row) +{ + g_return_val_if_fail (clist != NULL, 0); + + if (row < 0 || row >= clist->rows) + return 0; + + if (clist->row_height == 0) + return 0; + + if (row < ROW_FROM_YPIXEL (clist, 0)) + return 0; + + if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height)) + return 0; + + return 1; +} + +GtkAdjustment * +gtk_clist_get_vadjustment (GtkCList * clist) +{ + g_return_val_if_fail (clist != NULL, NULL); + g_return_val_if_fail (GTK_IS_CLIST (clist), NULL); + + return gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)); +} + +GtkAdjustment * +gtk_clist_get_hadjustment (GtkCList * clist) +{ + g_return_val_if_fail (clist != NULL, NULL); + g_return_val_if_fail (GTK_IS_CLIST (clist), NULL); + + return gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)); +} + +void +gtk_clist_set_policy (GtkCList * clist, + GtkPolicyType vscrollbar_policy, + GtkPolicyType hscrollbar_policy) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (clist->vscrollbar_policy != vscrollbar_policy) + { + clist->vscrollbar_policy = vscrollbar_policy; + + if (GTK_WIDGET (clist)->parent) + gtk_widget_queue_resize (GTK_WIDGET (clist)); + } + + if (clist->hscrollbar_policy != hscrollbar_policy) + { + clist->hscrollbar_policy = hscrollbar_policy; + + if (GTK_WIDGET (clist)->parent) + gtk_widget_queue_resize (GTK_WIDGET (clist)); + } +} + +static void +gtk_clist_destroy (GtkObject * object) +{ + gint i; + GtkCList *clist; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_CLIST (object)); + + clist = GTK_CLIST (object); + + /* freeze the list */ + GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN); + + /* destroy the scrollbars */ + gtk_widget_destroy (clist->vscrollbar); + gtk_widget_destroy (clist->hscrollbar); + + /* get rid of all the rows */ + gtk_clist_clear (clist); + + /* get rid of all the column buttons */ + for (i = 0; i < clist->columns; i++) + gtk_widget_destroy (clist->column[i].button); + + gtk_clist_columns_delete (clist); + + /* get rid of the memory chunks */ + g_mem_chunk_destroy (clist->cell_mem_chunk); + g_mem_chunk_destroy (clist->row_mem_chunk); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (*GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_clist_realize (GtkWidget * widget) +{ + GtkCList *clist; + GdkWindowAttr attributes; + gint attributes_mask; + GdkGCValues values; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); + + clist = GTK_CLIST (widget); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_KEY_PRESS_MASK); + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + + /* main window */ + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, clist); + + widget->style = gtk_style_attach (widget->style, widget->window); + + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); + + /* column-title window */ + clist->title_window = gdk_window_new (widget->window, &attributes, attributes_mask); + gdk_window_set_user_data (clist->title_window, clist); + + gtk_style_set_background (widget->style, clist->title_window, GTK_STATE_SELECTED); + gdk_window_show (clist->title_window); + + /* clist-window */ + clist->clist_window = gdk_window_new (widget->window, &attributes, attributes_mask); + gdk_window_set_user_data (clist->clist_window, clist); + + gdk_window_set_background (clist->clist_window, &widget->style->white); + gdk_window_show (clist->clist_window); + gdk_window_get_size (clist->clist_window, &clist->clist_window_width, + &clist->clist_window_height); + + /* cursor's and GC's */ + clist->cursor_drag = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW); + + clist->fg_gc = gdk_gc_new (widget->window); + clist->bg_gc = gdk_gc_new (widget->window); + + values.foreground = widget->style->white; + values.function = GDK_XOR; + values.subwindow_mode = GDK_INCLUDE_INFERIORS; + clist->xor_gc = gdk_gc_new_with_values (widget->window, + &values, + GDK_GC_FOREGROUND | + GDK_GC_FUNCTION | + GDK_GC_SUBWINDOW); + + /* text properties */ + if (!GTK_CLIST_ROW_HEIGHT_SET (clist)) + { + clist->row_height = widget->style->font->ascent + widget->style->font->descent + 1; + clist->row_center_offset = widget->style->font->ascent + 1.5; + } +} + +static void +gtk_clist_unrealize (GtkWidget * widget) +{ + GtkCList *clist; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); + + clist = GTK_CLIST (widget); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED); + GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN); + + gdk_cursor_destroy (clist->cursor_drag); + gdk_gc_destroy (clist->xor_gc); + gdk_gc_destroy (clist->fg_gc); + gdk_gc_destroy (clist->bg_gc); + + gtk_style_detach (widget->style); + + gdk_window_destroy (clist->clist_window); + gdk_window_destroy (clist->title_window); + gdk_window_set_user_data (widget->window, NULL); + gdk_window_destroy (widget->window); + + widget->window = NULL; + clist->clist_window = NULL; + clist->title_window = NULL; + clist->cursor_drag = NULL; + clist->xor_gc = NULL; + clist->fg_gc = NULL; + clist->bg_gc = NULL; +} + +static void +gtk_clist_map (GtkWidget * widget) +{ + gint i; + GtkCList *clist; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); + + clist = GTK_CLIST (widget); + + if (!GTK_WIDGET_MAPPED (widget)) + { + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + + gdk_window_show (widget->window); + gdk_window_show (clist->title_window); + gdk_window_show (clist->clist_window); + + /* map column buttons*/ + for (i = 0; i < clist->columns; i++) + if (GTK_WIDGET_VISIBLE (clist->column[i].button) && + !GTK_WIDGET_MAPPED (clist->column[i].button)) + gtk_widget_map (clist->column[i].button); + + /* map vscrollbars */ + if (GTK_WIDGET_VISIBLE (clist->vscrollbar) && + !GTK_WIDGET_MAPPED (clist->vscrollbar)) + gtk_widget_map (clist->vscrollbar); + + if (GTK_WIDGET_VISIBLE (clist->hscrollbar) && + !GTK_WIDGET_MAPPED (clist->hscrollbar)) + gtk_widget_map (clist->hscrollbar); + + /* unfreeze the list */ + GTK_CLIST_UNSET_FLAGS (clist, CLIST_FROZEN); + } +} + +static void +gtk_clist_unmap (GtkWidget * widget) +{ + gint i; + GtkCList *clist; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); + + clist = GTK_CLIST (widget); + + if (GTK_WIDGET_MAPPED (widget)) + { + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + + gdk_window_hide (clist->clist_window); + gdk_window_hide (clist->title_window); + gdk_window_hide (widget->window); + + /* unmap scrollbars */ + if (GTK_WIDGET_MAPPED (clist->vscrollbar)) + gtk_widget_unmap (clist->vscrollbar); + + if (GTK_WIDGET_MAPPED (clist->hscrollbar)) + gtk_widget_unmap (clist->hscrollbar); + + /* unmap column buttons */ + for (i = 0; i < clist->columns; i++) + if (GTK_WIDGET_MAPPED (clist->column[i].button)) + gtk_widget_unmap (clist->column[i].button); + + /* freeze the list */ + GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN); + } +} + +static void +gtk_clist_draw_row (GtkCList * clist, + GdkRectangle * area, + gint row, + GtkCListRow * clist_row) +{ + GtkWidget *widget; + GdkGC *fg_gc, *bg_gc; + GdkRectangle row_rectangle, cell_rectangle, clip_rectangle, intersect_rectangle, + *rect; + gint i, offset = 0, width, height, pixmap_width = 0; + gint xsrc, ysrc, xdest, ydest; + + g_return_if_fail (clist != NULL); + + /* bail now if we arn't drawable yet */ + if (!GTK_WIDGET_DRAWABLE (clist)) + return; + + if (row < 0 || row >= clist->rows) + return; + + widget = GTK_WIDGET (clist); + + /* if the function is passed the pointer to the row instead of null, + * it avoids this expensive lookup */ + if (!clist_row) + clist_row = (g_list_nth (clist->row_list, row))->data; + + /* rectangle of the entire row */ + row_rectangle.x = 0; + row_rectangle.y = ROW_TOP_YPIXEL (clist, row); + row_rectangle.width = clist->clist_window_width; + row_rectangle.height = clist->row_height; + + /* rectangle of the cell spacing above the row */ + cell_rectangle.x = 0; + cell_rectangle.y = row_rectangle.y - CELL_SPACING; + cell_rectangle.width = row_rectangle.width; + cell_rectangle.height = CELL_SPACING; + + /* rectangle used to clip drawing operations, it's y and height + * positions only need to be set once, so we set them once here. + * the x and width are set withing the drawing loop below once per + * column */ + clip_rectangle.y = row_rectangle.y; + clip_rectangle.height = row_rectangle.height; + + /* select GC for background rectangle */ + if (clist_row->state == GTK_STATE_SELECTED) + { + fg_gc = widget->style->fg_gc[GTK_STATE_SELECTED]; + bg_gc = widget->style->bg_gc[GTK_STATE_SELECTED]; + } + else + { + gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground); + gdk_gc_set_foreground (clist->bg_gc, &clist_row->background); + + fg_gc = clist->fg_gc; + bg_gc = clist->bg_gc; + } + + + if (area) + { + if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle)) + gdk_window_clear_area (clist->clist_window, + intersect_rectangle.x, + intersect_rectangle.y, + intersect_rectangle.width, + intersect_rectangle.height); + + /* the last row has to clear it's bottom cell spacing too */ + if (clist_row == clist->row_list_end->data) + { + cell_rectangle.y += clist->row_height + CELL_SPACING; + + if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle)) + gdk_window_clear_area (clist->clist_window, + intersect_rectangle.x, + intersect_rectangle.y, + intersect_rectangle.width, + intersect_rectangle.height); + } + + if (!gdk_rectangle_intersect (area, &row_rectangle, &intersect_rectangle)) + return; + + gdk_draw_rectangle (clist->clist_window, + bg_gc, + TRUE, + intersect_rectangle.x, + intersect_rectangle.y, + intersect_rectangle.width, + intersect_rectangle.height); + } + else + { + gdk_window_clear_area (clist->clist_window, + cell_rectangle.x, + cell_rectangle.y, + cell_rectangle.width, + cell_rectangle.height); + + cell_rectangle.y += clist->row_height + CELL_SPACING; + gdk_window_clear_area (clist->clist_window, + cell_rectangle.x, + cell_rectangle.y, + cell_rectangle.width, + cell_rectangle.height); + + gdk_draw_rectangle (clist->clist_window, + bg_gc, + TRUE, + row_rectangle.x, + row_rectangle.y, + row_rectangle.width, + row_rectangle.height); + } + + + /* iterate and draw all the columns (row cells) and draw their contents */ + for (i = 0; i < clist->columns; i++) + { + clip_rectangle.x = clist->column[i].area.x + clist->hoffset; + clip_rectangle.width = clist->column[i].area.width; + + /* calculate clipping region clipping region */ + if (!area) + { + rect = &clip_rectangle; + } + else + { + if (!gdk_rectangle_intersect (area, &clip_rectangle, &intersect_rectangle)) + continue; + rect = &intersect_rectangle; + } + + /* calculate real width for column justification */ + switch (clist_row->cell[i].type) + { + case GTK_CELL_EMPTY: + continue; + break; + + case GTK_CELL_TEXT: + width = gdk_string_width (GTK_WIDGET (clist)->style->font, + GTK_CELL_TEXT (clist_row->cell[i])->text); + break; + + case GTK_CELL_PIXMAP: + gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, &width, &height); + pixmap_width = width; + break; + + case GTK_CELL_PIXTEXT: + gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, &width, &height); + pixmap_width = width; + width += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing; + width = gdk_string_width (GTK_WIDGET (clist)->style->font, + GTK_CELL_PIXTEXT (clist_row->cell[i])->text); + break; + + case GTK_CELL_WIDGET: + /* unimplimented */ + continue; + break; + + default: + continue; + break; + } + + switch (clist->column[i].justification) + { + case GTK_JUSTIFY_LEFT: + offset = clip_rectangle.x; + break; + + case GTK_JUSTIFY_RIGHT: + offset = (clip_rectangle.x + clip_rectangle.width) - width; + break; + + case GTK_JUSTIFY_CENTER: + offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2); + break; + + case GTK_JUSTIFY_FILL: + offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2); + break; + + default: + offset = 0; + break; + }; + + /* + * Draw Text or Pixmap + */ + switch (clist_row->cell[i].type) + { + case GTK_CELL_EMPTY: + continue; + break; + + case GTK_CELL_TEXT: + gdk_gc_set_clip_rectangle (fg_gc, rect); + + gdk_draw_string (clist->clist_window, + widget->style->font, + fg_gc, + offset + clist_row->cell[i].horizontal, + row_rectangle.y + clist->row_center_offset + + clist_row->cell[i].verticle, + GTK_CELL_TEXT (clist_row->cell[i])->text); + + gdk_gc_set_clip_rectangle (fg_gc, NULL); + break; + + case GTK_CELL_PIXMAP: + xsrc = 0; + ysrc = 0; + xdest = offset + clist_row->cell[i].horizontal; + ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 + + clist_row->cell[i].verticle; + + gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXMAP (clist_row->cell[i])->mask); + gdk_gc_set_clip_origin (fg_gc, xdest, ydest); + + gdk_draw_pixmap (clist->clist_window, + fg_gc, + GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, + xsrc, ysrc, + xdest, + ydest, + pixmap_width, height); + + gdk_gc_set_clip_origin (fg_gc, 0, 0); + gdk_gc_set_clip_mask (fg_gc, NULL); + break; + + case GTK_CELL_PIXTEXT: + /* draw the pixmap */ + xsrc = 0; + ysrc = 0; + xdest = offset + clist_row->cell[i].horizontal; + ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 + + clist_row->cell[i].verticle; + + gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXTEXT (clist_row->cell[i])->mask); + gdk_gc_set_clip_origin (fg_gc, xdest, ydest); + + gdk_draw_pixmap (clist->clist_window, + fg_gc, + GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, + xsrc, ysrc, + xdest, + ydest, + pixmap_width, height); + + gdk_gc_set_clip_origin (fg_gc, 0, 0); + + offset += pixmap_width + GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing; + + /* draw the string */ + gdk_gc_set_clip_rectangle (fg_gc, rect); + + gdk_draw_string (clist->clist_window, + widget->style->font, + fg_gc, + offset + clist_row->cell[i].horizontal, + row_rectangle.y + clist->row_center_offset + + clist_row->cell[i].verticle, + GTK_CELL_PIXTEXT (clist_row->cell[i])->text); + + gdk_gc_set_clip_rectangle (fg_gc, NULL); + + break; + + case GTK_CELL_WIDGET: + /* unimplimented */ + continue; + break; + + default: + continue; + break; + } + } +} + +static void +gtk_clist_draw_rows (GtkCList * clist, + GdkRectangle * area) +{ + GList *list; + GtkCListRow *clist_row; + int i, first_row, last_row; + + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (clist->row_height == 0) + return; + + if (area) + { + first_row = ROW_FROM_YPIXEL (clist, area->y); + last_row = ROW_FROM_YPIXEL (clist, area->y + area->height); + } + else + { + first_row = ROW_FROM_YPIXEL (clist, 0); + last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height); + } + + list = g_list_nth (clist->row_list, first_row); + i = first_row; + while (list) + { + clist_row = list->data; + list = list->next; + + if (i > last_row) + return; + + gtk_clist_draw_row (clist, area, i, clist_row); + i++; + } + + if (!area) + gdk_window_clear_area (clist->clist_window, + 0, ROW_TOP_YPIXEL (clist, i + 1) - 1, + -1, -1); +} + +static gint +gtk_clist_get_selection_info (GtkCList * clist, + gint x, + gint y, + gint * row, + gint * column) +{ + gint trow, tcol; + + g_return_val_if_fail (clist != NULL, 0); + + /* bounds checking, return false if the user clicked + * on a blank area */ + trow = ROW_FROM_YPIXEL (clist, y); + if (trow >= clist->rows) + return 0; + + if (row) + *row = trow; + + tcol = COLUMN_FROM_XPIXEL (clist, x); + if (tcol >= clist->columns) + return 0; + + if (column) + *column = tcol; + + return 1; +} + +static void +gtk_clist_real_select_row (GtkCList * clist, + gint row, + gint column, + GdkEventButton * event) +{ + gint i; + GList *list; + GtkCListRow *clist_row; + + g_return_if_fail (clist != NULL); + + if (row < 0 || row >= clist->rows) + return; + + switch (clist->selection_mode) + { + case GTK_SELECTION_SINGLE: + i = 0; + list = clist->row_list; + while (list) + { + clist_row = list->data; + list = list->next; + + if (row == i) + { + if (clist_row->state == GTK_STATE_SELECTED) + { + clist_row->state = GTK_STATE_NORMAL; + gtk_clist_unselect_row (clist, i, column); + } + else + { + clist_row->state = GTK_STATE_SELECTED; + } + + if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row)) + gtk_clist_draw_row (clist, NULL, row, clist_row); + } + else if (clist_row->state == GTK_STATE_SELECTED) + { + gtk_clist_unselect_row (clist, i, column); + } + + i++; + } + break; + + case GTK_SELECTION_BROWSE: + i = 0; + list = clist->row_list; + while (list) + { + clist_row = list->data; + list = list->next; + + if (row == i) + { + clist_row->state = GTK_STATE_SELECTED; + + if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row)) + gtk_clist_draw_row (clist, NULL, row, clist_row); + } + else if (clist_row->state == GTK_STATE_SELECTED) + { + gtk_clist_unselect_row (clist, i, column); + } + + i++; + } + break; + + case GTK_SELECTION_MULTIPLE: + i = 0; + list = clist->row_list; + while (list) + { + clist_row = list->data; + list = list->next; + + if (row == i) + { + if (clist_row->state == GTK_STATE_SELECTED) + { + clist_row->state = GTK_STATE_NORMAL; + gtk_clist_unselect_row (clist, i, column); + } + else + { + clist_row->state = GTK_STATE_SELECTED; + } + + if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row)) + gtk_clist_draw_row (clist, NULL, row, clist_row); + } + + i++; + } + break; + + case GTK_SELECTION_EXTENDED: + break; + + default: + break; + } +} + +static void +gtk_clist_real_unselect_row (GtkCList * clist, + gint row, + gint column, + GdkEventButton * event) +{ + GtkCListRow *clist_row; + + g_return_if_fail (clist != NULL); + + if (row < 0 || row > (clist->rows - 1)) + return; + + clist_row = (g_list_nth (clist->row_list, row))->data; + clist_row->state = GTK_STATE_NORMAL; + + if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row)) + gtk_clist_draw_row (clist, NULL, row, clist_row); +} + +static void +gtk_clist_draw (GtkWidget * widget, + GdkRectangle * area) +{ + GtkCList *clist; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + clist = GTK_CLIST (widget); + + gdk_window_clear_area (widget->window, + area->x, area->y, + area->width, area->height); + + /* draw list shadow/border */ + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, clist->shadow_type, + 0, 0, -1, -1); + + gdk_window_clear_area (clist->clist_window, + 0, 0, -1, -1); + + gtk_clist_draw_rows (clist, NULL); + } +} + +static gint +gtk_clist_expose (GtkWidget * widget, + GdkEventExpose * event) +{ + GtkCList *clist; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + clist = GTK_CLIST (widget); + + /* draw border */ + if (event->window == widget->window) + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, clist->shadow_type, + 0, 0, -1, -1); + + /* exposure events on the list */ + if (event->window == clist->clist_window) + gtk_clist_draw_rows (clist, &event->area); + } + + return FALSE; +} + +static gint +gtk_clist_button_press (GtkWidget * widget, + GdkEventButton * event) +{ + GtkCList *clist; + gint x, y, row, column; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + clist = GTK_CLIST (widget); + + /* selections on the list */ + if (event->window == clist->clist_window) + { + x = event->x; + y = event->y; + + if (gtk_clist_get_selection_info (clist, x, y, &row, &column)) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + row, column, event); + } + + return FALSE; +} + +static void +gtk_clist_size_request (GtkWidget * widget, + GtkRequisition * requisition) +{ + gint i; + GtkCList *clist; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); + g_return_if_fail (requisition != NULL); + + clist = GTK_CLIST (widget); + + requisition->width = 0; + requisition->height = 0; + + /* compute the size of the column title (title) area */ + clist->column_title_area.height = 0; + for (i = 0; i < clist->columns; i++) + { + gtk_widget_size_request (clist->column[i].button, &clist->column[i].button->requisition); + clist->column_title_area.height = MAX (clist->column_title_area.height, + clist->column[i].button->requisition.height); + } + requisition->height += clist->column_title_area.height; + + /* add the vscrollbar space */ + if ((clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) || + GTK_WIDGET_VISIBLE (clist->vscrollbar)) + { + gtk_widget_size_request (clist->vscrollbar, &clist->vscrollbar->requisition); + + requisition->width += clist->vscrollbar->requisition.width; + requisition->height = MAX (requisition->height, + clist->vscrollbar->requisition.height); + } + + /* add the hscrollbar space */ + if ((clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) || + GTK_WIDGET_VISIBLE (clist->hscrollbar)) + { + gtk_widget_size_request (clist->hscrollbar, &clist->hscrollbar->requisition); + + requisition->height += clist->hscrollbar->requisition.height; + requisition->width = MAX (clist->hscrollbar->requisition.width, + requisition->width - + clist->vscrollbar->requisition.width); + + } + + requisition->width += widget->style->klass->xthickness * 2 + + GTK_CONTAINER (widget)->border_width * 2; + requisition->height += widget->style->klass->ythickness * 2 + + GTK_CONTAINER (widget)->border_width * 2; +} + +static void +gtk_clist_size_allocate (GtkWidget * widget, + GtkAllocation * allocation) +{ + GtkCList *clist; + GtkAllocation clist_allocation; + GtkAllocation child_allocation; + gint i, vscrollbar_vis, hscrollbar_vis; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); + g_return_if_fail (allocation != NULL); + + clist = GTK_CLIST (widget); + widget->allocation = *allocation; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x + GTK_CONTAINER (widget)->border_width, + allocation->y + GTK_CONTAINER (widget)->border_width, + allocation->width - GTK_CONTAINER (widget)->border_width * 2, + allocation->height - GTK_CONTAINER (widget)->border_width * 2); + + /* + * calculate internal size of the clist, compensating if + * there is no border + */ + if (clist->shadow_type == GTK_SHADOW_NONE) + { + clist->internal_allocation.x = 0; + clist->internal_allocation.y = 0; + clist->internal_allocation.width = allocation->width - + GTK_CONTAINER (widget)->border_width * 2; + clist->internal_allocation.height = allocation->height - + GTK_CONTAINER (widget)->border_width * 2; + } + else + { + clist->internal_allocation.x = widget->style->klass->xthickness; + clist->internal_allocation.y = widget->style->klass->ythickness; + clist->internal_allocation.width = allocation->width - + GTK_CONTAINER (widget)->border_width * 2 - + widget->style->klass->xthickness * 2; + clist->internal_allocation.height = allocation->height - + GTK_CONTAINER (widget)->border_width * 2 - + widget->style->klass->ythickness * 2; + } + + /* + * get the clist cell window allocated correctly + */ + clist_allocation.x = clist->internal_allocation.x; + clist_allocation.y = clist->internal_allocation.y + + clist->column_title_area.height; + clist_allocation.width = clist->internal_allocation.width; + clist_allocation.height = clist->internal_allocation.height - + clist->column_title_area.height; + + /* + * here's where we decide to show/not show the scrollbars + */ + vscrollbar_vis = 0; + hscrollbar_vis = 0; + + for (i = 0; i <= 1; i++) + { + if (LIST_HEIGHT (clist) <= clist_allocation.height && + clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) + { + vscrollbar_vis = 0; + } + else + { + if (!vscrollbar_vis) + { + vscrollbar_vis = 1; + clist_allocation.width -= clist->vscrollbar->requisition.width; + } + } + + if (LIST_WIDTH (clist) <= clist_allocation.width && + clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) + { + hscrollbar_vis = 0; + } + else + { + if (!hscrollbar_vis) + { + hscrollbar_vis = 1; + clist_allocation.height -= clist->hscrollbar->requisition.height; + } + } + } + + clist->clist_window_width = clist_allocation.width; + clist->clist_window_height = clist_allocation.height; + + gdk_window_move_resize (clist->clist_window, + clist_allocation.x, + clist_allocation.y, + clist_allocation.width, + clist_allocation.height); + + + /* + * position the window which holds the column title buttons + */ + clist->column_title_area.x = 0; + clist->column_title_area.y = 0; + clist->column_title_area.width = clist->internal_allocation.width - + (vscrollbar_vis ? clist->vscrollbar->requisition.width : 0); + + gdk_window_move_resize (clist->title_window, + clist->internal_allocation.x, + clist->internal_allocation.y, + clist->column_title_area.width, + clist->column_title_area.height); + + /* + * column button allocation + */ + gtk_clist_size_allocate_title_buttons (clist); + gtk_clist_size_allocate_columns (clist); + + /* + * allocate the vscrollbar + */ + if (vscrollbar_vis) + { + if (!GTK_WIDGET_VISIBLE (clist->vscrollbar)) + gtk_widget_show (clist->vscrollbar); + + child_allocation.x = clist->internal_allocation.x + + clist->internal_allocation.width - + clist->vscrollbar->requisition.width; + child_allocation.y = clist->internal_allocation.y; + child_allocation.width = clist->vscrollbar->requisition.width; + child_allocation.height = clist->internal_allocation.height - + (hscrollbar_vis ? clist->hscrollbar->requisition.height : 0); + + gtk_widget_size_allocate (clist->vscrollbar, &child_allocation); + } + else + { + if (GTK_WIDGET_VISIBLE (clist->vscrollbar)) + gtk_widget_hide (clist->vscrollbar); + } + + if (hscrollbar_vis) + { + if (!GTK_WIDGET_VISIBLE (clist->hscrollbar)) + gtk_widget_show (clist->hscrollbar); + + child_allocation.x = clist->internal_allocation.x; + child_allocation.y = clist->internal_allocation.y + + clist->internal_allocation.height - + clist->hscrollbar->requisition.height; + child_allocation.width = clist->internal_allocation.width - + (vscrollbar_vis ? clist->vscrollbar->requisition.width : 0); + child_allocation.height = clist->hscrollbar->requisition.height; + + gtk_widget_size_allocate (clist->hscrollbar, &child_allocation); + } + else + { + if (GTK_WIDGET_VISIBLE (clist->hscrollbar)) + gtk_widget_hide (clist->hscrollbar); + } + } + + /* + * set the vscrollbar adjustments + */ + gtk_clist_adjust_scrollbars (clist); +} + +static void +gtk_clist_size_allocate_title_buttons (GtkCList * clist) +{ + gint i; + GtkAllocation button_allocation; + + button_allocation.x = clist->hoffset; + button_allocation.y = 0; + button_allocation.height = clist->column_title_area.height; + + for (i = 0; i < clist->columns; i++) + { + button_allocation.width = clist->column[i].width; + + if (i == clist->columns - 1) + { + button_allocation.width += 2 * (CELL_SPACING + COLUMN_INSET); + + if (button_allocation.width < (clist->column_title_area.width - button_allocation.x)) + button_allocation.width = clist->column_title_area.width - button_allocation.x; + } + else + { + button_allocation.width += CELL_SPACING + (2 * COLUMN_INSET); + } + + gtk_widget_size_allocate (clist->column[i].button, &button_allocation); + button_allocation.x += button_allocation.width; + } +} + +static void +gtk_clist_size_allocate_columns (GtkCList * clist) +{ + gint i, xoffset; + + xoffset = 0; + + for (i = 0; i < clist->columns; i++) + { + clist->column[i].area.x = xoffset + CELL_SPACING + COLUMN_INSET; + + if (i == clist->columns - 1) + { + clist->column[i].area.width = MAX (clist->column[i].width, + clist->column_title_area.width - + xoffset - (2 * (CELL_SPACING + COLUMN_INSET))); + } + else + { + clist->column[i].area.width = clist->column[i].width; + } + + xoffset += clist->column[i].area.width + CELL_SPACING + (2 * COLUMN_INSET); + } +} + +static void +gtk_clist_foreach (GtkContainer * container, + GtkCallback callback, + gpointer callback_data) +{ + gint i; + GtkCList *clist; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_CLIST (container)); + g_return_if_fail (callback != NULL); + + clist = GTK_CLIST (container); + + /* callback for the column buttons */ + for (i = 0; i < clist->columns; i++) + (*callback) (clist->column[i].button, callback_data); + + /* callbacks for the scrollbars */ + (*callback) (clist->vscrollbar, callback_data); + (*callback) (clist->hscrollbar, callback_data); +} + +/* BUTTONS */ +static void +gtk_clist_column_button_realize (GtkWidget * widget, + gpointer data) +{ + GtkCList *clist; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (data)); + + clist = GTK_CLIST (data); + + if (widget->window && clist->title_window) + gdk_window_reparent (widget->window, clist->title_window, + widget->allocation.x, 0); +} + +static void +gtk_clist_column_button_clicked (GtkWidget * widget, + gpointer data) +{ + gint i; + GtkCList *clist; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (data)); + + clist = GTK_CLIST (data); + + /* find the column who's button was pressed */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button == widget) + break; + + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i); +} + +/* + * SCROLLBARS + * + * functions: + * gtk_clist_adjust_scrollbars + * gtk_clist_vadjustment_changed + * gtk_clist_hadjustment_changed + * gtk_clist_vadjustment_value_changed + * gtk_clist_hadjustment_value_changed + */ +static void +gtk_clist_adjust_scrollbars (GtkCList * clist) +{ + GTK_RANGE (clist->vscrollbar)->adjustment->page_size = clist->clist_window_height; + GTK_RANGE (clist->vscrollbar)->adjustment->page_increment = clist->clist_window_height / 2; + GTK_RANGE (clist->vscrollbar)->adjustment->step_increment = 10; + GTK_RANGE (clist->vscrollbar)->adjustment->lower = 0; + GTK_RANGE (clist->vscrollbar)->adjustment->upper = LIST_HEIGHT (clist); + + if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist)) + { + GTK_RANGE (clist->vscrollbar)->adjustment->value = LIST_HEIGHT (clist) - + clist->clist_window_height; + gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), + "value_changed"); + } + + GTK_RANGE (clist->hscrollbar)->adjustment->page_size = clist->clist_window_width; + GTK_RANGE (clist->hscrollbar)->adjustment->page_increment = clist->clist_window_width / 2; + GTK_RANGE (clist->hscrollbar)->adjustment->step_increment = 10; + GTK_RANGE (clist->hscrollbar)->adjustment->lower = 0; + GTK_RANGE (clist->hscrollbar)->adjustment->upper = LIST_WIDTH (clist); + + if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist)) + { + GTK_RANGE (clist->hscrollbar)->adjustment->value = LIST_WIDTH (clist) - + clist->clist_window_width; + gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), + "value_changed"); + } + + if (LIST_HEIGHT (clist) <= clist->clist_window_height && + clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) + { + if (GTK_WIDGET_VISIBLE (clist->vscrollbar)) + { + gtk_widget_hide (clist->vscrollbar); + gtk_widget_queue_resize (GTK_WIDGET (clist)); + } + } + else + { + if (!GTK_WIDGET_VISIBLE (clist->vscrollbar)) + { + gtk_widget_show (clist->vscrollbar); + gtk_widget_queue_resize (GTK_WIDGET (clist)); + } + } + + if (LIST_WIDTH (clist) <= clist->clist_window_width && + clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) + { + if (GTK_WIDGET_VISIBLE (clist->hscrollbar)) + { + gtk_widget_hide (clist->hscrollbar); + gtk_widget_queue_resize (GTK_WIDGET (clist)); + } + } + else + { + if (!GTK_WIDGET_VISIBLE (clist->hscrollbar)) + { + gtk_widget_show (clist->hscrollbar); + gtk_widget_queue_resize (GTK_WIDGET (clist)); + } + } + + gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed"); + gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), "changed"); +} + +static void +gtk_clist_vadjustment_changed (GtkAdjustment * adjustment, + gpointer data) +{ + GtkCList *clist; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + + clist = GTK_CLIST (data); +} + +static void +gtk_clist_hadjustment_changed (GtkAdjustment * adjustment, + gpointer data) +{ + GtkCList *clist; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + + clist = GTK_CLIST (data); +} + +static void +gtk_clist_vadjustment_value_changed (GtkAdjustment * adjustment, + gpointer data) +{ + GtkCList *clist; + GdkRectangle area; + gint diff, value; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + g_return_if_fail (GTK_IS_CLIST (data)); + + clist = GTK_CLIST (data); + + value = adjustment->value; + + if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar))) + { + if (value > -clist->voffset) + { + /* scroll down */ + diff = value + clist->voffset; + + /* we have to re-draw the whole screen here... */ + if (diff >= clist->clist_window_height) + { + clist->voffset = -value; + gtk_clist_draw_rows (clist, NULL); + return; + } + + gdk_window_copy_area (clist->clist_window, + GTK_WIDGET (clist)->style->white_gc, + 0, 0, + clist->clist_window, + 0, + diff, + clist->clist_window_width, + clist->clist_window_height - diff); + + area.x = 0; + area.y = clist->clist_window_height - diff; + area.width = clist->clist_window_width; + area.height = diff; + } + else + { + /* scroll up */ + diff = -clist->voffset - value; + + /* we have to re-draw the whole screen here... */ + if (diff >= clist->clist_window_height) + { + clist->voffset = -value; + gtk_clist_draw_rows (clist, NULL); + return; + } + + gdk_window_copy_area (clist->clist_window, + GTK_WIDGET (clist)->style->white_gc, + 0, diff, + clist->clist_window, + 0, + 0, + clist->clist_window_width, + clist->clist_window_height - diff); + + area.x = 0; + area.y = 0; + area.width = clist->clist_window_width; + area.height = diff; + + } + + clist->voffset = -value; + } + + gtk_clist_draw_rows (clist, &area); +} + +static void +gtk_clist_hadjustment_value_changed (GtkAdjustment * adjustment, + gpointer data) +{ + GtkCList *clist; + GdkRectangle area; + gint i, diff, value; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + g_return_if_fail (GTK_IS_CLIST (data)); + + clist = GTK_CLIST (data); + + value = adjustment->value; + + if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar))) + { + for (i = 0; i < clist->columns; i++) + { + clist->column[i].button->allocation.x -= value + clist->hoffset; + + if (clist->column[i].button->window) + gdk_window_move (clist->column[i].button->window, + clist->column[i].button->allocation.x, + clist->column[i].button->allocation.y); + } + + if (value > -clist->hoffset) + { + /* scroll right */ + diff = value + clist->hoffset; + + /* we have to re-draw the whole screen here... */ + if (diff >= clist->clist_window_width) + { + clist->hoffset = -value; + gtk_clist_draw_rows (clist, NULL); + return; + } + + gdk_window_copy_area (clist->clist_window, + GTK_WIDGET (clist)->style->white_gc, + 0, 0, + clist->clist_window, + diff, + 0, + clist->clist_window_width - diff, + clist->clist_window_height); + + area.x = clist->clist_window_width - diff; + area.y = 0; + area.width = diff; + area.height = clist->clist_window_height; + } + else + { + /* scroll left */ + diff = -clist->hoffset - value; + + /* we have to re-draw the whole screen here... */ + if (diff >= clist->clist_window_width) + { + clist->hoffset = -value; + gtk_clist_draw_rows (clist, NULL); + return; + } + + gdk_window_copy_area (clist->clist_window, + GTK_WIDGET (clist)->style->white_gc, + diff, 0, + clist->clist_window, + 0, + 0, + clist->clist_window_width - diff, + clist->clist_window_height); + + area.x = 0; + area.y = 0; + area.width = diff; + area.height = clist->clist_window_height; + } + + clist->hoffset = -value; + } + + gtk_clist_draw_rows (clist, &area); +} + +/* + * Memory Allocation/Distruction Routines for GtkCList stuctures + * + * functions: + * gtk_clist_columns_new + * gtk_clist_column_title_new + * gtk_clist_columns_delete + * gtk_clist_row_new + * gtk_clist_row_delete + * gtk_clist_cell_empty + * gtk_clist_cell_set_text + * gtk_clist_cell_set_pixmap + */ +static GtkCListColumn * +gtk_clist_columns_new (GtkCList * clist) +{ + gint i; + GtkCListColumn *column; + + column = g_new (GtkCListColumn, clist->columns); + + for (i = 0; i < clist->columns; i++) + { + column[i].area.x = 0; + column[i].area.y = 0; + column[i].area.width = 0; + column[i].area.height = 0; + column[i].title = NULL; + column[i].button = NULL; + column[i].width = 0; + column[i].justification = GTK_JUSTIFY_LEFT; + } + + return column; +} + +static void +gtk_clist_column_title_new (GtkCList * clist, + gint column, + gchar * title) +{ + if (clist->column[column].title) + g_free (clist->column[column].title); + + clist->column[column].title = g_strdup (title); +} + +static void +gtk_clist_columns_delete (GtkCList * clist) +{ + gint i; + + for (i = 0; i < clist->columns; i++) + if (clist->column[i].title) + g_free (clist->column[i].title); + + g_free (clist->column); +} + +static GtkCListRow * +gtk_clist_row_new (GtkCList * clist) +{ + int i; + GtkCListRow *clist_row; + + clist_row = g_chunk_new (GtkCListRow, clist->row_mem_chunk); + clist_row->cell = g_chunk_new (GtkCell, clist->cell_mem_chunk); + + for (i = 0; i < clist->columns; i++) + { + clist_row->cell[i].type = GTK_CELL_EMPTY; + clist_row->cell[i].verticle = 0; + clist_row->cell[i].horizontal = 0; + } + + clist_row->foreground = GTK_WIDGET (clist)->style->fg[GTK_STATE_NORMAL]; + clist_row->background = GTK_WIDGET (clist)->style->bg[GTK_STATE_PRELIGHT]; + clist_row->state = GTK_STATE_NORMAL; + clist_row->data = NULL; + + return clist_row; +} + +static void +gtk_clist_row_delete (GtkCList * clist, + GtkCListRow * clist_row) +{ + gint i; + + for (i = 0; i < clist->columns; i++) + gtk_clist_cell_empty (clist, clist_row, i); + + g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell); + g_mem_chunk_free (clist->row_mem_chunk, clist_row); + +} + +static void +gtk_clist_cell_empty (GtkCList * clist, + GtkCListRow * clist_row, + gint column) +{ + switch (clist_row->cell[column].type) + { + case GTK_CELL_EMPTY: + break; + + case GTK_CELL_TEXT: + g_free (GTK_CELL_TEXT (clist_row->cell[column])->text); + break; + + case GTK_CELL_PIXMAP: + gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap); + gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask); + break; + + case GTK_CELL_PIXTEXT: + g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text); + gdk_pixmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap); + gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask); + break; + + case GTK_CELL_WIDGET: + /* unimplimented */ + break; + + default: + break; + } + + clist_row->cell[column].type = GTK_CELL_EMPTY; +} + +static void +gtk_clist_cell_set_text (GtkCList * clist, + GtkCListRow * clist_row, + gint column, + gchar * text) +{ + gtk_clist_cell_empty (clist, clist_row, column); + + if (text) + { + clist_row->cell[column].type = GTK_CELL_TEXT; + GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text); + } +} + +static void +gtk_clist_cell_set_pixmap (GtkCList * clist, + GtkCListRow * clist_row, + gint column, + GdkPixmap * pixmap, + GdkBitmap * mask) +{ + gtk_clist_cell_empty (clist, clist_row, column); + + if (pixmap && mask) + { + clist_row->cell[column].type = GTK_CELL_PIXMAP; + GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap; + GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask; + } +} + +static void +gtk_clist_cell_set_pixtext (GtkCList * clist, + GtkCListRow * clist_row, + gint column, + gchar * text, + guint8 spacing, + GdkPixmap * pixmap, + GdkBitmap * mask) +{ + gtk_clist_cell_empty (clist, clist_row, column); + + if (text && pixmap && mask) + { + clist_row->cell[column].type = GTK_CELL_PIXTEXT; + GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text); + GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing; + GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap; + GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask; + } +} diff --git a/gtk/gtkclist.h b/gtk/gtkclist.h new file mode 100644 index 000000000..91ca04cd4 --- /dev/null +++ b/gtk/gtkclist.h @@ -0,0 +1,405 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald + * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_CLIST_H__ +#define __GTK_CLIST_H__ + +#include <gdk/gdk.h> +#include <gtk/gtksignal.h> +#include <gtk/gtkalignment.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkbutton.h> +#include <gtk/gtkhscrollbar.h> +#include <gtk/gtkvscrollbar.h> + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* clist flags */ +enum +{ + CLIST_FROZEN = 1 << 0, + CLIST_IN_DRAG = 1 << 1, + CLIST_ROW_HEIGHT_SET = 1 << 2 +}; + +/* cell types */ +typedef enum +{ + GTK_CELL_EMPTY, + GTK_CELL_TEXT, + GTK_CELL_PIXMAP, + GTK_CELL_PIXTEXT, + GTK_CELL_WIDGET +} GtkCellType; + +#define GTK_CLIST(obj) GTK_CHECK_CAST (obj, gtk_clist_get_type (), GtkCList) +#define GTK_CLIST_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_clist_get_type (), GtkCListClass) +#define GTK_IS_CLIST(obj) GTK_CHECK_TYPE (obj, gtk_clist_get_type ()) + +#define GTK_CLIST_FLAGS(clist) (GTK_CLIST (clist)->flags) +#define GTK_CLIST_SET_FLAGS(clist,flag) (GTK_CLIST_FLAGS (clist) |= (flag)) +#define GTK_CLIST_UNSET_FLAGS(clist,flag) (GTK_CLIST_FLAGS (clist) &= ~(flag)) + +#define GTK_CLIST_FROZEN(clist) (GTK_CLIST_FLAGS (clist) & CLIST_FROZEN) +#define GTK_CLIST_IN_DRAG(clist) (GTK_CLIST_FLAGS (clist) & CLIST_IN_DRAG) +#define GTK_CLIST_ROW_HEIGHT_SET(clist) (GTK_CLIST_FLAGS (clist) & CLIST_ROW_HEIGHT_SET) + +/* pointer casting for cells */ +#define GTK_CELL_TEXT(cell) (((GtkCellText *) &(cell))) +#define GTK_CELL_PIXMAP(cell) (((GtkCellPixmap *) &(cell))) +#define GTK_CELL_PIXTEXT(cell) (((GtkCellPixText *) &(cell))) +#define GTK_CELL_WIDGET(cell) (((GtkCellWidget *) &(cell))) + +typedef struct _GtkCList GtkCList; +typedef struct _GtkCListClass GtkCListClass; +typedef struct _GtkCListColumn GtkCListColumn; +typedef struct _GtkCListRow GtkCListRow; + +typedef struct _GtkCell GtkCell; +typedef struct _GtkCellText GtkCellText; +typedef struct _GtkCellPixmap GtkCellPixmap; +typedef struct _GtkCellPixText GtkCellPixText; +typedef struct _GtkCellWidget GtkCellWidget; + +struct _GtkCList +{ + GtkContainer container; + + guint8 flags; + + /* allocation rectangle after the conatiner_border_width + * and the width of the shadow border */ + GdkRectangle internal_allocation; + + /* memory chunks */ + GMemChunk *row_mem_chunk; + GMemChunk *cell_mem_chunk; + + /* rows */ + gint rows; + gint row_center_offset; + gint row_height; + GList *row_list; + GList *row_list_end; + + /* columns */ + gint columns; + GdkRectangle column_title_area; + GdkWindow *title_window; + + /* dynamicly allocated array of column structures */ + GtkCListColumn *column; + + /*the scrolling window and it's height and width to + * make things a little speedier */ + GdkWindow *clist_window; + gint clist_window_width; + gint clist_window_height; + + /* offsets for scrolling */ + gint hoffset; + gint voffset; + + /* border shadow style */ + GtkShadowType shadow_type; + + /* the list's selection mode (gtkenums.h) */ + GtkSelectionMode selection_mode; + + /* scrollbars */ + GtkWidget *vscrollbar; + GtkWidget *hscrollbar; + guint8 vscrollbar_policy; + guint8 hscrollbar_policy; + + /* xor GC for the verticle drag line */ + GdkGC *xor_gc; + + /* gc for drawing unselected cells */ + GdkGC *fg_gc; + GdkGC *bg_gc; + + /* cursor used to indicate dragging */ + GdkCursor *cursor_drag; + + /* the current x-pixel location of the xor-drag line */ + gint x_drag; +}; + +struct _GtkCListClass +{ + GtkContainerClass parent_class; + + void (*select_row) (GtkCList * clist, + gint row, + gint column, + GdkEventButton * event); + void (*unselect_row) (GtkCList * clist, + gint row, + gint column, + GdkEventButton * event); + void (*click_column) (GtkCList * clist, + gint column); +}; + +struct _GtkCListColumn +{ + gchar *title; + GdkRectangle area; + + GtkWidget *button; + gint width; + GtkJustification justification; +}; + +struct _GtkCListRow +{ + GtkCell *cell; + GtkStateType state; + + GdkColor foreground; + GdkColor background; + + gpointer data; +}; + +/* Cell Structures */ +struct _GtkCellText +{ + GtkCellType type; + + gint verticle; + gint horizontal; + + gchar *text; +}; + +struct _GtkCellPixmap +{ + GtkCellType type; + + gint verticle; + gint horizontal; + + GdkPixmap *pixmap; + GdkBitmap *mask; +}; + +struct _GtkCellPixText +{ + GtkCellType type; + + gint verticle; + gint horizontal; + + gchar *text; + guint8 spacing; + GdkPixmap *pixmap; + GdkBitmap *mask; +}; + +struct _GtkCellWidget +{ + GtkCellType type; + + gint verticle; + gint horizontal; + + GtkWidget *widget; +}; + +struct _GtkCell +{ + GtkCellType type; + + gint verticle; + gint horizontal; + + union { + gchar *text; + + struct { + GdkPixmap *pixmap; + GdkBitmap *mask; + } pm; + + struct { + gchar *text; + guint8 spacing; + GdkPixmap *pixmap; + GdkBitmap *mask; + } pt; + + GtkWidget *widget; + } u; +}; + +guint gtk_clist_get_type (void); + +/* create a new GtkCList */ +GtkWidget *gtk_clist_new (int columns, + gchar * titles[]); + +/* set the border style of the clist */ +void gtk_clist_set_border (GtkCList * clist, + GtkShadowType border); + +/* set the clist's selection mode */ +void gtk_clist_set_selection_mode (GtkCList * clist, + GtkSelectionMode mode); + +/* set policy on the scrollbar, to either show them all the time + * or show them only when they are needed, ie., when there is more than one page + * of information */ +void gtk_clist_set_policy (GtkCList * clist, + GtkPolicyType vscrollbar_policy, + GtkPolicyType hscrollbar_policy); + +/* freeze all visual updates of the list, and then thaw the list after you have made + * a number of changes and the updates wil occure in a more efficent mannor than if + * you made them on a unfrozen list */ +void gtk_clist_freeze (GtkCList * clist); +void gtk_clist_thaw (GtkCList * clist); + +/* set the title in the column title button */ +void gtk_clist_set_column_title (GtkCList * clist, + gint column, + gchar * title); + +/* set a widget instead of a title for the column title button */ +void gtk_clist_set_column_widget (GtkCList * clist, + gint column, + GtkWidget * widget); + +/* set the justification on a column */ +void gtk_clist_set_column_justification (GtkCList * clist, + gint column, + GtkJustification justification); + +/* set the pixel width of a column; this is a necessary step in + * creating a CList because otherwise the column width is chozen from + * the width of the column title, which will never be right */ +void gtk_clist_set_column_width (GtkCList * clist, + gint column, + gint width); + +/* change the height of the rows, the default is the hight of the current + * font */ +void gtk_clist_set_row_height (GtkCList * clist, + gint height); + +/* scroll the viewing area of the list to the given column + * and row; row_align and col_align are between 0-1 representing the + * location the row should appear on the screnn, 0.0 being top or left, + * 1.0 being bottom or right */ +void gtk_clist_moveto (GtkCList * clist, + gint row, + gint column, + gfloat row_align, + gfloat col_align); + +/* sets a given cell's text, replacing it's current contents */ +void gtk_clist_set_text (GtkCList * clist, + gint row, + gint column, + gchar * text); + +/* sets a given cell's pixmap, replacing it's current contents */ +void gtk_clist_set_pixmap (GtkCList * clist, + gint row, + gint column, + GdkPixmap * pixmap, + GdkBitmap * mask); + +/* sets a given cell's pixmap and text, replacing it's current contents */ +void gtk_clist_set_pixtext (GtkCList * clist, + gint row, + gint column, + gchar * text, + guint8 spacing, + GdkPixmap * pixmap, + GdkBitmap * mask); + +/* sets the foreground color of a row, the colar must already + * be allocated */ +void gtk_clist_set_foreground (GtkCList * clist, + gint row, + GdkColor * color); + +/* sets the background color of a row, the colar must already + * be allocated */ +void gtk_clist_set_background (GtkCList * clist, + gint row, + GdkColor * color); + +/* this sets a horizontal and verticle shift for drawing + * the contents of a cell; it can be positive or negitive; this is + * partuculary useful for indenting items in a column */ +void gtk_clist_set_shift (GtkCList * clist, + gint row, + gint column, + gint verticle, + gint horizontal); + +/* append returns the index of the row you just added, making + * it easier to append and modify a row */ +gint gtk_clist_append (GtkCList * clist, + gchar * text[]); + +/* inserts a row at index row */ +void gtk_clist_insert (GtkCList * clist, + gint row, + gchar * text[]); + +/* removes row at index row */ +void gtk_clist_remove (GtkCList * clist, + gint row); + +/* sets a arbitrary data pointer for a given row */ +void gtk_clist_set_row_data (GtkCList * clist, + gint row, + gpointer data); + +/* returns the data set for a row */ +gpointer gtk_clist_get_row_data (GtkCList * clist, + gint row); + +/* force selection of a row */ +void gtk_clist_select_row (GtkCList * clist, + gint row, + gint column); + +/* force unselection of a row */ +void gtk_clist_unselect_row (GtkCList * clist, + gint row, + gint column); + +/* clear the entire list -- this is much faster than removing each item + * with gtk_clist_remove */ +void gtk_clist_clear (GtkCList * clist); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_CLIST_H__ */ diff --git a/gtk/testgtk.c b/gtk/testgtk.c index b96b9b3d1..bfaa8ffb4 100644 --- a/gtk/testgtk.c +++ b/gtk/testgtk.c @@ -1559,6 +1559,108 @@ create_list () } void +create_clist () +{ + gint i; + static GtkWidget *window = NULL; + + static char *titles[] = + { + "Title 0", + "Title 1", + "Title 2", + "Title 3", + "Title 4", + "Title 5", + "Title 6" + }; + static int columns = sizeof (titles) / sizeof (titles[0]); + + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *clist; + GtkWidget *button; + GtkWidget *separator; + + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC(destroy_window), + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + GTK_SIGNAL_FUNC(destroy_window), + &window); + + gtk_window_set_title (GTK_WINDOW (window), "clist"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + clist = gtk_clist_new (columns, titles); + + gtk_clist_set_row_height (GTK_CLIST (clist), 20); + + for (i = 0; i < columns; i++) + gtk_clist_set_column_width (GTK_CLIST (clist), i, 50); + + gtk_clist_set_selection_mode (GTK_CLIST (clist), GTK_SELECTION_BROWSE); + + gtk_clist_set_policy (GTK_CLIST (clist), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + + gtk_clist_set_column_justification (GTK_CLIST (clist), 1, GTK_JUSTIFY_RIGHT); + gtk_clist_set_column_justification (GTK_CLIST (clist), 2, GTK_JUSTIFY_RIGHT); + + for (i = 0; i < 100; i++) + gtk_clist_append (GTK_CLIST (clist), titles); + + + gtk_container_border_width (GTK_CONTAINER (clist), 5); + gtk_box_pack_start (GTK_BOX (box2), clist, TRUE, TRUE, 0); + gtk_widget_show (clist); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT (window)); + + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); + +} + +void color_selection_ok (GtkWidget *w, GtkColorSelectionDialog *cs) { @@ -3529,6 +3631,7 @@ create_main_window () { "drawing areas", NULL }, { "entry", create_entry }, { "list", create_list }, + { "clist", create_clist}, { "color selection", create_color_selection }, { "file selection", create_file_selection }, { "dialog", create_dialog }, diff --git a/gtk/testgtkrc b/gtk/testgtkrc index 81d8855f7..1dc2304a3 100644 --- a/gtk/testgtkrc +++ b/gtk/testgtkrc @@ -28,8 +28,8 @@ style "scale" style "button" { - fg[PRELIGHT] = { 1.0, 1.0, 1.0 } - bg[PRELIGHT] = { 0, 0, 0.75 } +# fg[PRELIGHT] = { 1.0, 1.0, 1.0 } +# bg[PRELIGHT] = { 0, 0, 0.75 } } style "main_button" = "button" @@ -61,7 +61,7 @@ style "curve" fg[NORMAL] = { 58000, 0, 0 } # red } -widget_class "*" style "default" +#widget_class "*" style "default" widget_class "GtkWindow" style "window" widget_class "GtkDialog" style "window" widget_class "GtkFileSelection" style "window" diff --git a/tests/testgtk.c b/tests/testgtk.c index b96b9b3d1..bfaa8ffb4 100644 --- a/tests/testgtk.c +++ b/tests/testgtk.c @@ -1559,6 +1559,108 @@ create_list () } void +create_clist () +{ + gint i; + static GtkWidget *window = NULL; + + static char *titles[] = + { + "Title 0", + "Title 1", + "Title 2", + "Title 3", + "Title 4", + "Title 5", + "Title 6" + }; + static int columns = sizeof (titles) / sizeof (titles[0]); + + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *clist; + GtkWidget *button; + GtkWidget *separator; + + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC(destroy_window), + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + GTK_SIGNAL_FUNC(destroy_window), + &window); + + gtk_window_set_title (GTK_WINDOW (window), "clist"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + clist = gtk_clist_new (columns, titles); + + gtk_clist_set_row_height (GTK_CLIST (clist), 20); + + for (i = 0; i < columns; i++) + gtk_clist_set_column_width (GTK_CLIST (clist), i, 50); + + gtk_clist_set_selection_mode (GTK_CLIST (clist), GTK_SELECTION_BROWSE); + + gtk_clist_set_policy (GTK_CLIST (clist), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + + gtk_clist_set_column_justification (GTK_CLIST (clist), 1, GTK_JUSTIFY_RIGHT); + gtk_clist_set_column_justification (GTK_CLIST (clist), 2, GTK_JUSTIFY_RIGHT); + + for (i = 0; i < 100; i++) + gtk_clist_append (GTK_CLIST (clist), titles); + + + gtk_container_border_width (GTK_CONTAINER (clist), 5); + gtk_box_pack_start (GTK_BOX (box2), clist, TRUE, TRUE, 0); + gtk_widget_show (clist); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT (window)); + + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); + +} + +void color_selection_ok (GtkWidget *w, GtkColorSelectionDialog *cs) { @@ -3529,6 +3631,7 @@ create_main_window () { "drawing areas", NULL }, { "entry", create_entry }, { "list", create_list }, + { "clist", create_clist}, { "color selection", create_color_selection }, { "file selection", create_file_selection }, { "dialog", create_dialog }, diff --git a/tests/testgtkrc b/tests/testgtkrc index 81d8855f7..1dc2304a3 100644 --- a/tests/testgtkrc +++ b/tests/testgtkrc @@ -28,8 +28,8 @@ style "scale" style "button" { - fg[PRELIGHT] = { 1.0, 1.0, 1.0 } - bg[PRELIGHT] = { 0, 0, 0.75 } +# fg[PRELIGHT] = { 1.0, 1.0, 1.0 } +# bg[PRELIGHT] = { 0, 0, 0.75 } } style "main_button" = "button" @@ -61,7 +61,7 @@ style "curve" fg[NORMAL] = { 58000, 0, 0 } # red } -widget_class "*" style "default" +#widget_class "*" style "default" widget_class "GtkWindow" style "window" widget_class "GtkDialog" style "window" widget_class "GtkFileSelection" style "window" |