diff options
author | Alexander Larsson <alexl@redhat.com> | 2013-03-05 14:54:03 +0100 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2013-04-23 05:50:37 +0200 |
commit | 852cbb62b8b98bb3345604ce1dcf4186613f74e8 (patch) | |
tree | 58315efdf359698bb49c6b0febfc86b28db40337 /gtk/gtksizerequest.c | |
parent | f15bc7818e0941da80c4ee380a25daf7fcd99d72 (diff) | |
download | gtk+-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.c | 246 |
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, |