mirror of
https://github.com/eliasstepanik/imgui-rs.git
synced 2026-01-10 21:18:36 +00:00
1309 lines
48 KiB
Rust
1309 lines
48 KiB
Rust
use imgui::*;
|
|
|
|
mod support;
|
|
|
|
struct State {
|
|
show_app_main_menu_bar: bool,
|
|
show_app_console: bool,
|
|
show_app_log: bool,
|
|
show_app_layout: bool,
|
|
show_app_property_editor: bool,
|
|
show_app_long_text: bool,
|
|
show_app_auto_resize: bool,
|
|
show_app_constrained_resize: bool,
|
|
show_app_fixed_overlay: bool,
|
|
show_app_manipulating_window_title: bool,
|
|
show_app_custom_rendering: bool,
|
|
show_app_style_editor: bool,
|
|
show_app_metrics: bool,
|
|
show_app_about: bool,
|
|
no_titlebar: bool,
|
|
no_resize: bool,
|
|
no_move: bool,
|
|
no_scrollbar: bool,
|
|
no_collapse: bool,
|
|
no_menu: bool,
|
|
no_close: bool,
|
|
wrap_width: f32,
|
|
buf: String,
|
|
item: usize,
|
|
item2: usize,
|
|
item3: i32,
|
|
text: String,
|
|
text_with_hint: String,
|
|
text_multiline: String,
|
|
i0: i32,
|
|
u0: u64,
|
|
d0: f64,
|
|
f0: f32,
|
|
vec2f: [f32; 2],
|
|
vec3f: [f32; 3],
|
|
vec2i: [i32; 2],
|
|
vec3i: [i32; 3],
|
|
col1: [f32; 3],
|
|
col2: [f32; 4],
|
|
selected_fish: Option<usize>,
|
|
selected_fish2: Option<usize>,
|
|
auto_resize_state: AutoResizeState,
|
|
file_menu: FileMenuState,
|
|
radio_button: i32,
|
|
color_edit: ColorEditState,
|
|
custom_rendering: CustomRenderingState,
|
|
dont_ask_me_next_time: bool,
|
|
stacked_modals_item: usize,
|
|
stacked_modals_color: [f32; 4],
|
|
app_log: Vec<String>,
|
|
filter: imgui::TextFilter,
|
|
|
|
tabs: TabState,
|
|
}
|
|
|
|
impl Default for State {
|
|
fn default() -> Self {
|
|
let mut buf = String::with_capacity(32);
|
|
buf.push_str("日本語");
|
|
let mut text = String::with_capacity(128);
|
|
text.push_str("Hello, world!");
|
|
let text_with_hint = String::with_capacity(128);
|
|
let mut text_multiline = String::with_capacity(128);
|
|
text_multiline.push_str("Hello, world!\nMultiline");
|
|
State {
|
|
show_app_main_menu_bar: false,
|
|
show_app_console: false,
|
|
show_app_log: false,
|
|
show_app_layout: false,
|
|
show_app_property_editor: false,
|
|
show_app_long_text: false,
|
|
show_app_auto_resize: false,
|
|
show_app_fixed_overlay: false,
|
|
show_app_constrained_resize: false,
|
|
show_app_manipulating_window_title: false,
|
|
show_app_custom_rendering: false,
|
|
show_app_style_editor: false,
|
|
show_app_metrics: false,
|
|
show_app_about: false,
|
|
no_titlebar: false,
|
|
no_resize: false,
|
|
no_move: false,
|
|
no_scrollbar: false,
|
|
no_collapse: false,
|
|
no_menu: false,
|
|
no_close: false,
|
|
wrap_width: 200.0,
|
|
buf,
|
|
item: 0,
|
|
item2: 0,
|
|
item3: 0,
|
|
text,
|
|
text_with_hint,
|
|
text_multiline,
|
|
i0: 123,
|
|
u0: 1234,
|
|
f0: 0.001,
|
|
d0: 0.0001,
|
|
vec2f: [0.10, 0.20],
|
|
vec3f: [0.10, 0.20, 0.30],
|
|
vec2i: [10, 20],
|
|
vec3i: [10, 20, 30],
|
|
col1: [1.0, 0.0, 0.2],
|
|
col2: [0.4, 0.7, 0.0, 0.5],
|
|
selected_fish: None,
|
|
selected_fish2: None,
|
|
auto_resize_state: Default::default(),
|
|
file_menu: Default::default(),
|
|
radio_button: 0,
|
|
color_edit: ColorEditState::default(),
|
|
custom_rendering: Default::default(),
|
|
dont_ask_me_next_time: false,
|
|
stacked_modals_item: 0,
|
|
stacked_modals_color: [0.4, 0.7, 0.0, 0.5],
|
|
app_log: Vec::new(),
|
|
filter: TextFilter::new(String::from("Test")),
|
|
tabs: TabState::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
struct TabState {
|
|
// flags for the advanced tab example
|
|
reorderable: bool,
|
|
autoselect: bool,
|
|
listbutton: bool,
|
|
noclose_middlebutton: bool,
|
|
fitting_resizedown: bool,
|
|
fitting_scroll: bool,
|
|
|
|
// opened state for tab items
|
|
artichoke_tab: bool,
|
|
beetroot_tab: bool,
|
|
celery_tab: bool,
|
|
daikon_tab: bool,
|
|
}
|
|
|
|
impl Default for TabState {
|
|
fn default() -> Self {
|
|
Self {
|
|
reorderable: true,
|
|
autoselect: false,
|
|
listbutton: false,
|
|
noclose_middlebutton: false,
|
|
fitting_resizedown: true,
|
|
fitting_scroll: false,
|
|
|
|
artichoke_tab: true,
|
|
beetroot_tab: true,
|
|
celery_tab: true,
|
|
daikon_tab: true,
|
|
}
|
|
}
|
|
}
|
|
|
|
struct ColorEditState {
|
|
color: [f32; 4],
|
|
hdr: bool,
|
|
alpha_preview: bool,
|
|
alpha_half_preview: bool,
|
|
options_menu: bool,
|
|
alpha: bool,
|
|
alpha_bar: bool,
|
|
side_preview: bool,
|
|
ref_color: bool,
|
|
ref_color_v: [f32; 4],
|
|
}
|
|
|
|
impl Default for ColorEditState {
|
|
fn default() -> Self {
|
|
ColorEditState {
|
|
color: [114.0 / 255.0, 144.0 / 255.0, 154.0 / 255.0, 200.0 / 255.0],
|
|
hdr: false,
|
|
alpha_preview: true,
|
|
alpha_half_preview: false,
|
|
options_menu: true,
|
|
alpha: true,
|
|
alpha_bar: true,
|
|
side_preview: true,
|
|
ref_color: false,
|
|
ref_color_v: [1.0, 0.0, 1.0, 0.5],
|
|
}
|
|
}
|
|
}
|
|
|
|
struct FileMenuState {
|
|
enabled: bool,
|
|
f: f32,
|
|
n: usize,
|
|
b: bool,
|
|
}
|
|
|
|
impl Default for FileMenuState {
|
|
fn default() -> Self {
|
|
FileMenuState {
|
|
enabled: true,
|
|
f: 0.5,
|
|
n: 0,
|
|
b: true,
|
|
}
|
|
}
|
|
}
|
|
|
|
struct AutoResizeState {
|
|
lines: i32,
|
|
}
|
|
|
|
impl Default for AutoResizeState {
|
|
fn default() -> Self {
|
|
AutoResizeState { lines: 10 }
|
|
}
|
|
}
|
|
|
|
struct CustomRenderingState {
|
|
sz: f32,
|
|
col: [f32; 3],
|
|
points: Vec<[f32; 2]>,
|
|
adding_line: bool,
|
|
}
|
|
|
|
impl Default for CustomRenderingState {
|
|
fn default() -> Self {
|
|
CustomRenderingState {
|
|
sz: 36.0,
|
|
col: [1.0, 1.0, 0.4],
|
|
points: vec![],
|
|
adding_line: false,
|
|
}
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
let mut state = State::default();
|
|
|
|
support::simple_init(file!(), move |run, ui| {
|
|
show_test_window(ui, &mut state, run)
|
|
});
|
|
}
|
|
|
|
fn show_help_marker(ui: &Ui, desc: &str) {
|
|
ui.text_disabled("(?)");
|
|
if ui.is_item_hovered() {
|
|
ui.tooltip(|| {
|
|
ui.text(desc);
|
|
});
|
|
}
|
|
}
|
|
|
|
fn show_user_guide(ui: &Ui) {
|
|
ui.bullet_text("Double-click on title bar to collapse window.");
|
|
ui.bullet_text("Click and drag on lower right corner to resize window.");
|
|
ui.bullet_text("Click and drag on any empty space to move window.");
|
|
ui.bullet_text("Mouse Wheel to scroll.");
|
|
// TODO: check font_allow_user_scaling
|
|
ui.bullet_text("TAB/SHIFT+TAB to cycle through keyboard editable fields.");
|
|
ui.bullet_text("CTRL+Click on a slider or drag box to input text.");
|
|
ui.bullet_text(
|
|
"While editing text:
|
|
- Hold SHIFT or use mouse to select text
|
|
- CTRL+Left/Right to word jump
|
|
- CTRL+A or double-click to select all
|
|
- CTRL+X,CTRL+C,CTRL+V clipboard
|
|
- CTRL+Z,CTRL+Y undo/redo
|
|
- ESCAPE to revert
|
|
- You can apply arithmetic operators +,*,/ on numerical values.
|
|
Use +- to subtract.\n",
|
|
);
|
|
}
|
|
|
|
fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) {
|
|
if state.show_app_main_menu_bar {
|
|
show_example_app_main_menu_bar(ui, state)
|
|
}
|
|
if state.show_app_auto_resize {
|
|
show_example_app_auto_resize(
|
|
ui,
|
|
&mut state.auto_resize_state,
|
|
&mut state.show_app_auto_resize,
|
|
);
|
|
}
|
|
if state.show_app_fixed_overlay {
|
|
show_example_app_fixed_overlay(ui, &mut state.show_app_fixed_overlay);
|
|
}
|
|
if state.show_app_manipulating_window_title {
|
|
show_example_app_manipulating_window_title(ui);
|
|
}
|
|
if state.show_app_metrics {
|
|
ui.show_metrics_window(&mut state.show_app_metrics);
|
|
}
|
|
if state.show_app_style_editor {
|
|
ui.window("Style Editor")
|
|
.opened(&mut state.show_app_style_editor)
|
|
.build(|| ui.show_default_style_editor());
|
|
}
|
|
if state.show_app_about {
|
|
ui.window("About ImGui")
|
|
.always_auto_resize(true)
|
|
.opened(&mut state.show_app_about)
|
|
.build(|| {
|
|
ui.text(format!("dear imgui, {}", imgui::dear_imgui_version()));
|
|
ui.separator();
|
|
ui.text("By Omar Cornut and all github contributors.");
|
|
ui.text(
|
|
"ImGui is licensed under the MIT License, see LICENSE for more \
|
|
information.",
|
|
);
|
|
});
|
|
}
|
|
|
|
if state.show_app_custom_rendering {
|
|
show_example_app_custom_rendering(
|
|
ui,
|
|
&mut state.custom_rendering,
|
|
&mut state.show_app_custom_rendering,
|
|
);
|
|
}
|
|
|
|
if state.show_app_log {
|
|
show_app_log(ui, &mut state.app_log);
|
|
}
|
|
|
|
let mut window = ui
|
|
.window("ImGui Demo")
|
|
.title_bar(!state.no_titlebar)
|
|
.resizable(!state.no_resize)
|
|
.movable(!state.no_move)
|
|
.scroll_bar(!state.no_scrollbar)
|
|
.collapsible(!state.no_collapse)
|
|
.menu_bar(!state.no_menu)
|
|
.size([550.0, 680.0], Condition::FirstUseEver);
|
|
if !state.no_close {
|
|
window = window.opened(opened)
|
|
}
|
|
window.build(|| {
|
|
let _w = 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() {
|
|
if let Some(menu) = ui.begin_menu("Menu") {
|
|
show_example_menu_file(ui, &mut state.file_menu);
|
|
menu.end();
|
|
}
|
|
if let Some(_t) = ui.begin_menu("Examples") {
|
|
ui.menu_item_config("Main menu bar").build_with_ref(&mut state.show_app_main_menu_bar);
|
|
ui.menu_item_config("Console").build_with_ref(&mut state.show_app_console);
|
|
ui.menu_item_config("Log").build_with_ref(&mut state.show_app_log);
|
|
ui.menu_item_config("Simple layout").build_with_ref(&mut state.show_app_layout);
|
|
ui.menu_item_config("Property editor").build_with_ref(&mut state.show_app_property_editor);
|
|
ui.menu_item_config("Long text display").build_with_ref(&mut state.show_app_long_text);
|
|
ui.menu_item_config("Auto-resizing window").build_with_ref(&mut state.show_app_auto_resize);
|
|
ui.menu_item_config("Constrained-resizing window").build_with_ref(&mut state.show_app_constrained_resize);
|
|
ui.menu_item_config("Simple overlay").build_with_ref(&mut state.show_app_fixed_overlay);
|
|
ui.menu_item_config("Manipulating window title").build_with_ref(&mut state.show_app_manipulating_window_title);
|
|
ui.menu_item_config("Custom Rendering").build_with_ref(&mut state.show_app_custom_rendering);
|
|
}
|
|
if let Some(_menu) = ui.begin_menu("Help") {
|
|
ui.menu_item_config("Metrics").build_with_ref(&mut state.show_app_metrics);
|
|
ui.menu_item_config("Style Editor").build_with_ref(&mut state.show_app_style_editor);
|
|
ui.menu_item_config("About ImGui").build_with_ref(&mut state.show_app_about);
|
|
}
|
|
}
|
|
ui.spacing();
|
|
if CollapsingHeader::new("Help").build(ui) {
|
|
ui.text_wrapped(
|
|
"This window is being created by the show_test_window() \
|
|
function. Please refer to the code for programming \
|
|
reference.\n\nUser Guide:"
|
|
);
|
|
show_user_guide(ui);
|
|
}
|
|
|
|
if CollapsingHeader::new("Window options").build(ui) {
|
|
ui.checkbox("No titlebar", &mut state.no_titlebar);
|
|
ui.same_line_with_pos(150.0);
|
|
ui.checkbox("No scrollbar", &mut state.no_scrollbar);
|
|
ui.same_line_with_pos(300.0);
|
|
ui.checkbox("No menu", &mut state.no_menu);
|
|
ui.checkbox("No move", &mut state.no_move);
|
|
ui.same_line_with_pos(150.0);
|
|
ui.checkbox("No resize", &mut state.no_resize);
|
|
ui.same_line_with_pos(300.0);
|
|
ui.checkbox("No collapse", &mut state.no_collapse);
|
|
ui.checkbox("No close", &mut state.no_close);
|
|
|
|
if let Some(_t) = ui.tree_node("Style") {
|
|
ui.show_default_style_editor();
|
|
}
|
|
}
|
|
if CollapsingHeader::new("Widgets").build(ui) {
|
|
if let Some(_t) = ui.tree_node("Tree") {
|
|
let num_child = 4;
|
|
for i in 0..num_child {
|
|
if let Some(_t) = ui.tree_node(format!("Child {}", i)) {
|
|
ui.text("blah blah");
|
|
ui.same_line();
|
|
if ui.small_button("print") {
|
|
println!("Child {} pressed", i);
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
let tree_node_stack = ui.tree_node_config("##HideTreeNodeLabel")
|
|
.allow_item_overlap(true)
|
|
.push();
|
|
ui.same_line();
|
|
if ui.small_button(format!("Child {} is a button", num_child)) {
|
|
println!("TreeNode Button pressed.");
|
|
}
|
|
|
|
if tree_node_stack.is_some() {
|
|
ui.text("blah blah")
|
|
}
|
|
}
|
|
}
|
|
|
|
if let Some(_t) = ui.tree_node("Bullets") {
|
|
ui.bullet_text("Bullet point 1");
|
|
ui.bullet_text("Bullet point 2\nOn multiple lines");
|
|
ui.bullet();
|
|
ui.text("Bullet point 3 (two calls)");
|
|
|
|
ui.bullet();
|
|
ui.small_button("Button");
|
|
}
|
|
|
|
if let Some(_t) = ui.tree_node("Colored text") {
|
|
ui.text_colored([1.0, 0.0, 1.0, 1.0], "Pink");
|
|
ui.text_colored([1.0, 1.0, 0.0, 1.0], "Yellow");
|
|
ui.text_disabled("Disabled");
|
|
}
|
|
|
|
if let Some(_t) = ui.tree_node("Multi-line text") {
|
|
ui.input_text_multiline(
|
|
"multiline",
|
|
&mut state.text_multiline,
|
|
[300., 100.],
|
|
).build();
|
|
}
|
|
|
|
if let Some(_t) = ui.tree_node("Word wrapping") {
|
|
ui.text_wrapped(
|
|
"This text should automatically wrap on the edge of \
|
|
the window.The current implementation for text \
|
|
wrapping follows simple rules suitable for English \
|
|
and possibly other languages."
|
|
);
|
|
ui.spacing();
|
|
|
|
ui.slider_config("Wrap width", -20.0, 600.0)
|
|
.display_format("%.0f")
|
|
.build(&mut state.wrap_width);
|
|
|
|
ui.text("Test paragraph 1:");
|
|
// TODO
|
|
|
|
ui.text("Test paragraph 2:");
|
|
// TODO
|
|
}
|
|
|
|
if let Some(_t) = ui.tree_node("UTF-8 Text") {
|
|
ui.text_wrapped(
|
|
"CJK text will only appear if the font was loaded \
|
|
with theappropriate CJK character ranges. Call \
|
|
io.Font->LoadFromFileTTF()manually to load extra \
|
|
character ranges."
|
|
);
|
|
|
|
ui.text("Hiragana: かきくけこ (kakikukeko)");
|
|
ui.text("Kanjis: 日本語 (nihongo)");
|
|
ui.input_text("UTF-8 input", &mut state.buf)
|
|
.build();
|
|
}
|
|
|
|
ui.radio_button("radio a", &mut state.radio_button, 0);
|
|
ui.same_line();
|
|
ui.radio_button("radio b", &mut state.radio_button, 1);
|
|
ui.same_line();
|
|
ui.radio_button("radio c", &mut state.radio_button, 2);
|
|
|
|
ui.separator();
|
|
ui.label_text("label", "Value");
|
|
ui.combo_simple_string("combo",
|
|
&mut state.item,
|
|
&[
|
|
"aaaa",
|
|
"bbbb",
|
|
"cccc",
|
|
"dddd",
|
|
"eeee",
|
|
]);
|
|
let items = [
|
|
"AAAA",
|
|
"BBBB",
|
|
"CCCC",
|
|
"DDDD",
|
|
"EEEE",
|
|
"FFFF",
|
|
"GGGG",
|
|
"HHHH",
|
|
"IIII",
|
|
"JJJJ",
|
|
"KKKK",
|
|
];
|
|
ui.combo_simple_string("combo scroll", &mut state.item2, &items);
|
|
ui.list_box("list", &mut state.item3, &items, 8);
|
|
|
|
|
|
let names = [
|
|
"Bream",
|
|
"Haddock",
|
|
"Mackerel",
|
|
"Pollock",
|
|
"Tilefish",
|
|
];
|
|
|
|
ListBox::new("selectables list").build(ui, || {
|
|
for (index, name) in names.iter().enumerate() {
|
|
let selected = matches!(state.selected_fish2, Some(i) if i == index );
|
|
if ui.selectable_config(name).selected(selected).build() {
|
|
state.selected_fish2 = Some(index);
|
|
}
|
|
}
|
|
});
|
|
|
|
let last_size = ui.item_rect_size();
|
|
ListBox::new("selectable list 2").size([0.0, last_size[1] * 0.66]).build(ui, || {
|
|
for (index, name) in names.iter().enumerate() {
|
|
let selected = matches!(state.selected_fish2, Some(i) if i == index );
|
|
if ui.selectable_config(name).selected(selected).build() {
|
|
state.selected_fish2 = Some(index);
|
|
}
|
|
}
|
|
});
|
|
|
|
ui.input_text("input text", &mut state.text)
|
|
.build();
|
|
ui.input_text("input text with hint", &mut state.text_with_hint)
|
|
.hint("enter text here")
|
|
.build();
|
|
ui.input_int("input int", &mut state.i0).build();
|
|
// Drag::new("drag int").build(ui, &mut state.i0);
|
|
ui.input_float("input float", &mut state.f0)
|
|
.step(0.01)
|
|
.step_fast(1.0)
|
|
.build();
|
|
Drag::new("drag float").range(-1.0, 1.0).speed(0.001).build(ui, &mut state.f0);
|
|
ui.input_float3("input float3", &mut state.vec3f)
|
|
.build();
|
|
|
|
ui.color_edit3("color 1", &mut state.col1);
|
|
ui.color_edit4("color 2", &mut state.col2);
|
|
|
|
ui.input_scalar("input scalar i64", &mut state.u0).build();
|
|
ui.input_scalar("input scalar f64", &mut state.d0).build();
|
|
ui.input_scalar_n("input scalar int array", &mut state.vec3i).build();
|
|
ui.input_scalar_n("input scalar float array", &mut state.vec3f).build();
|
|
|
|
if let Some(_t) = ui.tree_node("Multi-component Widgets") {
|
|
ui.input_float2("input float2", &mut state.vec2f)
|
|
.build();
|
|
ui.input_int2("input int2", &mut state.vec2i)
|
|
.build();
|
|
ui.spacing();
|
|
|
|
ui.input_float3("input float3", &mut state.vec3f)
|
|
.build();
|
|
ui.input_int3("input int3", &mut state.vec3i)
|
|
.build();
|
|
ui.spacing();
|
|
};
|
|
|
|
if let Some(_t) = ui.tree_node("Color/Picker Widgets") {
|
|
let s = &mut state.color_edit;
|
|
ui.checkbox("With HDR", &mut s.hdr);
|
|
ui.same_line();
|
|
show_help_marker(
|
|
ui,
|
|
"Currently all this does is to lift the 0..1 \
|
|
limits on dragging widgets.",
|
|
);
|
|
|
|
ui.checkbox("With Alpha Preview", &mut s.alpha_preview);
|
|
ui.checkbox(
|
|
"With Half Alpha Preview",
|
|
&mut s.alpha_half_preview,
|
|
);
|
|
ui.checkbox("With Options Menu", &mut s.options_menu);
|
|
ui.same_line();
|
|
show_help_marker(
|
|
ui,
|
|
"Right-click on the individual color widget to \
|
|
show options.",
|
|
);
|
|
let misc_flags = {
|
|
let mut f = ColorEditFlags::empty();
|
|
f.set(ColorEditFlags::HDR, s.hdr);
|
|
f.set(ColorEditFlags::ALPHA_PREVIEW_HALF, s.alpha_half_preview);
|
|
if !s.alpha_half_preview {
|
|
f.set(ColorEditFlags::ALPHA_PREVIEW, s.alpha_preview);
|
|
}
|
|
f.set(ColorEditFlags::NO_OPTIONS, !s.options_menu);
|
|
f
|
|
};
|
|
|
|
ui.text("Color widget:");
|
|
ui.same_line();
|
|
show_help_marker(
|
|
ui,
|
|
"Click on the colored square to open a color picker.
|
|
CTRL+click on individual component to input value.\n",
|
|
);
|
|
ui.color_edit4_config("MyColor##1", &mut s.color)
|
|
.flags(misc_flags)
|
|
.alpha(false)
|
|
.build();
|
|
|
|
ui.text("Color widget HSV with Alpha:");
|
|
ui.color_edit4_config("MyColor##2", &mut s.color)
|
|
.flags(misc_flags)
|
|
.input_mode(ColorEditInputMode::HSV)
|
|
.build();
|
|
|
|
ui.text("Color widget with Float Display:");
|
|
ui.color_edit4_config("MyColor##2f", &mut s.color)
|
|
.flags(misc_flags)
|
|
.format(ColorFormat::Float)
|
|
.build();
|
|
|
|
ui.text("Color button with Picker:");
|
|
ui.same_line();
|
|
show_help_marker(
|
|
ui,
|
|
"With the inputs(false) function you can hide all \
|
|
the slider/text inputs.\n \
|
|
With the label(false) function you can pass a non-empty label which \
|
|
will only be used for the tooltip and picker popup.",
|
|
);
|
|
ui.color_edit4_config("MyColor##3", &mut s.color)
|
|
.flags(misc_flags)
|
|
.inputs(false)
|
|
.label(false)
|
|
.build();
|
|
|
|
ui.text("Color picker:");
|
|
ui.checkbox("With Alpha", &mut s.alpha);
|
|
ui.checkbox("With Alpha Bar", &mut s.alpha_bar);
|
|
ui.checkbox("With Side Preview", &mut s.side_preview);
|
|
if s.side_preview {
|
|
ui.same_line();
|
|
ui.checkbox("With Ref Color", &mut s.ref_color);
|
|
if s.ref_color {
|
|
ui.same_line();
|
|
ui.color_edit4_config("##RefColor", &mut s.ref_color_v)
|
|
.flags(misc_flags)
|
|
.inputs(false)
|
|
.build();
|
|
}
|
|
}
|
|
let mut b = ui.color_picker4_config
|
|
("MyColor##4", &mut s.color)
|
|
.flags(misc_flags)
|
|
.alpha(s.alpha)
|
|
.alpha_bar(s.alpha_bar)
|
|
.side_preview(s.side_preview)
|
|
.display_rgb(true);
|
|
|
|
if s.ref_color {
|
|
b = b.reference_color(s.ref_color_v)
|
|
}
|
|
b.build();
|
|
}
|
|
}
|
|
|
|
if CollapsingHeader::new("Layout").build(ui) {
|
|
if let Some(_t) = ui.tree_node("Tabs") {
|
|
if let Some(_t) = ui.tree_node("Basic") {
|
|
TabBar::new("basictabbar").build(ui, || {
|
|
TabItem::new("Avocado").build(ui, || {
|
|
ui.text("This is the Avocado tab!");
|
|
ui.text("blah blah blah blah blah");
|
|
});
|
|
TabItem::new("Broccoli").build(ui, || {
|
|
ui.text("This is the Broccoli tab!");
|
|
ui.text("blah blah blah blah blah");
|
|
});
|
|
TabItem::new("Cucumber").build(ui, || {
|
|
ui.text("This is the Cucumber tab!");
|
|
ui.text("blah blah blah blah blah");
|
|
});
|
|
});
|
|
}
|
|
|
|
if let Some(_t) = ui.tree_node("Advanced & Close button") {
|
|
|
|
ui.separator();
|
|
let s = &mut state.tabs;
|
|
|
|
ui.checkbox("ImGuiTabBarFlags_Reorderable", &mut s.reorderable);
|
|
ui.checkbox("ImGuiTabBarFlags_AutoSelectNewTabs", &mut s.autoselect);
|
|
ui.checkbox("ImGuiTabBarFlags_TabListPopupButton", &mut s.listbutton);
|
|
ui.checkbox("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &mut s.noclose_middlebutton);
|
|
if ui.checkbox("ImGuiTabBarFlags_FittingPolicyResizeDown", &mut s.fitting_resizedown) {
|
|
s.fitting_scroll = !s.fitting_resizedown;
|
|
}
|
|
if ui.checkbox("ImGuiTabBarFlags_FittingPolicyScroll", &mut s.fitting_scroll) {
|
|
s.fitting_resizedown = !s.fitting_scroll;
|
|
}
|
|
let style = ui.push_style_var(StyleVar::FramePadding([0.0, 0.0]));
|
|
ui.checkbox("Artichoke", &mut s.artichoke_tab);
|
|
ui.same_line();
|
|
ui.checkbox("Beetroot", &mut s.beetroot_tab);
|
|
ui.same_line();
|
|
ui.checkbox("Celery", &mut s.celery_tab);
|
|
ui.same_line();
|
|
ui.checkbox("Daikon", &mut s.daikon_tab);
|
|
style.pop();
|
|
|
|
let flags = {
|
|
let mut f = TabBarFlags::empty();
|
|
f.set(TabBarFlags::REORDERABLE, s.reorderable);
|
|
f.set(TabBarFlags::AUTO_SELECT_NEW_TABS, s.autoselect);
|
|
f.set(TabBarFlags::TAB_LIST_POPUP_BUTTON, s.listbutton);
|
|
f.set(TabBarFlags::NO_CLOSE_WITH_MIDDLE_MOUSE_BUTTON, s.noclose_middlebutton);
|
|
f.set(TabBarFlags::FITTING_POLICY_RESIZE_DOWN, s.fitting_resizedown);
|
|
f.set(TabBarFlags::FITTING_POLICY_SCROLL, s.fitting_scroll);
|
|
f
|
|
};
|
|
|
|
TabBar::new("tabbar").flags(flags).build(ui, || {
|
|
TabItem::new("Artichoke").opened(&mut s.artichoke_tab).build(ui, || {
|
|
ui.text("This is the Artichoke tab!");
|
|
});
|
|
TabItem::new("Beetroot").opened(&mut s.beetroot_tab).build(ui, || {
|
|
ui.text("This is the Beetroot tab!");
|
|
});
|
|
TabItem::new("Celery").opened(&mut s.celery_tab).build(ui, || {
|
|
ui.text("This is the Celery tab!");
|
|
});
|
|
TabItem::new("Daikon").opened(&mut s.daikon_tab).build(ui, || {
|
|
ui.text("This is the Daikon tab!");
|
|
});
|
|
});
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if CollapsingHeader::new("Filtering").build(ui) {
|
|
ui.text_wrapped(
|
|
"Filter usage:\n\
|
|
\"\" display all lines\n\
|
|
\"xxx\" display lines containing \"xxx\"\n\
|
|
\"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n\
|
|
\"-xxx\" hide lines containing \"xxx\""
|
|
);
|
|
|
|
state.filter.draw();
|
|
let lines = ["aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world!"];
|
|
|
|
ui.same_line();
|
|
if ui.button("Clear##clear_filter") {
|
|
state.filter.clear();
|
|
}
|
|
|
|
for i in lines.iter() {
|
|
if state.filter.pass_filter(i) {
|
|
ui.bullet_text(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
if CollapsingHeader::new("Popups & Modal windows").build(ui) {
|
|
if let Some(_t) = ui.tree_node("Popups") {
|
|
ui.text_wrapped(
|
|
"When a popup is active, it inhibits interacting \
|
|
with windows that are behind the popup. Clicking \
|
|
outside the popup closes it."
|
|
);
|
|
let names = [
|
|
"Bream",
|
|
"Haddock",
|
|
"Mackerel",
|
|
"Pollock",
|
|
"Tilefish",
|
|
];
|
|
if ui.small_button("Select..") {
|
|
ui.open_popup("select");
|
|
}
|
|
ui.same_line();
|
|
ui.text(match state.selected_fish {
|
|
Some(index) => names[index],
|
|
None => "<None>",
|
|
});
|
|
ui.popup("select", || {
|
|
ui.text("Aquarium");
|
|
ui.separator();
|
|
for (index, name) in names.iter().enumerate() {
|
|
if ui.selectable(name) {
|
|
state.selected_fish = Some(index);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
if let Some(_t) = ui.tree_node("Modals") {
|
|
ui.text_wrapped(
|
|
"Modal windows are like popups but the user cannot close \
|
|
them by clicking outside the window."
|
|
);
|
|
|
|
if ui.button("Delete..") {
|
|
ui.open_popup("Delete?");
|
|
}
|
|
ui.modal_popup_config("Delete?").always_auto_resize(true).build(|| {
|
|
ui.text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n");
|
|
ui.separator();
|
|
let style = ui.push_style_var(StyleVar::FramePadding([0.0, 0.0]));
|
|
ui.checkbox("Don't ask me next time", &mut state.dont_ask_me_next_time);
|
|
|
|
if ui.button_with_size("OK", [120.0, 0.0]) {
|
|
ui.close_current_popup();
|
|
}
|
|
ui.same_line();
|
|
if ui.button_with_size("Cancel", [120.0, 0.0]) {
|
|
ui.close_current_popup();
|
|
}
|
|
style.pop();
|
|
});
|
|
|
|
if ui.button("Stacked modals..") {
|
|
ui.open_popup("Stacked 1");
|
|
}
|
|
ui.modal_popup_config("Stacked 1").build(|| {
|
|
ui.text(
|
|
"Hello from Stacked The First\n\
|
|
Using style[StyleColor::ModalWindowDarkening] for darkening."
|
|
);
|
|
|
|
let items = &["aaaa", "bbbb", "cccc", "dddd", "eeee"];
|
|
ui.combo_simple_string("Combo", &mut state.stacked_modals_item, items);
|
|
|
|
ui.color_edit4_config("color", &mut state.stacked_modals_color).build();
|
|
|
|
if ui.button("Add another modal..") {
|
|
ui.open_popup("Stacked 2") ;
|
|
}
|
|
ui.modal_popup_config("Stacked 2").build(|| {
|
|
ui.text("Hello from Stacked The Second");
|
|
if ui.button("Close") {
|
|
ui.close_current_popup();
|
|
}
|
|
});
|
|
|
|
if ui.button("Close") {
|
|
ui.close_current_popup();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
fn show_example_app_main_menu_bar(ui: &Ui, state: &mut State) {
|
|
if let Some(menu_bar) = ui.begin_main_menu_bar() {
|
|
if let Some(menu) = ui.begin_menu("File") {
|
|
show_example_menu_file(ui, &mut state.file_menu);
|
|
menu.end();
|
|
}
|
|
if let Some(menu) = ui.begin_menu("Edit") {
|
|
ui.menu_item_config("Undo").shortcut("CTRL+Z").build();
|
|
ui.menu_item_config("Redo")
|
|
.shortcut("CTRL+Y")
|
|
.enabled(false)
|
|
.build();
|
|
ui.separator();
|
|
ui.menu_item_config("Cut").shortcut("CTRL+X").build();
|
|
ui.menu_item_config("Copy").shortcut("CTRL+C").build();
|
|
ui.menu_item_config("Paste").shortcut("CTRL+V").build();
|
|
menu.end();
|
|
}
|
|
menu_bar.end();
|
|
}
|
|
}
|
|
|
|
fn show_example_menu_file(ui: &Ui, state: &mut FileMenuState) {
|
|
ui.menu_item_config("(dummy_menu)").enabled(false).build();
|
|
ui.menu_item("New");
|
|
ui.menu_item_config("Open").shortcut("Ctrl+O").build();
|
|
if let Some(_menu) = ui.begin_menu("Open Recent") {
|
|
ui.menu_item("fish_hat.c");
|
|
ui.menu_item("fish_hat.inl");
|
|
ui.menu_item("fish_hat.h");
|
|
if let Some(menu) = ui.begin_menu("More..") {
|
|
ui.menu_item("Hello");
|
|
ui.menu_item("Sailor");
|
|
|
|
if let Some(_menu) = ui.begin_menu("Recurse..") {
|
|
show_example_menu_file(ui, state);
|
|
menu.end();
|
|
}
|
|
}
|
|
}
|
|
ui.menu_item_config("Save").shortcut("Ctrl+S").build();
|
|
ui.menu_item("Save As..");
|
|
ui.separator();
|
|
if let Some(_menu) = ui.begin_menu("Options") {
|
|
ui.menu_item_config("Enabled")
|
|
.build_with_ref(&mut state.enabled);
|
|
|
|
ui.child_window("child")
|
|
.size([0.0, 60.0])
|
|
.border(true)
|
|
.build(|| {
|
|
for i in 0..10 {
|
|
ui.text(format!("Scrolling Text {}", i));
|
|
}
|
|
});
|
|
ui.slider("Value", 0.0, 1.0, &mut state.f);
|
|
|
|
ui.input_float("Input", &mut state.f).step(0.1).build();
|
|
let items = ["Yes", "No", "Maybe"];
|
|
ui.combo_simple_string("Combo", &mut state.n, &items);
|
|
ui.checkbox("Check", &mut state.b);
|
|
}
|
|
if let Some(_menu) = ui.begin_menu("Colors") {
|
|
for &col in StyleColor::VARIANTS.iter() {
|
|
ui.menu_item(format!("{:?}", col));
|
|
}
|
|
}
|
|
assert!(ui.begin_menu_with_enabled("Disabled", false).is_none());
|
|
ui.menu_item_config("Checked").selected(true).build();
|
|
ui.menu_item_config("Quit").shortcut("Alt+F4").build();
|
|
}
|
|
|
|
fn show_example_app_auto_resize(ui: &Ui, state: &mut AutoResizeState, opened: &mut bool) {
|
|
ui.window("Example: Auto-resizing window")
|
|
.opened(opened)
|
|
.always_auto_resize(true)
|
|
.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
|
|
output your content because that would create a feedback loop.",
|
|
);
|
|
ui.slider("Number of lines", 1, 20, &mut state.lines);
|
|
for i in 0..state.lines {
|
|
ui.text(format!("{:2$}This is line {}", "", i, i as usize * 4));
|
|
}
|
|
});
|
|
}
|
|
|
|
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]);
|
|
ui.window("Example: Fixed Overlay")
|
|
.opened(opened)
|
|
.position(window_pos, Condition::Always)
|
|
.title_bar(false)
|
|
.resizable(false)
|
|
.always_auto_resize(true)
|
|
.movable(false)
|
|
.save_settings(false)
|
|
.build(|| {
|
|
ui.text(
|
|
"Simple overlay\nin the corner of the screen.\n(right-click to change position)",
|
|
);
|
|
ui.separator();
|
|
let mouse_pos = ui.io().mouse_pos;
|
|
ui.text(format!(
|
|
"Mouse Position: ({:.1},{:.1})",
|
|
mouse_pos[0], mouse_pos[1]
|
|
));
|
|
});
|
|
style.pop();
|
|
}
|
|
|
|
fn show_example_app_manipulating_window_title(ui: &Ui) {
|
|
ui.window("Same title as another window##1")
|
|
.position([100.0, 100.0], Condition::FirstUseEver)
|
|
.build(|| {
|
|
ui.text(
|
|
"This is window 1.
|
|
My title is the same as window 2, but my identifier is unique.",
|
|
);
|
|
});
|
|
ui.window("Same title as another window##2")
|
|
.position([100.0, 200.0], Condition::FirstUseEver)
|
|
.build(|| {
|
|
ui.text(
|
|
"This is window 2.
|
|
My title is the same as window 1, but my identifier is unique.",
|
|
);
|
|
});
|
|
let chars = ['|', '/', '-', '\\'];
|
|
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);
|
|
ui.window(title)
|
|
.position([100.0, 300.0], Condition::FirstUseEver)
|
|
.build(|| ui.text("This window has a changing title"));
|
|
}
|
|
|
|
fn show_example_app_custom_rendering(ui: &Ui, state: &mut CustomRenderingState, opened: &mut bool) {
|
|
ui.window("Example: Custom rendering")
|
|
.size([350.0, 560.0], Condition::FirstUseEver)
|
|
.opened(opened)
|
|
.build(|| {
|
|
ui.text("Primitives");
|
|
// TODO: Add DragFloat to change value of sz
|
|
ui.color_edit3("Color", &mut state.col);
|
|
let draw_list = ui.get_window_draw_list();
|
|
let p = ui.cursor_screen_pos();
|
|
let spacing = 8.0;
|
|
let mut y = p[1] + 4.0;
|
|
for n in 0..2 {
|
|
let mut x = p[0] + 4.0;
|
|
let thickness = if n == 0 { 1.0 } else { 4.0 };
|
|
draw_list
|
|
.add_circle(
|
|
[x + state.sz * 0.5, y + state.sz * 0.5],
|
|
state.sz * 0.5,
|
|
state.col,
|
|
)
|
|
.num_segments(20)
|
|
.thickness(thickness)
|
|
.build();
|
|
x += state.sz + spacing;
|
|
draw_list
|
|
.add_rect([x, y], [x + state.sz, y + state.sz], state.col)
|
|
.thickness(thickness)
|
|
.build();
|
|
x += state.sz + spacing;
|
|
draw_list
|
|
.add_rect([x, y], [x + state.sz, y + state.sz], state.col)
|
|
.thickness(thickness)
|
|
.rounding(10.0)
|
|
.build();
|
|
x += state.sz + spacing;
|
|
draw_list
|
|
.add_rect([x, y], [x + state.sz, y + state.sz], state.col)
|
|
.thickness(thickness)
|
|
.rounding(10.0)
|
|
.round_top_right(false)
|
|
.round_bot_left(false)
|
|
.build();
|
|
x += state.sz + spacing;
|
|
draw_list
|
|
.add_triangle(
|
|
[x + state.sz * 0.5, y],
|
|
[x + state.sz, y + state.sz - 0.5],
|
|
[x, y + state.sz - 0.5],
|
|
state.col,
|
|
)
|
|
.thickness(thickness)
|
|
.build();
|
|
x += state.sz + spacing;
|
|
draw_list
|
|
.add_line([x, y], [x + state.sz, y], state.col)
|
|
.thickness(thickness)
|
|
.build();
|
|
x += state.sz + spacing;
|
|
draw_list
|
|
.add_line([x, y], [x + state.sz, y + state.sz], state.col)
|
|
.thickness(thickness)
|
|
.build();
|
|
x += state.sz + spacing;
|
|
draw_list
|
|
.add_line([x, y], [x, y + state.sz], state.col)
|
|
.thickness(thickness)
|
|
.build();
|
|
x += spacing;
|
|
draw_list
|
|
.add_bezier_curve(
|
|
[x, y],
|
|
[x + state.sz * 1.3, y + state.sz * 0.3],
|
|
[x + state.sz - state.sz * 1.3, y + state.sz - state.sz * 0.3],
|
|
[x + state.sz, y + state.sz],
|
|
state.col,
|
|
)
|
|
.thickness(thickness)
|
|
.build();
|
|
y += state.sz + spacing;
|
|
}
|
|
let mut x = p[0] + 4.0;
|
|
draw_list
|
|
.add_circle(
|
|
[x + state.sz * 0.5, y + state.sz * 0.5],
|
|
state.sz * 0.5,
|
|
state.col,
|
|
)
|
|
.num_segments(32)
|
|
.filled(true)
|
|
.build();
|
|
x += state.sz + spacing;
|
|
draw_list
|
|
.add_rect([x, y], [x + state.sz, y + state.sz], state.col)
|
|
.filled(true)
|
|
.build();
|
|
x += state.sz + spacing;
|
|
draw_list
|
|
.add_rect([x, y], [x + state.sz, y + state.sz], state.col)
|
|
.filled(true)
|
|
.rounding(10.0)
|
|
.build();
|
|
x += state.sz + spacing;
|
|
draw_list
|
|
.add_rect([x, y], [x + state.sz, y + state.sz], state.col)
|
|
.filled(true)
|
|
.rounding(10.0)
|
|
.round_top_right(false)
|
|
.round_bot_left(false)
|
|
.build();
|
|
x += state.sz + spacing;
|
|
draw_list
|
|
.add_triangle(
|
|
[x + state.sz * 0.5, y],
|
|
[x + state.sz, y + state.sz - 0.5],
|
|
[x, y + state.sz - 0.5],
|
|
state.col,
|
|
)
|
|
.filled(true)
|
|
.build();
|
|
x += state.sz + spacing;
|
|
const MULTICOLOR_RECT_CORNER_COLOR1: [f32; 3] = [0.0, 0.0, 0.0];
|
|
const MULTICOLOR_RECT_CORNER_COLOR2: [f32; 3] = [1.0, 0.0, 0.0];
|
|
const MULTICOLOR_RECT_CORNER_COLOR3: [f32; 3] = [1.0, 1.0, 0.0];
|
|
const MULTICOLOR_RECT_CORNER_COLOR4: [f32; 3] = [0.0, 1.0, 0.0];
|
|
draw_list.add_rect_filled_multicolor(
|
|
[x, y],
|
|
[x + state.sz, y + state.sz],
|
|
MULTICOLOR_RECT_CORNER_COLOR1,
|
|
MULTICOLOR_RECT_CORNER_COLOR2,
|
|
MULTICOLOR_RECT_CORNER_COLOR3,
|
|
MULTICOLOR_RECT_CORNER_COLOR4,
|
|
);
|
|
ui.dummy([(state.sz + spacing) * 8.0, (state.sz + spacing) * 3.0]);
|
|
ui.separator();
|
|
|
|
ui.text("Canvas example");
|
|
if ui.button("Clear") {
|
|
state.points.clear();
|
|
}
|
|
if state.points.len() >= 2 {
|
|
ui.same_line();
|
|
if ui.button("Undo") {
|
|
state.points.pop();
|
|
state.points.pop();
|
|
}
|
|
}
|
|
ui.text("Left-click and drag to add lines,\nRight-click to undo");
|
|
// Here we are using InvisibleButton() as a convenience to
|
|
// 1) advance the cursor, and
|
|
// 2) allows us to use IsItemHovered()
|
|
// However you can draw directly and poll mouse/keyboard by
|
|
// yourself. You can manipulate the cursor using GetCursorPos() and
|
|
// SetCursorPos(). If you only use the ImDrawList API, you can
|
|
// notify the owner window of its extends by using
|
|
// SetCursorPos(max).
|
|
|
|
// ImDrawList API uses screen coordinates!
|
|
let canvas_pos = ui.cursor_screen_pos();
|
|
// Resize canvas to what's available
|
|
let mut canvas_size = ui.content_region_avail();
|
|
if canvas_size[0] < 50.0 {
|
|
canvas_size[0] = 50.0;
|
|
}
|
|
if canvas_size[1] < 50.0 {
|
|
canvas_size[1] = 50.0;
|
|
}
|
|
const CANVAS_CORNER_COLOR1: [f32; 3] = [0.2, 0.2, 0.2];
|
|
const CANVAS_CORNER_COLOR2: [f32; 3] = [0.2, 0.2, 0.24];
|
|
const CANVAS_CORNER_COLOR3: [f32; 3] = [0.24, 0.24, 0.27];
|
|
const CANVAS_CORNER_COLOR4: [f32; 3] = [0.2, 0.2, 0.24];
|
|
draw_list.add_rect_filled_multicolor(
|
|
canvas_pos,
|
|
[
|
|
canvas_pos[0] + canvas_size[0],
|
|
canvas_pos[1] + canvas_size[1],
|
|
],
|
|
CANVAS_CORNER_COLOR1,
|
|
CANVAS_CORNER_COLOR2,
|
|
CANVAS_CORNER_COLOR3,
|
|
CANVAS_CORNER_COLOR4,
|
|
);
|
|
const CANVAS_BORDER_COLOR: [f32; 3] = [1.0, 1.0, 1.0];
|
|
draw_list
|
|
.add_rect(
|
|
canvas_pos,
|
|
[
|
|
canvas_pos[0] + canvas_size[0],
|
|
canvas_pos[1] + canvas_size[1],
|
|
],
|
|
CANVAS_BORDER_COLOR,
|
|
)
|
|
.build();
|
|
|
|
let mut adding_preview = false;
|
|
ui.invisible_button("canvas", canvas_size);
|
|
let mouse_pos = ui.io().mouse_pos;
|
|
let mouse_pos_in_canvas = [mouse_pos[0] - canvas_pos[0], mouse_pos[1] - canvas_pos[1]];
|
|
if state.adding_line {
|
|
adding_preview = true;
|
|
state.points.push(mouse_pos_in_canvas);
|
|
if !ui.is_mouse_down(MouseButton::Left) {
|
|
state.adding_line = false;
|
|
adding_preview = false;
|
|
}
|
|
}
|
|
if ui.is_item_hovered() {
|
|
if !state.adding_line && ui.is_mouse_clicked(MouseButton::Left) {
|
|
state.points.push(mouse_pos_in_canvas);
|
|
state.adding_line = true;
|
|
}
|
|
if ui.is_mouse_clicked(MouseButton::Right) && !state.points.is_empty() {
|
|
state.adding_line = false;
|
|
adding_preview = false;
|
|
state.points.pop();
|
|
state.points.pop();
|
|
}
|
|
}
|
|
draw_list.with_clip_rect_intersect(
|
|
canvas_pos,
|
|
[
|
|
canvas_pos[0] + canvas_size[0],
|
|
canvas_pos[1] + canvas_size[1],
|
|
],
|
|
|| {
|
|
const LINE_COLOR: [f32; 3] = [1.0, 1.0, 0.0];
|
|
for line in state.points.chunks(2) {
|
|
if line.len() < 2 {
|
|
break;
|
|
}
|
|
let (p1, p2) = (line[0], line[1]);
|
|
draw_list
|
|
.add_line(
|
|
[canvas_pos[0] + p1[0], canvas_pos[1] + p1[1]],
|
|
[canvas_pos[0] + p2[0], canvas_pos[1] + p2[1]],
|
|
LINE_COLOR,
|
|
)
|
|
.thickness(2.0)
|
|
.build();
|
|
}
|
|
},
|
|
);
|
|
if adding_preview {
|
|
state.points.pop();
|
|
}
|
|
});
|
|
}
|
|
|
|
fn show_app_log(ui: &Ui, app_log: &mut Vec<String>) {
|
|
ui.window("Example: Log")
|
|
.size([500.0, 400.0], Condition::FirstUseEver)
|
|
.build(|| {
|
|
if ui.small_button("[Debug] Add 5 entries") {
|
|
let categories = ["info", "warn", "error"];
|
|
let words = [
|
|
"Bumfuzzled",
|
|
"Cattywampus",
|
|
"Snickersnee",
|
|
"Abibliophobia",
|
|
"Absquatulate",
|
|
"Nincompoop",
|
|
"Pauciloquent",
|
|
];
|
|
for _ in 0..5 {
|
|
let category = categories[app_log.len() % categories.len()];
|
|
let word = words[app_log.len() % words.len()];
|
|
let frame = ui.frame_count();
|
|
let time = ui.time();
|
|
let text = format!(
|
|
"{:05} {} Hello, current time is {:.1}, here's a word: {}",
|
|
frame, category, time, word
|
|
);
|
|
app_log.push(text);
|
|
}
|
|
}
|
|
if ui.button("Clear") {
|
|
app_log.clear();
|
|
}
|
|
ui.same_line();
|
|
if ui.button("Copy") {
|
|
ui.set_clipboard_text(ImString::from(app_log.join("\n")));
|
|
}
|
|
ui.separator();
|
|
ui.child_window("logwindow")
|
|
.flags(WindowFlags::HORIZONTAL_SCROLLBAR)
|
|
.build(|| {
|
|
if !app_log.is_empty() {
|
|
let mut clipper = ListClipper::new(app_log.len() as i32).begin(ui);
|
|
while clipper.step() {
|
|
for line in clipper.display_start()..clipper.display_end() {
|
|
ui.text(&app_log[line as usize]);
|
|
}
|
|
}
|
|
}
|
|
if ui.scroll_y() >= ui.scroll_max_y() {
|
|
ui.set_scroll_here_y();
|
|
}
|
|
});
|
|
});
|
|
}
|