Native Windows GUI: Layouts
A layout resizes and moves the children controls of a Window control
Native windows GUI includes 2 type of layouts: BoxLayout and GridLayout.
- A FlexboxLayout lays out widgets in vertical line or horizontal line
- A GridLayout lays out widgets in a grid
To learn how to use layouts with
native-windows-derive
see
the derive section
Basic usage
Just like most NWG objects, layouts are created using a builder api. A layout uses 1 parent control and 0 or more children control. For children or for the parent,
the layout only accepts window-like controls (
valid: buttons, edit, etc.
not valid: menu, timer, notice, etc).
Layouts implement default. A default layout must first be initialized with a builder. Trying to call methods on default builders will cause a panic.
Layouts resize their children automatically when the parent control is resized. This also triggers a
OnResize
event.
GridLayout and
flexbox have a similar builder API. With some exceptions when defining children.
Layouts uses interior mutability, as such it's always possible to edit their properties or their children
Gridlayout
The GridLayout splits the parent control into an equally spaced grid. Children are placed in that grid using a [row, column] index.
Optionally, children controls can span across more than one row/column.
Children in a gridlayout can be added using the
child
method or the
child_item
method. The first one is a simpler interface when the
children control do not span across multiple cells.
child_item
is used to specify the row span and the column span of the children.
A gridlayout can be manually resized with the
resize
method. Also, if one of the layout properties was updates, the
fit
method can be used
to show the change and refit the children in the parent.
Lastly, check out the grid layout docs for the layout properties.
A grid layout example:
let grid = nwg::GridLayout::default();
let window: &nwg::Window = /*...*/;
let item1: &nwg::Button = /*...*/;
let item2: &nwg::Label = /*...*/;
nwg::GridLayout::builder()
.parent(&window)
.max_row(Some(6))
.spacing(5)
.margin([0,0,0,0])
.child(0, 0, &item1)
.child_item(nwg::GridLayoutItem::new(&item2, 1, 0, 2, 1))
.build(&grid);
FlexboxLayout
Flexbox layout uses
stretch to align children controls in a row or in column.
Internally, nwg controls (both the parent and the children) are associated with a stretch node/style. See the flexbox layout docs for the style methods.
At building time, a new children can be added to the layout using the
child
method. Following this method, any
child_*
method call will
customize the style of this child. Another call to
child
will finalize the current child style
A flexbox layout example:
use native_windows_gui as nwg;
// native_windows_gui exports stretch
use nwg::stretch::{geometry::{Size, Rect}, style::{Dimension as D, FlexDirection}};
const FIFTY_PC: D = D::Percent(0.5);
const PT_10: D = D::Points(10.0);
const PT_5: D = D::Points(5.0);
const PADDING: Rect<D> = Rect{ start: PT_10, end: PT_10, top: PT_10, bottom: PT_10 };
const MARGIN: Rect<D> = Rect{ start: PT_5, end: PT_5, top: PT_5, bottom: PT_5 };
fn build_layout(window: &nwg::Window, item1: &nwg::Button, item2: &nwg::Button) {
let layout = nwg::FlexboxLayout::default();
nwg::FlexboxLayout::builder()
.parent(&window)
.flex_direction(FlexDirection::Row)
.padding(PADDING)
.child(item1)
.child_margin(MARGIN)
.child_max_size(Size { width: D::Points(200.0), height: D::Undefined })
.child_size(Size { width: FIFTY_PC, height: D::Auto })
.child(item2)
.child_margin(MARGIN)
.child_size(Size { width: D::Percent(0.25), height: FIFTY_PC })
.build(&layout);
layout
}
Flexbox with sub layouts:
use native_windows_gui as nwg;
// native_windows_gui exports stretch
use nwg::stretch::{
geometry::Size,
style::{Dimension as D, FlexDirection, JustifyContent},
};
const PC_50: D = D::Percent(0.5);
const PT_50: D = D::Points(50.0);
fn build_complex_layout(
window: &nwg::Window,
label_a: &nwg::Label,
label_b: &nwg::Label,
textbox_a: &nwg::TextBox,
box_a: &nwg::Button,
box_b: &nwg::Button,
) {
let top_layout = Default::default();
let middle_layout = Default::default();
let bottom_layout = Default::default();
let full_layout = Default::default();
nwg::FlexboxLayout::builder()
.parent(window)
.flex_direction(FlexDirection::Column)
.justify_content(JustifyContent::Center)
.child(label_a)
.child_size(Size { width: PC_50, height: PT_50 })
.child(textbox_a)
.child_flex_grow(1.0)
.build_partial(&top_layout)
.unwrap();
nwg::FlexboxLayout::builder()
.parent(window)
.flex_direction(FlexDirection::Row)
.child(box_a)
.child_size(Size { width: PT_50, height: PT_50 })
.child(box_b)
.child_size(Size { width: PT_50, height: PT_50 })
.build_partial(&middle_layout)
.unwrap();
nwg::FlexboxLayout::builder()
.parent(window)
.child(label_b)
.child_size(Size { width: D::Percent(1.0), height: PT_50 })
.build_partial(&bottom_layout)
.unwrap();
nwg::FlexboxLayout::builder()
.parent(window)
.flex_direction(FlexDirection::Column)
.child_layout(&top_layout)
.child_layout(&middle_layout)
.child_flex_grow(1.0)
.child_layout(&bottom_layout)
.build(&full_layout)
.unwrap();
}
DynLayout
DynLayout layout works like Dynamic Layout in MFC.
It uses ratios for moving and sizing a control horizontally and vertically, when its parent Window is resized.
Application can define the ratios and call
fit
function to move and resize a control. An example is to add a control with preferred ratio in
OnInit
and call the
fit
method in
OnResize
method to adjust the position and size of the control.
The ratios are in percents
(0, 100)
,
0
means not to move or resize a control,
100
means to move or resize a control a hundre percent accordingly to Window size.
A dynamic layout example:
use native_windows_gui as nwg;
use native_windows_derive as nwd;
use nwd::{NwgUi, NwgPartial};
use nwg::NativeUi;
#[derive(Default, NwgUi)]
pub struct Application {
#[nwg_control(size: (500, 400), position: (300, 300), title: "DynLayout")]
#[nwg_events(OnInit: [Application::init], OnResize: [Application::size])]
window: nwg::Window,
#[nwg_layout(parent: window)]
layout: nwg::DynLayout,
#[nwg_control(text: "Ok", position: (120, 350), size: (100, 25))]
ok_btn: nwg::Button,
}
mpl Application {
fn init(&self) {
self.layout.add_child((0, 100), (0, 0), &self.ok_btn);
self.layout.fit();
}
fn size(&self) {
self.layout.fit();
}
}
Examples