use bitflags::bitflags;
use std::marker::PhantomData;
use std::os::raw::{c_int, c_void};
use std::ptr;
use crate::imgui::{ImStr, ImString, Ui};
bitflags!(
#[repr(C)]
pub struct InputTextFlags: u32 {
const CHARS_DECIMAL = crate::imgui_sys::ImGuiInputTextFlags_CharsDecimal;
const CHARS_HEXADECIMAL = crate::imgui_sys::ImGuiInputTextFlags_CharsHexadecimal;
const CHARS_UPPERCASE = crate::imgui_sys::ImGuiInputTextFlags_CharsUppercase;
const CHARS_NO_BLANK = crate::imgui_sys::ImGuiInputTextFlags_CharsNoBlank;
const AUTO_SELECT_ALL = crate::imgui_sys::ImGuiInputTextFlags_AutoSelectAll;
const ENTER_RETURNS_TRUE = crate::imgui_sys::ImGuiInputTextFlags_EnterReturnsTrue;
const CALLBACK_COMPLETION = crate::imgui_sys::ImGuiInputTextFlags_CallbackCompletion;
const CALLBACK_HISTORY = crate::imgui_sys::ImGuiInputTextFlags_CallbackHistory;
const CALLBACK_ALWAYS = crate::imgui_sys::ImGuiInputTextFlags_CallbackAlways;
const CALLBACK_CHAR_FILTER = crate::imgui_sys::ImGuiInputTextFlags_CallbackCharFilter;
const ALLOW_TAB_INPUT = crate::imgui_sys::ImGuiInputTextFlags_AllowTabInput;
const CTRL_ENTER_FOR_NEW_LINE = crate::imgui_sys::ImGuiInputTextFlags_CtrlEnterForNewLine;
const NO_HORIZONTAL_SCROLL = crate::imgui_sys::ImGuiInputTextFlags_NoHorizontalScroll;
const ALWAYS_OVERWRITE = crate::imgui_sys::ImGuiInputTextFlags_AlwaysOverwrite;
const READ_ONLY = crate::imgui_sys::ImGuiInputTextFlags_ReadOnly;
const PASSWORD = crate::imgui_sys::ImGuiInputTextFlags_Password;
const NO_UNDO_REDO = crate::imgui_sys::ImGuiInputTextFlags_NoUndoRedo;
const CHARS_SCIENTIFIC = crate::imgui_sys::ImGuiInputTextFlags_CharsScientific;
const CALLBACK_RESIZE = crate::imgui_sys::ImGuiInputTextFlags_CallbackResize;
}
);
macro_rules! impl_text_flags {
($InputType:ident) => {
#[inline]
pub fn flags(mut self, flags: InputTextFlags) -> Self {
self.flags = flags;
self
}
#[inline]
pub fn chars_decimal(mut self, value: bool) -> Self {
self.flags.set(InputTextFlags::CHARS_DECIMAL, value);
self
}
#[inline]
pub fn chars_hexadecimal(mut self, value: bool) -> Self {
self.flags.set(InputTextFlags::CHARS_HEXADECIMAL, value);
self
}
#[inline]
pub fn chars_uppercase(mut self, value: bool) -> Self {
self.flags.set(InputTextFlags::CHARS_UPPERCASE, value);
self
}
#[inline]
pub fn chars_noblank(mut self, value: bool) -> Self {
self.flags.set(InputTextFlags::CHARS_NO_BLANK, value);
self
}
#[inline]
pub fn auto_select_all(mut self, value: bool) -> Self {
self.flags.set(InputTextFlags::AUTO_SELECT_ALL, value);
self
}
#[inline]
pub fn enter_returns_true(mut self, value: bool) -> Self {
self.flags.set(InputTextFlags::ENTER_RETURNS_TRUE, value);
self
}
#[inline]
pub fn callback_completion(mut self, value: bool) -> Self {
self.flags.set(InputTextFlags::CALLBACK_COMPLETION, value);
self
}
#[inline]
pub fn callback_history(mut self, value: bool) -> Self {
self.flags.set(InputTextFlags::CALLBACK_HISTORY, value);
self
}
#[inline]
pub fn callback_always(mut self, value: bool) -> Self {
self.flags.set(InputTextFlags::CALLBACK_ALWAYS, value);
self
}
#[inline]
pub fn callback_char_filter(mut self, value: bool) -> Self {
self.flags.set(InputTextFlags::CALLBACK_CHAR_FILTER, value);
self
}
#[inline]
pub fn resize_buffer(mut self, value: bool) -> Self {
self.flags.set(InputTextFlags::CALLBACK_RESIZE, value);
self
}
#[inline]
pub fn allow_tab_input(mut self, value: bool) -> Self {
self.flags.set(InputTextFlags::ALLOW_TAB_INPUT, value);
self
}
#[inline]
pub fn no_horizontal_scroll(mut self, value: bool) -> Self {
self.flags.set(InputTextFlags::NO_HORIZONTAL_SCROLL, value);
self
}
#[inline]
pub fn always_insert_mode(self, value: bool) -> Self {
self.always_overwrite(value)
}
#[inline]
#[allow(deprecated)]
pub fn always_overwrite(mut self, value: bool) -> Self {
self.flags.set(InputTextFlags::ALWAYS_OVERWRITE, value);
self
}
#[inline]
pub fn read_only(mut self, value: bool) -> Self {
self.flags.set(InputTextFlags::READ_ONLY, value);
self
}
#[inline]
pub fn password(mut self, value: bool) -> Self {
self.flags.set(InputTextFlags::PASSWORD, value);
self
}
#[inline]
pub fn no_undo_redo(mut self, value: bool) -> Self {
self.flags.set(InputTextFlags::NO_UNDO_REDO, value);
self
}
};
}
macro_rules! impl_step_params {
($InputType:ident, $Value:ty) => {
#[inline]
pub fn step(mut self, value: $Value) -> Self {
self.step = value;
self
}
#[inline]
pub fn step_fast(mut self, value: $Value) -> Self {
self.step_fast = value;
self
}
};
}
extern "C" fn resize_callback(data: *mut crate::imgui_sys::ImGuiInputTextCallbackData) -> c_int {
unsafe {
if (*data).EventFlag == InputTextFlags::CALLBACK_RESIZE.bits() as i32 {
if let Some(buffer) = ((*data).UserData as *mut ImString).as_mut() {
let requested_size = (*data).BufSize as usize;
if requested_size > buffer.capacity_with_nul() {
buffer.refresh_len();
buffer.reserve(requested_size - buffer.0.len());
debug_assert!(buffer.capacity_with_nul() >= requested_size);
(*data).Buf = buffer.as_mut_ptr();
(*data).BufDirty = true;
}
}
}
0
}
}
#[must_use]
pub struct InputText<'ui, 'p> {
label: &'p ImStr,
hint: Option<&'p ImStr>,
buf: &'p mut ImString,
flags: InputTextFlags,
_phantom: PhantomData<&'ui Ui<'ui>>,
}
impl<'ui, 'p> InputText<'ui, 'p> {
pub fn new(_: &Ui<'ui>, label: &'p ImStr, buf: &'p mut ImString) -> Self {
InputText {
label,
hint: None,
buf,
flags: InputTextFlags::empty(),
_phantom: PhantomData,
}
}
#[inline]
pub fn hint(mut self, hint: &'p ImStr) -> Self {
self.hint = Some(hint);
self
}
impl_text_flags!(InputText);
pub fn build(self) -> bool {
let (ptr, capacity) = (self.buf.as_mut_ptr(), self.buf.capacity_with_nul());
let (callback, data): (crate::imgui_sys::ImGuiInputTextCallback, _) = {
if self.flags.contains(InputTextFlags::CALLBACK_RESIZE) {
(Some(resize_callback), self.buf as *mut _ as *mut c_void)
} else {
(None, ptr::null_mut())
}
};
unsafe {
let result = if let Some(hint) = self.hint {
crate::imgui_sys::igInputTextWithHint(
self.label.as_ptr(),
hint.as_ptr(),
ptr,
capacity,
self.flags.bits() as i32,
callback,
data,
)
} else {
crate::imgui_sys::igInputText(
self.label.as_ptr(),
ptr,
capacity,
self.flags.bits() as i32,
callback,
data,
)
};
self.buf.refresh_len();
result
}
}
}
#[must_use]
pub struct InputTextMultiline<'ui, 'p> {
label: &'p ImStr,
buf: &'p mut ImString,
flags: InputTextFlags,
size: [f32; 2],
_phantom: PhantomData<&'ui Ui<'ui>>,
}
impl<'ui, 'p> InputTextMultiline<'ui, 'p> {
pub fn new(_: &Ui<'ui>, label: &'p ImStr, buf: &'p mut ImString, size: [f32; 2]) -> Self {
InputTextMultiline {
label,
buf,
flags: InputTextFlags::empty(),
size,
_phantom: PhantomData,
}
}
impl_text_flags!(InputText);
pub fn build(self) -> bool {
let (ptr, capacity) = (self.buf.as_mut_ptr(), self.buf.capacity_with_nul());
let (callback, data): (crate::imgui_sys::ImGuiInputTextCallback, _) = {
if self.flags.contains(InputTextFlags::CALLBACK_RESIZE) {
(Some(resize_callback), self.buf as *mut _ as *mut c_void)
} else {
(None, ptr::null_mut())
}
};
unsafe {
let result = crate::imgui_sys::igInputTextMultiline(
self.label.as_ptr(),
ptr,
capacity,
self.size.into(),
self.flags.bits() as i32,
callback,
data,
);
self.buf.refresh_len();
result
}
}
}
#[must_use]
pub struct InputInt<'ui, 'p> {
label: &'p ImStr,
value: &'p mut i32,
step: i32,
step_fast: i32,
flags: InputTextFlags,
_phantom: PhantomData<&'ui Ui<'ui>>,
}
impl<'ui, 'p> InputInt<'ui, 'p> {
pub fn new(_: &Ui<'ui>, label: &'p ImStr, value: &'p mut i32) -> Self {
InputInt {
label,
value,
step: 1,
step_fast: 100,
flags: InputTextFlags::empty(),
_phantom: PhantomData,
}
}
pub fn build(self) -> bool {
unsafe {
crate::imgui_sys::igInputInt(
self.label.as_ptr(),
self.value as *mut i32,
self.step,
self.step_fast,
self.flags.bits() as i32,
)
}
}
impl_step_params!(InputInt, i32);
impl_text_flags!(InputInt);
}
#[must_use]
pub struct InputFloat<'ui, 'p> {
label: &'p ImStr,
value: &'p mut f32,
step: f32,
step_fast: f32,
flags: InputTextFlags,
_phantom: PhantomData<&'ui Ui<'ui>>,
}
impl<'ui, 'p> InputFloat<'ui, 'p> {
pub fn new(_: &Ui<'ui>, label: &'p ImStr, value: &'p mut f32) -> Self {
InputFloat {
label,
value,
step: 0.0,
step_fast: 0.0,
flags: InputTextFlags::empty(),
_phantom: PhantomData,
}
}
pub fn build(self) -> bool {
unsafe {
crate::imgui_sys::igInputFloat(
self.label.as_ptr(),
self.value as *mut f32,
self.step,
self.step_fast,
b"%.3f\0".as_ptr() as *const _,
self.flags.bits() as i32,
)
}
}
impl_step_params!(InputFloat, f32);
impl_text_flags!(InputFloat);
}
macro_rules! impl_input_floatn {
($InputFloatN:ident, $N:expr, $igInputFloatN:ident) => {
#[must_use]
pub struct $InputFloatN<'ui, 'p> {
label: &'p ImStr,
value: &'p mut [f32; $N],
flags: InputTextFlags,
_phantom: PhantomData<&'ui Ui<'ui>>,
}
impl<'ui, 'p> $InputFloatN<'ui, 'p> {
pub fn new(_: &Ui<'ui>, label: &'p ImStr, value: &'p mut [f32; $N]) -> Self {
$InputFloatN {
label,
value,
flags: InputTextFlags::empty(),
_phantom: PhantomData,
}
}
pub fn build(self) -> bool {
unsafe {
crate::imgui_sys::$igInputFloatN(
self.label.as_ptr(),
self.value.as_mut_ptr(),
b"%.3f\0".as_ptr() as *const _,
self.flags.bits() as i32,
)
}
}
impl_text_flags!($InputFloatN);
}
};
}
impl_input_floatn!(InputFloat2, 2, igInputFloat2);
impl_input_floatn!(InputFloat3, 3, igInputFloat3);
impl_input_floatn!(InputFloat4, 4, igInputFloat4);
macro_rules! impl_input_intn {
($InputIntN:ident, $N:expr, $igInputIntN:ident) => {
#[must_use]
pub struct $InputIntN<'ui, 'p> {
label: &'p ImStr,
value: &'p mut [i32; $N],
flags: InputTextFlags,
_phantom: PhantomData<&'ui Ui<'ui>>,
}
impl<'ui, 'p> $InputIntN<'ui, 'p> {
pub fn new(_: &Ui<'ui>, label: &'p ImStr, value: &'p mut [i32; $N]) -> Self {
$InputIntN {
label,
value,
flags: InputTextFlags::empty(),
_phantom: PhantomData,
}
}
pub fn build(self) -> bool {
unsafe {
crate::imgui_sys::$igInputIntN(
self.label.as_ptr(),
self.value.as_mut_ptr(),
self.flags.bits() as i32,
)
}
}
impl_text_flags!($InputIntN);
}
};
}
impl_input_intn!(InputInt2, 2, igInputInt2);
impl_input_intn!(InputInt3, 3, igInputInt3);
impl_input_intn!(InputInt4, 4, igInputInt4);