Struct WindowBuilder

Source
pub struct WindowBuilder<'a> { /* private fields */ }
Expand description

A WidgetBuilder specifically for creating windows.

Windows can have a titlebar, close button, move, and resizing capabilities. Each window is automatically part of its own render group and will automatically come on top of other widgets when clicked on. You can create a WindowBuilder from a WidgetBuilder by calling window after any calls to general purpose widget layout.

There is also a window method on Frame as a convenience for simple cases.

Once you are finished setting up the window, you call children to add children and add the widget to the frame.

§Example

fn create_window(ui: &mut Frame, unique_id: &str) {
    ui.start("window")
    .window(unique_id)
    .title("My Window")
    .resizable(false)
    .children(|ui| {
        // window content here
    });
}

§Theme definition

An example of a theme definition for a window:

  window:
    background: gui/window_bg
    wants_mouse: true
    layout: Vertical
    layout_spacing: [5, 5]
    border: { left: 5, right: 5, top: 35, bot: 5 }
    size: [300, 400]
    child_align: Top
    children:
      titlebar:
        wants_mouse: true
        background: gui/small_button
        size: [10, 30]
        pos: [-6, -36]
        border: { all: 5 }
        width_from: Parent
        child_align: Center
        align: TopLeft
        children:
          title:
            from: label
            text: "Main Window"
            font: medium
            width_from: Parent
          close:
            wants_mouse: true
            background: gui/small_button
            foreground: gui/close_icon
            size: [20, 20]
            border: { all: 4 }
            align: TopRight
      handle:
        wants_mouse: true
        background: gui/window_handle
        size: [12, 12]
        align: BotRight
        pos: [-1, -1]

Implementations§

Source§

impl<'a> WindowBuilder<'a>

Source

pub fn cancel_render_group(self) -> WindowBuilder<'a>

Specifies that this window will not use a new render group. This can be useful in some cases where you want to handle grouping yourself. See WidgetBuilder.new_render_group

Source

pub fn with_titlebar(self, with_titlebar: bool) -> WindowBuilder<'a>

Specifies whether the created window should show a titlebar.

Source

pub fn title<T: Into<String>>(self, title: T) -> WindowBuilder<'a>

Specify a title to show in the window’s titlebar, if it is present. If the titlebar is not present, does nothing. This will override any text set in the theme.

Source

pub fn with_close_button(self, with_close_button: bool) -> WindowBuilder<'a>

Specifies whether the created window should have a close button.

Examples found in repository?
examples/demo.rs (line 221)
189pub fn build_ui(ui: &mut Frame, party: &mut Party) {
190    match party.theme_choice {
191        ThemeChoice::Pixels | ThemeChoice::Fantasy | ThemeChoice::Transparent | ThemeChoice::Golden => {
192            // show a custom cursor.  it automatically inherits mouse presses in its state
193            ui.set_mouse_cursor("gui/cursor", thyme::Align::TopLeft);
194        },
195        ThemeChoice::NoImage => {
196            // don't show a custom cursor
197        }
198    }
199
200    ui.label("bench", format!(
201        "{}\n{}\n{}",
202        bench::short_report("thyme"),
203        bench::short_report("frame"),
204        bench::short_report("draw"),
205    ));
206
207    ui.start("theme_panel").children(|ui| {
208        if ui.start("live_reload").active(!party.live_reload_disabled).finish().clicked {
209            party.live_reload_disabled = !party.live_reload_disabled;
210        }
211
212        if let Some(choice) = ui.combo_box("theme_choice", "theme_choice", &party.theme_choice, &THEME_CHOICES) {
213            party.old_theme_choice = Some(party.theme_choice);
214            party.theme_choice = *choice;
215            party.reload_assets = true;
216        }
217    });
218
219    ui.start("party_window")
220    .window("party_window")
221    .with_close_button(false)
222    .moveable(false)
223    .resizable(false)
224    .children(|ui| {
225        ui.scrollpane("members_panel", "party_content", |ui| {
226            party_members_panel(ui, party);
227        });
228    });
229
230    if let Some(index) = party.editing_index {
231        let character = &mut party.members[index];
232
233        ui.window("character_window", |ui| {
234            ui.scrollpane("pane", "character_content", |ui| {
235                ui.start("name_panel")
236                .children(|ui| {
237                    if let Some(new_name) = ui.input_field("name_input", "name_input", None) {
238                        character.name = new_name;
239                    }
240                });
241
242                ui.gap(10.0);
243                ui.label("age_label", format!("Age: {}", character.age.round() as u32));
244                if let Some(age) = ui.horizontal_slider("age_slider", MIN_AGE, MAX_AGE, character.age) {
245                    character.age = age;
246                }
247
248                for stat in Stat::iter() {
249                    let value = format!("{}", character.stats.get(&stat).unwrap_or(&10));
250                    let key = format!("{:?}", stat);
251                    ui.set_variable(key, value);
252                }
253
254                ui.scrollpane("description_panel", "description_pane", |ui| {
255                    ui.text_area("description_box");
256                });
257
258                ui.gap(10.0);
259
260                if let Some(race) = ui.combo_box("race_selector", "race_selector", &character.race, Race::all()) {
261                    character.race = *race;
262                }
263    
264                ui.gap(10.0);
265    
266                ui.tree("stats_panel", "stats_panel", true,
267                |ui| {
268                    ui.child("title");
269                },|ui| {
270                    stats_panel(ui, character);
271                });
272                
273                ui.gap(10.0);
274    
275                ui.tree("inventory_panel", "inventory_panel", true,
276                |ui| {
277                    ui.child("title");
278                }, |ui| {
279                    inventory_panel(ui, character);
280                });
281            });
282        });
283
284        ui.window("item_picker", |ui| {
285            let display_size = ui.display_size();
286
287            ui.start("greyed_out")
288            .unclip()
289            .unparent()
290            .size(display_size.x, display_size.y)
291            .screen_pos(0.0, 0.0).finish();
292
293            item_picker(ui, character);
294        });
295    }
296}
Source

pub fn moveable(self, moveable: bool) -> WindowBuilder<'a>

Specifies whether the user should be able to move the created window by dragging the mouse. Note that if the titlebar is not shown, there will be no way to move the window regardless of this setting.

Examples found in repository?
examples/demo.rs (line 222)
189pub fn build_ui(ui: &mut Frame, party: &mut Party) {
190    match party.theme_choice {
191        ThemeChoice::Pixels | ThemeChoice::Fantasy | ThemeChoice::Transparent | ThemeChoice::Golden => {
192            // show a custom cursor.  it automatically inherits mouse presses in its state
193            ui.set_mouse_cursor("gui/cursor", thyme::Align::TopLeft);
194        },
195        ThemeChoice::NoImage => {
196            // don't show a custom cursor
197        }
198    }
199
200    ui.label("bench", format!(
201        "{}\n{}\n{}",
202        bench::short_report("thyme"),
203        bench::short_report("frame"),
204        bench::short_report("draw"),
205    ));
206
207    ui.start("theme_panel").children(|ui| {
208        if ui.start("live_reload").active(!party.live_reload_disabled).finish().clicked {
209            party.live_reload_disabled = !party.live_reload_disabled;
210        }
211
212        if let Some(choice) = ui.combo_box("theme_choice", "theme_choice", &party.theme_choice, &THEME_CHOICES) {
213            party.old_theme_choice = Some(party.theme_choice);
214            party.theme_choice = *choice;
215            party.reload_assets = true;
216        }
217    });
218
219    ui.start("party_window")
220    .window("party_window")
221    .with_close_button(false)
222    .moveable(false)
223    .resizable(false)
224    .children(|ui| {
225        ui.scrollpane("members_panel", "party_content", |ui| {
226            party_members_panel(ui, party);
227        });
228    });
229
230    if let Some(index) = party.editing_index {
231        let character = &mut party.members[index];
232
233        ui.window("character_window", |ui| {
234            ui.scrollpane("pane", "character_content", |ui| {
235                ui.start("name_panel")
236                .children(|ui| {
237                    if let Some(new_name) = ui.input_field("name_input", "name_input", None) {
238                        character.name = new_name;
239                    }
240                });
241
242                ui.gap(10.0);
243                ui.label("age_label", format!("Age: {}", character.age.round() as u32));
244                if let Some(age) = ui.horizontal_slider("age_slider", MIN_AGE, MAX_AGE, character.age) {
245                    character.age = age;
246                }
247
248                for stat in Stat::iter() {
249                    let value = format!("{}", character.stats.get(&stat).unwrap_or(&10));
250                    let key = format!("{:?}", stat);
251                    ui.set_variable(key, value);
252                }
253
254                ui.scrollpane("description_panel", "description_pane", |ui| {
255                    ui.text_area("description_box");
256                });
257
258                ui.gap(10.0);
259
260                if let Some(race) = ui.combo_box("race_selector", "race_selector", &character.race, Race::all()) {
261                    character.race = *race;
262                }
263    
264                ui.gap(10.0);
265    
266                ui.tree("stats_panel", "stats_panel", true,
267                |ui| {
268                    ui.child("title");
269                },|ui| {
270                    stats_panel(ui, character);
271                });
272                
273                ui.gap(10.0);
274    
275                ui.tree("inventory_panel", "inventory_panel", true,
276                |ui| {
277                    ui.child("title");
278                }, |ui| {
279                    inventory_panel(ui, character);
280                });
281            });
282        });
283
284        ui.window("item_picker", |ui| {
285            let display_size = ui.display_size();
286
287            ui.start("greyed_out")
288            .unclip()
289            .unparent()
290            .size(display_size.x, display_size.y)
291            .screen_pos(0.0, 0.0).finish();
292
293            item_picker(ui, character);
294        });
295    }
296}
Source

pub fn resizable(self, resizable: bool) -> WindowBuilder<'a>

Specifies whether the user should be able to resize the created window. If false, the resize handle will not be shown.

Examples found in repository?
examples/demo.rs (line 223)
189pub fn build_ui(ui: &mut Frame, party: &mut Party) {
190    match party.theme_choice {
191        ThemeChoice::Pixels | ThemeChoice::Fantasy | ThemeChoice::Transparent | ThemeChoice::Golden => {
192            // show a custom cursor.  it automatically inherits mouse presses in its state
193            ui.set_mouse_cursor("gui/cursor", thyme::Align::TopLeft);
194        },
195        ThemeChoice::NoImage => {
196            // don't show a custom cursor
197        }
198    }
199
200    ui.label("bench", format!(
201        "{}\n{}\n{}",
202        bench::short_report("thyme"),
203        bench::short_report("frame"),
204        bench::short_report("draw"),
205    ));
206
207    ui.start("theme_panel").children(|ui| {
208        if ui.start("live_reload").active(!party.live_reload_disabled).finish().clicked {
209            party.live_reload_disabled = !party.live_reload_disabled;
210        }
211
212        if let Some(choice) = ui.combo_box("theme_choice", "theme_choice", &party.theme_choice, &THEME_CHOICES) {
213            party.old_theme_choice = Some(party.theme_choice);
214            party.theme_choice = *choice;
215            party.reload_assets = true;
216        }
217    });
218
219    ui.start("party_window")
220    .window("party_window")
221    .with_close_button(false)
222    .moveable(false)
223    .resizable(false)
224    .children(|ui| {
225        ui.scrollpane("members_panel", "party_content", |ui| {
226            party_members_panel(ui, party);
227        });
228    });
229
230    if let Some(index) = party.editing_index {
231        let character = &mut party.members[index];
232
233        ui.window("character_window", |ui| {
234            ui.scrollpane("pane", "character_content", |ui| {
235                ui.start("name_panel")
236                .children(|ui| {
237                    if let Some(new_name) = ui.input_field("name_input", "name_input", None) {
238                        character.name = new_name;
239                    }
240                });
241
242                ui.gap(10.0);
243                ui.label("age_label", format!("Age: {}", character.age.round() as u32));
244                if let Some(age) = ui.horizontal_slider("age_slider", MIN_AGE, MAX_AGE, character.age) {
245                    character.age = age;
246                }
247
248                for stat in Stat::iter() {
249                    let value = format!("{}", character.stats.get(&stat).unwrap_or(&10));
250                    let key = format!("{:?}", stat);
251                    ui.set_variable(key, value);
252                }
253
254                ui.scrollpane("description_panel", "description_pane", |ui| {
255                    ui.text_area("description_box");
256                });
257
258                ui.gap(10.0);
259
260                if let Some(race) = ui.combo_box("race_selector", "race_selector", &character.race, Race::all()) {
261                    character.race = *race;
262                }
263    
264                ui.gap(10.0);
265    
266                ui.tree("stats_panel", "stats_panel", true,
267                |ui| {
268                    ui.child("title");
269                },|ui| {
270                    stats_panel(ui, character);
271                });
272                
273                ui.gap(10.0);
274    
275                ui.tree("inventory_panel", "inventory_panel", true,
276                |ui| {
277                    ui.child("title");
278                }, |ui| {
279                    inventory_panel(ui, character);
280                });
281            });
282        });
283
284        ui.window("item_picker", |ui| {
285            let display_size = ui.display_size();
286
287            ui.start("greyed_out")
288            .unclip()
289            .unparent()
290            .size(display_size.x, display_size.y)
291            .screen_pos(0.0, 0.0).finish();
292
293            item_picker(ui, character);
294        });
295    }
296}
Source

pub fn children<F: FnOnce(&mut Frame)>(self, children: F) -> WidgetState

Consumes the builder and adds a widget to the current frame. The returned data includes information about the animation state and mouse interactions of the created element. The provided closure is called to enable adding children to this window.

Examples found in repository?
examples/demo.rs (lines 224-228)
189pub fn build_ui(ui: &mut Frame, party: &mut Party) {
190    match party.theme_choice {
191        ThemeChoice::Pixels | ThemeChoice::Fantasy | ThemeChoice::Transparent | ThemeChoice::Golden => {
192            // show a custom cursor.  it automatically inherits mouse presses in its state
193            ui.set_mouse_cursor("gui/cursor", thyme::Align::TopLeft);
194        },
195        ThemeChoice::NoImage => {
196            // don't show a custom cursor
197        }
198    }
199
200    ui.label("bench", format!(
201        "{}\n{}\n{}",
202        bench::short_report("thyme"),
203        bench::short_report("frame"),
204        bench::short_report("draw"),
205    ));
206
207    ui.start("theme_panel").children(|ui| {
208        if ui.start("live_reload").active(!party.live_reload_disabled).finish().clicked {
209            party.live_reload_disabled = !party.live_reload_disabled;
210        }
211
212        if let Some(choice) = ui.combo_box("theme_choice", "theme_choice", &party.theme_choice, &THEME_CHOICES) {
213            party.old_theme_choice = Some(party.theme_choice);
214            party.theme_choice = *choice;
215            party.reload_assets = true;
216        }
217    });
218
219    ui.start("party_window")
220    .window("party_window")
221    .with_close_button(false)
222    .moveable(false)
223    .resizable(false)
224    .children(|ui| {
225        ui.scrollpane("members_panel", "party_content", |ui| {
226            party_members_panel(ui, party);
227        });
228    });
229
230    if let Some(index) = party.editing_index {
231        let character = &mut party.members[index];
232
233        ui.window("character_window", |ui| {
234            ui.scrollpane("pane", "character_content", |ui| {
235                ui.start("name_panel")
236                .children(|ui| {
237                    if let Some(new_name) = ui.input_field("name_input", "name_input", None) {
238                        character.name = new_name;
239                    }
240                });
241
242                ui.gap(10.0);
243                ui.label("age_label", format!("Age: {}", character.age.round() as u32));
244                if let Some(age) = ui.horizontal_slider("age_slider", MIN_AGE, MAX_AGE, character.age) {
245                    character.age = age;
246                }
247
248                for stat in Stat::iter() {
249                    let value = format!("{}", character.stats.get(&stat).unwrap_or(&10));
250                    let key = format!("{:?}", stat);
251                    ui.set_variable(key, value);
252                }
253
254                ui.scrollpane("description_panel", "description_pane", |ui| {
255                    ui.text_area("description_box");
256                });
257
258                ui.gap(10.0);
259
260                if let Some(race) = ui.combo_box("race_selector", "race_selector", &character.race, Race::all()) {
261                    character.race = *race;
262                }
263    
264                ui.gap(10.0);
265    
266                ui.tree("stats_panel", "stats_panel", true,
267                |ui| {
268                    ui.child("title");
269                },|ui| {
270                    stats_panel(ui, character);
271                });
272                
273                ui.gap(10.0);
274    
275                ui.tree("inventory_panel", "inventory_panel", true,
276                |ui| {
277                    ui.child("title");
278                }, |ui| {
279                    inventory_panel(ui, character);
280                });
281            });
282        });
283
284        ui.window("item_picker", |ui| {
285            let display_size = ui.display_size();
286
287            ui.start("greyed_out")
288            .unclip()
289            .unparent()
290            .size(display_size.x, display_size.y)
291            .screen_pos(0.0, 0.0).finish();
292
293            item_picker(ui, character);
294        });
295    }
296}

Auto Trait Implementations§

§

impl<'a> Freeze for WindowBuilder<'a>

§

impl<'a> !RefUnwindSafe for WindowBuilder<'a>

§

impl<'a> !Send for WindowBuilder<'a>

§

impl<'a> !Sync for WindowBuilder<'a>

§

impl<'a> Unpin for WindowBuilder<'a>

§

impl<'a> !UnwindSafe for WindowBuilder<'a>

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> Downcast<T> for T

Source§

fn downcast(&self) -> &T

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, 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.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>