Overhaul the drag slider API

This commit is contained in:
Joonas Javanainen 2020-09-19 14:47:09 +03:00
parent 4ce852a87c
commit 03ad6b10e0
No known key found for this signature in database
GPG Key ID: D39CCA5CB19B9179
7 changed files with 259 additions and 415 deletions

View File

@ -11,6 +11,7 @@
of closures
- API for accessing the background drawlist
- Tab bar / tab item API
- Redesigned drag slider API
### Changed

View File

@ -493,16 +493,12 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) {
ui.input_text(im_str!("input text"), &mut state.text)
.build();
ui.input_int(im_str!("input int"), &mut state.i0).build();
ui.drag_int(im_str!("drag int"), &mut state.i0).build();
Drag::new(im_str!("drag int")).build(ui, &mut state.i0);
ui.input_float(im_str!("input float"), &mut state.f0)
.step(0.01)
.step_fast(1.0)
.build();
ui.drag_float(im_str!("drag float"), &mut state.f0)
.speed(0.001)
.min(-1.0)
.max(1.0)
.build();
Drag::new(im_str!("drag float")).range(-1.0..=1.0).speed(0.001).build(ui, &mut state.f0);
ui.input_float3(im_str!("input float3"), &mut state.vec3f)
.build();
ColorEdit::new(im_str!("color 1"), &mut state.col1).build(ui);

View File

@ -1,348 +0,0 @@
use std::marker::PhantomData;
use std::ptr;
use super::{ImStr, Ui};
macro_rules! impl_display_format {
($InputType:ident) => {
#[inline]
pub fn display_format(mut self, display_format: &'p ImStr) -> Self {
self.display_format = display_format;
self
}
};
}
macro_rules! impl_speed {
($InputType:ident) => {
#[inline]
pub fn speed(mut self, value: f32) -> Self {
self.speed = value;
self
}
};
}
macro_rules! impl_min_max {
($InputType:ident, $Value:ty) => {
#[inline]
pub fn min(mut self, value: $Value) -> Self {
self.min = value;
self
}
#[inline]
pub fn max(mut self, value: $Value) -> Self {
self.max = value;
self
}
};
}
#[must_use]
pub struct DragFloat<'ui, 'p> {
label: &'p ImStr,
value: &'p mut f32,
speed: f32,
min: f32,
max: f32,
display_format: &'p ImStr,
_phantom: PhantomData<&'ui Ui<'ui>>,
}
impl<'ui, 'p> DragFloat<'ui, 'p> {
pub fn new(_: &Ui<'ui>, label: &'p ImStr, value: &'p mut f32) -> Self {
DragFloat {
label,
value,
speed: 1.0,
min: 0.0,
max: 0.0,
display_format: unsafe { ImStr::from_utf8_with_nul_unchecked(b"%.3f\0") },
_phantom: PhantomData,
}
}
pub fn build(self) -> bool {
unsafe {
sys::igDragFloat(
self.label.as_ptr(),
self.value as *mut f32,
self.speed,
self.min,
self.max,
self.display_format.as_ptr(),
0,
)
}
}
impl_display_format!(DragFloat);
impl_min_max!(DragFloat, f32);
impl_speed!(DragFloat);
}
macro_rules! impl_drag_floatn {
($DragFloatN:ident, $N:expr, $igDragFloatN:ident) => {
#[must_use]
pub struct $DragFloatN<'ui, 'p> {
label: &'p ImStr,
value: &'p mut [f32; $N],
speed: f32,
min: f32,
max: f32,
display_format: &'p ImStr,
_phantom: PhantomData<&'ui Ui<'ui>>,
}
impl<'ui, 'p> $DragFloatN<'ui, 'p> {
pub fn new(_: &Ui<'ui>, label: &'p ImStr, value: &'p mut [f32; $N]) -> Self {
$DragFloatN {
label,
value,
speed: 1.0,
min: 0.0,
max: 0.0,
display_format: unsafe { ImStr::from_utf8_with_nul_unchecked(b"%.3f\0") },
_phantom: PhantomData,
}
}
pub fn build(self) -> bool {
unsafe {
sys::$igDragFloatN(
self.label.as_ptr(),
self.value.as_mut_ptr(),
self.speed,
self.min,
self.max,
self.display_format.as_ptr(),
0,
)
}
}
impl_display_format!(DragFloat);
impl_min_max!(DragFloat, f32);
impl_speed!(DragFloat);
}
};
}
impl_drag_floatn!(DragFloat2, 2, igDragFloat2);
impl_drag_floatn!(DragFloat3, 3, igDragFloat3);
impl_drag_floatn!(DragFloat4, 4, igDragFloat4);
#[must_use]
pub struct DragFloatRange2<'ui, 'p> {
label: &'p ImStr,
current_min: &'p mut f32,
current_max: &'p mut f32,
speed: f32,
min: f32,
max: f32,
display_format: &'p ImStr,
display_format_max: Option<&'p ImStr>,
_phantom: PhantomData<&'ui Ui<'ui>>,
}
impl<'ui, 'p> DragFloatRange2<'ui, 'p> {
pub fn new(
_: &Ui<'ui>,
label: &'p ImStr,
current_min: &'p mut f32,
current_max: &'p mut f32,
) -> Self {
DragFloatRange2 {
label,
current_min,
current_max,
speed: 1.0,
min: 0.0,
max: 0.0,
display_format: unsafe { ImStr::from_utf8_with_nul_unchecked(b"%.3f\0") },
display_format_max: None,
_phantom: PhantomData,
}
}
pub fn build(self) -> bool {
unsafe {
sys::igDragFloatRange2(
self.label.as_ptr(),
self.current_min as *mut f32,
self.current_max as *mut f32,
self.speed,
self.min,
self.max,
self.display_format.as_ptr(),
self.display_format_max.map_or(ptr::null(), |f| f.as_ptr()),
0,
)
}
}
#[inline]
pub fn display_format_max(mut self, display_format: Option<&'p ImStr>) -> Self {
self.display_format_max = display_format;
self
}
impl_display_format!(DragFloatRange2);
impl_min_max!(DragFloatRange2, f32);
impl_speed!(DragFloatRange2);
}
#[must_use]
pub struct DragInt<'ui, 'p> {
label: &'p ImStr,
value: &'p mut i32,
speed: f32,
min: i32,
max: i32,
display_format: &'p ImStr,
_phantom: PhantomData<&'ui Ui<'ui>>,
}
impl<'ui, 'p> DragInt<'ui, 'p> {
pub fn new(_: &Ui<'ui>, label: &'p ImStr, value: &'p mut i32) -> Self {
DragInt {
label,
value,
speed: 1.0,
min: 0,
max: 0,
display_format: unsafe { ImStr::from_utf8_with_nul_unchecked(b"%.0f\0") },
_phantom: PhantomData,
}
}
pub fn build(self) -> bool {
unsafe {
sys::igDragInt(
self.label.as_ptr(),
self.value as *mut i32,
self.speed,
self.min,
self.max,
self.display_format.as_ptr(),
0,
)
}
}
impl_display_format!(DragInt);
impl_min_max!(DragInt, i32);
impl_speed!(DragInt);
}
macro_rules! impl_drag_intn {
($DragIntN:ident, $N:expr, $igDragIntN:ident) => {
#[must_use]
pub struct $DragIntN<'ui, 'p> {
label: &'p ImStr,
value: &'p mut [i32; $N],
speed: f32,
min: i32,
max: i32,
display_format: &'p ImStr,
_phantom: PhantomData<&'ui Ui<'ui>>,
}
impl<'ui, 'p> $DragIntN<'ui, 'p> {
pub fn new(_: &Ui<'ui>, label: &'p ImStr, value: &'p mut [i32; $N]) -> Self {
$DragIntN {
label,
value,
speed: 1.0,
min: 0,
max: 0,
display_format: unsafe { ImStr::from_utf8_with_nul_unchecked(b"%.0f\0") },
_phantom: PhantomData,
}
}
pub fn build(self) -> bool {
unsafe {
sys::$igDragIntN(
self.label.as_ptr(),
self.value.as_mut_ptr(),
self.speed,
self.min,
self.max,
self.display_format.as_ptr(),
0,
)
}
}
impl_display_format!(DragInt);
impl_min_max!(DragInt, i32);
impl_speed!(DragInt);
}
};
}
impl_drag_intn!(DragInt2, 2, igDragInt2);
impl_drag_intn!(DragInt3, 3, igDragInt3);
impl_drag_intn!(DragInt4, 4, igDragInt4);
#[must_use]
pub struct DragIntRange2<'ui, 'p> {
label: &'p ImStr,
current_min: &'p mut i32,
current_max: &'p mut i32,
speed: f32,
min: i32,
max: i32,
display_format: &'p ImStr,
display_format_max: Option<&'p ImStr>,
_phantom: PhantomData<&'ui Ui<'ui>>,
}
impl<'ui, 'p> DragIntRange2<'ui, 'p> {
pub fn new(
_: &Ui<'ui>,
label: &'p ImStr,
current_min: &'p mut i32,
current_max: &'p mut i32,
) -> Self {
DragIntRange2 {
label,
current_min,
current_max,
speed: 1.0,
min: 0,
max: 0,
display_format: unsafe { ImStr::from_utf8_with_nul_unchecked(b"%.0f\0") },
display_format_max: None,
_phantom: PhantomData,
}
}
pub fn build(self) -> bool {
unsafe {
sys::igDragIntRange2(
self.label.as_ptr(),
self.current_min as *mut i32,
self.current_max as *mut i32,
self.speed,
self.min,
self.max,
self.display_format.as_ptr(),
self.display_format_max.map_or(ptr::null(), |f| f.as_ptr()),
0,
)
}
}
#[inline]
pub fn display_format_max(mut self, display_format: Option<&'p ImStr>) -> Self {
self.display_format_max = display_format;
self
}
impl_display_format!(DragIntRange2);
impl_min_max!(DragIntRange2, i32);
impl_speed!(DragIntRange2);
}

View File

@ -1,5 +1,6 @@
//! Internal raw utilities (don't use unless you know what you're doing!)
use std::ops::{RangeFrom, RangeInclusive, RangeToInclusive};
use std::slice;
/// A generic version of the raw imgui-sys ImVector struct types
@ -149,3 +150,35 @@ unsafe impl DataTypeKind for f32 {
unsafe impl DataTypeKind for f64 {
const KIND: DataType = DataType::F64;
}
pub trait InclusiveRangeBounds<T: Copy> {
fn start_bound(&self) -> Option<&T>;
fn end_bound(&self) -> Option<&T>;
}
impl<T: Copy> InclusiveRangeBounds<T> for RangeFrom<T> {
fn start_bound(&self) -> Option<&T> {
Some(&self.start)
}
fn end_bound(&self) -> Option<&T> {
None
}
}
impl<T: Copy> InclusiveRangeBounds<T> for RangeInclusive<T> {
fn start_bound(&self) -> Option<&T> {
Some(self.start())
}
fn end_bound(&self) -> Option<&T> {
Some(self.end())
}
}
impl<T: Copy> InclusiveRangeBounds<T> for RangeToInclusive<T> {
fn start_bound(&self) -> Option<&T> {
None
}
fn end_bound(&self) -> Option<&T> {
Some(&self.end)
}
}

View File

@ -11,10 +11,6 @@ use std::thread;
pub use self::clipboard::*;
pub use self::context::*;
pub use self::drag::{
DragFloat, DragFloat2, DragFloat3, DragFloat4, DragFloatRange2, DragInt, DragInt2, DragInt3,
DragInt4, DragIntRange2,
};
pub use self::fonts::atlas::*;
pub use self::fonts::font::*;
pub use self::fonts::glyph::*;
@ -38,6 +34,7 @@ pub use self::style::*;
pub use self::utils::*;
pub use self::widget::color_editors::*;
pub use self::widget::combo_box::*;
pub use self::widget::drag::*;
pub use self::widget::image::*;
pub use self::widget::menu::*;
pub use self::widget::progress_bar::*;
@ -53,7 +50,6 @@ use internal::RawCast;
mod clipboard;
mod columns;
mod context;
mod drag;
mod fonts;
mod input;
mod input_widget;
@ -272,62 +268,6 @@ impl<'ui> Ui<'ui> {
}
}
// Widgets: Drag
impl<'ui> Ui<'ui> {
pub fn drag_float<'p>(&self, label: &'p ImStr, value: &'p mut f32) -> DragFloat<'ui, 'p> {
DragFloat::new(self, label, value)
}
pub fn drag_float2<'p>(
&self,
label: &'p ImStr,
value: &'p mut [f32; 2],
) -> DragFloat2<'ui, 'p> {
DragFloat2::new(self, label, value)
}
pub fn drag_float3<'p>(
&self,
label: &'p ImStr,
value: &'p mut [f32; 3],
) -> DragFloat3<'ui, 'p> {
DragFloat3::new(self, label, value)
}
pub fn drag_float4<'p>(
&self,
label: &'p ImStr,
value: &'p mut [f32; 4],
) -> DragFloat4<'ui, 'p> {
DragFloat4::new(self, label, value)
}
pub fn drag_float_range2<'p>(
&self,
label: &'p ImStr,
current_min: &'p mut f32,
current_max: &'p mut f32,
) -> DragFloatRange2<'ui, 'p> {
DragFloatRange2::new(self, label, current_min, current_max)
}
pub fn drag_int<'p>(&self, label: &'p ImStr, value: &'p mut i32) -> DragInt<'ui, 'p> {
DragInt::new(self, label, value)
}
pub fn drag_int2<'p>(&self, label: &'p ImStr, value: &'p mut [i32; 2]) -> DragInt2<'ui, 'p> {
DragInt2::new(self, label, value)
}
pub fn drag_int3<'p>(&self, label: &'p ImStr, value: &'p mut [i32; 3]) -> DragInt3<'ui, 'p> {
DragInt3::new(self, label, value)
}
pub fn drag_int4<'p>(&self, label: &'p ImStr, value: &'p mut [i32; 4]) -> DragInt4<'ui, 'p> {
DragInt4::new(self, label, value)
}
pub fn drag_int_range2<'p>(
&self,
label: &'p ImStr,
current_min: &'p mut i32,
current_max: &'p mut i32,
) -> DragIntRange2<'ui, 'p> {
DragIntRange2::new(self, label, current_min, current_max)
}
}
/// Tracks a layout tooltip that must be ended by calling `.end()`
#[must_use]
pub struct TooltipToken {

221
src/widget/drag.rs Normal file
View File

@ -0,0 +1,221 @@
use std::os::raw::c_void;
use std::ptr;
use crate::internal::{DataTypeKind, InclusiveRangeBounds};
use crate::string::ImStr;
use crate::sys;
use crate::widget::slider::SliderFlags;
use crate::Ui;
/// Builder for a drag slider widget.
#[derive(Copy, Clone, Debug)]
#[must_use]
pub struct Drag<'a, T: DataTypeKind> {
label: &'a ImStr,
speed: f32,
min: Option<T>,
max: Option<T>,
display_format: Option<&'a ImStr>,
flags: SliderFlags,
}
impl<'a, T: DataTypeKind> Drag<'a, T> {
/// Constructs a new drag slider builder.
pub fn new(label: &ImStr) -> Drag<T> {
Drag {
label,
speed: 1.0,
min: None,
max: None,
display_format: None,
flags: SliderFlags::empty(),
}
}
#[inline]
pub fn range<R: InclusiveRangeBounds<T>>(mut self, range: R) -> Self {
self.min = range.start_bound().copied();
self.max = range.end_bound().copied();
self
}
/// 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
}
/// Replaces all current settings with the given flags
#[inline]
pub fn flags(mut self, flags: SliderFlags) -> Self {
self.flags = flags;
self
}
/// Builds a drag slider that is bound to the given value.
///
/// Returns true if the slider value was changed.
pub fn build(self, _: &Ui, value: &mut T) -> bool {
unsafe {
sys::igDragScalar(
self.label.as_ptr(),
T::KIND as i32,
value as *mut T as *mut c_void,
self.speed,
self.min
.as_ref()
.map(|min| min as *const T)
.unwrap_or(ptr::null()) as *const c_void,
self.max
.as_ref()
.map(|max| max as *const T)
.unwrap_or(ptr::null()) as *const c_void,
self.display_format
.map(ImStr::as_ptr)
.unwrap_or(ptr::null()),
self.flags.bits() as i32,
)
}
}
/// Builds a horizontal array of multiple drag sliders attached to the given slice.
///
/// Returns true if any slider value was changed.
pub fn build_array(self, _: &Ui, values: &mut [T]) -> bool {
unsafe {
sys::igDragScalarN(
self.label.as_ptr(),
T::KIND as i32,
values.as_mut_ptr() as *mut c_void,
values.len() as i32,
self.speed,
self.min
.as_ref()
.map(|min| min as *const T)
.unwrap_or(ptr::null()) as *const c_void,
self.max
.as_ref()
.map(|max| max as *const T)
.unwrap_or(ptr::null()) as *const c_void,
self.display_format
.map(ImStr::as_ptr)
.unwrap_or(ptr::null()),
self.flags.bits() as i32,
)
}
}
}
/// Builder for a drag slider widget.
#[derive(Copy, Clone, Debug)]
#[must_use]
pub struct DragRange<'a, T: DataTypeKind> {
label: &'a ImStr,
speed: f32,
min: Option<T>,
max: Option<T>,
display_format: Option<&'a ImStr>,
max_display_format: Option<&'a ImStr>,
flags: SliderFlags,
}
impl<'a, T: DataTypeKind> DragRange<'a, T> {
/// Constructs a new drag slider builder.
pub fn new(label: &ImStr) -> DragRange<T> {
DragRange {
label,
speed: 1.0,
min: None,
max: None,
display_format: None,
max_display_format: None,
flags: SliderFlags::empty(),
}
}
#[inline]
pub fn range<R: InclusiveRangeBounds<T>>(mut self, range: R) -> Self {
self.min = range.start_bound().copied();
self.max = range.end_bound().copied();
self
}
/// 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
}
/// 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
}
/// 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> {
/// Builds a drag range slider that is bound to the given min/max values.
///
/// Returns true if the slider value was changed.
pub fn build(self, _: &Ui, min: &mut f32, max: &mut f32) -> bool {
unsafe {
sys::igDragFloatRange2(
self.label.as_ptr(),
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()),
self.flags.bits() as i32,
)
}
}
}
impl<'a> DragRange<'a, i32> {
/// Builds a drag range slider that is bound to the given min/max values.
///
/// Returns true if the slider value was changed.
pub fn build(self, _: &Ui, min: &mut i32, max: &mut i32) -> bool {
unsafe {
sys::igDragIntRange2(
self.label.as_ptr(),
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()),
self.flags.bits() as i32,
)
}
}
}

View File

@ -1,5 +1,6 @@
pub mod color_editors;
pub mod combo_box;
pub mod drag;
pub mod image;
pub mod menu;
pub mod misc;