Merge pull request #15 from bitshifter/input

Exposed more input functionality
This commit is contained in:
Joonas Javanainen 2016-06-09 09:14:34 +03:00
commit 3d3709bd73
4 changed files with 507 additions and 119 deletions

View File

@ -33,6 +33,18 @@ struct State {
bg_alpha: f32,
wrap_width: f32,
buf: String,
item: i32,
item2: i32,
text: String,
i0: i32,
f0: f32,
vec2f: [f32;2],
vec3f: [f32;3],
vec2i: [i32;2],
vec3i: [i32;3],
col1: [f32;3],
col2: [f32;4],
selected_fish: Option<usize>,
auto_resize_state: AutoResizeState,
file_menu: FileMenuState
}
@ -42,6 +54,10 @@ impl Default for State {
let mut buf = "日本語".to_owned();
buf.extend(repeat('\0').take(32));
buf.truncate(32);
let mut text = String::with_capacity(128);
text.push_str("Hello, world!");
let remaining = text.capacity() - text.len();
text.extend(repeat('\0').take(remaining));
State {
clear_color: (114.0 / 255.0, 144.0 / 255.0, 154.0 / 255.0, 1.0),
show_app_metrics: false,
@ -64,6 +80,18 @@ impl Default for State {
bg_alpha: 0.65,
wrap_width: 200.0,
buf: buf,
item: 0,
item2: 0,
text: text,
i0: 123,
f0: 0.001,
vec2f: [0.10, 0.20],
vec3f: [0.10, 0.20, 0.30],
vec2i: [10, 20],
vec3i: [10, 20, 30],
col1: [1.0, 0.0, 0.2],
col2: [0.4, 0.7, 0.0, 0.5],
selected_fish: None,
auto_resize_state: Default::default(),
file_menu: Default::default()
}
@ -213,7 +241,7 @@ fn show_test_window<'a>(ui: &Ui<'a>, state: &mut State, opened: &mut bool) {
ui.same_line(300.0);
ui.checkbox(im_str!("no collapse"), &mut state.no_collapse);
ui.checkbox(im_str!("no menu"), &mut state.no_menu);
ui.slider_f32(im_str!("bg alpha"), &mut state.bg_alpha, 0.0, 1.0).build();
ui.slider_float(im_str!("bg alpha"), &mut state.bg_alpha, 0.0, 1.0).build();
ui.tree_node(im_str!("Style")).build(|| {
// TODO: Reimplement style editor
@ -261,7 +289,7 @@ fn show_test_window<'a>(ui: &Ui<'a>, state: &mut State, opened: &mut bool) {
suitable for English and possibly other languages."));
ui.spacing();
ui.slider_f32(im_str!("Wrap width"), &mut state.wrap_width, -20.0, 600.0)
ui.slider_float(im_str!("Wrap width"), &mut state.wrap_width, -20.0, 600.0)
.display_format(im_str!("%.0f"))
.build();
@ -281,6 +309,57 @@ fn show_test_window<'a>(ui: &Ui<'a>, state: &mut State, opened: &mut bool) {
ui.text(im_str!("Kanjis: 日本語 (nihongo)"));
ui.input_text(im_str!("UTF-8 input"), &mut state.buf).build();
});
ui.separator();
ui.label_text(im_str!("label"), im_str!("Value"));
ui.combo(im_str!("combo"), &mut state.item, &[im_str!("aaaa"), im_str!("bbbb"),
im_str!("cccc"), im_str!("dddd"), im_str!("eeee")], -1);
let items = [
im_str!("AAAA"), im_str!("BBBB"), im_str!("CCCC"), im_str!("DDDD"),
im_str!("EEEE"), im_str!("FFFF"), im_str!("GGGG"), im_str!("HHHH"),
im_str!("IIII"), im_str!("JJJJ"), im_str!("KKKK")];
ui.combo(im_str!("combo scroll"), &mut state.item2, &items, -1);
ui.input_text(im_str!("input text"), &mut state.text).build();
ui.input_int(im_str!("input int"), &mut state.i0).build();
ui.input_float(im_str!("input float"), &mut state.f0)
.step(0.01).step_fast(1.0).build();
ui.input_float3(im_str!("input float3"), &mut state.vec3f).build();
ui.color_edit3(im_str!("color 1"), &mut state.col1).build();
ui.color_edit4(im_str!("color 2"), &mut state.col2).build();
ui.tree_node(im_str!("Multi-component Widgets")).build(|| {
ui.input_float2(im_str!("input float2"), &mut state.vec2f).build();
ui.input_int2(im_str!("input int2"), &mut state.vec2i).build();
ui.spacing();
ui.input_float3(im_str!("input float3"), &mut state.vec3f).build();
ui.input_int3(im_str!("input int3"), &mut state.vec3i).build();
ui.spacing();
});
}
if ui.collapsing_header(im_str!("Popups & Modal windows")).build() {
ui.tree_node(im_str!("Popups")).build(|| {
ui.text_wrapped(im_str!("When a popup is active, it inhibits interacting with windows that are behind the popup. Clicking outside the popup closes it."));
let names = [im_str!("Bream"), im_str!("Haddock"), im_str!("Mackerel"), im_str!("Pollock"), im_str!("Tilefish")];
if ui.small_button(im_str!("Select..")) {
ui.open_popup(im_str!("select"));
}
ui.same_line(0.0);
ui.text(
match state.selected_fish {
Some(index) => names[index].clone(),
None => im_str!("<None>")
});
ui.popup(im_str!("select"), || {
ui.text(im_str!("Aquarium"));
ui.separator();
for (index, name) in names.iter().enumerate() {
if ui.selectable(name.clone(), false, ImGuiSelectableFlags::empty(), ImVec2::new(0.0, 0.0)) {
state.selected_fish = Some(index);
}
}
});
});
}
})
}
@ -344,7 +423,7 @@ fn show_example_app_auto_resize<'a>(ui: &Ui<'a>, state: &mut AutoResizeState, op
ui.text(im_str!("Window will resize every-ui to the size of its content.
Note that you probably don't want to query the window size to
output your content because that would create a feedback loop."));
ui.slider_i32(im_str!("Number of lines"), &mut state.lines, 1, 20).build();
ui.slider_int(im_str!("Number of lines"), &mut state.lines, 1, 20).build();
for i in 0 .. state.lines {
ui.text(im_str!("{:2$}This is line {}", "", i, i as usize * 4));
}

View File

@ -794,8 +794,8 @@ extern "C" {
data: *mut c_void, items_count: c_int,
height_in_items: c_int) -> bool;
pub fn igColorButton(col: ImVec4, small_height: bool, outline_border: bool) -> bool;
pub fn igColorEdit3(label: *const c_char, col: [c_float; 3]) -> bool;
pub fn igColorEdit4(label: *const c_char, col: [c_float; 4], show_alpha: bool) -> bool;
pub fn igColorEdit3(label: *const c_char, col: *mut f32) -> bool;
pub fn igColorEdit4(label: *const c_char, col: *mut f32, show_alpha: bool) -> bool;
pub fn igColorEditMode(mode: ImGuiColorEditMode);
pub fn igPlotLines(label: *const c_char,
values: *const c_float, values_count: c_int, values_offset: c_int,

View File

@ -15,6 +15,155 @@ use super::{
ImStr
};
macro_rules! impl_text_flags {
($InputType:ident) => {
#[inline]
pub fn flags(self, flags: ImGuiInputTextFlags) -> Self {
$InputType {
flags: flags,
.. self
}
}
#[inline]
pub fn chars_decimal(self, value: bool) -> Self {
$InputType {
flags: self.flags.with(ImGuiInputTextFlags_CharsDecimal, value),
.. self
}
}
#[inline]
pub fn chars_hexadecimal(self, value: bool) -> Self {
$InputType {
flags: self.flags.with(ImGuiInputTextFlags_CharsHexadecimal, value),
.. self
}
}
#[inline]
pub fn chars_uppercase(self, value: bool) -> Self {
$InputType {
flags: self.flags.with(ImGuiInputTextFlags_CharsUppercase, value),
.. self
}
}
#[inline]
pub fn chars_noblank(self, value: bool) -> Self {
$InputType {
flags: self.flags.with(ImGuiInputTextFlags_CharsNoBlank, value),
.. self
}
}
#[inline]
pub fn auto_select_all(self, value: bool) -> Self {
$InputType {
flags: self.flags.with(ImGuiInputTextFlags_AutoSelectAll, value),
.. self
}
}
#[inline]
pub fn enter_returns_true(self, value: bool) -> Self {
$InputType {
flags: self.flags.with(ImGuiInputTextFlags_EnterReturnsTrue, value),
.. self
}
}
#[inline]
pub fn callback_completion(self, value: bool) -> Self {
$InputType {
flags: self.flags.with(ImGuiInputTextFlags_CallbackCompletion, value),
.. self
}
}
#[inline]
pub fn callback_history(self, value: bool) -> Self {
$InputType {
flags: self.flags.with(ImGuiInputTextFlags_CallbackHistory, value),
.. self
}
}
#[inline]
pub fn callback_always(self, value: bool) -> Self {
$InputType {
flags: self.flags.with(ImGuiInputTextFlags_CallbackAlways, value),
.. self
}
}
#[inline]
pub fn callback_char_filter(self, value: bool) -> Self {
$InputType {
flags: self.flags.with(ImGuiInputTextFlags_CallbackCharFilter, value),
.. self
}
}
#[inline]
pub fn allow_tab_input(self, value: bool) -> Self {
$InputType {
flags: self.flags.with(ImGuiInputTextFlags_AllowTabInput, value),
.. self
}
}
#[inline]
pub fn no_horizontal_scroll(self, value: bool) -> Self {
$InputType {
flags: self.flags.with(ImGuiInputTextFlags_NoHorizontalScroll, value),
.. self
}
}
#[inline]
pub fn always_insert_mode(self, value: bool) -> Self {
$InputType {
flags: self.flags.with(ImGuiInputTextFlags_AlwaysInsertMode, value),
.. self
}
}
}
}
macro_rules! impl_step_params {
($InputType:ident, $Value:ty) => {
#[inline]
pub fn step(self, value: $Value) -> Self {
$InputType {
step: value,
.. self
}
}
#[inline]
pub fn step_fast(self, value: $Value) -> Self {
$InputType {
step_fast: value,
.. self
}
}
}
}
macro_rules! impl_precision_params {
($InputType:ident) => {
#[inline]
pub fn decimal_precision(self, value: i32) -> Self {
$InputType {
decimal_precision: value,
.. self
}
}
}
}
#[must_use]
pub struct InputText<'ui, 'p> {
label: ImStr<'p>,
@ -33,117 +182,7 @@ impl<'ui, 'p> InputText<'ui, 'p> {
}
}
#[inline]
pub fn flags(self, flags: ImGuiInputTextFlags) -> Self {
InputText {
flags: flags,
.. self
}
}
#[inline]
pub fn chars_decimal(self, value: bool) -> Self {
InputText {
flags: self.flags.with(ImGuiInputTextFlags_CharsDecimal, value),
.. self
}
}
#[inline]
pub fn chars_hexadecimal(self, value: bool) -> Self {
InputText {
flags: self.flags.with(ImGuiInputTextFlags_CharsHexadecimal, value),
.. self
}
}
#[inline]
pub fn chars_uppercase(self, value: bool) -> Self {
InputText {
flags: self.flags.with(ImGuiInputTextFlags_CharsUppercase, value),
.. self
}
}
#[inline]
pub fn chars_noblank(self, value: bool) -> Self {
InputText {
flags: self.flags.with(ImGuiInputTextFlags_CharsNoBlank, value),
.. self
}
}
#[inline]
pub fn auto_select_all(self, value: bool) -> Self {
InputText {
flags: self.flags.with(ImGuiInputTextFlags_AutoSelectAll, value),
.. self
}
}
#[inline]
pub fn enter_returns_true(self, value: bool) -> Self {
InputText {
flags: self.flags.with(ImGuiInputTextFlags_EnterReturnsTrue, value),
.. self
}
}
#[inline]
pub fn callback_completion(self, value: bool) -> Self {
InputText {
flags: self.flags.with(ImGuiInputTextFlags_CallbackCompletion, value),
.. self
}
}
#[inline]
pub fn callback_history(self, value: bool) -> Self {
InputText {
flags: self.flags.with(ImGuiInputTextFlags_CallbackHistory, value),
.. self
}
}
#[inline]
pub fn callback_always(self, value: bool) -> Self {
InputText {
flags: self.flags.with(ImGuiInputTextFlags_CallbackAlways, value),
.. self
}
}
#[inline]
pub fn callback_char_filter(self, value: bool) -> Self {
InputText {
flags: self.flags.with(ImGuiInputTextFlags_CallbackCharFilter, value),
.. self
}
}
#[inline]
pub fn allow_tab_input(self, value: bool) -> Self {
InputText {
flags: self.flags.with(ImGuiInputTextFlags_AllowTabInput, value),
.. self
}
}
#[inline]
pub fn no_horizontal_scroll(self, value: bool) -> Self {
InputText {
flags: self.flags.with(ImGuiInputTextFlags_NoHorizontalScroll, value),
.. self
}
}
#[inline]
pub fn always_insert_mode(self, value: bool) -> Self {
InputText {
flags: self.flags.with(ImGuiInputTextFlags_AlwaysInsertMode, value),
.. self
}
}
impl_text_flags!(InputText);
// TODO: boxed closure...?
// pub fn callback(self) -> Self { }
@ -161,3 +200,214 @@ impl<'ui, 'p> InputText<'ui, 'p> {
}
}
}
#[must_use]
pub struct InputInt<'ui, 'p> {
label: ImStr<'p>,
value: &'p mut i32,
step: i32,
step_fast: i32,
flags: ImGuiInputTextFlags,
_phantom: PhantomData<&'ui Ui<'ui>>
}
impl<'ui, 'p> InputInt<'ui, 'p> {
pub fn new(label: ImStr<'p>, value: &'p mut i32) -> Self {
InputInt {
label: label,
value: value,
step: 1,
step_fast: 100,
flags: ImGuiInputTextFlags::empty(),
_phantom: PhantomData
}
}
pub fn build(self) -> bool {
unsafe {
imgui_sys::igInputInt(
self.label.as_ptr(),
self.value as *mut i32,
self.step,
self.step_fast,
self.flags)
}
}
impl_step_params!(InputInt, i32);
impl_text_flags!(InputInt);
}
#[must_use]
pub struct InputFloat<'ui, 'p> {
label: ImStr<'p>,
value: &'p mut f32,
step: f32,
step_fast: f32,
decimal_precision: i32,
flags: ImGuiInputTextFlags,
_phantom: PhantomData<&'ui Ui<'ui>>
}
impl<'ui, 'p> InputFloat<'ui, 'p> {
pub fn new(label: ImStr<'p>, value: &'p mut f32) -> Self {
InputFloat {
label: label,
value: value,
step: 0.0,
step_fast: 0.0,
decimal_precision: -1,
flags: ImGuiInputTextFlags::empty(),
_phantom: PhantomData
}
}
pub fn build(self) -> bool {
unsafe {
imgui_sys::igInputFloat(
self.label.as_ptr(),
self.value as *mut f32,
self.step,
self.step_fast,
self.decimal_precision,
self.flags)
}
}
impl_step_params!(InputFloat, f32);
impl_precision_params!(InputFloat);
impl_text_flags!(InputFloat);
}
macro_rules! impl_input_floatn {
($InputFloatN:ident, $N:expr, $igInputFloatN:ident) => {
#[must_use]
pub struct $InputFloatN<'ui, 'p> {
label: ImStr<'p>,
value: &'p mut [f32;$N],
decimal_precision: i32,
flags: ImGuiInputTextFlags,
_phantom: PhantomData<&'ui Ui<'ui>>
}
impl<'ui, 'p> $InputFloatN<'ui, 'p> {
pub fn new(label: ImStr<'p>, value: &'p mut [f32;$N]) -> Self {
$InputFloatN {
label: label,
value: value,
decimal_precision: -1,
flags: ImGuiInputTextFlags::empty(),
_phantom: PhantomData
}
}
pub fn build(self) -> bool {
unsafe {
imgui_sys::$igInputFloatN(
self.label.as_ptr(),
self.value.as_mut_ptr(),
self.decimal_precision,
self.flags)
}
}
impl_precision_params!($InputFloatN);
impl_text_flags!($InputFloatN);
}
}
}
impl_input_floatn!(InputFloat2, 2, igInputFloat2);
impl_input_floatn!(InputFloat3, 3, igInputFloat3);
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: ImStr<'p>,
value: &'p mut [i32;$N],
flags: ImGuiInputTextFlags,
_phantom: PhantomData<&'ui Ui<'ui>>
}
impl<'ui, 'p> $InputIntN<'ui, 'p> {
pub fn new(label: ImStr<'p>, value: &'p mut [i32;$N]) -> Self {
$InputIntN {
label: label,
value: value,
flags: ImGuiInputTextFlags::empty(),
_phantom: PhantomData
}
}
pub fn build(self) -> bool {
unsafe {
imgui_sys::$igInputIntN(
self.label.as_ptr(),
self.value.as_mut_ptr(),
self.flags)
}
}
impl_text_flags!($InputIntN);
}
}
}
impl_input_intn!(InputInt2, 2, igInputInt2);
impl_input_intn!(InputInt3, 3, igInputInt3);
impl_input_intn!(InputInt4, 4, igInputInt4);
#[must_use]
pub struct ColorEdit3<'ui, 'p> {
label: ImStr<'p>,
value: &'p mut [f32;3],
_phantom: PhantomData<&'ui Ui<'ui>>
}
impl<'ui, 'p> ColorEdit3<'ui, 'p> {
pub fn new(label: ImStr<'p>, value: &'p mut [f32;3]) -> Self {
ColorEdit3 {
label: label,
value: value,
_phantom: PhantomData
}
}
pub fn build(self) -> bool {
unsafe {
imgui_sys::igColorEdit3(
self.label.as_ptr(),
self.value.as_mut_ptr())
}
}
}
#[must_use]
pub struct ColorEdit4<'ui, 'p> {
label: ImStr<'p>,
value: &'p mut [f32;4],
show_alpha: bool,
_phantom: PhantomData<&'ui Ui<'ui>>
}
impl<'ui, 'p> ColorEdit4<'ui, 'p> {
pub fn new(label: ImStr<'p>, value: &'p mut [f32;4]) -> Self {
ColorEdit4 {
label: label,
value: value,
show_alpha: true,
_phantom: PhantomData
}
}
pub fn build(self) -> bool {
unsafe {
imgui_sys::igColorEdit4(
self.label.as_ptr(),
self.value.as_mut_ptr(),
self.show_alpha)
}
}
}

View File

@ -26,6 +26,8 @@ pub use imgui_sys::{
ImGuiInputTextFlags_NoHorizontalScroll, ImGuiInputTextFlags_AlwaysInsertMode,
ImGuiInputTextFlags_ReadOnly,
ImGuiInputTextFlags_Password,
ImGuiSelectableFlags,
ImGuiSelectableFlags_DontClosePopups, ImGuiSelectableFlags_SpanAllColumns,
ImGuiSetCond,
ImGuiSetCond_Always, ImGuiSetCond_Once,
ImGuiSetCond_FirstUseEver, ImGuiSetCond_Appearing,
@ -40,7 +42,12 @@ pub use imgui_sys::{
ImVec2, ImVec4,
ImGuiKey
};
pub use input::{InputText};
pub use input::{
ColorEdit3, ColorEdit4,
InputFloat, InputFloat2, InputFloat3, InputFloat4,
InputInt, InputInt2, InputInt3, InputInt4,
InputText
};
pub use menus::{Menu, MenuItem};
pub use sliders::{SliderFloat, SliderInt};
pub use trees::{TreeNode};
@ -485,18 +492,48 @@ impl<'ui> Ui<'ui> {
// Widgets: Input
impl<'ui> Ui<'ui> {
pub fn color_edit3<'p>(&self, label: ImStr<'p>, value: &'p mut [f32;3]) -> ColorEdit3<'ui, 'p> {
ColorEdit3::new(label, value)
}
pub fn color_edit4<'p>(&self, label: ImStr<'p>, value: &'p mut [f32;4]) -> ColorEdit4<'ui, 'p> {
ColorEdit4::new(label, value)
}
pub fn input_text<'p>(&self, label: ImStr<'p>, buf: &'p mut str) -> InputText<'ui, 'p> {
InputText::new(label, buf)
}
pub fn input_float<'p>(&self, label: ImStr<'p>, value: &'p mut f32) -> InputFloat<'ui, 'p> {
InputFloat::new(label, value)
}
pub fn input_float2<'p>(&self, label: ImStr<'p>, value: &'p mut [f32;2]) -> InputFloat2<'ui, 'p> {
InputFloat2::new(label, value)
}
pub fn input_float3<'p>(&self, label: ImStr<'p>, value: &'p mut [f32;3]) -> InputFloat3<'ui, 'p> {
InputFloat3::new(label, value)
}
pub fn input_float4<'p>(&self, label: ImStr<'p>, value: &'p mut [f32;4]) -> InputFloat4<'ui, 'p> {
InputFloat4::new(label, value)
}
pub fn input_int<'p>(&self, label: ImStr<'p>, value: &'p mut i32) -> InputInt<'ui, 'p> {
InputInt::new(label, value)
}
pub fn input_int2<'p>(&self, label: ImStr<'p>, value: &'p mut [i32;2]) -> InputInt2<'ui, 'p> {
InputInt2::new(label, value)
}
pub fn input_int3<'p>(&self, label: ImStr<'p>, value: &'p mut [i32;3]) -> InputInt3<'ui, 'p> {
InputInt3::new(label, value)
}
pub fn input_int4<'p>(&self, label: ImStr<'p>, value: &'p mut [i32;4]) -> InputInt4<'ui, 'p> {
InputInt4::new(label, value)
}
}
// Widgets: Sliders
impl<'ui> Ui<'ui> {
pub fn slider_f32<'p>(&self, label: ImStr<'p>,
pub fn slider_float<'p>(&self, label: ImStr<'p>,
value: &'p mut f32, min: f32, max: f32) -> SliderFloat<'ui, 'p> {
SliderFloat::new(label, value, min, max)
}
pub fn slider_i32<'p>(&self, label: ImStr<'p>,
pub fn slider_int<'p>(&self, label: ImStr<'p>,
value: &'p mut i32, min: i32, max: i32) -> SliderInt<'ui, 'p> {
SliderInt::new(label, value, min, max)
}
@ -509,6 +546,14 @@ impl<'ui> Ui<'ui> {
}
}
// Widgets: Selectable / Lists
impl<'ui> Ui<'ui> {
pub fn selectable<'p>(&self, label: ImStr<'p>, selected: bool, flags: ImGuiSelectableFlags,
size: ImVec2) -> bool {
unsafe { imgui_sys::igSelectable(label.as_ptr(), selected, flags, size) }
}
}
// Widgets: Menus
impl<'ui> Ui<'ui> {
pub fn main_menu_bar<F>(&self, f: F) where F: FnOnce() {
@ -529,6 +574,20 @@ impl<'ui> Ui<'ui> {
pub fn menu_item<'p>(&self, label: ImStr<'p>) -> MenuItem<'ui, 'p> { MenuItem::new(label) }
}
// Widgets: Popups
impl<'ui> Ui<'ui> {
pub fn open_popup<'p>(&self, str_id: ImStr<'p>) {
unsafe { imgui_sys::igOpenPopup(str_id.as_ptr()) };
}
pub fn popup<'p, F>(&self, str_id: ImStr<'p>, f: F) where F: FnOnce() {
let render = unsafe { imgui_sys::igBeginPopup(str_id.as_ptr()) };
if render {
f();
unsafe { imgui_sys::igEndPopup() };
}
}
}
//Widgets: Combos
impl<'ui> Ui<'ui> {
pub fn combo<'p>(&self,