#![allow(
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
clippy::as_conversions
)]
use crate::MouseButton;
use crate::sys;
use crate::ui::Ui;
use crate::window::WindowFlags;
impl Ui {
#[doc(alias = "OpenPopup")]
pub fn open_popup(&self, str_id: impl AsRef<str>) {
let str_id_ptr = self.scratch_txt(str_id);
unsafe { sys::igOpenPopup_Str(str_id_ptr, PopupFlags::NONE.bits()) }
}
#[doc(alias = "OpenPopup")]
pub fn open_popup_with_flags(&self, str_id: impl AsRef<str>, flags: PopupFlags) {
let str_id_ptr = self.scratch_txt(str_id);
unsafe { sys::igOpenPopup_Str(str_id_ptr, flags.bits()) }
}
#[doc(alias = "OpenPopupOnItemClick")]
pub fn open_popup_on_item_click(&self, str_id: Option<&str>) {
self.open_popup_on_item_click_with_flags(str_id, PopupContextOptions::new());
}
#[doc(alias = "OpenPopupOnItemClick")]
pub fn open_popup_on_item_click_with_flags(
&self,
str_id: Option<&str>,
flags: impl Into<PopupContextOptions>,
) {
let options = flags.into();
let str_id_ptr = str_id
.map(|s| self.scratch_txt(s))
.unwrap_or(std::ptr::null());
unsafe { sys::igOpenPopupOnItemClick(str_id_ptr, options.raw()) }
}
#[doc(alias = "BeginPopup")]
pub fn begin_popup(&self, str_id: impl AsRef<str>) -> Option<PopupToken<'_>> {
self.begin_popup_with_flags(str_id, WindowFlags::empty())
}
#[doc(alias = "BeginPopup")]
pub fn begin_popup_with_flags(
&self,
str_id: impl AsRef<str>,
flags: WindowFlags,
) -> Option<PopupToken<'_>> {
let str_id_ptr = self.scratch_txt(str_id);
let render = unsafe { sys::igBeginPopup(str_id_ptr, flags.bits()) };
if render {
Some(PopupToken::new(self))
} else {
None
}
}
#[doc(alias = "BeginPopup")]
pub fn popup<F>(&self, str_id: impl AsRef<str>, f: F)
where
F: FnOnce(),
{
if let Some(_token) = self.begin_popup(str_id) {
f();
}
}
#[doc(alias = "BeginPopupModal")]
pub fn begin_modal_popup(&self, name: impl AsRef<str>) -> Option<ModalPopupToken<'_>> {
let name_ptr = self.scratch_txt(name);
let render = unsafe {
sys::igBeginPopupModal(name_ptr, std::ptr::null_mut(), WindowFlags::empty().bits())
};
if render {
Some(ModalPopupToken::new(self))
} else {
None
}
}
#[doc(alias = "BeginPopupModal")]
pub fn begin_modal_popup_with_opened(
&self,
name: impl AsRef<str>,
opened: &mut bool,
) -> Option<ModalPopupToken<'_>> {
let name_ptr = self.scratch_txt(name);
let opened_ptr = opened as *mut bool;
let render =
unsafe { sys::igBeginPopupModal(name_ptr, opened_ptr, WindowFlags::empty().bits()) };
if render {
Some(ModalPopupToken::new(self))
} else {
None
}
}
pub fn begin_modal_popup_config<'a>(&'a self, name: &'a str) -> ModalPopup<'a> {
ModalPopup {
name,
opened: None,
flags: WindowFlags::empty(),
ui: self,
}
}
pub fn modal_popup<F, R>(&self, name: impl AsRef<str>, f: F) -> Option<R>
where
F: FnOnce() -> R,
{
self.begin_modal_popup(name).map(|_token| f())
}
pub fn modal_popup_with_opened<F, R>(
&self,
name: impl AsRef<str>,
opened: &mut bool,
f: F,
) -> Option<R>
where
F: FnOnce() -> R,
{
self.begin_modal_popup_with_opened(name, opened)
.map(|_token| f())
}
#[doc(alias = "CloseCurrentPopup")]
pub fn close_current_popup(&self) {
unsafe {
sys::igCloseCurrentPopup();
}
}
#[doc(alias = "IsPopupOpen")]
pub fn is_popup_open(&self, str_id: impl AsRef<str>) -> bool {
let str_id_ptr = self.scratch_txt(str_id);
unsafe { sys::igIsPopupOpen_Str(str_id_ptr, PopupFlags::NONE.bits()) }
}
#[doc(alias = "IsPopupOpen")]
pub fn is_popup_open_with_flags(&self, str_id: impl AsRef<str>, flags: PopupFlags) -> bool {
let str_id_ptr = self.scratch_txt(str_id);
unsafe { sys::igIsPopupOpen_Str(str_id_ptr, flags.bits()) }
}
#[doc(alias = "BeginPopupContextItem")]
pub fn begin_popup_context_item(&self) -> Option<PopupToken<'_>> {
self.begin_popup_context_item_with_flags(None, PopupContextOptions::new())
}
#[doc(alias = "BeginPopupContextItem")]
pub fn begin_popup_context_item_with_label(
&self,
str_id: Option<&str>,
) -> Option<PopupToken<'_>> {
self.begin_popup_context_item_with_flags(str_id, PopupContextOptions::new())
}
#[doc(alias = "BeginPopupContextItem")]
pub fn begin_popup_context_item_with_flags(
&self,
str_id: Option<&str>,
flags: impl Into<PopupContextOptions>,
) -> Option<PopupToken<'_>> {
let options = flags.into();
let str_id_ptr = str_id
.map(|s| self.scratch_txt(s))
.unwrap_or(std::ptr::null());
let render = unsafe { sys::igBeginPopupContextItem(str_id_ptr, options.raw()) };
render.then(|| PopupToken::new(self))
}
#[doc(alias = "BeginPopupContextWindow")]
pub fn begin_popup_context_window(&self) -> Option<PopupToken<'_>> {
self.begin_popup_context_window_with_flags(None, PopupContextOptions::new())
}
#[doc(alias = "BeginPopupContextWindow")]
pub fn begin_popup_context_window_with_label(
&self,
str_id: Option<&str>,
) -> Option<PopupToken<'_>> {
self.begin_popup_context_window_with_flags(str_id, PopupContextOptions::new())
}
#[doc(alias = "BeginPopupContextWindow")]
pub fn begin_popup_context_window_with_flags(
&self,
str_id: Option<&str>,
flags: impl Into<PopupContextOptions>,
) -> Option<PopupToken<'_>> {
let options = flags.into();
let str_id_ptr = str_id
.map(|s| self.scratch_txt(s))
.unwrap_or(std::ptr::null());
let render = unsafe { sys::igBeginPopupContextWindow(str_id_ptr, options.raw()) };
render.then(|| PopupToken::new(self))
}
#[doc(alias = "BeginPopupContextVoid")]
pub fn begin_popup_context_void(&self) -> Option<PopupToken<'_>> {
self.begin_popup_context_void_with_flags(None, PopupContextOptions::new())
}
#[doc(alias = "BeginPopupContextVoid")]
pub fn begin_popup_context_void_with_label(
&self,
str_id: Option<&str>,
) -> Option<PopupToken<'_>> {
self.begin_popup_context_void_with_flags(str_id, PopupContextOptions::new())
}
#[doc(alias = "BeginPopupContextVoid")]
pub fn begin_popup_context_void_with_flags(
&self,
str_id: Option<&str>,
flags: impl Into<PopupContextOptions>,
) -> Option<PopupToken<'_>> {
let options = flags.into();
let str_id_ptr = str_id
.map(|s| self.scratch_txt(s))
.unwrap_or(std::ptr::null());
let render = unsafe { sys::igBeginPopupContextVoid(str_id_ptr, options.raw()) };
render.then(|| PopupToken::new(self))
}
}
bitflags::bitflags! {
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct PopupFlags: i32 {
const NONE = sys::ImGuiPopupFlags_None as i32;
const NO_REOPEN = sys::ImGuiPopupFlags_NoReopen as i32;
const NO_OPEN_OVER_EXISTING_POPUP = sys::ImGuiPopupFlags_NoOpenOverExistingPopup as i32;
const NO_OPEN_OVER_ITEMS = sys::ImGuiPopupFlags_NoOpenOverItems as i32;
const ANY_POPUP_ID = sys::ImGuiPopupFlags_AnyPopupId as i32;
const ANY_POPUP_LEVEL = sys::ImGuiPopupFlags_AnyPopupLevel as i32;
const ANY_POPUP = Self::ANY_POPUP_ID.bits() | Self::ANY_POPUP_LEVEL.bits();
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum PopupContextMouseButton {
Left,
#[default]
Right,
Middle,
}
impl PopupContextMouseButton {
#[inline]
const fn raw(self) -> i32 {
match self {
Self::Left => sys::ImGuiPopupFlags_MouseButtonLeft as i32,
Self::Right => sys::ImGuiPopupFlags_MouseButtonRight as i32,
Self::Middle => sys::ImGuiPopupFlags_MouseButtonMiddle as i32,
}
}
}
impl From<MouseButton> for PopupContextMouseButton {
fn from(button: MouseButton) -> Self {
match button {
MouseButton::Left => Self::Left,
MouseButton::Right => Self::Right,
MouseButton::Middle => Self::Middle,
MouseButton::Extra1 | MouseButton::Extra2 => {
panic!(
"Dear ImGui popup context helpers only support left, right, and middle buttons"
)
}
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct PopupContextOptions {
pub flags: PopupFlags,
pub mouse_button: PopupContextMouseButton,
}
impl PopupContextOptions {
pub const fn new() -> Self {
Self {
flags: PopupFlags::NONE,
mouse_button: PopupContextMouseButton::Right,
}
}
pub fn flags(mut self, flags: PopupFlags) -> Self {
self.flags = flags;
self
}
pub fn mouse_button(mut self, button: impl Into<PopupContextMouseButton>) -> Self {
self.mouse_button = button.into();
self
}
pub fn bits(self) -> i32 {
self.raw()
}
#[inline]
pub(crate) fn raw(self) -> i32 {
self.flags.bits() | self.mouse_button.raw()
}
}
impl Default for PopupContextOptions {
fn default() -> Self {
Self::new()
}
}
impl From<PopupFlags> for PopupContextOptions {
fn from(flags: PopupFlags) -> Self {
Self::new().flags(flags)
}
}
impl From<PopupContextMouseButton> for PopupContextOptions {
fn from(button: PopupContextMouseButton) -> Self {
Self::new().mouse_button(button)
}
}
impl From<MouseButton> for PopupContextOptions {
fn from(button: MouseButton) -> Self {
Self::new().mouse_button(button)
}
}
#[derive(Debug)]
#[must_use]
pub struct ModalPopup<'ui> {
name: &'ui str,
opened: Option<&'ui mut bool>,
flags: WindowFlags,
ui: &'ui Ui,
}
impl<'ui> ModalPopup<'ui> {
pub fn opened(mut self, opened: &'ui mut bool) -> Self {
self.opened = Some(opened);
self
}
pub fn flags(mut self, flags: WindowFlags) -> Self {
self.flags = flags;
self
}
pub fn begin(self) -> Option<ModalPopupToken<'ui>> {
let name_ptr = self.ui.scratch_txt(self.name);
let opened_ptr = self
.opened
.map(|o| o as *mut bool)
.unwrap_or(std::ptr::null_mut());
let render = unsafe { sys::igBeginPopupModal(name_ptr, opened_ptr, self.flags.bits()) };
if render {
Some(ModalPopupToken::new(self.ui))
} else {
None
}
}
}
#[must_use]
pub struct PopupToken<'ui> {
_ui: &'ui Ui,
}
impl<'ui> PopupToken<'ui> {
fn new(ui: &'ui Ui) -> Self {
PopupToken { _ui: ui }
}
pub fn end(self) {
}
}
impl<'ui> Drop for PopupToken<'ui> {
fn drop(&mut self) {
unsafe {
sys::igEndPopup();
}
}
}
#[must_use]
pub struct ModalPopupToken<'ui> {
_ui: &'ui Ui,
}
impl<'ui> ModalPopupToken<'ui> {
fn new(ui: &'ui Ui) -> Self {
ModalPopupToken { _ui: ui }
}
pub fn end(self) {
}
}
impl<'ui> Drop for ModalPopupToken<'ui> {
fn drop(&mut self) {
unsafe {
sys::igEndPopup();
}
}
}