Skip to content

Commit f971194

Browse files
committed
Implement numeric entries and sample for their use
1 parent 50131ca commit f971194

File tree

5 files changed

+205
-1
lines changed

5 files changed

+205
-1
lines changed

iui/examples/inputs.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//! Demonstrates a mutable application state manipulated over a number of UIs
2+
3+
extern crate iui;
4+
use iui::prelude::*;
5+
use iui::controls::{Label, Spinbox, Slider, VerticalBox, HorizontalBox, Group};
6+
use std::rc::Rc;
7+
use std::cell::RefCell;
8+
9+
/// This struct will hold the values that multiple callbacks will need to access.
10+
struct State {
11+
slider_val: i64,
12+
spinner_val: i64
13+
}
14+
15+
fn main() {
16+
// Initialize the UI framework.
17+
let ui = UI::init().unwrap();
18+
19+
// Initialize the state of the application.
20+
let state = Rc::new(RefCell::new(State { slider_val: 0, spinner_val: 0}));
21+
22+
let input_group = Group::new(&ui, "Inputs");
23+
let input_vbox = VerticalBox::new(&ui);
24+
let slider = Slider::new(&ui, 1, 100);
25+
let spinner = Spinbox::new(&ui, 1, 100);
26+
input_vbox.append(&ui, slider.clone(), LayoutStrategy::Compact);
27+
input_vbox.append(&ui, spinner.clone(), LayoutStrategy::Compact);
28+
input_group.set_child(&ui, input_vbox);
29+
30+
let output_group = Group::new(&ui, "Outputs");
31+
let output_vbox = VerticalBox::new(&ui);
32+
let add_label = Label::new(&ui, "");
33+
let sub_label = Label::new(&ui, "");
34+
output_vbox.append(&ui, add_label.clone(), LayoutStrategy::Compact);
35+
output_vbox.append(&ui, sub_label.clone(), LayoutStrategy::Compact);
36+
output_group.set_child(&ui, output_vbox);
37+
38+
let hbox = HorizontalBox::new(&ui);
39+
hbox.append(&ui, input_group, LayoutStrategy::Stretchy);
40+
hbox.append(&ui, output_group, LayoutStrategy::Stretchy);
41+
42+
let window = Window::new(&ui, "Input Output Test", 300, 150, WindowType::NoMenubar);
43+
window.set_child(&ui, hbox);
44+
window.show(&ui);
45+
46+
let update_view = Rc::new({
47+
let ui = ui.clone();
48+
let add_label = add_label.clone();
49+
let sub_label = sub_label.clone();
50+
let state = state.clone();
51+
move || {
52+
let state = state.borrow();
53+
add_label.set_text(&ui, &format!("Added: {}", state.slider_val + state.spinner_val));
54+
sub_label.set_text(&ui, &format!("Subtracted: {}", state.slider_val - state.spinner_val));
55+
}
56+
});
57+
58+
update_view();
59+
60+
{
61+
let ui = ui.clone();
62+
let update_view = update_view.clone();
63+
let state = state.clone();
64+
slider.on_changed(&ui, |val| {
65+
state.borrow_mut().slider_val = val;
66+
update_view();
67+
});
68+
}
69+
70+
{
71+
let ui = ui.clone();
72+
let update_view = update_view.clone();
73+
let state = state.clone();
74+
spinner.on_changed(&ui, |val| {
75+
state.borrow_mut().spinner_val = val;
76+
update_view();
77+
});
78+
}
79+
80+
ui.main();
81+
}

iui/src/controls/entry.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
//! User input mechanisms: numbers, colors, and text in various forms.
2+
3+
use std::mem;
4+
use std::ffi::{CString};
5+
use std::i64;
6+
use libc::c_void;
7+
use ui_sys::{self, uiControl, uiSpinbox, uiSlider};
8+
use super::Control;
9+
use ui::UI;
10+
11+
pub trait NumericEntry {
12+
fn value(&self, ctx: &UI) -> i64;
13+
fn set_value(&self, ctx: &UI, value: i64);
14+
fn on_changed<F: FnMut(i64)>(&self, ctx: &UI, callback: F);
15+
}
16+
17+
pub trait TextEntry {
18+
fn value(&self, ctx: &UI) -> String;
19+
fn set_value(&self, ctx: &UI, value: &str);
20+
fn on_changed<F: FnMut(String)>(&self, ctx: &UI, callback: F);
21+
}
22+
23+
define_control!{
24+
/// Numerical entry control which allows users to set any value in a range.
25+
rust_type: Spinbox,
26+
sys_type: uiSpinbox
27+
}
28+
29+
define_control!{
30+
/// Allows users to select a value by picking a location along a line.
31+
rust_type: Slider,
32+
sys_type: uiSlider
33+
}
34+
35+
impl Spinbox {
36+
// Create a new Spinbox which can produce values from `min` to `max`.
37+
pub fn new(_ctx: &UI, min: i64, max: i64) -> Self {
38+
unsafe { Spinbox::from_raw(ui_sys::uiNewSpinbox(min, max)) }
39+
}
40+
41+
// Create a new Spinbox with the maximum possible range.
42+
pub fn new_unlimited(_ctx: &UI) -> Self {
43+
Self::new(_ctx, i64::MIN, i64::MAX)
44+
}
45+
}
46+
47+
impl Slider {
48+
// Create a new Spinbox which can produce values from `min` to `max`.
49+
pub fn new(_ctx: &UI, min: i64, max: i64) -> Self {
50+
unsafe { Slider::from_raw(ui_sys::uiNewSlider(min, max)) }
51+
}
52+
}
53+
54+
impl NumericEntry for Spinbox {
55+
fn value(&self, _ctx: &UI) -> i64 {
56+
unsafe { ui_sys::uiSpinboxValue(self.uiSpinbox) }
57+
}
58+
59+
fn set_value(&self, _ctx: &UI, value: i64) {
60+
unsafe { ui_sys::uiSpinboxSetValue(self.uiSpinbox, value) }
61+
}
62+
63+
fn on_changed<F: FnMut(i64)>(&self, _ctx: &UI, callback: F) {
64+
unsafe {
65+
let mut data: Box<Box<FnMut(i64)>> = Box::new(Box::new(callback));
66+
ui_sys::uiSpinboxOnChanged(
67+
self.uiSpinbox,
68+
c_callback,
69+
&mut *data as *mut Box<FnMut(i64)> as *mut c_void,
70+
);
71+
mem::forget(data);
72+
}
73+
74+
extern "C" fn c_callback(spinbox: *mut uiSpinbox, data: *mut c_void) {
75+
unsafe {
76+
let val = ui_sys::uiSpinboxValue(spinbox);
77+
mem::transmute::<*mut c_void, &mut Box<FnMut(i64)>>(data)(val);
78+
}
79+
}
80+
}
81+
}
82+
83+
impl NumericEntry for Slider {
84+
fn value(&self, _ctx: &UI) -> i64 {
85+
unsafe { ui_sys::uiSliderValue(self.uiSlider) }
86+
}
87+
88+
fn set_value(&self, _ctx: &UI, value: i64) {
89+
unsafe { ui_sys::uiSliderSetValue(self.uiSlider, value) }
90+
}
91+
92+
fn on_changed<F: FnMut(i64)>(&self, _ctx: &UI, callback: F) {
93+
unsafe {
94+
let mut data: Box<Box<FnMut(i64)>> = Box::new(Box::new(callback));
95+
ui_sys::uiSliderOnChanged(
96+
self.uiSlider,
97+
c_callback,
98+
&mut *data as *mut Box<FnMut(i64)> as *mut c_void,
99+
);
100+
mem::forget(data);
101+
}
102+
103+
extern "C" fn c_callback(slider: *mut uiSlider, data: *mut c_void) {
104+
unsafe {
105+
let val = ui_sys::uiSliderValue(slider);
106+
mem::transmute::<*mut c_void, &mut Box<FnMut(i64)>>(data)(val);
107+
}
108+
}
109+
}
110+
}

iui/src/controls/layout.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::mem;
22
use std::ffi::{CStr, CString};
33
use libc::c_int;
4-
use ui_sys::{self, uiBox, uiControl, uiTab, uiGroup};
4+
use ui_sys::{self, uiBox, uiControl, uiTab, uiGroup, uiSeparator};
55
use super::Control;
66
use ui::UI;
77
use error::UIError;
@@ -214,6 +214,16 @@ impl TabGroup {
214214
pub fn set_margined(&self, _ctx: &UI, page: u64, margined: bool) {
215215
unsafe { ui_sys::uiTabSetMargined(self.uiTab, page, margined as c_int) }
216216
}
217+
}
217218

219+
define_control!{
220+
/// Simply adds a horizontal line, to seperate things visually.
221+
rust_type: HorizontalSeparator,
222+
sys_type: uiSeparator
223+
}
218224

225+
impl HorizontalSeparator {
226+
pub fn new(_ctx: &UI) -> Self {
227+
unsafe { HorizontalSeparator::from_raw(ui_sys::uiNewHorizontalSeparator()) }
228+
}
219229
}

iui/src/controls/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ mod window;
1515
pub use self::window::*;
1616
mod layout;
1717
pub use self::layout::*;
18+
mod entry;
19+
pub use self::entry::*;
1820

1921
/// A generic UI control. Any UI control can be turned into this type.
2022
///

iui/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@ pub mod prelude {
3030
pub use ui::UI;
3131
pub use controls::{Window, WindowType};
3232
pub use controls::{LayoutStrategy};
33+
pub use controls::{NumericEntry, TextEntry};
3334
}

0 commit comments

Comments
 (0)