mirror of
https://github.com/eliasstepanik/imgui-rs.git
synced 2026-01-13 06:28:36 +00:00
351 lines
12 KiB
Rust
351 lines
12 KiB
Rust
use std::marker::PhantomData;
|
|
use std::mem;
|
|
use std::os::raw::{c_char, c_void};
|
|
|
|
use crate::fonts::atlas::FontId;
|
|
use crate::internal::RawCast;
|
|
use crate::style::{StyleColor, StyleVar};
|
|
use crate::sys;
|
|
use crate::{Id, Ui};
|
|
|
|
/// # Parameter stacks (shared)
|
|
impl<'ui> Ui<'ui> {
|
|
/// Switches to the given font by pushing it to the font stack.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// Panics if the font atlas does not contain the given font
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// # use imgui::*;
|
|
/// # let mut ctx = Context::create();
|
|
/// # let font_data_sources = [];
|
|
/// // At initialization time
|
|
/// let my_custom_font = ctx.fonts().add_font(&font_data_sources);
|
|
/// # let ui = ctx.frame();
|
|
/// // During UI construction
|
|
/// let _token = ui.push_font(my_custom_font);
|
|
/// ui.text("I use the custom font!");
|
|
/// ```
|
|
#[must_use]
|
|
pub fn push_font(&self, id: FontId) -> FontStackToken {
|
|
let fonts = self.fonts();
|
|
let font = fonts
|
|
.get_font(id)
|
|
.expect("Font atlas did not contain the given font");
|
|
unsafe { sys::igPushFont(font.raw() as *const _ as *mut _) };
|
|
FontStackToken { _ui: PhantomData }
|
|
}
|
|
/// Changes a style color by pushing a change to the color stack.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// # use imgui::*;
|
|
/// # let mut ctx = Context::create();
|
|
/// # let ui = ctx.frame();
|
|
/// const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
|
|
/// let _token = ui.push_style_color(StyleColor::Text, RED);
|
|
/// ui.text("I'm red!");
|
|
/// ```
|
|
#[must_use]
|
|
pub fn push_style_color(&self, style_color: StyleColor, color: [f32; 4]) -> ColorStackToken {
|
|
unsafe { sys::igPushStyleColor(style_color as i32, color.into()) };
|
|
ColorStackToken {
|
|
count: 1,
|
|
_ui: PhantomData,
|
|
}
|
|
}
|
|
/// Changes style colors by pushing several changes to the color stack.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// # use imgui::*;
|
|
/// # let mut ctx = Context::create();
|
|
/// # let ui = ctx.frame();
|
|
/// const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
|
|
/// const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
|
|
/// let _token = ui.push_style_colors(&[
|
|
/// (StyleColor::Text, RED),
|
|
/// (StyleColor::TextDisabled, GREEN),
|
|
/// ]);
|
|
/// ui.text("I'm red!");
|
|
/// ui.text_disabled("I'm green!");
|
|
/// ```
|
|
#[must_use]
|
|
pub fn push_style_colors<'a, I>(&self, style_colors: I) -> ColorStackToken
|
|
where
|
|
I: IntoIterator<Item = &'a (StyleColor, [f32; 4])>,
|
|
{
|
|
let mut count = 0;
|
|
for &(style_color, color) in style_colors {
|
|
unsafe { sys::igPushStyleColor(style_color as i32, color.into()) };
|
|
count += 1;
|
|
}
|
|
ColorStackToken {
|
|
count,
|
|
_ui: PhantomData,
|
|
}
|
|
}
|
|
/// Changes a style variable by pushing a change to the style stack.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// # use imgui::*;
|
|
/// # let mut ctx = Context::create();
|
|
/// # let ui = ctx.frame();
|
|
/// let _token = ui.push_style_var(StyleVar::Alpha(0.2));
|
|
/// ui.text("I'm transparent!");
|
|
/// ```
|
|
#[must_use]
|
|
pub fn push_style_var(&self, style_var: StyleVar) -> StyleStackToken {
|
|
unsafe { push_style_var(style_var) };
|
|
StyleStackToken {
|
|
count: 1,
|
|
_ui: PhantomData,
|
|
}
|
|
}
|
|
/// Changes style variables by pushing several changes to the style stack.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// # use imgui::*;
|
|
/// # let mut ctx = Context::create();
|
|
/// # let ui = ctx.frame();
|
|
/// let _token = ui.push_style_vars(&[
|
|
/// StyleVar::Alpha(0.2),
|
|
/// StyleVar::ItemSpacing([50.0, 50.0])
|
|
/// ]);
|
|
/// ui.text("We're transparent...");
|
|
/// ui.text("...with large spacing as well");
|
|
/// ```
|
|
#[must_use]
|
|
pub fn push_style_vars<'a, I>(&self, style_vars: I) -> StyleStackToken
|
|
where
|
|
I: IntoIterator<Item = &'a StyleVar>,
|
|
{
|
|
let mut count = 0;
|
|
for &style_var in style_vars {
|
|
unsafe { push_style_var(style_var) };
|
|
count += 1;
|
|
}
|
|
StyleStackToken {
|
|
count,
|
|
_ui: PhantomData,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Represents a change pushed to the font stack
|
|
pub struct FontStackToken<'ui> {
|
|
_ui: PhantomData<&'ui Ui<'ui>>,
|
|
}
|
|
|
|
impl<'ui> Drop for FontStackToken<'ui> {
|
|
fn drop(&mut self) {
|
|
unsafe { sys::igPopFont() };
|
|
}
|
|
}
|
|
|
|
/// Represents one or more changes pushed to the color stack
|
|
pub struct ColorStackToken<'ui> {
|
|
count: usize,
|
|
_ui: PhantomData<&'ui Ui<'ui>>,
|
|
}
|
|
|
|
impl<'ui> Drop for ColorStackToken<'ui> {
|
|
fn drop(&mut self) {
|
|
unsafe { sys::igPopStyleColor(self.count as i32) };
|
|
}
|
|
}
|
|
|
|
/// Represents one or more changes pushed to the style stack
|
|
pub struct StyleStackToken<'ui> {
|
|
count: usize,
|
|
_ui: PhantomData<&'ui Ui<'ui>>,
|
|
}
|
|
|
|
impl<'ui> Drop for StyleStackToken<'ui> {
|
|
fn drop(&mut self) {
|
|
unsafe { sys::igPopStyleVar(self.count as i32) };
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
unsafe fn push_style_var(style_var: StyleVar) {
|
|
use crate::style::StyleVar::*;
|
|
use crate::sys::{igPushStyleVarFloat, igPushStyleVarVec2};
|
|
match style_var {
|
|
Alpha(v) => igPushStyleVarFloat(sys::ImGuiStyleVar_Alpha as i32, v),
|
|
WindowPadding(v) => igPushStyleVarVec2(sys::ImGuiStyleVar_WindowPadding as i32, v.into()),
|
|
WindowRounding(v) => igPushStyleVarFloat(sys::ImGuiStyleVar_WindowRounding as i32, v),
|
|
WindowBorderSize(v) => igPushStyleVarFloat(sys::ImGuiStyleVar_WindowBorderSize as i32, v),
|
|
WindowMinSize(v) => igPushStyleVarVec2(sys::ImGuiStyleVar_WindowMinSize as i32, v.into()),
|
|
WindowTitleAlign(v) => {
|
|
igPushStyleVarVec2(sys::ImGuiStyleVar_WindowTitleAlign as i32, v.into())
|
|
}
|
|
ChildRounding(v) => igPushStyleVarFloat(sys::ImGuiStyleVar_ChildRounding as i32, v),
|
|
ChildBorderSize(v) => igPushStyleVarFloat(sys::ImGuiStyleVar_ChildBorderSize as i32, v),
|
|
PopupRounding(v) => igPushStyleVarFloat(sys::ImGuiStyleVar_PopupRounding as i32, v),
|
|
PopupBorderSize(v) => igPushStyleVarFloat(sys::ImGuiStyleVar_PopupBorderSize as i32, v),
|
|
FramePadding(v) => igPushStyleVarVec2(sys::ImGuiStyleVar_FramePadding as i32, v.into()),
|
|
FrameRounding(v) => igPushStyleVarFloat(sys::ImGuiStyleVar_FrameRounding as i32, v),
|
|
FrameBorderSize(v) => igPushStyleVarFloat(sys::ImGuiStyleVar_FrameBorderSize as i32, v),
|
|
ItemSpacing(v) => igPushStyleVarVec2(sys::ImGuiStyleVar_ItemSpacing as i32, v.into()),
|
|
ItemInnerSpacing(v) => {
|
|
igPushStyleVarVec2(sys::ImGuiStyleVar_ItemInnerSpacing as i32, v.into())
|
|
}
|
|
IndentSpacing(v) => igPushStyleVarFloat(sys::ImGuiStyleVar_IndentSpacing as i32, v),
|
|
ScrollbarSize(v) => igPushStyleVarFloat(sys::ImGuiStyleVar_ScrollbarSize as i32, v),
|
|
ScrollbarRounding(v) => igPushStyleVarFloat(sys::ImGuiStyleVar_ScrollbarRounding as i32, v),
|
|
GrabMinSize(v) => igPushStyleVarFloat(sys::ImGuiStyleVar_GrabMinSize as i32, v),
|
|
GrabRounding(v) => igPushStyleVarFloat(sys::ImGuiStyleVar_GrabRounding as i32, v),
|
|
TabRounding(v) => igPushStyleVarFloat(sys::ImGuiStyleVar_TabRounding as i32, v),
|
|
ButtonTextAlign(v) => {
|
|
igPushStyleVarVec2(sys::ImGuiStyleVar_ButtonTextAlign as i32, v.into())
|
|
}
|
|
SelectableTextAlign(v) => {
|
|
igPushStyleVarVec2(sys::ImGuiStyleVar_SelectableTextAlign as i32, v.into())
|
|
}
|
|
}
|
|
}
|
|
|
|
/// # Parameter stacks (current window)
|
|
impl<'ui> Ui<'ui> {
|
|
/// Changes the item width by pushing a change to the item width stack.
|
|
///
|
|
/// - `> 0.0`: width is `item_width` pixels
|
|
/// - `= 0.0`: default to ~2/3 of window width
|
|
/// - `< 0.0`: `item_width` pixels relative to the right of window (-1.0 always aligns width to
|
|
/// the right side)
|
|
#[must_use]
|
|
pub fn push_item_width(&self, item_width: f32) -> ItemWidthStackToken {
|
|
unsafe { sys::igPushItemWidth(item_width) };
|
|
ItemWidthStackToken { _ui: PhantomData }
|
|
}
|
|
/// Sets the width of the next item.
|
|
///
|
|
/// - `> 0.0`: width is `item_width` pixels
|
|
/// - `= 0.0`: default to ~2/3 of window width
|
|
/// - `< 0.0`: `item_width` pixels relative to the right of window (-1.0 always aligns width to
|
|
/// the right side)
|
|
pub fn set_next_item_width(&self, item_width: f32) {
|
|
unsafe { sys::igSetNextItemWidth(item_width) };
|
|
}
|
|
/// Returns the width of the item given the pushed settings and the current cursor position
|
|
pub fn calc_item_width(&self) -> f32 {
|
|
unsafe { sys::igCalcItemWidth() }
|
|
}
|
|
/// Changes the text wrapping position by pushing a change to the text wrapping position stack.
|
|
///
|
|
/// - `> 0.0`: wrap at `wrap_pos_x` position in window local space
|
|
/// - `= 0.0`: wrap to end of window (or column)
|
|
/// - `< 0.0`: no wrapping
|
|
#[must_use]
|
|
pub fn push_text_wrap_pos(&self, wrap_pos_x: f32) -> TextWrapPosStackToken {
|
|
unsafe { sys::igPushTextWrapPos(wrap_pos_x) };
|
|
TextWrapPosStackToken { _ui: PhantomData }
|
|
}
|
|
/// Changes an item flag by pushing a change to the item flag stack
|
|
#[must_use]
|
|
pub fn push_item_flag(&self, item_flag: ItemFlag) -> ItemFlagsStackToken {
|
|
use self::ItemFlag::*;
|
|
match item_flag {
|
|
AllowKeyboardFocus(v) => unsafe { sys::igPushAllowKeyboardFocus(v) },
|
|
ButtonRepeat(v) => unsafe { sys::igPushButtonRepeat(v) },
|
|
}
|
|
ItemFlagsStackToken {
|
|
discriminant: mem::discriminant(&item_flag),
|
|
_ui: PhantomData,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// A temporary change in item flags
|
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
|
pub enum ItemFlag {
|
|
AllowKeyboardFocus(bool),
|
|
ButtonRepeat(bool),
|
|
}
|
|
|
|
/// Represents a change pushed to the item width stack
|
|
pub struct ItemWidthStackToken<'ui> {
|
|
_ui: PhantomData<&'ui Ui<'ui>>,
|
|
}
|
|
|
|
impl<'ui> Drop for ItemWidthStackToken<'ui> {
|
|
fn drop(&mut self) {
|
|
unsafe { sys::igPopItemWidth() };
|
|
}
|
|
}
|
|
|
|
/// Represents a change pushed to the text wrap position stack
|
|
pub struct TextWrapPosStackToken<'ui> {
|
|
_ui: PhantomData<&'ui Ui<'ui>>,
|
|
}
|
|
|
|
impl<'ui> Drop for TextWrapPosStackToken<'ui> {
|
|
fn drop(&mut self) {
|
|
unsafe { sys::igPopTextWrapPos() };
|
|
}
|
|
}
|
|
|
|
/// Represents a change pushed to the item flags stack
|
|
pub struct ItemFlagsStackToken<'ui> {
|
|
discriminant: mem::Discriminant<ItemFlag>,
|
|
_ui: PhantomData<&'ui Ui<'ui>>,
|
|
}
|
|
|
|
impl<'ui> Drop for ItemFlagsStackToken<'ui> {
|
|
fn drop(&mut self) {
|
|
const ALLOW_KEYBOARD_FOCUS: ItemFlag = ItemFlag::AllowKeyboardFocus(true);
|
|
const BUTTON_REPEAT: ItemFlag = ItemFlag::ButtonRepeat(true);
|
|
|
|
if self.discriminant == mem::discriminant(&ALLOW_KEYBOARD_FOCUS) {
|
|
unsafe { sys::igPopAllowKeyboardFocus() };
|
|
} else if self.discriminant == mem::discriminant(&BUTTON_REPEAT) {
|
|
unsafe { sys::igPopButtonRepeat() };
|
|
} else {
|
|
unreachable!();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// # ID stack
|
|
impl<'ui> Ui<'ui> {
|
|
/// Pushes an identifier to the ID stack
|
|
#[must_use]
|
|
pub fn push_id<'a, I: Into<Id<'a>>>(&self, id: I) -> IdStackToken {
|
|
let id = id.into();
|
|
|
|
unsafe {
|
|
match id {
|
|
Id::Int(i) => sys::igPushIDInt(i),
|
|
Id::Str(s) => {
|
|
let start = s.as_ptr() as *const c_char;
|
|
let end = start.add(s.len());
|
|
sys::igPushIDRange(start, end)
|
|
}
|
|
Id::Ptr(p) => sys::igPushIDPtr(p as *const c_void),
|
|
}
|
|
}
|
|
IdStackToken { _ui: PhantomData }
|
|
}
|
|
}
|
|
|
|
/// Represents a change pushed to the ID stack
|
|
pub struct IdStackToken<'ui> {
|
|
_ui: PhantomData<&'ui Ui<'ui>>,
|
|
}
|
|
|
|
impl<'ui> Drop for IdStackToken<'ui> {
|
|
fn drop(&mut self) {
|
|
unsafe { sys::igPopID() };
|
|
}
|
|
}
|