Skip to main content

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