mirror of
https://github.com/eliasstepanik/imgui-rs.git
synced 2026-01-11 13:38:35 +00:00
tons of updates, added examples
This commit is contained in:
parent
805f5e93e7
commit
a0d3cbb7e4
@ -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"))
|
||||
|
||||
151
imgui-examples/examples/text_callbacks.rs
Normal file
151
imgui-examples/examples/text_callbacks.rs
Normal 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",
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -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 {}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user