extern crate native_windows_gui2 as nwg;
use nwg::NativeUi;
#[derive(Default)]
pub struct PartialDemo {
window: nwg::Window,
layout: nwg::FlexboxLayout,
menu: nwg::ListBox<&'static str>,
frame1: nwg::Frame,
frame2: nwg::Frame,
frame3: nwg::Frame,
people_ui: PeopleUi,
animal_ui: AnimalUi,
food_ui: FoodUi,
}
impl PartialDemo {
fn change_interface(&self) {
self.frame1.set_visible(false);
self.frame2.set_visible(false);
self.frame3.set_visible(false);
let layout = &self.layout;
if layout.has_child(&self.frame1) {
layout.remove_child(&self.frame1);
}
if layout.has_child(&self.frame2) {
layout.remove_child(&self.frame2);
}
if layout.has_child(&self.frame3) {
layout.remove_child(&self.frame3);
}
use nwg::stretch::{
geometry::Size,
style::{Dimension as D, Style},
};
let mut style = Style::default();
style.size = Size {
width: D::Percent(1.0),
height: D::Auto,
};
match self.menu.selection() {
None | Some(0) => {
layout.add_child(&self.frame1, style).unwrap();
self.frame1.set_visible(true);
}
Some(1) => {
layout.add_child(&self.frame2, style).unwrap();
self.frame2.set_visible(true);
}
Some(2) => {
layout.add_child(&self.frame3, style).unwrap();
self.frame3.set_visible(true);
}
Some(_) => unreachable!(),
}
}
fn save(&self) {
nwg::simple_message("Saved!", "Data saved!");
}
fn exit(&self) {
nwg::stop_thread_dispatch();
}
}
#[derive(Default)]
pub struct PeopleUi {
layout: nwg::GridLayout,
layout2: nwg::GridLayout,
label1: nwg::Label,
label2: nwg::Label,
label3: nwg::Label,
name_input: nwg::TextInput,
age_input: nwg::TextInput,
job_input: nwg::TextInput,
save_btn: nwg::Button,
}
#[derive(Default)]
pub struct AnimalUi {
layout: nwg::GridLayout,
layout2: nwg::GridLayout,
label1: nwg::Label,
label2: nwg::Label,
label3: nwg::Label,
name_input: nwg::TextInput,
race_input: nwg::ComboBox<&'static str>,
is_soft_input: nwg::CheckBox,
save_btn: nwg::Button,
}
#[derive(Default)]
pub struct FoodUi {
layout: nwg::GridLayout,
layout2: nwg::GridLayout,
label1: nwg::Label,
label2: nwg::Label,
name_input: nwg::TextInput,
tasty_input: nwg::CheckBox,
save_btn: nwg::Button,
}
mod partial_demo_ui {
use self::nwg::PartialUi;
use super::*;
use native_windows_gui2 as nwg;
use std::cell::RefCell;
use std::ops::Deref;
use std::rc::Rc;
pub struct PartialDemoUi {
inner: PartialDemo,
default_handler: RefCell<Vec<nwg::EventHandler>>,
}
impl nwg::NativeUi<Rc<PartialDemoUi>> for PartialDemo {
fn build_ui(mut data: PartialDemo) -> Result<Rc<PartialDemoUi>, nwg::NwgError> {
use nwg::Event as E;
nwg::Window::builder()
.size((500, 400))
.position((300, 300))
.title("Many UI")
.build(&mut data.window)?;
nwg::ListBox::builder()
.collection(vec!["People", "Animals", "Food"])
.focus(true)
.parent(&data.window)
.build(&mut data.menu)?;
nwg::Frame::builder()
.parent(&data.window)
.build(&mut data.frame1)?;
nwg::Frame::builder()
.flags(nwg::FrameFlags::BORDER)
.parent(&data.window)
.build(&mut data.frame2)?;
nwg::Frame::builder()
.flags(nwg::FrameFlags::BORDER)
.parent(&data.window)
.build(&mut data.frame3)?;
PeopleUi::build_partial(&mut data.people_ui, Some(&data.frame1))?;
AnimalUi::build_partial(&mut data.animal_ui, Some(&data.frame2))?;
FoodUi::build_partial(&mut data.food_ui, Some(&data.frame3))?;
let ui = Rc::new(PartialDemoUi {
inner: data,
default_handler: Default::default(),
});
let mut window_handles = vec![&ui.window.handle];
window_handles.append(&mut ui.people_ui.handles());
window_handles.append(&mut ui.animal_ui.handles());
window_handles.append(&mut ui.food_ui.handles());
for handle in window_handles.iter() {
let evt_ui = ui.clone();
let handle_events = move |evt, evt_data, handle| {
evt_ui.people_ui.process_event(evt, &evt_data, handle);
evt_ui.animal_ui.process_event(evt, &evt_data, handle);
evt_ui.food_ui.process_event(evt, &evt_data, handle);
match evt {
E::OnListBoxSelect => {
if &handle == &evt_ui.menu {
PartialDemo::change_interface(&evt_ui.inner);
}
}
E::OnWindowClose => {
if &handle == &evt_ui.window {
PartialDemo::exit(&evt_ui.inner);
}
}
E::OnButtonClick => {
if &handle == &evt_ui.people_ui.save_btn
|| &handle == &evt_ui.animal_ui.save_btn
|| &handle == &evt_ui.food_ui.save_btn
{
PartialDemo::save(&evt_ui.inner);
}
}
_ => {}
}
};
ui.default_handler
.borrow_mut()
.push(nwg::full_bind_event_handler(handle, handle_events));
}
use nwg::stretch::{geometry::Size, style::Dimension as D};
nwg::FlexboxLayout::builder()
.parent(&ui.window)
.child(&ui.menu)
.child_size(Size {
width: D::Percent(0.3),
height: D::Auto,
})
.child(&ui.frame1)
.child_size(Size {
width: D::Percent(1.0),
height: D::Auto,
})
.build(&ui.layout)?;
return Ok(ui);
}
}
impl PartialDemoUi {
pub fn destroy(&self) {
let mut handlers = self.default_handler.borrow_mut();
for handler in handlers.drain(0..) {
nwg::unbind_event_handler(&handler);
}
}
}
impl Deref for PartialDemoUi {
type Target = PartialDemo;
fn deref(&self) -> &PartialDemo {
&self.inner
}
}
}
mod partial_people_ui {
use self::nwg::{ControlHandle, NwgError, PartialUi};
use super::*;
use native_windows_gui2 as nwg;
impl PartialUi for PeopleUi {
fn build_partial<W: Into<ControlHandle>>(
data: &mut PeopleUi,
parent: Option<W>,
) -> Result<(), NwgError> {
let parent = parent.unwrap().into();
nwg::Label::builder()
.text("Name:")
.h_align(nwg::HTextAlign::Right)
.parent(&parent)
.build(&mut data.label1)?;
nwg::Label::builder()
.text("Age:")
.h_align(nwg::HTextAlign::Right)
.parent(&parent)
.build(&mut data.label2)?;
nwg::Label::builder()
.text("Job:")
.h_align(nwg::HTextAlign::Right)
.parent(&parent)
.build(&mut data.label3)?;
nwg::TextInput::builder()
.text("John Doe")
.parent(&parent)
.build(&mut data.name_input)?;
nwg::TextInput::builder()
.text("75")
.flags(nwg::TextInputFlags::VISIBLE | nwg::TextInputFlags::NUMBER)
.parent(&parent)
.build(&mut data.age_input)?;
nwg::TextInput::builder()
.text("Programmer")
.parent(&parent)
.build(&mut data.job_input)?;
nwg::Button::builder()
.text("Save")
.parent(&parent)
.build(&mut data.save_btn)?;
nwg::GridLayout::builder()
.parent(&parent)
.max_size([1000, 150])
.min_size([100, 120])
.child(0, 0, &data.label1)
.child(0, 1, &data.label2)
.child(0, 2, &data.label3)
.child(1, 0, &data.name_input)
.child(1, 1, &data.age_input)
.child(1, 2, &data.job_input)
.build(&data.layout)?;
nwg::GridLayout::builder()
.min_size([100, 200])
.max_column(Some(2))
.max_row(Some(6))
.child(1, 5, &data.save_btn)
.parent(&parent)
.build(&data.layout2)?;
Ok(())
}
fn process_event<'a>(
&self,
_evt: nwg::Event,
_evt_data: &nwg::EventData,
_handle: ControlHandle,
) {
}
fn handles(&self) -> Vec<&ControlHandle> {
Vec::new()
}
}
}
mod partial_animal_ui {
use self::nwg::{ControlHandle, NwgError, PartialUi};
use super::*;
use native_windows_gui2 as nwg;
impl PartialUi for AnimalUi {
fn build_partial<W: Into<ControlHandle>>(
data: &mut AnimalUi,
parent: Option<W>,
) -> Result<(), NwgError> {
let parent = parent.unwrap().into();
nwg::Label::builder()
.text("Name:")
.h_align(nwg::HTextAlign::Right)
.parent(&parent)
.build(&mut data.label1)?;
nwg::Label::builder()
.text("Race:")
.h_align(nwg::HTextAlign::Right)
.parent(&parent)
.build(&mut data.label2)?;
nwg::Label::builder()
.text("Is fluffy:")
.h_align(nwg::HTextAlign::Right)
.parent(&parent)
.build(&mut data.label3)?;
nwg::TextInput::builder()
.text("Mittens")
.parent(&parent)
.build(&mut data.name_input)?;
nwg::ComboBox::builder()
.collection(vec!["Cat", "Dog", "Pidgeon", "Monkey"])
.selected_index(Some(0))
.parent(&parent)
.build(&mut data.race_input)?;
nwg::CheckBox::builder()
.text("")
.check_state(nwg::CheckBoxState::Checked)
.parent(&parent)
.build(&mut data.is_soft_input)?;
nwg::Button::builder()
.text("Save")
.parent(&parent)
.build(&mut data.save_btn)?;
nwg::GridLayout::builder()
.parent(&parent)
.max_size([1000, 150])
.min_size([100, 120])
.child(0, 0, &data.label1)
.child(0, 1, &data.label2)
.child(0, 2, &data.label3)
.child(1, 0, &data.name_input)
.child(1, 1, &data.race_input)
.child(1, 2, &data.is_soft_input)
.build(&data.layout)?;
nwg::GridLayout::builder()
.min_size([100, 200])
.max_column(Some(2))
.max_row(Some(6))
.child(1, 5, &data.save_btn)
.parent(&parent)
.build(&data.layout2)?;
Ok(())
}
fn process_event<'a>(
&self,
_evt: nwg::Event,
_evt_data: &nwg::EventData,
_handle: ControlHandle,
) {
}
fn handles(&self) -> Vec<&ControlHandle> {
Vec::new()
}
}
}
mod partial_food_ui {
use self::nwg::{ControlHandle, NwgError, PartialUi};
use super::*;
use native_windows_gui2 as nwg;
impl PartialUi for FoodUi {
fn build_partial<W: Into<ControlHandle>>(
data: &mut FoodUi,
parent: Option<W>,
) -> Result<(), NwgError> {
let parent = parent.unwrap().into();
nwg::Label::builder()
.text("Name:")
.h_align(nwg::HTextAlign::Right)
.parent(&parent)
.build(&mut data.label1)?;
nwg::Label::builder()
.text("Tasty:")
.h_align(nwg::HTextAlign::Right)
.parent(&parent)
.build(&mut data.label2)?;
nwg::TextInput::builder()
.text("Banana")
.parent(&parent)
.build(&mut data.name_input)?;
nwg::CheckBox::builder()
.text("")
.check_state(nwg::CheckBoxState::Checked)
.parent(&parent)
.build(&mut data.tasty_input)?;
nwg::Button::builder()
.text("Save")
.parent(&parent)
.build(&mut data.save_btn)?;
nwg::GridLayout::builder()
.parent(&parent)
.max_size([1000, 90])
.min_size([100, 80])
.child(0, 0, &data.label1)
.child(0, 1, &data.label2)
.child(1, 0, &data.name_input)
.child(1, 1, &data.tasty_input)
.build(&data.layout)?;
nwg::GridLayout::builder()
.min_size([100, 200])
.max_column(Some(2))
.max_row(Some(6))
.child(1, 5, &data.save_btn)
.parent(&parent)
.build(&data.layout2)?;
Ok(())
}
fn process_event<'a>(
&self,
_evt: nwg::Event,
_evt_data: &nwg::EventData,
_handle: ControlHandle,
) {
}
fn handles(&self) -> Vec<&ControlHandle> {
Vec::new()
}
}
}
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 ui = PartialDemo::build_ui(Default::default()).expect("Failed to build UI");
nwg::dispatch_thread_events();
ui.destroy();
}