use bitflags::bitflags;
use std::f32;
use std::ptr;
use std::thread;
use crate::context::Context;
use crate::string::ImStr;
use crate::sys;
use crate::{Condition, Ui};
pub(crate) mod child_window;
pub(crate) mod content_region;
pub(crate) mod scroll;
bitflags! {
#[repr(transparent)]
pub struct WindowHoveredFlags: u32 {
const CHILD_WINDOWS = sys::ImGuiHoveredFlags_ChildWindows;
const ROOT_WINDOW = sys::ImGuiHoveredFlags_RootWindow;
const ANY_WINDOW = sys::ImGuiHoveredFlags_AnyWindow;
const ALLOW_WHEN_BLOCKED_BY_POPUP = sys::ImGuiHoveredFlags_AllowWhenBlockedByPopup;
const ALLOW_WHEN_BLOCKED_BY_ACTIVE_ITEM = sys::ImGuiHoveredFlags_AllowWhenBlockedByActiveItem;
const ROOT_AND_CHILD_WINDOWS = Self::ROOT_WINDOW.bits | Self::CHILD_WINDOWS.bits;
}
}
bitflags! {
#[repr(transparent)]
pub struct WindowFocusedFlags: u32 {
const CHILD_WINDOWS = sys::ImGuiFocusedFlags_ChildWindows;
const ROOT_WINDOW = sys::ImGuiFocusedFlags_RootWindow;
const ANY_WINDOW = sys::ImGuiFocusedFlags_AnyWindow;
const ROOT_AND_CHILD_WINDOWS = Self::ROOT_WINDOW.bits | Self::CHILD_WINDOWS.bits;
}
}
bitflags! {
#[repr(transparent)]
pub struct WindowFlags: u32 {
const NO_TITLE_BAR = sys::ImGuiWindowFlags_NoTitleBar;
const NO_RESIZE = sys::ImGuiWindowFlags_NoResize;
const NO_MOVE = sys::ImGuiWindowFlags_NoMove;
const NO_SCROLLBAR = sys::ImGuiWindowFlags_NoScrollbar;
const NO_SCROLL_WITH_MOUSE = sys::ImGuiWindowFlags_NoScrollWithMouse;
const NO_COLLAPSE = sys::ImGuiWindowFlags_NoCollapse;
const ALWAYS_AUTO_RESIZE = sys::ImGuiWindowFlags_AlwaysAutoResize;
const NO_BACKGROUND = sys::ImGuiWindowFlags_NoBackground;
const NO_SAVED_SETTINGS = sys::ImGuiWindowFlags_NoSavedSettings;
const NO_MOUSE_INPUTS = sys::ImGuiWindowFlags_NoMouseInputs;
const MENU_BAR = sys::ImGuiWindowFlags_MenuBar;
const HORIZONTAL_SCROLLBAR = sys::ImGuiWindowFlags_HorizontalScrollbar;
const NO_FOCUS_ON_APPEARING = sys::ImGuiWindowFlags_NoFocusOnAppearing;
const NO_BRING_TO_FRONT_ON_FOCUS = sys::ImGuiWindowFlags_NoBringToFrontOnFocus;
const ALWAYS_VERTICAL_SCROLLBAR = sys::ImGuiWindowFlags_AlwaysVerticalScrollbar;
const ALWAYS_HORIZONTAL_SCROLLBAR = sys::ImGuiWindowFlags_AlwaysHorizontalScrollbar;
const ALWAYS_USE_WINDOW_PADDING = sys::ImGuiWindowFlags_AlwaysUseWindowPadding;
const NO_NAV_INPUTS = sys::ImGuiWindowFlags_NoNavInputs;
const NO_NAV_FOCUS = sys::ImGuiWindowFlags_NoNavFocus;
const UNSAVED_DOCUMENT = sys::ImGuiWindowFlags_UnsavedDocument;
const NO_NAV = sys::ImGuiWindowFlags_NoNav;
const NO_DECORATION = sys::ImGuiWindowFlags_NoDecoration;
const NO_INPUTS = sys::ImGuiWindowFlags_NoInputs;
}
}
impl<'ui> Ui<'ui> {
pub fn is_window_appearing(&self) -> bool {
unsafe { sys::igIsWindowAppearing() }
}
pub fn is_window_collapsed(&self) -> bool {
unsafe { sys::igIsWindowCollapsed() }
}
pub fn is_window_focused(&self) -> bool {
unsafe { sys::igIsWindowFocused(0) }
}
pub fn is_window_focused_with_flags(&self, flags: WindowFocusedFlags) -> bool {
unsafe { sys::igIsWindowFocused(flags.bits() as i32) }
}
pub fn is_window_hovered(&self) -> bool {
unsafe { sys::igIsWindowHovered(0) }
}
pub fn is_window_hovered_with_flags(&self, flags: WindowHoveredFlags) -> bool {
unsafe { sys::igIsWindowHovered(flags.bits() as i32) }
}
pub fn window_pos(&self) -> [f32; 2] {
let mut out = sys::ImVec2::zero();
unsafe { sys::igGetWindowPos(&mut out) };
out.into()
}
pub fn window_size(&self) -> [f32; 2] {
let mut out = sys::ImVec2::zero();
unsafe { sys::igGetWindowSize(&mut out) };
out.into()
}
}
#[derive(Debug)]
#[must_use]
pub struct Window<'a> {
name: &'a ImStr,
opened: Option<&'a mut bool>,
flags: WindowFlags,
pos: [f32; 2],
pos_cond: Condition,
pos_pivot: [f32; 2],
size: [f32; 2],
size_cond: Condition,
size_constraints: Option<([f32; 2], [f32; 2])>,
content_size: [f32; 2],
collapsed: bool,
collapsed_cond: Condition,
focused: bool,
bg_alpha: f32,
}
impl<'a> Window<'a> {
pub fn new(name: &ImStr) -> Window {
Window {
name,
opened: None,
flags: WindowFlags::empty(),
pos: [0.0, 0.0],
pos_cond: Condition::Never,
pos_pivot: [0.0, 0.0],
size: [0.0, 0.0],
size_cond: Condition::Never,
size_constraints: None,
content_size: [0.0, 0.0],
collapsed: false,
collapsed_cond: Condition::Never,
focused: false,
bg_alpha: f32::NAN,
}
}
#[inline]
pub fn opened(mut self, opened: &'a mut bool) -> Self {
self.opened = Some(opened);
self
}
#[inline]
pub fn flags(mut self, flags: WindowFlags) -> Self {
self.flags = flags;
self
}
#[inline]
pub fn position(mut self, position: [f32; 2], condition: Condition) -> Self {
self.pos = position;
self.pos_cond = condition;
self
}
#[inline]
pub fn position_pivot(mut self, pivot: [f32; 2]) -> Self {
self.pos_pivot = pivot;
self
}
#[inline]
pub fn size(mut self, size: [f32; 2], condition: Condition) -> Self {
self.size = size;
self.size_cond = condition;
self
}
#[inline]
pub fn size_constraints(mut self, size_min: [f32; 2], size_max: [f32; 2]) -> Self {
self.size_constraints = Some((size_min, size_max));
self
}
#[inline]
pub fn content_size(mut self, size: [f32; 2]) -> Self {
self.content_size = size;
self
}
#[inline]
pub fn collapsed(mut self, collapsed: bool, condition: Condition) -> Self {
self.collapsed = collapsed;
self.collapsed_cond = condition;
self
}
#[inline]
pub fn focused(mut self, focused: bool) -> Self {
self.focused = focused;
self
}
#[inline]
pub fn bg_alpha(mut self, bg_alpha: f32) -> Self {
self.bg_alpha = bg_alpha;
self
}
#[inline]
pub fn title_bar(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_TITLE_BAR, !value);
self
}
#[inline]
pub fn resizable(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_RESIZE, !value);
self
}
#[inline]
pub fn movable(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_MOVE, !value);
self
}
#[inline]
pub fn scroll_bar(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_SCROLLBAR, !value);
self
}
#[inline]
pub fn scrollable(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_SCROLL_WITH_MOUSE, !value);
self
}
#[inline]
pub fn collapsible(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_COLLAPSE, !value);
self
}
#[inline]
pub fn always_auto_resize(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::ALWAYS_AUTO_RESIZE, value);
self
}
#[inline]
pub fn draw_background(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_BACKGROUND, !value);
self
}
#[inline]
pub fn save_settings(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_SAVED_SETTINGS, !value);
self
}
#[inline]
pub fn mouse_inputs(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_MOUSE_INPUTS, !value);
self
}
#[inline]
pub fn menu_bar(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::MENU_BAR, value);
self
}
#[inline]
pub fn horizontal_scrollbar(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::HORIZONTAL_SCROLLBAR, value);
self
}
#[inline]
pub fn focus_on_appearing(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_FOCUS_ON_APPEARING, !value);
self
}
#[inline]
pub fn bring_to_front_on_focus(mut self, value: bool) -> Self {
self.flags
.set(WindowFlags::NO_BRING_TO_FRONT_ON_FOCUS, !value);
self
}
#[inline]
pub fn always_vertical_scrollbar(mut self, value: bool) -> Self {
self.flags
.set(WindowFlags::ALWAYS_VERTICAL_SCROLLBAR, value);
self
}
#[inline]
pub fn always_horizontal_scrollbar(mut self, value: bool) -> Self {
self.flags
.set(WindowFlags::ALWAYS_HORIZONTAL_SCROLLBAR, value);
self
}
#[inline]
pub fn always_use_window_padding(mut self, value: bool) -> Self {
self.flags
.set(WindowFlags::ALWAYS_USE_WINDOW_PADDING, value);
self
}
#[inline]
pub fn nav_inputs(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_NAV_INPUTS, !value);
self
}
#[inline]
pub fn nav_focus(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_NAV_FOCUS, !value);
self
}
#[inline]
pub fn unsaved_document(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::UNSAVED_DOCUMENT, value);
self
}
#[inline]
pub fn no_nav(mut self) -> Self {
self.flags |= WindowFlags::NO_NAV;
self
}
#[inline]
pub fn no_decoration(mut self) -> Self {
self.flags |= WindowFlags::NO_DECORATION;
self
}
#[inline]
pub fn no_inputs(mut self) -> Self {
self.flags |= WindowFlags::NO_INPUTS;
self
}
#[must_use]
pub fn begin(self, ui: &Ui) -> Option<WindowToken> {
if self.pos_cond != Condition::Never {
unsafe {
sys::igSetNextWindowPos(
self.pos.into(),
self.pos_cond as i32,
self.pos_pivot.into(),
)
};
}
if self.size_cond != Condition::Never {
unsafe { sys::igSetNextWindowSize(self.size.into(), self.size_cond as i32) };
}
if let Some((size_min, size_max)) = self.size_constraints {
unsafe {
sys::igSetNextWindowSizeConstraints(
size_min.into(),
size_max.into(),
None,
ptr::null_mut(),
)
};
}
if self.content_size[0] != 0.0 || self.content_size[1] != 0.0 {
unsafe { sys::igSetNextWindowContentSize(self.content_size.into()) };
}
if self.collapsed_cond != Condition::Never {
unsafe { sys::igSetNextWindowCollapsed(self.collapsed, self.collapsed_cond as i32) };
}
if self.focused {
unsafe { sys::igSetNextWindowFocus() };
}
if self.bg_alpha.is_finite() {
unsafe { sys::igSetNextWindowBgAlpha(self.bg_alpha) };
}
let should_render = unsafe {
sys::igBegin(
self.name.as_ptr(),
self.opened
.map(|x| x as *mut bool)
.unwrap_or(ptr::null_mut()),
self.flags.bits() as i32,
)
};
if should_render {
Some(WindowToken { ctx: ui.ctx })
} else {
unsafe { sys::igEnd() };
None
}
}
pub fn build<F: FnOnce()>(self, ui: &Ui, f: F) {
if let Some(window) = self.begin(ui) {
f();
window.end(ui);
}
}
}
pub struct WindowToken {
ctx: *const Context,
}
impl WindowToken {
pub fn end(mut self, _: &Ui) {
self.ctx = ptr::null();
unsafe { sys::igEnd() };
}
}
impl Drop for WindowToken {
fn drop(&mut self) {
if !self.ctx.is_null() && !thread::panicking() {
panic!("A WindowToken was leaked. Did you call .end()?");
}
}
}