gabdube / native-windows-gui

A light windows GUI toolkit for rust
https://gabdube.github.io/native-windows-gui/
MIT License
1.96k stars 127 forks source link

Can't find a way to create a fieldset #244

Closed arslivinski closed 2 years ago

arslivinski commented 2 years ago

I'm trying to replicate this layout:

image

But I'm unable to find a component that let me to create the Results and Actions fieldsets at the bottom. There's a way to do that with NWG?

gabdube commented 2 years ago

Native-windows-gui doesn't handle layout within layout very well. That's mostly because defining gui layouts is very verbose. That said, if you don't mind the verbosity, you can achieve that using partials:

use native_windows_gui as nwg;
use native_windows_derive as nwd;

use nwd::{NwgUi, NwgPartial};
use nwg::NativeUi;

use nwg::stretch::{style::*, geometry::*};

const ZERO: Dimension = Dimension::Points(0.0);
const NULL_PADDING: Rect<Dimension> = Rect { start: ZERO, end: ZERO, top: ZERO, bottom: ZERO };

// A "Label:  Button" field
#[derive(Default, NwgPartial)]
pub struct ButtonPanelField {
    label_text: &'static str,

    #[nwg_layout(flex_direction: FlexDirection::Row)]
    layout: nwg::FlexboxLayout,

    #[nwg_control(text: data.label_text)]
    #[nwg_layout_item(
        layout: layout,
        size: Size { width: Dimension::Percent(0.5), height: Dimension::Points(30.0) },
        flex_grow: 1.0
    )]
    label: nwg::Label,

    #[nwg_control(text: "Go")]
    #[nwg_layout_item(
        layout: layout,
        size: Size { width: Dimension::Points(100.0), height: Dimension::Points(30.0) },
    )]
    button: nwg::Button,
}

// A "Label:  Label" field
#[derive(Default, NwgPartial)]
pub struct TextPanelField {
    label_text: &'static str,

    #[nwg_layout(flex_direction: FlexDirection::Row)]
    layout: nwg::FlexboxLayout,

    #[nwg_control(text: data.label_text)]
    #[nwg_layout_item(
        layout: layout,
        size: Size { width: Dimension::Percent(0.5), height: Dimension::Points(30.0) },
        flex_grow: 1.0
    )]
    label: nwg::Label,

    #[nwg_control(text: "TEST", h_align: nwg::HTextAlign::Right)]
    #[nwg_layout_item(
        layout: layout,
        size: Size { width: Dimension::Points(100.0), height: Dimension::Points(30.0) },
    )]
    button: nwg::Label,
}

#[derive(Default, NwgPartial)]
pub struct ResultsPanel {
    #[nwg_layout(flex_direction: FlexDirection::Column, padding: NULL_PADDING )]
    layout: nwg::FlexboxLayout,

    #[nwg_control(flags: "VISIBLE")]
    #[nwg_layout_item(layout: layout, size: Size { height: Dimension::Points(40.0), ..Default::default() })]
    f1: nwg::Frame,

    #[nwg_partial(parent: f1)]
    file: TextPanelField,

    #[nwg_control(flags: "VISIBLE")]
    #[nwg_layout_item(layout: layout, size: Size { height: Dimension::Points(40.0), ..Default::default() })]
    f2: nwg::Frame,

    #[nwg_partial(parent: f2)]
    crc: TextPanelField,

    #[nwg_control(flags: "VISIBLE")]
    #[nwg_layout_item(layout: layout, size: Size { height: Dimension::Points(40.0), ..Default::default() })]
    f3: nwg::Frame,

    #[nwg_partial(parent: f3)]
    md5: TextPanelField,

    #[nwg_control(flags: "VISIBLE")]
    #[nwg_layout_item(layout: layout, size: Size { height: Dimension::Points(40.0), ..Default::default() })]
    f4: nwg::Frame,

    #[nwg_partial(parent: f4)]
    info: TextPanelField,
}

#[derive(Default, NwgPartial)]
pub struct ActionsPanel {
    #[nwg_layout(flex_direction: FlexDirection::Column, padding: NULL_PADDING )]
    layout: nwg::FlexboxLayout,

    #[nwg_control(flags: "VISIBLE")]
    #[nwg_layout_item(layout: layout, size: Size { height: Dimension::Points(40.0), ..Default::default() })]
    f1: nwg::Frame,

    #[nwg_partial(parent: f1)]
    action1: ButtonPanelField,

    #[nwg_control(flags: "VISIBLE")]
    #[nwg_layout_item(layout: layout, size: Size { height: Dimension::Points(40.0), ..Default::default() })]
    f2: nwg::Frame,

    #[nwg_partial(parent: f2)]
    action2: ButtonPanelField,

    #[nwg_control(flags: "VISIBLE")]
    #[nwg_layout_item(layout: layout, size: Size { height: Dimension::Points(40.0), ..Default::default() })]
    f3: nwg::Frame,

    #[nwg_partial(parent: f3)]
    action3: ButtonPanelField,
}

#[derive(Default, NwgUi)]
pub struct App {
    #[nwg_control(size: (600, 300), position: (300, 300), title: "Layout example")]
    #[nwg_events( OnWindowClose: [App::exit] )]
    window: nwg::Window,

    #[nwg_layout(parent: window, flex_direction: FlexDirection::Row)]
    layout1: nwg::FlexboxLayout,

    #[nwg_control(parent: window)]
    #[nwg_layout_item(layout: layout1, size: Size { width: Dimension::Percent(0.6), height: Dimension::Auto } )]
    group1: nwg::Frame,

    #[nwg_partial(parent: group1)]
    results: ResultsPanel,

    #[nwg_control(parent: window)]
    #[nwg_layout_item(layout: layout1, size: Size { width: Dimension::Percent(0.4), height: Dimension::Auto } )]
    group2: nwg::Frame,

    #[nwg_partial(parent: group2)]
    actions: ActionsPanel,

}

impl App {
    fn exit(&self) {
        nwg::stop_thread_dispatch();
    }
}

fn main() {
    nwg::init().expect("Failed to init Native Windows GUI");
    nwg::Font::set_global_family("Segoe UI").expect("Failed to set default font");

    let app = App {
        actions: ActionsPanel {
            action1: ButtonPanelField { label_text: "Action 1", ..Default::default() },
            action2: ButtonPanelField { label_text: "Action 2", ..Default::default() },
            action3: ButtonPanelField { label_text: "Action 3", ..Default::default() },
            ..Default::default()
        },
        results: ResultsPanel {
            file: TextPanelField { label_text: "File:", ..Default::default() },
            crc: TextPanelField { label_text: "CR:", ..Default::default() },
            md5: TextPanelField { label_text: "MD5:", ..Default::default() },
            info: TextPanelField { label_text: "Info:", ..Default::default() },
            ..Default::default()
        },
        ..Default::default()
    };

    let _app = App::build_ui(app).expect("Failed to build UI");

    nwg::dispatch_thread_events();
}

This example will give you this:

image