X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkclist.c;h=34396b6295c06faefbe95dd69f4f175df58eec63;hb=10ba4fd066042b4335ae45e7560565872f71ba9b;hp=ea1dc32033477f9207fc357bd7516f2143367841;hpb=3a5447574bd97c21fcf663f9c3947011ece48017;p=~andy%2Fgtk diff --git a/gtk/gtkclist.c b/gtk/gtkclist.c index ea1dc3203..34396b629 100644 --- a/gtk/gtkclist.c +++ b/gtk/gtkclist.c @@ -17,16 +17,28 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + #include #include -#include "../config.h" +#include "config.h" #include "gtkmain.h" #include "gtkclist.h" #include "gtkbindings.h" +#include "gtkdnd.h" #include +/* length of button_actions array */ +#define MAX_BUTTON 5 + /* the number rows memchunk expands at a time */ -#define CLIST_OPTIMUM_SIZE 512 +#define CLIST_OPTIMUM_SIZE 64 /* the width of the column resize windows */ #define DRAG_WIDTH 6 @@ -43,9 +55,6 @@ /* used for auto-scrolling */ #define SCROLL_TIME 100 -/* scrollbar spacing class macro */ -#define SCROLLBAR_SPACING(w) (GTK_CLIST_CLASS (GTK_OBJECT (w)->klass)->scrollbar_spacing) - /* 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)) + \ @@ -71,13 +80,14 @@ COLUMN_FROM_XPIXEL (GtkCList * clist, gint i, cx; for (i = 0; i < clist->columns; i++) - { - cx = clist->column[i].area.x + clist->hoffset; + if (clist->column[i].visible) + { + 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; - } + if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) && + x <= (cx + clist->column[i].area.width + COLUMN_INSET)) + return i; + } /* no match */ return -1; @@ -112,15 +122,27 @@ LIST_WIDTH (GtkCList * clist) return 0; } +/* returns the GList item for the nth row */ +#define ROW_ELEMENT(clist, row) (((row) == (clist)->rows - 1) ? \ + (clist)->row_list_end : \ + g_list_nth ((clist)->row_list, (row))) + + +#define GTK_CLIST_CLASS_FW(_widget_) GTK_CLIST_CLASS (((GtkObject*) (_widget_))->klass) -#define GTK_CLIST_CLASS_FW(_widget_) GTK_CLIST_CLASS (GTK_OBJECT (_widget_)->klass) +/* redraw the list if it's not frozen */ +#define CLIST_UNFROZEN(clist) (((GtkCList*) (clist))->freeze_count == 0) +#define CLIST_REFRESH(clist) G_STMT_START { \ + if (CLIST_UNFROZEN (clist)) \ + GTK_CLIST_CLASS_FW (clist)->refresh ((GtkCList*) (clist)); \ +} G_STMT_END /* Signals */ -enum -{ +enum { SELECT_ROW, UNSELECT_ROW, + ROW_MOVE, CLICK_COLUMN, RESIZE_COLUMN, TOGGLE_FOCUS_ROW, @@ -137,248 +159,308 @@ enum LAST_SIGNAL }; -enum -{ +enum { SYNC_REMOVE, SYNC_INSERT }; - -typedef void (*GtkCListSignal1) (GtkObject * object, - gint arg1, - gint arg2, - GdkEvent * arg3, - gpointer data); - -typedef void (*GtkCListSignal2) (GtkObject *object, - gpointer data); - -typedef void (*GtkCListSignal3) (GtkObject * object, - gint arg1, - gpointer data); -typedef void (*GtkCListSignal4) (GtkObject * object, - gint arg1, - gfloat arg2, - gpointer data); -typedef void (*GtkCListSignal5) (GtkObject * object, - gint arg1, - gfloat arg2, - gboolean arg3, - gpointer data); - - -static void sync_selection (GtkCList * clist, - gint row, - gint mode); +enum { + ARG_0, + ARG_N_COLUMNS, + ARG_SHADOW_TYPE, + ARG_SELECTION_MODE, + ARG_ROW_HEIGHT, + ARG_TITLES_ACTIVE, + ARG_REORDERABLE, + ARG_USE_DRAG_ICONS, + ARG_SORT_TYPE +}; /* GtkCList Methods */ -static void gtk_clist_class_init (GtkCListClass * klass); -static void gtk_clist_init (GtkCList * clist); -static void real_clear (GtkCList * clist); +static void gtk_clist_class_init (GtkCListClass *klass); +static void gtk_clist_init (GtkCList *clist); /* GtkObject Methods */ -static void gtk_clist_destroy (GtkObject * object); -static void gtk_clist_finalize (GtkObject * object); - +static void gtk_clist_destroy (GtkObject *object); +static void gtk_clist_finalize (GtkObject *object); +static void gtk_clist_set_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); +static void gtk_clist_get_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); /* 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 gint gtk_clist_button_release (GtkWidget * widget, - GdkEventButton * event); -static gint gtk_clist_motion (GtkWidget * widget, - GdkEventMotion * event); -static void gtk_clist_size_request (GtkWidget * widget, - GtkRequisition * requisition); -static void gtk_clist_size_allocate (GtkWidget * widget, - GtkAllocation * allocation); -static gint get_selection_info (GtkCList * clist, - gint x, - gint y, - gint * row, - gint * column); +static void gtk_clist_set_scroll_adjustments (GtkCList *clist, + GtkAdjustment *hadjustment, + GtkAdjustment *vadjustment); +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_key_press (GtkWidget *widget, + GdkEventKey *event); +static gint gtk_clist_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_clist_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_clist_motion (GtkWidget *widget, + GdkEventMotion *event); +static void gtk_clist_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_clist_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_clist_draw_focus (GtkWidget *widget); +static gint gtk_clist_focus_in (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_clist_focus_out (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_clist_focus (GtkContainer *container, + GtkDirectionType direction); +static void gtk_clist_style_set (GtkWidget *widget, + GtkStyle *previous_style); +static void gtk_clist_drag_begin (GtkWidget *widget, + GdkDragContext *context); +static gint gtk_clist_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time); +static void gtk_clist_drag_leave (GtkWidget *widget, + GdkDragContext *context, + guint time); +static void gtk_clist_drag_end (GtkWidget *widget, + GdkDragContext *context); +static gboolean gtk_clist_drag_drop (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time); +static void gtk_clist_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time); +static void gtk_clist_drag_data_received (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time); /* GtkContainer Methods */ -static void gtk_clist_forall (GtkContainer *container, - gboolean include_internals, - GtkCallback callback, - gpointer callback_data); - -/* Drawing */ -static void draw_row (GtkCList * clist, - GdkRectangle * area, - gint row, - GtkCListRow * clist_row); -static void draw_rows (GtkCList * clist, - GdkRectangle * area); - -/* Size Allocation */ -static void size_allocate_title_buttons (GtkCList * clist); -static void size_allocate_columns (GtkCList * clist); +static void gtk_clist_set_focus_child (GtkContainer *container, + GtkWidget *child); +static void gtk_clist_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); /* Selection */ -static void toggle_row (GtkCList * clist, - gint row, - gint column, - GdkEvent * event); -static void select_row (GtkCList * clist, - gint row, - gint column, - GdkEvent * event); -static void unselect_row (GtkCList * clist, - gint row, - gint column, - GdkEvent * event); -static void real_select_row (GtkCList * clist, - gint row, - gint column, - GdkEvent * event); -static void real_unselect_row (GtkCList * clist, - gint row, - gint column, - GdkEvent * event); -static void update_extended_selection (GtkCList *clist, - gint row); -static GList * selection_find (GtkCList *clist, - gint row_number, - GList *row_list_element); -static void real_select_all (GtkCList * clist); -static void real_unselect_all (GtkCList * clist); -static void move_vertical (GtkCList *clist, - gint row, - gfloat align); -static void move_horizontal (GtkCList *clist, - gint diff); -static void real_undo_selection (GtkCList * clist); -static void fake_unselect_all (GtkCList *clist, - gint row); -static void fake_toggle_row (GtkCList *clist, - gint row); -static void resync_selection (GtkCList *clist, - GdkEvent *event); +static void toggle_row (GtkCList *clist, + gint row, + gint column, + GdkEvent *event); +static void real_select_row (GtkCList *clist, + gint row, + gint column, + GdkEvent *event); +static void real_unselect_row (GtkCList *clist, + gint row, + gint column, + GdkEvent *event); +static void update_extended_selection (GtkCList *clist, + gint row); +static GList *selection_find (GtkCList *clist, + gint row_number, + GList *row_list_element); +static void real_select_all (GtkCList *clist); +static void real_unselect_all (GtkCList *clist); +static void move_vertical (GtkCList *clist, + gint row, + gfloat align); +static void move_horizontal (GtkCList *clist, + gint diff); +static void real_undo_selection (GtkCList *clist); +static void fake_unselect_all (GtkCList *clist, + gint row); +static void fake_toggle_row (GtkCList *clist, + gint row); +static void resync_selection (GtkCList *clist, + GdkEvent *event); +static void sync_selection (GtkCList *clist, + gint row, + gint mode); +static void set_anchor (GtkCList *clist, + gboolean add_mode, + gint anchor, + gint undo_anchor); +static void start_selection (GtkCList *clist); +static void end_selection (GtkCList *clist); +static void toggle_add_mode (GtkCList *clist); +static void toggle_focus_row (GtkCList *clist); +static void extend_selection (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position, + gboolean auto_start_selection); +static gint get_selection_info (GtkCList *clist, + gint x, + gint y, + gint *row, + gint *column); + +/* Scrolling */ +static void move_focus_row (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position); +static void scroll_horizontal (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position); +static void scroll_vertical (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position); +static void move_horizontal (GtkCList *clist, + gint diff); +static void move_vertical (GtkCList *clist, + gint row, + gfloat align); +static gint horizontal_timeout (GtkCList *clist); +static gint vertical_timeout (GtkCList *clist); +static void remove_grab (GtkCList *clist); + /* Resize Columns */ -static void draw_xor_line (GtkCList * clist); -static gint new_column_width (GtkCList * clist, - gint column, - gint * x); -static void real_resize_column (GtkCList * clist, - gint column, - gint width); -static void resize_column (GtkCList * clist, - gint column, - gint width); -static void abort_column_resize (GtkCList *clist); +static void draw_xor_line (GtkCList *clist); +static gint new_column_width (GtkCList *clist, + gint column, + gint *x); +static void column_auto_resize (GtkCList *clist, + GtkCListRow *clist_row, + gint column, + gint old_width); +static void real_resize_column (GtkCList *clist, + gint column, + gint width); +static void abort_column_resize (GtkCList *clist); +static void cell_size_request (GtkCList *clist, + GtkCListRow *clist_row, + gint column, + GtkRequisition *requisition); /* Buttons */ -static void column_button_create (GtkCList * clist, - gint column); -static void column_button_clicked (GtkWidget * widget, - gpointer data); - -/* Scrollbars */ -static void create_scrollbars (GtkCList * clist); -static void adjust_scrollbars (GtkCList * clist); -static void check_exposures (GtkCList * clist); -static void vadjustment_changed (GtkAdjustment * adjustment, - gpointer data); -static void vadjustment_value_changed (GtkAdjustment * adjustment, - gpointer data); -static void hadjustment_changed (GtkAdjustment * adjustment, - gpointer data); -static void hadjustment_value_changed (GtkAdjustment * adjustment, - gpointer data); +static void column_button_create (GtkCList *clist, + gint column); +static void column_button_clicked (GtkWidget *widget, + gpointer data); + +/* Adjustments */ +static void adjust_adjustments (GtkCList *clist, + gboolean block_resize); +static void check_exposures (GtkCList *clist); +static void vadjustment_changed (GtkAdjustment *adjustment, + gpointer data); +static void vadjustment_value_changed (GtkAdjustment *adjustment, + gpointer data); +static void hadjustment_changed (GtkAdjustment *adjustment, + gpointer data); +static void hadjustment_value_changed (GtkAdjustment *adjustment, + gpointer data); + +/* Drawing */ +static void get_cell_style (GtkCList *clist, + GtkCListRow *clist_row, + gint state, + gint column, + GtkStyle **style, + GdkGC **fg_gc, + GdkGC **bg_gc); +static gint draw_cell_pixmap (GdkWindow *window, + GdkRectangle *clip_rectangle, + GdkGC *fg_gc, + GdkPixmap *pixmap, + GdkBitmap *mask, + gint x, + gint y, + gint width, + gint height); +static void draw_row (GtkCList *clist, + GdkRectangle *area, + gint row, + GtkCListRow *clist_row); +static void draw_rows (GtkCList *clist, + GdkRectangle *area); +static void clist_refresh (GtkCList *clist); +static void draw_drag_highlight (GtkCList *clist, + GtkCListRow *dest_row, + gint dest_row_number, + GtkCListDragPos drag_pos); + +/* Size Allocation / Requisition */ +static void size_allocate_title_buttons (GtkCList *clist); +static void size_allocate_columns (GtkCList *clist, + gboolean block_resize); +static gint list_requisition_width (GtkCList *clist); /* Memory Allocation/Distruction Routines */ -static GtkCListColumn *columns_new (GtkCList * clist); - -static void column_title_new (GtkCList *clist, - gint column, - const gchar *title); -static void columns_delete (GtkCList * clist); - -static GtkCListRow *row_new (GtkCList * clist); - -static void row_delete (GtkCList * clist, - GtkCListRow * clist_row); -static void set_cell_contents (GtkCList *clist, - GtkCListRow *clist_row, - gint column, - GtkCellType type, - const gchar *text, - guint8 spacing, - GdkPixmap *pixmap, - GdkBitmap *mask); -static gint real_insert_row (GtkCList * clist, - gint row, - gchar * text[]); -static void real_remove_row (GtkCList * clist, - gint row); - -/* Focus handling */ -static void gtk_clist_draw_focus (GtkWidget *widget); -static gint gtk_clist_focus_in (GtkWidget *widget, - GdkEventFocus *event); -static gint gtk_clist_focus_out (GtkWidget *widget, - GdkEventFocus *event); -static gint gtk_clist_focus (GtkContainer *container, - GtkDirectionType direction); -static void gtk_clist_set_focus_child (GtkContainer *container, - GtkWidget *child); -static gint gtk_clist_key_press (GtkWidget *widget, - GdkEventKey *event); - -/* Selection handling */ -static void set_anchor (GtkCList *clist, - gboolean add_mode, - gint anchor, - gint undo_anchor); -static void start_selection (GtkCList *clist); -static void end_selection (GtkCList *clist); - -static void toggle_add_mode (GtkCList *clist); -static void toggle_focus_row (GtkCList *clist); -static void move_focus_row (GtkCList *clist, - GtkScrollType scroll_type, - gfloat position); -static void scroll_horizontal (GtkCList *clist, - GtkScrollType scroll_type, - gfloat position); -static void scroll_vertical (GtkCList *clist, - GtkScrollType scroll_type, - gfloat position); -static void extend_selection (GtkCList *clist, - GtkScrollType scroll_type, - gfloat position, - gboolean auto_start_selection); +static GtkCListColumn *columns_new (GtkCList *clist); +static void column_title_new (GtkCList *clist, + gint column, + const gchar *title); +static void columns_delete (GtkCList *clist); +static GtkCListRow *row_new (GtkCList *clist); +static void row_delete (GtkCList *clist, + GtkCListRow *clist_row); +static void set_cell_contents (GtkCList *clist, + GtkCListRow *clist_row, + gint column, + GtkCellType type, + const gchar *text, + guint8 spacing, + GdkPixmap *pixmap, + GdkBitmap *mask); +static gint real_insert_row (GtkCList *clist, + gint row, + gchar *text[]); +static void real_remove_row (GtkCList *clist, + gint row); +static void real_clear (GtkCList *clist); /* Sorting */ -static gint default_compare (GtkCList *clist, - gconstpointer row1, - gconstpointer row2); -static GList * gtk_clist_merge (GtkCList *clist, - GList *a, - GList *b); -static GList * gtk_clist_mergesort (GtkCList *clist, - GList *list, - gint num); -static void real_sort_list (GtkCList *clist); +static gint default_compare (GtkCList *clist, + gconstpointer row1, + gconstpointer row2); +static void real_sort_list (GtkCList *clist); +static GList *gtk_clist_merge (GtkCList *clist, + GList *a, + GList *b); +static GList *gtk_clist_mergesort (GtkCList *clist, + GList *list, + gint num); +/* Misc */ +static gboolean title_focus (GtkCList *clist, + gint dir); +static void real_row_move (GtkCList *clist, + gint source_row, + gint dest_row); +static gint column_title_passive_func (GtkWidget *widget, + GdkEvent *event, + gpointer data); +static void drag_dest_cell (GtkCList *clist, + gint x, + gint y, + GtkCListDestInfo *dest_info); -/* Fill in data after widget is realized and has style */ -static void add_style_data (GtkCList * clist); static GtkContainerClass *parent_class = NULL; static guint clist_signals[LAST_SIGNAL] = {0}; +static GtkTargetEntry clist_target_table = { "gtk-clist-drag-reorder", 0, 0}; GtkType gtk_clist_get_type (void) @@ -387,7 +469,7 @@ gtk_clist_get_type (void) if (!clist_type) { - GtkTypeInfo clist_info = + static const GtkTypeInfo clist_info = { "GtkCList", sizeof (GtkCList), @@ -406,11 +488,12 @@ gtk_clist_get_type (void) } static void -gtk_clist_class_init (GtkCListClass * klass) +gtk_clist_class_init (GtkCListClass *klass) { GtkObjectClass *object_class; GtkWidgetClass *widget_class; GtkContainerClass *container_class; + GtkBindingSet *binding_set; object_class = (GtkObjectClass *) klass; widget_class = (GtkWidgetClass *) klass; @@ -418,6 +501,52 @@ gtk_clist_class_init (GtkCListClass * klass) parent_class = gtk_type_class (GTK_TYPE_CONTAINER); + gtk_object_add_arg_type ("GtkCList::n_columns", + GTK_TYPE_UINT, + GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT_ONLY, + ARG_N_COLUMNS); + gtk_object_add_arg_type ("GtkCList::shadow_type", + GTK_TYPE_SHADOW_TYPE, + GTK_ARG_READWRITE, + ARG_SHADOW_TYPE); + gtk_object_add_arg_type ("GtkCList::selection_mode", + GTK_TYPE_SELECTION_MODE, + GTK_ARG_READWRITE, + ARG_SELECTION_MODE); + gtk_object_add_arg_type ("GtkCList::row_height", + GTK_TYPE_UINT, + GTK_ARG_READWRITE, + ARG_ROW_HEIGHT); + gtk_object_add_arg_type ("GtkCList::reorderable", + GTK_TYPE_BOOL, + GTK_ARG_READWRITE, + ARG_REORDERABLE); + gtk_object_add_arg_type ("GtkCList::titles_active", + GTK_TYPE_BOOL, + GTK_ARG_READWRITE, + ARG_TITLES_ACTIVE); + gtk_object_add_arg_type ("GtkCList::use_drag_icons", + GTK_TYPE_BOOL, + GTK_ARG_READWRITE, + ARG_USE_DRAG_ICONS); + gtk_object_add_arg_type ("GtkCList::sort_type", + GTK_TYPE_SORT_TYPE, + GTK_ARG_READWRITE, + ARG_SORT_TYPE); + object_class->set_arg = gtk_clist_set_arg; + object_class->get_arg = gtk_clist_get_arg; + object_class->destroy = gtk_clist_destroy; + object_class->finalize = gtk_clist_finalize; + + + widget_class->set_scroll_adjustments_signal = + gtk_signal_new ("set_scroll_adjustments", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkCListClass, set_scroll_adjustments), + gtk_marshal_NONE__POINTER_POINTER, + GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT); + clist_signals[SELECT_ROW] = gtk_signal_new ("select_row", GTK_RUN_FIRST, @@ -434,7 +563,15 @@ gtk_clist_class_init (GtkCListClass * klass) object_class->type, GTK_SIGNAL_OFFSET (GtkCListClass, unselect_row), gtk_marshal_NONE__INT_INT_POINTER, - GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_GDK_EVENT); + GTK_TYPE_NONE, 3, GTK_TYPE_INT, + GTK_TYPE_INT, GTK_TYPE_GDK_EVENT); + clist_signals[ROW_MOVE] = + gtk_signal_new ("row_move", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkCListClass, row_move), + gtk_marshal_NONE__INT_INT, + GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); clist_signals[CLICK_COLUMN] = gtk_signal_new ("click_column", GTK_RUN_FIRST, @@ -528,13 +665,8 @@ gtk_clist_class_init (GtkCListClass * klass) GTK_SIGNAL_OFFSET (GtkCListClass, abort_column_resize), gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); - - gtk_object_class_add_signals (object_class, clist_signals, LAST_SIGNAL); - object_class->destroy = gtk_clist_destroy; - object_class->finalize = gtk_clist_finalize; - widget_class->realize = gtk_clist_realize; widget_class->unrealize = gtk_clist_unrealize; widget_class->map = gtk_clist_map; @@ -550,21 +682,34 @@ gtk_clist_class_init (GtkCListClass * klass) widget_class->focus_in_event = gtk_clist_focus_in; widget_class->focus_out_event = gtk_clist_focus_out; widget_class->draw_focus = gtk_clist_draw_focus; + widget_class->style_set = gtk_clist_style_set; + widget_class->drag_begin = gtk_clist_drag_begin; + widget_class->drag_end = gtk_clist_drag_end; + widget_class->drag_motion = gtk_clist_drag_motion; + widget_class->drag_leave = gtk_clist_drag_leave; + widget_class->drag_drop = gtk_clist_drag_drop; + widget_class->drag_data_get = gtk_clist_drag_data_get; + widget_class->drag_data_received = gtk_clist_drag_data_received; /* container_class->add = NULL; use the default GtkContainerClass warning */ - /* container_class->remove = NULL; use the default GtkContainerClass warning */ + /* container_class->remove=NULL; use the default GtkContainerClass warning */ + container_class->forall = gtk_clist_forall; container_class->focus = gtk_clist_focus; container_class->set_focus_child = gtk_clist_set_focus_child; + klass->set_scroll_adjustments = gtk_clist_set_scroll_adjustments; + klass->refresh = clist_refresh; klass->select_row = real_select_row; klass->unselect_row = real_unselect_row; + klass->row_move = real_row_move; klass->undo_selection = real_undo_selection; klass->resync_selection = resync_selection; klass->selection_find = selection_find; klass->click_column = NULL; klass->resize_column = real_resize_column; klass->draw_row = draw_row; + klass->draw_drag_highlight = draw_drag_highlight; klass->insert_row = real_insert_row; klass->remove_row = real_remove_row; klass->clear = real_clear; @@ -581,221 +726,213 @@ gtk_clist_class_init (GtkCListClass * klass) klass->end_selection = end_selection; klass->abort_column_resize = abort_column_resize; klass->set_cell_contents = set_cell_contents; + klass->cell_size_request = cell_size_request; + + binding_set = gtk_binding_set_by_class (klass); + gtk_binding_entry_add_signal (binding_set, GDK_Up, 0, + "scroll_vertical", 2, + GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD, + GTK_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_Down, 0, + "scroll_vertical", 2, + GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD, + GTK_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0, + "scroll_vertical", 2, + GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD, + GTK_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0, + "scroll_vertical", 2, + GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD, + GTK_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK, + "scroll_vertical", 2, + GTK_TYPE_ENUM, GTK_SCROLL_JUMP, + GTK_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK, + "scroll_vertical", 2, + GTK_TYPE_ENUM, GTK_SCROLL_JUMP, + GTK_TYPE_FLOAT, 1.0); + + gtk_binding_entry_add_signal (binding_set, GDK_Up, GDK_SHIFT_MASK, + "extend_selection", 3, + GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD, + GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_Down, GDK_SHIFT_MASK, + "extend_selection", 3, + GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD, + GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, GDK_SHIFT_MASK, + "extend_selection", 3, + GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD, + GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, GDK_SHIFT_MASK, + "extend_selection", 3, + GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD, + GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_Home, + GDK_SHIFT_MASK | GDK_CONTROL_MASK, + "extend_selection", 3, + GTK_TYPE_ENUM, GTK_SCROLL_JUMP, + GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_End, + GDK_SHIFT_MASK | GDK_CONTROL_MASK, + "extend_selection", 3, + GTK_TYPE_ENUM, GTK_SCROLL_JUMP, + GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE); + + gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, + "scroll_horizontal", 2, + GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD, + GTK_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, + "scroll_horizontal", 2, + GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD, + GTK_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_Home, 0, + "scroll_horizontal", 2, + GTK_TYPE_ENUM, GTK_SCROLL_JUMP, + GTK_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_End, 0, + "scroll_horizontal", 2, + GTK_TYPE_ENUM, GTK_SCROLL_JUMP, + GTK_TYPE_FLOAT, 1.0); + + gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0, + "undo_selection", 0); + gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0, + "abort_column_resize", 0); + gtk_binding_entry_add_signal (binding_set, GDK_space, 0, + "toggle_focus_row", 0); + gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, + "toggle_add_mode", 0); + gtk_binding_entry_add_signal (binding_set, '/', GDK_CONTROL_MASK, + "select_all", 0); + gtk_binding_entry_add_signal (binding_set, '\\', GDK_CONTROL_MASK, + "unselect_all", 0); + gtk_binding_entry_add_signal (binding_set, GDK_Shift_L, + GDK_RELEASE_MASK | GDK_SHIFT_MASK, + "end_selection", 0); + gtk_binding_entry_add_signal (binding_set, GDK_Shift_R, + GDK_RELEASE_MASK | GDK_SHIFT_MASK, + "end_selection", 0); + gtk_binding_entry_add_signal (binding_set, GDK_Shift_L, + GDK_RELEASE_MASK | GDK_SHIFT_MASK | + GDK_CONTROL_MASK, + "end_selection", 0); + gtk_binding_entry_add_signal (binding_set, GDK_Shift_R, + GDK_RELEASE_MASK | GDK_SHIFT_MASK | + GDK_CONTROL_MASK, + "end_selection", 0); +} - klass->scrollbar_spacing = 5; +static void +gtk_clist_set_arg (GtkObject *object, + GtkArg *arg, + guint arg_id) +{ + GtkCList *clist; - { - GtkBindingSet *binding_set; - - binding_set = gtk_binding_set_by_class (klass); - gtk_binding_entry_add_signal (binding_set, GDK_Up, 0, - "scroll_vertical", 2, - GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD, - GTK_TYPE_FLOAT, 0.0); - gtk_binding_entry_add_signal (binding_set, GDK_Down, 0, - "scroll_vertical", 2, - GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD, - GTK_TYPE_FLOAT, 0.0); - gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0, - "scroll_vertical", 2, - GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD, - GTK_TYPE_FLOAT, 0.0); - gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0, - "scroll_vertical", 2, - GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD, - GTK_TYPE_FLOAT, 0.0); - gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK, - "scroll_vertical", 2, - GTK_TYPE_ENUM, GTK_SCROLL_JUMP, - GTK_TYPE_FLOAT, 0.0); - gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK, - "scroll_vertical", 2, - GTK_TYPE_ENUM, GTK_SCROLL_JUMP, - GTK_TYPE_FLOAT, 1.0); - - gtk_binding_entry_add_signal (binding_set, GDK_Up, GDK_SHIFT_MASK, - "extend_selection", 3, - GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD, - GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_Down, GDK_SHIFT_MASK, - "extend_selection", 3, - GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD, - GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, GDK_SHIFT_MASK, - "extend_selection", 3, - GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD, - GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, GDK_SHIFT_MASK, - "extend_selection", 3, - GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD, - GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_Home, - GDK_SHIFT_MASK | GDK_CONTROL_MASK, - "extend_selection", 3, - GTK_TYPE_ENUM, GTK_SCROLL_JUMP, - GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_End, - GDK_SHIFT_MASK | GDK_CONTROL_MASK, - "extend_selection", 3, - GTK_TYPE_ENUM, GTK_SCROLL_JUMP, - GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE); - - - gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, - "scroll_horizontal", 2, - GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD, - GTK_TYPE_FLOAT, 0.0); - gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, - "scroll_horizontal", 2, - GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD, - GTK_TYPE_FLOAT, 0.0); - gtk_binding_entry_add_signal (binding_set, GDK_Home, 0, - "scroll_horizontal", 2, - GTK_TYPE_ENUM, GTK_SCROLL_JUMP, - GTK_TYPE_FLOAT, 0.0); - gtk_binding_entry_add_signal (binding_set, GDK_End, 0, - "scroll_horizontal", 2, - GTK_TYPE_ENUM, GTK_SCROLL_JUMP, - GTK_TYPE_FLOAT, 1.0); - - - gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0, - "undo_selection", 0); - gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0, - "abort_column_resize", 0); - gtk_binding_entry_add_signal (binding_set, GDK_space, 0, - "toggle_focus_row", 0); - gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, - "toggle_add_mode", 0); - gtk_binding_entry_add_signal (binding_set, '/', GDK_CONTROL_MASK, - "select_all", 0); - gtk_binding_entry_add_signal (binding_set, '\\', GDK_CONTROL_MASK, - "unselect_all", 0); - gtk_binding_entry_add_signal (binding_set, GDK_Shift_L, - GDK_RELEASE_MASK | GDK_SHIFT_MASK, - "end_selection", 0); - gtk_binding_entry_add_signal (binding_set, GDK_Shift_R, - GDK_RELEASE_MASK | GDK_SHIFT_MASK, - "end_selection", 0); - gtk_binding_entry_add_signal (binding_set, GDK_Shift_L, - GDK_RELEASE_MASK | GDK_SHIFT_MASK | - GDK_CONTROL_MASK, - "end_selection", 0); - gtk_binding_entry_add_signal (binding_set, GDK_Shift_R, - GDK_RELEASE_MASK | GDK_SHIFT_MASK | - GDK_CONTROL_MASK, - "end_selection", 0); - } + clist = GTK_CLIST (object); - /* - { - GtkBindingSet *binding_set; - - binding_set = gtk_binding_set_by_class (klass); - gtk_binding_entry_add_signal (binding_set, GDK_Up, 0, - "scroll_vertical", 2, - GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD, - GTK_TYPE_FLOAT, 0.0); - gtk_binding_entry_add_signal (binding_set, GDK_Down, 0, - "scroll_vertical", 2, - GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD, - GTK_TYPE_FLOAT, 0.0); - gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0, - "scroll_vertical", 2, - GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD, - GTK_TYPE_FLOAT, 0.0); - gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0, - "scroll_vertical", 2, - GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD, - GTK_TYPE_FLOAT, 0.0); - gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK, - "scroll_vertical", 2, - GTK_TYPE_ENUM, GTK_SCROLL_JUMP, - GTK_TYPE_FLOAT, 0.0); - gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK, - "scroll_vertical", 2, - GTK_TYPE_ENUM, GTK_SCROLL_JUMP, - GTK_TYPE_FLOAT, 0); - - gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0, - "extend_selection", 3, - GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD, - GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0, - "extend_selection", 3, - GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD, - GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Up, 0, - "extend_selection", 3, - GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD, - GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Down, 0, - "extend_selection", 3, - GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD, - GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, 0, - "extend_selection", 3, - GTK_TYPE_ENUM, GTK_SCROLL_JUMP, - GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_End, 0, - "extend_selection", 3, - GTK_TYPE_ENUM, GTK_SCROLL_JUMP, - GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE); - - gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, - "scroll_horizontal", 2, - GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD, - GTK_TYPE_FLOAT, 0.0); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0, - "scroll_horizontal", 2, - GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD, - GTK_TYPE_FLOAT, 0.0); - gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, - "scroll_horizontal", 2, - GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD, - GTK_TYPE_FLOAT, 0.0); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0, - "scroll_horizontal", 2, - GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD, - GTK_TYPE_FLOAT, 0.0); - gtk_binding_entry_add_signal (binding_set, GDK_Home, 0, - "scroll_horizontal", 2, - GTK_TYPE_ENUM, GTK_SCROLL_JUMP, - GTK_TYPE_FLOAT, 0.0); - gtk_binding_entry_add_signal (binding_set, GDK_End, 0, - "sroll_horizontal", 2, - GTK_TYPE_ENUM, GTK_SCROLL_JUMP, - GTK_TYPE_FLOAT, 1.0); - - gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, 0, - "undo_selection", 0); - gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0, - "abort_column_resize", 0); - gtk_binding_entry_add_signal (binding_set, GDK_space, 0, - "toggle_focus_row", 0); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0, - "toggle_add_mode", 0); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0, - "select_all", 0); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0, - "unselect_all", 0); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, - "end_selection", 0); - } - */ + switch (arg_id) + { + case ARG_N_COLUMNS: /* construct-only arg, only set when !GTK_CONSTRUCTED */ + gtk_clist_construct (clist, MAX (1, GTK_VALUE_UINT (*arg)), NULL); + break; + case ARG_SHADOW_TYPE: + gtk_clist_set_shadow_type (clist, GTK_VALUE_ENUM (*arg)); + break; + case ARG_SELECTION_MODE: + gtk_clist_set_selection_mode (clist, GTK_VALUE_ENUM (*arg)); + break; + case ARG_ROW_HEIGHT: + gtk_clist_set_row_height (clist, GTK_VALUE_UINT (*arg)); + break; + case ARG_REORDERABLE: + gtk_clist_set_reorderable (clist, GTK_VALUE_BOOL (*arg)); + break; + case ARG_TITLES_ACTIVE: + if (GTK_VALUE_BOOL (*arg)) + gtk_clist_column_titles_active (clist); + else + gtk_clist_column_titles_passive (clist); + break; + case ARG_USE_DRAG_ICONS: + gtk_clist_set_use_drag_icons (clist, GTK_VALUE_BOOL (*arg)); + break; + case ARG_SORT_TYPE: + gtk_clist_set_sort_type (clist, GTK_VALUE_ENUM (*arg)); + break; + } } static void -gtk_clist_init (GtkCList * clist) +gtk_clist_get_arg (GtkObject *object, + GtkArg *arg, + guint arg_id) +{ + GtkCList *clist; + + clist = GTK_CLIST (object); + + switch (arg_id) + { + guint i; + + case ARG_N_COLUMNS: + GTK_VALUE_UINT (*arg) = clist->columns; + break; + case ARG_SHADOW_TYPE: + GTK_VALUE_ENUM (*arg) = clist->shadow_type; + break; + case ARG_SELECTION_MODE: + GTK_VALUE_ENUM (*arg) = clist->selection_mode; + break; + case ARG_ROW_HEIGHT: + GTK_VALUE_UINT (*arg) = GTK_CLIST_ROW_HEIGHT_SET(clist) ? clist->row_height : 0; + break; + case ARG_REORDERABLE: + GTK_VALUE_BOOL (*arg) = GTK_CLIST_REORDERABLE (clist); + break; + case ARG_TITLES_ACTIVE: + GTK_VALUE_BOOL (*arg) = TRUE; + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button && + !GTK_WIDGET_SENSITIVE (clist->column[i].button)) + { + GTK_VALUE_BOOL (*arg) = FALSE; + break; + } + break; + case ARG_USE_DRAG_ICONS: + GTK_VALUE_BOOL (*arg) = GTK_CLIST_USE_DRAG_ICONS (clist); + break; + case ARG_SORT_TYPE: + GTK_VALUE_ENUM (*arg) = clist->sort_type; + break; + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +static void +gtk_clist_init (GtkCList *clist) { clist->flags = 0; GTK_WIDGET_UNSET_FLAGS (clist, GTK_NO_WINDOW); - GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN); + GTK_WIDGET_SET_FLAGS (clist, GTK_CAN_FOCUS); + GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS); + GTK_CLIST_SET_FLAG (clist, CLIST_DRAW_DRAG_LINE); + GTK_CLIST_SET_FLAG (clist, CLIST_USE_DRAG_ICONS); clist->row_mem_chunk = NULL; clist->cell_mem_chunk = NULL; + clist->freeze_count = 0; + clist->rows = 0; clist->row_center_offset = 0; clist->row_height = 0; @@ -818,8 +955,14 @@ gtk_clist_init (GtkCList * clist) clist->voffset = 0; clist->shadow_type = GTK_SHADOW_IN; - clist->hscrollbar_policy = GTK_POLICY_ALWAYS; - clist->vscrollbar_policy = GTK_POLICY_ALWAYS; + clist->vadjustment = NULL; + clist->hadjustment = NULL; + + clist->button_actions[0] = GTK_BUTTON_SELECTS | GTK_BUTTON_DRAGS; + clist->button_actions[1] = GTK_BUTTON_IGNORED; + clist->button_actions[2] = GTK_BUTTON_IGNORED; + clist->button_actions[3] = GTK_BUTTON_IGNORED; + clist->button_actions[4] = GTK_BUTTON_IGNORED; clist->cursor_drag = NULL; clist->xor_gc = NULL; @@ -833,8 +976,6 @@ gtk_clist_init (GtkCList * clist) clist->undo_selection = NULL; clist->undo_unselection = NULL; - GTK_WIDGET_SET_FLAGS (clist, GTK_CAN_FOCUS); - GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS); clist->focus_row = -1; clist->undo_anchor = -1; @@ -844,6 +985,9 @@ gtk_clist_init (GtkCList * clist) clist->htimer = 0; clist->vtimer = 0; + clist->click_cell.row = -1; + clist->click_cell.column = -1; + clist->compare = default_compare; clist->sort_type = GTK_SORT_ASCENDING; clist->sort_column = 0; @@ -851,17 +995,17 @@ gtk_clist_init (GtkCList * clist) /* Constructors */ void -gtk_clist_construct (GtkCList * clist, - gint columns, - gchar *titles[]) +gtk_clist_construct (GtkCList *clist, + gint columns, + gchar *titles[]) { - int i; - g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - g_return_if_fail (GTK_CLIST_CONSTRUCTED (clist) == FALSE); + g_return_if_fail (columns > 0); + g_return_if_fail (GTK_OBJECT_CONSTRUCTED (clist) == FALSE); - GTK_CLIST_SET_FLAG (clist, CLIST_CONSTRUCTED); + /* mark the object as constructed */ + gtk_object_constructed (GTK_OBJECT (clist)); /* initalize memory chunks, if this has not been done by any * possibly derived widget @@ -869,13 +1013,15 @@ gtk_clist_construct (GtkCList * clist, if (!clist->row_mem_chunk) clist->row_mem_chunk = g_mem_chunk_new ("clist row mem chunk", sizeof (GtkCListRow), - sizeof (GtkCListRow) * CLIST_OPTIMUM_SIZE, + sizeof (GtkCListRow) * + CLIST_OPTIMUM_SIZE, G_ALLOC_AND_FREE); if (!clist->cell_mem_chunk) clist->cell_mem_chunk = g_mem_chunk_new ("clist cell mem chunk", sizeof (GtkCell) * columns, - sizeof (GtkCell) * columns * CLIST_OPTIMUM_SIZE, + sizeof (GtkCell) * columns * + CLIST_OPTIMUM_SIZE, G_ALLOC_AND_FREE); /* set number of columns, allocate memory */ @@ -887,11 +1033,10 @@ gtk_clist_construct (GtkCList * clist, * isn't there*/ column_button_create (clist, 0); - /* create scrollbars */ - create_scrollbars (clist); - if (titles) { + guint i; + GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES); for (i = 0; i < columns; i++) gtk_clist_set_column_title (clist, i, titles[i]); @@ -902,55 +1047,163 @@ gtk_clist_construct (GtkCList * clist, } } -/* - * GTKCLIST PUBLIC INTERFACE - * gtk_clist_new_with_titles +/* GTKCLIST PUBLIC INTERFACE * gtk_clist_new + * gtk_clist_new_with_titles + * gtk_clist_set_hadjustment + * gtk_clist_set_vadjustment + * gtk_clist_get_hadjustment + * gtk_clist_get_vadjustment + * gtk_clist_set_shadow_type + * gtk_clist_set_selection_mode + * gtk_clist_freeze + * gtk_clist_thaw */ -GtkWidget * -gtk_clist_new_with_titles (gint columns, - gchar * titles[]) +GtkWidget* +gtk_clist_new (gint columns) +{ + return gtk_clist_new_with_titles (columns, NULL); +} + +GtkWidget* +gtk_clist_new_with_titles (gint columns, + gchar *titles[]) { GtkWidget *widget; - g_return_val_if_fail (titles != NULL, NULL); - widget = gtk_type_new (GTK_TYPE_CLIST); - gtk_clist_construct (GTK_CLIST (widget), columns, titles); return widget; } -GtkWidget * -gtk_clist_new (gint columns) +void +gtk_clist_set_hadjustment (GtkCList *clist, + GtkAdjustment *adjustment) { - GtkCList *clist; + GtkAdjustment *old_adjustment; - if (columns < 1) - return NULL; + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + if (adjustment) + g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); + + if (clist->hadjustment == adjustment) + return; + + old_adjustment = clist->hadjustment; + + if (clist->hadjustment) + { + gtk_signal_disconnect_by_data (GTK_OBJECT (clist->hadjustment), clist); + gtk_object_unref (GTK_OBJECT (clist->hadjustment)); + } + + clist->hadjustment = adjustment; + + if (clist->hadjustment) + { + gtk_object_ref (GTK_OBJECT (clist->hadjustment)); + gtk_object_sink (GTK_OBJECT (clist->hadjustment)); + + gtk_signal_connect (GTK_OBJECT (clist->hadjustment), "changed", + (GtkSignalFunc) hadjustment_changed, + (gpointer) clist); + gtk_signal_connect (GTK_OBJECT (clist->hadjustment), "value_changed", + (GtkSignalFunc) hadjustment_value_changed, + (gpointer) clist); + } + + if (!clist->hadjustment || !old_adjustment) + gtk_widget_queue_resize (GTK_WIDGET (clist)); +} + +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 clist->hadjustment; +} + +void +gtk_clist_set_vadjustment (GtkCList *clist, + GtkAdjustment *adjustment) +{ + GtkAdjustment *old_adjustment; + + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + if (adjustment) + g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); + + if (clist->vadjustment == adjustment) + return; + + old_adjustment = clist->vadjustment; + + if (clist->vadjustment) + { + gtk_signal_disconnect_by_data (GTK_OBJECT (clist->vadjustment), clist); + gtk_object_unref (GTK_OBJECT (clist->vadjustment)); + } + + clist->vadjustment = adjustment; + + if (clist->vadjustment) + { + gtk_object_ref (GTK_OBJECT (clist->vadjustment)); + gtk_object_sink (GTK_OBJECT (clist->vadjustment)); + + gtk_signal_connect (GTK_OBJECT (clist->vadjustment), "changed", + (GtkSignalFunc) vadjustment_changed, + (gpointer) clist); + gtk_signal_connect (GTK_OBJECT (clist->vadjustment), "value_changed", + (GtkSignalFunc) vadjustment_value_changed, + (gpointer) clist); + } + + if (!clist->vadjustment || !old_adjustment) + gtk_widget_queue_resize (GTK_WIDGET (clist)); +} - clist = gtk_type_new (GTK_TYPE_CLIST); - gtk_clist_construct (clist, columns, NULL); - return GTK_WIDGET (clist); +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 clist->vadjustment; +} + +static void +gtk_clist_set_scroll_adjustments (GtkCList *clist, + GtkAdjustment *hadjustment, + GtkAdjustment *vadjustment) +{ + if (clist->hadjustment != hadjustment) + gtk_clist_set_hadjustment (clist, hadjustment); + if (clist->vadjustment != vadjustment) + gtk_clist_set_vadjustment (clist, vadjustment); } void -gtk_clist_set_border (GtkCList * clist, - GtkShadowType border) +gtk_clist_set_shadow_type (GtkCList *clist, + GtkShadowType type) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - clist->shadow_type = border; + clist->shadow_type = type; if (GTK_WIDGET_VISIBLE (clist)) gtk_widget_queue_resize (GTK_WIDGET (clist)); } void -gtk_clist_set_selection_mode (GtkCList * clist, - GtkSelectionMode mode) +gtk_clist_set_selection_mode (GtkCList *clist, + GtkSelectionMode mode) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); @@ -982,242 +1235,182 @@ gtk_clist_set_selection_mode (GtkCList * clist, } void -gtk_clist_freeze (GtkCList * clist) +gtk_clist_freeze (GtkCList *clist) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN); + clist->freeze_count++; } void -gtk_clist_thaw (GtkCList * clist) +gtk_clist_thaw (GtkCList *clist) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN); - - adjust_scrollbars (clist); - draw_rows (clist, NULL); -} - + if (clist->freeze_count) + { + clist->freeze_count--; + CLIST_REFRESH (clist); + } +} + +/* PUBLIC COLUMN FUNCTIONS + * gtk_clist_column_titles_show + * gtk_clist_column_titles_hide + * gtk_clist_column_title_active + * gtk_clist_column_title_passive + * gtk_clist_column_titles_active + * gtk_clist_column_titles_passive + * gtk_clist_set_column_title + * gtk_clist_get_column_title + * gtk_clist_set_column_widget + * gtk_clist_set_column_justification + * gtk_clist_set_column_visibility + * gtk_clist_set_column_resizeable + * gtk_clist_set_column_auto_resize + * gtk_clist_optimal_column_width + * gtk_clist_set_column_width + * gtk_clist_set_column_min_width + * gtk_clist_set_column_max_width + */ void -gtk_clist_column_titles_show (GtkCList * clist) +gtk_clist_column_titles_show (GtkCList *clist) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (!GTK_CLIST_SHOW_TITLES (clist)) + if (!GTK_CLIST_SHOW_TITLES(clist)) { GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES); if (clist->title_window) - gdk_window_show (clist->title_window); + gdk_window_show (clist->title_window); gtk_widget_queue_resize (GTK_WIDGET (clist)); } } void -gtk_clist_column_titles_hide (GtkCList * clist) +gtk_clist_column_titles_hide (GtkCList *clist) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (GTK_CLIST_SHOW_TITLES (clist)) + if (GTK_CLIST_SHOW_TITLES(clist)) { GTK_CLIST_UNSET_FLAG (clist, CLIST_SHOW_TITLES); if (clist->title_window) - gdk_window_hide (clist->title_window); + gdk_window_hide (clist->title_window); gtk_widget_queue_resize (GTK_WIDGET (clist)); } } void -gtk_clist_set_column_visibility (GtkCList *clist, - gint column, - gboolean visible) +gtk_clist_column_title_active (GtkCList *clist, + gint column) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); if (column < 0 || column >= clist->columns) return; - if (clist->column[column].visible == visible) + if (!clist->column[column].button || !clist->column[column].button_passive) return; - /* don't hide last visible column */ - if (!visible) - { - gint i; - gint vis_columns = 0; - - for (i = 0, vis_columns = 0; i < clist->columns && vis_columns < 2; i++) - if (clist->column[i].visible) - vis_columns++; + clist->column[column].button_passive = FALSE; - if (vis_columns < 2) - return; - } + gtk_signal_disconnect_by_func (GTK_OBJECT (clist->column[column].button), + (GtkSignalFunc) column_title_passive_func, + NULL); - clist->column[column].visible = visible; - if (visible) - gtk_widget_show (clist->column[column].button); - else - gtk_widget_hide (clist->column[column].button); + GTK_WIDGET_SET_FLAGS (clist->column[column].button, GTK_CAN_FOCUS); + if (GTK_WIDGET_VISIBLE (clist)) + gtk_widget_queue_draw (clist->column[column].button); } void -gtk_clist_set_column_resizeable (GtkCList *clist, - gint column, - gint resizeable) +gtk_clist_column_title_passive (GtkCList *clist, + gint column) { + GtkButton *button; + g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); if (column < 0 || column >= clist->columns) return; - if (clist->column[column].resizeable == resizeable) + if (!clist->column[column].button || clist->column[column].button_passive) return; - clist->column[column].resizeable = resizeable; - - if (GTK_WIDGET_VISIBLE (clist)) - size_allocate_title_buttons (clist); -} + button = GTK_BUTTON (clist->column[column].button); -void -gtk_clist_set_column_min_width (GtkCList *clist, - gint column, - gint min_width) -{ - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + clist->column[column].button_passive = TRUE; - if (column < 0 || column >= clist->columns) - return; - if (clist->column[column].min_width == min_width) - return; + if (button->button_down) + gtk_button_released (button); + if (button->in_button) + gtk_button_leave (button); - if (clist->column[column].max_width >= 0 && - clist->column[column].max_width < min_width) - clist->column[column].min_width = clist->column[column].max_width; - else - clist->column[column].min_width = min_width; + gtk_signal_connect (GTK_OBJECT (clist->column[column].button), "event", + (GtkSignalFunc) column_title_passive_func, NULL); - if (clist->column[column].area.width < clist->column[column].min_width) - gtk_clist_set_column_width (clist, column,clist->column[column].min_width); + GTK_WIDGET_UNSET_FLAGS (clist->column[column].button, GTK_CAN_FOCUS); + if (GTK_WIDGET_VISIBLE (clist)) + gtk_widget_queue_draw (clist->column[column].button); } void -gtk_clist_set_column_max_width (GtkCList * clist, - gint column, - gint max_width) +gtk_clist_column_titles_active (GtkCList *clist) { + gint i; + g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (column < 0 || column >= clist->columns) - return; - if (clist->column[column].max_width == max_width) + if (!GTK_CLIST_SHOW_TITLES(clist)) return; - if (clist->column[column].min_width >= 0 && max_width >= 0 && - clist->column[column].min_width > max_width) - clist->column[column].max_width = clist->column[column].min_width; - else - clist->column[column].max_width = max_width; - - if (clist->column[column].area.width > clist->column[column].max_width) - gtk_clist_set_column_width (clist, column,clist->column[column].max_width); + for (i = 0; i < clist->columns; i++) + gtk_clist_column_title_active (clist, i); } void -gtk_clist_column_title_active (GtkCList * clist, - gint column) +gtk_clist_column_titles_passive (GtkCList *clist) { + gint i; + g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (column < 0 || column >= clist->columns) + if (!GTK_CLIST_SHOW_TITLES(clist)) return; - if (!GTK_WIDGET_SENSITIVE (clist->column[column].button) || - !GTK_WIDGET_CAN_FOCUS (clist->column[column].button)) - { - GTK_WIDGET_SET_FLAGS (clist->column[column].button, - GTK_SENSITIVE | GTK_CAN_FOCUS); - if (GTK_WIDGET_VISIBLE (clist)) - gtk_widget_queue_draw (clist->column[column].button); - } + for (i = 0; i < clist->columns; i++) + gtk_clist_column_title_passive (clist, i); } void -gtk_clist_column_title_passive (GtkCList * clist, - gint column) +gtk_clist_set_column_title (GtkCList *clist, + gint column, + const gchar *title) { + gint new_button = 0; + GtkWidget *old_widget; + GtkWidget *alignment = NULL; + GtkWidget *label; + g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); if (column < 0 || column >= clist->columns) return; - if (GTK_WIDGET_SENSITIVE (clist->column[column].button) || - GTK_WIDGET_CAN_FOCUS (clist->column[column].button)) + /* if the column button doesn't currently exist, + * it has to be created first */ + if (!clist->column[column].button) { - GTK_WIDGET_UNSET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS); - if (GTK_WIDGET_VISIBLE (clist)) - gtk_widget_queue_draw (clist->column[column].button); - } -} - -void -gtk_clist_column_titles_active (GtkCList * clist) -{ - gint i; - - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - for (i = 0; i < clist->columns; i++) - if (clist->column[i].button) - gtk_clist_column_title_active (clist, i); -} - -void -gtk_clist_column_titles_passive (GtkCList * clist) -{ - gint i; - - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - for (i = 0; i < clist->columns; i++) - if (clist->column[i].button) - gtk_clist_column_title_passive (clist, i); -} - -void -gtk_clist_set_column_title (GtkCList *clist, - gint column, - const gchar *title) -{ - gint new_button = 0; - GtkWidget *old_widget; - GtkWidget *alignment = NULL; - GtkWidget *label; - - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - if (column < 0 || column >= clist->columns) - return; - - /* if the column button doesn't currently exist, - * it has to be created first */ - if (!clist->column[column].button) - { - column_button_create (clist, column); - new_button = 1; + column_button_create (clist, column); + new_button = 1; } column_title_new (clist, column, title); @@ -1247,7 +1440,9 @@ gtk_clist_set_column_title (GtkCList *clist, break; } + gtk_widget_push_composite_child (); label = gtk_label_new (clist->column[column].title); + gtk_widget_pop_composite_child (); gtk_container_add (GTK_CONTAINER (alignment), label); gtk_container_add (GTK_CONTAINER (clist->column[column].button), alignment); gtk_widget_show (label); @@ -1259,10 +1454,23 @@ gtk_clist_set_column_title (GtkCList *clist, size_allocate_title_buttons (clist); } +gchar * +gtk_clist_get_column_title (GtkCList *clist, + gint column) +{ + g_return_val_if_fail (clist != NULL, NULL); + g_return_val_if_fail (GTK_IS_CLIST (clist), NULL); + + if (column < 0 || column >= clist->columns) + return NULL; + + return clist->column[column].title; +} + void -gtk_clist_set_column_widget (GtkCList * clist, - gint column, - GtkWidget * widget) +gtk_clist_set_column_widget (GtkCList *clist, + gint column, + GtkWidget *widget) { gint new_button = 0; GtkWidget *old_widget; @@ -1286,7 +1494,8 @@ gtk_clist_set_column_widget (GtkCList * clist, /* remove and destroy the old widget */ old_widget = GTK_BIN (clist->column[column].button)->child; if (old_widget) - gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget); + gtk_container_remove (GTK_CONTAINER (clist->column[column].button), + old_widget); /* add and show the widget */ if (widget) @@ -1301,10 +1510,26 @@ gtk_clist_set_column_widget (GtkCList * clist, size_allocate_title_buttons (clist); } +GtkWidget * +gtk_clist_get_column_widget (GtkCList *clist, + gint column) +{ + g_return_val_if_fail (clist != NULL, NULL); + g_return_val_if_fail (GTK_IS_CLIST (clist), NULL); + + if (column < 0 || column >= clist->columns) + return NULL; + + if (clist->column[column].button) + return GTK_BUTTON (clist->column[column].button)->child; + + return NULL; +} + void -gtk_clist_set_column_justification (GtkCList * clist, - gint column, - GtkJustification justification) +gtk_clist_set_column_justification (GtkCList *clist, + gint column, + GtkJustification justification) { GtkWidget *alignment; @@ -1345,4563 +1570,5180 @@ gtk_clist_set_column_justification (GtkCList * clist, } } - if (!GTK_CLIST_FROZEN (clist)) + if (CLIST_UNFROZEN (clist)) draw_rows (clist, NULL); } -static void -real_resize_column (GtkCList * clist, - gint column, - gint width) +void +gtk_clist_set_column_visibility (GtkCList *clist, + gint column, + gboolean visible) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); if (column < 0 || column >= clist->columns) return; + if (clist->column[column].visible == visible) + return; - if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width)) - width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width); - if (clist->column[column].max_width >= 0 && - width > clist->column[column].max_width) - width = clist->column[column].max_width; - - clist->column[column].width = width; - clist->column[column].width_set = TRUE; + /* don't hide last visible column */ + if (!visible) + { + gint i; + gint vis_columns = 0; - /* FIXME: this is quite expensive to do if the widget hasn't - * been size_allocated yet, and pointless. Should - * a flag be kept - */ - size_allocate_columns (clist); - size_allocate_title_buttons (clist); + for (i = 0, vis_columns = 0; i < clist->columns && vis_columns < 2; i++) + if (clist->column[i].visible) + vis_columns++; + + if (vis_columns < 2) + return; + } - if (!GTK_CLIST_FROZEN (clist)) + clist->column[column].visible = visible; + + if (clist->column[column].button) { - adjust_scrollbars (clist); - draw_rows (clist, NULL); + if (visible) + gtk_widget_show (clist->column[column].button); + else + gtk_widget_hide (clist->column[column].button); } + + gtk_widget_queue_resize (GTK_WIDGET(clist)); } void -gtk_clist_set_column_width (GtkCList * clist, - gint column, - gint width) +gtk_clist_set_column_resizeable (GtkCList *clist, + gint column, + gboolean resizeable) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); if (column < 0 || column >= clist->columns) return; + if (clist->column[column].resizeable == resizeable) + return; - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[RESIZE_COLUMN], - column, width); + clist->column[column].resizeable = resizeable; + if (resizeable) + clist->column[column].auto_resize = FALSE; + + if (GTK_WIDGET_VISIBLE (clist)) + size_allocate_title_buttons (clist); } void -gtk_clist_set_row_height (GtkCList * clist, - gint height) +gtk_clist_set_column_auto_resize (GtkCList *clist, + gint column, + gboolean auto_resize) { - gint text_height; - g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (height > 0) - clist->row_height = height; - else + if (column < 0 || column >= clist->columns) + return; + if (clist->column[column].auto_resize == auto_resize) return; - GTK_CLIST_SET_FLAG (clist, CLIST_ROW_HEIGHT_SET); - - if (GTK_WIDGET_REALIZED (clist)) - { - 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)) + clist->column[column].auto_resize = auto_resize; + if (auto_resize) { - adjust_scrollbars (clist); - draw_rows (clist, NULL); + clist->column[column].resizeable = FALSE; + if (!GTK_CLIST_AUTO_RESIZE_BLOCKED(clist)) + { + gint width; + + width = gtk_clist_optimal_column_width (clist, column); + gtk_clist_set_column_width (clist, column, width); + } } + + if (GTK_WIDGET_VISIBLE (clist)) + size_allocate_title_buttons (clist); } -void -gtk_clist_moveto (GtkCList * clist, - gint row, - gint column, - gfloat row_align, - gfloat col_align) +gint +gtk_clist_columns_autosize (GtkCList *clist) { - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - if (row < -1 || row >= clist->rows) - return; - if (column < -1 || column >= clist->columns) - return; + gint i; + gint width; - row_align = CLAMP (row_align, 0, 1); - col_align = CLAMP (col_align, 0, 1); + g_return_val_if_fail (clist != NULL, 0); + g_return_val_if_fail (GTK_IS_CLIST (clist), 0); - /* adjust horizontal scrollbar */ - if (column >= 0) + gtk_clist_freeze (clist); + width = 0; + for (i = 0; i < clist->columns; i++) { - GtkAdjustment *adj; - gint x; + gtk_clist_set_column_width (clist, i, + gtk_clist_optimal_column_width (clist, i)); - adj = GTK_RANGE (clist->hscrollbar)->adjustment; - - x = COLUMN_LEFT (clist, column) - CELL_SPACING - COLUMN_INSET - - (col_align * (clist->clist_window_width - 2 * COLUMN_INSET - - CELL_SPACING - clist->column[column].area.width)); - if (x < 0) - gtk_adjustment_set_value (adj, 0.0); - else if (x > LIST_WIDTH (clist) - clist->clist_window_width) - gtk_adjustment_set_value - (adj, LIST_WIDTH (clist) - clist->clist_window_width); - else - gtk_adjustment_set_value (adj, x); + width += clist->column[i].width; } - /* adjust vertical scrollbar */ - if (row >= 0) - move_vertical (clist, row, row_align); + gtk_clist_thaw (clist); + return width; } -GtkCellType -gtk_clist_get_cell_type (GtkCList * clist, - gint row, - gint column) +gint +gtk_clist_optimal_column_width (GtkCList *clist, + gint column) { - GtkCListRow *clist_row; + GtkRequisition requisition; + GList *list; + gint width; - g_return_val_if_fail (clist != NULL, -1); - g_return_val_if_fail (GTK_IS_CLIST (clist), -1); + g_return_val_if_fail (clist != NULL, 0); + g_return_val_if_fail (GTK_CLIST (clist), 0); - if (row < 0 || row >= clist->rows) - return -1; - if (column < 0 || column >= clist->columns) - return -1; + if (column < 0 || column > clist->columns) + return 0; + + if (GTK_CLIST_SHOW_TITLES(clist) && clist->column[column].button) + width = (clist->column[column].button->requisition.width) +#if 0 + (CELL_SPACING + (2 * COLUMN_INSET))) +#endif + ; + else + width = 0; - clist_row = (g_list_nth (clist->row_list, row))->data; + for (list = clist->row_list; list; list = list->next) + { + GTK_CLIST_CLASS_FW (clist)->cell_size_request + (clist, GTK_CLIST_ROW (list), column, &requisition); + width = MAX (width, requisition.width); + } - return clist_row->cell[column].type; + return width; } void -gtk_clist_set_text (GtkCList *clist, - gint row, - gint column, - const gchar *text) +gtk_clist_set_column_width (GtkCList *clist, + gint column, + gint width) { - GtkCListRow *clist_row; - g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - 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 */ - GTK_CLIST_CLASS_FW (clist)->set_cell_contents - (clist, clist_row, column, GTK_CELL_TEXT, text, 0, NULL, NULL); - - /* redraw the list if it's not frozen */ - if (!GTK_CLIST_FROZEN (clist)) - { - if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); - } + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[RESIZE_COLUMN], + column, width); } -gint -gtk_clist_get_text (GtkCList * clist, - gint row, - gint column, - gchar ** text) +void +gtk_clist_set_column_min_width (GtkCList *clist, + gint column, + gint min_width) { - GtkCListRow *clist_row; - - g_return_val_if_fail (clist != NULL, 0); - g_return_val_if_fail (GTK_IS_CLIST (clist), 0); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - if (row < 0 || row >= clist->rows) - return 0; if (column < 0 || column >= clist->columns) - return 0; - - clist_row = (g_list_nth (clist->row_list, row))->data; - - if (clist_row->cell[column].type != GTK_CELL_TEXT) - return 0; + return; + if (clist->column[column].min_width == min_width) + return; - if (text) - *text = GTK_CELL_TEXT (clist_row->cell[column])->text; + if (clist->column[column].max_width >= 0 && + clist->column[column].max_width < min_width) + clist->column[column].min_width = clist->column[column].max_width; + else + clist->column[column].min_width = min_width; - return 1; + if (clist->column[column].area.width < clist->column[column].min_width) + gtk_clist_set_column_width (clist, column,clist->column[column].min_width); } void -gtk_clist_set_pixmap (GtkCList * clist, - gint row, - gint column, - GdkPixmap * pixmap, - GdkBitmap * mask) +gtk_clist_set_column_max_width (GtkCList *clist, + gint column, + gint max_width) { - GtkCListRow *clist_row; - g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (row < 0 || row >= clist->rows) - return; if (column < 0 || column >= clist->columns) return; + if (clist->column[column].max_width == max_width) + return; - clist_row = (g_list_nth (clist->row_list, row))->data; - - gdk_pixmap_ref (pixmap); - - if (mask) gdk_pixmap_ref (mask); + if (clist->column[column].min_width >= 0 && max_width >= 0 && + clist->column[column].min_width > max_width) + clist->column[column].max_width = clist->column[column].min_width; + else + clist->column[column].max_width = max_width; - GTK_CLIST_CLASS_FW (clist)->set_cell_contents - (clist, clist_row, column, GTK_CELL_PIXMAP, NULL, 0, pixmap, mask); - - /* redraw the list if it's not frozen */ - if (!GTK_CLIST_FROZEN (clist)) - { - if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); - } + if (clist->column[column].area.width > clist->column[column].max_width) + gtk_clist_set_column_width (clist, column,clist->column[column].max_width); } -gint -gtk_clist_get_pixmap (GtkCList * clist, - gint row, - gint column, - GdkPixmap ** pixmap, - GdkBitmap ** mask) -{ - GtkCListRow *clist_row; - - g_return_val_if_fail (clist != NULL, 0); - g_return_val_if_fail (GTK_IS_CLIST (clist), 0); +/* PRIVATE COLUMN FUNCTIONS + * column_auto_resize + * real_resize_column + * abort_column_resize + * size_allocate_title_buttons + * size_allocate_columns + * list_requisition_width + * new_column_width + * column_button_create + * column_button_clicked + * column_title_passive_func + */ +static void +column_auto_resize (GtkCList *clist, + GtkCListRow *clist_row, + gint column, + gint old_width) +{ + /* resize column if needed for auto_resize */ + GtkRequisition requisition; - if (row < 0 || row >= clist->rows) - return 0; - if (column < 0 || column >= clist->columns) - return 0; + if (!clist->column[column].auto_resize || + GTK_CLIST_AUTO_RESIZE_BLOCKED(clist)) + return; - clist_row = (g_list_nth (clist->row_list, row))->data; + if (clist_row) + GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row, + column, &requisition); + else + requisition.width = 0; - if (clist_row->cell[column].type != GTK_CELL_PIXMAP) - return 0; + if (requisition.width > clist->column[column].width) + gtk_clist_set_column_width (clist, column, requisition.width); + else if (requisition.width < old_width && + old_width == clist->column[column].width) + { + GList *list; + gint new_width = 0; - if (pixmap) - { - *pixmap = GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap; - /* mask can be NULL */ - *mask = GTK_CELL_PIXMAP (clist_row->cell[column])->mask; - } + /* run a "gtk_clist_optimal_column_width" but break, if + * the column doesn't shrink */ + if (GTK_CLIST_SHOW_TITLES(clist) && clist->column[column].button) + new_width = (clist->column[column].button->requisition.width - + (CELL_SPACING + (2 * COLUMN_INSET))); + else + new_width = 0; - return 1; + for (list = clist->row_list; list; list = list->next) + { + GTK_CLIST_CLASS_FW (clist)->cell_size_request + (clist, GTK_CLIST_ROW (list), column, &requisition); + new_width = MAX (new_width, requisition.width); + if (new_width == clist->column[column].width) + break; + } + if (new_width < clist->column[column].width) + gtk_clist_set_column_width + (clist, column, MAX (new_width, clist->column[column].min_width)); + } } -void -gtk_clist_set_pixtext (GtkCList *clist, - gint row, - gint column, - const gchar *text, - guint8 spacing, - GdkPixmap *pixmap, - GdkBitmap *mask) +static void +real_resize_column (GtkCList *clist, + gint column, + gint width) { - GtkCListRow *clist_row; - g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - 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); - if (mask) gdk_pixmap_ref (mask); - GTK_CLIST_CLASS_FW (clist)->set_cell_contents - (clist, clist_row, column, GTK_CELL_PIXTEXT, text, spacing, pixmap, mask); - - /* redraw the list if it's not frozen */ - if (!GTK_CLIST_FROZEN (clist)) - { - if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); - } -} - -gint -gtk_clist_get_pixtext (GtkCList * clist, - gint row, - gint column, - gchar ** text, - guint8 * spacing, - GdkPixmap ** pixmap, - GdkBitmap ** mask) -{ - GtkCListRow *clist_row; - - g_return_val_if_fail (clist != NULL, 0); - g_return_val_if_fail (GTK_IS_CLIST (clist), 0); - - if (row < 0 || row >= clist->rows) - return 0; - if (column < 0 || column >= clist->columns) - return 0; - - clist_row = (g_list_nth (clist->row_list, row))->data; - - if (clist_row->cell[column].type != GTK_CELL_PIXTEXT) - return 0; + if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width)) + width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width); + if (clist->column[column].max_width >= 0 && + width > clist->column[column].max_width) + width = clist->column[column].max_width; - if (text) - *text = GTK_CELL_PIXTEXT (clist_row->cell[column])->text; - if (spacing) - *spacing = GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing; - if (pixmap) - *pixmap = GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap; + clist->column[column].width = width; + clist->column[column].width_set = TRUE; - /* mask can be NULL */ - *mask = GTK_CELL_PIXTEXT (clist_row->cell[column])->mask; + /* FIXME: this is quite expensive to do if the widget hasn't + * been size_allocated yet, and pointless. Should + * a flag be kept + */ + size_allocate_columns (clist, TRUE); + size_allocate_title_buttons (clist); - return 1; + CLIST_REFRESH (clist); } -void -gtk_clist_set_foreground (GtkCList * clist, - gint row, - GdkColor * color) +static void +abort_column_resize (GtkCList *clist) { - GtkCListRow *clist_row; - g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (row < 0 || row >= clist->rows) + if (!GTK_CLIST_IN_DRAG(clist)) return; - clist_row = (g_list_nth (clist->row_list, row))->data; + GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG); + gtk_grab_remove (GTK_WIDGET (clist)); + gdk_pointer_ungrab (GDK_CURRENT_TIME); + clist->drag_pos = -1; - if (color) + if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1) + draw_xor_line (clist); + + if (GTK_CLIST_ADD_MODE(clist)) { - clist_row->foreground = *color; - clist_row->fg_set = TRUE; + gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_ON_OFF_DASH, 0,0); + gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2); } - else - clist_row->fg_set = FALSE; - - if (!GTK_CLIST_FROZEN (clist) - && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); } -void -gtk_clist_set_background (GtkCList * clist, - gint row, - GdkColor * color) +static void +size_allocate_title_buttons (GtkCList *clist) { - GtkCListRow *clist_row; - - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + GtkAllocation button_allocation; + gint last_column; + gint last_button = 0; + gint i; - if (row < 0 || row >= clist->rows) + if (!GTK_WIDGET_REALIZED (clist)) return; - clist_row = (g_list_nth (clist->row_list, row))->data; + button_allocation.x = clist->hoffset; + button_allocation.y = 0; + button_allocation.width = 0; + button_allocation.height = clist->column_title_area.height; - if (color) + /* find last visible column */ + for (last_column = clist->columns - 1; last_column >= 0; last_column--) + if (clist->column[last_column].visible) + break; + + for (i = 0; i < last_column; i++) { - clist_row->background = *color; - clist_row->bg_set = TRUE; - } - else - clist_row->bg_set = FALSE; + if (!clist->column[i].visible) + { + last_button = i + 1; + gdk_window_hide (clist->column[i].window); + continue; + } - if (!GTK_CLIST_FROZEN (clist) - && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); -} + button_allocation.width += (clist->column[i].area.width + + CELL_SPACING + 2 * COLUMN_INSET); -void -gtk_clist_set_shift (GtkCList * clist, - gint row, - gint column, - gint vertical, - gint horizontal) -{ - GtkCListRow *clist_row; + if (!clist->column[i + 1].button) + { + gdk_window_hide (clist->column[i].window); + continue; + } - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + gtk_widget_size_allocate (clist->column[last_button].button, + &button_allocation); + button_allocation.x += button_allocation.width; + button_allocation.width = 0; - if (row < 0 || row >= clist->rows) - return; - if (column < 0 || column >= clist->columns) - return; + if (clist->column[last_button].resizeable) + { + gdk_window_show (clist->column[last_button].window); + gdk_window_move_resize (clist->column[last_button].window, + button_allocation.x - (DRAG_WIDTH / 2), + 0, DRAG_WIDTH, + clist->column_title_area.height); + } + else + gdk_window_hide (clist->column[last_button].window); - clist_row = (g_list_nth (clist->row_list, row))->data; + last_button = i + 1; + } - clist_row->cell[column].vertical = vertical; - clist_row->cell[column].horizontal = horizontal; + button_allocation.width += (clist->column[last_column].area.width + + 2 * (CELL_SPACING + COLUMN_INSET)); + gtk_widget_size_allocate (clist->column[last_button].button, + &button_allocation); - if (!GTK_CLIST_FROZEN (clist) - && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); + if (clist->column[last_button].resizeable) + { + button_allocation.x += button_allocation.width; + + gdk_window_show (clist->column[last_button].window); + gdk_window_move_resize (clist->column[last_button].window, + button_allocation.x - (DRAG_WIDTH / 2), + 0, DRAG_WIDTH, clist->column_title_area.height); + } + else + gdk_window_hide (clist->column[last_button].window); } -void -gtk_clist_set_selectable (GtkCList *clist, - gint row, - gboolean selectable) +static void +size_allocate_columns (GtkCList *clist, + gboolean block_resize) { - GtkCListRow *clist_row; - - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - if (row < 0 || row >= clist->rows) - return; + gint xoffset = CELL_SPACING + COLUMN_INSET; + gint last_column; + gint i; - clist_row = (g_list_nth (clist->row_list, row))->data; + /* find last visible column and calculate correct column width */ + for (last_column = clist->columns - 1; + last_column >= 0 && !clist->column[last_column].visible; last_column--); - if (selectable == clist_row->selectable) + if (last_column < 0) return; - clist_row->selectable = selectable; - - if (!selectable && clist_row->state == GTK_STATE_SELECTED) + for (i = 0; i <= last_column; i++) { - if (clist->anchor >= 0 && - clist->selection_mode == GTK_SELECTION_EXTENDED) + if (!clist->column[i].visible) + continue; + clist->column[i].area.x = xoffset; + if (clist->column[i].width_set) { - if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist))) + if (!block_resize && GTK_CLIST_SHOW_TITLES(clist) && + clist->column[i].auto_resize && clist->column[i].button) { - GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION); - gtk_grab_remove (GTK_WIDGET (clist)); - gdk_pointer_ungrab (GDK_CURRENT_TIME); - if (clist->htimer) - { - gtk_timeout_remove (clist->htimer); - clist->htimer = 0; - } - if (clist->vtimer) - { - gtk_timeout_remove (clist->vtimer); - clist->vtimer = 0; - } + gint width; + + width = (clist->column[i].button->requisition.width - + (CELL_SPACING + (2 * COLUMN_INSET))); + + if (width > clist->column[i].width) + gtk_clist_set_column_width (clist, i, width); } - GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); + + clist->column[i].area.width = clist->column[i].width; + xoffset += clist->column[i].width + CELL_SPACING + (2* COLUMN_INSET); } - unselect_row (clist, row, -1, NULL); - } + else if (GTK_CLIST_SHOW_TITLES(clist) && clist->column[i].button) + { + clist->column[i].area.width = + clist->column[i].button->requisition.width - + (CELL_SPACING + (2 * COLUMN_INSET)); + xoffset += clist->column[i].button->requisition.width; + } + } + + clist->column[last_column].area.width = clist->column[last_column].area.width + + MAX (0, clist->clist_window_width + COLUMN_INSET - xoffset); } -gboolean -gtk_clist_get_selectable (GtkCList *clist, - gint row) +static gint +list_requisition_width (GtkCList *clist) { - g_return_val_if_fail (clist != NULL, FALSE); - g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE); + gint width = CELL_SPACING; + gint i; - if (row < 0 || row >= clist->rows) - return FALSE; + for (i = clist->columns - 1; i >= 0; i--) + { + if (!clist->column[i].visible) + continue; - return GTK_CLIST_ROW (g_list_nth (clist->row_list, row))->selectable; -} + if (clist->column[i].width_set) + width += clist->column[i].width + CELL_SPACING + (2 * COLUMN_INSET); + else if (GTK_CLIST_SHOW_TITLES(clist) && clist->column[i].button) + width += clist->column[i].button->requisition.width; + } -gint -gtk_clist_prepend (GtkCList *clist, - gchar *text[]) -{ - g_return_val_if_fail (clist != NULL, -1); - g_return_val_if_fail (GTK_IS_CLIST (clist), -1); - g_return_val_if_fail (text != NULL, -1); - - return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, 0, text); + return width; } -gint -gtk_clist_append (GtkCList *clist, - gchar *text[]) +/* this function returns the new width of the column being resized given + * the column and x position of the cursor; the x cursor position is passed + * in as a pointer and automagicly corrected if it's beyond min/max limits */ +static gint +new_column_width (GtkCList *clist, + gint column, + gint *x) { - g_return_val_if_fail (clist != NULL, -1); - g_return_val_if_fail (GTK_IS_CLIST (clist), -1); - g_return_val_if_fail (text != NULL, -1); + gint xthickness = GTK_WIDGET (clist)->style->klass->xthickness; + gint width; + gint cx; + gint dx; + gint last_column; - return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, clist->rows, text); + /* first translate the x position from widget->window + * to clist->clist_window */ + cx = *x - xthickness; + + for (last_column = clist->columns - 1; + last_column >= 0 && !clist->column[last_column].visible; last_column--); + + /* calculate new column width making sure it doesn't end up + * less than the minimum width */ + dx = (COLUMN_LEFT_XPIXEL (clist, column) + COLUMN_INSET + + (column < last_column) * CELL_SPACING); + width = cx - dx; + + if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width)) + { + width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width); + cx = dx + width; + *x = cx + xthickness; + } + else if (clist->column[column].max_width >= COLUMN_MIN_WIDTH && + width > clist->column[column].max_width) + { + width = clist->column[column].max_width; + cx = dx + clist->column[column].max_width; + *x = cx + xthickness; + } + + if (cx < 0 || cx > clist->clist_window_width) + *x = -1; + + return width; } -gint -gtk_clist_insert (GtkCList *clist, - gint row, - gchar *text[]) +static void +column_button_create (GtkCList *clist, + gint column) { - g_return_val_if_fail (clist != NULL, -1); - g_return_val_if_fail (GTK_IS_CLIST (clist), -1); - g_return_val_if_fail (text != NULL, -1); + GtkWidget *button; - if (row < 0 || row > clist->rows) - row = clist->rows; + gtk_widget_push_composite_child (); + button = clist->column[column].button = gtk_button_new (); + gtk_widget_pop_composite_child (); - return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, row, text); + if (GTK_WIDGET_REALIZED (clist) && clist->title_window) + gtk_widget_set_parent_window (clist->column[column].button, + clist->title_window); + gtk_widget_set_parent (button, GTK_WIDGET (clist)); + + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) column_button_clicked, + (gpointer) clist); + gtk_widget_show (button); } -static gint -real_insert_row (GtkCList *clist, - gint row, - gchar *text[]) +static void +column_button_clicked (GtkWidget *widget, + gpointer data) { gint i; - GtkCListRow *clist_row; - - g_return_val_if_fail (clist != NULL, -1); - g_return_val_if_fail (GTK_IS_CLIST (clist), -1); - g_return_val_if_fail (text != NULL, -1); + GtkCList *clist; - /* return if out of bounds */ - if (row < 0 || row > clist->rows) - return -1; + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (data)); - /* create the row */ - clist_row = row_new (clist); + clist = GTK_CLIST (data); - /* set the text in the row's columns */ + /* find the column who's button was pressed */ for (i = 0; i < clist->columns; i++) - if (text[i]) - GTK_CLIST_CLASS_FW (clist)->set_cell_contents - (clist, clist_row, i, GTK_CELL_TEXT, text[i], 0, NULL ,NULL); + if (clist->column[i].button == widget) + break; - if (!clist->rows) - { - clist->row_list = g_list_append (clist->row_list, clist_row); - clist->row_list_end = clist->row_list; - } - else - { - if (GTK_CLIST_AUTO_SORT (clist)) /* override insertion pos */ - { - GList *work; - - row = 0; - work = clist->row_list; - - if (clist->sort_type == GTK_SORT_ASCENDING) - { - while (row < clist->rows && - clist->compare (clist, clist_row, - GTK_CLIST_ROW (work)) > 0) - { - row++; - work = work->next; - } - } - else - { - while (row < clist->rows && - clist->compare (clist, clist_row, - GTK_CLIST_ROW (work)) < 0) - { - row++; - work = work->next; - } - } - } - - /* 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); - } + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i); +} + +static gint +column_title_passive_func (GtkWidget *widget, + GdkEvent *event, + gpointer data) +{ + g_return_val_if_fail (event != NULL, FALSE); - clist->rows++; + switch (event->type) + { + case GDK_MOTION_NOTIFY: + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: + return TRUE; + default: + break; + } + return FALSE; +} - if (row < ROW_FROM_YPIXEL (clist, 0)) - clist->voffset -= (clist->row_height + CELL_SPACING); - /* syncronize the selection list */ - sync_selection (clist, row, SYNC_INSERT); +/* PUBLIC CELL FUNCTIONS + * gtk_clist_get_cell_type + * gtk_clist_set_text + * gtk_clist_get_text + * gtk_clist_set_pixmap + * gtk_clist_get_pixmap + * gtk_clist_set_pixtext + * gtk_clist_get_pixtext + * gtk_clist_set_shift + */ +GtkCellType +gtk_clist_get_cell_type (GtkCList *clist, + gint row, + gint column) +{ + GtkCListRow *clist_row; - /* redraw the list if it isn't frozen */ - if (!GTK_CLIST_FROZEN (clist)) - { - adjust_scrollbars (clist); + g_return_val_if_fail (clist != NULL, -1); + g_return_val_if_fail (GTK_IS_CLIST (clist), -1); - if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) - draw_rows (clist, NULL); - } + if (row < 0 || row >= clist->rows) + return -1; + if (column < 0 || column >= clist->columns) + return -1; - return row; -} + clist_row = ROW_ELEMENT (clist, row)->data; -void -gtk_clist_remove (GtkCList * clist, - gint row) -{ - GTK_CLIST_CLASS_FW (clist)->remove_row (clist, row); + return clist_row->cell[column].type; } -static void -real_remove_row (GtkCList * clist, - gint row) +void +gtk_clist_set_text (GtkCList *clist, + gint row, + gint column, + const gchar *text) { - gint was_visible, was_selected; - GList *list; GtkCListRow *clist_row; g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - /* return if out of bounds */ - if (row < 0 || row > (clist->rows - 1)) + if (row < 0 || row >= clist->rows) + return; + if (column < 0 || column >= clist->columns) return; - was_visible = (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE); - was_selected = 0; + clist_row = ROW_ELEMENT (clist, row)->data; - /* get the row we're going to delete */ - list = g_list_nth (clist->row_list, row); - clist_row = list->data; + /* if text is null, then the cell is empty */ + GTK_CLIST_CLASS_FW (clist)->set_cell_contents + (clist, clist_row, column, GTK_CELL_TEXT, text, 0, NULL, NULL); - /* if we're removing a selected row, we have to make sure - * it's properly unselected, and then sync up the clist->selected - * list to reflect the deincrimented indexies of rows after the - * removal */ - if (clist_row->state == GTK_STATE_SELECTED) + /* redraw the list if it's not frozen */ + if (CLIST_UNFROZEN (clist)) { - switch (clist->selection_mode) - { - case GTK_SELECTION_SINGLE: - case GTK_SELECTION_MULTIPLE: - case GTK_SELECTION_EXTENDED: - unselect_row (clist, row, -1, NULL); - break; - - case GTK_SELECTION_BROWSE: - select_row (clist, row - 1, -1, NULL); - break; - - default: - break; - } + if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); } +} - /* 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; - if (row >= clist->focus_row && clist->focus_row >=0) - clist->focus_row--; +gint +gtk_clist_get_text (GtkCList *clist, + gint row, + gint column, + gchar **text) +{ + GtkCListRow *clist_row; - clist->row_list = g_list_remove (clist->row_list, clist_row); - clist->rows--; - - if (row < ROW_FROM_YPIXEL (clist, 0)) - clist->voffset += clist->row_height + CELL_SPACING; + g_return_val_if_fail (clist != NULL, 0); + g_return_val_if_fail (GTK_IS_CLIST (clist), 0); - sync_selection (clist, row, SYNC_REMOVE); + if (row < 0 || row >= clist->rows) + return 0; + if (column < 0 || column >= clist->columns) + return 0; - /* toast the row */ - row_delete (clist, clist_row); + clist_row = ROW_ELEMENT (clist, row)->data; - /* redraw the row if it isn't frozen */ - if (!GTK_CLIST_FROZEN (clist)) - { - adjust_scrollbars (clist); + if (clist_row->cell[column].type != GTK_CELL_TEXT) + return 0; - if (was_visible) - draw_rows (clist, NULL); - } + if (text) + *text = GTK_CELL_TEXT (clist_row->cell[column])->text; + + return 1; } -static void -sync_selection (GtkCList * clist, - gint row, - gint mode) +void +gtk_clist_set_pixmap (GtkCList *clist, + gint row, + gint column, + GdkPixmap *pixmap, + GdkBitmap *mask) { - GList *list; - gint d; - - if (mode == SYNC_INSERT) - d = 1; - else - d = -1; - - if (clist->focus_row >= row) - { - clist->focus_row += d; - if (clist->focus_row == -1 && clist->rows >= 1) - clist->focus_row = 0; - } - - if (clist->selection_mode == GTK_SELECTION_BROWSE && clist->anchor != -1) - GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); - - g_list_free (clist->undo_selection); - g_list_free (clist->undo_unselection); - clist->undo_selection = NULL; - clist->undo_unselection = NULL; - - clist->anchor = -1; - clist->drag_pos = -1; - clist->undo_anchor = clist->focus_row; - - list = clist->selection; - while (list) - { - if (GPOINTER_TO_INT (list->data) >= row) - list->data = ((gchar*) list->data) + d; - list = list->next; - } -} - -void -gtk_clist_clear (GtkCList * clist) -{ - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - GTK_CLIST_CLASS_FW (clist)->clear (clist); -} - -static void -real_clear (GtkCList * clist) -{ - GList *list, *free_list; + GtkCListRow *clist_row; g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - /* free up the selection list */ - g_list_free (clist->selection); - g_list_free (clist->undo_selection); - g_list_free (clist->undo_unselection); - - clist->selection = NULL; - clist->selection_end = NULL; - clist->undo_selection = NULL; - clist->undo_unselection = NULL; - clist->voffset = 0; - clist->focus_row = -1; - clist->anchor = -1; - clist->undo_anchor = -1; - clist->anchor_state = GTK_STATE_SELECTED; - clist->drag_pos = -1; + if (row < 0 || row >= clist->rows) + return; + if (column < 0 || column >= clist->columns) + return; - /* remove all the rows */ - free_list = clist->row_list; - clist->row_list = NULL; - clist->row_list_end = NULL; - clist->rows = 0; - for (list = free_list; list; list = list->next) - row_delete (clist, GTK_CLIST_ROW (list)); - g_list_free (free_list); + clist_row = ROW_ELEMENT (clist, row)->data; + + gdk_pixmap_ref (pixmap); + + if (mask) gdk_pixmap_ref (mask); + + GTK_CLIST_CLASS_FW (clist)->set_cell_contents + (clist, clist_row, column, GTK_CELL_PIXMAP, NULL, 0, pixmap, mask); - /* zero-out the scrollbars */ - if (clist->vscrollbar) + /* redraw the list if it's not frozen */ + if (CLIST_UNFROZEN (clist)) { - 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_thaw (clist); + if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); } } -void -gtk_clist_swap_rows (GtkCList * clist, - gint row1, - gint row2) +gint +gtk_clist_get_pixmap (GtkCList *clist, + gint row, + gint column, + GdkPixmap **pixmap, + GdkBitmap **mask) { - gint first, last; - GList *list, *link1, *link2; - gpointer swap; - - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - if (GTK_CLIST_AUTO_SORT (clist)) - return; - - if (row1 < 0 || row1 > (clist->rows - 1)) - return; + GtkCListRow *clist_row; - if (row2 < 0 || row2 > (clist->rows - 1)) - return; + g_return_val_if_fail (clist != NULL, 0); + g_return_val_if_fail (GTK_IS_CLIST (clist), 0); - first = MIN (row1, row2); - last = MAX (row1, row2); + if (row < 0 || row >= clist->rows) + return 0; + if (column < 0 || column >= clist->columns) + return 0; - link1 = g_list_nth (clist->row_list, first); - link2 = g_list_nth (link1, row2 - row1); + clist_row = ROW_ELEMENT (clist, row)->data; - swap = link1->data; - link1->data = link2->data; - link2->data = swap; - - list = clist->selection; - while (list) - { - if (GPOINTER_TO_INT (list->data) == row1) - list->data = GINT_TO_POINTER (row2); - - if (GPOINTER_TO_INT (list->data) == row2) - list->data = GINT_TO_POINTER (row1); - - list = list->next; - } - - if (!GTK_CLIST_FROZEN (clist)) - { - if (gtk_clist_row_is_visible (clist, row1) != GTK_VISIBILITY_NONE) - GTK_CLIST_CLASS_FW (clist)->draw_row - (clist, NULL, row1, GTK_CLIST_ROW (link2)); + if (clist_row->cell[column].type != GTK_CELL_PIXMAP) + return 0; - if (gtk_clist_row_is_visible (clist, row2) != GTK_VISIBILITY_NONE) - GTK_CLIST_CLASS_FW (clist)->draw_row - (clist, NULL, row2, GTK_CLIST_ROW (link1)); - } -} + if (pixmap) + { + *pixmap = GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap; + /* mask can be NULL */ + *mask = GTK_CELL_PIXMAP (clist_row->cell[column])->mask; + } -void -gtk_clist_set_row_data (GtkCList * clist, - gint row, - gpointer data) -{ - gtk_clist_set_row_data_full (clist, row, data, NULL); + return 1; } void -gtk_clist_set_row_data_full (GtkCList * clist, - gint row, - gpointer data, - GtkDestroyNotify destroy) +gtk_clist_set_pixtext (GtkCList *clist, + gint row, + gint column, + const gchar *text, + guint8 spacing, + GdkPixmap *pixmap, + GdkBitmap *mask) { GtkCListRow *clist_row; g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (row < 0 || row > (clist->rows - 1)) + 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->data = data; - clist_row->destroy = destroy; -} - -gpointer -gtk_clist_get_row_data (GtkCList * clist, - gint row) -{ - GtkCListRow *clist_row; - - g_return_val_if_fail (clist != NULL, NULL); - g_return_val_if_fail (GTK_IS_CLIST (clist), NULL); - - if (row < 0 || row > (clist->rows - 1)) - return NULL; + clist_row = ROW_ELEMENT (clist, row)->data; + + gdk_pixmap_ref (pixmap); + if (mask) gdk_pixmap_ref (mask); + GTK_CLIST_CLASS_FW (clist)->set_cell_contents + (clist, clist_row, column, GTK_CELL_PIXTEXT, text, spacing, pixmap, mask); - clist_row = (g_list_nth (clist->row_list, row))->data; - return clist_row->data; + /* redraw the list if it's not frozen */ + if (CLIST_UNFROZEN (clist)) + { + if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); + } } gint -gtk_clist_find_row_from_data (GtkCList * clist, - gpointer data) +gtk_clist_get_pixtext (GtkCList *clist, + gint row, + gint column, + gchar **text, + guint8 *spacing, + GdkPixmap **pixmap, + GdkBitmap **mask) { - GList *list; - gint n; - - g_return_val_if_fail (clist != NULL, -1); - g_return_val_if_fail (GTK_IS_CLIST (clist), -1); + GtkCListRow *clist_row; - if (clist->rows < 1) - return -1; /* is this an optimization or just worthless? */ + g_return_val_if_fail (clist != NULL, 0); + g_return_val_if_fail (GTK_IS_CLIST (clist), 0); - for (n = 0, list = clist->row_list; list; n++, list = list->next) - if (GTK_CLIST_ROW (list)->data == data) - return n; + if (row < 0 || row >= clist->rows) + return 0; + if (column < 0 || column >= clist->columns) + return 0; - return -1; -} + clist_row = ROW_ELEMENT (clist, row)->data; -void -gtk_clist_select_row (GtkCList * clist, - gint row, - gint column) -{ - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + if (clist_row->cell[column].type != GTK_CELL_PIXTEXT) + return 0; - if (row < 0 || row >= clist->rows) - return; + if (text) + *text = GTK_CELL_PIXTEXT (clist_row->cell[column])->text; + if (spacing) + *spacing = GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing; + if (pixmap) + *pixmap = GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap; - if (column < -1 || column >= clist->columns) - return; + /* mask can be NULL */ + *mask = GTK_CELL_PIXTEXT (clist_row->cell[column])->mask; - select_row (clist, row, column, NULL); + return 1; } void -gtk_clist_unselect_row (GtkCList * clist, - gint row, - gint column) +gtk_clist_set_shift (GtkCList *clist, + gint row, + gint column, + gint vertical, + gint horizontal) { + GtkRequisition requisition = { 0 }; + GtkCListRow *clist_row; + g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); if (row < 0 || row >= clist->rows) return; - - if (column < -1 || column >= clist->columns) + if (column < 0 || column >= clist->columns) return; - unselect_row (clist, row, column, NULL); -} - -GtkVisibility -gtk_clist_row_is_visible (GtkCList * clist, - gint row) -{ - gint top; - - g_return_val_if_fail (clist != NULL, 0); - g_return_val_if_fail (GTK_IS_CLIST (clist), 0); - - if (row < 0 || row >= clist->rows) - return GTK_VISIBILITY_NONE; - - if (clist->row_height == 0) - return GTK_VISIBILITY_NONE; - - if (row < ROW_FROM_YPIXEL (clist, 0)) - return GTK_VISIBILITY_NONE; - - if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height)) - return GTK_VISIBILITY_NONE; - - top = ROW_TOP_YPIXEL (clist, row); + clist_row = ROW_ELEMENT (clist, row)->data; - if ((top < 0) - || ((top + clist->row_height) >= clist->clist_window_height)) - return GTK_VISIBILITY_PARTIAL; + if (clist->column[column].auto_resize && + !GTK_CLIST_AUTO_RESIZE_BLOCKED(clist)) + GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row, + column, &requisition); - return GTK_VISIBILITY_FULL; -} + clist_row->cell[column].vertical = vertical; + clist_row->cell[column].horizontal = horizontal; -#if 0 -static 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); + column_auto_resize (clist, clist_row, column, requisition.width); - return gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)); + if (CLIST_UNFROZEN (clist) && gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); } -static GtkAdjustment* -gtk_clist_get_hadjustment (GtkCList * clist) +/* PRIVATE CELL FUNCTIONS + * set_cell_contents + * cell_size_request + */ +static void +set_cell_contents (GtkCList *clist, + GtkCListRow *clist_row, + gint column, + GtkCellType type, + const gchar *text, + guint8 spacing, + GdkPixmap *pixmap, + GdkBitmap *mask) { - 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)); -} -#endif + GtkRequisition requisition; -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)); + g_return_if_fail (clist_row != NULL); - 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->column[column].auto_resize && + !GTK_CLIST_AUTO_RESIZE_BLOCKED(clist)) + GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row, + column, &requisition); - if (clist->hscrollbar_policy != hscrollbar_policy) + switch (clist_row->cell[column].type) { - clist->hscrollbar_policy = hscrollbar_policy; - - if (GTK_WIDGET (clist)->parent) - gtk_widget_queue_resize (GTK_WIDGET (clist)); - } -} - -void -gtk_clist_undo_selection (GtkCList *clist) -{ - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + 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); + if (GTK_CELL_PIXMAP (clist_row->cell[column])->mask) + 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); + if (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask) + gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask); + break; + case GTK_CELL_WIDGET: + /* unimplimented */ + break; + default: + break; + } - if (clist->selection_mode == GTK_SELECTION_EXTENDED && - (clist->undo_selection || clist->undo_unselection)) - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNDO_SELECTION]); + clist_row->cell[column].type = GTK_CELL_EMPTY; + + switch (type) + { + case GTK_CELL_TEXT: + if (text) + { + clist_row->cell[column].type = GTK_CELL_TEXT; + GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text); + } + break; + case GTK_CELL_PIXMAP: + if (pixmap) + { + clist_row->cell[column].type = GTK_CELL_PIXMAP; + GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap; + /* We set the mask even if it is NULL */ + GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask; + } + break; + case GTK_CELL_PIXTEXT: + if (text && pixmap) + { + 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; + } + break; + default: + break; + } + + if (clist->column[column].auto_resize && + !GTK_CLIST_AUTO_RESIZE_BLOCKED(clist)) + column_auto_resize (clist, clist_row, column, requisition.width); } static void -real_undo_selection (GtkCList *clist) +cell_size_request (GtkCList *clist, + GtkCListRow *clist_row, + gint column, + GtkRequisition *requisition) { - GList *work; + GtkStyle *style; + gint width; + gint height; g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); + g_return_if_fail (requisition != NULL); - if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) || - clist->selection_mode != GTK_SELECTION_EXTENDED) - return; - - if (clist->anchor >= 0) - GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); + get_cell_style (clist, clist_row, GTK_STATE_NORMAL, column, &style, + NULL, NULL); - if (!(clist->undo_selection || clist->undo_unselection)) + switch (clist_row->cell[column].type) { - gtk_clist_unselect_all (clist); - return; + case GTK_CELL_TEXT: + requisition->width = + gdk_string_width (style->font, + GTK_CELL_TEXT (clist_row->cell[column])->text); + requisition->height = style->font->ascent + style->font->descent; + break; + case GTK_CELL_PIXTEXT: + gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap, + &width, &height); + requisition->width = width + + GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing + + gdk_string_width (style->font, + GTK_CELL_TEXT (clist_row->cell[column])->text); + + requisition->height = MAX (style->font->ascent + style->font->descent, + height); + break; + case GTK_CELL_PIXMAP: + gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap, + &width, &height); + requisition->width = width; + requisition->height = height; + break; + default: + requisition->width = 0; + requisition->height = 0; + break; } - for (work = clist->undo_selection; work; work = work->next) - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], - GPOINTER_TO_INT (work->data), -1, NULL); + requisition->width += clist_row->cell[column].horizontal; + requisition->height += clist_row->cell[column].vertical; +} - for (work = clist->undo_unselection; work; work = work->next) - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], - GPOINTER_TO_INT (work->data), -1, NULL); +/* PUBLIC INSERT/REMOVE ROW FUNCTIONS + * gtk_clist_prepend + * gtk_clist_append + * gtk_clist_insert + * gtk_clist_remove + * gtk_clist_clear + */ +gint +gtk_clist_prepend (GtkCList *clist, + gchar *text[]) +{ + g_return_val_if_fail (clist != NULL, -1); + g_return_val_if_fail (GTK_IS_CLIST (clist), -1); + g_return_val_if_fail (text != NULL, -1); - if (GTK_WIDGET_HAS_FOCUS (clist) && clist->focus_row != clist->undo_anchor) - { - gtk_clist_draw_focus (GTK_WIDGET (clist)); - clist->focus_row = clist->undo_anchor; - gtk_clist_draw_focus (GTK_WIDGET (clist)); - } - else - clist->focus_row = clist->undo_anchor; - - clist->undo_anchor = -1; - - g_list_free (clist->undo_selection); - g_list_free (clist->undo_unselection); - clist->undo_selection = NULL; - clist->undo_unselection = NULL; + return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, 0, text); +} - if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height > - clist->clist_window_height) - gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); - else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0) - gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); +gint +gtk_clist_append (GtkCList *clist, + gchar *text[]) +{ + g_return_val_if_fail (clist != NULL, -1); + g_return_val_if_fail (GTK_IS_CLIST (clist), -1); + g_return_val_if_fail (text != NULL, -1); + + return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, clist->rows, text); } -/* - * GTKOBJECT - * gtk_clist_destroy - * gtk_clist_finalize +gint +gtk_clist_insert (GtkCList *clist, + gint row, + gchar *text[]) +{ + g_return_val_if_fail (clist != NULL, -1); + g_return_val_if_fail (GTK_IS_CLIST (clist), -1); + g_return_val_if_fail (text != NULL, -1); + + if (row < 0 || row > clist->rows) + row = clist->rows; + + return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, row, text); +} + +void +gtk_clist_remove (GtkCList *clist, + gint row) +{ + GTK_CLIST_CLASS_FW (clist)->remove_row (clist, row); +} + +void +gtk_clist_clear (GtkCList *clist) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + GTK_CLIST_CLASS_FW (clist)->clear (clist); +} + +/* PRIVATE INSERT/REMOVE ROW FUNCTIONS + * real_insert_row + * real_remove_row + * real_clear + * real_row_move */ -static void -gtk_clist_destroy (GtkObject * object) +static gint +real_insert_row (GtkCList *clist, + gint row, + gchar *text[]) { gint i; - GtkCList *clist; - - g_return_if_fail (object != NULL); - g_return_if_fail (GTK_IS_CLIST (object)); + GtkCListRow *clist_row; - clist = GTK_CLIST (object); + g_return_val_if_fail (clist != NULL, -1); + g_return_val_if_fail (GTK_IS_CLIST (clist), -1); + g_return_val_if_fail (text != NULL, -1); - /* freeze the list */ - GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN); + /* return if out of bounds */ + if (row < 0 || row > clist->rows) + return -1; - /* get rid of all the rows */ - gtk_clist_clear (clist); + /* create the row */ + clist_row = row_new (clist); - /* Since we don't have a _remove method, unparent the children - * instead of destroying them so the focus will be unset properly. - * (For other containers, the _remove method takes care of the - * unparent) The destroy will happen when the refcount drops - * to zero. - */ + /* set the text in the row's columns */ + for (i = 0; i < clist->columns; i++) + if (text[i]) + GTK_CLIST_CLASS_FW (clist)->set_cell_contents + (clist, clist_row, i, GTK_CELL_TEXT, text[i], 0, NULL ,NULL); - /* destroy the scrollbars */ - if (clist->vscrollbar) + if (!clist->rows) { - gtk_widget_unparent (clist->vscrollbar); - clist->vscrollbar = NULL; + clist->row_list = g_list_append (clist->row_list, clist_row); + clist->row_list_end = clist->row_list; } - if (clist->hscrollbar) + else { - gtk_widget_unparent (clist->hscrollbar); - clist->hscrollbar = NULL; + if (GTK_CLIST_AUTO_SORT(clist)) /* override insertion pos */ + { + GList *work; + + row = 0; + work = clist->row_list; + + if (clist->sort_type == GTK_SORT_ASCENDING) + { + while (row < clist->rows && + clist->compare (clist, clist_row, + GTK_CLIST_ROW (work)) > 0) + { + row++; + work = work->next; + } + } + else + { + while (row < clist->rows && + clist->compare (clist, clist_row, + GTK_CLIST_ROW (work)) < 0) + { + row++; + work = work->next; + } + } + } + + /* 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++; - if (clist->htimer) + if (row < ROW_FROM_YPIXEL (clist, 0)) + clist->voffset -= (clist->row_height + CELL_SPACING); + + /* syncronize the selection list */ + sync_selection (clist, row, SYNC_INSERT); + + if (clist->rows == 1) { - gtk_timeout_remove (clist->htimer); - clist->htimer = 0; + clist->focus_row = 0; + if (clist->selection_mode == GTK_SELECTION_BROWSE) + gtk_clist_select_row (clist, 0, -1); } - if (clist->vtimer) + + /* redraw the list if it isn't frozen */ + if (CLIST_UNFROZEN (clist)) { - gtk_timeout_remove (clist->vtimer); - clist->vtimer = 0; - } + adjust_adjustments (clist, FALSE); - /* destroy the column buttons */ - for (i = 0; i < clist->columns; i++) - if (clist->column[i].button) - { - gtk_widget_unparent (clist->column[i].button); - clist->column[i].button = NULL; - } + if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + draw_rows (clist, NULL); + } - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (*GTK_OBJECT_CLASS (parent_class)->destroy) (object); + return row; } static void -gtk_clist_finalize (GtkObject * object) +real_remove_row (GtkCList *clist, + gint row) { - GtkCList *clist; - - g_return_if_fail (object != NULL); - g_return_if_fail (GTK_IS_CLIST (object)); + gint was_visible, was_selected; + GList *list; + GtkCListRow *clist_row; - clist = GTK_CLIST (object); - - columns_delete (clist); - - g_mem_chunk_destroy (clist->cell_mem_chunk); - g_mem_chunk_destroy (clist->row_mem_chunk); - - if (GTK_OBJECT_CLASS (parent_class)->finalize) - (*GTK_OBJECT_CLASS (parent_class)->finalize) (object); -} - -/* - * GTKWIDGET - * gtk_clist_realize - * gtk_clist_unrealize - * gtk_clist_map - * gtk_clist_unmap - * gtk_clist_draw - * gtk_clist_expose - * gtk_clist_button_press - * gtk_clist_button_release - * gtk_clist_motion - * gtk_clist_size_request - * gtk_clist_size_allocate - */ -static void -gtk_clist_realize (GtkWidget * widget) -{ - gint i; - GtkCList *clist; - GdkWindowAttr attributes; - gint attributes_mask; - GdkGCValues values; - gint border_width; - - 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); - - add_style_data (clist); - - border_width = GTK_CONTAINER (widget)->border_width; - - attributes.window_type = GDK_WINDOW_CHILD; - attributes.x = widget->allocation.x + border_width; - attributes.y = widget->allocation.y + border_width; - attributes.width = widget->allocation.width - border_width * 2; - attributes.height = widget->allocation.height - border_width * 2; - 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 | - GDK_KEY_RELEASE_MASK); - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - /* main window */ - widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); - gdk_window_set_user_data (widget->window, clist); + /* return if out of bounds */ + if (row < 0 || row > (clist->rows - 1)) + return; - widget->style = gtk_style_attach (widget->style, widget->window); + was_visible = (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE); + was_selected = 0; - gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); + /* get the row we're going to delete */ + list = ROW_ELEMENT (clist, row); + g_assert (list != NULL); + clist_row = list->data; - /* column-title window */ + /* if we're removing a selected row, we have to make sure + * it's properly unselected, and then sync up the clist->selected + * list to reflect the deincrimented indexies of rows after the + * removal */ + if (clist_row->state == GTK_STATE_SELECTED) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], + row, -1, NULL); - attributes.x = clist->column_title_area.x; - attributes.y = clist->column_title_area.y; - attributes.width = clist->column_title_area.width; - attributes.height = clist->column_title_area.height; - - clist->title_window = gdk_window_new (widget->window, &attributes, attributes_mask); - gdk_window_set_user_data (clist->title_window, clist); + /* reset the row end pointer if we're removing at the end of the list */ + clist->rows--; + if (clist->row_list == list) + clist->row_list = g_list_next (list); + if (clist->row_list_end == list) + clist->row_list_end = g_list_previous (list); + g_list_remove (list, clist_row); - gtk_style_set_background (widget->style, clist->title_window, GTK_STATE_SELECTED); - gdk_window_show (clist->title_window); + /*if (clist->focus_row >=0 && + (row <= clist->focus_row || clist->focus_row >= clist->rows)) + clist->focus_row--;*/ - /* set things up so column buttons are drawn in title window */ - for (i = 0; i < clist->columns; i++) - if (clist->column[i].button) - gtk_widget_set_parent_window (clist->column[i].button, clist->title_window); + if (row < ROW_FROM_YPIXEL (clist, 0)) + clist->voffset += clist->row_height + CELL_SPACING; - /* clist-window */ - attributes.x = clist->internal_allocation.x + widget->style->klass->xthickness; - attributes.y = clist->internal_allocation.y + widget->style->klass->ythickness + - clist->column_title_area.height; - attributes.width = clist->clist_window_width; - attributes.height = clist->clist_window_height; - - clist->clist_window = gdk_window_new (widget->window, &attributes, attributes_mask); - gdk_window_set_user_data (clist->clist_window, clist); + sync_selection (clist, row, SYNC_REMOVE); - gdk_window_set_background (clist->clist_window, &widget->style->bg[GTK_STATE_PRELIGHT]); - gdk_window_show (clist->clist_window); - gdk_window_get_size (clist->clist_window, &clist->clist_window_width, - &clist->clist_window_height); + if (clist->selection_mode == GTK_SELECTION_BROWSE && !clist->selection && + clist->focus_row >= 0) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + clist->focus_row, -1, NULL); - /* create resize windows */ - attributes.wclass = GDK_INPUT_ONLY; - attributes.event_mask = (GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_POINTER_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK | - GDK_KEY_PRESS_MASK); - attributes.cursor = clist->cursor_drag = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW); - attributes_mask = GDK_WA_CURSOR; - - attributes.x = LIST_WIDTH (clist) + 1; - attributes.y = 0; - attributes.width = 0; - attributes.height = 0; + /* toast the row */ + row_delete (clist, clist_row); - for (i = 0; i < clist->columns; i++) + /* redraw the row if it isn't frozen */ + if (CLIST_UNFROZEN (clist)) { - clist->column[i].window = gdk_window_new (clist->title_window, &attributes, attributes_mask); - gdk_window_set_user_data (clist->column[i].window, clist); - } - - /* This is slightly less efficient than creating them with the - * right size to begin with, but easier - */ - size_allocate_title_buttons (clist); - - /* GCs */ - clist->fg_gc = gdk_gc_new (widget->window); - clist->bg_gc = gdk_gc_new (widget->window); - - /* We'll use this gc to do scrolling as well */ - gdk_gc_set_exposures (clist->fg_gc, TRUE); + adjust_adjustments (clist, FALSE); - 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); + if (was_visible) + draw_rows (clist, NULL); + } } static void -gtk_clist_unrealize (GtkWidget * widget) +real_clear (GtkCList *clist) { + GList *list; + GList *free_list; gint i; - GtkCList *clist; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_CLIST (widget)); - clist = GTK_CLIST (widget); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN); + /* free up the selection list */ + g_list_free (clist->selection); + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); - gdk_cursor_destroy (clist->cursor_drag); - gdk_gc_destroy (clist->xor_gc); - gdk_gc_destroy (clist->fg_gc); - gdk_gc_destroy (clist->bg_gc); + clist->selection = NULL; + clist->selection_end = NULL; + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + clist->voffset = 0; + clist->focus_row = -1; + clist->anchor = -1; + clist->undo_anchor = -1; + clist->anchor_state = GTK_STATE_SELECTED; + clist->drag_pos = -1; + /* remove all the rows */ + GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED); + free_list = clist->row_list; + clist->row_list = NULL; + clist->row_list_end = NULL; + clist->rows = 0; + for (list = free_list; list; list = list->next) + row_delete (clist, GTK_CLIST_ROW (list)); + g_list_free (free_list); + GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED); for (i = 0; i < clist->columns; i++) - if (clist->column[i].window) + if (clist->column[i].auto_resize) { - gdk_window_set_user_data (clist->column[i].window, NULL); - gdk_window_destroy (clist->column[i].window); - clist->column[i].window = NULL; + if (GTK_CLIST_SHOW_TITLES(clist) && clist->column[i].button) + gtk_clist_set_column_width + (clist, i, (clist->column[i].button->requisition.width - + (CELL_SPACING + (2 * COLUMN_INSET)))); + else + gtk_clist_set_column_width (clist, i, 0); } - - gdk_window_set_user_data (clist->clist_window, NULL); - gdk_window_destroy (clist->clist_window); - clist->clist_window = NULL; - - gdk_window_set_user_data (clist->title_window, NULL); - gdk_window_destroy (clist->title_window); - clist->title_window = NULL; - - clist->cursor_drag = NULL; - clist->xor_gc = NULL; - clist->fg_gc = NULL; - clist->bg_gc = NULL; - - if (GTK_WIDGET_CLASS (parent_class)->unrealize) - (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); + /* zero-out the scrollbars */ + if (clist->vadjustment) + { + gtk_adjustment_set_value (clist->vadjustment, 0.0); + CLIST_REFRESH (clist); + } + else + gtk_widget_queue_resize (GTK_WIDGET (clist)); } static void -gtk_clist_map (GtkWidget * widget) +real_row_move (GtkCList *clist, + gint source_row, + gint dest_row) { - gint i; - GtkCList *clist; + GtkCListRow *clist_row; + GList *list; + gint first, last; + gint d; - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_CLIST (widget)); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - clist = GTK_CLIST (widget); + if (GTK_CLIST_AUTO_SORT(clist)) + return; - if (!GTK_WIDGET_MAPPED (widget)) - { - GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + if (source_row < 0 || source_row >= clist->rows || + dest_row < 0 || dest_row >= clist->rows || + source_row == dest_row) + return; - gdk_window_show (widget->window); - gdk_window_show (clist->title_window); - gdk_window_show (clist->clist_window); + gtk_clist_freeze (clist); - /* map column buttons */ - for (i = 0; i < clist->columns; i++) - if (clist->column[i].button && - GTK_WIDGET_VISIBLE (clist->column[i].button) && - !GTK_WIDGET_MAPPED (clist->column[i].button)) - gtk_widget_map (clist->column[i].button); - - /* map resize windows AFTER column buttons (above) */ - for (i = 0; i < clist->columns; i++) - if (clist->column[i].window && clist->column[i].button) - gdk_window_show (clist->column[i].window); - - /* map vscrollbars */ - if (GTK_WIDGET_VISIBLE (clist->vscrollbar) && - !GTK_WIDGET_MAPPED (clist->vscrollbar)) - gtk_widget_map (clist->vscrollbar); + /* unlink source row */ + clist_row = ROW_ELEMENT (clist, source_row)->data; + if (source_row == clist->rows - 1) + clist->row_list_end = clist->row_list_end->prev; + clist->row_list = g_list_remove (clist->row_list, clist_row); + clist->rows--; - if (GTK_WIDGET_VISIBLE (clist->hscrollbar) && - !GTK_WIDGET_MAPPED (clist->hscrollbar)) - gtk_widget_map (clist->hscrollbar); + /* relink source row */ + clist->row_list = g_list_insert (clist->row_list, clist_row, dest_row); + if (dest_row == clist->rows) + clist->row_list_end = clist->row_list_end->next; + clist->rows++; - /* unfreeze the list */ - GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN); + /* sync selection */ + if (source_row > dest_row) + { + first = dest_row; + last = source_row; + d = 1; + } + else + { + first = source_row; + last = dest_row; + d = -1; } -} -static void -gtk_clist_unmap (GtkWidget * widget) + for (list = clist->selection; list; list = list->next) + { + if (list->data == GINT_TO_POINTER (source_row)) + list->data = GINT_TO_POINTER (dest_row); + else if (first <= GPOINTER_TO_INT (list->data) && + last >= GPOINTER_TO_INT (list->data)) + list->data = GINT_TO_POINTER (GPOINTER_TO_INT (list->data) + d); + } + + if (clist->focus_row == source_row) + clist->focus_row = dest_row; + else if (clist->focus_row > first) + clist->focus_row += d; + + gtk_clist_thaw (clist); +} + +/* PUBLIC ROW FUNCTIONS + * gtk_clist_moveto + * gtk_clist_set_row_height + * gtk_clist_set_row_data + * gtk_clist_set_row_data_full + * gtk_clist_get_row_data + * gtk_clist_find_row_from_data + * gtk_clist_swap_rows + * gtk_clist_row_move + * gtk_clist_row_is_visible + * gtk_clist_set_foreground + * gtk_clist_set_background + */ +void +gtk_clist_moveto (GtkCList *clist, + gint row, + gint column, + gfloat row_align, + gfloat col_align) { - gint i; - GtkCList *clist; + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_CLIST (widget)); + if (row < -1 || row >= clist->rows) + return; + if (column < -1 || column >= clist->columns) + return; - clist = GTK_CLIST (widget); + row_align = CLAMP (row_align, 0, 1); + col_align = CLAMP (col_align, 0, 1); - if (GTK_WIDGET_MAPPED (widget)) + /* adjust horizontal scrollbar */ + if (clist->hadjustment && column >= 0) { - GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + gint x; - for (i = 0; i < clist->columns; i++) - if (clist->column[i].window) - gdk_window_hide (clist->column[i].window); - - 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 (clist->column[i].button && - GTK_WIDGET_MAPPED (clist->column[i].button)) - gtk_widget_unmap (clist->column[i].button); - - /* freeze the list */ - GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN); + x = (COLUMN_LEFT (clist, column) - CELL_SPACING - COLUMN_INSET - + (col_align * (clist->clist_window_width - 2 * COLUMN_INSET - + CELL_SPACING - clist->column[column].area.width))); + if (x < 0) + gtk_adjustment_set_value (clist->hadjustment, 0.0); + else if (x > LIST_WIDTH (clist) - clist->clist_window_width) + gtk_adjustment_set_value + (clist->hadjustment, LIST_WIDTH (clist) - clist->clist_window_width); + else + gtk_adjustment_set_value (clist->hadjustment, x); } + + /* adjust vertical scrollbar */ + if (clist->vadjustment && row >= 0) + move_vertical (clist, row, row_align); } -static void -gtk_clist_draw (GtkWidget * widget, - GdkRectangle * area) +void +gtk_clist_set_row_height (GtkCList *clist, + guint height) { - GtkCList *clist; - gint border_width; - GdkRectangle child_area; - int i; - - 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); - border_width = GTK_CONTAINER (widget)->border_width; - - gdk_window_clear_area (widget->window, - area->x - border_width, - area->y - border_width, - area->width, area->height); + GtkWidget *widget; - /* draw list shadow/border */ - gtk_draw_shadow (widget->style, widget->window, - GTK_STATE_NORMAL, clist->shadow_type, - 0, 0, - clist->clist_window_width + (2 * widget->style->klass->xthickness), - clist->clist_window_height + (2 * widget->style->klass->ythickness) + - clist->column_title_area.height); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - gdk_window_clear_area (clist->clist_window, - 0, 0, -1, -1); + widget = GTK_WIDGET (clist); - draw_rows (clist, NULL); + if (height > 0) + { + clist->row_height = height; + GTK_CLIST_SET_FLAG (clist, CLIST_ROW_HEIGHT_SET); + } + else + { + GTK_CLIST_UNSET_FLAG (clist, CLIST_ROW_HEIGHT_SET); + clist->row_height = 0; + } - for (i = 0; i < clist->columns; i++) + if (GTK_WIDGET_REALIZED (clist)) + { + if (!GTK_CLIST_ROW_HEIGHT_SET(clist)) { - if (!clist->column[i].visible) - continue; - if (gtk_widget_intersect (clist->column[i].button, area, &child_area)) - gtk_widget_draw (clist->column[i].button, &child_area); + clist->row_height = (widget->style->font->ascent + + widget->style->font->descent + 1); + clist->row_center_offset = widget->style->font->ascent + 1.5; } + else + clist->row_center_offset = 1.5 + (clist->row_height + + widget->style->font->ascent - + widget->style->font->descent - 1) / 2; } + + CLIST_REFRESH (clist); } -static gint -gtk_clist_expose (GtkWidget * widget, - GdkEventExpose * event) +void +gtk_clist_set_row_data (GtkCList *clist, + gint row, + gpointer data) { - GtkCList *clist; + gtk_clist_set_row_data_full (clist, row, data, NULL); +} - 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); +void +gtk_clist_set_row_data_full (GtkCList *clist, + gint row, + gpointer data, + GtkDestroyNotify destroy) +{ + GtkCListRow *clist_row; - if (GTK_WIDGET_DRAWABLE (widget)) - { - clist = GTK_CLIST (widget); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - /* draw border */ - if (event->window == widget->window) - gtk_draw_shadow (widget->style, widget->window, - GTK_STATE_NORMAL, clist->shadow_type, - 0, 0, - clist->clist_window_width + (2 * widget->style->klass->xthickness), - clist->clist_window_height + (2 * widget->style->klass->ythickness) + - clist->column_title_area.height); + if (row < 0 || row > (clist->rows - 1)) + return; - /* exposure events on the list */ - if (event->window == clist->clist_window) - draw_rows (clist, &event->area); - } + clist_row = ROW_ELEMENT (clist, row)->data; - return FALSE; + if (clist_row->destroy) + clist_row->destroy (clist_row->data); + + clist_row->data = data; + clist_row->destroy = destroy; } -static gint -gtk_clist_button_press (GtkWidget * widget, - GdkEventButton * event) +gpointer +gtk_clist_get_row_data (GtkCList *clist, + gint row) { - gint i; - GtkCList *clist; - gint x; - gint y; - gint row; - gint 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); - - /* we don't handle button 2 and 3 */ - if (event->button != 1) - return FALSE; - - /* selections on the list */ - if (event->window == clist->clist_window) - { - x = event->x; - y = event->y; + GtkCListRow *clist_row; - if (get_selection_info (clist, x, y, &row, &column)) - { - gint old_row = clist->focus_row; + g_return_val_if_fail (clist != NULL, NULL); + g_return_val_if_fail (GTK_IS_CLIST (clist), NULL); - if (clist->focus_row == -1) - old_row = row; + if (row < 0 || row > (clist->rows - 1)) + return NULL; - if (event->type == GDK_BUTTON_PRESS) - { - GTK_CLIST_SET_FLAG (clist, CLIST_DRAG_SELECTION); - gdk_pointer_grab (clist->clist_window, FALSE, - GDK_POINTER_MOTION_HINT_MASK | - GDK_BUTTON1_MOTION_MASK | - GDK_BUTTON_RELEASE_MASK, - NULL, NULL, event->time); - gtk_grab_add (widget); - } - else if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (widget)) - { - GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION); - gtk_grab_remove (widget); - gdk_pointer_ungrab (event->time); - } + clist_row = ROW_ELEMENT (clist, row)->data; + return clist_row->data; +} - if (GTK_CLIST_ADD_MODE (clist)) - { - GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE); - if (GTK_WIDGET_HAS_FOCUS (widget)) - { - gtk_clist_draw_focus (widget); - gdk_gc_set_line_attributes (clist->xor_gc, 1, - GDK_LINE_SOLID, 0, 0); - clist->focus_row = row; - gtk_clist_draw_focus (widget); - } - else - { - gdk_gc_set_line_attributes (clist->xor_gc, 1, - GDK_LINE_SOLID, 0, 0); - clist->focus_row = row; - } - } - else if (row != clist->focus_row) - { - if (GTK_WIDGET_HAS_FOCUS (widget)) - { - gtk_clist_draw_focus (widget); - clist->focus_row = row; - gtk_clist_draw_focus (widget); - } - else - clist->focus_row = row; - } +gint +gtk_clist_find_row_from_data (GtkCList *clist, + gpointer data) +{ + GList *list; + gint n; - if (!GTK_WIDGET_HAS_FOCUS (widget)) - gtk_widget_grab_focus (widget); + g_return_val_if_fail (clist != NULL, -1); + g_return_val_if_fail (GTK_IS_CLIST (clist), -1); - switch (clist->selection_mode) - { - case GTK_SELECTION_SINGLE: - case GTK_SELECTION_MULTIPLE: - if (event->type != GDK_BUTTON_PRESS) - select_row (clist, row, column, (GdkEvent *) event); - else - clist->anchor = row; - break; + for (n = 0, list = clist->row_list; list; n++, list = list->next) + if (GTK_CLIST_ROW (list)->data == data) + return n; - case GTK_SELECTION_BROWSE: - select_row (clist, row, column, (GdkEvent *) event); - break; + return -1; +} - case GTK_SELECTION_EXTENDED: - if (event->type != GDK_BUTTON_PRESS) - { - if (clist->anchor != -1) - { - update_extended_selection (clist, clist->focus_row); - GTK_CLIST_CLASS_FW (clist)->resync_selection - (clist, (GdkEvent *) event); - } - select_row (clist, row, column, (GdkEvent *) event); - break; - } - - if (event->state & GDK_CONTROL_MASK) - { - if (event->state & GDK_SHIFT_MASK) - { - if (clist->anchor < 0) - { - g_list_free (clist->undo_selection); - g_list_free (clist->undo_unselection); - clist->undo_selection = NULL; - clist->undo_unselection = NULL; - clist->anchor = old_row; - clist->drag_pos = old_row; - clist->undo_anchor = old_row; - } - update_extended_selection (clist, clist->focus_row); - } - else - { - if (clist->anchor == -1) - set_anchor (clist, TRUE, row, old_row); - else - update_extended_selection (clist, clist->focus_row); - } - break; - } +void +gtk_clist_swap_rows (GtkCList *clist, + gint row1, + gint row2) +{ + gint first, last; - if (event->state & GDK_SHIFT_MASK) - { - set_anchor (clist, FALSE, old_row, old_row); - update_extended_selection (clist, clist->focus_row); - break; - } + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + g_return_if_fail (row1 != row2); - if (clist->anchor == -1) - set_anchor (clist, FALSE, row, old_row); - else - update_extended_selection (clist, clist->focus_row); - break; + if (GTK_CLIST_AUTO_SORT(clist)) + return; - default: - break; - } - } + gtk_clist_freeze (clist); - return FALSE; - } + first = MIN (row1, row2); + last = MAX (row1, row2); - /* press on resize windows */ - for (i = 0; i < clist->columns; i++) - if (clist->column[i].resizeable && clist->column[i].window && - event->window == clist->column[i].window) - { - gdk_pointer_grab (clist->column[i].window, FALSE, - GDK_POINTER_MOTION_HINT_MASK | - GDK_BUTTON1_MOTION_MASK | - GDK_BUTTON_RELEASE_MASK, - NULL, NULL, event->time); - gtk_grab_add (widget); - GTK_CLIST_SET_FLAG (clist, CLIST_IN_DRAG); + gtk_clist_row_move (clist, last, first); + gtk_clist_row_move (clist, first + 1, last); + + gtk_clist_thaw (clist); +} - if (!GTK_WIDGET_HAS_FOCUS (widget)) - gtk_widget_grab_focus (widget); +void +gtk_clist_row_move (GtkCList *clist, + gint source_row, + gint dest_row) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - clist->drag_pos = i; - clist->x_drag = (COLUMN_LEFT_XPIXEL(clist, i) + COLUMN_INSET + - clist->column[i].area.width + CELL_SPACING); + if (GTK_CLIST_AUTO_SORT(clist)) + return; - if (GTK_CLIST_ADD_MODE (clist)) - gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0); - draw_xor_line (clist); + if (source_row < 0 || source_row >= clist->rows || + dest_row < 0 || dest_row >= clist->rows || + source_row == dest_row) + return; - return FALSE; - } - return FALSE; + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[ROW_MOVE], + source_row, dest_row); } -static gint -gtk_clist_button_release (GtkWidget * widget, - GdkEventButton * event) +GtkVisibility +gtk_clist_row_is_visible (GtkCList *clist, + gint row) { - GtkCList *clist; + gint top; - 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); + g_return_val_if_fail (clist != NULL, 0); + g_return_val_if_fail (GTK_IS_CLIST (clist), 0); - clist = GTK_CLIST (widget); + if (row < 0 || row >= clist->rows) + return GTK_VISIBILITY_NONE; - /* we don't handle button 2 and 3 */ - if (event->button != 1) - return FALSE; + if (clist->row_height == 0) + return GTK_VISIBILITY_NONE; - /* release on resize windows */ - if (GTK_CLIST_IN_DRAG (clist)) - { - gint width; - gint x; - gint i; + if (row < ROW_FROM_YPIXEL (clist, 0)) + return GTK_VISIBILITY_NONE; - i = clist->drag_pos; - clist->drag_pos = -1; + if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height)) + return GTK_VISIBILITY_NONE; - GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG); - gtk_widget_get_pointer (widget, &x, NULL); - gtk_grab_remove (widget); - gdk_pointer_ungrab (event->time); + top = ROW_TOP_YPIXEL (clist, row); - if (clist->x_drag >= 0) - draw_xor_line (clist); + if ((top < 0) + || ((top + clist->row_height) >= clist->clist_window_height)) + return GTK_VISIBILITY_PARTIAL; - if (GTK_CLIST_ADD_MODE (clist)) - { - gdk_gc_set_line_attributes (clist->xor_gc, 1, - GDK_LINE_ON_OFF_DASH, 0, 0); - gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2); - } + return GTK_VISIBILITY_FULL; +} - width = new_column_width (clist, i, &x); - resize_column (clist, i, width); - return FALSE; - } +void +gtk_clist_set_foreground (GtkCList *clist, + gint row, + GdkColor *color) +{ + GtkCListRow *clist_row; - if (GTK_CLIST_DRAG_SELECTION (clist)) - { - gint row; - gint column; + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION); - gtk_grab_remove (widget); - gdk_pointer_ungrab (event->time); - if (clist->htimer) - { - gtk_timeout_remove (clist->htimer); - clist->htimer = 0; - } - if (clist->vtimer) - { - gtk_timeout_remove (clist->vtimer); - clist->vtimer = 0; - } - switch (clist->selection_mode) - { - case GTK_SELECTION_EXTENDED: - if (!(event->state & GDK_SHIFT_MASK) || - event->x < 0 || event->x >= clist->clist_window_width || - event->y < 0 || event->y >= clist->clist_window_height) - GTK_CLIST_CLASS_FW (clist)->resync_selection - (clist, (GdkEvent *) event); - break; + if (row < 0 || row >= clist->rows) + return; - case GTK_SELECTION_SINGLE: - case GTK_SELECTION_MULTIPLE: - if (get_selection_info (clist, event->x, event->y, &row, &column)) - { - if (clist->anchor == clist->focus_row) - toggle_row (clist, row, column, (GdkEvent *) event); - } - clist->anchor = -1; - break; + clist_row = ROW_ELEMENT (clist, row)->data; - default: - break; - } + if (color) + { + clist_row->foreground = *color; + clist_row->fg_set = TRUE; + if (GTK_WIDGET_REALIZED (clist)) + gdk_color_alloc (gtk_widget_get_colormap (GTK_WIDGET (clist)), + &clist_row->foreground); } + else + clist_row->fg_set = FALSE; - return FALSE; + if (CLIST_UNFROZEN (clist) && gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); } -static gint -horizontal_timeout (GtkCList *clist) +void +gtk_clist_set_background (GtkCList *clist, + gint row, + GdkColor *color) { - gint x, y; - GdkEventMotion event; - GdkModifierType mask; + GtkCListRow *clist_row; - g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - clist->htimer = 0; - gdk_window_get_pointer (clist->clist_window, &x, &y, &mask); + if (row < 0 || row >= clist->rows) + return; - event.is_hint = 0; - event.x = x; - event.y = y; - event.state = mask; + clist_row = ROW_ELEMENT (clist, row)->data; - gtk_clist_motion (GTK_WIDGET (clist), &event); + if (color) + { + clist_row->background = *color; + clist_row->bg_set = TRUE; + if (GTK_WIDGET_REALIZED (clist)) + gdk_color_alloc (gtk_widget_get_colormap (GTK_WIDGET (clist)), + &clist_row->background); + } + else + clist_row->bg_set = FALSE; - return FALSE; + if (CLIST_UNFROZEN (clist) + && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); } -static gint -vertical_timeout (GtkCList *clist) +/* PUBLIC ROW/CELL STYLE FUNCTIONS + * gtk_clist_set_cell_style + * gtk_clist_get_cell_style + * gtk_clist_set_row_style + * gtk_clist_get_row_style + */ +void +gtk_clist_set_cell_style (GtkCList *clist, + gint row, + gint column, + GtkStyle *style) { - gint x, y; - GdkEventMotion event; - GdkModifierType mask; + GtkRequisition requisition = { 0 }; + GtkCListRow *clist_row; - g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - clist->vtimer = 0; - gdk_window_get_pointer (clist->clist_window, &x, &y, &mask); + if (row < 0 || row >= clist->rows) + return; + if (column < 0 || column >= clist->columns) + return; - event.is_hint = 0; - event.x = x; - event.y = y; - event.state = mask; + clist_row = ROW_ELEMENT (clist, row)->data; - gtk_clist_motion (GTK_WIDGET (clist), &event); + if (clist_row->cell[column].style == style) + return; - return FALSE; -} + if (clist->column[column].auto_resize && + !GTK_CLIST_AUTO_RESIZE_BLOCKED(clist)) + GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row, + column, &requisition); -static void -move_vertical (GtkCList *clist, - gint row, - gfloat align) -{ - gint y; - GtkAdjustment *adj; + if (clist_row->cell[column].style) + { + if (GTK_WIDGET_REALIZED (clist)) + gtk_style_detach (clist_row->cell[column].style); + gtk_style_unref (clist_row->cell[column].style); + } - adj = GTK_RANGE (clist->vscrollbar)->adjustment; + clist_row->cell[column].style = style; - y = ROW_TOP_YPIXEL (clist, row) - clist->voffset; - - y = y - align * (clist->clist_window_height - clist->row_height) - + (2 * align - 1) * CELL_SPACING; - - if (y + adj->page_size > adj->upper) - adj->value = adj->upper - adj->page_size; - else - adj->value = y; + if (clist_row->cell[column].style) + { + gtk_style_ref (clist_row->cell[column].style); + + if (GTK_WIDGET_REALIZED (clist)) + clist_row->cell[column].style = + gtk_style_attach (clist_row->cell[column].style, + clist->clist_window); + } + + column_auto_resize (clist, clist_row, column, requisition.width); - gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed"); + /* redraw the list if it's not frozen */ + if (CLIST_UNFROZEN (clist)) + { + if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); + } } -static void -move_horizontal (GtkCList *clist, - gint diff) +GtkStyle * +gtk_clist_get_cell_style (GtkCList *clist, + gint row, + gint column) { - gfloat upper; - GtkAdjustment *adj; + GtkCListRow *clist_row; - adj = GTK_RANGE (clist->hscrollbar)->adjustment; + g_return_val_if_fail (clist != NULL, NULL); + g_return_val_if_fail (GTK_IS_CLIST (clist), NULL); - adj->value += diff; + if (row < 0 || row >= clist->rows || column < 0 || column >= clist->columns) + return NULL; - upper = adj->upper - adj->page_size; - adj->value = MIN (adj->value, upper); - adj->value = MAX (adj->value, 0.0); + clist_row = ROW_ELEMENT (clist, row)->data; - gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed"); + return clist_row->cell[column].style; } -static gint -gtk_clist_motion (GtkWidget * widget, - GdkEventMotion * event) +void +gtk_clist_set_row_style (GtkCList *clist, + gint row, + GtkStyle *style) { - GtkCList *clist; - gint x; - gint y; - gint row; - gint new_width; + GtkRequisition requisition; + GtkCListRow *clist_row; + gint *old_width; + gint i; - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - clist = GTK_CLIST (widget); - if (!(gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))) - return FALSE; + if (row < 0 || row >= clist->rows) + return; - if (GTK_CLIST_IN_DRAG (clist)) - { - if (event->is_hint || event->window != widget->window) - gtk_widget_get_pointer (widget, &x, NULL); - else - x = event->x; - - new_width = new_column_width (clist, clist->drag_pos, &x); - if (x != clist->x_drag) - { - /* x_drag < 0 indicates that the xor line is already invisible */ - if (clist->x_drag >= 0) - draw_xor_line (clist); + clist_row = ROW_ELEMENT (clist, row)->data; - clist->x_drag = x; + if (clist_row->style == style) + return; - if (clist->x_drag >= 0) - draw_xor_line (clist); - } + old_width = g_new (gint, clist->columns); - if (new_width <= MAX (COLUMN_MIN_WIDTH + 1, - clist->column[clist->drag_pos].min_width + 1)) - { - if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) < 0 && x < 0) - gtk_clist_moveto (clist, -1, clist->drag_pos, 0, 0); - return FALSE; - } - if (clist->column[clist->drag_pos].max_width >= COLUMN_MIN_WIDTH && - new_width >= clist->column[clist->drag_pos].max_width) - { - if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) + new_width > - clist->clist_window_width && x < 0) - move_horizontal (clist, - COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) + - new_width - clist->clist_window_width + - COLUMN_INSET + CELL_SPACING); - return FALSE; - } + if (!GTK_CLIST_AUTO_RESIZE_BLOCKED(clist)) + { + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + { + GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row, + i, &requisition); + old_width[i] = requisition.width; + } } - if (event->is_hint || event->window != clist->clist_window) - gdk_window_get_pointer (clist->clist_window, &x, &y, NULL); - - /* horizontal autoscrolling */ - if (LIST_WIDTH (clist) > clist->clist_window_width && - (x < 0 || x >= clist->clist_window_width)) + if (clist_row->style) { - if (clist->htimer) - return FALSE; + if (GTK_WIDGET_REALIZED (clist)) + gtk_style_detach (clist_row->style); + gtk_style_unref (clist_row->style); + } - clist->htimer = gtk_timeout_add - (SCROLL_TIME, (GtkFunction) horizontal_timeout, clist); + clist_row->style = style; - if (!((x < 0 && GTK_RANGE (clist->hscrollbar)->adjustment->value == 0) || - (x >= clist->clist_window_width && - GTK_RANGE (clist->hscrollbar)->adjustment->value == - LIST_WIDTH (clist) - clist->clist_window_width))) - { - if (x < 0) - move_horizontal (clist, -1 + (x/2)); - else - move_horizontal (clist, 1 + (x - clist->clist_window_width) / 2); - } + if (clist_row->style) + { + gtk_style_ref (clist_row->style); + + if (GTK_WIDGET_REALIZED (clist)) + clist_row->style = gtk_style_attach (clist_row->style, + clist->clist_window); } - if (GTK_CLIST_IN_DRAG (clist)) - return FALSE; - - /* vertical autoscrolling */ - row = ROW_FROM_YPIXEL (clist, y); + if (GTK_CLIST_AUTO_RESIZE_BLOCKED(clist)) + for (i = 0; i < clist->columns; i++) + column_auto_resize (clist, clist_row, i, old_width[i]); - /* don't scroll on last pixel row if it's a cell spacing */ - if (y == clist->clist_window_height-1 && - y == ROW_TOP_YPIXEL (clist, row-1) + clist->row_height) - return FALSE; + g_free (old_width); - if (LIST_HEIGHT (clist) > clist->clist_window_height && - (y < 0 || y >= clist->clist_window_height)) + /* redraw the list if it's not frozen */ + if (CLIST_UNFROZEN (clist)) { - if (clist->vtimer) - return FALSE; - - clist->vtimer = gtk_timeout_add (SCROLL_TIME, - (GtkFunction) vertical_timeout, clist); - - if (GTK_CLIST_DRAG_SELECTION (clist)) - { - if ((y < 0 && clist->focus_row == 0) || - (y >= clist->clist_window_height && - clist->focus_row == clist->rows-1)) - return FALSE; - } + if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); } +} - row = CLAMP (row, 0, clist->rows - 1); +GtkStyle * +gtk_clist_get_row_style (GtkCList *clist, + gint row) +{ + GtkCListRow *clist_row; - if (GTK_CLIST_DRAG_SELECTION (clist)) - { - if (row == clist->focus_row) - return FALSE; + g_return_val_if_fail (clist != NULL, NULL); + g_return_val_if_fail (GTK_IS_CLIST (clist), NULL); - gtk_clist_draw_focus (widget); - clist->focus_row = row; - gtk_clist_draw_focus (widget); + if (row < 0 || row >= clist->rows) + return NULL; - switch (clist->selection_mode) - { - case GTK_SELECTION_BROWSE: - select_row (clist, clist->focus_row, - 1, (GdkEvent *) event); - break; - - case GTK_SELECTION_EXTENDED: - update_extended_selection (clist, clist->focus_row); - break; - - default: - break; - } - } - - if (ROW_TOP_YPIXEL(clist, row) < 0) - move_vertical (clist, row, 0); - else if (ROW_TOP_YPIXEL(clist, row) + clist->row_height > - clist->clist_window_height) - move_vertical (clist, row, 1); + clist_row = ROW_ELEMENT (clist, row)->data; - return FALSE; + return clist_row->style; } -static void -gtk_clist_size_request (GtkWidget * widget, - GtkRequisition * requisition) +/* PUBLIC SELECTION FUNCTIONS + * gtk_clist_set_selectable + * gtk_clist_get_selectable + * gtk_clist_select_row + * gtk_clist_unselect_row + * gtk_clist_select_all + * gtk_clist_unselect_all + * gtk_clist_undo_selection + */ +void +gtk_clist_set_selectable (GtkCList *clist, + gint row, + gboolean selectable) { - gint i; - GtkCList *clist; + GtkCListRow *clist_row; - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_CLIST (widget)); - g_return_if_fail (requisition != NULL); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - clist = GTK_CLIST (widget); + if (row < 0 || row >= clist->rows) + return; - add_style_data (clist); + clist_row = ROW_ELEMENT (clist, row)->data; - requisition->width = 0; - requisition->height = 0; + if (selectable == clist_row->selectable) + return; - /* compute the size of the column title (title) area */ - clist->column_title_area.height = 0; - if (GTK_CLIST_SHOW_TITLES (clist)) - for (i = 0; i < clist->columns; i++) - if (clist->column[i].button) + clist_row->selectable = selectable; + + if (!selectable && clist_row->state == GTK_STATE_SELECTED) + { + if (clist->anchor >= 0 && + clist->selection_mode == GTK_SELECTION_EXTENDED) { - 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); + clist->drag_button = 0; + remove_grab (clist); + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); } - requisition->height += clist->column_title_area.height; + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], + row, -1, NULL); + } +} - /* 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); +gboolean +gtk_clist_get_selectable (GtkCList *clist, + gint row) +{ + g_return_val_if_fail (clist != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE); - requisition->width += (clist->vscrollbar->requisition.width + - SCROLLBAR_SPACING (clist)); - requisition->height = MAX (requisition->height, - clist->vscrollbar->requisition.height); - } + if (row < 0 || row >= clist->rows) + return FALSE; - /* 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); + return GTK_CLIST_ROW (ROW_ELEMENT (clist, row))->selectable; +} - requisition->height += (clist->hscrollbar->requisition.height + - SCROLLBAR_SPACING (clist)); - requisition->width = MAX (clist->hscrollbar->requisition.width, - requisition->width - - clist->vscrollbar->requisition.width); +void +gtk_clist_select_row (GtkCList *clist, + gint row, + gint column) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - } + if (row < 0 || row >= clist->rows) + return; + if (column < -1 || column >= clist->columns) + return; - 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); + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + row, column, NULL); } -static void -gtk_clist_size_allocate (GtkWidget * widget, - GtkAllocation * allocation) +void +gtk_clist_unselect_row (GtkCList *clist, + gint row, + gint column) { - GtkCList *clist; - GtkAllocation clist_allocation; - GtkAllocation child_allocation; - gint i, vscrollbar_vis, hscrollbar_vis; - gint border_width; + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_CLIST (widget)); - g_return_if_fail (allocation != NULL); + if (row < 0 || row >= clist->rows) + return; + if (column < -1 || column >= clist->columns) + return; - clist = GTK_CLIST (widget); - widget->allocation = *allocation; - border_width = GTK_CONTAINER (widget)->border_width; + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], + row, column, NULL); +} - if (GTK_WIDGET_REALIZED (widget)) - { - gdk_window_move_resize (widget->window, - allocation->x + border_width, - allocation->y + border_width, - allocation->width - border_width * 2, - allocation->height - border_width * 2); - } +void +gtk_clist_select_all (GtkCList *clist) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - /* use internal allocation structure for all the math - * because it's easier than always subtracting the container - * border width */ - clist->internal_allocation.x = 0; - clist->internal_allocation.y = 0; - clist->internal_allocation.width = MAX (1, allocation->width - - border_width * 2); - clist->internal_allocation.height = MAX (1, allocation->height - - border_width * 2); - - /* allocate clist window assuming no scrollbars */ - clist_allocation.x = (clist->internal_allocation.x + - widget->style->klass->xthickness); - clist_allocation.y = (clist->internal_allocation.y + - widget->style->klass->ythickness + - clist->column_title_area.height); - clist_allocation.width = MAX (1, clist->internal_allocation.width - - (2 * widget->style->klass->xthickness)); - clist_allocation.height = MAX (1, clist->internal_allocation.height - - (2 * widget->style->klass->ythickness) - - 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 = MAX (1, clist_allocation.width - - (clist->vscrollbar->requisition.width + - SCROLLBAR_SPACING (clist))); - } - - 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 = MAX (1, clist_allocation.height - - (clist->hscrollbar->requisition.height - + SCROLLBAR_SPACING (clist))); - } - } - - clist->clist_window_width = clist_allocation.width; - clist->clist_window_height = clist_allocation.height; - - if (GTK_WIDGET_REALIZED (widget)) - { - 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 = widget->style->klass->xthickness; - clist->column_title_area.y = widget->style->klass->ythickness; - clist->column_title_area.width = clist_allocation.width; - - if (GTK_WIDGET_REALIZED (widget)) - { - gdk_window_move_resize (clist->title_window, - clist->column_title_area.x, - clist->column_title_area.y, - clist->column_title_area.width, - clist->column_title_area.height); - } - - /* column button allocation */ - size_allocate_columns (clist); - size_allocate_title_buttons (clist); + GTK_CLIST_CLASS_FW (clist)->select_all (clist); +} - adjust_scrollbars (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 = MAX (1, clist->internal_allocation.height - - (hscrollbar_vis ? - (clist->hscrollbar->requisition.height + - SCROLLBAR_SPACING (clist)) : 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 = MAX (1, clist->internal_allocation.width - - (vscrollbar_vis ? - (clist->vscrollbar->requisition.width + - SCROLLBAR_SPACING (clist)) : 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); - } +void +gtk_clist_unselect_all (GtkCList *clist) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - /* set the vscrollbar adjustments */ - adjust_scrollbars (clist); + GTK_CLIST_CLASS_FW (clist)->unselect_all (clist); } -/* - * GTKCONTAINER - * gtk_clist_forall +void +gtk_clist_undo_selection (GtkCList *clist) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (clist->selection_mode == GTK_SELECTION_EXTENDED && + (clist->undo_selection || clist->undo_unselection)) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNDO_SELECTION]); +} + +/* PRIVATE SELECTION FUNCTIONS + * selection_find + * toggle_row + * fake_toggle_row + * toggle_focus_row + * toggle_add_mode + * real_select_row + * real_unselect_row + * real_select_all + * real_unselect_all + * fake_unselect_all + * real_undo_selection + * set_anchor + * resync_selection + * update_extended_selection + * start_selection + * end_selection + * extend_selection + * sync_selection */ -static void -gtk_clist_forall (GtkContainer *container, - gboolean include_internals, - GtkCallback callback, - gpointer callback_data) +static GList * +selection_find (GtkCList *clist, + gint row_number, + GList *row_list_element) { - GtkCList *clist; + return g_list_find (clist->selection, GINT_TO_POINTER (row_number)); +} - g_return_if_fail (container != NULL); - g_return_if_fail (GTK_IS_CLIST (container)); - g_return_if_fail (callback != NULL); +static void +toggle_row (GtkCList *clist, + gint row, + gint column, + GdkEvent *event) +{ + GtkCListRow *clist_row; - clist = GTK_CLIST (container); - - if (include_internals) + switch (clist->selection_mode) { - guint i; - - /* callback for the column buttons */ - for (i = 0; i < clist->columns; i++) - if (clist->column[i].button) - (*callback) (clist->column[i].button, callback_data); - - /* callbacks for the scrollbars */ - if (clist->vscrollbar) - (*callback) (clist->vscrollbar, callback_data); - if (clist->hscrollbar) - (*callback) (clist->hscrollbar, callback_data); + case GTK_SELECTION_EXTENDED: + case GTK_SELECTION_MULTIPLE: + case GTK_SELECTION_SINGLE: + clist_row = ROW_ELEMENT (clist, row)->data; + + if (!clist_row) + return; + + if (clist_row->state == GTK_STATE_SELECTED) + { + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], + row, column, event); + return; + } + case GTK_SELECTION_BROWSE: + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + row, column, event); + break; } } -/* - * DRAWING - * draw_row - * draw_rows - */ static void -draw_row (GtkCList * clist, - GdkRectangle * area, - gint row, - GtkCListRow * clist_row) +fake_toggle_row (GtkCList *clist, + gint 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; + GList *work; - g_return_if_fail (clist != NULL); + work = ROW_ELEMENT (clist, row); - /* bail now if we arn't drawable yet */ - if (!GTK_WIDGET_DRAWABLE (clist)) + if (!work || !GTK_CLIST_ROW (work)->selectable) return; + + if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL) + clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED; + else + clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL; + + if (CLIST_UNFROZEN (clist) && + gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, + GTK_CLIST_ROW (work)); +} - if (row < 0 || row >= clist->rows) +static void +toggle_focus_row (GtkCList *clist) +{ + g_return_if_fail (clist != 0); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) || + clist->focus_row < 0 || clist->focus_row >= clist->rows) return; - widget = GTK_WIDGET (clist); + switch (clist->selection_mode) + { + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_MULTIPLE: + toggle_row (clist, clist->focus_row, 0, NULL); + break; + case GTK_SELECTION_EXTENDED: + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; - /* 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; + clist->anchor = clist->focus_row; + clist->drag_pos = clist->focus_row; + clist->undo_anchor = clist->focus_row; + + if (GTK_CLIST_ADD_MODE(clist)) + fake_toggle_row (clist, clist->focus_row); + else + GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist,clist->focus_row); - /* 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; + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); + break; + default: + break; + } +} - /* 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; +static void +toggle_add_mode (GtkCList *clist) +{ + g_return_if_fail (clist != 0); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) || + clist->selection_mode != GTK_SELECTION_EXTENDED) + return; - /* select GC for background rectangle */ - if (clist_row->state == GTK_STATE_SELECTED) + gtk_clist_draw_focus (GTK_WIDGET (clist)); + if (!GTK_CLIST_ADD_MODE(clist)) { - fg_gc = widget->style->fg_gc[GTK_STATE_SELECTED]; - bg_gc = widget->style->bg_gc[GTK_STATE_SELECTED]; + GTK_CLIST_SET_FLAG (clist, CLIST_ADD_MODE); + gdk_gc_set_line_attributes (clist->xor_gc, 1, + GDK_LINE_ON_OFF_DASH, 0, 0); + gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2); } else { - if (clist_row->fg_set) - { - gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground); - fg_gc = clist->fg_gc; - } - else - fg_gc = widget->style->fg_gc[GTK_STATE_NORMAL]; - - if (clist_row->bg_set) - { - gdk_gc_set_foreground (clist->bg_gc, &clist_row->background); - bg_gc = clist->bg_gc; - } - else - bg_gc = widget->style->bg_gc[GTK_STATE_PRELIGHT]; + GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE); + gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0); + clist->anchor_state = GTK_STATE_SELECTED; } + gtk_clist_draw_focus (GTK_WIDGET (clist)); +} - /* draw the cell borders and background */ - if (area) +static void +real_select_row (GtkCList *clist, + gint row, + gint column, + GdkEvent *event) +{ + GtkCListRow *clist_row; + GList *list; + gint sel_row; + gboolean row_selected; + + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (row < 0 || row > (clist->rows - 1)) + return; + + switch (clist->selection_mode) { - if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle)) - gdk_draw_rectangle (clist->clist_window, - widget->style->base_gc[GTK_STATE_NORMAL], - TRUE, - intersect_rectangle.x, - intersect_rectangle.y, - intersect_rectangle.width, - intersect_rectangle.height); + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_BROWSE: - /* the last row has to clear it's bottom cell spacing too */ - if (clist_row == clist->row_list_end->data) + row_selected = FALSE; + list = clist->selection; + + while (list) { - cell_rectangle.y += clist->row_height + CELL_SPACING; + sel_row = GPOINTER_TO_INT (list->data); + list = list->next; - if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle)) - gdk_draw_rectangle (clist->clist_window, - widget->style->base_gc[GTK_STATE_NORMAL], - TRUE, - intersect_rectangle.x, - intersect_rectangle.y, - intersect_rectangle.width, - intersect_rectangle.height); + if (row == sel_row) + row_selected = TRUE; + else + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], + sel_row, column, event); } - if (!gdk_rectangle_intersect (area, &row_rectangle, &intersect_rectangle)) + if (row_selected) return; - - if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set) - 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, - intersect_rectangle.x, - intersect_rectangle.y, - intersect_rectangle.width, - intersect_rectangle.height); + + default: + break; } - else - { - gdk_draw_rectangle (clist->clist_window, - widget->style->base_gc[GTK_STATE_NORMAL], - TRUE, - cell_rectangle.x, - cell_rectangle.y, - cell_rectangle.width, - cell_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; - gdk_draw_rectangle (clist->clist_window, - widget->style->base_gc[GTK_STATE_NORMAL], - TRUE, - cell_rectangle.x, - cell_rectangle.y, - cell_rectangle.width, - cell_rectangle.height); - } + clist_row = ROW_ELEMENT (clist, row)->data; - if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set) - gdk_draw_rectangle (clist->clist_window, - bg_gc, - TRUE, - row_rectangle.x, - row_rectangle.y, - row_rectangle.width, - row_rectangle.height); - else - gdk_window_clear_area (clist->clist_window, - row_rectangle.x, - row_rectangle.y, - row_rectangle.width, - row_rectangle.height); - } + if (clist_row->state != GTK_STATE_NORMAL || !clist_row->selectable) + return; - /* iterate and draw all the columns (row cells) and draw their contents */ - for (i = 0; i < clist->columns; i++) + clist_row->state = GTK_STATE_SELECTED; + if (!clist->selection) { - if (!clist->column[i].visible) - continue; - - clip_rectangle.x = clist->column[i].area.x + clist->hoffset; - clip_rectangle.width = clist->column[i].area.width; + clist->selection = g_list_append (clist->selection, + GINT_TO_POINTER (row)); + clist->selection_end = clist->selection; + } + else + clist->selection_end = + g_list_append (clist->selection_end, GINT_TO_POINTER (row))->next; + + if (CLIST_UNFROZEN (clist) + && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); +} - /* calculate clipping region clipping region */ - if (!area) - { - rect = &clip_rectangle; - } - else - { - if (!gdk_rectangle_intersect (area, &clip_rectangle, - &intersect_rectangle)) - continue; - rect = &intersect_rectangle; - } +static void +real_unselect_row (GtkCList *clist, + gint row, + gint column, + GdkEvent *event) +{ + GtkCListRow *clist_row; - /* calculate real width for column justification */ - switch (clist_row->cell[i].type) - { - case GTK_CELL_EMPTY: - continue; - break; + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - case GTK_CELL_TEXT: - width = gdk_string_width (GTK_WIDGET (clist)->style->font, - GTK_CELL_TEXT (clist_row->cell[i])->text); - break; + if (row < 0 || row > (clist->rows - 1)) + return; - case GTK_CELL_PIXMAP: - gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, &width, &height); - pixmap_width = width; - break; + clist_row = ROW_ELEMENT (clist, row)->data; - 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; + if (clist_row->state == GTK_STATE_SELECTED) + { + clist_row->state = GTK_STATE_NORMAL; - case GTK_CELL_WIDGET: - /* unimplimented */ - continue; - break; + if (clist->selection_end && + clist->selection_end->data == GINT_TO_POINTER (row)) + clist->selection_end = clist->selection_end->prev; - default: - continue; - break; - } + clist->selection = g_list_remove (clist->selection, + GINT_TO_POINTER (row)); + + if (CLIST_UNFROZEN (clist) + && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); + } +} - switch (clist->column[i].justification) - { - case GTK_JUSTIFY_LEFT: - offset = clip_rectangle.x; - break; +static void +real_select_all (GtkCList *clist) +{ + GList *list; + gint i; + + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - case GTK_JUSTIFY_RIGHT: - offset = (clip_rectangle.x + clip_rectangle.width) - width; - break; + if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) + return; - case GTK_JUSTIFY_CENTER: - offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2); - break; + switch (clist->selection_mode) + { + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_BROWSE: + return; - case GTK_JUSTIFY_FILL: - offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2); - break; + case GTK_SELECTION_EXTENDED: + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + + if (clist->rows && + ((GtkCListRow *) (clist->row_list->data))->state != + GTK_STATE_SELECTED) + fake_toggle_row (clist, 0); - default: - offset = 0; - break; - }; + clist->anchor_state = GTK_STATE_SELECTED; + clist->anchor = 0; + clist->drag_pos = 0; + clist->undo_anchor = clist->focus_row; + update_extended_selection (clist, clist->rows); + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); + return; - /* Draw Text or Pixmap */ - switch (clist_row->cell[i].type) + case GTK_SELECTION_MULTIPLE: + for (i = 0, list = clist->row_list; list; i++, list = list->next) { - 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].vertical, - 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].vertical; - - if (xdest < clip_rectangle.x) - { - xsrc = clip_rectangle.x - xdest; - pixmap_width -= xsrc; - xdest = clip_rectangle.x; - } - - if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width) - pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest; - - if (ydest < clip_rectangle.y) - { - ysrc = clip_rectangle.y - ydest; - height -= ysrc; - ydest = clip_rectangle.y; - } - - if (ydest + height > clip_rectangle.y + clip_rectangle.height) - height = (clip_rectangle.y + clip_rectangle.height) - ydest; - - if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask) - { - 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); - - if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask) - { - 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].vertical; - - if (xdest < clip_rectangle.x) - { - xsrc = clip_rectangle.x - xdest; - pixmap_width -= xsrc; - xdest = clip_rectangle.x; - } - - if (xdest + pixmap_width > clip_rectangle.x + clip_rectangle.width) - pixmap_width = (clip_rectangle.x + clip_rectangle.width) - xdest; - - if (ydest < clip_rectangle.y) - { - ysrc = clip_rectangle.y - ydest; - height -= ysrc; - ydest = clip_rectangle.y; - } - - if (ydest + height > clip_rectangle.y + clip_rectangle.height) - height = (clip_rectangle.y + clip_rectangle.height) - ydest; - - if (GTK_CELL_PIXTEXT (clist_row->cell[i])->mask) - { - 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].vertical, - 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; - } - } - if (clist->focus_row == row && GTK_WIDGET_HAS_FOCUS (widget)) - { - if (area) - { - if (gdk_rectangle_intersect (area, &row_rectangle, - &intersect_rectangle)) - { - gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle); - gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, - row_rectangle.x, row_rectangle.y, - row_rectangle.width - 1, - row_rectangle.height - 1); - gdk_gc_set_clip_rectangle (clist->xor_gc, NULL); - } + if (((GtkCListRow *)(list->data))->state == GTK_STATE_NORMAL) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + i, -1, NULL); } - else - gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, - row_rectangle.x, row_rectangle.y, - row_rectangle.width - 1, row_rectangle.height - 1); + return; } } static void -draw_rows (GtkCList * clist, - GdkRectangle * area) +real_unselect_all (GtkCList *clist) { GList *list; - GtkCListRow *clist_row; - int i, first_row, last_row; - + gint i; + g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (clist->row_height == 0 || - !GTK_WIDGET_DRAWABLE (clist)) + if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) return; - if (area) - { - first_row = ROW_FROM_YPIXEL (clist, area->y); - last_row = ROW_FROM_YPIXEL (clist, area->y + area->height); - } - else + switch (clist->selection_mode) { - first_row = ROW_FROM_YPIXEL (clist, 0); - last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height); - } + case GTK_SELECTION_BROWSE: + if (clist->focus_row >= 0) + { + gtk_signal_emit (GTK_OBJECT (clist), + clist_signals[SELECT_ROW], + clist->focus_row, -1, NULL); + return; + } + break; + case GTK_SELECTION_EXTENDED: + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; - /* this is a small special case which exposes the bottom cell line - * on the last row -- it might go away if I change the wall the cell spacings - * are drawn */ - if (clist->rows == first_row) - first_row--; + clist->anchor = -1; + clist->drag_pos = -1; + clist->undo_anchor = clist->focus_row; + break; + default: + break; + } - list = g_list_nth (clist->row_list, first_row); - i = first_row; + list = clist->selection; while (list) { - clist_row = list->data; + i = GPOINTER_TO_INT (list->data); list = list->next; - - if (i > last_row) - return; - - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, area, i, clist_row); - i++; + gtk_signal_emit (GTK_OBJECT (clist), + clist_signals[UNSELECT_ROW], i, -1, NULL); } - - if (!area) - gdk_window_clear_area (clist->clist_window, 0, ROW_TOP_YPIXEL (clist, i), -1, -1); } -/* - * SIZE ALLOCATION - * size_allocate_title_buttons - * size_allocate_columns - */ static void -size_allocate_title_buttons (GtkCList * clist) +fake_unselect_all (GtkCList *clist, + gint row) { - GtkAllocation button_allocation; - gint last_column; - gint last_button = 0; + GList *list; + GList *work; gint i; - if (!GTK_WIDGET_REALIZED (clist)) - return; - - button_allocation.x = clist->hoffset; - button_allocation.y = 0; - button_allocation.width = 0; - button_allocation.height = clist->column_title_area.height; - - /* find last visible column */ - for (last_column = clist->columns - 1; last_column >= 0; last_column--) - if (clist->column[last_column].visible) - break; - - for (i = 0; i < last_column; i++) + if (row >= 0 && (work = ROW_ELEMENT (clist, row))) { - if (!clist->column[i].visible) - { - last_button = i + 1; - gdk_window_hide (clist->column[i].window); - continue; - } - - button_allocation.width += (clist->column[i].area.width + - CELL_SPACING + 2 * COLUMN_INSET); - - if (!clist->column[i + 1].button) - { - gdk_window_hide (clist->column[i].window); - continue; - } - - gtk_widget_size_allocate (clist->column[last_button].button, - &button_allocation); - button_allocation.x += button_allocation.width; - button_allocation.width = 0; - - if (clist->column[last_button].resizeable) + if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL && + GTK_CLIST_ROW (work)->selectable) { - gdk_window_show (clist->column[last_button].window); - gdk_window_move_resize (clist->column[last_button].window, - button_allocation.x - (DRAG_WIDTH / 2), - 0, DRAG_WIDTH, - clist->column_title_area.height); - } - else - gdk_window_hide (clist->column[last_button].window); - - last_button = i + 1; + GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED; + + if (CLIST_UNFROZEN (clist) && + gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, + GTK_CLIST_ROW (work)); + } } - button_allocation.width += (clist->column[last_column].area.width + - 2 * (CELL_SPACING + COLUMN_INSET)); - gtk_widget_size_allocate (clist->column[last_button].button, - &button_allocation); + clist->undo_selection = clist->selection; + clist->selection = NULL; + clist->selection_end = NULL; - if (clist->column[last_button].resizeable) + for (list = clist->undo_selection; list; list = list->next) { - button_allocation.x += button_allocation.width; + if ((i = GPOINTER_TO_INT (list->data)) == row || + !(work = g_list_nth (clist->row_list, i))) + continue; - gdk_window_show (clist->column[last_button].window); - gdk_window_move_resize (clist->column[last_button].window, - button_allocation.x - (DRAG_WIDTH / 2), - 0, DRAG_WIDTH, clist->column_title_area.height); + GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL; + if (CLIST_UNFROZEN (clist) && + gtk_clist_row_is_visible (clist, i) != GTK_VISIBILITY_NONE) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, i, + GTK_CLIST_ROW (work)); } - else - gdk_window_hide (clist->column[last_button].window); } static void -size_allocate_columns (GtkCList * clist) +real_undo_selection (GtkCList *clist) { - gint xoffset = CELL_SPACING + COLUMN_INSET; - gint last_column; - gint width = 0; - gint i; + GList *work; - /* find last visible column and calculate correct column width */ - for (last_column = clist->columns - 1; - last_column >= 0 && !clist->column[last_column].visible; last_column--); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - if (last_column < 0) + if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) || + clist->selection_mode != GTK_SELECTION_EXTENDED) return; - for (i = 0; i < last_column; i++) + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); + + if (!(clist->undo_selection || clist->undo_unselection)) { - if (!clist->column[i].visible) - continue; - clist->column[i].area.x = xoffset; - clist->column[i].area.width = clist->column[i].width; - xoffset += clist->column[i].width + CELL_SPACING + (2 * COLUMN_INSET); + gtk_clist_unselect_all (clist); + return; + } + + for (work = clist->undo_selection; work; work = work->next) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + GPOINTER_TO_INT (work->data), -1, NULL); + + for (work = clist->undo_unselection; work; work = work->next) + { + /* g_print ("unselect %d\n",GPOINTER_TO_INT (work->data)); */ + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], + GPOINTER_TO_INT (work->data), -1, NULL); } - if (clist->column[i].width_set) - width = clist->column[i].width; - else if (clist->column[i].title) - width = gdk_string_width (GTK_WIDGET (clist)->style->font, - clist->column[i].title); + if (GTK_WIDGET_HAS_FOCUS(clist) && clist->focus_row != clist->undo_anchor) + { + gtk_clist_draw_focus (GTK_WIDGET (clist)); + clist->focus_row = clist->undo_anchor; + gtk_clist_draw_focus (GTK_WIDGET (clist)); + } + else + clist->focus_row = clist->undo_anchor; + + clist->undo_anchor = -1; + + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; - clist->column[i].area.x = xoffset; - clist->column[i].area.width = MAX (width, - clist->clist_window_width - xoffset - - (CELL_SPACING + COLUMN_INSET)); + if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height > + clist->clist_window_height) + gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0) + gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); } -/* - * SELECTION - * select_row - * real_select_row - * real_unselect_row - * get_selection_info - */ static void -toggle_row (GtkCList * clist, - gint row, - gint column, - GdkEvent * event) +set_anchor (GtkCList *clist, + gboolean add_mode, + gint anchor, + gint undo_anchor) { - GtkCListRow *clist_row; + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor >= 0) + return; - switch (clist->selection_mode) - { - case GTK_SELECTION_EXTENDED: - case GTK_SELECTION_MULTIPLE: - case GTK_SELECTION_SINGLE: - - clist_row = g_list_nth (clist->row_list, row)->data; - if (clist_row->state == GTK_STATE_SELECTED) - { - unselect_row (clist, row, column, event); - return; - } + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; - case GTK_SELECTION_BROWSE: - select_row (clist, row, column, event); - break; + if (add_mode) + fake_toggle_row (clist, anchor); + else + { + GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist, anchor); + clist->anchor_state = GTK_STATE_SELECTED; } -} - -static void -select_row (GtkCList * clist, - gint row, - gint column, - GdkEvent * event) -{ - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], - row, column, event); -} -static void -unselect_row (GtkCList * clist, - gint row, - gint column, - GdkEvent * event) -{ - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], - row, column, event); + clist->anchor = anchor; + clist->drag_pos = anchor; + clist->undo_anchor = undo_anchor; } static void -real_select_row (GtkCList * clist, - gint row, - gint column, - GdkEvent * event) +resync_selection (GtkCList *clist, + GdkEvent *event) { - GtkCListRow *clist_row; + gint i; + gint e; + gint row; GList *list; - gint sel_row; - gboolean row_selected; + GtkCListRow *clist_row; - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + if (clist->selection_mode != GTK_SELECTION_EXTENDED) + return; - if (row < 0 || row > (clist->rows - 1)) + if (clist->anchor < 0 || clist->drag_pos < 0) return; - switch (clist->selection_mode) - { - case GTK_SELECTION_SINGLE: - case GTK_SELECTION_BROWSE: + gtk_clist_freeze (clist); - row_selected = FALSE; - list = clist->selection; + i = MIN (clist->anchor, clist->drag_pos); + e = MAX (clist->anchor, clist->drag_pos); + if (clist->undo_selection) + { + list = clist->selection; + clist->selection = clist->undo_selection; + clist->selection_end = g_list_last (clist->selection); + clist->undo_selection = list; + list = clist->selection; while (list) { - sel_row = GPOINTER_TO_INT (list->data); + row = GPOINTER_TO_INT (list->data); list = list->next; - - if (row == sel_row) - row_selected = TRUE; - else - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], - sel_row, column, event); + if (row < i || row > e) + { + clist_row = g_list_nth (clist->row_list, row)->data; + if (clist_row->selectable) + { + clist_row->state = GTK_STATE_SELECTED; + gtk_signal_emit (GTK_OBJECT (clist), + clist_signals[UNSELECT_ROW], + row, -1, event); + clist->undo_selection = g_list_prepend + (clist->undo_selection, GINT_TO_POINTER (row)); + } + } } + } - if (row_selected) - return; - - default: - break; - } - - clist_row = (g_list_nth (clist->row_list, row))->data; - - if (clist_row->state != GTK_STATE_NORMAL || !clist_row->selectable) - return; - - clist_row->state = GTK_STATE_SELECTED; - if (!clist->selection) + if (clist->anchor < clist->drag_pos) { - clist->selection = g_list_append (clist->selection, - GINT_TO_POINTER (row)); - clist->selection_end = clist->selection; + for (list = g_list_nth (clist->row_list, i); i <= e; + i++, list = list->next) + if (GTK_CLIST_ROW (list)->selectable) + { + if (g_list_find (clist->selection, GINT_TO_POINTER(i))) + { + if (GTK_CLIST_ROW (list)->state == GTK_STATE_NORMAL) + { + GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED; + gtk_signal_emit (GTK_OBJECT (clist), + clist_signals[UNSELECT_ROW], + i, -1, event); + clist->undo_selection = + g_list_prepend (clist->undo_selection, + GINT_TO_POINTER (i)); + } + } + else if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED) + { + GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL; + clist->undo_unselection = + g_list_prepend (clist->undo_unselection, + GINT_TO_POINTER (i)); + } + } } else - clist->selection_end = - g_list_append (clist->selection_end, GINT_TO_POINTER (row))->next; + { + for (list = g_list_nth (clist->row_list, e); i <= e; + e--, list = list->prev) + if (GTK_CLIST_ROW (list)->selectable) + { + if (g_list_find (clist->selection, GINT_TO_POINTER(e))) + { + if (GTK_CLIST_ROW (list)->state == GTK_STATE_NORMAL) + { + GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED; + gtk_signal_emit (GTK_OBJECT (clist), + clist_signals[UNSELECT_ROW], + e, -1, event); + clist->undo_selection = + g_list_prepend (clist->undo_selection, + GINT_TO_POINTER (e)); + } + } + else if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED) + { + GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL; + clist->undo_unselection = + g_list_prepend (clist->undo_unselection, + GINT_TO_POINTER (e)); + } + } + } - if (!GTK_CLIST_FROZEN (clist) - && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); + clist->undo_unselection = g_list_reverse (clist->undo_unselection); + for (list = clist->undo_unselection; list; list = list->next) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + GPOINTER_TO_INT (list->data), -1, event); + + clist->anchor = -1; + clist->drag_pos = -1; + + gtk_clist_thaw (clist); } static void -real_unselect_row (GtkCList * clist, - gint row, - gint column, - GdkEvent * event) +update_extended_selection (GtkCList *clist, + gint row) { - GtkCListRow *clist_row; - - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + gint i; + GList *list; + GdkRectangle area; + gint s1 = -1; + gint s2 = -1; + gint e1 = -1; + gint e2 = -1; + gint y1 = clist->clist_window_height; + gint y2 = clist->clist_window_height; + gint h1 = 0; + gint h2 = 0; + gint top; - if (row < 0 || row > (clist->rows - 1)) + if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor == -1) return; - clist_row = (g_list_nth (clist->row_list, row))->data; + if (row < 0) + row = 0; + if (row >= clist->rows) + row = clist->rows - 1; - if (clist_row->state == GTK_STATE_SELECTED) + /* extending downwards */ + if (row > clist->drag_pos && clist->anchor <= clist->drag_pos) { - clist_row->state = GTK_STATE_NORMAL; - - if (clist->selection_end && - clist->selection_end->data == GINT_TO_POINTER (row)) - clist->selection_end = clist->selection_end->prev; - - clist->selection = g_list_remove (clist->selection, - GINT_TO_POINTER (row)); - - if (!GTK_CLIST_FROZEN (clist) - && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); + s2 = clist->drag_pos + 1; + e2 = row; + } + /* extending upwards */ + else if (row < clist->drag_pos && clist->anchor >= clist->drag_pos) + { + s2 = row; + e2 = clist->drag_pos - 1; + } + else if (row < clist->drag_pos && clist->anchor < clist->drag_pos) + { + e1 = clist->drag_pos; + /* row and drag_pos on different sides of anchor : + take back the selection between anchor and drag_pos, + select between anchor and row */ + if (row < clist->anchor) + { + s1 = clist->anchor + 1; + s2 = row; + e2 = clist->anchor - 1; + } + /* take back the selection between anchor and drag_pos */ + else + s1 = row + 1; + } + else if (row > clist->drag_pos && clist->anchor > clist->drag_pos) + { + s1 = clist->drag_pos; + /* row and drag_pos on different sides of anchor : + take back the selection between anchor and drag_pos, + select between anchor and row */ + if (row > clist->anchor) + { + e1 = clist->anchor - 1; + s2 = clist->anchor + 1; + e2 = row; + } + /* take back the selection between anchor and drag_pos */ + else + e1 = row - 1; } -} -static gint -get_selection_info (GtkCList * clist, - gint x, - gint y, - gint * row, - gint * column) -{ - gint trow, tcol; + clist->drag_pos = row; - g_return_val_if_fail (clist != NULL, 0); - g_return_val_if_fail (GTK_IS_CLIST (clist), 0); + area.x = 0; + area.width = clist->clist_window_width; - /* bounds checking, return false if the user clicked - * on a blank area */ - trow = ROW_FROM_YPIXEL (clist, y); - if (trow >= clist->rows) - return 0; + /* restore the elements between s1 and e1 */ + if (s1 >= 0) + { + for (i = s1, list = g_list_nth (clist->row_list, i); i <= e1; + i++, list = list->next) + if (GTK_CLIST_ROW (list)->selectable) + { + if (GTK_CLIST_CLASS_FW (clist)->selection_find (clist, i, list)) + GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED; + else + GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL; + } - if (row) - *row = trow; + top = ROW_TOP_YPIXEL (clist, clist->focus_row); - tcol = COLUMN_FROM_XPIXEL (clist, x); - if (tcol >= clist->columns) - return 0; + if (top + clist->row_height <= 0) + { + area.y = 0; + area.height = ROW_TOP_YPIXEL (clist, e1) + clist->row_height; + draw_rows (clist, &area); + gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + } + else if (top >= clist->clist_window_height) + { + area.y = ROW_TOP_YPIXEL (clist, s1) - 1; + area.height = clist->clist_window_height - area.y; + draw_rows (clist, &area); + gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + } + else if (top < 0) + gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + else if (top + clist->row_height > clist->clist_window_height) + gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); - if (column) - *column = tcol; + y1 = ROW_TOP_YPIXEL (clist, s1) - 1; + h1 = (e1 - s1 + 1) * (clist->row_height + CELL_SPACING); + } - return 1; -} - -gint -gtk_clist_get_selection_info (GtkCList *clist, - gint x, - gint y, - gint * row, - gint * column) -{ - g_return_val_if_fail (clist != NULL, 0); - g_return_val_if_fail (GTK_IS_CLIST (clist), 0); - return get_selection_info (clist, x, y, row, column); -} - -/* - * RESIZE COLUMNS - * draw_xor_line - * new_column_width - * resize_column - */ -static void -draw_xor_line (GtkCList * clist) -{ - GtkWidget *widget; - - g_return_if_fail (clist != NULL); - - widget = GTK_WIDGET (clist); - - gdk_draw_line (widget->window, clist->xor_gc, - clist->x_drag, - widget->style->klass->ythickness, - clist->x_drag, - clist->column_title_area.height + - clist->clist_window_height + 1); -} - -/* this function returns the new width of the column being resized given - * the column and x position of the cursor; the x cursor position is passed - * in as a pointer and automagicly corrected if it's beyond min/max limits */ -static gint -new_column_width (GtkCList *clist, - gint column, - gint *x) -{ - gint xthickness = GTK_WIDGET (clist)->style->klass->xthickness; - gint width; - gint cx; - gint dx; + /* extend the selection between s2 and e2 */ + if (s2 >= 0) + { + for (i = s2, list = g_list_nth (clist->row_list, i); i <= e2; + i++, list = list->next) + if (GTK_CLIST_ROW (list)->selectable && + GTK_CLIST_ROW (list)->state != clist->anchor_state) + GTK_CLIST_ROW (list)->state = clist->anchor_state; - /* first translate the x position from widget->window - * to clist->clist_window */ - cx = *x - xthickness; + top = ROW_TOP_YPIXEL (clist, clist->focus_row); - /* calculate new column width making sure it doesn't end up - * less than the minimum width */ - dx = (COLUMN_LEFT_XPIXEL (clist, column) + COLUMN_INSET + - (column < clist->columns - 1) * CELL_SPACING); - width = cx - dx; + if (top + clist->row_height <= 0) + { + area.y = 0; + area.height = ROW_TOP_YPIXEL (clist, e2) + clist->row_height; + draw_rows (clist, &area); + gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + } + else if (top >= clist->clist_window_height) + { + area.y = ROW_TOP_YPIXEL (clist, s2) - 1; + area.height = clist->clist_window_height - area.y; + draw_rows (clist, &area); + gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + } + else if (top < 0) + gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + else if (top + clist->row_height > clist->clist_window_height) + gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); - if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width)) - { - width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width); - cx = dx + width; - *x = cx + xthickness; + y2 = ROW_TOP_YPIXEL (clist, s2) - 1; + h2 = (e2 - s2 + 1) * (clist->row_height + CELL_SPACING); } - else if (clist->column[column].max_width >= COLUMN_MIN_WIDTH && - width > clist->column[column].max_width) - { - width = clist->column[column].max_width; - cx = dx + clist->column[column].max_width; - *x = cx + xthickness; - } - - if (cx < 0 || cx > clist->clist_window_width) - *x = -1; - return width; + area.y = MAX (0, MIN (y1, y2)); + if (area.y > clist->clist_window_height) + area.y = 0; + area.height = MIN (clist->clist_window_height, h1 + h2); + if (s1 >= 0 && s2 >= 0) + area.height += (clist->row_height + CELL_SPACING); + draw_rows (clist, &area); } -/* this will do more later */ static void -resize_column (GtkCList * clist, - gint column, - gint width) +start_selection (GtkCList *clist) { - gtk_clist_set_column_width (clist, column, width); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) + return; + + set_anchor (clist, GTK_CLIST_ADD_MODE(clist), clist->focus_row, + clist->focus_row); } -/* BUTTONS */ static void -column_button_create (GtkCList * clist, - gint column) +end_selection (GtkCList *clist) { - GtkWidget *button; + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - button = clist->column[column].button = gtk_button_new (); - if (GTK_WIDGET_REALIZED (clist) && clist->title_window) - gtk_widget_set_parent_window (clist->column[column].button, clist->title_window); - gtk_widget_set_parent (button, GTK_WIDGET (clist)); - - gtk_signal_connect (GTK_OBJECT (button), "clicked", - (GtkSignalFunc) column_button_clicked, - (gpointer) clist); + if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS(clist)) + return; - gtk_widget_show (button); + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); } static void -column_button_clicked (GtkWidget * widget, - gpointer data) +extend_selection (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position, + gboolean auto_start_selection) { - gint i; - GtkCList *clist; + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_CLIST (data)); + if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) || + clist->selection_mode != GTK_SELECTION_EXTENDED) + return; - clist = GTK_CLIST (data); + if (auto_start_selection) + set_anchor (clist, GTK_CLIST_ADD_MODE(clist), clist->focus_row, + clist->focus_row); + else if (clist->anchor == -1) + return; - /* find the column who's button was pressed */ - for (i = 0; i < clist->columns; i++) - if (clist->column[i].button == widget) - break; + move_focus_row (clist, scroll_type, position); - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i); + if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height > + clist->clist_window_height) + gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0) + gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + + update_extended_selection (clist, clist->focus_row); } -/* - * SCROLLBARS - * - * functions: - * create_scrollbars - * adjust_scrollbars - * vadjustment_changed - * hadjustment_changed - * vadjustment_value_changed - * hadjustment_value_changed - */ static void -create_scrollbars (GtkCList * clist) +sync_selection (GtkCList *clist, + gint row, + gint mode) { - GtkAdjustment *adjustment; - - clist->vscrollbar = gtk_vscrollbar_new (NULL); - - adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)); - - gtk_signal_connect (GTK_OBJECT (adjustment), "changed", - (GtkSignalFunc) vadjustment_changed, - (gpointer) clist); - - gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", - (GtkSignalFunc) vadjustment_value_changed, - (gpointer) clist); + GList *list; + gint d; - gtk_widget_set_parent (clist->vscrollbar, GTK_WIDGET (clist)); - gtk_widget_show (clist->vscrollbar); + if (mode == SYNC_INSERT) + d = 1; + else + d = -1; + + if (clist->focus_row >= row) + { + if (d > 0 || clist->focus_row > row) + clist->focus_row += d; + if (clist->focus_row == -1 && clist->rows >= 1) + clist->focus_row = 0; + else if (clist->focus_row >= clist->rows) + clist->focus_row = clist->rows - 1; + } - clist->hscrollbar = gtk_hscrollbar_new (NULL); + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); - adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)); + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; - gtk_signal_connect (GTK_OBJECT (adjustment), "changed", - (GtkSignalFunc) hadjustment_changed, - (gpointer) clist); + clist->anchor = -1; + clist->drag_pos = -1; + clist->undo_anchor = clist->focus_row; - gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", - (GtkSignalFunc) hadjustment_value_changed, - (gpointer) clist); + list = clist->selection; - gtk_widget_set_parent (clist->hscrollbar, GTK_WIDGET (clist)); - gtk_widget_show (clist->hscrollbar); + while (list) + { + if (GPOINTER_TO_INT (list->data) >= row) + list->data = ((gchar*) list->data) + d; + list = list->next; + } } +/* GTKOBJECT + * gtk_clist_destroy + * gtk_clist_finalize + */ static void -adjust_scrollbars (GtkCList * clist) +gtk_clist_destroy (GtkObject *object) { - 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); + gint i; + GtkCList *clist; - if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist)) - { - GTK_RANGE (clist->vscrollbar)->adjustment->value = MAX (0, LIST_HEIGHT (clist) - - clist->clist_window_height); - gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), - "value_changed"); - } + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_CLIST (object)); - 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); + clist = GTK_CLIST (object); - if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist)) - { - GTK_RANGE (clist->hscrollbar)->adjustment->value = MAX (0, LIST_WIDTH (clist) - - clist->clist_window_width); - gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), - "value_changed"); - } + /* freeze the list */ + clist->freeze_count++; - 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_size_allocate (GTK_WIDGET (clist), - >K_WIDGET (clist)->allocation); - } - } - else - { - if (!GTK_WIDGET_VISIBLE (clist->vscrollbar)) - { - gtk_widget_show (clist->vscrollbar); - gtk_widget_size_allocate (GTK_WIDGET (clist), - >K_WIDGET (clist)->allocation); - } - } + /* get rid of all the rows */ + gtk_clist_clear (clist); + + /* Since we don't have a _remove method, unparent the children + * instead of destroying them so the focus will be unset properly. + * (For other containers, the _remove method takes care of the + * unparent) The destroy will happen when the refcount drops + * to zero. + */ - if (LIST_WIDTH (clist) <= clist->clist_window_width && - clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) + /* unref adjustments */ + if (clist->hadjustment) { - if (GTK_WIDGET_VISIBLE (clist->hscrollbar)) - { - gtk_widget_hide (clist->hscrollbar); - gtk_widget_size_allocate (GTK_WIDGET (clist), - >K_WIDGET (clist)->allocation); - } + gtk_signal_disconnect_by_data (GTK_OBJECT (clist->hadjustment), clist); + gtk_object_unref (GTK_OBJECT (clist->hadjustment)); + clist->hadjustment = NULL; } - else + if (clist->vadjustment) { - if (!GTK_WIDGET_VISIBLE (clist->hscrollbar)) - { - gtk_widget_show (clist->hscrollbar); - gtk_widget_size_allocate (GTK_WIDGET (clist), - >K_WIDGET (clist)->allocation); - } + gtk_signal_disconnect_by_data (GTK_OBJECT (clist->vadjustment), clist); + gtk_object_unref (GTK_OBJECT (clist->vadjustment)); + clist->vadjustment = NULL; } - 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 -vadjustment_changed (GtkAdjustment * adjustment, - gpointer data) -{ - GtkCList *clist; + remove_grab (clist); - g_return_if_fail (adjustment != NULL); - g_return_if_fail (data != NULL); + /* destroy the column buttons */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button) + { + gtk_widget_unparent (clist->column[i].button); + clist->column[i].button = NULL; + } - clist = GTK_CLIST (data); + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (*GTK_OBJECT_CLASS (parent_class)->destroy) (object); } static void -hadjustment_changed (GtkAdjustment * adjustment, - gpointer data) +gtk_clist_finalize (GtkObject *object) { GtkCList *clist; - g_return_if_fail (adjustment != NULL); - g_return_if_fail (data != NULL); + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_CLIST (object)); - clist = GTK_CLIST (data); -} + clist = GTK_CLIST (object); -static void -check_exposures (GtkCList *clist) -{ - GdkEvent *event; + columns_delete (clist); - if (!GTK_WIDGET_REALIZED (clist)) - return; + g_mem_chunk_destroy (clist->cell_mem_chunk); + g_mem_chunk_destroy (clist->row_mem_chunk); - /* Make sure graphics expose events are processed before scrolling - * again */ - while ((event = gdk_event_get_graphics_expose (clist->clist_window)) != NULL) - { - gtk_widget_event (GTK_WIDGET (clist), event); - if (event->expose.count == 0) - { - gdk_event_free (event); - break; - } - gdk_event_free (event); - } + if (GTK_OBJECT_CLASS (parent_class)->finalize) + (*GTK_OBJECT_CLASS (parent_class)->finalize) (object); } +/* GTKWIDGET + * gtk_clist_realize + * gtk_clist_unrealize + * gtk_clist_map + * gtk_clist_unmap + * gtk_clist_draw + * gtk_clist_expose + * gtk_clist_style_set + * gtk_clist_key_press + * gtk_clist_button_press + * gtk_clist_button_release + * gtk_clist_motion + * gtk_clist_size_request + * gtk_clist_size_allocate + */ static void -vadjustment_value_changed (GtkAdjustment * adjustment, - gpointer data) +gtk_clist_realize (GtkWidget *widget) { GtkCList *clist; - GdkRectangle area; - gint diff, value; + GdkWindowAttr attributes; + GdkGCValues values; + GtkCListRow *clist_row; + GList *list; + gint attributes_mask; + gint border_width; + gint i; + gint j; - g_return_if_fail (adjustment != NULL); - g_return_if_fail (data != NULL); - g_return_if_fail (GTK_IS_CLIST (data)); + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); - clist = GTK_CLIST (data); + clist = GTK_CLIST (widget); - if (!GTK_WIDGET_DRAWABLE (clist)) - return; + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); - value = adjustment->value; + border_width = GTK_CONTAINER (widget)->border_width; + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x + border_width; + attributes.y = widget->allocation.y + border_width; + attributes.width = widget->allocation.width - border_width * 2; + attributes.height = widget->allocation.height - border_width * 2; + 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 | + GDK_KEY_RELEASE_MASK); + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar))) - { - if (value > -clist->voffset) - { - /* scroll down */ - diff = value + clist->voffset; + /* main window */ + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, clist); - /* we have to re-draw the whole screen here... */ - if (diff >= clist->clist_window_height) - { - clist->voffset = -value; - draw_rows (clist, NULL); - return; - } + widget->style = gtk_style_attach (widget->style, widget->window); - if ((diff != 0) && (diff != clist->clist_window_height)) - gdk_window_copy_area (clist->clist_window, - clist->fg_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; + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); - /* we have to re-draw the whole screen here... */ - if (diff >= clist->clist_window_height) - { - clist->voffset = -value; - draw_rows (clist, NULL); - return; - } + /* column-title window */ - if ((diff != 0) && (diff != clist->clist_window_height)) - gdk_window_copy_area (clist->clist_window, - clist->fg_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; + attributes.x = clist->column_title_area.x; + attributes.y = clist->column_title_area.y; + attributes.width = clist->column_title_area.width; + attributes.height = clist->column_title_area.height; + + 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_NORMAL); + gdk_window_show (clist->title_window); - clist->voffset = -value; - if ((diff != 0) && (diff != clist->clist_window_height)) - check_exposures (clist); + /* set things up so column buttons are drawn in title window */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button) + gtk_widget_set_parent_window (clist->column[i].button, + clist->title_window); + + /* clist-window */ + attributes.x = (clist->internal_allocation.x + + widget->style->klass->xthickness); + attributes.y = (clist->internal_allocation.y + + widget->style->klass->ythickness + + clist->column_title_area.height); + attributes.width = clist->clist_window_width; + attributes.height = clist->clist_window_height; + + 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->base[GTK_STATE_NORMAL]); + gdk_window_show (clist->clist_window); + gdk_window_get_size (clist->clist_window, &clist->clist_window_width, + &clist->clist_window_height); + + /* create resize windows */ + attributes.wclass = GDK_INPUT_ONLY; + attributes.event_mask = (GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK | + GDK_KEY_PRESS_MASK); + attributes_mask = GDK_WA_CURSOR; + attributes.cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW); + clist->cursor_drag = attributes.cursor; + + attributes.x = LIST_WIDTH (clist) + 1; + attributes.y = 0; + attributes.width = 0; + attributes.height = 0; + + for (i = 0; i < clist->columns; i++) + { + clist->column[i].window = gdk_window_new (clist->title_window, + &attributes, attributes_mask); + gdk_window_set_user_data (clist->column[i].window, clist); } - draw_rows (clist, &area); + /* This is slightly less efficient than creating them with the + * right size to begin with, but easier + */ + size_allocate_title_buttons (clist); + + /* GCs */ + clist->fg_gc = gdk_gc_new (widget->window); + clist->bg_gc = gdk_gc_new (widget->window); + + /* We'll use this gc to do scrolling as well */ + gdk_gc_set_exposures (clist->fg_gc, TRUE); + + values.foreground = (widget->style->white.pixel==0 ? + widget->style->black: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); + + /* attach optional row/cell styles, allocate foreground/background colors */ + list = clist->row_list; + for (i = 0; i < clist->rows; i++) + { + clist_row = list->data; + list = list->next; + + if (clist_row->style) + clist_row->style = gtk_style_attach (clist_row->style, + clist->clist_window); + + if (clist_row->fg_set || clist_row->bg_set) + { + GdkColormap *colormap; + + colormap = gtk_widget_get_colormap (widget); + if (clist_row->fg_set) + gdk_color_alloc (colormap, &clist_row->foreground); + if (clist_row->bg_set) + gdk_color_alloc (colormap, &clist_row->background); + } + + for (j = 0; j < clist->columns; j++) + if (clist_row->cell[j].style) + clist_row->cell[j].style = + gtk_style_attach (clist_row->cell[j].style, clist->clist_window); + } } static void -hadjustment_value_changed (GtkAdjustment * adjustment, - gpointer data) +gtk_clist_unrealize (GtkWidget *widget) { - GtkCList *clist; - GdkRectangle area; gint i; - gint y = 0; - gint diff = 0; - gint value; + GtkCList *clist; - g_return_if_fail (adjustment != NULL); - g_return_if_fail (data != NULL); - g_return_if_fail (GTK_IS_CLIST (data)); + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); - clist = GTK_CLIST (data); + clist = GTK_CLIST (widget); - if (!GTK_WIDGET_DRAWABLE (clist) || - adjustment != gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar))) - return; + /* freeze the list */ + clist->freeze_count++; - value = adjustment->value; - - /* move the column buttons and resize windows */ - for (i = 0; i < clist->columns; i++) + if (GTK_WIDGET_MAPPED (widget)) + gtk_clist_unmap (widget); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + + /* detach optional row/cell styles */ + if (GTK_WIDGET_REALIZED (widget)) { - if (clist->column[i].button) + GtkCListRow *clist_row; + GList *list; + gint j; + + list = clist->row_list; + for (i = 0; i < clist->rows; 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 (clist->column[i].window) - gdk_window_move (clist->column[i].window, - clist->column[i].button->allocation.x + - clist->column[i].button->allocation.width - - (DRAG_WIDTH / 2), 0); - } + clist_row = list->data; + list = list->next; + + if (clist_row->style) + gtk_style_detach (clist_row->style); + for (j = 0; j < clist->columns; j++) + if (clist_row->cell[j].style) + gtk_style_detach (clist_row->cell[j].style); } } - if (value > -clist->hoffset) + gdk_cursor_destroy (clist->cursor_drag); + gdk_gc_destroy (clist->xor_gc); + gdk_gc_destroy (clist->fg_gc); + gdk_gc_destroy (clist->bg_gc); + + for (i = 0; i < clist->columns; i++) { - /* scroll right */ - diff = value + clist->hoffset; - - clist->hoffset = -value; - - /* we have to re-draw the whole screen here... */ - if (diff >= clist->clist_window_width) + if (clist->column[i].button) + gtk_widget_unrealize (clist->column[i].button); + if (clist->column[i].window) { - draw_rows (clist, NULL); - return; + gdk_window_set_user_data (clist->column[i].window, NULL); + gdk_window_destroy (clist->column[i].window); + clist->column[i].window = NULL; } + } - if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) && - GTK_CLIST_ADD_MODE (clist)) - { - y = ROW_TOP_YPIXEL (clist, clist->focus_row); - - gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y, - clist->clist_window_width - 1, - clist->row_height - 1); - } - gdk_window_copy_area (clist->clist_window, - clist->fg_gc, - 0, 0, - clist->clist_window, - diff, - 0, - clist->clist_window_width - diff, - clist->clist_window_height); + gdk_window_set_user_data (clist->clist_window, NULL); + gdk_window_destroy (clist->clist_window); + clist->clist_window = NULL; - area.x = clist->clist_window_width - diff; - } - else - { - /* scroll left */ - if (!(diff = -clist->hoffset - value)) - return; + gdk_window_set_user_data (clist->title_window, NULL); + gdk_window_destroy (clist->title_window); + clist->title_window = NULL; - clist->hoffset = -value; - - /* we have to re-draw the whole screen here... */ - if (diff >= clist->clist_window_width) - { - draw_rows (clist, NULL); - return; - } - - if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) && - GTK_CLIST_ADD_MODE (clist)) - { - y = ROW_TOP_YPIXEL (clist, clist->focus_row); - - gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y, - clist->clist_window_width - 1, - clist->row_height - 1); - } + clist->cursor_drag = NULL; + clist->xor_gc = NULL; + clist->fg_gc = NULL; + clist->bg_gc = NULL; - gdk_window_copy_area (clist->clist_window, - clist->fg_gc, - diff, 0, - clist->clist_window, - 0, - 0, - clist->clist_window_width - diff, - clist->clist_window_height); - - area.x = 0; - } + if (GTK_WIDGET_CLASS (parent_class)->unrealize) + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); +} - area.y = 0; - area.width = diff; - area.height = clist->clist_window_height; +static void +gtk_clist_map (GtkWidget *widget) +{ + gint i; + GtkCList *clist; - check_exposures (clist); + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); + + clist = GTK_CLIST (widget); - if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist)) + if (!GTK_WIDGET_MAPPED (widget)) { - if (GTK_CLIST_ADD_MODE (clist)) - { - gint focus_row; - - focus_row = clist->focus_row; - clist->focus_row = -1; - draw_rows (clist, &area); - clist->focus_row = focus_row; - - gdk_draw_rectangle (clist->clist_window, clist->xor_gc, - FALSE, 0, y, clist->clist_window_width - 1, - clist->row_height - 1); - return; - } - else + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + + /* map column buttons */ + for (i = 0; i < clist->columns; i++) { - gint x0; - gint x1; - - if (area.x == 0) - { - x0 = clist->clist_window_width - 1; - x1 = diff; - } - else - { - x0 = 0; - x1 = area.x - 1; - } - - y = ROW_TOP_YPIXEL (clist, clist->focus_row); - gdk_draw_line (clist->clist_window, clist->xor_gc, - x0, y + 1, x0, y + clist->row_height - 2); - gdk_draw_line (clist->clist_window, clist->xor_gc, - x1, y + 1, x1, y + clist->row_height - 2); - + if (clist->column[i].button && + GTK_WIDGET_VISIBLE (clist->column[i].button) && + !GTK_WIDGET_MAPPED (clist->column[i].button)) + gtk_widget_map (clist->column[i].button); } + + for (i = 0; i < clist->columns; i++) + if (clist->column[i].window && clist->column[i].button) + { + gdk_window_raise (clist->column[i].window); + gdk_window_show (clist->column[i].window); + } + + gdk_window_show (clist->title_window); + gdk_window_show (clist->clist_window); + gdk_window_show (widget->window); + + /* unfreeze the list */ + clist->freeze_count = 0; } - draw_rows (clist, &area); } -/* - * Memory Allocation/Distruction Routines for GtkCList stuctures - * - * functions: - * columns_new - * column_title_new - * columns_delete - * row_new - * row_delete - * set_cell_contents - */ -static GtkCListColumn * -columns_new (GtkCList * clist) +static void +gtk_clist_unmap (GtkWidget *widget) { gint i; - GtkCListColumn *column; + GtkCList *clist; - column = g_new (GtkCListColumn, clist->columns); + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); - for (i = 0; i < clist->columns; i++) + clist = GTK_CLIST (widget); + + if (GTK_WIDGET_MAPPED (widget)) { - 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].window = NULL; - column[i].width = 0; - column[i].min_width = -1; - column[i].max_width = -1; - column[i].visible = TRUE; - column[i].width_set = FALSE; - column[i].resizeable = TRUE; - column[i].justification = GTK_JUSTIFY_LEFT; - } + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); - return column; -} + if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) + { + remove_grab (clist); -static void -column_title_new (GtkCList *clist, - gint column, - const gchar *title) -{ - if (clist->column[column].title) - g_free (clist->column[column].title); + GTK_CLIST_CLASS_FW (widget)->resync_selection (clist, NULL); - clist->column[column].title = g_strdup (title); -} + clist->click_cell.row = -1; + clist->click_cell.column = -1; + clist->drag_button = 0; -static void -columns_delete (GtkCList * clist) -{ - gint i; + if (GTK_CLIST_IN_DRAG(clist)) + { + gpointer drag_data; + + GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG); + drag_data = gtk_object_get_data (GTK_OBJECT (clist), + "gtk-site-data"); + if (drag_data) + gtk_signal_handler_unblock_by_data (GTK_OBJECT (clist), + drag_data); + } + } - for (i = 0; i < clist->columns; i++) - if (clist->column[i].title) - g_free (clist->column[i].title); - - g_free (clist->column); + for (i = 0; i < clist->columns; i++) + if (clist->column[i].window) + gdk_window_hide (clist->column[i].window); + + gdk_window_hide (clist->clist_window); + gdk_window_hide (clist->title_window); + gdk_window_hide (widget->window); + + /* unmap column buttons */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button && + GTK_WIDGET_MAPPED (clist->column[i].button)) + gtk_widget_unmap (clist->column[i].button); + + /* freeze the list */ + clist->freeze_count++; + } } -static GtkCListRow * -row_new (GtkCList * clist) +static void +gtk_clist_draw (GtkWidget *widget, + GdkRectangle *area) { + GtkCList *clist; + gint border_width; + GdkRectangle child_area; 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); + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); + g_return_if_fail (area != NULL); - for (i = 0; i < clist->columns; i++) + if (GTK_WIDGET_DRAWABLE (widget)) { - clist_row->cell[i].type = GTK_CELL_EMPTY; - clist_row->cell[i].vertical = 0; - clist_row->cell[i].horizontal = 0; - } + clist = GTK_CLIST (widget); + border_width = GTK_CONTAINER (widget)->border_width; - clist_row->fg_set = FALSE; - clist_row->bg_set = FALSE; - clist_row->selectable = TRUE; - clist_row->state = GTK_STATE_NORMAL; - clist_row->data = NULL; - clist_row->destroy = NULL; + gdk_window_clear_area (widget->window, + area->x - border_width, + area->y - border_width, + area->width, area->height); - return clist_row; + /* draw list shadow/border */ + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, clist->shadow_type, + 0, 0, + clist->clist_window_width + + (2 * widget->style->klass->xthickness), + clist->clist_window_height + + (2 * widget->style->klass->ythickness) + + clist->column_title_area.height); + + gdk_window_clear_area (clist->clist_window, 0, 0, 0, 0); + draw_rows (clist, NULL); + + for (i = 0; i < clist->columns; i++) + { + if (!clist->column[i].visible) + continue; + if (clist->column[i].button && + gtk_widget_intersect(clist->column[i].button, area, &child_area)) + gtk_widget_draw (clist->column[i].button, &child_area); + } + } } -static void -row_delete (GtkCList * clist, - GtkCListRow * clist_row) +static gint +gtk_clist_expose (GtkWidget *widget, + GdkEventExpose *event) { - gint i; + GtkCList *clist; - for (i = 0; i < clist->columns; i++) - GTK_CLIST_CLASS_FW (clist)->set_cell_contents - (clist, clist_row, i, GTK_CELL_EMPTY, NULL, 0, NULL, NULL); + 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 (clist_row->destroy) - clist_row->destroy (clist_row->data); + if (GTK_WIDGET_DRAWABLE (widget)) + { + clist = GTK_CLIST (widget); - g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell); - g_mem_chunk_free (clist->row_mem_chunk, clist_row); + /* draw border */ + if (event->window == widget->window) + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, clist->shadow_type, + 0, 0, + clist->clist_window_width + + (2 * widget->style->klass->xthickness), + clist->clist_window_height + + (2 * widget->style->klass->ythickness) + + clist->column_title_area.height); + + /* exposure events on the list */ + if (event->window == clist->clist_window) + draw_rows (clist, &event->area); + } + + return FALSE; } static void -set_cell_contents (GtkCList *clist, - GtkCListRow *clist_row, - gint column, - GtkCellType type, - const gchar *text, - guint8 spacing, - GdkPixmap *pixmap, - GdkBitmap *mask) +gtk_clist_style_set (GtkWidget *widget, + GtkStyle *previous_style) { - g_return_if_fail (clist_row != NULL); + GtkCList *clist; - switch (clist_row->cell[column].type) + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); + + if (GTK_WIDGET_CLASS (parent_class)->style_set) + (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style); + + clist = GTK_CLIST (widget); + + if (GTK_WIDGET_REALIZED (widget)) { - 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); - if (GTK_CELL_PIXMAP (clist_row->cell[column])->mask) - 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); - if (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask) - 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; - - switch (type) - { - case GTK_CELL_TEXT: - if (text) - { - clist_row->cell[column].type = GTK_CELL_TEXT; - GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text); - } - break; - - case GTK_CELL_PIXMAP: - if (pixmap) - { - clist_row->cell[column].type = GTK_CELL_PIXMAP; - GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap; - /* We set the mask even if it is NULL */ - GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask; - } - break; - - case GTK_CELL_PIXTEXT: - if (text && pixmap) - { - 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; - } - break; - - default: - break; + gtk_style_set_background (widget->style, widget->window, widget->state); + gtk_style_set_background (widget->style, clist->title_window, GTK_STATE_SELECTED); + gdk_window_set_background (clist->clist_window, &widget->style->base[GTK_STATE_NORMAL]); } -} - -/* Fill in data after widget has correct style */ - -static void -add_style_data (GtkCList * clist) -{ - GtkWidget *widget; - widget = GTK_WIDGET(clist); + /* Fill in data after widget has correct style */ /* text properties */ - if (!GTK_CLIST_ROW_HEIGHT_SET (clist)) + if (!GTK_CLIST_ROW_HEIGHT_SET(clist)) { - clist->row_height = widget->style->font->ascent + widget->style->font->descent + 1; + clist->row_height = (widget->style->font->ascent + + widget->style->font->descent + 1); clist->row_center_offset = widget->style->font->ascent + 1.5; } else - { - gint text_height; - text_height = clist->row_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; - } + clist->row_center_offset = 1.5 + (clist->row_height + + widget->style->font->ascent - + widget->style->font->descent - 1) / 2; /* Column widths */ -} - - -/* focus functions */ - -static void -gtk_clist_draw_focus (GtkWidget *widget) -{ - GtkCList *clist; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_CLIST (widget)); - - if (!GTK_WIDGET_DRAWABLE (widget)) - return; - - clist = GTK_CLIST (widget); - if (clist->focus_row >= 0) - gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, - 0, ROW_TOP_YPIXEL(clist, clist->focus_row), - clist->clist_window_width - 1, - clist->row_height - 1); -} - -static void -gtk_clist_set_focus_child (GtkContainer *container, - GtkWidget *child) -{ - g_return_if_fail (container != NULL); - g_return_if_fail (GTK_IS_CLIST (container)); - - if (child) + if (!GTK_CLIST_AUTO_RESIZE_BLOCKED(clist)) { - g_return_if_fail (GTK_IS_WIDGET (child)); - GTK_CLIST_SET_FLAG (GTK_CLIST (container), CLIST_CHILD_HAS_FOCUS); - } + gint width; + gint i; - parent_class->set_focus_child (container, child); + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + { + width = gtk_clist_optimal_column_width (clist, i); + if (width != clist->column[i].width) + gtk_clist_set_column_width (clist, i, width); + } + } } static gint -gtk_clist_focus_in (GtkWidget *widget, - GdkEventFocus *event) +gtk_clist_key_press (GtkWidget *widget, + GdkEventKey *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); - GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); - GTK_CLIST_UNSET_FLAG (widget, CLIST_CHILD_HAS_FOCUS); - - clist = GTK_CLIST (widget); + if (GTK_WIDGET_CLASS (parent_class)->key_press_event && + GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event)) + return TRUE; - if (clist->selection_mode == GTK_SELECTION_BROWSE && - clist->selection == NULL && clist->focus_row > -1) + switch (event->keyval) { - GList *list; - - list = g_list_nth (clist->row_list, clist->focus_row); - if (list && GTK_CLIST_ROW (list)->selectable) - select_row (clist, clist->focus_row, -1, (GdkEvent *) event); + case GDK_Tab: + case GDK_ISO_Left_Tab: + if (event->state & GDK_SHIFT_MASK) + return gtk_container_focus (GTK_CONTAINER (widget), + GTK_DIR_TAB_BACKWARD); else - gtk_widget_draw_focus (widget); + return gtk_container_focus (GTK_CONTAINER (widget), + GTK_DIR_TAB_FORWARD); + default: + break; } - else - gtk_widget_draw_focus (widget); - return FALSE; } static gint -gtk_clist_focus_out (GtkWidget *widget, - GdkEventFocus *event) +gtk_clist_button_press (GtkWidget *widget, + GdkEventButton *event) { + gint i; GtkCList *clist; + gint x; + gint y; + gint row; + gint column; + gint button_actions; 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); - GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); - gtk_widget_draw_focus (widget); - clist = GTK_CLIST (widget); - if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED) - GTK_CLIST_CLASS_FW (widget)->resync_selection (clist, (GdkEvent *) event); - - return FALSE; -} + button_actions = clist->button_actions[event->button - 1]; -static void -toggle_add_mode (GtkCList *clist) -{ - g_return_if_fail (clist != 0); - g_return_if_fail (GTK_IS_CLIST (clist)); - - if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) || - clist->selection_mode != GTK_SELECTION_EXTENDED) - return; + if (button_actions == GTK_BUTTON_IGNORED) + return FALSE; - gtk_clist_draw_focus (GTK_WIDGET (clist)); - if (!GTK_CLIST_ADD_MODE (clist)) - { - GTK_CLIST_SET_FLAG (clist, CLIST_ADD_MODE); - gdk_gc_set_line_attributes (clist->xor_gc, 1, - GDK_LINE_ON_OFF_DASH, 0, 0); - gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2); - } - else + /* selections on the list */ + if (event->window == clist->clist_window) { - GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE); - gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0); - clist->anchor_state = GTK_STATE_SELECTED; - } - gtk_clist_draw_focus (GTK_WIDGET (clist)); -} + x = event->x; + y = event->y; -static void -toggle_focus_row (GtkCList *clist) -{ - g_return_if_fail (clist != 0); - g_return_if_fail (GTK_IS_CLIST (clist)); + if (get_selection_info (clist, x, y, &row, &column)) + { + gint old_row = clist->focus_row; - if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) || - clist->focus_row < 0 || clist->focus_row >= clist->rows) - return; + if (clist->focus_row == -1) + old_row = row; - switch (clist->selection_mode) - { - case GTK_SELECTION_SINGLE: - case GTK_SELECTION_MULTIPLE: - toggle_row (clist, clist->focus_row, 0, NULL); - break; - case GTK_SELECTION_EXTENDED: - g_list_free (clist->undo_selection); - g_list_free (clist->undo_unselection); - clist->undo_selection = NULL; - clist->undo_unselection = NULL; + if (event->type == GDK_BUTTON_PRESS) + { + GdkEventMask mask = ((1 << (4 + event->button)) | + GDK_POINTER_MOTION_HINT_MASK | + GDK_BUTTON_RELEASE_MASK); - clist->anchor = clist->focus_row; - clist->drag_pos = clist->focus_row; - clist->undo_anchor = clist->focus_row; - - if (GTK_CLIST_ADD_MODE (clist)) - fake_toggle_row (clist, clist->focus_row); - else - GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist,clist->focus_row); + if (gdk_pointer_grab (clist->clist_window, FALSE, mask, + NULL, NULL, event->time)) + return FALSE; + gtk_grab_add (widget); - GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); - break; - default: - break; - } -} + clist->click_cell.row = row; + clist->click_cell.column = column; + clist->drag_button = event->button; + } + else + { + clist->click_cell.row = -1; + clist->click_cell.column = -1; -static void -move_focus_row (GtkCList *clist, - GtkScrollType scroll_type, - gfloat position) -{ - GtkWidget *widget; + clist->drag_button = 0; + remove_grab (clist); + } - g_return_if_fail (clist != 0); - g_return_if_fail (GTK_IS_CLIST (clist)); + if (button_actions & GTK_BUTTON_SELECTS) + { + if (GTK_CLIST_ADD_MODE(clist)) + { + GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE); + if (GTK_WIDGET_HAS_FOCUS(widget)) + { + gtk_clist_draw_focus (widget); + gdk_gc_set_line_attributes (clist->xor_gc, 1, + GDK_LINE_SOLID, 0, 0); + clist->focus_row = row; + gtk_clist_draw_focus (widget); + } + else + { + gdk_gc_set_line_attributes (clist->xor_gc, 1, + GDK_LINE_SOLID, 0, 0); + clist->focus_row = row; + } + } + else if (row != clist->focus_row) + { + if (GTK_WIDGET_HAS_FOCUS(widget)) + { + gtk_clist_draw_focus (widget); + clist->focus_row = row; + gtk_clist_draw_focus (widget); + } + else + clist->focus_row = row; + } + } - widget = GTK_WIDGET (clist); + if (!GTK_WIDGET_HAS_FOCUS(widget)) + gtk_widget_grab_focus (widget); - switch (scroll_type) - { - case GTK_SCROLL_STEP_BACKWARD: - if (clist->focus_row <= 0) - return; - gtk_clist_draw_focus (widget); - clist->focus_row--; - gtk_clist_draw_focus (widget); - break; - case GTK_SCROLL_STEP_FORWARD: - if (clist->focus_row >= clist->rows - 1) - return; - gtk_clist_draw_focus (widget); - clist->focus_row++; - gtk_clist_draw_focus (widget); - break; - case GTK_SCROLL_PAGE_BACKWARD: - if (clist->focus_row <= 0) - return; - gtk_clist_draw_focus (widget); - clist->focus_row = MAX (0, clist->focus_row - - (2 * clist->clist_window_height - - clist->row_height - CELL_SPACING) / - (2 * (clist->row_height + CELL_SPACING))); - gtk_clist_draw_focus (widget); - break; - case GTK_SCROLL_PAGE_FORWARD: - if (clist->focus_row >= clist->rows - 1) - return; - gtk_clist_draw_focus (widget); - clist->focus_row = MIN (clist->rows - 1, clist->focus_row + - (2 * clist->clist_window_height - - clist->row_height - CELL_SPACING) / - (2 * (clist->row_height + CELL_SPACING))); - gtk_clist_draw_focus (widget); - break; - case GTK_SCROLL_JUMP: - if (position >= 0 && position <= 1) - { - gtk_clist_draw_focus (widget); - clist->focus_row = position * (clist->rows - 1); - gtk_clist_draw_focus (widget); + if (button_actions & GTK_BUTTON_SELECTS) + { + switch (clist->selection_mode) + { + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_MULTIPLE: + if (event->type != GDK_BUTTON_PRESS) + { + gtk_signal_emit (GTK_OBJECT (clist), + clist_signals[SELECT_ROW], + row, column, event); + clist->anchor = -1; + } + else + clist->anchor = row; + break; + case GTK_SELECTION_BROWSE: + gtk_signal_emit (GTK_OBJECT (clist), + clist_signals[SELECT_ROW], + row, column, event); + break; + case GTK_SELECTION_EXTENDED: + if (event->type != GDK_BUTTON_PRESS) + { + if (clist->anchor != -1) + { + update_extended_selection (clist, clist->focus_row); + GTK_CLIST_CLASS_FW (clist)->resync_selection + (clist, (GdkEvent *) event); + } + gtk_signal_emit (GTK_OBJECT (clist), + clist_signals[SELECT_ROW], + row, column, event); + break; + } + + if (event->state & GDK_CONTROL_MASK) + { + if (event->state & GDK_SHIFT_MASK) + { + if (clist->anchor < 0) + { + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + clist->anchor = old_row; + clist->drag_pos = old_row; + clist->undo_anchor = old_row; + } + update_extended_selection (clist, clist->focus_row); + } + else + { + if (clist->anchor == -1) + set_anchor (clist, TRUE, row, old_row); + else + update_extended_selection (clist, + clist->focus_row); + } + break; + } + + if (event->state & GDK_SHIFT_MASK) + { + set_anchor (clist, FALSE, old_row, old_row); + update_extended_selection (clist, clist->focus_row); + break; + } + + if (clist->anchor == -1) + set_anchor (clist, FALSE, row, old_row); + else + update_extended_selection (clist, clist->focus_row); + break; + default: + break; + } + } } - break; - default: - break; + return FALSE; } -} -static void -scroll_horizontal (GtkCList *clist, - GtkScrollType scroll_type, - gfloat position) -{ - gint column = 0; + /* press on resize windows */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].resizeable && clist->column[i].window && + event->window == clist->column[i].window) + { + gpointer drag_data; - g_return_if_fail (clist != 0); - g_return_if_fail (GTK_IS_CLIST (clist)); + if (gdk_pointer_grab (clist->column[i].window, FALSE, + GDK_POINTER_MOTION_HINT_MASK | + GDK_BUTTON1_MOTION_MASK | + GDK_BUTTON_RELEASE_MASK, + NULL, NULL, event->time)) + return FALSE; - if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) - return; + gtk_grab_add (widget); + GTK_CLIST_SET_FLAG (clist, CLIST_IN_DRAG); - switch (scroll_type) - { - case GTK_SCROLL_STEP_BACKWARD: - column = COLUMN_FROM_XPIXEL (clist, 0); - if (COLUMN_LEFT_XPIXEL (clist, column) - CELL_SPACING - COLUMN_INSET >= 0 - && column > 0) - column--; - break; - case GTK_SCROLL_STEP_FORWARD: - column = COLUMN_FROM_XPIXEL (clist, clist->clist_window_width); - if (column < 0) - return; - if (COLUMN_LEFT_XPIXEL (clist, column) + clist->column[column].area.width - + CELL_SPACING + COLUMN_INSET - 1 <= clist->clist_window_width && - column < clist->columns - 1) - column++; - break; - case GTK_SCROLL_PAGE_BACKWARD: - case GTK_SCROLL_PAGE_FORWARD: - return; - case GTK_SCROLL_JUMP: - if (position >= 0 && position <= 1) - column = position * (clist->columns - 1); - else - return; - break; - default: - break; - } + /* block attached dnd signal handler */ + drag_data = gtk_object_get_data (GTK_OBJECT (clist), "gtk-site-data"); + if (drag_data) + gtk_signal_handler_block_by_data (GTK_OBJECT (clist), drag_data); - if (COLUMN_LEFT_XPIXEL (clist, column) < CELL_SPACING + COLUMN_INSET) - gtk_clist_moveto (clist, -1, column, 0, 0); - else if (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET - 1 - + clist->column[column].area.width > clist->clist_window_width) - { - if (column == clist->columns - 1) - gtk_clist_moveto (clist, -1, column, 0, 0); - else - gtk_clist_moveto (clist, -1, column, 0, 1); - } + if (!GTK_WIDGET_HAS_FOCUS(widget)) + gtk_widget_grab_focus (widget); + + clist->drag_pos = i; + clist->x_drag = (COLUMN_LEFT_XPIXEL(clist, i) + COLUMN_INSET + + clist->column[i].area.width + CELL_SPACING); + + if (GTK_CLIST_ADD_MODE(clist)) + gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0); + draw_xor_line (clist); + } + return FALSE; } -static void -scroll_vertical (GtkCList *clist, - GtkScrollType scroll_type, - gfloat position) +static gint +gtk_clist_button_release (GtkWidget *widget, + GdkEventButton *event) { - gint old_focus_row; + GtkCList *clist; + gint button_actions; - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (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 (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) - return; + clist = GTK_CLIST (widget); - switch (clist->selection_mode) + button_actions = clist->button_actions[event->button - 1]; + if (button_actions == GTK_BUTTON_IGNORED) + return FALSE; + + /* release on resize windows */ + if (GTK_CLIST_IN_DRAG(clist)) { - case GTK_SELECTION_EXTENDED: - if (clist->anchor >= 0) - return; + gpointer drag_data; + gint width; + gint x; + gint i; - case GTK_SELECTION_BROWSE: + i = clist->drag_pos; + clist->drag_pos = -1; - old_focus_row = clist->focus_row; - move_focus_row (clist, scroll_type, position); + /* unblock attached dnd signal handler */ + drag_data = gtk_object_get_data (GTK_OBJECT (clist), "gtk-site-data"); + if (drag_data) + gtk_signal_handler_unblock_by_data (GTK_OBJECT (clist), drag_data); - if (old_focus_row != clist->focus_row) + GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG); + gtk_widget_get_pointer (widget, &x, NULL); + gtk_grab_remove (widget); + gdk_pointer_ungrab (event->time); + + if (clist->x_drag >= 0) + draw_xor_line (clist); + + if (GTK_CLIST_ADD_MODE(clist)) { - if (clist->selection_mode == GTK_SELECTION_BROWSE) - unselect_row (clist,old_focus_row, -1, NULL); - else if (!GTK_CLIST_ADD_MODE (clist)) - { - gtk_clist_unselect_all (clist); - clist->undo_anchor = old_focus_row; - } + gdk_gc_set_line_attributes (clist->xor_gc, 1, + GDK_LINE_ON_OFF_DASH, 0, 0); + gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2); } - switch (gtk_clist_row_is_visible (clist, clist->focus_row)) - { - case GTK_VISIBILITY_NONE: - if (old_focus_row != clist->focus_row && - !(clist->selection_mode == GTK_SELECTION_EXTENDED && - GTK_CLIST_ADD_MODE (clist))) - select_row (clist, clist->focus_row, -1, NULL); - switch (scroll_type) - { - case GTK_SCROLL_STEP_BACKWARD: - case GTK_SCROLL_PAGE_BACKWARD: - gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); - break; - case GTK_SCROLL_STEP_FORWARD: - case GTK_SCROLL_PAGE_FORWARD: - gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); - break; - case GTK_SCROLL_JUMP: - gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0); - break; - default: - break; - } - break; + width = new_column_width (clist, i, &x); + gtk_clist_set_column_width (clist, i, width); + return FALSE; + } - case GTK_VISIBILITY_PARTIAL: - switch (scroll_type) + if (clist->drag_button == event->button) + { + gint row; + gint column; + + clist->drag_button = 0; + clist->click_cell.row = -1; + clist->click_cell.column = -1; + + remove_grab (clist); + + if (button_actions & GTK_BUTTON_SELECTS) + { + switch (clist->selection_mode) { - case GTK_SCROLL_STEP_BACKWARD: - case GTK_SCROLL_PAGE_BACKWARD: - gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); - break; - case GTK_SCROLL_STEP_FORWARD: - case GTK_SCROLL_PAGE_FORWARD: - gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + case GTK_SELECTION_EXTENDED: + if (!(event->state & GDK_SHIFT_MASK) || + !GTK_WIDGET_CAN_FOCUS (widget) || + event->x < 0 || event->x >= clist->clist_window_width || + event->y < 0 || event->y >= clist->clist_window_height) + GTK_CLIST_CLASS_FW (clist)->resync_selection + (clist, (GdkEvent *) event); break; - case GTK_SCROLL_JUMP: - gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0); + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_MULTIPLE: + if (get_selection_info (clist, event->x, event->y, + &row, &column)) + { + if (row >= 0 && row < clist->rows && clist->anchor == row) + toggle_row (clist, row, column, (GdkEvent *) event); + } + clist->anchor = -1; break; default: break; } - - default: - if (old_focus_row != clist->focus_row && - !(clist->selection_mode == GTK_SELECTION_EXTENDED && - GTK_CLIST_ADD_MODE (clist))) - select_row (clist, clist->focus_row, -1, NULL); - break; } - break; - - default: - move_focus_row (clist, scroll_type, position); - - if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height > - clist->clist_window_height) - gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); - else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0) - gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); - break; } + return FALSE; } -static void -set_anchor (GtkCList *clist, - gboolean add_mode, - gint anchor, - gint undo_anchor) +static gint +gtk_clist_motion (GtkWidget *widget, + GdkEventMotion *event) { - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor >= 0) - return; - - g_list_free (clist->undo_selection); - g_list_free (clist->undo_unselection); - clist->undo_selection = NULL; - clist->undo_unselection = NULL; + GtkCList *clist; + gint x; + gint y; + gint row; + gint new_width; + gint button_actions = 0; - if (add_mode) - fake_toggle_row (clist, anchor); - else + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE); + + clist = GTK_CLIST (widget); + if (!(gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))) + return FALSE; + + if (clist->drag_button > 0) + button_actions = clist->button_actions[clist->drag_button - 1]; + + if (GTK_CLIST_IN_DRAG(clist)) { - GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist, anchor); - clist->anchor_state = GTK_STATE_SELECTED; + if (event->is_hint || event->window != widget->window) + gtk_widget_get_pointer (widget, &x, NULL); + else + x = event->x; + + new_width = new_column_width (clist, clist->drag_pos, &x); + if (x != clist->x_drag) + { + /* x_drag < 0 indicates that the xor line is already invisible */ + if (clist->x_drag >= 0) + draw_xor_line (clist); + + clist->x_drag = x; + + if (clist->x_drag >= 0) + draw_xor_line (clist); + } + + if (new_width <= MAX (COLUMN_MIN_WIDTH + 1, + clist->column[clist->drag_pos].min_width + 1)) + { + if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) < 0 && x < 0) + gtk_clist_moveto (clist, -1, clist->drag_pos, 0, 0); + return FALSE; + } + if (clist->column[clist->drag_pos].max_width >= COLUMN_MIN_WIDTH && + new_width >= clist->column[clist->drag_pos].max_width) + { + if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) + new_width > + clist->clist_window_width && x < 0) + move_horizontal (clist, + COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) + + new_width - clist->clist_window_width + + COLUMN_INSET + CELL_SPACING); + return FALSE; + } } - clist->anchor = anchor; - clist->drag_pos = anchor; - clist->undo_anchor = undo_anchor; -} + if (event->is_hint || event->window != clist->clist_window) + gdk_window_get_pointer (clist->clist_window, &x, &y, NULL); -static void -resync_selection (GtkCList *clist, - GdkEvent *event) -{ - gint i; - gint e; - gint row; - gboolean thaw = FALSE; - GList *list; - GtkCListRow *clist_row; + if (GTK_CLIST_REORDERABLE(clist) && button_actions & GTK_BUTTON_DRAGS) + { + /* delayed drag start */ + if (event->window == clist->clist_window && + clist->click_cell.row >= 0 && clist->click_cell.column >= 0 && + (y < 0 || y >= clist->clist_window_height || + x < 0 || x >= clist->clist_window_width || + y < ROW_TOP_YPIXEL (clist, clist->click_cell.row) || + y >= (ROW_TOP_YPIXEL (clist, clist->click_cell.row) + + clist->row_height) || + x < COLUMN_LEFT_XPIXEL (clist, clist->click_cell.column) || + x >= (COLUMN_LEFT_XPIXEL(clist, clist->click_cell.column) + + clist->column[clist->click_cell.column].area.width))) + { + GtkTargetList *target_list; - if (clist->anchor < 0) - return; + target_list = gtk_target_list_new (&clist_target_table, 1); + gtk_drag_begin (widget, target_list, GDK_ACTION_MOVE, + clist->drag_button, (GdkEvent *)event); - if (!GTK_CLIST_FROZEN (clist)) - { - GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN); - thaw = TRUE; + } + return TRUE; } - i = MIN (clist->anchor, clist->drag_pos); - e = MAX (clist->anchor, clist->drag_pos); - - if (clist->undo_selection) + /* horizontal autoscrolling */ + if (clist->hadjustment && LIST_WIDTH (clist) > clist->clist_window_width && + (x < 0 || x >= clist->clist_window_width)) { - list = clist->selection; - clist->selection = clist->undo_selection; - clist->selection_end = g_list_last (clist->selection); - clist->undo_selection = list; - list = clist->selection; - while (list) + if (clist->htimer) + return FALSE; + + clist->htimer = gtk_timeout_add + (SCROLL_TIME, (GtkFunction) horizontal_timeout, clist); + + if (!((x < 0 && clist->hadjustment->value == 0) || + (x >= clist->clist_window_width && + clist->hadjustment->value == + LIST_WIDTH (clist) - clist->clist_window_width))) { - row = GPOINTER_TO_INT (list->data); - list = list->next; - if (row < i || row > e) - { - clist_row = g_list_nth (clist->row_list, row)->data; - if (clist_row->selectable) - { - clist_row->state = GTK_STATE_SELECTED; - unselect_row (clist, row, -1, event); - clist->undo_selection = g_list_prepend - (clist->undo_selection, GINT_TO_POINTER (row)); - } - } + if (x < 0) + move_horizontal (clist, -1 + (x/2)); + else + move_horizontal (clist, 1 + (x - clist->clist_window_width) / 2); } - } + } - for (list = g_list_nth (clist->row_list, i); i <= e; i++, list = list->next) - if (GTK_CLIST_ROW (list)->selectable) - { - if (g_list_find (clist->selection, GINT_TO_POINTER(i))) - { - if (GTK_CLIST_ROW (list)->state == GTK_STATE_NORMAL) - { - GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED; - unselect_row (clist, i, -1, event); - clist->undo_selection = g_list_prepend (clist->undo_selection, - GINT_TO_POINTER (i)); - } - } - else if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED) - { - GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL; - clist->undo_unselection = g_list_prepend (clist->undo_unselection, - GINT_TO_POINTER (i)); - } - } + if (GTK_CLIST_IN_DRAG(clist)) + return FALSE; - for (list = clist->undo_unselection; list; list = list->next) - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], - GPOINTER_TO_INT (list->data), -1, event); + /* vertical autoscrolling */ + row = ROW_FROM_YPIXEL (clist, y); - clist->anchor = -1; - clist->drag_pos = -1; + /* don't scroll on last pixel row if it's a cell spacing */ + if (y == clist->clist_window_height - 1 && + y == ROW_TOP_YPIXEL (clist, row-1) + clist->row_height) + return FALSE; - if (thaw) - GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN); -} + if (LIST_HEIGHT (clist) > clist->clist_window_height && + (y < 0 || y >= clist->clist_window_height)) + { + if (clist->vtimer) + return FALSE; -static void -update_extended_selection (GtkCList *clist, - gint row) -{ - gint i; - GList *list; - GdkRectangle area; - gint s1 = -1; - gint s2 = -1; - gint e1 = -1; - gint e2 = -1; - gint y1 = clist->clist_window_height; - gint y2 = clist->clist_window_height; - gint h1 = 0; - gint h2 = 0; - gint top; + clist->vtimer = gtk_timeout_add (SCROLL_TIME, + (GtkFunction) vertical_timeout, clist); - if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor == -1) - return; + if (clist->drag_button && + ((y < 0 && clist->focus_row == 0) || + (y >= clist->clist_window_height && + clist->focus_row == clist->rows - 1))) + return FALSE; + } - if (row < 0) - row = 0; - if (row >= clist->rows) - row = clist->rows - 1; + row = CLAMP (row, 0, clist->rows - 1); - /* extending downwards */ - if (row > clist->drag_pos && clist->anchor <= clist->drag_pos) - { - s2 = clist->drag_pos + 1; - e2 = row; - } - /* extending upwards */ - else if (row < clist->drag_pos && clist->anchor >= clist->drag_pos) - { - s2 = row; - e2 = clist->drag_pos - 1; - } - else if (row < clist->drag_pos && clist->anchor < clist->drag_pos) - { - e1 = clist->drag_pos; - /* row and drag_pos on different sides of anchor : - take back the selection between anchor and drag_pos, - select between anchor and row */ - if (row < clist->anchor) - { - s1 = clist->anchor + 1; - s2 = row; - e2 = clist->anchor - 1; - } - /* take back the selection between anchor and drag_pos */ - else - s1 = row + 1; - } - else if (row > clist->drag_pos && clist->anchor > clist->drag_pos) + if (button_actions & GTK_BUTTON_SELECTS & + !gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data")) { - s1 = clist->drag_pos; - /* row and drag_pos on different sides of anchor : - take back the selection between anchor and drag_pos, - select between anchor and row */ - if (row > clist->anchor) + if (row == clist->focus_row) + return FALSE; + + gtk_clist_draw_focus (widget); + clist->focus_row = row; + gtk_clist_draw_focus (widget); + + switch (clist->selection_mode) { - e1 = clist->anchor - 1; - s2 = clist->anchor + 1; - e2 = row; + case GTK_SELECTION_BROWSE: + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + clist->focus_row, -1, event); + break; + case GTK_SELECTION_EXTENDED: + update_extended_selection (clist, clist->focus_row); + break; + default: + break; } - /* take back the selection between anchor and drag_pos */ - else - e1 = row - 1; } + + if (ROW_TOP_YPIXEL(clist, row) < 0) + move_vertical (clist, row, 0); + else if (ROW_TOP_YPIXEL(clist, row) + clist->row_height > + clist->clist_window_height) + move_vertical (clist, row, 1); - clist->drag_pos = row; + return FALSE; +} - area.x = 0; - area.width = clist->clist_window_width; +static void +gtk_clist_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkCList *clist; + gint i; - /* restore the elements between s1 and e1 */ - if (s1 >= 0) - { - for (i = s1, list = g_list_nth (clist->row_list, i); i <= e1; - i++, list = list->next) - if (GTK_CLIST_ROW (list)->selectable) - { - if (GTK_CLIST_CLASS_FW (clist)->selection_find (clist, i, list)) - GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED; - else - GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL; - } + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); + g_return_if_fail (requisition != NULL); - top = ROW_TOP_YPIXEL (clist, clist->focus_row); + clist = GTK_CLIST (widget); - if (top + clist->row_height <= 0) - { - area.y = 0; - area.height = ROW_TOP_YPIXEL (clist, e1) + clist->row_height; - draw_rows (clist, &area); - gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + requisition->width = 0; + requisition->height = 0; + + /* compute the size of the column title (title) area */ + clist->column_title_area.height = 0; + if (GTK_CLIST_SHOW_TITLES(clist)) + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button) + { + GtkRequisition child_requisition; + + gtk_widget_size_request (clist->column[i].button, + &child_requisition); + clist->column_title_area.height = + MAX (clist->column_title_area.height, + child_requisition.height); + } + + requisition->width += (widget->style->klass->xthickness + + GTK_CONTAINER (widget)->border_width) * 2; + requisition->height += (clist->column_title_area.height + + (widget->style->klass->ythickness + + GTK_CONTAINER (widget)->border_width) * 2); + + /* if (!clist->hadjustment) */ + requisition->width += list_requisition_width (clist); + /* if (!clist->vadjustment) */ + requisition->height += LIST_HEIGHT (clist); +} + +static void +gtk_clist_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkCList *clist; + GtkAllocation clist_allocation; + gint border_width; + + 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; + border_width = GTK_CONTAINER (widget)->border_width; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x + border_width, + allocation->y + border_width, + allocation->width - border_width * 2, + allocation->height - border_width * 2); + } + + /* use internal allocation structure for all the math + * because it's easier than always subtracting the container + * border width */ + clist->internal_allocation.x = 0; + clist->internal_allocation.y = 0; + clist->internal_allocation.width = MAX (1, (gint)allocation->width - + border_width * 2); + clist->internal_allocation.height = MAX (1, (gint)allocation->height - + border_width * 2); + + /* allocate clist window assuming no scrollbars */ + clist_allocation.x = (clist->internal_allocation.x + + widget->style->klass->xthickness); + clist_allocation.y = (clist->internal_allocation.y + + widget->style->klass->ythickness + + clist->column_title_area.height); + clist_allocation.width = MAX (1, (gint)clist->internal_allocation.width - + (2 * (gint)widget->style->klass->xthickness)); + clist_allocation.height = MAX (1, (gint)clist->internal_allocation.height - + (2 * (gint)widget->style->klass->ythickness) - + (gint)clist->column_title_area.height); + + clist->clist_window_width = clist_allocation.width; + clist->clist_window_height = clist_allocation.height; + + if (GTK_WIDGET_REALIZED (widget)) + { + 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 = widget->style->klass->xthickness; + clist->column_title_area.y = widget->style->klass->ythickness; + clist->column_title_area.width = clist_allocation.width; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (clist->title_window, + clist->column_title_area.x, + clist->column_title_area.y, + clist->column_title_area.width, + clist->column_title_area.height); + } + + /* column button allocation */ + size_allocate_columns (clist, FALSE); + size_allocate_title_buttons (clist); + + adjust_adjustments (clist, TRUE); +} + +/* GTKCONTAINER + * gtk_clist_forall + */ +static void +gtk_clist_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + GtkCList *clist; + guint i; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_CLIST (container)); + g_return_if_fail (callback != NULL); + + if (!include_internals) + return; + + clist = GTK_CLIST (container); + + /* callback for the column buttons */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button) + (*callback) (clist->column[i].button, callback_data); +} + +/* PRIVATE DRAWING FUNCTIONS + * get_cell_style + * draw_cell_pixmap + * draw_row + * draw_rows + * draw_xor_line + * clist_refresh + */ +static void +get_cell_style (GtkCList *clist, + GtkCListRow *clist_row, + gint state, + gint column, + GtkStyle **style, + GdkGC **fg_gc, + GdkGC **bg_gc) +{ + gint fg_state; + + if ((state == GTK_STATE_NORMAL) && + (GTK_WIDGET (clist)->state == GTK_STATE_INSENSITIVE)) + fg_state = GTK_STATE_INSENSITIVE; + else + fg_state = state; + + if (clist_row->cell[column].style) + { + if (style) + *style = clist_row->cell[column].style; + if (fg_gc) + *fg_gc = clist_row->cell[column].style->fg_gc[fg_state]; + if (bg_gc) { + if (state == GTK_STATE_SELECTED) + *bg_gc = clist_row->cell[column].style->bg_gc[state]; + else + *bg_gc = clist_row->cell[column].style->base_gc[state]; + } + } + else if (clist_row->style) + { + if (style) + *style = clist_row->style; + if (fg_gc) + *fg_gc = clist_row->style->fg_gc[fg_state]; + if (bg_gc) { + if (state == GTK_STATE_SELECTED) + *bg_gc = clist_row->style->bg_gc[state]; + else + *bg_gc = clist_row->style->base_gc[state]; + } + } + else + { + if (style) + *style = GTK_WIDGET (clist)->style; + if (fg_gc) + *fg_gc = GTK_WIDGET (clist)->style->fg_gc[fg_state]; + if (bg_gc) { + if (state == GTK_STATE_SELECTED) + *bg_gc = GTK_WIDGET (clist)->style->bg_gc[state]; + else + *bg_gc = GTK_WIDGET (clist)->style->base_gc[state]; + } + + if (state != GTK_STATE_SELECTED) + { + if (fg_gc && clist_row->fg_set) + *fg_gc = clist->fg_gc; + if (bg_gc && clist_row->bg_set) + *bg_gc = clist->bg_gc; + } + } +} + +static gint +draw_cell_pixmap (GdkWindow *window, + GdkRectangle *clip_rectangle, + GdkGC *fg_gc, + GdkPixmap *pixmap, + GdkBitmap *mask, + gint x, + gint y, + gint width, + gint height) +{ + gint xsrc = 0; + gint ysrc = 0; + + if (mask) + { + gdk_gc_set_clip_mask (fg_gc, mask); + gdk_gc_set_clip_origin (fg_gc, x, y); + } + + if (x < clip_rectangle->x) + { + xsrc = clip_rectangle->x - x; + width -= xsrc; + x = clip_rectangle->x; + } + if (x + width > clip_rectangle->x + clip_rectangle->width) + width = clip_rectangle->x + clip_rectangle->width - x; + + if (y < clip_rectangle->y) + { + ysrc = clip_rectangle->y - y; + height -= ysrc; + y = clip_rectangle->y; + } + if (y + height > clip_rectangle->y + clip_rectangle->height) + height = clip_rectangle->y + clip_rectangle->height - y; + + gdk_draw_pixmap (window, fg_gc, pixmap, xsrc, ysrc, x, y, width, height); + gdk_gc_set_clip_origin (fg_gc, 0, 0); + if (mask) + gdk_gc_set_clip_mask (fg_gc, NULL); + + return x + MAX (width, 0); +} + +static void +draw_row (GtkCList *clist, + GdkRectangle *area, + gint row, + GtkCListRow *clist_row) +{ + GtkWidget *widget; + GdkRectangle *rect; + GdkRectangle row_rectangle; + GdkRectangle cell_rectangle; + GdkRectangle clip_rectangle; + GdkRectangle intersect_rectangle; + gint last_column; + gint state; + gint i; + + g_return_if_fail (clist != NULL); + + /* bail now if we arn't drawable yet */ + if (!GTK_WIDGET_DRAWABLE (clist) || 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 = ROW_ELEMENT (clist, 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, its 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; + + if (clist_row->state == GTK_STATE_NORMAL) + { + if (clist_row->fg_set) + gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground); + if (clist_row->bg_set) + gdk_gc_set_foreground (clist->bg_gc, &clist_row->background); + } + + state = clist_row->state; + + /* draw the cell borders and background */ + if (area) + { + rect = &intersect_rectangle; + if (gdk_rectangle_intersect (area, &cell_rectangle, + &intersect_rectangle)) + gdk_draw_rectangle (clist->clist_window, + widget->style->base_gc[GTK_STATE_ACTIVE], + TRUE, + intersect_rectangle.x, + intersect_rectangle.y, + intersect_rectangle.width, + intersect_rectangle.height); + + /* the last row has to clear its 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_draw_rectangle (clist->clist_window, + widget->style->base_gc[GTK_STATE_ACTIVE], + TRUE, + intersect_rectangle.x, + intersect_rectangle.y, + intersect_rectangle.width, + intersect_rectangle.height); + } + + if (!gdk_rectangle_intersect (area, &row_rectangle,&intersect_rectangle)) + return; + + } + else + { + rect = &clip_rectangle; + gdk_draw_rectangle (clist->clist_window, + widget->style->base_gc[GTK_STATE_ACTIVE], + TRUE, + cell_rectangle.x, + cell_rectangle.y, + cell_rectangle.width, + cell_rectangle.height); + + /* the last row has to clear its bottom cell spacing too */ + if (clist_row == clist->row_list_end->data) + { + cell_rectangle.y += clist->row_height + CELL_SPACING; + + gdk_draw_rectangle (clist->clist_window, + widget->style->base_gc[GTK_STATE_ACTIVE], + TRUE, + cell_rectangle.x, + cell_rectangle.y, + cell_rectangle.width, + cell_rectangle.height); + } + } + + for (last_column = clist->columns - 1; + last_column >= 0 && !clist->column[last_column].visible; last_column--) + ; + + /* iterate and draw all the columns (row cells) and draw their contents */ + for (i = 0; i < clist->columns; i++) + { + GtkStyle *style; + GdkGC *fg_gc; + GdkGC *bg_gc; + + gint width; + gint height; + gint pixmap_width; + gint offset = 0; + gint row_center_offset; + + if (!clist->column[i].visible) + continue; + + get_cell_style (clist, clist_row, state, i, &style, &fg_gc, &bg_gc); + + clip_rectangle.x = clist->column[i].area.x + clist->hoffset; + clip_rectangle.width = clist->column[i].area.width; + + /* calculate clipping region clipping region */ + clip_rectangle.x -= COLUMN_INSET + CELL_SPACING; + clip_rectangle.width += (2 * COLUMN_INSET + CELL_SPACING + + (i == last_column) * CELL_SPACING); + + if (area && !gdk_rectangle_intersect (area, &clip_rectangle, + &intersect_rectangle)) + continue; + + gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE, + rect->x, rect->y, rect->width, rect->height); + + clip_rectangle.x += COLUMN_INSET + CELL_SPACING; + clip_rectangle.width -= (2 * COLUMN_INSET + CELL_SPACING + + (i == last_column) * CELL_SPACING); + + /* calculate real width for column justification */ + pixmap_width = 0; + offset = 0; + switch (clist_row->cell[i].type) + { + case GTK_CELL_TEXT: + width = gdk_string_width (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, + &pixmap_width, &height); + width = pixmap_width; + break; + case GTK_CELL_PIXTEXT: + gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, + &pixmap_width, &height); + width = (pixmap_width + + GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing + + gdk_string_width (style->font, + GTK_CELL_PIXTEXT + (clist_row->cell[i])->text)); + break; + default: + continue; + break; + } + + switch (clist->column[i].justification) + { + case GTK_JUSTIFY_LEFT: + offset = clip_rectangle.x + clist_row->cell[i].horizontal; + break; + case GTK_JUSTIFY_RIGHT: + offset = (clip_rectangle.x + clist_row->cell[i].horizontal + + clip_rectangle.width - width); + break; + case GTK_JUSTIFY_CENTER: + case GTK_JUSTIFY_FILL: + offset = (clip_rectangle.x + clist_row->cell[i].horizontal + + (clip_rectangle.width / 2) - (width / 2)); + break; + }; + + /* Draw Text and/or Pixmap */ + switch (clist_row->cell[i].type) + { + case GTK_CELL_PIXMAP: + draw_cell_pixmap (clist->clist_window, &clip_rectangle, fg_gc, + GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, + GTK_CELL_PIXMAP (clist_row->cell[i])->mask, + offset, + clip_rectangle.y + clist_row->cell[i].vertical + + (clip_rectangle.height - height) / 2, + pixmap_width, height); + break; + case GTK_CELL_PIXTEXT: + offset = + draw_cell_pixmap (clist->clist_window, &clip_rectangle, fg_gc, + GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, + GTK_CELL_PIXTEXT (clist_row->cell[i])->mask, + offset, + clip_rectangle.y + clist_row->cell[i].vertical+ + (clip_rectangle.height - height) / 2, + pixmap_width, height); + offset += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing; + case GTK_CELL_TEXT: + if (style != GTK_WIDGET (clist)->style) + row_center_offset = (((clist->row_height - style->font->ascent - + style->font->descent - 1) / 2) + 1.5 + + style->font->ascent); + else + row_center_offset = clist->row_center_offset; + + gdk_gc_set_clip_rectangle (fg_gc, &clip_rectangle); + gdk_draw_string (clist->clist_window, style->font, fg_gc, + offset, + row_rectangle.y + row_center_offset + + clist_row->cell[i].vertical, + (clist_row->cell[i].type == GTK_CELL_PIXTEXT) ? + GTK_CELL_PIXTEXT (clist_row->cell[i])->text : + GTK_CELL_TEXT (clist_row->cell[i])->text); + gdk_gc_set_clip_rectangle (fg_gc, NULL); + break; + default: + break; + } + } + + /* draw focus rectangle */ + if (clist->focus_row == row && + GTK_WIDGET_CAN_FOCUS (widget) && GTK_WIDGET_HAS_FOCUS(widget)) + { + if (!area) + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, + row_rectangle.x, row_rectangle.y, + row_rectangle.width - 1, row_rectangle.height - 1); + else if (gdk_rectangle_intersect (area, &row_rectangle, + &intersect_rectangle)) + { + gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle); + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, + row_rectangle.x, row_rectangle.y, + row_rectangle.width - 1, + row_rectangle.height - 1); + gdk_gc_set_clip_rectangle (clist->xor_gc, NULL); + } + } +} + +static void +draw_rows (GtkCList *clist, + GdkRectangle *area) +{ + GList *list; + GtkCListRow *clist_row; + gint i; + gint first_row; + gint last_row; + + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (clist->row_height == 0 || + !GTK_WIDGET_DRAWABLE (clist)) + 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); + } + + /* this is a small special case which exposes the bottom cell line + * on the last row -- it might go away if I change the wall the cell + * spacings are drawn + */ + if (clist->rows == first_row) + first_row--; + + list = ROW_ELEMENT (clist, first_row); + i = first_row; + while (list) + { + clist_row = list->data; + list = list->next; + + if (i > last_row) + return; + + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, area, i, clist_row); + i++; + } + + if (!area) + gdk_window_clear_area (clist->clist_window, 0, + ROW_TOP_YPIXEL (clist, i), 0, 0); +} + +static void +draw_xor_line (GtkCList *clist) +{ + GtkWidget *widget; + + g_return_if_fail (clist != NULL); + + widget = GTK_WIDGET (clist); + + gdk_draw_line (widget->window, clist->xor_gc, + clist->x_drag, + widget->style->klass->ythickness, + clist->x_drag, + clist->column_title_area.height + + clist->clist_window_height + 1); +} + +static void +clist_refresh (GtkCList *clist) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (CLIST_UNFROZEN (clist)) + { + adjust_adjustments (clist, FALSE); + draw_rows (clist, NULL); + } +} + +/* get cell from coordinates + * get_selection_info + * gtk_clist_get_selection_info + */ +static gint +get_selection_info (GtkCList *clist, + gint x, + gint y, + gint *row, + gint *column) +{ + gint trow, tcol; + + g_return_val_if_fail (clist != NULL, 0); + g_return_val_if_fail (GTK_IS_CLIST (clist), 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; +} + +gint +gtk_clist_get_selection_info (GtkCList *clist, + gint x, + gint y, + gint *row, + gint *column) +{ + g_return_val_if_fail (clist != NULL, 0); + g_return_val_if_fail (GTK_IS_CLIST (clist), 0); + return get_selection_info (clist, x, y, row, column); +} + +/* PRIVATE ADJUSTMENT FUNCTIONS + * adjust_adjustments + * vadjustment_changed + * hadjustment_changed + * vadjustment_value_changed + * hadjustment_value_changed + * check_exposures + */ +static void +adjust_adjustments (GtkCList *clist, + gboolean block_resize) +{ + if (clist->vadjustment) + { + clist->vadjustment->page_size = clist->clist_window_height; + clist->vadjustment->page_increment = clist->clist_window_height / 2; + clist->vadjustment->step_increment = clist->row_height; + clist->vadjustment->lower = 0; + clist->vadjustment->upper = LIST_HEIGHT (clist); + + if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist) || + (clist->voffset + (gint)clist->vadjustment->value) != 0) + { + clist->vadjustment->value = MAX (0, (LIST_HEIGHT (clist) - + clist->clist_window_height)); + gtk_signal_emit_by_name (GTK_OBJECT (clist->vadjustment), + "value_changed"); + } + gtk_signal_emit_by_name (GTK_OBJECT (clist->vadjustment), "changed"); + } + + if (clist->hadjustment) + { + clist->hadjustment->page_size = clist->clist_window_width; + clist->hadjustment->page_increment = clist->clist_window_width / 2; + clist->hadjustment->step_increment = 10; + clist->hadjustment->lower = 0; + clist->hadjustment->upper = LIST_WIDTH (clist); + + if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist) || + (clist->hoffset + (gint)clist->hadjustment->value) != 0) + { + clist->hadjustment->value = MAX (0, (LIST_WIDTH (clist) - + clist->clist_window_width)); + gtk_signal_emit_by_name (GTK_OBJECT (clist->hadjustment), + "value_changed"); + } + gtk_signal_emit_by_name (GTK_OBJECT (clist->hadjustment), "changed"); + } + + if (!block_resize && (!clist->vadjustment || !clist->hadjustment)) + { + GtkWidget *widget; + GtkRequisition requisition; + + widget = GTK_WIDGET (clist); + gtk_widget_size_request (widget, &requisition); + + if ((!clist->hadjustment && + requisition.width != widget->allocation.width) || + (!clist->vadjustment && + requisition.height != widget->allocation.height)) + gtk_widget_queue_resize (widget); + } +} + +static void +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 +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 +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); + + if (!GTK_WIDGET_DRAWABLE (clist) || adjustment != clist->vadjustment) + return; + + value = adjustment->value; + + 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; + draw_rows (clist, NULL); + return; + } + + if ((diff != 0) && (diff != clist->clist_window_height)) + gdk_window_copy_area (clist->clist_window, clist->fg_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; + draw_rows (clist, NULL); + return; + } + + if ((diff != 0) && (diff != clist->clist_window_height)) + gdk_window_copy_area (clist->clist_window, clist->fg_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; + if ((diff != 0) && (diff != clist->clist_window_height)) + check_exposures (clist); + + draw_rows (clist, &area); +} + +static void +hadjustment_value_changed (GtkAdjustment *adjustment, + gpointer data) +{ + GtkCList *clist; + GdkRectangle area; + gint i; + gint y = 0; + gint diff = 0; + gint 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); + + if (!GTK_WIDGET_DRAWABLE (clist) || adjustment != clist->hadjustment) + return; + + value = adjustment->value; + + /* move the column buttons and resize windows */ + for (i = 0; i < clist->columns; i++) + { + if (clist->column[i].button) + { + 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 (clist->column[i].window) + gdk_window_move (clist->column[i].window, + clist->column[i].button->allocation.x + + clist->column[i].button->allocation.width - + (DRAG_WIDTH / 2), 0); + } } - else if (top >= clist->clist_window_height) + } + + if (value > -clist->hoffset) + { + /* scroll right */ + diff = value + clist->hoffset; + + clist->hoffset = -value; + + /* we have to re-draw the whole screen here... */ + if (diff >= clist->clist_window_width) { - area.y = ROW_TOP_YPIXEL (clist, s1); - area.height = clist->clist_window_height - area.y; + draw_rows (clist, NULL); + return; + } + + if (GTK_WIDGET_CAN_FOCUS(clist) && GTK_WIDGET_HAS_FOCUS(clist) && + !GTK_CLIST_CHILD_HAS_FOCUS(clist) && GTK_CLIST_ADD_MODE(clist)) + { + y = ROW_TOP_YPIXEL (clist, clist->focus_row); + + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y, + clist->clist_window_width - 1, + clist->row_height - 1); + } + gdk_window_copy_area (clist->clist_window, + clist->fg_gc, + 0, 0, + clist->clist_window, + diff, + 0, + clist->clist_window_width - diff, + clist->clist_window_height); + + area.x = clist->clist_window_width - diff; + } + else + { + /* scroll left */ + if (!(diff = -clist->hoffset - value)) + return; + + clist->hoffset = -value; + + /* we have to re-draw the whole screen here... */ + if (diff >= clist->clist_window_width) + { + draw_rows (clist, NULL); + return; + } + + if (GTK_WIDGET_CAN_FOCUS(clist) && GTK_WIDGET_HAS_FOCUS(clist) && + !GTK_CLIST_CHILD_HAS_FOCUS(clist) && GTK_CLIST_ADD_MODE(clist)) + { + y = ROW_TOP_YPIXEL (clist, clist->focus_row); + + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y, + clist->clist_window_width - 1, + clist->row_height - 1); + } + + gdk_window_copy_area (clist->clist_window, + clist->fg_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; + + check_exposures (clist); + + if (GTK_WIDGET_CAN_FOCUS(clist) && GTK_WIDGET_HAS_FOCUS(clist) && + !GTK_CLIST_CHILD_HAS_FOCUS(clist)) + { + if (GTK_CLIST_ADD_MODE(clist)) + { + gint focus_row; + + focus_row = clist->focus_row; + clist->focus_row = -1; draw_rows (clist, &area); - gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + clist->focus_row = focus_row; + + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, + FALSE, 0, y, clist->clist_window_width - 1, + clist->row_height - 1); + return; } - else if (top < 0) - gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); - else if (top + clist->row_height > clist->clist_window_height) - gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + else + { + gint x0; + gint x1; + + if (area.x == 0) + { + x0 = clist->clist_window_width - 1; + x1 = diff; + } + else + { + x0 = 0; + x1 = area.x - 1; + } + + y = ROW_TOP_YPIXEL (clist, clist->focus_row); + gdk_draw_line (clist->clist_window, clist->xor_gc, + x0, y + 1, x0, y + clist->row_height - 2); + gdk_draw_line (clist->clist_window, clist->xor_gc, + x1, y + 1, x1, y + clist->row_height - 2); + + } + } + draw_rows (clist, &area); +} - y1 = ROW_TOP_YPIXEL (clist, s1); - h1 = (e1 - s1 + 1) * (clist->row_height + CELL_SPACING); +static void +check_exposures (GtkCList *clist) +{ + GdkEvent *event; + + if (!GTK_WIDGET_REALIZED (clist)) + return; + + /* Make sure graphics expose events are processed before scrolling + * again */ + while ((event = gdk_event_get_graphics_expose (clist->clist_window)) != NULL) + { + gtk_widget_event (GTK_WIDGET (clist), event); + if (event->expose.count == 0) + { + gdk_event_free (event); + break; + } + gdk_event_free (event); + } +} + +/* PRIVATE + * Memory Allocation/Distruction Routines for GtkCList stuctures + * + * functions: + * columns_new + * column_title_new + * columns_delete + * row_new + * row_delete + */ +static GtkCListColumn * +columns_new (GtkCList *clist) +{ + GtkCListColumn *column; + gint i; + + 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].window = NULL; + column[i].width = 0; + column[i].min_width = -1; + column[i].max_width = -1; + column[i].visible = TRUE; + column[i].width_set = FALSE; + column[i].resizeable = TRUE; + column[i].auto_resize = FALSE; + column[i].button_passive = FALSE; + column[i].justification = GTK_JUSTIFY_LEFT; + } + + return column; +} + +static void +column_title_new (GtkCList *clist, + gint column, + const gchar *title) +{ + if (clist->column[column].title) + g_free (clist->column[column].title); + + clist->column[column].title = g_strdup (title); +} + +static void +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 * +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].vertical = 0; + clist_row->cell[i].horizontal = 0; + clist_row->cell[i].style = NULL; } - /* extend the selection between s2 and e2 */ - if (s2 >= 0) - { - for (i = s2, list = g_list_nth (clist->row_list, i); i <= e2; - i++, list = list->next) - if (GTK_CLIST_ROW (list)->selectable && - GTK_CLIST_ROW (list)->state != clist->anchor_state) - GTK_CLIST_ROW (list)->state = clist->anchor_state; + clist_row->fg_set = FALSE; + clist_row->bg_set = FALSE; + clist_row->style = NULL; + clist_row->selectable = TRUE; + clist_row->state = GTK_STATE_NORMAL; + clist_row->data = NULL; + clist_row->destroy = NULL; - top = ROW_TOP_YPIXEL (clist, clist->focus_row); + return clist_row; +} - if (top + clist->row_height <= 0) - { - area.y = 0; - area.height = ROW_TOP_YPIXEL (clist, e2) + clist->row_height; - draw_rows (clist, &area); - gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); - } - else if (top >= clist->clist_window_height) +static void +row_delete (GtkCList *clist, + GtkCListRow *clist_row) +{ + gint i; + + for (i = 0; i < clist->columns; i++) + { + GTK_CLIST_CLASS_FW (clist)->set_cell_contents + (clist, clist_row, i, GTK_CELL_EMPTY, NULL, 0, NULL, NULL); + if (clist_row->cell[i].style) { - area.y = ROW_TOP_YPIXEL (clist, s2); - area.height = clist->clist_window_height - area.y; - draw_rows (clist, &area); - gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + if (GTK_WIDGET_REALIZED (clist)) + gtk_style_detach (clist_row->cell[i].style); + gtk_style_unref (clist_row->cell[i].style); } - else if (top < 0) - gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); - else if (top + clist->row_height > clist->clist_window_height) - gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + } - y2 = ROW_TOP_YPIXEL (clist, s2); - h2 = (e2 - s2 + 1) * (clist->row_height + CELL_SPACING); + if (clist_row->style) + { + if (GTK_WIDGET_REALIZED (clist)) + gtk_style_detach (clist_row->style); + gtk_style_unref (clist_row->style); } - area.y = MAX (0, MIN (y1, y2)); - if (area.y > clist->clist_window_height) - area.y = 0; - area.height = MIN (clist->clist_window_height, h1 + h2); - if (s1 >= 0 && s2 >= 0) - area.height += (clist->row_height + CELL_SPACING); - draw_rows (clist, &area); + if (clist_row->destroy) + clist_row->destroy (clist_row->data); + + g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell); + g_mem_chunk_free (clist->row_mem_chunk, clist_row); } -static void -start_selection (GtkCList *clist) +/* FOCUS FUNCTIONS + * gtk_clist_focus + * gtk_clist_draw_focus + * gtk_clist_focus_in + * gtk_clist_focus_out + * gtk_clist_set_focus_child + * title_focus + */ +static gint +gtk_clist_focus (GtkContainer *container, + GtkDirectionType direction) { - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + GtkCList *clist; + GtkWidget *focus_child; + gint old_row; - if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) - return; + g_return_val_if_fail (container != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CLIST (container), FALSE); - set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row, - clist->focus_row); -} + if (!GTK_WIDGET_IS_SENSITIVE (container)) + return FALSE; + + clist = GTK_CLIST (container); + focus_child = container->focus_child; + old_row = clist->focus_row; -static void -end_selection (GtkCList *clist) -{ - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + switch (direction) + { + case GTK_DIR_LEFT: + case GTK_DIR_RIGHT: + if (GTK_CLIST_CHILD_HAS_FOCUS(clist)) + { + if (title_focus (clist, direction)) + return TRUE; + gtk_container_set_focus_child (container, NULL); + return FALSE; + } + gtk_widget_grab_focus (GTK_WIDGET (container)); + return TRUE; + case GTK_DIR_DOWN: + case GTK_DIR_TAB_FORWARD: + if (GTK_CLIST_CHILD_HAS_FOCUS(clist)) + { + gboolean tf = FALSE; - if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist)) || - clist->anchor == -1) - return; - - GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); -} + if (((focus_child && direction == GTK_DIR_DOWN) || + !(tf = title_focus (clist, GTK_DIR_TAB_FORWARD))) + && clist->rows) + { + if (clist->focus_row < 0) + { + clist->focus_row = 0; -static void -extend_selection (GtkCList *clist, - GtkScrollType scroll_type, - gfloat position, - gboolean auto_start_selection) -{ - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + if ((clist->selection_mode == GTK_SELECTION_BROWSE || + clist->selection_mode == GTK_SELECTION_EXTENDED) && + !clist->selection) + gtk_signal_emit (GTK_OBJECT (clist), + clist_signals[SELECT_ROW], + clist->focus_row, -1, NULL); + } + gtk_widget_grab_focus (GTK_WIDGET (container)); + return TRUE; + } - if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) || - clist->selection_mode != GTK_SELECTION_EXTENDED) - return; + if (tf) + return TRUE; + } + + GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS); + break; + case GTK_DIR_UP: + case GTK_DIR_TAB_BACKWARD: + if (!focus_child && + GTK_CLIST_CHILD_HAS_FOCUS(clist) && clist->rows) + { + if (clist->focus_row < 0) + { + clist->focus_row = 0; + if ((clist->selection_mode == GTK_SELECTION_BROWSE || + clist->selection_mode == GTK_SELECTION_EXTENDED) && + !clist->selection) + gtk_signal_emit (GTK_OBJECT (clist), + clist_signals[SELECT_ROW], + clist->focus_row, -1, NULL); + } + gtk_widget_grab_focus (GTK_WIDGET (container)); + return TRUE; + } - if (auto_start_selection) - set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row, - clist->focus_row); - else if (clist->anchor == -1) - return; + GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS); - move_focus_row (clist, scroll_type, position); + if (title_focus (clist, direction)) + return TRUE; - if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height > - clist->clist_window_height) - gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); - else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0) - gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + break; + default: + break; + } - update_extended_selection (clist, clist->focus_row); + gtk_container_set_focus_child (container, NULL); + return FALSE; } static void -abort_column_resize (GtkCList *clist) +gtk_clist_draw_focus (GtkWidget *widget) { - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + GtkCList *clist; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); - if (!GTK_CLIST_IN_DRAG (clist)) + if (!GTK_WIDGET_DRAWABLE (widget) || !GTK_WIDGET_CAN_FOCUS (widget)) return; - GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG); - gtk_grab_remove (GTK_WIDGET (clist)); - gdk_pointer_ungrab (GDK_CURRENT_TIME); - clist->drag_pos = -1; + clist = GTK_CLIST (widget); + if (clist->focus_row >= 0) + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, + 0, ROW_TOP_YPIXEL(clist, clist->focus_row), + clist->clist_window_width - 1, + clist->row_height - 1); +} - if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1) - draw_xor_line (clist); +static gint +gtk_clist_focus_in (GtkWidget *widget, + GdkEventFocus *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); + + GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); + GTK_CLIST_UNSET_FLAG (widget, CLIST_CHILD_HAS_FOCUS); + + clist = GTK_CLIST (widget); - if (GTK_CLIST_ADD_MODE (clist)) + if (clist->selection_mode == GTK_SELECTION_BROWSE && + clist->selection == NULL && clist->focus_row > -1) { - gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_ON_OFF_DASH, 0,0); - gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2); + GList *list; + + list = g_list_nth (clist->row_list, clist->focus_row); + if (list && GTK_CLIST_ROW (list)->selectable) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + clist->focus_row, -1, event); + else + gtk_widget_draw_focus (widget); } + else + gtk_widget_draw_focus (widget); + + return FALSE; } static gint -gtk_clist_key_press (GtkWidget * widget, - GdkEventKey * event) +gtk_clist_focus_out (GtkWidget *widget, + GdkEventFocus *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_CLASS (parent_class)->key_press_event && - GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event)) - return TRUE; - - switch (event->keyval) - { - case GDK_Tab: - case GDK_ISO_Left_Tab: - if (event->state & GDK_SHIFT_MASK) - return gtk_container_focus (GTK_CONTAINER (widget), - GTK_DIR_TAB_BACKWARD); - else - return gtk_container_focus (GTK_CONTAINER (widget), - GTK_DIR_TAB_FORWARD); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); + GTK_CLIST_SET_FLAG (widget, CLIST_CHILD_HAS_FOCUS); - default: - break; - } + gtk_widget_draw_focus (widget); + clist = GTK_CLIST (widget); + + GTK_CLIST_CLASS_FW (widget)->resync_selection (clist, (GdkEvent *) event); + return FALSE; } +static void +gtk_clist_set_focus_child (GtkContainer *container, + GtkWidget *child) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_CLIST (container)); + + if (child) + { + g_return_if_fail (GTK_IS_WIDGET (child)); + GTK_CLIST_SET_FLAG (container, CLIST_CHILD_HAS_FOCUS); + } + + parent_class->set_focus_child (container, child); +} + static gboolean -title_focus (GtkCList * clist, - gint dir) +title_focus (GtkCList *clist, + gint dir) { GtkWidget *focus_child; gboolean return_val = FALSE; + gint last_column; gint d = 1; gint i = 0; gint j; - if (!GTK_CLIST_SHOW_TITLES (clist)) + if (!GTK_CLIST_SHOW_TITLES(clist)) return FALSE; focus_child = GTK_CONTAINER (clist)->focus_child; + + for (last_column = clist->columns - 1; + last_column >= 0 && !clist->column[last_column].visible; last_column--) + ; switch (dir) { case GTK_DIR_TAB_BACKWARD: case GTK_DIR_UP: - if (!focus_child || focus_child == clist->hscrollbar || - focus_child == clist->hscrollbar || - !GTK_CLIST_CHILD_HAS_FOCUS (clist)) + if (!focus_child || !GTK_CLIST_CHILD_HAS_FOCUS(clist)) { if (dir == GTK_DIR_UP) i = COLUMN_FROM_XPIXEL (clist, 0); else - i = clist->columns - 1; + i = last_column; focus_child = clist->column[i].button; dir = GTK_DIR_TAB_FORWARD; } @@ -5910,16 +6752,14 @@ title_focus (GtkCList * clist, break; case GTK_DIR_LEFT: d = -1; - if (!focus_child || focus_child == clist->hscrollbar || - focus_child == clist->hscrollbar) + if (!focus_child) { - i = clist->columns - 1; + i = last_column; focus_child = clist->column[i].button; } break; case GTK_DIR_RIGHT: - if (!focus_child || focus_child == clist->hscrollbar || - focus_child == clist->hscrollbar) + if (!focus_child) { i = 0; focus_child = clist->column[i].button; @@ -5935,7 +6775,7 @@ title_focus (GtkCList * clist, if (clist->column[i].button && GTK_WIDGET_VISIBLE (clist->column[i].button) && GTK_IS_CONTAINER (clist->column[i].button) && - !GTK_WIDGET_HAS_FOCUS (clist->column[i].button)) + !GTK_WIDGET_HAS_FOCUS(clist->column[i].button)) if (gtk_container_focus (GTK_CONTAINER (clist->column[i].button), dir)) { @@ -5982,7 +6822,7 @@ title_focus (GtkCList * clist, else if (COLUMN_LEFT_XPIXEL(clist, j) + clist->column[j].area.width > clist->clist_window_width) { - if (j == clist->columns-1) + if (j == last_column) gtk_clist_moveto (clist, -1, j, 0, 0); else gtk_clist_moveto (clist, -1, j, 0, 1); @@ -5991,325 +6831,421 @@ title_focus (GtkCList * clist, return return_val; } -static gint -gtk_clist_focus (GtkContainer * container, - GtkDirectionType direction) +/* PRIVATE SCROLLING FUNCTIONS + * move_focus_row + * scroll_horizontal + * scroll_vertical + * move_horizontal + * move_vertical + * horizontal_timeout + * vertical_timeout + * remove_grab + */ +static void +move_focus_row (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position) { - GtkCList *clist; - GtkWidget *focus_child; - gint old_row; + GtkWidget *widget; - g_return_val_if_fail (container != NULL, FALSE); - g_return_val_if_fail (GTK_IS_CLIST (container), FALSE); + g_return_if_fail (clist != 0); + g_return_if_fail (GTK_IS_CLIST (clist)); - if (!GTK_WIDGET_SENSITIVE (container)) - return FALSE; - - clist = GTK_CLIST (container); - focus_child = container->focus_child; - old_row = clist->focus_row; + widget = GTK_WIDGET (clist); - switch (direction) + switch (scroll_type) { - case GTK_DIR_LEFT: - case GTK_DIR_RIGHT: - if (GTK_CLIST_CHILD_HAS_FOCUS (clist) && - (!focus_child || (focus_child && focus_child != clist->vscrollbar && - focus_child != clist->hscrollbar))) - { - if (title_focus (clist, direction)) - return TRUE; - gtk_container_set_focus_child (container, NULL); - return FALSE; - } - gtk_widget_grab_focus (GTK_WIDGET (container)); - return TRUE; - case GTK_DIR_DOWN: - case GTK_DIR_TAB_FORWARD: - if (GTK_CLIST_CHILD_HAS_FOCUS (clist) && - (!focus_child || (focus_child != clist->vscrollbar && - focus_child != clist->hscrollbar))) + case GTK_SCROLL_STEP_BACKWARD: + if (clist->focus_row <= 0) + return; + gtk_clist_draw_focus (widget); + clist->focus_row--; + gtk_clist_draw_focus (widget); + break; + case GTK_SCROLL_STEP_FORWARD: + if (clist->focus_row >= clist->rows - 1) + return; + gtk_clist_draw_focus (widget); + clist->focus_row++; + gtk_clist_draw_focus (widget); + break; + case GTK_SCROLL_PAGE_BACKWARD: + if (clist->focus_row <= 0) + return; + gtk_clist_draw_focus (widget); + clist->focus_row = MAX (0, clist->focus_row - + (2 * clist->clist_window_height - + clist->row_height - CELL_SPACING) / + (2 * (clist->row_height + CELL_SPACING))); + gtk_clist_draw_focus (widget); + break; + case GTK_SCROLL_PAGE_FORWARD: + if (clist->focus_row >= clist->rows - 1) + return; + gtk_clist_draw_focus (widget); + clist->focus_row = MIN (clist->rows - 1, clist->focus_row + + (2 * clist->clist_window_height - + clist->row_height - CELL_SPACING) / + (2 * (clist->row_height + CELL_SPACING))); + gtk_clist_draw_focus (widget); + break; + case GTK_SCROLL_JUMP: + if (position >= 0 && position <= 1) { - gboolean tf = FALSE; + gtk_clist_draw_focus (widget); + clist->focus_row = position * (clist->rows - 1); + gtk_clist_draw_focus (widget); + } + break; + default: + break; + } +} - if (((focus_child && direction == GTK_DIR_DOWN) || - !(tf = title_focus (clist, GTK_DIR_TAB_FORWARD))) - && clist->rows) - { - if (clist->focus_row < 0) - { - clist->focus_row = 0; +static void +scroll_horizontal (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position) +{ + gint column = 0; + gint last_column; - if ((clist->selection_mode == GTK_SELECTION_BROWSE || - clist->selection_mode == GTK_SELECTION_EXTENDED) && - !clist->selection) - select_row (clist, clist->focus_row, -1, NULL); - } - gtk_widget_grab_focus (GTK_WIDGET (container)); - return TRUE; - } + g_return_if_fail (clist != 0); + g_return_if_fail (GTK_IS_CLIST (clist)); - if (tf) - return TRUE; - } - - GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS); + if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) + return; - if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child || - (focus_child != clist->vscrollbar && - focus_child != clist->hscrollbar)) && - GTK_WIDGET_VISIBLE (clist->vscrollbar) && - GTK_WIDGET_CAN_FOCUS (clist->vscrollbar)) - { - gtk_widget_grab_focus (clist->vscrollbar); - return TRUE; - } + for (last_column = clist->columns - 1; + last_column >= 0 && !clist->column[last_column].visible; last_column--) + ; - if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child || - focus_child != clist->hscrollbar) && - GTK_WIDGET_VISIBLE (clist->hscrollbar) && - GTK_WIDGET_CAN_FOCUS (clist->hscrollbar)) - { - gtk_widget_grab_focus (clist->hscrollbar); - return TRUE; - } + switch (scroll_type) + { + case GTK_SCROLL_STEP_BACKWARD: + column = COLUMN_FROM_XPIXEL (clist, 0); + if (COLUMN_LEFT_XPIXEL (clist, column) - CELL_SPACING - COLUMN_INSET >= 0 + && column > 0) + column--; break; - case GTK_DIR_UP: - case GTK_DIR_TAB_BACKWARD: - if (!focus_child && GTK_CLIST_CHILD_HAS_FOCUS (clist) && - GTK_WIDGET_VISIBLE (clist->hscrollbar) && - GTK_WIDGET_CAN_FOCUS (clist->hscrollbar)) + case GTK_SCROLL_STEP_FORWARD: + column = COLUMN_FROM_XPIXEL (clist, clist->clist_window_width); + if (column < 0) + return; + if (COLUMN_LEFT_XPIXEL (clist, column) + + clist->column[column].area.width + + CELL_SPACING + COLUMN_INSET - 1 <= clist->clist_window_width && + column < last_column) + column++; + break; + case GTK_SCROLL_PAGE_BACKWARD: + case GTK_SCROLL_PAGE_FORWARD: + return; + case GTK_SCROLL_JUMP: + if (position >= 0 && position <= 1) { - gtk_widget_grab_focus (clist->hscrollbar); - return TRUE; + gint vis_columns = 0; + gint i; + + for (i = 0; i <= last_column; i++) + if (clist->column[i].visible) + vis_columns++; + + column = position * vis_columns; + + for (i = 0; i <= last_column && column > 0; i++) + if (clist->column[i].visible) + column--; + + column = i; } - - if ((!focus_child || focus_child == clist->hscrollbar) && - GTK_CLIST_CHILD_HAS_FOCUS (clist) && - GTK_WIDGET_VISIBLE (clist->vscrollbar) && - GTK_WIDGET_CAN_FOCUS (clist->vscrollbar)) + else + return; + break; + default: + break; + } + + if (COLUMN_LEFT_XPIXEL (clist, column) < CELL_SPACING + COLUMN_INSET) + gtk_clist_moveto (clist, -1, column, 0, 0); + else if (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET - 1 + + clist->column[column].area.width > clist->clist_window_width) + { + if (column == last_column) + gtk_clist_moveto (clist, -1, column, 0, 0); + else + gtk_clist_moveto (clist, -1, column, 0, 1); + } +} + +static void +scroll_vertical (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position) +{ + gint old_focus_row; + + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) + return; + + switch (clist->selection_mode) + { + case GTK_SELECTION_EXTENDED: + if (clist->anchor >= 0) + return; + case GTK_SELECTION_BROWSE: + + old_focus_row = clist->focus_row; + move_focus_row (clist, scroll_type, position); + + if (old_focus_row != clist->focus_row) { - gtk_widget_grab_focus (clist->vscrollbar); - return TRUE; + if (clist->selection_mode == GTK_SELECTION_BROWSE) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], + old_focus_row, -1, NULL); + else if (!GTK_CLIST_ADD_MODE(clist)) + { + gtk_clist_unselect_all (clist); + clist->undo_anchor = old_focus_row; + } } - if ((!focus_child || focus_child == clist->hscrollbar || - focus_child == clist->vscrollbar) && - GTK_CLIST_CHILD_HAS_FOCUS (clist) && clist->rows) + switch (gtk_clist_row_is_visible (clist, clist->focus_row)) { - if (clist->focus_row < 0) + case GTK_VISIBILITY_NONE: + if (old_focus_row != clist->focus_row && + !(clist->selection_mode == GTK_SELECTION_EXTENDED && + GTK_CLIST_ADD_MODE(clist))) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + clist->focus_row, -1, NULL); + switch (scroll_type) { - clist->focus_row = 0; - if ((clist->selection_mode == GTK_SELECTION_BROWSE || - clist->selection_mode == GTK_SELECTION_EXTENDED) && - !clist->selection) - select_row (clist, clist->focus_row, -1, NULL); + case GTK_SCROLL_STEP_BACKWARD: + case GTK_SCROLL_PAGE_BACKWARD: + gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + break; + case GTK_SCROLL_STEP_FORWARD: + case GTK_SCROLL_PAGE_FORWARD: + gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + break; + case GTK_SCROLL_JUMP: + gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0); + break; + default: + break; } - gtk_widget_grab_focus (GTK_WIDGET (container)); - return TRUE; + break; + case GTK_VISIBILITY_PARTIAL: + switch (scroll_type) + { + case GTK_SCROLL_STEP_BACKWARD: + case GTK_SCROLL_PAGE_BACKWARD: + gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + break; + case GTK_SCROLL_STEP_FORWARD: + case GTK_SCROLL_PAGE_FORWARD: + gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + break; + case GTK_SCROLL_JUMP: + gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0); + break; + default: + break; + } + default: + if (old_focus_row != clist->focus_row && + !(clist->selection_mode == GTK_SELECTION_EXTENDED && + GTK_CLIST_ADD_MODE(clist))) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + clist->focus_row, -1, NULL); + break; } + break; + default: + move_focus_row (clist, scroll_type, position); + + if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height > + clist->clist_window_height) + gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0) + gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + break; + } +} + +static void +move_horizontal (GtkCList *clist, + gint diff) +{ + gfloat value; - GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS); + if (!clist->hadjustment) + return; - if (title_focus (clist, direction)) - return TRUE; + value = CLAMP (clist->hadjustment->value + diff, 0.0, + clist->hadjustment->upper - clist->hadjustment->page_size); + gtk_adjustment_set_value(clist->hadjustment, value); +} - break; +static void +move_vertical (GtkCList *clist, + gint row, + gfloat align) +{ + gfloat value; - default: - break; - } + if (!clist->vadjustment) + return; - gtk_container_set_focus_child (container, NULL); - return FALSE; + value = (ROW_TOP_YPIXEL (clist, row) - clist->voffset - + align * (clist->clist_window_height - clist->row_height) + + (2 * align - 1) * CELL_SPACING); + + if (value + clist->vadjustment->page_size > clist->vadjustment->upper) + value = clist->vadjustment->upper - clist->vadjustment->page_size; + + gtk_adjustment_set_value(clist->vadjustment, value); } -void -gtk_clist_unselect_all (GtkCList * clist) +static gint +horizontal_timeout (GtkCList *clist) { - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + GdkEventMotion event = { 0 }; - GTK_CLIST_CLASS_FW (clist)->unselect_all (clist); + GDK_THREADS_ENTER (); + + clist->htimer = 0; + + event.type = GDK_MOTION_NOTIFY; + event.send_event = TRUE; + + gtk_clist_motion (GTK_WIDGET (clist), &event); + + GDK_THREADS_LEAVE (); + + return FALSE; } -static void -real_unselect_all (GtkCList * clist) +static gint +vertical_timeout (GtkCList *clist) { - GList *list; - gint i; - - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + GdkEventMotion event = { 0 }; - if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) - return; + GDK_THREADS_ENTER (); - switch (clist->selection_mode) - { - case GTK_SELECTION_BROWSE: - if (clist->focus_row >= 0) - { - select_row (clist, clist->focus_row, -1, NULL); - return; - } - break; + clist->vtimer = 0; - case GTK_SELECTION_EXTENDED: - g_list_free (clist->undo_selection); - g_list_free (clist->undo_unselection); - clist->undo_selection = NULL; - clist->undo_unselection = NULL; + event.type = GDK_MOTION_NOTIFY; + event.send_event = TRUE; - clist->anchor = -1; - clist->drag_pos = -1; - clist->undo_anchor = clist->focus_row; - break; + gtk_clist_motion (GTK_WIDGET (clist), &event); - default: - break; + GDK_THREADS_LEAVE (); + + return FALSE; +} + +static void +remove_grab (GtkCList *clist) +{ + if (GTK_WIDGET_HAS_GRAB (clist)) + { + gtk_grab_remove (GTK_WIDGET (clist)); + if (gdk_pointer_is_grabbed ()) + gdk_pointer_ungrab (GDK_CURRENT_TIME); } - list = clist->selection; + if (clist->htimer) + { + gtk_timeout_remove (clist->htimer); + clist->htimer = 0; + } - while (list) + if (clist->vtimer) { - i = GPOINTER_TO_INT (list->data); - list = list->next; - unselect_row (clist, i, -1, NULL); + gtk_timeout_remove (clist->vtimer); + clist->vtimer = 0; } } +/* PUBLIC SORTING FUNCTIONS + * gtk_clist_sort + * gtk_clist_set_compare_func + * gtk_clist_set_auto_sort + * gtk_clist_set_sort_type + * gtk_clist_set_sort_column + */ void -gtk_clist_select_all (GtkCList * clist) +gtk_clist_sort (GtkCList *clist) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - GTK_CLIST_CLASS_FW (clist)->select_all (clist); + GTK_CLIST_CLASS_FW (clist)->sort_list (clist); } -static void -real_select_all (GtkCList * clist) +void +gtk_clist_set_compare_func (GtkCList *clist, + GtkCListCompareFunc cmp_func) { - GList *list; - gint i; - g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) - return; - - switch (clist->selection_mode) - { - case GTK_SELECTION_SINGLE: - case GTK_SELECTION_BROWSE: - return; - - case GTK_SELECTION_EXTENDED: - g_list_free (clist->undo_selection); - g_list_free (clist->undo_unselection); - clist->undo_selection = NULL; - clist->undo_unselection = NULL; - - if (clist->rows && - ((GtkCListRow *) (clist->row_list->data))->state != - GTK_STATE_SELECTED) - fake_toggle_row (clist, 0); - - clist->anchor_state = GTK_STATE_SELECTED; - clist->anchor = 0; - clist->drag_pos = 0; - clist->undo_anchor = clist->focus_row; - update_extended_selection (clist, clist->rows); - GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); - return; - - case GTK_SELECTION_MULTIPLE: - for (i = 0, list = clist->row_list; list; i++, list = list->next) - { - if (((GtkCListRow *)(list->data))->state == GTK_STATE_NORMAL) - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], - i, -1, NULL); - } - return; - } + clist->compare = (cmp_func) ? cmp_func : default_compare; } -static void -fake_unselect_all (GtkCList * clist, - gint row) +void +gtk_clist_set_auto_sort (GtkCList *clist, + gboolean auto_sort) { - GList *list; - GList *work; - gint i; - - if (row >= 0 && (work = g_list_nth (clist->row_list, row))) - { - if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL && - GTK_CLIST_ROW (work)->selectable) - { - GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED; - - if (!GTK_CLIST_FROZEN (clist) && - gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, - GTK_CLIST_ROW (work)); - } - } - - clist->undo_selection = clist->selection; - clist->selection = NULL; - clist->selection_end = NULL; + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - for (list = clist->undo_selection; list; list = list->next) + if (GTK_CLIST_AUTO_SORT(clist) && !auto_sort) + GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_SORT); + else if (!GTK_CLIST_AUTO_SORT(clist) && auto_sort) { - if ((i = GPOINTER_TO_INT (list->data)) == row || - !(work = g_list_nth (clist->row_list, i))) - continue; - - GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL; - if (!GTK_CLIST_FROZEN (clist) && - gtk_clist_row_is_visible (clist, i) != GTK_VISIBILITY_NONE) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, i, - GTK_CLIST_ROW (work)); + GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_SORT); + gtk_clist_sort (clist); } } -static void -fake_toggle_row (GtkCList *clist, - gint row) +void +gtk_clist_set_sort_type (GtkCList *clist, + GtkSortType sort_type) { - GList *work; - - if (!(work = g_list_nth (clist->row_list, row))|| - !GTK_CLIST_ROW (work)->selectable) - return; - - if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL) - clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED; - else - clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL; + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - if (!GTK_CLIST_FROZEN (clist) && - gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, - GTK_CLIST_ROW (work)); + clist->sort_type = sort_type; } -static GList * -selection_find (GtkCList *clist, - gint row_number, - GList *row_list_element) +void +gtk_clist_set_sort_column (GtkCList *clist, + gint column) { - return g_list_find (clist->selection, GINT_TO_POINTER (row_number)); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (column < 0 || column >= clist->columns) + return; + + clist->sort_column = column; } +/* PRIVATE SORTING FUNCTIONS + * default_compare + * real_sort_list + * gtk_clist_merge + * gtk_clist_mergesort + */ static gint -default_compare (GtkCList *clist, - gconstpointer ptr1, - gconstpointer ptr2) +default_compare (GtkCList *clist, + gconstpointer ptr1, + gconstpointer ptr2) { char *text1 = NULL; char *text2 = NULL; @@ -6350,53 +7286,50 @@ default_compare (GtkCList *clist, return strcmp (text1, text2); } -void -gtk_clist_set_compare_func (GtkCList *clist, - GtkCListCompareFunc cmp_func) +static void +real_sort_list (GtkCList *clist) { + GList *list; + GList *work; + gint i; + g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - clist->compare = (cmp_func) ? cmp_func : default_compare; -} + if (clist->rows <= 1) + return; -void -gtk_clist_set_auto_sort (GtkCList *clist, - gboolean auto_sort) -{ - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - if (GTK_CLIST_AUTO_SORT (clist) && !auto_sort) - GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_SORT); - else if (!GTK_CLIST_AUTO_SORT (clist) && auto_sort) + if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) + return; + + gtk_clist_freeze (clist); + + if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED) { - GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_SORT); - gtk_clist_sort (clist); + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; } -} - -void -gtk_clist_set_sort_type (GtkCList *clist, - GtkSortType sort_type) -{ - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - clist->sort_type = sort_type; -} + + clist->row_list = gtk_clist_mergesort (clist, clist->row_list, clist->rows); -void -gtk_clist_set_sort_column (GtkCList *clist, - gint column) -{ - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + work = clist->selection; - if (column < 0 || column >= clist->columns) - return; + for (i = 0, list = clist->row_list; i < clist->rows; i++, list = list->next) + { + if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED) + { + work->data = GINT_TO_POINTER (i); + work = work->next; + } + + if (i == clist->rows - 1) + clist->row_list_end = list; + } - clist->sort_column = column; + gtk_clist_thaw (clist); } static GList * @@ -6483,63 +7416,479 @@ gtk_clist_mergesort (GtkCList *clist, } } -void -gtk_clist_sort (GtkCList *clist) +/************************/ + +static void +drag_source_info_destroy (gpointer data) { - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + GtkCListCellInfo *info = data; - GTK_CLIST_CLASS_FW (clist)->sort_list (clist); + g_free (info); } static void -real_sort_list (GtkCList *clist) +drag_dest_info_destroy (gpointer data) { - GList *list; - GList *work; - gint i; - gboolean thaw = FALSE; + GtkCListDestInfo *info = data; + + g_free (info); +} + +static void +drag_dest_cell (GtkCList *clist, + gint x, + gint y, + GtkCListDestInfo *dest_info) +{ + GtkWidget *widget; + + widget = GTK_WIDGET (clist); + + dest_info->insert_pos = GTK_CLIST_DRAG_NONE; + + y -= (GTK_CONTAINER (clist)->border_width + + widget->style->klass->ythickness + + clist->column_title_area.height); + + dest_info->cell.row = ROW_FROM_YPIXEL (clist, y); + if (dest_info->cell.row >= clist->rows) + { + dest_info->cell.row = clist->rows - 1; + y = ROW_TOP_YPIXEL (clist, dest_info->cell.row) + clist->row_height; + } + if (dest_info->cell.row < -1) + dest_info->cell.row = -1; + + x -= GTK_CONTAINER (widget)->border_width + widget->style->klass->xthickness; + dest_info->cell.column = COLUMN_FROM_XPIXEL (clist, x); + + if (dest_info->cell.row >= 0) + { + gint y_delta; + gint h = 0; + + y_delta = y - ROW_TOP_YPIXEL (clist, dest_info->cell.row); + + if (GTK_CLIST_DRAW_DRAG_RECT(clist)) + { + dest_info->insert_pos = GTK_CLIST_DRAG_INTO; + h = clist->row_height / 4; + } + else if (GTK_CLIST_DRAW_DRAG_LINE(clist)) + { + dest_info->insert_pos = GTK_CLIST_DRAG_BEFORE; + h = clist->row_height / 2; + } + + if (GTK_CLIST_DRAW_DRAG_LINE(clist)) + { + if (y_delta < h) + dest_info->insert_pos = GTK_CLIST_DRAG_BEFORE; + else if (clist->row_height - y_delta < h) + dest_info->insert_pos = GTK_CLIST_DRAG_AFTER; + } + } +} + +static void +gtk_clist_drag_begin (GtkWidget *widget, + GdkDragContext *context) +{ + GtkCList *clist; + GtkCListCellInfo *info; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); + g_return_if_fail (context != NULL); + + clist = GTK_CLIST (widget); + + clist->drag_button = 0; + remove_grab (clist); + + switch (clist->selection_mode) + { + case GTK_SELECTION_EXTENDED: + update_extended_selection (clist, clist->focus_row); + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); + break; + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_MULTIPLE: + clist->anchor = -1; + case GTK_SELECTION_BROWSE: + break; + } + + info = g_dataset_get_data (context, "gtk-clist-drag-source"); + + if (!info) + { + info = g_new (GtkCListCellInfo, 1); + + if (clist->click_cell.row < 0) + clist->click_cell.row = 0; + else if (clist->click_cell.row >= clist->rows) + clist->click_cell.row = clist->rows - 1; + info->row = clist->click_cell.row; + info->column = clist->click_cell.column; + + g_dataset_set_data_full (context, "gtk-clist-drag-source", info, + drag_source_info_destroy); + } + + if (GTK_CLIST_USE_DRAG_ICONS (clist)) + gtk_drag_set_icon_default (context); +} + +static void +gtk_clist_drag_end (GtkWidget *widget, + GdkDragContext *context) +{ + GtkCList *clist; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); + g_return_if_fail (context != NULL); + + clist = GTK_CLIST (widget); + + clist->click_cell.row = -1; + clist->click_cell.column = -1; +} + +static void +gtk_clist_drag_leave (GtkWidget *widget, + GdkDragContext *context, + guint time) +{ + GtkCList *clist; + GtkCListDestInfo *dest_info; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); + g_return_if_fail (context != NULL); + + clist = GTK_CLIST (widget); + + dest_info = g_dataset_get_data (context, "gtk-clist-drag-dest"); + + if (dest_info) + { + if (dest_info->cell.row >= 0 && + GTK_CLIST_REORDERABLE(clist) && + gtk_drag_get_source_widget (context) == widget) + { + GList *list; + GdkAtom atom = gdk_atom_intern ("gtk-clist-drag-reorder", FALSE); + + list = context->targets; + while (list) + { + if (atom == GPOINTER_TO_INT (list->data)) + { + GTK_CLIST_CLASS_FW (clist)->draw_drag_highlight + (clist, + g_list_nth (clist->row_list, dest_info->cell.row)->data, + dest_info->cell.row, dest_info->insert_pos); + break; + } + list = list->next; + } + } + g_dataset_remove_data (context, "gtk-clist-drag-dest"); + } +} + +static gint +gtk_clist_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time) +{ + GtkCList *clist; + GtkCListDestInfo new_info; + GtkCListDestInfo *dest_info; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE); + + clist = GTK_CLIST (widget); + + dest_info = g_dataset_get_data (context, "gtk-clist-drag-dest"); + + if (!dest_info) + { + dest_info = g_new (GtkCListDestInfo, 1); + + dest_info->insert_pos = GTK_CLIST_DRAG_NONE; + dest_info->cell.row = -1; + dest_info->cell.column = -1; + + g_dataset_set_data_full (context, "gtk-clist-drag-dest", dest_info, + drag_dest_info_destroy); + } + + drag_dest_cell (clist, x, y, &new_info); + + if (GTK_CLIST_REORDERABLE (clist)) + { + GList *list; + GdkAtom atom = gdk_atom_intern ("gtk-clist-drag-reorder", FALSE); + + list = context->targets; + while (list) + { + if (atom == GPOINTER_TO_INT (list->data)) + break; + list = list->next; + } + + if (list) + { + if (gtk_drag_get_source_widget (context) != widget || + new_info.insert_pos == GTK_CLIST_DRAG_NONE || + new_info.cell.row == clist->click_cell.row || + (new_info.cell.row == clist->click_cell.row - 1 && + new_info.insert_pos == GTK_CLIST_DRAG_AFTER) || + (new_info.cell.row == clist->click_cell.row + 1 && + new_info.insert_pos == GTK_CLIST_DRAG_BEFORE)) + { + if (dest_info->cell.row < 0) + { + gdk_drag_status (context, GDK_ACTION_DEFAULT, time); + return FALSE; + } + return TRUE; + } + + if (new_info.cell.row != dest_info->cell.row || + (new_info.cell.row == dest_info->cell.row && + dest_info->insert_pos != new_info.insert_pos)) + { + if (dest_info->cell.row >= 0) + GTK_CLIST_CLASS_FW (clist)->draw_drag_highlight + (clist, g_list_nth (clist->row_list, + dest_info->cell.row)->data, + dest_info->cell.row, dest_info->insert_pos); + + dest_info->insert_pos = new_info.insert_pos; + dest_info->cell.row = new_info.cell.row; + dest_info->cell.column = new_info.cell.column; + + GTK_CLIST_CLASS_FW (clist)->draw_drag_highlight + (clist, g_list_nth (clist->row_list, + dest_info->cell.row)->data, + dest_info->cell.row, dest_info->insert_pos); + + gdk_drag_status (context, context->suggested_action, time); + } + return TRUE; + } + } + + dest_info->insert_pos = new_info.insert_pos; + dest_info->cell.row = new_info.cell.row; + dest_info->cell.column = new_info.cell.column; + return TRUE; +} + +static gboolean +gtk_clist_drag_drop (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE); + g_return_val_if_fail (context != NULL, FALSE); + + if (GTK_CLIST_REORDERABLE (widget) && + gtk_drag_get_source_widget (context) == widget) + { + GList *list; + GdkAtom atom = gdk_atom_intern ("gtk-clist-drag-reorder", FALSE); + + list = context->targets; + while (list) + { + if (atom == GPOINTER_TO_INT (list->data)) + return TRUE; + list = list->next; + } + } + return FALSE; +} + +static void +gtk_clist_drag_data_received (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time) +{ + GtkCList *clist; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); + g_return_if_fail (context != NULL); + g_return_if_fail (selection_data != NULL); + + clist = GTK_CLIST (widget); + + if (GTK_CLIST_REORDERABLE (clist) && + gtk_drag_get_source_widget (context) == widget && + selection_data->target == + gdk_atom_intern ("gtk-clist-drag-reorder", FALSE) && + selection_data->format == GTK_TYPE_POINTER && + selection_data->length == sizeof (GtkCListCellInfo)) + { + GtkCListCellInfo *source_info; + + source_info = (GtkCListCellInfo *)(selection_data->data); + if (source_info) + { + GtkCListDestInfo dest_info; + + drag_dest_cell (clist, x, y, &dest_info); + + if (dest_info.insert_pos == GTK_CLIST_DRAG_AFTER) + dest_info.cell.row++; + if (source_info->row < dest_info.cell.row) + dest_info.cell.row--; + if (dest_info.cell.row != source_info->row) + gtk_clist_row_move (clist, source_info->row, dest_info.cell.row); + + g_dataset_remove_data (context, "gtk-clist-drag-dest"); + } + } +} + +static void +gtk_clist_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); + g_return_if_fail (context != NULL); + g_return_if_fail (selection_data != NULL); + + if (selection_data->target == + gdk_atom_intern ("gtk-clist-drag-reorder", FALSE)) + { + GtkCListCellInfo *info; + + info = g_dataset_get_data (context, "gtk-clist-drag-source"); + + if (info) + { + GtkCListCellInfo ret_info; + + ret_info.row = info->row; + ret_info.column = info->column; + + gtk_selection_data_set (selection_data, selection_data->target, + GTK_TYPE_POINTER, (guchar *) &ret_info, + sizeof (GtkCListCellInfo)); + } + else + gtk_selection_data_set (selection_data, selection_data->target, + GTK_TYPE_POINTER, NULL, 0); + } +} + +static void +draw_drag_highlight (GtkCList *clist, + GtkCListRow *dest_row, + gint dest_row_number, + GtkCListDragPos drag_pos) +{ + gint y; + + y = ROW_TOP_YPIXEL (clist, dest_row_number) - 1; + + switch (drag_pos) + { + case GTK_CLIST_DRAG_NONE: + break; + case GTK_CLIST_DRAG_AFTER: + y += clist->row_height + 1; + case GTK_CLIST_DRAG_BEFORE: + gdk_draw_line (clist->clist_window, clist->xor_gc, + 0, y, clist->clist_window_width, y); + break; + case GTK_CLIST_DRAG_INTO: + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y, + clist->clist_window_width - 1, clist->row_height); + break; + } +} + +void +gtk_clist_set_reorderable (GtkCList *clist, + gboolean reorderable) +{ + GtkWidget *widget; g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (clist->rows <= 1) + if ((GTK_CLIST_REORDERABLE(clist) != 0) == reorderable) return; - if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) - return; + widget = GTK_WIDGET (clist); - if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED) + if (reorderable) { - GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); - g_list_free (clist->undo_selection); - g_list_free (clist->undo_unselection); - clist->undo_selection = NULL; - clist->undo_unselection = NULL; + GTK_CLIST_SET_FLAG (clist, CLIST_REORDERABLE); + gtk_drag_dest_set (widget, + GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, + &clist_target_table, 1, GDK_ACTION_MOVE); } - - if (!GTK_CLIST_FROZEN (clist)) + else { - gtk_clist_freeze (clist); - thaw = TRUE; + GTK_CLIST_UNSET_FLAG (clist, CLIST_REORDERABLE); + gtk_drag_dest_unset (GTK_WIDGET (clist)); } +} - clist->row_list = gtk_clist_mergesort (clist, clist->row_list, clist->rows); +void +gtk_clist_set_use_drag_icons (GtkCList *clist, + gboolean use_icons) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - work = clist->selection; + if (use_icons != 0) + GTK_CLIST_SET_FLAG (clist, CLIST_USE_DRAG_ICONS); + else + GTK_CLIST_UNSET_FLAG (clist, CLIST_USE_DRAG_ICONS); +} - for (i = 0, list = clist->row_list; i < clist->rows; i++, list = list->next) +void +gtk_clist_set_button_actions (GtkCList *clist, + guint button, + guint8 button_actions) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (button < MAX_BUTTON) { - if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED) + if (gdk_pointer_is_grabbed () || GTK_WIDGET_HAS_GRAB (clist)) { - work->data = GINT_TO_POINTER (i); - work = work->next; + remove_grab (clist); + clist->drag_button = 0; } - - if (i == clist->rows - 1) - clist->row_list_end = list; - } - if (thaw) - gtk_clist_thaw (clist); + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); + + clist->button_actions[button] = button_actions; + } }