diff --git a/imgui-examples/examples/draw_list.rs b/imgui-examples/examples/draw_list.rs new file mode 100644 index 0000000..a80aa48 --- /dev/null +++ b/imgui-examples/examples/draw_list.rs @@ -0,0 +1,90 @@ +use imgui::*; + +mod support; + +// rect is [x, y, w, h] +fn draw_text_centered( + ui: &Ui, + draw_list: &DrawListMut, + rect: [f32; 4], + text: &ImStr, + color: [f32; 3], +) { + let text_size = ui.calc_text_size(text, false, 0.0); + let cx = (rect[2] - text_size[0]) / 2.0; + let cy = (rect[3] - text_size[1]) / 2.0; + draw_list.add_text([rect[0] + cx, rect[1] + cy], color, text); +} + +fn main() { + let system = support::init(file!()); + system.main_loop(move |_, ui| { + { + let bg_draw_list = ui.get_background_draw_list(); + bg_draw_list + .add_circle([150.0, 150.0], 150.0, [1.0, 0.0, 0.0]) + .thickness(4.0) + .build(); + draw_text_centered( + ui, + &bg_draw_list, + [0.0, 0.0, 300.0, 300.0], + im_str!("background draw list"), + [0.0, 0.0, 0.0], + ); + } + + { + let [w, h] = ui.io().display_size; + let fg_draw_list = ui.get_foreground_draw_list(); + fg_draw_list + .add_circle([w - 150.0, h - 150.0], 150.0, [1.0, 0.0, 0.0]) + .thickness(4.0) + .build(); + draw_text_centered( + ui, + &fg_draw_list, + [w - 300.0, h - 300.0, 300.0, 300.0], + im_str!("foreground draw list"), + [1.0, 0.0, 0.0], + ); + } + + Window::new(im_str!("Draw list")) + .size([300.0, 110.0], Condition::FirstUseEver) + .scroll_bar(false) + .build(ui, || { + ui.button(im_str!("random button"), [0.0, 0.0]); + let draw_list = ui.get_window_draw_list(); + let o = ui.cursor_screen_pos(); + let ws = ui.content_region_avail(); + draw_list + .add_circle([o[0] + 10.0, o[1] + 10.0], 5.0, [1.0, 0.0, 0.0]) + .thickness(4.0) + .build(); + draw_list + .add_circle([o[0] + ws[0] - 10.0, o[1] + 10.0], 5.0, [0.0, 1.0, 0.0]) + .thickness(4.0) + .build(); + draw_list + .add_circle( + [o[0] + ws[0] - 10.0, o[1] + ws[1] - 10.0], + 5.0, + [0.0, 0.0, 1.0], + ) + .thickness(4.0) + .build(); + draw_list + .add_circle([o[0] + 10.0, o[1] + ws[1] - 10.0], 5.0, [1.0, 1.0, 0.0]) + .thickness(4.0) + .build(); + draw_text_centered( + ui, + &draw_list, + [o[0], o[1], ws[0], ws[1]], + im_str!("window draw list"), + [1.0, 1.0, 1.0], + ); + }); + }); +} diff --git a/imgui/src/window_draw_list.rs b/imgui/src/draw_list.rs similarity index 90% rename from imgui/src/window_draw_list.rs rename to imgui/src/draw_list.rs index b2f63f9..9aff014 100644 --- a/imgui/src/window_draw_list.rs +++ b/imgui/src/draw_list.rs @@ -53,26 +53,25 @@ impl From<(f32, f32, f32)> for ImColor { /// Object implementing the custom draw API. /// -/// Called from [`Ui::get_window_draw_list`]. No more than one instance of this -/// structure can live in a program at the same time. +/// Called from [`Ui::get_window_draw_list`], [`Ui::get_background_draw_list`] or [`Ui::get_foreground_draw_list`]. +/// No more than one instance of this structure can live in a program at the same time. /// The program will panic on creating a second instance. -pub struct WindowDrawList<'ui> { +pub struct DrawListMut<'ui> { draw_list: *mut ImDrawList, _phantom: PhantomData<&'ui Ui<'ui>>, } -static WINDOW_DRAW_LIST_LOADED: std::sync::atomic::AtomicBool = - std::sync::atomic::AtomicBool::new(false); +static DRAW_LIST_LOADED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); -impl<'ui> Drop for WindowDrawList<'ui> { +impl<'ui> Drop for DrawListMut<'ui> { fn drop(&mut self) { - WINDOW_DRAW_LIST_LOADED.store(false, std::sync::atomic::Ordering::Release); + DRAW_LIST_LOADED.store(false, std::sync::atomic::Ordering::Release); } } -impl<'ui> WindowDrawList<'ui> { - pub(crate) fn new(_: &Ui<'ui>) -> Self { - let already_loaded = WINDOW_DRAW_LIST_LOADED +impl<'ui> DrawListMut<'ui> { + fn lock_draw_list() { + let already_loaded = DRAW_LIST_LOADED .compare_exchange( false, true, @@ -81,21 +80,34 @@ impl<'ui> WindowDrawList<'ui> { ) .is_err(); if already_loaded { - panic!("WindowDrawList is already loaded! You can only load one instance of it!") + panic!("DrawListMut is already loaded! You can only load one instance of it!") } + } + + pub(crate) fn window(_: &Ui<'ui>) -> Self { + Self::lock_draw_list(); Self { draw_list: unsafe { sys::igGetWindowDrawList() }, _phantom: PhantomData, } } - pub(crate) fn background(self) -> Self { + pub(crate) fn background(_: &Ui<'ui>) -> Self { + Self::lock_draw_list(); Self { draw_list: unsafe { sys::igGetBackgroundDrawList() }, _phantom: PhantomData, } } + pub(crate) fn foreground(_: &Ui<'ui>) -> Self { + Self::lock_draw_list(); + Self { + draw_list: unsafe { sys::igGetForegroundDrawList() }, + _phantom: PhantomData, + } + } + /// Split into *channels_count* drawing channels. /// At the end of the closure, the channels are merged. The objects /// are then drawn in the increasing order of their channel number, and not @@ -127,9 +139,9 @@ impl<'ui> WindowDrawList<'ui> { /// Represent the drawing interface within a call to [`channels_split`]. /// -/// [`channels_split`]: WindowDrawList::channels_split +/// [`channels_split`]: DrawListMut::channels_split pub struct ChannelsSplit<'ui> { - draw_list: &'ui WindowDrawList<'ui>, + draw_list: &'ui DrawListMut<'ui>, channels_count: u32, } @@ -151,7 +163,7 @@ impl<'ui> ChannelsSplit<'ui> { } /// Drawing functions -impl<'ui> WindowDrawList<'ui> { +impl<'ui> DrawListMut<'ui> { /// Returns a line from point `p1` to `p2` with color `c`. pub fn add_line(&'ui self, p1: [f32; 2], p2: [f32; 2], c: C) -> Line<'ui> where @@ -291,11 +303,11 @@ pub struct Line<'ui> { p2: [f32; 2], color: ImColor, thickness: f32, - draw_list: &'ui WindowDrawList<'ui>, + draw_list: &'ui DrawListMut<'ui>, } impl<'ui> Line<'ui> { - fn new(draw_list: &'ui WindowDrawList, p1: [f32; 2], p2: [f32; 2], c: C) -> Self + fn new(draw_list: &'ui DrawListMut, p1: [f32; 2], p2: [f32; 2], c: C) -> Self where C: Into, { @@ -338,11 +350,11 @@ pub struct Rect<'ui> { flags: ImDrawCornerFlags, thickness: f32, filled: bool, - draw_list: &'ui WindowDrawList<'ui>, + draw_list: &'ui DrawListMut<'ui>, } impl<'ui> Rect<'ui> { - fn new(draw_list: &'ui WindowDrawList, p1: [f32; 2], p2: [f32; 2], c: C) -> Self + fn new(draw_list: &'ui DrawListMut, p1: [f32; 2], p2: [f32; 2], c: C) -> Self where C: Into, { @@ -439,17 +451,11 @@ pub struct Triangle<'ui> { color: ImColor, thickness: f32, filled: bool, - draw_list: &'ui WindowDrawList<'ui>, + draw_list: &'ui DrawListMut<'ui>, } impl<'ui> Triangle<'ui> { - fn new( - draw_list: &'ui WindowDrawList, - p1: [f32; 2], - p2: [f32; 2], - p3: [f32; 2], - c: C, - ) -> Self + fn new(draw_list: &'ui DrawListMut, p1: [f32; 2], p2: [f32; 2], p3: [f32; 2], c: C) -> Self where C: Into, { @@ -512,11 +518,11 @@ pub struct Circle<'ui> { num_segments: u32, thickness: f32, filled: bool, - draw_list: &'ui WindowDrawList<'ui>, + draw_list: &'ui DrawListMut<'ui>, } impl<'ui> Circle<'ui> { - pub fn new(draw_list: &'ui WindowDrawList, center: [f32; 2], radius: f32, color: C) -> Self + pub fn new(draw_list: &'ui DrawListMut, center: [f32; 2], radius: f32, color: C) -> Self where C: Into, { @@ -588,12 +594,12 @@ pub struct BezierCurve<'ui> { thickness: f32, /// If num_segments is not set, the bezier curve is auto-tessalated. num_segments: Option, - draw_list: &'ui WindowDrawList<'ui>, + draw_list: &'ui DrawListMut<'ui>, } impl<'ui> BezierCurve<'ui> { fn new( - draw_list: &'ui WindowDrawList, + draw_list: &'ui DrawListMut, pos0: [f32; 2], cp0: [f32; 2], cp1: [f32; 2], diff --git a/imgui/src/lib.rs b/imgui/src/lib.rs index 038946c..5b84be6 100644 --- a/imgui/src/lib.rs +++ b/imgui/src/lib.rs @@ -10,6 +10,7 @@ use std::thread; pub use self::clipboard::*; pub use self::context::*; +pub use self::draw_list::{ChannelsSplit, DrawListMut, ImColor}; pub use self::fonts::atlas::*; pub use self::fonts::font::*; pub use self::fonts::glyph::*; @@ -46,12 +47,12 @@ pub use self::widget::tab::*; pub use self::widget::tree::*; pub use self::window::child_window::*; pub use self::window::*; -pub use self::window_draw_list::{ChannelsSplit, ImColor, WindowDrawList}; use internal::RawCast; mod clipboard; mod columns; mod context; +mod draw_list; mod fonts; mod input; mod input_widget; @@ -72,7 +73,6 @@ mod test; mod utils; mod widget; mod window; -mod window_draw_list; /// Returns the underlying Dear ImGui library version pub fn dear_imgui_version() -> &'static str { @@ -470,7 +470,7 @@ impl<'ui> Ui<'ui> { /// } /// ``` /// - /// This function will panic if several instances of [`WindowDrawList`] + /// This function will panic if several instances of [`DrawListMut`] /// coexist. Before a new instance is got, a previous instance should be /// dropped. /// @@ -485,13 +485,18 @@ impl<'ui> Ui<'ui> { /// } /// ``` #[must_use] - pub fn get_window_draw_list(&'ui self) -> WindowDrawList<'ui> { - WindowDrawList::new(self) + pub fn get_window_draw_list(&'ui self) -> DrawListMut<'ui> { + DrawListMut::window(self) } #[must_use] - pub fn get_background_draw_list(&'ui self) -> WindowDrawList<'ui> { - WindowDrawList::new(self).background() + pub fn get_background_draw_list(&'ui self) -> DrawListMut<'ui> { + DrawListMut::background(self) + } + + #[must_use] + pub fn get_foreground_draw_list(&'ui self) -> DrawListMut<'ui> { + DrawListMut::foreground(self) } }