Skip to content

Commit 74182bf

Browse files
committed
Add open/close file and other modals.
1 parent d2b6c99 commit 74182bf

File tree

4 files changed

+106
-6
lines changed

4 files changed

+106
-6
lines changed

iui/examples/files.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//! Demonstrates the use of the Window::save_file() call to get a filename via a friendly GUI,
2+
//! and the Window::modal_err() call to display modal dialog boxes.
3+
4+
extern crate iui;
5+
use iui::prelude::*;
6+
use iui::controls::{VerticalBox, MultilineEntry, Button};
7+
use std::io::prelude::*;
8+
use std::error::Error;
9+
use std::fs::File;
10+
11+
fn main() {
12+
// Initialize the UI
13+
let ui = UI::init().unwrap();
14+
15+
// Create the input controls
16+
let entry = MultilineEntry::new(&ui);
17+
let button = Button::new(&ui, "Save Buffer");
18+
19+
// Set up the application's layout
20+
let window = Window::new(&ui, "Save Buffer to File", 640, 480, WindowType::NoMenubar);
21+
let vbox = VerticalBox::new(&ui);
22+
vbox.append(&ui, entry.clone(), LayoutStrategy::Stretchy);
23+
vbox.append(&ui, button.clone(), LayoutStrategy::Compact);
24+
window.set_child(&ui, vbox);
25+
window.show(&ui);
26+
27+
// When the button is clicked, get the name of a file and then write the entry's contents to it.
28+
// Note the in real code you should spin off a thread to do the actual writing, do it between UI events,
29+
// or use Tokio. Even with minmal content, this method shows noticable lag.
30+
button.on_clicked(&ui, {
31+
let ui = ui.clone();
32+
move |_| {
33+
if let Some(path) = window.save_file(&ui) {
34+
let mut file = match File::create(&path) {
35+
Err(why) => { window.modal_err(&ui, "I/O Error", &format!("Could not open file {}: {}", path.display(), why.description())); return; }
36+
Ok(f) => f
37+
};
38+
match file.write_all(entry.value(&ui).as_bytes()) {
39+
Err(why) => { window.modal_err(&ui, "I/O Error", &format!("Could not write to file {}: {}", path.display(), why.description())); return; }
40+
Ok(_) => ()
41+
};
42+
}
43+
}
44+
});
45+
46+
ui.main();
47+
48+
}

iui/src/controls/create_macro.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,18 @@ macro_rules! define_control {
4343
}
4444

4545
impl $rust_type {
46+
// Show this control to the user. This will also show its non-hidden children.
4647
pub fn show(&self, _ctx: &UI) {
4748
let control: Control = self.clone().into();
4849
unsafe { ui_sys::uiControlShow(control.ui_control) }
4950
}
51+
52+
// Hide this control from the user. This will hide its children.
53+
pub fn hide(&self, _ctx: &UI) {
54+
let control: Control = self.clone().into();
55+
unsafe { ui_sys::uiControlHide(control.ui_control) }
56+
}
57+
5058
/// Create an `iui` struct for this control from the raw pointer for it.
5159
///
5260
/// # Unsafety
@@ -58,6 +66,11 @@ macro_rules! define_control {
5866
$sys_type: $sys_type
5967
}
6068
}
69+
70+
#[allow(non_snake_case)]
71+
pub unsafe fn ptr(&self) -> *mut $sys_type {
72+
self.$sys_type
73+
}
6174
}
6275
}
6376
}

iui/src/controls/window.rs

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use libc::{c_int, c_void};
66
use std::cell::RefCell;
77
use std::ffi::{CStr, CString};
88
use std::mem;
9+
use std::path::PathBuf;
910
use ui_sys::{self, uiControl, uiWindow};
1011

1112
thread_local! {
@@ -36,7 +37,7 @@ impl Window {
3637
};
3738
let window = unsafe {
3839
let c_string = CString::new(title.as_bytes().to_vec()).unwrap();
39-
let window = Window::from_ui_window(ui_sys::uiNewWindow(
40+
let window = Window::from_raw(ui_sys::uiNewWindow(
4041
c_string.as_ptr(),
4142
width,
4243
height,
@@ -125,12 +126,49 @@ impl Window {
125126
unsafe { ui_sys::uiWindowSetChild(self.uiWindow, child.into().as_ui_control()) }
126127
}
127128

128-
pub unsafe fn from_ui_window(window: *mut uiWindow) -> Window {
129-
Window { uiWindow: window }
129+
/// Allow the user to select an existing file.
130+
pub fn open_file(&self, _ctx: &UI) -> Option<PathBuf> {
131+
let ptr = unsafe { ui_sys::uiOpenFile(self.uiWindow) };
132+
if ptr.is_null() { return None };
133+
let path_string: String = unsafe { CStr::from_ptr(ptr).to_string_lossy().into() };
134+
Some(path_string.into())
130135
}
131136

132-
pub fn as_ui_window(&self) -> *mut uiWindow {
133-
self.uiWindow
137+
/// Allow the user to select a new or existing file.
138+
pub fn save_file(&self, _ctx: &UI) -> Option<PathBuf> {
139+
let ptr = unsafe { ui_sys::uiSaveFile(self.uiWindow) };
140+
if ptr.is_null() { return None };
141+
let path_string: String = unsafe { CStr::from_ptr(ptr).to_string_lossy().into() };
142+
Some(path_string.into())
143+
}
144+
145+
146+
/// Open a generic message box to show a message to the user.
147+
/// Returns when the user acknowledges the message.
148+
pub fn modal_msg(&self, _ctx: &UI, title: &str, description: &str) {
149+
unsafe {
150+
let c_title = CString::new(title.as_bytes().to_vec()).unwrap();
151+
let c_description = CString::new(description.as_bytes().to_vec()).unwrap();
152+
ui_sys::uiMsgBox(
153+
self.uiWindow,
154+
c_title.as_ptr(),
155+
c_description.as_ptr(),
156+
)
157+
}
158+
}
159+
160+
/// Open an error-themed message box to show a message to the user.
161+
/// Returns when the user acknowledges the message.
162+
pub fn modal_err(&self, _ctx: &UI, title: &str, description: &str) {
163+
unsafe {
164+
let c_title = CString::new(title.as_bytes().to_vec()).unwrap();
165+
let c_description = CString::new(description.as_bytes().to_vec()).unwrap();
166+
ui_sys::uiMsgBoxError(
167+
self.uiWindow,
168+
c_title.as_ptr(),
169+
c_description.as_ptr(),
170+
)
171+
}
134172
}
135173

136174
pub unsafe fn destroy_all_windows() {

iui/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
//! `iui`, the `i`mproved `u`ser `i`nterface crate, provides Rust bindings to `libui`, a wrapper library for native(ish) GUI libraries
22
//! - Win32API on Windows, Cocoa on Mac OS X, and GTK+ on Linux and elsewhere. This library exposes a Rusty procedural interface to the
33
//! "Least Common Denominator" of GUI widgets. They are all available on all supported platforms.
4+
//!
45
//! To use this library, import it in your `Cargo.toml`:
56
//!
67
//! ```toml
7-
//! iui = { git = "https://github.com/LeoTindall/libui-rs" }
8+
//! iui = "0.1.0"
89
//! ```
910
//!
1011
//! Most of the functionality of the crate is exposed via the [UI](struct.UI.html) RAII guard, which handles all initialization and cleanup for the

0 commit comments

Comments
 (0)