summaryrefslogtreecommitdiff
path: root/gtk/gtksizerequest.c
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2013-03-05 14:54:03 +0100
committerAlexander Larsson <alexl@redhat.com>2013-04-23 05:50:37 +0200
commit852cbb62b8b98bb3345604ce1dcf4186613f74e8 (patch)
tree58315efdf359698bb49c6b0febfc86b28db40337 /gtk/gtksizerequest.c
parentf15bc7818e0941da80c4ee380a25daf7fcd99d72 (diff)
downloadgtk+-852cbb62b8b98bb3345604ce1dcf4186613f74e8.tar.gz
Initial support for baselines
This modifies the size machinery in order to allow baseline support. We add a new widget vfunc get_preferred_height_and_baseline_for_width which queries the normal height_for_width (or non-for-width if width is -1) and additionally returns optional (-1 means "no baseline") baselines for the minimal and natural heights. We also add a new gtk_widget_size_allocate_with_baseline() which baseline-aware containers can use to allocate children with a specific baseline, either one inherited from the parent, or one introduced due to requested baseline alignment in the container itself. size_allocate_with_baseline() works just like a normal size allocation, except the baseline gets recorded so that the child can access it via gtk_widget_get_allocated_baseline() when it aligns itself. There are also adjust_baseline_request/allocation similar to the allocation adjustment, and we extend the size request cache to also store the baselines.
Diffstat (limited to 'gtk/gtksizerequest.c')
-rw-r--r--gtk/gtksizerequest.c246
1 files changed, 197 insertions, 49 deletions
diff --git a/gtk/gtksizerequest.c b/gtk/gtksizerequest.c
index 36d24f2f0c..4e47d88420 100644
--- a/gtk/gtksizerequest.c
+++ b/gtk/gtksizerequest.c
@@ -98,11 +98,16 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
GtkOrientation orientation,
gint for_size,
gint *minimum_size,
- gint *natural_size)
+ gint *natural_size,
+ gint *minimum_baseline,
+ gint *natural_baseline)
{
SizeRequestCache *cache;
+ GtkWidgetClass *widget_class;
gint min_size = 0;
gint nat_size = 0;
+ gint min_baseline = -1;
+ gint nat_baseline = -1;
gboolean found_in_cache;
if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_CONSTANT_SIZE)
@@ -113,7 +118,11 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
orientation,
for_size,
&min_size,
- &nat_size);
+ &nat_size,
+ &min_baseline,
+ &nat_baseline);
+
+ widget_class = GTK_WIDGET_GET_CLASS (widget);
if (!found_in_cache)
{
@@ -128,7 +137,7 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
if (for_size < 0)
{
push_recursion_check (widget, orientation, for_size);
- GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_size, &nat_size);
+ widget_class->get_preferred_width (widget, &min_size, &nat_size);
pop_recursion_check (widget, orientation);
}
else
@@ -142,17 +151,17 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
gtk_widget_get_preferred_height (widget, &minimum_height, &natural_height);
/* convert for_size to unadjusted height (for_size is a proposed allocation) */
- GTK_WIDGET_GET_CLASS (widget)->adjust_size_allocation (widget,
- GTK_ORIENTATION_VERTICAL,
- &minimum_height,
- &natural_height,
- &ignored_position,
- &adjusted_for_size);
+ widget_class->adjust_size_allocation (widget,
+ GTK_ORIENTATION_VERTICAL,
+ &minimum_height,
+ &natural_height,
+ &ignored_position,
+ &adjusted_for_size);
push_recursion_check (widget, orientation, for_size);
- GTK_WIDGET_GET_CLASS (widget)->get_preferred_width_for_height (widget,
- MAX (adjusted_for_size, minimum_height),
- &min_size, &nat_size);
+ widget_class->get_preferred_width_for_height (widget,
+ MAX (adjusted_for_size, minimum_height),
+ &min_size, &nat_size);
pop_recursion_check (widget, orientation);
}
}
@@ -161,7 +170,9 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
if (for_size < 0)
{
push_recursion_check (widget, orientation, for_size);
- GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, &min_size, &nat_size);
+ widget_class->get_preferred_height_and_baseline_for_width (widget, -1,
+ &min_size, &nat_size,
+ &min_baseline, &nat_baseline);
pop_recursion_check (widget, orientation);
}
else
@@ -175,17 +186,17 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
gtk_widget_get_preferred_width (widget, &minimum_width, &natural_width);
/* convert for_size to unadjusted width (for_size is a proposed allocation) */
- GTK_WIDGET_GET_CLASS (widget)->adjust_size_allocation (widget,
- GTK_ORIENTATION_HORIZONTAL,
- &minimum_width,
- &natural_width,
- &ignored_position,
- &adjusted_for_size);
+ widget_class->adjust_size_allocation (widget,
+ GTK_ORIENTATION_HORIZONTAL,
+ &minimum_width,
+ &natural_width,
+ &ignored_position,
+ &adjusted_for_size);
push_recursion_check (widget, orientation, for_size);
- GTK_WIDGET_GET_CLASS (widget)->get_preferred_height_for_width (widget,
- MAX (adjusted_for_size, minimum_width),
- &min_size, &nat_size);
+ widget_class->get_preferred_height_and_baseline_for_width (widget, MAX (adjusted_for_size, minimum_width),
+ &min_size, &nat_size,
+ &min_baseline, &nat_baseline);
pop_recursion_check (widget, orientation);
}
}
@@ -198,10 +209,10 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
adjusted_min = min_size;
adjusted_natural = nat_size;
- GTK_WIDGET_GET_CLASS (widget)->adjust_size_request (widget,
- orientation,
- &adjusted_min,
- &adjusted_natural);
+ widget_class->adjust_size_request (widget,
+ orientation,
+ &adjusted_min,
+ &adjusted_natural);
if (adjusted_min < min_size ||
adjusted_natural < nat_size)
@@ -229,11 +240,42 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
nat_size = adjusted_natural;
}
+ if (min_baseline != -1 || nat_baseline != -1)
+ {
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ g_warning ("%s %p reported a horizontal baseline",
+ G_OBJECT_TYPE_NAME (widget), widget);
+ min_baseline = -1;
+ nat_baseline = -1;
+ }
+ else if (min_baseline == -1 || nat_baseline == -1)
+ {
+ g_warning ("%s %p reported baseline for only one of min/natural (min: %d, natural: %d)",
+ G_OBJECT_TYPE_NAME (widget), widget,
+ min_baseline, nat_baseline);
+ min_baseline = -1;
+ nat_baseline = -1;
+ }
+ else if (gtk_widget_get_valign_with_baseline (widget) != GTK_ALIGN_BASELINE)
+ {
+ /* Ignore requested baseline for non-aligned widgets */
+ min_baseline = -1;
+ nat_baseline = -1;
+ }
+ else
+ widget_class->adjust_baseline_request (widget,
+ &min_baseline,
+ &nat_baseline);
+ }
+
_gtk_size_request_cache_commit (cache,
orientation,
for_size,
min_size,
- nat_size);
+ nat_size,
+ min_baseline,
+ nat_baseline);
}
if (minimum_size)
@@ -242,15 +284,26 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
if (natural_size)
*natural_size = nat_size;
+ if (minimum_baseline)
+ *minimum_baseline = min_baseline;
+
+ if (natural_baseline)
+ *natural_baseline = nat_baseline;
+
g_assert (min_size <= nat_size);
GTK_NOTE (SIZE_REQUEST,
- g_print ("[%p] %s\t%s: %d is minimum %d and natural: %d (hit cache: %s)\n",
+ g_print ("[%p] %s\t%s: %d is minimum %d and natural: %d",
widget, G_OBJECT_TYPE_NAME (widget),
orientation == GTK_ORIENTATION_HORIZONTAL ?
"width for height" : "height for width" ,
- for_size, min_size, nat_size,
- found_in_cache ? "yes" : "no"));
+ for_size, min_size, nat_size);
+ if (min_baseline != -1 || nat_baseline != -1)
+ g_print (", baseline %d/%d",
+ min_baseline, nat_baseline);
+ g_print (" (hit cache: %s)\n",
+ found_in_cache ? "yes" : "no")
+ );
}
/* This is the main function that checks for a cached size and
@@ -263,7 +316,9 @@ _gtk_widget_compute_size_for_orientation (GtkWidget *widget,
GtkOrientation orientation,
gint for_size,
gint *minimum,
- gint *natural)
+ gint *natural,
+ gint *minimum_baseline,
+ gint *natural_baseline)
{
GHashTable *widgets;
GHashTableIter iter;
@@ -276,12 +331,17 @@ _gtk_widget_compute_size_for_orientation (GtkWidget *widget,
*minimum = 0;
if (natural)
*natural = 0;
+ if (minimum_baseline)
+ *minimum_baseline = -1;
+ if (natural_baseline)
+ *natural_baseline = -1;
return;
}
if (G_LIKELY (!_gtk_widget_get_sizegroups (widget)))
{
- gtk_widget_query_size_for_orientation (widget, orientation, for_size, minimum, natural);
+ gtk_widget_query_size_for_orientation (widget, orientation, for_size, minimum, natural,
+ minimum_baseline, natural_baseline);
return;
}
@@ -295,7 +355,7 @@ _gtk_widget_compute_size_for_orientation (GtkWidget *widget,
GtkWidget *tmp_widget = key;
gint min_dimension, nat_dimension;
- gtk_widget_query_size_for_orientation (tmp_widget, orientation, for_size, &min_dimension, &nat_dimension);
+ gtk_widget_query_size_for_orientation (tmp_widget, orientation, for_size, &min_dimension, &nat_dimension, NULL, NULL);
min_result = MAX (min_result, min_dimension);
nat_result = MAX (nat_result, nat_dimension);
@@ -305,6 +365,13 @@ _gtk_widget_compute_size_for_orientation (GtkWidget *widget,
g_hash_table_destroy (widgets);
+ /* Baselines make no sense with sizegroups really */
+ if (minimum_baseline)
+ *minimum_baseline = -1;
+
+ if (natural_baseline)
+ *natural_baseline = -1;
+
if (minimum)
*minimum = min_result;
@@ -377,7 +444,8 @@ gtk_widget_get_preferred_width (GtkWidget *widget,
GTK_ORIENTATION_HORIZONTAL,
-1,
minimum_width,
- natural_width);
+ natural_width,
+ NULL, NULL);
}
@@ -411,7 +479,8 @@ gtk_widget_get_preferred_height (GtkWidget *widget,
GTK_ORIENTATION_VERTICAL,
-1,
minimum_height,
- natural_height);
+ natural_height,
+ NULL, NULL);
}
@@ -448,7 +517,8 @@ gtk_widget_get_preferred_width_for_height (GtkWidget *widget,
GTK_ORIENTATION_HORIZONTAL,
height,
minimum_width,
- natural_width);
+ natural_width,
+ NULL, NULL);
}
/**
@@ -483,17 +553,61 @@ gtk_widget_get_preferred_height_for_width (GtkWidget *widget,
GTK_ORIENTATION_VERTICAL,
width,
minimum_height,
- natural_height);
+ natural_height,
+ NULL, NULL);
}
/**
- * gtk_widget_get_preferred_size:
+ * gtk_widget_get_preferred_height_and_baseline_for_width:
+ * @widget: a #GtkWidget instance
+ * @width: the width which is available for allocation, or -1 if none
+ * @minimum_height: (out) (allow-none): location for storing the minimum height, or %NULL
+ * @natural_height: (out) (allow-none): location for storing the natural height, or %NULL
+ * @minimum_baseline: (out) (allow-none): location for storing the baseline for the minimum height, or %NULL
+ * @natural_baseline: (out) (allow-none): location for storing the baseline for the natural height, or %NULL
+ *
+ * Retrieves a widget's minimum and natural height and the corresponding baselines if it would be given
+ * the specified @width, or the default height if @width is -1. The baselines may be -1 which means
+ * that no baseline is requested for this widget.
+ *
+ * The returned request will be modified by the
+ * GtkWidgetClass::adjust_size_request and GtkWidgetClass::adjust_baseline_request virtual methods
+ * and by any #GtkSizeGroup<!-- -->s that have been applied. That is, the returned request
+ * is the one that should be used for layout, not necessarily the one
+ * returned by the widget itself.
+ *
+ * Since: 3.10
+ */
+void
+gtk_widget_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height,
+ gint *minimum_baseline,
+ gint *natural_baseline)
+{
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (minimum_height != NULL || natural_height != NULL);
+ g_return_if_fail (width >= -1);
+
+ _gtk_widget_compute_size_for_orientation (widget,
+ GTK_ORIENTATION_VERTICAL,
+ width,
+ minimum_height,
+ natural_height,
+ minimum_baseline,
+ natural_baseline);
+}
+
+/**
+ * gtk_widget_get_preferred_size_and_baseline:
* @widget: a #GtkWidget instance
* @minimum_size: (out) (allow-none): location for storing the minimum size, or %NULL
* @natural_size: (out) (allow-none): location for storing the natural size, or %NULL
*
- * Retrieves the minimum and natural size of a widget, taking
- * into account the widget's preference for height-for-width management.
+ * Retrieves the minimum and natural size and the corresponding baselines of a widget, taking
+ * into account the widget's preference for height-for-width management. The baselines may
+ * be -1 which means that no baseline is requested for this widget.
*
* This is used to retrieve a suitable size by container widgets which do
* not impose any restrictions on the child placement. It can be used
@@ -505,12 +619,14 @@ gtk_widget_get_preferred_height_for_width (GtkWidget *widget,
* height for the natural width is generally smaller than the required height for
* the minimum width.</para></note>
*
- * Since: 3.0
+ * Since: 3.10
*/
void
-gtk_widget_get_preferred_size (GtkWidget *widget,
- GtkRequisition *minimum_size,
- GtkRequisition *natural_size)
+gtk_widget_get_preferred_size_and_baseline (GtkWidget *widget,
+ GtkRequisition *minimum_size,
+ GtkRequisition *natural_size,
+ gint *minimum_baseline,
+ gint *natural_baseline)
{
gint min_width, nat_width;
gint min_height, nat_height;
@@ -524,20 +640,20 @@ gtk_widget_get_preferred_size (GtkWidget *widget,
if (minimum_size)
{
minimum_size->width = min_width;
- gtk_widget_get_preferred_height_for_width (widget, min_width,
- &minimum_size->height, NULL);
+ gtk_widget_get_preferred_height_and_baseline_for_width (widget, min_width,
+ &minimum_size->height, NULL, minimum_baseline, NULL);
}
if (natural_size)
{
natural_size->width = nat_width;
- gtk_widget_get_preferred_height_for_width (widget, nat_width,
- NULL, &natural_size->height);
+ gtk_widget_get_preferred_height_and_baseline_for_width (widget, nat_width,
+ NULL, &natural_size->height, NULL, natural_baseline);
}
}
else /* GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT or CONSTANT_SIZE */
{
- gtk_widget_get_preferred_height (widget, &min_height, &nat_height);
+ gtk_widget_get_preferred_height_and_baseline_for_width (widget, -1, &min_height, &nat_height, minimum_baseline, natural_baseline);
if (minimum_size)
{
@@ -555,6 +671,38 @@ gtk_widget_get_preferred_size (GtkWidget *widget,
}
}
+/**
+ * gtk_widget_get_preferred_size:
+ * @widget: a #GtkWidget instance
+ * @minimum_size: (out) (allow-none): location for storing the minimum size, or %NULL
+ * @natural_size: (out) (allow-none): location for storing the natural size, or %NULL
+ *
+ * Retrieves the minimum and natural size of a widget, taking
+ * into account the widget's preference for height-for-width management.
+ *
+ * This is used to retrieve a suitable size by container widgets which do
+ * not impose any restrictions on the child placement. It can be used
+ * to deduce toplevel window and menu sizes as well as child widgets in
+ * free-form containers such as GtkLayout.
+ *
+ * <note><para>Handle with care. Note that the natural height of a height-for-width
+ * widget will generally be a smaller size than the minimum height, since the required
+ * height for the natural width is generally smaller than the required height for
+ * the minimum width.</para></note>
+ *
+ * Use gtk_widget_get_preferred_size_and_baseline() if you want to support
+ * baseline alignment.
+ *
+ * Since: 3.0
+ */
+void
+gtk_widget_get_preferred_size (GtkWidget *widget,
+ GtkRequisition *minimum_size,
+ GtkRequisition *natural_size)
+{
+ gtk_widget_get_preferred_size_and_baseline (widget, minimum_size, natural_size,
+ NULL, NULL);
+}
static gint
compare_gap (gconstpointer p1,