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() {
let system = support::init(file!());
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
.add_circle([150.0, 150.0], 150.0, [1.0, 0.0, 0.0])
.thickness(4.0)
@ -36,7 +45,6 @@ fn main() {
{
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)

View File

@ -61,27 +61,47 @@ bitflags!(
}
);
enum DrawListType {
Window,
Background,
Foreground,
}
/// Object implementing the custom draw API.
///
/// 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 DrawListMut<'ui> {
draw_list_type: DrawListType,
draw_list: *mut ImDrawList,
_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> {
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> {
fn lock_draw_list() {
let already_loaded = DRAW_LIST_LOADED
fn lock_draw_list(t: DrawListType) {
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(
false,
true,
@ -90,33 +110,42 @@ impl<'ui> DrawListMut<'ui> {
)
.is_err();
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")]
pub(crate) fn window(_: &Ui<'ui>) -> Self {
Self::lock_draw_list();
Self::lock_draw_list(DrawListType::Window);
Self {
draw_list: unsafe { sys::igGetWindowDrawList() },
draw_list_type: DrawListType::Window,
_phantom: PhantomData,
}
}
#[doc(alias = "GetBackgroundDrawList")]
pub(crate) fn background(_: &Ui<'ui>) -> Self {
Self::lock_draw_list();
Self::lock_draw_list(DrawListType::Background);
Self {
draw_list: unsafe { sys::igGetBackgroundDrawList() },
draw_list_type: DrawListType::Background,
_phantom: PhantomData,
}
}
#[doc(alias = "GetForegroundDrawList")]
pub(crate) fn foreground(_: &Ui<'ui>) -> Self {
Self::lock_draw_list();
Self::lock_draw_list(DrawListType::Foreground);
Self {
draw_list: unsafe { sys::igGetForegroundDrawList() },
draw_list_type: DrawListType::Foreground,
_phantom: PhantomData,
}
}