Skip to content

Commit fcfb5aa

Browse files
mjhanninenbarzamin
authored andcommitted
Add password entry control (#78)
* Add PasswordEntry * Amend examples with PasswordEntry
1 parent 61e06ca commit fcfb5aa

File tree

3 files changed

+91
-17
lines changed

3 files changed

+91
-17
lines changed

iui/examples/inputs-grid.rs

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
44
extern crate iui;
55
use iui::prelude::*;
6-
use iui::controls::{Label, Spinbox, Slider, Entry, MultilineEntry, LayoutGrid,
6+
use iui::controls::{Label, Spinbox, Slider, PasswordEntry, Entry, MultilineEntry, LayoutGrid,
77
GridAlignment, GridExpand, HorizontalSeparator, ProgressBar};
88
use std::rc::Rc;
99
use std::cell::RefCell;
@@ -13,6 +13,7 @@ struct State {
1313
slider_val: i32,
1414
spinner_val: i32,
1515
entry_val: String,
16+
password_val: String,
1617
multi_val: String,
1718
}
1819

@@ -21,7 +22,7 @@ fn main() {
2122
let ui = UI::init().unwrap();
2223

2324
// Initialize the state of the application.
24-
let state = Rc::new(RefCell::new(State { slider_val: 0, spinner_val: 0, entry_val: "".into(), multi_val: "".into() }));
25+
let state = Rc::new(RefCell::new(State { slider_val: 0, spinner_val: 0, entry_val: "".into(), password_val: "".into(), multi_val: "".into() }));
2526

2627
// Create the grid which we'll use to lay out controls
2728
let mut grid = LayoutGrid::new(&ui);
@@ -31,12 +32,13 @@ fn main() {
3132
// While it's not necessary to create a block for this, it makes the code a lot easier
3233
// to read; the indentation presents a visual cue informing the reader that these
3334
// statements are related.
34-
let (mut slider, mut spinner, mut entry, mut multi) = {
35+
let (mut slider, mut spinner, mut entry, mut password, mut multi) = {
3536
// Numerical inputs
3637
let slider = Slider::new(&ui, 1, 100);
3738
let spinner = Spinbox::new(&ui, 1, 100);
3839
// Text inputs
3940
let entry = Entry::new(&ui);
41+
let password = PasswordEntry::new(&ui);
4042
let multi = MultilineEntry::new(&ui);
4143
// Add everything into the grid
4244
grid.append(&ui, slider.clone(),
@@ -51,33 +53,38 @@ fn main() {
5153
0, 3, 1, 1, GridExpand::Neither, GridAlignment::Fill, GridAlignment::Fill);
5254
grid.append(&ui, entry.clone(),
5355
0, 4, 1, 1, GridExpand::Neither, GridAlignment::Fill, GridAlignment::Fill);
56+
grid.append(&ui, password.clone(),
57+
0, 5, 1, 1, GridExpand::Neither, GridAlignment::Fill, GridAlignment::Fill);
5458
grid.append(&ui, multi.clone(),
5559
// The multiline entry is at column 0, row 1, and expands vertically.
56-
0, 5, 1, 1, GridExpand::Vertical, GridAlignment::Fill, GridAlignment::Fill);
57-
(slider, spinner, entry, multi)
60+
0, 6, 1, 1, GridExpand::Vertical, GridAlignment::Fill, GridAlignment::Fill);
61+
(slider, spinner, entry, password, multi)
5862
};
5963

6064
// Set up the outputs for the application. Organization is very similar to the
6165
// previous setup.
62-
let (add_label, sub_label, text_label, bigtext_label, progress_bar) = {
66+
let (add_label, sub_label, text_label, password_label, bigtext_label, progress_bar) = {
6367
let add_label = Label::new(&ui, "");
6468
let sub_label = Label::new(&ui, "");
6569
let text_label = Label::new(&ui, "");
70+
let password_label = Label::new(&ui, "");
6671
let bigtext_label = Label::new(&ui, "");
6772
let progress_bar = ProgressBar::indeterminate(&ui);
68-
grid.append(&ui, add_label.clone(),
73+
grid.append(&ui, add_label.clone(),
6974
1, 0, 1, 1, GridExpand::Neither, GridAlignment::Fill, GridAlignment::Fill);
7075
grid.append(&ui, sub_label.clone(),
7176
1, 1, 1, 1, GridExpand::Neither, GridAlignment::Fill, GridAlignment::Fill);
7277
// We skip the #2 & 3 slots so that the text labels will align with their inputs.
7378
// This is important because the big text label can expand vertically.
7479
grid.append(&ui, text_label.clone(),
7580
1, 4, 1, 1, GridExpand::Neither, GridAlignment::Fill, GridAlignment::Fill);
76-
grid.append(&ui, bigtext_label.clone(),
81+
grid.append(&ui, password_label.clone(),
7782
1, 5, 1, 1, GridExpand::Neither, GridAlignment::Fill, GridAlignment::Fill);
83+
grid.append(&ui, bigtext_label.clone(),
84+
1, 6, 1, 1, GridExpand::Neither, GridAlignment::Fill, GridAlignment::Fill);
7885
grid.append(&ui, progress_bar.clone(),
79-
0, 6, 2, 1, GridExpand::Neither, GridAlignment::Fill, GridAlignment::Fill);
80-
(add_label, sub_label, text_label, bigtext_label, progress_bar)
86+
0, 7, 2, 1, GridExpand::Neither, GridAlignment::Fill, GridAlignment::Fill);
87+
(add_label, sub_label, text_label, password_label, bigtext_label, progress_bar)
8188
};
8289

8390
// The window allows all constituent components to be displayed.
@@ -103,6 +110,11 @@ fn main() {
103110
move |val| { state.borrow_mut().entry_val = val; }
104111
});
105112

113+
password.on_changed(&ui, {
114+
let state = state.clone();
115+
move |val| { state.borrow_mut().password_val = val; }
116+
});
117+
106118
multi.on_changed(&ui, {
107119
let state = state.clone();
108120
move |val| { state.borrow_mut().multi_val = val; }
@@ -118,6 +130,7 @@ fn main() {
118130
let mut add_label = add_label.clone();
119131
let mut sub_label = sub_label.clone();
120132
let mut text_label = text_label.clone();
133+
let mut password_label = password_label.clone();
121134
let mut bigtext_label = bigtext_label.clone();
122135
let mut progress_bar = progress_bar.clone();
123136
move || {
@@ -127,6 +140,7 @@ fn main() {
127140
add_label.set_text(&ui, &format!("Added: {}", state.slider_val + state.spinner_val));
128141
sub_label.set_text(&ui, &format!("Subtracted: {}", state.slider_val - state.spinner_val));
129142
text_label.set_text(&ui, &format!("Text: {}", state.entry_val));
143+
password_label.set_text(&ui, &format!("Secret Text: {}", state.password_val));
130144
bigtext_label.set_text(&ui, &format!("Multiline Text: {}", state.multi_val));
131145
progress_bar.set_value(&ui, (state.slider_val + state.spinner_val) as u32);
132146
}

iui/examples/inputs.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
extern crate iui;
44
use iui::prelude::*;
5-
use iui::controls::{Label, Spinbox, Slider, Entry, MultilineEntry, VerticalBox, HorizontalBox, HorizontalSeparator, Group, Spacer, ProgressBar};
5+
use iui::controls::{Label, Spinbox, Slider, Entry, PasswordEntry, MultilineEntry, VerticalBox, HorizontalBox, HorizontalSeparator, Group, Spacer, ProgressBar};
66
use std::rc::Rc;
77
use std::cell::RefCell;
88

@@ -11,6 +11,7 @@ struct State {
1111
slider_val: i32,
1212
spinner_val: i32,
1313
entry_val: String,
14+
password_val: String,
1415
multi_val: String,
1516
}
1617

@@ -19,13 +20,13 @@ fn main() {
1920
let ui = UI::init().unwrap();
2021

2122
// Initialize the state of the application.
22-
let state = Rc::new(RefCell::new(State { slider_val: 0, spinner_val: 0, entry_val: "".into(), multi_val: "".into() }));
23+
let state = Rc::new(RefCell::new(State { slider_val: 0, spinner_val: 0, entry_val: "".into(), password_val: "".into(), multi_val: "".into() }));
2324

2425
// Set up the inputs for the application.
2526
// While it's not necessary to create a block for this, it makes the code a lot easier
2627
// to read; the indentation presents a visual cue informing the reader that these
2728
// statements are related.
28-
let (input_group, mut slider, mut spinner, mut entry, mut multi) = {
29+
let (input_group, mut slider, mut spinner, mut entry, mut password, mut multi) = {
2930
// The group will hold all the inputs
3031
let mut input_group = Group::new(&ui, "Inputs");
3132
// The vertical box arranges the inputs within the groups
@@ -35,6 +36,7 @@ fn main() {
3536
let slider = Slider::new(&ui, 1, 100);
3637
let spinner = Spinbox::new(&ui, 1, 100);
3738
let entry = Entry::new(&ui);
39+
let password = PasswordEntry::new(&ui);
3840
let multi = MultilineEntry::new(&ui);
3941
// Add everything in hierarchy
4042
// Note the reverse order here. Again, it's not necessary, but it improves
@@ -45,28 +47,31 @@ fn main() {
4547
input_vbox.append(&ui, HorizontalSeparator::new(&ui), LayoutStrategy::Compact);
4648
input_vbox.append(&ui, Spacer::new(&ui), LayoutStrategy::Compact);
4749
input_vbox.append(&ui, entry.clone(), LayoutStrategy::Compact);
50+
input_vbox.append(&ui, password.clone(), LayoutStrategy::Compact);
4851
input_vbox.append(&ui, multi.clone(), LayoutStrategy::Stretchy);
4952
input_group.set_child(&ui, input_vbox);
50-
(input_group, slider, spinner, entry, multi)
53+
(input_group, slider, spinner, entry, password, multi)
5154
};
5255

5356
// Set up the outputs for the application. Organization is very similar to the
5457
// previous setup.
55-
let (output_group, add_label, sub_label, text_label, bigtext_label, progress_bar) = {
58+
let (output_group, add_label, sub_label, text_label, password_label, bigtext_label, progress_bar) = {
5659
let mut output_group = Group::new(&ui, "Outputs");
5760
let mut output_vbox = VerticalBox::new(&ui);
5861
let add_label = Label::new(&ui, "");
5962
let sub_label = Label::new(&ui, "");
6063
let text_label = Label::new(&ui, "");
64+
let password_label = Label::new(&ui, "");
6165
let bigtext_label = Label::new(&ui, "");
6266
let progress_bar = ProgressBar::indeterminate(&ui);
6367
output_vbox.append(&ui, add_label.clone(), LayoutStrategy::Compact);
6468
output_vbox.append(&ui, sub_label.clone(), LayoutStrategy::Compact);
6569
output_vbox.append(&ui, progress_bar.clone(), LayoutStrategy::Compact);
6670
output_vbox.append(&ui, text_label.clone(), LayoutStrategy::Compact);
71+
output_vbox.append(&ui, password_label.clone(), LayoutStrategy::Compact);
6772
output_vbox.append(&ui, bigtext_label.clone(), LayoutStrategy::Stretchy);
6873
output_group.set_child(&ui, output_vbox);
69-
(output_group, add_label, sub_label, text_label, bigtext_label, progress_bar)
74+
(output_group, add_label, sub_label, text_label, password_label, bigtext_label, progress_bar)
7075
};
7176

7277
// This horizontal box will arrange the two groups of controls.
@@ -97,6 +102,11 @@ fn main() {
97102
move |val| { state.borrow_mut().entry_val = val; }
98103
});
99104

105+
password.on_changed(&ui, {
106+
let state = state.clone();
107+
move |val| { state.borrow_mut().password_val = val; }
108+
});
109+
100110
multi.on_changed(&ui, {
101111
let state = state.clone();
102112
move |val| { state.borrow_mut().multi_val = val; }
@@ -112,15 +122,17 @@ fn main() {
112122
let mut add_label = add_label.clone();
113123
let mut sub_label = sub_label.clone();
114124
let mut text_label = text_label.clone();
125+
let mut password_label = password_label.clone();
115126
let mut bigtext_label = bigtext_label.clone();
116127
let mut progress_bar = progress_bar.clone();
117128
move || {
118129
let state = state.borrow();
119130

120-
// Update all the outputs
131+
// Update all the outputs
121132
add_label.set_text(&ui, &format!("Added: {}", state.slider_val + state.spinner_val));
122133
sub_label.set_text(&ui, &format!("Subtracted: {}", state.slider_val - state.spinner_val));
123134
text_label.set_text(&ui, &format!("Text: {}", state.entry_val));
135+
password_label.set_text(&ui, &format!("Secret Text: {}", state.password_val));
124136
bigtext_label.set_text(&ui, &format!("Multiline Text: {}", state.multi_val));
125137
progress_bar.set_value(&ui, (state.slider_val + state.spinner_val) as u32)
126138
}

iui/src/controls/entry.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ define_control! {
118118
sys_type: uiEntry
119119
}
120120

121+
define_control! {
122+
/// Single-line editable text buffer.
123+
rust_type: PasswordEntry,
124+
sys_type: uiEntry
125+
}
126+
121127
define_control! {
122128
/// Multi-line editable text buffer.
123129
rust_type: MultilineEntry,
@@ -130,6 +136,12 @@ impl Entry {
130136
}
131137
}
132138

139+
impl PasswordEntry {
140+
pub fn new(_ctx: &UI) -> PasswordEntry {
141+
unsafe { PasswordEntry::from_raw(ui_sys::uiNewPasswordEntry()) }
142+
}
143+
}
144+
133145
impl MultilineEntry {
134146
pub fn new(_ctx: &UI) -> MultilineEntry {
135147
unsafe { MultilineEntry::from_raw(ui_sys::uiNewMultilineEntry()) }
@@ -172,6 +184,42 @@ impl TextEntry for Entry {
172184
}
173185
}
174186

187+
impl TextEntry for PasswordEntry {
188+
fn value(&self, _ctx: &UI) -> String {
189+
unsafe {
190+
CStr::from_ptr(ui_sys::uiEntryText(self.uiEntry))
191+
.to_string_lossy()
192+
.into_owned()
193+
}
194+
}
195+
fn set_value(&mut self, _ctx: &UI, value: &str) {
196+
let cstring = CString::new(value.as_bytes().to_vec()).unwrap();
197+
unsafe { ui_sys::uiEntrySetText(self.uiEntry, cstring.as_ptr()) }
198+
}
199+
200+
fn on_changed<'ctx, F: FnMut(String) + 'ctx>(&mut self, _ctx: &'ctx UI, callback: F) {
201+
unsafe {
202+
let mut data: Box<Box<FnMut(String)>> = Box::new(Box::new(callback));
203+
ui_sys::uiEntryOnChanged(
204+
self.uiEntry,
205+
Some(c_callback),
206+
&mut *data as *mut Box<FnMut(String)> as *mut c_void,
207+
);
208+
mem::forget(data);
209+
}
210+
211+
extern "C" fn c_callback(entry: *mut uiEntry, data: *mut c_void) {
212+
unsafe {
213+
let string = CStr::from_ptr(ui_sys::uiEntryText(entry))
214+
.to_string_lossy()
215+
.into_owned();
216+
mem::transmute::<*mut c_void, &mut Box<FnMut(String)>>(data)(string);
217+
mem::forget(entry);
218+
}
219+
}
220+
}
221+
}
222+
175223
impl TextEntry for MultilineEntry {
176224
fn value(&self, _ctx: &UI) -> String {
177225
unsafe {

0 commit comments

Comments
 (0)