|
| 1 | +//! Demonstrates a mutable application state manipulated over a number of UIs |
| 2 | +//! Using the UIGrid function for a prettier interface. |
| 3 | +
|
| 4 | +extern crate iui; |
| 5 | +use iui::prelude::*; |
| 6 | +use iui::controls::{Label, Spinbox, Slider, Entry, MultilineEntry, LayoutGrid, |
| 7 | + GridAlignment, HorizontalSeparator}; |
| 8 | +use std::rc::Rc; |
| 9 | +use std::cell::RefCell; |
| 10 | + |
| 11 | +/// This struct will hold the values that multiple callbacks will need to access. |
| 12 | +struct State { |
| 13 | + slider_val: i64, |
| 14 | + spinner_val: i64, |
| 15 | + entry_val: String, |
| 16 | + multi_val: String, |
| 17 | +} |
| 18 | + |
| 19 | +fn main() { |
| 20 | + // Initialize the UI framework. |
| 21 | + let ui = UI::init().unwrap(); |
| 22 | + |
| 23 | + // Initialize the state of the application. |
| 24 | + let state = Rc::new(RefCell::new(State { slider_val: 0, spinner_val: 0, entry_val: "".into(), multi_val: "".into() })); |
| 25 | + |
| 26 | + // Create the grid which we'll use to lay out controls |
| 27 | + let mut grid = LayoutGrid::new(&ui); |
| 28 | + grid.set_padded(&ui, true); |
| 29 | + |
| 30 | + // Set up the inputs for the application. |
| 31 | + // While it's not necessary to create a block for this, it makes the code a lot easier |
| 32 | + // to read; the indentation presents a visual cue informing the reader that these |
| 33 | + // statements are related. |
| 34 | + let (mut slider, mut spinner, mut entry, mut multi) = { |
| 35 | + // Numerical inputs |
| 36 | + let slider = Slider::new(&ui, 1, 100); |
| 37 | + let spinner = Spinbox::new(&ui, 1, 100); |
| 38 | + // Text inputs |
| 39 | + let entry = Entry::new(&ui); |
| 40 | + let multi = MultilineEntry::new(&ui); |
| 41 | + // Add everything into the grid |
| 42 | + grid.append(&ui, slider.clone(), |
| 43 | + // This is position (by slot) and size, expansion, and alignment. |
| 44 | + // In this case, row 0, col 0, 1 by 1, compress as much as possible, |
| 45 | + // and align to the fill. |
| 46 | + 0, 0, 1, 1, false, false, GridAlignment::Fill, GridAlignment::Fill); |
| 47 | + grid.append(&ui, spinner.clone(), |
| 48 | + // This one is at column zero, row 1. |
| 49 | + 0, 1, 1, 1, false, false, GridAlignment::Fill, GridAlignment::Fill); |
| 50 | + grid.append(&ui, HorizontalSeparator::new(&ui), |
| 51 | + 0, 3, 1, 1, false, false, GridAlignment::Fill, GridAlignment::Fill); |
| 52 | + grid.append(&ui, entry.clone(), |
| 53 | + 0, 4, 1, 1, false, false, GridAlignment::Fill, GridAlignment::Fill); |
| 54 | + grid.append(&ui, multi.clone(), |
| 55 | + // The multiline entry is at column 0, row 1, and expands vertically. |
| 56 | + 0, 5, 1, 1, false, true, GridAlignment::Fill, GridAlignment::Fill); |
| 57 | + (slider, spinner, entry, multi) |
| 58 | + }; |
| 59 | + |
| 60 | + // Set up the outputs for the application. Organization is very similar to the |
| 61 | + // previous setup. |
| 62 | + let (add_label, sub_label, text_label, bigtext_label) = { |
| 63 | + let add_label = Label::new(&ui, ""); |
| 64 | + let sub_label = Label::new(&ui, ""); |
| 65 | + let text_label = Label::new(&ui, ""); |
| 66 | + let bigtext_label = Label::new(&ui, ""); |
| 67 | + grid.append(&ui, add_label.clone(), |
| 68 | + 1, 0, 1, 1, false, false, GridAlignment::Fill, GridAlignment::Fill); |
| 69 | + grid.append(&ui, sub_label.clone(), |
| 70 | + 1, 1, 1, 1, false, false, GridAlignment::Fill, GridAlignment::Fill); |
| 71 | + grid.append(&ui, text_label.clone(), |
| 72 | + 1, 2, 1, 1, false, false, GridAlignment::Fill, GridAlignment::Fill); |
| 73 | + grid.append(&ui, bigtext_label.clone(), |
| 74 | + 1, 3, 1, 1, false, false, GridAlignment::Fill, GridAlignment::Fill); |
| 75 | + (add_label, sub_label, text_label, bigtext_label) |
| 76 | + }; |
| 77 | + |
| 78 | + // The window allows all constituent components to be displayed. |
| 79 | + let mut window = Window::new(&ui, "Input Output Test", 300, 150, WindowType::NoMenubar); |
| 80 | + window.set_child(&ui, grid); |
| 81 | + window.show(&ui); |
| 82 | + |
| 83 | + // These on_changed functions allow updating the application state when a |
| 84 | + // control changes its value. |
| 85 | + |
| 86 | + slider.on_changed(&ui, { |
| 87 | + let state = state.clone(); |
| 88 | + move |val| { state.borrow_mut().slider_val = val; } |
| 89 | + }); |
| 90 | + |
| 91 | + spinner.on_changed(&ui, { |
| 92 | + let state = state.clone(); |
| 93 | + move |val| { state.borrow_mut().spinner_val = val; } |
| 94 | + }); |
| 95 | + |
| 96 | + entry.on_changed(&ui, { |
| 97 | + let state = state.clone(); |
| 98 | + move |val| { state.borrow_mut().entry_val = val; } |
| 99 | + }); |
| 100 | + |
| 101 | + multi.on_changed(&ui, { |
| 102 | + let state = state.clone(); |
| 103 | + move |val| { state.borrow_mut().multi_val = val; } |
| 104 | + }); |
| 105 | + |
| 106 | + |
| 107 | + // Rather than just invoking ui.run(), using EventLoop gives a lot more control |
| 108 | + // over the user interface event loop. |
| 109 | + // Here, the on_tick() callback is used to update the view against the state. |
| 110 | + let mut event_loop = ui.event_loop(); |
| 111 | + event_loop.on_tick(&ui, { |
| 112 | + let ui = ui.clone(); |
| 113 | + let mut add_label = add_label.clone(); |
| 114 | + let mut sub_label = sub_label.clone(); |
| 115 | + let mut text_label = text_label.clone(); |
| 116 | + let mut bigtext_label = bigtext_label.clone(); |
| 117 | + move || { |
| 118 | + let state = state.borrow(); |
| 119 | + |
| 120 | + // Update all the labels |
| 121 | + add_label.set_text(&ui, &format!("Added: {}", state.slider_val + state.spinner_val)); |
| 122 | + sub_label.set_text(&ui, &format!("Subtracted: {}", state.slider_val - state.spinner_val)); |
| 123 | + text_label.set_text(&ui, &format!("Text: {}", state.entry_val)); |
| 124 | + bigtext_label.set_text(&ui, &format!("Multiline Text: {}", state.multi_val)); |
| 125 | + } |
| 126 | + }); |
| 127 | + event_loop.run(&ui); |
| 128 | +} |
0 commit comments