[gtk+] Add margin and alignment properties to GtkWidget
- From: Havoc Pennington <hp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] Add margin and alignment properties to GtkWidget
- Date: Mon, 13 Sep 2010 01:49:34 +0000 (UTC)
commit 474f80442a6f3cf72a3c3b9efc5a846e7664d758
Author: Havoc Pennington <hp pobox com>
Date: Sun Sep 5 12:21:27 2010 -0400
Add margin and alignment properties to GtkWidget
h-align = START,END,CENTER,FILL
v-align = START,END,CENTER,FILL
margin-left,right,top,bottom
margin
These should obsolete all such similar properties on
layout containers, GtkMisc, GtkAlignment, GtkContainer::border-width
Margin is outside the size request.
If margin were not outside the set_size_request() it would not work the
same way as container-supplied (child property) padding.
Conceptually set_size_request() forces the value from the subclass
(the original unadjusted request) and then we go on to adjust
the request further by adding the margin.
gtk/gtkenums.h | 30 ++++
gtk/gtkwidget.c | 499 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
gtk/gtkwidget.h | 27 +++
3 files changed, 548 insertions(+), 8 deletions(-)
---
diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h
index 019fb05..71ea365 100644
--- a/gtk/gtkenums.h
+++ b/gtk/gtkenums.h
@@ -35,6 +35,36 @@
G_BEGIN_DECLS
+/**
+ * GtkAlign:
+ *
+ * @GTK_ALIGN_FILL: stretch to fill all space if possible, center if
+ * no meaningful way to stretch
+ * @GTK_ALIGN_START: snap to left or top side, leaving space on right
+ * or bottom
+ * @GTK_ALIGN_END: snap to right or bottom side, leaving space on left
+ * or top
+ * @GTK_ALIGN_CENTER: center natural width of widget inside the
+ * allocation
+ *
+ * Controls how a widget deals with extra space in a single (x or y)
+ * dimension.
+ *
+ * Alignment only matters if the widget receives a "too large"
+ * allocation, for example if you packed the widget with the "expand"
+ * flag inside a #GtkBox, then the widget might get extra space. If
+ * you have for example a 16x16 icon inside a 32x32 space, the icon
+ * could be scaled and stretched, it could be centered, or it could be
+ * positioned to one side of the space.
+ */
+typedef enum
+{
+ GTK_ALIGN_FILL,
+ GTK_ALIGN_START,
+ GTK_ALIGN_END,
+ GTK_ALIGN_CENTER
+} GtkAlign;
+
/* Arrow placement */
typedef enum
{
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 874be7e..fa383f3 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -278,7 +278,14 @@ enum {
PROP_TOOLTIP_MARKUP,
PROP_TOOLTIP_TEXT,
PROP_WINDOW,
- PROP_DOUBLE_BUFFERED
+ PROP_DOUBLE_BUFFERED,
+ PROP_H_ALIGN,
+ PROP_V_ALIGN,
+ PROP_MARGIN_LEFT,
+ PROP_MARGIN_RIGHT,
+ PROP_MARGIN_TOP,
+ PROP_MARGIN_BOTTOM,
+ PROP_MARGIN
};
typedef struct _GtkStateData GtkStateData;
@@ -864,6 +871,140 @@ gtk_widget_class_init (GtkWidgetClass *klass)
GTK_PARAM_READWRITE));
/**
+ * GtkWidget:h-align
+ *
+ * How to distribute horizontal space if widget gets extra space, see #GtkAlign
+ *
+ * Since: 3.0
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_H_ALIGN,
+ g_param_spec_enum ("h-align",
+ P_("Horizontal Alignment"),
+ P_("How to position in extra horizontal space"),
+ GTK_TYPE_ALIGN,
+ GTK_ALIGN_FILL,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GtkWidget:v-align
+ *
+ * How to distribute vertical space if widget gets extra space, see #GtkAlign
+ *
+ * Since: 3.0
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_V_ALIGN,
+ g_param_spec_enum ("v-align",
+ P_("Vertical Alignment"),
+ P_("How to position in extra vertical space"),
+ GTK_TYPE_ALIGN,
+ GTK_ALIGN_FILL,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GtkWidget:margin-left
+ *
+ * Margin on left side of widget.
+ *
+ * This property adds margin outside of the widget's normal size
+ * request, the margin will be added in addition to the size from
+ * gtk_widget_set_size_request() for example.
+ *
+ * Since: 3.0
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_MARGIN_LEFT,
+ g_param_spec_int ("margin-left",
+ P_("Margin on Left"),
+ P_("Pixels of extra space on the left side"),
+ 0,
+ G_MAXINT16,
+ 0,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GtkWidget:margin-right
+ *
+ * Margin on right side of widget.
+ *
+ * This property adds margin outside of the widget's normal size
+ * request, the margin will be added in addition to the size from
+ * gtk_widget_set_size_request() for example.
+ *
+ * Since: 3.0
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_MARGIN_RIGHT,
+ g_param_spec_int ("margin-right",
+ P_("Margin on Right"),
+ P_("Pixels of extra space on the right side"),
+ 0,
+ G_MAXINT16,
+ 0,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GtkWidget:margin-top
+ *
+ * Margin on top side of widget.
+ *
+ * This property adds margin outside of the widget's normal size
+ * request, the margin will be added in addition to the size from
+ * gtk_widget_set_size_request() for example.
+ *
+ * Since: 3.0
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_MARGIN_TOP,
+ g_param_spec_int ("margin-top",
+ P_("Margin on Top"),
+ P_("Pixels of extra space on the top side"),
+ 0,
+ G_MAXINT16,
+ 0,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GtkWidget:margin-bottom
+ *
+ * Margin on bottom side of widget.
+ *
+ * This property adds margin outside of the widget's normal size
+ * request, the margin will be added in addition to the size from
+ * gtk_widget_set_size_request() for example.
+ *
+ * Since: 3.0
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_MARGIN_BOTTOM,
+ g_param_spec_int ("margin-bottom",
+ P_("Margin on Bottom"),
+ P_("Pixels of extra space on the bottom side"),
+ 0,
+ G_MAXINT16,
+ 0,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GtkWidget:margin
+ *
+ * Sets all four sides' margin at once. If read, returns max
+ * margin on any side.
+ *
+ * Since: 3.0
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_MARGIN,
+ g_param_spec_int ("margin",
+ P_("All Margins"),
+ P_("Pixels of extra space on all four sides"),
+ 0,
+ G_MAXINT16,
+ 0,
+ GTK_PARAM_READWRITE));
+
+ /**
* GtkWidget::show:
* @widget: the object which received the signal.
*/
@@ -2800,6 +2941,32 @@ gtk_widget_set_property (GObject *object,
case PROP_DOUBLE_BUFFERED:
gtk_widget_set_double_buffered (widget, g_value_get_boolean (value));
break;
+ case PROP_H_ALIGN:
+ gtk_widget_set_h_align (widget, g_value_get_enum (value));
+ break;
+ case PROP_V_ALIGN:
+ gtk_widget_set_v_align (widget, g_value_get_enum (value));
+ break;
+ case PROP_MARGIN_LEFT:
+ gtk_widget_set_margin_left (widget, g_value_get_int (value));
+ break;
+ case PROP_MARGIN_RIGHT:
+ gtk_widget_set_margin_right (widget, g_value_get_int (value));
+ break;
+ case PROP_MARGIN_TOP:
+ gtk_widget_set_margin_top (widget, g_value_get_int (value));
+ break;
+ case PROP_MARGIN_BOTTOM:
+ gtk_widget_set_margin_bottom (widget, g_value_get_int (value));
+ break;
+ case PROP_MARGIN:
+ g_object_freeze_notify (G_OBJECT (widget));
+ gtk_widget_set_margin_left (widget, g_value_get_int (value));
+ gtk_widget_set_margin_right (widget, g_value_get_int (value));
+ gtk_widget_set_margin_top (widget, g_value_get_int (value));
+ gtk_widget_set_margin_bottom (widget, g_value_get_int (value));
+ g_object_thaw_notify (G_OBJECT (widget));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -2910,6 +3077,40 @@ gtk_widget_get_property (GObject *object,
case PROP_DOUBLE_BUFFERED:
g_value_set_boolean (value, gtk_widget_get_double_buffered (widget));
break;
+ case PROP_H_ALIGN:
+ g_value_set_enum (value, gtk_widget_get_h_align (widget));
+ break;
+ case PROP_V_ALIGN:
+ g_value_set_enum (value, gtk_widget_get_v_align (widget));
+ break;
+ case PROP_MARGIN_LEFT:
+ g_value_set_int (value, gtk_widget_get_margin_left (widget));
+ break;
+ case PROP_MARGIN_RIGHT:
+ g_value_set_int (value, gtk_widget_get_margin_right (widget));
+ break;
+ case PROP_MARGIN_TOP:
+ g_value_set_int (value, gtk_widget_get_margin_top (widget));
+ break;
+ case PROP_MARGIN_BOTTOM:
+ g_value_set_int (value, gtk_widget_get_margin_bottom (widget));
+ break;
+ case PROP_MARGIN:
+ {
+ GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (widget, FALSE);
+ if (aux_info == NULL)
+ {
+ g_value_set_int (value, 0);
+ }
+ else
+ {
+ g_value_set_int (value, MAX (MAX (aux_info->margin.left,
+ aux_info->margin.right),
+ MAX (aux_info->margin.top,
+ aux_info->margin.bottom)));
+ }
+ }
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -4309,13 +4510,119 @@ gtk_widget_real_size_allocate (GtkWidget *widget,
}
static void
+get_span_inside_border (GtkWidget *widget,
+ GtkAlign align,
+ int start_pad,
+ int end_pad,
+ int allocated_outside_size,
+ int natural_inside_size,
+ int *coord_inside_p,
+ int *size_inside_p)
+{
+ int inside_allocated;
+ int content_size;
+ int coord, size;
+
+ inside_allocated = allocated_outside_size - start_pad - end_pad;
+
+ content_size = natural_inside_size;
+ if (content_size > inside_allocated)
+ {
+ /* didn't get full natural size */
+ content_size = inside_allocated;
+ }
+
+ coord = size = 0; /* silence compiler */
+ switch (align)
+ {
+ case GTK_ALIGN_FILL:
+ coord = start_pad;
+ size = inside_allocated;
+ break;
+ case GTK_ALIGN_START:
+ coord = start_pad;
+ size = content_size;
+ break;
+ case GTK_ALIGN_END:
+ coord = allocated_outside_size - end_pad - content_size;
+ size = content_size;
+ break;
+ case GTK_ALIGN_CENTER:
+ coord = start_pad + (inside_allocated - content_size) / 2;
+ size = content_size;
+ break;
+ }
+
+ if (coord_inside_p)
+ *coord_inside_p = coord;
+
+ if (size_inside_p)
+ *size_inside_p = size;
+}
+
+static void
+get_span_inside_border_horizontal (GtkWidget *widget,
+ const GtkWidgetAuxInfo *aux_info,
+ int allocated_outside_width,
+ int natural_inside_width,
+ int *x_inside_p,
+ int *width_inside_p)
+{
+ get_span_inside_border (widget,
+ aux_info->h_align,
+ aux_info->margin.left,
+ aux_info->margin.right,
+ allocated_outside_width,
+ natural_inside_width,
+ x_inside_p,
+ width_inside_p);
+}
+
+static void
+get_span_inside_border_vertical (GtkWidget *widget,
+ const GtkWidgetAuxInfo *aux_info,
+ int allocated_outside_height,
+ int natural_inside_height,
+ int *y_inside_p,
+ int *height_inside_p)
+{
+ get_span_inside_border (widget,
+ aux_info->v_align,
+ aux_info->margin.top,
+ aux_info->margin.bottom,
+ allocated_outside_height,
+ natural_inside_height,
+ y_inside_p,
+ height_inside_p);
+}
+
+static void
gtk_widget_real_adjust_size_allocation (GtkWidget *widget,
GtkAllocation *allocation)
{
- /* We have no adjustments by default for now, but we have this empty
- * function here so subclasses can chain up in case we do add
- * something.
- */
+ const GtkWidgetAuxInfo *aux_info;
+ GtkRequisition min, natural;
+ int x, y, w, h;
+
+ aux_info = _gtk_widget_get_aux_info_or_defaults (widget);
+
+ gtk_size_request_get_size (GTK_SIZE_REQUEST (widget), &min, &natural);
+
+ get_span_inside_border_horizontal (widget,
+ aux_info,
+ allocation->width,
+ natural.width,
+ &x, &w);
+ get_span_inside_border_vertical (widget,
+ aux_info,
+ allocation->height,
+ natural.height,
+ &y, &h);
+
+ allocation->x += x;
+ allocation->y += y;
+ allocation->width = w;
+ allocation->height = h;
}
static gboolean
@@ -8028,6 +8335,11 @@ gtk_widget_set_usize_internal (GtkWidget *widget,
*
* Widgets can't actually be allocated a size less than 1 by 1, but
* you can pass 0,0 to this function to mean "as small as possible."
+ *
+ * The size request set here does not include any margin from the
+ * #GtkWidget properties margin-left, margin-right, margin-top, and
+ * margin-bottom, but it does include pretty much all other padding
+ * or border properties set by any subclass of #GtkWidget.
**/
void
gtk_widget_set_size_request (GtkWidget *widget,
@@ -9129,6 +9441,17 @@ gtk_widget_real_adjust_size_request (GtkWidget *widget,
* in gtksizerequest.c when calling their size request vfuncs.
*/
*natural_size = MAX (*natural_size, *minimum_size);
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ *minimum_size += (aux_info->margin.left + aux_info->margin.right);
+ *natural_size += (aux_info->margin.left + aux_info->margin.right);
+ }
+ else
+ {
+ *minimum_size += (aux_info->margin.top + aux_info->margin.bottom);
+ *natural_size += (aux_info->margin.top + aux_info->margin.bottom);
+ }
}
/**
@@ -9634,7 +9957,10 @@ gtk_widget_propagate_state (GtkWidget *widget,
}
static const GtkWidgetAuxInfo default_aux_info = {
- -1, -1
+ -1, -1,
+ GTK_ALIGN_FILL,
+ GTK_ALIGN_FILL,
+ { 0, 0, 0, 0 }
};
/*
@@ -11156,8 +11482,165 @@ gtk_widget_size_request_init (GtkSizeRequestIface *iface)
iface->get_width_for_height = gtk_widget_real_get_width_for_height;
iface->get_height_for_width = gtk_widget_real_get_height_for_width;
}
-
-
+
+GtkAlign
+gtk_widget_get_h_align (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), GTK_ALIGN_FILL);
+ return _gtk_widget_get_aux_info_or_defaults (widget)->h_align;
+}
+
+void
+gtk_widget_set_h_align (GtkWidget *widget,
+ GtkAlign align)
+{
+ GtkWidgetAuxInfo *aux_info;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ aux_info = _gtk_widget_get_aux_info (widget, TRUE);
+
+ if (aux_info->h_align == align)
+ return;
+
+ aux_info->h_align = align;
+ gtk_widget_queue_resize (widget);
+ g_object_notify (G_OBJECT (widget), "h-align");
+}
+
+GtkAlign
+gtk_widget_get_v_align (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), GTK_ALIGN_FILL);
+ return _gtk_widget_get_aux_info_or_defaults (widget)->v_align;
+}
+
+void
+gtk_widget_set_v_align (GtkWidget *widget,
+ GtkAlign align)
+{
+ GtkWidgetAuxInfo *aux_info;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ aux_info = _gtk_widget_get_aux_info (widget, TRUE);
+
+ if (aux_info->v_align == align)
+ return;
+
+ aux_info->v_align = align;
+ gtk_widget_queue_resize (widget);
+ g_object_notify (G_OBJECT (widget), "v-align");
+}
+
+int
+gtk_widget_get_margin_left (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
+
+ return _gtk_widget_get_aux_info_or_defaults (widget)->margin.left;
+}
+
+void
+gtk_widget_set_margin_left (GtkWidget *widget,
+ int margin)
+{
+ GtkWidgetAuxInfo *aux_info;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (margin <= G_MAXINT16);
+
+ aux_info = _gtk_widget_get_aux_info (widget, TRUE);
+
+ if (aux_info->margin.left == margin)
+ return;
+
+ aux_info->margin.left = margin;
+ gtk_widget_queue_resize (widget);
+ g_object_notify (G_OBJECT (widget), "margin-left");
+}
+
+int
+gtk_widget_get_margin_right (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
+
+ return _gtk_widget_get_aux_info_or_defaults (widget)->margin.right;
+}
+
+void
+gtk_widget_set_margin_right (GtkWidget *widget,
+ int margin)
+{
+ GtkWidgetAuxInfo *aux_info;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (margin <= G_MAXINT16);
+
+ aux_info = _gtk_widget_get_aux_info (widget, TRUE);
+
+ if (aux_info->margin.right == margin)
+ return;
+
+ aux_info->margin.right = margin;
+ gtk_widget_queue_resize (widget);
+ g_object_notify (G_OBJECT (widget), "margin-right");
+}
+
+int
+gtk_widget_get_margin_top (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
+
+ return _gtk_widget_get_aux_info_or_defaults (widget)->margin.top;
+}
+
+void
+gtk_widget_set_margin_top (GtkWidget *widget,
+ int margin)
+{
+ GtkWidgetAuxInfo *aux_info;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (margin <= G_MAXINT16);
+
+ aux_info = _gtk_widget_get_aux_info (widget, TRUE);
+
+ if (aux_info->margin.top == margin)
+ return;
+
+ aux_info->margin.top = margin;
+ gtk_widget_queue_resize (widget);
+ g_object_notify (G_OBJECT (widget), "margin-top");
+}
+
+int
+gtk_widget_get_margin_bottom (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
+
+ return _gtk_widget_get_aux_info_or_defaults (widget)->margin.bottom;
+}
+
+void
+gtk_widget_set_margin_bottom (GtkWidget *widget,
+ int margin)
+{
+ GtkWidgetAuxInfo *aux_info;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (margin <= G_MAXINT16);
+
+ aux_info = _gtk_widget_get_aux_info (widget, TRUE);
+
+ if (aux_info->margin.bottom == margin)
+ return;
+
+ aux_info->margin.bottom = margin;
+ gtk_widget_queue_resize (widget);
+ g_object_notify (G_OBJECT (widget), "margin-bottom");
+}
+
/**
* gtk_widget_get_clipboard:
* @widget: a #GtkWidget
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index 66d3f27..8efdcd6 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -502,6 +502,11 @@ struct _GtkWidgetAuxInfo
{
gint width;
gint height;
+
+ guint h_align : 4;
+ guint v_align : 4;
+
+ GtkBorder margin;
};
struct _GtkWidgetShapeInfo
@@ -730,6 +735,28 @@ void gtk_widget_set_support_multidevice (GtkWidget *widget,
/* Accessibility support */
AtkObject* gtk_widget_get_accessible (GtkWidget *widget);
+
+/* Margin and alignment */
+GtkAlign gtk_widget_get_h_align (GtkWidget *widget);
+void gtk_widget_set_h_align (GtkWidget *widget,
+ GtkAlign align);
+GtkAlign gtk_widget_get_v_align (GtkWidget *widget);
+void gtk_widget_set_v_align (GtkWidget *widget,
+ GtkAlign align);
+int gtk_widget_get_margin_left (GtkWidget *widget);
+void gtk_widget_set_margin_left (GtkWidget *widget,
+ int margin);
+int gtk_widget_get_margin_right (GtkWidget *widget);
+void gtk_widget_set_margin_right (GtkWidget *widget,
+ int margin);
+int gtk_widget_get_margin_top (GtkWidget *widget);
+void gtk_widget_set_margin_top (GtkWidget *widget,
+ int margin);
+int gtk_widget_get_margin_bottom (GtkWidget *widget);
+void gtk_widget_set_margin_bottom (GtkWidget *widget,
+ int margin);
+
+
/* The following functions must not be called on an already
* realized widget. Because it is possible that somebody
* can call get_colormap() or get_visual() and save the
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]