Struct UI

Source
pub struct UI { /* private fields */ }
Expand description

A handle to user interface functionality.

Implementations§

Source§

impl UI

Source

pub fn parent_of<T: Into<Control>>(&self, control: T) -> Option<Control>

Source

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.

Source

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.

Source

pub fn is_shown<T: Into<Control>>(&self, control: T) -> bool

Returns true if this control is currently set to be displayed.

Source

pub fn set_shown<T: Into<Control>>(&mut self, control: T, show: bool)

Sets whether or not the control should be displayed.

Source

pub fn is_enabled<T: Into<Control>>(&self, control: T) -> bool

Returns true if the control is enabled (can be interacted with).

Source

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

Source

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?
examples/canvas.rs (line 52)
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
Hide additional examples
examples/controlgallery/main.rs (line 14)
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}
examples/basic.rs (line 8)
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}
examples/menus.rs (line 10)
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}
examples/inputs.rs (line 23)
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}
examples/builder.rs (line 9)
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}
Source

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?
examples/canvas.rs (line 61)
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
Hide additional examples
examples/controlgallery/main.rs (line 41)
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}
examples/basic.rs (line 53)
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}
examples/menus.rs (line 121)
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}
examples/builder.rs (line 152)
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}
Source

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?
examples/inputs.rs (line 159)
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
Hide additional examples
examples/inputs-grid.rs (line 247)
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}
Source

pub fn event_queue(&self) -> EventQueue

Returns an EventQueue, a struct that allows you to queue closure from other threads

Source

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?
examples/basic.rs (line 32)
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
Hide additional examples
examples/menus.rs (line 116)
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}
Source

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();
Source

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?
examples/menus.rs (lines 113-118)
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}

Trait Implementations§

Source§

impl Clone for UI

Source§

fn clone(&self) -> UI

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

§

impl Freeze for UI

§

impl RefUnwindSafe for UI

§

impl !Send for UI

§

impl !Sync for UI

§

impl Unpin for UI

§

impl UnwindSafe for UI

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.