mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-27 22:20:24 +00:00
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:
parent
e8376f5c01
commit
cba24360b1
@ -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,
|
||||
* it’s 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, it’s 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 [GtkWidget’s geometry management section][geometry-management]
|
||||
* to learn more about implementing height-for-width geometry management for widgets.
|
||||
*
|
||||
* # Child properties
|
||||
*
|
||||
* GtkContainer introduces child properties.
|
||||
|
@ -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 [GtkWidget’s geometry management section][geometry-management] for
|
||||
* a more details on implementing #GtkWidgetClass.measure().
|
||||
*
|
||||
* Since: 3.90
|
||||
*/
|
||||
void
|
||||
|
138
gtk/gtkwidget.c
138
gtk/gtkwidget.c
@ -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 it’s 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
|
||||
* [GtkContainer’s 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 doesn’t 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
|
||||
**/
|
||||
|
Loading…
Reference in New Issue
Block a user