pub struct UI { /* private fields */ }
Expand description
A handle to user interface functionality.
Implementations§
Source§impl UI
impl UI
pub fn parent_of<T: Into<Control>>(&self, control: T) -> Option<Control>
Sourcepub unsafe fn set_parent_of<T: Into<Control>>(
&mut self,
control: T,
parent: Option<T>,
)
pub unsafe fn set_parent_of<T: Into<Control>>( &mut self, control: T, parent: Option<T>, )
Set the parent control of this control, “moving” it to a new place in
the UI tree or, if passed None
, removing it from the tree.
Sourcepub fn is_toplevel<T: Into<Control>>(&self, control: T) -> bool
pub fn is_toplevel<T: Into<Control>>(&self, control: T) -> bool
Returns true if this control is a top-level control; the root of the UI tree.
Sourcepub fn is_shown<T: Into<Control>>(&self, control: T) -> bool
pub fn is_shown<T: Into<Control>>(&self, control: T) -> bool
Returns true if this control is currently set to be displayed.
Sourcepub fn set_shown<T: Into<Control>>(&mut self, control: T, show: bool)
pub fn set_shown<T: Into<Control>>(&mut self, control: T, show: bool)
Sets whether or not the control should be displayed.
Sourcepub fn is_enabled<T: Into<Control>>(&self, control: T) -> bool
pub fn is_enabled<T: Into<Control>>(&self, control: T) -> bool
Returns true if the control is enabled (can be interacted with).
Sourcepub fn set_enabled<T: Into<Control>>(&mut self, control: T, enabled: bool)
pub fn set_enabled<T: Into<Control>>(&mut self, control: T, enabled: bool)
Sets the enable/disable state of the control. If disabled, a control cannot be interacted with, and visual cues to that effect are presented to the user.
Source§impl UI
impl UI
Sourcepub fn init() -> Result<UI, UIError>
pub fn init() -> Result<UI, UIError>
Initializes the underlying UI bindings, producing a UI
struct which can be used
to actually build your user interface. This is a reference counted type; clone it
to get an additional reference that can be passed to, e.g., callbacks.
Only one libUI binding can be active at once; if multiple instances are detected,
this function will return a MultipleInitError
.
Be aware the Cocoa (GUI toolkit on Mac OS) requires that the first thread spawned controls
the UI, so do not spin off your UI interactions into an alternative thread. You’re likely to
have problems on Mac OS.
{
let ui1 = UI::init().unwrap();
// This will fail because there is already an instance of UI.
let ui2 = UI::init();
assert!(ui2.is_err());
// ui1 dropped here.
}
let ui3 = UI::init().unwrap();
If libUI cannot initialize its hooks into the platform bindings, this function will
return a FailedInitError
with the description of the problem.
Examples found in repository?
51fn main() {
52 let ui = UI::init().expect("Couldn't initialize UI library");
53 let mut win = Window::new(&ui, "Area Canvas Example", 200, 200, WindowType::NoMenubar);
54
55 let mut hbox = HorizontalBox::new();
56 let area = Area::new(Box::new(HandleCanvas {}));
57 hbox.append(area, LayoutStrategy::Stretchy);
58
59 win.set_child(hbox);
60 win.show();
61 ui.main();
62}
More examples
12fn main() {
13 // Initialize the UI framework.
14 let ui = UI::init().unwrap();
15
16 let mut layout = HorizontalBox::new();
17 let window = Rc::new(RefCell::new(Window::new(
18 &ui,
19 "Control Gallery",
20 640,
21 480,
22 WindowType::NoMenubar,
23 )));
24
25 let page1 = page1::make_basic_page(ui.clone());
26 let page2 = page2::make_numbers_page(ui.clone());
27 let page3 = page3::make_data_page(ui.clone(), window.clone());
28 let page4 = page4::make_table_page(ui.clone());
29
30 let mut tabs = TabGroup::new();
31 tabs.append("Basic Controls", page1);
32 tabs.append("Numbers and Lists", page2);
33 tabs.append("Data Choosers", page3);
34 tabs.append("Table", page4);
35
36 layout.append(tabs, LayoutStrategy::Stretchy);
37
38 window.borrow_mut().set_child(layout);
39 window.borrow_mut().show();
40
41 ui.main();
42}
6fn main() {
7 // Initialize the UI library
8 let ui = UI::init().expect("Couldn't initialize UI library");
9
10 // Create a window into which controls can be placed
11 let mut win = Window::new(&ui.clone(), "Test App", 200, 200, WindowType::NoMenubar);
12
13 // Create a vertical layout to hold the controls
14 let mut vbox = VerticalBox::new();
15 vbox.set_padded(true);
16
17 let mut group_vbox = VerticalBox::new();
18 let mut group = Group::new("Group");
19
20 // Create two buttons to place in the window
21 let mut button = Button::new("Button");
22 button.on_clicked({
23 move |btn| {
24 btn.set_text("Clicked!");
25 }
26 });
27
28 let mut quit_button = Button::new("Quit");
29 quit_button.on_clicked({
30 let ui = ui.clone();
31 move |_| {
32 ui.quit();
33 }
34 });
35 // Create a new label. Note that labels don't auto-wrap!
36 let mut label_text = String::new();
37 label_text.push_str("There is a ton of text in this label.\n");
38 label_text.push_str("Pretty much every unicode character is supported.\n");
39 label_text.push_str("🎉 用户界面 사용자 인터페이스");
40 let label = Label::new(&label_text);
41
42 vbox.append(label, LayoutStrategy::Stretchy);
43 group_vbox.append(button, LayoutStrategy::Compact);
44 group_vbox.append(quit_button, LayoutStrategy::Compact);
45 group.set_child(group_vbox);
46 vbox.append(group, LayoutStrategy::Compact);
47
48 // Actually put the button in the window
49 win.set_child(vbox);
50 // Show the window
51 win.show();
52 // Run the application
53 ui.main();
54}
9fn main() {
10 let ui = UI::init().unwrap();
11
12 // Menus must be created before the window. They belong to the window automatically.
13 libui::menu! { &ui,
14 let menu_file = Menu("File") {
15 let menu_file_open = MenuItem("Open")
16 let menu_file_save = MenuItem("Save")
17 Separator()
18 let menu_file_close = MenuItem("Close")
19 let menu_file_pref = PreferencesItem()
20 let _menu_file_quit = QuitItem()
21 }
22 let menu_help = Menu("Help") {
23 let _menu_help_updates = MenuItem("Updates")
24 let menu_help_about = AboutItem()
25 }
26 }
27
28 // Set up the application's layout
29 let mut window = Window::new(&ui, "Text Editor", 640, 480, WindowType::HasMenubar);
30 libui::layout! { &ui,
31 let layout = VerticalBox() {
32 Stretchy: let entry = MultilineEntry()
33 }
34 }
35 window.set_child(layout);
36
37 menu_file_open.on_clicked({
38 let mut entry = entry.clone();
39 move |_, w| {
40 let path = match w.open_file() {
41 None => return,
42 Some(v) => v,
43 };
44
45 let mut file = match File::open(&path) {
46 Err(e) => {
47 w.modal_err(
48 "I/O Error",
49 &format!(
50 "Couldn't open file for reading {}: {}",
51 path.display(),
52 e.to_string()
53 ),
54 );
55 return;
56 }
57 Ok(f) => f,
58 };
59
60 let mut text = String::new();
61 match file.read_to_string(&mut text) {
62 Err(_) => return,
63 Ok(_) => (),
64 };
65 entry.set_value(&text);
66 }
67 });
68
69 menu_file_save.on_clicked({
70 let entry = entry.clone();
71 move |_, w| {
72 let path = match w.save_file() {
73 None => return,
74 Some(v) => v,
75 };
76
77 let mut file = match File::create(&path) {
78 Err(e) => {
79 w.modal_err(
80 "I/O Error",
81 &format!(
82 "Couldn't open file for writing {}: {}",
83 path.display(),
84 e.to_string()
85 ),
86 );
87 return;
88 }
89 Ok(f) => f,
90 };
91
92 match file.write_all(entry.value().as_bytes()) {
93 Err(_) => return,
94 Ok(_) => (),
95 };
96 }
97 });
98
99 menu_file_close.on_clicked({
100 let mut entry = entry.clone();
101 move |_, _| {
102 entry.set_value("");
103 }
104 });
105
106 menu_file_pref
107 .on_clicked(move |_, w| w.modal_msg("Preferences", "Preferences menu item clicked!"));
108
109 menu_help_about.on_clicked(move |_, w| w.modal_msg("About", "libui: Menu Example"));
110
111 // The special MenuItem from `Menu::append_quit_item()` or a `libui::menu! { QuitMenuItem() }` macro
112 // doesn't accept a callback with MenuItem::on_clicked(). Instead, call UI::on_should_quit() instead.
113 ui.on_should_quit({
114 let ui = ui.clone();
115 move || {
116 ui.quit();
117 }
118 });
119
120 window.show();
121 ui.main();
122}
21fn main() {
22 // Initialize the UI framework.
23 let ui = UI::init().unwrap();
24
25 // Initialize the state of the application.
26 let state = Rc::new(RefCell::new(State {
27 slider_val: 1,
28 spinner_val: 1,
29 entry_val: "".into(),
30 password_val: "".into(),
31 multi_val: "".into(),
32 }));
33
34 // Set up the inputs for the application.
35 // While it's not necessary to create a block for this, it makes the code a lot easier
36 // to read; the indentation presents a visual cue informing the reader that these
37 // statements are related.
38 let (input_group, mut slider, mut spinner, mut entry, mut password, mut multi) = {
39 // The group will hold all the inputs
40 let mut input_group = Group::new("Inputs");
41 // The vertical box arranges the inputs within the groups
42 let mut input_vbox = VerticalBox::new();
43 input_vbox.set_padded(true);
44 // Numerical inputs
45 let slider = Slider::new(1, 100);
46 let spinner = Spinbox::new(1, 100);
47 let entry = Entry::new();
48 let password = PasswordEntry::new();
49 let multi = MultilineEntry::new();
50 // Add everything in hierarchy
51 // Note the reverse order here. Again, it's not necessary, but it improves
52 // readability.
53 input_vbox.append(slider.clone(), LayoutStrategy::Compact);
54 input_vbox.append(spinner.clone(), LayoutStrategy::Compact);
55 input_vbox.append(Spacer::new(), LayoutStrategy::Compact);
56 input_vbox.append(HorizontalSeparator::new(), LayoutStrategy::Compact);
57 input_vbox.append(Spacer::new(), LayoutStrategy::Compact);
58 input_vbox.append(entry.clone(), LayoutStrategy::Compact);
59 input_vbox.append(password.clone(), LayoutStrategy::Compact);
60 input_vbox.append(multi.clone(), LayoutStrategy::Stretchy);
61 input_group.set_child(input_vbox);
62 (input_group, slider, spinner, entry, password, multi)
63 };
64
65 // Set up the outputs for the application. Organization is very similar to the
66 // previous setup.
67 let (
68 output_group,
69 add_label,
70 sub_label,
71 text_label,
72 password_label,
73 bigtext_label,
74 progress_bar,
75 ) = {
76 let mut output_group = Group::new("Outputs");
77 let mut output_vbox = VerticalBox::new();
78 let add_label = Label::new("");
79 let sub_label = Label::new("");
80 let text_label = Label::new("");
81 let password_label = Label::new("");
82 let bigtext_label = Label::new("");
83 let progress_bar = ProgressBar::indeterminate();
84 output_vbox.append(add_label.clone(), LayoutStrategy::Compact);
85 output_vbox.append(sub_label.clone(), LayoutStrategy::Compact);
86 output_vbox.append(progress_bar.clone(), LayoutStrategy::Compact);
87 output_vbox.append(text_label.clone(), LayoutStrategy::Compact);
88 output_vbox.append(password_label.clone(), LayoutStrategy::Compact);
89 output_vbox.append(bigtext_label.clone(), LayoutStrategy::Stretchy);
90 output_group.set_child(output_vbox);
91 (
92 output_group,
93 add_label,
94 sub_label,
95 text_label,
96 password_label,
97 bigtext_label,
98 progress_bar,
99 )
100 };
101
102 // This horizontal box will arrange the two groups of controls.
103 let mut hbox = HorizontalBox::new();
104 hbox.append(input_group, LayoutStrategy::Stretchy);
105 hbox.append(output_group, LayoutStrategy::Stretchy);
106
107 // The window allows all constituent components to be displayed.
108 let mut window = Window::new(
109 &ui.clone(),
110 "Input Output Test",
111 300,
112 150,
113 WindowType::NoMenubar,
114 );
115 window.set_child(hbox);
116 window.show();
117
118 // These on_changed functions allow updating the application state when a
119 // control changes its value.
120
121 slider.on_changed({
122 let state = state.clone();
123 move |val| {
124 state.borrow_mut().slider_val = val;
125 }
126 });
127
128 spinner.on_changed({
129 let state = state.clone();
130 move |val| {
131 state.borrow_mut().spinner_val = val;
132 }
133 });
134
135 entry.on_changed({
136 let state = state.clone();
137 move |val| {
138 state.borrow_mut().entry_val = val;
139 }
140 });
141
142 password.on_changed({
143 let state = state.clone();
144 move |val| {
145 state.borrow_mut().password_val = val;
146 }
147 });
148
149 multi.on_changed({
150 let state = state.clone();
151 move |val| {
152 state.borrow_mut().multi_val = val;
153 }
154 });
155
156 // Rather than just invoking ui.run(), using EventLoop gives a lot more control
157 // over the user interface event loop.
158 // Here, the on_tick() callback is used to update the view against the state.
159 let mut event_loop = ui.event_loop();
160 event_loop.on_tick({
161 let mut add_label = add_label.clone();
162 let mut sub_label = sub_label.clone();
163 let mut text_label = text_label.clone();
164 let mut password_label = password_label.clone();
165 let mut bigtext_label = bigtext_label.clone();
166 let mut progress_bar = progress_bar.clone();
167 move || {
168 let state = state.borrow();
169
170 // Update all the outputs
171 add_label.set_text(&format!("Added: {}", state.slider_val + state.spinner_val));
172 sub_label.set_text(&format!(
173 "Subtracted: {}",
174 state.slider_val - state.spinner_val
175 ));
176 text_label.set_text(&format!("Text: {}", state.entry_val));
177 password_label.set_text(&format!("Secret Text: {}", state.password_val));
178 bigtext_label.set_text(&format!("Multiline Text: {}", state.multi_val));
179 progress_bar.set_value((state.slider_val + state.spinner_val) as u32)
180 }
181 });
182 event_loop.run();
183}
7fn main() {
8 // Initialize the UI framework
9 let ui = UI::init().unwrap();
10
11 // The macro based builder vastly reduces the amount of code required
12 // to build complex user interfaces. Compare this example to the "controlgallery".
13 // It creates mostly the same UI in a fraction of lines.
14 libui::layout! { &ui,
15 let layout = HorizontalBox() {
16 Stretchy: let tabs = TabGroup() {
17 // TAB PAGE 1
18 ("Basic Controls", margined: false): let page1 = VerticalBox() {
19 Compact: let hb = HorizontalBox() {
20 Compact: let btn = Button("Button")
21 Compact: let btn = Checkbox("Checkbox")
22 }
23 Compact: let lb = Label("This is a label.\nLabels can span multiple lines.")
24 Compact: let _hs = HorizontalSeparator()
25 Stretchy: let input_group = Group("Entries") {
26 let form = Form(padded: true) {
27 (Compact, "Entry"): let entry = Entry()
28 (Compact, "Password Entry"): let entry_pwd = PasswordEntry()
29 (Compact, "Search Entry"): let entry_search = SearchEntry()
30 (Stretchy, "Multiline Entry"): let entry_multi = MultilineEntry()
31 (Stretchy, "Non-wrapping Entry"): let entry_nowrap = MultilineEntry( wrapping: false )
32 }
33 }
34 }
35 // TAB PAGE 2
36 ("Numbers and Lists", margined: false): let page2 = HorizontalBox() {
37 Stretchy: let g1 = Group("Numbers") {
38 let _vb1 = VerticalBox(padded: true) {
39 Compact: let spinner = Spinbox(0, 100)
40 Compact: let slider = Slider(0, 100)
41 Compact: let progress = ProgressBar()
42 }
43 }
44 Stretchy: let g1 = Group("Lists") {
45 let _vb2 = VerticalBox(padded: true) {
46 Compact: let combo = Combobox(selected: 1) {
47 "Combobox Item 1", "Combobox Item 2", "Combobox Item 3"
48 }
49 Compact: let combobox_editable = EditableCombobox() {
50 "Editable Item 1", "Editable Item 2", "Editable Item 3"
51 }
52 Compact: let radiobuttons = RadioButtons(selected: 0) {
53 "Radio Button 1", "Radio Button 2", "Radio Button 3"
54 }
55 }
56 }
57 }
58 // TAB PAGE 3
59 ("Data Choosers", margined: false): let page2 = HorizontalBox(padded: true) {
60 Stretchy: let _vb1 = VerticalBox(padded: true) {
61 Compact: let bt_date = DateTimePicker(Date)
62 Compact: let bt_time = DateTimePicker(Time)
63 Compact: let bt_datetime = DateTimePicker(DateTime)
64 Compact: let bt_color = ColorButton()
65 Compact: let bt_font = FontButton()
66 }
67 Stretchy: let _vb2 = VerticalBox(padded: true) {
68 Compact: let grid = LayoutGrid(padded: true) {
69 (0, 0)(1, 1) Vertical (Fill, Fill) : let bt_open_file = Button("Open File")
70 (0, 1)(1, 1) Vertical (Fill, Fill) : let bt_open_folder_pwd = Button("Open Folder")
71 (0, 2)(1, 1) Vertical (Fill, Fill) : let bt_save_file = Button("Save File")
72 (0, 3)(1, 1) Vertical (Fill, Fill) : let bt_msgbox = Button("Message Box")
73 (0, 4)(1, 1) Vertical (Fill, Fill) : let bt_msgbox_error = Button("Error Message")
74 (1, 0)(1, 1) Vertical (Fill, Fill) : let tb_open_file = Entry()
75 (1, 1)(1, 1) Vertical (Fill, Fill) : let tb_open_folder = Entry()
76 (1, 2)(1, 1) Vertical (Fill, Fill) : let tb_save_file = Entry()
77 }
78 }
79 }
80 }
81 }
82 }
83
84 // Display the layout in a window
85 let window = Rc::new(RefCell::new(Window::new(
86 &ui,
87 "Control Gallery (Builder Macro)",
88 640,
89 480,
90 WindowType::NoMenubar,
91 )));
92 window.borrow_mut().set_child(layout);
93
94 // You can easily reference the controls declared in the `libui::build!` macro.
95 // Note that all controls are created mutable, contrary to what the macro syntax
96 // suggests. This is because most control will be mutated in user code anyways.
97 bt_open_file.on_clicked({
98 let window = window.clone();
99 let mut tb_open_file = tb_open_file.clone();
100 move |_| -> () {
101 match window.borrow_mut().open_file() {
102 Some(path) => tb_open_file.set_value(path.to_str().unwrap()),
103 None => (),
104 }
105 }
106 });
107
108 bt_open_folder_pwd.on_clicked({
109 let window = window.clone();
110 let mut tb_open_folder = tb_open_folder.clone();
111 move |_| -> () {
112 match window.borrow_mut().open_folder() {
113 Some(path) => tb_open_folder.set_value(path.to_str().unwrap()),
114 None => (),
115 }
116 }
117 });
118
119 bt_save_file.on_clicked({
120 let window = window.clone();
121 let mut tb_save_file = tb_save_file.clone();
122 move |_| -> () {
123 match window.borrow_mut().save_file() {
124 Some(path) => tb_save_file.set_value(path.to_str().unwrap()),
125 None => (),
126 }
127 }
128 });
129
130 bt_msgbox.on_clicked({
131 let window = window.clone();
132 move |_| -> () {
133 window.borrow_mut().modal_msg(
134 "This is a normal message box.",
135 "More detailed information can be shown here.",
136 );
137 }
138 });
139
140 bt_msgbox_error.on_clicked({
141 let window = window.clone();
142 move |_| -> () {
143 window.borrow_mut().modal_err(
144 "This message box describes an error.",
145 "More detailed information can be shown here.",
146 );
147 }
148 });
149
150 // Display and run
151 window.borrow_mut().show();
152 ui.main();
153}
Sourcepub fn main(&self)
pub fn main(&self)
Hands control of this thread to the UI toolkit, allowing it to display the UI and respond to events. Does not return until the UI quits.
For more control, use the EventLoop
struct.
Examples found in repository?
51fn main() {
52 let ui = UI::init().expect("Couldn't initialize UI library");
53 let mut win = Window::new(&ui, "Area Canvas Example", 200, 200, WindowType::NoMenubar);
54
55 let mut hbox = HorizontalBox::new();
56 let area = Area::new(Box::new(HandleCanvas {}));
57 hbox.append(area, LayoutStrategy::Stretchy);
58
59 win.set_child(hbox);
60 win.show();
61 ui.main();
62}
More examples
12fn main() {
13 // Initialize the UI framework.
14 let ui = UI::init().unwrap();
15
16 let mut layout = HorizontalBox::new();
17 let window = Rc::new(RefCell::new(Window::new(
18 &ui,
19 "Control Gallery",
20 640,
21 480,
22 WindowType::NoMenubar,
23 )));
24
25 let page1 = page1::make_basic_page(ui.clone());
26 let page2 = page2::make_numbers_page(ui.clone());
27 let page3 = page3::make_data_page(ui.clone(), window.clone());
28 let page4 = page4::make_table_page(ui.clone());
29
30 let mut tabs = TabGroup::new();
31 tabs.append("Basic Controls", page1);
32 tabs.append("Numbers and Lists", page2);
33 tabs.append("Data Choosers", page3);
34 tabs.append("Table", page4);
35
36 layout.append(tabs, LayoutStrategy::Stretchy);
37
38 window.borrow_mut().set_child(layout);
39 window.borrow_mut().show();
40
41 ui.main();
42}
6fn main() {
7 // Initialize the UI library
8 let ui = UI::init().expect("Couldn't initialize UI library");
9
10 // Create a window into which controls can be placed
11 let mut win = Window::new(&ui.clone(), "Test App", 200, 200, WindowType::NoMenubar);
12
13 // Create a vertical layout to hold the controls
14 let mut vbox = VerticalBox::new();
15 vbox.set_padded(true);
16
17 let mut group_vbox = VerticalBox::new();
18 let mut group = Group::new("Group");
19
20 // Create two buttons to place in the window
21 let mut button = Button::new("Button");
22 button.on_clicked({
23 move |btn| {
24 btn.set_text("Clicked!");
25 }
26 });
27
28 let mut quit_button = Button::new("Quit");
29 quit_button.on_clicked({
30 let ui = ui.clone();
31 move |_| {
32 ui.quit();
33 }
34 });
35 // Create a new label. Note that labels don't auto-wrap!
36 let mut label_text = String::new();
37 label_text.push_str("There is a ton of text in this label.\n");
38 label_text.push_str("Pretty much every unicode character is supported.\n");
39 label_text.push_str("🎉 用户界面 사용자 인터페이스");
40 let label = Label::new(&label_text);
41
42 vbox.append(label, LayoutStrategy::Stretchy);
43 group_vbox.append(button, LayoutStrategy::Compact);
44 group_vbox.append(quit_button, LayoutStrategy::Compact);
45 group.set_child(group_vbox);
46 vbox.append(group, LayoutStrategy::Compact);
47
48 // Actually put the button in the window
49 win.set_child(vbox);
50 // Show the window
51 win.show();
52 // Run the application
53 ui.main();
54}
9fn main() {
10 let ui = UI::init().unwrap();
11
12 // Menus must be created before the window. They belong to the window automatically.
13 libui::menu! { &ui,
14 let menu_file = Menu("File") {
15 let menu_file_open = MenuItem("Open")
16 let menu_file_save = MenuItem("Save")
17 Separator()
18 let menu_file_close = MenuItem("Close")
19 let menu_file_pref = PreferencesItem()
20 let _menu_file_quit = QuitItem()
21 }
22 let menu_help = Menu("Help") {
23 let _menu_help_updates = MenuItem("Updates")
24 let menu_help_about = AboutItem()
25 }
26 }
27
28 // Set up the application's layout
29 let mut window = Window::new(&ui, "Text Editor", 640, 480, WindowType::HasMenubar);
30 libui::layout! { &ui,
31 let layout = VerticalBox() {
32 Stretchy: let entry = MultilineEntry()
33 }
34 }
35 window.set_child(layout);
36
37 menu_file_open.on_clicked({
38 let mut entry = entry.clone();
39 move |_, w| {
40 let path = match w.open_file() {
41 None => return,
42 Some(v) => v,
43 };
44
45 let mut file = match File::open(&path) {
46 Err(e) => {
47 w.modal_err(
48 "I/O Error",
49 &format!(
50 "Couldn't open file for reading {}: {}",
51 path.display(),
52 e.to_string()
53 ),
54 );
55 return;
56 }
57 Ok(f) => f,
58 };
59
60 let mut text = String::new();
61 match file.read_to_string(&mut text) {
62 Err(_) => return,
63 Ok(_) => (),
64 };
65 entry.set_value(&text);
66 }
67 });
68
69 menu_file_save.on_clicked({
70 let entry = entry.clone();
71 move |_, w| {
72 let path = match w.save_file() {
73 None => return,
74 Some(v) => v,
75 };
76
77 let mut file = match File::create(&path) {
78 Err(e) => {
79 w.modal_err(
80 "I/O Error",
81 &format!(
82 "Couldn't open file for writing {}: {}",
83 path.display(),
84 e.to_string()
85 ),
86 );
87 return;
88 }
89 Ok(f) => f,
90 };
91
92 match file.write_all(entry.value().as_bytes()) {
93 Err(_) => return,
94 Ok(_) => (),
95 };
96 }
97 });
98
99 menu_file_close.on_clicked({
100 let mut entry = entry.clone();
101 move |_, _| {
102 entry.set_value("");
103 }
104 });
105
106 menu_file_pref
107 .on_clicked(move |_, w| w.modal_msg("Preferences", "Preferences menu item clicked!"));
108
109 menu_help_about.on_clicked(move |_, w| w.modal_msg("About", "libui: Menu Example"));
110
111 // The special MenuItem from `Menu::append_quit_item()` or a `libui::menu! { QuitMenuItem() }` macro
112 // doesn't accept a callback with MenuItem::on_clicked(). Instead, call UI::on_should_quit() instead.
113 ui.on_should_quit({
114 let ui = ui.clone();
115 move || {
116 ui.quit();
117 }
118 });
119
120 window.show();
121 ui.main();
122}
7fn main() {
8 // Initialize the UI framework
9 let ui = UI::init().unwrap();
10
11 // The macro based builder vastly reduces the amount of code required
12 // to build complex user interfaces. Compare this example to the "controlgallery".
13 // It creates mostly the same UI in a fraction of lines.
14 libui::layout! { &ui,
15 let layout = HorizontalBox() {
16 Stretchy: let tabs = TabGroup() {
17 // TAB PAGE 1
18 ("Basic Controls", margined: false): let page1 = VerticalBox() {
19 Compact: let hb = HorizontalBox() {
20 Compact: let btn = Button("Button")
21 Compact: let btn = Checkbox("Checkbox")
22 }
23 Compact: let lb = Label("This is a label.\nLabels can span multiple lines.")
24 Compact: let _hs = HorizontalSeparator()
25 Stretchy: let input_group = Group("Entries") {
26 let form = Form(padded: true) {
27 (Compact, "Entry"): let entry = Entry()
28 (Compact, "Password Entry"): let entry_pwd = PasswordEntry()
29 (Compact, "Search Entry"): let entry_search = SearchEntry()
30 (Stretchy, "Multiline Entry"): let entry_multi = MultilineEntry()
31 (Stretchy, "Non-wrapping Entry"): let entry_nowrap = MultilineEntry( wrapping: false )
32 }
33 }
34 }
35 // TAB PAGE 2
36 ("Numbers and Lists", margined: false): let page2 = HorizontalBox() {
37 Stretchy: let g1 = Group("Numbers") {
38 let _vb1 = VerticalBox(padded: true) {
39 Compact: let spinner = Spinbox(0, 100)
40 Compact: let slider = Slider(0, 100)
41 Compact: let progress = ProgressBar()
42 }
43 }
44 Stretchy: let g1 = Group("Lists") {
45 let _vb2 = VerticalBox(padded: true) {
46 Compact: let combo = Combobox(selected: 1) {
47 "Combobox Item 1", "Combobox Item 2", "Combobox Item 3"
48 }
49 Compact: let combobox_editable = EditableCombobox() {
50 "Editable Item 1", "Editable Item 2", "Editable Item 3"
51 }
52 Compact: let radiobuttons = RadioButtons(selected: 0) {
53 "Radio Button 1", "Radio Button 2", "Radio Button 3"
54 }
55 }
56 }
57 }
58 // TAB PAGE 3
59 ("Data Choosers", margined: false): let page2 = HorizontalBox(padded: true) {
60 Stretchy: let _vb1 = VerticalBox(padded: true) {
61 Compact: let bt_date = DateTimePicker(Date)
62 Compact: let bt_time = DateTimePicker(Time)
63 Compact: let bt_datetime = DateTimePicker(DateTime)
64 Compact: let bt_color = ColorButton()
65 Compact: let bt_font = FontButton()
66 }
67 Stretchy: let _vb2 = VerticalBox(padded: true) {
68 Compact: let grid = LayoutGrid(padded: true) {
69 (0, 0)(1, 1) Vertical (Fill, Fill) : let bt_open_file = Button("Open File")
70 (0, 1)(1, 1) Vertical (Fill, Fill) : let bt_open_folder_pwd = Button("Open Folder")
71 (0, 2)(1, 1) Vertical (Fill, Fill) : let bt_save_file = Button("Save File")
72 (0, 3)(1, 1) Vertical (Fill, Fill) : let bt_msgbox = Button("Message Box")
73 (0, 4)(1, 1) Vertical (Fill, Fill) : let bt_msgbox_error = Button("Error Message")
74 (1, 0)(1, 1) Vertical (Fill, Fill) : let tb_open_file = Entry()
75 (1, 1)(1, 1) Vertical (Fill, Fill) : let tb_open_folder = Entry()
76 (1, 2)(1, 1) Vertical (Fill, Fill) : let tb_save_file = Entry()
77 }
78 }
79 }
80 }
81 }
82 }
83
84 // Display the layout in a window
85 let window = Rc::new(RefCell::new(Window::new(
86 &ui,
87 "Control Gallery (Builder Macro)",
88 640,
89 480,
90 WindowType::NoMenubar,
91 )));
92 window.borrow_mut().set_child(layout);
93
94 // You can easily reference the controls declared in the `libui::build!` macro.
95 // Note that all controls are created mutable, contrary to what the macro syntax
96 // suggests. This is because most control will be mutated in user code anyways.
97 bt_open_file.on_clicked({
98 let window = window.clone();
99 let mut tb_open_file = tb_open_file.clone();
100 move |_| -> () {
101 match window.borrow_mut().open_file() {
102 Some(path) => tb_open_file.set_value(path.to_str().unwrap()),
103 None => (),
104 }
105 }
106 });
107
108 bt_open_folder_pwd.on_clicked({
109 let window = window.clone();
110 let mut tb_open_folder = tb_open_folder.clone();
111 move |_| -> () {
112 match window.borrow_mut().open_folder() {
113 Some(path) => tb_open_folder.set_value(path.to_str().unwrap()),
114 None => (),
115 }
116 }
117 });
118
119 bt_save_file.on_clicked({
120 let window = window.clone();
121 let mut tb_save_file = tb_save_file.clone();
122 move |_| -> () {
123 match window.borrow_mut().save_file() {
124 Some(path) => tb_save_file.set_value(path.to_str().unwrap()),
125 None => (),
126 }
127 }
128 });
129
130 bt_msgbox.on_clicked({
131 let window = window.clone();
132 move |_| -> () {
133 window.borrow_mut().modal_msg(
134 "This is a normal message box.",
135 "More detailed information can be shown here.",
136 );
137 }
138 });
139
140 bt_msgbox_error.on_clicked({
141 let window = window.clone();
142 move |_| -> () {
143 window.borrow_mut().modal_err(
144 "This message box describes an error.",
145 "More detailed information can be shown here.",
146 );
147 }
148 });
149
150 // Display and run
151 window.borrow_mut().show();
152 ui.main();
153}
Sourcepub fn event_loop(&self) -> EventLoop<'_>
pub fn event_loop(&self) -> EventLoop<'_>
Returns an EventLoop
, a struct that allows you to step over iterations or events in the UI.
Examples found in repository?
21fn main() {
22 // Initialize the UI framework.
23 let ui = UI::init().unwrap();
24
25 // Initialize the state of the application.
26 let state = Rc::new(RefCell::new(State {
27 slider_val: 1,
28 spinner_val: 1,
29 entry_val: "".into(),
30 password_val: "".into(),
31 multi_val: "".into(),
32 }));
33
34 // Set up the inputs for the application.
35 // While it's not necessary to create a block for this, it makes the code a lot easier
36 // to read; the indentation presents a visual cue informing the reader that these
37 // statements are related.
38 let (input_group, mut slider, mut spinner, mut entry, mut password, mut multi) = {
39 // The group will hold all the inputs
40 let mut input_group = Group::new("Inputs");
41 // The vertical box arranges the inputs within the groups
42 let mut input_vbox = VerticalBox::new();
43 input_vbox.set_padded(true);
44 // Numerical inputs
45 let slider = Slider::new(1, 100);
46 let spinner = Spinbox::new(1, 100);
47 let entry = Entry::new();
48 let password = PasswordEntry::new();
49 let multi = MultilineEntry::new();
50 // Add everything in hierarchy
51 // Note the reverse order here. Again, it's not necessary, but it improves
52 // readability.
53 input_vbox.append(slider.clone(), LayoutStrategy::Compact);
54 input_vbox.append(spinner.clone(), LayoutStrategy::Compact);
55 input_vbox.append(Spacer::new(), LayoutStrategy::Compact);
56 input_vbox.append(HorizontalSeparator::new(), LayoutStrategy::Compact);
57 input_vbox.append(Spacer::new(), LayoutStrategy::Compact);
58 input_vbox.append(entry.clone(), LayoutStrategy::Compact);
59 input_vbox.append(password.clone(), LayoutStrategy::Compact);
60 input_vbox.append(multi.clone(), LayoutStrategy::Stretchy);
61 input_group.set_child(input_vbox);
62 (input_group, slider, spinner, entry, password, multi)
63 };
64
65 // Set up the outputs for the application. Organization is very similar to the
66 // previous setup.
67 let (
68 output_group,
69 add_label,
70 sub_label,
71 text_label,
72 password_label,
73 bigtext_label,
74 progress_bar,
75 ) = {
76 let mut output_group = Group::new("Outputs");
77 let mut output_vbox = VerticalBox::new();
78 let add_label = Label::new("");
79 let sub_label = Label::new("");
80 let text_label = Label::new("");
81 let password_label = Label::new("");
82 let bigtext_label = Label::new("");
83 let progress_bar = ProgressBar::indeterminate();
84 output_vbox.append(add_label.clone(), LayoutStrategy::Compact);
85 output_vbox.append(sub_label.clone(), LayoutStrategy::Compact);
86 output_vbox.append(progress_bar.clone(), LayoutStrategy::Compact);
87 output_vbox.append(text_label.clone(), LayoutStrategy::Compact);
88 output_vbox.append(password_label.clone(), LayoutStrategy::Compact);
89 output_vbox.append(bigtext_label.clone(), LayoutStrategy::Stretchy);
90 output_group.set_child(output_vbox);
91 (
92 output_group,
93 add_label,
94 sub_label,
95 text_label,
96 password_label,
97 bigtext_label,
98 progress_bar,
99 )
100 };
101
102 // This horizontal box will arrange the two groups of controls.
103 let mut hbox = HorizontalBox::new();
104 hbox.append(input_group, LayoutStrategy::Stretchy);
105 hbox.append(output_group, LayoutStrategy::Stretchy);
106
107 // The window allows all constituent components to be displayed.
108 let mut window = Window::new(
109 &ui.clone(),
110 "Input Output Test",
111 300,
112 150,
113 WindowType::NoMenubar,
114 );
115 window.set_child(hbox);
116 window.show();
117
118 // These on_changed functions allow updating the application state when a
119 // control changes its value.
120
121 slider.on_changed({
122 let state = state.clone();
123 move |val| {
124 state.borrow_mut().slider_val = val;
125 }
126 });
127
128 spinner.on_changed({
129 let state = state.clone();
130 move |val| {
131 state.borrow_mut().spinner_val = val;
132 }
133 });
134
135 entry.on_changed({
136 let state = state.clone();
137 move |val| {
138 state.borrow_mut().entry_val = val;
139 }
140 });
141
142 password.on_changed({
143 let state = state.clone();
144 move |val| {
145 state.borrow_mut().password_val = val;
146 }
147 });
148
149 multi.on_changed({
150 let state = state.clone();
151 move |val| {
152 state.borrow_mut().multi_val = val;
153 }
154 });
155
156 // Rather than just invoking ui.run(), using EventLoop gives a lot more control
157 // over the user interface event loop.
158 // Here, the on_tick() callback is used to update the view against the state.
159 let mut event_loop = ui.event_loop();
160 event_loop.on_tick({
161 let mut add_label = add_label.clone();
162 let mut sub_label = sub_label.clone();
163 let mut text_label = text_label.clone();
164 let mut password_label = password_label.clone();
165 let mut bigtext_label = bigtext_label.clone();
166 let mut progress_bar = progress_bar.clone();
167 move || {
168 let state = state.borrow();
169
170 // Update all the outputs
171 add_label.set_text(&format!("Added: {}", state.slider_val + state.spinner_val));
172 sub_label.set_text(&format!(
173 "Subtracted: {}",
174 state.slider_val - state.spinner_val
175 ));
176 text_label.set_text(&format!("Text: {}", state.entry_val));
177 password_label.set_text(&format!("Secret Text: {}", state.password_val));
178 bigtext_label.set_text(&format!("Multiline Text: {}", state.multi_val));
179 progress_bar.set_value((state.slider_val + state.spinner_val) as u32)
180 }
181 });
182 event_loop.run();
183}
More examples
22fn main() {
23 // Initialize the UI framework.
24 let ui = UI::init().unwrap();
25
26 // Initialize the state of the application.
27 let state = Rc::new(RefCell::new(State {
28 slider_val: 1,
29 spinner_val: 1,
30 entry_val: "".into(),
31 password_val: "".into(),
32 multi_val: "".into(),
33 }));
34
35 // Create the grid which we'll use to lay out controls
36 let mut grid = LayoutGrid::new();
37 grid.set_padded(true);
38
39 // Set up the inputs for the application.
40 // While it's not necessary to create a block for this, it makes the code a lot easier
41 // to read; the indentation presents a visual cue informing the reader that these
42 // statements are related.
43 let (mut slider, mut spinner, mut entry, mut password, mut multi) = {
44 // Numerical inputs
45 let slider = Slider::new(1, 100);
46 let spinner = Spinbox::new(1, 100);
47 // Text inputs
48 let entry = Entry::new();
49 let password = PasswordEntry::new();
50 let multi = MultilineEntry::new();
51 // Add everything into the grid
52 grid.append(
53 slider.clone(),
54 // This is position (by slot) and size, expansion, and alignment.
55 // In this case, row 0, col 0, 1 by 1, compress as much as possible,
56 // and align to the fill.
57 0,
58 0,
59 1,
60 1,
61 GridExpand::Neither,
62 GridAlignment::Fill,
63 GridAlignment::Fill,
64 );
65 grid.append(
66 spinner.clone(),
67 // This one is at column zero, row 1.
68 0,
69 1,
70 1,
71 1,
72 GridExpand::Neither,
73 GridAlignment::Fill,
74 GridAlignment::Fill,
75 );
76 grid.append(
77 HorizontalSeparator::new(),
78 0,
79 3,
80 1,
81 1,
82 GridExpand::Neither,
83 GridAlignment::Fill,
84 GridAlignment::Fill,
85 );
86 grid.append(
87 entry.clone(),
88 0,
89 4,
90 1,
91 1,
92 GridExpand::Neither,
93 GridAlignment::Fill,
94 GridAlignment::Fill,
95 );
96 grid.append(
97 password.clone(),
98 0,
99 5,
100 1,
101 1,
102 GridExpand::Neither,
103 GridAlignment::Fill,
104 GridAlignment::Fill,
105 );
106 grid.append(
107 multi.clone(),
108 // The multiline entry is at column 0, row 1, and expands vertically.
109 0,
110 6,
111 1,
112 1,
113 GridExpand::Vertical,
114 GridAlignment::Fill,
115 GridAlignment::Fill,
116 );
117 (slider, spinner, entry, password, multi)
118 };
119
120 // Set up the outputs for the application. Organization is very similar to the
121 // previous setup.
122 let (add_label, sub_label, text_label, password_label, bigtext_label, progress_bar) = {
123 let add_label = Label::new("");
124 let sub_label = Label::new("");
125 let text_label = Label::new("");
126 let password_label = Label::new("");
127 let bigtext_label = Label::new("");
128 let progress_bar = ProgressBar::indeterminate();
129 grid.append(
130 add_label.clone(),
131 1,
132 0,
133 1,
134 1,
135 GridExpand::Neither,
136 GridAlignment::Fill,
137 GridAlignment::Fill,
138 );
139 grid.append(
140 sub_label.clone(),
141 1,
142 1,
143 1,
144 1,
145 GridExpand::Neither,
146 GridAlignment::Fill,
147 GridAlignment::Fill,
148 );
149 // We skip the #2 & 3 slots so that the text labels will align with their inputs.
150 // This is important because the big text label can expand vertically.
151 grid.append(
152 text_label.clone(),
153 1,
154 4,
155 1,
156 1,
157 GridExpand::Neither,
158 GridAlignment::Fill,
159 GridAlignment::Fill,
160 );
161 grid.append(
162 password_label.clone(),
163 1,
164 5,
165 1,
166 1,
167 GridExpand::Neither,
168 GridAlignment::Fill,
169 GridAlignment::Fill,
170 );
171 grid.append(
172 bigtext_label.clone(),
173 1,
174 6,
175 1,
176 1,
177 GridExpand::Neither,
178 GridAlignment::Fill,
179 GridAlignment::Fill,
180 );
181 grid.append(
182 progress_bar.clone(),
183 0,
184 7,
185 2,
186 1,
187 GridExpand::Neither,
188 GridAlignment::Fill,
189 GridAlignment::Fill,
190 );
191 (
192 add_label,
193 sub_label,
194 text_label,
195 password_label,
196 bigtext_label,
197 progress_bar,
198 )
199 };
200
201 // The window allows all constituent components to be displayed.
202 let mut window = Window::new(&ui, "Input Output Test", 300, 150, WindowType::NoMenubar);
203 window.set_child(grid);
204 window.show();
205
206 // These on_changed functions allow updating the application state when a
207 // control changes its value.
208
209 slider.on_changed({
210 let state = state.clone();
211 move |val| {
212 state.borrow_mut().slider_val = val;
213 }
214 });
215
216 spinner.on_changed({
217 let state = state.clone();
218 move |val| {
219 state.borrow_mut().spinner_val = val;
220 }
221 });
222
223 entry.on_changed({
224 let state = state.clone();
225 move |val| {
226 state.borrow_mut().entry_val = val;
227 }
228 });
229
230 password.on_changed({
231 let state = state.clone();
232 move |val| {
233 state.borrow_mut().password_val = val;
234 }
235 });
236
237 multi.on_changed({
238 let state = state.clone();
239 move |val| {
240 state.borrow_mut().multi_val = val;
241 }
242 });
243
244 // Rather than just invoking ui.run(), using EventLoop gives a lot more control
245 // over the user interface event loop.
246 // Here, the on_tick() callback is used to update the view against the state.
247 let mut event_loop = ui.event_loop();
248 event_loop.on_tick({
249 let mut add_label = add_label.clone();
250 let mut sub_label = sub_label.clone();
251 let mut text_label = text_label.clone();
252 let mut password_label = password_label.clone();
253 let mut bigtext_label = bigtext_label.clone();
254 let mut progress_bar = progress_bar.clone();
255 move || {
256 let state = state.borrow();
257
258 // Update all the outputs
259 add_label.set_text(&format!("Added: {}", state.slider_val + state.spinner_val));
260 sub_label.set_text(&format!(
261 "Subtracted: {}",
262 state.slider_val - state.spinner_val
263 ));
264 text_label.set_text(&format!("Text: {}", state.entry_val));
265 password_label.set_text(&format!("Secret Text: {}", state.password_val));
266 bigtext_label.set_text(&format!("Multiline Text: {}", state.multi_val));
267 progress_bar.set_value((state.slider_val + state.spinner_val) as u32);
268 }
269 });
270 event_loop.run();
271}
Sourcepub fn event_queue(&self) -> EventQueue
pub fn event_queue(&self) -> EventQueue
Returns an EventQueue
, a struct that allows you to queue closure from other threads
Sourcepub fn quit(&self)
pub fn quit(&self)
Running this function causes the UI to quit, exiting from main and no longer showing any widgets.
Run in every window’s default on_closing
callback.
Examples found in repository?
6fn main() {
7 // Initialize the UI library
8 let ui = UI::init().expect("Couldn't initialize UI library");
9
10 // Create a window into which controls can be placed
11 let mut win = Window::new(&ui.clone(), "Test App", 200, 200, WindowType::NoMenubar);
12
13 // Create a vertical layout to hold the controls
14 let mut vbox = VerticalBox::new();
15 vbox.set_padded(true);
16
17 let mut group_vbox = VerticalBox::new();
18 let mut group = Group::new("Group");
19
20 // Create two buttons to place in the window
21 let mut button = Button::new("Button");
22 button.on_clicked({
23 move |btn| {
24 btn.set_text("Clicked!");
25 }
26 });
27
28 let mut quit_button = Button::new("Quit");
29 quit_button.on_clicked({
30 let ui = ui.clone();
31 move |_| {
32 ui.quit();
33 }
34 });
35 // Create a new label. Note that labels don't auto-wrap!
36 let mut label_text = String::new();
37 label_text.push_str("There is a ton of text in this label.\n");
38 label_text.push_str("Pretty much every unicode character is supported.\n");
39 label_text.push_str("🎉 用户界面 사용자 인터페이스");
40 let label = Label::new(&label_text);
41
42 vbox.append(label, LayoutStrategy::Stretchy);
43 group_vbox.append(button, LayoutStrategy::Compact);
44 group_vbox.append(quit_button, LayoutStrategy::Compact);
45 group.set_child(group_vbox);
46 vbox.append(group, LayoutStrategy::Compact);
47
48 // Actually put the button in the window
49 win.set_child(vbox);
50 // Show the window
51 win.show();
52 // Run the application
53 ui.main();
54}
More examples
9fn main() {
10 let ui = UI::init().unwrap();
11
12 // Menus must be created before the window. They belong to the window automatically.
13 libui::menu! { &ui,
14 let menu_file = Menu("File") {
15 let menu_file_open = MenuItem("Open")
16 let menu_file_save = MenuItem("Save")
17 Separator()
18 let menu_file_close = MenuItem("Close")
19 let menu_file_pref = PreferencesItem()
20 let _menu_file_quit = QuitItem()
21 }
22 let menu_help = Menu("Help") {
23 let _menu_help_updates = MenuItem("Updates")
24 let menu_help_about = AboutItem()
25 }
26 }
27
28 // Set up the application's layout
29 let mut window = Window::new(&ui, "Text Editor", 640, 480, WindowType::HasMenubar);
30 libui::layout! { &ui,
31 let layout = VerticalBox() {
32 Stretchy: let entry = MultilineEntry()
33 }
34 }
35 window.set_child(layout);
36
37 menu_file_open.on_clicked({
38 let mut entry = entry.clone();
39 move |_, w| {
40 let path = match w.open_file() {
41 None => return,
42 Some(v) => v,
43 };
44
45 let mut file = match File::open(&path) {
46 Err(e) => {
47 w.modal_err(
48 "I/O Error",
49 &format!(
50 "Couldn't open file for reading {}: {}",
51 path.display(),
52 e.to_string()
53 ),
54 );
55 return;
56 }
57 Ok(f) => f,
58 };
59
60 let mut text = String::new();
61 match file.read_to_string(&mut text) {
62 Err(_) => return,
63 Ok(_) => (),
64 };
65 entry.set_value(&text);
66 }
67 });
68
69 menu_file_save.on_clicked({
70 let entry = entry.clone();
71 move |_, w| {
72 let path = match w.save_file() {
73 None => return,
74 Some(v) => v,
75 };
76
77 let mut file = match File::create(&path) {
78 Err(e) => {
79 w.modal_err(
80 "I/O Error",
81 &format!(
82 "Couldn't open file for writing {}: {}",
83 path.display(),
84 e.to_string()
85 ),
86 );
87 return;
88 }
89 Ok(f) => f,
90 };
91
92 match file.write_all(entry.value().as_bytes()) {
93 Err(_) => return,
94 Ok(_) => (),
95 };
96 }
97 });
98
99 menu_file_close.on_clicked({
100 let mut entry = entry.clone();
101 move |_, _| {
102 entry.set_value("");
103 }
104 });
105
106 menu_file_pref
107 .on_clicked(move |_, w| w.modal_msg("Preferences", "Preferences menu item clicked!"));
108
109 menu_help_about.on_clicked(move |_, w| w.modal_msg("About", "libui: Menu Example"));
110
111 // The special MenuItem from `Menu::append_quit_item()` or a `libui::menu! { QuitMenuItem() }` macro
112 // doesn't accept a callback with MenuItem::on_clicked(). Instead, call UI::on_should_quit() instead.
113 ui.on_should_quit({
114 let ui = ui.clone();
115 move || {
116 ui.quit();
117 }
118 });
119
120 window.show();
121 ui.main();
122}
Sourcepub fn queue_main<F: FnMut() + 'static>(&self, callback: F)
pub fn queue_main<F: FnMut() + 'static>(&self, callback: F)
Queues a function to be executed on the GUI thread when next possible. Returns immediately, not waiting for the function to be executed.
§Example
use libui::prelude::*;
let ui = UI::init().unwrap();
ui.queue_main(|| { println!("Runs first") } );
ui.queue_main(|| { println!("Runs second") } );
ui.quit();
Sourcepub fn on_should_quit<F: FnMut() + 'static>(&self, callback: F)
pub fn on_should_quit<F: FnMut() + 'static>(&self, callback: F)
Set a callback to be run when the application quits.
Examples found in repository?
9fn main() {
10 let ui = UI::init().unwrap();
11
12 // Menus must be created before the window. They belong to the window automatically.
13 libui::menu! { &ui,
14 let menu_file = Menu("File") {
15 let menu_file_open = MenuItem("Open")
16 let menu_file_save = MenuItem("Save")
17 Separator()
18 let menu_file_close = MenuItem("Close")
19 let menu_file_pref = PreferencesItem()
20 let _menu_file_quit = QuitItem()
21 }
22 let menu_help = Menu("Help") {
23 let _menu_help_updates = MenuItem("Updates")
24 let menu_help_about = AboutItem()
25 }
26 }
27
28 // Set up the application's layout
29 let mut window = Window::new(&ui, "Text Editor", 640, 480, WindowType::HasMenubar);
30 libui::layout! { &ui,
31 let layout = VerticalBox() {
32 Stretchy: let entry = MultilineEntry()
33 }
34 }
35 window.set_child(layout);
36
37 menu_file_open.on_clicked({
38 let mut entry = entry.clone();
39 move |_, w| {
40 let path = match w.open_file() {
41 None => return,
42 Some(v) => v,
43 };
44
45 let mut file = match File::open(&path) {
46 Err(e) => {
47 w.modal_err(
48 "I/O Error",
49 &format!(
50 "Couldn't open file for reading {}: {}",
51 path.display(),
52 e.to_string()
53 ),
54 );
55 return;
56 }
57 Ok(f) => f,
58 };
59
60 let mut text = String::new();
61 match file.read_to_string(&mut text) {
62 Err(_) => return,
63 Ok(_) => (),
64 };
65 entry.set_value(&text);
66 }
67 });
68
69 menu_file_save.on_clicked({
70 let entry = entry.clone();
71 move |_, w| {
72 let path = match w.save_file() {
73 None => return,
74 Some(v) => v,
75 };
76
77 let mut file = match File::create(&path) {
78 Err(e) => {
79 w.modal_err(
80 "I/O Error",
81 &format!(
82 "Couldn't open file for writing {}: {}",
83 path.display(),
84 e.to_string()
85 ),
86 );
87 return;
88 }
89 Ok(f) => f,
90 };
91
92 match file.write_all(entry.value().as_bytes()) {
93 Err(_) => return,
94 Ok(_) => (),
95 };
96 }
97 });
98
99 menu_file_close.on_clicked({
100 let mut entry = entry.clone();
101 move |_, _| {
102 entry.set_value("");
103 }
104 });
105
106 menu_file_pref
107 .on_clicked(move |_, w| w.modal_msg("Preferences", "Preferences menu item clicked!"));
108
109 menu_help_about.on_clicked(move |_, w| w.modal_msg("About", "libui: Menu Example"));
110
111 // The special MenuItem from `Menu::append_quit_item()` or a `libui::menu! { QuitMenuItem() }` macro
112 // doesn't accept a callback with MenuItem::on_clicked(). Instead, call UI::on_should_quit() instead.
113 ui.on_should_quit({
114 let ui = ui.clone();
115 move || {
116 ui.quit();
117 }
118 });
119
120 window.show();
121 ui.main();
122}