mirror of
https://github.com/eliasstepanik/imgui-rs.git
synced 2026-01-27 13:28:28 +00:00
imstr and imstring have been removed.
fixed some instability and added a hacky shim to input_text functions. We're looking okay so far, but more testing will be needed
This commit is contained in:
parent
694cd96d49
commit
3eaee3359d
@ -1,7 +1,7 @@
|
|||||||
use clipboard::{ClipboardContext, ClipboardProvider};
|
use clipboard::{ClipboardContext, ClipboardProvider};
|
||||||
use imgui::ClipboardBackend;
|
use imgui::ClipboardBackend;
|
||||||
|
|
||||||
pub struct ClipboardSupport(ClipboardContext);
|
pub struct ClipboardSupport(pub ClipboardContext);
|
||||||
|
|
||||||
pub fn init() -> Option<ClipboardSupport> {
|
pub fn init() -> Option<ClipboardSupport> {
|
||||||
ClipboardContext::new().ok().map(ClipboardSupport)
|
ClipboardContext::new().ok().map(ClipboardSupport)
|
||||||
|
|||||||
@ -7,7 +7,7 @@ fn main() {
|
|||||||
let mut buffers = vec![String::default(), String::default(), String::default()];
|
let mut buffers = vec![String::default(), String::default(), String::default()];
|
||||||
|
|
||||||
system.main_loop(move |_, ui| {
|
system.main_loop(move |_, ui| {
|
||||||
Window::new(im_str!("Input text callbacks"))
|
Window::new("Input text callbacks")
|
||||||
.size([500.0, 300.0], Condition::FirstUseEver)
|
.size([500.0, 300.0], Condition::FirstUseEver)
|
||||||
.build(ui, || {
|
.build(ui, || {
|
||||||
ui.text("You can make a variety of buffer callbacks on an Input Text");
|
ui.text("You can make a variety of buffer callbacks on an Input Text");
|
||||||
@ -24,9 +24,10 @@ fn main() {
|
|||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
ui.text("No callbacks:");
|
ui.text("No callbacks:");
|
||||||
ui.input_text(im_str!("buf0"), &mut buffers[0]).build();
|
|
||||||
ui.input_text(im_str!("buf0"), &mut buffers[1]).build();
|
ui.input_text("buf0", &mut buffers[0]).build();
|
||||||
ui.input_text(im_str!("buf0"), &mut buffers[2]).build();
|
ui.input_text("buf1", &mut buffers[1]).build();
|
||||||
|
ui.input_text("buf2", &mut buffers[2]).build();
|
||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
@ -50,18 +51,15 @@ fn main() {
|
|||||||
println!("History was fired by pressing {:?}", dir);
|
println!("History was fired by pressing {:?}", dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_always(&mut self, _: TextCallbackData<'_>) {
|
fn on_always(&mut self, txt: TextCallbackData<'_>) {
|
||||||
// We don't actually print this out because it will flood your log a lot!
|
// We don't actually print this out because it will flood your log a lot!
|
||||||
// println!("The always callback fired! It always fires.");
|
// println!("The always callback fired! It always fires.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.input_text(
|
ui.input_text("All Callbacks logging", buffers.get_mut(0).unwrap())
|
||||||
im_str!("All Callbacks logging"),
|
.callback(InputTextCallback::all(), AllCallback)
|
||||||
buffers.get_mut(0).unwrap(),
|
.build();
|
||||||
)
|
|
||||||
.callback(InputTextCallback::all(), AllCallback)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
@ -79,7 +77,7 @@ fn main() {
|
|||||||
let (buf0, brwchk_dance) = buffers.split_first_mut().unwrap();
|
let (buf0, brwchk_dance) = buffers.split_first_mut().unwrap();
|
||||||
let buf1 = Wrapper(&mut brwchk_dance[0]);
|
let buf1 = Wrapper(&mut brwchk_dance[0]);
|
||||||
|
|
||||||
ui.input_text(im_str!("Edits copied to buf1"), buf0)
|
ui.input_text("Edits copied to buf1", buf0)
|
||||||
.callback(InputTextCallback::ALWAYS, buf1)
|
.callback(InputTextCallback::ALWAYS, buf1)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@ -132,7 +130,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.input_text(im_str!("Wild buf2 editor"), buf2)
|
ui.input_text("Wild buf2 editor", buf2)
|
||||||
.callback(InputTextCallback::HISTORY, Wrapper2(buf0, buf1))
|
.callback(InputTextCallback::HISTORY, Wrapper2(buf0, buf1))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|||||||
@ -513,9 +513,10 @@ impl Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn configure_imgui_context(&self, imgui_context: &mut imgui::Context) {
|
fn configure_imgui_context(&self, imgui_context: &mut imgui::Context) {
|
||||||
imgui_context.set_renderer_name(Some(
|
imgui_context.set_renderer_name(Some(format!(
|
||||||
format!("imgui-rs-glow-render {}", env!("CARGO_PKG_VERSION")).into(),
|
"imgui-rs-glow-render {}",
|
||||||
));
|
env!("CARGO_PKG_VERSION")
|
||||||
|
)));
|
||||||
|
|
||||||
#[cfg(feature = "vertex_offset_support")]
|
#[cfg(feature = "vertex_offset_support")]
|
||||||
if self.gl_version.vertex_offset_support() {
|
if self.gl_version.vertex_offset_support() {
|
||||||
|
|||||||
@ -32,6 +32,24 @@ impl ClipboardContext {
|
|||||||
last_value: CString::default(),
|
last_value: CString::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dummy() -> ClipboardContext {
|
||||||
|
Self {
|
||||||
|
backend: Box::new(DummyClipboardContext),
|
||||||
|
last_value: CString::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DummyClipboardContext;
|
||||||
|
impl ClipboardBackend for DummyClipboardContext {
|
||||||
|
fn get(&mut self) -> Option<String> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set(&mut self, _: &str) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for ClipboardContext {
|
impl fmt::Debug for ClipboardContext {
|
||||||
@ -46,9 +64,14 @@ impl fmt::Debug for ClipboardContext {
|
|||||||
|
|
||||||
pub(crate) unsafe extern "C" fn get_clipboard_text(user_data: *mut c_void) -> *const c_char {
|
pub(crate) unsafe extern "C" fn get_clipboard_text(user_data: *mut c_void) -> *const c_char {
|
||||||
let result = catch_unwind(|| {
|
let result = catch_unwind(|| {
|
||||||
|
println!("gettin!");
|
||||||
let ctx = &mut *(user_data as *mut ClipboardContext);
|
let ctx = &mut *(user_data as *mut ClipboardContext);
|
||||||
|
println!("gettin!");
|
||||||
|
|
||||||
match ctx.backend.get() {
|
match ctx.backend.get() {
|
||||||
Some(text) => {
|
Some(text) => {
|
||||||
|
println!("gettin!");
|
||||||
|
|
||||||
ctx.last_value = CString::new(text).unwrap();
|
ctx.last_value = CString::new(text).unwrap();
|
||||||
ctx.last_value.as_ptr()
|
ctx.last_value.as_ptr()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use parking_lot::ReentrantMutex;
|
use parking_lot::ReentrantMutex;
|
||||||
use std::cell::RefCell;
|
use std::cell::{RefCell, UnsafeCell};
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
use std::ops::Drop;
|
use std::ops::Drop;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@ -55,7 +55,11 @@ pub struct Context {
|
|||||||
log_filename: Option<CString>,
|
log_filename: Option<CString>,
|
||||||
platform_name: Option<CString>,
|
platform_name: Option<CString>,
|
||||||
renderer_name: Option<CString>,
|
renderer_name: Option<CString>,
|
||||||
clipboard_ctx: Option<ClipboardContext>,
|
// we need to box this because we hand imgui a pointer to it,
|
||||||
|
// and we don't want to deal with finding `clipboard_ctx`.
|
||||||
|
// we also put it in an unsafecell since we're going to give
|
||||||
|
// imgui a mutable pointer to it.
|
||||||
|
clipboard_ctx: Box<UnsafeCell<ClipboardContext>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// This mutex needs to be used to guard all public functions that can affect the underlying
|
// This mutex needs to be used to guard all public functions that can affect the underlying
|
||||||
@ -203,13 +207,13 @@ impl Context {
|
|||||||
}
|
}
|
||||||
/// Sets the clipboard backend used for clipboard operations
|
/// Sets the clipboard backend used for clipboard operations
|
||||||
pub fn set_clipboard_backend<T: ClipboardBackend>(&mut self, backend: T) {
|
pub fn set_clipboard_backend<T: ClipboardBackend>(&mut self, backend: T) {
|
||||||
use std::borrow::BorrowMut;
|
let clipboard_ctx: Box<UnsafeCell<_>> = Box::new(ClipboardContext::new(backend).into());
|
||||||
let mut clipboard_ctx = ClipboardContext::new(backend);
|
|
||||||
let io = self.io_mut();
|
let io = self.io_mut();
|
||||||
io.set_clipboard_text_fn = Some(crate::clipboard::set_clipboard_text);
|
io.set_clipboard_text_fn = Some(crate::clipboard::set_clipboard_text);
|
||||||
io.get_clipboard_text_fn = Some(crate::clipboard::get_clipboard_text);
|
io.get_clipboard_text_fn = Some(crate::clipboard::get_clipboard_text);
|
||||||
io.clipboard_user_data = clipboard_ctx.borrow_mut() as *mut ClipboardContext as *mut _;
|
|
||||||
self.clipboard_ctx.replace(clipboard_ctx);
|
io.clipboard_user_data = clipboard_ctx.get() as *mut _;
|
||||||
|
self.clipboard_ctx = clipboard_ctx;
|
||||||
}
|
}
|
||||||
fn create_internal(shared_font_atlas: Option<Rc<RefCell<SharedFontAtlas>>>) -> Self {
|
fn create_internal(shared_font_atlas: Option<Rc<RefCell<SharedFontAtlas>>>) -> Self {
|
||||||
let _guard = CTX_MUTEX.lock();
|
let _guard = CTX_MUTEX.lock();
|
||||||
@ -236,7 +240,7 @@ impl Context {
|
|||||||
log_filename: None,
|
log_filename: None,
|
||||||
platform_name: None,
|
platform_name: None,
|
||||||
renderer_name: None,
|
renderer_name: None,
|
||||||
clipboard_ctx: None,
|
clipboard_ctx: Box::new(ClipboardContext::dummy().into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn is_current_context(&self) -> bool {
|
fn is_current_context(&self) -> bool {
|
||||||
@ -317,7 +321,7 @@ impl SuspendedContext {
|
|||||||
log_filename: None,
|
log_filename: None,
|
||||||
platform_name: None,
|
platform_name: None,
|
||||||
renderer_name: None,
|
renderer_name: None,
|
||||||
clipboard_ctx: None,
|
clipboard_ctx: Box::new(ClipboardContext::dummy().into()),
|
||||||
};
|
};
|
||||||
if ctx.is_current_context() {
|
if ctx.is_current_context() {
|
||||||
// Oops, the context was activated -> deactivate
|
// Oops, the context was activated -> deactivate
|
||||||
|
|||||||
@ -208,8 +208,14 @@ where
|
|||||||
///
|
///
|
||||||
/// If, for some reason, you don't want this, you can run this function to prevent this.
|
/// If, for some reason, you don't want this, you can run this function to prevent this.
|
||||||
/// In that case, edits which would cause a resize will not occur.
|
/// In that case, edits which would cause a resize will not occur.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// Importantly, we silently push and pop a `\0` to the string given here.
|
||||||
|
/// If you do not want mutable access (ie, do not want that string to resize),
|
||||||
|
/// you **must** make sure to null-terminate it yourself. This is janky, but ImGui
|
||||||
|
/// expects a null termination, and we didn't want to re-allocate an entire string per call.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn do_not_resize(mut self) -> Self {
|
pub unsafe fn do_not_resize(mut self) -> Self {
|
||||||
self.flags.remove(InputTextFlags::CALLBACK_RESIZE);
|
self.flags.remove(InputTextFlags::CALLBACK_RESIZE);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -246,6 +252,8 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> bool {
|
pub fn build(self) -> bool {
|
||||||
|
// needs to be null-terminated!
|
||||||
|
self.buf.push('\0');
|
||||||
let (ptr, capacity) = (self.buf.as_mut_ptr(), self.buf.capacity());
|
let (ptr, capacity) = (self.buf.as_mut_ptr(), self.buf.capacity());
|
||||||
|
|
||||||
let mut data = UserData {
|
let mut data = UserData {
|
||||||
@ -254,7 +262,7 @@ where
|
|||||||
};
|
};
|
||||||
let data = &mut data as *mut _ as *mut c_void;
|
let data = &mut data as *mut _ as *mut c_void;
|
||||||
|
|
||||||
unsafe {
|
let o = unsafe {
|
||||||
if let Some(hint) = self.hint {
|
if let Some(hint) = self.hint {
|
||||||
let (label, hint) = self.ui.scratch_txt_two(self.label, hint);
|
let (label, hint) = self.ui.scratch_txt_two(self.label, hint);
|
||||||
sys::igInputTextWithHint(
|
sys::igInputTextWithHint(
|
||||||
@ -278,7 +286,14 @@ where
|
|||||||
data,
|
data,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// it should always end with this \0.
|
||||||
|
if self.buf.ends_with('\0') {
|
||||||
|
self.buf.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
o
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,6 +364,8 @@ impl<'ui, 'p, T: InputTextCallbackHandler, L: AsRef<str>> InputTextMultiline<'ui
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> bool {
|
pub fn build(self) -> bool {
|
||||||
|
// needs to be null-terminated!
|
||||||
|
self.buf.push('\0');
|
||||||
let (ptr, capacity) = (self.buf.as_mut_ptr(), self.buf.capacity());
|
let (ptr, capacity) = (self.buf.as_mut_ptr(), self.buf.capacity());
|
||||||
|
|
||||||
let mut data = UserData {
|
let mut data = UserData {
|
||||||
@ -357,7 +374,7 @@ impl<'ui, 'p, T: InputTextCallbackHandler, L: AsRef<str>> InputTextMultiline<'ui
|
|||||||
};
|
};
|
||||||
let data = &mut data as *mut _ as *mut c_void;
|
let data = &mut data as *mut _ as *mut c_void;
|
||||||
|
|
||||||
unsafe {
|
let o = unsafe {
|
||||||
sys::igInputTextMultiline(
|
sys::igInputTextMultiline(
|
||||||
self.ui.scratch_txt(self.label),
|
self.ui.scratch_txt(self.label),
|
||||||
ptr as *mut sys::cty::c_char,
|
ptr as *mut sys::cty::c_char,
|
||||||
@ -367,7 +384,14 @@ impl<'ui, 'p, T: InputTextCallbackHandler, L: AsRef<str>> InputTextMultiline<'ui
|
|||||||
Some(callback::<T>),
|
Some(callback::<T>),
|
||||||
data,
|
data,
|
||||||
)
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
// it should always end with this \0.
|
||||||
|
if self.buf.ends_with('\0') {
|
||||||
|
self.buf.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
o
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -857,17 +881,24 @@ extern "C" fn callback<T: InputTextCallbackHandler>(
|
|||||||
}
|
}
|
||||||
InputTextFlags::CALLBACK_RESIZE => {
|
InputTextFlags::CALLBACK_RESIZE => {
|
||||||
unsafe {
|
unsafe {
|
||||||
let requested_size = (*data).BufSize as usize;
|
let requested_size = (*data).BufTextLen as usize;
|
||||||
let buffer = &mut callback_data.user_data.container;
|
|
||||||
todo!()
|
// just confirm that we ARE working with our string.
|
||||||
// if requested_size > buffer.capacity_with_nul() {
|
debug_assert_eq!(
|
||||||
// // Refresh the buffer's length to take into account changes made by dear imgui.
|
callback_data.user_data.container.as_ptr() as *const _,
|
||||||
// buffer.refresh_len();
|
(*data).Buf
|
||||||
// buffer.reserve(requested_size - buffer.0.len());
|
);
|
||||||
// debug_assert!(buffer.capacity_with_nul() >= requested_size);
|
|
||||||
// (*data).Buf = buffer.as_mut_ptr();
|
if requested_size > callback_data.user_data.container.capacity() {
|
||||||
// (*data).BufDirty = true;
|
// reserve more data...
|
||||||
// }
|
callback_data
|
||||||
|
.user_data
|
||||||
|
.container
|
||||||
|
.reserve(requested_size - callback_data.user_data.container.capacity());
|
||||||
|
|
||||||
|
(*data).Buf = callback_data.user_data.container.as_mut_ptr() as *mut _;
|
||||||
|
(*data).BufDirty = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputTextFlags::CALLBACK_CHAR_FILTER => {
|
InputTextFlags::CALLBACK_CHAR_FILTER => {
|
||||||
|
|||||||
@ -438,18 +438,27 @@ impl<'ui> Ui<'ui> {
|
|||||||
// Widgets: ListBox
|
// Widgets: ListBox
|
||||||
impl<'ui> Ui<'ui> {
|
impl<'ui> Ui<'ui> {
|
||||||
#[doc(alias = "ListBox")]
|
#[doc(alias = "ListBox")]
|
||||||
pub fn list_box<'p, StringType: AsRef<ImStr> + ?Sized>(
|
pub fn list_box<'p, StringType: AsRef<str> + ?Sized>(
|
||||||
&self,
|
&self,
|
||||||
label: &'p ImStr,
|
label: impl AsRef<str>,
|
||||||
current_item: &mut i32,
|
current_item: &mut i32,
|
||||||
items: &'p [&'p StringType],
|
items: &'p [&'p StringType],
|
||||||
height_in_items: i32,
|
height_in_items: i32,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let items_inner: Vec<*const c_char> =
|
let (label_ptr, items_inner) = unsafe {
|
||||||
items.iter().map(|item| item.as_ref().as_ptr()).collect();
|
let handle = &mut *self.buffer.get();
|
||||||
|
|
||||||
|
handle.refresh_buffer();
|
||||||
|
let label_ptr = handle.push(label);
|
||||||
|
|
||||||
|
let items_inner: Vec<_> = items.iter().map(|&v| handle.push(v)).collect();
|
||||||
|
|
||||||
|
(label_ptr, items_inner)
|
||||||
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
sys::igListBoxStr_arr(
|
sys::igListBoxStr_arr(
|
||||||
label.as_ptr(),
|
label_ptr,
|
||||||
current_item,
|
current_item,
|
||||||
items_inner.as_ptr() as *mut *const c_char,
|
items_inner.as_ptr() as *mut *const c_char,
|
||||||
items_inner.len() as i32,
|
items_inner.len() as i32,
|
||||||
@ -457,11 +466,50 @@ impl<'ui> Ui<'ui> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// written out for the future times...
|
||||||
|
// #[doc(alias = "ListBox")]
|
||||||
|
// pub fn list_box_const<'p, StringType: AsRef<str> + ?Sized, const N: usize>(
|
||||||
|
// &self,
|
||||||
|
// label: impl AsRef<str>,
|
||||||
|
// current_item: &mut i32,
|
||||||
|
// items: [&'p StringType; N],
|
||||||
|
// height_in_items: i32,
|
||||||
|
// ) -> bool {
|
||||||
|
// let (label_ptr, items_inner) = unsafe {
|
||||||
|
// let handle = &mut *self.buffer.get();
|
||||||
|
|
||||||
|
// handle.refresh_buffer();
|
||||||
|
// let label_ptr = handle.push(label);
|
||||||
|
|
||||||
|
// let mut items_inner: [*const i8; N] = [std::ptr::null(); N];
|
||||||
|
|
||||||
|
// for (i, item) in items.iter().enumerate() {
|
||||||
|
// items_inner[i] = handle.push(item);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// (label_ptr, items_inner)
|
||||||
|
// };
|
||||||
|
|
||||||
|
// unsafe {
|
||||||
|
// sys::igListBoxStr_arr(
|
||||||
|
// label_ptr,
|
||||||
|
// current_item,
|
||||||
|
// items_inner.as_ptr() as *mut *const c_char,
|
||||||
|
// items_inner.len() as i32,
|
||||||
|
// height_in_items,
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ui> Ui<'ui> {
|
impl<'ui> Ui<'ui> {
|
||||||
#[doc(alias = "PlotLines")]
|
#[doc(alias = "PlotLines")]
|
||||||
pub fn plot_lines<'p>(&self, label: &'p ImStr, values: &'p [f32]) -> PlotLines<'ui, 'p> {
|
pub fn plot_lines<'p, Label: AsRef<str>>(
|
||||||
|
&'ui self,
|
||||||
|
label: Label,
|
||||||
|
values: &'p [f32],
|
||||||
|
) -> PlotLines<'ui, 'p, Label> {
|
||||||
PlotLines::new(self, label, values)
|
PlotLines::new(self, label, values)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,23 +1,22 @@
|
|||||||
use std::marker::PhantomData;
|
|
||||||
use std::os::raw::c_float;
|
use std::os::raw::c_float;
|
||||||
use std::{f32, mem, ptr};
|
use std::{f32, mem};
|
||||||
|
|
||||||
use super::{ImStr, Ui};
|
use super::Ui;
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct PlotLines<'ui, 'p> {
|
pub struct PlotLines<'ui, 'p, Label, Overlay = &'static str> {
|
||||||
label: &'p ImStr,
|
label: Label,
|
||||||
values: &'p [f32],
|
values: &'p [f32],
|
||||||
values_offset: usize,
|
values_offset: usize,
|
||||||
overlay_text: Option<&'p ImStr>,
|
overlay_text: Option<Overlay>,
|
||||||
scale_min: f32,
|
scale_min: f32,
|
||||||
scale_max: f32,
|
scale_max: f32,
|
||||||
graph_size: [f32; 2],
|
graph_size: [f32; 2],
|
||||||
_phantom: PhantomData<&'ui Ui<'ui>>,
|
ui: &'ui Ui<'ui>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ui, 'p> PlotLines<'ui, 'p> {
|
impl<'ui, 'p, Label: AsRef<str>> PlotLines<'ui, 'p, Label> {
|
||||||
pub const fn new(_: &Ui<'ui>, label: &'p ImStr, values: &'p [f32]) -> Self {
|
pub fn new(ui: &'ui Ui<'ui>, label: Label, values: &'p [f32]) -> Self {
|
||||||
PlotLines {
|
PlotLines {
|
||||||
label,
|
label,
|
||||||
values,
|
values,
|
||||||
@ -26,48 +25,58 @@ impl<'ui, 'p> PlotLines<'ui, 'p> {
|
|||||||
scale_min: f32::MAX,
|
scale_min: f32::MAX,
|
||||||
scale_max: f32::MAX,
|
scale_max: f32::MAX,
|
||||||
graph_size: [0.0, 0.0],
|
graph_size: [0.0, 0.0],
|
||||||
_phantom: PhantomData,
|
ui,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
impl<'ui, 'p, Label: AsRef<str>, Overlay: AsRef<str>> PlotLines<'ui, 'p, Label, Overlay> {
|
||||||
pub const fn values_offset(mut self, values_offset: usize) -> Self {
|
pub fn values_offset(mut self, values_offset: usize) -> Self {
|
||||||
self.values_offset = values_offset;
|
self.values_offset = values_offset;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
pub fn overlay_text<Overlay2: AsRef<str>>(
|
||||||
pub const fn overlay_text(mut self, overlay_text: &'p ImStr) -> Self {
|
self,
|
||||||
self.overlay_text = Some(overlay_text);
|
overlay_text: Overlay2,
|
||||||
self
|
) -> PlotLines<'ui, 'p, Label, Overlay2> {
|
||||||
|
PlotLines {
|
||||||
|
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 fn scale_min(mut self, scale_min: f32) -> Self {
|
||||||
pub const fn scale_min(mut self, scale_min: f32) -> Self {
|
|
||||||
self.scale_min = scale_min;
|
self.scale_min = scale_min;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
pub fn scale_max(mut self, scale_max: f32) -> Self {
|
||||||
pub const fn scale_max(mut self, scale_max: f32) -> Self {
|
|
||||||
self.scale_max = scale_max;
|
self.scale_max = scale_max;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
pub fn graph_size(mut self, graph_size: [f32; 2]) -> Self {
|
||||||
pub const fn graph_size(mut self, graph_size: [f32; 2]) -> Self {
|
|
||||||
self.graph_size = graph_size;
|
self.graph_size = graph_size;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) {
|
pub fn build(self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
let (label, overlay) = self.ui.scratch_txt_with_opt(self.label, self.overlay_text);
|
||||||
|
|
||||||
sys::igPlotLinesFloatPtr(
|
sys::igPlotLinesFloatPtr(
|
||||||
self.label.as_ptr(),
|
label,
|
||||||
self.values.as_ptr() as *const c_float,
|
self.values.as_ptr() as *const c_float,
|
||||||
self.values.len() as i32,
|
self.values.len() as i32,
|
||||||
self.values_offset as i32,
|
self.values_offset as i32,
|
||||||
self.overlay_text.map(|x| x.as_ptr()).unwrap_or(ptr::null()),
|
overlay,
|
||||||
self.scale_min,
|
self.scale_min,
|
||||||
self.scale_max,
|
self.scale_max,
|
||||||
self.graph_size.into(),
|
self.graph_size.into(),
|
||||||
|
|||||||
@ -2,16 +2,7 @@ use std::ptr;
|
|||||||
|
|
||||||
use crate::sys;
|
use crate::sys;
|
||||||
use crate::window::WindowFlags;
|
use crate::window::WindowFlags;
|
||||||
use crate::{ImStr, Ui};
|
use crate::Ui;
|
||||||
|
|
||||||
create_token!(
|
|
||||||
/// Tracks a popup token that can be ended with `end` or by dropping.
|
|
||||||
pub struct PopupToken<'ui>;
|
|
||||||
|
|
||||||
/// Drops the popup token manually. You can also just allow this token
|
|
||||||
/// to drop on its own.
|
|
||||||
drop { sys::igEndPopup() }
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Create a modal pop-up.
|
/// Create a modal pop-up.
|
||||||
///
|
///
|
||||||
@ -31,14 +22,14 @@ create_token!(
|
|||||||
/// };
|
/// };
|
||||||
/// ```
|
/// ```
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct PopupModal<'p> {
|
pub struct PopupModal<'p, Label> {
|
||||||
label: &'p ImStr,
|
label: Label,
|
||||||
opened: Option<&'p mut bool>,
|
opened: Option<&'p mut bool>,
|
||||||
flags: WindowFlags,
|
flags: WindowFlags,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'p> PopupModal<'p> {
|
impl<'p, Label: AsRef<str>> PopupModal<'p, Label> {
|
||||||
pub fn new(label: &'p ImStr) -> Self {
|
pub fn new(label: Label) -> Self {
|
||||||
PopupModal {
|
PopupModal {
|
||||||
label,
|
label,
|
||||||
opened: None,
|
opened: None,
|
||||||
@ -140,7 +131,7 @@ impl<'p> PopupModal<'p> {
|
|||||||
pub fn begin_popup<'ui>(self, ui: &Ui<'ui>) -> Option<PopupToken<'ui>> {
|
pub fn begin_popup<'ui>(self, ui: &Ui<'ui>) -> Option<PopupToken<'ui>> {
|
||||||
let render = unsafe {
|
let render = unsafe {
|
||||||
sys::igBeginPopupModal(
|
sys::igBeginPopupModal(
|
||||||
self.label.as_ptr(),
|
ui.scratch_txt(self.label),
|
||||||
self.opened
|
self.opened
|
||||||
.map(|x| x as *mut bool)
|
.map(|x| x as *mut bool)
|
||||||
.unwrap_or(ptr::null_mut()),
|
.unwrap_or(ptr::null_mut()),
|
||||||
@ -165,8 +156,8 @@ impl<'ui> Ui<'ui> {
|
|||||||
/// can also force close a popup when a user clicks outside a popup. If you do not want users to be
|
/// can also force close a popup when a user clicks outside a popup. If you do not want users to be
|
||||||
/// able to close a popup without selected an option, use [`PopupModal`].
|
/// able to close a popup without selected an option, use [`PopupModal`].
|
||||||
#[doc(alias = "OpenPopup")]
|
#[doc(alias = "OpenPopup")]
|
||||||
pub fn open_popup(&self, str_id: &ImStr) {
|
pub fn open_popup(&self, str_id: impl AsRef<str>) {
|
||||||
unsafe { sys::igOpenPopup(str_id.as_ptr(), 0) };
|
unsafe { sys::igOpenPopup(self.scratch_txt(str_id), 0) };
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a popup that can have any kind of content.
|
/// Construct a popup that can have any kind of content.
|
||||||
@ -174,9 +165,10 @@ impl<'ui> Ui<'ui> {
|
|||||||
/// This should be called *per frame*, whereas [`open_popup`](Self::open_popup) should be called *once*
|
/// This should be called *per frame*, whereas [`open_popup`](Self::open_popup) should be called *once*
|
||||||
/// when you want to actual create the popup.
|
/// when you want to actual create the popup.
|
||||||
#[doc(alias = "BeginPopup")]
|
#[doc(alias = "BeginPopup")]
|
||||||
pub fn begin_popup(&self, str_id: &ImStr) -> Option<PopupToken<'_>> {
|
pub fn begin_popup(&self, str_id: impl AsRef<str>) -> Option<PopupToken<'_>> {
|
||||||
let render =
|
let render = unsafe {
|
||||||
unsafe { sys::igBeginPopup(str_id.as_ptr(), WindowFlags::empty().bits() as i32) };
|
sys::igBeginPopup(self.scratch_txt(str_id), WindowFlags::empty().bits() as i32)
|
||||||
|
};
|
||||||
|
|
||||||
if render {
|
if render {
|
||||||
Some(PopupToken::new(self))
|
Some(PopupToken::new(self))
|
||||||
@ -190,21 +182,17 @@ impl<'ui> Ui<'ui> {
|
|||||||
/// This should be called *per frame*, whereas [`open_popup`](Self::open_popup) should be called *once*
|
/// This should be called *per frame*, whereas [`open_popup`](Self::open_popup) should be called *once*
|
||||||
/// when you want to actual create the popup.
|
/// when you want to actual create the popup.
|
||||||
#[doc(alias = "BeginPopup")]
|
#[doc(alias = "BeginPopup")]
|
||||||
pub fn popup<F>(&self, str_id: &ImStr, f: F)
|
pub fn popup<F>(&self, str_id: impl AsRef<str>, f: F)
|
||||||
where
|
where
|
||||||
F: FnOnce(),
|
F: FnOnce(),
|
||||||
{
|
{
|
||||||
let render =
|
if let Some(_t) = self.begin_popup(str_id) {
|
||||||
unsafe { sys::igBeginPopup(str_id.as_ptr(), WindowFlags::empty().bits() as i32) };
|
|
||||||
if render {
|
|
||||||
f();
|
f();
|
||||||
unsafe { sys::igEndPopup() };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a PopupModal directly.
|
/// Creates a PopupModal directly.
|
||||||
#[deprecated = "Please use PopupModal to create a modal popup."]
|
pub fn popup_modal<'p, Label: AsRef<str>>(&self, str_id: Label) -> PopupModal<'p, Label> {
|
||||||
pub fn popup_modal<'p>(&self, str_id: &'p ImStr) -> PopupModal<'p> {
|
|
||||||
PopupModal::new(str_id)
|
PopupModal::new(str_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,3 +203,12 @@ impl<'ui> Ui<'ui> {
|
|||||||
unsafe { sys::igCloseCurrentPopup() };
|
unsafe { sys::igCloseCurrentPopup() };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
create_token!(
|
||||||
|
/// Tracks a popup token that can be ended with `end` or by dropping.
|
||||||
|
pub struct PopupToken<'ui>;
|
||||||
|
|
||||||
|
/// Drops the popup token manually. You can also just allow this token
|
||||||
|
/// to drop on its own.
|
||||||
|
drop { sys::igEndPopup() }
|
||||||
|
);
|
||||||
|
|||||||
@ -74,6 +74,7 @@ impl UiBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
#[deprecated = "all functions take AsRef<str> now -- use inline strings or `format` instead"]
|
||||||
macro_rules! im_str {
|
macro_rules! im_str {
|
||||||
($e:literal $(,)?) => {{
|
($e:literal $(,)?) => {{
|
||||||
const __INPUT: &str = concat!($e, "\0");
|
const __INPUT: &str = concat!($e, "\0");
|
||||||
@ -345,7 +346,6 @@ impl fmt::Write for ImString {
|
|||||||
/// A UTF-8 encoded, implicitly nul-terminated string slice.
|
/// A UTF-8 encoded, implicitly nul-terminated string slice.
|
||||||
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[deprecated]
|
|
||||||
pub struct ImStr([u8]);
|
pub struct ImStr([u8]);
|
||||||
|
|
||||||
impl<'a> Default for &'a ImStr {
|
impl<'a> Default for &'a ImStr {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user