getting close! input_text resize is broken,

and i'll need to check the imgui docs example with std::string
to get a reference to how to do it properly.
This commit is contained in:
Jack Mac 2021-09-11 19:03:20 -04:00
parent e0125f4c06
commit 694cd96d49
14 changed files with 436 additions and 302 deletions

View File

@ -11,7 +11,7 @@ fn main() {
let mut uncaptured_counter = 0u32;
let mut home_counter = 0u32;
let mut f1_release_count = 0u32;
let mut text_buffer = ImString::new("");
let mut text_buffer = String::new();
system.main_loop(move |_, ui| {
Window::new(im_str!("Means of accessing key state"))

View File

@ -25,13 +25,13 @@ struct State {
no_menu: bool,
no_close: bool,
wrap_width: f32,
buf: ImString,
buf: String,
item: usize,
item2: usize,
item3: i32,
text: ImString,
text_with_hint: ImString,
text_multiline: ImString,
text: String,
text_with_hint: String,
text_multiline: String,
i0: i32,
f0: f32,
vec2f: [f32; 2],
@ -57,12 +57,12 @@ struct State {
impl Default for State {
fn default() -> Self {
let mut buf = ImString::with_capacity(32);
let mut buf = String::with_capacity(32);
buf.push_str("日本語");
let mut text = ImString::with_capacity(128);
let mut text = String::with_capacity(128);
text.push_str("Hello, world!");
let text_with_hint = ImString::with_capacity(128);
let mut text_multiline = ImString::with_capacity(128);
let text_with_hint = String::with_capacity(128);
let mut text_multiline = String::with_capacity(128);
text_multiline.push_str("Hello, world!\nMultiline");
State {
show_app_main_menu_bar: false,
@ -873,9 +873,7 @@ fn show_example_menu_file<'a>(ui: &Ui<'a>, state: &mut FileMenuState) {
}
menu.end();
}
MenuItem::new(im_str!("Save"))
.shortcut("Ctrl+S")
.build(ui);
MenuItem::new(im_str!("Save")).shortcut("Ctrl+S").build(ui);
MenuItem::new(im_str!("Save As..")).build(ui);
ui.separator();
if let Some(menu) = ui.begin_menu(im_str!("Options")) {
@ -908,9 +906,7 @@ fn show_example_menu_file<'a>(ui: &Ui<'a>, state: &mut FileMenuState) {
.begin_menu_with_enabled(im_str!("Disabled"), false)
.is_none());
MenuItem::new(im_str!("Checked")).selected(true).build(ui);
MenuItem::new(im_str!("Quit"))
.shortcut("Alt+F4")
.build(ui);
MenuItem::new(im_str!("Quit")).shortcut("Alt+F4").build(ui);
}
fn show_example_app_auto_resize(ui: &Ui, state: &mut AutoResizeState, opened: &mut bool) {

View File

@ -4,11 +4,7 @@ mod support;
fn main() {
let system = support::init(file!());
let mut buffers = vec![
ImString::default(),
ImString::default(),
ImString::default(),
];
let mut buffers = vec![String::default(), String::default(), String::default()];
system.main_loop(move |_, ui| {
Window::new(im_str!("Input text callbacks"))
@ -70,13 +66,13 @@ fn main() {
ui.separator();
ui.text("You can also define a callback on structs with data.");
ui.text("Here we implement the callback handler on a wrapper around &mut ImString");
ui.text("Here we implement the callback handler on a wrapper around &mut String");
ui.text("to duplicate edits to buf0 on buf1");
struct Wrapper<'a>(&'a mut ImString);
struct Wrapper<'a>(&'a mut String);
impl<'a> InputTextCallbackHandler for Wrapper<'a> {
fn on_always(&mut self, data: TextCallbackData<'_>) {
*self.0 = im_str!("{}", data.str());
*self.0 = data.str().to_owned();
}
}
@ -137,10 +133,7 @@ fn main() {
}
ui.input_text(im_str!("Wild buf2 editor"), buf2)
.callback(
InputTextCallback::HISTORY,
Wrapper2(buf0.to_str(), buf1.to_str()),
)
.callback(InputTextCallback::HISTORY, Wrapper2(buf0, buf1))
.build();
ui.text(

View File

@ -10,9 +10,7 @@ use gfx::texture::{FilterMethod, SamplerInfo, WrapMode};
use gfx::traits::FactoryExt;
use gfx::{CommandBuffer, Encoder, Factory, IntoIndexBuffer, Rect, Resources, Slice};
use imgui::internal::RawWrapper;
use imgui::{
BackendFlags, DrawCmd, DrawCmdParams, DrawData, DrawIdx, ImString, TextureId, Textures,
};
use imgui::{BackendFlags, DrawCmd, DrawCmdParams, DrawData, DrawIdx, TextureId, Textures};
use std::error::Error;
use std::fmt;
use std::usize;
@ -178,10 +176,10 @@ where
instances: None,
buffer: index_buffer.clone().into_index_buffer(factory),
};
ctx.set_renderer_name(Some(ImString::from(format!(
ctx.set_renderer_name(Some(format!(
"imgui-gfx-renderer {}",
env!("CARGO_PKG_VERSION")
))));
)));
ctx.io_mut()
.backend_flags
.insert(BackendFlags::RENDERER_HAS_VTX_OFFSET);

View File

@ -13,7 +13,7 @@ use glium::{
Surface, Texture2d, VertexBuffer,
};
use imgui::internal::RawWrapper;
use imgui::{BackendFlags, DrawCmd, DrawCmdParams, DrawData, ImString, TextureId, Textures};
use imgui::{BackendFlags, DrawCmd, DrawCmdParams, DrawData, TextureId, Textures};
use std::borrow::Cow;
use std::error::Error;
use std::fmt;
@ -143,10 +143,10 @@ impl Renderer {
) -> Result<Renderer, RendererError> {
let program = compile_default_program(facade)?;
let font_texture = upload_font_texture(ctx.fonts(), facade.get_context())?;
ctx.set_renderer_name(Some(ImString::from(format!(
ctx.set_renderer_name(Some(format!(
"imgui-glium-renderer {}",
env!("CARGO_PKG_VERSION")
))));
)));
ctx.io_mut()
.backend_flags
.insert(BackendFlags::RENDERER_HAS_VTX_OFFSET);

View File

@ -174,7 +174,7 @@ use winit_20 as winit;
))]
use winit_19 as winit;
use imgui::{self, BackendFlags, ConfigFlags, Context, ImString, Io, Key, Ui};
use imgui::{self, BackendFlags, ConfigFlags, Context, Io, Key, Ui};
use std::cell::Cell;
use std::cmp::Ordering;
use winit::dpi::{LogicalPosition, LogicalSize};
@ -459,10 +459,10 @@ impl WinitPlatform {
io[Key::X] = VirtualKeyCode::X as _;
io[Key::Y] = VirtualKeyCode::Y as _;
io[Key::Z] = VirtualKeyCode::Z as _;
imgui.set_platform_name(Some(ImString::from(format!(
imgui.set_platform_name(Some(format!(
"imgui-winit-support {}",
env!("CARGO_PKG_VERSION")
))));
)));
WinitPlatform {
hidpi_mode: ActiveHiDpiMode::Default,
hidpi_factor: 1.0,

View File

@ -1,12 +1,11 @@
use crate::string::ImStr;
use crate::sys;
use crate::Ui;
/// # Columns
impl<'ui> Ui<'ui> {
#[doc(alias = "Columns")]
pub fn columns(&self, count: i32, id: &ImStr, border: bool) {
unsafe { sys::igColumns(count, id.as_ptr(), border) }
pub fn columns(&self, count: i32, id: impl AsRef<str>, border: bool) {
unsafe { sys::igColumns(count, self.scratch_txt(id), border) }
}
/// Switches to the next column.
///

View File

@ -1,6 +1,6 @@
use parking_lot::ReentrantMutex;
use std::cell::RefCell;
use std::ffi::CStr;
use std::ffi::{CStr, CString};
use std::ops::Drop;
use std::path::PathBuf;
use std::ptr;
@ -9,7 +9,6 @@ use std::rc::Rc;
use crate::clipboard::{ClipboardBackend, ClipboardContext};
use crate::fonts::atlas::{FontAtlas, FontAtlasRefMut, FontId, SharedFontAtlas};
use crate::io::Io;
use crate::string::{ImStr, ImString};
use crate::style::Style;
use crate::sys;
use crate::Ui;
@ -52,10 +51,10 @@ use crate::Ui;
pub struct Context {
raw: *mut sys::ImGuiContext,
shared_font_atlas: Option<Rc<RefCell<SharedFontAtlas>>>,
ini_filename: Option<ImString>,
log_filename: Option<ImString>,
platform_name: Option<ImString>,
renderer_name: Option<ImString>,
ini_filename: Option<CString>,
log_filename: Option<CString>,
platform_name: Option<CString>,
renderer_name: Option<CString>,
clipboard_ctx: Option<ClipboardContext>,
}
@ -109,18 +108,17 @@ impl Context {
if io.ini_filename.is_null() {
None
} else {
let s = unsafe { ImStr::from_ptr_unchecked(io.ini_filename) };
Some(PathBuf::from(s.to_str().to_owned()))
let s = unsafe { CStr::from_ptr(io.ini_filename) };
Some(PathBuf::from(s.to_str().ok()?))
}
}
/// Sets the path to the ini file (default is "imgui.ini")
///
/// Pass None to disable automatic .Ini saving.
pub fn set_ini_filename<T: Into<Option<PathBuf>>>(&mut self, ini_filename: T) {
let ini_filename = ini_filename
.into()
.and_then(|path| path.to_str().map(str::to_owned))
.map(ImString::from);
let ini_filename: Option<PathBuf> = ini_filename.into();
let ini_filename = ini_filename.and_then(|v| CString::new(v.to_str()?).ok());
self.io_mut().ini_filename = ini_filename
.as_ref()
.map(|x| x.as_ptr())
@ -128,21 +126,22 @@ impl Context {
self.ini_filename = ini_filename;
}
/// Returns the path to the log file, or None if not set
// TODO: why do we return an `Option<PathBuf>` instead of an `Option<&Path>`?
pub fn log_filename(&self) -> Option<PathBuf> {
let io = self.io();
if io.log_filename.is_null() {
None
} else {
let s = unsafe { ImStr::from_ptr_unchecked(io.log_filename) };
Some(PathBuf::from(s.to_str().to_owned()))
let cstr = unsafe { CStr::from_ptr(io.log_filename) };
Some(PathBuf::from(cstr.to_str().ok()?))
}
}
/// Sets the log filename (default is "imgui_log.txt").
pub fn set_log_filename<T: Into<Option<PathBuf>>>(&mut self, log_filename: T) {
let log_filename = log_filename
.into()
.and_then(|path| path.to_str().map(str::to_owned))
.map(ImString::from);
.and_then(|v| CString::new(v.to_str()?).ok());
self.io_mut().log_filename = log_filename
.as_ref()
.map(|x| x.as_ptr())
@ -150,17 +149,19 @@ impl Context {
self.log_filename = log_filename;
}
/// Returns the backend platform name, or None if not set
pub fn platform_name(&self) -> Option<&ImStr> {
pub fn platform_name(&self) -> Option<&str> {
let io = self.io();
if io.backend_platform_name.is_null() {
None
} else {
unsafe { Some(ImStr::from_ptr_unchecked(io.backend_platform_name)) }
let cstr = unsafe { CStr::from_ptr(io.backend_platform_name) };
cstr.to_str().ok()
}
}
/// Sets the backend platform name
pub fn set_platform_name<T: Into<Option<ImString>>>(&mut self, platform_name: T) {
let platform_name = platform_name.into();
pub fn set_platform_name<T: Into<Option<String>>>(&mut self, platform_name: T) {
let platform_name: Option<CString> =
platform_name.into().and_then(|v| CString::new(v).ok());
self.io_mut().backend_platform_name = platform_name
.as_ref()
.map(|x| x.as_ptr())
@ -168,21 +169,25 @@ impl Context {
self.platform_name = platform_name;
}
/// Returns the backend renderer name, or None if not set
pub fn renderer_name(&self) -> Option<&ImStr> {
pub fn renderer_name(&self) -> Option<&str> {
let io = self.io();
if io.backend_renderer_name.is_null() {
None
} else {
unsafe { Some(ImStr::from_ptr_unchecked(io.backend_renderer_name)) }
let cstr = unsafe { CStr::from_ptr(io.backend_renderer_name) };
cstr.to_str().ok()
}
}
/// Sets the backend renderer name
pub fn set_renderer_name<T: Into<Option<ImString>>>(&mut self, renderer_name: T) {
let renderer_name = renderer_name.into();
pub fn set_renderer_name<T: Into<Option<String>>>(&mut self, renderer_name: T) {
let renderer_name: Option<CString> =
renderer_name.into().and_then(|v| CString::new(v).ok());
self.io_mut().backend_renderer_name = renderer_name
.as_ref()
.map(|x| x.as_ptr())
.unwrap_or(ptr::null());
self.renderer_name = renderer_name;
}
/// Loads settings from a string slice containing settings in .Ini file format
@ -527,7 +532,7 @@ impl Context {
Ui {
ctx: self,
font_atlas,
buffer: Vec::new().into(),
buffer: crate::UiBuffer::new(1024).into(),
}
}
}

View File

@ -28,7 +28,7 @@
//! For examples of each payload type, see [DragDropSource].
use std::{any, ffi, marker::PhantomData};
use crate::{sys, Condition, ImStr, Ui};
use crate::{sys, Condition, Ui};
use bitflags::bitflags;
bitflags!(
@ -92,18 +92,17 @@ bitflags!(
/// will manage, and then give to a [DragDropTarget], which will received the payload. The
/// simplest and safest Payload is the empty payload, created with [begin](Self::begin).
#[derive(Debug)]
pub struct DragDropSource<'a> {
name: &'a ImStr,
pub struct DragDropSource<T> {
name: T,
flags: DragDropFlags,
cond: Condition,
}
impl<'a> DragDropSource<'a> {
impl<T: AsRef<str>> DragDropSource<T> {
/// Creates a new [DragDropSource] with no flags and the `Condition::Always` with the given name.
/// ImGui refers to this `name` field as a `type`, but really it's just an identifier to match up
/// Source/Target for DragDrop.
#[inline]
pub const fn new(name: &'a ImStr) -> Self {
pub fn new(name: T) -> Self {
Self {
name,
flags: DragDropFlags::empty(),
@ -116,14 +115,14 @@ impl<'a> DragDropSource<'a> {
/// `SOURCE_EXTERN`, `SOURCE_AUTO_EXPIRE_PAYLOAD` make semantic sense, but any other flags will
/// be accepted without panic.
#[inline]
pub const fn flags(mut self, flags: DragDropFlags) -> Self {
pub fn flags(mut self, flags: DragDropFlags) -> Self {
self.flags = flags;
self
}
/// Sets the condition on the [DragDropSource]. Defaults to [Always](Condition::Always).
#[inline]
pub const fn condition(mut self, cond: Condition) -> Self {
pub fn condition(mut self, cond: Condition) -> Self {
self.cond = cond;
self
}
@ -223,17 +222,17 @@ impl<'a> DragDropSource<'a> {
/// }
/// ```
#[inline]
pub fn begin_payload<'ui, T: Copy + 'static>(
pub fn begin_payload<'ui, P: Copy + 'static>(
self,
ui: &Ui<'ui>,
payload: T,
payload: P,
) -> Option<DragDropSourceToolTip<'ui>> {
unsafe {
let payload = TypedPayload::new(payload);
self.begin_payload_unchecked(
ui,
&payload as *const _ as *const ffi::c_void,
std::mem::size_of::<TypedPayload<T>>(),
std::mem::size_of::<TypedPayload<P>>(),
)
}
}
@ -267,14 +266,14 @@ impl<'a> DragDropSource<'a> {
#[inline]
pub unsafe fn begin_payload_unchecked<'ui>(
&self,
_ui: &Ui<'ui>,
ui: &Ui<'ui>,
ptr: *const ffi::c_void,
size: usize,
) -> Option<DragDropSourceToolTip<'ui>> {
let should_begin = sys::igBeginDragDropSource(self.flags.bits() as i32);
if should_begin {
sys::igSetDragDropPayload(self.name.as_ptr(), ptr, size, self.cond as i32);
sys::igSetDragDropPayload(ui.scratch_txt(&self.name), ptr, size, self.cond as i32);
Some(DragDropSourceToolTip::push())
} else {
@ -340,17 +339,17 @@ impl Drop for DragDropSourceToolTip<'_> {
/// on this struct. Each of these methods will spit out a _Payload struct with an increasing
/// amount of information on the Payload. The absolute safest solution is [accept_payload_empty](Self::accept_payload_empty).
#[derive(Debug)]
pub struct DragDropTarget<'ui>(PhantomData<Ui<'ui>>);
pub struct DragDropTarget<'ui>(&'ui Ui<'ui>);
impl<'ui> DragDropTarget<'ui> {
/// Creates a new DragDropTarget, holding the [Ui]'s lifetime for the duration
/// of its existence. This is required since this struct runs some code on its Drop
/// to end the DragDropTarget code.
#[doc(alias = "BeginDragDropTarget")]
pub fn new(_ui: &Ui<'_>) -> Option<Self> {
pub fn new(ui: &'ui Ui<'ui>) -> Option<Self> {
let should_begin = unsafe { sys::igBeginDragDropTarget() };
if should_begin {
Some(Self(PhantomData))
Some(Self(ui))
} else {
None
}
@ -364,12 +363,12 @@ impl<'ui> DragDropTarget<'ui> {
/// to use this function. Use `accept_payload_unchecked` instead
pub fn accept_payload_empty(
&self,
name: &ImStr,
name: impl AsRef<str>,
flags: DragDropFlags,
) -> Option<DragDropPayloadEmpty> {
self.accept_payload::<()>(name, flags)?
self.accept_payload(name, flags)?
.ok()
.map(|payload_pod| DragDropPayloadEmpty {
.map(|payload_pod: DragDropPayloadPod<()>| DragDropPayloadEmpty {
preview: payload_pod.preview,
delivery: payload_pod.delivery,
})
@ -382,7 +381,7 @@ impl<'ui> DragDropTarget<'ui> {
/// to use this function. Use `accept_payload_unchecked` instead
pub fn accept_payload<T: 'static + Copy>(
&self,
name: &ImStr,
name: impl AsRef<str>,
flags: DragDropFlags,
) -> Option<Result<DragDropPayloadPod<T>, PayloadIsWrongType>> {
let output = unsafe { self.accept_payload_unchecked(name, flags) };
@ -435,10 +434,10 @@ impl<'ui> DragDropTarget<'ui> {
/// of the various edge cases.
pub unsafe fn accept_payload_unchecked(
&self,
name: &ImStr,
name: impl AsRef<str>,
flags: DragDropFlags,
) -> Option<DragDropPayload> {
let inner = sys::igAcceptDragDropPayload(name.as_ptr(), flags.bits() as i32);
let inner = sys::igAcceptDragDropPayload(self.0.scratch_txt(name), flags.bits() as i32);
if inner.is_null() {
None
} else {

View File

@ -1,10 +1,9 @@
use bitflags::bitflags;
use std::marker::PhantomData;
use std::ops::Range;
use std::os::raw::{c_char, c_int, c_void};
use crate::sys;
use crate::{ImStr, ImString, Ui};
use crate::Ui;
bitflags!(
/// Flags for text inputs
@ -160,17 +159,17 @@ macro_rules! impl_step_params {
}
#[must_use]
pub struct InputText<'ui, 'p, T = PassthroughCallback> {
label: &'p ImStr,
hint: Option<&'p ImStr>,
buf: &'p mut ImString,
pub struct InputText<'ui, 'p, L, H = &'static str, T = PassthroughCallback> {
label: L,
hint: Option<H>,
buf: &'p mut String,
callback_handler: T,
flags: InputTextFlags,
_phantom: PhantomData<&'ui Ui<'ui>>,
ui: &'ui Ui<'ui>,
}
impl<'ui, 'p> InputText<'ui, 'p, PassthroughCallback> {
pub fn new(_: &Ui<'ui>, label: &'p ImStr, buf: &'p mut ImString) -> Self {
impl<'ui, 'p, L: AsRef<str>> InputText<'ui, 'p, L> {
pub fn new(ui: &'ui Ui<'ui>, label: L, buf: &'p mut String) -> Self {
InputText {
label,
hint: None,
@ -178,17 +177,28 @@ impl<'ui, 'p> InputText<'ui, 'p, PassthroughCallback> {
callback_handler: PassthroughCallback,
buf,
flags: InputTextFlags::CALLBACK_RESIZE,
_phantom: PhantomData,
ui,
}
}
}
impl<'ui, 'p, T: InputTextCallbackHandler> InputText<'ui, 'p, T> {
impl<'ui, 'p, T, L, H> InputText<'ui, 'p, L, H, T>
where
L: AsRef<str>,
H: AsRef<str>,
T: InputTextCallbackHandler,
{
/// Sets the hint displayed in the input text background.
#[inline]
pub fn hint(mut self, hint: &'p ImStr) -> Self {
self.hint = Some(hint);
self
pub fn hint<H2: AsRef<str>>(self, hint: H2) -> InputText<'ui, 'p, L, H2, T> {
InputText {
label: self.label,
hint: Some(hint),
buf: self.buf,
callback_handler: self.callback_handler,
flags: self.flags,
ui: self.ui,
}
}
impl_text_flags!(InputText);
@ -209,7 +219,7 @@ impl<'ui, 'p, T: InputTextCallbackHandler> InputText<'ui, 'p, T> {
mut self,
callbacks: InputTextCallback,
callback: T2,
) -> InputText<'ui, 'p, T2> {
) -> InputText<'ui, 'p, L, H, T2> {
if callbacks.contains(InputTextCallback::COMPLETION) {
self.flags.insert(InputTextFlags::CALLBACK_COMPLETION);
}
@ -231,12 +241,12 @@ impl<'ui, 'p, T: InputTextCallbackHandler> InputText<'ui, 'p, T> {
hint: self.hint,
buf: self.buf,
flags: self.flags,
_phantom: self._phantom,
ui: self.ui,
}
}
pub fn build(self) -> bool {
let (ptr, capacity) = (self.buf.as_mut_ptr(), self.buf.capacity_with_nul());
let (ptr, capacity) = (self.buf.as_mut_ptr(), self.buf.capacity());
let mut data = UserData {
container: self.buf,
@ -245,57 +255,57 @@ impl<'ui, 'p, T: InputTextCallbackHandler> InputText<'ui, 'p, T> {
let data = &mut data as *mut _ as *mut c_void;
unsafe {
let result = if let Some(hint) = self.hint {
if let Some(hint) = self.hint {
let (label, hint) = self.ui.scratch_txt_two(self.label, hint);
sys::igInputTextWithHint(
self.label.as_ptr(),
hint.as_ptr(),
ptr,
label,
hint,
ptr as *mut sys::cty::c_char,
capacity,
self.flags.bits() as i32,
Some(callback::<T>),
data,
)
} else {
let label = self.ui.scratch_txt(self.label);
sys::igInputText(
self.label.as_ptr(),
ptr,
label,
ptr as *mut sys::cty::c_char,
capacity,
self.flags.bits() as i32,
Some(callback::<T>),
data,
)
};
self.buf.refresh_len();
result
}
}
}
}
#[must_use]
pub struct InputTextMultiline<'ui, 'p, T = PassthroughCallback> {
label: &'p ImStr,
buf: &'p mut ImString,
pub struct InputTextMultiline<'ui, 'p, L, T = PassthroughCallback> {
label: L,
buf: &'p mut String,
flags: InputTextFlags,
size: [f32; 2],
callback_handler: T,
_phantom: PhantomData<&'ui Ui<'ui>>,
ui: &'ui Ui<'ui>,
}
impl<'ui, 'p> InputTextMultiline<'ui, 'p, PassthroughCallback> {
pub fn new(_: &Ui<'ui>, label: &'p ImStr, buf: &'p mut ImString, size: [f32; 2]) -> Self {
impl<'ui, 'p, L: AsRef<str>> InputTextMultiline<'ui, 'p, L, PassthroughCallback> {
pub fn new(ui: &'ui Ui<'ui>, label: L, buf: &'p mut String, size: [f32; 2]) -> Self {
InputTextMultiline {
label,
buf,
flags: InputTextFlags::CALLBACK_RESIZE,
size,
// this is safe because
callback_handler: PassthroughCallback,
_phantom: PhantomData,
ui,
}
}
}
impl<'ui, 'p, T: InputTextCallbackHandler> InputTextMultiline<'ui, 'p, T> {
impl<'ui, 'p, T: InputTextCallbackHandler, L: AsRef<str>> InputTextMultiline<'ui, 'p, L, T> {
impl_text_flags!(InputText);
/// By default (as of 0.8.0), imgui-rs will automatically handle string resizes
@ -314,7 +324,7 @@ impl<'ui, 'p, T: InputTextCallbackHandler> InputTextMultiline<'ui, 'p, T> {
mut self,
callbacks: InputTextMultilineCallback,
callback_handler: T2,
) -> InputTextMultiline<'ui, 'p, T2> {
) -> InputTextMultiline<'ui, 'p, L, T2> {
if callbacks.contains(InputTextMultilineCallback::COMPLETION) {
self.flags.insert(InputTextFlags::CALLBACK_COMPLETION);
}
@ -334,12 +344,12 @@ impl<'ui, 'p, T: InputTextCallbackHandler> InputTextMultiline<'ui, 'p, T> {
flags: self.flags,
size: self.size,
callback_handler,
_phantom: self._phantom,
ui: self.ui,
}
}
pub fn build(self) -> bool {
let (ptr, capacity) = (self.buf.as_mut_ptr(), self.buf.capacity_with_nul());
let (ptr, capacity) = (self.buf.as_mut_ptr(), self.buf.capacity());
let mut data = UserData {
container: self.buf,
@ -348,47 +358,45 @@ impl<'ui, 'p, T: InputTextCallbackHandler> InputTextMultiline<'ui, 'p, T> {
let data = &mut data as *mut _ as *mut c_void;
unsafe {
let result = sys::igInputTextMultiline(
self.label.as_ptr(),
ptr,
sys::igInputTextMultiline(
self.ui.scratch_txt(self.label),
ptr as *mut sys::cty::c_char,
capacity,
self.size.into(),
self.flags.bits() as i32,
Some(callback::<T>),
data,
);
self.buf.refresh_len();
result
)
}
}
}
#[must_use]
pub struct InputInt<'ui, 'p> {
label: &'p ImStr,
pub struct InputInt<'ui, 'p, L> {
label: L,
value: &'p mut i32,
step: i32,
step_fast: i32,
flags: InputTextFlags,
_phantom: PhantomData<&'ui Ui<'ui>>,
ui: &'ui Ui<'ui>,
}
impl<'ui, 'p> InputInt<'ui, 'p> {
pub fn new(_: &Ui<'ui>, label: &'p ImStr, value: &'p mut i32) -> Self {
impl<'ui, 'p, L: AsRef<str>> InputInt<'ui, 'p, L> {
pub fn new(ui: &'ui Ui<'ui>, label: L, value: &'p mut i32) -> Self {
InputInt {
label,
value,
step: 1,
step_fast: 100,
flags: InputTextFlags::empty(),
_phantom: PhantomData,
ui,
}
}
pub fn build(self) -> bool {
unsafe {
sys::igInputInt(
self.label.as_ptr(),
self.ui.scratch_txt(self.label),
self.value as *mut i32,
self.step,
self.step_fast,
@ -402,31 +410,31 @@ impl<'ui, 'p> InputInt<'ui, 'p> {
}
#[must_use]
pub struct InputFloat<'ui, 'p> {
label: &'p ImStr,
pub struct InputFloat<'ui, 'p, L> {
label: L,
value: &'p mut f32,
step: f32,
step_fast: f32,
flags: InputTextFlags,
_phantom: PhantomData<&'ui Ui<'ui>>,
ui: &'ui Ui<'ui>,
}
impl<'ui, 'p> InputFloat<'ui, 'p> {
pub fn new(_: &Ui<'ui>, label: &'p ImStr, value: &'p mut f32) -> Self {
impl<'ui, 'p, L: AsRef<str>> InputFloat<'ui, 'p, L> {
pub fn new(ui: &'ui Ui<'ui>, label: L, value: &'p mut f32) -> Self {
InputFloat {
label,
value,
step: 0.0,
step_fast: 0.0,
flags: InputTextFlags::empty(),
_phantom: PhantomData,
ui,
}
}
pub fn build(self) -> bool {
unsafe {
sys::igInputFloat(
self.label.as_ptr(),
self.ui.scratch_txt(self.label),
self.value as *mut f32,
self.step,
self.step_fast,
@ -443,27 +451,27 @@ impl<'ui, 'p> InputFloat<'ui, 'p> {
macro_rules! impl_input_floatn {
($InputFloatN:ident, $N:expr, $igInputFloatN:ident) => {
#[must_use]
pub struct $InputFloatN<'ui, 'p> {
label: &'p ImStr,
pub struct $InputFloatN<'ui, 'p, L> {
label: L,
value: &'p mut [f32; $N],
flags: InputTextFlags,
_phantom: PhantomData<&'ui Ui<'ui>>,
ui: &'ui Ui<'ui>,
}
impl<'ui, 'p> $InputFloatN<'ui, 'p> {
pub fn new(_: &Ui<'ui>, label: &'p ImStr, value: &'p mut [f32; $N]) -> Self {
impl<'ui, 'p, L: AsRef<str>> $InputFloatN<'ui, 'p, L> {
pub fn new(ui: &'ui Ui<'ui>, label: L, value: &'p mut [f32; $N]) -> Self {
$InputFloatN {
label,
value,
flags: InputTextFlags::empty(),
_phantom: PhantomData,
ui,
}
}
pub fn build(self) -> bool {
unsafe {
sys::$igInputFloatN(
self.label.as_ptr(),
self.ui.scratch_txt(self.label),
self.value.as_mut_ptr(),
b"%.3f\0".as_ptr() as *const _,
self.flags.bits() as i32,
@ -483,27 +491,27 @@ 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,
pub struct $InputIntN<'ui, 'p, L> {
label: L,
value: &'p mut [i32; $N],
flags: InputTextFlags,
_phantom: PhantomData<&'ui Ui<'ui>>,
ui: &'ui Ui<'ui>,
}
impl<'ui, 'p> $InputIntN<'ui, 'p> {
pub fn new(_: &Ui<'ui>, label: &'p ImStr, value: &'p mut [i32; $N]) -> Self {
impl<'ui, 'p, L: AsRef<str>> $InputIntN<'ui, 'p, L> {
pub fn new(ui: &'ui Ui<'ui>, label: L, value: &'p mut [i32; $N]) -> Self {
$InputIntN {
label,
value,
flags: InputTextFlags::empty(),
_phantom: PhantomData,
ui,
}
}
pub fn build(self) -> bool {
unsafe {
sys::$igInputIntN(
self.label.as_ptr(),
self.ui.scratch_txt(self.label),
self.value.as_mut_ptr(),
self.flags.bits() as i32,
)
@ -809,7 +817,7 @@ impl<'a> TextCallbackData<'a> {
#[repr(C)]
struct UserData<'a, T> {
container: &'a mut ImString,
container: &'a mut String,
cback_handler: T,
}
@ -851,14 +859,15 @@ extern "C" fn callback<T: InputTextCallbackHandler>(
unsafe {
let requested_size = (*data).BufSize as usize;
let buffer = &mut callback_data.user_data.container;
if requested_size > buffer.capacity_with_nul() {
// Refresh the buffer's length to take into account changes made by dear imgui.
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;
}
todo!()
// if requested_size > buffer.capacity_with_nul() {
// // Refresh the buffer's length to take into account changes made by dear imgui.
// 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;
// }
}
}
InputTextFlags::CALLBACK_CHAR_FILTER => {

View File

@ -117,11 +117,12 @@ impl Context {
}
/// A temporary reference for building the user interface for one frame
#[derive(Debug)]
pub struct Ui<'ui> {
ctx: &'ui Context,
font_atlas: Option<cell::RefMut<'ui, SharedFontAtlas>>,
// imgui isn't mutli-threaded -- so no one will ever access
buffer: cell::UnsafeCell<Vec<u8>>,
// imgui isn't mutli-threaded -- so no one will ever access twice.
buffer: cell::UnsafeCell<string::UiBuffer>,
}
impl<'ui> Ui<'ui> {
@ -129,19 +130,15 @@ impl<'ui> Ui<'ui> {
fn scratch_txt(&self, txt: impl AsRef<str>) -> *const sys::cty::c_char {
unsafe {
let handle = &mut *self.buffer.get();
handle.clear();
handle.extend(txt.as_ref().as_bytes());
handle.push(b'\0');
handle.as_ptr() as *const _
handle.scratch_txt(txt)
}
}
/// Internal method to push an option text to our scratch buffer.
fn scratch_txt_opt(&self, txt: Option<impl AsRef<str>>) -> *const sys::cty::c_char {
match txt {
Some(v) => self.scratch_txt(v),
None => std::ptr::null(),
unsafe {
let handle = &mut *self.buffer.get();
handle.scratch_txt_opt(txt)
}
}
@ -152,16 +149,7 @@ impl<'ui> Ui<'ui> {
) -> (*const sys::cty::c_char, *const sys::cty::c_char) {
unsafe {
let handle = &mut *self.buffer.get();
handle.clear();
handle.extend(txt_0.as_ref().as_bytes());
handle.push(b'\0');
handle.extend(txt_1.as_ref().as_bytes());
handle.push(b'\0');
(
handle.as_ptr() as *const _,
handle.as_ptr().add(txt_1.as_ref().len() + 1) as *const _,
)
handle.scratch_txt_two(txt_0, txt_1)
}
}
@ -172,21 +160,7 @@ impl<'ui> Ui<'ui> {
) -> (*const sys::cty::c_char, *const sys::cty::c_char) {
unsafe {
let handle = &mut *self.buffer.get();
handle.clear();
handle.extend(txt_0.as_ref().as_bytes());
handle.push(b'\0');
if let Some(txt_1) = txt_1 {
handle.extend(txt_1.as_ref().as_bytes());
handle.push(b'\0');
(
handle.as_ptr() as *const _,
handle.as_ptr().add(txt_1.as_ref().len() + 1) as *const _,
)
} else {
(handle.as_ptr() as *const _, std::ptr::null())
}
handle.scratch_txt_with_opt(txt_0, txt_1)
}
}
@ -317,59 +291,83 @@ impl<T> From<*mut T> for Id<'static> {
// Widgets: Input
impl<'ui> Ui<'ui> {
#[doc(alias = "InputText", alias = "InputTextWithHint")]
pub fn input_text<'p>(&self, label: &'p ImStr, buf: &'p mut ImString) -> InputText<'ui, 'p> {
pub fn input_text<'p, L: AsRef<str>>(
&'ui self,
label: L,
buf: &'p mut String,
) -> InputText<'ui, 'p, L> {
InputText::new(self, label, buf)
}
#[doc(alias = "InputText", alias = "InputTextMultiline")]
pub fn input_text_multiline<'p>(
&self,
label: &'p ImStr,
buf: &'p mut ImString,
pub fn input_text_multiline<'p, L: AsRef<str>>(
&'ui self,
label: L,
buf: &'p mut String,
size: [f32; 2],
) -> InputTextMultiline<'ui, 'p> {
) -> InputTextMultiline<'ui, 'p, L> {
InputTextMultiline::new(self, label, buf, size)
}
#[doc(alias = "InputFloat2")]
pub fn input_float<'p>(&self, label: &'p ImStr, value: &'p mut f32) -> InputFloat<'ui, 'p> {
pub fn input_float<'p, L: AsRef<str>>(
&'ui self,
label: L,
value: &'p mut f32,
) -> InputFloat<'ui, 'p, L> {
InputFloat::new(self, label, value)
}
pub fn input_float2<'p>(
&self,
label: &'p ImStr,
pub fn input_float2<'p, L: AsRef<str>>(
&'ui self,
label: L,
value: &'p mut [f32; 2],
) -> InputFloat2<'ui, 'p> {
) -> InputFloat2<'ui, 'p, L> {
InputFloat2::new(self, label, value)
}
#[doc(alias = "InputFloat3")]
pub fn input_float3<'p>(
&self,
label: &'p ImStr,
pub fn input_float3<'p, L: AsRef<str>>(
&'ui self,
label: L,
value: &'p mut [f32; 3],
) -> InputFloat3<'ui, 'p> {
) -> InputFloat3<'ui, 'p, L> {
InputFloat3::new(self, label, value)
}
#[doc(alias = "InputFloat4")]
pub fn input_float4<'p>(
&self,
label: &'p ImStr,
pub fn input_float4<'p, L: AsRef<str>>(
&'ui self,
label: L,
value: &'p mut [f32; 4],
) -> InputFloat4<'ui, 'p> {
) -> InputFloat4<'ui, 'p, L> {
InputFloat4::new(self, label, value)
}
#[doc(alias = "InputInt")]
pub fn input_int<'p>(&self, label: &'p ImStr, value: &'p mut i32) -> InputInt<'ui, 'p> {
pub fn input_int<'p, L: AsRef<str>>(
&'ui self,
label: L,
value: &'p mut i32,
) -> InputInt<'ui, 'p, L> {
InputInt::new(self, label, value)
}
#[doc(alias = "InputInt2")]
pub fn input_int2<'p>(&self, label: &'p ImStr, value: &'p mut [i32; 2]) -> InputInt2<'ui, 'p> {
pub fn input_int2<'p, L: AsRef<str>>(
&'ui self,
label: L,
value: &'p mut [i32; 2],
) -> InputInt2<'ui, 'p, L> {
InputInt2::new(self, label, value)
}
#[doc(alias = "InputInt3")]
pub fn input_int3<'p>(&self, label: &'p ImStr, value: &'p mut [i32; 3]) -> InputInt3<'ui, 'p> {
pub fn input_int3<'p, L: AsRef<str>>(
&'ui self,
label: L,
value: &'p mut [i32; 3],
) -> InputInt3<'ui, 'p, L> {
InputInt3::new(self, label, value)
}
#[doc(alias = "InputInt4")]
pub fn input_int4<'p>(&self, label: &'p ImStr, value: &'p mut [i32; 4]) -> InputInt4<'ui, 'p> {
pub fn input_int4<'p, L: AsRef<str>>(
&'ui self,
label: L,
value: &'p mut [i32; 4],
) -> InputInt4<'ui, 'p, L> {
InputInt4::new(self, label, value)
}
}
@ -470,11 +468,11 @@ impl<'ui> Ui<'ui> {
impl<'ui> Ui<'ui> {
#[doc(alias = "PlotHistogram")]
pub fn plot_histogram<'p>(
&self,
label: &'p ImStr,
pub fn plot_histogram<'p, Label: AsRef<str>>(
&'ui self,
label: Label,
values: &'p [f32],
) -> PlotHistogram<'ui, 'p> {
) -> PlotHistogram<'ui, 'p, Label> {
PlotHistogram::new(self, label, values)
}
}

View File

@ -1,23 +1,22 @@
use std::marker::PhantomData;
use std::os::raw::c_float;
use std::{f32, mem, ptr};
use std::{f32, mem};
use super::{ImStr, Ui};
use super::Ui;
#[must_use]
pub struct PlotHistogram<'ui, 'p> {
label: &'p ImStr,
pub struct PlotHistogram<'ui, 'p, Label, Overlay = &'static str> {
label: Label,
values: &'p [f32],
values_offset: usize,
overlay_text: Option<&'p ImStr>,
overlay_text: Option<Overlay>,
scale_min: f32,
scale_max: f32,
graph_size: [f32; 2],
_phantom: PhantomData<&'ui Ui<'ui>>,
ui: &'ui Ui<'ui>,
}
impl<'ui, 'p> PlotHistogram<'ui, 'p> {
pub const fn new(_: &Ui<'ui>, label: &'p ImStr, values: &'p [f32]) -> Self {
impl<'ui, 'p, Label: AsRef<str>> PlotHistogram<'ui, 'p, Label> {
pub fn new(ui: &'ui Ui<'ui>, label: Label, values: &'p [f32]) -> Self {
PlotHistogram {
label,
values,
@ -26,48 +25,58 @@ impl<'ui, 'p> PlotHistogram<'ui, 'p> {
scale_min: f32::MAX,
scale_max: f32::MAX,
graph_size: [0.0, 0.0],
_phantom: PhantomData,
ui,
}
}
}
#[inline]
pub const fn values_offset(mut self, values_offset: usize) -> Self {
impl<'ui, 'p, Label: AsRef<str>, Overlay: AsRef<str>> PlotHistogram<'ui, 'p, Label, Overlay> {
pub fn values_offset(mut self, values_offset: usize) -> Self {
self.values_offset = values_offset;
self
}
#[inline]
pub const fn overlay_text(mut self, overlay_text: &'p ImStr) -> Self {
self.overlay_text = Some(overlay_text);
self
pub fn overlay_text<NewOverlay: AsRef<str>>(
self,
overlay_text: NewOverlay,
) -> PlotHistogram<'ui, 'p, Label, NewOverlay> {
PlotHistogram {
label: self.label,
values: self.values,
values_offset: self.values_offset,
overlay_text: Some(overlay_text),
scale_min: self.scale_min,
scale_max: self.scale_max,
graph_size: self.graph_size,
ui: self.ui,
}
}
#[inline]
pub const fn scale_min(mut self, scale_min: f32) -> Self {
pub fn scale_min(mut self, scale_min: f32) -> Self {
self.scale_min = scale_min;
self
}
#[inline]
pub const fn scale_max(mut self, scale_max: f32) -> Self {
pub fn scale_max(mut self, scale_max: f32) -> Self {
self.scale_max = scale_max;
self
}
#[inline]
pub const fn graph_size(mut self, graph_size: [f32; 2]) -> Self {
pub fn graph_size(mut self, graph_size: [f32; 2]) -> Self {
self.graph_size = graph_size;
self
}
pub fn build(self) {
unsafe {
let (label, overlay_text) = self.ui.scratch_txt_with_opt(self.label, self.overlay_text);
sys::igPlotHistogramFloatPtr(
self.label.as_ptr(),
label,
self.values.as_ptr() as *const c_float,
self.values.len() as i32,
self.values_offset as i32,
self.overlay_text.map(|x| x.as_ptr()).unwrap_or(ptr::null()),
overlay_text,
self.scale_min,
self.scale_max,
self.graph_size.into(),

View File

@ -1,9 +1,77 @@
use std::borrow::{Borrow, Cow};
use std::ffi::CStr;
use std::fmt;
use std::ops::{Deref, Index, RangeFull};
use std::os::raw::c_char;
use std::str;
use std::{fmt, ptr};
/// this is the unsafe cell upon which we build our abstraction.
pub(crate) struct UiBuffer {
buffer: Vec<u8>,
max_len: usize,
}
impl UiBuffer {
/// Creates a new max buffer with the given length.
pub fn new(max_len: usize) -> Self {
Self {
buffer: Vec::with_capacity(max_len),
max_len,
}
}
/// Internal method to push a single text to our scratch buffer.
pub fn scratch_txt(&mut self, txt: impl AsRef<str>) -> *const sys::cty::c_char {
self.refresh_buffer();
self.push(txt)
}
/// Internal method to push an option text to our scratch buffer.
pub fn scratch_txt_opt(&mut self, txt: Option<impl AsRef<str>>) -> *const sys::cty::c_char {
match txt {
Some(v) => self.scratch_txt(v),
None => ptr::null(),
}
}
pub fn scratch_txt_two(
&mut self,
txt_0: impl AsRef<str>,
txt_1: impl AsRef<str>,
) -> (*const sys::cty::c_char, *const sys::cty::c_char) {
self.refresh_buffer();
(self.push(txt_0), self.push(txt_1))
}
pub fn scratch_txt_with_opt(
&mut self,
txt_0: impl AsRef<str>,
txt_1: Option<impl AsRef<str>>,
) -> (*const sys::cty::c_char, *const sys::cty::c_char) {
match txt_1 {
Some(value) => self.scratch_txt_two(txt_0, value),
None => (self.scratch_txt(txt_0), ptr::null()),
}
}
/// Attempts to clear the buffer if it's over the maximum length allowed.
pub fn refresh_buffer(&mut self) {
if self.buffer.len() > self.max_len {
self.buffer.clear();
}
}
/// Pushes a new scratch sheet text, which means it's not handling any clearing at all.
pub fn push(&mut self, txt: impl AsRef<str>) -> *const sys::cty::c_char {
unsafe {
let len = self.buffer.len();
self.buffer.extend(txt.as_ref().as_bytes());
self.buffer.push(b'\0');
self.buffer.as_ptr().add(len) as *const _
}
}
}
#[macro_export]
macro_rules! im_str {
@ -277,6 +345,7 @@ impl fmt::Write for ImString {
/// A UTF-8 encoded, implicitly nul-terminated string slice.
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
#[deprecated]
pub struct ImStr([u8]);
impl<'a> Default for &'a ImStr {

View File

@ -2,7 +2,6 @@ use std::os::raw::c_void;
use std::ptr;
use crate::internal::DataTypeKind;
use crate::string::ImStr;
use crate::sys;
use crate::widget::slider::SliderFlags;
use crate::Ui;
@ -10,16 +9,16 @@ use crate::Ui;
/// Builder for a drag slider widget.
#[derive(Copy, Clone, Debug)]
#[must_use]
pub struct Drag<'a, T, L> {
pub struct Drag<T, L, F = &'static str> {
label: L,
speed: f32,
min: Option<T>,
max: Option<T>,
display_format: Option<&'a str>,
display_format: Option<F>,
flags: SliderFlags,
}
impl<'a, L: AsRef<str>, T: DataTypeKind> Drag<'a, T, L> {
impl<L: AsRef<str>, T: DataTypeKind> Drag<T, L> {
/// Constructs a new drag slider builder.
#[doc(alias = "DragScalar", alias = "DragScalarN")]
pub fn new(label: L) -> Self {
@ -32,8 +31,10 @@ impl<'a, L: AsRef<str>, T: DataTypeKind> Drag<'a, T, L> {
flags: SliderFlags::empty(),
}
}
}
impl<L: AsRef<str>, T: DataTypeKind, F: AsRef<str>> Drag<T, L, F> {
/// Sets the range (inclusive)
#[inline]
pub fn range(mut self, min: T, max: T) -> Self {
self.min = Some(min);
self.max = Some(max);
@ -42,19 +43,22 @@ impl<'a, L: AsRef<str>, T: DataTypeKind> Drag<'a, T, L> {
/// Sets the value increment for a movement of one pixel.
///
/// Example: speed=0.2 means mouse needs to move 5 pixels to increase the slider value by 1
#[inline]
pub fn speed(mut self, speed: f32) -> Self {
self.speed = speed;
self
}
/// Sets the display format using *a C-style printf string*
#[inline]
pub fn display_format(mut self, display_format: &'a str) -> Self {
self.display_format = Some(display_format);
self
pub fn display_format<F2: AsRef<str>>(self, display_format: F2) -> Drag<T, L, F2> {
Drag {
label: self.label,
speed: self.speed,
min: self.min,
max: self.max,
display_format: Some(display_format),
flags: self.flags,
}
}
/// Replaces all current settings with the given flags
#[inline]
pub fn flags(mut self, flags: SliderFlags) -> Self {
self.flags = flags;
self
@ -115,20 +119,20 @@ impl<'a, L: AsRef<str>, T: DataTypeKind> Drag<'a, T, L> {
/// Builder for a drag slider widget.
#[derive(Copy, Clone, Debug)]
#[must_use]
pub struct DragRange<'a, T: DataTypeKind> {
label: &'a ImStr,
pub struct DragRange<T, L, F = &'static str, M = &'static str> {
label: L,
speed: f32,
min: Option<T>,
max: Option<T>,
display_format: Option<&'a ImStr>,
max_display_format: Option<&'a ImStr>,
display_format: Option<F>,
max_display_format: Option<M>,
flags: SliderFlags,
}
impl<'a, T: DataTypeKind> DragRange<'a, T> {
impl<T: DataTypeKind, L: AsRef<str>> DragRange<T, L> {
/// Constructs a new drag slider builder.
#[doc(alias = "DragIntRange2", alias = "DragFloatRange2")]
pub fn new(label: &ImStr) -> DragRange<T> {
pub fn new(label: L) -> DragRange<T, L> {
DragRange {
label,
speed: 1.0,
@ -139,7 +143,15 @@ impl<'a, T: DataTypeKind> DragRange<'a, T> {
flags: SliderFlags::empty(),
}
}
#[inline]
}
impl<T, L, F, M> DragRange<T, L, F, M>
where
T: DataTypeKind,
L: AsRef<str>,
F: AsRef<str>,
M: AsRef<str>,
{
pub fn range(mut self, min: T, max: T) -> Self {
self.min = Some(min);
self.max = Some(max);
@ -148,77 +160,124 @@ impl<'a, T: DataTypeKind> DragRange<'a, T> {
/// Sets the value increment for a movement of one pixel.
///
/// Example: speed=0.2 means mouse needs to move 5 pixels to increase the slider value by 1
#[inline]
pub fn speed(mut self, speed: f32) -> Self {
self.speed = speed;
self
}
/// Sets the display format using *a C-style printf string*
#[inline]
pub fn display_format(mut self, display_format: &'a ImStr) -> Self {
self.display_format = Some(display_format);
self
pub fn display_format<F2: AsRef<str>>(self, display_format: F2) -> DragRange<T, L, F2, M> {
DragRange {
label: self.label,
speed: self.speed,
min: self.min,
max: self.max,
display_format: Some(display_format),
max_display_format: self.max_display_format,
flags: self.flags,
}
}
/// Sets the display format for the max value using *a C-style printf string*
#[inline]
pub fn max_display_format(mut self, max_display_format: &'a ImStr) -> Self {
self.max_display_format = Some(max_display_format);
self
pub fn max_display_format<M2: AsRef<str>>(
self,
max_display_format: M2,
) -> DragRange<T, L, F, M2> {
DragRange {
label: self.label,
speed: self.speed,
min: self.min,
max: self.max,
display_format: self.display_format,
max_display_format: Some(max_display_format),
flags: self.flags,
}
}
/// Replaces all current settings with the given flags
#[inline]
pub fn flags(mut self, flags: SliderFlags) -> Self {
self.flags = flags;
self
}
}
impl<'a> DragRange<'a, f32> {
impl<L, F, M> DragRange<f32, L, F, M>
where
L: AsRef<str>,
F: AsRef<str>,
M: AsRef<str>,
{
/// Builds a drag range slider that is bound to the given min/max values.
///
/// Returns true if the slider value was changed.
#[doc(alias = "DragFloatRange2")]
pub fn build(self, _: &Ui, min: &mut f32, max: &mut f32) -> bool {
pub fn build(self, ui: &Ui, min: &mut f32, max: &mut f32) -> bool {
let label;
let mut display_format = std::ptr::null();
let mut max_display_format = std::ptr::null();
// we do this ourselves the long way...
unsafe {
let buffer = &mut *ui.buffer.get();
buffer.refresh_buffer();
label = buffer.push(self.label);
if let Some(v) = self.display_format {
display_format = buffer.push(v);
}
if let Some(v) = self.max_display_format {
max_display_format = buffer.push(v);
}
sys::igDragFloatRange2(
self.label.as_ptr(),
label,
min as *mut f32,
max as *mut f32,
self.speed,
self.min.unwrap_or(0.0),
self.max.unwrap_or(0.0),
self.display_format
.map(ImStr::as_ptr)
.unwrap_or(ptr::null()),
self.max_display_format
.map(ImStr::as_ptr)
.unwrap_or(ptr::null()),
display_format,
max_display_format,
self.flags.bits() as i32,
)
}
}
}
impl<'a> DragRange<'a, i32> {
impl<L, F, M> DragRange<i32, L, F, M>
where
L: AsRef<str>,
F: AsRef<str>,
M: AsRef<str>,
{
/// Builds a drag range slider that is bound to the given min/max values.
///
/// Returns true if the slider value was changed.
#[doc(alias = "DragIntRange2")]
pub fn build(self, _: &Ui, min: &mut i32, max: &mut i32) -> bool {
pub fn build(self, ui: &Ui, min: &mut i32, max: &mut i32) -> bool {
unsafe {
let label;
let mut display_format = std::ptr::null();
let mut max_display_format = std::ptr::null();
// we do this ourselves the long way...
let buffer = &mut *ui.buffer.get();
buffer.refresh_buffer();
label = buffer.push(self.label);
if let Some(v) = self.display_format {
display_format = buffer.push(v);
}
if let Some(v) = self.max_display_format {
max_display_format = buffer.push(v);
}
sys::igDragIntRange2(
self.label.as_ptr(),
label,
min as *mut i32,
max as *mut i32,
self.speed,
self.min.unwrap_or(0),
self.max.unwrap_or(0),
self.display_format
.map(ImStr::as_ptr)
.unwrap_or(ptr::null()),
self.max_display_format
.map(ImStr::as_ptr)
.unwrap_or(ptr::null()),
display_format,
max_display_format,
self.flags.bits() as i32,
)
}