mirror of
https://github.com/eliasstepanik/imgui-rs.git
synced 2026-01-14 15:08:36 +00:00
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:
parent
e0125f4c06
commit
694cd96d49
@ -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"))
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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.
|
||||
///
|
||||
|
||||
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 => {
|
||||
|
||||
122
imgui/src/lib.rs
122
imgui/src/lib.rs
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user