extern crate glium;
#[macro_use]
extern crate imgui;
extern crate imgui_glium_renderer;

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: ImString,
    item: i32,
    item2: i32,
    text: ImString,
    i0: i32,
    f0: f32,
    vec2f: [f32; 2],
    vec3f: [f32; 3],
    vec2i: [i32; 2],
    vec3i: [i32; 3],
    col1: [f32; 3],
    col2: [f32; 4],
    selected_fish: Option<usize>,
    auto_resize_state: AutoResizeState,
    file_menu: FileMenuState,
    radio_button: i32,
    color_edit: ColorEditState,
    custom_rendering: CustomRenderingState,
}

impl Default for State {
    fn default() -> Self {
        let mut buf = ImString::with_capacity(32);
        buf.push_str("日本語");
        let mut text = ImString::with_capacity(128);
        text.push_str("Hello, world!");
        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: buf,
            item: 0,
            item2: 0,
            text: text,
            i0: 123,
            f0: 0.001,
            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,
            auto_resize_state: Default::default(),
            file_menu: Default::default(),
            radio_button: 0,
            color_edit: ColorEditState::default(),
            custom_rendering: Default::default(),
        }
    }
}

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: i32,
    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, f32)>,
    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,
        }
    }
}

const CLEAR_COLOR: [f32; 4] = [114.0 / 255.0, 144.0 / 255.0, 154.0 / 255.0, 1.0];

fn main() {
    let mut state = State::default();

    support::run("test_window.rs".to_owned(), CLEAR_COLOR, |ui| {
        let mut open = true;
        show_test_window(ui, &mut state, &mut open);
        open
    });
}

fn show_help_marker(ui: &Ui, desc: &str) {
    ui.text_disabled(im_str!("(?)"));
    if ui.is_item_hovered() {
        ui.tooltip(|| { ui.text(desc); });
    }
}

fn show_user_guide(ui: &Ui) {
    ui.bullet_text(im_str!("Double-click on title bar to collapse window."));
    ui.bullet_text(im_str!(
        "Click and drag on lower right corner to resize window."
    ));
    ui.bullet_text(im_str!("Click and drag on any empty space to move window."));
    ui.bullet_text(im_str!("Mouse Wheel to scroll."));
    // TODO: check font_allow_user_scaling
    ui.bullet_text(im_str!(
        "TAB/SHIFT+TAB to cycle through keyboard editable fields."
    ));
    ui.bullet_text(im_str!("CTRL+Click on a slider or drag box to input text."));
    ui.bullet_text(im_str!(
        "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(im_str!("Style Editor"))
            .opened(&mut state.show_app_style_editor)
            .build(|| ui.show_default_style_editor());
    }
    if state.show_app_about {
        ui.window(im_str!("About ImGui"))
            .always_auto_resize(true)
            .opened(&mut state.show_app_about)
            .build(|| {
                ui.text(format!("dear imgui, {}", imgui::get_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,
        );
    }

    let mut window = ui.window(im_str!("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), ImGuiCond::FirstUseEver);
    if !state.no_close {
        window = window.opened(opened)
    }
    window.build(|| {
            ui.push_item_width(-140.0);
            ui.text(format!("dear imgui says hello. ({})", imgui::get_version()));
            ui.menu_bar(|| {
                ui.menu(im_str!("Menu")).build(|| {
                    show_example_menu_file(ui, &mut state.file_menu);
                });
                ui.menu(im_str!("Examples")).build(|| {
                    ui.menu_item(im_str!("Main menu bar"))
                        .selected(&mut state.show_app_main_menu_bar)
                        .build();
                    ui.menu_item(im_str!("Console"))
                        .selected(&mut state.show_app_console)
                        .build();
                    ui.menu_item(im_str!("Log"))
                        .selected(&mut state.show_app_log)
                        .build();
                    ui.menu_item(im_str!("Simple layout"))
                        .selected(&mut state.show_app_layout)
                        .build();
                    ui.menu_item(im_str!("Property editor"))
                        .selected(&mut state.show_app_property_editor)
                        .build();
                    ui.menu_item(im_str!("Long text display"))
                        .selected(&mut state.show_app_long_text)
                        .build();
                    ui.menu_item(im_str!("Auto-resizing window"))
                        .selected(&mut state.show_app_auto_resize)
                        .build();
                    ui.menu_item(im_str!("Constrained-resizing window"))
                        .selected(&mut state.show_app_constrained_resize)
                        .build();
                    ui.menu_item(im_str!("Simple overlay"))
                        .selected(&mut state.show_app_fixed_overlay)
                        .build();
                    ui.menu_item(im_str!("Manipulating window title"))
                        .selected(&mut state.show_app_manipulating_window_title)
                        .build();
                    ui.menu_item(im_str!("Custom rendering"))
                        .selected(&mut state.show_app_custom_rendering)
                        .build();
                });
                ui.menu(im_str!("Help")).build(|| {
                    ui.menu_item(im_str!("Metrics"))
                        .selected(&mut state.show_app_metrics)
                        .build();
                    ui.menu_item(im_str!("Style Editor"))
                        .selected(&mut state.show_app_style_editor)
                        .build();
                    ui.menu_item(im_str!("About ImGui"))
                        .selected(&mut state.show_app_about)
                        .build();
                });
            });
            ui.spacing();
            if ui.collapsing_header(im_str!("Help")).build() {
                ui.text_wrapped(im_str!(
                    "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 ui.collapsing_header(im_str!("Window options")).build() {
                ui.checkbox(im_str!("No titlebar"), &mut state.no_titlebar);
                ui.same_line(150.0);
                ui.checkbox(im_str!("No scrollbar"), &mut state.no_scrollbar);
                ui.same_line(300.0);
                ui.checkbox(im_str!("No menu"), &mut state.no_menu);
                ui.checkbox(im_str!("No move"), &mut state.no_move);
                ui.same_line(150.0);
                ui.checkbox(im_str!("No resize"), &mut state.no_resize);
                ui.same_line(300.0);
                ui.checkbox(im_str!("No collapse"), &mut state.no_collapse);
                ui.checkbox(im_str!("No close"), &mut state.no_close);

                ui.tree_node(im_str!("Style")).build(|| {
                    ui.show_default_style_editor()
                });
            }
            if ui.collapsing_header(im_str!("Widgets")).build() {
                ui.tree_node(im_str!("Tree")).build(|| for i in 0..5 {
                    ui.tree_node(im_str!("Child {}", i)).build(|| {
                        ui.text(im_str!("blah blah"));
                        ui.same_line(0.0);
                        if ui.small_button(im_str!("print")) {
                            println!("Child {} pressed", i);
                        }
                    });
                });
                ui.tree_node(im_str!("Bullets")).build(|| {
                    ui.bullet_text(im_str!("Bullet point 1"));
                    ui.bullet_text(im_str!("Bullet point 2\nOn multiple lines"));
                    ui.bullet();
                    ui.text(im_str!("Bullet point 3 (two calls)"));

                    ui.bullet();
                    ui.small_button(im_str!("Button"));
                });
                ui.tree_node(im_str!("Colored text")).build(|| {
                    ui.text_colored((1.0, 0.0, 1.0, 1.0), im_str!("Pink"));
                    ui.text_colored((1.0, 1.0, 0.0, 1.0), im_str!("Yellow"));
                    ui.text_disabled(im_str!("Disabled"));
                });
                ui.tree_node(im_str!("Word Wrapping")).build(|| {
                    ui.text_wrapped(im_str!(
                        "This text should automatically wrap on the edge of \
                                             the window.The current implementation for text \
                                             wrapping follows simple rulessuitable for English \
                                             and possibly other languages."
                    ));
                    ui.spacing();

                    ui.slider_float(im_str!("Wrap width"), &mut state.wrap_width, -20.0, 600.0)
                        .display_format(im_str!("%.0f"))
                        .build();

                    ui.text(im_str!("Test paragraph 1:"));
                    // TODO

                    ui.text(im_str!("Test paragraph 2:"));
                    // TODO
                });
                ui.tree_node(im_str!("UTF-8 Text")).build(|| {
                    ui.text_wrapped(im_str!(
                        "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(im_str!("Hiragana: かきくけこ (kakikukeko)"));
                    ui.text(im_str!("Kanjis: 日本語 (nihongo)"));
                    ui.input_text(im_str!("UTF-8 input"), &mut state.buf)
                        .build();
                });

                ui.radio_button(im_str!("radio a"), &mut state.radio_button, 0);
                ui.same_line(0.0);
                ui.radio_button(im_str!("radio b"), &mut state.radio_button, 1);
                ui.same_line(0.0);
                ui.radio_button(im_str!("radio c"), &mut state.radio_button, 2);

                ui.separator();
                ui.label_text(im_str!("label"), im_str!("Value"));
                ui.combo(
                    im_str!("combo"),
                    &mut state.item,
                    &[
                        im_str!("aaaa"),
                        im_str!("bbbb"),
                        im_str!("cccc"),
                        im_str!("dddd"),
                        im_str!("eeee"),
                    ],
                    -1,
                );
                let items = [
                    im_str!("AAAA"),
                    im_str!("BBBB"),
                    im_str!("CCCC"),
                    im_str!("DDDD"),
                    im_str!("EEEE"),
                    im_str!("FFFF"),
                    im_str!("GGGG"),
                    im_str!("HHHH"),
                    im_str!("IIII"),
                    im_str!("JJJJ"),
                    im_str!("KKKK"),
                ];
                ui.combo(im_str!("combo scroll"), &mut state.item2, &items, -1);
                ui.input_text(im_str!("input text"), &mut state.text)
                    .build();
                ui.input_int(im_str!("input int"), &mut state.i0).build();
                ui.drag_int(im_str!("drag int"), &mut state.i0).build();
                ui.input_float(im_str!("input float"), &mut state.f0)
                    .step(0.01)
                    .step_fast(1.0)
                    .build();
                ui.drag_float(im_str!("drag float"), &mut state.f0)
                    .speed(0.001)
                    .min(-1.0)
                    .max(1.0)
                    .build();
                ui.input_float3(im_str!("input float3"), &mut state.vec3f)
                    .build();
                ui.color_edit(im_str!("color 1"), &mut state.col1).build();
                ui.color_edit(im_str!("color 2"), &mut state.col2).build();

                ui.tree_node(im_str!("Multi-component Widgets")).build(|| {
                    ui.input_float2(im_str!("input float2"), &mut state.vec2f)
                        .build();
                    ui.input_int2(im_str!("input int2"), &mut state.vec2i)
                        .build();
                    ui.spacing();

                    ui.input_float3(im_str!("input float3"), &mut state.vec3f)
                        .build();
                    ui.input_int3(im_str!("input int3"), &mut state.vec3i)
                        .build();
                    ui.spacing();
                });

                ui.tree_node(im_str!("Color/Picker Widgets")).build(|| {
                    let s = &mut state.color_edit;
                    ui.checkbox(im_str!("With HDR"), &mut s.hdr);
                    ui.same_line(0.0);
                    show_help_marker(
                        ui,
                        "Currently all this does is to lift the 0..1 \
                                               limits on dragging widgets.",
                    );

                    ui.checkbox(im_str!("With Alpha Preview"), &mut s.alpha_preview);
                    ui.checkbox(
                        im_str!("With Half Alpha Preview"),
                        &mut s.alpha_half_preview,
                    );
                    ui.checkbox(im_str!("With Options Menu"), &mut s.options_menu);
                    ui.same_line(0.0);
                    show_help_marker(
                        ui,
                        "Right-click on the individual color widget to \
                                               show options.",
                    );
                    let misc_flags = {
                        let mut f = ImGuiColorEditFlags::empty();
                        f.set(ImGuiColorEditFlags::HDR, s.hdr);
                        f.set(ImGuiColorEditFlags::AlphaPreviewHalf, s.alpha_half_preview);
                        if !s.alpha_half_preview {
                            f.set(ImGuiColorEditFlags::AlphaPreview, s.alpha_preview);
                        }
                        f.set(ImGuiColorEditFlags::NoOptions, !s.options_menu);
                        f
                    };

                    ui.text(im_str!("Color widget:"));
                    ui.same_line(0.0);
                    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_edit(im_str!("MyColor##1"), &mut s.color)
                        .flags(misc_flags)
                        .alpha(false)
                        .build();

                    ui.text(im_str!("Color widget HSV with Alpha:"));
                    ui.color_edit(im_str!("MyColor##2"), &mut s.color)
                        .flags(misc_flags)
                        .mode(ColorEditMode::HSV)
                        .build();

                    ui.text(im_str!("Color widget with Float Display:"));
                    ui.color_edit(im_str!("MyColor##2f"), &mut s.color)
                        .flags(misc_flags)
                        .format(ColorFormat::Float)
                        .build();

                    ui.text(im_str!("Color button with Picker:"));
                    ui.same_line(0.0);
                    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_edit(im_str!("MyColor##3"), &mut s.color)
                        .flags(misc_flags)
                        .inputs(false)
                        .label(false)
                        .build();

                    ui.text(im_str!("Color picker:"));
                    ui.checkbox(im_str!("With Alpha"), &mut s.alpha);
                    ui.checkbox(im_str!("With Alpha Bar"), &mut s.alpha_bar);
                    ui.checkbox(im_str!("With Side Preview"), &mut s.side_preview);
                    if s.side_preview {
                        ui.same_line(0.0);
                        ui.checkbox(im_str!("With Ref Color"), &mut s.ref_color);
                        if s.ref_color {
                            ui.same_line(0.0);
                            ui.color_edit(im_str!("##RefColor"), &mut s.ref_color_v)
                                .flags(misc_flags)
                                .inputs(false)
                                .build();
                        }
                    }
                    let mut b = ui.color_picker(im_str!("MyColor##4"), &mut s.color)
                        .flags(misc_flags)
                        .alpha(s.alpha)
                        .alpha_bar(s.alpha_bar)
                        .side_preview(s.side_preview)
                        .rgb(true);

                    if s.ref_color {
                        b = b.reference_color(&s.ref_color_v)
                    }
                    b.build();
                });
            }
            if ui.collapsing_header(im_str!("Popups & Modal windows"))
                .build()
            {
                ui.tree_node(im_str!("Popups")).build(|| {
                    ui.text_wrapped(im_str!(
                        "When a popup is active, it inhibits interacting \
                                             with windows that are behind the popup. Clicking \
                                             outside the popup closes it."
                    ));
                    let names = [
                        im_str!("Bream"),
                        im_str!("Haddock"),
                        im_str!("Mackerel"),
                        im_str!("Pollock"),
                        im_str!("Tilefish"),
                    ];
                    if ui.small_button(im_str!("Select..")) {
                        ui.open_popup(im_str!("select"));
                    }
                    ui.same_line(0.0);
                    ui.text(match state.selected_fish {
                        Some(index) => names[index],
                        None => im_str!("<None>"),
                    });
                    ui.popup(im_str!("select"), || {
                        ui.text(im_str!("Aquarium"));
                        ui.separator();
                        for (index, name) in names.iter().enumerate() {
                            if ui.selectable(
                                name,
                                false,
                                ImGuiSelectableFlags::empty(),
                                ImVec2::new(0.0, 0.0),
                            )
                            {
                                state.selected_fish = Some(index);
                            }
                        }
                    });
                });
            }
        })
}

fn show_example_app_main_menu_bar<'a>(ui: &Ui<'a>, state: &mut State) {
    ui.main_menu_bar(|| {
        ui.menu(im_str!("File")).build(|| {
            show_example_menu_file(ui, &mut state.file_menu);
        });
        ui.menu(im_str!("Edit")).build(|| {
            ui.menu_item(im_str!("Undo"))
                .shortcut(im_str!("CTRL+Z"))
                .build();
            ui.menu_item(im_str!("Redo"))
                .shortcut(im_str!("CTRL+Y"))
                .enabled(false)
                .build();
            ui.separator();
            ui.menu_item(im_str!("Cut"))
                .shortcut(im_str!("CTRL+X"))
                .build();
            ui.menu_item(im_str!("Copy"))
                .shortcut(im_str!("CTRL+C"))
                .build();
            ui.menu_item(im_str!("Paste"))
                .shortcut(im_str!("CTRL+V"))
                .build();
        });
    });
}

fn show_example_menu_file<'a>(ui: &Ui<'a>, state: &mut FileMenuState) {
    ui.menu_item(im_str!("(dummy menu)")).enabled(false).build();
    ui.menu_item(im_str!("New")).build();
    ui.menu_item(im_str!("Open"))
        .shortcut(im_str!("Ctrl+O"))
        .build();
    ui.menu(im_str!("Open Recent")).build(|| {
        ui.menu_item(im_str!("fish_hat.c")).build();
        ui.menu_item(im_str!("fish_hat.inl")).build();
        ui.menu_item(im_str!("fish_hat.h")).build();
        ui.menu(im_str!("More..")).build(|| {
            ui.menu_item(im_str!("Hello")).build();
            ui.menu_item(im_str!("Sailor")).build();
            ui.menu(im_str!("Recurse..")).build(|| {
                show_example_menu_file(ui, state);
            });
        });
    });
    ui.menu_item(im_str!("Save"))
        .shortcut(im_str!("Ctrl+S"))
        .build();
    ui.menu_item(im_str!("Save As..")).build();
    ui.separator();
    ui.menu(im_str!("Options")).build(|| {
        ui.menu_item(im_str!("Enabled"))
            .selected(&mut state.enabled)
            .build();
        ui.child_frame(im_str!("child"), (0.0, 60.0))
            .show_borders(true)
            .build(|| for i in 0..10 {
                ui.text(format!("Scrolling Text {}", i));
            });
        ui.slider_float(im_str!("Value"), &mut state.f, 0.0, 1.0)
            .build();
        ui.input_float(im_str!("Input"), &mut state.f)
            .step(0.1)
            .build();
        let items = [im_str!("Yes"), im_str!("No"), im_str!("Maybe")];
        ui.combo(im_str!("Combo"), &mut state.n, &items, -1);
        ui.checkbox(im_str!("Check"), &mut state.b);
    });
    ui.menu(im_str!("Colors")).build(|| for &col in
        ImGuiCol::values()
    {
        ui.menu_item(imgui::get_style_color_name(col)).build();
    });
    ui.menu(im_str!("Disabled")).enabled(false).build(|| {
        unreachable!();
    });
    ui.menu_item(im_str!("Checked")).selected(&mut true).build();
    ui.menu_item(im_str!("Quit"))
        .shortcut(im_str!("Alt+F4"))
        .build();
}

fn show_example_app_auto_resize(ui: &Ui, state: &mut AutoResizeState, opened: &mut bool) {
    ui.window(im_str!("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_int(im_str!("Number of lines"), &mut state.lines, 1, 20)
                .build();
            for i in 0..state.lines {
                ui.text(format!("{:2$}This is line {}", "", i, i as usize * 4));
            }
        })
}

#[allow(deprecated)]
fn show_example_app_fixed_overlay(ui: &Ui, opened: &mut bool) {
    const DISTANCE: f32 = 10.0;
    let window_pos = (DISTANCE, DISTANCE);
    ui.with_color_var(ImGuiCol::WindowBg, (0.0, 0.0, 0.0, 0.3), || {
        ui.window(im_str!("Example: Fixed Overlay"))
        .opened(opened)
        .position(window_pos, ImGuiCond::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.imgui().mouse_pos();
          ui.text(format!(
              "Mouse Position: ({:.1},{:.1})",
              mouse_pos.0,
              mouse_pos.1
              ));
        })
    })
}

fn show_example_app_manipulating_window_title(ui: &Ui) {
    ui.window(im_str!("Same title as another window##1"))
        .position((100.0, 100.0), ImGuiCond::FirstUseEver)
        .build(|| {
            ui.text(
                "This is window 1.
My title is the same as window 2, but my identifier is unique.",
            );
        });
    ui.window(im_str!("Same title as another window##2"))
        .position((100.0, 200.0), ImGuiCond::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.imgui().get_time() / 0.25) as usize & 3;
    let num = ui.imgui().get_frame_count(); // The C++ version uses rand() here
    let title = im_str!("Animated title {} {}###AnimatedTitle", chars[ch_idx], num);
    ui.window(title)
        .position((100.0, 300.0), ImGuiCond::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(im_str!("Example: Custom rendering"))
        .size((350.0, 560.0), ImGuiCond::FirstUseEver)
        .opened(opened)
        .build(|| {
            ui.text("Primitives");
            // TODO: Add DragFloat to change value of sz
            ui.color_edit(im_str!("Color"), &mut state.col).build();
            let draw_list = ui.get_window_draw_list();
            let p = ui.get_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(im_str!("Canvas example"));
            if ui.button(im_str!("Clear"), (0.0, 0.0)) {
                state.points.clear();
            }
            if state.points.len() >= 2 {
                ui.same_line(0.0);
                if ui.button(im_str!("Undo"), (0.0, 0.0)) {
                    state.points.pop();
                    state.points.pop();
                }
            }
            ui.text(im_str!(
                "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.get_cursor_screen_pos();
            // Resize canvas to what's available
            let mut canvas_size = ui.get_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(im_str!("canvas"), canvas_size);
            let mouse_pos = ui.imgui().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.imgui().is_mouse_down(ImMouseButton::Left) {
                    state.adding_line = false;
                    adding_preview = false;
                }
            }
            if ui.is_item_hovered() {
                if !state.adding_line && ui.imgui().is_mouse_clicked(ImMouseButton::Left) {
                    state.points.push(mouse_pos_in_canvas);
                    state.adding_line = true;
                }
                if ui.imgui().is_mouse_clicked(ImMouseButton::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();
            }
        });
}
