Extended Layout incubator branch.



Good morning,
  I've managed to get the base feature set of the native-layout
branch working and in a usable state.

By usable I mean: I've been running Glade on the extended
layout branch for the past week and all of the regressions
I've spotted so far have been fixed, I can also run the
Gimp and gedit with no visible regressions yet (and ofcourse,
the gtk-demo and testgtk as well).

It should also of course essentially solve the height-for-width
bug[0] and at least provide the right framework to adress
the GtkExpander ellipsize bug[1] and probably a few more.

I also spent some time today documenting the API which
makes alot more sense now (at least to me)

I've salvaged everything that is clean and usable thus
far into a new 'native-layout-incubator' branch.
This branch was created for the review process and potential
inclusion of the whole height-for-width geometry management
system and modest feature set to leverage it.

Anyone interested should try compiling the incubator branch
(or the native-layout branch even) and run the example in
the tests directory:
 ./tests/extendedlayoutexample
(note in the native-layout branch its still called
testextendedlayout2).

So, here's a global picture of what's in the incubator
branch and what didnt make it:

In:
  - The GtkExtendedLayout ofcourse (this is the
    basic API for requesting height-for-width size
    requests (this is all the new code that manages what
    sizes a widget will request in either dimension,
    doing deals with size groups and explicit size
    requests, caching the whole expensive operation and
    all that noise).
  - GtkLabel features:
     o The label now does height-for-width and
       also width-for-height when the text is
       rotated to 90 or 270 degrees.
     o The label now requests a full natural size to fit
       ellipsizing text unless capped by "max-width-chars".
       (this includes rotated text in any angle).
     o "max-width-chars" / "width-chars" act as guides to
       hint at good minimum widths and max natural widths
       when wrapping text.
   - GtkBox will allocate children according to their
     natural sizes (the key container right now producing the
     overall effect of height-for-width geometry)
   - Mathias Hasselmann's testellipsize test which demos
     rotating ellipsizing label allocations.
   - A new test 'extendedlayoutexample' showing various
     interfaces using the natural layout features.

Out:
   - GtkExtendedCell: this is the cell renderer specific api,
     the cell renderers already do natural sizes for ellipsize
     but don't yet do width-for-height or height-for-width
     (they also just need some basic attention I didnt have
     time for).

   - Mathias Hasselmann's testextendedlayout test which is
     really a great and thorough test, it needs work to bring
     up to speed on what to expect in terms of behaviors of
     GtkLabel, it also expects other stuff to pass that's just
     not ready yet (cell renderers etc).

   - GtkComboBox support depends on the cell renderer stuff
     so its still not ready.

   - GtkPlug/GtkSocket support: this is just a matter of changing
     the api from a natural requisition of width/height pair to
     a dual pass requisition of ->get_height_for_width().
     Would be really simple to finish these off as it just needs
     to be set straight to forward along the new height-for-width
     api.

The idea here is of course that we keep native-layout branch
up to date and that will be a great place to continue work
on GtkTable, finish up cell renderers and incrementally
introduce these new features to GTK+.

About compatibility, afaics only these side effects are
introduced:

 - Direct access to ->requisition is invalid and needs
   to be gtk_extended_layout_get_desired_size (or at least
   gtk_widget_get_child_requisition).

 - GtkBin classes that define a custom padding must implement
   get_desired_width()/get_desired_height() to report them
   correctly along with the child values (otherwise only the
   base values from a "size-request" is used).

 - GtkLabel heuristics have change a bit with regards to
   "max-width-chars" and "width-chars", although I doubt
   the impacts are going to be visibly negative.

Some regrets:

 - I think in the end I would have preferred an enum return
   type for gtk_extended_layout_is_height_for_width(); it really
   makes no difference in practice but would make for better
   readable documentation.

 - While it was besides the point; it would be nice to take a
   few days; maybe include ->size_allocate() in the new API
   and come up with a completely floating point api for GTK+ 3.0.
   (this was one among the countless bugzilla comments I read).

And ofcourse, the whole thing is going to consume more memory
to cache the multiple requisitions; and the requests are going
to be slower no matter what. While there is undoubtedly room
for optimization in GtkLabel, over all we are moving from a one
size requisition and one size allocation; to a dual pass requisition
phase, followed by a recursive allocation that fires recursive
contextual requisitions along the way.

But all that being said the caching works well and interfaces
resize nicely from what I've seen so far, a little extra
resources I guess is the price you pay for a more modern
geometry management system.

Ok time to sleep for now; try it test it review it enjoy it !

Cheers,
     -Tristan

PS: New API with documentation attached

[0] https://bugzilla.gnome.org/show_bug.cgi?id=101968
[1] https://bugzilla.gnome.org/show_bug.cgi?id=406528
/**
 * SECTION:gtkextendedlayout
 * @Short_Description: Height for Width Geometry management
 * @Title: GtkExtendedLayout
 *
 * The extended layout is GTK+'s height for width geometry management
 * system.
 *
 * <refsect2>
 * <title>Implementing GtkExtendedLayout</title>
 * <para>
 * Some important things to keep in mind when implementing 
 * or using the extended layout.
 *
 * The Extended Layout system will query a logical heirarchy in
 * only one orientation at a time. When widgets are initially queried
 * for their minimum sizes it is generally done in a dual pass
 * in the direction chosen by the toplevel.
 *
 * For instance when queried in the normal height-for-width mode:
 * First the default minimum and natural width for each widget
 * in the interface will computed and collectively returned to 
 * the toplevel by way of gtk_extended_layout_get_desired_width(). 
 * Next; the toplevel will use the minimum width to query for the 
 * minimum height contextual to that width using gtk_extended_layout_get_height_for_width()
 * which will also be a highly recursive operation. This minimum
 * for minimum size can be used to set the minimum size constraint 
 * on the toplevel.
 *
 * When allocating; each container can use the minimum and natural
 * sizes reported by thier children to allocate natural sizes and
 * expose as much content as possible with the given allocation.
 *
 * That means that the request operation at allocation time will
 * usually fire again in contexts of different allocated sizes than
 * the ones originally queried for.
 *
 * A Widget that does not actually do height-for-width 
 * or width-for-height size negotiations only has to implement
 * get_desired_width() and get_desired_height()
 *
 * If a widget does move content around to smartly use up the
 * allocated size, then it must support the request properly in
 * both orientations; even if the request only makes sense in
 * one orientation.
 *
 * For instance; a GtkLabel that does height-for-width word wrapping
 * will not expect to have get_desired_height() called because that
 * call is specific to a width-for-height request, in this case the
 * label must return the heights contextual to its minimum possible
 * width. By following this rule any widget that handles height-for-width
 * or width-for-height requests will always be allocated at least
 * enough space to fit its own content.
 * </para>
 * </refsect2>
 */


/**
 * gtk_extended_layout_is_height_for_width:
 * @layout: a #GtkExtendedLayout instance
 *
 * Gets whether the widget prefers a height-for-width layout
 * or a width-for-height layout
 *
 * Returns: %TRUE if the widget prefers height-for-width, %FALSE if
 * the widget should be treated with a width-for-height preference.
 *
 * <note><para>#GtkBin widgets generally propagate the preference of thier child, 
 * container widgets need to request something either in context of their
 * children or in context of their allocation capabilities.</para></note>
 *
 * Since: 3.0
 */
gboolean
gtk_extended_layout_is_height_for_width (GtkExtendedLayout *layout);

/**
 * gtk_extended_layout_get_desired_width:
 * @layout: a #GtkExtendedLayout instance
 * @minimum_width: location to store the minimum size, or %NULL
 * @natural_width: location to store the natural size, or %NULL
 *
 * Retreives a widget's initial minimum and natural width.
 *
 * <note><para>This call is specific to height for width requests.</para></note>
 *
 * Since: 3.0
 */
void
gtk_extended_layout_get_desired_width (GtkExtendedLayout *layout,
				       gint              *minimum_width,
				       gint              *natural_width);


/**
 * gtk_extended_layout_get_desired_height:
 * @layout: a #GtkExtendedLayout instance
 * @minimum_width: location to store the minimum size, or %NULL
 * @natural_width: location to store the natural size, or %NULL
 *
 * Retreives a widget's minimum and natural size in a single dimension.
 *
 * <note><para>This call is specific to width for height requests.</para></note>
 *
 * Since: 3.0
 */
void
gtk_extended_layout_get_desired_height (GtkExtendedLayout *layout,
					gint              *minimum_height,
					gint              *natural_height);



/**
 * gtk_extended_layout_get_width_for_height:
 * @layout: a #GtkExtendedLayout instance
 * @height: the size which is available for allocation
 * @minimum_size: location for storing the minimum size, or %NULL
 * @natural_size: location for storing the natural size, or %NULL
 *
 * Retreives a widget's desired width if it would be given
 * the specified @height.
 *
 * Since: 3.0
 */
void
gtk_extended_layout_get_width_for_height (GtkExtendedLayout *layout,
                                          gint               height,
                                          gint              *minimum_width,
                                          gint              *natural_width);

/**
 * gtk_extended_layout_get_height_for_width:
 * @layout: a #GtkExtendedLayout instance
 * @width: the size which is available for allocation
 * @minimum_size: location for storing the minimum size, or %NULL
 * @natural_size: location for storing the natural size, or %NULL
 *
 * Retreives a widget's desired height if it would be given
 * the specified @width.
 *
 * Since: 3.0
 */
void
gtk_extended_layout_get_height_for_width (GtkExtendedLayout *layout,
                                          gint               width,
                                          gint              *minimum_height,
                                          gint              *natural_height);

/**
 * gtk_extended_layout_get_desired_size:
 * @layout: a #GtkExtendedLayout instance
 * @width: the size which is available for allocation
 * @request_natural: Whether to base the contextual request off of the 
 *  base natural or the base minimum
 * @minimum_size: location for storing the minimum size, or %NULL
 * @natural_size: location for storing the natural size, or %NULL
 *
 * Retreives the minimum and natural size of a widget taking
 * into account the widget's preference for height-for-width management.
 *
 * If request_natural is specified, the non-contextual natural value will
 * be used to make the contextual request; otherwise the minimum will be used.
 *
 * This is used to retreive a suitable size by container widgets whom dont 
 * impose any restrictions on the child placement. 
 *
 * Since: 3.0
 */
void
gtk_extended_layout_get_desired_size (GtkExtendedLayout *layout,
				      gboolean           request_natural,
                                      GtkRequisition    *minimum_size,
                                      GtkRequisition    *natural_size);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]