[gtk+/overlay] overlay: add a signal for custom positioning
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/overlay] overlay: add a signal for custom positioning
- Date: Sun, 12 Jun 2011 03:27:56 +0000 (UTC)
commit ddf813128f2ccc63e7c33acc9097ce68c0c65cbe
Author: Matthias Clasen <mclasen redhat com>
Date: Sat Jun 11 23:17:55 2011 -0400
overlay: add a signal for custom positioning
This is a replacement for the earlier relative-widget functionality.
gtk/gtkoverlay.c | 231 ++++++++++++++++++++++++++++++++------------------
gtk/gtkoverlay.h | 4 +
tests/testoverlay.c | 52 +++++++++---
3 files changed, 192 insertions(+), 95 deletions(-)
---
diff --git a/gtk/gtkoverlay.c b/gtk/gtkoverlay.c
index 5d89da4..90d8a6e 100644
--- a/gtk/gtkoverlay.c
+++ b/gtk/gtkoverlay.c
@@ -25,6 +25,8 @@
#include "gtkoverlay.h"
#include "gtkbuildable.h"
#include "gtkscrolledwindow.h"
+#include "gtkmainprivate.h"
+#include "gtkmarshalers.h"
#include "gtkprivate.h"
#include "gtkintl.h"
@@ -67,6 +69,13 @@ struct _GtkOverlayChild
GdkWindow *window;
};
+enum {
+ GET_CHILD_POSITION,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
static void gtk_overlay_buildable_init (GtkBuildableIface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkOverlay, gtk_overlay, GTK_TYPE_BIN,
@@ -137,21 +146,6 @@ gtk_overlay_child_allocate (GtkOverlayChild *child,
gtk_widget_size_allocate (child->widget, &child_allocation);
}
-static GtkAlign
-effective_align (GtkAlign align,
- GtkTextDirection direction)
-{
- switch (align)
- {
- case GTK_ALIGN_START:
- return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_END : GTK_ALIGN_START;
- case GTK_ALIGN_END:
- return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_START : GTK_ALIGN_END;
- default:
- return align;
- }
-}
-
static void
gtk_overlay_get_preferred_width (GtkWidget *widget,
gint *minimum,
@@ -196,46 +190,22 @@ gtk_overlay_size_allocate (GtkWidget *widget,
{
GtkOverlay *overlay = GTK_OVERLAY (widget);
GtkOverlayPrivate *priv = overlay->priv;
- GtkOverlayChild *child;
- GtkAllocation main_alloc;
GSList *children;
GtkWidget *main_widget;
GTK_WIDGET_CLASS (gtk_overlay_parent_class)->size_allocate (widget, allocation);
main_widget = gtk_bin_get_child (GTK_BIN (overlay));
- if (main_widget == NULL)
+ if (!main_widget || !gtk_widget_get_visible (main_widget))
return;
gtk_widget_size_allocate (main_widget, allocation);
- /* special-case scrolled windows */
- if (GTK_IS_SCROLLED_WINDOW (main_widget))
- {
- GtkWidget *grandchild;
- gint x, y;
-
- grandchild = gtk_bin_get_child (GTK_BIN (main_widget));
- gtk_widget_translate_coordinates (grandchild, main_widget, 0, 0, &x, &y);
- main_alloc.x = allocation->x + x;
- main_alloc.y = allocation->y + y;
- main_alloc.width = gtk_widget_get_allocated_width (grandchild);
- main_alloc.height = gtk_widget_get_allocated_height (grandchild);
- }
- else
- {
- main_alloc.x = allocation->x;
- main_alloc.y = allocation->y;
- main_alloc.width = allocation->width;
- main_alloc.height = allocation->height;
- }
-
for (children = priv->children; children; children = children->next)
{
- GtkRequisition req;
+ GtkOverlayChild *child;
GtkAllocation alloc;
- GtkAlign halign;
- GtkTextDirection direction;
+ gboolean result;
child = children->data;
@@ -250,51 +220,110 @@ gtk_overlay_size_allocate (GtkWidget *widget,
if (!gtk_widget_get_visible (child->widget))
continue;
- gtk_widget_get_preferred_size (child->widget, NULL, &req);
+ g_signal_emit (overlay, signals[GET_CHILD_POSITION],
+ 0, child->widget, &alloc, &result);
- alloc.x = main_alloc.x;
- alloc.width = MIN (main_alloc.width, req.width);
+ alloc.x += allocation->x;
+ alloc.y += allocation->y;
- direction = gtk_widget_get_direction (child->widget);
+ gtk_overlay_child_allocate (child, &alloc);
+ }
+}
- halign = gtk_widget_get_halign (child->widget);
- switch (effective_align (halign, direction))
- {
- case GTK_ALIGN_START:
- /* nothing to do */
- break;
- case GTK_ALIGN_FILL:
- alloc.width = main_alloc.width;
- break;
- case GTK_ALIGN_CENTER:
- alloc.x += main_alloc.width / 2 - req.width / 2;
- break;
- case GTK_ALIGN_END:
- alloc.x += main_alloc.width - req.width;
- break;
- }
+static GtkAlign
+effective_align (GtkAlign align,
+ GtkTextDirection direction)
+{
+ switch (align)
+ {
+ case GTK_ALIGN_START:
+ return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_END : GTK_ALIGN_START;
+ case GTK_ALIGN_END:
+ return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_START : GTK_ALIGN_END;
+ default:
+ return align;
+ }
+}
- alloc.y = main_alloc.y;
- alloc.height = MIN (main_alloc.height, req.height);
+static gboolean
+gtk_overlay_get_child_position (GtkOverlay *overlay,
+ GtkWidget *widget,
+ GtkAllocation *alloc)
+{
+ GtkWidget *main_widget;
+ GtkAllocation main_alloc;
+ GtkRequisition req;
+ GtkAlign halign;
+ GtkTextDirection direction;
- switch (gtk_widget_get_valign (child->widget))
- {
- case GTK_ALIGN_START:
- /* nothing to do */
- break;
- case GTK_ALIGN_FILL:
- alloc.height = main_alloc.height;
- break;
- case GTK_ALIGN_CENTER:
- alloc.y += main_alloc.height / 2 - req.height / 2;
- break;
- case GTK_ALIGN_END:
- alloc.y += main_alloc.height - req.height;
- break;
- }
+ main_widget = gtk_bin_get_child (GTK_BIN (overlay));
- gtk_overlay_child_allocate (child, &alloc);
+ /* special-case scrolled windows */
+ if (GTK_IS_SCROLLED_WINDOW (main_widget))
+ {
+ GtkWidget *grandchild;
+ gint x, y;
+
+ grandchild = gtk_bin_get_child (GTK_BIN (main_widget));
+ gtk_widget_translate_coordinates (grandchild, main_widget, 0, 0, &x, &y);
+
+ main_alloc.x = x;
+ main_alloc.y = y;
+ main_alloc.width = gtk_widget_get_allocated_width (grandchild);
+ main_alloc.height = gtk_widget_get_allocated_height (grandchild);
+ }
+ else
+ {
+ main_alloc.x = 0;
+ main_alloc.y = 0;
+ main_alloc.width = gtk_widget_get_allocated_width (main_widget);
+ main_alloc.height = gtk_widget_get_allocated_height (main_widget);
}
+
+ gtk_widget_get_preferred_size (widget, NULL, &req);
+
+ alloc->x = main_alloc.x;
+ alloc->width = MIN (main_alloc.width, req.width);
+
+ direction = gtk_widget_get_direction (widget);
+
+ halign = gtk_widget_get_halign (widget);
+ switch (effective_align (halign, direction))
+ {
+ case GTK_ALIGN_START:
+ /* nothing to do */
+ break;
+ case GTK_ALIGN_FILL:
+ alloc->width = main_alloc.width;
+ break;
+ case GTK_ALIGN_CENTER:
+ alloc->x += main_alloc.width / 2 - req.width / 2;
+ break;
+ case GTK_ALIGN_END:
+ alloc->x += main_alloc.width - req.width;
+ break;
+ }
+
+ alloc->y = main_alloc.y;
+ alloc->height = MIN (main_alloc.height, req.height);
+
+ switch (gtk_widget_get_valign (widget))
+ {
+ case GTK_ALIGN_START:
+ /* nothing to do */
+ break;
+ case GTK_ALIGN_FILL:
+ alloc->height = main_alloc.height;
+ break;
+ case GTK_ALIGN_CENTER:
+ alloc->y += main_alloc.height / 2 - req.height / 2;
+ break;
+ case GTK_ALIGN_END:
+ alloc->y += main_alloc.height - req.height;
+ break;
+ }
+
+ return TRUE;
}
static void
@@ -485,6 +514,41 @@ gtk_overlay_class_init (GtkOverlayClass *klass)
container_class->remove = gtk_overlay_remove;
container_class->forall = gtk_overlay_forall;
+ klass->get_child_position = gtk_overlay_get_child_position;
+
+ /**
+ * GtkOverlay::get-child-position:
+ * @overlay: the #GtkOverlay
+ * @widget: the child widget to position
+ * @allocation: (out): return location for the allocation
+ *
+ * The ::get-child-position signal is emitted to determine
+ * the position and size of any overlay child widgets. A
+ * handler for this signal should fill @allocation with
+ * the desired position and size for @widget, relative to
+ * the 'main' child of @overlay.
+ *
+ * The default handler for this signal uses the @widget's
+ * halign and valign properties to determine the position
+ * and gives the widget its natural size (except that an
+ * alignment of %GTK_ALIGN_FILL will cause the overlay to
+ * be full-width/height). If the main child is a
+ * #GtkScrolledWindow, the overlays are placed relative
+ * to its contents.
+ *
+ * Return: %TRUE if the @allocation has been filled
+ */
+ signals[GET_CHILD_POSITION] =
+ g_signal_new (I_("get-child-position"),
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkOverlayClass, get_child_position),
+ _gtk_boolean_handled_accumulator, NULL,
+ _gtk_marshal_BOOLEAN__OBJECT_BOXED,
+ G_TYPE_BOOLEAN, 2,
+ GTK_TYPE_WIDGET,
+ GDK_TYPE_RECTANGLE | G_SIGNAL_TYPE_STATIC_SCOPE);
+
g_type_class_add_private (object_class, sizeof (GtkOverlayPrivate));
}
@@ -539,9 +603,10 @@ gtk_overlay_new (void)
* Adds @widget to @overlay.
*
* The widget will be stacked on top of the main widget
- * added with gtk_container_add(). The position at which
- * @widget is placed is determined from its #GtkWidget::halign
- * and #GtkWidget::valign properties.
+ * added with gtk_container_add().
+ *
+ * The position at which @widget is placed is determined
+ * from its #GtkWidget::halign and #GtkWidget::valign properties.
*
* Since: 3.2
*/
diff --git a/gtk/gtkoverlay.h b/gtk/gtkoverlay.h
index 0a9740d..baa0e57 100644
--- a/gtk/gtkoverlay.h
+++ b/gtk/gtkoverlay.h
@@ -53,6 +53,10 @@ struct _GtkOverlayClass
{
GtkBinClass parent_class;
+ gboolean (*get_child_position) (GtkOverlay *overlay,
+ GtkWidget *widget,
+ GtkAllocation *allocation);
+
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
diff --git a/tests/testoverlay.c b/tests/testoverlay.c
index 7a64f33..d59032c 100644
--- a/tests/testoverlay.c
+++ b/tests/testoverlay.c
@@ -51,10 +51,41 @@ test_nonzerox (void)
return win;
}
-#if 0
-/* test that margins and non-zero allocation x/y
- * of the relative widget are handled correctly
- */
+static gboolean
+get_child_position (GtkOverlay *overlay,
+ GtkWidget *widget,
+ GtkAllocation *alloc,
+ GtkWidget *relative)
+{
+ GtkRequisition req;
+ GtkWidget *child;
+ GtkAllocation main_alloc;
+ gint x, y;
+
+ child = gtk_bin_get_child (GTK_BIN (overlay));
+
+ gtk_widget_translate_coordinates (relative, child, 0, 0, &x, &y);
+ main_alloc.x = x;
+ main_alloc.y = y;
+ main_alloc.width = gtk_widget_get_allocated_width (relative);
+ main_alloc.height = gtk_widget_get_allocated_height (relative);
+
+ gtk_widget_get_preferred_size (widget, NULL, &req);
+
+ alloc->x = main_alloc.x;
+ alloc->width = MIN (main_alloc.width, req.width);
+ if (gtk_widget_get_halign (widget) == GTK_ALIGN_END)
+ alloc->x += main_alloc.width - req.width;
+
+ alloc->y = main_alloc.y;
+ alloc->height = MIN (main_alloc.height, req.height);
+ if (gtk_widget_get_valign (widget) == GTK_ALIGN_END)
+ alloc->y += main_alloc.height - req.height;
+
+ return TRUE;
+}
+
+/* test custom positioning */
static GtkWidget *
test_relative (void)
{
@@ -66,7 +97,7 @@ test_relative (void)
GdkRGBA color;
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- gtk_window_set_title (GTK_WINDOW (win), "Relative positioning");
+ gtk_window_set_title (GTK_WINDOW (win), "Custom positioning");
overlay = gtk_overlay_new ();
gdk_rgba_parse (&color, "yellow");
@@ -86,23 +117,23 @@ test_relative (void)
gtk_widget_set_hexpand (text, TRUE);
gtk_widget_set_vexpand (text, TRUE);
gtk_grid_attach (GTK_GRID (grid), text, 1, 1, 1, 1);
- gtk_overlay_set_relative_widget (GTK_OVERLAY (overlay), text);
+ g_signal_connect (overlay, "get-child-position",
+ G_CALLBACK (get_child_position), text);
child = gtk_label_new ("Top left overlay");
gtk_widget_set_halign (child, GTK_ALIGN_START);
gtk_widget_set_valign (child, GTK_ALIGN_START);
- gtk_overlay_add (GTK_OVERLAY (overlay), child);
+ gtk_overlay_add_overlay (GTK_OVERLAY (overlay), child);
g_object_set (child, "margin", 1, NULL);
child = gtk_label_new ("Bottom right overlay");
gtk_widget_set_halign (child, GTK_ALIGN_END);
gtk_widget_set_valign (child, GTK_ALIGN_END);
- gtk_overlay_add (GTK_OVERLAY (overlay), child);
+ gtk_overlay_add_overlay (GTK_OVERLAY (overlay), child);
g_object_set (child, "margin", 1, NULL);
return win;
}
-#endif
/* test GTK_ALIGN_FILL handling */
static GtkWidget *
@@ -188,7 +219,6 @@ static const gchar *buffer =
" <property name='title'>GtkBuilder support</property>"
" <child>"
" <object class='GtkOverlay' id='overlay'>"
-"<!-- <property name='relative_widget'>text</property> -->"
" <child type='overlay'>"
" <object class='GtkLabel' id='overlay-child'>"
" <property name='label'>Witty remark goes here</property>"
@@ -393,10 +423,8 @@ main (int argc, char *argv[])
win1 = test_nonzerox ();
gtk_widget_show_all (win1);
-#if 0
win2 = test_relative ();
gtk_widget_show_all (win2);
-#endif
win3 = test_fullwidth ();
gtk_widget_show_all (win3);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]