Compare commits

...

45 Commits

Author SHA1 Message Date
Alexander Larsson
1c2393cc73 Add docs for gtk_widget_get_preferred_size_and_baseline 2013-03-26 15:49:43 +01:00
Alexander Larsson
75fe9b5f57 Add docs for gtk_widget_get_preferred_height_and_baseline_for_width 2013-03-26 15:47:50 +01:00
Alexander Larsson
3de86b38a0 Document gtk_widget_get_allocated_baseline 2013-03-26 15:43:44 +01:00
Alexander Larsson
95d5f0c33b Document gtk_widget_get_valign_with_baseline 2013-03-26 15:43:30 +01:00
Alexander Larsson
9269fc82b1 Document gtk_widget_size_allocate_with_baseline 2013-03-26 15:43:04 +01:00
Alexander Larsson
0c4103f9b7 GtkWidget - generic baseline docs 2013-03-26 15:42:24 +01:00
Alexander Larsson
4034a13263 Document GtkBaselinePosition 2013-03-26 15:41:55 +01:00
Alexander Larsson
926c50c3f9 Document GTK_ALIGN_BASELINE 2013-03-26 15:41:29 +01:00
Alexander Larsson
0fca2a0f82 Document gtk_grid_set/get_baseline_row 2013-03-26 15:40:52 +01:00
Alexander Larsson
a4f1bc97a5 Document gtk_grid_set/get_row_baseline_position: 2013-03-26 15:40:32 +01:00
Alexander Larsson
6ce70b33c6 Document gtkbox functions 2013-03-26 15:39:32 +01:00
Alexander Larsson
8535e32b8d GtkDialog: Baseline align buttons in action area 2013-03-26 11:46:55 +01:00
Alexander Larsson
e240742d0a testbaseline: Test GtkEventBox 2013-03-26 11:46:24 +01:00
Alexander Larsson
c75e10e9ea GtkEventBox: Support baseline alignment
This allows baselines to propagate from the child of the eventbox.
2013-03-26 11:08:33 +01:00
Alexander Larsson
5405383cb2 testbaseline: Add a baseline align image to test it 2013-03-26 10:58:25 +01:00
Alexander Larsson
aeab118289 GtkButton: Baseline align butttons 2013-03-26 10:58:12 +01:00
Alexander Larsson
fc5ba0a6ef 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 10:56:53 +01:00
Alexander Larsson
3d92798c96 Fix indicator position for baseline aligned radio/check buttons
Rather than just always centering the indicator we adjust it according
to the metrics of the widget font.
2013-03-26 10:31:13 +01:00
Alexander Larsson
8cb229a847 testbase: Make test nicer 2013-03-25 18:04:19 +01:00
Alexander Larsson
9cfb89990e GtkButtonBox: Support baseline alignment 2013-03-25 17:59:55 +01:00
Alexander Larsson
8b8d6e188d GtkGrid: Modify requested baseline as per baseline_pos
If non-baseline-aligned items in the row make the height higher,
use baseline_pos to figure out where to request the baseline.
2013-03-25 17:58:29 +01:00
Alexander Larsson
f7863d7fa5 GtkBox: Modify requested baseline as per baseline_pos
If non-baseline-aligned items in the box make the height higher,
use baseline_pos to figure out where to request the baseline.
2013-03-25 17:57:07 +01:00
Alexander Larsson
7918b3d1a3 Add gtk_widget_get_preferred_size_and_baseline
This is needed by baseline & h4w/w4h aware containers.
2013-03-25 17:55:59 +01:00
Alexander Larsson
601b5f4f52 testbaseline: Test toggle, radio and checkbuttons 2013-03-22 13:19:27 +01:00
Alexander Larsson
89ef97cd25 GtkCheckButton: Implement baseline alignment 2013-03-22 13:19:27 +01:00
Alexander Larsson
8f17db9b4a GtkButton: Fix y displacement with baseline alignment
We need to shift down the baseline too when displacing y.
2013-03-22 13:19:27 +01:00
Alexander Larsson
dcacd41641 testbaseline: Test spinbuttons 2013-03-22 13:19:27 +01:00
Alexander Larsson
6b3f27c76c GtkSpinButton: Support baseline alignment 2013-03-22 13:19:27 +01:00
Alexander Larsson
faf2d7aab7 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-22 13:19:26 +01:00
Alexander Larsson
2725f74d92 testbaseline: Add more tests 2013-03-21 23:43:08 +01:00
Alexander Larsson
498bb2046a GtkGrid: Add baseline alignment of grid itself
You can now set which row is the baseline for the grid itself, and
if that row has a baseline and the grid itself is GTK_ALIGN_BASELINE
then the grid will be vertically baseline aligned.
2013-03-21 23:43:08 +01:00
Alexander Larsson
c7c2767d76 GtkGrid: Add gtk_grid_set/get_row_baseline_position 2013-03-21 23:43:07 +01:00
Alexander Larsson
e3345e74c5 GtkWidget: Redraw widget when baseline changes
The baseline affects how widget is drawn, so we need to repaint it
when the baseline changes
2013-03-21 23:43:07 +01:00
Alexander Larsson
361ff36120 Add GTK_DEBUG=baselines support
This draws red lines to show where the baselines are
2013-03-21 23:43:07 +01:00
Alexander Larsson
37c9c5e49e testbaseline: Test GtkGrid 2013-03-21 11:10:09 +01:00
Alexander Larsson
d0ab7336ba GtkGrid: Support baseline alignment in grid rows 2013-03-21 11:09:43 +01:00
Alexander Larsson
639f1407c9 testbaseline: Add entries 2013-03-20 14:30:57 +01:00
Alexander Larsson
62952efc04 GtkEntry: Support baselines 2013-03-20 14:30:41 +01:00
Alexander Larsson
21c2e6da9a Add tests/testbaseline 2013-03-20 14:06:41 +01:00
Alexander Larsson
3e2606f4f4 GtkButton: Add baseline align support 2013-03-20 14:06:41 +01:00
Alexander Larsson
ac7dcd90cc 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-20 14:06:41 +01:00
Alexander Larsson
e6b12e0fd7 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-20 14:06:41 +01:00
Alexander Larsson
f76e22b39e GtkLabel: Support baseline
Report the baseline in get_preferred_height_and_baseline_for_width().
2013-03-20 14:06:41 +01:00
Alexander Larsson
7a568a6127 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-20 14:06:41 +01:00
Alexander Larsson
df6dcfb511 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-20 14:06:41 +01:00
28 changed files with 2789 additions and 430 deletions

View File

@@ -108,6 +108,12 @@ static void gtk_alignment_get_preferred_height_for_width (GtkWidget *w
gint for_size,
gint *minimum_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)
@@ -128,6 +134,7 @@ gtk_alignment_class_init (GtkAlignmentClass *class)
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_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,
PROP_XALIGN,
@@ -507,6 +514,7 @@ gtk_alignment_size_allocate (GtkWidget *widget,
gint width, height;
guint border_width;
gint padding_horizontal, padding_vertical;
gint baseline;
padding_horizontal = 0;
padding_vertical = 0;
@@ -520,6 +528,7 @@ gtk_alignment_size_allocate (GtkWidget *widget,
gint child_nat_width;
gint child_nat_height;
gint child_width, child_height;
double yalign, yscale;
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);
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)
{
gtk_widget_get_preferred_width (child, NULL, &child_nat_width);
@@ -559,8 +587,8 @@ gtk_alignment_size_allocate (GtkWidget *widget,
if (height > child_height)
child_allocation.height = (child_height *
(1.0 - priv->yscale) +
height * priv->yscale);
(1.0 - yscale) +
height * yscale);
else
child_allocation.height = height;
@@ -569,9 +597,9 @@ gtk_alignment_size_allocate (GtkWidget *widget,
else
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,
gint for_size,
gint *minimum_size,
gint *natural_size)
gint *natural_size,
gint *minimum_baseline,
gint *natural_baseline)
{
GtkAlignment *alignment = GTK_ALIGNMENT (widget);
GtkAlignmentPrivate *priv = alignment->priv;
GtkWidget *child;
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))
{
gint child_min, child_nat;
gint child_min_baseline = -1, child_nat_baseline = -1;
/* Request extra space for the padding: */
if (orientation == GTK_ORIENTATION_HORIZONTAL)
@@ -619,9 +659,10 @@ gtk_alignment_get_preferred_size (GtkWidget *widget,
else
{
minimum += (priv->padding_top + priv->padding_bottom);
top_offset += priv->padding_top;
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
{
gint min_width;
@@ -634,8 +675,13 @@ gtk_alignment_get_preferred_size (GtkWidget *widget,
for_size = (min_width * (1.0 - 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;
@@ -656,7 +702,7 @@ gtk_alignment_get_preferred_width (GtkWidget *widget,
gint *minimum_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
@@ -664,7 +710,7 @@ gtk_alignment_get_preferred_height (GtkWidget *widget,
gint *minimum_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 *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
@@ -683,9 +729,21 @@ gtk_alignment_get_preferred_height_for_width (GtkWidget *widget,
gint *minimum_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:
* @alignment: a #GtkAlignment

View File

@@ -101,6 +101,12 @@ static void gtk_button_box_get_preferred_height_for_width (GtkWidget *widget,
gint width,
gint *minimum,
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,
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_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_and_baseline_for_width = gtk_button_box_get_preferred_height_and_baseline_for_width;
widget_class->size_allocate = gtk_button_box_size_allocate;
container_class->remove = gtk_button_box_remove;
@@ -438,7 +445,10 @@ gtk_button_box_child_requisition (GtkWidget *widget,
gint *nvis_children,
gint *nvis_secondaries,
gint **widths,
gint **heights)
gint **heights,
gint **baselines,
gint *baseline,
gint *baseline_height)
{
GtkButtonBox *bbox;
GList *children, *list;
@@ -446,6 +456,7 @@ gtk_button_box_child_requisition (GtkWidget *widget,
gint nsecondaries;
gint needed_width;
gint needed_height;
gint needed_above, needed_below;
gint avg_w, avg_h;
GtkRequisition child_requisition;
gint ipad_w;
@@ -456,11 +467,15 @@ gtk_button_box_child_requisition (GtkWidget *widget,
gint ipad_y;
gboolean homogeneous;
gint i;
gint max_above, max_below, child_baseline;
GtkOrientation orientation;
gboolean have_baseline;
g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
bbox = GTK_BUTTON_BOX (widget);
orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (widget));
homogeneous = gtk_box_get_homogeneous (GTK_BOX (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));
needed_width = child_min_width;
needed_height = child_min_height;
needed_above = 0;
needed_below = 0;
ipad_w = ipad_x * 2;
ipad_h = ipad_y * 2;
have_baseline = FALSE;
max_above = max_below = 0;
avg_w = avg_h = 0;
while (children)
for (children = list; children != NULL; children = children->next)
{
GtkWidget *child;
child = children->data;
children = children->next;
if (gtk_widget_get_visible (child))
{
nchildren += 1;
gtk_widget_get_preferred_size (child,
&child_requisition, NULL);
gtk_widget_get_preferred_size_and_baseline (child,
&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_h += child_requisition.height + ipad_h;
}
@@ -498,8 +524,14 @@ gtk_button_box_child_requisition (GtkWidget *widget,
avg_w /= 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);
*heights = g_new (gint, nchildren);
*baselines = g_new (gint, nchildren);
i = 0;
children = list;
@@ -520,7 +552,8 @@ gtk_button_box_child_requisition (GtkWidget *widget,
if (is_secondary)
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 ||
(!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;
}
(*baselines)[i] = -1;
if (homogeneous ||
(!non_homogeneous && (child_requisition.height + ipad_h < avg_h * 1.5)))
{
(*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
{
(*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++;
@@ -552,12 +607,18 @@ gtk_button_box_child_requisition (GtkWidget *widget,
g_list_free (list);
needed_height = MAX (needed_height, needed_above + needed_below);
for (i = 0; i < nchildren; i++)
{
if ((*widths)[i] == -1)
(*widths)[i] = needed_width;
if ((*heights)[i] == -1)
(*heights)[i] = needed_height;
{
(*heights)[i] = needed_height;
if ((*baselines)[i] != -1)
(*baselines)[i] = needed_above;
}
}
if (nvis_children)
@@ -569,19 +630,24 @@ gtk_button_box_child_requisition (GtkWidget *widget,
static void
gtk_button_box_size_request (GtkWidget *widget,
GtkRequisition *requisition)
GtkRequisition *requisition,
gint *baseline)
{
GtkButtonBoxPrivate *priv;
GtkButtonBox *bbox;
gint nvis_children;
gint max_size;
gint max_size, max_above, max_below;
gint total_size;
gint spacing;
GtkOrientation orientation;
gint *widths;
gint *heights;
gint *baselines;
gint i;
if (baseline)
*baseline = -1;
bbox = GTK_BUTTON_BOX (widget);
priv = bbox->priv;
@@ -591,16 +657,22 @@ gtk_button_box_size_request (GtkWidget *widget,
gtk_button_box_child_requisition (widget,
&nvis_children,
NULL,
&widths, &heights);
&widths, &heights, &baselines, baseline, NULL);
max_size = 0;
max_size = max_above = max_below = 0;
total_size = 0;
for (i = 0; i < nvis_children; i++)
{
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
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
{
@@ -610,6 +682,23 @@ gtk_button_box_size_request (GtkWidget *widget,
}
g_free (widths);
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)
{
@@ -656,7 +745,7 @@ gtk_button_box_get_preferred_width (GtkWidget *widget,
{
GtkRequisition requisition;
gtk_button_box_size_request (widget, &requisition);
gtk_button_box_size_request (widget, &requisition, NULL);
*minimum = *natural = requisition.width;
}
@@ -666,11 +755,9 @@ gtk_button_box_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural)
{
GtkRequisition requisition;
gtk_button_box_size_request (widget, &requisition);
*minimum = *natural = requisition.height;
gtk_button_box_get_preferred_height_and_baseline_for_width (widget, -1,
minimum, natural,
NULL, NULL);
}
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);
}
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
gtk_button_box_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
@@ -714,10 +821,13 @@ gtk_button_box_size_allocate (GtkWidget *widget,
gint ipad_x, ipad_y;
gint *widths;
gint *heights;
gint *baselines;
gint *sizes;
gint primary_size;
gint secondary_size;
gint total_size;
gint baseline, baseline_height;
gint child_baseline, allocated_baseline;
gint i;
bbox = GTK_BUTTON_BOX (widget);
@@ -733,7 +843,27 @@ gtk_button_box_size_allocate (GtkWidget *widget,
gtk_button_box_child_requisition (widget,
&nvis_children,
&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;
primary_size = 0;
@@ -917,10 +1047,17 @@ gtk_button_box_size_allocate (GtkWidget *widget,
{
child_allocation.width = widths[i];
child_allocation.height = heights[i];
child_baseline = -1;
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))
{
@@ -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++;
}
}
@@ -961,6 +1098,7 @@ gtk_button_box_size_allocate (GtkWidget *widget,
g_list_free (list);
g_free (widths);
g_free (heights);
g_free (baselines);
}
/**

View File

@@ -94,7 +94,8 @@ enum {
PROP_0,
PROP_ORIENTATION,
PROP_SPACING,
PROP_HOMOGENEOUS
PROP_HOMOGENEOUS,
PROP_BASELINE_POSITION
};
enum {
@@ -116,6 +117,7 @@ struct _GtkBoxPrivate
guint default_expand : 1;
guint homogeneous : 1;
guint spacing_set : 1;
guint baseline_pos : 2;
};
typedef struct _GtkBoxChild GtkBoxChild;
@@ -200,6 +202,12 @@ static void gtk_box_get_preferred_height_for_width (GtkWidget
gint width,
gint *minimum_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,
@@ -220,6 +228,7 @@ gtk_box_class_init (GtkBoxClass *class)
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_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->compute_expand = gtk_box_compute_expand;
widget_class->direction_changed = gtk_box_direction_changed;
@@ -255,6 +264,15 @@ gtk_box_class_init (GtkBoxClass *class)
FALSE,
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:
*
@@ -340,6 +358,7 @@ gtk_box_init (GtkBox *box)
private->homogeneous = FALSE;
private->spacing = 0;
private->spacing_set = FALSE;
private->baseline_pos = GTK_BASELINE_POSITION_CENTER;
}
static void
@@ -361,6 +380,9 @@ gtk_box_set_property (GObject *object,
case PROP_SPACING:
gtk_box_set_spacing (box, g_value_get_int (value));
break;
case PROP_BASELINE_POSITION:
gtk_box_set_baseline_position (box, g_value_get_enum (value));
break;
case PROP_HOMOGENEOUS:
gtk_box_set_homogeneous (box, g_value_get_boolean (value));
break;
@@ -387,6 +409,9 @@ gtk_box_get_property (GObject *object,
case PROP_SPACING:
g_value_set_int (value, private->spacing);
break;
case PROP_BASELINE_POSITION:
g_value_set_enum (value, private->baseline_pos);
break;
case PROP_HOMOGENEOUS:
g_value_set_boolean (value, private->homogeneous);
break;
@@ -435,6 +460,11 @@ gtk_box_size_allocate (GtkWidget *widget,
GtkTextDirection direction;
GtkAllocation child_allocation;
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;
@@ -461,6 +491,10 @@ gtk_box_size_allocate (GtkWidget *widget,
else
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. */
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].natural_size);
else
gtk_widget_get_preferred_height_for_width (child->widget,
allocation->width,
&sizes[i].minimum_size,
&sizes[i].natural_size);
gtk_widget_get_preferred_height_and_baseline_for_width (child->widget,
allocation->width,
&sizes[i].minimum_size,
&sizes[i].natural_size,
NULL, NULL);
/* Assert the api is working properly */
if (sizes[i].minimum_size < 0)
@@ -537,28 +571,9 @@ gtk_box_size_allocate (GtkWidget *widget,
extra = 0;
}
/* Allocate child positions. */
/* Allocate child sizes. */
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)
@@ -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. */
if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
{
@@ -658,7 +772,7 @@ gtk_box_size_allocate (GtkWidget *widget,
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++;
}
@@ -1015,18 +1129,28 @@ static void
gtk_box_get_size (GtkWidget *widget,
GtkOrientation orientation,
gint *minimum_size,
gint *natural_size)
gint *natural_size,
gint *minimum_baseline,
gint *natural_baseline)
{
GtkBox *box;
GtkBoxPrivate *private;
GList *children;
gint nvis_children;
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);
private = box->priv;
have_baseline = FALSE;
minimum = natural = 0;
minimum_above = natural_above = 0;
minimum_below = natural_below = 0;
min_baseline = nat_baseline = -1;
nvis_children = 0;
@@ -1037,13 +1161,15 @@ gtk_box_get_size (GtkWidget *widget,
if (gtk_widget_get_visible (child->widget))
{
gint child_minimum, child_natural;
gint child_minimum_baseline = -1, child_natural_baseline = -1;
if (orientation == GTK_ORIENTATION_HORIZONTAL)
gtk_widget_get_preferred_width (child->widget,
&child_minimum, &child_natural);
else
gtk_widget_get_preferred_height (child->widget,
&child_minimum, &child_natural);
gtk_widget_get_preferred_height_and_baseline_for_width (child->widget, -1,
&child_minimum, &child_natural,
&child_minimum_baseline, &child_natural_baseline);
if (private->orientation == orientation)
{
@@ -1065,9 +1191,20 @@ gtk_box_get_size (GtkWidget *widget,
}
else
{
/* The biggest mins and naturals in the opposing orientation */
minimum = MAX (minimum, child_minimum);
natural = MAX (natural, child_natural);
if (child_minimum_baseline >= 0)
{
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;
@@ -1085,11 +1222,39 @@ gtk_box_get_size (GtkWidget *widget,
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)
*minimum_size = minimum;
if (natural_size)
*natural_size = natural;
if (minimum_baseline)
*minimum_baseline = min_baseline;
if (natural_baseline)
*natural_baseline = nat_baseline;
}
static void
@@ -1097,7 +1262,7 @@ gtk_box_get_preferred_width (GtkWidget *widget,
gint *minimum_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
@@ -1105,14 +1270,16 @@ gtk_box_get_preferred_height (GtkWidget *widget,
gint *minimum_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
gtk_box_compute_size_for_opposing_orientation (GtkBox *box,
gint avail_size,
gint *minimum_size,
gint *natural_size)
gint *natural_size,
gint *minimum_baseline,
gint *natural_baseline)
{
GtkBoxPrivate *private = box->priv;
GtkBoxChild *child;
@@ -1120,11 +1287,16 @@ gtk_box_compute_size_for_opposing_orientation (GtkBox *box,
gint nvis_children;
gint nexpand_children;
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;
GtkPackType packing;
gint size, extra, i;
gint child_size, child_minimum, child_natural;
gint child_minimum_baseline, child_natural_baseline;
gint n_extra_widgets = 0;
gboolean have_baseline;
count_expand_children (box, &nvis_children, &nexpand_children);
@@ -1199,6 +1371,7 @@ gtk_box_compute_size_for_opposing_orientation (GtkBox *box,
extra = 0;
}
have_baseline = FALSE;
/* Allocate child positions. */
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. */
if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
gtk_widget_get_preferred_height_for_width (child->widget,
child_size, &child_minimum, &child_natural);
gtk_widget_get_preferred_height_and_baseline_for_width (child->widget, child_size,
&child_minimum, &child_natural,
&child_minimum_baseline, &child_natural_baseline);
else /* (private->orientation == GTK_ORIENTATION_VERTICAL) */
gtk_widget_get_preferred_width_for_height (child->widget,
child_size, &child_minimum, &child_natural);
computed_minimum = MAX (computed_minimum, child_minimum);
computed_natural = MAX (computed_natural, child_natural);
if (child_minimum_baseline >= 0)
{
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;
}
}
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)
*minimum_size = computed_minimum;
if (natural_size)
*natural_size = computed_natural;
*natural_size = MAX (computed_natural, computed_natural_below + computed_natural_above);
}
static void
@@ -1355,24 +1566,46 @@ gtk_box_get_preferred_width_for_height (GtkWidget *widget,
GtkBoxPrivate *private = box->priv;
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
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
gtk_box_get_preferred_height_for_width (GtkWidget *widget,
gint width,
gint *minimum_height,
gint *natural_height)
{
GtkBox *box = GTK_BOX (widget);
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);
gtk_box_get_preferred_height_and_baseline_for_width (widget, width, minimum_height, natural_height, NULL, NULL);
}
/**
@@ -1550,6 +1783,55 @@ gtk_box_get_spacing (GtkBox *box)
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.
*/
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
**/
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
_gtk_box_set_spacing_set (GtkBox *box,
gboolean spacing_set)

View File

@@ -89,6 +89,11 @@ gboolean gtk_box_get_homogeneous (GtkBox *box);
void gtk_box_set_spacing (GtkBox *box,
gint spacing);
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,
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,
gint *minimum_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 };
@@ -196,6 +202,7 @@ gtk_button_class_init (GtkButtonClass *klass)
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_and_baseline_for_width = gtk_button_get_preferred_height_and_baseline_for_width;
widget_class->destroy = gtk_button_destroy;
widget_class->screen_changed = gtk_button_screen_changed;
widget_class->realize = gtk_button_realize;
@@ -1150,11 +1157,16 @@ gtk_button_construct_child (GtkButton *button)
else
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)
align = gtk_alignment_new (priv->xalign, priv->yalign, 0.0, 0.0);
else
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 ||
priv->image_position == GTK_POS_TOP)
gtk_box_pack_start (GTK_BOX (box), priv->image, FALSE, FALSE, 0);
@@ -1172,6 +1184,8 @@ gtk_button_construct_child (GtkButton *button)
else
label = gtk_label_new (label_text);
gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
if (priv->image_position == GTK_POS_RIGHT ||
priv->image_position == GTK_POS_BOTTOM)
gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
@@ -1196,6 +1210,8 @@ gtk_button_construct_child (GtkButton *button)
else
label = gtk_label_new (priv->label_text);
gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
if (priv->align_set)
gtk_misc_set_alignment (GTK_MISC (label), priv->xalign, priv->yalign);
@@ -1584,6 +1600,7 @@ gtk_button_size_allocate (GtkWidget *widget,
GtkBorder border;
gint focus_width;
gint focus_pad;
gint baseline;
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;
}
baseline = gtk_widget_get_allocated_baseline (widget);
if (baseline != -1)
baseline -= child_allocation.y - allocation->y;
if (priv->depressed)
{
gint child_displacement_x;
@@ -1651,7 +1672,7 @@ gtk_button_size_allocate (GtkWidget *widget,
child_allocation.width = MAX (1, child_allocation.width);
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,
GtkOrientation orientation,
gint *minimum_size,
gint *natural_size)
gint *natural_size,
gint *minimum_baseline,
gint *natural_baseline)
{
GtkButton *button = GTK_BUTTON (widget);
GtkStyleContext *context;
@@ -2074,6 +2097,7 @@ gtk_button_get_size (GtkWidget *widget,
gint focus_width;
gint focus_pad;
gint minimum, natural;
gint top_offset;
context = gtk_widget_get_style_context (widget);
@@ -2084,6 +2108,8 @@ gtk_button_get_size (GtkWidget *widget,
"focus-padding", &focus_pad,
NULL);
top_offset = 0;
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
minimum = padding.left + padding.right +
@@ -2097,9 +2123,14 @@ gtk_button_get_size (GtkWidget *widget,
minimum = padding.top + padding.bottom +
border.top + border.bottom;
top_offset = padding.top + border.top + focus_width + focus_pad;
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);
natural = minimum;
@@ -2108,11 +2139,17 @@ gtk_button_get_size (GtkWidget *widget,
gtk_widget_get_visible (child))
{
gint child_min, child_nat;
gint child_min_baseline = -1, child_nat_baseline = -1;
if (orientation == GTK_ORIENTATION_HORIZONTAL)
gtk_widget_get_preferred_width (child, &child_min, &child_nat);
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;
natural += child_nat;
@@ -2130,7 +2167,7 @@ gtk_button_get_preferred_width (GtkWidget *widget,
gint *minimum_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
@@ -2138,7 +2175,20 @@ gtk_button_get_preferred_height (GtkWidget *widget,
gint *minimum_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 yalign;
/* This is only used by checkbox and subclasses */
gfloat baseline_align;
guint activate_timeout;
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,
gint *minimum,
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,
GtkAllocation *allocation);
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_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->draw = gtk_check_button_draw;
@@ -287,9 +294,12 @@ gtk_check_button_get_preferred_width (GtkWidget *widget,
}
static void
gtk_check_button_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural)
gtk_check_button_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint width,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{
GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (widget);
@@ -301,6 +311,7 @@ gtk_check_button_get_preferred_height (GtkWidget *widget,
gint indicator_spacing;
gint focus_width;
gint focus_pad;
gint old_minimum, old_natural;
guint border_width;
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))
{
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;
*natural += child_nat;
}
old_minimum = *minimum;
old_natural = *natural;
temp = indicator_size + indicator_spacing * 2;
*minimum = MAX (*minimum, 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
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
gtk_check_button_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
PangoContext *pango_context;
PangoFontMetrics *metrics;
GtkCheckButton *check_button;
GtkToggleButton *toggle_button;
GtkButton *button;
GtkAllocation child_allocation;
gint baseline;
button = GTK_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 + 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
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 focus_width;
gint focus_pad;
gint baseline;
guint border_width;
gboolean interior_focus;
GtkAllocation allocation;
@@ -458,6 +515,7 @@ gtk_real_check_button_draw_indicator (GtkCheckButton *check_button,
toggle_button = GTK_TOGGLE_BUTTON (check_button);
gtk_widget_get_allocation (widget, &allocation);
baseline = gtk_widget_get_allocated_baseline (widget);
context = gtk_widget_get_style_context (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));
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));
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,
gint *minimum_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,
GtkOrientation orientation,
gint *minimum_size,
gint *natural_size,
gint *allocated_pos,
gint *allocated_size);
static void gtk_container_adjust_baseline_allocation (GtkWidget *widget,
gint *baseline);
static GtkSizeRequestMode gtk_container_get_request_mode (GtkWidget *widget);
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->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_baseline_allocation = gtk_container_adjust_baseline_allocation;
widget_class->get_request_mode = gtk_container_get_request_mode;
class->add = gtk_container_add_unimplemented;
@@ -1917,6 +1924,28 @@ gtk_container_adjust_size_request (GtkWidget *widget,
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
gtk_container_adjust_size_allocation (GtkWidget *widget,
GtkOrientation orientation,
@@ -1952,6 +1981,27 @@ gtk_container_adjust_size_allocation (GtkWidget *widget,
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 {
gint hfw;
gint wfh;

View File

@@ -47,7 +47,8 @@ typedef enum {
GTK_DEBUG_PRINTING = 1 << 10,
GTK_DEBUG_BUILDER = 1 << 11,
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;
#ifdef G_ENABLE_DEBUG

View File

@@ -787,6 +787,7 @@ gtk_dialog_add_button (GtkDialog *dialog,
button = gtk_button_new_from_stock (button_text);
gtk_widget_set_can_default (button, TRUE);
gtk_widget_set_valign (button, GTK_ALIGN_BASELINE);
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,
gint *minimum,
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,
GtkAllocation *allocation);
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->get_preferred_width = gtk_entry_get_preferred_width;
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->draw = gtk_entry_draw;
widget_class->enter_notify_event = gtk_entry_enter_notify;
@@ -3305,16 +3312,19 @@ gtk_entry_get_preferred_width (GtkWidget *widget,
}
static void
gtk_entry_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural)
gtk_entry_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint width,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{
GtkEntry *entry = GTK_ENTRY (widget);
GtkEntryPrivate *priv = entry->priv;
PangoFontMetrics *metrics;
GtkBorder borders;
PangoContext *context;
gint height;
gint height, baseline;
PangoLayout *layout;
layout = gtk_entry_ensure_layout (entry, TRUE);
@@ -3333,8 +3343,27 @@ gtk_entry_get_preferred_height (GtkWidget *widget,
height += borders.top + borders.bottom;
baseline = pango_layout_get_baseline (layout) / PANGO_SCALE;
baseline += borders.top;
*minimum = 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
@@ -3452,13 +3481,17 @@ gtk_entry_get_frame_size (GtkEntry *entry,
GtkAllocation allocation;
GtkRequisition requisition;
GtkWidget *widget = GTK_WIDGET (entry);
gint area_height, y_pos;
gint baseline;
gint req_height;
GtkBorder borders;
gtk_widget_get_preferred_size (widget, &requisition, NULL);
req_height = requisition.height - gtk_widget_get_margin_top (widget) - gtk_widget_get_margin_bottom (widget);
gtk_widget_get_allocation (widget, &allocation);
baseline = gtk_widget_get_allocated_baseline (widget);
if (x)
*x = allocation.x;
@@ -3468,7 +3501,17 @@ gtk_entry_get_frame_size (GtkEntry *entry,
if (priv->is_cell_renderer)
*y = 0;
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;
}

View File

@@ -51,6 +51,7 @@ G_BEGIN_DECLS
* or top
* @GTK_ALIGN_CENTER: center natural width of widget inside the
* 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)
* dimension.
@@ -64,13 +65,18 @@ G_BEGIN_DECLS
*
* Note that in horizontal context @GTK_ALIGN_START and @GTK_ALIGN_END
* 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
{
GTK_ALIGN_FILL,
GTK_ALIGN_START,
GTK_ALIGN_END,
GTK_ALIGN_CENTER
GTK_ALIGN_CENTER,
GTK_ALIGN_BASELINE
} GtkAlign;
@@ -125,6 +131,28 @@ typedef enum
GTK_FILL = 1 << 2
} 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:
* @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,
gint *minimum,
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,
GtkAllocation *allocation);
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->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_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->draw = gtk_event_box_draw;
@@ -515,9 +522,12 @@ gtk_event_box_get_preferred_width (GtkWidget *widget,
}
static void
gtk_event_box_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural)
gtk_event_box_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint width,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{
GtkBin *bin = GTK_BIN (widget);
GtkWidget *child;
@@ -528,9 +538,30 @@ gtk_event_box_get_preferred_height (GtkWidget *widget,
if (natural)
*natural = 0;
if (minimum_baseline)
*minimum_baseline = -1;
if (natural_baseline)
*natural_baseline = -1;
child = gtk_bin_get_child (bin);
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
@@ -539,6 +570,7 @@ gtk_event_box_size_allocate (GtkWidget *widget,
{
GtkBin *bin;
GtkAllocation child_allocation;
gint baseline;
GtkEventBoxPrivate *priv;
GtkWidget *child;
@@ -578,9 +610,10 @@ gtk_event_box_size_allocate (GtkWidget *widget,
child_allocation.height);
}
baseline = gtk_widget_get_allocated_baseline (widget);
child = gtk_bin_get_child (bin);
if (child)
gtk_widget_size_allocate (child, &child_allocation);
gtk_widget_size_allocate_with_baseline (child, &child_allocation, baseline);
}
static gboolean

File diff suppressed because it is too large Load Diff

View File

@@ -103,6 +103,18 @@ gboolean gtk_grid_get_column_homogeneous (GtkGrid *grid);
void gtk_grid_set_column_spacing (GtkGrid *grid,
guint spacing);
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

View File

@@ -140,6 +140,8 @@ struct _GtkImagePrivate
gchar *filename; /* Only used with GTK_IMAGE_ANIMATION, 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,
gint *minimum,
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_screen_changed (GtkWidget *widget,
@@ -207,6 +215,7 @@ gtk_image_class_init (GtkImageClass *class)
widget_class->draw = gtk_image_draw;
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_and_baseline_for_width = gtk_image_get_preferred_height_and_baseline_for_width;
widget_class->unmap = gtk_image_unmap;
widget_class->unrealize = gtk_image_unrealize;
widget_class->style_updated = gtk_image_style_updated;
@@ -1393,6 +1402,26 @@ gtk_image_get_preferred_size (GtkImage *image,
*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
gtk_image_draw (GtkWidget *widget,
cairo_t *cr)
@@ -1401,7 +1430,7 @@ gtk_image_draw (GtkWidget *widget,
GtkImagePrivate *priv;
GtkMisc *misc;
GtkStyleContext *context;
gint x, y, width, height;
gint x, y, width, height, baseline;
gfloat xalign, yalign;
GtkBorder border;
@@ -1427,8 +1456,28 @@ gtk_image_draw (GtkWidget *widget,
if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR)
xalign = 1.0 - xalign;
baseline = gtk_widget_get_allocated_baseline (widget);
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
{
PangoContext *pango_context;
PangoFontMetrics *metrics;
float baseline_align;
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));
baseline_align =
(double)pango_font_metrics_get_ascent (metrics) /
(pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent (metrics));
y = CLAMP (baseline - height * baseline_align,
border.top, gtk_widget_get_allocated_height (widget) - height);
}
if (gtk_image_get_storage_type (image) == GTK_IMAGE_ANIMATION)
{
@@ -1535,15 +1584,37 @@ gtk_image_get_preferred_width (GtkWidget *widget,
*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
gtk_image_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural)
{
gint height;
gtk_image_get_preferred_size (GTK_IMAGE (widget), NULL, &height);
*minimum = *natural = height;
gtk_image_get_preferred_height_and_baseline_for_width (widget, -1, minimum, natural,
NULL, NULL);
}
static void
@@ -1558,9 +1629,13 @@ icon_theme_changed (GtkImage *image)
static void
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);
icon_theme_changed (GTK_IMAGE (widget));
icon_theme_changed (image);
priv->baseline_align = 0.0;
}
static void

View File

@@ -519,6 +519,12 @@ static void gtk_label_get_preferred_height_for_width (GtkWidget
gint width,
gint *minimum_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;
@@ -585,6 +591,7 @@ gtk_label_class_init (GtkLabelClass *class)
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_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->copy_clipboard = gtk_label_copy_clipboard;
@@ -3462,15 +3469,18 @@ gtk_label_get_request_mode (GtkWidget *widget)
return GTK_SIZE_REQUEST_CONSTANT_SIZE;
}
static void
get_size_for_allocation (GtkLabel *label,
GtkOrientation orientation,
gint allocation,
gint *minimum_size,
gint *natural_size)
gint *natural_size,
gint *minimum_baseline,
gint *natural_baseline)
{
PangoLayout *layout;
gint text_height;
gint text_height, baseline;
layout = gtk_label_get_measuring_layout (label, NULL, allocation * PANGO_SCALE);
@@ -3482,6 +3492,16 @@ get_size_for_allocation (GtkLabel *label,
if (natural_size)
*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);
}
@@ -3578,7 +3598,9 @@ static void
gtk_label_get_preferred_size (GtkWidget *widget,
GtkOrientation orientation,
gint *minimum_size,
gint *natural_size)
gint *natural_size,
gint *minimum_baseline,
gint *natural_baseline)
{
GtkLabel *label = GTK_LABEL (widget);
GtkLabelPrivate *priv = label->priv;
@@ -3586,6 +3608,12 @@ gtk_label_get_preferred_size (GtkWidget *widget,
PangoRectangle smallest_rect;
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);
/* 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,
GTK_ORIENTATION_VERTICAL,
smallest_rect.height,
minimum_size, natural_size);
minimum_size, natural_size,
NULL, NULL);
}
else
@@ -3667,7 +3696,16 @@ gtk_label_get_preferred_size (GtkWidget *widget,
get_size_for_allocation (label,
GTK_ORIENTATION_HORIZONTAL,
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
{
@@ -3680,6 +3718,12 @@ gtk_label_get_preferred_size (GtkWidget *widget,
*minimum_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 *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
@@ -3696,7 +3740,7 @@ gtk_label_get_preferred_height (GtkWidget *widget,
gint *minimum_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
@@ -3719,7 +3763,8 @@ gtk_label_get_preferred_width_for_height (GtkWidget *widget,
get_size_for_allocation (label, GTK_ORIENTATION_VERTICAL,
MAX (1, height - border.top - border.bottom),
minimum_width, natural_width);
minimum_width, natural_width,
NULL, NULL);
if (minimum_width)
*minimum_width += border.right + border.left;
@@ -3732,15 +3777,17 @@ gtk_label_get_preferred_width_for_height (GtkWidget *widget,
}
static void
gtk_label_get_preferred_height_for_width (GtkWidget *widget,
gint width,
gint *minimum_height,
gint *natural_height)
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)
{
GtkLabel *label = GTK_LABEL (widget);
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;
@@ -3751,7 +3798,13 @@ gtk_label_get_preferred_height_for_width (GtkWidget *widget,
get_size_for_allocation (label, GTK_ORIENTATION_HORIZONTAL,
MAX (1, width - border.left - border.right),
minimum_height, natural_height);
minimum_height, natural_height,
minimum_baseline, natural_baseline);
if (minimum_baseline && *minimum_baseline >= 0)
*minimum_baseline += border.top;
if (natural_baseline && *natural_baseline >= 0)
*natural_baseline += border.top;
if (minimum_height)
*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;
}
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
@@ -3855,6 +3919,7 @@ get_layout_location (GtkLabel *label,
gint req_height;
gfloat xalign, yalign;
PangoRectangle logical;
gint baseline, layout_baseline, baseline_offset;
misc = GTK_MISC (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);
baseline_offset = 0;
baseline = gtk_widget_get_allocated_baseline (widget);
if (baseline >= 0 && !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
* 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
@@ -3901,9 +3975,9 @@ get_layout_location (GtkLabel *label,
* middle". You want to read the first line, at least, to get some context.
*/
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
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)
*xp = x;

View File

@@ -172,7 +172,8 @@ static const GDebugKey gtk_debug_keys[] = {
{"printing", GTK_DEBUG_PRINTING},
{"builder", GTK_DEBUG_BUILDER},
{"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 */

View File

@@ -903,6 +903,7 @@ gtk_radio_button_draw_indicator (GtkCheckButton *check_button,
gint indicator_size, indicator_spacing;
gint focus_width;
gint focus_pad;
gint baseline;
guint border_width;
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_widget_get_allocation (widget, &allocation);
baseline = gtk_widget_get_allocated_baseline (widget);
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));
if (!interior_focus || !(child && gtk_widget_get_visible (child)))

View File

@@ -98,11 +98,16 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
GtkOrientation orientation,
gint for_size,
gint *minimum_size,
gint *natural_size)
gint *natural_size,
gint *minimum_baseline,
gint *natural_baseline)
{
SizeRequestCache *cache;
GtkWidgetClass *widget_class;
gint min_size = 0;
gint nat_size = 0;
gint min_baseline = -1;
gint nat_baseline = -1;
gboolean found_in_cache;
if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_CONSTANT_SIZE)
@@ -113,7 +118,11 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
orientation,
for_size,
&min_size,
&nat_size);
&nat_size,
&min_baseline,
&nat_baseline);
widget_class = GTK_WIDGET_GET_CLASS (widget);
if (!found_in_cache)
{
@@ -126,7 +135,7 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
if (for_size < 0)
{
push_recursion_check (widget, orientation, for_size);
GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_size, &nat_size);
widget_class->get_preferred_width (widget, &min_size, &nat_size);
pop_recursion_check (widget, orientation);
}
else
@@ -140,17 +149,17 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
gtk_widget_get_preferred_height (widget, &minimum_height, &natural_height);
/* convert for_size to unadjusted height (for_size is a proposed allocation) */
GTK_WIDGET_GET_CLASS (widget)->adjust_size_allocation (widget,
GTK_ORIENTATION_VERTICAL,
&minimum_height,
&natural_height,
&ignored_position,
&adjusted_for_size);
widget_class->adjust_size_allocation (widget,
GTK_ORIENTATION_VERTICAL,
&minimum_height,
&natural_height,
&ignored_position,
&adjusted_for_size);
push_recursion_check (widget, orientation, for_size);
GTK_WIDGET_GET_CLASS (widget)->get_preferred_width_for_height (widget,
MAX (adjusted_for_size, minimum_height),
&min_size, &nat_size);
widget_class->get_preferred_width_for_height (widget,
MAX (adjusted_for_size, minimum_height),
&min_size, &nat_size);
pop_recursion_check (widget, orientation);
}
}
@@ -159,7 +168,9 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
if (for_size < 0)
{
push_recursion_check (widget, orientation, for_size);
GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, &min_size, &nat_size);
widget_class->get_preferred_height_and_baseline_for_width (widget, -1,
&min_size, &nat_size,
&min_baseline, &nat_baseline);
pop_recursion_check (widget, orientation);
}
else
@@ -173,17 +184,17 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
gtk_widget_get_preferred_width (widget, &minimum_width, &natural_width);
/* convert for_size to unadjusted width (for_size is a proposed allocation) */
GTK_WIDGET_GET_CLASS (widget)->adjust_size_allocation (widget,
GTK_ORIENTATION_HORIZONTAL,
&minimum_width,
&natural_width,
&ignored_position,
&adjusted_for_size);
widget_class->adjust_size_allocation (widget,
GTK_ORIENTATION_HORIZONTAL,
&minimum_width,
&natural_width,
&ignored_position,
&adjusted_for_size);
push_recursion_check (widget, orientation, for_size);
GTK_WIDGET_GET_CLASS (widget)->get_preferred_height_for_width (widget,
MAX (adjusted_for_size, minimum_width),
&min_size, &nat_size);
widget_class->get_preferred_height_and_baseline_for_width (widget, MAX (adjusted_for_size, minimum_width),
&min_size, &nat_size,
&min_baseline, &nat_baseline);
pop_recursion_check (widget, orientation);
}
}
@@ -196,10 +207,10 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
adjusted_min = min_size;
adjusted_natural = nat_size;
GTK_WIDGET_GET_CLASS (widget)->adjust_size_request (widget,
orientation,
&adjusted_min,
&adjusted_natural);
widget_class->adjust_size_request (widget,
orientation,
&adjusted_min,
&adjusted_natural);
if (adjusted_min < min_size ||
adjusted_natural < nat_size)
@@ -227,11 +238,42 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
nat_size = adjusted_natural;
}
if (min_baseline != -1 || nat_baseline != -1)
{
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
g_warning ("%s %p reported a horizontal baseline",
G_OBJECT_TYPE_NAME (widget), widget);
min_baseline = -1;
nat_baseline = -1;
}
else if (min_baseline == -1 || nat_baseline == -1)
{
g_warning ("%s %p reported baseline for only one of min/natural (min: %d, natural: %d)",
G_OBJECT_TYPE_NAME (widget), widget,
min_baseline, nat_baseline);
min_baseline = -1;
nat_baseline = -1;
}
else if (gtk_widget_get_valign_with_baseline (widget) != GTK_ALIGN_BASELINE)
{
/* Ignore requested baseline for non-aligned widgets */
min_baseline = -1;
nat_baseline = -1;
}
else
widget_class->adjust_baseline_request (widget,
&min_baseline,
&nat_baseline);
}
_gtk_size_request_cache_commit (cache,
orientation,
for_size,
min_size,
nat_size);
nat_size,
min_baseline,
nat_baseline);
}
if (minimum_size)
@@ -240,15 +282,26 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
if (natural_size)
*natural_size = nat_size;
if (minimum_baseline)
*minimum_baseline = min_baseline;
if (natural_baseline)
*natural_baseline = nat_baseline;
g_assert (min_size <= nat_size);
GTK_NOTE (SIZE_REQUEST,
g_print ("[%p] %s\t%s: %d is minimum %d and natural: %d (hit cache: %s)\n",
g_print ("[%p] %s\t%s: %d is minimum %d and natural: %d",
widget, G_OBJECT_TYPE_NAME (widget),
orientation == GTK_ORIENTATION_HORIZONTAL ?
"width for height" : "height for width" ,
for_size, min_size, nat_size,
found_in_cache ? "yes" : "no"));
for_size, min_size, nat_size);
if (min_baseline != -1 || nat_baseline != -1)
g_print (", baseline %d/%d",
min_baseline, nat_baseline);
g_print (" (hit cache: %s)\n",
found_in_cache ? "yes" : "no")
);
}
/* This is the main function that checks for a cached size and
@@ -261,7 +314,9 @@ _gtk_widget_compute_size_for_orientation (GtkWidget *widget,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural)
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{
GHashTable *widgets;
GHashTableIter iter;
@@ -274,12 +329,17 @@ _gtk_widget_compute_size_for_orientation (GtkWidget *widget,
*minimum = 0;
if (natural)
*natural = 0;
if (minimum_baseline)
*minimum_baseline = -1;
if (natural_baseline)
*natural_baseline = -1;
return;
}
if (G_LIKELY (!_gtk_widget_get_sizegroups (widget)))
{
gtk_widget_query_size_for_orientation (widget, orientation, for_size, minimum, natural);
gtk_widget_query_size_for_orientation (widget, orientation, for_size, minimum, natural,
minimum_baseline, natural_baseline);
return;
}
@@ -293,7 +353,7 @@ _gtk_widget_compute_size_for_orientation (GtkWidget *widget,
GtkWidget *tmp_widget = key;
gint min_dimension, nat_dimension;
gtk_widget_query_size_for_orientation (tmp_widget, orientation, for_size, &min_dimension, &nat_dimension);
gtk_widget_query_size_for_orientation (tmp_widget, orientation, for_size, &min_dimension, &nat_dimension, NULL, NULL);
min_result = MAX (min_result, min_dimension);
nat_result = MAX (nat_result, nat_dimension);
@@ -303,6 +363,13 @@ _gtk_widget_compute_size_for_orientation (GtkWidget *widget,
g_hash_table_destroy (widgets);
/* Baselines make no sense with sizegroups really */
if (minimum_baseline)
*minimum_baseline = -1;
if (natural_baseline)
*natural_baseline = -1;
if (minimum)
*minimum = min_result;
@@ -375,7 +442,8 @@ gtk_widget_get_preferred_width (GtkWidget *widget,
GTK_ORIENTATION_HORIZONTAL,
-1,
minimum_width,
natural_width);
natural_width,
NULL, NULL);
}
@@ -409,7 +477,8 @@ gtk_widget_get_preferred_height (GtkWidget *widget,
GTK_ORIENTATION_VERTICAL,
-1,
minimum_height,
natural_height);
natural_height,
NULL, NULL);
}
@@ -446,7 +515,8 @@ gtk_widget_get_preferred_width_for_height (GtkWidget *widget,
GTK_ORIENTATION_HORIZONTAL,
height,
minimum_width,
natural_width);
natural_width,
NULL, NULL);
}
/**
@@ -481,7 +551,122 @@ gtk_widget_get_preferred_height_for_width (GtkWidget *widget,
GTK_ORIENTATION_VERTICAL,
width,
minimum_height,
natural_height);
natural_height,
NULL, NULL);
}
/**
* gtk_widget_get_preferred_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 +688,9 @@ gtk_widget_get_preferred_height_for_width (GtkWidget *widget,
* height for the natural width is generally smaller than the required height for
* the minimum width.</para></note>
*
* Use gtk_widget_get_preferred_size_and_baseline() if you want to support
* baseline alignment.
*
* Since: 3.0
*/
void
@@ -510,50 +698,10 @@ gtk_widget_get_preferred_size (GtkWidget *widget,
GtkRequisition *minimum_size,
GtkRequisition *natural_size)
{
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_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);
}
}
gtk_widget_get_preferred_size_and_baseline (widget, minimum_size, natural_size,
NULL, NULL);
}
static gint
compare_gap (gconstpointer p1,
gconstpointer p2,

View File

@@ -32,31 +32,38 @@ _gtk_size_request_cache_init (SizeRequestCache *cache)
}
static void
free_sizes (SizeRequest **sizes)
free_sizes_x (SizeRequestX **sizes)
{
gint i;
for (i = 0; i < GTK_SIZE_REQUEST_CACHED_SIZES && sizes[i] != NULL; i++)
g_slice_free (SizeRequest, sizes[i]);
g_slice_free1 (sizeof (SizeRequest *) * GTK_SIZE_REQUEST_CACHED_SIZES, sizes);
g_slice_free (SizeRequestX, sizes[i]);
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
_gtk_size_request_cache_free (SizeRequestCache *cache)
{
guint i;
for (i = 0; i < 2; i++)
{
if (cache->requests[i])
free_sizes (cache->requests[i]);
}
if (cache->requests_x)
free_sizes_x (cache->requests_x);
if (cache->requests_x)
free_sizes_y (cache->requests_y);
}
void
_gtk_size_request_cache_clear (SizeRequestCache *cache)
{
_gtk_size_request_cache_free (cache);
_gtk_size_request_cache_init (cache);
@@ -67,17 +74,34 @@ _gtk_size_request_cache_commit (SizeRequestCache *cache,
GtkOrientation orientation,
gint for_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;
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
g_assert (minimum_baseline == -1);
g_assert (natural_baseline == -1);
}
/* First handle caching of the base requests */
if (for_size < 0)
{
cache->cached_size[orientation].minimum_size = minimum_size;
cache->cached_size[orientation].natural_size = natural_size;
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
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;
return;
}
@@ -86,45 +110,99 @@ _gtk_size_request_cache_commit (SizeRequestCache *cache,
* in the cache and if this result can be used to extend
* that cache entry
*/
cached_sizes = cache->requests[orientation];
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
* 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)
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
cache->flags[orientation].n_cached_requests++;
cache->flags[orientation].last_cached_request = cache->flags[orientation].n_cached_requests - 1;
SizeRequestX **cached_sizes;
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
{
if (++cache->flags[orientation].last_cached_request == GTK_SIZE_REQUEST_CACHED_SIZES)
cache->flags[orientation].last_cached_request = 0;
SizeRequestY **cached_sizes;
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.
@@ -137,40 +215,85 @@ _gtk_size_request_cache_lookup (SizeRequestCache *cache,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural)
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{
CachedSize *result = NULL;
if (for_size < 0)
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
if (cache->flags[orientation].cached_size_valid)
result = &cache->cached_size[orientation];
CachedSizeX *result = NULL;
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
{
guint i;
CachedSizeY *result = NULL;
/* Search for an already cached size */
for (i = 0; i < cache->flags[orientation].n_cached_requests; i++)
{
SizeRequest *cur = cache->requests[orientation][i];
if (for_size < 0)
{
if (cache->flags[orientation].cached_size_valid)
result = &cache->cached_size_y;
}
else
{
guint i;
if (cur->lower_for_size <= for_size &&
cur->upper_for_size >= for_size)
{
result = &cur->cached_size;
break;
}
}
/* Search for an already cached size */
for (i = 0; i < cache->flags[orientation].n_cached_requests; i++)
{
SizeRequestY *cur = cache->requests_y[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 = 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 {
gint minimum_size;
gint natural_size;
} CachedSize;
} CachedSizeX;
typedef struct {
gint minimum_size;
gint natural_size;
gint minimum_baseline;
gint natural_baseline;
} CachedSizeY;
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 */
CachedSize cached_size;
} SizeRequest;
CachedSizeX cached_size;
} 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 {
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;
guint request_mode_valid : 1;
@@ -72,12 +88,16 @@ void _gtk_size_request_cache_commit (SizeRequestCach
GtkOrientation orientation,
gint for_size,
gint minimum_size,
gint natural_size);
gint natural_size,
gint minimum_baseline,
gint natural_baseline);
gboolean _gtk_size_request_cache_lookup (SizeRequestCache *cache,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural);
gint *natural,
gint *minimum_baseline,
gint *natural_baseline);
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,
gint *minimum,
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,
GtkAllocation *allocation);
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->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_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->draw = gtk_spin_button_draw;
widget_class->scroll_event = gtk_spin_button_scroll;
@@ -1197,14 +1204,20 @@ gtk_spin_button_get_preferred_width (GtkWidget *widget,
}
static void
gtk_spin_button_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural)
gtk_spin_button_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint width,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{
GtkSpinButton *spin_button = GTK_SPIN_BUTTON (widget);
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)
{
@@ -1216,9 +1229,22 @@ gtk_spin_button_get_preferred_height (GtkWidget *widget,
*minimum += 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
gtk_spin_button_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)

View File

@@ -95,6 +95,7 @@
* <listitem>#GtkWidgetClass.get_preferred_height()</listitem>
* <listitem>#GtkWidgetClass.get_preferred_height_for_width()</listitem>
* <listitem>#GtkWidgetClass.get_preferred_width_for_height()</listitem>
* <listitem>#GtkWidgetClass.get_preferred_height_and_baseline_for_width()</listitem>
* </itemizedlist>
*
* There are some important things to keep in mind when implementing
@@ -222,6 +223,26 @@
* container, you <emphasis>must</emphasis> use the wrapper APIs.
* Otherwise, you would not properly consider widget margins,
* #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>
* </refsect2>
* <refsect2 id="style-properties">
@@ -395,6 +416,7 @@ struct _GtkWidgetPrivate
/* The widget's allocated size */
GtkAllocation allocation;
gint allocated_baseline;
/* The widget's requested sizes */
SizeRequestCache requests;
@@ -689,6 +711,12 @@ static void gtk_widget_real_get_width (GtkWidget
static void gtk_widget_real_get_height (GtkWidget *widget,
gint *minimum_size,
gint *natural_size);
static void gtk_widget_real_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_widget_queue_tooltip_query (GtkWidget *widget);
@@ -697,12 +725,17 @@ static void gtk_widget_real_adjust_size_request (GtkWidget
GtkOrientation orientation,
gint *minimum_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,
GtkOrientation orientation,
gint *minimum_size,
gint *natural_size,
gint *allocated_pos,
gint *allocated_size);
static void gtk_widget_real_adjust_baseline_allocation (GtkWidget *widget,
gint *baseline);
static void gtk_widget_set_usize_internal (GtkWidget *widget,
gint width,
@@ -984,6 +1017,7 @@ gtk_widget_class_init (GtkWidgetClass *klass)
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_height_for_width = gtk_widget_real_get_height_for_width;
klass->get_preferred_height_and_baseline_for_width = gtk_widget_real_get_preferred_height_and_baseline_for_width;
klass->state_changed = NULL;
klass->state_flags_changed = gtk_widget_real_state_flags_changed;
klass->parent_set = NULL;
@@ -1043,7 +1077,9 @@ gtk_widget_class_init (GtkWidgetClass *klass)
klass->get_accessible = gtk_widget_real_get_accessible;
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_baseline_allocation = gtk_widget_real_adjust_baseline_allocation;
g_object_class_install_property (gobject_class,
PROP_NAME,
@@ -5189,22 +5225,31 @@ gtk_widget_invalidate_widget_windows (GtkWidget *widget,
}
/**
* gtk_widget_size_allocate:
* gtk_widget_size_allocate_with_baseline:
* @widget: a #GtkWidget
* @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
* and position to their child widgets.
* This function is only used by #GtkContainer subclasses, to assign a size,
* position and (optionally) baseline 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.
* In this function, the allocation and baseline may be adjusted. It
* will be forced to a 1x1 minimum size, and the
* adjust_size_allocation virtual and adjust_baseline_allocation
* methods on the child will be used to adjust the allocation and
* 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
gtk_widget_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
gtk_widget_size_allocate_with_baseline (GtkWidget *widget,
GtkAllocation *allocation,
gint baseline)
{
GtkWidgetPrivate *priv;
GdkRectangle real_allocation;
@@ -5212,9 +5257,11 @@ gtk_widget_size_allocate (GtkWidget *widget,
GdkRectangle adjusted_allocation;
gboolean alloc_needed;
gboolean size_changed;
gboolean baseline_changed;
gboolean position_changed;
gint natural_width, natural_height, dummy;
gint min_width, min_height;
gint old_baseline;
priv = widget->priv;
@@ -5241,17 +5288,27 @@ gtk_widget_size_allocate (GtkWidget *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,
allocation->width, allocation->height);
if (baseline != -1)
g_print (" baseline: %d", baseline);
g_print ("\n");
}
#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)
baseline = -1;
alloc_needed = priv->alloc_needed;
/* Preserve request/allocate ordering */
priv->alloc_needed = FALSE;
old_allocation = priv->allocation;
old_baseline = priv->allocated_baseline;
real_allocation = *allocation;
adjusted_allocation = real_allocation;
@@ -5301,6 +5358,9 @@ gtk_widget_size_allocate (GtkWidget *widget,
&natural_height,
&adjusted_allocation.y,
&adjusted_allocation.height);
if (baseline >= 0)
GTK_WIDGET_GET_CLASS (widget)->adjust_baseline_allocation (widget,
&baseline);
if (adjusted_allocation.x < real_allocation.x ||
adjusted_allocation.y < real_allocation.y ||
@@ -5330,14 +5390,16 @@ gtk_widget_size_allocate (GtkWidget *widget,
real_allocation.width = MAX (real_allocation.width, 1);
real_allocation.height = MAX (real_allocation.height, 1);
baseline_changed = old_baseline != baseline;
size_changed = (old_allocation.width != real_allocation.width ||
old_allocation.height != real_allocation.height);
position_changed = (old_allocation.x != real_allocation.x ||
old_allocation.y != real_allocation.y);
if (!alloc_needed && !size_changed && !position_changed)
if (!alloc_needed && !size_changed && !position_changed && !baseline_changed)
goto out;
priv->allocated_baseline = baseline;
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 */
@@ -5356,7 +5418,7 @@ gtk_widget_size_allocate (GtkWidget *widget,
cairo_region_destroy (invalidate);
}
if (size_changed)
if (size_changed || baseline_changed)
{
if (priv->redraw_on_alloc)
{
@@ -5371,7 +5433,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)))
{
cairo_region_t *invalidate = cairo_region_create_rectangle (&priv->parent->priv->allocation);
@@ -5383,6 +5445,31 @@ out:
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:
* @widget_a: a #GtkWidget
@@ -5604,6 +5691,7 @@ adjust_for_align (GtkAlign align,
{
switch (align)
{
case GTK_ALIGN_BASELINE:
case GTK_ALIGN_FILL:
/* change nothing */
break;
@@ -5674,6 +5762,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
gtk_widget_real_can_activate_accel (GtkWidget *widget,
guint signal_id)
@@ -6166,6 +6266,26 @@ _gtk_widget_draw_internal (GtkWidget *widget,
0, cr,
&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) &&
_gtk_cairo_get_event (cr))
{
@@ -11015,6 +11135,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:
*
@@ -13165,6 +13307,25 @@ gtk_widget_real_get_width_for_height (GtkWidget *widget,
GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, minimum_width, natural_width);
}
static void
gtk_widget_real_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint width,
gint *minimum_height,
gint *natural_height,
gint *minimum_baseline,
gint *natural_baseline)
{
if (width == -1)
GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, minimum_height, natural_height);
else
GTK_WIDGET_GET_CLASS (widget)->get_preferred_height_for_width (widget, width, minimum_height, natural_height);
if (minimum_baseline)
*minimum_baseline = -1;
if (natural_baseline)
*natural_baseline = -1;
}
/**
* gtk_widget_get_halign:
* @widget: a #GtkWidget
@@ -13206,19 +13367,44 @@ gtk_widget_set_halign (GtkWidget *widget,
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
*/
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:
* @widget: a #GtkWidget
*
* 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
gtk_widget_get_valign (GtkWidget *widget)
{
g_return_val_if_fail (GTK_IS_WIDGET (widget), GTK_ALIGN_FILL);
return _gtk_widget_get_aux_info_or_defaults (widget)->valign;
GtkAlign align;
align = gtk_widget_get_valign_with_baseline (widget);
if (align == GTK_ALIGN_BASELINE)
return GTK_ALIGN_FILL;
return align;
}
/**
@@ -13995,6 +14181,25 @@ gtk_widget_get_allocated_height (GtkWidget *widget)
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
**/
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:
* @widget: a #GtkWidget

View File

@@ -433,14 +433,23 @@ struct _GtkWidgetClass
gboolean (* touch_event) (GtkWidget *widget,
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 >*/
GtkWidgetClassPrivate *priv;
/* Padding for future expansion */
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
void (*_gtk_reserved5) (void);
void (*_gtk_reserved6) (void);
void (*_gtk_reserved7) (void);
@@ -498,6 +507,10 @@ void gtk_widget_size_request (GtkWidget *widget,
GtkRequisition *requisition);
void gtk_widget_size_allocate (GtkWidget *widget,
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);
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 *minimum_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,
GtkRequisition *minimum_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)
void gtk_widget_get_child_requisition (GtkWidget *widget,
@@ -659,6 +685,8 @@ void gtk_widget_unregister_window (GtkWidget *widget,
int gtk_widget_get_allocated_width (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,
GtkAllocation *allocation);
@@ -756,6 +784,8 @@ GtkAlign gtk_widget_get_halign (GtkWidget *widget);
void gtk_widget_set_halign (GtkWidget *widget,
GtkAlign align);
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,
GtkAlign align);
gint gtk_widget_get_margin_left (GtkWidget *widget);

View File

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

View File

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