converted combo_box and drag

This commit is contained in:
Jack Spira 2021-09-07 22:44:39 -07:00 committed by Jack Mac
parent 08d285d029
commit 540aa5f292
4 changed files with 167 additions and 55 deletions

View File

@ -480,7 +480,7 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) {
ui.separator();
ui.label_text(im_str!("label"), im_str!("Value"));
ComboBox::new(&"combo").build_simple_string(ui,
ui.combo_simple_string("combo",
&mut state.item,
&[
im_str!("aaaa"),
@ -502,8 +502,7 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) {
im_str!("JJJJ"),
im_str!("KKKK"),
];
ComboBox::new(im_str!("combo scroll")).build_simple_string(ui, &mut state.item2, &items);
ui.combo_simple_string("combo scroll", &mut state.item2, &items);
ui.list_box(im_str!("list"), &mut state.item3, &items, 8);
@ -540,7 +539,7 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) {
.hint(im_str!("enter text here"))
.build();
ui.input_int(im_str!("input int"), &mut state.i0).build();
Drag::new(im_str!("drag int")).build(ui, &mut state.i0);
// 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)
@ -808,7 +807,7 @@ CTRL+click on individual component to input value.\n",
);
let items = &[im_str!("aaaa"), im_str!("bbbb"), im_str!("cccc"), im_str!("dddd"), im_str!("eeee")];
ComboBox::new(im_str!("Combo")).build_simple_string(ui, &mut state.stacked_modals_item, items);
ui.combo_simple_string("Combo", &mut state.stacked_modals_item, items);
ColorEdit::new(im_str!("color"), &mut state.stacked_modals_color).build(ui);
@ -904,8 +903,8 @@ fn show_example_menu_file<'a>(ui: &Ui<'a>, state: &mut FileMenuState) {
ui.input_float(im_str!("Input"), &mut state.f)
.step(0.1)
.build();
let items = [im_str!("Yes"), im_str!("No"), im_str!("Maybe")];
ComboBox::new(im_str!("Combo")).build_simple_string(ui, &mut state.n, &items);
let items = ["Yes", "No", "Maybe"];
ui.combo_simple_string("Combo", &mut state.n, &items);
ui.checkbox(im_str!("Check"), &mut state.b);
menu.end();
}

View File

@ -157,6 +157,31 @@ impl<'ui> Ui<'ui> {
}
}
fn scratch_txt_with_opt(
&self,
txt_0: impl AsRef<str>,
txt_1: Option<impl AsRef<str>>,
) -> (*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())
}
}
}
/// Returns an immutable reference to the inputs/outputs object
#[doc(alias = "GetIO")]
pub fn io(&self) -> &Io {

View File

@ -54,7 +54,7 @@ pub struct ComboBoxFlags: u32 {
/// Builder for a combo box widget
#[derive(Copy, Clone, Debug)]
#[must_use]
pub struct ComboBox<T, P = String> {
pub struct ComboBox<T, P> {
label: T,
preview_value: Option<P>,
flags: ComboBoxFlags,
@ -63,21 +63,14 @@ pub struct ComboBox<T, P = String> {
impl<'a, T: AsRef<str>, P: AsRef<str>> ComboBox<T, P> {
/// Constructs a new combo box builder.
#[doc(alias = "BeginCombo")]
pub fn new(label: T) -> Self {
pub fn new(label: T, preview_value: Option<P>) -> Self {
ComboBox {
label,
preview_value: None,
preview_value,
flags: ComboBoxFlags::empty(),
}
}
/// Sets the preview value displayed in the preview box (if visible).
#[inline]
pub fn preview_value(mut self, preview_value: P) -> Self {
self.preview_value = Some(preview_value);
self
}
/// Replaces all current settings with the given flags.
#[inline]
pub fn flags(mut self, flags: ComboBoxFlags) -> Self {
@ -173,48 +166,143 @@ create_token!(
);
/// # Convenience functions
impl<'a, T: AsRef<str> + Clone> ComboBox<T, Cow<'a, str>> {
/// Builds a simple combo box for choosing from a slice of values
impl<'ui> Ui<'ui> {
/// Creates a combo box which can be appended to with `Selectable::new`.
///
/// If you do not want to provide a preview, use [begin_combo_no_preview]. If you want
/// to pass flags, use [begin_combo_with_flags].
///
/// Returns `Some(ComboBoxToken)` if the combo box is open. After content has been
/// rendered, the token must be ended by calling `.end()`.
///
/// Returns `None` if the combo box is not open and no content should be rendered.
#[must_use]
#[doc(alias = "BeginCombo")]
pub fn build_simple<V, L>(
mut self,
ui: &Ui,
pub fn begin_combo(
&self,
label: impl AsRef<str>,
preview_value: impl AsRef<str>,
) -> Option<ComboBoxToken<'ui>> {
self.begin_combo_with_flags(label, preview_value, ComboBoxFlags::empty())
}
/// Creates a combo box which can be appended to with `Selectable::new`.
///
/// If you do not want to provide a preview, use [begin_combo_no_preview].
/// Returns `Some(ComboBoxToken)` if the combo box is open. After content has been
/// rendered, the token must be ended by calling `.end()`.
///
/// Returns `None` if the combo box is not open and no content should be rendered.
#[must_use]
#[doc(alias = "BeginCombo")]
pub fn begin_combo_with_flags(
&self,
label: impl AsRef<str>,
preview_value: impl AsRef<str>,
flags: ComboBoxFlags,
) -> Option<ComboBoxToken<'ui>> {
self._begin_combo(label, Some(preview_value), flags)
}
/// Creates a combo box which can be appended to with `Selectable::new`.
///
/// If you want to provide a preview, use [begin_combo]. If you want
/// to pass flags, use [begin_combo_no_preview_with_flags].
///
/// Returns `Some(ComboBoxToken)` if the combo box is open. After content has been
/// rendered, the token must be ended by calling `.end()`.
///
/// Returns `None` if the combo box is not open and no content should be rendered.
#[must_use]
#[doc(alias = "BeginCombo")]
pub fn begin_combo_no_preview(&self, label: impl AsRef<str>) -> Option<ComboBoxToken<'ui>> {
self.begin_combo_no_preview_with_flags(label, ComboBoxFlags::empty())
}
/// Creates a combo box which can be appended to with `Selectable::new`.
///
/// If you do not want to provide a preview, use [begin_combo_no_preview].
/// Returns `Some(ComboBoxToken)` if the combo box is open. After content has been
/// rendered, the token must be ended by calling `.end()`.
///
/// Returns `None` if the combo box is not open and no content should be rendered.
#[must_use]
#[doc(alias = "BeginCombo")]
pub fn begin_combo_no_preview_with_flags(
&self,
label: impl AsRef<str>,
flags: ComboBoxFlags,
) -> Option<ComboBoxToken<'ui>> {
self._begin_combo(label, Option::<&'static str>::None, flags)
}
/// This is the internal begin combo method that they all...eventually call.
fn _begin_combo(
&self,
label: impl AsRef<str>,
preview_value: Option<impl AsRef<str>>,
flags: ComboBoxFlags,
) -> Option<ComboBoxToken<'ui>> {
let should_render = unsafe {
let (ptr_one, ptr_two) = self.scratch_txt_with_opt(label, preview_value);
sys::igBeginCombo(ptr_one, ptr_two, flags.bits() as i32)
};
if should_render {
Some(ComboBoxToken::new(self))
} else {
None
}
}
/// Builds a simple combo box for choosing from a slice of values
#[doc(alias = "Combo")]
pub fn combo<V, L>(
&self,
label: impl AsRef<str>,
current_item: &mut usize,
items: &'a [V],
label_fn: &L,
items: &[V],
label_fn: L,
) -> bool
where
for<'b> L: Fn(&'b V) -> Cow<'b, str>,
{
use crate::widget::selectable::Selectable;
let label_fn = &label_fn;
let mut result = false;
let preview_value = items.get(*current_item).map(label_fn);
if self.preview_value.is_none() {
if let Some(preview_value) = preview_value {
self = self.preview_value(preview_value);
}
}
if let Some(_cb) = self.begin(ui) {
if let Some(_cb) = self._begin_combo(label, preview_value, ComboBoxFlags::empty()) {
for (idx, item) in items.iter().enumerate() {
let text = label_fn(item);
let selected = idx == *current_item;
if Selectable::new(&text).selected(selected).build(ui) {
if Selectable::new(&text).selected(selected).build(self) {
*current_item = idx;
result = true;
}
if selected {
ui.set_item_default_focus();
self.set_item_default_focus();
}
}
}
result
}
/// Builds a simple combo box for choosing from a slice of strings
#[doc(alias = "BeginCombo")]
pub fn build_simple_string<S>(self, ui: &Ui, current_item: &mut usize, items: &[&S]) -> bool
where
S: AsRef<str> + ?Sized,
{
self.build_simple(ui, current_item, items, &|&s| s.as_ref().into())
/// Builds a simple combo box for choosing from a slice of values
#[doc(alias = "Combo")]
pub fn combo_simple_string(
&self,
label: impl AsRef<str>,
current_item: &mut usize,
items: &[impl AsRef<str>],
) -> bool {
self.combo(label, current_item, items, |s| Cow::Borrowed(s.as_ref()))
}
// /// Builds a simple combo box for choosing from a slice of strings
// #[doc(alias = "BeginCombo")]
// pub fn build_simple_string<S>(self, ui: &Ui, current_item: &mut usize, items: &[&S]) -> bool
// where
// S: AsRef<str> + ?Sized,
// {
// self.build_simple(ui, current_item, items, &|&s| s.as_ref().into())
// }
}

View File

@ -10,19 +10,19 @@ use crate::Ui;
/// Builder for a drag slider widget.
#[derive(Copy, Clone, Debug)]
#[must_use]
pub struct Drag<'a, T: DataTypeKind> {
label: &'a ImStr,
pub struct Drag<'a, T, L> {
label: L,
speed: f32,
min: Option<T>,
max: Option<T>,
display_format: Option<&'a ImStr>,
display_format: Option<&'a str>,
flags: SliderFlags,
}
impl<'a, T: DataTypeKind> Drag<'a, T> {
impl<'a, L: AsRef<str>, T: DataTypeKind> Drag<'a, T, L> {
/// Constructs a new drag slider builder.
#[doc(alias = "DragScalar", alias = "DragScalarN")]
pub fn new(label: &ImStr) -> Drag<T> {
pub fn new(label: L) -> Self {
Drag {
label,
speed: 1.0,
@ -49,7 +49,7 @@ impl<'a, T: DataTypeKind> Drag<'a, T> {
}
/// Sets the display format using *a C-style printf string*
#[inline]
pub fn display_format(mut self, display_format: &'a ImStr) -> Self {
pub fn display_format(mut self, display_format: &'a str) -> Self {
self.display_format = Some(display_format);
self
}
@ -62,10 +62,12 @@ impl<'a, T: DataTypeKind> Drag<'a, T> {
/// 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 {
pub fn build(self, ui: &Ui, value: &mut T) -> bool {
unsafe {
let (one, two) = ui.scratch_txt_with_opt(self.label, self.display_format);
sys::igDragScalar(
self.label.as_ptr(),
one,
T::KIND as i32,
value as *mut T as *mut c_void,
self.speed,
@ -77,9 +79,7 @@ impl<'a, T: DataTypeKind> Drag<'a, T> {
.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()),
two,
self.flags.bits() as i32,
)
}
@ -87,10 +87,12 @@ impl<'a, T: DataTypeKind> Drag<'a, T> {
/// 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 {
pub fn build_array(self, ui: &Ui, values: &mut [T]) -> bool {
unsafe {
let (one, two) = ui.scratch_txt_with_opt(self.label, self.display_format);
sys::igDragScalarN(
self.label.as_ptr(),
one,
T::KIND as i32,
values.as_mut_ptr() as *mut c_void,
values.len() as i32,
@ -103,9 +105,7 @@ impl<'a, T: DataTypeKind> Drag<'a, T> {
.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()),
two,
self.flags.bits() as i32,
)
}