From cba24360b1bae58c690ff6044d6fbc5c5391f707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Wed, 3 Jan 2018 16:14:47 +0100 Subject: [PATCH] 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. --- gtk/gtkcontainer.c | 116 ------------------------------------ gtk/gtksizerequest.c | 3 + gtk/gtkwidget.c | 138 ++++++++++++++++++------------------------- 3 files changed, 61 insertions(+), 196 deletions(-) diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c index 820af54703..9cbe2e52ce 100644 --- a/gtk/gtkcontainer.c +++ b/gtk/gtkcontainer.c @@ -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: - * - * |[ - * 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: - * - * |[ - * 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. diff --git a/gtk/gtksizerequest.c b/gtk/gtksizerequest.c index 458a6d1aa8..507d0ecfe8 100644 --- a/gtk/gtksizerequest.c +++ b/gtk/gtksizerequest.c @@ -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 diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index db7c0980ef..90ded7c67e 100644 --- a/gtk/gtkwidget.c +++ b/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: * * |[ * 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: - * |[ - * 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. * - * |[ - * 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 **/