Resizing for R3 GUI framework
Author: Ladislav Mecir, Richard Smolak
Date: 13-Jan-2013/15:50:55+1:00
The purpose of this document is to describe the R3 GUI resizing subsystem.
The original resizing in R3 GUI had the following bugs and limitations:
What was needed, was to define an algorithm that would:
Since the idea to use the MAX-SIZE field to determine the expansion ratio was not accepted well, we needed to use a different approach, looking more “natural” to the user.
The most natural expansion principle seemed to be the principle to expand objects “evenly”, i.e. proportionally to their original dimensions. The attribute used is called INIT-SIZE.
Let’s consider two objects with no resizing limits, object A having INIT-SIZE 50x20, object B having INIT-SIZE 100x20. Moreover, let’s suppose that the objects are in a hpanel consisting of just one row and containing no additional space.
Initially, both objects will have the dimensions 50x20 and 100x20, and the hpanel will have the dimensions 150x20. If it is needed to expand the hpanel to 300x20, the object A will be resized to 100x20, while the object B will be resized to 200x20, i.e. proportionally to their INIT-SIZE values.
For every object it is possible to specify the smallest dimensions the object is allowed to have after resizing. The attribute is called MIN-SIZE. When the size computed by the resizing algorithm would be smaller than the MIN-SIZE, the calculated size is clipped to the MIN-SIZE.
If we do not want to limit the object’s ability to shrink, we can set the MIN-SIZE of the object to 0x0. That does not limit the object’s ability to shrink.
For every object it is possible to specify the greatest dimensions the object is allowed to have after resizing. The attribute is called MAX-SIZE. When the size computed by the resizing algorithm would be greater than the MAX-SIZE, the calculated size is clipped to the MAX-SIZE.
If we do not want to limit the object’s ability to expand, we can set the MAX-SIZE of the object to GUIE/MAX-PAIR value, which is large enough to not limit the object’s ability to expand.
To specify the way, how the dimensions of layouts, layout rows and columns are calculated, it is possible to use hints.
Every graphic object has a content area and optional surrounding padding, border, and margin areas.
For every object in a layout it is possible to specify that the object is:
In a hpanel, vpanel, hgroup, or vgroup the initial, minimal, and maximal sizes are computed using the dimensions of the graphic elements the layout contains and the hints user has given.
These attributes are the hints used to calculate the layout dimensions, the INIT-HINT is used to calculate the INIT-SIZE, the MIN-HINT is used to calculate the MIN-SIZE, and the MAX-HINT is used to calculate the MAX-SIZE.
Since the contents of a layout can be examined, it is possible to calculate the INIT-SIZE, MIN-SIZE and MAX-SIZE values for a layout based on its contents.
For example, if we set the INIT-HINT layout attribute to ‘AUTO, we are suggesting that the INIT-SIZE of the layout shall be calculated automatically, from the dimensions of the layout contents.
This is the default value, i.e., if not specified otherwise by the user, the layout dimensions will be calculated automatically from dimensions of the layout contents.
For the MAX-SIZE and MIN-SIZE, the default hint is the ‘AUTO hint as well, i.e. the values are calculated automatically from the contents of the layout.
When calculating the MIN-SIZE, the ‘INIT hint can be used, if the user does not want the layout to become smaller than its INIT-SIZE is.
Similarly, when calculating the MAX-SIZE, the ‘INIT hint can be used, if the user does not want the layout to become larger than its INIT-SIZE is.
To specify that the layout does not resize at all, it is sufficient to use the ‘INIT hint both for the layout MIN and MAX sizes. This way, the layout size cannot change.
When used e.g. as the MAX-HINT, this value specifies that the MAX-SIZE of the layout should be kept as it is now, i.e. not recalculated.
For every coordinate it is possible to specify a separate hint. For example, the INIT-HINT = 100x200 value specifies that the INIT-SIZE of the layout should always be 100x200. Another way, how to specify the same is to set the INIT-HINT to [100 200]. In the latter case, any of the numbers can be replaced by one of the above word hints.
Every style can have its own resizing. Currently, there are three resizing methods available:
In a hpanel or vpanel, the graphic objects are arranged into both rows and columns at the same time. As opposed to the group layout, layout resize always respects both rows as well as columns, producing a “perfectly tabular” layout.
Similarly as for hgroup/vgroup, the hpanel and vpanel differ by their LAYOUT-MODE attribute, which can be changed at run time. This attribute is the main difference between a hpanel and vpanel.
When the LAYOUT-MODE is set to HORIZONTAL (for hpanel), the primary orientation is left-to-right, rows are layed out in top-down manner; when the LAYOUT-MODE is set to VERTICAL (for hpanel), the primary orientation is top-down, columns are layed in left-to-right manner.
The LAYOUT-MODE can be changed at run-time, changing effectively a hpanel to vpanel or vice versa.
Initial, minimal and maximal sizes of all rows and columns are computed from initial, minimal and maximal sizes of their graphic elements.
Similarly as for layouts, the init, min, and max sizes of rows and columns are calculated using hints. The hints used are ROW-INIT - used to calculate the init height of row, ROW-MIN - used to calculate the min height of row, ROW-MAX - used to calculate the max height of a row, COLUMN-INIT - used to calculate the init width of a column, COLUMN-MIN used to calculate the min width of a column, and COLUMN-MAX - used to calculate the max width of a column.
When used as the value of the ROW-INIT hint, it suggests that all initial heights shall be calculated as the maxima of the initial heights of their contents.
When used as the value of the ROW-MAX hint, it suggests that all the max heights of the rows shall be calculated as the minima of the max heights of their contents.
When used as the value of the ROW-MIN hint, it suggests that all the min heights of the rows shall be kept “as is”.
When a number such as 100 is used as the COLUMN-INIT hint, it suggests that the initial widths of all columns shall be set to 100.
It is possible to specify a hint for every column individually, by specifying a block containing one of the above hints for every layout column. (or row)
For every object, the resizing function computes the “layout cell” that contains it, which is an intersection of object’s row with object’s column. In the “layout cell”, the horizontal position of the object is chosen in accordance with object’s ALIGN attribute, the vertical position is chosen in accordance with object’s VALIGN attribute.
Respecting the PANE-ALIGN and PANE-VALIGN attributes, the whole “tabular layout” is positioned in the layout viewport. For example, if the PANE-ALIGN is left and PANE-VALIGN is top, the top left point of the layout is positioned to the top left point of the layout viewport, similarly for other cases.
In a group, the graphic objects are primarily arranged depending on its LAYOUT-MODE attribute. The LAYOUT-MODE attribute can have two possible values: HORIZONTAL and VERTICAL.
If the LAYOUT-MODE is HORIZONTAL, the graphic object in the hgroup are arranged into rows in a left to right manner. Rows are positioned in a top-down manner.
If the LAYOUT-MODE is VERTICAL, the graphic object in the vgroup are arranged into columns in a top to down manner. Columns are positioned in a left-to-right manner.
By changing the LAYOUT-MODE of a hgroup/vgroup it is possible to change the way how the subobjects are arranged, which actually transforms a hgroup into a vgroup and vice versa.
Every graphic object in a row (or column, depending on the LAYOUT-MODE) is supposed to lay next to another, so, if we eventually want to have a “gap” between two subsequent graphic objects, we may need to insert a “filler object” “occupying” the “empty space” between the objects.
The resizing algorithm works so that for a pair of graphic objects laying next to each other holds that they will remain to lay next to each other after any resizing operation.
If the LAYOUT-MODE is HORIZONTAL, the height of a row is the maximum of the heights of all graphic objects in the row.
Analogically, if the LAYOUT-MODE is VERTICAL, the width of a column is the maximum of the widths of all graphic objects in the column.
If the LAYOUT-MODE is HORIZONTAL, the height of a row can be adjusted by inserting a “flexible” graphic object into the row (which may even be invisible), allowing the row to grow more, than “ordinary graphic objects” would allow. This suggestion works analogically columns, if the LAYOUT-MODE is VERTICAL.
To compute the transverzal position of a graphic object, its alignment attributes are taken into account.
If the LAYOUT-MODE is HORIZONTAL, the the VALIGN attribute is used to align the object relative to its row as follows:
If the LAYOUT-MODE is VERTICAL, the the ALIGN attribute is used to align the object relative to its column as follows:
If the LAYOUT-MODE is HORIZONTAL, the row ALIGN attribute specifies the horizontal alignment of the row relative to the group viewport. Three alignment alternatives are available:
If the LAYOUT-MODE is HORIZONTAL, the PANE-ALIGN attribute is used to set the ALIGN attributes of all rows in the group. In case the PANE-ALIGN attribute is a word, all group rows get the same ALIGN attribute as specified by PANE-ALIGN. If the PANE-ALIGN attribute is a block, every row obtains its own ALIGN attribute from the PANE-ALIGN block.
If the LAYOUT-MODE is VERTICAL, the VALIGN attribute specifies the vertical alignment of the column relative to the group viewport. Three alignment alternatives are available:
If the LAYOUT-MODE is VERTICAL, the PANE-VALIGN attribute is used to set the VALIGN attributes of all columns in the group. In case the PANE-VALIGN attribute is a word, all group columns get the same VALIGN attribute as specified by PANE-VALIGN. If the PANE-VALIGN attribute is a block, every column obtains its own VALIGN attribute from the PANE-VALIGN block.
The resizing algorithm is working so that if two rows/columns lay next to each other, they will remain to lay next to each other (without any gap) after any resizing operation.
To specify the vertical position of all group rows, three alignment alternatives using the PANE-VALIGN attribute of the group are available:
To specify the horizontal position of all group columns, three alignment alternatives using the PANE-ALIGN attribute of the group are available:
Similarly as for (h/v)panels, it is possible to specify hints for group lines. The hints used are: LINE-INIT - used to calculate the initial transversal dimensions of lines, LINE-MIN - used to calculate the minimal transversal dimensions of lines, LINE-MAX - used to calculate the maximal transversal dimensions of line.
The same types of hint values as for layout rows/columns are available.
The box model used is similar to the well known CSS box model. Every GOB has a viewport(content) area and optional surrounding padding, border, and margin areas.
The margin, border, and padding can be broken down into top, right, bottom, and left segments.
The perimeter of each of the four areas (viewport, padding, border, and margin) is called an “edge”, so each box has four edges:
The viewport edge surrounds the viewport area of GOB. The four viewport edges define the GOB’s viewport box.
The padding edge surrounds the GOB padding. If the padding has 0 width, the padding edge is the same as the viewport edge. The four padding edges define the GOB’s padding box.
The border edge surrounds the GOB border. If the border has 0 width, the border edge is the same as the padding edge. The four border edges define the GOB’s border box.
The margin edge surrounds the GOB margin. If the margin has 0 width, the margin edge is the same as the border edge. The four margin edges define the GOB’s margin box.
Note
NOTE: The margin area has a transparent background, so it reveals the content under the GOB, while the background of the padding area is of the same color as the background of the GOB.
Each edge may be broken down into a top, right, bottom, and left edge. The offset/size values for each edge have to be specified in pixel units.
The dimensions of the viewport area of a GOB can be affected by the settings of all edges. The final width and height of the GOB is always equal to the defined size of the gob.
The following equation is always true:
viewport-size = gob-size - margin-top-left - border-top-left - padding-top-left -
margin-bottom-right - border-bottom-right - padding-bottom-right
For example GOB of size 100x100 pixels with border of 1 pixel on all edges will have viewport area of size 98x98 pixels.
The resizing system needs to define a couple of additional atributes(accessible thru FACETS object) for each GOB to be able to work properly.
This section will describe data formats used by specific attributes.
format |
description |
---|---|
word! |
layout mode, variants are: HORIZONTAL VERTICAL |
format |
description |
---|---|
word! |
horizontal alignment, variants are: LEFT CENTER RIGHT |
format |
description |
---|---|
word! or block! |
horizontal alignment, variants are: left center right |
format |
description |
---|---|
word! |
vertical alignment, variants are: TOP MIDDLE BOTTOM |
format |
description |
---|---|
word! or block! |
vertical alignment, variants are: TOP MIDDLE BOTTOM |
format |
description |
---|---|
pair! |
size as a pair, in pixels |
format |
description |
---|---|
integer! (positive) |
The column count in a hpanel, or the row count in a vpanel |
format |
description |
---|---|
tuple! |
color of the border defined as a rebol tuple |
format |
description |
---|---|
integer! |
all edges will have the same integer value, in pixels |
pair! |
top/bottom and left/right edge pairs will have the same value, in pixels |
[pair!] |
only the top/left edges are set, in pixels |
[pair! pair!] |
every edge is defined separately, in pixels |
format |
description |
---|---|
block! |
valid DRAW dialect block |
format |
description |
---|---|
[pair! pair!] |
first pair is left/top, second right/bottom value, in pixels |
When a face was updated by changing its dimensions, or otherwise affecting its appearance/handling by its parent layout, the UPDATE-FACE function should be called to “signal” that event to its parent.
update-face: funct [
face [object!]
/no-show
/contents
/contents-only
]
When called with the /NO-SHOW refinement, the function just sets the respective flags for the layout resizing algorithm to be able to update the layout.