1use super::buffers::{finish_string_input_buffer, make_string_input_buffer};
2use super::callback_bridge::{
3 StringCallbackState, im_string_resize_callback, string_callback_router,
4};
5use super::callbacks::{InputTextCallback, InputTextCallbackHandler, PassthroughCallback};
6use super::validation::validate_input_text_flags;
7use crate::InputTextFlags;
8use crate::string::ImString;
9use crate::sys;
10use crate::ui::Ui;
11use std::borrow::Cow;
12use std::ffi::c_void;
13use std::marker::PhantomData;
14
15#[must_use]
17pub struct InputText<'ui, 'p, L = Cow<'ui, str>, H = Cow<'ui, str>, T = PassthroughCallback> {
18 ui: &'ui Ui,
19 label: L,
20 buf: &'p mut String,
21 flags: InputTextFlags,
22 capacity_hint: Option<usize>,
23 hint: Option<H>,
24 callback_handler: T,
25 _phantom: PhantomData<&'ui ()>,
26}
27
28#[must_use]
30pub struct InputTextImStr<'ui, 'p, L = Cow<'ui, str>, H = Cow<'ui, str>, T = PassthroughCallback> {
31 ui: &'ui Ui,
32 label: L,
33 buf: &'p mut ImString,
34 flags: InputTextFlags,
35 hint: Option<H>,
36 callback_handler: T,
37 _phantom: PhantomData<&'ui ()>,
38}
39
40impl<'ui, 'p> InputTextImStr<'ui, 'p, Cow<'ui, str>, Cow<'ui, str>, PassthroughCallback> {
41 pub fn new(ui: &'ui Ui, label: impl Into<Cow<'ui, str>>, buf: &'p mut ImString) -> Self {
42 Self {
43 ui,
44 label: label.into(),
45 buf,
46 flags: InputTextFlags::empty(),
47 hint: None,
48 callback_handler: PassthroughCallback,
49 _phantom: PhantomData,
50 }
51 }
52}
53
54impl<'ui, 'p, L: AsRef<str>, H: AsRef<str>, T> InputTextImStr<'ui, 'p, L, H, T> {
55 pub fn flags(mut self, flags: InputTextFlags) -> Self {
56 self.flags = flags;
57 self
58 }
59 pub fn hint<H2: AsRef<str>>(self, hint: H2) -> InputTextImStr<'ui, 'p, L, H2, T> {
60 InputTextImStr {
61 ui: self.ui,
62 label: self.label,
63 buf: self.buf,
64 flags: self.flags,
65 hint: Some(hint),
66 callback_handler: self.callback_handler,
67 _phantom: PhantomData,
68 }
69 }
70 pub fn read_only(mut self, ro: bool) -> Self {
71 self.flags.set(InputTextFlags::READ_ONLY, ro);
72 self
73 }
74 pub fn password(mut self, pw: bool) -> Self {
75 self.flags.set(InputTextFlags::PASSWORD, pw);
76 self
77 }
78 pub fn auto_select_all(mut self, v: bool) -> Self {
79 self.flags.set(InputTextFlags::AUTO_SELECT_ALL, v);
80 self
81 }
82 pub fn enter_returns_true(mut self, v: bool) -> Self {
83 self.flags.set(InputTextFlags::ENTER_RETURNS_TRUE, v);
84 self
85 }
86
87 pub fn build(self) -> bool {
88 let (label_ptr, hint_ptr) = self.ui.scratch_txt_with_opt(
89 self.label.as_ref(),
90 self.hint.as_ref().map(|hint| hint.as_ref()),
91 );
92 let buf_size = self.buf.capacity_with_nul().max(1);
93 self.buf.ensure_buf_size(buf_size);
94 let buf_ptr = self.buf.as_mut_ptr();
95 let user_ptr = self.buf as *mut ImString as *mut c_void;
96
97 validate_input_text_flags("InputTextImStr::build()", self.flags);
98 let flags = self.flags.raw() | sys::ImGuiInputTextFlags_CallbackResize as i32;
99 let result = self.ui.run_with_bound_context(|| unsafe {
100 if hint_ptr.is_null() {
101 sys::igInputText(
102 label_ptr,
103 buf_ptr,
104 buf_size,
105 flags,
106 Some(im_string_resize_callback),
107 user_ptr,
108 )
109 } else {
110 sys::igInputTextWithHint(
111 label_ptr,
112 hint_ptr,
113 buf_ptr,
114 buf_size,
115 flags,
116 Some(im_string_resize_callback),
117 user_ptr,
118 )
119 }
120 });
121 unsafe { self.buf.refresh_len() };
123 result
124 }
125}
126impl<'ui, 'p> InputText<'ui, 'p, Cow<'ui, str>, Cow<'ui, str>, PassthroughCallback> {
127 pub fn new(ui: &'ui Ui, label: impl Into<Cow<'ui, str>>, buf: &'p mut String) -> Self {
129 Self {
130 ui,
131 label: label.into(),
132 buf,
133 flags: InputTextFlags::NONE,
134 capacity_hint: None,
135 hint: None,
136 callback_handler: PassthroughCallback,
137 _phantom: PhantomData,
138 }
139 }
140}
141
142impl<'ui, 'p, L, H, T> InputText<'ui, 'p, L, H, T> {
143 pub fn flags(mut self, flags: InputTextFlags) -> Self {
145 self.flags = flags;
146 self
147 }
148
149 pub fn capacity_hint(mut self, cap: usize) -> Self {
151 self.capacity_hint = Some(cap);
152 self
153 }
154
155 pub fn hint(self, hint: impl Into<Cow<'ui, str>>) -> InputText<'ui, 'p, L, Cow<'ui, str>, T> {
157 InputText {
158 ui: self.ui,
159 label: self.label,
160 buf: self.buf,
161 flags: self.flags,
162 capacity_hint: self.capacity_hint,
163 hint: Some(hint.into()),
164 callback_handler: self.callback_handler,
165 _phantom: PhantomData,
166 }
167 }
168
169 pub fn callback<T2: InputTextCallbackHandler>(
171 self,
172 callback_handler: T2,
173 ) -> InputText<'ui, 'p, L, H, T2> {
174 InputText {
175 ui: self.ui,
176 label: self.label,
177 buf: self.buf,
178 flags: self.flags,
179 capacity_hint: self.capacity_hint,
180 hint: self.hint,
181 callback_handler,
182 _phantom: PhantomData,
183 }
184 }
185
186 pub fn callback_flags(mut self, callback_flags: InputTextCallback) -> Self {
188 self.flags |= InputTextFlags::from_bits_retain(callback_flags.bits() as i32);
189 self
190 }
191
192 pub fn read_only(mut self, read_only: bool) -> Self {
194 self.flags.set(InputTextFlags::READ_ONLY, read_only);
195 self
196 }
197
198 pub fn password(mut self, password: bool) -> Self {
200 self.flags.set(InputTextFlags::PASSWORD, password);
201 self
202 }
203
204 pub fn auto_select_all(mut self, auto_select: bool) -> Self {
206 self.flags.set(InputTextFlags::AUTO_SELECT_ALL, auto_select);
207 self
208 }
209
210 pub fn enter_returns_true(mut self, enter_returns: bool) -> Self {
212 self.flags
213 .set(InputTextFlags::ENTER_RETURNS_TRUE, enter_returns);
214 self
215 }
216
217 pub fn chars_decimal(mut self, decimal: bool) -> Self {
219 self.flags.set(InputTextFlags::CHARS_DECIMAL, decimal);
220 self
221 }
222
223 pub fn chars_hexadecimal(mut self, hex: bool) -> Self {
225 self.flags.set(InputTextFlags::CHARS_HEXADECIMAL, hex);
226 self
227 }
228
229 pub fn chars_uppercase(mut self, uppercase: bool) -> Self {
231 self.flags.set(InputTextFlags::CHARS_UPPERCASE, uppercase);
232 self
233 }
234
235 pub fn chars_no_blank(mut self, no_blank: bool) -> Self {
237 self.flags.set(InputTextFlags::CHARS_NO_BLANK, no_blank);
238 self
239 }
240}
241
242impl<'ui, 'p, L, H, T> InputText<'ui, 'p, L, H, T>
244where
245 L: AsRef<str>,
246 H: AsRef<str>,
247 T: InputTextCallbackHandler,
248{
249 pub fn build(self) -> bool {
251 let (label_ptr, hint_ptr) = self.ui.scratch_txt_with_opt(
252 self.label.as_ref(),
253 self.hint.as_ref().map(|hint| hint.as_ref()),
254 );
255
256 let mut input_buffer = make_string_input_buffer(self.buf, self.capacity_hint);
257 let capacity = input_buffer.len();
258 let buf_ptr = input_buffer.as_mut_ptr() as *mut std::os::raw::c_char;
259
260 let mut callback_state = StringCallbackState::new(&mut input_buffer, self.callback_handler);
261 let user_ptr = callback_state.user_ptr();
262
263 validate_input_text_flags("InputText::build()", self.flags);
264 let flags = self.flags.raw() | sys::ImGuiInputTextFlags_CallbackResize as i32;
265 let result = self.ui.run_with_bound_context(|| unsafe {
266 if hint_ptr.is_null() {
267 sys::igInputText(
268 label_ptr,
269 buf_ptr,
270 capacity,
271 flags,
272 Some(string_callback_router::<T>),
273 user_ptr,
274 )
275 } else {
276 sys::igInputTextWithHint(
277 label_ptr,
278 hint_ptr,
279 buf_ptr,
280 capacity,
281 flags,
282 Some(string_callback_router::<T>),
283 user_ptr,
284 )
285 }
286 });
287
288 finish_string_input_buffer(self.buf, input_buffer);
289 result
290 }
291}