diff options
author | Lars Hamann <lars@src.gnome.org> | 1998-07-15 23:40:00 +0000 |
---|---|---|
committer | Lars Hamann <lars@src.gnome.org> | 1998-07-15 23:40:00 +0000 |
commit | 8b9b7b9d04c1f11118f28a9ec7b4c65a7a3f967c (patch) | |
tree | c85c8864d97e7306662c535a3680878f103376cc /gtk | |
parent | b6656088162e00c77f9d84f96e5721c0b84dd5ec (diff) | |
download | gtk+-8b9b7b9d04c1f11118f28a9ec7b4c65a7a3f967c.tar.gz |
Added focus handling, horizontal and vertical autoscrolling, extended
* gtk/gtkctree.h :
* gtk/gtkctree.c :
Added focus handling, horizontal and vertical autoscrolling,
extended Selection Mode, key bindings
Added gtk_ctree_toggle_expansion & gtk_ctree_toggle_expansion_recursive
Changed gtk_ctree_scroll_to to gtk_ctree_moveto.
Removed gtk_ctree_clear.
* gtk/gtkclist.h :
* gtk/gtkclist.c :
Added focus handling, horizontal and vertical autoscrolling,
extended Selection Mode, key bindings
Diffstat (limited to 'gtk')
-rw-r--r-- | gtk/gtkclist.c | 2833 | ||||
-rw-r--r-- | gtk/gtkclist.h | 91 | ||||
-rw-r--r-- | gtk/gtkctree.c | 1226 | ||||
-rw-r--r-- | gtk/gtkctree.h | 24 | ||||
-rw-r--r-- | gtk/testgtk.c | 239 |
5 files changed, 3681 insertions, 732 deletions
diff --git a/gtk/gtkclist.c b/gtk/gtkclist.c index 99674ee2c2..f8cbe3326d 100644 --- a/gtk/gtkclist.c +++ b/gtk/gtkclist.c @@ -18,8 +18,12 @@ * Boston, MA 02111-1307, USA. */ #include <stdlib.h> +#include <string.h> #include "../config.h" +#include "gtkmain.h" #include "gtkclist.h" +#include "gtkbindings.h" +#include <gdk/gdkkeysyms.h> /* the number rows memchunk expands at a time */ #define CLIST_OPTIMUM_SIZE 512 @@ -36,6 +40,9 @@ /* added the horizontal space at the beginning and end of a row*/ #define COLUMN_INSET 3 +/* 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) @@ -52,7 +59,7 @@ /* gives the left pixel of the given column in context of * the clist's hoffset */ -#define COLUMN_LEFT_XPIXEL(clist, column) ((clist)->column[(column)].area.x + \ +#define COLUMN_LEFT_XPIXEL(clist, colnum) ((clist)->column[(colnum)].area.x + \ (clist)->hoffset) /* returns the column index from a x pixel location in the @@ -82,7 +89,7 @@ COLUMN_FROM_XPIXEL (GtkCList * clist, /* returns the left pixel of the given column in the context of * the list width */ -#define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x) +#define COLUMN_LEFT(clist, colnum) ((clist)->column[(colnum)].area.x) /* returns the total height of the list */ #define LIST_HEIGHT(clist) (((clist)->row_height * ((clist)->rows)) + \ @@ -94,12 +101,26 @@ COLUMN_FROM_XPIXEL (GtkCList * clist, COLUMN_INSET + CELL_SPACING) +#define GTK_CLIST_CLASS_FW(_widget_) GTK_CLIST_CLASS (GTK_OBJECT (_widget_)->klass) + + /* Signals */ enum { SELECT_ROW, UNSELECT_ROW, CLICK_COLUMN, + TOGGLE_FOCUS_ROW, + SELECT_ALL, + UNSELECT_ALL, + UNDO_SELECTION, + START_SELECTION, + END_SELECTION, + TOGGLE_ADD_MODE, + EXTEND_SELECTION, + SCROLL_VERTICAL, + SCROLL_HORIZONTAL, + ABORT_COLUMN_RESIZE, LAST_SIGNAL }; @@ -113,12 +134,24 @@ enum typedef void (*GtkCListSignal1) (GtkObject * object, gint arg1, gint arg2, - GdkEventButton * arg3, + GdkEvent * arg3, gpointer data); -typedef void (*GtkCListSignal2) (GtkObject * object, +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, @@ -128,6 +161,7 @@ static void sync_selection (GtkCList * clist, /* GtkCList Methods */ static void gtk_clist_class_init (GtkCListClass * klass); static void gtk_clist_init (GtkCList * clist); +static void real_clear (GtkCList * clist); /* GtkObject Methods */ static void gtk_clist_destroy (GtkObject * object); @@ -149,7 +183,6 @@ 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, @@ -181,24 +214,42 @@ static void size_allocate_columns (GtkCList * clist); static void toggle_row (GtkCList * clist, gint row, gint column, - GdkEventButton * event); + GdkEvent * event); static void select_row (GtkCList * clist, gint row, gint column, - GdkEventButton * event); + GdkEvent * event); static void unselect_row (GtkCList * clist, gint row, gint column, - GdkEventButton * event); - + GdkEvent * event); static void real_select_row (GtkCList * clist, gint row, gint column, - GdkEventButton * event); + GdkEvent * event); static void real_unselect_row (GtkCList * clist, gint row, gint column, - GdkEventButton * event); + 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); /* Resize Columns */ static void draw_xor_line (GtkCList * clist); @@ -209,6 +260,7 @@ static gint new_column_width (GtkCList * clist, static void resize_column (GtkCList * clist, gint column, gint width); +static void abort_column_resize (GtkCList *clist); /* Buttons */ static void column_button_create (GtkCList * clist, @@ -229,7 +281,6 @@ static void hadjustment_changed (GtkAdjustment * adjustment, static void hadjustment_value_changed (GtkAdjustment * adjustment, gpointer data); - /* Memory Allocation/Distruction Routines */ static GtkCListColumn *columns_new (GtkCList * clist); @@ -262,6 +313,44 @@ static void cell_set_pixtext (GtkCList * clist, GdkPixmap * pixmap, GdkBitmap * mask); +/* 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); + + /* Signals */ static void gtk_clist_marshal_signal_1 (GtkObject * object, GtkSignalFunc func, @@ -271,6 +360,20 @@ static void gtk_clist_marshal_signal_2 (GtkObject * object, GtkSignalFunc func, gpointer func_data, GtkArg * args); +static void gtk_clist_marshal_signal_3 (GtkObject * object, + GtkSignalFunc func, + gpointer func_data, + GtkArg * args); +static void gtk_clist_marshal_signal_4 (GtkObject * object, + GtkSignalFunc func, + gpointer func_data, + GtkArg * args); +static void gtk_clist_marshal_signal_5 (GtkObject * object, + GtkSignalFunc func, + gpointer func_data, + GtkArg * args); + + /* Fill in data after widget is realized and has style */ @@ -295,8 +398,8 @@ gtk_clist_get_type (void) (GtkClassInitFunc) gtk_clist_class_init, (GtkObjectInitFunc) gtk_clist_init, /* reserved_1 */ NULL, - /* reserved_2 */ NULL, - (GtkClassInitFunc) NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, }; clist_type = gtk_type_unique (gtk_container_get_type (), &clist_info); @@ -337,9 +440,89 @@ gtk_clist_class_init (GtkCListClass * klass) GTK_RUN_FIRST, object_class->type, GTK_SIGNAL_OFFSET (GtkCListClass, click_column), - gtk_clist_marshal_signal_2, + gtk_clist_marshal_signal_3, GTK_TYPE_NONE, 1, GTK_TYPE_INT); + clist_signals[TOGGLE_FOCUS_ROW] = + gtk_signal_new ("toggle_focus_row", + GTK_RUN_LAST | GTK_RUN_ACTION, + object_class->type, + GTK_SIGNAL_OFFSET (GtkCListClass, toggle_focus_row), + gtk_clist_marshal_signal_2, + GTK_TYPE_NONE, 0); + clist_signals[SELECT_ALL] = + gtk_signal_new ("select_all", + GTK_RUN_LAST | GTK_RUN_ACTION, + object_class->type, + GTK_SIGNAL_OFFSET (GtkCListClass, select_all), + gtk_clist_marshal_signal_2, + GTK_TYPE_NONE, 0); + clist_signals[UNSELECT_ALL] = + gtk_signal_new ("unselect_all", + GTK_RUN_LAST | GTK_RUN_ACTION, + object_class->type, + GTK_SIGNAL_OFFSET (GtkCListClass, unselect_all), + gtk_clist_marshal_signal_2, + GTK_TYPE_NONE, 0); + clist_signals[UNDO_SELECTION] = + gtk_signal_new ("undo_selection", + GTK_RUN_LAST | GTK_RUN_ACTION, + object_class->type, + GTK_SIGNAL_OFFSET (GtkCListClass, undo_selection), + gtk_clist_marshal_signal_2, + GTK_TYPE_NONE, 0); + clist_signals[START_SELECTION] = + gtk_signal_new ("start_selection", + GTK_RUN_LAST | GTK_RUN_ACTION, + object_class->type, + GTK_SIGNAL_OFFSET (GtkCListClass, start_selection), + gtk_clist_marshal_signal_2, + GTK_TYPE_NONE, 0); + clist_signals[END_SELECTION] = + gtk_signal_new ("end_selection", + GTK_RUN_LAST | GTK_RUN_ACTION, + object_class->type, + GTK_SIGNAL_OFFSET (GtkCListClass, end_selection), + gtk_clist_marshal_signal_2, + GTK_TYPE_NONE, 0); + clist_signals[TOGGLE_ADD_MODE] = + gtk_signal_new ("toggle_add_mode", + GTK_RUN_LAST | GTK_RUN_ACTION, + object_class->type, + GTK_SIGNAL_OFFSET (GtkCListClass, toggle_add_mode), + gtk_clist_marshal_signal_2, + GTK_TYPE_NONE, 0); + clist_signals[EXTEND_SELECTION] = + gtk_signal_new ("extend_selection", + GTK_RUN_LAST | GTK_RUN_ACTION, + object_class->type, + GTK_SIGNAL_OFFSET (GtkCListClass, extend_selection), + gtk_clist_marshal_signal_5, + GTK_TYPE_NONE, 3, + GTK_TYPE_ENUM, GTK_TYPE_FLOAT, GTK_TYPE_BOOL); + clist_signals[SCROLL_VERTICAL] = + gtk_signal_new ("scroll_vertical", + GTK_RUN_LAST | GTK_RUN_ACTION, + object_class->type, + GTK_SIGNAL_OFFSET (GtkCListClass, scroll_vertical), + gtk_clist_marshal_signal_4, + GTK_TYPE_NONE, 2, GTK_TYPE_ENUM, GTK_TYPE_FLOAT); + clist_signals[SCROLL_HORIZONTAL] = + gtk_signal_new ("scroll_horizontal", + GTK_RUN_LAST | GTK_RUN_ACTION, + object_class->type, + GTK_SIGNAL_OFFSET (GtkCListClass, scroll_horizontal), + gtk_clist_marshal_signal_4, + GTK_TYPE_NONE, 2, GTK_TYPE_ENUM, GTK_TYPE_FLOAT); + clist_signals[ABORT_COLUMN_RESIZE] = + gtk_signal_new ("abort_column_resize", + GTK_RUN_LAST | GTK_RUN_ACTION, + object_class->type, + GTK_SIGNAL_OFFSET (GtkCListClass, abort_column_resize), + gtk_clist_marshal_signal_2, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, clist_signals, LAST_SIGNAL); object_class->destroy = gtk_clist_destroy; @@ -356,18 +539,230 @@ gtk_clist_class_init (GtkCListClass * klass) widget_class->expose_event = gtk_clist_expose; widget_class->size_request = gtk_clist_size_request; widget_class->size_allocate = gtk_clist_size_allocate; + widget_class->key_press_event = gtk_clist_key_press; + 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; /* container_class->add = NULL; use the default GtkContainerClass warning */ /* container_class->remove = NULL; use the default GtkContainerClass warning */ container_class->foreach = gtk_clist_foreach; + container_class->focus = gtk_clist_focus; + container_class->set_focus_child = gtk_clist_set_focus_child; klass->select_row = real_select_row; klass->unselect_row = real_unselect_row; + klass->undo_selection = real_undo_selection; + klass->resync_selection = resync_selection; + klass->selection_find = selection_find; klass->click_column = NULL; - klass->draw_row = draw_row; + klass->clear = real_clear; + klass->select_all = real_select_all; + klass->unselect_all = real_unselect_all; + klass->fake_unselect_all = fake_unselect_all; + klass->scroll_horizontal = scroll_horizontal; + klass->scroll_vertical = scroll_vertical; + klass->extend_selection = extend_selection; + klass->toggle_focus_row = toggle_focus_row; + klass->toggle_add_mode = toggle_add_mode; + klass->start_selection = start_selection; + klass->end_selection = end_selection; + klass->abort_column_resize = abort_column_resize; klass->scrollbar_spacing = 5; + + { + 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); + } + + /* + { + 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); + } + */ } static void @@ -396,8 +791,48 @@ gtk_clist_marshal_signal_2 (GtkObject * object, rfunc = (GtkCListSignal2) func; + (*rfunc) (object, func_data); +} + +static void +gtk_clist_marshal_signal_3 (GtkObject * object, + GtkSignalFunc func, + gpointer func_data, + GtkArg * args) +{ + GtkCListSignal3 rfunc; + + rfunc = (GtkCListSignal3) func; + + (*rfunc) (object, GTK_VALUE_INT (args[0]), func_data); +} + +static void +gtk_clist_marshal_signal_4 (GtkObject * object, + GtkSignalFunc func, + gpointer func_data, + GtkArg * args) +{ + GtkCListSignal4 rfunc; + + rfunc = (GtkCListSignal4) func; + (*rfunc) (object, GTK_VALUE_INT (args[0]), - func_data); + GTK_VALUE_FLOAT (args[1]), func_data); +} + +static void +gtk_clist_marshal_signal_5 (GtkObject * object, + GtkSignalFunc func, + gpointer func_data, + GtkArg * args) +{ + GtkCListSignal5 rfunc; + + rfunc = (GtkCListSignal5) func; + + (*rfunc) (object, GTK_VALUE_INT (args[0]), GTK_VALUE_FLOAT (args[1]), + GTK_VALUE_BOOL (args[2]), func_data); } static void @@ -444,6 +879,20 @@ gtk_clist_init (GtkCList * clist) clist->selection_mode = GTK_SELECTION_SINGLE; clist->selection = NULL; + clist->selection_end = NULL; + 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; + + clist->anchor = -1; + clist->anchor_state = GTK_STATE_SELECTED; + clist->drag_pos = -1; + clist->htimer = 0; + clist->vtimer = 0; } /* Constructors */ @@ -537,6 +986,7 @@ gtk_clist_set_border (GtkCList * clist, GtkShadowType border) { g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); clist->shadow_type = border; @@ -549,14 +999,39 @@ gtk_clist_set_selection_mode (GtkCList * clist, GtkSelectionMode mode) { g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (mode == clist->selection_mode) + return; clist->selection_mode = mode; + clist->anchor = -1; + clist->anchor_state = GTK_STATE_SELECTED; + clist->drag_pos = -1; + clist->undo_anchor = clist->focus_row; + + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + + switch (mode) + { + case GTK_SELECTION_MULTIPLE: + case GTK_SELECTION_EXTENDED: + return; + case GTK_SELECTION_BROWSE: + case GTK_SELECTION_SINGLE: + gtk_clist_unselect_all (clist); + break; + } } void 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); } @@ -565,6 +1040,7 @@ void 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); @@ -576,6 +1052,7 @@ void 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)) { @@ -590,6 +1067,7 @@ void 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)) { @@ -605,6 +1083,7 @@ 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; @@ -623,6 +1102,7 @@ gtk_clist_column_title_passive (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; @@ -642,6 +1122,7 @@ 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) @@ -654,6 +1135,7 @@ 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) @@ -671,6 +1153,7 @@ gtk_clist_set_column_title (GtkCList * clist, GtkWidget *label; g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); if (column < 0 || column >= clist->columns) return; @@ -731,6 +1214,7 @@ gtk_clist_set_column_widget (GtkCList * clist, GtkWidget *old_widget; g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); if (column < 0 || column >= clist->columns) return; @@ -771,6 +1255,7 @@ gtk_clist_set_column_justification (GtkCList * clist, GtkWidget *alignment; g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); if (column < 0 || column >= clist->columns) return; @@ -816,6 +1301,7 @@ gtk_clist_set_column_width (GtkCList * clist, gint width) { g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); if (column < 0 || column >= clist->columns) return; @@ -844,6 +1330,7 @@ gtk_clist_set_row_height (GtkCList * clist, gint text_height; g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); if (height > 0) clist->row_height = height; @@ -873,51 +1360,40 @@ gtk_clist_moveto (GtkCList * clist, gfloat row_align, gfloat col_align) { - gint x, y; - 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; - /* adjust vertical scrollbar */ - if (row >= 0) - { - x = ROW_TOP (clist, row) - (row_align * (clist->clist_window_height - - (clist->row_height + 2 * CELL_SPACING))); - - if (x < 0) - GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0; - else if (x > LIST_HEIGHT (clist) - clist->clist_window_height) - GTK_RANGE (clist->vscrollbar)->adjustment->value = LIST_HEIGHT (clist) - - clist->clist_window_height; - else - GTK_RANGE (clist->vscrollbar)->adjustment->value = x; - - gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), - "value_changed"); - } - + row_align = CLAMP (row_align, 0, 1); + col_align = CLAMP (col_align, 0, 1); + /* adjust horizontal scrollbar */ if (column >= 0) { - y = COLUMN_LEFT (clist, column) - (col_align * (clist->clist_window_width - - clist->column[column].area.width + - 2 * (CELL_SPACING + COLUMN_INSET))); - - if (y < 0) - GTK_RANGE (clist->hscrollbar)->adjustment->value = 0.0; - else if (y > LIST_WIDTH (clist) - clist->clist_window_width) - GTK_RANGE (clist->hscrollbar)->adjustment->value = LIST_WIDTH (clist) - - clist->clist_window_width; + GtkAdjustment *adj; + gint x; + + 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_RANGE (clist->hscrollbar)->adjustment->value = y; - - gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), - "value_changed"); + gtk_adjustment_set_value (adj, x); } + + /* adjust vertical scrollbar */ + if (row >= 0) + move_vertical (clist, row, row_align); } GtkCellType @@ -928,6 +1404,7 @@ gtk_clist_get_cell_type (GtkCList * clist, GtkCListRow *clist_row; g_return_val_if_fail (clist != NULL, -1); + g_return_val_if_fail (GTK_IS_CLIST (clist), -1); if (row < 0 || row >= clist->rows) return -1; @@ -948,6 +1425,7 @@ gtk_clist_set_text (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) return; @@ -966,8 +1444,7 @@ gtk_clist_set_text (GtkCList * clist, if (!GTK_CLIST_FROZEN (clist)) { if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) - (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row) - (clist, NULL, row, clist_row); + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); } } @@ -980,6 +1457,7 @@ gtk_clist_get_text (GtkCList * clist, 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; @@ -1007,6 +1485,7 @@ gtk_clist_set_pixmap (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) return; @@ -1025,8 +1504,7 @@ gtk_clist_set_pixmap (GtkCList * clist, if (!GTK_CLIST_FROZEN (clist)) { if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) - (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row) - (clist, NULL, row, clist_row); + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); } } @@ -1040,6 +1518,7 @@ gtk_clist_get_pixmap (GtkCList * clist, 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; @@ -1073,6 +1552,7 @@ gtk_clist_set_pixtext (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) return; @@ -1089,8 +1569,7 @@ gtk_clist_set_pixtext (GtkCList * clist, if (!GTK_CLIST_FROZEN (clist)) { if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) - (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row) - (clist, NULL, row, clist_row); + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); } } @@ -1106,6 +1585,7 @@ gtk_clist_get_pixtext (GtkCList * clist, 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; @@ -1138,6 +1618,7 @@ gtk_clist_set_foreground (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) return; @@ -1154,8 +1635,7 @@ gtk_clist_set_foreground (GtkCList * clist, if (!GTK_CLIST_FROZEN (clist) && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) - (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row) - (clist, NULL, row, clist_row); + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); } void @@ -1166,6 +1646,7 @@ gtk_clist_set_background (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) return; @@ -1182,8 +1663,7 @@ gtk_clist_set_background (GtkCList * clist, if (!GTK_CLIST_FROZEN (clist) && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) - (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row) - (clist, NULL, row, clist_row); + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); } void @@ -1196,6 +1676,7 @@ gtk_clist_set_shift (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) return; @@ -1209,8 +1690,7 @@ gtk_clist_set_shift (GtkCList * clist, if (!GTK_CLIST_FROZEN (clist) && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) - (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row) - (clist, NULL, row, clist_row); + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); } gint @@ -1221,6 +1701,7 @@ gtk_clist_append (GtkCList * clist, GtkCListRow *clist_row; g_return_val_if_fail (clist != NULL, -1); + g_return_val_if_fail (GTK_IS_CLIST (clist), -1); clist_row = row_new (clist); clist->rows++; @@ -1243,7 +1724,7 @@ gtk_clist_append (GtkCList * clist, switch (clist->selection_mode) { case GTK_SELECTION_BROWSE: - gtk_clist_select_row (clist, 0, -1); + select_row (clist, 0, -1, NULL); break; default: @@ -1275,6 +1756,7 @@ gtk_clist_insert (GtkCList * clist, GtkCListRow *clist_row; g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); g_return_if_fail (text != NULL); /* return if out of bounds */ @@ -1303,6 +1785,9 @@ gtk_clist_insert (GtkCList * clist, clist->rows++; + if (row < ROW_FROM_YPIXEL (clist, 0)) + clist->voffset -= (clist->row_height + CELL_SPACING); + /* syncronize the selection list */ sync_selection (clist, row, SYNC_INSERT); } @@ -1326,6 +1811,7 @@ gtk_clist_remove (GtkCList * clist, 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)) @@ -1344,14 +1830,16 @@ gtk_clist_remove (GtkCList * clist, * removal */ if (clist_row->state == GTK_STATE_SELECTED) { - was_selected = 1; - switch (clist->selection_mode) { case GTK_SELECTION_SINGLE: - case GTK_SELECTION_BROWSE: case GTK_SELECTION_MULTIPLE: - gtk_clist_unselect_row (clist, row, -1); + case GTK_SELECTION_EXTENDED: + unselect_row (clist, row, -1, NULL); + break; + + case GTK_SELECTION_BROWSE: + select_row (clist, row - 1, -1, NULL); break; default: @@ -1363,27 +1851,16 @@ gtk_clist_remove (GtkCList * clist, * 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--; clist->row_list = g_list_remove (clist->row_list, clist_row); clist->rows--; - sync_selection (clist, row, SYNC_REMOVE); - - /* preform any selections required by the selection mode */ - if (was_selected) - { - switch (clist->selection_mode) - { - case GTK_SELECTION_BROWSE: - if (row == clist->rows) - gtk_clist_select_row (clist, row - 1, -1); - else - gtk_clist_select_row (clist, row, -1); - break; + + if (row < ROW_FROM_YPIXEL (clist, 0)) + clist->voffset += clist->row_height + CELL_SPACING; - default: - break; - } - } + sync_selection (clist, row, SYNC_REMOVE); /* toast the row */ row_delete (clist, clist_row); @@ -1404,25 +1881,37 @@ sync_selection (GtkCList * clist, gint mode) { GList *list; - - list = clist->selection; - while (list) + gint d; + + if (mode == SYNC_INSERT) + d = 1; + else + d = -1; + + if (clist->focus_row >= row) { - if (GPOINTER_TO_INT (list->data) >= row) - switch (mode) - { - case SYNC_INSERT: - list->data = ((gchar*) list->data) + 1; - break; + clist->focus_row += d; + if (clist->focus_row == -1 && clist->rows >= 1) + clist->focus_row = 0; + } - case SYNC_REMOVE: - list->data = ((gchar*) list->data) - 1; - break; + if (clist->selection_mode == GTK_SELECTION_BROWSE && clist->anchor != -1) + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); - default: - break; - } + 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; } } @@ -1430,28 +1919,41 @@ sync_selection (GtkCList * clist, void gtk_clist_clear (GtkCList * clist) { + GTK_CLIST_CLASS_FW (clist)->clear (clist); +} + +static void +real_clear (GtkCList * clist) +{ GList *list; g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); /* remove all the rows */ for (list = clist->row_list; list; list = list->next) - { - GtkCListRow *clist_row; + row_delete (clist, GTK_CLIST_ROW (list)); - clist_row = list->data; - row_delete (clist, clist_row); - } g_list_free (clist->row_list); /* free up the selection list */ g_list_free (clist->selection); + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); clist->row_list = NULL; clist->row_list_end = NULL; clist->selection = NULL; + clist->selection_end = NULL; + clist->undo_selection = NULL; + clist->undo_unselection = NULL; clist->voffset = 0; clist->rows = 0; + clist->focus_row = -1; + clist->anchor = -1; + clist->undo_anchor = -1; + clist->anchor_state = GTK_STATE_SELECTED; + clist->drag_pos = -1; /* zero-out the scrollbars */ if (clist->vscrollbar) @@ -1460,10 +1962,7 @@ gtk_clist_clear (GtkCList * clist) gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed"); if (!GTK_CLIST_FROZEN (clist)) - { - adjust_scrollbars (clist); - draw_rows (clist, NULL); - } + gtk_clist_thaw (clist); } } @@ -1477,6 +1976,7 @@ gtk_clist_swap_rows (GtkCList * clist, gpointer swap; g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); if (row1 < 0 || row1 > (clist->rows - 1)) return; @@ -1509,12 +2009,12 @@ gtk_clist_swap_rows (GtkCList * clist, if (!GTK_CLIST_FROZEN (clist)) { if (gtk_clist_row_is_visible (clist, row1) != GTK_VISIBILITY_NONE) - (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row) - (clist, NULL, row1, (GtkCListRow *) link2->data); + GTK_CLIST_CLASS_FW (clist)->draw_row + (clist, NULL, row1, GTK_CLIST_ROW (link2)); if (gtk_clist_row_is_visible (clist, row2) != GTK_VISIBILITY_NONE) - (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row) - (clist, NULL, row2, (GtkCListRow *) link1->data); + GTK_CLIST_CLASS_FW (clist)->draw_row + (clist, NULL, row2, GTK_CLIST_ROW (link1)); } } @@ -1535,6 +2035,7 @@ gtk_clist_set_row_data_full (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 - 1)) return; @@ -1547,7 +2048,7 @@ gtk_clist_set_row_data_full (GtkCList * clist, * so the application can respond to the new data -- * this could be questionable behavior */ if (clist_row->state == GTK_STATE_SELECTED) - gtk_clist_select_row (clist, row, -1); + select_row (clist, row, -1, NULL); } gpointer @@ -1557,6 +2058,7 @@ gtk_clist_get_row_data (GtkCList * clist, 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; @@ -1578,21 +2080,9 @@ gtk_clist_find_row_from_data (GtkCList * clist, if (clist->rows < 1) return -1; /* is this an optimization or just worthless? */ - n = 0; - list = clist->row_list; - while (list) - { - GtkCListRow *clist_row; - - clist_row = list->data; - if (clist_row->data == data) - break; - n++; - list = list->next; - } - - if (list) - return n; + for (n = 0, list = clist->row_list; list; n++, list = list->next) + if (GTK_CLIST_ROW (list)->data == data) + return n; return -1; } @@ -1603,6 +2093,7 @@ gtk_clist_select_row (GtkCList * clist, gint column) { g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); if (row < 0 || row >= clist->rows) return; @@ -1619,6 +2110,7 @@ gtk_clist_unselect_row (GtkCList * clist, gint column) { g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); if (row < 0 || row >= clist->rows) return; @@ -1636,6 +2128,7 @@ gtk_clist_row_is_visible (GtkCList * clist, 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; @@ -1658,7 +2151,7 @@ gtk_clist_row_is_visible (GtkCList * clist, return GTK_VISIBILITY_FULL; } -GtkAdjustment* +GtkAdjustment * gtk_clist_get_vadjustment (GtkCList * clist) { g_return_val_if_fail (clist != NULL, NULL); @@ -1667,7 +2160,7 @@ gtk_clist_get_vadjustment (GtkCList * clist) return gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)); } -GtkAdjustment* +GtkAdjustment * gtk_clist_get_hadjustment (GtkCList * clist) { g_return_val_if_fail (clist != NULL, NULL); @@ -1701,6 +2194,69 @@ gtk_clist_set_policy (GtkCList * clist, } } +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]); +} + +static void +real_undo_selection (GtkCList *clist) +{ + GList *work; + + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (gdk_pointer_is_grabbed () || + clist->selection_mode != GTK_SELECTION_EXTENDED) + return; + + if (clist->anchor >= 0) + resync_selection (clist, NULL); + + if (!(clist->undo_selection || clist->undo_unselection)) + { + 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) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], + GPOINTER_TO_INT (work->data), -1, NULL); + + 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; + + 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); +} + /* * GTKOBJECT * gtk_clist_destroy @@ -1742,6 +2298,17 @@ gtk_clist_destroy (GtkObject * object) clist->hscrollbar = NULL; } + if (clist->htimer) + { + gtk_timeout_remove (clist->htimer); + clist->htimer = 0; + } + if (clist->vtimer) + { + gtk_timeout_remove (clist->vtimer); + clist->vtimer = 0; + } + /* destroy the column buttons */ for (i = 0; i < clist->columns; i++) if (clist->column[i].button) @@ -1820,10 +2387,10 @@ gtk_clist_realize (GtkWidget * widget) attributes.event_mask |= (GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | - GDK_KEY_PRESS_MASK); + GDK_KEY_PRESS_MASK | + GDK_KEY_RELEASE_MASK); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - /* main window */ widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); gdk_window_set_user_data (widget->window, clist); @@ -1870,7 +2437,8 @@ gtk_clist_realize (GtkWidget * widget) attributes.event_mask = (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | - GDK_POINTER_MOTION_HINT_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; @@ -2104,7 +2672,10 @@ gtk_clist_button_press (GtkWidget * widget, { gint i; GtkCList *clist; - gint x, y, row, column; + 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); @@ -2112,6 +2683,10 @@ gtk_clist_button_press (GtkWidget * widget, 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) { @@ -2119,8 +2694,102 @@ gtk_clist_button_press (GtkWidget * widget, y = event->y; if (get_selection_info (clist, x, y, &row, &column)) - toggle_row (clist, row, column, event); + { + gint old_row = clist->focus_row; + gboolean no_focus_row = FALSE; + + if (clist->focus_row == -1) + { + old_row = row; + no_focus_row = TRUE; + } + + 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); + + + 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; + } + + if (!GTK_WIDGET_HAS_FOCUS (widget)) + gtk_widget_grab_focus (widget); + switch (clist->selection_mode) + { + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_MULTIPLE: + clist->anchor = row; + break; + + case GTK_SELECTION_BROWSE: + if (row != old_row || no_focus_row) + select_row (clist, row, column, (GdkEvent *) event); + break; + + case GTK_SELECTION_EXTENDED: + if (event->state & GDK_CONTROL_MASK) + { + if (event->state & GDK_SHIFT_MASK) + { + set_anchor (clist, TRUE, old_row, 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); + } + return TRUE; + } + if (event->state & GDK_SHIFT_MASK) + { + set_anchor (clist, FALSE, old_row, old_row); + update_extended_selection (clist, clist->focus_row); + return TRUE; + } + if (clist->anchor == -1) + set_anchor (clist, FALSE, row, old_row); + else + update_extended_selection (clist, clist->focus_row); + return TRUE; + + default: + break; + } + } return FALSE; } @@ -2137,6 +2806,9 @@ gtk_clist_button_press (GtkWidget * widget, GDK_BUTTON_RELEASE_MASK, NULL, NULL, event->time); + 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; } @@ -2157,6 +2829,10 @@ gtk_clist_button_release (GtkWidget * widget, clist = GTK_CLIST (widget); + /* we don't handle button 2 and 3 */ + if (event->button != 1) + return FALSE; + /* release on resize windows */ if (GTK_CLIST_IN_DRAG (clist)) for (i = 0; i < clist->columns; i++) @@ -2166,22 +2842,156 @@ gtk_clist_button_release (GtkWidget * widget, gtk_widget_get_pointer (widget, &x, NULL); width = new_column_width (clist, i, &x, &visible); gdk_pointer_ungrab (event->time); - + if (visible) draw_xor_line (clist); + 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); + } + resize_column (clist, i, width); return FALSE; } + if (GTK_CLIST_DRAG_SELECTION (clist)) + { + gint row; + gint column; + + GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION); + 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; + + 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; + + default: + break; + } + } + return FALSE; } static gint +horizontal_timeout (GtkCList *clist) +{ + gint x, y; + GdkEventMotion event; + GdkModifierType mask; + + g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE); + + clist->htimer = 0; + gdk_window_get_pointer (clist->clist_window, &x, &y, &mask); + + event.is_hint = 0; + event.x = x; + event.y = y; + event.state = mask; + + gtk_clist_motion (GTK_WIDGET (clist), &event); + + return FALSE; +} + +static gint +vertical_timeout (GtkCList *clist) +{ + gint x, y; + GdkEventMotion event; + GdkModifierType mask; + + g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE); + + clist->vtimer = 0; + gdk_window_get_pointer (clist->clist_window, &x, &y, &mask); + + event.is_hint = 0; + event.x = x; + event.y = y; + event.state = mask; + + gtk_clist_motion (GTK_WIDGET (clist), &event); + + return FALSE; +} + +static void +move_vertical (GtkCList *clist, + gint row, + gfloat align) +{ + gint y; + GtkAdjustment *adj; + + adj = GTK_RANGE (clist->vscrollbar)->adjustment; + + 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; + + gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed"); +} + +static void +move_horizontal (GtkCList *clist, + gint diff) +{ + gfloat upper; + GtkAdjustment *adj; + + adj = GTK_RANGE (clist->hscrollbar)->adjustment; + + adj->value += diff; + + upper = adj->upper - adj->page_size; + adj->value = MIN (adj->value, upper); + adj->value = MAX (adj->value, 0.0); + + gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed"); +} + +static gint gtk_clist_motion (GtkWidget * widget, GdkEventMotion * event) { - gint i, x, visible; + gint i, x, y, visible; GtkCList *clist; g_return_val_if_fail (widget != NULL, FALSE); @@ -2217,6 +3027,155 @@ gtk_clist_motion (GtkWidget * widget, } } + if (GTK_CLIST_DRAG_SELECTION (clist)) + { + gint row; + + 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->htimer == 0) + { + clist->htimer = gtk_timeout_add + (SCROLL_TIME, (GtkFunction) horizontal_timeout, clist); + + 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); + } + } + else + return TRUE; + } + + row = ROW_FROM_YPIXEL (clist, y); + + /* 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 TRUE; + + /* vertical autoscrolling */ + if (LIST_HEIGHT (clist) > clist->clist_window_height && + (y < 0 || y >= clist->clist_window_height)) + { + if (clist->vtimer == 0) + { + clist->vtimer = gtk_timeout_add (SCROLL_TIME, + (GtkFunction) vertical_timeout, + clist); + + if ((y < 0 && clist->focus_row == 0) || + (y >= clist->clist_window_height && + clist->focus_row == clist->rows-1)) + return TRUE; + + if (row < 0 && clist->focus_row > 0) + { + gtk_clist_draw_focus (widget); + clist->focus_row = 0; + gtk_clist_draw_focus (widget); + } + else if (row > clist->rows - 1 && clist->focus_row + < clist->rows - 1) + { + gtk_clist_draw_focus (widget); + clist->focus_row = clist->rows - 1; + gtk_clist_draw_focus (widget); + } + else if (row >= 0 && row <= clist->rows - 1) + { + gtk_clist_draw_focus (widget); + clist->focus_row = row; + gtk_clist_draw_focus (widget); + } + else + return TRUE; + + 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 (y < 0) + move_vertical (clist, row, 0); + else + move_vertical (clist, row, 1); + } + else + return TRUE; + } + + if (row == clist->focus_row) + return TRUE; + + /* dragging inside clist_window */ + if (row < 0 && clist->focus_row > 0) + { + gtk_clist_draw_focus (widget); + clist->focus_row = 0; + gtk_clist_draw_focus (widget); + } + else if (row > clist->rows-1 && clist->focus_row < clist->rows-1) + { + gtk_clist_draw_focus (widget); + clist->focus_row = clist->rows-1; + gtk_clist_draw_focus (widget); + } + else if (row >= 0 && row <= clist->rows-1) + { + gtk_clist_draw_focus (widget); + clist->focus_row = row; + gtk_clist_draw_focus (widget); + } + else + return TRUE; + + switch (clist->selection_mode) + { + case GTK_SELECTION_EXTENDED: + update_extended_selection (clist, clist->focus_row); + return TRUE; + + case GTK_SELECTION_BROWSE: + select_row (clist, clist->focus_row, -1, (GdkEvent *) event); + break; + + default: + break; + } + + if (ROW_TOP_YPIXEL(clist, clist->focus_row) + clist->row_height <= 0) + gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0) + gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + else if (ROW_TOP_YPIXEL (clist, clist->focus_row) >= + clist->clist_window_height) + gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + else 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); + } return TRUE; } @@ -2854,6 +3813,26 @@ draw_row (GtkCList * clist, 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); + } + } + 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); + } } static void @@ -2898,8 +3877,7 @@ draw_rows (GtkCList * clist, if (i > last_row) return; - (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row) - (clist, area, i, clist_row); + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, area, i, clist_row); i++; } @@ -3006,75 +3984,25 @@ static void toggle_row (GtkCList * clist, gint row, gint column, - GdkEventButton * event) + GdkEvent * event) { - gint i; - GList *list; - GtkCListRow *clist_row, *selected_row; - - i = 0; - list = clist->row_list; - selected_row = NULL; + GtkCListRow *clist_row; switch (clist->selection_mode) { + case GTK_SELECTION_EXTENDED: + case GTK_SELECTION_MULTIPLE: case GTK_SELECTION_SINGLE: - while (list) - { - clist_row = list->data; - list = list->next; - - if (row == i) - selected_row = clist_row; - else if (clist_row->state == GTK_STATE_SELECTED) - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], - i, column, event); - i++; - } - - if (selected_row && selected_row->state == GTK_STATE_SELECTED) - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], - row, column, event); - else - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], - row, column, event); - break; - - - case GTK_SELECTION_BROWSE: - while (list) + clist_row = g_list_nth (clist->row_list, row)->data; + if (clist_row->state == GTK_STATE_SELECTED) { - clist_row = list->data; - list = list->next; - - if (i != row && clist_row->state == GTK_STATE_SELECTED) - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], - i, column, event); - i++; + unselect_row (clist, row, column, event); + return; } - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], - row, column, event); - break; - - - case GTK_SELECTION_MULTIPLE: - clist_row = (g_list_nth (clist->row_list, row))->data; - - if (clist_row->state == GTK_STATE_SELECTED) - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], - row, column, event); - else - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], - row, column, event); - break; - - - case GTK_SELECTION_EXTENDED: - break; - - default: + case GTK_SELECTION_BROWSE: + select_row (clist, row, column, event); break; } } @@ -3083,107 +4011,97 @@ static void select_row (GtkCList * clist, gint row, gint column, - GdkEventButton * event) + GdkEvent * event) { - gint i; - GList *list; - GtkCListRow *clist_row; - - switch (clist->selection_mode) - { - case GTK_SELECTION_SINGLE: - case GTK_SELECTION_BROWSE: - i = 0; - list = clist->row_list; - while (list) - { - clist_row = list->data; - list = list->next; - - if (row != i && clist_row->state == GTK_STATE_SELECTED) - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], - i, column, event); - - i++; - } - - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], - row, column, event); - break; - - case GTK_SELECTION_MULTIPLE: - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], - row, column, event); - - break; - - case GTK_SELECTION_EXTENDED: - break; - - default: - break; - } + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + row, column, event); } static void unselect_row (GtkCList * clist, gint row, gint column, - GdkEventButton * event) + GdkEvent * event) { - switch (clist->selection_mode) - { - case GTK_SELECTION_SINGLE: - case GTK_SELECTION_BROWSE: - case GTK_SELECTION_MULTIPLE: - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], - row, column, event); - break; - - case GTK_SELECTION_EXTENDED: - break; - - default: - break; - } + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], + row, column, event); } static void real_select_row (GtkCList * clist, gint row, gint column, - GdkEventButton * event) + 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) + { + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_BROWSE: + + row_selected = FALSE; + list = clist->selection; + + while (list) + { + sel_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_selected) + return; + + default: + break; + } + clist_row = (g_list_nth (clist->row_list, row))->data; - if (clist_row->state == GTK_STATE_NORMAL) - { - clist_row->state = GTK_STATE_SELECTED; - clist->selection = g_list_append (clist->selection, GINT_TO_POINTER (row)); + if (clist_row->state != GTK_STATE_NORMAL) + return; - if (!GTK_CLIST_FROZEN (clist) - && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) - (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row) - (clist, NULL, row, clist_row); + clist_row->state = GTK_STATE_SELECTED; + if (!clist->selection) + { + 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 (!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); } static void real_unselect_row (GtkCList * clist, gint row, gint column, - GdkEventButton * event) + GdkEvent * event) { GtkCListRow *clist_row; g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); if (row < 0 || row > (clist->rows - 1)) return; @@ -3193,12 +4111,17 @@ real_unselect_row (GtkCList * clist, if (clist_row->state == GTK_STATE_SELECTED) { clist_row->state = GTK_STATE_NORMAL; - clist->selection = g_list_remove (clist->selection, GINT_TO_POINTER (row)); + 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 (GTK_OBJECT (clist)->klass)->draw_row) - (clist, NULL, row, clist_row); + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); } } @@ -3212,6 +4135,7 @@ get_selection_info (GtkCList * clist, 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 */ @@ -3331,8 +4255,7 @@ column_button_create (GtkCList * clist, if (GTK_WIDGET_REALIZED (clist) && clist->title_window) gtk_widget_set_parent_window (clist->column[column].button, clist->title_window); - gtk_signal_connect (GTK_OBJECT (button), - "clicked", + gtk_signal_connect (GTK_OBJECT (button), "clicked", (GtkSignalFunc) column_button_clicked, (gpointer) clist); @@ -3376,6 +4299,7 @@ create_scrollbars (GtkCList * clist) GtkAdjustment *adjustment; clist->vscrollbar = gtk_vscrollbar_new (NULL); + adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)); gtk_signal_connect (GTK_OBJECT (adjustment), "changed", @@ -3390,6 +4314,7 @@ create_scrollbars (GtkCList * clist) gtk_widget_show (clist->vscrollbar); clist->hscrollbar = gtk_hscrollbar_new (NULL); + adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)); gtk_signal_connect (GTK_OBJECT (adjustment), "changed", @@ -3614,7 +4539,10 @@ hadjustment_value_changed (GtkAdjustment * adjustment, { GtkCList *clist; GdkRectangle area; - gint i, diff, value; + gint i; + gint y = 0; + gint diff = 0; + gint value; g_return_if_fail (adjustment != NULL); g_return_if_fail (data != NULL); @@ -3622,97 +4550,151 @@ hadjustment_value_changed (GtkAdjustment * adjustment, clist = GTK_CLIST (data); - if (!GTK_WIDGET_DRAWABLE (clist)) + if (!GTK_WIDGET_DRAWABLE (clist) || + adjustment != gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar))) return; value = adjustment->value; - - if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar))) + + /* move the column buttons and resize windows */ + for (i = 0; i < clist->columns; i++) { - /* move the column buttons and resize windows */ - for (i = 0; i < clist->columns; i++) + if (clist->column[i].button) { - if (clist->column[i].button) + clist->column[i].button->allocation.x -= value + clist->hoffset; + + if (clist->column[i].button->window) { - 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); - } + 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); } } + } + + 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) + { + draw_rows (clist, NULL); + return; + } - if (value > -clist->hoffset) + if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) && + GTK_CLIST_ADD_MODE (clist)) { - /* scroll right */ - diff = value + clist->hoffset; + 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; - /* we have to re-draw the whole screen here... */ - if (diff >= clist->clist_window_width) - { - clist->hoffset = -value; - draw_rows (clist, NULL); - 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_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); + } - if ((diff != 0) && (diff != clist->clist_window_width)) - 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_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.x = clist->clist_window_width - diff; - area.y = 0; - area.width = diff; - area.height = clist->clist_window_height; + area.y = 0; + area.width = diff; + area.height = clist->clist_window_height; + + check_exposures (clist); + + if (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); + 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 { - /* scroll left */ - diff = -clist->hoffset - value; - - /* we have to re-draw the whole screen here... */ - if (diff >= clist->clist_window_width) + gint x0; + gint x1; + + if (area.x == 0) { - clist->hoffset = -value; - draw_rows (clist, NULL); - return; + x0 = clist->clist_window_width - 1; + x1 = diff; } - - if ((diff != 0) && (diff != clist->clist_window_width)) - 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; + 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); + } - - clist->hoffset = -value; - if ((diff != 0) && (diff != clist->clist_window_width)) - check_exposures (clist); } - draw_rows (clist, &area); } @@ -3935,3 +4917,1172 @@ add_style_data (GtkCList * clist) /* 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) + { + g_return_if_fail (GTK_IS_WIDGET (child)); + GTK_CLIST_SET_FLAG (GTK_CLIST (container), CLIST_CHILD_HAS_FOCUS); + } + + parent_class->set_focus_child (container, child); +} + +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 (clist->selection_mode == GTK_SELECTION_BROWSE && + clist->selection == NULL && clist->focus_row > -1) + select_row (clist, clist->focus_row, -1, (GdkEvent *) event); + else + gtk_widget_draw_focus (widget); + + return FALSE; +} + +static gint +gtk_clist_focus_out (GtkWidget *widget, + GdkEventFocus *event) +{ + 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); + + if (GTK_CLIST (widget)->anchor != -1) + GTK_CLIST_CLASS_FW (widget)->resync_selection + (GTK_CLIST (widget), (GdkEvent *) event); + + return FALSE; +} + +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 () || + clist->selection_mode != GTK_SELECTION_EXTENDED) + return; + + 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 + { + 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)); +} + +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 ()) + return; + + 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 (GTK_CLIST_ADD_MODE (clist)) + { + clist->anchor = clist->focus_row; + clist->drag_pos = clist->focus_row; + clist->undo_anchor = clist->focus_row; + fake_toggle_row (clist, clist->focus_row); + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); + } + else + { + clist->anchor = clist->focus_row; + clist->drag_pos = clist->focus_row; + clist->undo_anchor = clist->focus_row; + GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist, + clist->focus_row); + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); + } + break; + + default: + break; + } +} + +static void +move_focus_row (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position) +{ + GtkWidget *widget; + + g_return_if_fail (clist != 0); + g_return_if_fail (GTK_IS_CLIST (clist)); + + widget = GTK_WIDGET (clist); + + 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); + } + break; + default: + break; + } +} + +static void +scroll_horizontal (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position) +{ + gint column = 0; + + g_return_if_fail (clist != 0); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (gdk_pointer_is_grabbed ()) + return; + + 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; + } + + 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); + } +} + +static void +scroll_vertical (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (gdk_pointer_is_grabbed ()) + return; + + switch (clist->selection_mode) + { + case GTK_SELECTION_EXTENDED: + if (clist->anchor >= 0) + return; + if (!GTK_CLIST_ADD_MODE (clist)) + gtk_clist_unselect_all (clist); + + case GTK_SELECTION_BROWSE: + + if (clist->selection_mode == GTK_SELECTION_BROWSE) + unselect_row (clist,clist->focus_row, -1, NULL); + + move_focus_row (clist, scroll_type, position); + + if (clist->selection_mode == GTK_SELECTION_EXTENDED && + GTK_CLIST_ADD_MODE (clist)) + return; + + switch (gtk_clist_row_is_visible (clist, clist->focus_row)) + { + case GTK_VISIBILITY_NONE: + 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; + + 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: + 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; + } +} + +static void +set_anchor (GtkCList *clist, + gboolean add_mode, + gint anchor, + gint undo_anchor) +{ + 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; + + 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; + } + + clist->anchor = anchor; + clist->drag_pos = anchor; + clist->undo_anchor = undo_anchor; +} + +static void +resync_selection (GtkCList *clist, + GdkEvent *event) +{ + gint i; + gint e; + gint row; + gboolean thaw = FALSE; + GList *list; + GtkCListRow *clist_row; + + if (clist->anchor < 0) + return; + + if (!GTK_CLIST_FROZEN (clist)) + { + GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN); + thaw = TRUE; + } + + 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) + { + row = GPOINTER_TO_INT (list->data); + list = list->next; + if (row < i || row > e) + { + clist_row = g_list_nth (clist->row_list, row)->data; + 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)); + } + } + } + + for (list = g_list_nth (clist->row_list, i); i <= e; i++, list = list->next) + 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)); + } + + 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; + + if (thaw) + GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN); +} + +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; + + if (row < 0) + row = 0; + if (row >= clist->rows) + row = 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) + { + 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; + } + + clist->drag_pos = row; + + area.x = 0; + area.width = clist->clist_window_width; + + /* 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_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; + } + + top = ROW_TOP_YPIXEL (clist, clist->focus_row); + + 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); + 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); + + y1 = ROW_TOP_YPIXEL (clist, s1); + h1 = (e1 - s1 + 1) * (clist->row_height + CELL_SPACING); + } + + /* 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)->state != clist->anchor_state) + GTK_CLIST_ROW (list)->state = clist->anchor_state; + + top = ROW_TOP_YPIXEL (clist, clist->focus_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) + { + 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); + } + 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); + } + + 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); +} + +static void +start_selection (GtkCList *clist) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (gdk_pointer_is_grabbed ()) + return; + + set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row, + clist->focus_row); +} + +static void +end_selection (GtkCList *clist) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (gdk_pointer_is_grabbed () || clist->anchor == -1) + return; + + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); +} + +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 (gdk_pointer_is_grabbed () || + clist->selection_mode != GTK_SELECTION_EXTENDED) + return; + + if (auto_start_selection) + set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row, + clist->focus_row); + else if (clist->anchor == -1) + return; + + 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); + + update_extended_selection (clist, clist->focus_row); +} + +static void +abort_column_resize (GtkCList *clist) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (!GTK_CLIST_IN_DRAG (clist)) + return; + + GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG); + gdk_pointer_ungrab (gdk_time_get()); + + if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1) + draw_xor_line (clist); + + 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); + } +} + +static gint +gtk_clist_key_press (GtkWidget * widget, + GdkEventKey * event) +{ + GtkCList *clist; + gboolean handled = FALSE; + + 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); + + + if (event->keyval == GDK_Escape && GTK_CLIST_IN_DRAG (clist)) + { + GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG); + gdk_pointer_ungrab (event->time); + + if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1) + draw_xor_line (clist); + + 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 TRUE; + } + + if (GTK_WIDGET_CLASS (parent_class)->key_press_event) + handled = GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event); + + if (handled) + return handled; + + 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); + + default: + break; + } + + return FALSE; +} + +static gboolean +title_focus (GtkCList * clist, + gint dir) +{ + GtkWidget *focus_child; + gboolean return_val = FALSE; + gint d = 1; + gint i = 0; + gint j; + + if (!GTK_CLIST_SHOW_TITLES (clist)) + return FALSE; + + focus_child = GTK_CONTAINER (clist)->focus_child; + + 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 (dir == GTK_DIR_UP) + i = COLUMN_FROM_XPIXEL (clist, 0); + else + i = clist->columns - 1; + focus_child = clist->column[i].button; + dir = GTK_DIR_TAB_FORWARD; + } + else + d = -1; + break; + case GTK_DIR_LEFT: + d = -1; + if (!focus_child || focus_child == clist->hscrollbar || + focus_child == clist->hscrollbar) + { + i = clist->columns - 1; + focus_child = clist->column[i].button; + } + break; + case GTK_DIR_RIGHT: + if (!focus_child || focus_child == clist->hscrollbar || + focus_child == clist->hscrollbar) + { + i = 0; + focus_child = clist->column[i].button; + } + break; + } + + if (focus_child) + while (i < clist->columns) + { + if (clist->column[i].button == focus_child) + { + 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)) + if (gtk_container_focus + (GTK_CONTAINER (clist->column[i].button), dir)) + { + return_val = TRUE; + i -= d; + } + if (!return_val && dir == GTK_DIR_UP) + return FALSE; + i += d; + break; + } + i++; + } + + j = i; + + if (!return_val) + while (j >= 0 && j < clist->columns) + { + if (clist->column[j].button && + GTK_WIDGET_VISIBLE (clist->column[j].button)) + { + if (GTK_IS_CONTAINER (clist->column[j].button) && + gtk_container_focus + (GTK_CONTAINER (clist->column[j].button), dir)) + { + return_val = TRUE; + break; + } + else if (GTK_WIDGET_CAN_FOCUS (clist->column[j].button)) + { + gtk_widget_grab_focus (clist->column[j].button); + return_val = TRUE; + break; + } + } + j += d; + } + + if (return_val) + { + if (COLUMN_LEFT_XPIXEL (clist, j) < CELL_SPACING + COLUMN_INSET) + gtk_clist_moveto (clist, -1, j, 0, 0); + else if (COLUMN_LEFT_XPIXEL(clist, j) + clist->column[j].area.width > + clist->clist_window_width) + { + if (j == clist->columns-1) + gtk_clist_moveto (clist, -1, j, 0, 0); + else + gtk_clist_moveto (clist, -1, j, 0, 1); + } + } + return return_val; +} + +static gint +gtk_clist_focus (GtkContainer * container, + GtkDirectionType direction) +{ + GtkCList *clist; + GtkWidget *focus_child; + gint old_row; + + g_return_val_if_fail (container != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CLIST (container), FALSE); + + if (!GTK_WIDGET_SENSITIVE (container)) + return FALSE; + + clist = GTK_CLIST (container); + focus_child = container->focus_child; + old_row = clist->focus_row; + + switch (direction) + { + 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))) + { + gboolean tf = FALSE; + + 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; + + 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; + } + + if (tf) + return TRUE; + } + + GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS); + + 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; + } + + 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; + } + 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)) + { + gtk_widget_grab_focus (clist->hscrollbar); + return TRUE; + } + + if ((!focus_child || focus_child == clist->hscrollbar) && + GTK_CLIST_CHILD_HAS_FOCUS (clist) && + GTK_WIDGET_VISIBLE (clist->vscrollbar) && + GTK_WIDGET_CAN_FOCUS (clist->vscrollbar)) + { + gtk_widget_grab_focus (clist->vscrollbar); + return TRUE; + } + + if ((!focus_child || focus_child == clist->hscrollbar || + focus_child == clist->vscrollbar) && + 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) + select_row (clist, clist->focus_row, -1, NULL); + } + gtk_widget_grab_focus (GTK_WIDGET (container)); + return TRUE; + } + + GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS); + + if (title_focus (clist, direction)) + return TRUE; + + break; + + default: + break; + } + + gtk_container_set_focus_child (container, NULL); + return FALSE; +} + +void +gtk_clist_unselect_all (GtkCList * clist) +{ + GTK_CLIST_CLASS_FW (clist)->unselect_all (clist); +} + +static void +real_unselect_all (GtkCList * clist) +{ + GList *list; + gint i; + + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (gdk_pointer_is_grabbed ()) + return; + + switch (clist->selection_mode) + { + case GTK_SELECTION_BROWSE: + if (clist->focus_row >= 0) + { + select_row (clist, 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; + + clist->anchor = -1; + clist->drag_pos = -1; + clist->undo_anchor = clist->focus_row; + break; + + default: + break; + } + + list = clist->selection; + + while (list) + { + i = GPOINTER_TO_INT (list->data); + list = list->next; + unselect_row (clist, i, -1, NULL); + } +} + +void +gtk_clist_select_all (GtkCList * clist) +{ + GTK_CLIST_CLASS_FW (clist)->select_all (clist); +} + +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)); + + if (gdk_pointer_is_grabbed ()) + 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; + } +} + +static void +fake_unselect_all (GtkCList * clist, + gint row) +{ + 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)->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; + + for (list = clist->undo_selection; list; list = list->next) + { + 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)); + } +} + +static void +fake_toggle_row (GtkCList *clist, + gint row) +{ + GList *work; + + if (!(work = g_list_nth (clist->row_list, row))) + 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 (!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)); +} + +static GList * +selection_find (GtkCList *clist, + gint row_number, + GList *row_list_element) +{ + return g_list_find (clist->selection, GINT_TO_POINTER (row_number)); +} diff --git a/gtk/gtkclist.h b/gtk/gtkclist.h index fb1ed5d58d..ec347dda74 100644 --- a/gtk/gtkclist.h +++ b/gtk/gtkclist.h @@ -27,6 +27,7 @@ #include <gtk/gtkbutton.h> #include <gtk/gtkhscrollbar.h> #include <gtk/gtkvscrollbar.h> +#include <gtk/gtkenums.h> #ifdef __cplusplus extern "C" @@ -38,9 +39,12 @@ enum { GTK_CLIST_FROZEN = 1 << 0, GTK_CLIST_IN_DRAG = 1 << 1, - GTK_CLIST_ROW_HEIGHT_SET = 1 << 2, - GTK_CLIST_SHOW_TITLES = 1 << 3, - GTK_CLIST_CONSTRUCTED = 1 << 4 + GTK_CLIST_DRAG_SELECTION = 1 << 2, + GTK_CLIST_ROW_HEIGHT_SET = 1 << 3, + GTK_CLIST_SHOW_TITLES = 1 << 4, + GTK_CLIST_CONSTRUCTED = 1 << 5, + GTK_CLIST_CHILD_HAS_FOCUS = 1 << 6, + GTK_CLIST_ADD_MODE = 1 << 7 }; /* cell types */ @@ -53,11 +57,11 @@ typedef enum GTK_CELL_WIDGET } GtkCellType; -#define GTK_TYPE_CLIST (gtk_clist_get_type ()) -#define GTK_CLIST(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_CLIST, GtkCList)) -#define GTK_CLIST_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_CLIST, GtkCListClass)) -#define GTK_IS_CLIST(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_CLIST)) -#define GTK_IS_CLIST_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_CLIST)) +#define GTK_TYPE_CLIST (gtk_clist_get_type ()) +#define GTK_CLIST(obj) (GTK_CHECK_CAST ((obj), gtk_clist_get_type (), GtkCList)) +#define GTK_CLIST_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), gtk_clist_get_type (), GtkCListClass)) +#define GTK_IS_CLIST(obj) (GTK_CHECK_TYPE ((obj), gtk_clist_get_type ())) +#define GTK_IS_CLIST_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_CLIST)) #define GTK_CLIST_FLAGS(clist) (GTK_CLIST (clist)->flags) #define GTK_CLIST_SET_FLAG(clist,flag) (GTK_CLIST_FLAGS (clist) |= (GTK_ ## flag)) @@ -68,6 +72,11 @@ typedef enum #define GTK_CLIST_ROW_HEIGHT_SET(clist) (GTK_CLIST_FLAGS (clist) & GTK_CLIST_ROW_HEIGHT_SET) #define GTK_CLIST_SHOW_TITLES(clist) (GTK_CLIST_FLAGS (clist) & GTK_CLIST_SHOW_TITLES) #define GTK_CLIST_CONSTRUCTED(clist) (GTK_CLIST_FLAGS (clist) & GTK_CLIST_CONSTRUCTED) +#define GTK_CLIST_CHILD_HAS_FOCUS(clist) (GTK_CLIST_FLAGS (clist) & GTK_CLIST_CHILD_HAS_FOCUS) +#define GTK_CLIST_DRAG_SELECTION(clist) (GTK_CLIST_FLAGS (clist) & GTK_CLIST_DRAG_SELECTION) +#define GTK_CLIST_ADD_MODE(clist) (GTK_CLIST_FLAGS (clist) & GTK_CLIST_ADD_MODE) + +#define GTK_CLIST_ROW(_glist_) ((GtkCListRow *)((_glist_)->data)) /* pointer casting for cells */ #define GTK_CELL_TEXT(cell) (((GtkCellText *) &(cell))) @@ -90,7 +99,7 @@ struct _GtkCList { GtkContainer container; - guint8 flags; + guint16 flags; /* mem chunks */ GMemChunk *row_mem_chunk; @@ -133,6 +142,11 @@ struct _GtkCList /* list of selected rows */ GList *selection; + GList *selection_end; + + GList *undo_selection; + GList *undo_unselection; + gint undo_anchor; /* scrollbars */ GtkWidget *vscrollbar; @@ -152,6 +166,16 @@ struct _GtkCList /* the current x-pixel location of the xor-drag line */ gint x_drag; + + /* focus handling */ + gint focus_row; + + /* dragging the selection */ + gint anchor; + GtkStateType anchor_state; + gint drag_pos; + gint htimer; + gint vtimer; }; struct _GtkCListClass @@ -161,17 +185,48 @@ struct _GtkCListClass void (*select_row) (GtkCList * clist, gint row, gint column, - GdkEventButton * event); + GdkEvent * event); void (*unselect_row) (GtkCList * clist, gint row, gint column, - GdkEventButton * event); + GdkEvent * event); void (*click_column) (GtkCList * clist, gint column); + + void (*toggle_focus_row) (GtkCList * clist); + void (*select_all) (GtkCList * clist); + void (*unselect_all) (GtkCList * clist); + void (*undo_selection) (GtkCList * clist); + void (*start_selection) (GtkCList * clist); + void (*end_selection) (GtkCList * clist); + void (*extend_selection) (GtkCList * clist, + GtkScrollType scroll_type, + gfloat position, + gboolean auto_start_selection); + void (*scroll_horizontal) (GtkCList * clist, + GtkScrollType scroll_type, + gfloat position); + void (*scroll_vertical) (GtkCList * clist, + GtkScrollType scroll_type, + gfloat position); + void (*toggle_add_mode) (GtkCList * clist); + void (*abort_column_resize) (GtkCList * clist); + + void (*resync_selection) (GtkCList * clist, + GdkEvent * event); + GList * (*selection_find) (GtkCList *clist, + gint row_number, + GList *row_list_element); void (*draw_row) (GtkCList * clist, GdkRectangle * area, gint row, GtkCListRow * clist_row); + void (*clear) (GtkCList * clist); + void (*fake_unselect_all) (GtkCList * clist, + gint row); + + + gint scrollbar_spacing; }; @@ -364,9 +419,6 @@ void gtk_clist_moveto (GtkCList * clist, GtkVisibility gtk_clist_row_is_visible (GtkCList * clist, gint row); -GtkAdjustment* gtk_clist_get_vadjustment (GtkCList * clist); -GtkAdjustment* gtk_clist_get_hadjustment (GtkCList * clist); - /* returns the cell type */ GtkCellType gtk_clist_get_cell_type (GtkCList * clist, gint row, @@ -480,6 +532,9 @@ void gtk_clist_unselect_row (GtkCList * clist, gint row, gint column); +/* undo the last select/unselect operation */ +void gtk_clist_undo_selection (GtkCList *clist); + /* clear the entire list -- this is much faster than removing each item * with gtk_clist_remove */ void gtk_clist_clear (GtkCList * clist); @@ -491,10 +546,14 @@ gint gtk_clist_get_selection_info (GtkCList * clist, gint * row, gint * column); -/* swap the position of two rows */ -void gtk_clist_swap_rows (GtkCList * clist, gint row1, gint row2); +/* in multiple or extended mode, select all rows */ +void gtk_clist_select_all (GtkCList *clist); +/* in all modes except browse mode, deselect all rows */ +void gtk_clist_unselect_all (GtkCList *clist); +/* swap the position of two rows */ +void gtk_clist_swap_rows (GtkCList * clist, gint row1, gint row2); #ifdef __cplusplus } diff --git a/gtk/gtkctree.c b/gtk/gtkctree.c index 5e001c1782..503b163fe6 100644 --- a/gtk/gtkctree.c +++ b/gtk/gtkctree.c @@ -23,7 +23,9 @@ #include <stdlib.h> #include "gtkctree.h" +#include "gtkbindings.h" #include <gdk/gdkx.h> +#include <gdk/gdkkeysyms.h> #define PM_SIZE 8 #define TAB_SIZE (PM_SIZE + 6) @@ -41,6 +43,9 @@ + (clist)->hoffset) #define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x) +#define GTK_CLIST_CLASS_FW(_widget_) GTK_CLIST_CLASS (GTK_OBJECT (_widget_)->klass) + + static void gtk_ctree_class_init (GtkCTreeClass *klass); static void gtk_ctree_init (GtkCTree *ctree); static void gtk_ctree_destroy (GtkObject *object); @@ -102,6 +107,7 @@ static void tree_delete (GtkCTree *ctree, static void tree_delete_row (GtkCTree *ctree, GList *node, gpointer data); +static void real_clear (GtkCList *clist); static void tree_update_level (GtkCTree *ctree, GList *node, gpointer data); @@ -111,12 +117,27 @@ static void tree_select (GtkCTree *ctree, static void tree_unselect (GtkCTree *ctree, GList *node, gpointer data); +static void real_select_all (GtkCList *clist); +static void real_unselect_all (GtkCList *clist); static void tree_expand (GtkCTree *ctree, GList *node, gpointer data); static void tree_collapse (GtkCTree *ctree, GList *node, gpointer data); +static void tree_toggle_expansion (GtkCTree *ctree, + GList *node, + gpointer data); +static void change_focus_row_expansion (GtkCTree *ctree, + GtkCTreeExpansion expansion); +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 real_tree_select (GtkCTree *ctree, GList *node, gint column); @@ -137,9 +158,11 @@ static void real_tree_move (GtkCTree *ctree, static void gtk_ctree_link (GtkCTree *ctree, GList *node, GList *parent, - GList *sibling); + GList *sibling, + gboolean update_focus_row); static void gtk_ctree_unlink (GtkCTree *ctree, - GList *node); + GList *node, + gboolean update_focus_row); static GList * gtk_ctree_last_visible (GtkCTree *ctree, GList *node); static void gtk_ctree_marshal_signal_1 (GtkObject *object, @@ -154,6 +177,10 @@ static void gtk_ctree_marshal_signal_3 (GtkObject *object, GtkSignalFunc func, gpointer func_data, GtkArg *args); +static void gtk_ctree_marshal_signal_4 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); static gboolean ctree_is_hot_spot (GtkCTree *ctree, GList *node, gint row, @@ -166,6 +193,23 @@ static gint default_compare (GtkCTree *ctree, const GList *node1, const GList *node2); + + +static void fake_unselect_all (GtkCList *clist, + gint row); +static GList* selection_find (GtkCList *clist, + gint row_number, + GList *row_list_element); +static void resync_selection (GtkCList *clist, + GdkEvent *event); +static void real_undo_selection (GtkCList *clist); +static void select_row_recursive (GtkCTree *ctree, + GList *node, + gpointer data); + + + + enum { TREE_SELECT_ROW, @@ -173,6 +217,7 @@ enum TREE_EXPAND, TREE_COLLAPSE, TREE_MOVE, + CHANGE_FOCUS_ROW_EXPANSION, LAST_SIGNAL }; @@ -191,6 +236,10 @@ typedef void (*GtkCTreeSignal3) (GtkObject *object, GList *arg1, gpointer data); +typedef void (*GtkCTreeSignal4) (GtkObject *object, + GtkCTreeExpansion arg1, + gpointer data); + static GtkCListClass *parent_class = NULL; static GtkContainerClass *container_class = NULL; @@ -264,6 +313,19 @@ gtk_ctree_marshal_signal_3 (GtkObject *object, } static void +gtk_ctree_marshal_signal_4 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkCTreeSignal4 rfunc; + + rfunc = (GtkCTreeSignal4) func; + + (*rfunc) (object, GTK_VALUE_ENUM (args[0]), func_data); +} + +static void gtk_ctree_class_init (GtkCTreeClass *klass) { GtkObjectClass *object_class; @@ -314,6 +376,14 @@ gtk_ctree_class_init (GtkCTreeClass *klass) gtk_ctree_marshal_signal_2, GTK_TYPE_NONE, 3, GTK_TYPE_POINTER, GTK_TYPE_POINTER, GTK_TYPE_POINTER); + ctree_signals[CHANGE_FOCUS_ROW_EXPANSION] = + gtk_signal_new ("change_focus_row_expansion", + GTK_RUN_LAST | GTK_RUN_ACTION, + object_class->type, + GTK_SIGNAL_OFFSET (GtkCTreeClass, + change_focus_row_expansion), + gtk_ctree_marshal_signal_4, + GTK_TYPE_NONE, 1, GTK_TYPE_ENUM); gtk_object_class_add_signals (object_class, ctree_signals, LAST_SIGNAL); @@ -325,16 +395,70 @@ gtk_ctree_class_init (GtkCTreeClass *klass) widget_class->button_release_event = gtk_ctree_button_release; widget_class->motion_notify_event = gtk_ctree_button_motion; - clist_class->select_row = NULL; - clist_class->unselect_row = NULL; + clist_class->select_row = real_select_row; + clist_class->unselect_row = real_unselect_row; + clist_class->undo_selection = real_undo_selection; + clist_class->resync_selection = resync_selection; + clist_class->selection_find = selection_find; clist_class->click_column = NULL; clist_class->draw_row = draw_row; + clist_class->clear = real_clear; + clist_class->select_all = real_select_all; + clist_class->unselect_all = real_unselect_all; + clist_class->fake_unselect_all = fake_unselect_all; klass->tree_select_row = real_tree_select; klass->tree_unselect_row = real_tree_unselect; klass->tree_expand = real_tree_expand; klass->tree_collapse = real_tree_collapse; klass->tree_move = real_tree_move; + klass->change_focus_row_expansion = change_focus_row_expansion; + + { + GtkBindingSet *binding_set; + + binding_set = gtk_binding_set_by_class (klass); + gtk_binding_entry_add_signal (binding_set, + '+', GDK_SHIFT_MASK, + "change_focus_row_expansion", 1, + GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_EXPAND); + gtk_binding_entry_add_signal (binding_set, + GDK_KP_Add, 0, + "change_focus_row_expansion", 1, + GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_EXPAND); + gtk_binding_entry_add_signal (binding_set, + GDK_KP_Add, GDK_CONTROL_MASK, + "change_focus_row_expansion", 1, + GTK_TYPE_ENUM, + GTK_CTREE_EXPANSION_EXPAND_RECURSIVE); + gtk_binding_entry_add_signal (binding_set, + '-', 0, + "change_focus_row_expansion", 1, + GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_COLLAPSE); + gtk_binding_entry_add_signal (binding_set, + GDK_KP_Subtract, 0, + "change_focus_row_expansion", 1, + GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_COLLAPSE); + gtk_binding_entry_add_signal (binding_set, + GDK_KP_Subtract, GDK_CONTROL_MASK, + "change_focus_row_expansion", 1, + GTK_TYPE_ENUM, + GTK_CTREE_EXPANSION_COLLAPSE_RECURSIVE); + gtk_binding_entry_add_signal (binding_set, + '=', 0, + "change_focus_row_expansion", 1, + GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_TOGGLE); + gtk_binding_entry_add_signal (binding_set, + GDK_KP_Multiply, 0, + "change_focus_row_expansion", 1, + GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_TOGGLE); + gtk_binding_entry_add_signal (binding_set, + GDK_KP_Multiply, GDK_CONTROL_MASK, + "change_focus_row_expansion", 1, + GTK_TYPE_ENUM, + GTK_CTREE_EXPANSION_TOGGLE_RECURSIVE); + } + } static void @@ -344,7 +468,6 @@ gtk_ctree_init (GtkCTree *ctree) ctree->drag_icon = NULL; ctree->tree_indent = 20; ctree->tree_column = 0; - ctree->selection_last = NULL; ctree->drag_row = -1; ctree->drag_source = NULL; ctree->drag_target = NULL; @@ -371,7 +494,7 @@ gtk_ctree_destroy (GtkObject *object) GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN); - gtk_ctree_clear (GTK_CTREE (object)); + gtk_clist_clear (GTK_CLIST (object)); if (clist->vscrollbar) { @@ -458,6 +581,7 @@ gtk_ctree_button_press (GtkWidget *widget, if (event->window == clist->clist_window) { + gboolean collapse_expand = FALSE; GList *work; gint x; gint y; @@ -466,40 +590,105 @@ gtk_ctree_button_press (GtkWidget *widget, x = event->x; y = event->y; - if (gtk_clist_get_selection_info (clist, x, y, &row, &column)) - { - if (event->button == 1) - ctree->drag_row = - 1 - ROW_FROM_YPIXEL (clist, y); - work = g_list_nth (clist->row_list, row); + if (!gtk_clist_get_selection_info (clist, x, y, &row, &column)) + return FALSE; + + if (event->button == 2) + ctree->drag_row = - 1 - ROW_FROM_YPIXEL (clist, y); + + work = g_list_nth (clist->row_list, row); - if (GTK_CTREE_ROW (work)->children && - (event->type == GDK_2BUTTON_PRESS || - (ctree_is_hot_spot (ctree, work, row, x, y) - && event->button == 1))) - { - if (GTK_CTREE_ROW (work)->expanded) - gtk_ctree_collapse (ctree, work); - else - gtk_ctree_expand (ctree, work); - } - else if (ctree->reorderable && event->button == 1 && !ctree->in_drag) + if (ctree->reorderable && event->button == 2 && !ctree->in_drag && + clist->anchor == -1) + { + gdk_pointer_grab (event->window, FALSE, + GDK_POINTER_MOTION_HINT_MASK | + GDK_BUTTON2_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, + NULL, NULL, event->time); + ctree->in_drag = TRUE; + ctree->drag_source = work; + ctree->drag_target = NULL; + return FALSE; + } + else if (event->button == 1 && + (GTK_CTREE_ROW (work)->children && + (event->type == GDK_2BUTTON_PRESS || + ctree_is_hot_spot (ctree, work, row, x, y)))) + { + if (GTK_CTREE_ROW (work)->expanded) + gtk_ctree_collapse (ctree, work); + else + gtk_ctree_expand (ctree, work); + + collapse_expand = TRUE; + } + if (event->button == 1) + { + gint old_row = clist->focus_row; + gboolean no_focus_row = FALSE; + + switch (clist->selection_mode) { - gdk_pointer_grab (event->window, FALSE, + case GTK_SELECTION_MULTIPLE: + case GTK_SELECTION_SINGLE: + if (!collapse_expand) + break; + + if (clist->focus_row == -1) + { + old_row = row; + no_focus_row = TRUE; + } + + 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); - ctree->in_drag = TRUE; - ctree->drag_source = work; - ctree->drag_target = NULL; + + if (GTK_CLIST_ADD_MODE (clist)) + { + GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE); + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + gtk_widget_draw_focus (widget); + gdk_gc_set_line_attributes (clist->xor_gc, 1, + GDK_LINE_SOLID, 0, 0); + clist->focus_row = row; + gtk_widget_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_widget_draw_focus (widget); + clist->focus_row = row; + gtk_widget_draw_focus (widget); + } + else + clist->focus_row = row; + } + + if (!GTK_WIDGET_HAS_FOCUS (widget)) + gtk_widget_grab_focus (widget); + return FALSE; + + default: + break; } } - return FALSE; } - return - (* GTK_WIDGET_CLASS (parent_class)->button_press_event) (widget, event); + return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event); } static gint @@ -520,11 +709,12 @@ gtk_ctree_button_motion (GtkWidget *widget, ctree = GTK_CTREE (widget); clist = GTK_CLIST (widget); - if (!ctree->reorderable) - return - (* GTK_WIDGET_CLASS (parent_class)->motion_notify_event) (widget, event); + if (GTK_CLIST_IN_DRAG (clist)) + return GTK_WIDGET_CLASS (parent_class)->motion_notify_event + (widget, event); - if (event->window == clist->clist_window && ctree->in_drag) + if (event->window == clist->clist_window && + ctree->in_drag && ctree->reorderable) { GdkModifierType modmask; gint root_x; @@ -540,8 +730,7 @@ gtk_ctree_button_motion (GtkWidget *widget, y >= ROW_TOP_YPIXEL (clist, -ctree->drag_row-1) && y <= ROW_TOP_YPIXEL (clist, -ctree->drag_row-1) + clist->row_height) return - (* GTK_WIDGET_CLASS (parent_class)->motion_notify_event) - (widget, event); + GTK_WIDGET_CLASS (parent_class)->motion_notify_event (widget, event); if (ctree->use_icons) { @@ -585,7 +774,7 @@ gtk_ctree_button_motion (GtkWidget *widget, if (y < 0 || y > clist->clist_window_height || ROW_TOP_YPIXEL (clist, row + 1) > clist->clist_window_height || row >= clist->rows) - return (* GTK_WIDGET_CLASS (parent_class)->motion_notify_event) + return GTK_WIDGET_CLASS (parent_class)->motion_notify_event (widget, event); if (y - ROW_TOP_YPIXEL (clist, row) < clist->row_height / 4) @@ -632,8 +821,7 @@ gtk_ctree_button_motion (GtkWidget *widget, } } } - return - (* GTK_WIDGET_CLASS (parent_class)->motion_notify_event) (widget, event); + return GTK_WIDGET_CLASS (parent_class)->motion_notify_event (widget, event); } static gint @@ -650,7 +838,7 @@ gtk_ctree_button_release (GtkWidget *widget, ctree = GTK_CTREE (widget); clist = GTK_CLIST (widget); - if (event->button == 1) + if (event->button == 2 && clist->anchor == -1) { gdk_pointer_ungrab (event->time); ctree->in_drag = FALSE; @@ -672,40 +860,13 @@ gtk_ctree_button_release (GtkWidget *widget, draw_xor_line (ctree); ctree->drag_row = -1; } - else - { - if (event->window == clist->clist_window) - { - gint row; - gint column; - GList *work; - - if (gtk_clist_get_selection_info (clist, event->x, event->y, - &row, &column)) - if (row == - (ctree->drag_row + 1) && - (work = g_list_nth (clist->row_list, row))) - { - if (GTK_CTREE_ROW (work)->children && - ctree_is_hot_spot (ctree, work, row, event->x, - event->y)) - return (* GTK_WIDGET_CLASS (parent_class) - ->button_release_event) (widget, event); - tree_toggle_selection (ctree, work, column); - } - return FALSE; - } - return - (* GTK_WIDGET_CLASS (parent_class)->button_release_event) - (widget, event); - } /* nop if out of bounds / source == target */ if (event->x < 0 || event->y < -3 || event->x > clist->clist_window_width || event->y > clist->clist_window_height + 3 || ctree->drag_target == ctree->drag_source) - return - (* GTK_WIDGET_CLASS (parent_class)->button_release_event) + return GTK_WIDGET_CLASS (parent_class)->button_release_event (widget, event); if (!GTK_CTREE_ROW (ctree->drag_source)->children || @@ -746,8 +907,24 @@ gtk_ctree_button_release (GtkWidget *widget, ctree->drag_source = NULL; ctree->drag_target = NULL; } - return - (* GTK_WIDGET_CLASS (parent_class)->button_release_event) (widget, event); + else if (event->button == 1 && GTK_CLIST_DRAG_SELECTION (clist) && + (clist->selection_mode == GTK_SELECTION_SINGLE || + clist->selection_mode == GTK_SELECTION_MULTIPLE)) + { + gint row; + gint column; + GList *work; + + if (gtk_clist_get_selection_info + (clist, event->x, event->y, &row, &column)) + { + if (clist->anchor == clist->focus_row && + (work = g_list_nth (clist->row_list, row))) + tree_toggle_selection (ctree, work, column); + } + clist->anchor = -1; + } + return GTK_WIDGET_CLASS (parent_class)->button_release_event (widget, event); } static void @@ -2246,6 +2423,26 @@ draw_row (GtkCList *clist, } } } + 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); + } + } + 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); + } } static void @@ -2268,8 +2465,8 @@ tree_draw_row (GtkCTree *ctree, num++; } if (gtk_clist_row_is_visible (clist, num) != GTK_VISIBILITY_NONE) - (GTK_CLIST_CLASS (GTK_OBJECT (clist)->klass)->draw_row) - (clist, NULL, num, &(GTK_CTREE_ROW (row)->row)); + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, num, + GTK_CLIST_ROW (row)); } } @@ -2297,11 +2494,12 @@ static void gtk_ctree_link (GtkCTree *ctree, GList *node, GList *parent, - GList *sibling) + GList *sibling, + gboolean update_focus_row) { GtkCList *clist; GList *list_end; - gint visible = TRUE; + gboolean visible = FALSE; gint rows = 0; g_return_if_fail (!sibling || GTK_CTREE_ROW (sibling)->parent == parent); @@ -2311,20 +2509,30 @@ gtk_ctree_link (GtkCTree *ctree, clist = GTK_CLIST (ctree); + if (update_focus_row && clist->selection_mode == GTK_SELECTION_BROWSE) + { + if (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; + } + for (rows = 1, list_end = node; list_end->next; list_end = list_end->next) rows++; GTK_CTREE_ROW (node)->parent = parent; GTK_CTREE_ROW (node)->sibling = sibling; - if (parent) + if (!parent || (parent && (gtk_ctree_is_visible (ctree, parent) && + GTK_CTREE_ROW (parent)->expanded))) { - if ((visible = gtk_ctree_is_visible (ctree, parent)) && - GTK_CTREE_ROW (parent)->expanded) - clist->rows += rows; + visible = TRUE; + clist->rows += rows; } - else - clist->rows += rows; + if (sibling) { @@ -2407,13 +2615,24 @@ gtk_ctree_link (GtkCTree *ctree, if (clist->row_list_end == NULL || clist->row_list_end->next == node) clist->row_list_end = list_end; - if (!GTK_CLIST_FROZEN (clist) && visible) - gtk_clist_thaw (clist); + if (visible && update_focus_row) + { + gint pos; + + pos = g_list_position (clist->row_list, node); + + if (pos <= clist->focus_row) + { + clist->focus_row += rows; + clist->undo_anchor = clist->focus_row; + } + } } static void gtk_ctree_unlink (GtkCTree *ctree, - GList *node) + GList *node, + gboolean update_focus_row) { GtkCList *clist; gint rows; @@ -2428,6 +2647,17 @@ gtk_ctree_unlink (GtkCTree *ctree, clist = GTK_CLIST (ctree); + if (update_focus_row && clist->selection_mode == GTK_SELECTION_BROWSE) + { + if (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; + } + visible = gtk_ctree_is_visible (ctree, node); /* clist->row_list_end unlinked ? */ @@ -2446,6 +2676,24 @@ gtk_ctree_unlink (GtkCTree *ctree, rows++; } + if (visible) + { + clist->rows -= (rows + 1); + + if (update_focus_row) + { + gint pos; + + pos = g_list_position (clist->row_list, node); + if (pos + rows + 1 < clist->focus_row) + clist->focus_row -= (rows + 1); + else if (pos <= clist->focus_row) + clist->focus_row = pos - 1; + clist->undo_anchor = clist->focus_row; + } + } + + if (work) { work->prev->next = NULL; @@ -2499,14 +2747,6 @@ gtk_ctree_unlink (GtkCTree *ctree, GTK_CTREE_ROW (sibling)->sibling = GTK_CTREE_ROW (node)->sibling; } } - - if (visible) - { - clist->rows -= (rows + 1); - - if (!GTK_CLIST_FROZEN (clist)) - gtk_clist_thaw (clist); - } } static void @@ -2534,6 +2774,17 @@ real_tree_move (GtkCTree *ctree, clist = GTK_CLIST (ctree); + if (clist->selection_mode == GTK_SELECTION_BROWSE) + { + if (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; + } + if (ctree->auto_sort) { if (new_parent == GTK_CTREE_ROW (node)->parent) @@ -2558,23 +2809,87 @@ real_tree_move (GtkCTree *ctree, thaw = TRUE; } - gtk_ctree_unlink (ctree, node); - gtk_ctree_link (ctree, node, new_parent, new_sibling); + work = NULL; + if (gtk_ctree_is_visible (ctree, node) || + gtk_ctree_is_visible (ctree, new_sibling)) + work = g_list_nth (clist->row_list, clist->focus_row); + + gtk_ctree_unlink (ctree, node, FALSE); + gtk_ctree_link (ctree, node, new_parent, new_sibling, FALSE); + + if (work) + { + while (work && !gtk_ctree_is_visible (ctree, work)) + work = GTK_CTREE_ROW (work)->parent; + clist->focus_row = g_list_position (clist->row_list, work); + clist->undo_anchor = clist->focus_row; + } if (thaw) gtk_clist_thaw (clist); } +static void +change_focus_row_expansion (GtkCTree *ctree, + GtkCTreeExpansion action) +{ + GtkCList *clist; + GList *node; + + g_return_if_fail (ctree != NULL); + g_return_if_fail (GTK_IS_CTREE (ctree)); + + clist = GTK_CLIST (ctree); + + if (gdk_pointer_is_grabbed ()) + return; + + if (!(node = g_list_nth (clist->row_list, clist->focus_row)) || + GTK_CTREE_ROW (node)->is_leaf || !(GTK_CTREE_ROW (node)->children)) + return; + + switch (action) + { + case GTK_CTREE_EXPANSION_EXPAND: + gtk_ctree_expand (ctree, node); + break; + case GTK_CTREE_EXPANSION_EXPAND_RECURSIVE: + gtk_ctree_expand_recursive (ctree, node); + break; + case GTK_CTREE_EXPANSION_COLLAPSE: + gtk_ctree_collapse (ctree, node); + break; + case GTK_CTREE_EXPANSION_COLLAPSE_RECURSIVE: + gtk_ctree_collapse_recursive (ctree, node); + break; + case GTK_CTREE_EXPANSION_TOGGLE: + gtk_ctree_toggle_expansion (ctree, node); + break; + case GTK_CTREE_EXPANSION_TOGGLE_RECURSIVE: + gtk_ctree_toggle_expansion_recursive (ctree, node); + break; + } +} + static void real_tree_expand (GtkCTree *ctree, GList *node) { + GtkCList *clist; GList *work; gint level; + g_return_if_fail (ctree != NULL); + g_return_if_fail (GTK_IS_CTREE (ctree)); + if (!node || GTK_CTREE_ROW (node)->expanded) return; + clist = GTK_CLIST (ctree); + + if (clist->selection_mode == GTK_SELECTION_EXTENDED && clist->anchor >= 0) + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); + GTK_CTREE_ROW (node)->expanded = TRUE; level = GTK_CTREE_ROW (node)->level; @@ -2591,7 +2906,11 @@ real_tree_expand (GtkCTree *ctree, work = GTK_CTREE_ROW (node)->children; if (work) { + GtkCList *clist; gint tmp = 0; + gint row; + + clist = GTK_CLIST (ctree); while (work->next) { @@ -2604,15 +2923,18 @@ real_tree_expand (GtkCTree *ctree, if (node->next) node->next->prev = work; else - GTK_CLIST (ctree)->row_list_end = work; + clist->row_list_end = work; node->next = GTK_CTREE_ROW (node)->children; if (gtk_ctree_is_visible (ctree, node)) { - GTK_CLIST (ctree)->rows += tmp + 1; + row = g_list_position (clist->row_list, node); + if (row < clist->focus_row) + clist->focus_row += tmp + 1; + clist->rows += tmp + 1; if (!GTK_CLIST_FROZEN (ctree)) - gtk_clist_thaw (GTK_CLIST (ctree)); + gtk_clist_thaw (clist); } } } @@ -2621,12 +2943,21 @@ static void real_tree_collapse (GtkCTree *ctree, GList *node) { + GtkCList *clist; GList *work; gint level; + g_return_if_fail (ctree != NULL); + g_return_if_fail (GTK_IS_CTREE (ctree)); + if (!node || !GTK_CTREE_ROW (node)->expanded) return; + clist = GTK_CLIST (ctree); + + if (clist->selection_mode == GTK_SELECTION_EXTENDED && clist->anchor >= 0) + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); + GTK_CTREE_ROW (node)->expanded = FALSE; level = GTK_CTREE_ROW (node)->level; @@ -2643,7 +2974,11 @@ real_tree_collapse (GtkCTree *ctree, work = GTK_CTREE_ROW (node)->children; if (work) { + GtkCList *clist; gint tmp = 0; + gint row; + + clist = GTK_CLIST (ctree); while (work && GTK_CTREE_ROW (work)->level > level) { @@ -2660,14 +2995,17 @@ real_tree_collapse (GtkCTree *ctree, else { node->next = NULL; - GTK_CLIST (ctree)->row_list_end = node; + clist->row_list_end = node; } if (gtk_ctree_is_visible (ctree, node)) { - GTK_CLIST (ctree)->rows -= tmp; + row = g_list_position (clist->row_list, node); + if (row < clist->focus_row) + clist->focus_row -= tmp; + clist->rows -= tmp; if (!GTK_CLIST_FROZEN (ctree)) - gtk_clist_thaw (GTK_CLIST (ctree)); + gtk_clist_thaw (clist); } } } @@ -2812,8 +3150,8 @@ tree_delete (GtkCTree *ctree, work = g_list_find (clist->selection, node); if (work) { - if (ctree->selection_last && ctree->selection_last == work) - ctree->selection_last = ctree->selection_last->prev; + if (clist->selection_end && clist->selection_end == work) + clist->selection_end = clist->selection_end->prev; clist->selection = g_list_remove (clist->selection, node); } } @@ -2886,6 +3224,22 @@ tree_collapse (GtkCTree *ctree, data); } +static void +tree_toggle_expansion (GtkCTree *ctree, + GList *node, + gpointer data) +{ + if (!node) + return; + + if (GTK_CTREE_ROW (node)->expanded) + gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], node, + data); + else + gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_EXPAND], node, + data); +} + static GtkCTreeRow * row_new (GtkCTree *ctree) { @@ -3003,12 +3357,46 @@ cell_empty (GtkCList *clist, } static void +real_select_row (GtkCList *clist, + gint row, + gint column, + GdkEvent *event) +{ + GList *node; + + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CTREE (clist)); + + if ((node = g_list_nth (clist->row_list, row))) + gtk_signal_emit (GTK_OBJECT (clist), ctree_signals[TREE_SELECT_ROW], + node, event); +} + +static void +real_unselect_row (GtkCList *clist, + gint row, + gint column, + GdkEvent *event) +{ + GList *node; + + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CTREE (clist)); + + if ((node = g_list_nth (clist->row_list, row))) + gtk_signal_emit (GTK_OBJECT (clist), ctree_signals[TREE_UNSELECT_ROW], + node, event); +} + +static void real_tree_select (GtkCTree *ctree, GList *node, gint column) { GtkCList *clist; - GList *selection; + GList *list; + GList *sel_row; + gboolean node_selected; g_return_if_fail (ctree != NULL); @@ -3017,15 +3405,12 @@ real_tree_select (GtkCTree *ctree, clist = GTK_CLIST (ctree); - if (GTK_CTREE_ROW (node)->row.state == GTK_STATE_SELECTED) - return; - - if (clist->selection_mode == GTK_SELECTION_SINGLE || - clist->selection_mode == GTK_SELECTION_BROWSE) + switch (clist->selection_mode) { - GList *list; - GList *sel_row; + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_BROWSE: + node_selected = FALSE; list = clist->selection; while (list) @@ -3033,27 +3418,29 @@ real_tree_select (GtkCTree *ctree, sel_row = list->data; list = list->next; - if (node != sel_row && - GTK_CTREE_ROW (sel_row)->row.state == GTK_STATE_SELECTED) - gtk_signal_emit (GTK_OBJECT (ctree), - ctree_signals[TREE_UNSELECT_ROW], sel_row, - column); + if (node == sel_row) + node_selected = TRUE; + else + gtk_signal_emit (GTK_OBJECT (ctree), + ctree_signals[TREE_UNSELECT_ROW], sel_row, column); } + + if (node_selected) + return; + + default: + break; } GTK_CTREE_ROW (node)->row.state = GTK_STATE_SELECTED; - selection = g_list_alloc (); - selection->data = node; - if (ctree->selection_last) + if (!clist->selection) { - ctree->selection_last->next = selection; - selection->prev = ctree->selection_last; + clist->selection = g_list_append (clist->selection, node); + clist->selection_end = clist->selection; } - else - clist->selection = selection; - - ctree->selection_last = selection; + else + clist->selection_end = g_list_append (clist->selection_end, node)->next; tree_draw_row (ctree, node); } @@ -3070,15 +3457,16 @@ real_tree_unselect (GtkCTree *ctree, if (!node) return; + clist = GTK_CLIST (ctree); + if (GTK_CTREE_ROW (node)->row.state != GTK_STATE_SELECTED) return; - clist = GTK_CLIST (ctree); - - if (ctree->selection_last && ctree->selection_last->data == node) - ctree->selection_last = ctree->selection_last->prev; + if (clist->selection_end && clist->selection_end->data == node) + clist->selection_end = clist->selection_end->prev; clist->selection = g_list_remove (clist->selection, node); + GTK_CTREE_ROW (node)->row.state = GTK_STATE_NORMAL; tree_draw_row (ctree, node); @@ -3089,7 +3477,14 @@ tree_toggle_selection (GtkCTree *ctree, GList *node, gint column) { - switch (GTK_CLIST (ctree)->selection_mode) + GtkCList *clist; + + g_return_if_fail (ctree != NULL); + g_return_if_fail (GTK_IS_CTREE (ctree)); + + clist = GTK_CLIST (ctree); + + switch (clist->selection_mode) { case GTK_SELECTION_SINGLE: case GTK_SELECTION_MULTIPLE: @@ -3109,10 +3504,117 @@ tree_toggle_selection (GtkCTree *ctree, case GTK_SELECTION_EXTENDED: break; + } +} + +static void +select_row_recursive (GtkCTree *ctree, + GList *node, + gpointer data) +{ + if (!node || GTK_CTREE_ROW (node)->row.state == GTK_STATE_SELECTED) + return; + + GTK_CLIST (ctree)->undo_unselection = + g_list_prepend (GTK_CLIST (ctree)->undo_unselection, node); + gtk_ctree_select (ctree, node); +} + +static void +real_select_all (GtkCList *clist) +{ + GtkCTree *ctree; + GList *node; + gboolean thaw = FALSE; + + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CTREE (clist)); + + ctree = GTK_CTREE (clist); + + switch (clist->selection_mode) + { + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_BROWSE: + return; + + case GTK_SELECTION_EXTENDED: + + if (!GTK_CLIST_FROZEN (clist)) + { + gtk_clist_freeze (clist); + thaw = TRUE; + } + + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + + clist->anchor_state = GTK_STATE_SELECTED; + clist->anchor = -1; + clist->drag_pos = -1; + clist->undo_anchor = clist->focus_row; + + for (node = clist->row_list; node; node = node->next) + gtk_ctree_pre_recursive (ctree, node, select_row_recursive, NULL); + + if (thaw) + gtk_clist_thaw (clist); + break; + + case GTK_SELECTION_MULTIPLE: + gtk_ctree_select_recursive (ctree, NULL); + break;; + } +} + +static void +real_unselect_all (GtkCList *clist) +{ + GtkCTree *ctree; + GList *list; + GList *node; + + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CTREE (clist)); + + ctree = GTK_CTREE (clist); + + switch (clist->selection_mode) + { + case GTK_SELECTION_BROWSE: + if (clist->focus_row >= 0) + { + gtk_ctree_select + (ctree, g_list_nth (clist->row_list, clist->focus_row)); + 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; + + clist->anchor = -1; + clist->drag_pos = -1; + clist->undo_anchor = clist->focus_row; + break; default: break; } + + list = clist->selection; + + while (list) + { + node = list->data; + list = list->next; + gtk_ctree_unselect (ctree, node); + } } static gboolean @@ -3290,7 +3792,10 @@ gtk_ctree_insert (GtkCTree *ctree, sibling = GTK_CTREE_ROW (sibling)->sibling; } - gtk_ctree_link (ctree, node, parent, sibling); + gtk_ctree_link (ctree, node, parent, sibling, TRUE); + + if (!GTK_CLIST_FROZEN (clist)) + gtk_clist_thaw (clist); return node; } @@ -3315,55 +3820,40 @@ gtk_ctree_remove (GtkCTree *ctree, if (node) { - gtk_ctree_unlink (ctree, node); - gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (tree_delete), + gtk_ctree_unlink (ctree, node, TRUE); + gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (tree_delete), NULL); } else - { - GList *work; - GList *ptr; - - work = clist->row_list; - clist->row_list = NULL; - clist->row_list_end = NULL; - clist->rows = 0; - - while (work) - { - ptr = work; - work = GTK_CTREE_ROW (work)->sibling; - gtk_ctree_post_recursive (ctree, ptr, GTK_CTREE_FUNC (tree_delete), - NULL); - } - } + gtk_clist_clear (clist); if (thaw) gtk_clist_thaw (clist); } -void -gtk_ctree_clear (GtkCTree *ctree) +static void +real_clear (GtkCList *clist) { - GtkCList *clist; + GtkCTree *ctree; GList *work; GList *ptr; - g_return_if_fail (ctree != NULL); - g_return_if_fail (GTK_IS_CTREE (ctree)); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CTREE (clist)); - clist = GTK_CLIST (ctree); + ctree = GTK_CTREE (clist); - /* free up the selection list */ - g_list_free (clist->selection); - clist->selection = NULL; - ctree->selection_last = NULL; + ctree->drag_row = -1; + ctree->drag_rect = FALSE; + ctree->in_drag = FALSE; + ctree->drag_source = NULL; + ctree->drag_target = NULL; + ctree->drag_icon = NULL; /* remove all the rows */ work = clist->row_list; clist->row_list = NULL; clist->row_list_end = NULL; - clist->rows = 0; while (work) { @@ -3373,25 +3863,7 @@ gtk_ctree_clear (GtkCTree *ctree) NULL); } - clist->voffset = 0; - - ctree->drag_row = -1; - ctree->drag_rect = FALSE; - ctree->in_drag = FALSE; - ctree->drag_source = NULL; - ctree->drag_target = NULL; - ctree->drag_icon = NULL; - - /* zero-out the scrollbars */ - if (clist->vscrollbar) - { - 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); - } + (parent_class->clear) (clist); } @@ -3422,7 +3894,8 @@ gtk_ctree_post_recursive (GtkCTree *ctree, work = tmp; } - (* func) (ctree, node, data); + if (node) + func (ctree, node, data); } void @@ -3434,10 +3907,12 @@ gtk_ctree_pre_recursive (GtkCTree *ctree, GList *work; GList *tmp; - (* func) (ctree, node, data); if (node) - work = GTK_CTREE_ROW (node)->children; + { + work = GTK_CTREE_ROW (node)->children; + func (ctree, node, data); + } else work = GTK_CLIST (ctree)->row_list; @@ -3595,6 +4070,9 @@ gtk_ctree_expand (GtkCTree *ctree, g_return_if_fail (ctree != NULL); g_return_if_fail (node != NULL); + if (GTK_CTREE_ROW (node)->is_leaf) + return; + gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_EXPAND], node); } @@ -3609,7 +4087,7 @@ gtk_ctree_expand_recursive (GtkCTree *ctree, clist = GTK_CLIST (ctree); - if (node && !GTK_CTREE_ROW (node)->children) + if (node && GTK_CTREE_ROW (node)->is_leaf) return; if (((node && gtk_ctree_is_visible (ctree, node)) || !node) && @@ -3632,6 +4110,9 @@ gtk_ctree_collapse (GtkCTree *ctree, g_return_if_fail (ctree != NULL); g_return_if_fail (node != NULL); + if (GTK_CTREE_ROW (node)->is_leaf) + return; + gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], node); } @@ -3644,11 +4125,11 @@ gtk_ctree_collapse_recursive (GtkCTree *ctree, g_return_if_fail (ctree != NULL); - clist = GTK_CLIST (ctree); - - if (node && !GTK_CTREE_ROW (node)->children) + if (node && GTK_CTREE_ROW (node)->is_leaf) return; + clist = GTK_CLIST (ctree); + if (((node && gtk_ctree_is_visible (ctree, node)) || !node) && !GTK_CLIST_FROZEN (clist)) { @@ -3663,6 +4144,47 @@ gtk_ctree_collapse_recursive (GtkCTree *ctree, } void +gtk_ctree_toggle_expansion (GtkCTree *ctree, + GList *node) +{ + g_return_if_fail (ctree != NULL); + g_return_if_fail (node != NULL); + + if (GTK_CTREE_ROW (node)->is_leaf) + return; + + tree_toggle_expansion (ctree, node, NULL); +} + +void +gtk_ctree_toggle_expansion_recursive (GtkCTree *ctree, + GList *node) +{ + GtkCList *clist; + gboolean thaw = FALSE; + + g_return_if_fail (ctree != NULL); + + if (node && GTK_CTREE_ROW (node)->is_leaf) + return; + + clist = GTK_CLIST (ctree); + + if (((node && gtk_ctree_is_visible (ctree, node)) || !node) && + !GTK_CLIST_FROZEN (clist)) + { + gtk_clist_freeze (clist); + thaw = TRUE; + } + + gtk_ctree_post_recursive (ctree, node, + GTK_CTREE_FUNC (tree_toggle_expansion), NULL); + + if (thaw) + gtk_clist_thaw (clist); +} + +void gtk_ctree_select (GtkCTree *ctree, GList *node) { @@ -3708,8 +4230,9 @@ gtk_ctree_real_select_recursive (GtkCTree *ctree, clist = GTK_CLIST (ctree); - if (clist->selection_mode == GTK_SELECTION_EXTENDED || - (state && clist->selection_mode != GTK_SELECTION_MULTIPLE) || + if ((state && + (clist->selection_mode != GTK_SELECTION_MULTIPLE || + clist->selection_mode == GTK_SELECTION_EXTENDED)) || (!state && clist->selection_mode == GTK_SELECTION_BROWSE)) return; @@ -4053,53 +4576,6 @@ gtk_ctree_set_background (GtkCTree *ctree, } void -gtk_ctree_set_selection_mode (GtkCTree *ctree, - GtkSelectionMode mode) -{ - GtkCList *clist; - GList *selection; - GList *work; - gboolean thaw = FALSE; - - g_return_if_fail (ctree != NULL); - g_return_if_fail (GTK_IS_CTREE (ctree)); - - clist = GTK_CLIST (ctree); - - if (mode == clist->selection_mode) - return; - - clist->selection_mode = mode; - - if (mode == GTK_SELECTION_MULTIPLE) - return; - - selection = clist->selection; - if (selection && mode == GTK_SELECTION_BROWSE) - selection = selection->next; - - if (!selection) - return; - - if (!GTK_CLIST_FROZEN (clist)) - { - gtk_clist_freeze (clist); - thaw = TRUE; - } - - while (selection) - { - work = selection->data; - selection = selection->next; - gtk_signal_emit (GTK_OBJECT (ctree), - ctree_signals[TREE_UNSELECT_ROW], work); - } - - if (thaw) - gtk_clist_thaw (clist); -} - -void gtk_ctree_set_row_data (GtkCTree *ctree, GList *node, gpointer data) @@ -4131,62 +4607,27 @@ gtk_ctree_get_row_data (GtkCTree *ctree, } void -gtk_ctree_scroll_to (GtkCTree *ctree, - GList *node, - gint column, - gfloat row_align, - gfloat col_align) +gtk_ctree_moveto (GtkCTree *ctree, + GList *node, + gint column, + gfloat row_align, + gfloat col_align) { - gint x; - gint y; - gint row = 0; + gint row = -1; GtkCList *clist; - GList *work; - GtkAdjustment *adj; g_return_if_fail (ctree != NULL); g_return_if_fail (GTK_IS_CTREE (ctree)); clist = GTK_CLIST (ctree); - if (node && !gtk_ctree_is_visible (ctree, node)) - return; + while (node && !gtk_ctree_is_visible (ctree, node)) + node = GTK_CTREE_ROW (node)->parent; - /* adjust vertical scrollbar */ if (node) - { - adj = GTK_RANGE (clist->vscrollbar)->adjustment; - work = clist->row_list; - while (work && work != node) - { - work = work->next; - row++; - } - - if (!work) - return; - - y = ROW_TOP_YPIXEL (clist, row) - clist->voffset; - - y = y - row_align * (clist->clist_window_height - clist->row_height) - + (2 * row_align - 1) * CELL_SPACING; - - if (y + adj->page_size > adj->upper) - gtk_adjustment_set_value (adj, adj->upper - adj->page_size); - else - gtk_adjustment_set_value (adj, y); - } - - /* adjust horizontal scrollbar */ - if (column >= 0) - { - adj = GTK_RANGE (clist->hscrollbar)->adjustment; - x = COLUMN_LEFT (clist, column); - x = x - col_align * - (clist->clist_window_width - clist->column[column].area.width) - + (2 * col_align - 1) * COLUMN_INSET; - gtk_adjustment_set_value (adj, x); - } + row = g_list_position (clist->row_list, node); + + gtk_clist_moveto (clist, row, column, row_align, col_align); } @@ -4350,8 +4791,8 @@ tree_sort (GtkCTree *ctree, list_start = GTK_CTREE_ROW (max)->sibling; else { - gtk_ctree_unlink (ctree,max); - gtk_ctree_link (ctree, max, node, list_start); + gtk_ctree_unlink (ctree, max, FALSE); + gtk_ctree_link (ctree, max, node, list_start, FALSE); } } } @@ -4361,6 +4802,7 @@ gtk_ctree_sort_recursive (GtkCTree *ctree, GList *node) { GtkCList *clist; + GList *focus_node = NULL; gboolean thaw = FALSE; g_return_if_fail (ctree != NULL); @@ -4374,8 +4816,28 @@ gtk_ctree_sort_recursive (GtkCTree *ctree, thaw = TRUE; } + if (clist->selection_mode == GTK_SELECTION_BROWSE) + { + if (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; + } + + if (gtk_ctree_is_visible (ctree, node)) + focus_node = g_list_nth (clist->row_list, clist->focus_row); + gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (tree_sort), NULL); + if (focus_node) + { + clist->focus_row = g_list_position (clist->row_list, focus_node); + clist->undo_anchor = clist->focus_row; + } + if (thaw) gtk_clist_thaw (clist); } @@ -4385,6 +4847,7 @@ gtk_ctree_sort (GtkCTree *ctree, GList *node) { GtkCList *clist; + GList *focus_node = NULL; gboolean thaw = FALSE; g_return_if_fail (ctree != NULL); @@ -4398,8 +4861,209 @@ gtk_ctree_sort (GtkCTree *ctree, thaw = TRUE; } + if (clist->selection_mode == GTK_SELECTION_BROWSE) + { + if (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; + } + + if (gtk_ctree_is_visible (ctree, node)) + focus_node = g_list_nth (clist->row_list, clist->focus_row); + tree_sort (ctree, node, NULL); + if (focus_node) + { + clist->focus_row = g_list_position (clist->row_list, focus_node); + clist->undo_anchor = clist->focus_row; + } + if (thaw) gtk_clist_thaw (clist); } + +/************************************************************************/ + +static void +fake_unselect_all (GtkCList *clist, + gint row) +{ + GList *list; + GList *focus_node = NULL; + + if (row >= 0 && (focus_node = g_list_nth (clist->row_list, row))) + { + if (GTK_CTREE_ROW (focus_node)->row.state == GTK_STATE_NORMAL) + { + GTK_CTREE_ROW (focus_node)->row.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 (focus_node)); + } + } + + clist->undo_selection = clist->selection; + clist->selection = NULL; + clist->selection_end = NULL; + + for (list = clist->undo_selection; list; list = list->next) + { + if (list->data == focus_node) + continue; + + GTK_CTREE_ROW ((GList *)(list->data))->row.state = GTK_STATE_NORMAL; + tree_draw_row (GTK_CTREE (clist), (GList *)(list->data)); + } +} + +static GList * +selection_find (GtkCList *clist, + gint row_number, + GList *row_list_element) +{ + return g_list_find (clist->selection, row_list_element); +} + +static void +resync_selection (GtkCList *clist, GdkEvent *event) +{ + GtkCTree *ctree; + GList *list; + GList *node; + gint i; + gint e; + gint row; + gboolean thaw = FALSE; + gboolean unselect; + + if (clist->anchor < 0) + return; + + ctree = GTK_CTREE (clist); + + if (!GTK_CLIST_FROZEN (clist)) + { + GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN); + thaw = TRUE; + } + + 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) + { + node = list->data; + list = list->next; + + unselect = TRUE; + + if (gtk_ctree_is_visible (ctree, node)) + { + row = g_list_position (clist->row_list, node); + if (row >= i && row <= e) + unselect = FALSE; + } + if (unselect) + { + GTK_CTREE_ROW (node)->row.state = GTK_STATE_SELECTED; + gtk_ctree_unselect (ctree, node); + clist->undo_selection = g_list_prepend (clist->undo_selection, + node); + } + } + } + + + for (node = g_list_nth (clist->row_list, i); i <= e; i++, node = node->next) + if (g_list_find (clist->selection, node)) + { + if (GTK_CTREE_ROW (node)->row.state == GTK_STATE_NORMAL) + { + GTK_CTREE_ROW (node)->row.state = GTK_STATE_SELECTED; + gtk_ctree_unselect (ctree, node); + clist->undo_selection = g_list_prepend (clist->undo_selection, + node); + } + } + else if (GTK_CTREE_ROW (node)->row.state == GTK_STATE_SELECTED) + { + GTK_CTREE_ROW (node)->row.state = GTK_STATE_NORMAL; + clist->undo_unselection = g_list_prepend (clist->undo_unselection, + node); + } + + for (list = clist->undo_unselection; list; list = list->next) + gtk_ctree_select (ctree, list->data); + + clist->anchor = -1; + clist->drag_pos = -1; + + if (thaw) + GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN); +} + +static void +real_undo_selection (GtkCList *clist) +{ + GtkCTree *ctree; + GList *work; + + + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (clist->selection_mode != GTK_SELECTION_EXTENDED) + return; + + if (!(clist->undo_selection || clist->undo_unselection)) + { + gtk_clist_unselect_all (clist); + return; + } + + ctree = GTK_CTREE (clist); + + for (work = clist->undo_selection; work; work = work->next) + gtk_ctree_select (ctree, (GList *) work->data); + + for (work = clist->undo_unselection; work; work = work->next) + gtk_ctree_unselect (ctree, (GList *) work->data); + + if (GTK_WIDGET_HAS_FOCUS (clist) && clist->focus_row != clist->undo_anchor) + { + gtk_widget_draw_focus (GTK_WIDGET (clist)); + clist->focus_row = clist->undo_anchor; + gtk_widget_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; + + 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); + +} diff --git a/gtk/gtkctree.h b/gtk/gtkctree.h index 7f2fdc33c3..d13f6ca1c4 100644 --- a/gtk/gtkctree.h +++ b/gtk/gtkctree.h @@ -37,7 +37,7 @@ extern "C" (GTK_CHECK_CLASS_CAST ((klass), gtk_ctree_get_type (), GtkCTreeClass)) #define GTK_IS_CTREE(obj) \ (GTK_CHECK_TYPE ((obj), gtk_ctree_get_type ())) -#define GTK_CTREE_ROW(glist) ((GtkCTreeRow *)((glist)->data)) +#define GTK_CTREE_ROW(_glist_) ((GtkCTreeRow *)((_glist_)->data)) #define GTK_CTREE_TREE(_ctree_, _glist_) \ ((GtkCellTree *) &(((GtkCTreeRow *)((_glist_)->data))->cell[(_ctree_)->tree_col])) @@ -58,6 +58,16 @@ typedef enum GTK_CTREE_LINES_NONE } GtkCTreeLineStyle; +typedef enum +{ + GTK_CTREE_EXPANSION_EXPAND, + GTK_CTREE_EXPANSION_EXPAND_RECURSIVE, + GTK_CTREE_EXPANSION_COLLAPSE, + GTK_CTREE_EXPANSION_COLLAPSE_RECURSIVE, + GTK_CTREE_EXPANSION_TOGGLE, + GTK_CTREE_EXPANSION_TOGGLE_RECURSIVE +} GtkCTreeExpansion; + typedef struct _GtkCTree GtkCTree; typedef struct _GtkCTreeClass GtkCTreeClass; typedef struct _GtkCTreeRow GtkCTreeRow; @@ -82,7 +92,6 @@ struct _GtkCTree gint tree_indent; gint tree_column; - GList *selection_last; gint drag_row; GList *drag_source; GList *drag_target; @@ -115,6 +124,8 @@ struct _GtkCTreeClass GList *node, GList *new_parent, GList *new_sibling); + void (*change_focus_row_expansion) (GtkCTree *ctree, + GtkCTreeExpansion action); }; struct _GtkCTreeRow @@ -164,7 +175,6 @@ GList * gtk_ctree_insert (GtkCTree *ctree, gboolean expanded); void gtk_ctree_remove (GtkCTree *ctree, GList *node); -void gtk_ctree_clear (GtkCTree *ctree); /*********************************************************** * Generic recursive functions, querying / finding tree * @@ -214,6 +224,10 @@ void gtk_ctree_collapse (GtkCTree *ctree, GList *node); void gtk_ctree_collapse_recursive (GtkCTree *ctree, GList *node); +void gtk_ctree_toggle_expansion (GtkCTree *ctree, + GList *node); +void gtk_ctree_toggle_expansion_recursive (GtkCTree *ctree, + GList *node); void gtk_ctree_select (GtkCTree *ctree, GList *node); void gtk_ctree_select_recursive (GtkCTree *ctree, @@ -296,8 +310,6 @@ void gtk_ctree_set_foreground (GtkCTree *ctree, void gtk_ctree_set_background (GtkCTree *ctree, GList *node, GdkColor *color); -void gtk_ctree_set_selection_mode (GtkCTree *ctree, - GtkSelectionMode mode); void gtk_ctree_set_row_data (GtkCTree *ctree, GList *node, gpointer data); @@ -307,7 +319,7 @@ void gtk_ctree_set_row_data_full (GtkCTree *ctree, GtkDestroyNotify destroy); gpointer gtk_ctree_get_row_data (GtkCTree *ctree, GList *node); -void gtk_ctree_scroll_to (GtkCTree *ctree, +void gtk_ctree_moveto (GtkCTree *ctree, GList *node, gint column, gfloat row_align, diff --git a/gtk/testgtk.c b/gtk/testgtk.c index 2042ae8749..5f99a8336f 100644 --- a/gtk/testgtk.c +++ b/gtk/testgtk.c @@ -3034,12 +3034,14 @@ create_list (void) gtk_widget_destroy (window); } + /* * GtkCList */ -#define TESTGTK_CLIST_COLUMNS 7 + +#define TESTGTK_CLIST_COLUMNS 20 static gint clist_rows = 0; -static gint clist_selected_row = 0; +static GtkWidget *clist_omenu; static void add1000_clist (GtkWidget *widget, gpointer data) @@ -3101,7 +3103,6 @@ add10000_clist (GtkWidget *widget, gpointer data) gtk_clist_append (GTK_CLIST (data), texts); } gtk_clist_thaw (GTK_CLIST (data)); - } void @@ -3114,7 +3115,7 @@ clear_clist (GtkWidget *widget, gpointer data) void remove_row_clist (GtkWidget *widget, gpointer data) { - gtk_clist_remove (GTK_CLIST (data), clist_selected_row); + gtk_clist_remove (GTK_CLIST (data), GTK_CLIST (data)->focus_row); clist_rows--; } @@ -3134,7 +3135,8 @@ void select_clist (GtkWidget *widget, gint row, gint column, - GdkEventButton * bevent) + GdkEventButton * bevent, + GtkWidget *button) { gint i; guint8 spacing; @@ -3187,15 +3189,14 @@ select_clist (GtkWidget *widget, } g_print ("\n\n\n"); - - clist_selected_row = row; } void unselect_clist (GtkWidget *widget, gint row, gint column, - GdkEventButton * bevent) + GdkEventButton * bevent, + GtkWidget *button) { gint i; guint8 spacing; @@ -3248,8 +3249,6 @@ unselect_clist (GtkWidget *widget, } g_print ("\n\n\n"); - - clist_selected_row = row; } static void @@ -3257,16 +3256,14 @@ insert_row_clist (GtkWidget *widget, gpointer data) { static char *text[] = { - "This", - "is", - "a", - "inserted", - "row", - "la la la la la", - "la la la la" + "This", "is", "a", "inserted", "row.", + "This", "is", "a", "inserted", "row.", + "This", "is", "a", "inserted", "row.", + "This", "is", "a", "inserted", "row." }; - gtk_clist_insert (GTK_CLIST (data), clist_selected_row, text); + gtk_clist_insert (GTK_CLIST (data), GTK_CLIST (data)->focus_row, text); + clist_rows++; } @@ -3297,6 +3294,36 @@ clist_warning_test (GtkWidget *button, } static void +undo_selection (GtkWidget *button, GtkCList *clist) +{ + gtk_clist_undo_selection (clist); +} + +#define RADIOMENUTOGGLED(_rmi_, __i) { \ + GSList * __g; \ + __i = 0; \ + __g = gtk_radio_menu_item_group(_rmi_); \ + while( __g && !((GtkCheckMenuItem *)(__g->data))->active) { \ + __g = __g->next; \ + __i++; \ + }\ +} + +static void +clist_toggle_sel_mode (GtkWidget *widget, GtkCList *clist) +{ + gint i; + + if (!GTK_WIDGET_MAPPED (widget)) + return; + + RADIOMENUTOGGLED ((GtkRadioMenuItem *) + (((GtkOptionMenu *)clist_omenu)->menu_item), i); + + gtk_clist_set_selection_mode (clist, (GtkSelectionMode) (3-i)); +} + +static void create_clist (void) { gint i; @@ -3310,7 +3337,20 @@ create_clist (void) "Title 3", "Title 4", "Title 5", - "Title 6" + "Title 6", + "Title 7", + "Title 8", + "Title 9", + "Title 10", + "Title 11", + "Title 12", + "Title 13", + "Title 14", + "Title 15", + "Title 16", + "Title 17", + "Title 18", + "Title 19" }; char text[TESTGTK_CLIST_COLUMNS][50]; @@ -3322,9 +3362,15 @@ create_clist (void) GtkWidget *button; GtkWidget *separator; + GtkWidget *undo_button; + GtkWidget *label; + GtkWidget *menu; + GtkWidget *menu_item; + GSList *group; if (!window) { + clist_rows = 0; window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_signal_connect (GTK_OBJECT (window), "destroy", @@ -3334,16 +3380,12 @@ create_clist (void) gtk_window_set_title (GTK_WINDOW (window), "clist"); gtk_container_border_width (GTK_CONTAINER (window), 0); - box1 = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (window), box1); - gtk_widget_show (box1); - box2 = gtk_hbox_new (FALSE, 10); gtk_container_border_width (GTK_CONTAINER (box2), 10); gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0); - gtk_widget_show (box2); /* create GtkCList here so we have a pointer to throw at the * button callbacks -- more is done with it later */ @@ -3359,9 +3401,6 @@ create_clist (void) (GtkSignalFunc) add1000_clist, (gpointer) clist); - gtk_widget_show (button); - - button = gtk_button_new_with_label ("Add 10,000 Rows"); gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); @@ -3370,8 +3409,6 @@ create_clist (void) (GtkSignalFunc) add10000_clist, (gpointer) clist); - gtk_widget_show (button); - button = gtk_button_new_with_label ("Clear List"); gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); @@ -3380,8 +3417,6 @@ create_clist (void) (GtkSignalFunc) clear_clist, (gpointer) clist); - gtk_widget_show (button); - button = gtk_button_new_with_label ("Remove Row"); gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); @@ -3390,13 +3425,10 @@ create_clist (void) (GtkSignalFunc) remove_row_clist, (gpointer) clist); - gtk_widget_show (button); - /* second layer of buttons */ box2 = gtk_hbox_new (FALSE, 10); gtk_container_border_width (GTK_CONTAINER (box2), 10); gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0); - gtk_widget_show (box2); button = gtk_button_new_with_label ("Insert Row"); gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); @@ -3406,8 +3438,6 @@ create_clist (void) (GtkSignalFunc) insert_row_clist, (gpointer) clist); - gtk_widget_show (button); - button = gtk_button_new_with_label ("Show Title Buttons"); gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); @@ -3416,8 +3446,6 @@ create_clist (void) (GtkSignalFunc) show_titles_clist, (gpointer) clist); - gtk_widget_show (button); - button = gtk_button_new_with_label ("Hide Title Buttons"); gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); @@ -3426,8 +3454,6 @@ create_clist (void) (GtkSignalFunc) hide_titles_clist, (gpointer) clist); - gtk_widget_show (button); - button = gtk_button_new_with_label ("Warning Test"); gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); @@ -3436,41 +3462,96 @@ create_clist (void) (GtkSignalFunc) clist_warning_test, (gpointer) clist); - gtk_widget_show (button); + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0); + + undo_button = gtk_button_new_with_label ("Undo last selection"); + gtk_box_pack_start (GTK_BOX (box2), undo_button, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (undo_button), + "clicked", + (GtkSignalFunc) undo_selection, + (gpointer) clist); + + label = gtk_label_new ("Selection Mode :"); + gtk_box_pack_start (GTK_BOX (box2), label, FALSE, TRUE, 0); + + clist_omenu = gtk_option_menu_new (); + + menu = gtk_menu_new (); + group = NULL; + + menu_item = gtk_radio_menu_item_new_with_label (group, "Single"); + gtk_signal_connect (GTK_OBJECT (menu_item), "activate", + GTK_SIGNAL_FUNC (clist_toggle_sel_mode), clist); + group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menu_item)); + gtk_menu_append (GTK_MENU (menu), menu_item); + gtk_widget_show (menu_item); + + menu_item = gtk_radio_menu_item_new_with_label (group, "Browse"); + gtk_signal_connect (GTK_OBJECT (menu_item), "activate", + GTK_SIGNAL_FUNC (clist_toggle_sel_mode), clist); + group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menu_item)); + gtk_menu_append (GTK_MENU (menu), menu_item); + gtk_widget_show (menu_item); + + menu_item = gtk_radio_menu_item_new_with_label (group, "Multiple"); + gtk_signal_connect (GTK_OBJECT (menu_item), "activate", + GTK_SIGNAL_FUNC (clist_toggle_sel_mode), clist); + group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menu_item)); + gtk_menu_append (GTK_MENU (menu), menu_item); + gtk_widget_show (menu_item); + + menu_item = gtk_radio_menu_item_new_with_label (group, "Extended"); + gtk_signal_connect (GTK_OBJECT (menu_item), "activate", + GTK_SIGNAL_FUNC (clist_toggle_sel_mode), clist); + group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menu_item)); + gtk_menu_append (GTK_MENU (menu), menu_item); + gtk_check_menu_item_set_state (GTK_CHECK_MENU_ITEM (menu_item), TRUE); + gtk_widget_show (menu_item); + + gtk_option_menu_set_menu (GTK_OPTION_MENU (clist_omenu), menu); + gtk_box_pack_start (GTK_BOX (box2), clist_omenu, FALSE, TRUE, 0); + + gtk_option_menu_set_history (GTK_OPTION_MENU (clist_omenu), 3); /* vbox for the list itself */ box2 = gtk_vbox_new (FALSE, 10); gtk_container_border_width (GTK_CONTAINER (box2), 10); gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); - gtk_widget_show (box2); /* * the rest of the clist configuration */ - gtk_clist_set_row_height (GTK_CLIST (clist), 20); - + + /* gtk_signal_connect (GTK_OBJECT (clist), "select_row", (GtkSignalFunc) select_clist, - NULL); + undo_button); gtk_signal_connect (GTK_OBJECT (clist), "unselect_row", (GtkSignalFunc) unselect_clist, - NULL); + undo_button); + */ + + gtk_clist_set_row_height (GTK_CLIST (clist), 18); + gtk_widget_set_usize (clist, -1, 300); gtk_clist_set_column_width (GTK_CLIST (clist), 0, 100); for (i = 1; i < TESTGTK_CLIST_COLUMNS; i++) gtk_clist_set_column_width (GTK_CLIST (clist), i, 80); - gtk_clist_set_selection_mode (GTK_CLIST (clist), GTK_SELECTION_BROWSE); - gtk_clist_set_policy (GTK_CLIST (clist), - GTK_POLICY_AUTOMATIC, + gtk_clist_set_selection_mode (GTK_CLIST (clist), GTK_SELECTION_EXTENDED); + gtk_clist_set_policy (GTK_CLIST (clist), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_clist_set_column_justification (GTK_CLIST (clist), 1, GTK_JUSTIFY_RIGHT); - gtk_clist_set_column_justification (GTK_CLIST (clist), 2, GTK_JUSTIFY_CENTER); + gtk_clist_set_column_justification (GTK_CLIST (clist), 1, + GTK_JUSTIFY_RIGHT); + gtk_clist_set_column_justification (GTK_CLIST (clist), 2, + GTK_JUSTIFY_CENTER); for (i = 0; i < TESTGTK_CLIST_COLUMNS; i++) { @@ -3481,7 +3562,7 @@ create_clist (void) sprintf (text[1], "Right"); sprintf (text[2], "Center"); - for (i = 0; i < 100; i++) + for (i = 0; i < 10; i++) { sprintf (text[0], "Row %d", clist_rows++); gtk_clist_append (GTK_CLIST (clist), texts); @@ -3489,17 +3570,13 @@ create_clist (void) gtk_container_border_width (GTK_CONTAINER (clist), 5); gtk_box_pack_start (GTK_BOX (box2), clist, TRUE, TRUE, 0); - gtk_widget_show (clist); - separator = gtk_hseparator_new (); gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); - gtk_widget_show (separator); box2 = gtk_vbox_new (FALSE, 10); gtk_container_border_width (GTK_CONTAINER (box2), 10); gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); - gtk_widget_show (box2); button = gtk_button_new_with_label ("close"); gtk_signal_connect_object (GTK_OBJECT (button), "clicked", @@ -3509,21 +3586,17 @@ create_clist (void) gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_widget_grab_default (button); - - gtk_widget_show (button); } if (!GTK_WIDGET_VISIBLE (window)) - gtk_widget_show (window); + gtk_widget_show_all (window); else { clist_rows = 0; gtk_widget_destroy (window); } - } - /* * GtkCTree */ @@ -3621,26 +3694,6 @@ static GtkWidget *spin2; static GtkWidget *spin3; static GdkColor *col_bg; -#define RADIOMENUTOGGLED(_rmi_, __i) { \ - GSList * __g; \ - __i = 0; \ - __g = gtk_radio_menu_item_group(_rmi_); \ - while( __g && !((GtkCheckMenuItem *)(__g->data))->active) { \ - __g = __g->next; \ - __i++; \ - }\ -} - -#define RADIOBUTTONTOGGLED(_rb_, __i) { \ - GSList * __g; \ - __i = 0; \ - __g = gtk_radio_button_group(_rb_); \ - while( __g && !((GtkToggleButton *)(__g->data))->active) { \ - __g = __g->next; \ - __i++; \ - }\ -} - void after_press (GtkCTree *ctree, gpointer data) { char buf[80]; @@ -3708,7 +3761,7 @@ gint button_press (GtkCTree *ctree, GdkEventButton *event, gpointer data) else gtk_ctree_expand_recursive (ctree, work); after_press (ctree, NULL); - gtk_signal_emit_stop_by_name (GTK_OBJECT (ctree), + gtk_signal_emit_stop_by_name (GTK_OBJECT (ctree), "button_press_event"); } break; @@ -3907,7 +3960,7 @@ void toggle_sel_mode (GtkWidget *widget, GtkCTree *ctree) RADIOMENUTOGGLED ((GtkRadioMenuItem *) (((GtkOptionMenu *)omenu)->menu_item), i); - gtk_ctree_set_selection_mode (ctree, (GtkSelectionMode) (3-i)); + gtk_clist_set_selection_mode (GTK_CLIST (ctree), (GtkSelectionMode) (3-i)); after_press (ctree, NULL); } @@ -3996,14 +4049,14 @@ void rebuild_tree (GtkWidget *widget, GtkCTree *ctree) n = ((pow (b, d) - 1) / (b - 1)) * (p + 1); - if (n > 200000) + if (n > 100000) { g_print ("%d total items? Try less\n",n); return; } gtk_clist_freeze (GTK_CLIST (ctree)); - gtk_ctree_clear (ctree); + gtk_clist_clear (GTK_CLIST (ctree)); books = 1; pages = 0; @@ -4117,9 +4170,20 @@ void create_ctree (void) GTK_SIGNAL_FUNC (after_press), NULL); gtk_signal_connect_after (GTK_OBJECT (ctree), "tree_move", GTK_SIGNAL_FUNC (after_move), NULL); + gtk_signal_connect_after (GTK_OBJECT (ctree), "end_selection", + GTK_SIGNAL_FUNC (after_press), NULL); + gtk_signal_connect_after (GTK_OBJECT (ctree), "toggle_focus_row", + GTK_SIGNAL_FUNC (after_press), NULL); + gtk_signal_connect_after (GTK_OBJECT (ctree), "select_all", + GTK_SIGNAL_FUNC (after_press), NULL); + gtk_signal_connect_after (GTK_OBJECT (ctree), "unselect_all", + GTK_SIGNAL_FUNC (after_press), NULL); + gtk_signal_connect_after (GTK_OBJECT (ctree), "scroll_vertical", + GTK_SIGNAL_FUNC (after_press), NULL); + gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (ctree), TRUE, TRUE, 0); gtk_clist_column_titles_passive (GTK_CLIST (ctree)); - gtk_clist_set_selection_mode (GTK_CLIST (ctree), GTK_SELECTION_MULTIPLE); + gtk_clist_set_selection_mode (GTK_CLIST (ctree), GTK_SELECTION_EXTENDED); gtk_clist_set_policy (GTK_CLIST (ctree), GTK_POLICY_ALWAYS, GTK_POLICY_AUTOMATIC); gtk_clist_set_column_width (GTK_CLIST (ctree), 0, 200); @@ -4299,7 +4363,6 @@ void create_ctree (void) GTK_SIGNAL_FUNC (toggle_sel_mode), ctree); group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menu_item)); gtk_menu_append (GTK_MENU (menu), menu_item); - gtk_check_menu_item_set_state (GTK_CHECK_MENU_ITEM (menu_item), TRUE); gtk_widget_show (menu_item); menu_item = gtk_radio_menu_item_new_with_label (group, "Extended"); @@ -4307,12 +4370,13 @@ void create_ctree (void) GTK_SIGNAL_FUNC (toggle_sel_mode), ctree); group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menu_item)); gtk_menu_append (GTK_MENU (menu), menu_item); + gtk_check_menu_item_set_state (GTK_CHECK_MENU_ITEM (menu_item), TRUE); gtk_widget_show (menu_item); gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu), menu); gtk_box_pack_start (GTK_BOX (hbox), omenu, FALSE, TRUE, 0); - gtk_option_menu_set_history (GTK_OPTION_MENU (omenu), 2); + gtk_option_menu_set_history (GTK_OPTION_MENU (omenu), 3); gtk_widget_realize (window); @@ -4403,7 +4467,6 @@ void create_ctree (void) gtk_widget_destroy (window); } - /* * GtkColorSelect */ |