[baobab] Update the the C version of egg-list-box
- From: Paolo Borelli <pborelli src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [baobab] Update the the C version of egg-list-box
- Date: Mon, 20 Aug 2012 21:12:13 +0000 (UTC)
commit 63aaa39c3e3f3ca2928e98d887b3f9483562e45e
Author: Paolo Borelli <pborelli gnome org>
Date: Fri Aug 17 10:57:31 2012 +0200
Update the the C version of egg-list-box
src/Makefile.am | 7 +-
src/baobab-main-window.ui | 1 +
src/egg-list-box.c | 1945 +++++++++++++++++++++++++++++++++++++++++++++
src/egg-list-box.h | 78 ++
src/egg-list-box.vala | 1098 -------------------------
src/egglistbox.vapi | 55 ++
6 files changed, 2083 insertions(+), 1101 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 969d3ae..2fb52d5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -23,12 +23,14 @@ baobab_VALAFLAGS = \
noinst_HEADERS = \
baobab-chart.h \
baobab-treemap.h \
- baobab-ringschart.h
+ baobab-ringschart.h \
+ egg-list-box.h
baobab_SOURCES = \
fixes.vapi \
baobab.vapi \
config.vapi \
+ egglistbox.vapi \
baobab-chart.c \
baobab-treemap.c \
baobab-ringschart.c \
@@ -40,7 +42,7 @@ baobab_SOURCES = \
baobab-location-widget.vala \
baobab-scanner.vala \
baobab-window.vala \
- egg-list-box.vala \
+ egg-list-box.c \
main.vala \
$(BUILT_SOURCES)
@@ -71,7 +73,6 @@ MAINTAINERCLEANFILES = \
baobab-scanner.c \
baobab-window.c \
baobab_vala.stamp \
- egg-list-box.c \
main.c \
$(BUILT_SOURCES)
diff --git a/src/baobab-main-window.ui b/src/baobab-main-window.ui
index 792ab05..08dbeb1 100644
--- a/src/baobab-main-window.ui
+++ b/src/baobab-main-window.ui
@@ -11,6 +11,7 @@
<property name="show_arrow">False</property>
<style>
<class name="baobab-toolbar"/>
+ <class name="baobab-toolbar"/>
</style>
<child>
<object class="GtkToolItem" id="home-page-toolitem">
diff --git a/src/egg-list-box.c b/src/egg-list-box.c
new file mode 100644
index 0000000..5108597
--- /dev/null
+++ b/src/egg-list-box.c
@@ -0,0 +1,1945 @@
+/*
+ * Copyright (C) 2012 Alexander Larsson <alexl redhat com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <float.h>
+#include <math.h>
+#include <cairo.h>
+#include <string.h>
+#include <gobject/gvaluecollector.h>
+
+#include "egg-list-box.h"
+
+/* This already exists in gtk as _gtk_marshal_VOID__ENUM_INT, inline it here for now
+ to avoid separate marshallers file */
+static void
+_egg_marshal_VOID__ENUM_INT (GClosure * closure,
+ GValue * return_value,
+ guint n_param_values,
+ const GValue * param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__ENUM_INT) (gpointer data1, gint arg_1, gint arg_2, gpointer data2);
+ register GMarshalFunc_VOID__ENUM_INT callback;
+ register GCClosure * cc;
+ register gpointer data1;
+ register gpointer data2;
+ cc = (GCClosure *) closure;
+ g_return_if_fail (n_param_values == 3);
+ if (G_CCLOSURE_SWAP_DATA (closure)) {
+ data1 = closure->data;
+ data2 = param_values->data[0].v_pointer;
+ } else {
+ data1 = param_values->data[0].v_pointer;
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__ENUM_INT) (marshal_data ? marshal_data : cc->callback);
+ callback (data1, g_value_get_enum (param_values + 1), g_value_get_int (param_values + 2), data2);
+}
+
+typedef struct _EggListBoxChildInfo EggListBoxChildInfo;
+
+struct _EggListBoxPrivate
+{
+ GSequence *children;
+ GHashTable *child_hash;
+ GHashTable *separator_hash;
+
+ GCompareDataFunc sort_func;
+ gpointer sort_func_target;
+ GDestroyNotify sort_func_target_destroy_notify;
+
+ EggListBoxFilterFunc filter_func;
+ gpointer filter_func_target;
+ GDestroyNotify filter_func_target_destroy_notify;
+
+ EggListBoxUpdateSeparatorFunc update_separator_func;
+ gpointer update_separator_func_target;
+ GDestroyNotify update_separator_func_target_destroy_notify;
+
+ EggListBoxChildInfo *selected_child;
+ EggListBoxChildInfo *prelight_child;
+ EggListBoxChildInfo *cursor_child;
+
+ gboolean active_child_active;
+ EggListBoxChildInfo *active_child;
+
+ GtkSelectionMode selection_mode;
+
+ GtkAdjustment *adjustment;
+ gboolean activate_single_click;
+
+ /* DnD */
+ GtkWidget *drag_highlighted_widget;
+ guint auto_scroll_timeout_id;
+};
+
+struct _EggListBoxChildInfo
+{
+ GSequenceIter *iter;
+ GtkWidget *widget;
+ GtkWidget *separator;
+ gint y;
+ gint height;
+};
+
+enum {
+ CHILD_SELECTED,
+ CHILD_ACTIVATED,
+ ACTIVATE_CURSOR_CHILD,
+ TOGGLE_CURSOR_CHILD,
+ MOVE_CURSOR,
+ LAST_SIGNAL
+};
+
+enum {
+ PROP_0
+};
+
+G_DEFINE_TYPE (EggListBox, egg_list_box, GTK_TYPE_CONTAINER)
+
+static EggListBoxChildInfo *egg_list_box_find_child_at_y (EggListBox *list_box,
+ gint y);
+static EggListBoxChildInfo *egg_list_box_lookup_info (EggListBox *list_box,
+ GtkWidget *widget);
+static void egg_list_box_update_selected (EggListBox *list_box,
+ EggListBoxChildInfo *child);
+static void egg_list_box_apply_filter_all (EggListBox *list_box);
+static void egg_list_box_update_separator (EggListBox *list_box,
+ GSequenceIter *iter);
+static GSequenceIter * egg_list_box_get_next_visible (EggListBox *list_box,
+ GSequenceIter *_iter);
+static void egg_list_box_apply_filter (EggListBox *list_box,
+ GtkWidget *child);
+static void egg_list_box_add_move_binding (GtkBindingSet *binding_set,
+ guint keyval,
+ GdkModifierType modmask,
+ GtkMovementStep step,
+ gint count);
+static void egg_list_box_update_cursor (EggListBox *list_box,
+ EggListBoxChildInfo *child);
+static void egg_list_box_select_and_activate (EggListBox *list_box,
+ EggListBoxChildInfo *child);
+static void egg_list_box_update_prelight (EggListBox *list_box,
+ EggListBoxChildInfo *child);
+static void egg_list_box_update_active (EggListBox *list_box,
+ EggListBoxChildInfo *child);
+static gboolean egg_list_box_real_enter_notify_event (GtkWidget *widget,
+ GdkEventCrossing *event);
+static gboolean egg_list_box_real_leave_notify_event (GtkWidget *widget,
+ GdkEventCrossing *event);
+static gboolean egg_list_box_real_motion_notify_event (GtkWidget *widget,
+ GdkEventMotion *event);
+static gboolean egg_list_box_real_button_press_event (GtkWidget *widget,
+ GdkEventButton *event);
+static gboolean egg_list_box_real_button_release_event (GtkWidget *widget,
+ GdkEventButton *event);
+static void egg_list_box_real_show (GtkWidget *widget);
+static gboolean egg_list_box_real_focus (GtkWidget *widget,
+ GtkDirectionType direction);
+static GSequenceIter* egg_list_box_get_previous_visible (EggListBox *list_box,
+ GSequenceIter *_iter);
+static EggListBoxChildInfo *egg_list_box_get_first_visible (EggListBox *list_box);
+static EggListBoxChildInfo *egg_list_box_get_last_visible (EggListBox *list_box);
+static gboolean egg_list_box_real_draw (GtkWidget *widget,
+ cairo_t *cr);
+static void egg_list_box_real_realize (GtkWidget *widget);
+static void egg_list_box_real_add (GtkContainer *container,
+ GtkWidget *widget);
+static void egg_list_box_real_remove (GtkContainer *container,
+ GtkWidget *widget);
+static void egg_list_box_real_forall_internal (GtkContainer *container,
+ gboolean include_internals,
+ GtkCallback callback,
+ void *callback_target);
+static void egg_list_box_real_compute_expand_internal (GtkWidget *widget,
+ gboolean *hexpand,
+ gboolean *vexpand);
+static GType egg_list_box_real_child_type (GtkContainer *container);
+static GtkSizeRequestMode egg_list_box_real_get_request_mode (GtkWidget *widget);
+static void egg_list_box_real_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
+static void egg_list_box_real_drag_leave (GtkWidget *widget,
+ GdkDragContext *context,
+ guint time_);
+static gboolean egg_list_box_real_drag_motion (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time_);
+static void egg_list_box_real_activate_cursor_child (EggListBox *list_box);
+static void egg_list_box_real_toggle_cursor_child (EggListBox *list_box);
+static void egg_list_box_real_move_cursor (EggListBox *list_box,
+ GtkMovementStep step,
+ gint count);
+static void egg_list_box_finalize (GObject *obj);
+
+
+static void egg_list_box_real_get_preferred_height (GtkWidget *widget,
+ gint *minimum_height,
+ gint *natural_height);
+static void egg_list_box_real_get_preferred_height_for_width (GtkWidget *widget,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height);
+static void egg_list_box_real_get_preferred_width (GtkWidget *widget,
+ gint *minimum_width,
+ gint *natural_width);
+static void egg_list_box_real_get_preferred_width_for_height (GtkWidget *widget,
+ gint height,
+ gint *minimum_width,
+ gint *natural_width);
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static EggListBoxChildInfo*
+egg_list_box_child_info_new (GtkWidget *widget)
+{
+ EggListBoxChildInfo *info;
+
+ info = g_new0 (EggListBoxChildInfo, 1);
+ info->widget = g_object_ref (widget);
+ return info;
+}
+
+static void
+egg_list_box_child_info_free (EggListBoxChildInfo *info)
+{
+ g_clear_object (&info->widget);
+ g_clear_object (&info->separator);
+ g_free (info);
+}
+
+EggListBox*
+egg_list_box_new (void)
+{
+ return g_object_new (EGG_TYPE_LIST_BOX, NULL);
+}
+
+static void
+egg_list_box_init (EggListBox *list_box)
+{
+ EggListBoxPrivate *priv;
+
+ list_box->priv = priv =
+ G_TYPE_INSTANCE_GET_PRIVATE (list_box, EGG_TYPE_LIST_BOX, EggListBoxPrivate);
+
+ gtk_widget_set_can_focus (GTK_WIDGET (list_box), TRUE);
+ gtk_widget_set_has_window (GTK_WIDGET (list_box), TRUE);
+ gtk_widget_set_redraw_on_allocate (GTK_WIDGET (list_box), TRUE);
+ priv->selection_mode = GTK_SELECTION_SINGLE;
+ priv->activate_single_click = TRUE;
+
+ priv->children = g_sequence_new ((GDestroyNotify)egg_list_box_child_info_free);
+ priv->child_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+ priv->separator_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+}
+
+static void
+egg_list_box_finalize (GObject *obj)
+{
+ EggListBox *list_box = EGG_LIST_BOX (obj);
+ EggListBoxPrivate *priv = list_box->priv;
+
+ if (priv->auto_scroll_timeout_id != ((guint) 0))
+ g_source_remove (priv->auto_scroll_timeout_id);
+
+ if (priv->sort_func_target_destroy_notify != NULL)
+ priv->sort_func_target_destroy_notify (priv->sort_func_target);
+ if (priv->filter_func_target_destroy_notify != NULL)
+ priv->filter_func_target_destroy_notify (priv->filter_func_target);
+ if (priv->update_separator_func_target_destroy_notify != NULL)
+ priv->update_separator_func_target_destroy_notify (priv->update_separator_func_target);
+
+ g_clear_object (&priv->adjustment);
+ g_clear_object (&priv->drag_highlighted_widget);
+
+ g_sequence_free (priv->children);
+ g_hash_table_unref (priv->child_hash);
+ g_hash_table_unref (priv->separator_hash);
+
+ G_OBJECT_CLASS (egg_list_box_parent_class)->finalize (obj);
+}
+
+static void
+egg_list_box_class_init (EggListBoxClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+ GtkBindingSet *binding_set;
+
+ egg_list_box_parent_class = g_type_class_peek_parent (klass);
+
+ g_type_class_add_private (klass, sizeof (EggListBoxPrivate));
+
+ object_class->finalize = egg_list_box_finalize;
+ widget_class->enter_notify_event = egg_list_box_real_enter_notify_event;
+ widget_class->leave_notify_event = egg_list_box_real_leave_notify_event;
+ widget_class->motion_notify_event = egg_list_box_real_motion_notify_event;
+ widget_class->button_press_event = egg_list_box_real_button_press_event;
+ widget_class->button_release_event = egg_list_box_real_button_release_event;
+ widget_class->show = egg_list_box_real_show;
+ widget_class->focus = egg_list_box_real_focus;
+ widget_class->draw = egg_list_box_real_draw;
+ widget_class->realize = egg_list_box_real_realize;
+ widget_class->compute_expand = egg_list_box_real_compute_expand_internal;
+ widget_class->get_request_mode = egg_list_box_real_get_request_mode;
+ widget_class->get_preferred_height = egg_list_box_real_get_preferred_height;
+ widget_class->get_preferred_height_for_width = egg_list_box_real_get_preferred_height_for_width;
+ widget_class->get_preferred_width = egg_list_box_real_get_preferred_width;
+ widget_class->get_preferred_width_for_height = egg_list_box_real_get_preferred_width_for_height;
+ widget_class->size_allocate = egg_list_box_real_size_allocate;
+ widget_class->drag_leave = egg_list_box_real_drag_leave;
+ widget_class->drag_motion = egg_list_box_real_drag_motion;
+ container_class->add = egg_list_box_real_add;
+ container_class->remove = egg_list_box_real_remove;
+ container_class->forall = egg_list_box_real_forall_internal;
+ container_class->child_type = egg_list_box_real_child_type;
+ klass->activate_cursor_child = egg_list_box_real_activate_cursor_child;
+ klass->toggle_cursor_child = egg_list_box_real_toggle_cursor_child;
+ klass->move_cursor = egg_list_box_real_move_cursor;
+
+ signals[CHILD_SELECTED] =
+ g_signal_new ("child-selected",
+ EGG_TYPE_LIST_BOX,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EggListBoxClass, child_selected),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ GTK_TYPE_WIDGET);
+ signals[CHILD_ACTIVATED] =
+ g_signal_new ("child-activated",
+ EGG_TYPE_LIST_BOX,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EggListBoxClass, child_activated),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ GTK_TYPE_WIDGET);
+ signals[ACTIVATE_CURSOR_CHILD] =
+ g_signal_new ("activate-cursor-child",
+ EGG_TYPE_LIST_BOX,
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EggListBoxClass, activate_cursor_child),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ signals[TOGGLE_CURSOR_CHILD] =
+ g_signal_new ("toggle-cursor-child",
+ EGG_TYPE_LIST_BOX,
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EggListBoxClass, toggle_cursor_child),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ signals[MOVE_CURSOR] =
+ g_signal_new ("move-cursor",
+ EGG_TYPE_LIST_BOX,
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EggListBoxClass, move_cursor),
+ NULL, NULL,
+ _egg_marshal_VOID__ENUM_INT,
+ G_TYPE_NONE, 2,
+ GTK_TYPE_MOVEMENT_STEP, G_TYPE_INT);
+
+ widget_class->activate_signal = signals[ACTIVATE_CURSOR_CHILD];
+
+ binding_set = gtk_binding_set_by_class (klass);
+ egg_list_box_add_move_binding (binding_set, GDK_KEY_Home, 0,
+ GTK_MOVEMENT_BUFFER_ENDS, -1);
+ egg_list_box_add_move_binding (binding_set, GDK_KEY_KP_Home, 0,
+ GTK_MOVEMENT_BUFFER_ENDS, -1);
+ egg_list_box_add_move_binding (binding_set, GDK_KEY_End, 0,
+ GTK_MOVEMENT_BUFFER_ENDS, 1);
+ egg_list_box_add_move_binding (binding_set, GDK_KEY_KP_End, 0,
+ GTK_MOVEMENT_BUFFER_ENDS, 1);
+ egg_list_box_add_move_binding (binding_set, GDK_KEY_Up, GDK_CONTROL_MASK,
+ GTK_MOVEMENT_DISPLAY_LINES, -1);
+ egg_list_box_add_move_binding (binding_set, GDK_KEY_KP_Up, GDK_CONTROL_MASK,
+ GTK_MOVEMENT_DISPLAY_LINES, -1);
+ egg_list_box_add_move_binding (binding_set, GDK_KEY_Down, GDK_CONTROL_MASK,
+ GTK_MOVEMENT_DISPLAY_LINES, 1);
+ egg_list_box_add_move_binding (binding_set, GDK_KEY_KP_Down, GDK_CONTROL_MASK,
+ GTK_MOVEMENT_DISPLAY_LINES, 1);
+ egg_list_box_add_move_binding (binding_set, GDK_KEY_Page_Up, 0,
+ GTK_MOVEMENT_PAGES, -1);
+ egg_list_box_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0,
+ GTK_MOVEMENT_PAGES, -1);
+ egg_list_box_add_move_binding (binding_set, GDK_KEY_Page_Down, 0,
+ GTK_MOVEMENT_PAGES, 1);
+ egg_list_box_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0,
+ GTK_MOVEMENT_PAGES, 1);
+ gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK,
+ "toggle-cursor-child", 0, NULL);
+}
+
+GtkWidget *
+egg_list_box_get_selected_child (EggListBox *list_box)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+
+ g_return_val_if_fail (list_box != NULL, NULL);
+
+ if (priv->selected_child != NULL)
+ return priv->selected_child->widget;
+
+ return NULL;
+}
+
+GtkWidget *
+egg_list_box_get_child_at_y (EggListBox *list_box, gint y)
+{
+ EggListBoxChildInfo *child;
+
+ g_return_val_if_fail (list_box != NULL, NULL);
+
+ child = egg_list_box_find_child_at_y (list_box, y);
+ if (child == NULL)
+ return NULL;
+
+ return child->widget;
+}
+
+
+void
+egg_list_box_select_child (EggListBox *list_box, GtkWidget *child)
+{
+ EggListBoxChildInfo *info = NULL;
+
+ g_return_if_fail (list_box != NULL);
+
+ if (child != NULL)
+ info = egg_list_box_lookup_info (list_box, child);
+
+ egg_list_box_update_selected (list_box, info);
+}
+
+void
+egg_list_box_set_adjustment (EggListBox *list_box,
+ GtkAdjustment *adjustment)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+
+ g_return_if_fail (list_box != NULL);
+
+ g_object_ref (adjustment);
+ if (priv->adjustment)
+ g_object_unref (priv->adjustment);
+ priv->adjustment = adjustment;
+ gtk_container_set_focus_vadjustment (GTK_CONTAINER (list_box),
+ adjustment);
+}
+
+void
+egg_list_box_add_to_scrolled (EggListBox *list_box,
+ GtkScrolledWindow *scrolled)
+{
+ g_return_if_fail (list_box != NULL);
+ g_return_if_fail (scrolled != NULL);
+
+ gtk_scrolled_window_add_with_viewport (scrolled,
+ GTK_WIDGET (list_box));
+ egg_list_box_set_adjustment (list_box,
+ gtk_scrolled_window_get_vadjustment (scrolled));
+}
+
+
+void
+egg_list_box_set_selection_mode (EggListBox *list_box, GtkSelectionMode mode)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+
+ g_return_if_fail (list_box != NULL);
+
+ if (mode == GTK_SELECTION_MULTIPLE)
+ {
+ g_warning ("egg-list-box.vala:115: Multiple selections not supported");
+ return;
+ }
+
+ priv->selection_mode = mode;
+ if (mode == GTK_SELECTION_NONE)
+ egg_list_box_update_selected (list_box, NULL);
+}
+
+
+void
+egg_list_box_set_filter_func (EggListBox *list_box,
+ EggListBoxFilterFunc f,
+ void *f_target,
+ GDestroyNotify f_target_destroy_notify)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+
+ g_return_if_fail (list_box != NULL);
+
+ if (priv->filter_func_target_destroy_notify != NULL)
+ priv->filter_func_target_destroy_notify (priv->filter_func_target);
+
+ priv->filter_func = f;
+ priv->filter_func_target = f_target;
+ priv->filter_func_target_destroy_notify = f_target_destroy_notify;
+
+ egg_list_box_refilter (list_box);
+}
+
+void
+egg_list_box_set_separator_funcs (EggListBox *list_box,
+ EggListBoxUpdateSeparatorFunc update_separator,
+ void *update_separator_target,
+ GDestroyNotify update_separator_target_destroy_notify)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+
+ g_return_if_fail (list_box != NULL);
+
+ if (priv->update_separator_func_target_destroy_notify != NULL)
+ priv->update_separator_func_target_destroy_notify (priv->update_separator_func_target);
+
+ priv->update_separator_func = update_separator;
+ priv->update_separator_func_target = update_separator_target;
+ priv->update_separator_func_target_destroy_notify = update_separator_target_destroy_notify;
+ egg_list_box_reseparate (list_box);
+}
+
+void
+egg_list_box_refilter (EggListBox *list_box)
+{
+ g_return_if_fail (list_box != NULL);
+
+
+ egg_list_box_apply_filter_all (list_box);
+ egg_list_box_reseparate (list_box);
+ gtk_widget_queue_resize (GTK_WIDGET (list_box));
+}
+
+static gint
+do_sort (EggListBoxChildInfo *a,
+ EggListBoxChildInfo *b,
+ EggListBox *list_box)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+
+ return priv->sort_func (a->widget, b->widget,
+ priv->sort_func_target);
+}
+
+void
+egg_list_box_resort (EggListBox *list_box)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+
+ g_return_if_fail (list_box != NULL);
+
+ g_sequence_sort (priv->children,
+ (GCompareDataFunc)do_sort, list_box);
+ egg_list_box_reseparate (list_box);
+ gtk_widget_queue_resize (GTK_WIDGET (list_box));
+}
+
+void
+egg_list_box_reseparate (EggListBox *list_box)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+ GSequenceIter *iter;
+
+ g_return_if_fail (list_box != NULL);
+
+ for (iter = g_sequence_get_begin_iter (priv->children);
+ !g_sequence_iter_is_end (iter);
+ iter = g_sequence_iter_next (iter))
+ egg_list_box_update_separator (list_box, iter);
+
+ gtk_widget_queue_resize (GTK_WIDGET (list_box));
+}
+
+void
+egg_list_box_set_sort_func (EggListBox *list_box,
+ GCompareDataFunc f,
+ void *f_target,
+ GDestroyNotify f_target_destroy_notify)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+
+ g_return_if_fail (list_box != NULL);
+
+ if (priv->sort_func_target_destroy_notify != NULL)
+ priv->sort_func_target_destroy_notify (priv->sort_func_target);
+
+ priv->sort_func = f;
+ priv->sort_func_target = f_target;
+ priv->sort_func_target_destroy_notify = f_target_destroy_notify;
+ egg_list_box_resort (list_box);
+}
+
+void
+egg_list_box_child_changed (EggListBox *list_box, GtkWidget *widget)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+ EggListBoxChildInfo *info;
+ GSequenceIter *prev_next, *next;
+
+ g_return_if_fail (list_box != NULL);
+ g_return_if_fail (widget != NULL);
+
+ info = egg_list_box_lookup_info (list_box, widget);
+ if (info == NULL)
+ return;
+
+ prev_next = egg_list_box_get_next_visible (list_box, info->iter);
+ if (priv->sort_func != NULL)
+ {
+ g_sequence_sort_changed (info->iter,
+ (GCompareDataFunc)do_sort,
+ list_box);
+ gtk_widget_queue_resize (GTK_WIDGET (list_box));
+ }
+ egg_list_box_apply_filter (list_box, info->widget);
+ if (gtk_widget_get_visible (GTK_WIDGET (list_box)))
+ {
+ next = egg_list_box_get_next_visible (list_box, info->iter);
+ egg_list_box_update_separator (list_box, info->iter);
+ egg_list_box_update_separator (list_box, next);
+ egg_list_box_update_separator (list_box, prev_next);
+ }
+}
+
+void
+egg_list_box_set_activate_on_single_click (EggListBox *list_box,
+ gboolean single)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+
+ g_return_if_fail (list_box != NULL);
+
+ priv->activate_single_click = single;
+}
+
+static void
+egg_list_box_add_move_binding (GtkBindingSet *binding_set,
+ guint keyval,
+ GdkModifierType modmask,
+ GtkMovementStep step,
+ gint count)
+{
+ gtk_binding_entry_add_signal (binding_set, keyval, modmask,
+ "move-cursor", (guint) 2, GTK_TYPE_MOVEMENT_STEP, step, G_TYPE_INT, count, NULL);
+
+ if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
+ return;
+
+ gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
+ "move-cursor", (guint) 2, GTK_TYPE_MOVEMENT_STEP, step, G_TYPE_INT, count, NULL);
+}
+
+static EggListBoxChildInfo*
+egg_list_box_find_child_at_y (EggListBox *list_box, gint y)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+ EggListBoxChildInfo *child_info;
+ GSequenceIter *iter;
+ EggListBoxChildInfo *info;
+
+ child_info = NULL;
+ for (iter = g_sequence_get_begin_iter (priv->children);
+ !g_sequence_iter_is_end (iter);
+ iter = g_sequence_iter_next (iter))
+ {
+ info = (EggListBoxChildInfo*) g_sequence_get (iter);
+ if (y >= info->y && y < (info->y + info->height))
+ {
+ child_info = info;
+ break;
+ }
+ }
+
+ return child_info;
+}
+
+static void
+egg_list_box_update_cursor (EggListBox *list_box,
+ EggListBoxChildInfo *child)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+
+ priv->cursor_child = child;
+ gtk_widget_grab_focus (GTK_WIDGET (list_box));
+ gtk_widget_queue_draw (GTK_WIDGET (list_box));
+ if (child != NULL && priv->adjustment != NULL)
+ {
+ GtkAllocation allocation;
+ gtk_widget_get_allocation (GTK_WIDGET (list_box), &allocation);
+ gtk_adjustment_clamp_page (priv->adjustment,
+ priv->cursor_child->y + allocation.y,
+ priv->cursor_child->y + allocation.y + priv->cursor_child->height);
+ }
+}
+
+static void
+egg_list_box_update_selected (EggListBox *list_box,
+ EggListBoxChildInfo *child)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+
+ if (child != priv->selected_child &&
+ (child == NULL || priv->selection_mode != GTK_SELECTION_NONE))
+ {
+ priv->selected_child = child;
+ g_signal_emit (list_box, signals[CHILD_SELECTED], 0,
+ (priv->selected_child != NULL) ? priv->selected_child->widget : NULL);
+ gtk_widget_queue_draw (GTK_WIDGET (list_box));
+ }
+ if (child != NULL)
+ egg_list_box_update_cursor (list_box, child);
+}
+
+static void
+egg_list_box_select_and_activate (EggListBox *list_box, EggListBoxChildInfo *child)
+{
+ GtkWidget *w = NULL;
+
+ if (child != NULL)
+ w = child->widget;
+
+ egg_list_box_update_selected (list_box, child);
+
+ if (w != NULL)
+ g_signal_emit (list_box, signals[CHILD_ACTIVATED], 0, w);
+}
+
+static void
+egg_list_box_update_prelight (EggListBox *list_box, EggListBoxChildInfo *child)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+
+ if (child != priv->prelight_child)
+ {
+ priv->prelight_child = child;
+ gtk_widget_queue_draw (GTK_WIDGET (list_box));
+ }
+}
+
+static void
+egg_list_box_update_active (EggListBox *list_box, EggListBoxChildInfo *child)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+ gboolean val;
+
+ val = priv->active_child == child;
+ if (priv->active_child != NULL &&
+ val != priv->active_child_active)
+ {
+ priv->active_child_active = val;
+ gtk_widget_queue_draw (GTK_WIDGET (list_box));
+ }
+}
+
+static gboolean
+egg_list_box_real_enter_notify_event (GtkWidget *widget,
+ GdkEventCrossing *event)
+{
+ EggListBox *list_box = EGG_LIST_BOX (widget);
+ EggListBoxChildInfo *child;
+
+
+ if (event->window != gtk_widget_get_window (GTK_WIDGET (list_box)))
+ return FALSE;
+
+ child = egg_list_box_find_child_at_y (list_box, event->y);
+ egg_list_box_update_prelight (list_box, child);
+ egg_list_box_update_active (list_box, child);
+
+ return FALSE;
+}
+
+static gboolean
+egg_list_box_real_leave_notify_event (GtkWidget *widget,
+ GdkEventCrossing *event)
+{
+ EggListBox *list_box = EGG_LIST_BOX (widget);
+ EggListBoxChildInfo *child = NULL;
+
+ if (event->window != gtk_widget_get_window (GTK_WIDGET (list_box)))
+ return FALSE;
+
+ if (event->detail != GDK_NOTIFY_INFERIOR)
+ child = NULL;
+ else
+ child = egg_list_box_find_child_at_y (list_box, event->y);
+
+ egg_list_box_update_prelight (list_box, child);
+ egg_list_box_update_active (list_box, child);
+
+ return FALSE;
+}
+
+static gboolean
+egg_list_box_real_motion_notify_event (GtkWidget *widget,
+ GdkEventMotion *event)
+{
+ EggListBox *list_box = EGG_LIST_BOX (widget);
+ EggListBoxChildInfo *child;
+
+
+ child = egg_list_box_find_child_at_y (list_box, event->y);
+ egg_list_box_update_prelight (list_box, child);
+ egg_list_box_update_active (list_box, child);
+
+ return FALSE;
+}
+
+static gboolean
+egg_list_box_real_button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ EggListBox *list_box = EGG_LIST_BOX (widget);
+ EggListBoxPrivate *priv = list_box->priv;
+
+ if (event->button == 1)
+ {
+ EggListBoxChildInfo *child;
+ child = egg_list_box_find_child_at_y (list_box, event->y);
+ if (child != NULL)
+ {
+ priv->active_child = child;
+ priv->active_child_active = TRUE;
+ gtk_widget_queue_draw (GTK_WIDGET (list_box));
+ if (event->type == GDK_2BUTTON_PRESS &&
+ !priv->activate_single_click &&
+ child->widget != NULL)
+ g_signal_emit (list_box, signals[CHILD_ACTIVATED], 0,
+ child->widget);
+
+ }
+ /* TODO:
+ Should mark as active while down,
+ and handle grab breaks */
+ }
+
+ return FALSE;
+}
+
+static gboolean
+egg_list_box_real_button_release_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ EggListBox *list_box = EGG_LIST_BOX (widget);
+ EggListBoxPrivate *priv = list_box->priv;
+
+ if (event->button == 1)
+ {
+ if (priv->active_child != NULL &&
+ priv->active_child_active)
+ {
+ if (priv->activate_single_click)
+ egg_list_box_select_and_activate (list_box, priv->active_child);
+ else
+ egg_list_box_update_selected (list_box, priv->active_child);
+ }
+ priv->active_child = NULL;
+ priv->active_child_active = FALSE;
+ gtk_widget_queue_draw (GTK_WIDGET (list_box));
+ }
+
+ return FALSE;
+}
+
+static void
+egg_list_box_real_show (GtkWidget *widget)
+{
+ EggListBox * list_box = EGG_LIST_BOX (widget);
+
+ egg_list_box_reseparate (list_box);
+
+ GTK_WIDGET_CLASS (egg_list_box_parent_class)->show ((GtkWidget*) G_TYPE_CHECK_INSTANCE_CAST (list_box, GTK_TYPE_CONTAINER, GtkContainer));
+}
+
+
+static gboolean
+egg_list_box_real_focus (GtkWidget* widget, GtkDirectionType direction)
+{
+ EggListBox *list_box = EGG_LIST_BOX (widget);
+ EggListBoxPrivate *priv = list_box->priv;
+ gboolean had_focus = FALSE;
+ gboolean focus_into = FALSE;
+ GtkWidget* recurse_into;
+ EggListBoxChildInfo *current_focus_child;
+ EggListBoxChildInfo *next_focus_child;
+ gboolean modify_selection_pressed;
+ GdkModifierType state = 0;
+
+ recurse_into = NULL;
+ focus_into = TRUE;
+
+ g_object_get (GTK_WIDGET (list_box), "has-focus", &had_focus, NULL);
+ current_focus_child = NULL;
+ next_focus_child = NULL;
+ if (had_focus)
+ {
+ /* If on row, going right, enter into possible container */
+ if (direction == GTK_DIR_RIGHT || direction == GTK_DIR_TAB_FORWARD)
+ {
+ if (priv->cursor_child != NULL)
+ recurse_into = priv->cursor_child->widget;
+ }
+ current_focus_child = priv->cursor_child;
+ /* Unless we're going up/down we're always leaving
+ the container */
+ if (direction != GTK_DIR_UP && direction != GTK_DIR_DOWN)
+ focus_into = FALSE;
+ }
+ else if (gtk_container_get_focus_child ((GtkContainer*) list_box) != NULL)
+ {
+ /* There is a focus child, always navigat inside it first */
+ recurse_into = gtk_container_get_focus_child ((GtkContainer*) list_box);
+ current_focus_child = egg_list_box_lookup_info (list_box, recurse_into);
+
+ /* If exiting child container to the right, exit row */
+ if (direction == GTK_DIR_RIGHT || direction == GTK_DIR_TAB_FORWARD)
+ focus_into = FALSE;
+
+ /* If exiting child container to the left, select row or out */
+ if (direction == GTK_DIR_LEFT || direction == GTK_DIR_TAB_BACKWARD)
+ next_focus_child = current_focus_child;
+ }
+ else
+ {
+ /* If coming from the left, enter into possible container */
+ if (direction == GTK_DIR_LEFT || direction == GTK_DIR_TAB_BACKWARD)
+ {
+ if (priv->selected_child != NULL)
+ recurse_into = priv->selected_child->widget;
+ }
+ }
+
+ if (recurse_into != NULL)
+ {
+ if (gtk_widget_child_focus (recurse_into, direction))
+ return TRUE;
+ }
+
+ if (!focus_into)
+ return FALSE; /* Focus is leaving us */
+
+ /* TODO: This doesn't handle up/down going into a focusable separator */
+
+ if (next_focus_child == NULL)
+ {
+ if (current_focus_child != NULL)
+ {
+ GSequenceIter* i;
+ if (direction == GTK_DIR_UP)
+ {
+ i = egg_list_box_get_previous_visible (list_box, current_focus_child->iter);
+ if (i != NULL)
+ next_focus_child = g_sequence_get (i);
+
+ }
+ else
+ {
+ i = egg_list_box_get_next_visible (list_box, current_focus_child->iter);
+ if (!g_sequence_iter_is_end (i))
+ next_focus_child = g_sequence_get (i);
+
+ }
+ }
+ else
+ {
+ switch (direction)
+ {
+ case GTK_DIR_DOWN:
+ case GTK_DIR_TAB_FORWARD:
+ next_focus_child = egg_list_box_get_first_visible (list_box);
+ break;
+ case GTK_DIR_UP:
+ case GTK_DIR_TAB_BACKWARD:
+ next_focus_child = egg_list_box_get_last_visible (list_box);
+ break;
+ default:
+ next_focus_child = priv->selected_child;
+ if (next_focus_child == NULL)
+ next_focus_child =
+ egg_list_box_get_first_visible (list_box);
+ break;
+ }
+ }
+ }
+
+ if (next_focus_child == NULL)
+ {
+ if (direction == GTK_DIR_UP || direction == GTK_DIR_DOWN)
+ {
+ gtk_widget_error_bell (GTK_WIDGET (list_box));
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ modify_selection_pressed = FALSE;
+ if (gtk_get_current_event_state (&state))
+ {
+ GdkModifierType modify_mod_mask;
+ modify_mod_mask =
+ gtk_widget_get_modifier_mask (GTK_WIDGET (list_box),
+ GDK_MODIFIER_INTENT_MODIFY_SELECTION);
+ if ((state & modify_mod_mask) == modify_mod_mask)
+ modify_selection_pressed = TRUE;
+ }
+
+ egg_list_box_update_cursor (list_box, next_focus_child);
+ if (!modify_selection_pressed)
+ egg_list_box_update_selected (list_box, next_focus_child);
+
+ return TRUE;
+}
+
+typedef struct {
+ EggListBoxChildInfo *child;
+ GtkStateFlags state;
+} ChildFlags;
+
+static ChildFlags*
+child_flags_find_or_add (ChildFlags *array,
+ int *array_length,
+ EggListBoxChildInfo *to_find)
+{
+ gint i;
+
+ for (i = 0; i < *array_length; i++)
+ {
+ if (array[i].child == to_find)
+ return &array[i];
+ }
+
+ *array_length = *array_length + 1;
+ array[*array_length - 1].child = to_find;
+ array[*array_length - 1].state = 0;
+ return &array[*array_length - 1];
+}
+
+static gboolean
+egg_list_box_real_draw (GtkWidget* widget, cairo_t* cr)
+{
+ EggListBox * list_box = EGG_LIST_BOX (widget);
+ EggListBoxPrivate *priv = list_box->priv;
+ GtkAllocation allocation = {0};
+ GtkStyleContext* context;
+ ChildFlags flags[3], *found;
+ gint flags_length;
+ int i;
+
+ gtk_widget_get_allocation (GTK_WIDGET (list_box), &allocation);
+ context = gtk_widget_get_style_context (GTK_WIDGET (list_box));
+ gtk_render_background (context, cr, (gdouble) 0, (gdouble) 0, (gdouble) allocation.width, (gdouble) allocation.height);
+ flags_length = 0;
+
+ if (priv->selected_child != NULL)
+ {
+ found = child_flags_find_or_add (flags, &flags_length, priv->selected_child);
+ found->state |= GTK_STATE_FLAG_SELECTED;
+ }
+
+ if (priv->prelight_child != NULL)
+ {
+ found = child_flags_find_or_add (flags, &flags_length, priv->prelight_child);
+ found->state |= GTK_STATE_FLAG_PRELIGHT;
+ }
+
+ if (priv->active_child != NULL && priv->active_child_active)
+ {
+ found = child_flags_find_or_add (flags, &flags_length, priv->active_child);
+ found->state |= GTK_STATE_FLAG_ACTIVE;
+ }
+
+ for (i = 0; i < flags_length; i++)
+ {
+ ChildFlags *flag = &flags[i];
+ gtk_style_context_save (context);
+ gtk_style_context_set_state (context, flag->state);
+ gtk_render_background (context, cr, 0, flag->child->y, allocation.width, flag->child->height);
+ gtk_style_context_restore (context);
+ }
+
+ if (gtk_widget_has_visible_focus (GTK_WIDGET (list_box)) && priv->cursor_child != NULL)
+ gtk_render_focus (context, cr, 0, priv->cursor_child->y, allocation.width, priv->cursor_child->height);
+
+ GTK_WIDGET_CLASS (egg_list_box_parent_class)->draw ((GtkWidget*) G_TYPE_CHECK_INSTANCE_CAST (list_box, GTK_TYPE_CONTAINER, GtkContainer), cr);
+
+ return TRUE;
+}
+
+
+static void
+egg_list_box_real_realize (GtkWidget* widget)
+{
+ EggListBox *list_box = EGG_LIST_BOX (widget);
+ GtkAllocation allocation;
+ GdkWindowAttr attributes = {0};
+ GdkWindow *window;
+
+ gtk_widget_get_allocation (GTK_WIDGET (list_box), &allocation);
+ gtk_widget_set_realized (GTK_WIDGET (list_box), TRUE);
+
+ attributes.x = allocation.x;
+ attributes.y = allocation.y;
+ attributes.width = allocation.width;
+ attributes.height = allocation.height;
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.event_mask = gtk_widget_get_events (GTK_WIDGET (list_box)) |
+ GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK |
+ GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+
+ window = gdk_window_new (gtk_widget_get_parent_window (GTK_WIDGET (list_box)),
+ &attributes, GDK_WA_X | GDK_WA_Y);
+ gtk_style_context_set_background (gtk_widget_get_style_context (GTK_WIDGET (list_box)), window);
+ gdk_window_set_user_data (window, (GObject*) list_box);
+ gtk_widget_set_window (GTK_WIDGET (list_box), window); /* Passes ownership */
+}
+
+
+static void
+egg_list_box_apply_filter (EggListBox *list_box, GtkWidget *child)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+ gboolean do_show;
+
+ do_show = TRUE;
+ if (priv->filter_func != NULL)
+ do_show = priv->filter_func (child, priv->filter_func_target);
+
+ gtk_widget_set_child_visible (child, do_show);
+}
+
+static void
+egg_list_box_apply_filter_all (EggListBox *list_box)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+ EggListBoxChildInfo *child_info;
+ GSequenceIter *iter;
+
+ for (iter = g_sequence_get_begin_iter (priv->children);
+ !g_sequence_iter_is_end (iter);
+ iter = g_sequence_iter_next (iter))
+ {
+ child_info = g_sequence_get (iter);
+ egg_list_box_apply_filter (list_box, child_info->widget);
+ }
+}
+
+/* Children are visible if they are shown by the app (visible)
+ and not filtered out (child_visible) by the listbox */
+static gboolean
+child_is_visible (GtkWidget *child)
+{
+ return gtk_widget_get_visible (child) && gtk_widget_get_child_visible (child);
+}
+
+static EggListBoxChildInfo*
+egg_list_box_get_first_visible (EggListBox *list_box)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+ EggListBoxChildInfo *child_info;
+ GSequenceIter *iter;
+
+ for (iter = g_sequence_get_begin_iter (priv->children);
+ !g_sequence_iter_is_end (iter);
+ iter = g_sequence_iter_next (iter))
+ {
+ child_info = g_sequence_get (iter);
+ if (child_is_visible (child_info->widget))
+ return child_info;
+ }
+
+ return NULL;
+}
+
+
+static EggListBoxChildInfo*
+egg_list_box_get_last_visible (EggListBox *list_box)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+ EggListBoxChildInfo *child_info;
+ GSequenceIter *iter;
+
+ iter = g_sequence_get_end_iter (priv->children);
+ while (!g_sequence_iter_is_begin (iter))
+ {
+ iter = g_sequence_iter_prev (iter);
+ child_info = g_sequence_get (iter);
+ if (child_is_visible (child_info->widget))
+ return child_info;
+ }
+
+ return NULL;
+}
+
+static GSequenceIter*
+egg_list_box_get_previous_visible (EggListBox *list_box,
+ GSequenceIter* iter)
+{
+ EggListBoxChildInfo *child_info;
+
+ if (g_sequence_iter_is_begin (iter))
+ return NULL;
+
+ do
+ {
+ iter = g_sequence_iter_prev (iter);
+ child_info = g_sequence_get (iter);
+ if (child_is_visible (child_info->widget))
+ return iter;
+ }
+ while (!g_sequence_iter_is_begin (iter));
+
+ return NULL;
+}
+
+static GSequenceIter*
+egg_list_box_get_next_visible (EggListBox *list_box, GSequenceIter* iter)
+{
+ EggListBoxChildInfo *child_info;
+
+ if (g_sequence_iter_is_end (iter))
+ return iter;
+
+ do
+ {
+ iter = g_sequence_iter_next (iter);
+ if (!g_sequence_iter_is_end (iter))
+ {
+ child_info = g_sequence_get (iter);
+ if (child_is_visible (child_info->widget))
+ return iter;
+ }
+ }
+ while (!g_sequence_iter_is_end (iter));
+
+ return iter;
+}
+
+
+static void
+egg_list_box_update_separator (EggListBox *list_box, GSequenceIter* iter)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+ EggListBoxChildInfo *info;
+ GSequenceIter *before_iter;
+ GtkWidget *child;
+ GtkWidget *before_child;
+ EggListBoxChildInfo *before_info;
+ GtkWidget *old_separator;
+
+ if (iter == NULL || g_sequence_iter_is_end (iter))
+ return;
+
+ info = g_sequence_get (iter);
+ before_iter = egg_list_box_get_previous_visible (list_box, iter);
+ child = info->widget;
+ if (child)
+ g_object_ref (child);
+ before_child = NULL;
+ if (before_iter != NULL)
+ {
+ before_info = g_sequence_get (before_iter);
+ before_child = before_info->widget;
+ if (before_child)
+ g_object_ref (before_child);
+ }
+
+ if (priv->update_separator_func != NULL &&
+ child_is_visible (child))
+ {
+ old_separator = info->separator;
+ if (old_separator)
+ g_object_ref (old_separator);
+ priv->update_separator_func (&info->separator,
+ child,
+ before_child,
+ priv->update_separator_func_target);
+ if (old_separator != info->separator)
+ {
+ if (old_separator != NULL)
+ {
+ gtk_widget_unparent (old_separator);
+ g_hash_table_remove (priv->separator_hash, old_separator);
+ }
+ if (info->separator != NULL)
+ {
+ g_hash_table_insert (priv->separator_hash, info->separator, info);
+ gtk_widget_set_parent (info->separator, GTK_WIDGET (list_box));
+ gtk_widget_show (info->separator);
+ }
+ gtk_widget_queue_resize (GTK_WIDGET (list_box));
+ }
+ if (old_separator)
+ g_object_unref (old_separator);
+ }
+ else
+ {
+ if (info->separator != NULL)
+ {
+ g_hash_table_remove (priv->separator_hash, info->separator);
+ gtk_widget_unparent (info->separator);
+ g_clear_object (&info->separator);
+ gtk_widget_queue_resize (GTK_WIDGET (list_box));
+ }
+ }
+ if (before_child)
+ g_object_unref (before_child);
+ if (child)
+ g_object_unref (child);
+}
+
+static EggListBoxChildInfo*
+egg_list_box_lookup_info (EggListBox *list_box, GtkWidget* child)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+
+ return g_hash_table_lookup (priv->child_hash, child);
+}
+
+static void
+child_visibility_changed (GObject* object, GParamSpec* pspec, EggListBox *list_box)
+{
+ EggListBoxChildInfo *info;
+
+ if (gtk_widget_get_visible (GTK_WIDGET (list_box)))
+ {
+ info = egg_list_box_lookup_info (list_box, GTK_WIDGET (object));
+ if (info != NULL)
+ {
+ egg_list_box_update_separator (list_box, info->iter);
+ egg_list_box_update_separator (list_box,
+ egg_list_box_get_next_visible (list_box, info->iter));
+ }
+ }
+}
+
+static void
+egg_list_box_real_add (GtkContainer* container, GtkWidget* child)
+{
+ EggListBox *list_box = EGG_LIST_BOX (container);
+ EggListBoxPrivate *priv = list_box->priv;
+ EggListBoxChildInfo *info;
+ GSequenceIter* iter = NULL;
+ info = egg_list_box_child_info_new (child);
+ g_hash_table_insert (priv->child_hash, child, info);
+ if (priv->sort_func != NULL)
+ iter = g_sequence_insert_sorted (priv->children, info,
+ (GCompareDataFunc)do_sort, list_box);
+ else
+ iter = g_sequence_append (priv->children, info);
+
+ info->iter = iter;
+ gtk_widget_set_parent (child, GTK_WIDGET (list_box));
+ egg_list_box_apply_filter (list_box, child);
+ if (gtk_widget_get_visible (GTK_WIDGET (list_box)))
+ {
+ egg_list_box_update_separator (list_box, iter);
+ egg_list_box_update_separator (list_box, egg_list_box_get_next_visible (list_box, iter));
+ }
+ g_signal_connect_object (child, "notify::visible",
+ (GCallback) child_visibility_changed, list_box, 0);
+}
+
+static void
+egg_list_box_real_remove (GtkContainer* container, GtkWidget* child)
+{
+ EggListBox *list_box = EGG_LIST_BOX (container);
+ EggListBoxPrivate *priv = list_box->priv;
+ gboolean was_visible;
+ EggListBoxChildInfo *info;
+ GSequenceIter *next;
+
+ g_return_if_fail (child != NULL);
+ was_visible = gtk_widget_get_visible (child);
+
+ g_signal_handlers_disconnect_by_func (child, (GCallback) child_visibility_changed, list_box);
+
+ info = egg_list_box_lookup_info (list_box, child);
+ if (info == NULL)
+ {
+ info = g_hash_table_lookup (priv->separator_hash, child);
+ if (info != NULL)
+ {
+ g_hash_table_remove (priv->separator_hash, child);
+ g_clear_object (&info->separator);
+ gtk_widget_unparent (child);
+ if (was_visible && gtk_widget_get_visible (GTK_WIDGET (list_box)))
+ gtk_widget_queue_resize (GTK_WIDGET (list_box));
+ }
+ else
+ {
+ g_warning ("egg-list-box.vala:846: Tried to remove non-child %p\n", child);
+ }
+ return;
+ }
+
+ if (info->separator != NULL)
+ {
+ g_hash_table_remove (priv->separator_hash, info->separator);
+ gtk_widget_unparent (info->separator);
+ g_clear_object (&info->separator);
+ }
+
+ if (info == priv->selected_child)
+ egg_list_box_update_selected (list_box, NULL);
+ if (info == priv->prelight_child)
+ priv->prelight_child = NULL;
+ if (info == priv->cursor_child)
+ priv->cursor_child = NULL;
+ if (info == priv->active_child)
+ priv->active_child = NULL;
+
+ next = egg_list_box_get_next_visible (list_box, info->iter);
+ gtk_widget_unparent (child);
+ g_hash_table_remove (priv->child_hash, child);
+ g_sequence_remove (info->iter);
+ if (gtk_widget_get_visible (GTK_WIDGET (list_box)))
+ egg_list_box_update_separator (list_box, next);
+
+ if (was_visible && gtk_widget_get_visible (GTK_WIDGET (list_box)))
+ gtk_widget_queue_resize (GTK_WIDGET (list_box));
+}
+
+
+static void
+egg_list_box_real_forall_internal (GtkContainer* container,
+ gboolean include_internals,
+ GtkCallback callback,
+ void* callback_target)
+{
+ EggListBox *list_box = EGG_LIST_BOX (container);
+ EggListBoxPrivate *priv = list_box->priv;
+ GSequenceIter *iter;
+ EggListBoxChildInfo *child_info;
+
+ iter = g_sequence_get_begin_iter (priv->children);
+ while (!g_sequence_iter_is_end (iter))
+ {
+ child_info = g_sequence_get (iter);
+ iter = g_sequence_iter_next (iter);
+ if (child_info->separator != NULL && include_internals)
+ callback (child_info->separator, callback_target);
+ callback (child_info->widget, callback_target);
+ }
+}
+
+static void
+egg_list_box_real_compute_expand_internal (GtkWidget* widget,
+ gboolean* hexpand,
+ gboolean* vexpand)
+{
+ GTK_WIDGET_CLASS (egg_list_box_parent_class)->compute_expand (widget,
+ hexpand, vexpand);
+
+ /* We don't expand vertically beyound the minimum size */
+ if (vexpand)
+ *vexpand = FALSE;
+}
+
+static GType
+egg_list_box_real_child_type (GtkContainer* container)
+{
+ return GTK_TYPE_WIDGET;
+}
+
+static GtkSizeRequestMode
+egg_list_box_real_get_request_mode (GtkWidget* widget)
+{
+ return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
+}
+
+static void
+egg_list_box_real_get_preferred_height (GtkWidget* widget,
+ gint* minimum_height,
+ gint* natural_height)
+{
+ gint natural_width;
+ egg_list_box_real_get_preferred_width (widget, NULL, &natural_width);
+ egg_list_box_real_get_preferred_height_for_width (widget, natural_width,
+ minimum_height, natural_height);
+}
+
+static void
+egg_list_box_real_get_preferred_height_for_width (GtkWidget* widget, gint width,
+ gint* minimum_height_out, gint* natural_height_out)
+{
+ EggListBox *list_box = EGG_LIST_BOX (widget);
+ EggListBoxPrivate *priv = list_box->priv;
+ GSequenceIter *iter;
+ gint minimum_height;
+ gint natural_height;
+ GtkStyleContext *context;
+ gint focus_width;
+ gint focus_pad;
+
+ minimum_height = 0;
+
+ context = gtk_widget_get_style_context (GTK_WIDGET (list_box));
+ gtk_style_context_get_style (context,
+ "focus-line-width", &focus_width,
+ "focus-padding", &focus_pad, NULL);
+
+ for (iter = g_sequence_get_begin_iter (priv->children);
+ !g_sequence_iter_is_end (iter);
+ iter = g_sequence_iter_next (iter))
+ {
+ EggListBoxChildInfo *child_info;
+ GtkWidget *child;
+ gint child_min = 0;
+ child_info = g_sequence_get (iter);
+ child = child_info->widget;
+
+ if (!child_is_visible (child))
+ continue;
+
+ if (child_info->separator != NULL)
+ {
+ gtk_widget_get_preferred_height_for_width (child_info->separator, width, &child_min, NULL);
+ minimum_height += child_min;
+ }
+ gtk_widget_get_preferred_height_for_width (child, width - 2 * (focus_width + focus_pad),
+ &child_min, NULL);
+ minimum_height += child_min + 2 * (focus_width + focus_pad);
+ }
+
+ /* We always allocate the minimum height, since handling
+ expanding rows is way too costly, and unlikely to
+ be used, as lists are generally put inside a scrolling window
+ anyway.
+ */
+ natural_height = minimum_height;
+ if (minimum_height_out)
+ *minimum_height_out = minimum_height;
+ if (natural_height_out)
+ *natural_height_out = natural_height;
+}
+
+static void
+egg_list_box_real_get_preferred_width (GtkWidget* widget, gint* minimum_width_out, gint* natural_width_out)
+{
+ EggListBox *list_box = EGG_LIST_BOX (widget);
+ EggListBoxPrivate *priv = list_box->priv;
+ gint minimum_width;
+ gint natural_width;
+ GtkStyleContext *context;
+ gint focus_width;
+ gint focus_pad;
+ GSequenceIter *iter;
+ EggListBoxChildInfo *child_info;
+ GtkWidget *child;
+ gint child_min;
+ gint child_nat;
+
+ context = gtk_widget_get_style_context (GTK_WIDGET (list_box));
+ gtk_style_context_get_style (context, "focus-line-width", &focus_width, "focus-padding", &focus_pad, NULL);
+
+ minimum_width = 0;
+ natural_width = 0;
+
+ for (iter = g_sequence_get_begin_iter (priv->children);
+ !g_sequence_iter_is_end (iter);
+ iter = g_sequence_iter_next (iter))
+ {
+ child_info = g_sequence_get (iter);
+ child = child_info->widget;
+ if (!child_is_visible (child))
+ continue;
+
+ gtk_widget_get_preferred_width (child, &child_min, &child_nat);
+ minimum_width = MAX (minimum_width, child_min + 2 * (focus_width + focus_pad));
+ natural_width = MAX (natural_width, child_nat + 2 * (focus_width + focus_pad));
+
+ if (child_info->separator != NULL)
+ {
+ gtk_widget_get_preferred_width (child_info->separator, &child_min, &child_nat);
+ minimum_width = MAX (minimum_width, child_min);
+ natural_width = MAX (natural_width, child_nat);
+ }
+ }
+
+ if (minimum_width_out)
+ *minimum_width_out = minimum_width;
+ if (natural_width_out)
+ *natural_width_out = natural_width;
+}
+
+static void
+egg_list_box_real_get_preferred_width_for_height (GtkWidget *widget, gint height,
+ gint *minimum_width, gint *natural_width)
+{
+ EggListBox *list_box = EGG_LIST_BOX (widget);
+ egg_list_box_real_get_preferred_width (GTK_WIDGET (list_box), minimum_width, natural_width);
+}
+
+static void
+egg_list_box_real_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
+{
+ EggListBox *list_box = EGG_LIST_BOX (widget);
+ EggListBoxPrivate *priv = list_box->priv;
+ GtkAllocation child_allocation;
+ GtkAllocation separator_allocation;
+ EggListBoxChildInfo *child_info;
+ GdkWindow *window;
+ GtkWidget *child;
+ GSequenceIter *iter;
+ GtkStyleContext *context;
+ gint focus_width;
+ gint focus_pad;
+ int child_min;
+
+
+ child_allocation.x = 0;
+ child_allocation.y = 0;
+ child_allocation.width = 0;
+ child_allocation.height = 0;
+
+ separator_allocation.x = 0;
+ separator_allocation.y = 0;
+ separator_allocation.width = 0;
+ separator_allocation.height = 0;
+
+ gtk_widget_set_allocation (GTK_WIDGET (list_box), allocation);
+ window = gtk_widget_get_window (GTK_WIDGET (list_box));
+ if (window != NULL)
+ gdk_window_move_resize (window,
+ allocation->x, allocation->y,
+ allocation->width, allocation->height);
+
+ context = gtk_widget_get_style_context (GTK_WIDGET (list_box));
+ gtk_style_context_get_style (context,
+ "focus-line-width", &focus_width,
+ "focus-padding", &focus_pad,
+ NULL);
+ child_allocation.x = 0 + focus_width + focus_pad;
+ child_allocation.y = 0;
+ child_allocation.width = allocation->width - 2 * (focus_width + focus_pad);
+ separator_allocation.x = 0;
+ separator_allocation.width = allocation->width;
+
+ for (iter = g_sequence_get_begin_iter (priv->children);
+ !g_sequence_iter_is_end (iter);
+ iter = g_sequence_iter_next (iter))
+ {
+ child_info = g_sequence_get (iter);
+ child = child_info->widget;
+ if (!child_is_visible (child))
+ {
+ child_info->y = child_allocation.y;
+ child_info->height = 0;
+ continue;
+ }
+
+ if (child_info->separator != NULL)
+ {
+ gtk_widget_get_preferred_height_for_width (child_info->separator,
+ allocation->width, &child_min, NULL);
+ separator_allocation.height = child_min;
+ separator_allocation.y = child_allocation.y;
+ gtk_widget_size_allocate (child_info->separator,
+ &separator_allocation);
+ child_allocation.y += child_min;
+ }
+
+ child_info->y = child_allocation.y;
+ child_allocation.y += focus_width + focus_pad;
+
+ gtk_widget_get_preferred_height_for_width (child, child_allocation.width, &child_min, NULL);
+ child_allocation.height = child_min;
+
+ child_info->height = child_allocation.height + 2 * (focus_width + focus_pad);
+ gtk_widget_size_allocate (child, &child_allocation);
+
+ child_allocation.y += child_min + focus_width + focus_pad;
+ }
+}
+
+void
+egg_list_box_drag_unhighlight_widget (EggListBox *list_box)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+
+ g_return_if_fail (list_box != NULL);
+
+ if (priv->drag_highlighted_widget == NULL)
+ return;
+
+ gtk_drag_unhighlight (priv->drag_highlighted_widget);
+ g_clear_object (&priv->drag_highlighted_widget);
+}
+
+
+void
+egg_list_box_drag_highlight_widget (EggListBox *list_box, GtkWidget *child)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+ GtkWidget *old_highlight;
+
+ g_return_if_fail (list_box != NULL);
+ g_return_if_fail (child != NULL);
+
+ if (priv->drag_highlighted_widget == child)
+ return;
+
+ egg_list_box_drag_unhighlight_widget (list_box);
+ gtk_drag_highlight (child);
+
+ old_highlight = priv->drag_highlighted_widget;
+ priv->drag_highlighted_widget = g_object_ref (child);
+ if (old_highlight)
+ g_object_unref (old_highlight);
+}
+
+static void
+egg_list_box_real_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time_)
+{
+ EggListBox *list_box = EGG_LIST_BOX (widget);
+ EggListBoxPrivate *priv = list_box->priv;
+
+ egg_list_box_drag_unhighlight_widget (list_box);
+ if (priv->auto_scroll_timeout_id != 0) {
+ g_source_remove (priv->auto_scroll_timeout_id);
+ priv->auto_scroll_timeout_id = 0;
+ }
+}
+
+typedef struct
+{
+ EggListBox *list_box;
+ gint move;
+} MoveData;
+
+static void
+move_data_free (MoveData *data)
+{
+ g_slice_free (MoveData, data);
+}
+
+static gboolean
+drag_motion_timeout (MoveData *data)
+{
+ EggListBox *list_box = data->list_box;
+ EggListBoxPrivate *priv = list_box->priv;
+
+ gtk_adjustment_set_value (priv->adjustment,
+ gtk_adjustment_get_value (priv->adjustment) +
+ gtk_adjustment_get_step_increment (priv->adjustment) * data->move);
+ return TRUE;
+}
+
+static gboolean
+egg_list_box_real_drag_motion (GtkWidget *widget, GdkDragContext *context,
+ gint x, gint y, guint time_)
+{
+ EggListBox *list_box = EGG_LIST_BOX (widget);
+ EggListBoxPrivate *priv = list_box->priv;
+ int move;
+ MoveData *data;
+ gdouble size;
+
+ /* Auto-scroll during Dnd if cursor is moving into the top/bottom portion of the
+ * box. */
+ if (priv->auto_scroll_timeout_id != 0)
+ {
+ g_source_remove (priv->auto_scroll_timeout_id);
+ priv->auto_scroll_timeout_id = 0;
+ }
+
+ if (priv->adjustment == NULL)
+ return FALSE;
+
+ /* Part of the view triggering auto-scroll */
+ size = 30;
+ move = 0;
+
+ if (y < (gtk_adjustment_get_value (priv->adjustment) + size))
+ {
+ /* Scroll up */
+ move = -1;
+ }
+ else if (y > ((gtk_adjustment_get_value (priv->adjustment) + gtk_adjustment_get_page_size (priv->adjustment)) - size))
+ {
+ /* Scroll down */
+ move = 1;
+ }
+
+ if (move == 0)
+ return FALSE;
+
+ data = g_slice_new0 (MoveData);
+ data->list_box = list_box;
+
+ priv->auto_scroll_timeout_id =
+ g_timeout_add_full (G_PRIORITY_DEFAULT, 150, (GSourceFunc)drag_motion_timeout,
+ data, (GDestroyNotify) move_data_free);
+
+ return FALSE;
+}
+
+static void
+egg_list_box_real_activate_cursor_child (EggListBox *list_box)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+
+ egg_list_box_select_and_activate (list_box, priv->cursor_child);
+}
+
+static void
+egg_list_box_real_toggle_cursor_child (EggListBox *list_box)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+
+ if (priv->cursor_child == NULL)
+ return;
+
+ if (priv->selection_mode == GTK_SELECTION_SINGLE &&
+ priv->selected_child == priv->cursor_child)
+ egg_list_box_update_selected (list_box, NULL);
+ else
+ egg_list_box_select_and_activate (list_box, priv->cursor_child);
+}
+
+static void
+egg_list_box_real_move_cursor (EggListBox *list_box,
+ GtkMovementStep step,
+ gint count)
+{
+ EggListBoxPrivate *priv = list_box->priv;
+ GdkModifierType state;
+ gboolean modify_selection_pressed;
+ EggListBoxChildInfo *child;
+ GdkModifierType modify_mod_mask;
+ EggListBoxChildInfo *prev;
+ EggListBoxChildInfo *next;
+ gint page_size;
+ GSequenceIter *iter;
+ gint start_y;
+ gint end_y;
+
+ modify_selection_pressed = FALSE;
+
+ if (gtk_get_current_event_state (&state))
+ {
+ modify_mod_mask = gtk_widget_get_modifier_mask (GTK_WIDGET (list_box),
+ GDK_MODIFIER_INTENT_MODIFY_SELECTION);
+ if ((state & modify_mod_mask) == modify_mod_mask)
+ modify_selection_pressed = TRUE;
+ }
+
+ child = NULL;
+ switch (step)
+ {
+ case GTK_MOVEMENT_BUFFER_ENDS:
+ if (count < 0)
+ child = egg_list_box_get_first_visible (list_box);
+ else
+ child = egg_list_box_get_last_visible (list_box);
+ break;
+ case GTK_MOVEMENT_DISPLAY_LINES:
+ if (priv->cursor_child != NULL)
+ {
+ iter = priv->cursor_child->iter;
+
+ while (count < 0 && iter != NULL)
+ {
+ iter = egg_list_box_get_previous_visible (list_box, iter);
+ count = count + 1;
+ }
+ while (count > 0 && iter != NULL)
+ {
+ iter = egg_list_box_get_next_visible (list_box, iter);
+ count = count - 1;
+ }
+
+ if (iter != NULL && !g_sequence_iter_is_end (iter))
+ child = g_sequence_get (iter);
+ }
+ break;
+ case GTK_MOVEMENT_PAGES:
+ page_size = 100;
+ if (priv->adjustment != NULL)
+ page_size = gtk_adjustment_get_page_increment (priv->adjustment);
+
+ if (priv->cursor_child != NULL)
+ {
+ start_y = priv->cursor_child->y;
+ end_y = start_y;
+ iter = priv->cursor_child->iter;
+
+ child = priv->cursor_child;
+ if (count < 0)
+ {
+ /* Up */
+ while (iter != NULL && !g_sequence_iter_is_begin (iter))
+ {
+ iter = egg_list_box_get_previous_visible (list_box, iter);
+ if (iter == NULL)
+ break;
+
+ prev = g_sequence_get (iter);
+ if (prev->y < start_y - page_size)
+ break;
+
+ child = prev;
+ }
+ }
+ else
+ {
+ /* Down */
+ while (iter != NULL && !g_sequence_iter_is_end (iter))
+ {
+ iter = egg_list_box_get_next_visible (list_box, iter);
+ if (g_sequence_iter_is_end (iter))
+ break;
+
+ next = g_sequence_get (iter);
+ if (next->y > start_y + page_size)
+ break;
+
+ child = next;
+ }
+ }
+ end_y = child->y;
+ if (end_y != start_y && priv->adjustment != NULL)
+ gtk_adjustment_set_value (priv->adjustment,
+ gtk_adjustment_get_value (priv->adjustment) +
+ end_y - start_y);
+ }
+ break;
+ default:
+ return;
+ }
+
+ if (child == NULL)
+ {
+ gtk_widget_error_bell (GTK_WIDGET (list_box));
+ return;
+ }
+
+ egg_list_box_update_cursor (list_box, child);
+ if (!modify_selection_pressed)
+ egg_list_box_update_selected (list_box, child);
+}
diff --git a/src/egg-list-box.h b/src/egg-list-box.h
new file mode 100644
index 0000000..c816a14
--- /dev/null
+++ b/src/egg-list-box.h
@@ -0,0 +1,78 @@
+#ifndef __EGG_LIST_BOX_H__
+#define __EGG_LIST_BOX_H__
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+
+#define EGG_TYPE_LIST_BOX (egg_list_box_get_type ())
+#define EGG_LIST_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_LIST_BOX, EggListBox))
+#define EGG_LIST_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_LIST_BOX, EggListBoxClass))
+#define EGG_IS_LIST_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_LIST_BOX))
+#define EGG_IS_LIST_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_LIST_BOX))
+#define EGG_LIST_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_LIST_BOX, EggListBoxClass))
+
+typedef struct _EggListBox EggListBox;
+typedef struct _EggListBoxClass EggListBoxClass;
+typedef struct _EggListBoxPrivate EggListBoxPrivate;
+
+struct _EggListBox
+{
+ GtkContainer parent_instance;
+ EggListBoxPrivate * priv;
+};
+
+struct _EggListBoxClass
+{
+ GtkContainerClass parent_class;
+ void (*child_selected) (EggListBox* self, GtkWidget* child);
+ void (*child_activated) (EggListBox* self, GtkWidget* child);
+ void (*activate_cursor_child) (EggListBox* self);
+ void (*toggle_cursor_child) (EggListBox* self);
+ void (*move_cursor) (EggListBox* self, GtkMovementStep step, gint count);
+};
+
+typedef gboolean (*EggListBoxFilterFunc) (GtkWidget* child, void* user_data);
+typedef void (*EggListBoxUpdateSeparatorFunc) (GtkWidget** separator, GtkWidget* child, GtkWidget* before, void* user_data);
+
+GType egg_list_box_get_type (void) G_GNUC_CONST;
+GtkWidget* egg_list_box_get_selected_child (EggListBox *self);
+GtkWidget* egg_list_box_get_child_at_y (EggListBox *self,
+ gint y);
+void egg_list_box_select_child (EggListBox *self,
+ GtkWidget *child);
+void egg_list_box_set_adjustment (EggListBox *self,
+ GtkAdjustment *adjustment);
+void egg_list_box_add_to_scrolled (EggListBox *self,
+ GtkScrolledWindow *scrolled);
+void egg_list_box_set_selection_mode (EggListBox *self,
+ GtkSelectionMode mode);
+void egg_list_box_set_filter_func (EggListBox *self,
+ EggListBoxFilterFunc f,
+ void *f_target,
+ GDestroyNotify f_target_destroy_notify);
+void egg_list_box_set_separator_funcs (EggListBox *self,
+ EggListBoxUpdateSeparatorFunc update_separator,
+ void *update_separator_target,
+ GDestroyNotify update_separator_target_destroy_notify);
+void egg_list_box_refilter (EggListBox *self);
+void egg_list_box_resort (EggListBox *self);
+void egg_list_box_reseparate (EggListBox *self);
+void egg_list_box_set_sort_func (EggListBox *self,
+ GCompareDataFunc f,
+ void *f_target,
+ GDestroyNotify f_target_destroy_notify);
+void egg_list_box_child_changed (EggListBox *self,
+ GtkWidget *widget);
+void egg_list_box_set_activate_on_single_click (EggListBox *self,
+ gboolean single);
+void egg_list_box_drag_unhighlight_widget (EggListBox *self);
+void egg_list_box_drag_highlight_widget (EggListBox *self,
+ GtkWidget *widget);
+EggListBox* egg_list_box_new (void);
+
+G_END_DECLS
+
+#endif
diff --git a/src/egglistbox.vapi b/src/egglistbox.vapi
new file mode 100644
index 0000000..8fe65cb
--- /dev/null
+++ b/src/egglistbox.vapi
@@ -0,0 +1,55 @@
+namespace Egg {
+ [CCode (cheader_filename = "egg-list-box.h")]
+ public class ListBox : Gtk.Container {
+ public delegate bool FilterFunc (Gtk.Widget child);
+ public delegate void UpdateSeparatorFunc (ref Gtk.Widget? separator, Gtk.Widget child, Gtk.Widget? before);
+ [CCode (has_construct_function = false)]
+ public ListBox ();
+ public override void add (Gtk.Widget widget);
+ public void add_to_scrolled (Gtk.ScrolledWindow scrolled);
+ public override bool button_press_event (Gdk.EventButton event);
+ public override bool button_release_event (Gdk.EventButton event);
+ public void child_changed (Gtk.Widget widget);
+ public override GLib.Type child_type ();
+ public override void compute_expand_internal (out bool hexpand, out bool vexpand);
+ public void drag_highlight_widget (Gtk.Widget widget);
+ public override void drag_leave (Gdk.DragContext context, uint time_);
+ public override bool drag_motion (Gdk.DragContext context, int x, int y, uint time_);
+ public void drag_unhighlight_widget ();
+ public override bool draw (Cairo.Context cr);
+ public override bool enter_notify_event (Gdk.EventCrossing event);
+ public override bool focus (Gtk.DirectionType direction);
+ public override void forall_internal (bool include_internals, Gtk.Callback callback);
+ public unowned Gtk.Widget? get_child_at_y (int y);
+ public override void get_preferred_height (out int minimum_height, out int natural_height);
+ public override void get_preferred_height_for_width (int width, out int minimum_height, out int natural_height);
+ public override void get_preferred_width (out int minimum_width, out int natural_width);
+ public override void get_preferred_width_for_height (int height, out int minimum_width, out int natural_width);
+ public override Gtk.SizeRequestMode get_request_mode ();
+ public unowned Gtk.Widget? get_selected_child ();
+ public override bool leave_notify_event (Gdk.EventCrossing event);
+ public override bool motion_notify_event (Gdk.EventMotion event);
+ public override void realize ();
+ public void refilter ();
+ public override void remove (Gtk.Widget widget);
+ public void reseparate ();
+ public void resort ();
+ public void select_child (Gtk.Widget? child);
+ public void set_activate_on_single_click (bool single);
+ public void set_adjustment (Gtk.Adjustment? adjustment);
+ public void set_filter_func (owned Egg.ListBox.FilterFunc? f);
+ public void set_selection_mode (Gtk.SelectionMode mode);
+ public void set_separator_funcs (owned Egg.ListBox.UpdateSeparatorFunc? update_separator);
+ public void set_sort_func (owned GLib.CompareDataFunc<Gtk.Widget>? f);
+ public override void show ();
+ public override void size_allocate (Gtk.Allocation allocation);
+ [Signal (action = true)]
+ public virtual signal void activate_cursor_child ();
+ public virtual signal void child_activated (Gtk.Widget? child);
+ public virtual signal void child_selected (Gtk.Widget? child);
+ [Signal (action = true)]
+ public virtual signal void move_cursor (Gtk.MovementStep step, int count);
+ [Signal (action = true)]
+ public virtual signal void toggle_cursor_child ();
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]