mirror of
https://github.com/eliasstepanik/imgui-rs.git
synced 2026-01-11 21:48:36 +00:00
Merge pull request #537 from dbr/uiwindowredux
Window::new -> Ui::window attempt 2
This commit is contained in:
commit
7b9ce6bb1c
@ -10,9 +10,9 @@
|
||||

|
||||
|
||||
```rust
|
||||
Window::new("Hello world")
|
||||
ui.window("Hello world")
|
||||
.size([300.0, 100.0], Condition::FirstUseEver)
|
||||
.build(&ui, || {
|
||||
.build(|| {
|
||||
ui.text("Hello world!");
|
||||
ui.text("こんにちは世界!");
|
||||
ui.text("This...is...imgui-rs!");
|
||||
|
||||
@ -8,11 +8,12 @@ fn main() {
|
||||
};
|
||||
let system = support::init(file!());
|
||||
system.main_loop(move |run, ui| {
|
||||
let w = Window::new("Collapsing header")
|
||||
let w = ui
|
||||
.window("Collapsing header")
|
||||
.opened(run)
|
||||
.position([20.0, 20.0], Condition::Appearing)
|
||||
.size([700.0, 500.0], Condition::Appearing);
|
||||
w.build(ui, || {
|
||||
w.build(|| {
|
||||
if CollapsingHeader::new("I'm a collapsing header. Click me!").build(ui) {
|
||||
ui.text(
|
||||
"A collapsing header can be used to toggle rendering of a group of widgets",
|
||||
|
||||
@ -17,12 +17,13 @@ fn main() {
|
||||
}
|
||||
|
||||
fn example_selector(run: &mut bool, ui: &mut Ui, state: &mut State) {
|
||||
let w = Window::new("Color button examples")
|
||||
let w = ui
|
||||
.window("Color button examples")
|
||||
.opened(run)
|
||||
.position([20.0, 20.0], Condition::Appearing)
|
||||
.size([700.0, 100.0], Condition::Appearing)
|
||||
.resizable(false);
|
||||
w.build(ui, || {
|
||||
w.build(|| {
|
||||
let ex1 = ui.radio_button("Example 1: Basics", &mut state.example, 1);
|
||||
let ex2 = ui.radio_button("Example 2: Alpha component", &mut state.example, 2);
|
||||
let ex3 = ui.radio_button("Example 3: Input format", &mut state.example, 3);
|
||||
@ -33,10 +34,11 @@ fn example_selector(run: &mut bool, ui: &mut Ui, state: &mut State) {
|
||||
}
|
||||
|
||||
fn example_1(ui: &Ui, state: &mut State) {
|
||||
let w = Window::new("Example 1: Basics")
|
||||
let w = ui
|
||||
.window("Example 1: Basics")
|
||||
.size([700.0, 300.0], Condition::Appearing)
|
||||
.position([20.0, 140.0], Condition::Appearing);
|
||||
w.build(ui, || {
|
||||
w.build(|| {
|
||||
ui.text_wrapped(
|
||||
"Color button is a widget that displays a color value as a clickable rectangle. \
|
||||
It also supports a tooltip with detailed information about the color value. \
|
||||
@ -73,10 +75,11 @@ fn example_1(ui: &Ui, state: &mut State) {
|
||||
}
|
||||
|
||||
fn example_2(ui: &Ui) {
|
||||
let w = Window::new("Example 2: Alpha component")
|
||||
let w = ui
|
||||
.window("Example 2: Alpha component")
|
||||
.size([700.0, 320.0], Condition::Appearing)
|
||||
.position([20.0, 140.0], Condition::Appearing);
|
||||
w.build(ui, || {
|
||||
w.build(|| {
|
||||
ui.text_wrapped(
|
||||
"The displayed color is passed to the button as four float values between \
|
||||
0.0 - 1.0 (RGBA). If you don't care about the alpha component, it can be \
|
||||
@ -123,10 +126,11 @@ fn example_2(ui: &Ui) {
|
||||
}
|
||||
|
||||
fn example_3(ui: &Ui) {
|
||||
let w = Window::new("Example 3: Input format")
|
||||
let w = ui
|
||||
.window("Example 3: Input format")
|
||||
.size([700.0, 320.0], Condition::Appearing)
|
||||
.position([20.0, 140.0], Condition::Appearing);
|
||||
w.build(ui, || {
|
||||
w.build(|| {
|
||||
ui.text("This button interprets the input value [1.0, 0.0, 0.0, 1.0] as RGB(A) (default):");
|
||||
ColorButton::new("RGBA red", [1.0, 0.0, 0.0, 1.0]).build(ui);
|
||||
|
||||
|
||||
67
imgui-examples/examples/creating_windows.rs
Normal file
67
imgui-examples/examples/creating_windows.rs
Normal file
@ -0,0 +1,67 @@
|
||||
mod support;
|
||||
|
||||
fn main() {
|
||||
let system = support::init(file!());
|
||||
|
||||
system.main_loop(move |_, ui| {
|
||||
// If we don't explicitly create a window before creating some kind of widget, then Dear Imgui will automatically create one
|
||||
ui.text("This text will appear in a default window titled 'Debug'");
|
||||
|
||||
// However, in almost all cases it's best to make a window, so it has a useful title etc
|
||||
|
||||
// imgui-rs has two main methods of creating windows (and these same approaches
|
||||
// apply to many other widgets). First, callback based:
|
||||
|
||||
ui.window("My window via callback").build(|| {
|
||||
ui.text("This content appears in a window");
|
||||
|
||||
// Everything in this callback appears in the window, like this button:
|
||||
ui.button("This button");
|
||||
});
|
||||
|
||||
// Often the callback approach is most convenient, however occasionally the callbacks can be hard to use.
|
||||
// In this case, there is the "token based" approach. You call a method and get a "window token",
|
||||
// everything that happens until the token is dropped is included in the window this is more-or-less how
|
||||
// the Dear ImGui C++ API works)
|
||||
|
||||
// Here we (maybe) get a window token:
|
||||
let window_token = ui.window("Token based window").begin();
|
||||
if let Some(_t) = window_token {
|
||||
// If the token is Some(...) then the window contents are visible, so we need to draw them!
|
||||
ui.text("Window contents!")
|
||||
}
|
||||
|
||||
// Here we create a window with a specific size, and force it to always have a vertical scrollbar visible
|
||||
ui.window("Big complex window")
|
||||
.size([200.0, 100.0], imgui::Condition::FirstUseEver)
|
||||
.always_vertical_scrollbar(true)
|
||||
.build(|| {
|
||||
ui.text("Imagine something complicated here..");
|
||||
|
||||
// Note you can create windows inside other windows, however, they both appear as separate windows.
|
||||
// For example, somewhere deep inside a complex window, we can quickly create a widget to display a
|
||||
// variable, like a graphical "debug print"
|
||||
ui.window("Confusion")
|
||||
.build(|| ui.text(format!("Some variable: {:?}", ui.io().mouse_pos)))
|
||||
});
|
||||
|
||||
// If you want to nest windows inside other windows, you can a "child window".
|
||||
// This is essentially a scrollable area, with all the same properties as a regular window
|
||||
ui.window("Parent window").build(|| {
|
||||
ui.child_window("Child window")
|
||||
.size([100.0, 100.0])
|
||||
.build(|| {
|
||||
for _ in 0..10 {
|
||||
ui.text("Lines and");
|
||||
}
|
||||
});
|
||||
ui.child_window("Second child window")
|
||||
.size([100.0, 100.0])
|
||||
.build(|| {
|
||||
for _ in 0..10 {
|
||||
ui.text("More and");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -78,9 +78,9 @@ impl CustomTexturesApp {
|
||||
}
|
||||
|
||||
fn show_textures(&self, ui: &Ui) {
|
||||
Window::new("Hello textures")
|
||||
ui.window("Hello textures")
|
||||
.size([400.0, 400.0], Condition::FirstUseEver)
|
||||
.build(ui, || {
|
||||
.build(|| {
|
||||
ui.text("Hello textures!");
|
||||
if let Some(my_texture_id) = self.my_texture_id {
|
||||
ui.text("Some generated texture");
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
//! Demonstrates disabling widgets. Prevents mouse interaction and greys out widgets
|
||||
|
||||
use imgui::*;
|
||||
|
||||
mod support;
|
||||
@ -11,9 +13,9 @@ fn main() {
|
||||
let mut click_count = 0;
|
||||
|
||||
system.main_loop(move |_, ui| {
|
||||
Window::new("Disabling widgets")
|
||||
ui.window("Disabling widgets")
|
||||
.size([300.0, 200.0], Condition::FirstUseEver)
|
||||
.build(ui, || {
|
||||
.build(|| {
|
||||
ui.checkbox("Edit mode", &mut edit_mode);
|
||||
ui.checkbox("Safe mode", &mut safe_mode);
|
||||
|
||||
|
||||
@ -57,10 +57,10 @@ fn main() {
|
||||
);
|
||||
}
|
||||
|
||||
Window::new("Draw list")
|
||||
ui.window("Draw list")
|
||||
.size([300.0, 110.0], Condition::FirstUseEver)
|
||||
.scroll_bar(false)
|
||||
.build(ui, || {
|
||||
.build(|| {
|
||||
ui.button("random button");
|
||||
let draw_list = ui.get_window_draw_list();
|
||||
let o = ui.cursor_screen_pos();
|
||||
|
||||
@ -7,9 +7,9 @@ fn main() {
|
||||
let mut value = 0;
|
||||
let choices = ["test test this is 1", "test test this is 2"];
|
||||
system.main_loop(move |_, ui| {
|
||||
Window::new("Hello world")
|
||||
ui.window("Hello world")
|
||||
.size([300.0, 110.0], Condition::FirstUseEver)
|
||||
.build(ui, || {
|
||||
.build(|| {
|
||||
ui.text_wrapped("Hello world!");
|
||||
ui.text_wrapped("こんにちは世界!");
|
||||
if ui.button(choices[value]) {
|
||||
|
||||
45
imgui-examples/examples/id_wrangling.rs
Normal file
45
imgui-examples/examples/id_wrangling.rs
Normal file
@ -0,0 +1,45 @@
|
||||
mod support;
|
||||
|
||||
fn main() {
|
||||
let system = support::init(file!());
|
||||
system.main_loop(move |_, ui| {
|
||||
let items = vec!["a", "b", "c", "d"];
|
||||
|
||||
ui.window("Broken Example")
|
||||
.position([0.0, 0.0], imgui::Condition::FirstUseEver)
|
||||
.size([390.0, 200.0], imgui::Condition::FirstUseEver)
|
||||
.build(|| {
|
||||
ui.text("Broken! Only first button responds to clicks");
|
||||
|
||||
// Because all our buttons have the same label (and thus ID),
|
||||
// only the first button responds to clicks!
|
||||
for it in &items {
|
||||
ui.text(it);
|
||||
for num in 0..5 {
|
||||
ui.same_line();
|
||||
if ui.button("Example") {
|
||||
println!("{}: {}", it, num);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ui.window("Good Example")
|
||||
.position([400.0, 0.0], imgui::Condition::FirstUseEver)
|
||||
.size([390.0, 200.0], imgui::Condition::FirstUseEver)
|
||||
.build(|| {
|
||||
ui.text("Works!");
|
||||
for it in &items {
|
||||
let _label_id = ui.push_id(it);
|
||||
ui.text(it);
|
||||
for num in 0..5 {
|
||||
let _num_id = ui.push_id(num);
|
||||
ui.same_line();
|
||||
if ui.button("Example") {
|
||||
println!("{}: {}", it, num);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -14,9 +14,9 @@ fn main() {
|
||||
let mut text_buffer = String::new();
|
||||
|
||||
system.main_loop(move |_, ui| {
|
||||
Window::new("Means of accessing key state")
|
||||
ui.window("Means of accessing key state")
|
||||
.size([500.0, 300.0], Condition::FirstUseEver)
|
||||
.build(ui, || {
|
||||
.build(|| {
|
||||
// You can check if a key is currently held down
|
||||
if ui.is_key_down(Key::A) {
|
||||
ui.text("The A key is down!");
|
||||
|
||||
@ -15,9 +15,9 @@ fn main() {
|
||||
|
||||
let system = support::init(file!());
|
||||
system.main_loop(move |_, ui| {
|
||||
Window::new("Hello long world")
|
||||
ui.window("Hello long world")
|
||||
.size([300.0, 110.0], Condition::FirstUseEver)
|
||||
.build(ui, || {
|
||||
.build(|| {
|
||||
let mut clipper = imgui::ListClipper::new(lots_of_words.len() as i32)
|
||||
.items_height(ui.current_font_size())
|
||||
.begin(ui);
|
||||
|
||||
@ -19,7 +19,7 @@ fn main() {
|
||||
.reload_font_texture(&mut system.imgui)
|
||||
.expect("Failed to reload fonts");
|
||||
system.main_loop(move |run, ui| {
|
||||
Window::new("Hello world").opened(run).build(ui, || {
|
||||
ui.window("Hello world").opened(run).build(|| {
|
||||
ui.text("Hello, I'm the default font!");
|
||||
let _roboto = ui.push_font(roboto);
|
||||
ui.text("Hello, I'm Roboto Regular!");
|
||||
|
||||
@ -5,11 +5,12 @@ mod support;
|
||||
fn main() {
|
||||
let system = support::init(file!());
|
||||
system.main_loop(move |run, ui| {
|
||||
let w = Window::new("Progress bar")
|
||||
let w = ui
|
||||
.window("Progress bar")
|
||||
.opened(run)
|
||||
.position([20.0, 20.0], Condition::Appearing)
|
||||
.size([700.0, 200.0], Condition::Appearing);
|
||||
w.build(ui, || {
|
||||
w.build(|| {
|
||||
ui.text("This is a simple progress bar:");
|
||||
ProgressBar::new(0.5).build(ui);
|
||||
|
||||
|
||||
@ -16,12 +16,13 @@ fn main() {
|
||||
}
|
||||
|
||||
fn example_selector(run: &mut bool, ui: &mut Ui, state: &mut State) {
|
||||
let w = Window::new("Radio button examples")
|
||||
let w = ui
|
||||
.window("Radio button examples")
|
||||
.opened(run)
|
||||
.position([20.0, 20.0], Condition::Appearing)
|
||||
.size([700.0, 80.0], Condition::Appearing)
|
||||
.resizable(false);
|
||||
w.build(ui, || {
|
||||
w.build(|| {
|
||||
let mut clicked = false;
|
||||
clicked |= ui.radio_button("Example 1: Boolean radio buttons", &mut state.example, 1);
|
||||
clicked |= ui.radio_button("Example 2: Radio buttons", &mut state.example, 2);
|
||||
@ -32,10 +33,11 @@ fn example_selector(run: &mut bool, ui: &mut Ui, state: &mut State) {
|
||||
}
|
||||
|
||||
fn example_1(ui: &Ui, state: &mut State) {
|
||||
let w = Window::new("Example 1: Boolean radio buttons")
|
||||
let w = ui
|
||||
.window("Example 1: Boolean radio buttons")
|
||||
.size([700.0, 200.0], Condition::Appearing)
|
||||
.position([20.0, 120.0], Condition::Appearing);
|
||||
w.build(ui, || {
|
||||
w.build(|| {
|
||||
ui.text_wrapped(
|
||||
"Boolean radio buttons accept a boolean active state, which is passed as a value and \
|
||||
not as a mutable reference. This means that it's not updated automatically, so you \
|
||||
@ -58,10 +60,11 @@ fn example_1(ui: &Ui, state: &mut State) {
|
||||
}
|
||||
|
||||
fn example_2(ui: &Ui, state: &mut State) {
|
||||
let w = Window::new("Example 2: Radio buttons")
|
||||
let w = ui
|
||||
.window("Example 2: Radio buttons")
|
||||
.size([700.0, 300.0], Condition::Appearing)
|
||||
.position([20.0, 120.0], Condition::Appearing);
|
||||
w.build(ui, || {
|
||||
w.build(|| {
|
||||
ui.text_wrapped(
|
||||
"Normal radio buttons accept a mutable reference to state, and the value \
|
||||
corresponding to this button. They are very flexible, because the value can be any \
|
||||
|
||||
@ -16,12 +16,13 @@ fn main() {
|
||||
}
|
||||
|
||||
fn example_selector(run: &mut bool, ui: &mut Ui, state: &mut State) {
|
||||
let w = Window::new("Slider examples")
|
||||
let w = ui
|
||||
.window("Slider examples")
|
||||
.opened(run)
|
||||
.position([20.0, 20.0], Condition::Appearing)
|
||||
.size([700.0, 80.0], Condition::Appearing)
|
||||
.resizable(false);
|
||||
w.build(ui, || {
|
||||
w.build(|| {
|
||||
let mut clicked = false;
|
||||
clicked |= ui.radio_button("Example 1: Basic sliders", &mut state.example, 1);
|
||||
clicked |= ui.radio_button("Example 2: Slider arrays", &mut state.example, 2);
|
||||
@ -32,10 +33,11 @@ fn example_selector(run: &mut bool, ui: &mut Ui, state: &mut State) {
|
||||
}
|
||||
|
||||
fn example_1(ui: &Ui, state: &mut State) {
|
||||
let w = Window::new("Example 1: Basic sliders")
|
||||
let w = ui
|
||||
.window("Example 1: Basic sliders")
|
||||
.size([700.0, 340.0], Condition::Appearing)
|
||||
.position([20.0, 120.0], Condition::Appearing);
|
||||
w.build(ui, || {
|
||||
w.build(|| {
|
||||
ui.text("All of the following data types are supported:");
|
||||
ui.text("Signed: i8 i16 i32 i64");
|
||||
ui.text("Unsigned: u8 u16 u32 u64");
|
||||
@ -67,10 +69,11 @@ fn example_1(ui: &Ui, state: &mut State) {
|
||||
}
|
||||
|
||||
fn example_2(ui: &Ui, state: &mut State) {
|
||||
let w = Window::new("Example 2: Slider arrays")
|
||||
let w = ui
|
||||
.window("Example 2: Slider arrays")
|
||||
.size([700.0, 260.0], Condition::Appearing)
|
||||
.position([20.0, 120.0], Condition::Appearing);
|
||||
w.build(ui, || {
|
||||
w.build(|| {
|
||||
ui.text("You can easily build a slider group from an array of values:");
|
||||
Slider::new("[u8; 4]", 0, u8::MAX).build_array(ui, &mut state.array);
|
||||
|
||||
|
||||
@ -29,9 +29,9 @@ fn main() {
|
||||
| TableFlags::NO_BORDERS_IN_BODY;
|
||||
|
||||
system.main_loop(move |_, ui| {
|
||||
Window::new("Input text callbacks")
|
||||
ui.window("Input text callbacks")
|
||||
.size([800.0, 400.0], Condition::FirstUseEver)
|
||||
.build(ui, || {
|
||||
.build(|| {
|
||||
if let Some(_t) = ui.begin_table("Basic-Table", 3) {
|
||||
// we must also call `next_row` here, because we declined
|
||||
// to set up header rows. If we set up header rows ourselves,
|
||||
|
||||
@ -286,15 +286,15 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) {
|
||||
ui.show_metrics_window(&mut state.show_app_metrics);
|
||||
}
|
||||
if state.show_app_style_editor {
|
||||
Window::new("Style Editor")
|
||||
ui.window("Style Editor")
|
||||
.opened(&mut state.show_app_style_editor)
|
||||
.build(ui, || ui.show_default_style_editor());
|
||||
.build(|| ui.show_default_style_editor());
|
||||
}
|
||||
if state.show_app_about {
|
||||
Window::new("About ImGui")
|
||||
ui.window("About ImGui")
|
||||
.always_auto_resize(true)
|
||||
.opened(&mut state.show_app_about)
|
||||
.build(ui, || {
|
||||
.build(|| {
|
||||
ui.text(format!("dear imgui, {}", imgui::dear_imgui_version()));
|
||||
ui.separator();
|
||||
ui.text("By Omar Cornut and all github contributors.");
|
||||
@ -317,7 +317,8 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) {
|
||||
show_app_log(ui, &mut state.app_log);
|
||||
}
|
||||
|
||||
let mut window = Window::new("ImGui Demo")
|
||||
let mut window = ui
|
||||
.window("ImGui Demo")
|
||||
.title_bar(!state.no_titlebar)
|
||||
.resizable(!state.no_resize)
|
||||
.movable(!state.no_move)
|
||||
@ -328,7 +329,7 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) {
|
||||
if !state.no_close {
|
||||
window = window.opened(opened)
|
||||
}
|
||||
window.build(ui, || {
|
||||
window.build(|| {
|
||||
ui.push_item_width(-140.0);
|
||||
ui.text(format!("dear imgui says hello. ({})", imgui::dear_imgui_version()));
|
||||
if let Some(menu_bar) = ui.begin_menu_bar() {
|
||||
@ -872,10 +873,10 @@ fn show_example_menu_file<'a>(ui: &Ui<'a>, state: &mut FileMenuState) {
|
||||
ui.separator();
|
||||
if let Some(menu) = ui.begin_menu("Options") {
|
||||
MenuItem::new("Enabled").build_with_ref(ui, &mut state.enabled);
|
||||
ChildWindow::new("child")
|
||||
ui.child_window("child")
|
||||
.size([0.0, 60.0])
|
||||
.border(true)
|
||||
.build(ui, || {
|
||||
.build(|| {
|
||||
for i in 0..10 {
|
||||
ui.text(format!("Scrolling Text {}", i));
|
||||
}
|
||||
@ -900,10 +901,10 @@ fn show_example_menu_file<'a>(ui: &Ui<'a>, state: &mut FileMenuState) {
|
||||
}
|
||||
|
||||
fn show_example_app_auto_resize(ui: &Ui, state: &mut AutoResizeState, opened: &mut bool) {
|
||||
Window::new("Example: Auto-resizing window")
|
||||
ui.window("Example: Auto-resizing window")
|
||||
.opened(opened)
|
||||
.always_auto_resize(true)
|
||||
.build(ui, || {
|
||||
.build(|| {
|
||||
ui.text(
|
||||
"Window will resize every-ui to the size of its content.
|
||||
Note that you probably don't want to query the window size to
|
||||
@ -920,7 +921,7 @@ fn show_example_app_fixed_overlay(ui: &Ui, opened: &mut bool) {
|
||||
const DISTANCE: f32 = 10.0;
|
||||
let window_pos = [DISTANCE, DISTANCE];
|
||||
let style = ui.push_style_color(StyleColor::WindowBg, [0.0, 0.0, 0.0, 0.3]);
|
||||
Window::new("Example: Fixed Overlay")
|
||||
ui.window("Example: Fixed Overlay")
|
||||
.opened(opened)
|
||||
.position(window_pos, Condition::Always)
|
||||
.title_bar(false)
|
||||
@ -928,7 +929,7 @@ fn show_example_app_fixed_overlay(ui: &Ui, opened: &mut bool) {
|
||||
.always_auto_resize(true)
|
||||
.movable(false)
|
||||
.save_settings(false)
|
||||
.build(ui, || {
|
||||
.build(|| {
|
||||
ui.text(
|
||||
"Simple overlay\nin the corner of the screen.\n(right-click to change position)",
|
||||
);
|
||||
@ -943,17 +944,17 @@ fn show_example_app_fixed_overlay(ui: &Ui, opened: &mut bool) {
|
||||
}
|
||||
|
||||
fn show_example_app_manipulating_window_title(ui: &Ui) {
|
||||
Window::new("Same title as another window##1")
|
||||
ui.window("Same title as another window##1")
|
||||
.position([100.0, 100.0], Condition::FirstUseEver)
|
||||
.build(ui, || {
|
||||
.build(|| {
|
||||
ui.text(
|
||||
"This is window 1.
|
||||
My title is the same as window 2, but my identifier is unique.",
|
||||
);
|
||||
});
|
||||
Window::new("Same title as another window##2")
|
||||
ui.window("Same title as another window##2")
|
||||
.position([100.0, 200.0], Condition::FirstUseEver)
|
||||
.build(ui, || {
|
||||
.build(|| {
|
||||
ui.text(
|
||||
"This is window 2.
|
||||
My title is the same as window 1, but my identifier is unique.",
|
||||
@ -963,16 +964,16 @@ My title is the same as window 1, but my identifier is unique.",
|
||||
let ch_idx = (ui.time() / 0.25) as usize & 3;
|
||||
let num = ui.frame_count(); // The C++ version uses rand() here
|
||||
let title = format!("Animated title {} {}###AnimatedTitle", chars[ch_idx], num);
|
||||
Window::new(title)
|
||||
ui.window(title)
|
||||
.position([100.0, 300.0], Condition::FirstUseEver)
|
||||
.build(ui, || ui.text("This window has a changing title"));
|
||||
.build(|| ui.text("This window has a changing title"));
|
||||
}
|
||||
|
||||
fn show_example_app_custom_rendering(ui: &Ui, state: &mut CustomRenderingState, opened: &mut bool) {
|
||||
Window::new("Example: Custom rendering")
|
||||
ui.window("Example: Custom rendering")
|
||||
.size([350.0, 560.0], Condition::FirstUseEver)
|
||||
.opened(opened)
|
||||
.build(ui, || {
|
||||
.build(|| {
|
||||
ui.text("Primitives");
|
||||
// TODO: Add DragFloat to change value of sz
|
||||
ColorEdit::new("Color", &mut state.col).build(ui);
|
||||
@ -1217,9 +1218,9 @@ fn show_example_app_custom_rendering(ui: &Ui, state: &mut CustomRenderingState,
|
||||
}
|
||||
|
||||
fn show_app_log(ui: &Ui, app_log: &mut Vec<String>) {
|
||||
Window::new("Example: Log")
|
||||
ui.window("Example: Log")
|
||||
.size([500.0, 400.0], Condition::FirstUseEver)
|
||||
.build(ui, || {
|
||||
.build(|| {
|
||||
if ui.small_button("[Debug] Add 5 entries") {
|
||||
let categories = ["info", "warn", "error"];
|
||||
let words = [
|
||||
@ -1251,9 +1252,9 @@ fn show_app_log(ui: &Ui, app_log: &mut Vec<String>) {
|
||||
ui.set_clipboard_text(&ImString::from(app_log.join("\n")));
|
||||
}
|
||||
ui.separator();
|
||||
ChildWindow::new("logwindow")
|
||||
ui.child_window("logwindow")
|
||||
.flags(WindowFlags::HORIZONTAL_SCROLLBAR)
|
||||
.build(ui, || {
|
||||
.build(|| {
|
||||
if !app_log.is_empty() {
|
||||
let mut clipper = ListClipper::new(app_log.len() as i32).begin(ui);
|
||||
while clipper.step() {
|
||||
|
||||
@ -7,9 +7,9 @@ fn main() {
|
||||
let mut buffers = vec![String::default(), String::default(), String::default()];
|
||||
|
||||
system.main_loop(move |_, ui| {
|
||||
Window::new("Input text callbacks")
|
||||
ui.window("Input text callbacks")
|
||||
.size([500.0, 300.0], Condition::FirstUseEver)
|
||||
.build(ui, || {
|
||||
.build(|| {
|
||||
ui.text("You can make a variety of buffer callbacks on an Input Text");
|
||||
ui.text(
|
||||
"or on an InputTextMultiline. In this example, we'll use \
|
||||
|
||||
@ -144,9 +144,9 @@ impl TexturesUi {
|
||||
}
|
||||
|
||||
fn show(&self, ui: &imgui::Ui) {
|
||||
imgui::Window::new("Hello textures")
|
||||
ui.window("Hello textures")
|
||||
.size([400.0, 400.0], Condition::FirstUseEver)
|
||||
.build(ui, || {
|
||||
.build(|| {
|
||||
ui.text("Hello textures!");
|
||||
ui.text("Some generated texture");
|
||||
imgui::Image::new(self.generated_texture, [100.0, 100.0]).build(ui);
|
||||
|
||||
@ -314,6 +314,52 @@ impl<'a> Default for Id<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// # Windows
|
||||
/// Start constructing a window.
|
||||
///
|
||||
/// This, like many objects in the library, uses the builder
|
||||
/// pattern to set optional arguments (like window size, flags,
|
||||
/// etc). Once all desired options are set, you must call either
|
||||
/// [`Window::build`] or [`Window::begin`] must be called to
|
||||
/// actually create the window.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Create a window using the closure based [`Window::build`]:
|
||||
/// ```no_run
|
||||
/// # let mut ctx = imgui::Context::create();
|
||||
/// # let ui = ctx.frame();
|
||||
/// ui.window("Example Window")
|
||||
/// .size([100.0, 50.0], imgui::Condition::FirstUseEver)
|
||||
/// .build(|| {
|
||||
/// ui.text("An example");
|
||||
/// });
|
||||
/// ```
|
||||
pub fn window<Label: AsRef<str>>(&'ui self, name: Label) -> Window<'ui, '_, Label> {
|
||||
Window::new(self, name)
|
||||
}
|
||||
|
||||
/// Same as [`Ui::window`] but using the "token based" `.begin()` approach.
|
||||
///
|
||||
/// ```
|
||||
/// fn example(ui: &imgui::Ui) {
|
||||
/// let wt = ui.window("Example Window")
|
||||
/// .size([100.0, 50.0], imgui::Condition::FirstUseEver)
|
||||
/// .begin();
|
||||
/// if wt.is_some() {
|
||||
/// ui.text("Window is visible");
|
||||
/// }
|
||||
/// // Window ends where where wt is dropped,
|
||||
/// // or you could call
|
||||
/// wt.unwrap().end()
|
||||
/// }
|
||||
/// ```
|
||||
pub fn child_window<Label: AsRef<str>>(&'ui self, name: Label) -> ChildWindow<'ui, Label> {
|
||||
ChildWindow::new(self, name)
|
||||
}
|
||||
}
|
||||
|
||||
// Widgets: Input
|
||||
impl<'ui> Ui<'ui> {
|
||||
#[doc(alias = "InputText", alias = "InputTextWithHint")]
|
||||
@ -724,15 +770,20 @@ impl<'ui> Ui<'ui> {
|
||||
pub enum Condition {
|
||||
/// Never apply the setting
|
||||
Never = -1,
|
||||
/// Always apply the setting
|
||||
|
||||
/// Apply the setting every frame
|
||||
Always = sys::ImGuiCond_Always as i8,
|
||||
/// Apply the setting once per runtime session (only the first call will succeed)
|
||||
|
||||
/// Apply the setting once per runtime session (only the first
|
||||
/// call will succeed). Will ignore any setting saved in `.ini`
|
||||
Once = sys::ImGuiCond_Once as i8,
|
||||
/// Apply the setting if the object/window has no persistently saved data (no entry in .ini
|
||||
/// file)
|
||||
|
||||
/// Apply the setting if the object/window has no persistently
|
||||
/// saved data (but otherwise use the setting from the .ini file)
|
||||
FirstUseEver = sys::ImGuiCond_FirstUseEver as i8,
|
||||
/// Apply the setting if the object/window is appearing after being hidden/inactive (or the
|
||||
/// first time)
|
||||
|
||||
/// Apply the setting if the object/window is appearing after
|
||||
/// being hidden/inactive (or the first time)
|
||||
Appearing = sys::ImGuiCond_Appearing as i8,
|
||||
}
|
||||
|
||||
|
||||
@ -331,9 +331,81 @@ impl IdStackToken<'_> {
|
||||
/// # ID stack
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Pushes an identifier to the ID stack.
|
||||
/// This can be called with an integer, a string, or a pointer.
|
||||
///
|
||||
/// Returns an `IdStackToken` that can be popped by calling `.end()`
|
||||
/// or by dropping manually.
|
||||
///
|
||||
/// # Examples
|
||||
/// Dear ImGui uses labels to uniquely identify widgets. For a good explaination, see this part of the [Dear ImGui FAQ][faq]
|
||||
///
|
||||
/// [faq]: https://github.com/ocornut/imgui/blob/v1.84.2/docs/FAQ.md#q-why-is-my-widget-not-reacting-when-i-click-on-it
|
||||
///
|
||||
/// In `imgui-rs` the same applies, we can manually specify labels with the `##` syntax:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # let mut imgui = imgui::Context::create();
|
||||
/// # let ui = imgui.frame();
|
||||
///
|
||||
/// ui.button("Click##button1");
|
||||
/// ui.button("Click##button2");
|
||||
/// ```
|
||||
///
|
||||
/// Here `Click` is the label used for both buttons, and everything after `##` is used as the identifier.
|
||||
///
|
||||
/// However when you either have many items (say, created in a loop), we can use our loop number as an item in the "ID stack":
|
||||
///
|
||||
/// ```no_run
|
||||
/// # let mut imgui = imgui::Context::create();
|
||||
/// # let ui = imgui.frame();
|
||||
///
|
||||
/// ui.window("Example").build(|| {
|
||||
/// // The window adds "Example" to the token stack.
|
||||
/// for num in 0..10 {
|
||||
/// // And now we add the loop number to the stack too,
|
||||
/// // to make our buttons unique within this window.
|
||||
/// let _id = ui.push_id(num);
|
||||
/// if ui.button("Click!") {
|
||||
/// println!("Button {} clicked", num);
|
||||
/// }
|
||||
/// }
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// We don't have to use numbers - strings also work:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # let mut imgui = imgui::Context::create();
|
||||
/// # let ui = imgui.frame();
|
||||
///
|
||||
/// fn callback1(ui: &imgui::Ui) {
|
||||
/// if ui.button("Click") {
|
||||
/// println!("First button clicked")
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn callback2(ui: &imgui::Ui) {
|
||||
/// if ui.button("Click") {
|
||||
/// println!("Second button clicked")
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// ui.window("Example")
|
||||
/// .build(||{
|
||||
/// {
|
||||
/// // Since we don't know what callback1 might do, we create
|
||||
/// // a unique ID stack by pushing (a hash of) "first" to the ID stack:
|
||||
/// let _id1 = ui.push_id("first");
|
||||
/// callback1(&ui);
|
||||
/// }
|
||||
/// {
|
||||
/// // Same for second callback. If we didn't do this, clicking the "Click" button
|
||||
/// // would trigger both println statements!
|
||||
/// let _id2 = ui.push_id("second");
|
||||
/// callback2(&ui);
|
||||
/// }
|
||||
/// });
|
||||
/// ```
|
||||
#[doc(alias = "PushId")]
|
||||
pub fn push_id<'a, I: Into<Id<'a>>>(&self, id: I) -> IdStackToken<'ui> {
|
||||
let id = id.into();
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
use std::f32;
|
||||
use std::os::raw::{c_char, c_void};
|
||||
|
||||
use crate::sys;
|
||||
use crate::window::WindowFlags;
|
||||
use crate::{Id, Ui};
|
||||
use crate::Ui;
|
||||
|
||||
/// Builder for a child window
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[must_use]
|
||||
pub struct ChildWindow<'a> {
|
||||
id: Id<'a>,
|
||||
pub struct ChildWindow<'ui, Label> {
|
||||
ui: &'ui Ui<'ui>,
|
||||
name: Label,
|
||||
flags: WindowFlags,
|
||||
size: [f32; 2],
|
||||
content_size: [f32; 2],
|
||||
@ -18,12 +18,13 @@ pub struct ChildWindow<'a> {
|
||||
border: bool,
|
||||
}
|
||||
|
||||
impl<'a> ChildWindow<'a> {
|
||||
impl<'ui, Label: AsRef<str>> ChildWindow<'ui, Label> {
|
||||
/// Creates a new child window builder with the given ID
|
||||
#[doc(alias = "BeginChildID")]
|
||||
pub fn new<T: Into<Id<'a>>>(id: T) -> ChildWindow<'a> {
|
||||
pub fn new(ui: &'ui Ui<'ui>, name: Label) -> ChildWindow<'ui, Label> {
|
||||
ChildWindow {
|
||||
id: id.into(),
|
||||
ui,
|
||||
name,
|
||||
flags: WindowFlags::empty(),
|
||||
size: [0.0, 0.0],
|
||||
content_size: [0.0, 0.0],
|
||||
@ -245,7 +246,7 @@ impl<'a> ChildWindow<'a> {
|
||||
/// rendered, the token must be ended by calling `.end()`.
|
||||
///
|
||||
/// Returns `None` if the window is not visible and no content should be rendered.
|
||||
pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option<ChildWindowToken<'ui>> {
|
||||
pub fn begin(self) -> Option<ChildWindowToken<'ui>> {
|
||||
if self.content_size[0] != 0.0 || self.content_size[1] != 0.0 {
|
||||
unsafe { sys::igSetNextWindowContentSize(self.content_size.into()) };
|
||||
}
|
||||
@ -255,22 +256,16 @@ impl<'a> ChildWindow<'a> {
|
||||
if self.bg_alpha.is_finite() {
|
||||
unsafe { sys::igSetNextWindowBgAlpha(self.bg_alpha) };
|
||||
}
|
||||
let id = unsafe {
|
||||
match self.id {
|
||||
Id::Int(i) => sys::igGetID_Ptr(i as *const c_void),
|
||||
Id::Ptr(p) => sys::igGetID_Ptr(p),
|
||||
Id::Str(s) => {
|
||||
let start = s.as_ptr() as *const c_char;
|
||||
let end = start.add(s.len());
|
||||
sys::igGetID_StrStr(start, end)
|
||||
}
|
||||
}
|
||||
};
|
||||
let should_render = unsafe {
|
||||
sys::igBeginChild_ID(id, self.size.into(), self.border, self.flags.bits() as i32)
|
||||
sys::igBeginChild_Str(
|
||||
self.ui.scratch_txt(self.name),
|
||||
self.size.into(),
|
||||
self.border,
|
||||
self.flags.bits() as i32,
|
||||
)
|
||||
};
|
||||
if should_render {
|
||||
Some(ChildWindowToken::new(ui))
|
||||
Some(ChildWindowToken::new(self.ui))
|
||||
} else {
|
||||
unsafe { sys::igEndChild() };
|
||||
None
|
||||
@ -281,8 +276,8 @@ impl<'a> ChildWindow<'a> {
|
||||
///
|
||||
/// Note: the closure is not called if no window content is visible (e.g. window is collapsed
|
||||
/// or fully clipped).
|
||||
pub fn build<T, F: FnOnce() -> T>(self, ui: &Ui<'_>, f: F) -> Option<T> {
|
||||
self.begin(ui).map(|_window| f())
|
||||
pub fn build<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
|
||||
self.begin().map(|_window| f())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -160,8 +160,9 @@ impl<'ui> Ui<'ui> {
|
||||
/// Builder for a window
|
||||
#[derive(Debug)]
|
||||
#[must_use]
|
||||
pub struct Window<'a, T> {
|
||||
name: T,
|
||||
pub struct Window<'ui, 'a, Label> {
|
||||
ui: &'ui Ui<'ui>,
|
||||
name: Label,
|
||||
opened: Option<&'a mut bool>,
|
||||
flags: WindowFlags,
|
||||
pos: [f32; 2],
|
||||
@ -177,10 +178,11 @@ pub struct Window<'a, T> {
|
||||
bg_alpha: f32,
|
||||
}
|
||||
|
||||
impl<'a, T: AsRef<str>> Window<'a, T> {
|
||||
/// Creates a new window builder with the given name
|
||||
pub fn new(name: T) -> Self {
|
||||
impl<'ui, 'a, Label: AsRef<str>> Window<'ui, 'a, Label> {
|
||||
/// Typically created via [`Ui::window`]
|
||||
pub fn new(ui: &'ui Ui<'ui>, name: Label) -> Self {
|
||||
Window {
|
||||
ui,
|
||||
name,
|
||||
opened: None,
|
||||
flags: WindowFlags::empty(),
|
||||
@ -487,7 +489,7 @@ impl<'a, T: AsRef<str>> Window<'a, T> {
|
||||
///
|
||||
/// Returns `None` if the window is not visible and no content should be rendered.
|
||||
#[must_use]
|
||||
pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option<WindowToken<'ui>> {
|
||||
pub fn begin(self) -> Option<WindowToken<'ui>> {
|
||||
if self.pos_cond != Condition::Never {
|
||||
unsafe {
|
||||
sys::igSetNextWindowPos(
|
||||
@ -525,7 +527,7 @@ impl<'a, T: AsRef<str>> Window<'a, T> {
|
||||
}
|
||||
let should_render = unsafe {
|
||||
sys::igBegin(
|
||||
ui.scratch_txt(self.name),
|
||||
self.ui.scratch_txt(self.name),
|
||||
self.opened
|
||||
.map(|x| x as *mut bool)
|
||||
.unwrap_or(ptr::null_mut()),
|
||||
@ -533,7 +535,7 @@ impl<'a, T: AsRef<str>> Window<'a, T> {
|
||||
)
|
||||
};
|
||||
if should_render {
|
||||
Some(WindowToken::new(ui))
|
||||
Some(WindowToken::new(self.ui))
|
||||
} else {
|
||||
unsafe { sys::igEnd() };
|
||||
None
|
||||
@ -542,10 +544,10 @@ impl<'a, T: AsRef<str>> Window<'a, T> {
|
||||
/// Creates a window and runs a closure to construct the contents.
|
||||
/// Returns the result of the closure, if it is called.
|
||||
///
|
||||
/// Note: the closure is not called if no window content is visible (e.g. window is collapsed
|
||||
/// or fully clipped).
|
||||
pub fn build<R, F: FnOnce() -> R>(self, ui: &Ui<'_>, f: F) -> Option<R> {
|
||||
self.begin(ui).map(|_window| f())
|
||||
/// Note: the closure is only called if the window content is
|
||||
/// visible (e.g. will not run if window is collapsed).
|
||||
pub fn build<R, F: FnOnce() -> R>(self, f: F) -> Option<R> {
|
||||
self.begin().map(|_window| f())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user