Skip to content
Ariel Vina-Rodriguez edited this page Apr 16, 2024 · 18 revisions

Div-Text is a string used to specify a rule of layout how child windows are sized/placed within its parent window.

Table of Contents

Basic Concept

Attributes of Field

Fit-Content Layout

Advanced Fields

Basic Concept

Field

A basic concept is field. It represents an area in the window. Define a field

<>

It represents the whole area of the window.

Define fields

<><>

The two fields represent left area and right area of the window.

Fields can be nested, one outter field and three nested fields

<<><><>>

The three nested fields represent left area, center area and right area of the window.

Root field. There is an implicit root field, all the fields defined by Div-Text are children of root field.

Array

[1, 2, 3]

Define an array that has 1, 2 and 3 three elements.

[1, 2, 3, repeated]

The keyword repeated indicates the array is countless. Its elements are 1,2,3,1,2,3,1,2,3,...

[1, 2, variable, 3]

The keyword variable is a unspecified value, it is interpreted differently by different attributes of the field (arrange, gap, margin). Refer to the attributes for more details.

Attributes of Field

Name

If a field has a name, the field can be operated. The name is a field's identifier.

<id_you_specify> A named field can be addressed by using following statement.

place.field("id_you_specify");
//or
place["id_you_specify"];

vertical or vert

Specifies a field that all its nested fields and contents are positioned vertically. If vertical or vert is not specified, the nested fields and contents are positioned horizontally. For example.

place plc{fm}; //fm is an instance of nana::form
plc.div("<abc>"); //name abc for the field.
plc["abc"]<<btn0<<btn1<<btn2<<btn3; //These buttons are child widgets of fm.
plc.collocate();

Place horizontal

//Replace the line
plc.div("<abc>"); 
//with
plc.div("<vert abc>");

Then, the buttons are positioned vertically.

Place vertical

width or height (or weight)

Specifies the width or height of a field. It depends on the type of its owner field. If the owner field is vertical, the weight indicates the height. If the owner field is horizontal, the weight indicates the width. The weight supports different units type.

<abc><weight=200 def>

If the width of form is 1000px, the field abc is 800px and def is 200px.

<abc><weight=60% def><ghi>

If the width of form is 1000px, the field abc is 200px, def is 600px and ghi is 200px.

max/min

Specifies the minimized/maximized weight of a field. When specifies the weight and min/max for a field at same time, the weight attribute only works for initializing the field.

arrange

Specifies weight for a group of widgets.

place.div("<abc arrange=[50,100]>");
place["abc"]<<btn0<<btn1;

Arrange

If the number of widgets in the field is larger than the number of elements in arrange, the extra widgets will be resized by place.

If the variable is given in the arrange's array, it indicates a corresponding widget's weight is not specified, the widget will be resized by place.

place.div("fld arrange=[30,variable,60,repeated]"); //Refer the arrange section for keyword repeated.
std::vector<std::unique_ptr<button>> buttons;
for (int i = 0; i < 6; ++i)
{
	buttons.emplace_back(std::make_unique<button>(fm.handle(), std::to_string(i)));
	place["fld"] << *buttons.back();
}
place.collocate();

Variable in arrange

After enlarging, the width of widget 1 and 4 is changed by the place, because their corresponding weight in arrange is variable.

gap

Gap is used to specify a space between widgets, in pixels. The value of gap is an array.

place.div("<fld gap=[5,10,20]>");
for (int i = 0; i < 5; ++i)
{
	buttons.emplace_back(std::make_unique<button>(fm.handle(), std::to_string(i)));
	place["fld"] << *buttons.back();
}
place.collocate();

Gap

As you see, there are 3 gaps.

The gap can be assigned with an integral number, the gap interprets the integral number as an repeated array.

<gap=5> is interpreted as <gap=[5,repeated]>

If the element of gap's array is variable, the variable here will be interpreted as zero.

gap in grid

<grid=[3,3] gap=5>

Gap in grid

When a field is a grid, the place only employs the first element of gap, other elements are ignored.

margin

Specifies the whitespace at edges of a field. It can have from 1 to 4 values.

<margin=[10,20,30,40]>

top margin = 10, right margin = 20, bottom margin = 30, left margin = 40

<margin=[10,20,30]>

top margin = 10, right margin = 20, bottom margin = 30

<margin=[10,20]>

top and bottom margin = 10, left and right margin = 20

<margin=[10]>

top margin = 10

<margin=20>

top, right, bottom and left margin = 20

The varible in margin is interpreted as zero.

Fit-Content Layout

fit

The fit defines a field that layouts a measurable widget to fit its content.

btna.caption("This is very long long long title");
btnb.caption("Short title");
place.div("<><fit x gap=5><>");
place["x"]<<btna<<btnb;
place.collocate();

fit

vfit

The vfit layouts a measurable widget to fit its content, and the height of the content is measured with a specified fixed width. At present (Nana 1.7) only label supports vfit.

std::string content = "Nana C++ Library takes aim at easy-to-use and portable library, it provides a GUI framework and threads for easy programming with modern C++ methods.";

label.caption(content);
place.div("<><vfit=200 x><>");
place["x"]<<label;
place.collocate();

vfit

Advanced Fields

dock

When a field is specified with dock, its child fields are dockable. These child fields called dockable field. A widget that attaches to a dockable field can be docked inside the dock field or floated on the desktop. The dockable field can't have a child field.

Dockpane is a library maintained internal window which attaches to the dockable field, it has a title bar and a close button, it is the parent of user widgets which attaches to dockable field.

//Create a dock field that has one dockable field.
place.div("<dock<dockableA>>");

//Create a dockpane factory that creates a button.
place.dock<button>("dockableA", "f", std::string{"Button"});

//Create a dockpane
place.dock_create("f");

Dock

The line

place.dock<button>("dockableA", "f", std::string("Button"));

Adds a factory that creates a button for the dockable field "dockableA", The name of the factory is "f", the 3rd parameter and after the 3rd parameters, are passed to the constructor of class button. The button is constructed by following function call

button{DockPaneHandle, std::forward<Args>(third_args)...};

If a factory doesn't have a name, the factory will be called immediately. Because of no name, the factory also can't be called by using place::dock_create().

The line

place.dock_create("f");

calls the specified factory "f" which creates a button. See above screenshot. If the "f" factory get called many times, a tabbar will be created for switching the multiple buttons that attaches to the same dockable field.

Dock tabswitch

top, right, bottom and left

These 4 attributes specify the position of a dockable field to the next silbing dockable field. Therefore the position attribute of last dockable field is always ignored.

weight

Specifies width or height of a dockable field. But the weight behaves differently with other type fields if the weight is assigned with a percentage. The percentage weight for dockable field is a percentage of sum of current dockable field and its right field(s).

dock-weight

Above screenshot illustrates the weight of dockable field when the dock field is defined as

<dock><A weight=25%><B weight=25%><C weight=50%>

grid

Specifies a field that positions its widgets as a grid. The value of grid is an array with 2 integral numbers.

<grid=[3,2]>

It defines a grid field that has 3 columns and 2 rows.

place.div("<fld grid=[3,3]>");
std::vector<std::unique_ptr<button>> buttons;
for(int i = 0; i < 9; ++i)
{
	buttons.emplace_back(std::make_unique<button>(fm.handle(), "Button"));
	place["fld"] << *buttons.back();
}

Grid

The grid lays the buttons out from left to right, top to bottom.

collapse

The grid is like to divide the field into blocks. The collapse can merge the blocks, it has 4 parameters

<grid=[3,2] collapse(0,1,3,1)>

These 4 parameters indicate (left, top, columns, rows), collapse merges 3 blocks in that area.

//Merges the 3 blocks in row 2.
place.div("<fld grid=[3,2] collapse(0,1,3,1)>");
std::vector<std::unique_ptr<button>> buttons;
for(int i = 0; i < 4; ++i)
{
	buttons.emplace_back(std::make_unique<button>(fm.handle(), "Button"));
	place["fld"] << *buttons.back();
}

Grid collapse

A grid can be specified with more than one collapse, but overlapped collapse will be ignored.

<grid=[3,2] collapse(0,1,3,1) collapse(1,1,2,2)>

The second collapse is ignored, because of overlap with the first one.

Splitter bar

<a>|<b>

Sets a splitter bar between field a and b. When a number is specified behand |, it stands for an initial weight of right field.

<a>|30<b>

Field b's weight is 30px.

<a>|30%<b>

If the number is a percentage, it indicates the percentage of sum of left and right field. The weight of field b is (weight of a + weight of b) * 30%. Note: the initial weight attribute will be ignored if the weight is specified for right field, for example.

<a>|30%<b weight=20>

The 30% is ignored because of b's weight=20.

switchable

When a field is specified with switchable, it only shows one child field. If display another child field using field_display method, the shown child field will be hidden. It performs like a tab control.

int main()
{
    using namespace nana;

    form fm;

    button switch_btn{ fm };

    listbox list{ fm };
    textbox text{ fm };
    label labl{ fm };
    labl.caption("label");
    fm.div("<btn><switchable <list><text><label>>");
    fm["btn"] << switch_btn;
    fm["list"] << list;
    fm["text"] << text;
    fm["label"] << labl;
    fm.collocate();


    //one of the panel list, text and label is shown when every time the switch_btn get clicked.
    switch_btn.events().click([&] {
        static std::vector<std::string> panels{"list", "text", "label"};
        static int i = 0;
        ++i;
        if (i >= panels.size())
            i = 0;

        //Displays one of the field, other 2 fields will be hidden automatically.
        fm.get_place().field_display(panels[i].c_str(), true);
        fm.collocate();
    });

    fm.show();
    exec();
}