Re: GtkToolbar drag and drop
- From: Soeren Sandmann <sandmann daimi au dk>
- To: gtk-devel-list gnome org
- Cc: marco gnome org, james daa com au
- Subject: Re: GtkToolbar drag and drop
- Date: 05 Oct 2003 21:29:29 +0200
Soeren Sandmann <sandmann daimi au dk> writes:
> So here is a patch that implements this (including Mac OS X style
I forgot the patch.
Søren
Index: gtk/gtktoolbar.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktoolbar.c,v
retrieving revision 1.108
diff -u -r1.108 gtktoolbar.c
--- gtk/gtktoolbar.c 4 Oct 2003 22:58:14 -0000 1.108
+++ gtk/gtktoolbar.c 5 Oct 2003 19:00:50 -0000
@@ -57,8 +57,8 @@
#define DEFAULT_ICON_SIZE GTK_ICON_SIZE_LARGE_TOOLBAR
#define DEFAULT_TOOLBAR_STYLE GTK_TOOLBAR_BOTH
-#define MAX_HOMOGENEOUS_N_CHARS 13 /* Items that are wider than this do not participate in
- * the homogeneous game. In units of
+#define MAX_HOMOGENEOUS_N_CHARS 13 /* Items that are wider than this do not participate
+ * in the homogeneous game. In units of
* pango_font_get_estimated_char_width().
*/
@@ -116,14 +116,6 @@
static void gtk_toolbar_map (GtkWidget *widget);
static void gtk_toolbar_unmap (GtkWidget *widget);
-static void gtk_toolbar_drag_leave (GtkWidget *widget,
- GdkDragContext *context,
- guint time_);
-static gboolean gtk_toolbar_drag_motion (GtkWidget *widget,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time_);
static void gtk_toolbar_set_child_property (GtkContainer *container,
GtkWidget *child,
guint property_id,
@@ -183,6 +175,10 @@
gpointer user_data,
gint position,
gboolean use_stock);
+static void gtk_toolbar_insert_tool_item (GtkToolbar *toolbar,
+ GtkToolItem *item,
+ gint pos,
+ gboolean is_placeholder);
typedef enum {
@@ -192,23 +188,38 @@
} ApiMode;
#define GTK_TOOLBAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_TOOLBAR, GtkToolbarPrivate))
+typedef struct _ToolbarContent ToolbarContent;
+struct _ToolbarContent
+{
+ GtkToolItem *item;
+ guint is_overflow : 1;
+ guint is_placeholder : 1;
+ gint start_width;
+ gint goal_width;
+ gint start_height;
+ gint goal_height;
+};
struct _GtkToolbarPrivate
{
- GList *items;
+ GList *content;
GtkWidget *arrow;
GtkWidget *arrow_button;
gboolean show_arrow;
- gint drop_index;
- GdkWindow *drag_highlight;
GtkMenu *menu;
GdkWindow *event_window;
ApiMode api_mode;
GtkSettings *settings;
+ int idle_id;
+ GTimer *timer;
+ gboolean need_sync;
+ gboolean leaving_dnd;
+ gboolean in_dnd;
+ gint n_overflow_items_when_dnd_started;
};
static GtkContainerClass *parent_class = NULL;
@@ -304,9 +315,6 @@
widget_class->unmap = gtk_toolbar_unmap;
widget_class->popup_menu = gtk_toolbar_popup_menu;
- widget_class->drag_leave = gtk_toolbar_drag_leave;
- widget_class->drag_motion = gtk_toolbar_drag_motion;
-
container_class->add = gtk_toolbar_add;
container_class->remove = gtk_toolbar_remove;
container_class->forall = gtk_toolbar_forall;
@@ -586,12 +594,11 @@
gtk_widget_set_parent (priv->arrow_button, GTK_WIDGET (toolbar));
/* which child position a drop will occur at */
- priv->drop_index = -1;
- priv->drag_highlight = NULL;
-
priv->menu = NULL;
priv->show_arrow = TRUE;
priv->settings = NULL;
+
+ priv->timer = g_timer_new ();
}
static gboolean
@@ -661,23 +668,6 @@
}
static void
-toolbar_item_set_is_overflow (GtkToolItem *item,
- gboolean is_overflow)
-{
- g_object_set_data (G_OBJECT (item), "gtk-toolbar-item-is-overflow", GINT_TO_POINTER (is_overflow));
-}
-
-static gboolean
-toolbar_item_get_is_overflow (GtkToolItem *item)
-{
- gpointer result;
-
- result = g_object_get_data (G_OBJECT (item), "gtk-toolbar-item-is-overflow");
-
- return GPOINTER_TO_INT (result);
-}
-
-static void
gtk_toolbar_set_property (GObject *object,
guint prop_id,
const GValue *value,
@@ -792,13 +782,6 @@
{
GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
- if (priv->drag_highlight)
- {
- gdk_window_set_user_data (priv->drag_highlight, NULL);
- gdk_window_destroy (priv->drag_highlight);
- priv->drag_highlight = NULL;
- }
-
if (priv->event_window)
{
gdk_window_set_user_data (priv->event_window, NULL);
@@ -817,7 +800,7 @@
GtkToolbar *toolbar = GTK_TOOLBAR (widget);
GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
- GList *items;
+ GList *list;
gint border_width;
border_width = GTK_CONTAINER (widget)->border_width;
@@ -835,16 +818,15 @@
widget->allocation.height - 2 * border_width);
}
- items = priv->items;
- while (items)
+ for (list = priv->content; list != NULL; list = list->next)
{
- GtkToolItem *item = GTK_TOOL_ITEM (items->data);
+ ToolbarContent *content = list->data;
+ GtkToolItem *item = content->item;
- gtk_container_propagate_expose (GTK_CONTAINER (widget),
- GTK_WIDGET (item),
- event);
-
- items = items->next;
+ if (!content->is_placeholder)
+ gtk_container_propagate_expose (GTK_CONTAINER (widget),
+ GTK_WIDGET (item),
+ event);
}
gtk_container_propagate_expose (GTK_CONTAINER (widget),
@@ -876,10 +858,11 @@
max_homogeneous_child_height = 0;
max_child_width = 0;
max_child_height = 0;
- for (list = priv->items; list != NULL; list = list->next)
+ for (list = priv->content; list != NULL; list = list->next)
{
GtkRequisition requisition;
- GtkToolItem *item = list->data;
+ ToolbarContent *content = list->data;
+ GtkToolItem *item = content->item;
if (!toolbar_item_visible (toolbar, item))
continue;
@@ -903,9 +886,10 @@
pack_end_size = 0;
pack_front_size = 0;
- for (list = priv->items; list != NULL; list = list->next)
+ for (list = priv->content; list != NULL; list = list->next)
{
- GtkToolItem *item = list->data;
+ ToolbarContent *content = list->data;
+ GtkToolItem *item = content->item;
guint size;
if (!toolbar_item_visible (toolbar, item))
@@ -1046,8 +1030,9 @@
gint available_size;
gint n_items;
gint needed_size;
- GList *items;
+ GList *content;
GtkRequisition arrow_requisition;
+ gint n_overflowed;
widget->allocation = *allocation;
@@ -1092,13 +1077,14 @@
}
}
- n_items = g_list_length (priv->items);
+ n_items = g_list_length (priv->content);
allocations = g_new0 (GtkAllocation, n_items);
needed_size = 0;
- for (list = priv->items; list != NULL; list = list->next)
+ for (list = priv->content; list != NULL; list = list->next)
{
- GtkToolItem *item = list->data;
+ ToolbarContent *content = list->data;
+ GtkToolItem *item = content->item;
if (toolbar_item_visible (toolbar, item))
needed_size += get_item_size (toolbar, GTK_WIDGET (item));
@@ -1111,12 +1097,15 @@
else
size = available_size;
- items = g_list_copy (priv->items);
+ content = g_list_copy (priv->content);
+ n_overflowed = 0;
+
/* calculate widths of pack end items */
- for (list = g_list_last (items), i = 0; list != NULL; list = list->prev, ++i)
+ for (list = g_list_last (content), i = 0; list != NULL; list = list->prev, ++i)
{
- GtkToolItem *item = list->data;
+ ToolbarContent *content = list->data;
+ GtkToolItem *item = content->item;
GtkAllocation *allocation = &(allocations[n_items - i - 1]);
gint item_size;
@@ -1129,16 +1118,17 @@
{
size -= item_size;
allocation->width = item_size;
- toolbar_item_set_is_overflow (item, FALSE);
+ content->is_overflow = FALSE;
}
else
{
while (list)
{
- item = list->data;
+ content = list->data;
+ item = content->item;
if (gtk_tool_item_get_pack_end (item))
- toolbar_item_set_is_overflow (item, TRUE);
-
+ content->is_overflow = TRUE;
+ ++n_overflowed;
list = list->prev;
}
break;
@@ -1146,9 +1136,10 @@
}
/* calculate widths of pack front items */
- for (list = items, i = 0; list != NULL; list = list->next, ++i)
+ for (list = content, i = 0; list != NULL; list = list->next, ++i)
{
- GtkToolItem *item = list->data;
+ ToolbarContent *content = list->data;
+ GtkToolItem *item = content->item;
gint item_size;
if (gtk_tool_item_get_pack_end (item) || !toolbar_item_visible (toolbar, item))
@@ -1159,15 +1150,17 @@
{
size -= item_size;
allocations[i].width = item_size;
- toolbar_item_set_is_overflow (item, FALSE);
+ content->is_overflow = FALSE;
}
else
{
while (list)
{
- item = list->data;
+ content = list->data;
+ item = content->item;
if (!gtk_tool_item_get_pack_end (item))
- toolbar_item_set_is_overflow (item, TRUE);
+ content->is_overflow = TRUE;
+ ++n_overflowed;
list = list->next;
}
break;
@@ -1181,47 +1174,67 @@
}
/* expand expandable items */
- n_expand_items = 0;
- for (list = priv->items; list != NULL; list = list->next)
+
+ /* We don't expand when dnd causes items to overflow. Doing so would result in
+ * weird jumps as items are overflowed and expandable items suddenly get lots of
+ * extra space. On the other hand we can't disable expanding completely, because
+ * that would cause a weird jump when dnd begins
+ *
+ * So, if the overflow is *caused* by dnd, we disable expanding. This works
+ * because at the moment when item overflows, all expandable items are non-expanded,
+ * (since shrinking an expanded item would be preferred over overflowing).
+ *
+ * So disabling expanding at that point will not cause any jumping.
+ */
+ if (!(priv->in_dnd && n_overflowed > priv->n_overflow_items_when_dnd_started))
{
- GtkToolItem *item = list->data;
-
- if (toolbar_item_visible (toolbar, item) &&
- gtk_tool_item_get_expand (item) &&
- !toolbar_item_get_is_overflow (item) &&
- !GTK_IS_SEPARATOR_TOOL_ITEM (item))
+ n_expand_items = 0;
+ for (list = priv->content; list != NULL; list = list->next)
{
- n_expand_items++;
+ ToolbarContent *content = list->data;
+ GtkToolItem *item = content->item;
+
+ if (toolbar_item_visible (toolbar, item) &&
+ gtk_tool_item_get_expand (item) &&
+ !content->is_overflow &&
+ !GTK_IS_SEPARATOR_TOOL_ITEM (item))
+ {
+ n_expand_items++;
+ }
}
- }
-
- for (list = items, i = 0; list != NULL; list = list->next, ++i)
- {
- GtkToolItem *item = list->data;
- if (toolbar_item_visible (toolbar, item) && gtk_tool_item_get_expand (item) &&
- !toolbar_item_get_is_overflow (item) &&
- !GTK_IS_SEPARATOR_TOOL_ITEM (item))
+ for (list = content, i = 0; list != NULL; list = list->next, ++i)
{
- gint extra = size / n_expand_items;
- if (size % n_expand_items != 0)
- extra++;
-
- allocations[i].width += extra;
- size -= extra;
- n_expand_items--;
+ ToolbarContent *content = list->data;
+ GtkToolItem *item = content->item;
+
+ if (toolbar_item_visible (toolbar, item) && gtk_tool_item_get_expand (item) &&
+ !content->is_overflow &&
+ !GTK_IS_SEPARATOR_TOOL_ITEM (item))
+ {
+ gint extra = size / n_expand_items;
+ if (size % n_expand_items != 0)
+ extra++;
+
+ allocations[i].width += extra;
+ size -= extra;
+ n_expand_items--;
+ }
}
+
+ g_assert (n_expand_items == 0);
}
-
- g_assert (n_expand_items == 0);
/* position pack front items */
pos = border_width;
- for (list = items, i = 0; list != NULL; list = list->next, ++i)
+ for (list = content, i = 0; list != NULL; list = list->next, ++i)
{
- GtkToolItem *item = list->data;
+ ToolbarContent *content = list->data;
+ GtkToolItem *item = content->item;
- if (toolbar_item_visible (toolbar, item) && !toolbar_item_get_is_overflow (item) && !gtk_tool_item_get_pack_end (item))
+ if (toolbar_item_visible (toolbar, item) &&
+ !content->is_overflow &&
+ !gtk_tool_item_get_pack_end (item))
{
allocations[i].x = pos;
allocations[i].y = border_width;
@@ -1233,11 +1246,14 @@
/* position pack end items */
pos = available_size + border_width;
- for (list = g_list_last (items), i = 0; list != NULL; list = list->prev, ++i)
+ for (list = g_list_last (content), i = 0; list != NULL; list = list->prev, ++i)
{
- GtkToolItem *item = list->data;
+ ToolbarContent *content = list->data;
+ GtkToolItem *item = content->item;
- if (toolbar_item_visible (toolbar, item) && !toolbar_item_get_is_overflow (item) && gtk_tool_item_get_pack_end (item))
+ if (toolbar_item_visible (toolbar, item) &&
+ !content->is_overflow &&
+ gtk_tool_item_get_pack_end (item))
{
GtkAllocation *allocation = &(allocations[n_items - i - 1]);
@@ -1300,11 +1316,12 @@
}
/* finally allocate the items */
- for (list = items, i = 0; list != NULL; list = list->next, i++)
+ for (list = content, i = 0; list != NULL; list = list->next, i++)
{
- GtkToolItem *item = list->data;
+ ToolbarContent *content = list->data;
+ GtkToolItem *item = content->item;
- if (toolbar_item_visible (toolbar, item) && !toolbar_item_get_is_overflow (item))
+ if (toolbar_item_visible (toolbar, item) && !content->is_overflow)
{
gtk_widget_size_allocate (GTK_WIDGET (item), &(allocations[i]));
gtk_widget_set_child_visible (GTK_WIDGET (item), TRUE);
@@ -1327,7 +1344,7 @@
}
g_free (allocations);
- g_list_free (items);
+ g_list_free (content);
}
static void
@@ -1370,18 +1387,20 @@
/* generate list of children in reverse logical order */
- for (list = priv->items; list != NULL; list = list->next)
+ for (list = priv->content; list != NULL; list = list->next)
{
- GtkToolItem *item = list->data;
+ ToolbarContent *content = list->data;
+ GtkToolItem *item = content->item;
if (!gtk_tool_item_get_pack_end (item))
result = g_list_prepend (result, item);
}
result = g_list_prepend (result, priv->arrow_button);
- for (list = priv->items; list != NULL; list = list->next)
+ for (list = priv->content; list != NULL; list = list->next)
{
- GtkToolItem *item = list->data;
+ ToolbarContent *content = list->data;
+ GtkToolItem *item = content->item;
if (gtk_tool_item_get_pack_end (item))
result = g_list_prepend (result, item);
@@ -1585,175 +1604,345 @@
icon_size_change_notify (toolbar);
}
-static void
-find_drop_pos (GtkToolbar *toolbar,
- gint x,
- gint y,
- gint *drop_index,
- gint *drop_pos)
+static int
+find_drop_index (GtkToolbar *toolbar,
+ gint x,
+ gint y)
{
GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
+ GList *interesting_content;
+ GList *list;
GtkOrientation orientation;
GtkTextDirection direction;
- GList *items;
- GtkToolItem *item;
- gint border_width;
- gint best_distance, best_pos, best_index, index;
+ gint best_distance = G_MAXINT;
+ gint distance;
+ gint cursor;
+ gint pos;
+ ToolbarContent *best_content;
+
+ /* list items we care about wrt. drag and drop */
+ interesting_content = NULL;
+ for (list = priv->content; list != NULL; list = list->next)
+ {
+ ToolbarContent *content = list->data;
+ GtkToolItem *item = content->item;
+
+ if (!gtk_tool_item_get_pack_end (item) &&
+ toolbar_item_visible (toolbar, item) &&
+ !content->is_overflow)
+ {
+ interesting_content = g_list_prepend (interesting_content, content);
+ }
+ }
+ interesting_content = g_list_reverse (interesting_content);
+
+ if (!interesting_content)
+ return 0;
orientation = toolbar->orientation;
direction = gtk_widget_get_direction (GTK_WIDGET (toolbar));
- border_width = GTK_CONTAINER (toolbar)->border_width + get_internal_padding (toolbar);
- items = priv->items;
- if (!items)
+ /* distance to first interesting item */
+ best_content = interesting_content->data;
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ cursor = x;
+
+ if (direction == GTK_TEXT_DIR_LTR)
+ pos = GTK_WIDGET (best_content->item)->allocation.x;
+ else
+ pos = GTK_WIDGET (best_content->item)->allocation.x +
+ GTK_WIDGET (best_content->item)->allocation.width;
+ }
+ else
+ {
+ cursor = y;
+ pos = GTK_WIDGET (best_content->item)->allocation.y;
+ }
+
+ best_content = NULL;
+ best_distance = ABS (pos - cursor);
+
+ /* distance to far end of each item */
+ for (list = interesting_content; list != NULL; list = list->next)
{
- *drop_index = 0;
+ ToolbarContent *content = list->data;
+ GtkWidget *widget = GTK_WIDGET (content->item);
+
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
- if (direction == GTK_TEXT_DIR_LTR)
- *drop_pos = border_width;
+ if (direction == GTK_TEXT_DIR_LTR)
+ pos = widget->allocation.x + widget->allocation.width;
else
- *drop_pos = GTK_WIDGET (toolbar)->allocation.width - border_width;
+ pos = widget->allocation.x;
}
else
{
- *drop_pos = border_width;
+ pos = widget->allocation.y + widget->allocation.height;
+ }
+
+ distance = ABS (pos - cursor);
+
+ if (distance < best_distance)
+ {
+ best_distance = distance;
+ best_content = content;
}
- return;
}
- /* initial conditions */
- item = GTK_TOOL_ITEM (items->data);
- best_index = 0;
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ g_list_free (interesting_content);
+
+ if (!best_content)
+ return 0;
+ else
+ return g_list_index (priv->content, best_content) + 1;
+}
+
+static void
+get_size (GtkToolItem *tool_item, gint *width, gint *height)
+{
+ if (!GTK_WIDGET_VISIBLE (tool_item))
{
- if (direction == GTK_TEXT_DIR_LTR)
- best_pos = GTK_WIDGET (item)->allocation.x;
- else
- best_pos = GTK_WIDGET (item)->allocation.x +
- GTK_WIDGET (item)->allocation.width;
- best_distance = ABS (best_pos - x);
+ *width = 0;
+ *height = 0;
}
else
{
- best_pos = GTK_WIDGET (item)->allocation.y;
- best_distance = ABS (best_pos - y);
+ GtkRequisition req;
+
+ gtk_widget_get_child_requisition (GTK_WIDGET (tool_item), &req);
+ *width = req.width;
+ *height = req.height;
}
+}
+
+#define UPDATE_TIME (0.10)
+
+static gboolean
+update_dnd_animation (gpointer data)
+{
+ GtkToolbar *toolbar = data;
+ GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
+ GList *list;
+ gboolean cont;
+ gdouble elapsed;
+ double error;
+
+ GDK_THREADS_ENTER();
+
+ if (priv->need_sync)
+ gdk_flush ();
+
+ elapsed = g_timer_elapsed (priv->timer, NULL);
- index = 0;
- while (items)
+ cont = FALSE;
+
+ list = priv->content;
+ error = 0.0;
+ while (list)
{
- item = GTK_TOOL_ITEM (items->data);
- index++;
- if (GTK_WIDGET_DRAWABLE (item) && !gtk_tool_item_get_pack_end (item))
+ ToolbarContent *content = list->data;
+ GtkWidget *widget = GTK_WIDGET (content->item);
+ GList *next = list->next;
+ gdouble exact_value;
+ gint start_value, goal_value;
+ gint new_value, prev_value;
+
+ if (content->is_placeholder)
{
- gint pos, distance;
+ gint prev_width, prev_height;
+
+ get_size (GTK_TOOL_ITEM (widget), &prev_width, &prev_height);
+ if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ start_value = content->start_width;
+ goal_value = content->goal_width;
+ prev_value = prev_width;
+ }
+ else
+ {
+ start_value = content->start_height;
+ goal_value = content->goal_height;
+ prev_value = prev_height;
+ }
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ if (elapsed <= UPDATE_TIME)
{
- if (direction == GTK_TEXT_DIR_LTR)
- pos = GTK_WIDGET (item)->allocation.x +
- GTK_WIDGET (item)->allocation.width;
- else
- pos = GTK_WIDGET (item)->allocation.x;
- distance = ABS (pos - x);
+ exact_value = start_value + (elapsed / UPDATE_TIME) * (goal_value - start_value);
+ new_value = (int) (exact_value + error + 0.5);
+
+ error += (exact_value - new_value);
+
+ cont = TRUE;
}
else
{
- pos = GTK_WIDGET (item)->allocation.y +
- GTK_WIDGET (item)->allocation.height;
- distance = ABS (pos - y);
+ exact_value = (double)goal_value;
+ new_value = goal_value;
+ }
+
+ if (new_value == 0)
+ gtk_widget_hide (widget);
+ else
+ gtk_widget_show (widget);
+
+ /* We need to check for "elapsed > UPDATE_TIME" so that the widget
+ * doesn't disappear before time. We need its contribution to
+ * the error value, even if its pixel width is 0.
+ */
+ if (goal_value == 0 && elapsed > UPDATE_TIME)
+ {
+ gtk_toolbar_remove_tool_item (toolbar, GTK_TOOL_ITEM (widget));
}
- if (distance < best_distance)
+ else if (new_value != prev_value)
{
- best_index = index;
- best_pos = pos;
- best_distance = distance;
+ if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
+ gtk_widget_set_size_request (widget, new_value, 0);
+ else
+ gtk_widget_set_size_request (widget, 0, new_value);
+
+ priv->need_sync = TRUE;
+ cont = TRUE;
}
}
- items = items->next;
+
+ list = next;
+ }
+
+ gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
+
+ GDK_THREADS_LEAVE();
+
+ if (!cont)
+ {
+ priv->idle_id = 0;
+ if (priv->leaving_dnd)
+ {
+ priv->in_dnd = FALSE;
+ priv->leaving_dnd = FALSE;
+ priv->n_overflow_items_when_dnd_started = 0;
+ }
+
+ return FALSE;
}
- *drop_index = best_index;
- *drop_pos = best_pos;
+
+ return TRUE;
}
static void
-gtk_toolbar_drag_leave (GtkWidget *widget,
- GdkDragContext *context,
- guint time_)
+ensure_idle_handler (GtkToolbar *toolbar)
{
- GtkToolbar *toolbar = GTK_TOOLBAR (widget);
GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
- if (priv->drag_highlight)
+ if (!priv->idle_id)
+ priv->idle_id = g_idle_add (update_dnd_animation, toolbar);
+}
+
+static void
+reset_all_placeholders (GtkToolbar *toolbar)
+{
+ GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
+ GList *list;
+
+ for (list = priv->content; list != NULL; list = list->next)
{
- gdk_window_set_user_data (priv->drag_highlight, NULL);
- gdk_window_destroy (priv->drag_highlight);
- priv->drag_highlight = NULL;
+ ToolbarContent *content = list->data;
+ if (content->is_placeholder)
+ {
+ get_size (content->item,
+ &(content->start_width), &(content->start_height));
+ content->goal_width = 0;
+ content->goal_height = 0;
+ }
}
- priv->drop_index = -1;
+ g_timer_reset (priv->timer);
}
-static gboolean
-gtk_toolbar_drag_motion (GtkWidget *widget,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time_)
+void
+gtk_toolbar_highlight_drop_location (GtkToolbar *toolbar,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
{
- GtkToolbar *toolbar = GTK_TOOLBAR (widget);
+ gint index;
+ ToolbarContent *content;
GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
- gint new_index, new_pos;
+ gint start_width, start_height;
+ GList *list;
+
+ if (!priv->in_dnd)
+ {
+ priv->n_overflow_items_when_dnd_started = 0;
+ for (list = priv->content; list != NULL; list = list->next)
+ {
+ content = list->data;
+ if (content->is_overflow)
+ priv->n_overflow_items_when_dnd_started++;
+ }
+ }
+
+ priv->in_dnd = TRUE;
+ priv->leaving_dnd = FALSE;
+
+ index = find_drop_index (toolbar, x, y);
- find_drop_pos(toolbar, x, y, &new_index, &new_pos);
+ content = g_list_nth_data (priv->content, index);
- if (!priv->drag_highlight)
+ if (index > 0)
{
- GdkWindowAttr attributes;
- guint attributes_mask;
+ ToolbarContent *prev_content;
- attributes.window_type = GDK_WINDOW_CHILD;
- attributes.wclass = GDK_INPUT_OUTPUT;
- attributes.visual = gtk_widget_get_visual (widget);
- attributes.colormap = gtk_widget_get_colormap (widget);
- attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
- attributes.width = 1;
- attributes.height = 1;
- attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
- priv->drag_highlight = gdk_window_new (widget->window,
- &attributes, attributes_mask);
- gdk_window_set_user_data (priv->drag_highlight, widget);
- gdk_window_set_background (priv->drag_highlight,
- &widget->style->fg[widget->state]);
- }
+ prev_content = g_list_nth_data (priv->content, index - 1);
- if (priv->drop_index < 0 ||
- priv->drop_index != new_index)
+ if (prev_content && prev_content->is_placeholder)
+ content = prev_content;
+ }
+
+ if (!content || !content->is_placeholder)
{
- gint border_width = GTK_CONTAINER (toolbar)->border_width;
- priv->drop_index = new_index;
- if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- gdk_window_move_resize (priv->drag_highlight,
- widget->allocation.x + new_pos - 1,
- widget->allocation.y + border_width,
- 2, widget->allocation.height-border_width*2);
- }
- else
- {
- gdk_window_move_resize (priv->drag_highlight,
- widget->allocation.x + border_width,
- widget->allocation.y + new_pos - 1,
- widget->allocation.width-border_width*2, 2);
- }
+ GtkWidget *placeholder = GTK_WIDGET (gtk_separator_tool_item_new ());
+ gtk_widget_set_size_request (placeholder, 0, 0);
+ gtk_toolbar_insert_tool_item (toolbar, GTK_TOOL_ITEM (placeholder),
+ index, TRUE);
+ content = g_list_nth_data (priv->content, index);
+ g_assert (content->is_placeholder);
+ start_width = start_height = 0;
+ }
+ else
+ {
+ get_size (content->item, &start_width, &start_height);
}
- gdk_window_show (priv->drag_highlight);
+ g_assert (content);
+ g_assert (content->is_placeholder);
- gdk_drag_status (context, context->suggested_action, time_);
+ if (content->start_width != start_width ||
+ content->start_height != start_height ||
+ content->goal_width != width ||
+ content->goal_height != height)
+ {
+ reset_all_placeholders (toolbar);
+
+ content->start_width = start_width;
+ content->goal_width = width;
+ content->start_height = start_height;
+ content->goal_height = height;
- return TRUE;
+ ensure_idle_handler (toolbar);
+ }
+}
+
+void
+gtk_toolbar_unhighlight_drop_location (GtkToolbar *toolbar)
+{
+ GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
+
+ priv->leaving_dnd = TRUE;
+ reset_all_placeholders (toolbar);
+ ensure_idle_handler (toolbar);
}
static void
@@ -1850,11 +2039,13 @@
GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
GList *list;
- for (list = priv->items; list != NULL; list = list->next)
+ for (list = priv->content; list != NULL; list = list->next)
{
- if (GTK_BIN (list->data)->child == widget)
+ ToolbarContent *content = list->data;
+
+ if (GTK_BIN (content->item)->child == widget)
{
- item = list->data;
+ item = content->item;
break;
}
}
@@ -1873,19 +2064,19 @@
{
GtkToolbar *toolbar = GTK_TOOLBAR (container);
GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
- GList *items;
+ GList *list;
g_return_if_fail (callback != NULL);
- items = priv->items;
-
- while (items)
+ list = priv->content;
+ while (list)
{
- GtkToolItem *item = GTK_TOOL_ITEM (items->data);
+ ToolbarContent *content = list->data;
+ GList *next = list->next;
- items = items->next;
+ (*callback) (GTK_WIDGET (content->item), callback_data);
- (*callback) (GTK_WIDGET (item), callback_data);
+ list = next;
}
if (include_internals)
@@ -1902,16 +2093,17 @@
gtk_toolbar_reconfigured (GtkToolbar *toolbar)
{
GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
- GList *items;
+ GList *list;
- items = priv->items;
- while (items)
+ list = priv->content;
+ while (list)
{
- GtkToolItem *item = GTK_TOOL_ITEM (items->data);
+ ToolbarContent *content = list->data;
+ GList *next = list->next;
- _gtk_tool_item_toolbar_reconfigured (item);
+ _gtk_tool_item_toolbar_reconfigured (content->item);
- items = items->next;
+ list = next;
}
}
@@ -2021,11 +2213,12 @@
priv->menu = GTK_MENU (gtk_menu_new ());
g_signal_connect (priv->menu, "deactivate", G_CALLBACK (menu_deactivated), toolbar);
- for (list = priv->items; list != NULL; list = list->next)
+ for (list = priv->content; list != NULL; list = list->next)
{
- GtkToolItem *item = list->data;
+ ToolbarContent *content = list->data;
+ GtkToolItem *item = content->item;
- if (toolbar_item_visible (toolbar, item) && toolbar_item_get_is_overflow (item))
+ if (toolbar_item_visible (toolbar, item) && content->is_overflow)
{
GtkWidget *menu_item = gtk_tool_item_retrieve_proxy_menu_item (item);
@@ -2182,16 +2375,72 @@
return TRUE;
}
+static gint
+physical_to_logical (GtkToolbar *toolbar, gint physical)
+{
+ GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
+ GList *list;
+ int logical;
+
+ if (physical < 0)
+ return -1;
+
+ logical = 0;
+ for (list = priv->content; list; list = list->next)
+ {
+ ToolbarContent *content = list->data;
+
+ if (!physical)
+ return logical;
+
+ if (!content->is_placeholder)
+ logical++;
+ physical--;
+ }
+ return -1;
+}
+
+static gint
+logical_to_physical (GtkToolbar *toolbar, gint logical)
+{
+ GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
+ GList *list;
+ gint physical;
+
+ if (logical < 0)
+ return -1;
+
+ physical = 0;
+ for (list = priv->content; list; list = list->next)
+ {
+ ToolbarContent *content = list->data;
+
+ if (!logical)
+ return physical;
+
+ if (!content->is_placeholder)
+ logical--;
+ physical++;
+ }
+ return -1;
+}
+
static void
gtk_toolbar_insert_tool_item (GtkToolbar *toolbar,
GtkToolItem *item,
- gint pos)
+ gint pos,
+ gboolean is_placeholder)
{
GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
-
- priv->items = g_list_insert (priv->items, item, pos);
+ ToolbarContent *content = g_new0 (ToolbarContent, 1);
+
+ content->is_overflow = FALSE;
+ content->is_placeholder = is_placeholder;
+ content->item = item;
toolbar->num_children++;
+ priv->content = g_list_insert (priv->content, content, pos);
+
gtk_widget_set_parent (GTK_WIDGET (item), GTK_WIDGET (toolbar));
}
@@ -2202,23 +2451,29 @@
GtkToolbarPrivate *priv;
GList *tmp;
gint nth_child;
+ ToolbarContent *content = NULL;
g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
- priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
g_return_if_fail (GTK_IS_TOOL_ITEM (item));
- g_return_if_fail (g_list_find (priv->items, item));
+
+ priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
nth_child = 0;
- for (tmp = priv->items; tmp != NULL; tmp = tmp->next)
+ for (tmp = priv->content; tmp != NULL; tmp = tmp->next)
{
- if (tmp->data == item)
+ content = tmp->data;
+ if (content->item == item)
break;
nth_child++;
}
- priv->items = g_list_remove (priv->items, item);
+ g_return_if_fail (content != NULL);
+
+ g_free (content);
+
+ priv->content = g_list_remove (priv->content, content);
gtk_widget_unparent (GTK_WIDGET (item));
@@ -2260,7 +2515,7 @@
*
* Insert a #GtkToolItem into the toolbar at position @pos. If @pos is
* 0 the item is prepended to the start of the toolbar. If @pos is
- * negative, append the item to the end of the toolbar.
+ * negative, the item is appended to the end of the toolbar.
*
* Since: 2.4
**/
@@ -2274,8 +2529,9 @@
if (!gtk_toolbar_check_new_api (toolbar))
return;
-
- gtk_toolbar_insert_tool_item (toolbar, item, pos);
+
+ gtk_toolbar_insert_tool_item (toolbar, item,
+ logical_to_physical (toolbar, pos), FALSE);
}
/**
@@ -2295,17 +2551,30 @@
GtkToolItem *item)
{
GtkToolbarPrivate *priv;
+ GList *list;
+ int n;
g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
g_return_val_if_fail (GTK_IS_TOOL_ITEM (item), -1);
+ g_return_val_if_fail (GTK_WIDGET (item)->parent == GTK_WIDGET (toolbar), -1);
if (!gtk_toolbar_check_new_api (toolbar))
return -1;
priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
- g_return_val_if_fail (g_list_find (priv->items, item) != NULL, -1);
- return g_list_index (priv->items, item);
+ n = 0;
+ for (list = priv->content; list != NULL; list = list->next)
+ {
+ ToolbarContent *content = list->data;
+
+ if (content->item == item)
+ break;
+
+ ++n;
+ }
+
+ return physical_to_logical (toolbar, n);
}
/**
@@ -2466,8 +2735,11 @@
return -1;
priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
-
- return g_list_length (priv->items);
+
+ if (!priv->content)
+ return 0;
+
+ return physical_to_logical (toolbar, g_list_length (priv->content) - 1);
}
/**
@@ -2488,15 +2760,21 @@
gint n)
{
GtkToolbarPrivate *priv;
-
+ ToolbarContent *content;
+
g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
if (!gtk_toolbar_check_new_api (toolbar))
return NULL;
priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
+
+ content = g_list_nth_data (priv->content, logical_to_physical (toolbar, n));
- return g_list_nth_data (priv->items, n);
+ if (content)
+ return content->item;
+
+ return NULL;
}
/**
@@ -2679,16 +2957,12 @@
gint x,
gint y)
{
- gint drop_index, drop_pos;
-
g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
-
+
if (!gtk_toolbar_check_new_api (toolbar))
return -1;
- find_drop_pos (toolbar, x, y, &drop_index, &drop_pos);
-
- return drop_index;
+ return physical_to_logical (toolbar, find_drop_index (toolbar, x, y));
}
/**
@@ -3248,7 +3522,7 @@
toolbar->children = g_list_insert (toolbar->children, child, position);
- gtk_toolbar_insert_tool_item (toolbar, item, position);
+ gtk_toolbar_insert_tool_item (toolbar, item, position, FALSE);
return child->widget;
}
@@ -3258,7 +3532,8 @@
{
GList *list;
GtkToolbar *toolbar = GTK_TOOLBAR (object);
-
+ GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
+
if (toolbar->tooltips)
g_object_unref (toolbar->tooltips);
@@ -3266,6 +3541,16 @@
g_free (list->data);
g_list_free (toolbar->children);
+
+ for (list = priv->content; list != NULL; list = list->next)
+ g_free (list->data);
+
+ g_list_free (priv->content);
+
+ g_timer_destroy (priv->timer);
+
+ if (priv->idle_id)
+ g_source_remove (priv->idle_id);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
Index: gtk/gtktoolbar.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktoolbar.h,v
retrieving revision 1.38
diff -u -r1.38 gtktoolbar.h
--- gtk/gtktoolbar.h 30 Sep 2003 22:48:10 -0000 1.38
+++ gtk/gtktoolbar.h 5 Oct 2003 19:00:50 -0000
@@ -91,21 +91,21 @@
struct _GtkToolbar
{
GtkContainer container;
-
+
gint num_children;
GList *children;
GtkOrientation orientation;
GtkToolbarStyle style;
GtkIconSize icon_size;
-
+
GtkTooltips *tooltips;
gint button_maxw; /* maximum width of homogeneous children */
gint button_maxh; /* maximum height of homogeneous children */
-
+
guint style_set_connection;
guint icon_size_connection;
-
+
guint style_set : 1;
guint icon_size_set : 1;
};
@@ -113,7 +113,7 @@
struct _GtkToolbarClass
{
GtkContainerClass parent_class;
-
+
/* signals */
void (* orientation_changed) (GtkToolbar *toolbar,
GtkOrientation orientation);
@@ -123,7 +123,7 @@
gint x,
gint y,
gint button_number);
-
+
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
@@ -131,33 +131,39 @@
};
GType gtk_toolbar_get_type (void) G_GNUC_CONST;
-GtkWidget* gtk_toolbar_new (void);
-void gtk_toolbar_insert (GtkToolbar *toolbar,
- GtkToolItem *item,
- gint pos);
-gint gtk_toolbar_get_item_index (GtkToolbar *toolbar,
- GtkToolItem *item);
-gint gtk_toolbar_get_n_items (GtkToolbar *toolbar);
-GtkToolItem * gtk_toolbar_get_nth_item (GtkToolbar *toolbar,
- gint n);
-gint gtk_toolbar_get_drop_index (GtkToolbar *toolbar,
- gint x,
- gint y);
-void gtk_toolbar_set_show_arrow (GtkToolbar *toolbar,
- gboolean show_arrow);
-void gtk_toolbar_set_orientation (GtkToolbar *toolbar,
- GtkOrientation orientation);
-void gtk_toolbar_set_tooltips (GtkToolbar *toolbar,
- gboolean enable);
-gboolean gtk_toolbar_get_show_arrow (GtkToolbar *toolbar);
-GtkOrientation gtk_toolbar_get_orientation (GtkToolbar *toolbar);
-GtkToolbarStyle gtk_toolbar_get_style (GtkToolbar *toolbar);
-GtkIconSize gtk_toolbar_get_icon_size (GtkToolbar *toolbar);
-gboolean gtk_toolbar_get_tooltips (GtkToolbar *toolbar);
-GtkReliefStyle gtk_toolbar_get_relief_style (GtkToolbar *toolbar);
-void gtk_toolbar_set_style (GtkToolbar *toolbar,
- GtkToolbarStyle style);
-void gtk_toolbar_unset_style (GtkToolbar *toolbar);
+GtkWidget* gtk_toolbar_new (void);
+void gtk_toolbar_insert (GtkToolbar *toolbar,
+ GtkToolItem *item,
+ gint pos);
+gint gtk_toolbar_get_item_index (GtkToolbar *toolbar,
+ GtkToolItem *item);
+gint gtk_toolbar_get_n_items (GtkToolbar *toolbar);
+GtkToolItem * gtk_toolbar_get_nth_item (GtkToolbar *toolbar,
+ gint n);
+void gtk_toolbar_set_show_arrow (GtkToolbar *toolbar,
+ gboolean show_arrow);
+void gtk_toolbar_set_orientation (GtkToolbar *toolbar,
+ GtkOrientation orientation);
+void gtk_toolbar_set_tooltips (GtkToolbar *toolbar,
+ gboolean enable);
+gboolean gtk_toolbar_get_show_arrow (GtkToolbar *toolbar);
+GtkOrientation gtk_toolbar_get_orientation (GtkToolbar *toolbar);
+GtkToolbarStyle gtk_toolbar_get_style (GtkToolbar *toolbar);
+GtkIconSize gtk_toolbar_get_icon_size (GtkToolbar *toolbar);
+gboolean gtk_toolbar_get_tooltips (GtkToolbar *toolbar);
+GtkReliefStyle gtk_toolbar_get_relief_style (GtkToolbar *toolbar);
+void gtk_toolbar_set_style (GtkToolbar *toolbar,
+ GtkToolbarStyle style);
+void gtk_toolbar_unset_style (GtkToolbar *toolbar);
+gint gtk_toolbar_get_drop_index (GtkToolbar *toolbar,
+ gint x,
+ gint y);
+void gtk_toolbar_highlight_drop_location (GtkToolbar *toolbar,
+ gint x,
+ gint y,
+ gint width,
+ gint height);
+void gtk_toolbar_unhighlight_drop_location (GtkToolbar *toolbar);
Index: tests/testtoolbar.c
===================================================================
RCS file: /cvs/gnome/gtk+/tests/testtoolbar.c,v
retrieving revision 1.7
diff -u -r1.7 testtoolbar.c
--- tests/testtoolbar.c 31 Aug 2003 22:32:49 -0000 1.7
+++ tests/testtoolbar.c 5 Oct 2003 19:00:58 -0000
@@ -472,6 +472,28 @@
return TRUE;
}
+static gboolean
+toolbar_drag_motion (GtkToolbar *toolbar,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time,
+ gpointer null)
+{
+ gdk_drag_status (context, GDK_ACTION_MOVE, time);
+ gtk_toolbar_highlight_drop_location (toolbar, x, y, 100, 60);
+ return TRUE;
+}
+
+static void
+toolbar_drag_leave (GtkToolbar *toolbar,
+ GdkDragContext *context,
+ guint time,
+ gpointer null)
+{
+ gtk_toolbar_unhighlight_drop_location (toolbar);
+}
+
gint
main (gint argc, gchar **argv)
{
@@ -577,6 +599,7 @@
gtk_tool_button_set_label (GTK_TOOL_BUTTON (item), NULL);
add_item_to_list (store, item, "New");
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
+ gtk_tool_item_set_expand (item, TRUE);
item = gtk_tool_button_new_from_stock (GTK_STOCK_OPEN);
add_item_to_list (store, item, "Open");
@@ -624,7 +647,10 @@
add_item_to_list (store, item, "Left");
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
- item = gtk_radio_tool_button_new_from_stock (group, GTK_STOCK_JUSTIFY_CENTER); make_prop_editor (G_OBJECT (item));
+ item = gtk_radio_tool_button_new_from_stock (group, GTK_STOCK_JUSTIFY_CENTER);
+#if 0
+ make_prop_editor (G_OBJECT (item));
+#endif
group = gtk_radio_tool_button_get_group (GTK_RADIO_TOOL_BUTTON (item));
add_item_to_list (store, item, "Center");
@@ -668,12 +694,18 @@
gtk_drag_dest_set (toolbar, GTK_DEST_DEFAULT_DROP,
target_table, G_N_ELEMENTS (target_table),
GDK_ACTION_MOVE);
+ g_signal_connect (toolbar, "drag_motion",
+ G_CALLBACK (toolbar_drag_motion), NULL);
+ g_signal_connect (toolbar, "drag_leave",
+ G_CALLBACK (toolbar_drag_leave), NULL);
g_signal_connect (toolbar, "drag_drop",
G_CALLBACK (toolbar_drag_drop), label);
gtk_widget_show_all (window);
+#if 0
make_prop_editor (G_OBJECT (toolbar));
+#endif
g_signal_connect (window, "delete_event", G_CALLBACK (gtk_main_quit), NULL);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]