Move geometry management docs do GtkWidget

Both GtkWidget and GtkContainer had similar docs regarding hfw/wfh
geometry management. Move these just to GtkWidget. Also make sure the
examples compile, port everything from gtk_preferred_* to measure and
replace some occurrences of "container" with "widget" where container
was just used to refer to a widget with child widgets.
This commit is contained in:
Timm Bäder 2018-01-03 16:14:47 +01:00
parent e8376f5c01
commit cba24360b1
3 changed files with 61 additions and 196 deletions

View File

@ -100,122 +100,6 @@
* in the #GtkWidgetClass.destroy() implementation.
* See more about implementing custom widgets at https://wiki.gnome.org/HowDoI/CustomWidgets
*
* # Height for width geometry management
*
* GTK+ uses a height-for-width (and width-for-height) geometry management system.
* Height-for-width means that a widget can change how much vertical space it needs,
* depending on the amount of horizontal space that it is given (and similar for
* width-for-height).
*
* There are some things to keep in mind when implementing container widgets
* that make use of GTK+s height for width geometry management system. First,
* its important to note that a container must prioritize one of its
* dimensions, that is to say that a widget or container can only have a
* #GtkSizeRequestMode that is %GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH or
* %GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT. However, every widget and container
* must be able to respond to the APIs for both dimensions, i.e. even if a
* widget has a request mode that is height-for-width, it is possible that
* its parent will request its sizes using the width-for-height APIs.
*
* To ensure that everything works properly, here are some guidelines to follow
* when implementing height-for-width (or width-for-height) containers.
*
* Each request mode involves 2 virtual methods. Height-for-width apis run
* through gtk_widget_get_preferred_width() and then through gtk_widget_get_preferred_height_for_width().
* When handling requests in the opposite #GtkSizeRequestMode it is important that
* every widget request at least enough space to display all of its content at all times.
*
* When gtk_widget_get_preferred_height() is called on a container that is height-for-width,
* the container must return the height for its minimum width. This is easily achieved by
* simply calling the reverse apis implemented for itself as follows:
*
* |[<!-- language="C" -->
* static void
* foo_container_get_preferred_height (GtkWidget *widget,
* gint *min_height,
* gint *nat_height)
* {
* if (i_am_in_height_for_width_mode)
* {
* gint min_width;
*
* GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget,
* &min_width,
* NULL);
* GTK_WIDGET_GET_CLASS (widget)->get_preferred_height_for_width
* (widget,
* min_width,
* min_height,
* nat_height);
* }
* else
* {
* ... many containers support both request modes, execute the
* real width-for-height request here by returning the
* collective heights of all widgets that are stacked
* vertically (or whatever is appropriate for this container)
* ...
* }
* }
* ]|
*
* Similarly, when gtk_widget_get_preferred_width_for_height() is called for a container or widget
* that is height-for-width, it then only needs to return the base minimum width like so:
*
* |[<!-- language="C" -->
* static void
* foo_container_get_preferred_width_for_height (GtkWidget *widget,
* gint for_height,
* gint *min_width,
* gint *nat_width)
* {
* if (i_am_in_height_for_width_mode)
* {
* GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget,
* min_width,
* nat_width);
* }
* else
* {
* ... execute the real width-for-height request here based on
* the required width of the children collectively if the
* container were to be allocated the said height ...
* }
* }
* ]|
*
* Height for width requests are generally implemented in terms of a virtual allocation
* of widgets in the input orientation. Assuming an height-for-width request mode, a container
* would implement the get_preferred_height_for_width() virtual function by first calling
* gtk_widget_get_preferred_width() for each of its children.
*
* For each potential group of children that are lined up horizontally, the values returned by
* gtk_widget_get_preferred_width() should be collected in an array of #GtkRequestedSize structures.
* Any child spacing should be removed from the input @for_width and then the collective size should be
* allocated using the gtk_distribute_natural_allocation() convenience function.
*
* The container will then move on to request the preferred height for each child by using
* gtk_widget_get_preferred_height_for_width() and using the sizes stored in the #GtkRequestedSize array.
*
* To allocate a height-for-width container, its again important
* to consider that a container must prioritize one dimension over the other. So if
* a container is a height-for-width container it must first allocate all widgets horizontally
* using a #GtkRequestedSize array and gtk_distribute_natural_allocation() and then add any
* extra space (if and where appropriate) for the widget to expand.
*
* After adding all the expand space, the container assumes it was allocated sufficient
* height to fit all of its content. At this time, the container must use the total horizontal sizes
* of each widget to request the height-for-width of each of its children and store the requests in a
* #GtkRequestedSize array for any widgets that stack vertically (for tabular containers this can
* be generalized into the heights and widths of rows and columns).
* The vertical space must then again be distributed using gtk_distribute_natural_allocation()
* while this time considering the allocated height of the widget minus any vertical spacing
* that the container adds. Then vertical expand space should be added where appropriate and available
* and the container should go on to actually allocating the child widgets.
*
* See [GtkWidgets geometry management section][geometry-management]
* to learn more about implementing height-for-width geometry management for widgets.
*
* # Child properties
*
* GtkContainer introduces child properties.

View File

@ -392,6 +392,9 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
* this functions will compute the minimum and natural width of @widget if
* it is allocated at a height of 300 pixels.
*
* See [GtkWidgets geometry management section][geometry-management] for
* a more details on implementing #GtkWidgetClass.measure().
*
* Since: 3.90
*/
void

View File

@ -106,7 +106,15 @@
* - #GtkWidgetClass.measure()
*
* There are some important things to keep in mind when implementing
* height-for-width and when using it in container implementations.
* height-for-width and when using it in widget implementations.
*
* If you implement a direct #GtkWidget subclass that supports
* height-for-width or width-for-height geometry management for
* itself or its child widgets, the #GtkWidgetClass.get_request_mode()
* virtual function must be implemented as well and return the widget's
* preferred request mode. The default implementation of this virtual function
* returns %GTK_SIZE_REQUEST_CONSTANT_SIZE, which means that the widget will only ever
* get -1 passed as the for_size value to its #GtkWidgetClass.measure() implementation.
*
* The geometry management system will query a widget hierarchy in
* only one orientation at a time. When widgets are initially queried
@ -117,8 +125,8 @@
* %GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH mode:
* First, the default minimum and natural width for each widget
* in the interface will be computed using gtk_widget_measure() with an orientation
* or %GTK_ORIENTATION_HORIZONTAL and a for_size of -1.
* Because the preferred widths for each container depend on the preferred
* of %GTK_ORIENTATION_HORIZONTAL and a for_size of -1.
* Because the preferred widths for each widget depend on the preferred
* widths of their children, this information propagates up the hierarchy,
* and finally a minimum and natural width is determined for the entire
* toplevel. Next, the toplevel will use the minimum width to query for the
@ -133,8 +141,8 @@
* dimensions it can go on to allocate itself a reasonable size (or a size
* previously specified with gtk_window_set_default_size()). During the
* recursive allocation process its important to note that request cycles
* will be recursively executed while container widgets allocate their children.
* Each container widget, once allocated a size, will go on to first share the
* will be recursively executed while widgets allocate their children.
* Each widget, once allocated a size, will go on to first share the
* space in one orientation among its children and then request each child's
* height for its target allocated width or its width for allocated height,
* depending. In this way a #GtkWidget will typically be requested its size
@ -143,77 +151,57 @@
* requested. For this reason, #GtkWidget caches a small number of results
* to avoid re-querying for the same sizes in one allocation cycle.
*
* See
* [GtkContainers geometry management section][container-geometry-management]
* to learn more about how height-for-width allocations are performed
* by container widgets.
*
* If a widget does move content around to intelligently use up the
* allocated size then it must support the request in both
* #GtkSizeRequestModes even if the widget in question only
* trades sizes in a single orientation.
*
* For instance, a #GtkLabel that does height-for-width word wrapping
* will not expect to have #GtkWidgetClass.get_preferred_height() called
* because that call is specific to a width-for-height request. In this
* will not expect to have #GtkWidgetClass.measure() with an orientation of
* %GTK_ORIENTATION_VERTICAL called because that call is specific to a
* width-for-height request. In this
* case the label must return the height required for its own 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.
*
* Here are some examples of how a %GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH widget
* generally deals with width-for-height requests, for #GtkWidgetClass.get_preferred_height()
* it will do:
* generally deals with width-for-height requests:
*
* |[<!-- language="C" -->
* static void
* foo_widget_get_preferred_height (GtkWidget *widget,
* gint *min_height,
* gint *nat_height)
* foo_widget_measure (GtkWidget *widget,
* GtkOrientation orientation,
* int for_size,
* int *minimum_size,
* int *natural_size,
* int *minimum_baseline,
* int *natural_baseline)
* {
* if (i_am_in_height_for_width_mode)
* {
* gint min_width, nat_width;
* if (orientation == GTK_ORIENTATION_HORIZONTAL)
* {
* // Calculate minimum and natural width
* }
* else // VERTICAL
* {
* if (i_am_in_height_for_width_mode)
* {
* int min_width;
*
* GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget,
* &min_width,
* &nat_width);
* GTK_WIDGET_GET_CLASS (widget)->get_preferred_height_for_width
* (widget,
* min_width,
* min_height,
* nat_height);
* }
* else
* {
* ... some widgets do both. For instance, if a GtkLabel is
* rotated to 90 degrees it will return the minimum and
* natural height for the rotated label here.
* }
* }
* ]|
* // First, get the minimum width of our widget
* GTK_WIDGET_GET_CLASS (widget)->measure (widget, GTK_ORIENTATION_HORIZONTAL, -1,
* &min_width, NULL, NULL, NULL);
*
* And in #GtkWidgetClass.get_preferred_width_for_height() it will simply return
* the minimum and natural width:
* |[<!-- language="C" -->
* static void
* foo_widget_get_preferred_width_for_height (GtkWidget *widget,
* gint for_height,
* gint *min_width,
* gint *nat_width)
* {
* if (i_am_in_height_for_width_mode)
* {
* GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget,
* min_width,
* nat_width);
* }
* else
* {
* ... again if a widget is sometimes operating in
* width-for-height mode (like a rotated GtkLabel) it can go
* ahead and do its real width for height calculation here.
* }
* // Now use the minimum width to retrieve the minmimum and natural height to display
* // that width.
* GTK_WIDGET_GET_CLASS (widget)->measure (widget, GTK_ORIENTATION_VERTICAL, min_width,
* minimum_size, natural_size, NULL, NULL);
* }
* else
* {
* // ... some widgets do both.
* }
* }
* }
* ]|
*
@ -221,42 +209,32 @@
* allocation. For example, when computing height it may need to also
* compute width. Or when deciding how to use an allocation, the widget
* may need to know its natural size. In these cases, the widget should
* be careful to call its virtual methods directly, like this:
* be careful to call its virtual methods directly, like in the code
* example above.
*
* |[<!-- language="C" -->
* GTK_WIDGET_GET_CLASS(widget)->get_preferred_width (widget,
* &min,
* &natural);
* ]|
*
* It will not work to use the wrapper functions, such as
* gtk_widget_get_preferred_width() inside your own size request
* implementation. These return a request adjusted by #GtkSizeGroup
* and by the #GtkWidgetClass.adjust_size_request() virtual method. If a
* widget used the wrappers inside its virtual method implementations,
* It will not work to use the wrapper function gtk_widget_measure()
* inside your own #GtkWidgetClass.size-allocate() implementation.
* These return a request adjusted by #GtkSizeGroup, the widget's align and expand flags
* as well as its CSS style.
* If a widget used the wrappers inside its virtual method implementations,
* then the adjustments (such as widget margins) would be applied
* twice. GTK+ therefore does not allow this and will warn if you try
* to do it.
*
* Of course if you are getting the size request for
* another widget, such as a child of a
* container, you must use the wrapper APIs.
* another widget, such as a child widget, you must use gtk_widget_measure().
* 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
* has a vertical alignment of %GTK_ALIGN_BASELINE, and is inside a widget
* 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 doesnt need to be implemented.
* Baseline alignment support for a widget is also done by the #GtkWidgetClass.measure()
* virtual function. It allows you to report a both a minimum and natural
*
* 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().
@ -1896,7 +1874,7 @@ gtk_widget_class_init (GtkWidgetClass *klass)
*
* Returns: %TRUE if stopping keyboard navigation is fine, %FALSE
* if the emitting widget should try to handle the keyboard
* navigation attempt in its parent container(s).
* navigation attempt in its parent widget(s).
*
* Since: 2.12
**/