message_bank/
message_bank.rs

1/*!
2    An application that saves messages into buttons. 
3    Demonstrate the dynamic functions of NWG.
4*/
5
6extern crate native_windows_gui as nwg;
7use nwg::NativeUi;
8use std::cell::RefCell;
9
10
11#[derive(Default)]
12pub struct MessageBank {
13    window: nwg::Window,
14    layout: nwg::GridLayout,
15
16    add_message_btn: nwg::Button,
17    message_title: nwg::TextInput,
18    message_content: nwg::TextInput,
19
20    buttons: RefCell<Vec<nwg::Button>>,
21    handlers: RefCell<Vec<nwg::EventHandler>>,
22}
23
24impl MessageBank {
25
26    fn add_message(&self) {
27        let title = self.message_title.text();
28        let content = self.message_content.text();
29
30        let mut new_button = Default::default();
31        nwg::Button::builder()
32            .text(&title)
33            .parent(&self.window)
34            .build(&mut new_button)
35            .expect("Failed to build button");
36
37        let mut buttons = self.buttons.borrow_mut();
38        let mut handlers = self.handlers.borrow_mut();
39
40        let blen = buttons.len() as u32;
41        let (x, y) = (blen % 6, blen / 6);
42        self.layout.add_child(x, y+1, &new_button);
43
44        // You can share controls handle with events handlers
45        let new_button_handle = new_button.handle;
46        let handler = nwg::bind_event_handler(&new_button.handle, &self.window.handle, move |evt, _evt_data, handle| {
47            match evt {
48                nwg::Event::OnButtonClick => {
49                    if handle == new_button_handle {
50                        nwg::simple_message(&title, &content);
51                    }
52                },
53                _ => {}
54            }
55        });
56
57        buttons.push(new_button);
58        handlers.push(handler);
59    }
60
61    fn exit(&self) {
62        let handlers = self.handlers.borrow();
63        for handler in handlers.iter() {
64            nwg::unbind_event_handler(&handler);
65        }
66
67        nwg::stop_thread_dispatch();
68    }
69
70}
71
72//
73// ALL of this stuff is handled by native-windows-derive
74//
75mod message_bank_ui {
76    use native_windows_gui as nwg;
77    use super::*;
78    use std::rc::Rc;
79    use std::cell::RefCell;
80    use std::ops::Deref;
81
82    pub struct MessageBankUi {
83        inner: Rc<MessageBank>,
84        default_handler: RefCell<Vec<nwg::EventHandler>>
85    }
86
87    impl nwg::NativeUi<MessageBankUi> for MessageBank {
88        fn build_ui(mut data: MessageBank) -> Result<MessageBankUi, nwg::NwgError> {
89            use nwg::Event as E;
90            
91            // Controls
92            nwg::Window::builder()
93                .flags(nwg::WindowFlags::MAIN_WINDOW | nwg::WindowFlags::VISIBLE)
94                .size((400, 300))
95                .position((800, 300))
96                .title("My message bank")
97                .build(&mut data.window)?;
98
99            nwg::TextInput::builder()
100                .text("Hello World!")
101                .focus(true)
102                .parent(&data.window)
103                .build(&mut data.message_content)?;
104
105            nwg::Button::builder()
106                .text("Save")
107                .parent(&data.window)
108                .build(&mut data.add_message_btn)?;
109
110            nwg::TextInput::builder()
111                .text("Title")
112                .parent(&data.window)
113                .build(&mut data.message_title)?;
114
115            // Wrap-up
116            let ui = MessageBankUi {
117                inner: Rc::new(data),
118                default_handler: Default::default(),
119            };
120
121            // Events
122            let window_handles = [&ui.window.handle];
123
124            for handle in window_handles.iter() {
125                let evt_ui = Rc::downgrade(&ui.inner);
126                let handle_events = move |evt, _evt_data, handle| {
127                    if let Some(evt_ui) = evt_ui.upgrade() {
128                        match evt {
129                            E::OnButtonClick => {
130                                if &handle == &evt_ui.add_message_btn { MessageBank::add_message(&evt_ui); }
131                            },
132                            E::OnWindowClose => {
133                                if &handle == &evt_ui.window { MessageBank::exit(&evt_ui); }
134                            },
135                            _ => {}
136                        }
137                    }
138                };
139
140                ui.default_handler.borrow_mut().push(
141                    nwg::full_bind_event_handler(handle, handle_events)
142                );
143            }
144
145            // Layout
146            nwg::GridLayout::builder()
147              .parent(&ui.window)
148              .max_row(Some(6))
149              .child(0, 0, &ui.add_message_btn)
150              .child_item(nwg::GridLayoutItem::new(&ui.message_title, 1, 0, 2, 1))
151              .child_item(nwg::GridLayoutItem::new(&ui.message_content, 3, 0, 3, 1))
152              .build(&ui.layout)?;
153            
154            return Ok(ui);
155        }
156    }
157
158    impl Drop for MessageBankUi {
159        /// To make sure that everything is freed without issues, the default handler must be unbound.
160        fn drop(&mut self) {
161            let mut handlers = self.default_handler.borrow_mut();
162            for handler in handlers.drain(0..) {
163                nwg::unbind_event_handler(&handler);
164            }
165        }
166    }
167
168    impl Deref for MessageBankUi {
169        type Target = MessageBank;
170
171        fn deref(&self) -> &MessageBank {
172            &self.inner
173        }
174    }
175
176}
177
178
179
180fn main() {
181    nwg::init().expect("Failed to init Native Windows GUI");
182    nwg::Font::set_global_family("Segoe UI").expect("Failed to set default font");
183
184    let _ui = MessageBank::build_ui(Default::default()).expect("Failed to build UI");
185    nwg::dispatch_thread_events();
186}