tons of updates, added examples

This commit is contained in:
Jack Spira 2021-09-08 11:50:14 -07:00
parent 805f5e93e7
commit a0d3cbb7e4
3 changed files with 175 additions and 16 deletions

View File

@ -11,8 +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("with some buffer");
text_buffer.reserve(100);
let mut text_buffer = ImString::new("");
system.main_loop(move |_, ui| {
Window::new(im_str!("Means of accessing key state"))

View File

@ -0,0 +1,151 @@
use imgui::*;
mod support;
fn main() {
let system = support::init(file!());
let mut buffers = vec![
ImString::default(),
ImString::default(),
ImString::default(),
];
system.main_loop(move |_, ui| {
Window::new(im_str!("Input text callbacks"))
.size([500.0, 300.0], Condition::FirstUseEver)
.build(ui, || {
ui.text("You can make a variety of buffer callbacks on an Input Text");
ui.text(
"or on an InputTextMultiline. In this example, we'll use \
InputText primarily.",
);
ui.text(
"The only difference is that InputTextMultiline doesn't get \
the `History` callback,",
);
ui.text("since, of course, you need the up/down keys to navigate.");
ui.separator();
ui.text("No callbacks:");
ui.input_text(im_str!("buf0"), &mut buffers[0]).build();
ui.input_text(im_str!("buf0"), &mut buffers[1]).build();
ui.input_text(im_str!("buf0"), &mut buffers[2]).build();
ui.separator();
ui.text("Here's a callback which printlns when each is ran.");
struct AllCallback;
impl InputTextCallbackHandler for AllCallback {
fn char_filter(&mut self, c: char) -> Option<char> {
println!("Char filter fired! This means a char was inputted.");
Some(c)
}
fn on_completion(&mut self, _: TextCallbackData<'_>) {
println!("Completion request fired! This means the tab key was hit.");
}
fn on_edit(&mut self, _: TextCallbackData<'_>) {
println!("Edit was fired! Any edit will cause this to fire.")
}
fn on_history(&mut self, dir: HistoryDirection, _: TextCallbackData<'_>) {
println!("History was fired by pressing {:?}", dir);
}
fn on_always(&mut self, _: TextCallbackData<'_>) {
// We don't actually print this out because it will flood your log a lot!
// println!("The always callback fired! It always fires.");
}
}
ui.input_text(
im_str!("All Callbacks logging"),
buffers.get_mut(0).unwrap(),
)
.callback(InputTextCallback::all(), AllCallback)
.build();
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("to duplicate edits to buf0 on buf1");
struct Wrapper<'a>(&'a mut ImString);
impl<'a> InputTextCallbackHandler for Wrapper<'a> {
fn on_always(&mut self, data: TextCallbackData<'_>) {
*self.0 = im_str!("{}", data.str());
}
}
let (buf0, brwchk_dance) = buffers.split_first_mut().unwrap();
let buf1 = Wrapper(&mut brwchk_dance[0]);
ui.input_text(im_str!("Edits copied to buf1"), buf0)
.callback(InputTextCallback::ALWAYS, buf1)
.build();
ui.separator();
ui.text("Finally, we'll do some whacky history to show inserting and removing");
ui.text("characters from the buffer.");
ui.text(
"Here, pressing UP (while editing the below widget) will remove the\n\
first and last character from buf2",
);
ui.text("and pressing DOWN will prepend the first char from buf0 AND");
ui.text("append the last char from buf1");
let (buf0, brwchk_dance) = buffers.split_first_mut().unwrap();
let (buf1, buf2_dance) = brwchk_dance.split_first_mut().unwrap();
let buf2 = &mut buf2_dance[0];
struct Wrapper2<'a>(&'a str, &'a str);
impl<'a> InputTextCallbackHandler for Wrapper2<'a> {
fn on_history(
&mut self,
dir: HistoryDirection,
mut data: TextCallbackData<'_>,
) {
match dir {
HistoryDirection::Up => {
// remove first char...
if !data.str().is_empty() {
data.remove_chars(0, 1);
if let Some((idx, _)) = data.str().char_indices().rev().next() {
data.remove_chars(idx, 1);
}
}
}
HistoryDirection::Down => {
// insert first char...
if let Some(first_char) = self.0.get(0..1) {
data.insert_chars(0, first_char);
}
// insert last char
if let Some((idx, _)) = self.1.char_indices().rev().next() {
data.push_str(&self.1[idx..]);
}
}
}
}
}
ui.input_text(im_str!("Wild buf2 editor"), buf2)
.callback(
InputTextCallback::HISTORY,
Wrapper2(buf0.to_str(), buf1.to_str()),
)
.build();
ui.text(
"For more examples on how to use callbacks non-chaotically, check the demo",
);
});
});
}

View File

@ -183,7 +183,7 @@ impl<'ui, 'p> InputText<'ui, 'p, PassthroughCallback> {
}
}
impl<'ui, 'p, T: TextCallbackHandler> InputText<'ui, 'p, T> {
impl<'ui, 'p, T: InputTextCallbackHandler> InputText<'ui, 'p, T> {
/// Sets the hint displayed in the input text background.
#[inline]
pub fn hint(mut self, hint: &'p ImStr) -> Self {
@ -194,7 +194,7 @@ impl<'ui, 'p, T: TextCallbackHandler> InputText<'ui, 'p, T> {
impl_text_flags!(InputText);
/// By default (as of 0.8.0), imgui-rs will automatically handle string resizes
/// for `InputText` and `InputTextMultiline`.
/// for [InputText] and [InputTextMultiline].
///
/// If, for some reason, you don't want this, you can run this function to prevent this.
/// In that case, edits which would cause a resize will not occur.
@ -205,7 +205,11 @@ impl<'ui, 'p, T: TextCallbackHandler> InputText<'ui, 'p, T> {
}
#[inline]
pub fn callback(mut self, callbacks: InputTextCallback, callback: T) -> InputText<'ui, 'p, T> {
pub fn callback<T2: InputTextCallbackHandler>(
mut self,
callbacks: InputTextCallback,
callback: T2,
) -> InputText<'ui, 'p, T2> {
if callbacks.contains(InputTextCallback::COMPLETION) {
self.flags.insert(InputTextFlags::CALLBACK_COMPLETION);
}
@ -221,8 +225,14 @@ impl<'ui, 'p, T: TextCallbackHandler> InputText<'ui, 'p, T> {
if callbacks.contains(InputTextCallback::EDIT) {
self.flags.insert(InputTextFlags::CALLBACK_EDIT);
}
self.callback_handler = callback;
self
InputText {
callback_handler: callback,
label: self.label,
hint: self.hint,
buf: self.buf,
flags: self.flags,
_phantom: self._phantom,
}
}
pub fn build(self) -> bool {
@ -285,11 +295,11 @@ impl<'ui, 'p> InputTextMultiline<'ui, 'p, PassthroughCallback> {
}
}
impl<'ui, 'p, T: TextCallbackHandler> InputTextMultiline<'ui, 'p, T> {
impl<'ui, 'p, T: InputTextCallbackHandler> InputTextMultiline<'ui, 'p, T> {
impl_text_flags!(InputText);
/// By default (as of 0.8.0), imgui-rs will automatically handle string resizes
/// for `InputText` and `InputTextMultiline`.
/// for [InputText] and [InputTextMultiline].
///
/// If, for some reason, you don't want this, you can run this function to prevent this.
/// In that case, edits which would cause a resize will not occur.
@ -544,7 +554,7 @@ bitflags!(
///
/// Each method here lists the flag required to call it, and this module begins
/// with an example of callbacks being used.
pub trait TextCallbackHandler {
pub trait InputTextCallbackHandler {
/// Filters a char -- returning a `None` means that the char is removed,
/// and returning another char substitutes it out.
///
@ -743,15 +753,14 @@ impl<'a> TextCallbackData<'a> {
/// at some byte pos.
///
/// ## Panics
/// Panics if the `pos` is not a char boundary or if
/// there are not enough chars remaining.
/// Panics if the `pos` is not a char boundary.
pub fn remove_chars(&mut self, pos: usize, char_count: usize) {
let inner = &self.str()[pos..];
let byte_count = inner
.char_indices()
.nth(char_count)
.expect("not enough characters in string")
.0;
.map(|v| v.0)
.unwrap_or(inner.len());
unsafe {
self.remove_chars_unchecked(pos, byte_count);
@ -798,7 +807,7 @@ struct UserData<'a, T> {
}
/// This is our default callback.
extern "C" fn callback<T: TextCallbackHandler>(
extern "C" fn callback<T: InputTextCallbackHandler>(
data: *mut sys::ImGuiInputTextCallbackData,
) -> c_int {
struct CallbackData<'a, T> {
@ -885,4 +894,4 @@ extern "C" fn callback<T: TextCallbackHandler>(
/// If you do not set a callback handler, this will be used (but will never
/// actually run, since you will not have pass imgui any flags).
pub struct PassthroughCallback;
impl TextCallbackHandler for PassthroughCallback {}
impl InputTextCallbackHandler for PassthroughCallback {}