1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
use nappgui_sys::{
window_OnClose, window_OnMoved, window_OnResize, window_clear_hotkeys, window_client_to_screen,
window_control_frame, window_create, window_cursor, window_cycle_tabstop, window_defbutton,
window_destroy, window_focus, window_focus_info, window_get_client_size, window_get_focus,
window_get_origin, window_get_size, window_hide, window_hotkey, window_is_visible,
window_modal, window_next_tabstop, window_origin, window_overlay, window_panel,
window_previous_tabstop, window_show, window_size, window_stop_modal, window_title,
window_update, S2Df, V2Df,
};
use std::ffi::CString;
use std::rc::{Rc, Weak};
use crate::draw_2d::ImageTrait;
use crate::gui::event::{EvPos, EvSize, EvWinClose};
use crate::gui::{ButtonTrait, ControlTrait, PanelTrait};
use crate::types::{
FocusInfo, GuiClose, GuiCursor, GuiFocus, GuiTab, KeyCode, ModifierKey, Point2D, Rect2D,
Size2D, WindowFlags,
};
use crate::util::macros::{callback, listener};
/// Window objects are the highest-level containers within the user interface.
pub struct Window {
pub(crate) inner: Rc<WindowInner>,
}
impl Window {
/// Create a new window.
pub fn new(flag: WindowFlags) -> Self {
let result = flag.to_window_flag_t();
let window = unsafe { window_create(result as u32) };
Window {
inner: Rc::new(WindowInner { inner: window }),
}
}
/// Get the weak reference of the window.
pub fn as_weak(&self) -> Weak<WindowInner> {
Rc::downgrade(&self.inner)
}
}
impl Default for Window {
fn default() -> Self {
Self::new(WindowFlags::default())
}
}
impl Drop for Window {
/// Destroy the window and all its contents.
///
/// # Remarks
/// Panels, layouts and components will be recursively destroyed.
fn drop(&mut self) {
if Rc::strong_count(&self.inner) == 1 {
unsafe { window_destroy(&mut self.as_ptr()) }
}
}
}
impl WindowTrait for Window {
fn as_ptr(&self) -> *mut nappgui_sys::Window {
self.inner.inner
}
}
/// Window Weak Reference
pub type WeakWindow = Weak<WindowInner>;
impl WindowTrait for WeakWindow {
fn as_ptr(&self) -> *mut nappgui_sys::Window {
let window = self.upgrade().unwrap();
window.inner
}
}
/// Wrappers to Window object.
#[doc(hidden)]
#[repr(transparent)]
pub struct WindowInner {
pub(crate) inner: *mut nappgui_sys::Window,
}
/// The Window Trait
pub trait WindowTrait {
/// Returns the raw pointer of Window object
fn as_ptr(&self) -> *mut nappgui_sys::Window;
/// Associate the main panel with a window.
///
/// # Remarks
/// The size of the window will be adjusted based on the Natural sizing of the main panel.
fn panel<T>(&self, panel: T)
where
T: PanelTrait,
{
unsafe { window_panel(self.as_ptr(), panel.as_ptr()) }
}
callback! {
/// Set an event handler for the window closing.
on_close(EvWinClose) -> bool => window_OnClose;
/// Set an event handler for moving the window on the desktop.
on_moved(EvPos) => window_OnMoved;
/// Set an event handler for window resizing.
on_resize(EvSize) => window_OnResize;
}
/// Set the text that will display the window in the title bar.
fn title(&self, text: &str) {
let text = CString::new(text).unwrap();
unsafe { window_title(self.as_ptr(), text.as_ptr()) }
}
/// Show the window. By default windows are created hidden. You have to show them explicitly.
fn show(&self) {
unsafe { window_show(self.as_ptr()) }
}
/// Hide the window.
fn hide(&self) {
unsafe { window_hide(self.as_ptr()) }
}
/// Launch an overlay window.
fn overlay<T>(&self, parent: &T)
where
T: WindowTrait,
{
unsafe {
window_overlay(self.as_ptr(), parent.as_ptr());
}
}
/// Launch a window in modal mode.
fn modal<T>(&self, parent: &T) -> GuiClose
where
T: WindowTrait,
{
let value = unsafe { window_modal(self.as_ptr(), parent.as_ptr()) };
GuiClose::try_from(value as i32).unwrap()
}
/// Ends the modal cycle of a window.
fn stop_modal(&self, return_value: GuiClose) {
unsafe {
window_stop_modal(self.as_ptr(), return_value as u32);
}
}
/// Returns whether or not the window is visible.
fn is_visible(&self) -> bool {
unsafe { window_is_visible(self.as_ptr()) != 0 }
}
/// Sets an action associated with pressing a key.
fn hotkey<F>(&self, key: KeyCode, modifiers: ModifierKey, handler: F)
where
F: FnMut() + 'static,
{
let listener = listener!(handler, ());
unsafe {
window_hotkey(self.as_ptr(), key as _, modifiers as _, listener);
}
}
/// Removes all keyboard shortcuts associated with the window.
fn clear_hotkeys(&self) {
unsafe { window_clear_hotkeys(self.as_ptr()) }
}
/// Activate or deactivate the cyclic behavior of tabstops.
fn cycle_tabstop(&self, cycle: bool) {
let cycle = cycle as _;
unsafe { window_cycle_tabstop(self.as_ptr(), cycle) }
}
/// Moves keyboard focus to the next control in the tab-list. It has the same effect as pressing \[TAB\].
fn next_tabstop(&self) -> GuiFocus {
let focus = unsafe { window_next_tabstop(self.as_ptr()) };
GuiFocus::try_from(focus).unwrap()
}
/// Moves the keyboard focus to the previous control in the tab-list. This has the same effect as pressing \[SHIFT\]+\[TAB\].
fn previous_tabstop(&self) -> GuiFocus {
let focus = unsafe { window_previous_tabstop(self.as_ptr()) };
GuiFocus::try_from(focus).unwrap()
}
/// Set keyboard focus to a specific control.
fn focus<T>(&self, control: &T) -> GuiFocus
where
T: ControlTrait,
{
let focus = unsafe { window_focus(self.as_ptr(), control.as_control_ptr()) };
GuiFocus::try_from(focus).unwrap()
}
/// Gets the control that keyboard focus has.
fn get_focus<T>(&self) -> Option<T>
where
T: ControlTrait,
{
let control = unsafe { window_get_focus(self.as_ptr()) };
T::from_control_ptr(control)
}
/// Gets additional information about a keyboard focus change operation.
///
/// # Remarks
/// Sometimes the decision to release keyboard focus for a control requires context information.
/// For example, what action caused the change (press \[TAB\], click on another control) or
/// what control will receive the focus.
fn focus_info(&self) -> FocusInfo {
let mut raw_info = nappgui_sys::FocusInfo {
action: nappgui_sys::_gui_tab_t_ekGUI_TAB_KEY,
next: std::ptr::null_mut() as _,
};
unsafe { window_focus_info(self.as_ptr(), &mut raw_info) };
FocusInfo {
action: GuiTab::try_from(raw_info.action).unwrap(),
next: raw_info.next,
}
}
/// Recalculate the position and size of the controls after modifying any Layout.
fn update(&self) {
unsafe { window_update(self.as_ptr()) }
}
/// Move the window to specific desktop coordinates.
fn origin(&self, x: f32, y: f32) {
unsafe {
window_origin(self.as_ptr(), V2Df { x, y });
}
}
/// Set the size of the client area of the window.
///
/// # Remarks
/// The final size will depend on the window frame and desktop theme settings. This measure only refers to the interior area.
fn size(&self, width: f32, height: f32) {
unsafe {
window_size(self.as_ptr(), S2Df { width, height });
}
}
/// Get the window position.
fn get_origin(&self) -> Point2D {
unsafe {
let origin = window_get_origin(self.as_ptr());
std::mem::transmute(origin)
}
}
/// Get the total dimensions of the window.
fn get_size(&self) -> Size2D {
unsafe {
let size = window_get_size(self.as_ptr());
std::mem::transmute(size)
}
}
/// Get the dimensions of the client area of the window.
fn get_client_size(&self) -> Size2D {
unsafe {
let size = window_get_client_size(self.as_ptr());
std::mem::transmute(size)
}
}
/// Gets the position and size of a control in window coordinates.
///
/// # Remarks
///
/// control must belong to the window, be active and visible. The point (0,0) corresponds to the upper left vertex of the client area of the window.
fn control_frame<T>(&self, control: &T) -> Rect2D
where
T: ControlTrait,
{
unsafe {
let rect = window_control_frame(self.as_ptr(), control.as_control_ptr());
std::mem::transmute(rect)
}
}
/// Transforms a point expressed in window coordinates to screen coordinates.
fn client_to_screen(&self, x: f32, y: f32) -> Point2D {
unsafe {
let pos = window_client_to_screen(self.as_ptr(), V2Df { x, y });
std::mem::transmute(pos)
}
}
/// Set the default window button. It will be activated when pressed \[Intro\].
///
/// # Remarks
///
/// This function disables the possible previous default button. For the new button to be set,
/// it must exist in the active layout, which requires this function to be called after window_panel
fn default_button<T>(&self, button: &T)
where
T: ButtonTrait,
{
unsafe {
window_defbutton(self.as_ptr(), button.as_ptr());
}
}
/// Change the mouse cursor.
///
/// # Remarks
///
/// hot_x, hot_y indicate the "sensitive" point within the image, which will indicate the exact position of the mouse.
fn cursor<T>(&self, cursor: GuiCursor, image: &T, hot_x: f32, hot_y: f32)
where
T: ImageTrait,
{
unsafe { window_cursor(self.as_ptr(), cursor as i32, image.as_ptr(), hot_x, hot_y) }
}
}