On Tue, 2013-02-26 at 15:30 +0100, Alexander Larsson wrote:
> One of the main layout features we're badly missing atm is baseline
> alignment. I spent some time looking at this recently but I bumped
> into some problems. I'd like to bring this up for discussion in the
> hope that we might figure out a solution to my problems.
>
> First, let me define what i mean by baseline layout and the API I
> expect it to have. Every widget has a single baseline, which is
> an offset from the top of the allocation to the baseline.
> Some layouts (such as e.g. multi-line text) have multiple possible
> baselines, but this is outside of the common gtk+ api and each
> widget gets to decide which one to use, via some per-widget API.
>
> We add a new GtkAlign element, GTK_ALIGN_BASELINE, which when not
> supported does the same as CENTER, but in containers that support
> baseline alignment we align all the children with BASELINE up so
> that they all have the baseline at the same y coord. Additionally
> we need a single setting for the container itself that decides how
> to align the whole group of baseline aligned widgets (i.e. do we
> put the baseline alignment widgets at the bottom or at the top?
>
> An example hbox layout could look like with baseline at botttom:
>
> +-----------------------------------------------+
> |+-------+ |
> || START | |
> |+-------+ |
> | +--------+|
> | +-------+ | CENTER ||
> | +-------+| | +--------+|
> | |--BASE-||-BASE--|+-------+ |
> | | |+-------+| END | |
> | +-------+ +-------+ |
> +-----------------------------------------------+
>
> Now, back to the problem. Consider implementing size request/allocation
> for the container above. We can start with the min width, asking each
> child for min width and summing that. Then we ask for min height for
> that width and for the baseline at that width. We can thus simply
> calculate the min and natural size requests and their corresponding
> baseline.
One thing to keep in mind here, please avoid assumptions of
minimum widths (when doing h4w, or minimum heights when
doing w4h).
The height-for-minimum-width is invariably the tallest height
that a widget can request, so guess work like this really doesn't
work (as you have recognized in the following paragraph).
> The problem comes later, when we get the final size allocation for the
> container. Its easy to distribute the widths, but if the final height
> is not the same as the min/natural request, how do we distribute the
> height among the baseline aligned children such that the total height
> after we baseline align them fits in the assigned height?
>
> Since the baseline position depends (non-linearly) on the exact height
> we assign to the child, and the total size depends on the baselines
> this seems circular, and I can't see any way to calculate this other
> than in some iterative fashion.
My thoughts are that, when performing get_preferred_height_for_width(),
you need some virtual allocation logic like such that is found in
gtkbox.c (when we are requesting in the 'uncomfortable/opposing'
orientation):
a.) Calculate how much width exactly would be given to each child
b.) Calculate height-for-width of each child
c.) Report the MAX of all child heights.
Now with baselines, this becomes slightly more complex, during
the h4w request phase you need to replace the above 'c' with
something that aligns the requested baseline(s) for all children,
and requests a little bit more height in order to logically fit
all children into that height (which is dependent on the provided
width).
> For instance, if you have two children with the baseline at the top,
> then all extra space can be assigned to each child. However, if one
> has the baseline att the bottom you need to give each half the extra
> height.
>
> I don't really see any way to solve this generically. But maybe we can
> somehow limit our baseline support so that this works? For instance,
> we could always request the naural size for baseline aligned widgets
> and never grow them? Would that be enough in practical use? I dunno...
>
> Ideas wanted...
I had some ideas about this, and I'm sure it can be done with
height-for-width in mind, however the "y" baseline(s) need to be
calculated on a per width basis (i.e. as you're problem statement
indicates, one "y" baseline can not rule-them-all as the required "y"
anchor point might differ depending on the width, so probably the
size requesting cache needs to also cache any baselines reported).
I don't think something particularly iterative is needed for this
either, just need to virtually allocate the children in the request
phase.
Also, I'm not convinced that 'baseline' is the right word for this API,
I would rather consider it in terms of X and Y "anchor points" (if we
handle this complexity in one orientation, we should be able to get
the other orientation with relatively little added effort).
Another thing, is that we need the ability to calculate more than
a single anchor point in a given orientation per widget. The
one 'baseline' per widget wont pan out in the long run.
There are two things to consider:
a.) A single content may have multiple base lines, the
amount of baselines reported by some content might depend
on the allocated width, even (consider a wrapping multi-line
label or a GtkWrapBox with a variable amount of
'rows-of-widgets').
The question about GtkLabel text baselines might be possible
to work around, for instance if consistent line height
is enforced in wrapping labels (but IIRC Pango has
apis which can report the baselines of each line in a
PangoLayout with an allocated 'width').
b.) Baseline logic should not be constrained to a single
container's children (although through recursion
into children, the idea that a widget/container has
multiple baselines might render this detail transparent),
for instance:
+------------------------------------------+
| Horizontal Box (or Grid) |
| |
| +-----------------------+ |
| +---------+ | Vertical Box (or Grid)| |
| | Image | | +--------+ | |
| | | | | Label | | |
| +---------+~~~~|~~~+--------+ | |
| | | |
| | +---------------+ | |
| | | Other Content | | |
| | +---------------+ | |
| +-----------------------+ |
+------------------------------------------+
So... in other words the Vertical Box element here must
report possibly a number of "y anchors" for the anchors
of it's children, and use the allocated anchors from it's
parent to properly position the "Label" content it contains.
I haven't taken the time to consider solutions to all of these
problems, but I'm convinced they can be solved (and without being
overly iterative in the process).
Another question to fiddle with while pondering anchor points
and baselines, is to what extent can this API be implicit, and
to what extent should it be explicit. GtkLabels could have the
capacity to report a number of baselines (Y anchors) for a
hypothetical allocation width (by using the Pango apis to report
them). This would be the implicit part.
One might think though, an application developer might want to
add symbolic anchor points to their widgets. for instance in
the above ascii art the Image gets base-aligned with the
(lowest) baseline of the label in it's neighboring VBox.
One might need the choice to align the Image with the VBox
directly, with the "Label", or with the lower "Other Content",
this indicates to me that we might end up with some declarative
API which might define anchor points with symbolic strings.
I hope these added thoughts are constructive for you, thanks
for getting the baselines ball rolling, too :)
Cheers,
-Tristan
_______________________________________________
gtk-devel-list mailing list
[email protected]
https://mail.gnome.org/mailman/listinfo/gtk-devel-list