[gtk+/widget-padding: 10/11] Add padding and alignment properties to GtkWidget
- From: Havoc Pennington <hp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/widget-padding: 10/11] Add padding and alignment properties to GtkWidget
- Date: Wed, 8 Sep 2010 02:10:57 +0000 (UTC)
commit c440a6760e90262ce0fb3d6356602709111ffb94
Author: Havoc Pennington <hp pobox com>
Date: Sun Sep 5 12:21:27 2010 -0400
Add padding and alignment properties to GtkWidget
h-align = START,END,CENTER,FILL
v-align = START,END,CENTER,FILL
padding-left,right,top,bottom,all-sides
These should obsolete all such similar properties on
layout containers, GtkMisc, GtkAlignment, GtkContainer::border-width
Padding is outside the size request.
If padding 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 padding.
To reflect this, we'll probably rename padding to margin
(and squash that back with this patch).
gtk/gtkenums.h | 30 ++++
gtk/gtkwidget.c | 499 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
gtk/gtkwidget.h | 39 +++++
3 files changed, 560 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 cff9b08..b04f99a 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -227,7 +227,14 @@ enum {
PROP_TOOLTIP_MARKUP,
PROP_TOOLTIP_TEXT,
PROP_WINDOW,
- PROP_DOUBLE_BUFFERED
+ PROP_DOUBLE_BUFFERED,
+ PROP_H_ALIGN,
+ PROP_V_ALIGN,
+ PROP_PADDING_LEFT,
+ PROP_PADDING_RIGHT,
+ PROP_PADDING_TOP,
+ PROP_PADDING_BOTTOM,
+ PROP_PADDING_ALL_SIDES
};
typedef struct _GtkStateData GtkStateData;
@@ -813,6 +820,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:padding-left
+ *
+ * Padding on left side of widget.
+ *
+ * This property adds padding outside of the widget's normal size
+ * request, the padding 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_PADDING_LEFT,
+ g_param_spec_int ("padding-left",
+ P_("Padding on Left"),
+ P_("Pixels of extra space on the left side"),
+ 0,
+ G_MAXINT16,
+ 0,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GtkWidget:padding-right
+ *
+ * Padding on right side of widget.
+ *
+ * This property adds padding outside of the widget's normal size
+ * request, the padding 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_PADDING_RIGHT,
+ g_param_spec_int ("padding-right",
+ P_("Padding on Right"),
+ P_("Pixels of extra space on the right side"),
+ 0,
+ G_MAXINT16,
+ 0,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GtkWidget:padding-top
+ *
+ * Padding on top side of widget.
+ *
+ * This property adds padding outside of the widget's normal size
+ * request, the padding 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_PADDING_TOP,
+ g_param_spec_int ("padding-top",
+ P_("Padding on Top"),
+ P_("Pixels of extra space on the top side"),
+ 0,
+ G_MAXINT16,
+ 0,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GtkWidget:padding-bottom
+ *
+ * Padding on bottom side of widget.
+ *
+ * This property adds padding outside of the widget's normal size
+ * request, the padding 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_PADDING_BOTTOM,
+ g_param_spec_int ("padding-bottom",
+ P_("Padding on Bottom"),
+ P_("Pixels of extra space on the bottom side"),
+ 0,
+ G_MAXINT16,
+ 0,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GtkWidget:padding-all-sides
+ *
+ * Sets all four sides' padding at once. If read, returns max
+ * padding on any side.
+ *
+ * Since: 3.0
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_PADDING_ALL_SIDES,
+ g_param_spec_int ("padding-all-sides",
+ P_("All Paddings"),
+ 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.
*/
@@ -2747,6 +2888,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_PADDING_LEFT:
+ gtk_widget_set_padding_left (widget, g_value_get_int (value));
+ break;
+ case PROP_PADDING_RIGHT:
+ gtk_widget_set_padding_right (widget, g_value_get_int (value));
+ break;
+ case PROP_PADDING_TOP:
+ gtk_widget_set_padding_top (widget, g_value_get_int (value));
+ break;
+ case PROP_PADDING_BOTTOM:
+ gtk_widget_set_padding_bottom (widget, g_value_get_int (value));
+ break;
+ case PROP_PADDING_ALL_SIDES:
+ g_object_freeze_notify (G_OBJECT (widget));
+ gtk_widget_set_padding_left (widget, g_value_get_int (value));
+ gtk_widget_set_padding_right (widget, g_value_get_int (value));
+ gtk_widget_set_padding_top (widget, g_value_get_int (value));
+ gtk_widget_set_padding_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;
@@ -2856,6 +3023,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_PADDING_LEFT:
+ g_value_set_int (value, gtk_widget_get_padding_left (widget));
+ break;
+ case PROP_PADDING_RIGHT:
+ g_value_set_int (value, gtk_widget_get_padding_right (widget));
+ break;
+ case PROP_PADDING_TOP:
+ g_value_set_int (value, gtk_widget_get_padding_top (widget));
+ break;
+ case PROP_PADDING_BOTTOM:
+ g_value_set_int (value, gtk_widget_get_padding_bottom (widget));
+ break;
+ case PROP_PADDING_ALL_SIDES:
+ {
+ 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->padding.left,
+ aux_info->padding.right),
+ MAX (aux_info->padding.top,
+ aux_info->padding.bottom)));
+ }
+ }
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -4223,13 +4424,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->padding.left,
+ aux_info->padding.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->padding.top,
+ aux_info->padding.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
@@ -7889,6 +8196,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 padding from the
+ * #GtkWidget properties padding-left, padding-right, padding-top, and
+ * padding-bottom, but it does include pretty much all other padding
+ * properties set by any subclass of #GtkWidget.
**/
void
gtk_widget_set_size_request (GtkWidget *widget,
@@ -8967,6 +9279,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->padding.left + aux_info->padding.right);
+ *natural_size += (aux_info->padding.left + aux_info->padding.right);
+ }
+ else
+ {
+ *minimum_size += (aux_info->padding.top + aux_info->padding.bottom);
+ *natural_size += (aux_info->padding.top + aux_info->padding.bottom);
+ }
}
/**
@@ -9447,7 +9770,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 }
};
/*
@@ -10956,8 +11282,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_padding_left (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
+
+ return _gtk_widget_get_aux_info_or_defaults (widget)->padding.left;
+}
+
+void
+gtk_widget_set_padding_left (GtkWidget *widget,
+ int padding)
+{
+ GtkWidgetAuxInfo *aux_info;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (padding <= G_MAXINT16);
+
+ aux_info = _gtk_widget_get_aux_info (widget, TRUE);
+
+ if (aux_info->padding.left == padding)
+ return;
+
+ aux_info->padding.left = padding;
+ gtk_widget_queue_resize (widget);
+ g_object_notify (G_OBJECT (widget), "padding-left");
+}
+
+int
+gtk_widget_get_padding_right (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
+
+ return _gtk_widget_get_aux_info_or_defaults (widget)->padding.right;
+}
+
+void
+gtk_widget_set_padding_right (GtkWidget *widget,
+ int padding)
+{
+ GtkWidgetAuxInfo *aux_info;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (padding <= G_MAXINT16);
+
+ aux_info = _gtk_widget_get_aux_info (widget, TRUE);
+
+ if (aux_info->padding.right == padding)
+ return;
+
+ aux_info->padding.right = padding;
+ gtk_widget_queue_resize (widget);
+ g_object_notify (G_OBJECT (widget), "padding-right");
+}
+
+int
+gtk_widget_get_padding_top (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
+
+ return _gtk_widget_get_aux_info_or_defaults (widget)->padding.top;
+}
+
+void
+gtk_widget_set_padding_top (GtkWidget *widget,
+ int padding)
+{
+ GtkWidgetAuxInfo *aux_info;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (padding <= G_MAXINT16);
+
+ aux_info = _gtk_widget_get_aux_info (widget, TRUE);
+
+ if (aux_info->padding.top == padding)
+ return;
+
+ aux_info->padding.top = padding;
+ gtk_widget_queue_resize (widget);
+ g_object_notify (G_OBJECT (widget), "padding-top");
+}
+
+int
+gtk_widget_get_padding_bottom (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
+
+ return _gtk_widget_get_aux_info_or_defaults (widget)->padding.bottom;
+}
+
+void
+gtk_widget_set_padding_bottom (GtkWidget *widget,
+ int padding)
+{
+ GtkWidgetAuxInfo *aux_info;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (padding <= G_MAXINT16);
+
+ aux_info = _gtk_widget_get_aux_info (widget, TRUE);
+
+ if (aux_info->padding.bottom == padding)
+ return;
+
+ aux_info->padding.bottom = padding;
+ gtk_widget_queue_resize (widget);
+ g_object_notify (G_OBJECT (widget), "padding-bottom");
+}
+
/**
* gtk_widget_get_clipboard:
* @widget: a #GtkWidget
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index 8d49485..3f41333 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -551,6 +551,24 @@ struct _GtkWidgetAuxInfo
{
gint width;
gint height;
+
+ guint h_align : 4;
+ guint v_align : 4;
+
+ /* FIXME GtkBorder uses 32-bit ints for each side which is kinda
+ * bloated; 255 (or even 128) already exceeds 99.99% of actual padding
+ * settings, int16 would exceed 100%, int32 is nuts. GtkBox uses
+ * uint16.
+ *
+ * Just fix GtkBorder itself? The main danger is probably going signed
+ * to unsigned, rather than 32 to 16.
+ */
+ struct {
+ guint16 left;
+ guint16 right;
+ guint16 top;
+ guint16 bottom;
+ } padding;
};
struct _GtkWidgetShapeInfo
@@ -779,6 +797,27 @@ void gtk_widget_set_support_multidevice (GtkWidget *widget,
/* Accessibility support */
AtkObject* gtk_widget_get_accessible (GtkWidget *widget);
+
+/* Padding 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_padding_left (GtkWidget *widget);
+void gtk_widget_set_padding_left (GtkWidget *widget,
+ int padding);
+int gtk_widget_get_padding_right (GtkWidget *widget);
+void gtk_widget_set_padding_right (GtkWidget *widget,
+ int padding);
+int gtk_widget_get_padding_top (GtkWidget *widget);
+void gtk_widget_set_padding_top (GtkWidget *widget,
+ int padding);
+int gtk_widget_get_padding_bottom (GtkWidget *widget);
+void gtk_widget_set_padding_bottom (GtkWidget *widget,
+ int padding);
+
/* 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]