Allow simultaneous access to different draw lists

Only need to prevent accessing the same draw-list twice at one time

Closes #488
This commit is contained in:
dbr 2021-09-13 18:22:51 +10:00
parent bb43463c2e
commit 52898779e1
2 changed files with 47 additions and 10 deletions

View File

@ -19,8 +19,17 @@ fn draw_text_centered(
fn main() { fn main() {
let system = support::init(file!()); let system = support::init(file!());
system.main_loop(move |_, ui| { system.main_loop(move |_, ui| {
// Get access to draw FG and BG draw lists.
let bg_draw_list = ui.get_background_draw_list();
let fg_draw_list = ui.get_foreground_draw_list();
// Note we cannot access two instances of the same draw list
// at once. That is to say, the following line would panic if
// uncommented:
//let bg_draw_list_2 = ui.get_background_draw_list(); // panic!
{ {
let bg_draw_list = ui.get_background_draw_list();
bg_draw_list bg_draw_list
.add_circle([150.0, 150.0], 150.0, [1.0, 0.0, 0.0]) .add_circle([150.0, 150.0], 150.0, [1.0, 0.0, 0.0])
.thickness(4.0) .thickness(4.0)
@ -36,7 +45,6 @@ fn main() {
{ {
let [w, h] = ui.io().display_size; let [w, h] = ui.io().display_size;
let fg_draw_list = ui.get_foreground_draw_list();
fg_draw_list fg_draw_list
.add_circle([w - 150.0, h - 150.0], 150.0, [1.0, 0.0, 0.0]) .add_circle([w - 150.0, h - 150.0], 150.0, [1.0, 0.0, 0.0])
.thickness(4.0) .thickness(4.0)

View File

@ -61,27 +61,47 @@ bitflags!(
} }
); );
enum DrawListType {
Window,
Background,
Foreground,
}
/// Object implementing the custom draw API. /// Object implementing the custom draw API.
/// ///
/// Called from [`Ui::get_window_draw_list`], [`Ui::get_background_draw_list`] or [`Ui::get_foreground_draw_list`]. /// 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. /// 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. /// The program will panic on creating a second instance.
pub struct DrawListMut<'ui> { pub struct DrawListMut<'ui> {
draw_list_type: DrawListType,
draw_list: *mut ImDrawList, draw_list: *mut ImDrawList,
_phantom: PhantomData<&'ui Ui<'ui>>, _phantom: PhantomData<&'ui Ui<'ui>>,
} }
static DRAW_LIST_LOADED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); // Lock for each variant of draw list. See https://github.com/imgui-rs/imgui-rs/issues/488
static DRAW_LIST_LOADED_WINDOW: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
static DRAW_LIST_LOADED_BACKGROUND: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
static DRAW_LIST_LOADED_FOREGROUND: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
impl<'ui> Drop for DrawListMut<'ui> { impl<'ui> Drop for DrawListMut<'ui> {
fn drop(&mut self) { fn drop(&mut self) {
DRAW_LIST_LOADED.store(false, std::sync::atomic::Ordering::Release); match self.draw_list_type {
DrawListType::Window => &DRAW_LIST_LOADED_WINDOW,
DrawListType::Background => &DRAW_LIST_LOADED_BACKGROUND,
DrawListType::Foreground => &DRAW_LIST_LOADED_FOREGROUND,
}.store(false, std::sync::atomic::Ordering::Release);
} }
} }
impl<'ui> DrawListMut<'ui> { impl<'ui> DrawListMut<'ui> {
fn lock_draw_list() { fn lock_draw_list(t: DrawListType) {
let already_loaded = DRAW_LIST_LOADED let lock = match t {
DrawListType::Window => &DRAW_LIST_LOADED_WINDOW,
DrawListType::Background => &DRAW_LIST_LOADED_BACKGROUND,
DrawListType::Foreground => &DRAW_LIST_LOADED_FOREGROUND,
};
let already_loaded = lock
.compare_exchange( .compare_exchange(
false, false,
true, true,
@ -90,33 +110,42 @@ impl<'ui> DrawListMut<'ui> {
) )
.is_err(); .is_err();
if already_loaded { if already_loaded {
panic!("DrawListMut is already loaded! You can only load one instance of it!") let name = match t {
DrawListType::Window => "window",
DrawListType::Background => "background",
DrawListType::Foreground => "foreground",
};
panic!("The DrawListMut instance for the {} draw list is already loaded! You can only load one instance of it!", name)
} }
} }
#[doc(alias = "GetWindowDrawList")] #[doc(alias = "GetWindowDrawList")]
pub(crate) fn window(_: &Ui<'ui>) -> Self { pub(crate) fn window(_: &Ui<'ui>) -> Self {
Self::lock_draw_list(); Self::lock_draw_list(DrawListType::Window);
Self { Self {
draw_list: unsafe { sys::igGetWindowDrawList() }, draw_list: unsafe { sys::igGetWindowDrawList() },
draw_list_type: DrawListType::Window,
_phantom: PhantomData, _phantom: PhantomData,
} }
} }
#[doc(alias = "GetBackgroundDrawList")] #[doc(alias = "GetBackgroundDrawList")]
pub(crate) fn background(_: &Ui<'ui>) -> Self { pub(crate) fn background(_: &Ui<'ui>) -> Self {
Self::lock_draw_list(); Self::lock_draw_list(DrawListType::Background);
Self { Self {
draw_list: unsafe { sys::igGetBackgroundDrawList() }, draw_list: unsafe { sys::igGetBackgroundDrawList() },
draw_list_type: DrawListType::Background,
_phantom: PhantomData, _phantom: PhantomData,
} }
} }
#[doc(alias = "GetForegroundDrawList")] #[doc(alias = "GetForegroundDrawList")]
pub(crate) fn foreground(_: &Ui<'ui>) -> Self { pub(crate) fn foreground(_: &Ui<'ui>) -> Self {
Self::lock_draw_list(); Self::lock_draw_list(DrawListType::Foreground);
Self { Self {
draw_list: unsafe { sys::igGetForegroundDrawList() }, draw_list: unsafe { sys::igGetForegroundDrawList() },
draw_list_type: DrawListType::Foreground,
_phantom: PhantomData, _phantom: PhantomData,
} }
} }