1mod layout;
2mod node;
3mod reconcile;
4
5use std::sync::Arc;
6
7pub(crate) use layout::measure_input;
8pub use node::InputNode;
9pub(crate) use reconcile::reconcile_input;
10
11use crate::callback::{Callback, KeyHandler};
12use crate::core::element::{Element, ElementKind};
13use crate::core::event::MouseEvent;
14use crate::style::{
15 BorderStyle, CaretShape, Color, LayoutConstraints, Length, Padding, Style, StyleSlot,
16};
17use crate::text::edit::TextEditEvent;
18use crate::text::input::TextInput;
19
20#[derive(Clone)]
27pub struct Input {
28 pub(crate) value: Arc<str>,
29 pub(crate) cursor: usize,
30 pub(crate) anchor: Option<usize>,
31 pub(crate) placeholder: Option<Arc<str>>,
32 pub(crate) prefix: Option<Arc<str>>,
33 pub(crate) suffix: Option<Arc<str>>,
34 pub(crate) truncate_head: bool,
35 pub(crate) style: Style,
36 pub(crate) hover_style: StyleSlot,
37 pub(crate) focus_style: StyleSlot,
38 pub(crate) focus_content_style: Style,
39 pub(crate) hover_border_style: Option<BorderStyle>,
40 pub(crate) placeholder_style: Style,
41 pub(crate) focus_placeholder_style: Style,
42 pub(crate) prefix_style: Style,
43 pub(crate) focus_prefix_style: Style,
44 pub(crate) suffix_style: Style,
45 pub(crate) focus_suffix_style: Style,
46 pub(crate) caret_shape: Option<CaretShape>,
47 pub(crate) caret_color: Option<Color>,
48 pub(crate) selection_style: StyleSlot,
49 pub(crate) border: bool,
50 pub(crate) border_style: BorderStyle,
53 pub(crate) padding: Padding,
56 pub(crate) mask: Option<char>,
57 pub(crate) disabled: bool,
58 pub(crate) disabled_style: Style,
59 pub(crate) read_only: bool,
60 pub(crate) error: Option<Arc<str>>,
61 pub(crate) error_style: Style,
62 pub(crate) reserve_error_row: bool,
63 pub(crate) width: Length,
66 pub(crate) height: Length,
69 pub(crate) on_change: Option<Callback<InputEvent>>,
70 pub(crate) on_edit: Option<Callback<TextEditEvent>>,
71 pub(crate) on_click: Option<Callback<MouseEvent>>,
72 pub(crate) on_key: Option<KeyHandler>,
73 pub(crate) key_interceptor: Option<KeyHandler>,
74 pub(crate) focusable: bool,
75 pub(crate) tab_stop: bool,
76 pub(crate) on_focus: Option<Callback<()>>,
77 pub(crate) on_blur: Option<Callback<()>>,
78}
79
80impl Input {
81 pub fn new(value: impl Into<Arc<str>>) -> Self {
83 let value = value.into();
84 let cursor = value.len();
85 Self {
86 value,
87 cursor,
88 anchor: None,
89 placeholder: None,
90 prefix: None,
91 suffix: None,
92 truncate_head: false,
93 style: Style::default(),
94 hover_style: StyleSlot::Inherit,
95 focus_style: StyleSlot::Inherit,
96 focus_content_style: Style::default(),
97 hover_border_style: None,
98 placeholder_style: Style::default(),
99 focus_placeholder_style: Style::default(),
100 prefix_style: Style::default(),
101 focus_prefix_style: Style::default(),
102 suffix_style: Style::default(),
103 focus_suffix_style: Style::default(),
104 caret_shape: None,
105 caret_color: None,
106 selection_style: StyleSlot::Inherit,
107 border: true,
108 border_style: BorderStyle::Plain,
109 padding: Padding {
110 left: 1,
111 right: 1,
112 top: 0,
113 bottom: 0,
114 },
115 mask: None,
116 disabled: false,
117 disabled_style: Style::default(),
118 read_only: false,
119 error: None,
120 error_style: Style::default(),
121 reserve_error_row: false,
122 width: Length::Flex(1),
123 height: Length::Auto,
124 on_change: None,
125 on_edit: None,
126 on_click: None,
127 on_key: None,
128 key_interceptor: None,
129 focusable: true,
130 tab_stop: true,
131 on_focus: None,
132 on_blur: None,
133 }
134 }
135
136 pub fn bound(state: &TextInput) -> Self {
138 Self::new("").bind(state)
139 }
140
141 pub fn cursor(mut self, cursor: usize) -> Self {
143 self.cursor = cursor;
144 self
145 }
146
147 pub fn anchor(mut self, anchor: Option<usize>) -> Self {
150 self.anchor = anchor;
151 self
152 }
153
154 pub fn bind(mut self, state: &TextInput) -> Self {
156 self.value = state.text().into();
157 self.cursor = state.cursor();
158 self.anchor = state.anchor();
159 self
160 }
161
162 pub fn placeholder(mut self, placeholder: impl Into<Arc<str>>) -> Self {
164 self.placeholder = Some(placeholder.into());
165 self
166 }
167
168 pub fn prefix(mut self, prefix: impl Into<Arc<str>>) -> Self {
170 self.prefix = Some(prefix.into());
171 self
172 }
173
174 pub fn suffix(mut self, suffix: impl Into<Arc<str>>) -> Self {
176 self.suffix = Some(suffix.into());
177 self
178 }
179
180 pub fn truncate_head(mut self, truncate_head: bool) -> Self {
182 self.truncate_head = truncate_head;
183 self
184 }
185
186 pub fn style(mut self, style: Style) -> Self {
188 self.style = style;
189 self
190 }
191
192 pub fn hover_style(mut self, style: Style) -> Self {
194 self.hover_style = StyleSlot::Replace(style);
195 self
196 }
197
198 pub fn extend_hover_style(mut self, style: Style) -> Self {
200 self.hover_style = StyleSlot::Extend(style);
201 self
202 }
203
204 pub fn inherit_hover_style(mut self) -> Self {
206 self.hover_style = StyleSlot::Inherit;
207 self
208 }
209
210 pub fn hover_style_slot(mut self, slot: StyleSlot) -> Self {
212 self.hover_style = slot;
213 self
214 }
215
216 pub fn focus_style(mut self, style: Style) -> Self {
218 self.focus_style = StyleSlot::Replace(style);
219 self
220 }
221
222 pub fn extend_focus_style(mut self, style: Style) -> Self {
224 self.focus_style = StyleSlot::Extend(style);
225 self
226 }
227
228 pub fn inherit_focus_style(mut self) -> Self {
230 self.focus_style = StyleSlot::Inherit;
231 self
232 }
233
234 pub fn focus_style_slot(mut self, slot: StyleSlot) -> Self {
236 self.focus_style = slot;
237 self
238 }
239
240 pub fn focus_content_style(mut self, style: Style) -> Self {
242 self.focus_content_style = style;
243 self
244 }
245
246 pub fn hover_border_style(mut self, border_style: BorderStyle) -> Self {
248 self.hover_border_style = Some(border_style);
249 self
250 }
251
252 pub fn placeholder_style(mut self, style: Style) -> Self {
254 self.placeholder_style = style;
255 self
256 }
257
258 pub fn focus_placeholder_style(mut self, style: Style) -> Self {
260 self.focus_placeholder_style = style;
261 self
262 }
263
264 pub fn prefix_style(mut self, style: Style) -> Self {
266 self.prefix_style = style;
267 self
268 }
269
270 pub fn focus_prefix_style(mut self, style: Style) -> Self {
272 self.focus_prefix_style = style;
273 self
274 }
275
276 pub fn suffix_style(mut self, style: Style) -> Self {
278 self.suffix_style = style;
279 self
280 }
281
282 pub fn focus_suffix_style(mut self, style: Style) -> Self {
284 self.focus_suffix_style = style;
285 self
286 }
287
288 pub fn caret_shape(mut self, shape: CaretShape) -> Self {
290 self.caret_shape = Some(shape);
291 self
292 }
293
294 pub fn caret_color(mut self, color: Color) -> Self {
296 self.caret_color = Some(color);
297 self
298 }
299
300 pub fn selection_style(mut self, style: Style) -> Self {
302 self.selection_style = StyleSlot::Replace(style);
303 self
304 }
305
306 pub fn extend_selection_style(mut self, style: Style) -> Self {
308 self.selection_style = StyleSlot::Extend(style);
309 self
310 }
311
312 pub fn inherit_selection_style(mut self) -> Self {
314 self.selection_style = StyleSlot::Inherit;
315 self
316 }
317
318 pub fn selection_style_slot(mut self, slot: StyleSlot) -> Self {
320 self.selection_style = slot;
321 self
322 }
323
324 pub fn border(mut self, border: bool) -> Self {
326 self.border = border;
327 self
328 }
329
330 pub fn border_style(mut self, border_style: BorderStyle) -> Self {
332 self.border_style = border_style;
333 self
334 }
335
336 pub fn padding(mut self, padding: impl Into<Padding>) -> Self {
338 self.padding = padding.into();
339 self
340 }
341
342 pub fn mask(mut self, mask: Option<char>) -> Self {
344 self.mask = mask;
345 self
346 }
347
348 pub fn width(mut self, width: Length) -> Self {
350 self.width = width;
351 self
352 }
353
354 pub fn height(mut self, height: Length) -> Self {
356 self.height = height;
357 self
358 }
359
360 pub fn on_change(mut self, cb: Callback<InputEvent>) -> Self {
362 self.on_change = Some(cb);
363 self
364 }
365
366 pub fn on_edit(mut self, cb: Callback<TextEditEvent>) -> Self {
368 self.on_edit = Some(cb);
369 self
370 }
371
372 pub fn on_click(mut self, cb: Callback<MouseEvent>) -> Self {
374 self.on_click = Some(cb);
375 self
376 }
377
378 pub fn on_key(mut self, handler: KeyHandler) -> Self {
380 self.on_key = Some(handler);
381 self
382 }
383
384 pub fn key_interceptor(mut self, handler: KeyHandler) -> Self {
391 self.key_interceptor = Some(handler);
392 self
393 }
394
395 pub fn disabled(mut self, disabled: bool) -> Self {
397 self.disabled = disabled;
398 self
399 }
400
401 pub fn disabled_style(mut self, style: Style) -> Self {
403 self.disabled_style = style;
404 self
405 }
406
407 pub fn read_only(mut self, read_only: bool) -> Self {
409 self.read_only = read_only;
410 self
411 }
412
413 pub fn error<S>(mut self, message: Option<S>) -> Self
415 where
416 S: Into<Arc<str>>,
417 {
418 self.error = message.map(Into::into);
419 self
420 }
421
422 pub fn error_style(mut self, style: Style) -> Self {
424 self.error_style = style;
425 self
426 }
427
428 pub fn reserve_error_row(mut self, reserve_error_row: bool) -> Self {
430 self.reserve_error_row = reserve_error_row;
431 self
432 }
433
434 pub fn focusable(mut self, focusable: bool) -> Self {
436 self.focusable = focusable;
437 self
438 }
439
440 pub fn tab_stop(mut self, tab_stop: bool) -> Self {
442 self.tab_stop = tab_stop;
443 self
444 }
445
446 pub fn on_focus(mut self, cb: Callback<()>) -> Self {
448 self.on_focus = Some(cb);
449 self
450 }
451
452 pub fn on_blur(mut self, cb: Callback<()>) -> Self {
454 self.on_blur = Some(cb);
455 self
456 }
457}
458
459impl From<Input> for Element {
460 fn from(value: Input) -> Self {
461 let mut layout = LayoutConstraints::default();
462 if value.focusable {
463 let (min_w, min_h) = measure_input(&value);
464 layout.focus_min_w = min_w;
465 layout.min_h = Length::Px(min_h);
468 } else {
469 let (_, min_h) = measure_input(&value);
470 layout.min_h = Length::Px(min_h);
471 }
472 Element::new(ElementKind::Input(Box::new(value))).with_layout(layout)
473 }
474}
475
476#[derive(Clone, Debug, PartialEq, Eq, Hash)]
478pub struct InputEvent {
479 pub value: Arc<str>,
481 pub cursor: usize,
483 pub anchor: Option<usize>,
485}
486
487impl InputEvent {
488 pub fn apply_to(&self, state: &mut TextInput) {
490 state.core.text = self.value.to_string();
491 state.core.cursor = crate::utils::text::clamp_cursor(&state.core.text, self.cursor);
492 state.core.anchor = self
493 .anchor
494 .map(|anchor| crate::utils::text::clamp_cursor(&state.core.text, anchor));
495 }
496}
497
498impl crate::layout::hash::LayoutHash for Input {
499 fn layout_hash(
500 &self,
501 hasher: &mut impl std::hash::Hasher,
502 _recurse: &dyn Fn(&Element) -> Option<u64>,
503 ) -> Option<()> {
504 use std::hash::Hash;
505 self.width.hash(hasher);
506 self.height.hash(hasher);
507 self.border.hash(hasher);
508 self.padding.hash(hasher);
509 self.focusable.hash(hasher);
510 self.value.hash(hasher);
511 self.placeholder.hash(hasher);
512 self.prefix.hash(hasher);
513 self.suffix.hash(hasher);
514 self.error.hash(hasher);
515 self.reserve_error_row.hash(hasher);
516 Some(())
517 }
518}