Compare commits

...

25 Commits

Author SHA1 Message Date
Alexander Larsson
308aebff9d Handle non-baseline supporting subclasses overriding baseline supporting classes
If a subclass (say a child of GtkButton) overrides the non-baseline
size request methods we need to call these, rather than the new
get_height_and_baseline_for_width method.

In order to handle this we make the default for this method to be
NULL, and instead check at runtime which method to call. If any
non-baseline vfunc has changed in a class but the baseline one
hasn't, then we can't use the baseline one.
2013-03-27 10:22:14 +01:00
Alexander Larsson
c8ac4b8fb3 Add baseline functions to docs 2013-03-27 09:48:58 +01:00
Alexander Larsson
c3669407dc Add baseline alignment functions to gtk.symbols 2013-03-27 09:45:08 +01:00
Alexander Larsson
90ab5e6a26 GtkLabel: Minor cleanup
Make sure we always compare for a set baseline in the same way.
I.e. baseline != -1, never baseline >= 0.
2013-03-27 09:44:02 +01:00
Alexander Larsson
1c04da3152 GtkWidget: Add missing Since docs 2013-03-27 09:43:40 +01:00
Alexander Larsson
e68a98e7b3 GtkImage: Reuse previously calculated baseline_align in draw()
No need to recalculate this every time we draw.
2013-03-27 09:42:43 +01:00
Alexander Larsson
cecf3657f7 GtkBox: Add missing Since in docs 2013-03-27 09:40:09 +01:00
Alexander Larsson
d1795a536b GtkGrid: Add missing Since docs 2013-03-27 09:39:44 +01:00
Alexander Larsson
280a94506c Add tests/testbaseline 2013-03-26 16:29:14 +01:00
Alexander Larsson
4ad55c3488 GtkDialog: Baseline align buttons in action area 2013-03-26 16:29:14 +01:00
Alexander Larsson
edcf32323f GtkEventBox: Support baseline alignment
This allows baselines to propagate from the child of the eventbox.
2013-03-26 16:29:14 +01:00
Alexander Larsson
115155ff52 GtkButtonBox: Support baseline alignment 2013-03-26 16:29:14 +01:00
Alexander Larsson
b8f1f78e4a GtkCheckButton and GtkRadioButton: Implement baseline alignment 2013-03-26 16:29:01 +01:00
Alexander Larsson
9ce05f75ff GtkSpinButton: Support baseline alignment 2013-03-26 16:27:44 +01:00
Alexander Larsson
44fbf3eed1 GtkGrid: Support baseline alignment in GtkGrid
We support a local baseline in each row, as well as selecting
a specific row for the global baseline of the entire GtkGrid.
2013-03-26 16:26:59 +01:00
Alexander Larsson
a985b5a904 GtkEntry: Support baselines 2013-03-26 16:24:42 +01:00
Alexander Larsson
0f16dbed52 GtkButton: Add baseline align support 2013-03-26 16:24:37 +01:00
Alexander Larsson
f690eae695 GtkImage: Support baselines
This uses the current font metrics to guess the baseline of the image.
Without this any non-centered baseline in buttons with images look weird.
2013-03-26 16:24:36 +01:00
Alexander Larsson
21a265f16e GtkAlignment: Support baselines
We now report any baselines from the child, and allocate it.
Also, in the case of a baselign aligned child we ignore yscale/yalign
as that is not supportable.
2013-03-26 16:24:36 +01:00
Alexander Larsson
794d68f47a GtkBox: Add baseline alignment for horizontal boxes
Report a baseline based height and baseline whenever there
are children with ALIGN_BASELINE.

Assign baseline to childen in size_allocate. Either the one inherited
from the parent if set, or otherwise calculate one based on any
ALIGN_BASELINE children.
2013-03-26 16:24:28 +01:00
Alexander Larsson
b2d80f9183 GtkLabel: Support baseline
Report the baseline in get_preferred_height_and_baseline_for_width().
2013-03-26 16:24:27 +01:00
Alexander Larsson
5cb27b3abf GtkSizeRequestCache: Don't store baselines in horizontal case
This saves memory for every widget (maximum 48 bytes per widget) at
a cost of a few duplicated codepaths in the size request cache.
2013-03-26 16:24:27 +01:00
Alexander Larsson
eda436a4be Add GTK_DEBUG=baselines support
This draws red lines to show where the baselines are
2013-03-26 16:24:27 +01:00
Alexander Larsson
28b77076a8 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.
2013-03-26 16:23:55 +01:00
Alexander Larsson
f7361c6eb9 Add GTK_ALIGN_BASELINE to GtkAlign
Setting this means baseline aware containers should align the widget
according to the baseline. For other containers this behaves like
FILL.

In order to not suprise old code with a new enum value we always
return _FILL for _BASELINE unless you specifically request it via
gtk_widget_get_valign_with_baseline().
2013-03-26 16:23:46 +01:00
30 changed files with 2838 additions and 430 deletions

View File

@@ -486,6 +486,8 @@ gtk_box_set_spacing
gtk_box_reorder_child gtk_box_reorder_child
gtk_box_query_child_packing gtk_box_query_child_packing
gtk_box_set_child_packing gtk_box_set_child_packing
gtk_box_get_baseline_position
gtk_box_set_baseline_position
<SUBSECTION Standard> <SUBSECTION Standard>
GTK_BOX GTK_BOX
GTK_IS_BOX GTK_IS_BOX
@@ -5159,6 +5161,7 @@ gtk_widget_remove_tick_callback
gtk_widget_size_request gtk_widget_size_request
gtk_widget_get_child_requisition gtk_widget_get_child_requisition
gtk_widget_size_allocate gtk_widget_size_allocate
gtk_widget_size_allocate_with_baseline
gtk_widget_add_accelerator gtk_widget_add_accelerator
gtk_widget_remove_accelerator gtk_widget_remove_accelerator
gtk_widget_set_accel_path gtk_widget_set_accel_path
@@ -5291,6 +5294,7 @@ gtk_widget_get_allocated_width
gtk_widget_get_allocated_height gtk_widget_get_allocated_height
gtk_widget_get_allocation gtk_widget_get_allocation
gtk_widget_set_allocation gtk_widget_set_allocation
gtk_widget_get_allocated_baseline
gtk_widget_get_app_paintable gtk_widget_get_app_paintable
gtk_widget_get_can_default gtk_widget_get_can_default
gtk_widget_set_can_default gtk_widget_set_can_default
@@ -5351,8 +5355,10 @@ gtk_widget_get_preferred_height
gtk_widget_get_preferred_width gtk_widget_get_preferred_width
gtk_widget_get_preferred_height_for_width gtk_widget_get_preferred_height_for_width
gtk_widget_get_preferred_width_for_height gtk_widget_get_preferred_width_for_height
gtk_widget_get_preferred_height_and_baseline_for_width
gtk_widget_get_request_mode gtk_widget_get_request_mode
gtk_widget_get_preferred_size gtk_widget_get_preferred_size
gtk_widget_get_preferred_size_and_baseline
gtk_distribute_natural_allocation gtk_distribute_natural_allocation
<SUBSECTION Alignment and Margins> <SUBSECTION Alignment and Margins>
@@ -5360,6 +5366,7 @@ GtkAlign
gtk_widget_get_halign gtk_widget_get_halign
gtk_widget_set_halign gtk_widget_set_halign
gtk_widget_get_valign gtk_widget_get_valign
gtk_widget_get_valign_with_baseline
gtk_widget_set_valign gtk_widget_set_valign
gtk_widget_get_margin_left gtk_widget_get_margin_left
gtk_widget_set_margin_left gtk_widget_set_margin_left
@@ -7249,6 +7256,10 @@ gtk_grid_set_column_homogeneous
gtk_grid_get_column_homogeneous gtk_grid_get_column_homogeneous
gtk_grid_set_column_spacing gtk_grid_set_column_spacing
gtk_grid_get_column_spacing gtk_grid_get_column_spacing
gtk_grid_get_baseline_row
gtk_grid_set_baseline_row
gtk_grid_get_row_baseline_position
gtk_grid_set_row_baseline_position
<SUBSECTION Standard> <SUBSECTION Standard>
GtkGridClass GtkGridClass

View File

@@ -288,6 +288,7 @@ gtk_assistant_set_page_title
gtk_assistant_set_page_type gtk_assistant_set_page_type
gtk_assistant_update_buttons_state gtk_assistant_update_buttons_state
gtk_attach_options_get_type gtk_attach_options_get_type
gtk_baseline_position_get_type
gtk_binding_entry_add_signal gtk_binding_entry_add_signal
gtk_binding_entry_add_signall gtk_binding_entry_add_signall
gtk_binding_entry_add_signal_from_string gtk_binding_entry_add_signal_from_string
@@ -308,6 +309,7 @@ gtk_border_free
gtk_border_get_type gtk_border_get_type
gtk_border_new gtk_border_new
gtk_border_style_get_type gtk_border_style_get_type
gtk_box_get_baseline_position
gtk_box_get_homogeneous gtk_box_get_homogeneous
gtk_box_get_spacing gtk_box_get_spacing
gtk_box_get_type gtk_box_get_type
@@ -316,6 +318,7 @@ gtk_box_pack_end
gtk_box_pack_start gtk_box_pack_start
gtk_box_query_child_packing gtk_box_query_child_packing
gtk_box_reorder_child gtk_box_reorder_child
gtk_box_set_baseline_position
gtk_box_set_child_packing gtk_box_set_child_packing
gtk_box_set_homogeneous gtk_box_set_homogeneous
gtk_box_set_spacing gtk_box_set_spacing
@@ -1195,9 +1198,11 @@ gtk_grab_get_current
gtk_grab_remove gtk_grab_remove
gtk_grid_attach gtk_grid_attach
gtk_grid_attach_next_to gtk_grid_attach_next_to
gtk_grid_get_baseline_row
gtk_grid_get_child_at gtk_grid_get_child_at
gtk_grid_get_column_homogeneous gtk_grid_get_column_homogeneous
gtk_grid_get_column_spacing gtk_grid_get_column_spacing
gtk_grid_get_row_baseline_position
gtk_grid_get_row_homogeneous gtk_grid_get_row_homogeneous
gtk_grid_get_row_spacing gtk_grid_get_row_spacing
gtk_grid_get_type gtk_grid_get_type
@@ -1207,8 +1212,10 @@ gtk_grid_insert_row
gtk_grid_new gtk_grid_new
gtk_grid_remove_column gtk_grid_remove_column
gtk_grid_remove_row gtk_grid_remove_row
gtk_grid_set_baseline_row
gtk_grid_set_column_homogeneous gtk_grid_set_column_homogeneous
gtk_grid_set_column_spacing gtk_grid_set_column_spacing
gtk_grid_set_row_baseline_position
gtk_grid_set_row_homogeneous gtk_grid_set_row_homogeneous
gtk_grid_set_row_spacing gtk_grid_set_row_spacing
gtk_handle_box_get_child_detached gtk_handle_box_get_child_detached
@@ -3707,6 +3714,7 @@ gtk_widget_error_bell
gtk_widget_event gtk_widget_event
gtk_widget_freeze_child_notify gtk_widget_freeze_child_notify
gtk_widget_get_accessible gtk_widget_get_accessible
gtk_widget_get_allocated_baseline
gtk_widget_get_allocated_height gtk_widget_get_allocated_height
gtk_widget_get_allocated_width gtk_widget_get_allocated_width
gtk_widget_get_allocation gtk_widget_get_allocation
@@ -3748,8 +3756,10 @@ gtk_widget_get_parent_window
gtk_widget_get_path gtk_widget_get_path
gtk_widget_get_pointer gtk_widget_get_pointer
gtk_widget_get_preferred_height gtk_widget_get_preferred_height
gtk_widget_get_preferred_height_and_baseline_for_width
gtk_widget_get_preferred_height_for_width gtk_widget_get_preferred_height_for_width
gtk_widget_get_preferred_size gtk_widget_get_preferred_size
gtk_widget_get_preferred_size_and_baseline
gtk_widget_get_preferred_width gtk_widget_get_preferred_width
gtk_widget_get_preferred_width_for_height gtk_widget_get_preferred_width_for_height
gtk_widget_get_realized gtk_widget_get_realized
@@ -3772,6 +3782,7 @@ gtk_widget_get_tooltip_window
gtk_widget_get_toplevel gtk_widget_get_toplevel
gtk_widget_get_type gtk_widget_get_type
gtk_widget_get_valign gtk_widget_get_valign
gtk_widget_get_valign_with_baseline
gtk_widget_get_vexpand gtk_widget_get_vexpand
gtk_widget_get_vexpand_set gtk_widget_get_vexpand_set
gtk_widget_get_visible gtk_widget_get_visible
@@ -3924,6 +3935,7 @@ gtk_widget_show
gtk_widget_show_all gtk_widget_show_all
gtk_widget_show_now gtk_widget_show_now
gtk_widget_size_allocate gtk_widget_size_allocate
gtk_widget_size_allocate_with_baseline
gtk_widget_size_request gtk_widget_size_request
gtk_widget_style_attach gtk_widget_style_attach
gtk_widget_style_get gtk_widget_style_get

View File

@@ -108,6 +108,12 @@ static void gtk_alignment_get_preferred_height_for_width (GtkWidget *w
gint for_size, gint for_size,
gint *minimum_size, gint *minimum_size,
gint *natural_size); gint *natural_size);
static void gtk_alignment_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint for_size,
gint *minimum_size,
gint *natural_size,
gint *minimum_baseline,
gint *natural_baseline);
G_DEFINE_TYPE (GtkAlignment, gtk_alignment, GTK_TYPE_BIN) G_DEFINE_TYPE (GtkAlignment, gtk_alignment, GTK_TYPE_BIN)
@@ -128,6 +134,7 @@ gtk_alignment_class_init (GtkAlignmentClass *class)
widget_class->get_preferred_height = gtk_alignment_get_preferred_height; widget_class->get_preferred_height = gtk_alignment_get_preferred_height;
widget_class->get_preferred_width_for_height = gtk_alignment_get_preferred_width_for_height; widget_class->get_preferred_width_for_height = gtk_alignment_get_preferred_width_for_height;
widget_class->get_preferred_height_for_width = gtk_alignment_get_preferred_height_for_width; widget_class->get_preferred_height_for_width = gtk_alignment_get_preferred_height_for_width;
widget_class->get_preferred_height_and_baseline_for_width = gtk_alignment_get_preferred_height_and_baseline_for_width;
g_object_class_install_property (gobject_class, g_object_class_install_property (gobject_class,
PROP_XALIGN, PROP_XALIGN,
@@ -507,6 +514,7 @@ gtk_alignment_size_allocate (GtkWidget *widget,
gint width, height; gint width, height;
guint border_width; guint border_width;
gint padding_horizontal, padding_vertical; gint padding_horizontal, padding_vertical;
gint baseline;
padding_horizontal = 0; padding_horizontal = 0;
padding_vertical = 0; padding_vertical = 0;
@@ -520,6 +528,7 @@ gtk_alignment_size_allocate (GtkWidget *widget,
gint child_nat_width; gint child_nat_width;
gint child_nat_height; gint child_nat_height;
gint child_width, child_height; gint child_width, child_height;
double yalign, yscale;
border_width = gtk_container_get_border_width (GTK_CONTAINER (alignment)); border_width = gtk_container_get_border_width (GTK_CONTAINER (alignment));
@@ -529,6 +538,25 @@ gtk_alignment_size_allocate (GtkWidget *widget,
width = MAX (1, allocation->width - padding_horizontal - 2 * border_width); width = MAX (1, allocation->width - padding_horizontal - 2 * border_width);
height = MAX (1, allocation->height - padding_vertical - 2 * border_width); height = MAX (1, allocation->height - padding_vertical - 2 * border_width);
baseline = gtk_widget_get_allocated_baseline (widget);
if (baseline != -1)
baseline -= border_width + priv->padding_top;
/* If we get a baseline set that means we're baseline aligned, and the parent
honored that. In that case we have to ignore yalign/yscale as we need
yalign based on the baseline and always FILL mode to ensure we can place
the baseline anywhere */
if (baseline != -1)
{
yalign = 0;
yscale = 1.0;
}
else
{
yalign = priv->yalign;
yscale = priv->yscale;
}
if (gtk_widget_get_request_mode (child) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH) if (gtk_widget_get_request_mode (child) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
{ {
gtk_widget_get_preferred_width (child, NULL, &child_nat_width); gtk_widget_get_preferred_width (child, NULL, &child_nat_width);
@@ -559,8 +587,8 @@ gtk_alignment_size_allocate (GtkWidget *widget,
if (height > child_height) if (height > child_height)
child_allocation.height = (child_height * child_allocation.height = (child_height *
(1.0 - priv->yscale) + (1.0 - yscale) +
height * priv->yscale); height * yscale);
else else
child_allocation.height = height; child_allocation.height = height;
@@ -569,9 +597,9 @@ gtk_alignment_size_allocate (GtkWidget *widget,
else else
child_allocation.x = priv->xalign * (width - child_allocation.width) + allocation->x + border_width + priv->padding_left; child_allocation.x = priv->xalign * (width - child_allocation.width) + allocation->x + border_width + priv->padding_left;
child_allocation.y = priv->yalign * (height - child_allocation.height) + allocation->y + border_width + priv->padding_top; child_allocation.y = yalign * (height - child_allocation.height) + allocation->y + border_width + priv->padding_top;
gtk_widget_size_allocate (child, &child_allocation); gtk_widget_size_allocate_with_baseline (child, &child_allocation, baseline);
} }
} }
@@ -581,18 +609,30 @@ gtk_alignment_get_preferred_size (GtkWidget *widget,
GtkOrientation orientation, GtkOrientation orientation,
gint for_size, gint for_size,
gint *minimum_size, gint *minimum_size,
gint *natural_size) gint *natural_size,
gint *minimum_baseline,
gint *natural_baseline)
{ {
GtkAlignment *alignment = GTK_ALIGNMENT (widget); GtkAlignment *alignment = GTK_ALIGNMENT (widget);
GtkAlignmentPrivate *priv = alignment->priv; GtkAlignmentPrivate *priv = alignment->priv;
GtkWidget *child; GtkWidget *child;
guint minimum, natural; guint minimum, natural;
guint top_offset;
guint border;
natural = minimum = gtk_container_get_border_width (GTK_CONTAINER (widget)) * 2; if (minimum_baseline)
*minimum_baseline = -1;
if (natural_baseline)
*natural_baseline = -1;
border = gtk_container_get_border_width (GTK_CONTAINER (widget));
natural = minimum = border * 2;
top_offset = border;
if ((child = gtk_bin_get_child (GTK_BIN (widget))) && gtk_widget_get_visible (child)) if ((child = gtk_bin_get_child (GTK_BIN (widget))) && gtk_widget_get_visible (child))
{ {
gint child_min, child_nat; gint child_min, child_nat;
gint child_min_baseline = -1, child_nat_baseline = -1;
/* Request extra space for the padding: */ /* Request extra space for the padding: */
if (orientation == GTK_ORIENTATION_HORIZONTAL) if (orientation == GTK_ORIENTATION_HORIZONTAL)
@@ -619,9 +659,10 @@ gtk_alignment_get_preferred_size (GtkWidget *widget,
else else
{ {
minimum += (priv->padding_top + priv->padding_bottom); minimum += (priv->padding_top + priv->padding_bottom);
top_offset += priv->padding_top;
if (for_size < 0) if (for_size < 0)
gtk_widget_get_preferred_height (child, &child_min, &child_nat); gtk_widget_get_preferred_height_and_baseline_for_width (child, -1, &child_min, &child_nat, &child_min_baseline, &child_nat_baseline);
else else
{ {
gint min_width; gint min_width;
@@ -634,8 +675,13 @@ gtk_alignment_get_preferred_size (GtkWidget *widget,
for_size = (min_width * (1.0 - priv->xscale) + for_size = (min_width * (1.0 - priv->xscale) +
for_size * priv->xscale); for_size * priv->xscale);
gtk_widget_get_preferred_height_for_width (child, for_size, &child_min, &child_nat); gtk_widget_get_preferred_height_and_baseline_for_width (child, for_size, &child_min, &child_nat, &child_min_baseline, &child_nat_baseline);
} }
if (minimum_baseline && child_min_baseline >= 0)
*minimum_baseline = child_min_baseline + top_offset;
if (natural_baseline && child_nat_baseline >= 0)
*natural_baseline = child_nat_baseline + top_offset;
} }
natural = minimum; natural = minimum;
@@ -656,7 +702,7 @@ gtk_alignment_get_preferred_width (GtkWidget *widget,
gint *minimum_size, gint *minimum_size,
gint *natural_size) gint *natural_size)
{ {
gtk_alignment_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, -1, minimum_size, natural_size); gtk_alignment_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, -1, minimum_size, natural_size, NULL, NULL);
} }
static void static void
@@ -664,7 +710,7 @@ gtk_alignment_get_preferred_height (GtkWidget *widget,
gint *minimum_size, gint *minimum_size,
gint *natural_size) gint *natural_size)
{ {
gtk_alignment_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, -1, minimum_size, natural_size); gtk_alignment_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, -1, minimum_size, natural_size, NULL, NULL);
} }
@@ -674,7 +720,7 @@ gtk_alignment_get_preferred_width_for_height (GtkWidget *widget,
gint *minimum_size, gint *minimum_size,
gint *natural_size) gint *natural_size)
{ {
gtk_alignment_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, for_size, minimum_size, natural_size); gtk_alignment_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, for_size, minimum_size, natural_size, NULL, NULL);
} }
static void static void
@@ -683,9 +729,21 @@ gtk_alignment_get_preferred_height_for_width (GtkWidget *widget,
gint *minimum_size, gint *minimum_size,
gint *natural_size) gint *natural_size)
{ {
gtk_alignment_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, for_size, minimum_size, natural_size); gtk_alignment_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, for_size, minimum_size, natural_size, NULL, NULL);
} }
static void
gtk_alignment_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint for_size,
gint *minimum_size,
gint *natural_size,
gint *minimum_baseline,
gint *natural_baseline)
{
gtk_alignment_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, for_size, minimum_size, natural_size, minimum_baseline, natural_baseline);
}
/** /**
* gtk_alignment_set_padding: * gtk_alignment_set_padding:
* @alignment: a #GtkAlignment * @alignment: a #GtkAlignment

View File

@@ -101,6 +101,12 @@ static void gtk_button_box_get_preferred_height_for_width (GtkWidget *widget,
gint width, gint width,
gint *minimum, gint *minimum,
gint *natural); gint *natural);
static void gtk_button_box_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint width,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline);
static void gtk_button_box_size_allocate (GtkWidget *widget, static void gtk_button_box_size_allocate (GtkWidget *widget,
GtkAllocation *allocation); GtkAllocation *allocation);
@@ -143,6 +149,7 @@ gtk_button_box_class_init (GtkButtonBoxClass *class)
widget_class->get_preferred_height = gtk_button_box_get_preferred_height; widget_class->get_preferred_height = gtk_button_box_get_preferred_height;
widget_class->get_preferred_width_for_height = gtk_button_box_get_preferred_width_for_height; widget_class->get_preferred_width_for_height = gtk_button_box_get_preferred_width_for_height;
widget_class->get_preferred_height_for_width = gtk_button_box_get_preferred_height_for_width; widget_class->get_preferred_height_for_width = gtk_button_box_get_preferred_height_for_width;
widget_class->get_preferred_height_and_baseline_for_width = gtk_button_box_get_preferred_height_and_baseline_for_width;
widget_class->size_allocate = gtk_button_box_size_allocate; widget_class->size_allocate = gtk_button_box_size_allocate;
container_class->remove = gtk_button_box_remove; container_class->remove = gtk_button_box_remove;
@@ -438,7 +445,10 @@ gtk_button_box_child_requisition (GtkWidget *widget,
gint *nvis_children, gint *nvis_children,
gint *nvis_secondaries, gint *nvis_secondaries,
gint **widths, gint **widths,
gint **heights) gint **heights,
gint **baselines,
gint *baseline,
gint *baseline_height)
{ {
GtkButtonBox *bbox; GtkButtonBox *bbox;
GList *children, *list; GList *children, *list;
@@ -446,6 +456,7 @@ gtk_button_box_child_requisition (GtkWidget *widget,
gint nsecondaries; gint nsecondaries;
gint needed_width; gint needed_width;
gint needed_height; gint needed_height;
gint needed_above, needed_below;
gint avg_w, avg_h; gint avg_w, avg_h;
GtkRequisition child_requisition; GtkRequisition child_requisition;
gint ipad_w; gint ipad_w;
@@ -456,11 +467,15 @@ gtk_button_box_child_requisition (GtkWidget *widget,
gint ipad_y; gint ipad_y;
gboolean homogeneous; gboolean homogeneous;
gint i; gint i;
gint max_above, max_below, child_baseline;
GtkOrientation orientation;
gboolean have_baseline;
g_return_if_fail (GTK_IS_BUTTON_BOX (widget)); g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
bbox = GTK_BUTTON_BOX (widget); bbox = GTK_BUTTON_BOX (widget);
orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (widget));
homogeneous = gtk_box_get_homogeneous (GTK_BOX (widget)); homogeneous = gtk_box_get_homogeneous (GTK_BOX (widget));
gtk_widget_style_get (widget, gtk_widget_style_get (widget,
@@ -475,22 +490,33 @@ gtk_button_box_child_requisition (GtkWidget *widget,
list = children = _gtk_box_get_children (GTK_BOX (bbox)); list = children = _gtk_box_get_children (GTK_BOX (bbox));
needed_width = child_min_width; needed_width = child_min_width;
needed_height = child_min_height; needed_height = child_min_height;
needed_above = 0;
needed_below = 0;
ipad_w = ipad_x * 2; ipad_w = ipad_x * 2;
ipad_h = ipad_y * 2; ipad_h = ipad_y * 2;
have_baseline = FALSE;
max_above = max_below = 0;
avg_w = avg_h = 0; avg_w = avg_h = 0;
while (children) for (children = list; children != NULL; children = children->next)
{ {
GtkWidget *child; GtkWidget *child;
child = children->data; child = children->data;
children = children->next;
if (gtk_widget_get_visible (child)) if (gtk_widget_get_visible (child))
{ {
nchildren += 1; nchildren += 1;
gtk_widget_get_preferred_size (child, gtk_widget_get_preferred_size_and_baseline (child,
&child_requisition, NULL); &child_requisition, NULL, &child_baseline, NULL);
if (orientation == GTK_ORIENTATION_HORIZONTAL &&
gtk_widget_get_valign_with_baseline (child) == GTK_ALIGN_BASELINE &&
child_baseline != -1)
{
have_baseline = TRUE;
max_above = MAX (max_above, child_baseline + ipad_y);
max_below = MAX (max_below , child_requisition.height + ipad_h - (child_baseline + ipad_y));
}
avg_w += child_requisition.width + ipad_w; avg_w += child_requisition.width + ipad_w;
avg_h += child_requisition.height + ipad_h; avg_h += child_requisition.height + ipad_h;
} }
@@ -498,8 +524,14 @@ gtk_button_box_child_requisition (GtkWidget *widget,
avg_w /= MAX (nchildren, 1); avg_w /= MAX (nchildren, 1);
avg_h /= MAX (nchildren, 1); avg_h /= MAX (nchildren, 1);
if (baseline)
*baseline = have_baseline ? max_above : -1;
if (baseline_height)
*baseline_height = max_above + max_below;
*widths = g_new (gint, nchildren); *widths = g_new (gint, nchildren);
*heights = g_new (gint, nchildren); *heights = g_new (gint, nchildren);
*baselines = g_new (gint, nchildren);
i = 0; i = 0;
children = list; children = list;
@@ -520,7 +552,8 @@ gtk_button_box_child_requisition (GtkWidget *widget,
if (is_secondary) if (is_secondary)
nsecondaries++; nsecondaries++;
gtk_widget_get_preferred_size (child, &child_requisition, NULL); gtk_widget_get_preferred_size_and_baseline (child,
&child_requisition, NULL, &child_baseline, NULL);
if (homogeneous || if (homogeneous ||
(!non_homogeneous && (child_requisition.width + ipad_w < avg_w * 1.5))) (!non_homogeneous && (child_requisition.width + ipad_w < avg_w * 1.5)))
@@ -534,16 +567,38 @@ gtk_button_box_child_requisition (GtkWidget *widget,
(*widths)[i] = child_requisition.width + ipad_w; (*widths)[i] = child_requisition.width + ipad_w;
} }
(*baselines)[i] = -1;
if (homogeneous || if (homogeneous ||
(!non_homogeneous && (child_requisition.height + ipad_h < avg_h * 1.5))) (!non_homogeneous && (child_requisition.height + ipad_h < avg_h * 1.5)))
{ {
(*heights)[i] = -1; (*heights)[i] = -1;
if (child_requisition.height + ipad_h > needed_height)
needed_height = child_requisition.height + ipad_h; if (orientation == GTK_ORIENTATION_HORIZONTAL &&
gtk_widget_get_valign_with_baseline (child) == GTK_ALIGN_BASELINE &&
child_baseline != -1)
{
(*baselines)[i] = child_baseline + ipad_y;
if (child_baseline + ipad_y > needed_above)
needed_above = child_baseline + ipad_y;
if (child_requisition.height - child_baseline + ipad_y > needed_below)
needed_below = child_requisition.height - child_baseline + ipad_y;
}
else
{
if (child_requisition.height + ipad_h > needed_height)
needed_height = child_requisition.height + ipad_h;
}
} }
else else
{ {
(*heights)[i] = child_requisition.height + ipad_h; (*heights)[i] = child_requisition.height + ipad_h;
if (orientation == GTK_ORIENTATION_HORIZONTAL &&
gtk_widget_get_valign_with_baseline (child) == GTK_ALIGN_BASELINE &&
child_baseline != -1)
(*baselines)[i] = child_baseline + ipad_y;
} }
i++; i++;
@@ -552,12 +607,18 @@ gtk_button_box_child_requisition (GtkWidget *widget,
g_list_free (list); g_list_free (list);
needed_height = MAX (needed_height, needed_above + needed_below);
for (i = 0; i < nchildren; i++) for (i = 0; i < nchildren; i++)
{ {
if ((*widths)[i] == -1) if ((*widths)[i] == -1)
(*widths)[i] = needed_width; (*widths)[i] = needed_width;
if ((*heights)[i] == -1) if ((*heights)[i] == -1)
(*heights)[i] = needed_height; {
(*heights)[i] = needed_height;
if ((*baselines)[i] != -1)
(*baselines)[i] = needed_above;
}
} }
if (nvis_children) if (nvis_children)
@@ -569,19 +630,24 @@ gtk_button_box_child_requisition (GtkWidget *widget,
static void static void
gtk_button_box_size_request (GtkWidget *widget, gtk_button_box_size_request (GtkWidget *widget,
GtkRequisition *requisition) GtkRequisition *requisition,
gint *baseline)
{ {
GtkButtonBoxPrivate *priv; GtkButtonBoxPrivate *priv;
GtkButtonBox *bbox; GtkButtonBox *bbox;
gint nvis_children; gint nvis_children;
gint max_size; gint max_size, max_above, max_below;
gint total_size; gint total_size;
gint spacing; gint spacing;
GtkOrientation orientation; GtkOrientation orientation;
gint *widths; gint *widths;
gint *heights; gint *heights;
gint *baselines;
gint i; gint i;
if (baseline)
*baseline = -1;
bbox = GTK_BUTTON_BOX (widget); bbox = GTK_BUTTON_BOX (widget);
priv = bbox->priv; priv = bbox->priv;
@@ -591,16 +657,22 @@ gtk_button_box_size_request (GtkWidget *widget,
gtk_button_box_child_requisition (widget, gtk_button_box_child_requisition (widget,
&nvis_children, &nvis_children,
NULL, NULL,
&widths, &heights); &widths, &heights, &baselines, baseline, NULL);
max_size = 0; max_size = max_above = max_below = 0;
total_size = 0; total_size = 0;
for (i = 0; i < nvis_children; i++) for (i = 0; i < nvis_children; i++)
{ {
if (orientation == GTK_ORIENTATION_HORIZONTAL) if (orientation == GTK_ORIENTATION_HORIZONTAL)
{ {
total_size += widths[i]; total_size += widths[i];
max_size = MAX (max_size, heights[i]); if (baselines[i] == -1)
max_size = MAX (max_size, heights[i]);
else
{
max_above = MAX (max_above, baselines[i]);
max_below = MAX (max_below, heights[i] - baselines[i]);
}
} }
else else
{ {
@@ -610,6 +682,23 @@ gtk_button_box_size_request (GtkWidget *widget,
} }
g_free (widths); g_free (widths);
g_free (heights); g_free (heights);
g_free (baselines);
max_size = MAX (max_size, max_above + max_below);
switch (gtk_box_get_baseline_position (GTK_BOX (widget)))
{
case GTK_BASELINE_POSITION_TOP:
break;
case GTK_BASELINE_POSITION_CENTER:
if (baseline != NULL && *baseline != -1)
*baseline += (max_size - (max_above + max_below)) / 2;
break;
case GTK_BASELINE_POSITION_BOTTOM:
if (baseline != NULL && *baseline != -1)
*baseline += max_size - (max_above + max_below);
break;
}
if (nvis_children == 0) if (nvis_children == 0)
{ {
@@ -656,7 +745,7 @@ gtk_button_box_get_preferred_width (GtkWidget *widget,
{ {
GtkRequisition requisition; GtkRequisition requisition;
gtk_button_box_size_request (widget, &requisition); gtk_button_box_size_request (widget, &requisition, NULL);
*minimum = *natural = requisition.width; *minimum = *natural = requisition.width;
} }
@@ -666,11 +755,9 @@ gtk_button_box_get_preferred_height (GtkWidget *widget,
gint *minimum, gint *minimum,
gint *natural) gint *natural)
{ {
GtkRequisition requisition; gtk_button_box_get_preferred_height_and_baseline_for_width (widget, -1,
minimum, natural,
gtk_button_box_size_request (widget, &requisition); NULL, NULL);
*minimum = *natural = requisition.height;
} }
static void static void
@@ -691,6 +778,26 @@ gtk_button_box_get_preferred_height_for_width (GtkWidget *widget,
gtk_button_box_get_preferred_height (widget, minimum, natural); gtk_button_box_get_preferred_height (widget, minimum, natural);
} }
static void
gtk_button_box_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint width,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{
GtkRequisition requisition;
gint baseline;
gtk_button_box_size_request (widget, &requisition, &baseline);
*minimum = *natural = requisition.height;
if (minimum_baseline)
*minimum_baseline = baseline;
if (natural_baseline)
*natural_baseline = baseline;
}
static void static void
gtk_button_box_size_allocate (GtkWidget *widget, gtk_button_box_size_allocate (GtkWidget *widget,
GtkAllocation *allocation) GtkAllocation *allocation)
@@ -714,10 +821,13 @@ gtk_button_box_size_allocate (GtkWidget *widget,
gint ipad_x, ipad_y; gint ipad_x, ipad_y;
gint *widths; gint *widths;
gint *heights; gint *heights;
gint *baselines;
gint *sizes; gint *sizes;
gint primary_size; gint primary_size;
gint secondary_size; gint secondary_size;
gint total_size; gint total_size;
gint baseline, baseline_height;
gint child_baseline, allocated_baseline;
gint i; gint i;
bbox = GTK_BUTTON_BOX (widget); bbox = GTK_BUTTON_BOX (widget);
@@ -733,7 +843,27 @@ gtk_button_box_size_allocate (GtkWidget *widget,
gtk_button_box_child_requisition (widget, gtk_button_box_child_requisition (widget,
&nvis_children, &nvis_children,
&n_secondaries, &n_secondaries,
&widths, &heights); &widths, &heights, &baselines, &baseline, &baseline_height);
allocated_baseline = gtk_widget_get_allocated_baseline (widget);
if (allocated_baseline != -1)
baseline = allocated_baseline;
else if (baseline != -1)
{
/* TODO: modify baseline based on baseline_pos && allocated_baseline*/
switch (gtk_box_get_baseline_position (GTK_BOX (widget)))
{
case GTK_BASELINE_POSITION_TOP:
baseline = baseline;
break;
case GTK_BASELINE_POSITION_CENTER:
baseline = baseline + (allocation->height - baseline_height) / 2;
break;
case GTK_BASELINE_POSITION_BOTTOM:
baseline = allocation->height - (baseline_height - baseline);
break;
}
}
n_primaries = nvis_children - n_secondaries; n_primaries = nvis_children - n_secondaries;
primary_size = 0; primary_size = 0;
@@ -917,10 +1047,17 @@ gtk_button_box_size_allocate (GtkWidget *widget,
{ {
child_allocation.width = widths[i]; child_allocation.width = widths[i];
child_allocation.height = heights[i]; child_allocation.height = heights[i];
child_baseline = -1;
if (orientation == GTK_ORIENTATION_HORIZONTAL) if (orientation == GTK_ORIENTATION_HORIZONTAL)
{ {
child_allocation.y = allocation->y + (allocation->height - child_allocation.height) / 2; if (baselines[i] != -1)
{
child_allocation.y = allocation->y + baseline - baselines[i];
child_baseline = baselines[i];
}
else
child_allocation.y = allocation->y + (allocation->height - child_allocation.height) / 2;
if (gtk_button_box_get_child_secondary (bbox, child)) if (gtk_button_box_get_child_secondary (bbox, child))
{ {
@@ -953,7 +1090,7 @@ gtk_button_box_size_allocate (GtkWidget *widget,
} }
} }
gtk_widget_size_allocate (child, &child_allocation); gtk_widget_size_allocate_with_baseline (child, &child_allocation, child_baseline);
i++; i++;
} }
} }
@@ -961,6 +1098,7 @@ gtk_button_box_size_allocate (GtkWidget *widget,
g_list_free (list); g_list_free (list);
g_free (widths); g_free (widths);
g_free (heights); g_free (heights);
g_free (baselines);
} }
/** /**

View File

@@ -94,7 +94,8 @@ enum {
PROP_0, PROP_0,
PROP_ORIENTATION, PROP_ORIENTATION,
PROP_SPACING, PROP_SPACING,
PROP_HOMOGENEOUS PROP_HOMOGENEOUS,
PROP_BASELINE_POSITION
}; };
enum { enum {
@@ -116,6 +117,7 @@ struct _GtkBoxPrivate
guint default_expand : 1; guint default_expand : 1;
guint homogeneous : 1; guint homogeneous : 1;
guint spacing_set : 1; guint spacing_set : 1;
guint baseline_pos : 2;
}; };
typedef struct _GtkBoxChild GtkBoxChild; typedef struct _GtkBoxChild GtkBoxChild;
@@ -200,6 +202,12 @@ static void gtk_box_get_preferred_height_for_width (GtkWidget
gint width, gint width,
gint *minimum_height, gint *minimum_height,
gint *natural_height); gint *natural_height);
static void gtk_box_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint width,
gint *minimum_height,
gint *natural_height,
gint *minimum_baseline,
gint *natural_baseline);
G_DEFINE_TYPE_WITH_CODE (GtkBox, gtk_box, GTK_TYPE_CONTAINER, G_DEFINE_TYPE_WITH_CODE (GtkBox, gtk_box, GTK_TYPE_CONTAINER,
@@ -220,6 +228,7 @@ gtk_box_class_init (GtkBoxClass *class)
widget_class->get_preferred_width = gtk_box_get_preferred_width; widget_class->get_preferred_width = gtk_box_get_preferred_width;
widget_class->get_preferred_height = gtk_box_get_preferred_height; widget_class->get_preferred_height = gtk_box_get_preferred_height;
widget_class->get_preferred_height_for_width = gtk_box_get_preferred_height_for_width; widget_class->get_preferred_height_for_width = gtk_box_get_preferred_height_for_width;
widget_class->get_preferred_height_and_baseline_for_width = gtk_box_get_preferred_height_and_baseline_for_width;
widget_class->get_preferred_width_for_height = gtk_box_get_preferred_width_for_height; widget_class->get_preferred_width_for_height = gtk_box_get_preferred_width_for_height;
widget_class->compute_expand = gtk_box_compute_expand; widget_class->compute_expand = gtk_box_compute_expand;
widget_class->direction_changed = gtk_box_direction_changed; widget_class->direction_changed = gtk_box_direction_changed;
@@ -255,6 +264,15 @@ gtk_box_class_init (GtkBoxClass *class)
FALSE, FALSE,
GTK_PARAM_READWRITE)); GTK_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_BASELINE_POSITION,
g_param_spec_enum ("baseline-position",
P_("Baseline position"),
P_("The position of the baseline aligned widgets if extra space is availible"),
GTK_TYPE_BASELINE_POSITION,
GTK_BASELINE_POSITION_CENTER,
GTK_PARAM_READWRITE));
/** /**
* GtkBox:expand: * GtkBox:expand:
* *
@@ -340,6 +358,7 @@ gtk_box_init (GtkBox *box)
private->homogeneous = FALSE; private->homogeneous = FALSE;
private->spacing = 0; private->spacing = 0;
private->spacing_set = FALSE; private->spacing_set = FALSE;
private->baseline_pos = GTK_BASELINE_POSITION_CENTER;
} }
static void static void
@@ -361,6 +380,9 @@ gtk_box_set_property (GObject *object,
case PROP_SPACING: case PROP_SPACING:
gtk_box_set_spacing (box, g_value_get_int (value)); gtk_box_set_spacing (box, g_value_get_int (value));
break; break;
case PROP_BASELINE_POSITION:
gtk_box_set_baseline_position (box, g_value_get_enum (value));
break;
case PROP_HOMOGENEOUS: case PROP_HOMOGENEOUS:
gtk_box_set_homogeneous (box, g_value_get_boolean (value)); gtk_box_set_homogeneous (box, g_value_get_boolean (value));
break; break;
@@ -387,6 +409,9 @@ gtk_box_get_property (GObject *object,
case PROP_SPACING: case PROP_SPACING:
g_value_set_int (value, private->spacing); g_value_set_int (value, private->spacing);
break; break;
case PROP_BASELINE_POSITION:
g_value_set_enum (value, private->baseline_pos);
break;
case PROP_HOMOGENEOUS: case PROP_HOMOGENEOUS:
g_value_set_boolean (value, private->homogeneous); g_value_set_boolean (value, private->homogeneous);
break; break;
@@ -435,6 +460,11 @@ gtk_box_size_allocate (GtkWidget *widget,
GtkTextDirection direction; GtkTextDirection direction;
GtkAllocation child_allocation; GtkAllocation child_allocation;
GtkRequestedSize *sizes; GtkRequestedSize *sizes;
gint child_minimum_baseline, child_natural_baseline;
gint minimum_above, natural_above;
gint minimum_below, natural_below;
gboolean have_baseline;
gint baseline;
GtkPackType packing; GtkPackType packing;
@@ -461,6 +491,10 @@ gtk_box_size_allocate (GtkWidget *widget,
else else
size = allocation->height - (nvis_children - 1) * private->spacing; size = allocation->height - (nvis_children - 1) * private->spacing;
have_baseline = FALSE;
minimum_above = natural_above = 0;
minimum_below = natural_below = 0;
/* Retrieve desired size for visible children. */ /* Retrieve desired size for visible children. */
for (i = 0, children = private->children; children; children = children->next) for (i = 0, children = private->children; children; children = children->next)
{ {
@@ -475,11 +509,11 @@ gtk_box_size_allocate (GtkWidget *widget,
&sizes[i].minimum_size, &sizes[i].minimum_size,
&sizes[i].natural_size); &sizes[i].natural_size);
else else
gtk_widget_get_preferred_height_for_width (child->widget, gtk_widget_get_preferred_height_and_baseline_for_width (child->widget,
allocation->width, allocation->width,
&sizes[i].minimum_size, &sizes[i].minimum_size,
&sizes[i].natural_size); &sizes[i].natural_size,
NULL, NULL);
/* Assert the api is working properly */ /* Assert the api is working properly */
if (sizes[i].minimum_size < 0) if (sizes[i].minimum_size < 0)
@@ -537,28 +571,9 @@ gtk_box_size_allocate (GtkWidget *widget,
extra = 0; extra = 0;
} }
/* Allocate child positions. */ /* Allocate child sizes. */
for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing) for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing)
{ {
if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
{
child_allocation.y = allocation->y;
child_allocation.height = MAX (1, allocation->height);
if (packing == GTK_PACK_START)
x = allocation->x;
else
x = allocation->x + allocation->width;
}
else
{
child_allocation.x = allocation->x;
child_allocation.width = MAX (1, allocation->width);
if (packing == GTK_PACK_START)
y = allocation->y;
else
y = allocation->y + allocation->height;
}
for (i = 0, children = private->children; for (i = 0, children = private->children;
children; children;
children = children->next) children = children->next)
@@ -605,6 +620,105 @@ gtk_box_size_allocate (GtkWidget *widget,
} }
} }
sizes[i].natural_size = child_size;
if (private->orientation == GTK_ORIENTATION_HORIZONTAL &&
gtk_widget_get_valign_with_baseline (child->widget) == GTK_ALIGN_BASELINE)
{
int child_allocation_width;
int child_minimum_height, child_natural_height;
if (child->fill)
child_allocation_width = MAX (1, child_size - child->padding * 2);
else
child_allocation_width = sizes[i].minimum_size;
child_minimum_baseline = -1;
child_natural_baseline = -1;
gtk_widget_get_preferred_height_and_baseline_for_width (child->widget,
child_allocation_width,
&child_minimum_height, &child_natural_height,
&child_minimum_baseline, &child_natural_baseline);
if (child_minimum_baseline >= 0)
{
have_baseline = TRUE;
minimum_below = MAX (minimum_below, child_minimum_height - child_minimum_baseline);
natural_below = MAX (natural_below, child_natural_height - child_natural_baseline);
minimum_above = MAX (minimum_above, child_minimum_baseline);
natural_above = MAX (natural_above, child_natural_baseline);
}
}
i++;
}
}
baseline = gtk_widget_get_allocated_baseline (widget);
if (baseline == -1 && have_baseline)
{
gint height = MAX (1, allocation->height);
/* TODO: This is purely based on the minimum baseline, when things fit we should
use the natural one? */
switch (private->baseline_pos)
{
case GTK_BASELINE_POSITION_TOP:
baseline = minimum_above;
break;
case GTK_BASELINE_POSITION_CENTER:
baseline = minimum_above + (height - (minimum_above + minimum_below)) / 2;
break;
case GTK_BASELINE_POSITION_BOTTOM:
baseline = height - minimum_below;
break;
}
}
/* Allocate child positions. */
for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing)
{
if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
{
child_allocation.y = allocation->y;
child_allocation.height = MAX (1, allocation->height);
if (packing == GTK_PACK_START)
x = allocation->x;
else
x = allocation->x + allocation->width;
}
else
{
child_allocation.x = allocation->x;
child_allocation.width = MAX (1, allocation->width);
if (packing == GTK_PACK_START)
y = allocation->y;
else
y = allocation->y + allocation->height;
}
for (i = 0, children = private->children;
children;
children = children->next)
{
child = children->data;
/* If widget is not visible, skip it. */
if (!gtk_widget_get_visible (child->widget))
continue;
/* If widget is packed differently skip it, but still increment i,
* since widget is visible and will be handled in next loop iteration.
*/
if (child->pack != packing)
{
i++;
continue;
}
child_size = sizes[i].natural_size;
/* Assign the child's position. */ /* Assign the child's position. */
if (private->orientation == GTK_ORIENTATION_HORIZONTAL) if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
{ {
@@ -658,7 +772,7 @@ gtk_box_size_allocate (GtkWidget *widget,
child_allocation.y -= child_size; child_allocation.y -= child_size;
} }
} }
gtk_widget_size_allocate (child->widget, &child_allocation); gtk_widget_size_allocate_with_baseline (child->widget, &child_allocation, baseline);
i++; i++;
} }
@@ -1015,18 +1129,28 @@ static void
gtk_box_get_size (GtkWidget *widget, gtk_box_get_size (GtkWidget *widget,
GtkOrientation orientation, GtkOrientation orientation,
gint *minimum_size, gint *minimum_size,
gint *natural_size) gint *natural_size,
gint *minimum_baseline,
gint *natural_baseline)
{ {
GtkBox *box; GtkBox *box;
GtkBoxPrivate *private; GtkBoxPrivate *private;
GList *children; GList *children;
gint nvis_children; gint nvis_children;
gint minimum, natural; gint minimum, natural;
gint minimum_above, natural_above;
gint minimum_below, natural_below;
gboolean have_baseline;
gint min_baseline, nat_baseline;
box = GTK_BOX (widget); box = GTK_BOX (widget);
private = box->priv; private = box->priv;
have_baseline = FALSE;
minimum = natural = 0; minimum = natural = 0;
minimum_above = natural_above = 0;
minimum_below = natural_below = 0;
min_baseline = nat_baseline = -1;
nvis_children = 0; nvis_children = 0;
@@ -1037,13 +1161,15 @@ gtk_box_get_size (GtkWidget *widget,
if (gtk_widget_get_visible (child->widget)) if (gtk_widget_get_visible (child->widget))
{ {
gint child_minimum, child_natural; gint child_minimum, child_natural;
gint child_minimum_baseline = -1, child_natural_baseline = -1;
if (orientation == GTK_ORIENTATION_HORIZONTAL) if (orientation == GTK_ORIENTATION_HORIZONTAL)
gtk_widget_get_preferred_width (child->widget, gtk_widget_get_preferred_width (child->widget,
&child_minimum, &child_natural); &child_minimum, &child_natural);
else else
gtk_widget_get_preferred_height (child->widget, gtk_widget_get_preferred_height_and_baseline_for_width (child->widget, -1,
&child_minimum, &child_natural); &child_minimum, &child_natural,
&child_minimum_baseline, &child_natural_baseline);
if (private->orientation == orientation) if (private->orientation == orientation)
{ {
@@ -1065,9 +1191,20 @@ gtk_box_get_size (GtkWidget *widget,
} }
else else
{ {
/* The biggest mins and naturals in the opposing orientation */ if (child_minimum_baseline >= 0)
minimum = MAX (minimum, child_minimum); {
natural = MAX (natural, child_natural); have_baseline = TRUE;
minimum_below = MAX (minimum_below, child_minimum - child_minimum_baseline);
natural_below = MAX (natural_below, child_natural - child_natural_baseline);
minimum_above = MAX (minimum_above, child_minimum_baseline);
natural_above = MAX (natural_above, child_natural_baseline);
}
else
{
/* The biggest mins and naturals in the opposing orientation */
minimum = MAX (minimum, child_minimum);
natural = MAX (natural, child_natural);
}
} }
nvis_children += 1; nvis_children += 1;
@@ -1085,11 +1222,39 @@ gtk_box_get_size (GtkWidget *widget,
natural += (nvis_children - 1) * private->spacing; natural += (nvis_children - 1) * private->spacing;
} }
minimum = MAX (minimum, minimum_below + minimum_above);
natural = MAX (natural, natural_below + natural_above);
if (have_baseline)
{
switch (private->baseline_pos)
{
case GTK_BASELINE_POSITION_TOP:
min_baseline = minimum_above;
nat_baseline = natural_above;
break;
case GTK_BASELINE_POSITION_CENTER:
min_baseline = minimum_above + (minimum - (minimum_above + minimum_below)) / 2;
nat_baseline = natural_above + (natural - (natural_above + natural_below)) / 2;
break;
case GTK_BASELINE_POSITION_BOTTOM:
min_baseline = minimum - minimum_below;
nat_baseline = natural - natural_below;
break;
}
}
if (minimum_size) if (minimum_size)
*minimum_size = minimum; *minimum_size = minimum;
if (natural_size) if (natural_size)
*natural_size = natural; *natural_size = natural;
if (minimum_baseline)
*minimum_baseline = min_baseline;
if (natural_baseline)
*natural_baseline = nat_baseline;
} }
static void static void
@@ -1097,7 +1262,7 @@ gtk_box_get_preferred_width (GtkWidget *widget,
gint *minimum_size, gint *minimum_size,
gint *natural_size) gint *natural_size)
{ {
gtk_box_get_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size); gtk_box_get_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size, NULL, NULL);
} }
static void static void
@@ -1105,14 +1270,16 @@ gtk_box_get_preferred_height (GtkWidget *widget,
gint *minimum_size, gint *minimum_size,
gint *natural_size) gint *natural_size)
{ {
gtk_box_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size); gtk_box_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size, NULL, NULL);
} }
static void static void
gtk_box_compute_size_for_opposing_orientation (GtkBox *box, gtk_box_compute_size_for_opposing_orientation (GtkBox *box,
gint avail_size, gint avail_size,
gint *minimum_size, gint *minimum_size,
gint *natural_size) gint *natural_size,
gint *minimum_baseline,
gint *natural_baseline)
{ {
GtkBoxPrivate *private = box->priv; GtkBoxPrivate *private = box->priv;
GtkBoxChild *child; GtkBoxChild *child;
@@ -1120,11 +1287,16 @@ gtk_box_compute_size_for_opposing_orientation (GtkBox *box,
gint nvis_children; gint nvis_children;
gint nexpand_children; gint nexpand_children;
gint computed_minimum = 0, computed_natural = 0; gint computed_minimum = 0, computed_natural = 0;
gint computed_minimum_above = 0, computed_natural_above = 0;
gint computed_minimum_below = 0, computed_natural_below = 0;
gint computed_minimum_baseline = -1, computed_natural_baseline = -1;
GtkRequestedSize *sizes; GtkRequestedSize *sizes;
GtkPackType packing; GtkPackType packing;
gint size, extra, i; gint size, extra, i;
gint child_size, child_minimum, child_natural; gint child_size, child_minimum, child_natural;
gint child_minimum_baseline, child_natural_baseline;
gint n_extra_widgets = 0; gint n_extra_widgets = 0;
gboolean have_baseline;
count_expand_children (box, &nvis_children, &nexpand_children); count_expand_children (box, &nvis_children, &nexpand_children);
@@ -1199,6 +1371,7 @@ gtk_box_compute_size_for_opposing_orientation (GtkBox *box,
extra = 0; extra = 0;
} }
have_baseline = FALSE;
/* Allocate child positions. */ /* Allocate child positions. */
for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing) for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing)
{ {
@@ -1260,26 +1433,64 @@ gtk_box_compute_size_for_opposing_orientation (GtkBox *box,
} }
child_minimum_baseline = child_natural_baseline = -1;
/* Assign the child's position. */ /* Assign the child's position. */
if (private->orientation == GTK_ORIENTATION_HORIZONTAL) if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
gtk_widget_get_preferred_height_for_width (child->widget, gtk_widget_get_preferred_height_and_baseline_for_width (child->widget, child_size,
child_size, &child_minimum, &child_natural); &child_minimum, &child_natural,
&child_minimum_baseline, &child_natural_baseline);
else /* (private->orientation == GTK_ORIENTATION_VERTICAL) */ else /* (private->orientation == GTK_ORIENTATION_VERTICAL) */
gtk_widget_get_preferred_width_for_height (child->widget, gtk_widget_get_preferred_width_for_height (child->widget,
child_size, &child_minimum, &child_natural); child_size, &child_minimum, &child_natural);
if (child_minimum_baseline >= 0)
computed_minimum = MAX (computed_minimum, child_minimum); {
computed_natural = MAX (computed_natural, child_natural); have_baseline = TRUE;
computed_minimum_below = MAX (computed_minimum_below, child_minimum - child_minimum_baseline);
computed_natural_below = MAX (computed_natural_below, child_natural - child_natural_baseline);
computed_minimum_above = MAX (computed_minimum_above, child_minimum_baseline);
computed_natural_above = MAX (computed_natural_above, child_natural_baseline);
}
else
{
computed_minimum = MAX (computed_minimum, child_minimum);
computed_natural = MAX (computed_natural, child_natural);
}
} }
i += 1; i += 1;
} }
} }
if (have_baseline)
{
computed_minimum = MAX (computed_minimum, computed_minimum_below + computed_minimum_above);
computed_natural = MAX (computed_natural, computed_natural_below + computed_natural_above);
switch (private->baseline_pos)
{
case GTK_BASELINE_POSITION_TOP:
computed_minimum_baseline = computed_minimum_above;
computed_natural_baseline = computed_natural_above;
break;
case GTK_BASELINE_POSITION_CENTER:
computed_minimum_baseline = computed_minimum_above + MAX((computed_minimum - (computed_minimum_above + computed_minimum_below)) / 2, 0);
computed_natural_baseline = computed_natural_above + MAX((computed_natural - (computed_natural_above + computed_natural_below)) / 2, 0);
break;
case GTK_BASELINE_POSITION_BOTTOM:
computed_minimum_baseline = computed_minimum - computed_minimum_below;
computed_natural_baseline = computed_natural - computed_natural_below;
break;
}
}
if (minimum_baseline)
*minimum_baseline = computed_minimum_baseline;
if (natural_baseline)
*natural_baseline = computed_natural_baseline;
if (minimum_size) if (minimum_size)
*minimum_size = computed_minimum; *minimum_size = computed_minimum;
if (natural_size) if (natural_size)
*natural_size = computed_natural; *natural_size = MAX (computed_natural, computed_natural_below + computed_natural_above);
} }
static void static void
@@ -1355,24 +1566,46 @@ gtk_box_get_preferred_width_for_height (GtkWidget *widget,
GtkBoxPrivate *private = box->priv; GtkBoxPrivate *private = box->priv;
if (private->orientation == GTK_ORIENTATION_VERTICAL) if (private->orientation == GTK_ORIENTATION_VERTICAL)
gtk_box_compute_size_for_opposing_orientation (box, height, minimum_width, natural_width); gtk_box_compute_size_for_opposing_orientation (box, height, minimum_width, natural_width, NULL, NULL);
else else
gtk_box_compute_size_for_orientation (box, height, minimum_width, natural_width); gtk_box_compute_size_for_orientation (box, height, minimum_width, natural_width);
} }
static void
gtk_box_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint width,
gint *minimum_height,
gint *natural_height,
gint *minimum_baseline,
gint *natural_baseline)
{
GtkBox *box = GTK_BOX (widget);
GtkBoxPrivate *private = box->priv;
if (width < 0)
gtk_box_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum_height, natural_height, minimum_baseline, natural_baseline);
else
{
if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
gtk_box_compute_size_for_opposing_orientation (box, width, minimum_height, natural_height, minimum_baseline, natural_baseline);
else
{
if (minimum_baseline)
*minimum_baseline = -1;
if (natural_baseline)
*natural_baseline = -1;
gtk_box_compute_size_for_orientation (box, width, minimum_height, natural_height);
}
}
}
static void static void
gtk_box_get_preferred_height_for_width (GtkWidget *widget, gtk_box_get_preferred_height_for_width (GtkWidget *widget,
gint width, gint width,
gint *minimum_height, gint *minimum_height,
gint *natural_height) gint *natural_height)
{ {
GtkBox *box = GTK_BOX (widget); gtk_box_get_preferred_height_and_baseline_for_width (widget, width, minimum_height, natural_height, NULL, NULL);
GtkBoxPrivate *private = box->priv;
if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
gtk_box_compute_size_for_opposing_orientation (box, width, minimum_height, natural_height);
else
gtk_box_compute_size_for_orientation (box, width, minimum_height, natural_height);
} }
/** /**
@@ -1550,6 +1783,59 @@ gtk_box_get_spacing (GtkBox *box)
return box->priv->spacing; return box->priv->spacing;
} }
/**
* gtk_box_set_baseline_position:
* @box: a #GtkBox
* @position: a #GtkBaselinePosition
*
* Sets the baseline position of a box. This affects
* only horizontal boxes with at least one baseline aligned
* child. If there is more vertical space availible than requested,
* and the baseline is not allocated by the parent then
* @position is used to allocate the baseline wrt the
* extra space available.
*
* Since: 3.10
*/
void
gtk_box_set_baseline_position (GtkBox *box,
GtkBaselinePosition position)
{
GtkBoxPrivate *private;
g_return_if_fail (GTK_IS_BOX (box));
private = box->priv;
if (position != private->baseline_pos)
{
private->baseline_pos = position;
g_object_notify (G_OBJECT (box), "baseline-position");
gtk_widget_queue_resize (GTK_WIDGET (box));
}
}
/**
* gtk_box_get_baseline_position:
* @box: a #GtkBox
*
* Gets the value set by gtk_box_set_baseline_position().
*
* Return value: the baseline position
*
* Since: 3.10
**/
GtkBaselinePosition
gtk_box_get_baseline_position (GtkBox *box)
{
g_return_val_if_fail (GTK_IS_BOX (box), GTK_BASELINE_POSITION_CENTER);
return box->priv->baseline_pos;
}
void void
_gtk_box_set_spacing_set (GtkBox *box, _gtk_box_set_spacing_set (GtkBox *box,
gboolean spacing_set) gboolean spacing_set)

View File

@@ -89,6 +89,11 @@ gboolean gtk_box_get_homogeneous (GtkBox *box);
void gtk_box_set_spacing (GtkBox *box, void gtk_box_set_spacing (GtkBox *box,
gint spacing); gint spacing);
gint gtk_box_get_spacing (GtkBox *box); gint gtk_box_get_spacing (GtkBox *box);
GDK_AVAILABLE_IN_3_10
void gtk_box_set_baseline_position (GtkBox *box,
GtkBaselinePosition position);
GDK_AVAILABLE_IN_3_10
GtkBaselinePosition gtk_box_get_baseline_position (GtkBox *box);
void gtk_box_reorder_child (GtkBox *box, void gtk_box_reorder_child (GtkBox *box,
GtkWidget *child, GtkWidget *child,

View File

@@ -170,6 +170,12 @@ static void gtk_button_get_preferred_width (GtkWidget *widget,
static void gtk_button_get_preferred_height (GtkWidget *widget, static void gtk_button_get_preferred_height (GtkWidget *widget,
gint *minimum_size, gint *minimum_size,
gint *natural_size); gint *natural_size);
static void gtk_button_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint width,
gint *minimum_size,
gint *natural_size,
gint *minimum_baseline,
gint *natural_baseline);
static guint button_signals[LAST_SIGNAL] = { 0 }; static guint button_signals[LAST_SIGNAL] = { 0 };
@@ -196,6 +202,7 @@ gtk_button_class_init (GtkButtonClass *klass)
widget_class->get_preferred_width = gtk_button_get_preferred_width; widget_class->get_preferred_width = gtk_button_get_preferred_width;
widget_class->get_preferred_height = gtk_button_get_preferred_height; widget_class->get_preferred_height = gtk_button_get_preferred_height;
widget_class->get_preferred_height_and_baseline_for_width = gtk_button_get_preferred_height_and_baseline_for_width;
widget_class->destroy = gtk_button_destroy; widget_class->destroy = gtk_button_destroy;
widget_class->screen_changed = gtk_button_screen_changed; widget_class->screen_changed = gtk_button_screen_changed;
widget_class->realize = gtk_button_realize; widget_class->realize = gtk_button_realize;
@@ -1150,11 +1157,16 @@ gtk_button_construct_child (GtkButton *button)
else else
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, image_spacing); box = gtk_box_new (GTK_ORIENTATION_VERTICAL, image_spacing);
gtk_widget_set_valign (image, GTK_ALIGN_BASELINE);
gtk_widget_set_valign (box, GTK_ALIGN_BASELINE);
if (priv->align_set) if (priv->align_set)
align = gtk_alignment_new (priv->xalign, priv->yalign, 0.0, 0.0); align = gtk_alignment_new (priv->xalign, priv->yalign, 0.0, 0.0);
else else
align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
gtk_widget_set_valign (align, GTK_ALIGN_BASELINE);
if (priv->image_position == GTK_POS_LEFT || if (priv->image_position == GTK_POS_LEFT ||
priv->image_position == GTK_POS_TOP) priv->image_position == GTK_POS_TOP)
gtk_box_pack_start (GTK_BOX (box), priv->image, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (box), priv->image, FALSE, FALSE, 0);
@@ -1172,6 +1184,8 @@ gtk_button_construct_child (GtkButton *button)
else else
label = gtk_label_new (label_text); label = gtk_label_new (label_text);
gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
if (priv->image_position == GTK_POS_RIGHT || if (priv->image_position == GTK_POS_RIGHT ||
priv->image_position == GTK_POS_BOTTOM) priv->image_position == GTK_POS_BOTTOM)
gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
@@ -1196,6 +1210,8 @@ gtk_button_construct_child (GtkButton *button)
else else
label = gtk_label_new (priv->label_text); label = gtk_label_new (priv->label_text);
gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
if (priv->align_set) if (priv->align_set)
gtk_misc_set_alignment (GTK_MISC (label), priv->xalign, priv->yalign); gtk_misc_set_alignment (GTK_MISC (label), priv->xalign, priv->yalign);
@@ -1584,6 +1600,7 @@ gtk_button_size_allocate (GtkWidget *widget,
GtkBorder border; GtkBorder border;
gint focus_width; gint focus_width;
gint focus_pad; gint focus_pad;
gint baseline;
context = gtk_widget_get_style_context (widget); context = gtk_widget_get_style_context (widget);
@@ -1635,6 +1652,10 @@ gtk_button_size_allocate (GtkWidget *widget,
child_allocation.height = child_allocation.height - (focus_width + focus_pad) * 2; child_allocation.height = child_allocation.height - (focus_width + focus_pad) * 2;
} }
baseline = gtk_widget_get_allocated_baseline (widget);
if (baseline != -1)
baseline -= child_allocation.y - allocation->y;
if (priv->depressed) if (priv->depressed)
{ {
gint child_displacement_x; gint child_displacement_x;
@@ -1651,7 +1672,7 @@ gtk_button_size_allocate (GtkWidget *widget,
child_allocation.width = MAX (1, child_allocation.width); child_allocation.width = MAX (1, child_allocation.width);
child_allocation.height = MAX (1, child_allocation.height); child_allocation.height = MAX (1, child_allocation.height);
gtk_widget_size_allocate (child, &child_allocation); gtk_widget_size_allocate_with_baseline (child, &child_allocation, baseline);
} }
} }
@@ -2063,7 +2084,9 @@ static void
gtk_button_get_size (GtkWidget *widget, gtk_button_get_size (GtkWidget *widget,
GtkOrientation orientation, GtkOrientation orientation,
gint *minimum_size, gint *minimum_size,
gint *natural_size) gint *natural_size,
gint *minimum_baseline,
gint *natural_baseline)
{ {
GtkButton *button = GTK_BUTTON (widget); GtkButton *button = GTK_BUTTON (widget);
GtkStyleContext *context; GtkStyleContext *context;
@@ -2074,6 +2097,7 @@ gtk_button_get_size (GtkWidget *widget,
gint focus_width; gint focus_width;
gint focus_pad; gint focus_pad;
gint minimum, natural; gint minimum, natural;
gint top_offset;
context = gtk_widget_get_style_context (widget); context = gtk_widget_get_style_context (widget);
@@ -2084,6 +2108,8 @@ gtk_button_get_size (GtkWidget *widget,
"focus-padding", &focus_pad, "focus-padding", &focus_pad,
NULL); NULL);
top_offset = 0;
if (orientation == GTK_ORIENTATION_HORIZONTAL) if (orientation == GTK_ORIENTATION_HORIZONTAL)
{ {
minimum = padding.left + padding.right + minimum = padding.left + padding.right +
@@ -2097,9 +2123,14 @@ gtk_button_get_size (GtkWidget *widget,
minimum = padding.top + padding.bottom + minimum = padding.top + padding.bottom +
border.top + border.bottom; border.top + border.bottom;
top_offset = padding.top + border.top + focus_width + focus_pad;
if (gtk_widget_get_can_default (GTK_WIDGET (widget))) if (gtk_widget_get_can_default (GTK_WIDGET (widget)))
minimum += default_border.top + default_border.bottom; {
} minimum += default_border.top + default_border.bottom;
top_offset += default_border.top;
}
}
minimum += 2 * (focus_width + focus_pad); minimum += 2 * (focus_width + focus_pad);
natural = minimum; natural = minimum;
@@ -2108,11 +2139,17 @@ gtk_button_get_size (GtkWidget *widget,
gtk_widget_get_visible (child)) gtk_widget_get_visible (child))
{ {
gint child_min, child_nat; gint child_min, child_nat;
gint child_min_baseline = -1, child_nat_baseline = -1;
if (orientation == GTK_ORIENTATION_HORIZONTAL) if (orientation == GTK_ORIENTATION_HORIZONTAL)
gtk_widget_get_preferred_width (child, &child_min, &child_nat); gtk_widget_get_preferred_width (child, &child_min, &child_nat);
else else
gtk_widget_get_preferred_height (child, &child_min, &child_nat); gtk_widget_get_preferred_height_and_baseline_for_width (child, -1, &child_min, &child_nat, &child_min_baseline, &child_nat_baseline);
if (minimum_baseline && child_min_baseline >= 0)
*minimum_baseline = child_min_baseline + top_offset;
if (natural_baseline && child_nat_baseline >= 0)
*natural_baseline = child_nat_baseline + top_offset;
minimum += child_min; minimum += child_min;
natural += child_nat; natural += child_nat;
@@ -2130,7 +2167,7 @@ gtk_button_get_preferred_width (GtkWidget *widget,
gint *minimum_size, gint *minimum_size,
gint *natural_size) gint *natural_size)
{ {
gtk_button_get_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size); gtk_button_get_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size, NULL, NULL);
} }
static void static void
@@ -2138,7 +2175,20 @@ gtk_button_get_preferred_height (GtkWidget *widget,
gint *minimum_size, gint *minimum_size,
gint *natural_size) gint *natural_size)
{ {
gtk_button_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size); gtk_button_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size, NULL, NULL);
}
static void
gtk_button_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint width,
gint *minimum_size,
gint *natural_size,
gint *minimum_baseline,
gint *natural_baseline)
{
/* GtkButton is GTK_SIZE_REQUEST_CONSTANT mode, so width will be -1 all the time */
g_assert (width == -1);
gtk_button_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size, minimum_baseline, natural_baseline);
} }
/** /**

View File

@@ -39,6 +39,9 @@ struct _GtkButtonPrivate
gfloat xalign; gfloat xalign;
gfloat yalign; gfloat yalign;
/* This is only used by checkbox and subclasses */
gfloat baseline_align;
guint activate_timeout; guint activate_timeout;
guint32 grab_time; guint32 grab_time;

View File

@@ -58,6 +58,12 @@ static void gtk_check_button_get_preferred_width (GtkWidget *widget,
static void gtk_check_button_get_preferred_height (GtkWidget *widget, static void gtk_check_button_get_preferred_height (GtkWidget *widget,
gint *minimum, gint *minimum,
gint *natural); gint *natural);
static void gtk_check_button_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint width,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline);
static void gtk_check_button_size_allocate (GtkWidget *widget, static void gtk_check_button_size_allocate (GtkWidget *widget,
GtkAllocation *allocation); GtkAllocation *allocation);
static gboolean gtk_check_button_draw (GtkWidget *widget, static gboolean gtk_check_button_draw (GtkWidget *widget,
@@ -80,6 +86,7 @@ gtk_check_button_class_init (GtkCheckButtonClass *class)
widget_class->get_preferred_width = gtk_check_button_get_preferred_width; widget_class->get_preferred_width = gtk_check_button_get_preferred_width;
widget_class->get_preferred_height = gtk_check_button_get_preferred_height; widget_class->get_preferred_height = gtk_check_button_get_preferred_height;
widget_class->get_preferred_height_and_baseline_for_width = gtk_check_button_get_preferred_height_and_baseline_for_width;
widget_class->size_allocate = gtk_check_button_size_allocate; widget_class->size_allocate = gtk_check_button_size_allocate;
widget_class->draw = gtk_check_button_draw; widget_class->draw = gtk_check_button_draw;
@@ -287,9 +294,12 @@ gtk_check_button_get_preferred_width (GtkWidget *widget,
} }
static void static void
gtk_check_button_get_preferred_height (GtkWidget *widget, gtk_check_button_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint *minimum, gint width,
gint *natural) gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{ {
GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (widget); GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (widget);
@@ -301,6 +311,7 @@ gtk_check_button_get_preferred_height (GtkWidget *widget,
gint indicator_spacing; gint indicator_spacing;
gint focus_width; gint focus_width;
gint focus_pad; gint focus_pad;
gint old_minimum, old_natural;
guint border_width; guint border_width;
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
@@ -320,29 +331,61 @@ gtk_check_button_get_preferred_height (GtkWidget *widget,
if (child && gtk_widget_get_visible (child)) if (child && gtk_widget_get_visible (child))
{ {
gint child_min, child_nat; gint child_min, child_nat;
gint child_min_baseline = -1, child_nat_baseline = -1;
gtk_widget_get_preferred_height (child, &child_min, &child_nat); gtk_widget_get_preferred_height_and_baseline_for_width (child, -1,
&child_min, &child_nat,
&child_min_baseline, &child_nat_baseline);
if (minimum_baseline && child_min_baseline >= 0)
*minimum_baseline = child_min_baseline + border_width;
if (natural_baseline && child_nat_baseline >= 0)
*natural_baseline = child_nat_baseline + border_width;
*minimum += child_min; *minimum += child_min;
*natural += child_nat; *natural += child_nat;
} }
old_minimum = *minimum;
old_natural = *natural;
temp = indicator_size + indicator_spacing * 2; temp = indicator_size + indicator_spacing * 2;
*minimum = MAX (*minimum, temp) + 2 * (focus_width + focus_pad); *minimum = MAX (*minimum, temp) + 2 * (focus_width + focus_pad);
*natural = MAX (*natural, temp) + 2 * (focus_width + focus_pad); *natural = MAX (*natural, temp) + 2 * (focus_width + focus_pad);
if (minimum_baseline && *minimum_baseline != -1)
minimum_baseline += (*minimum - old_minimum) / 2;
if (natural_baseline && *natural_baseline != -1)
natural_baseline += (*natural - old_natural) / 2;
} }
else else
GTK_WIDGET_CLASS (gtk_check_button_parent_class)->get_preferred_height (widget, minimum, natural); GTK_WIDGET_CLASS (gtk_check_button_parent_class)->get_preferred_height_and_baseline_for_width (widget, width,
minimum, natural,
minimum_baseline, natural_baseline);
}
static void
gtk_check_button_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural)
{
gtk_check_button_get_preferred_height_and_baseline_for_width (widget, -1,
minimum, natural,
NULL, NULL);
} }
static void static void
gtk_check_button_size_allocate (GtkWidget *widget, gtk_check_button_size_allocate (GtkWidget *widget,
GtkAllocation *allocation) GtkAllocation *allocation)
{ {
PangoContext *pango_context;
PangoFontMetrics *metrics;
GtkCheckButton *check_button; GtkCheckButton *check_button;
GtkToggleButton *toggle_button; GtkToggleButton *toggle_button;
GtkButton *button; GtkButton *button;
GtkAllocation child_allocation; GtkAllocation child_allocation;
gint baseline;
button = GTK_BUTTON (widget); button = GTK_BUTTON (widget);
check_button = GTK_CHECK_BUTTON (widget); check_button = GTK_CHECK_BUTTON (widget);
@@ -389,8 +432,21 @@ gtk_check_button_size_allocate (GtkWidget *widget,
child_allocation.x = allocation->x + allocation->width child_allocation.x = allocation->x + allocation->width
- (child_allocation.x - allocation->x + child_allocation.width); - (child_allocation.x - allocation->x + child_allocation.width);
gtk_widget_size_allocate (child, &child_allocation); baseline = gtk_widget_get_allocated_baseline (widget);
if (baseline != -1)
baseline -= child_allocation.y - allocation->y;
gtk_widget_size_allocate_with_baseline (child, &child_allocation, baseline);
} }
pango_context = gtk_widget_get_pango_context (widget);
metrics = pango_context_get_metrics (pango_context,
pango_context_get_font_description (pango_context),
pango_context_get_language (pango_context));
button->priv->baseline_align =
(double)pango_font_metrics_get_ascent (metrics) /
(pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent (metrics));
pango_font_metrics_unref (metrics);
} }
else else
GTK_WIDGET_CLASS (gtk_check_button_parent_class)->size_allocate (widget, allocation); GTK_WIDGET_CLASS (gtk_check_button_parent_class)->size_allocate (widget, allocation);
@@ -448,6 +504,7 @@ gtk_real_check_button_draw_indicator (GtkCheckButton *check_button,
gint indicator_spacing; gint indicator_spacing;
gint focus_width; gint focus_width;
gint focus_pad; gint focus_pad;
gint baseline;
guint border_width; guint border_width;
gboolean interior_focus; gboolean interior_focus;
GtkAllocation allocation; GtkAllocation allocation;
@@ -458,6 +515,7 @@ gtk_real_check_button_draw_indicator (GtkCheckButton *check_button,
toggle_button = GTK_TOGGLE_BUTTON (check_button); toggle_button = GTK_TOGGLE_BUTTON (check_button);
gtk_widget_get_allocation (widget, &allocation); gtk_widget_get_allocation (widget, &allocation);
baseline = gtk_widget_get_allocated_baseline (widget);
context = gtk_widget_get_style_context (widget); context = gtk_widget_get_style_context (widget);
state = gtk_widget_get_state_flags (widget); state = gtk_widget_get_state_flags (widget);
@@ -472,7 +530,11 @@ gtk_real_check_button_draw_indicator (GtkCheckButton *check_button,
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
x = indicator_spacing + border_width; x = indicator_spacing + border_width;
y = (allocation.height - indicator_size) / 2; if (baseline == -1)
y = (allocation.height - indicator_size) / 2;
else
y = CLAMP (baseline - indicator_size * button->priv->baseline_align,
0, allocation.height - indicator_size);
child = gtk_bin_get_child (GTK_BIN (check_button)); child = gtk_bin_get_child (GTK_BIN (check_button));
if (!interior_focus || !(child && gtk_widget_get_visible (child))) if (!interior_focus || !(child && gtk_widget_get_visible (child)))

View File

@@ -309,12 +309,17 @@ static void gtk_container_adjust_size_request (GtkWidget *widget,
GtkOrientation orientation, GtkOrientation orientation,
gint *minimum_size, gint *minimum_size,
gint *natural_size); gint *natural_size);
static void gtk_container_adjust_baseline_request (GtkWidget *widget,
gint *minimum_baseline,
gint *natural_baseline);
static void gtk_container_adjust_size_allocation (GtkWidget *widget, static void gtk_container_adjust_size_allocation (GtkWidget *widget,
GtkOrientation orientation, GtkOrientation orientation,
gint *minimum_size, gint *minimum_size,
gint *natural_size, gint *natural_size,
gint *allocated_pos, gint *allocated_pos,
gint *allocated_size); gint *allocated_size);
static void gtk_container_adjust_baseline_allocation (GtkWidget *widget,
gint *baseline);
static GtkSizeRequestMode gtk_container_get_request_mode (GtkWidget *widget); static GtkSizeRequestMode gtk_container_get_request_mode (GtkWidget *widget);
static gchar* gtk_container_child_default_composite_name (GtkContainer *container, static gchar* gtk_container_child_default_composite_name (GtkContainer *container,
@@ -444,7 +449,9 @@ gtk_container_class_init (GtkContainerClass *class)
widget_class->focus = gtk_container_focus; widget_class->focus = gtk_container_focus;
widget_class->adjust_size_request = gtk_container_adjust_size_request; widget_class->adjust_size_request = gtk_container_adjust_size_request;
widget_class->adjust_baseline_request = gtk_container_adjust_baseline_request;
widget_class->adjust_size_allocation = gtk_container_adjust_size_allocation; widget_class->adjust_size_allocation = gtk_container_adjust_size_allocation;
widget_class->adjust_baseline_allocation = gtk_container_adjust_baseline_allocation;
widget_class->get_request_mode = gtk_container_get_request_mode; widget_class->get_request_mode = gtk_container_get_request_mode;
class->add = gtk_container_add_unimplemented; class->add = gtk_container_add_unimplemented;
@@ -1917,6 +1924,28 @@ gtk_container_adjust_size_request (GtkWidget *widget,
minimum_size, natural_size); minimum_size, natural_size);
} }
static void
gtk_container_adjust_baseline_request (GtkWidget *widget,
gint *minimum_baseline,
gint *natural_baseline)
{
GtkContainer *container;
container = GTK_CONTAINER (widget);
if (GTK_CONTAINER_GET_CLASS (widget)->_handle_border_width)
{
int border_width;
border_width = container->priv->border_width;
*minimum_baseline += border_width;
*natural_baseline += border_width;
}
parent_class->adjust_baseline_request (widget, minimum_baseline, natural_baseline);
}
static void static void
gtk_container_adjust_size_allocation (GtkWidget *widget, gtk_container_adjust_size_allocation (GtkWidget *widget,
GtkOrientation orientation, GtkOrientation orientation,
@@ -1952,6 +1981,27 @@ gtk_container_adjust_size_allocation (GtkWidget *widget,
allocated_size); allocated_size);
} }
static void
gtk_container_adjust_baseline_allocation (GtkWidget *widget,
gint *baseline)
{
GtkContainer *container;
int border_width;
container = GTK_CONTAINER (widget);
if (GTK_CONTAINER_GET_CLASS (widget)->_handle_border_width)
{
border_width = container->priv->border_width;
if (*baseline >= 0)
*baseline -= border_width;
}
parent_class->adjust_baseline_allocation (widget, baseline);
}
typedef struct { typedef struct {
gint hfw; gint hfw;
gint wfh; gint wfh;

View File

@@ -47,7 +47,8 @@ typedef enum {
GTK_DEBUG_PRINTING = 1 << 10, GTK_DEBUG_PRINTING = 1 << 10,
GTK_DEBUG_BUILDER = 1 << 11, GTK_DEBUG_BUILDER = 1 << 11,
GTK_DEBUG_SIZE_REQUEST = 1 << 12, GTK_DEBUG_SIZE_REQUEST = 1 << 12,
GTK_DEBUG_NO_CSS_CACHE = 1 << 13 GTK_DEBUG_NO_CSS_CACHE = 1 << 13,
GTK_DEBUG_BASELINES = 1 << 14
} GtkDebugFlag; } GtkDebugFlag;
#ifdef G_ENABLE_DEBUG #ifdef G_ENABLE_DEBUG

View File

@@ -787,6 +787,7 @@ gtk_dialog_add_button (GtkDialog *dialog,
button = gtk_button_new_from_stock (button_text); button = gtk_button_new_from_stock (button_text);
gtk_widget_set_can_default (button, TRUE); gtk_widget_set_can_default (button, TRUE);
gtk_widget_set_valign (button, GTK_ALIGN_BASELINE);
gtk_widget_show (button); gtk_widget_show (button);

View File

@@ -367,6 +367,12 @@ static void gtk_entry_get_preferred_width (GtkWidget *widget,
static void gtk_entry_get_preferred_height (GtkWidget *widget, static void gtk_entry_get_preferred_height (GtkWidget *widget,
gint *minimum, gint *minimum,
gint *natural); gint *natural);
static void gtk_entry_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint width,
gint *minimum_height,
gint *natural_height,
gint *minimum_baseline,
gint *natural_baseline);
static void gtk_entry_size_allocate (GtkWidget *widget, static void gtk_entry_size_allocate (GtkWidget *widget,
GtkAllocation *allocation); GtkAllocation *allocation);
static void gtk_entry_draw_frame (GtkWidget *widget, static void gtk_entry_draw_frame (GtkWidget *widget,
@@ -682,6 +688,7 @@ gtk_entry_class_init (GtkEntryClass *class)
widget_class->unrealize = gtk_entry_unrealize; widget_class->unrealize = gtk_entry_unrealize;
widget_class->get_preferred_width = gtk_entry_get_preferred_width; widget_class->get_preferred_width = gtk_entry_get_preferred_width;
widget_class->get_preferred_height = gtk_entry_get_preferred_height; widget_class->get_preferred_height = gtk_entry_get_preferred_height;
widget_class->get_preferred_height_and_baseline_for_width = gtk_entry_get_preferred_height_and_baseline_for_width;
widget_class->size_allocate = gtk_entry_size_allocate; widget_class->size_allocate = gtk_entry_size_allocate;
widget_class->draw = gtk_entry_draw; widget_class->draw = gtk_entry_draw;
widget_class->enter_notify_event = gtk_entry_enter_notify; widget_class->enter_notify_event = gtk_entry_enter_notify;
@@ -3305,16 +3312,19 @@ gtk_entry_get_preferred_width (GtkWidget *widget,
} }
static void static void
gtk_entry_get_preferred_height (GtkWidget *widget, gtk_entry_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint *minimum, gint width,
gint *natural) gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{ {
GtkEntry *entry = GTK_ENTRY (widget); GtkEntry *entry = GTK_ENTRY (widget);
GtkEntryPrivate *priv = entry->priv; GtkEntryPrivate *priv = entry->priv;
PangoFontMetrics *metrics; PangoFontMetrics *metrics;
GtkBorder borders; GtkBorder borders;
PangoContext *context; PangoContext *context;
gint height; gint height, baseline;
PangoLayout *layout; PangoLayout *layout;
layout = gtk_entry_ensure_layout (entry, TRUE); layout = gtk_entry_ensure_layout (entry, TRUE);
@@ -3333,8 +3343,27 @@ gtk_entry_get_preferred_height (GtkWidget *widget,
height += borders.top + borders.bottom; height += borders.top + borders.bottom;
baseline = pango_layout_get_baseline (layout) / PANGO_SCALE;
baseline += borders.top;
*minimum = height; *minimum = height;
*natural = height; *natural = height;
if (minimum_baseline)
*minimum_baseline = baseline;
if (natural_baseline)
*natural_baseline = baseline;
}
static void
gtk_entry_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural)
{
gtk_entry_get_preferred_height_and_baseline_for_width (widget,
-1,
minimum,
natural,
NULL, NULL);
} }
static void static void
@@ -3452,13 +3481,17 @@ gtk_entry_get_frame_size (GtkEntry *entry,
GtkAllocation allocation; GtkAllocation allocation;
GtkRequisition requisition; GtkRequisition requisition;
GtkWidget *widget = GTK_WIDGET (entry); GtkWidget *widget = GTK_WIDGET (entry);
gint area_height, y_pos;
gint baseline;
gint req_height; gint req_height;
GtkBorder borders;
gtk_widget_get_preferred_size (widget, &requisition, NULL); gtk_widget_get_preferred_size (widget, &requisition, NULL);
req_height = requisition.height - gtk_widget_get_margin_top (widget) - gtk_widget_get_margin_bottom (widget); req_height = requisition.height - gtk_widget_get_margin_top (widget) - gtk_widget_get_margin_bottom (widget);
gtk_widget_get_allocation (widget, &allocation); gtk_widget_get_allocation (widget, &allocation);
baseline = gtk_widget_get_allocated_baseline (widget);
if (x) if (x)
*x = allocation.x; *x = allocation.x;
@@ -3468,7 +3501,17 @@ gtk_entry_get_frame_size (GtkEntry *entry,
if (priv->is_cell_renderer) if (priv->is_cell_renderer)
*y = 0; *y = 0;
else else
*y = (allocation.height - req_height) / 2; {
if (baseline == -1)
*y = (allocation.height - req_height) / 2;
else
{
_gtk_entry_get_borders (entry, &borders);
area_height = req_height - borders.top - borders.bottom;
y_pos = ((area_height * PANGO_SCALE - priv->ascent - priv->descent) / 2 + priv->ascent) / PANGO_SCALE;
*y = baseline - y_pos - borders.top;
}
}
*y += allocation.y; *y += allocation.y;
} }

View File

@@ -51,6 +51,7 @@ G_BEGIN_DECLS
* or top * or top
* @GTK_ALIGN_CENTER: center natural width of widget inside the * @GTK_ALIGN_CENTER: center natural width of widget inside the
* allocation * allocation
* @GTK_ALIGN_BASELINE: align the widget according to the baseline. Since 3.10.
* *
* Controls how a widget deals with extra space in a single (x or y) * Controls how a widget deals with extra space in a single (x or y)
* dimension. * dimension.
@@ -64,13 +65,18 @@ G_BEGIN_DECLS
* *
* Note that in horizontal context @GTK_ALIGN_START and @GTK_ALIGN_END * Note that in horizontal context @GTK_ALIGN_START and @GTK_ALIGN_END
* are interpreted relative to text direction. * are interpreted relative to text direction.
*
* GTK_ALIGN_BASELINE support for it is optional for containers and widgets, and
* it is only supported for vertical alignment. When its not supported by
* a child or a container it is treated as @GTK_ALIGN_FILL.
*/ */
typedef enum typedef enum
{ {
GTK_ALIGN_FILL, GTK_ALIGN_FILL,
GTK_ALIGN_START, GTK_ALIGN_START,
GTK_ALIGN_END, GTK_ALIGN_END,
GTK_ALIGN_CENTER GTK_ALIGN_CENTER,
GTK_ALIGN_BASELINE
} GtkAlign; } GtkAlign;
@@ -125,6 +131,28 @@ typedef enum
GTK_FILL = 1 << 2 GTK_FILL = 1 << 2
} GtkAttachOptions; } GtkAttachOptions;
/**
* GtkBaselinePosition:
* @GTK_BASELINE_POSITION_TOP: Align the baseline at the top
* @GTK_BASELINE_POSITION_CENTER: Center the baseline
* @GTK_BASELINE_POSITION_BOTTOM: Align the baseline at the bottom
*
* Whenever a container has some form of natural row it may align
* children in that row along a common typographical baseline. If
* the amount of verical space in the row is taller than the total
* requested height of the baseline-aligned children then it can use a
* #GtkBaselinePosition to select where to put the baseline inside the
* extra availible space.
*
* Since: 3.10
*/
typedef enum
{
GTK_BASELINE_POSITION_TOP,
GTK_BASELINE_POSITION_CENTER,
GTK_BASELINE_POSITION_BOTTOM
} GtkBaselinePosition;
/** /**
* GtkButtonBoxStyle: * GtkButtonBoxStyle:
* @GTK_BUTTONBOX_DEFAULT_STYLE: Default packing. * @GTK_BUTTONBOX_DEFAULT_STYLE: Default packing.

View File

@@ -65,6 +65,12 @@ static void gtk_event_box_get_preferred_width (GtkWidget *widget,
static void gtk_event_box_get_preferred_height (GtkWidget *widget, static void gtk_event_box_get_preferred_height (GtkWidget *widget,
gint *minimum, gint *minimum,
gint *natural); gint *natural);
static void gtk_event_box_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint width,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline);
static void gtk_event_box_size_allocate (GtkWidget *widget, static void gtk_event_box_size_allocate (GtkWidget *widget,
GtkAllocation *allocation); GtkAllocation *allocation);
static gboolean gtk_event_box_draw (GtkWidget *widget, static gboolean gtk_event_box_draw (GtkWidget *widget,
@@ -96,6 +102,7 @@ gtk_event_box_class_init (GtkEventBoxClass *class)
widget_class->unmap = gtk_event_box_unmap; widget_class->unmap = gtk_event_box_unmap;
widget_class->get_preferred_width = gtk_event_box_get_preferred_width; widget_class->get_preferred_width = gtk_event_box_get_preferred_width;
widget_class->get_preferred_height = gtk_event_box_get_preferred_height; widget_class->get_preferred_height = gtk_event_box_get_preferred_height;
widget_class->get_preferred_height_and_baseline_for_width = gtk_event_box_get_preferred_height_and_baseline_for_width;
widget_class->size_allocate = gtk_event_box_size_allocate; widget_class->size_allocate = gtk_event_box_size_allocate;
widget_class->draw = gtk_event_box_draw; widget_class->draw = gtk_event_box_draw;
@@ -515,9 +522,12 @@ gtk_event_box_get_preferred_width (GtkWidget *widget,
} }
static void static void
gtk_event_box_get_preferred_height (GtkWidget *widget, gtk_event_box_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint *minimum, gint width,
gint *natural) gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{ {
GtkBin *bin = GTK_BIN (widget); GtkBin *bin = GTK_BIN (widget);
GtkWidget *child; GtkWidget *child;
@@ -528,9 +538,30 @@ gtk_event_box_get_preferred_height (GtkWidget *widget,
if (natural) if (natural)
*natural = 0; *natural = 0;
if (minimum_baseline)
*minimum_baseline = -1;
if (natural_baseline)
*natural_baseline = -1;
child = gtk_bin_get_child (bin); child = gtk_bin_get_child (bin);
if (child && gtk_widget_get_visible (child)) if (child && gtk_widget_get_visible (child))
gtk_widget_get_preferred_height (child, minimum, natural); gtk_widget_get_preferred_height_and_baseline_for_width (child,
-1,
minimum,
natural,
minimum_baseline,
natural_baseline);
}
static void
gtk_event_box_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural)
{
gtk_event_box_get_preferred_height_and_baseline_for_width (widget, -1,
minimum, natural,
NULL, NULL);
} }
static void static void
@@ -539,6 +570,7 @@ gtk_event_box_size_allocate (GtkWidget *widget,
{ {
GtkBin *bin; GtkBin *bin;
GtkAllocation child_allocation; GtkAllocation child_allocation;
gint baseline;
GtkEventBoxPrivate *priv; GtkEventBoxPrivate *priv;
GtkWidget *child; GtkWidget *child;
@@ -578,9 +610,10 @@ gtk_event_box_size_allocate (GtkWidget *widget,
child_allocation.height); child_allocation.height);
} }
baseline = gtk_widget_get_allocated_baseline (widget);
child = gtk_bin_get_child (bin); child = gtk_bin_get_child (bin);
if (child) if (child)
gtk_widget_size_allocate (child, &child_allocation); gtk_widget_size_allocate_with_baseline (child, &child_allocation, baseline);
} }
static gboolean static gboolean

File diff suppressed because it is too large Load Diff

View File

@@ -109,6 +109,18 @@ gboolean gtk_grid_get_column_homogeneous (GtkGrid *grid);
void gtk_grid_set_column_spacing (GtkGrid *grid, void gtk_grid_set_column_spacing (GtkGrid *grid,
guint spacing); guint spacing);
guint gtk_grid_get_column_spacing (GtkGrid *grid); guint gtk_grid_get_column_spacing (GtkGrid *grid);
GDK_AVAILABLE_IN_3_10
void gtk_grid_set_row_baseline_position (GtkGrid *grid,
gint row,
GtkBaselinePosition pos);
GDK_AVAILABLE_IN_3_10
GtkBaselinePosition gtk_grid_get_row_baseline_position (GtkGrid *grid,
gint row);
GDK_AVAILABLE_IN_3_10
void gtk_grid_set_baseline_row (GtkGrid *grid,
gint row);
GDK_AVAILABLE_IN_3_10
gint gtk_grid_get_baseline_row (GtkGrid *grid);
G_END_DECLS G_END_DECLS

View File

@@ -140,6 +140,8 @@ struct _GtkImagePrivate
gchar *filename; /* Only used with GTK_IMAGE_ANIMATION, GTK_IMAGE_PIXBUF */ gchar *filename; /* Only used with GTK_IMAGE_ANIMATION, GTK_IMAGE_PIXBUF */
gchar *resource_path; /* Only used with GTK_IMAGE_PIXBUF */ gchar *resource_path; /* Only used with GTK_IMAGE_PIXBUF */
float baseline_align;
}; };
@@ -154,6 +156,12 @@ static void gtk_image_get_preferred_width (GtkWidget *widget,
static void gtk_image_get_preferred_height (GtkWidget *widget, static void gtk_image_get_preferred_height (GtkWidget *widget,
gint *minimum, gint *minimum,
gint *natural); gint *natural);
static void gtk_image_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint width,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline);
static void gtk_image_style_updated (GtkWidget *widget); static void gtk_image_style_updated (GtkWidget *widget);
static void gtk_image_screen_changed (GtkWidget *widget, static void gtk_image_screen_changed (GtkWidget *widget,
@@ -207,6 +215,7 @@ gtk_image_class_init (GtkImageClass *class)
widget_class->draw = gtk_image_draw; widget_class->draw = gtk_image_draw;
widget_class->get_preferred_width = gtk_image_get_preferred_width; widget_class->get_preferred_width = gtk_image_get_preferred_width;
widget_class->get_preferred_height = gtk_image_get_preferred_height; widget_class->get_preferred_height = gtk_image_get_preferred_height;
widget_class->get_preferred_height_and_baseline_for_width = gtk_image_get_preferred_height_and_baseline_for_width;
widget_class->unmap = gtk_image_unmap; widget_class->unmap = gtk_image_unmap;
widget_class->unrealize = gtk_image_unrealize; widget_class->unrealize = gtk_image_unrealize;
widget_class->style_updated = gtk_image_style_updated; widget_class->style_updated = gtk_image_style_updated;
@@ -1393,6 +1402,26 @@ gtk_image_get_preferred_size (GtkImage *image,
*height_out = height; *height_out = height;
} }
static float
gtk_image_get_baseline_align (GtkImage *image)
{
PangoContext *pango_context;
PangoFontMetrics *metrics;
if (image->priv->baseline_align == 0.0)
{
pango_context = gtk_widget_get_pango_context (GTK_WIDGET (image));
metrics = pango_context_get_metrics (pango_context,
pango_context_get_font_description (pango_context),
pango_context_get_language (pango_context));
image->priv->baseline_align =
(float)pango_font_metrics_get_ascent (metrics) /
(pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent (metrics));
}
return image->priv->baseline_align;
}
static gint static gint
gtk_image_draw (GtkWidget *widget, gtk_image_draw (GtkWidget *widget,
cairo_t *cr) cairo_t *cr)
@@ -1401,7 +1430,7 @@ gtk_image_draw (GtkWidget *widget,
GtkImagePrivate *priv; GtkImagePrivate *priv;
GtkMisc *misc; GtkMisc *misc;
GtkStyleContext *context; GtkStyleContext *context;
gint x, y, width, height; gint x, y, width, height, baseline;
gfloat xalign, yalign; gfloat xalign, yalign;
GtkBorder border; GtkBorder border;
@@ -1427,8 +1456,14 @@ gtk_image_draw (GtkWidget *widget,
if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR) if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR)
xalign = 1.0 - xalign; xalign = 1.0 - xalign;
baseline = gtk_widget_get_allocated_baseline (widget);
x = floor ((gtk_widget_get_allocated_width (widget) - width) * xalign) + border.left; x = floor ((gtk_widget_get_allocated_width (widget) - width) * xalign) + border.left;
y = floor ((gtk_widget_get_allocated_height (widget) - height) * yalign) + border.top; if (baseline == -1)
y = floor ((gtk_widget_get_allocated_height (widget) - height) * yalign) + border.top;
else
y = CLAMP (baseline - height * gtk_image_get_baseline_align (image),
border.top, gtk_widget_get_allocated_height (widget) - height);
if (gtk_image_get_storage_type (image) == GTK_IMAGE_ANIMATION) if (gtk_image_get_storage_type (image) == GTK_IMAGE_ANIMATION)
{ {
@@ -1535,15 +1570,37 @@ gtk_image_get_preferred_width (GtkWidget *widget,
*minimum = *natural = width; *minimum = *natural = width;
} }
static void
gtk_image_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint width,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{
gint height;
float baseline_align;
gtk_image_get_preferred_size (GTK_IMAGE (widget), NULL, &height);
*minimum = *natural = height;
if (minimum_baseline || natural_baseline)
{
baseline_align = gtk_image_get_baseline_align (GTK_IMAGE (widget));
if (minimum_baseline)
*minimum_baseline = height * baseline_align;
if (natural_baseline)
*natural_baseline = height * baseline_align;
}
}
static void static void
gtk_image_get_preferred_height (GtkWidget *widget, gtk_image_get_preferred_height (GtkWidget *widget,
gint *minimum, gint *minimum,
gint *natural) gint *natural)
{ {
gint height; gtk_image_get_preferred_height_and_baseline_for_width (widget, -1, minimum, natural,
NULL, NULL);
gtk_image_get_preferred_size (GTK_IMAGE (widget), NULL, &height);
*minimum = *natural = height;
} }
static void static void
@@ -1558,9 +1615,13 @@ icon_theme_changed (GtkImage *image)
static void static void
gtk_image_style_updated (GtkWidget *widget) gtk_image_style_updated (GtkWidget *widget)
{ {
GtkImage *image = GTK_IMAGE (widget);
GtkImagePrivate *priv = image->priv;
GTK_WIDGET_CLASS (gtk_image_parent_class)->style_updated (widget); GTK_WIDGET_CLASS (gtk_image_parent_class)->style_updated (widget);
icon_theme_changed (GTK_IMAGE (widget)); icon_theme_changed (image);
priv->baseline_align = 0.0;
} }
static void static void

View File

@@ -519,6 +519,12 @@ static void gtk_label_get_preferred_height_for_width (GtkWidget
gint width, gint width,
gint *minimum_height, gint *minimum_height,
gint *natural_height); gint *natural_height);
static void gtk_label_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint width,
gint *minimum_height,
gint *natural_height,
gint *minimum_baseline,
gint *natural_baseline);
static GtkBuildableIface *buildable_parent_iface = NULL; static GtkBuildableIface *buildable_parent_iface = NULL;
@@ -585,6 +591,7 @@ gtk_label_class_init (GtkLabelClass *class)
widget_class->get_preferred_height = gtk_label_get_preferred_height; widget_class->get_preferred_height = gtk_label_get_preferred_height;
widget_class->get_preferred_width_for_height = gtk_label_get_preferred_width_for_height; widget_class->get_preferred_width_for_height = gtk_label_get_preferred_width_for_height;
widget_class->get_preferred_height_for_width = gtk_label_get_preferred_height_for_width; widget_class->get_preferred_height_for_width = gtk_label_get_preferred_height_for_width;
widget_class->get_preferred_height_and_baseline_for_width = gtk_label_get_preferred_height_and_baseline_for_width;
class->move_cursor = gtk_label_move_cursor; class->move_cursor = gtk_label_move_cursor;
class->copy_clipboard = gtk_label_copy_clipboard; class->copy_clipboard = gtk_label_copy_clipboard;
@@ -3462,15 +3469,18 @@ gtk_label_get_request_mode (GtkWidget *widget)
return GTK_SIZE_REQUEST_CONSTANT_SIZE; return GTK_SIZE_REQUEST_CONSTANT_SIZE;
} }
static void static void
get_size_for_allocation (GtkLabel *label, get_size_for_allocation (GtkLabel *label,
GtkOrientation orientation, GtkOrientation orientation,
gint allocation, gint allocation,
gint *minimum_size, gint *minimum_size,
gint *natural_size) gint *natural_size,
gint *minimum_baseline,
gint *natural_baseline)
{ {
PangoLayout *layout; PangoLayout *layout;
gint text_height; gint text_height, baseline;
layout = gtk_label_get_measuring_layout (label, NULL, allocation * PANGO_SCALE); layout = gtk_label_get_measuring_layout (label, NULL, allocation * PANGO_SCALE);
@@ -3482,6 +3492,16 @@ get_size_for_allocation (GtkLabel *label,
if (natural_size) if (natural_size)
*natural_size = text_height; *natural_size = text_height;
if (minimum_baseline || natural_baseline)
{
baseline = pango_layout_get_baseline (layout) / PANGO_SCALE;
if (minimum_baseline)
*minimum_baseline = baseline;
if (natural_baseline)
*natural_baseline = baseline;
}
g_object_unref (layout); g_object_unref (layout);
} }
@@ -3578,7 +3598,9 @@ static void
gtk_label_get_preferred_size (GtkWidget *widget, gtk_label_get_preferred_size (GtkWidget *widget,
GtkOrientation orientation, GtkOrientation orientation,
gint *minimum_size, gint *minimum_size,
gint *natural_size) gint *natural_size,
gint *minimum_baseline,
gint *natural_baseline)
{ {
GtkLabel *label = GTK_LABEL (widget); GtkLabel *label = GTK_LABEL (widget);
GtkLabelPrivate *priv = label->priv; GtkLabelPrivate *priv = label->priv;
@@ -3586,6 +3608,12 @@ gtk_label_get_preferred_size (GtkWidget *widget,
PangoRectangle smallest_rect; PangoRectangle smallest_rect;
GtkBorder border; GtkBorder border;
if (minimum_baseline)
*minimum_baseline = -1;
if (natural_baseline)
*natural_baseline = -1;
gtk_label_get_preferred_layout_size (label, &smallest_rect, &widest_rect); gtk_label_get_preferred_layout_size (label, &smallest_rect, &widest_rect);
/* Now that we have minimum and natural sizes in pango extents, apply a possible transform */ /* Now that we have minimum and natural sizes in pango extents, apply a possible transform */
@@ -3640,7 +3668,8 @@ gtk_label_get_preferred_size (GtkWidget *widget,
get_size_for_allocation (label, get_size_for_allocation (label,
GTK_ORIENTATION_VERTICAL, GTK_ORIENTATION_VERTICAL,
smallest_rect.height, smallest_rect.height,
minimum_size, natural_size); minimum_size, natural_size,
NULL, NULL);
} }
else else
@@ -3667,7 +3696,16 @@ gtk_label_get_preferred_size (GtkWidget *widget,
get_size_for_allocation (label, get_size_for_allocation (label,
GTK_ORIENTATION_HORIZONTAL, GTK_ORIENTATION_HORIZONTAL,
widest_rect.width, widest_rect.width,
minimum_size, natural_size); minimum_size, natural_size,
minimum_baseline, natural_baseline);
if (priv->angle == 180)
{
if (minimum_baseline)
*minimum_baseline = *minimum_size - *minimum_baseline;
if (natural_baseline)
*natural_baseline = *natural_size - *natural_baseline;
}
} }
else else
{ {
@@ -3680,6 +3718,12 @@ gtk_label_get_preferred_size (GtkWidget *widget,
*minimum_size += border.top + border.bottom; *minimum_size += border.top + border.bottom;
*natural_size += border.top + border.bottom; *natural_size += border.top + border.bottom;
if (minimum_baseline && *minimum_baseline != -1)
*minimum_baseline += border.top;
if (natural_baseline && *natural_baseline != -1)
*natural_baseline += border.top;
} }
} }
@@ -3688,7 +3732,7 @@ gtk_label_get_preferred_width (GtkWidget *widget,
gint *minimum_size, gint *minimum_size,
gint *natural_size) gint *natural_size)
{ {
gtk_label_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size); gtk_label_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size, NULL, NULL);
} }
static void static void
@@ -3696,7 +3740,7 @@ gtk_label_get_preferred_height (GtkWidget *widget,
gint *minimum_size, gint *minimum_size,
gint *natural_size) gint *natural_size)
{ {
gtk_label_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size); gtk_label_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size, NULL, NULL);
} }
static void static void
@@ -3719,7 +3763,8 @@ gtk_label_get_preferred_width_for_height (GtkWidget *widget,
get_size_for_allocation (label, GTK_ORIENTATION_VERTICAL, get_size_for_allocation (label, GTK_ORIENTATION_VERTICAL,
MAX (1, height - border.top - border.bottom), MAX (1, height - border.top - border.bottom),
minimum_width, natural_width); minimum_width, natural_width,
NULL, NULL);
if (minimum_width) if (minimum_width)
*minimum_width += border.right + border.left; *minimum_width += border.right + border.left;
@@ -3732,15 +3777,17 @@ gtk_label_get_preferred_width_for_height (GtkWidget *widget,
} }
static void static void
gtk_label_get_preferred_height_for_width (GtkWidget *widget, gtk_label_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint width, gint width,
gint *minimum_height, gint *minimum_height,
gint *natural_height) gint *natural_height,
gint *minimum_baseline,
gint *natural_baseline)
{ {
GtkLabel *label = GTK_LABEL (widget); GtkLabel *label = GTK_LABEL (widget);
GtkLabelPrivate *priv = label->priv; GtkLabelPrivate *priv = label->priv;
if (priv->wrap && (priv->angle == 0 || priv->angle == 180 || priv->angle == 360)) if (width != -1 && priv->wrap && (priv->angle == 0 || priv->angle == 180 || priv->angle == 360))
{ {
GtkBorder border; GtkBorder border;
@@ -3751,7 +3798,13 @@ gtk_label_get_preferred_height_for_width (GtkWidget *widget,
get_size_for_allocation (label, GTK_ORIENTATION_HORIZONTAL, get_size_for_allocation (label, GTK_ORIENTATION_HORIZONTAL,
MAX (1, width - border.left - border.right), MAX (1, width - border.left - border.right),
minimum_height, natural_height); minimum_height, natural_height,
minimum_baseline, natural_baseline);
if (minimum_baseline && *minimum_baseline != -1)
*minimum_baseline += border.top;
if (natural_baseline && *natural_baseline != -1)
*natural_baseline += border.top;
if (minimum_height) if (minimum_height)
*minimum_height += border.top + border.bottom; *minimum_height += border.top + border.bottom;
@@ -3760,7 +3813,18 @@ gtk_label_get_preferred_height_for_width (GtkWidget *widget,
*natural_height += border.top + border.bottom; *natural_height += border.top + border.bottom;
} }
else else
GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, minimum_height, natural_height); gtk_label_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, minimum_height, natural_height, minimum_baseline, natural_baseline);
}
static void
gtk_label_get_preferred_height_for_width (GtkWidget *widget,
gint width,
gint *minimum_height,
gint *natural_height)
{
return gtk_label_get_preferred_height_and_baseline_for_width (widget, width,
minimum_height, natural_height,
NULL, NULL);
} }
static void static void
@@ -3855,6 +3919,7 @@ get_layout_location (GtkLabel *label,
gint req_height; gint req_height;
gfloat xalign, yalign; gfloat xalign, yalign;
PangoRectangle logical; PangoRectangle logical;
gint baseline, layout_baseline, baseline_offset;
misc = GTK_MISC (label); misc = GTK_MISC (label);
widget = GTK_WIDGET (label); widget = GTK_WIDGET (label);
@@ -3887,6 +3952,15 @@ get_layout_location (GtkLabel *label,
x = floor (allocation.x + border.left + xalign * (allocation.width - req_width) - logical.x); x = floor (allocation.x + border.left + xalign * (allocation.width - req_width) - logical.x);
baseline_offset = 0;
baseline = gtk_widget_get_allocated_baseline (widget);
if (baseline != -1 && !priv->have_transform)
{
layout_baseline = pango_layout_get_baseline (priv->layout) / PANGO_SCALE;
baseline_offset = baseline - layout_baseline;
yalign = 0.0; /* Can't support yalign while baseline aligning */
}
/* bgo#315462 - For single-line labels, *do* align the requisition with /* bgo#315462 - For single-line labels, *do* align the requisition with
* respect to the allocation, even if we are under-allocated. For multi-line * respect to the allocation, even if we are under-allocated. For multi-line
* labels, always show the top of the text when they are under-allocated. The * labels, always show the top of the text when they are under-allocated. The
@@ -3901,9 +3975,9 @@ get_layout_location (GtkLabel *label,
* middle". You want to read the first line, at least, to get some context. * middle". You want to read the first line, at least, to get some context.
*/ */
if (pango_layout_get_line_count (priv->layout) == 1) if (pango_layout_get_line_count (priv->layout) == 1)
y = floor (allocation.y + border.top + (allocation.height - req_height) * yalign) - logical.y; y = floor (allocation.y + border.top + (allocation.height - req_height) * yalign) - logical.y + baseline_offset;
else else
y = floor (allocation.y + border.top + MAX ((allocation.height - req_height) * yalign, 0)) - logical.y; y = floor (allocation.y + border.top + MAX ((allocation.height - req_height) * yalign, 0)) - logical.y + baseline_offset;
if (xp) if (xp)
*xp = x; *xp = x;

View File

@@ -172,7 +172,8 @@ static const GDebugKey gtk_debug_keys[] = {
{"printing", GTK_DEBUG_PRINTING}, {"printing", GTK_DEBUG_PRINTING},
{"builder", GTK_DEBUG_BUILDER}, {"builder", GTK_DEBUG_BUILDER},
{"size-request", GTK_DEBUG_SIZE_REQUEST}, {"size-request", GTK_DEBUG_SIZE_REQUEST},
{"no-css-cache", GTK_DEBUG_NO_CSS_CACHE} {"no-css-cache", GTK_DEBUG_NO_CSS_CACHE},
{"baselines", GTK_DEBUG_BASELINES}
}; };
#endif /* G_ENABLE_DEBUG */ #endif /* G_ENABLE_DEBUG */

View File

@@ -903,6 +903,7 @@ gtk_radio_button_draw_indicator (GtkCheckButton *check_button,
gint indicator_size, indicator_spacing; gint indicator_size, indicator_spacing;
gint focus_width; gint focus_width;
gint focus_pad; gint focus_pad;
gint baseline;
guint border_width; guint border_width;
gboolean interior_focus; gboolean interior_focus;
@@ -923,9 +924,14 @@ gtk_radio_button_draw_indicator (GtkCheckButton *check_button,
_gtk_check_button_get_props (check_button, &indicator_size, &indicator_spacing); _gtk_check_button_get_props (check_button, &indicator_size, &indicator_spacing);
gtk_widget_get_allocation (widget, &allocation); gtk_widget_get_allocation (widget, &allocation);
baseline = gtk_widget_get_allocated_baseline (widget);
x = indicator_spacing + border_width; x = indicator_spacing + border_width;
y = (allocation.height - indicator_size) / 2; if (baseline == -1)
y = (allocation.height - indicator_size) / 2;
else
y = CLAMP (baseline - indicator_size * button->priv->baseline_align,
0, allocation.height - indicator_size);
child = gtk_bin_get_child (GTK_BIN (check_button)); child = gtk_bin_get_child (GTK_BIN (check_button));
if (!interior_focus || !(child && gtk_widget_get_visible (child))) if (!interior_focus || !(child && gtk_widget_get_visible (child)))

View File

@@ -93,16 +93,61 @@ get_vfunc_name (GtkOrientation orientation,
return for_size < 0 ? "get_preferred_height" : "get_preferred_height_for_width"; return for_size < 0 ? "get_preferred_height" : "get_preferred_height_for_width";
} }
static gboolean
widget_class_has_baseline_support (GtkWidgetClass *widget_class)
{
GtkWidgetClass *parent_class;
if (widget_class->get_preferred_height_and_baseline_for_width == NULL)
return FALSE;
/* This is kinda hacky, but for backwards compatibility reasons we have to handle the case
where a class previously did not support get_preferred_height_and_baseline_for_width,
but then gained support for it, and a subclass of it overrides the previous non-baseline
methods. If this happens we need to call the overridden (non-baseline supporting) versions
on the subclass, rather than the inherited but not overriddent new get_preferred_height_and_baseline_for_width.
*/
/* Loop over all parent classes that inherit the same get_preferred_height_and_baseline_for_width */
parent_class = g_type_class_peek_parent (widget_class);
while (parent_class != NULL &&
parent_class->get_preferred_height_and_baseline_for_width == widget_class->get_preferred_height_and_baseline_for_width)
{
if (parent_class->get_preferred_height != widget_class->get_preferred_height ||
parent_class->get_preferred_height_for_width != widget_class->get_preferred_height_for_width)
return FALSE;
parent_class = g_type_class_peek_parent (parent_class);
}
return TRUE;
}
gboolean
_gtk_widget_has_baseline_support (GtkWidget *widget)
{
GtkWidgetClass *widget_class;
widget_class = GTK_WIDGET_GET_CLASS (widget);
return widget_class_has_baseline_support (widget_class);
}
static void static void
gtk_widget_query_size_for_orientation (GtkWidget *widget, gtk_widget_query_size_for_orientation (GtkWidget *widget,
GtkOrientation orientation, GtkOrientation orientation,
gint for_size, gint for_size,
gint *minimum_size, gint *minimum_size,
gint *natural_size) gint *natural_size,
gint *minimum_baseline,
gint *natural_baseline)
{ {
SizeRequestCache *cache; SizeRequestCache *cache;
GtkWidgetClass *widget_class;
gint min_size = 0; gint min_size = 0;
gint nat_size = 0; gint nat_size = 0;
gint min_baseline = -1;
gint nat_baseline = -1;
gboolean found_in_cache; gboolean found_in_cache;
if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_CONSTANT_SIZE) if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_CONSTANT_SIZE)
@@ -113,7 +158,11 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
orientation, orientation,
for_size, for_size,
&min_size, &min_size,
&nat_size); &nat_size,
&min_baseline,
&nat_baseline);
widget_class = GTK_WIDGET_GET_CLASS (widget);
if (!found_in_cache) if (!found_in_cache)
{ {
@@ -126,7 +175,7 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
if (for_size < 0) if (for_size < 0)
{ {
push_recursion_check (widget, orientation, for_size); 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); pop_recursion_check (widget, orientation);
} }
else else
@@ -140,17 +189,17 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
gtk_widget_get_preferred_height (widget, &minimum_height, &natural_height); gtk_widget_get_preferred_height (widget, &minimum_height, &natural_height);
/* convert for_size to unadjusted height (for_size is a proposed allocation) */ /* convert for_size to unadjusted height (for_size is a proposed allocation) */
GTK_WIDGET_GET_CLASS (widget)->adjust_size_allocation (widget, widget_class->adjust_size_allocation (widget,
GTK_ORIENTATION_VERTICAL, GTK_ORIENTATION_VERTICAL,
&minimum_height, &minimum_height,
&natural_height, &natural_height,
&ignored_position, &ignored_position,
&adjusted_for_size); &adjusted_for_size);
push_recursion_check (widget, orientation, for_size); push_recursion_check (widget, orientation, for_size);
GTK_WIDGET_GET_CLASS (widget)->get_preferred_width_for_height (widget, widget_class->get_preferred_width_for_height (widget,
MAX (adjusted_for_size, minimum_height), MAX (adjusted_for_size, minimum_height),
&min_size, &nat_size); &min_size, &nat_size);
pop_recursion_check (widget, orientation); pop_recursion_check (widget, orientation);
} }
} }
@@ -159,7 +208,12 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
if (for_size < 0) if (for_size < 0)
{ {
push_recursion_check (widget, orientation, for_size); push_recursion_check (widget, orientation, for_size);
GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, &min_size, &nat_size); if (widget_class_has_baseline_support (widget_class))
widget_class->get_preferred_height_and_baseline_for_width (widget, -1,
&min_size, &nat_size,
&min_baseline, &nat_baseline);
else
widget_class->get_preferred_height (widget, &min_size, &nat_size);
pop_recursion_check (widget, orientation); pop_recursion_check (widget, orientation);
} }
else else
@@ -173,17 +227,21 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
gtk_widget_get_preferred_width (widget, &minimum_width, &natural_width); gtk_widget_get_preferred_width (widget, &minimum_width, &natural_width);
/* convert for_size to unadjusted width (for_size is a proposed allocation) */ /* convert for_size to unadjusted width (for_size is a proposed allocation) */
GTK_WIDGET_GET_CLASS (widget)->adjust_size_allocation (widget, widget_class->adjust_size_allocation (widget,
GTK_ORIENTATION_HORIZONTAL, GTK_ORIENTATION_HORIZONTAL,
&minimum_width, &minimum_width,
&natural_width, &natural_width,
&ignored_position, &ignored_position,
&adjusted_for_size); &adjusted_for_size);
push_recursion_check (widget, orientation, for_size); push_recursion_check (widget, orientation, for_size);
GTK_WIDGET_GET_CLASS (widget)->get_preferred_height_for_width (widget, if (widget_class_has_baseline_support (widget_class))
MAX (adjusted_for_size, minimum_width), widget_class->get_preferred_height_and_baseline_for_width (widget, MAX (adjusted_for_size, minimum_width),
&min_size, &nat_size); &min_size, &nat_size,
&min_baseline, &nat_baseline);
else
widget_class->get_preferred_height_for_width (widget, MAX (adjusted_for_size, minimum_width),
&min_size, &nat_size);
pop_recursion_check (widget, orientation); pop_recursion_check (widget, orientation);
} }
} }
@@ -196,10 +254,10 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
adjusted_min = min_size; adjusted_min = min_size;
adjusted_natural = nat_size; adjusted_natural = nat_size;
GTK_WIDGET_GET_CLASS (widget)->adjust_size_request (widget, widget_class->adjust_size_request (widget,
orientation, orientation,
&adjusted_min, &adjusted_min,
&adjusted_natural); &adjusted_natural);
if (adjusted_min < min_size || if (adjusted_min < min_size ||
adjusted_natural < nat_size) adjusted_natural < nat_size)
@@ -227,11 +285,42 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
nat_size = adjusted_natural; 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, _gtk_size_request_cache_commit (cache,
orientation, orientation,
for_size, for_size,
min_size, min_size,
nat_size); nat_size,
min_baseline,
nat_baseline);
} }
if (minimum_size) if (minimum_size)
@@ -240,15 +329,26 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
if (natural_size) if (natural_size)
*natural_size = nat_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); g_assert (min_size <= nat_size);
GTK_NOTE (SIZE_REQUEST, 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), widget, G_OBJECT_TYPE_NAME (widget),
orientation == GTK_ORIENTATION_HORIZONTAL ? orientation == GTK_ORIENTATION_HORIZONTAL ?
"width for height" : "height for width" , "width for height" : "height for width" ,
for_size, min_size, nat_size, for_size, min_size, nat_size);
found_in_cache ? "yes" : "no")); 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 /* This is the main function that checks for a cached size and
@@ -261,7 +361,9 @@ _gtk_widget_compute_size_for_orientation (GtkWidget *widget,
GtkOrientation orientation, GtkOrientation orientation,
gint for_size, gint for_size,
gint *minimum, gint *minimum,
gint *natural) gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{ {
GHashTable *widgets; GHashTable *widgets;
GHashTableIter iter; GHashTableIter iter;
@@ -274,12 +376,17 @@ _gtk_widget_compute_size_for_orientation (GtkWidget *widget,
*minimum = 0; *minimum = 0;
if (natural) if (natural)
*natural = 0; *natural = 0;
if (minimum_baseline)
*minimum_baseline = -1;
if (natural_baseline)
*natural_baseline = -1;
return; return;
} }
if (G_LIKELY (!_gtk_widget_get_sizegroups (widget))) 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; return;
} }
@@ -293,7 +400,7 @@ _gtk_widget_compute_size_for_orientation (GtkWidget *widget,
GtkWidget *tmp_widget = key; GtkWidget *tmp_widget = key;
gint min_dimension, nat_dimension; 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); min_result = MAX (min_result, min_dimension);
nat_result = MAX (nat_result, nat_dimension); nat_result = MAX (nat_result, nat_dimension);
@@ -303,6 +410,13 @@ _gtk_widget_compute_size_for_orientation (GtkWidget *widget,
g_hash_table_destroy (widgets); 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) if (minimum)
*minimum = min_result; *minimum = min_result;
@@ -375,7 +489,8 @@ gtk_widget_get_preferred_width (GtkWidget *widget,
GTK_ORIENTATION_HORIZONTAL, GTK_ORIENTATION_HORIZONTAL,
-1, -1,
minimum_width, minimum_width,
natural_width); natural_width,
NULL, NULL);
} }
@@ -409,7 +524,8 @@ gtk_widget_get_preferred_height (GtkWidget *widget,
GTK_ORIENTATION_VERTICAL, GTK_ORIENTATION_VERTICAL,
-1, -1,
minimum_height, minimum_height,
natural_height); natural_height,
NULL, NULL);
} }
@@ -446,7 +562,8 @@ gtk_widget_get_preferred_width_for_height (GtkWidget *widget,
GTK_ORIENTATION_HORIZONTAL, GTK_ORIENTATION_HORIZONTAL,
height, height,
minimum_width, minimum_width,
natural_width); natural_width,
NULL, NULL);
} }
/** /**
@@ -481,7 +598,122 @@ gtk_widget_get_preferred_height_for_width (GtkWidget *widget,
GTK_ORIENTATION_VERTICAL, GTK_ORIENTATION_VERTICAL,
width, width,
minimum_height, minimum_height,
natural_height); natural_height,
NULL, NULL);
}
/**
* 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 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
* 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>
*
* Since: 3.10
*/
void
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;
g_return_if_fail (GTK_IS_WIDGET (widget));
if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
{
gtk_widget_get_preferred_width (widget, &min_width, &nat_width);
if (minimum_size)
{
minimum_size->width = min_width;
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_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_and_baseline_for_width (widget, -1, &min_height, &nat_height, minimum_baseline, natural_baseline);
if (minimum_size)
{
minimum_size->height = min_height;
gtk_widget_get_preferred_width_for_height (widget, min_height,
&minimum_size->width, NULL);
}
if (natural_size)
{
natural_size->height = nat_height;
gtk_widget_get_preferred_width_for_height (widget, nat_height,
NULL, &natural_size->width);
}
}
} }
/** /**
@@ -503,6 +735,9 @@ gtk_widget_get_preferred_height_for_width (GtkWidget *widget,
* height for the natural width is generally smaller than the required height for * height for the natural width is generally smaller than the required height for
* the minimum width.</para></note> * the minimum width.</para></note>
* *
* Use gtk_widget_get_preferred_size_and_baseline() if you want to support
* baseline alignment.
*
* Since: 3.0 * Since: 3.0
*/ */
void void
@@ -510,50 +745,10 @@ gtk_widget_get_preferred_size (GtkWidget *widget,
GtkRequisition *minimum_size, GtkRequisition *minimum_size,
GtkRequisition *natural_size) GtkRequisition *natural_size)
{ {
gint min_width, nat_width; gtk_widget_get_preferred_size_and_baseline (widget, minimum_size, natural_size,
gint min_height, nat_height; NULL, NULL);
g_return_if_fail (GTK_IS_WIDGET (widget));
if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
{
gtk_widget_get_preferred_width (widget, &min_width, &nat_width);
if (minimum_size)
{
minimum_size->width = min_width;
gtk_widget_get_preferred_height_for_width (widget, min_width,
&minimum_size->height, NULL);
}
if (natural_size)
{
natural_size->width = nat_width;
gtk_widget_get_preferred_height_for_width (widget, nat_width,
NULL, &natural_size->height);
}
}
else /* GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT or CONSTANT_SIZE */
{
gtk_widget_get_preferred_height (widget, &min_height, &nat_height);
if (minimum_size)
{
minimum_size->height = min_height;
gtk_widget_get_preferred_width_for_height (widget, min_height,
&minimum_size->width, NULL);
}
if (natural_size)
{
natural_size->height = nat_height;
gtk_widget_get_preferred_width_for_height (widget, nat_height,
NULL, &natural_size->width);
}
}
} }
static gint static gint
compare_gap (gconstpointer p1, compare_gap (gconstpointer p1,
gconstpointer p2, gconstpointer p2,

View File

@@ -32,31 +32,38 @@ _gtk_size_request_cache_init (SizeRequestCache *cache)
} }
static void static void
free_sizes (SizeRequest **sizes) free_sizes_x (SizeRequestX **sizes)
{ {
gint i; gint i;
for (i = 0; i < GTK_SIZE_REQUEST_CACHED_SIZES && sizes[i] != NULL; i++) for (i = 0; i < GTK_SIZE_REQUEST_CACHED_SIZES && sizes[i] != NULL; i++)
g_slice_free (SizeRequest, sizes[i]); g_slice_free (SizeRequestX, sizes[i]);
g_slice_free1 (sizeof (SizeRequest *) * GTK_SIZE_REQUEST_CACHED_SIZES, sizes); g_slice_free1 (sizeof (SizeRequestY *) * GTK_SIZE_REQUEST_CACHED_SIZES, sizes);
}
static void
free_sizes_y (SizeRequestY **sizes)
{
gint i;
for (i = 0; i < GTK_SIZE_REQUEST_CACHED_SIZES && sizes[i] != NULL; i++)
g_slice_free (SizeRequestY, sizes[i]);
g_slice_free1 (sizeof (SizeRequestY *) * GTK_SIZE_REQUEST_CACHED_SIZES, sizes);
} }
void void
_gtk_size_request_cache_free (SizeRequestCache *cache) _gtk_size_request_cache_free (SizeRequestCache *cache)
{ {
guint i; if (cache->requests_x)
free_sizes_x (cache->requests_x);
for (i = 0; i < 2; i++) if (cache->requests_x)
{ free_sizes_y (cache->requests_y);
if (cache->requests[i])
free_sizes (cache->requests[i]);
}
} }
void void
_gtk_size_request_cache_clear (SizeRequestCache *cache) _gtk_size_request_cache_clear (SizeRequestCache *cache)
{ {
_gtk_size_request_cache_free (cache); _gtk_size_request_cache_free (cache);
_gtk_size_request_cache_init (cache); _gtk_size_request_cache_init (cache);
@@ -67,17 +74,34 @@ _gtk_size_request_cache_commit (SizeRequestCache *cache,
GtkOrientation orientation, GtkOrientation orientation,
gint for_size, gint for_size,
gint minimum_size, gint minimum_size,
gint natural_size) gint natural_size,
gint minimum_baseline,
gint natural_baseline)
{ {
SizeRequest **cached_sizes;
SizeRequest *cached_size;
guint i, n_sizes; guint i, n_sizes;
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
g_assert (minimum_baseline == -1);
g_assert (natural_baseline == -1);
}
/* First handle caching of the base requests */ /* First handle caching of the base requests */
if (for_size < 0) if (for_size < 0)
{ {
cache->cached_size[orientation].minimum_size = minimum_size; if (orientation == GTK_ORIENTATION_HORIZONTAL)
cache->cached_size[orientation].natural_size = natural_size; {
cache->cached_size_x.minimum_size = minimum_size;
cache->cached_size_x.natural_size = natural_size;
}
else
{
cache->cached_size_y.minimum_size = minimum_size;
cache->cached_size_y.natural_size = natural_size;
cache->cached_size_y.minimum_baseline = minimum_baseline;
cache->cached_size_y.natural_baseline = natural_baseline;
}
cache->flags[orientation].cached_size_valid = TRUE; cache->flags[orientation].cached_size_valid = TRUE;
return; return;
} }
@@ -86,45 +110,99 @@ _gtk_size_request_cache_commit (SizeRequestCache *cache,
* in the cache and if this result can be used to extend * in the cache and if this result can be used to extend
* that cache entry * that cache entry
*/ */
cached_sizes = cache->requests[orientation];
n_sizes = cache->flags[orientation].n_cached_requests; n_sizes = cache->flags[orientation].n_cached_requests;
for (i = 0; i < n_sizes; i++)
{
if (cached_sizes[i]->cached_size.minimum_size == minimum_size &&
cached_sizes[i]->cached_size.natural_size == natural_size)
{
cached_sizes[i]->lower_for_size = MIN (cached_sizes[i]->lower_for_size, for_size);
cached_sizes[i]->upper_for_size = MAX (cached_sizes[i]->upper_for_size, for_size);
return;
}
}
/* If not found, pull a new size from the cache, the returned size cache if (orientation == GTK_ORIENTATION_HORIZONTAL)
* will immediately be used to cache the new computed size so we go ahead
* and increment the last_cached_request right away */
if (n_sizes < GTK_SIZE_REQUEST_CACHED_SIZES)
{ {
cache->flags[orientation].n_cached_requests++; SizeRequestX **cached_sizes;
cache->flags[orientation].last_cached_request = cache->flags[orientation].n_cached_requests - 1; SizeRequestX *cached_size;
cached_sizes = cache->requests_x;
for (i = 0; i < n_sizes; i++)
{
if (cached_sizes[i]->cached_size.minimum_size == minimum_size &&
cached_sizes[i]->cached_size.natural_size == natural_size)
{
cached_sizes[i]->lower_for_size = MIN (cached_sizes[i]->lower_for_size, for_size);
cached_sizes[i]->upper_for_size = MAX (cached_sizes[i]->upper_for_size, for_size);
return;
}
}
/* If not found, pull a new size from the cache, the returned size cache
* will immediately be used to cache the new computed size so we go ahead
* and increment the last_cached_request right away */
if (n_sizes < GTK_SIZE_REQUEST_CACHED_SIZES)
{
cache->flags[orientation].n_cached_requests++;
cache->flags[orientation].last_cached_request = cache->flags[orientation].n_cached_requests - 1;
}
else
{
if (++cache->flags[orientation].last_cached_request == GTK_SIZE_REQUEST_CACHED_SIZES)
cache->flags[orientation].last_cached_request = 0;
}
if (cache->requests_x == NULL)
cache->requests_x = g_slice_alloc0 (sizeof (SizeRequestX *) * GTK_SIZE_REQUEST_CACHED_SIZES);
if (cache->requests_x[cache->flags[orientation].last_cached_request] == NULL)
cache->requests_x[cache->flags[orientation].last_cached_request] = g_slice_new (SizeRequestX);
cached_size = cache->requests_x[cache->flags[orientation].last_cached_request];
cached_size->lower_for_size = for_size;
cached_size->upper_for_size = for_size;
cached_size->cached_size.minimum_size = minimum_size;
cached_size->cached_size.natural_size = natural_size;
} }
else else
{ {
if (++cache->flags[orientation].last_cached_request == GTK_SIZE_REQUEST_CACHED_SIZES) SizeRequestY **cached_sizes;
cache->flags[orientation].last_cached_request = 0; SizeRequestY *cached_size;
cached_sizes = cache->requests_y;
for (i = 0; i < n_sizes; i++)
{
if (cached_sizes[i]->cached_size.minimum_size == minimum_size &&
cached_sizes[i]->cached_size.natural_size == natural_size &&
cached_sizes[i]->cached_size.minimum_baseline == minimum_baseline &&
cached_sizes[i]->cached_size.natural_baseline == natural_baseline)
{
cached_sizes[i]->lower_for_size = MIN (cached_sizes[i]->lower_for_size, for_size);
cached_sizes[i]->upper_for_size = MAX (cached_sizes[i]->upper_for_size, for_size);
return;
}
}
/* If not found, pull a new size from the cache, the returned size cache
* will immediately be used to cache the new computed size so we go ahead
* and increment the last_cached_request right away */
if (n_sizes < GTK_SIZE_REQUEST_CACHED_SIZES)
{
cache->flags[orientation].n_cached_requests++;
cache->flags[orientation].last_cached_request = cache->flags[orientation].n_cached_requests - 1;
}
else
{
if (++cache->flags[orientation].last_cached_request == GTK_SIZE_REQUEST_CACHED_SIZES)
cache->flags[orientation].last_cached_request = 0;
}
if (cache->requests_y == NULL)
cache->requests_y = g_slice_alloc0 (sizeof (SizeRequestY *) * GTK_SIZE_REQUEST_CACHED_SIZES);
if (cache->requests_y[cache->flags[orientation].last_cached_request] == NULL)
cache->requests_y[cache->flags[orientation].last_cached_request] = g_slice_new (SizeRequestY);
cached_size = cache->requests_y[cache->flags[orientation].last_cached_request];
cached_size->lower_for_size = for_size;
cached_size->upper_for_size = for_size;
cached_size->cached_size.minimum_size = minimum_size;
cached_size->cached_size.natural_size = natural_size;
cached_size->cached_size.minimum_baseline = minimum_baseline;
cached_size->cached_size.natural_baseline = natural_baseline;
} }
if (cache->requests[orientation] == NULL)
cache->requests[orientation] = g_slice_alloc0 (sizeof (SizeRequest *) * GTK_SIZE_REQUEST_CACHED_SIZES);
if (cache->requests[orientation][cache->flags[orientation].last_cached_request] == NULL)
cache->requests[orientation][cache->flags[orientation].last_cached_request] = g_slice_new (SizeRequest);
cached_size = cache->requests[orientation][cache->flags[orientation].last_cached_request];
cached_size->lower_for_size = for_size;
cached_size->upper_for_size = for_size;
cached_size->cached_size.minimum_size = minimum_size;
cached_size->cached_size.natural_size = natural_size;
} }
/* looks for a cached size request for this for_size. /* looks for a cached size request for this for_size.
@@ -137,40 +215,85 @@ _gtk_size_request_cache_lookup (SizeRequestCache *cache,
GtkOrientation orientation, GtkOrientation orientation,
gint for_size, gint for_size,
gint *minimum, gint *minimum,
gint *natural) gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{ {
CachedSize *result = NULL; if (orientation == GTK_ORIENTATION_HORIZONTAL)
if (for_size < 0)
{ {
if (cache->flags[orientation].cached_size_valid) CachedSizeX *result = NULL;
result = &cache->cached_size[orientation];
if (for_size < 0)
{
if (cache->flags[orientation].cached_size_valid)
result = &cache->cached_size_x;
}
else
{
guint i;
/* Search for an already cached size */
for (i = 0; i < cache->flags[orientation].n_cached_requests; i++)
{
SizeRequestX *cur = cache->requests_x[i];
if (cur->lower_for_size <= for_size &&
cur->upper_for_size >= for_size)
{
result = &cur->cached_size;
break;
}
}
}
if (result)
{
*minimum = result->minimum_size;
*natural = result->natural_size;
*minimum_baseline = -1;
*natural_baseline = -1;
return TRUE;
}
else
return FALSE;
} }
else else
{ {
guint i; CachedSizeY *result = NULL;
/* Search for an already cached size */ if (for_size < 0)
for (i = 0; i < cache->flags[orientation].n_cached_requests; i++) {
{ if (cache->flags[orientation].cached_size_valid)
SizeRequest *cur = cache->requests[orientation][i]; result = &cache->cached_size_y;
}
else
{
guint i;
if (cur->lower_for_size <= for_size && /* Search for an already cached size */
cur->upper_for_size >= for_size) for (i = 0; i < cache->flags[orientation].n_cached_requests; i++)
{ {
result = &cur->cached_size; SizeRequestY *cur = cache->requests_y[i];
break;
} if (cur->lower_for_size <= for_size &&
} cur->upper_for_size >= for_size)
{
result = &cur->cached_size;
break;
}
}
}
if (result)
{
*minimum = result->minimum_size;
*natural = result->natural_size;
*minimum_baseline = result->minimum_baseline;
*natural_baseline = result->natural_baseline;
return TRUE;
}
else
return FALSE;
} }
if (result)
{
*minimum = result->minimum_size;
*natural = result->natural_size;
return TRUE;
}
else
return FALSE;
} }

View File

@@ -41,19 +41,35 @@ G_BEGIN_DECLS
typedef struct { typedef struct {
gint minimum_size; gint minimum_size;
gint natural_size; gint natural_size;
} CachedSize; } CachedSizeX;
typedef struct {
gint minimum_size;
gint natural_size;
gint minimum_baseline;
gint natural_baseline;
} CachedSizeY;
typedef struct typedef struct
{ {
gint lower_for_size; /* The minimum for_size with the same result */ gint lower_for_size; /* The minimum for_size with the same result */
gint upper_for_size; /* The maximum for_size with the same result */ gint upper_for_size; /* The maximum for_size with the same result */
CachedSize cached_size; CachedSizeX cached_size;
} SizeRequest; } SizeRequestX;
typedef struct
{
gint lower_for_size; /* The minimum for_size with the same result */
gint upper_for_size; /* The maximum for_size with the same result */
CachedSizeY cached_size;
} SizeRequestY;
typedef struct { typedef struct {
SizeRequest **requests[2]; SizeRequestX **requests_x;
SizeRequestY **requests_y;
CachedSize cached_size[2]; CachedSizeX cached_size_x;
CachedSizeY cached_size_y;
GtkSizeRequestMode request_mode : 3; GtkSizeRequestMode request_mode : 3;
guint request_mode_valid : 1; guint request_mode_valid : 1;
@@ -72,12 +88,16 @@ void _gtk_size_request_cache_commit (SizeRequestCach
GtkOrientation orientation, GtkOrientation orientation,
gint for_size, gint for_size,
gint minimum_size, gint minimum_size,
gint natural_size); gint natural_size,
gint minimum_baseline,
gint natural_baseline);
gboolean _gtk_size_request_cache_lookup (SizeRequestCache *cache, gboolean _gtk_size_request_cache_lookup (SizeRequestCache *cache,
GtkOrientation orientation, GtkOrientation orientation,
gint for_size, gint for_size,
gint *minimum, gint *minimum,
gint *natural); gint *natural,
gint *minimum_baseline,
gint *natural_baseline);
G_END_DECLS G_END_DECLS

View File

@@ -222,6 +222,12 @@ static void gtk_spin_button_get_preferred_width (GtkWidget *widget,
static void gtk_spin_button_get_preferred_height (GtkWidget *widget, static void gtk_spin_button_get_preferred_height (GtkWidget *widget,
gint *minimum, gint *minimum,
gint *natural); gint *natural);
static void gtk_spin_button_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint width,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline);
static void gtk_spin_button_size_allocate (GtkWidget *widget, static void gtk_spin_button_size_allocate (GtkWidget *widget,
GtkAllocation *allocation); GtkAllocation *allocation);
static gint gtk_spin_button_draw (GtkWidget *widget, static gint gtk_spin_button_draw (GtkWidget *widget,
@@ -309,6 +315,7 @@ gtk_spin_button_class_init (GtkSpinButtonClass *class)
widget_class->unrealize = gtk_spin_button_unrealize; widget_class->unrealize = gtk_spin_button_unrealize;
widget_class->get_preferred_width = gtk_spin_button_get_preferred_width; widget_class->get_preferred_width = gtk_spin_button_get_preferred_width;
widget_class->get_preferred_height = gtk_spin_button_get_preferred_height; widget_class->get_preferred_height = gtk_spin_button_get_preferred_height;
widget_class->get_preferred_height_and_baseline_for_width = gtk_spin_button_get_preferred_height_and_baseline_for_width;
widget_class->size_allocate = gtk_spin_button_size_allocate; widget_class->size_allocate = gtk_spin_button_size_allocate;
widget_class->draw = gtk_spin_button_draw; widget_class->draw = gtk_spin_button_draw;
widget_class->scroll_event = gtk_spin_button_scroll; widget_class->scroll_event = gtk_spin_button_scroll;
@@ -1197,14 +1204,20 @@ gtk_spin_button_get_preferred_width (GtkWidget *widget,
} }
static void static void
gtk_spin_button_get_preferred_height (GtkWidget *widget, gtk_spin_button_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint *minimum, gint width,
gint *natural) gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{ {
GtkSpinButton *spin_button = GTK_SPIN_BUTTON (widget); GtkSpinButton *spin_button = GTK_SPIN_BUTTON (widget);
GtkSpinButtonPrivate *priv = spin_button->priv; GtkSpinButtonPrivate *priv = spin_button->priv;
GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->get_preferred_height (widget, minimum, natural); GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->get_preferred_height_and_baseline_for_width (widget, width,
minimum, natural,
minimum_baseline,
natural_baseline);
if (priv->orientation == GTK_ORIENTATION_VERTICAL) if (priv->orientation == GTK_ORIENTATION_VERTICAL)
{ {
@@ -1216,9 +1229,22 @@ gtk_spin_button_get_preferred_height (GtkWidget *widget,
*minimum += up_panel_height + down_panel_height; *minimum += up_panel_height + down_panel_height;
*natural += up_panel_height + down_panel_height; *natural += up_panel_height + down_panel_height;
if (minimum_baseline && *minimum_baseline != -1)
*minimum_baseline += up_panel_height;
if (natural_baseline && *natural_baseline != -1)
*natural_baseline += up_panel_height;
} }
} }
static void
gtk_spin_button_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural)
{
gtk_spin_button_get_preferred_height_and_baseline_for_width (widget, -1, minimum, natural, NULL, NULL);
}
static void static void
gtk_spin_button_size_allocate (GtkWidget *widget, gtk_spin_button_size_allocate (GtkWidget *widget,
GtkAllocation *allocation) GtkAllocation *allocation)

View File

@@ -95,6 +95,7 @@
* <listitem>#GtkWidgetClass.get_preferred_height()</listitem> * <listitem>#GtkWidgetClass.get_preferred_height()</listitem>
* <listitem>#GtkWidgetClass.get_preferred_height_for_width()</listitem> * <listitem>#GtkWidgetClass.get_preferred_height_for_width()</listitem>
* <listitem>#GtkWidgetClass.get_preferred_width_for_height()</listitem> * <listitem>#GtkWidgetClass.get_preferred_width_for_height()</listitem>
* <listitem>#GtkWidgetClass.get_preferred_height_and_baseline_for_width()</listitem>
* </itemizedlist> * </itemizedlist>
* *
* There are some important things to keep in mind when implementing * There are some important things to keep in mind when implementing
@@ -222,6 +223,26 @@
* container, you <emphasis>must</emphasis> use the wrapper APIs. * container, you <emphasis>must</emphasis> use the wrapper APIs.
* Otherwise, you would not properly consider widget margins, * Otherwise, you would not properly consider widget margins,
* #GtkSizeGroup, and so forth. * #GtkSizeGroup, and so forth.
*
* Since 3.10 Gtk+ also supports baseline vertical alignment of widgets. This
* means that widgets are positioned such that the typographical baseline of
* widgets in the same row are aligned. This happens if a widget supports baselines,
* has a vertical alignment of %GTK_ALIGN_BASELINE, and is inside a container
* that supports baselines and has a natural "row" that it aligns to the baseline,
* or a baseline assigned to it by the grandparent.
*
* Baseline alignment support for a widget is done by the #GtkWidgetClass.get_preferred_height_and_baseline_for_width()
* virtual function. It allows you to report a baseline in combination with the
* minimum and natural height. If there is no baseline you can return -1 to indicate
* this. The default implementation of this virtual function calls into the
* #GtkWidgetClass.get_preferred_height() and #GtkWidgetClass.get_preferred_height_for_width(),
* so if baselines are not supported it doesn't need to be implemented.
*
* If a widget ends up baseline aligned it will be allocated all the space in the parent
* as if it was %GTK_ALIGN_FILL, but the selected baseline can be found via gtk_widget_get_allocated_baseline().
* If this has a value other than -1 you need to align the widget such that the baseline
* appears at the position.
*
* </para> * </para>
* </refsect2> * </refsect2>
* <refsect2 id="style-properties"> * <refsect2 id="style-properties">
@@ -395,6 +416,7 @@ struct _GtkWidgetPrivate
/* The widget's allocated size */ /* The widget's allocated size */
GtkAllocation allocation; GtkAllocation allocation;
gint allocated_baseline;
/* The widget's requested sizes */ /* The widget's requested sizes */
SizeRequestCache requests; SizeRequestCache requests;
@@ -697,12 +719,17 @@ static void gtk_widget_real_adjust_size_request (GtkWidget
GtkOrientation orientation, GtkOrientation orientation,
gint *minimum_size, gint *minimum_size,
gint *natural_size); gint *natural_size);
static void gtk_widget_real_adjust_baseline_request (GtkWidget *widget,
gint *minimum_baseline,
gint *natural_baseline);
static void gtk_widget_real_adjust_size_allocation (GtkWidget *widget, static void gtk_widget_real_adjust_size_allocation (GtkWidget *widget,
GtkOrientation orientation, GtkOrientation orientation,
gint *minimum_size, gint *minimum_size,
gint *natural_size, gint *natural_size,
gint *allocated_pos, gint *allocated_pos,
gint *allocated_size); gint *allocated_size);
static void gtk_widget_real_adjust_baseline_allocation (GtkWidget *widget,
gint *baseline);
static void gtk_widget_set_usize_internal (GtkWidget *widget, static void gtk_widget_set_usize_internal (GtkWidget *widget,
gint width, gint width,
@@ -984,6 +1011,7 @@ gtk_widget_class_init (GtkWidgetClass *klass)
klass->get_preferred_height = gtk_widget_real_get_height; klass->get_preferred_height = gtk_widget_real_get_height;
klass->get_preferred_width_for_height = gtk_widget_real_get_width_for_height; klass->get_preferred_width_for_height = gtk_widget_real_get_width_for_height;
klass->get_preferred_height_for_width = gtk_widget_real_get_height_for_width; klass->get_preferred_height_for_width = gtk_widget_real_get_height_for_width;
klass->get_preferred_height_and_baseline_for_width = NULL;
klass->state_changed = NULL; klass->state_changed = NULL;
klass->state_flags_changed = gtk_widget_real_state_flags_changed; klass->state_flags_changed = gtk_widget_real_state_flags_changed;
klass->parent_set = NULL; klass->parent_set = NULL;
@@ -1043,7 +1071,9 @@ gtk_widget_class_init (GtkWidgetClass *klass)
klass->get_accessible = gtk_widget_real_get_accessible; klass->get_accessible = gtk_widget_real_get_accessible;
klass->adjust_size_request = gtk_widget_real_adjust_size_request; klass->adjust_size_request = gtk_widget_real_adjust_size_request;
klass->adjust_baseline_request = gtk_widget_real_adjust_baseline_request;
klass->adjust_size_allocation = gtk_widget_real_adjust_size_allocation; klass->adjust_size_allocation = gtk_widget_real_adjust_size_allocation;
klass->adjust_baseline_allocation = gtk_widget_real_adjust_baseline_allocation;
g_object_class_install_property (gobject_class, g_object_class_install_property (gobject_class,
PROP_NAME, PROP_NAME,
@@ -5189,22 +5219,31 @@ gtk_widget_invalidate_widget_windows (GtkWidget *widget,
} }
/** /**
* gtk_widget_size_allocate: * gtk_widget_size_allocate_with_baseline:
* @widget: a #GtkWidget * @widget: a #GtkWidget
* @allocation: position and size to be allocated to @widget * @allocation: position and size to be allocated to @widget
* @baseline: The baseline of the child, or -1
* *
* This function is only used by #GtkContainer subclasses, to assign a size * This function is only used by #GtkContainer subclasses, to assign a size,
* and position to their child widgets. * position and (optionally) baseline to their child widgets.
* *
* In this function, the allocation may be adjusted. It will be forced * In this function, the allocation and baseline may be adjusted. It
* to a 1x1 minimum size, and the adjust_size_allocation virtual * will be forced to a 1x1 minimum size, and the
* method on the child will be used to adjust the allocation. Standard * adjust_size_allocation virtual and adjust_baseline_allocation
* adjustments include removing the widget's margins, and applying the * methods on the child will be used to adjust the allocation and
* widget's #GtkWidget:halign and #GtkWidget:valign properties. * baseline. Standard adjustments include removing the widget's
* margins, and applying the widget's #GtkWidget:halign and
* #GtkWidget:valign properties.
*
* If the child widget does not have a valign of %GTK_ALIGN_BASELINE the
* baseline argument is ignored and -1 is used instead.
*
* Since: 3.10
**/ **/
void void
gtk_widget_size_allocate (GtkWidget *widget, gtk_widget_size_allocate_with_baseline (GtkWidget *widget,
GtkAllocation *allocation) GtkAllocation *allocation,
gint baseline)
{ {
GtkWidgetPrivate *priv; GtkWidgetPrivate *priv;
GdkRectangle real_allocation; GdkRectangle real_allocation;
@@ -5212,9 +5251,11 @@ gtk_widget_size_allocate (GtkWidget *widget,
GdkRectangle adjusted_allocation; GdkRectangle adjusted_allocation;
gboolean alloc_needed; gboolean alloc_needed;
gboolean size_changed; gboolean size_changed;
gboolean baseline_changed;
gboolean position_changed; gboolean position_changed;
gint natural_width, natural_height, dummy; gint natural_width, natural_height, dummy;
gint min_width, min_height; gint min_width, min_height;
gint old_baseline;
priv = widget->priv; priv = widget->priv;
@@ -5241,17 +5282,28 @@ gtk_widget_size_allocate (GtkWidget *widget,
} }
name = g_type_name (G_OBJECT_TYPE (G_OBJECT (widget))); name = g_type_name (G_OBJECT_TYPE (G_OBJECT (widget)));
g_print ("gtk_widget_size_allocate: %*s%s %d %d\n", g_print ("gtk_widget_size_allocate: %*s%s %d %d",
2 * depth, " ", name, 2 * depth, " ", name,
allocation->width, allocation->height); allocation->width, allocation->height);
if (baseline != -1)
g_print (" baseline: %d", baseline);
g_print ("\n");
} }
#endif /* G_ENABLE_DEBUG */ #endif /* G_ENABLE_DEBUG */
/* Never pass a baseline to a child unless it requested it.
This means containers don't have to manually check for this. */
if (baseline != -1 &&
(gtk_widget_get_valign_with_baseline (widget) != GTK_ALIGN_BASELINE ||
!_gtk_widget_has_baseline_support (widget)))
baseline = -1;
alloc_needed = priv->alloc_needed; alloc_needed = priv->alloc_needed;
/* Preserve request/allocate ordering */ /* Preserve request/allocate ordering */
priv->alloc_needed = FALSE; priv->alloc_needed = FALSE;
old_allocation = priv->allocation; old_allocation = priv->allocation;
old_baseline = priv->allocated_baseline;
real_allocation = *allocation; real_allocation = *allocation;
adjusted_allocation = real_allocation; adjusted_allocation = real_allocation;
@@ -5301,6 +5353,9 @@ gtk_widget_size_allocate (GtkWidget *widget,
&natural_height, &natural_height,
&adjusted_allocation.y, &adjusted_allocation.y,
&adjusted_allocation.height); &adjusted_allocation.height);
if (baseline >= 0)
GTK_WIDGET_GET_CLASS (widget)->adjust_baseline_allocation (widget,
&baseline);
if (adjusted_allocation.x < real_allocation.x || if (adjusted_allocation.x < real_allocation.x ||
adjusted_allocation.y < real_allocation.y || adjusted_allocation.y < real_allocation.y ||
@@ -5330,14 +5385,16 @@ gtk_widget_size_allocate (GtkWidget *widget,
real_allocation.width = MAX (real_allocation.width, 1); real_allocation.width = MAX (real_allocation.width, 1);
real_allocation.height = MAX (real_allocation.height, 1); real_allocation.height = MAX (real_allocation.height, 1);
baseline_changed = old_baseline != baseline;
size_changed = (old_allocation.width != real_allocation.width || size_changed = (old_allocation.width != real_allocation.width ||
old_allocation.height != real_allocation.height); old_allocation.height != real_allocation.height);
position_changed = (old_allocation.x != real_allocation.x || position_changed = (old_allocation.x != real_allocation.x ||
old_allocation.y != real_allocation.y); old_allocation.y != real_allocation.y);
if (!alloc_needed && !size_changed && !position_changed) if (!alloc_needed && !size_changed && !position_changed && !baseline_changed)
goto out; goto out;
priv->allocated_baseline = baseline;
g_signal_emit (widget, widget_signals[SIZE_ALLOCATE], 0, &real_allocation); g_signal_emit (widget, widget_signals[SIZE_ALLOCATE], 0, &real_allocation);
/* Size allocation is god... after consulting god, no further requests or allocations are needed */ /* Size allocation is god... after consulting god, no further requests or allocations are needed */
@@ -5356,7 +5413,7 @@ gtk_widget_size_allocate (GtkWidget *widget,
cairo_region_destroy (invalidate); cairo_region_destroy (invalidate);
} }
if (size_changed) if (size_changed || baseline_changed)
{ {
if (priv->redraw_on_alloc) if (priv->redraw_on_alloc)
{ {
@@ -5371,7 +5428,7 @@ gtk_widget_size_allocate (GtkWidget *widget,
} }
} }
if ((size_changed || position_changed) && priv->parent && if ((size_changed || position_changed || baseline_changed) && priv->parent &&
gtk_widget_get_realized (priv->parent) && _gtk_container_get_reallocate_redraws (GTK_CONTAINER (priv->parent))) gtk_widget_get_realized (priv->parent) && _gtk_container_get_reallocate_redraws (GTK_CONTAINER (priv->parent)))
{ {
cairo_region_t *invalidate = cairo_region_create_rectangle (&priv->parent->priv->allocation); cairo_region_t *invalidate = cairo_region_create_rectangle (&priv->parent->priv->allocation);
@@ -5383,6 +5440,31 @@ out:
gtk_widget_pop_verify_invariants (widget); gtk_widget_pop_verify_invariants (widget);
} }
/**
* gtk_widget_size_allocate:
* @widget: a #GtkWidget
* @allocation: position and size to be allocated to @widget
*
* This function is only used by #GtkContainer subclasses, to assign a size
* and position to their child widgets.
*
* In this function, the allocation may be adjusted. It will be forced
* to a 1x1 minimum size, and the adjust_size_allocation virtual
* method on the child will be used to adjust the allocation. Standard
* adjustments include removing the widget's margins, and applying the
* widget's #GtkWidget:halign and #GtkWidget:valign properties.
*
* For baseline support in containers you need to use gtk_widget_size_allocate_with_baseline()
* instead.
**/
void
gtk_widget_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
gtk_widget_size_allocate_with_baseline (widget, allocation, -1);
}
/** /**
* gtk_widget_common_ancestor: * gtk_widget_common_ancestor:
* @widget_a: a #GtkWidget * @widget_a: a #GtkWidget
@@ -5604,6 +5686,7 @@ adjust_for_align (GtkAlign align,
{ {
switch (align) switch (align)
{ {
case GTK_ALIGN_BASELINE:
case GTK_ALIGN_FILL: case GTK_ALIGN_FILL:
/* change nothing */ /* change nothing */
break; break;
@@ -5674,6 +5757,18 @@ gtk_widget_real_adjust_size_allocation (GtkWidget *widget,
} }
} }
static void
gtk_widget_real_adjust_baseline_allocation (GtkWidget *widget,
gint *baseline)
{
const GtkWidgetAuxInfo *aux_info;
aux_info = _gtk_widget_get_aux_info_or_defaults (widget);
if (baseline >= 0)
*baseline -= aux_info->margin.top;
}
static gboolean static gboolean
gtk_widget_real_can_activate_accel (GtkWidget *widget, gtk_widget_real_can_activate_accel (GtkWidget *widget,
guint signal_id) guint signal_id)
@@ -6166,6 +6261,26 @@ _gtk_widget_draw_internal (GtkWidget *widget,
0, cr, 0, cr,
&result); &result);
#ifdef G_ENABLE_DEBUG
if (G_UNLIKELY (gtk_get_debug_flags () & GTK_DEBUG_BASELINES))
{
gint baseline = gtk_widget_get_allocated_baseline (widget);
gint width = gtk_widget_get_allocated_width (widget);
if (baseline != -1)
{
cairo_save (cr);
cairo_new_path (cr);
cairo_move_to (cr, 0, baseline+0.5);
cairo_line_to (cr, width, baseline+0.5);
cairo_set_line_width (cr, 1.0);
cairo_set_source_rgba (cr, 1.0, 0, 0, 0.25);
cairo_stroke (cr);
cairo_restore (cr);
}
}
#endif
if (cairo_status (cr) && if (cairo_status (cr) &&
_gtk_cairo_get_event (cr)) _gtk_cairo_get_event (cr))
{ {
@@ -11015,6 +11130,28 @@ gtk_widget_real_adjust_size_request (GtkWidget *widget,
} }
} }
static void
gtk_widget_real_adjust_baseline_request (GtkWidget *widget,
gint *minimum_baseline,
gint *natural_baseline)
{
const GtkWidgetAuxInfo *aux_info;
aux_info =_gtk_widget_get_aux_info_or_defaults (widget);
if (aux_info->height >= 0)
{
/* No baseline support for explicitly set height */
*minimum_baseline = -1;
*natural_baseline = -1;
}
else
{
*minimum_baseline += aux_info->margin.top;
*natural_baseline += aux_info->margin.top;
}
}
/** /**
* _gtk_widget_peek_request_cache: * _gtk_widget_peek_request_cache:
* *
@@ -13206,19 +13343,46 @@ gtk_widget_set_halign (GtkWidget *widget,
g_object_notify (G_OBJECT (widget), "halign"); g_object_notify (G_OBJECT (widget), "halign");
} }
/**
* gtk_widget_get_valign_with_baseline:
* @widget: a #GtkWidget
*
* Gets the value of the #GtkWidget:valign property, including
* %GTK_ALIGN_BASELINE.
*
* Returns: the vertical alignment of @widget
*
* Since: 3.10
*/
GtkAlign
gtk_widget_get_valign_with_baseline (GtkWidget *widget)
{
g_return_val_if_fail (GTK_IS_WIDGET (widget), GTK_ALIGN_FILL);
return _gtk_widget_get_aux_info_or_defaults (widget)->valign;
}
/** /**
* gtk_widget_get_valign: * gtk_widget_get_valign:
* @widget: a #GtkWidget * @widget: a #GtkWidget
* *
* Gets the value of the #GtkWidget:valign property. * Gets the value of the #GtkWidget:valign property.
* *
* Returns: the vertical alignment of @widget * For backwards compatibility reasons this method will never return
* %GTK_ALIGN_BASELINE, but instead it will convert it to
* %GTK_ALIGN_FILL. If your widget want to support baseline aligned
* children it must use gtk_widget_get_valign_with_baseline().
*
* Returns: the vertical alignment of @widget, ignoring baseline alignment
*/ */
GtkAlign GtkAlign
gtk_widget_get_valign (GtkWidget *widget) gtk_widget_get_valign (GtkWidget *widget)
{ {
g_return_val_if_fail (GTK_IS_WIDGET (widget), GTK_ALIGN_FILL); GtkAlign align;
return _gtk_widget_get_aux_info_or_defaults (widget)->valign;
align = gtk_widget_get_valign_with_baseline (widget);
if (align == GTK_ALIGN_BASELINE)
return GTK_ALIGN_FILL;
return align;
} }
/** /**
@@ -13995,6 +14159,27 @@ gtk_widget_get_allocated_height (GtkWidget *widget)
return widget->priv->allocation.height; return widget->priv->allocation.height;
} }
/**
* gtk_widget_get_allocated_baseline:
* @widget: the widget to query
*
* Returns the baseline that has currently been allocated to @widget.
* This function is intended to be used when implementing handlers
* for the #GtkWidget::draw function, and when allocating child
* widgets in #GtkWidget::size_allocate.
*
* Returns: the baseline of the @widget, or -1 if none
*
* Since: 3.10
**/
int
gtk_widget_get_allocated_baseline (GtkWidget *widget)
{
g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
return widget->priv->allocated_baseline;
}
/** /**
* gtk_widget_get_requisition: * gtk_widget_get_requisition:
* @widget: a #GtkWidget * @widget: a #GtkWidget

View File

@@ -433,14 +433,23 @@ struct _GtkWidgetClass
gboolean (* touch_event) (GtkWidget *widget, gboolean (* touch_event) (GtkWidget *widget,
GdkEventTouch *event); GdkEventTouch *event);
void (* get_preferred_height_and_baseline_for_width) (GtkWidget *widget,
gint width,
gint *minimum_height,
gint *natural_height,
gint *minimum_baseline,
gint *natural_baseline);
void (* adjust_baseline_request)(GtkWidget *widget,
gint *minimum_baseline,
gint *natural_baseline);
void (* adjust_baseline_allocation) (GtkWidget *widget,
gint *baseline);
/*< private >*/ /*< private >*/
GtkWidgetClassPrivate *priv; GtkWidgetClassPrivate *priv;
/* Padding for future expansion */ /* Padding for future expansion */
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
void (*_gtk_reserved5) (void); void (*_gtk_reserved5) (void);
void (*_gtk_reserved6) (void); void (*_gtk_reserved6) (void);
void (*_gtk_reserved7) (void); void (*_gtk_reserved7) (void);
@@ -498,6 +507,10 @@ void gtk_widget_size_request (GtkWidget *widget,
GtkRequisition *requisition); GtkRequisition *requisition);
void gtk_widget_size_allocate (GtkWidget *widget, void gtk_widget_size_allocate (GtkWidget *widget,
GtkAllocation *allocation); GtkAllocation *allocation);
GDK_AVAILABLE_IN_3_10
void gtk_widget_size_allocate_with_baseline (GtkWidget *widget,
GtkAllocation *allocation,
gint baseline);
GtkSizeRequestMode gtk_widget_get_request_mode (GtkWidget *widget); GtkSizeRequestMode gtk_widget_get_request_mode (GtkWidget *widget);
void gtk_widget_get_preferred_width (GtkWidget *widget, void gtk_widget_get_preferred_width (GtkWidget *widget,
@@ -514,9 +527,22 @@ void gtk_widget_get_preferred_width_for_height (GtkWidget *w
gint height, gint height,
gint *minimum_width, gint *minimum_width,
gint *natural_width); gint *natural_width);
GDK_AVAILABLE_IN_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);
void gtk_widget_get_preferred_size (GtkWidget *widget, void gtk_widget_get_preferred_size (GtkWidget *widget,
GtkRequisition *minimum_size, GtkRequisition *minimum_size,
GtkRequisition *natural_size); GtkRequisition *natural_size);
GDK_AVAILABLE_IN_3_10
void gtk_widget_get_preferred_size_and_baseline (GtkWidget *widget,
GtkRequisition *minimum_size,
GtkRequisition *natural_size,
gint *minimum_baseline,
gint *natural_baseline);
GDK_DEPRECATED_IN_3_0_FOR(gtk_widget_get_preferred_size) GDK_DEPRECATED_IN_3_0_FOR(gtk_widget_get_preferred_size)
void gtk_widget_get_child_requisition (GtkWidget *widget, void gtk_widget_get_child_requisition (GtkWidget *widget,
@@ -662,6 +688,8 @@ void gtk_widget_unregister_window (GtkWidget *widget,
int gtk_widget_get_allocated_width (GtkWidget *widget); int gtk_widget_get_allocated_width (GtkWidget *widget);
int gtk_widget_get_allocated_height (GtkWidget *widget); int gtk_widget_get_allocated_height (GtkWidget *widget);
GDK_AVAILABLE_IN_3_10
int gtk_widget_get_allocated_baseline (GtkWidget *widget);
void gtk_widget_get_allocation (GtkWidget *widget, void gtk_widget_get_allocation (GtkWidget *widget,
GtkAllocation *allocation); GtkAllocation *allocation);
@@ -760,6 +788,8 @@ GtkAlign gtk_widget_get_halign (GtkWidget *widget);
void gtk_widget_set_halign (GtkWidget *widget, void gtk_widget_set_halign (GtkWidget *widget,
GtkAlign align); GtkAlign align);
GtkAlign gtk_widget_get_valign (GtkWidget *widget); GtkAlign gtk_widget_get_valign (GtkWidget *widget);
GDK_AVAILABLE_IN_3_10
GtkAlign gtk_widget_get_valign_with_baseline (GtkWidget *widget);
void gtk_widget_set_valign (GtkWidget *widget, void gtk_widget_set_valign (GtkWidget *widget,
GtkAlign align); GtkAlign align);
gint gtk_widget_get_margin_left (GtkWidget *widget); gint gtk_widget_get_margin_left (GtkWidget *widget);

View File

@@ -69,7 +69,10 @@ void _gtk_widget_compute_size_for_orientation (GtkWidget *widget,
GtkOrientation orientation, GtkOrientation orientation,
gint for_size, gint for_size,
gint *minimum_size, gint *minimum_size,
gint *natural_size); gint *natural_size,
gint *minimum_baseline,
gint *natural_baseline);
gboolean _gtk_widget_has_baseline_support (GtkWidget *widget);
gboolean _gtk_widget_get_translation_to_window (GtkWidget *widget, gboolean _gtk_widget_get_translation_to_window (GtkWidget *widget,
GdkWindow *window, GdkWindow *window,

View File

@@ -36,6 +36,7 @@ noinst_PROGRAMS = $(TEST_PROGS) \
testappchooser \ testappchooser \
testappchooserbutton \ testappchooserbutton \
testassistant \ testassistant \
testbaseline \
testbbox \ testbbox \
testboxcss \ testboxcss \
testbuttons \ testbuttons \
@@ -165,6 +166,7 @@ testiconview_DEPENDENCIES = $(TEST_DEPS)
testaccel_DEPENDENCIES = $(TEST_DEPS) testaccel_DEPENDENCIES = $(TEST_DEPS)
testadjustsize_DEPENDENCIES = $(TEST_DEPS) testadjustsize_DEPENDENCIES = $(TEST_DEPS)
testassistant_DEPENDENCIES = $(TEST_DEPS) testassistant_DEPENDENCIES = $(TEST_DEPS)
testbaseline_DEPENDENCIES = $(TEST_DEPS)
testbbox_DEPENDENCIES = $(TEST_DEPS) testbbox_DEPENDENCIES = $(TEST_DEPS)
testbuttons_DEPENDENCIES = $(TEST_DEPS) testbuttons_DEPENDENCIES = $(TEST_DEPS)
testcairo_DEPENDENCIES = $(TEST_DEPS) testcairo_DEPENDENCIES = $(TEST_DEPS)
@@ -356,6 +358,9 @@ testmerge_SOURCES = \
testactions_SOURCES = \ testactions_SOURCES = \
testactions.c testactions.c
testbaseline_SOURCES = \
testbaseline.c
testbbox_SOURCES = \ testbbox_SOURCES = \
testbbox.c testbbox.c

382
tests/testbaseline.c Normal file
View File

@@ -0,0 +1,382 @@
/*
* Copyright (C) 2006 Nokia Corporation.
* Author: Xan Lopez <xan.lopez@nokia.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <gtk/gtk.h>
static char *baseline_pos_str[] = {
"BASELINE_POSITION_TOP",
"BASELINE_POSITION_CENTER",
"BASELINE_POSITION_BOTTOM"
};
static void
baseline_row_value_changed (GtkSpinButton *spin_button,
GtkGrid *grid)
{
gint row = gtk_spin_button_get_value_as_int (spin_button);
gtk_grid_set_baseline_row (grid, row);
}
static void
homogeneous_changed (GtkToggleButton *toggle_button,
GtkGrid *grid)
{
gtk_grid_set_row_homogeneous (grid, gtk_toggle_button_get_active (toggle_button));
}
static void
baseline_position_changed (GtkComboBox *combo,
GtkBox *hbox)
{
int i = gtk_combo_box_get_active (combo);
gtk_box_set_baseline_position (hbox, i);
}
static void
image_size_value_changed (GtkSpinButton *spin_button,
GtkImage *image)
{
gint size = gtk_spin_button_get_value_as_int (spin_button);
gtk_image_set_pixel_size (GTK_IMAGE (image), size);
}
int
main (int argc,
char **argv)
{
GtkWidget *window, *label, *entry, *button, *grid, *notebook;
GtkWidget *vbox, *hbox, *grid_hbox, *spin, *spin2, *toggle, *combo, *image, *ebox;
PangoFontDescription *font;
GtkAdjustment *adjustment;
int i, j;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (G_OBJECT (window), "delete-event", G_CALLBACK (gtk_main_quit), NULL);
notebook = gtk_notebook_new ();
gtk_container_add (GTK_CONTAINER (window), notebook);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
vbox, gtk_label_new ("hboxes"));
for (j = 0; j < 2; j++)
{
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 5);
char *aligns_names[] = { "FILL", "BASELINE" };
GtkAlign aligns[] = { GTK_ALIGN_FILL, GTK_ALIGN_BASELINE};
label = gtk_label_new (aligns_names[j]);
gtk_container_add (GTK_CONTAINER (hbox), label);
for (i = 0; i < 3; i++) {
label = gtk_label_new ("│XYyj,Ö...");
font = pango_font_description_new ();
pango_font_description_set_size (font, 5*(i+1)* 1024);
gtk_widget_override_font (label, font);
gtk_widget_set_valign (label, aligns[j]);
gtk_container_add (GTK_CONTAINER (hbox), label);
}
for (i = 0; i < 3; i++) {
entry = gtk_entry_new ();
gtk_entry_set_text (GTK_ENTRY (entry), "│XYyj,Ö...");
font = pango_font_description_new ();
pango_font_description_set_size (font, 5*(i+1)* 1024);
gtk_widget_override_font (entry, font);
gtk_widget_set_valign (entry, aligns[j]);
gtk_container_add (GTK_CONTAINER (hbox), entry);
}
spin = gtk_spin_button_new (NULL, 0, 1);
gtk_orientable_set_orientation (GTK_ORIENTABLE (spin), GTK_ORIENTATION_VERTICAL);
gtk_widget_set_valign (spin, aligns[j]);
gtk_container_add (GTK_CONTAINER (hbox), spin);
}
grid_hbox = hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
combo = gtk_combo_box_text_new ();
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), baseline_pos_str[0]);
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), baseline_pos_str[1]);
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), baseline_pos_str[2]);
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 1);
gtk_container_add (GTK_CONTAINER (hbox), combo);
for (j = 0; j < 2; j++)
{
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
g_signal_connect (G_OBJECT (combo), "changed",
G_CALLBACK (baseline_position_changed), hbox);
if (j == 0)
label = gtk_label_new ("Baseline:");
else
label = gtk_label_new ("Normal:");
gtk_container_add (GTK_CONTAINER (hbox), label);
for (i = 0; i < 3; i++)
{
button = gtk_button_new_with_label ("│Xyj,Ö");
font = pango_font_description_new ();
pango_font_description_set_size (font, 5*(i+1)* 1024);
gtk_widget_override_font (button, font);
if (j == 0)
gtk_widget_set_valign (button, GTK_ALIGN_BASELINE);
gtk_container_add (GTK_CONTAINER (hbox), button);
}
for (i = 0; i < 3; i++)
{
button = gtk_button_new_with_label ("│Xyj,Ö");
gtk_button_set_image (GTK_BUTTON (button),
gtk_image_new_from_icon_name ("face-sad", GTK_ICON_SIZE_BUTTON));
gtk_button_set_always_show_image (GTK_BUTTON (button), TRUE);
font = pango_font_description_new ();
pango_font_description_set_size (font, 5*(i+1)* 1024);
gtk_widget_override_font (button, font);
if (j == 0)
gtk_widget_set_valign (button, GTK_ALIGN_BASELINE);
gtk_container_add (GTK_CONTAINER (hbox), button);
}
ebox = gtk_event_box_new ();
if (j == 0)
gtk_widget_set_valign (ebox, GTK_ALIGN_BASELINE);
gtk_container_add (GTK_CONTAINER (hbox), ebox);
image = gtk_image_new_from_icon_name ("face-sad", GTK_ICON_SIZE_BUTTON);
gtk_image_set_pixel_size (GTK_IMAGE (image), 34);
if (j == 0)
gtk_widget_set_valign (image, GTK_ALIGN_BASELINE);
gtk_container_add (GTK_CONTAINER (ebox), image);
button = gtk_toggle_button_new_with_label ("│Xyj,Ö");
if (j == 0)
gtk_widget_set_valign (button, GTK_ALIGN_BASELINE);
gtk_container_add (GTK_CONTAINER (hbox), button);
button = gtk_toggle_button_new_with_label ("│Xyj,Ö");
gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (button), TRUE);
if (j == 0)
gtk_widget_set_valign (button, GTK_ALIGN_BASELINE);
gtk_container_add (GTK_CONTAINER (hbox), button);
button = gtk_check_button_new_with_label ("│Xyj,Ö");
if (j == 0)
gtk_widget_set_valign (button, GTK_ALIGN_BASELINE);
gtk_container_add (GTK_CONTAINER (hbox), button);
button = gtk_radio_button_new_with_label (NULL, "│Xyj,Ö");
if (j == 0)
gtk_widget_set_valign (button, GTK_ALIGN_BASELINE);
gtk_container_add (GTK_CONTAINER (hbox), button);
}
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
vbox, gtk_label_new ("grid"));
grid_hbox = hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
label = gtk_label_new ("Align me:");
gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
gtk_container_add (GTK_CONTAINER (hbox), label);
grid = gtk_grid_new ();
gtk_widget_set_valign (grid, GTK_ALIGN_BASELINE);
gtk_grid_set_column_spacing (GTK_GRID (grid), 8);
gtk_grid_set_row_spacing (GTK_GRID (grid), 8);
for (j = 0; j < 4; j++)
{
char *labels[] = { "Normal:", "Baseline (top):", "Baseline (center):", "Baseline (bottom):"};
label = gtk_label_new (labels[j]);
gtk_grid_attach (GTK_GRID (grid),
label,
0, j,
1, 1);
gtk_widget_set_vexpand (label, TRUE);
if (j != 0)
gtk_grid_set_row_baseline_position (GTK_GRID (grid),
j, (GtkBaselinePosition)(j-1));
for (i = 0; i < 3; i++)
{
label = gtk_label_new ("Xyjg,Ö.");
font = pango_font_description_new ();
pango_font_description_set_size (font, 5*(i+1)* 1024);
gtk_widget_override_font (label, font);
if (j != 0)
gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
gtk_grid_attach (GTK_GRID (grid),
label,
i+1, j,
1, 1);
}
for (i = 0; i < 3; i++)
{
button = gtk_button_new_with_label ("│Xyj,Ö");
gtk_button_set_image (GTK_BUTTON (button),
gtk_image_new_from_icon_name ("face-sad", GTK_ICON_SIZE_BUTTON));
gtk_button_set_always_show_image (GTK_BUTTON (button), TRUE);
font = pango_font_description_new ();
pango_font_description_set_size (font, 5*(i+1)* 1024);
gtk_widget_override_font (button, font);
if (j != 0)
gtk_widget_set_valign (button, GTK_ALIGN_BASELINE);
gtk_grid_attach (GTK_GRID (grid),
button,
i+4, j,
1, 1);
}
}
gtk_container_add (GTK_CONTAINER (hbox), grid);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 5);
adjustment = gtk_adjustment_new (0.0, -1.0, 5.0, 1.0, 1.0, 0.0);
spin = gtk_spin_button_new (adjustment, 1.0, 0);
g_signal_connect (spin, "value-changed", (GCallback)baseline_row_value_changed, grid);
gtk_container_add (GTK_CONTAINER (hbox), spin);
toggle = gtk_toggle_button_new_with_label ("Homogeneous");
g_signal_connect (toggle, "toggled", (GCallback)homogeneous_changed, grid);
gtk_container_add (GTK_CONTAINER (hbox), toggle);
combo = gtk_combo_box_text_new ();
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), baseline_pos_str[0]);
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), baseline_pos_str[1]);
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), baseline_pos_str[2]);
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 1);
g_signal_connect (G_OBJECT (combo), "changed",
G_CALLBACK (baseline_position_changed), grid_hbox);
gtk_container_add (GTK_CONTAINER (hbox), combo);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
vbox, gtk_label_new ("button box"));
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 5);
adjustment = gtk_adjustment_new (34.0, 1.0, 64.0, 1.0, 1.0, 0.0);
spin = gtk_spin_button_new (adjustment, 1.0, 0);
gtk_container_add (GTK_CONTAINER (hbox), spin);
adjustment = gtk_adjustment_new (16.0, 1.0, 64.0, 1.0, 1.0, 0.0);
spin2 = gtk_spin_button_new (adjustment, 1.0, 0);
gtk_container_add (GTK_CONTAINER (hbox), spin2);
for (j = 0; j < 3; j++)
{
hbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
gtk_box_set_baseline_position (GTK_BOX (hbox), j);
label = gtk_label_new (baseline_pos_str[j]);
gtk_container_add (GTK_CONTAINER (hbox), label);
gtk_widget_set_vexpand (label, TRUE);
image = gtk_image_new_from_icon_name ("face-sad", GTK_ICON_SIZE_BUTTON);
gtk_image_set_pixel_size (GTK_IMAGE (image), 34);
gtk_container_add (GTK_CONTAINER (hbox), image);
g_signal_connect (spin, "value-changed", (GCallback)image_size_value_changed, image);
for (i = 0; i < 3; i++)
{
button = gtk_button_new_with_label ("│Xyj,Ö");
font = pango_font_description_new ();
pango_font_description_set_size (font, 5*(i+1)* 1024);
gtk_widget_override_font (button, font);
if (i != 0)
gtk_widget_set_valign (button, GTK_ALIGN_BASELINE);
gtk_container_add (GTK_CONTAINER (hbox), button);
}
for (i = 0; i < 3; i++)
{
button = gtk_button_new_with_label ("│Xyj,Ö");
image = gtk_image_new_from_icon_name ("face-sad", GTK_ICON_SIZE_BUTTON);
gtk_image_set_pixel_size (GTK_IMAGE (image), 16);
gtk_button_set_image (GTK_BUTTON (button), image);
if (i == 0)
g_signal_connect (spin2, "value-changed", (GCallback)image_size_value_changed, image);
gtk_button_set_always_show_image (GTK_BUTTON (button), TRUE);
font = pango_font_description_new ();
pango_font_description_set_size (font, 5*(i+1)* 1024);
gtk_widget_override_font (button, font);
gtk_widget_set_valign (button, GTK_ALIGN_BASELINE);
gtk_container_add (GTK_CONTAINER (hbox), button);
}
}
gtk_widget_show_all (window);
gtk_main ();
return 0;
}