makepad_widgets/
text_input.rs

1use {
2    crate::{
3        makepad_derive_widget::*,
4        makepad_draw::{
5            text::{
6                geom::Point,
7                selection::{
8                    Cursor,
9                    CursorPosition,
10                    Selection
11                },
12                layouter::LaidoutText,
13            },
14            *
15        },
16        widget::*,
17    },
18    std::rc::Rc,
19    unicode_segmentation::{GraphemeCursor, UnicodeSegmentation},
20};
21
22
23live_design! {
24    link widgets;
25
26    use link::theme::*;
27    use makepad_draw::shader::std::*;
28
29    pub TextInputBase = {{TextInput}} {}
30    
31    pub TextInput = <TextInputBase> {
32        width: Fill, height: Fit,
33        padding: <THEME_MSPACE_1> { left: (THEME_SPACE_2), right: (THEME_SPACE_2) }
34        margin: <THEME_MSPACE_V_1> {}
35        flow: RightWrap,
36        is_password: false,
37        is_read_only: false,
38        is_numeric_only: false
39        empty_text: "Your text here",
40        
41        draw_bg: {
42            instance hover: 0.0
43            instance focus: 0.0
44            instance down: 0.0
45            instance empty: 0.0
46            instance disabled: 0.0
47
48            uniform border_radius: (THEME_CORNER_RADIUS)
49            uniform border_size: (THEME_BEVELING)
50
51            uniform color_dither: 1.0
52
53            color: (THEME_COLOR_INSET)
54            uniform color_hover: (THEME_COLOR_INSET_HOVER)
55            uniform color_focus: (THEME_COLOR_INSET_FOCUS)
56            uniform color_down: (THEME_COLOR_INSET_DOWN)
57            uniform color_empty: (THEME_COLOR_INSET_EMPTY)
58            uniform color_disabled: (THEME_COLOR_INSET_DISABLED)
59
60            uniform border_color_1: (THEME_COLOR_BEVEL_INSET_2)
61            uniform border_color_1_hover: (THEME_COLOR_BEVEL_INSET_2_HOVER)
62            uniform border_color_1_focus: (THEME_COLOR_BEVEL_INSET_2_FOCUS)
63            uniform border_color_1_down: (THEME_COLOR_BEVEL_INSET_2_DOWN)
64            uniform border_color_1_empty: (THEME_COLOR_BEVEL_INSET_2_EMPTY)
65            uniform border_color_1_disabled: (THEME_COLOR_BEVEL_INSET_2_DISABLED)
66
67            uniform border_color_2: (THEME_COLOR_BEVEL_INSET_1)
68            uniform border_color_2_hover: (THEME_COLOR_BEVEL_INSET_1_HOVER)
69            uniform border_color_2_focus: (THEME_COLOR_BEVEL_INSET_1_FOCUS)
70            uniform border_color_2_down: (THEME_COLOR_BEVEL_INSET_1_DOWN)
71            uniform border_color_2_empty: (THEME_COLOR_BEVEL_INSET_1_EMPTY)
72            uniform border_color_2_disabled: (THEME_COLOR_BEVEL_INSET_1_DISABLED)
73
74            fn pixel(self) -> vec4 {
75                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
76                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
77                
78                let border_sz_uv = vec2(
79                    self.border_size / self.rect_size.x,
80                    self.border_size / self.rect_size.y
81                )
82
83                let scale_factor_border = vec2(
84                    self.rect_size.x / self.rect_size.x,
85                    self.rect_size.y / self.rect_size.y
86                );
87
88                let gradient_border = vec2(
89                    self.pos.x * scale_factor_border.x + dither,
90                    self.pos.y * scale_factor_border.y + dither
91                )
92
93                let sz_inner_px = vec2(
94                    self.rect_size.x - self.border_size * 2.,
95                    self.rect_size.y - self.border_size * 2.
96                );
97
98                let scale_factor_fill = vec2(
99                    self.rect_size.x / sz_inner_px.x,
100                    self.rect_size.y / sz_inner_px.y
101                );
102
103                let gradient_fill = vec2(
104                    self.pos.x * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
105                    self.pos.y * scale_factor_fill.y - border_sz_uv.y * 2. + dither
106                )
107
108                sdf.box(
109                    self.border_size,
110                    self.border_size,
111                    self.rect_size.x - self.border_size * 2.,
112                    self.rect_size.y - self.border_size * 2.,
113                    self.border_radius
114                )
115
116                sdf.fill_keep(
117                    mix(
118                        mix(
119                            mix(
120                                mix(
121                                    self.color,
122                                    self.color_empty,
123                                    self.empty
124                                ),
125                                self.color_focus,
126                                self.focus
127                            ),
128                            mix(
129                                self.color_hover,
130                                self.color_down,
131                                self.down
132                            ),
133                            self.hover
134                        ),
135                        self.color_disabled,
136                        self.disabled
137                    )
138                );
139
140                sdf.stroke(
141                    mix(
142                        mix(
143                            mix(
144                                mix(
145                                    mix(self.border_color_1, self.border_color_2, gradient_border.y),
146                                    mix(self.border_color_1_empty, self.border_color_2_empty, gradient_border.y),
147                                    self.empty
148                                ),
149                                mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
150                                self.focus
151                            ),
152                            mix(
153                                mix(self.border_color_1_hover, self.border_color_2_hover, gradient_border.y),
154                                mix(self.border_color_1_down, self.border_color_2_down, gradient_border.y),
155                                self.down
156                            ),
157                            self.hover
158                        ),
159                        mix(self.border_color_1_disabled, self.border_color_2_disabled, gradient_border.y),
160                        self.disabled
161                    ),
162                    self.border_size
163                );
164
165                
166                return sdf.result;
167            }
168        }
169
170        draw_text: {
171            instance hover: 0.0
172            instance focus: 0.0
173            instance down: 0.0
174            instance empty: 0.0
175            instance disabled: 0.0
176
177            color: (THEME_COLOR_TEXT)
178            uniform color_hover: (THEME_COLOR_TEXT_HOVER)
179            uniform color_focus: (THEME_COLOR_TEXT_FOCUS)
180            uniform color_down: (THEME_COLOR_TEXT_DOWN)
181            uniform color_disabled: (THEME_COLOR_TEXT_DISABLED)
182            uniform color_empty: (THEME_COLOR_TEXT_PLACEHOLDER)
183            uniform color_empty_hover: (THEME_COLOR_TEXT_PLACEHOLDER_HOVER)
184            uniform color_empty_focus: (THEME_COLOR_TEXT_FOCUS)
185
186            text_style: <THEME_FONT_REGULAR> {
187                line_spacing: (THEME_FONT_WDGT_LINE_SPACING),
188                font_size: (THEME_FONT_SIZE_P)
189            }
190
191            fn get_color(self) -> vec4 {
192                return
193                    mix( 
194                        mix(
195                            mix(
196                                mix(
197                                    self.color,
198                                    mix(
199                                        self.color_hover,
200                                        self.color_down,
201                                        self.down
202                                    ),
203                                    self.hover
204                                ),
205                                self.color_empty,
206                                self.empty
207                            ),
208                            self.color_focus,
209                            self.focus
210                        ),
211                        self.color_disabled,
212                        self.disabled
213                    )
214            }
215        }
216
217        draw_selection: {
218            instance hover: 0.0
219            instance focus: 0.0
220            instance down: 0.0
221            instance empty: 0.0
222            instance disabled: 0.0
223
224            uniform border_radius: (THEME_TEXTSELECTION_CORNER_RADIUS)
225
226            uniform color: (THEME_COLOR_SELECTION)
227            uniform color_hover: (THEME_COLOR_SELECTION_HOVER)
228            uniform color_focus: (THEME_COLOR_SELECTION_FOCUS)
229            uniform color_down: (THEME_COLOR_SELECTION_DOWN)
230            uniform color_empty: (THEME_COLOR_SELECTION_EMPTY)
231            uniform color_disabled: (THEME_COLOR_SELECTION_DISABLED)
232
233            fn pixel(self) -> vec4 {
234                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
235                sdf.box(
236                    0.0,
237                    0.0,
238                    self.rect_size.x,
239                    self.rect_size.y,
240                    self.border_radius
241                );
242                sdf.fill(
243                    mix(
244                        mix(
245                            mix(
246                                mix(
247                                    self.color,
248                                    self.color_empty,
249                                    self.empty
250                                ),
251                                self.color_focus,
252                                self.focus
253                            ),
254                            mix(
255                                self.color_hover,
256                                self.color_down,
257                                self.down
258                            ),
259                            self.hover
260                        ),
261                        self.color_disabled,
262                        self.disabled
263                    )
264                );
265                return sdf.result;
266            }
267        }
268
269        draw_cursor: {
270            instance focus: 0.0
271            instance down: 0.0
272            instance empty: 0.0
273            instance disabled: 0.0
274            instance blink: 0.0
275            
276            uniform border_radius: 0.5
277
278            uniform color: (THEME_COLOR_TEXT_CURSOR)
279
280            fn pixel(self) -> vec4 {
281                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
282                sdf.box(
283                    0.0,
284                    0.0,
285                    self.rect_size.x,
286                    self.rect_size.y,
287                    self.border_radius
288                );
289                sdf.fill(
290                    mix(THEME_COLOR_U_HIDDEN, self.color, (1.0-self.blink) * self.focus)
291                );
292                return sdf.result;
293            }
294        }
295
296        animator: {
297            empty = {
298                default: off,
299                off = {
300                    from: {all: Forward {duration: 0.}}
301                    apply: {
302                        draw_bg: {empty: 0.0}
303                        draw_text: {empty: 0.0}
304                        draw_selection: {empty: 0.0}
305                        draw_cursor: {empty: 0.0}
306                    }
307                }
308                on = {
309                    from: {all: Forward {duration: 0.2}}
310                    apply: {
311                        draw_bg: {empty: 1.0}
312                        draw_text: {empty: 1.0}
313                        draw_selection: {empty: 1.0}
314                        draw_cursor: {empty: 1.0}
315                    }
316                }
317            }
318            blink = {
319                default: off
320                off = {
321                    from: {all: Forward {duration:0.05}}
322                    apply: {
323                        draw_cursor: {blink:0.0}
324                    }
325                }
326                on = {
327                    from: {all: Forward {duration: 0.05}}
328                    apply: {
329                        draw_cursor: {blink:1.0}
330                    }
331                }
332            }
333            hover = {
334                default: off,
335                off = {
336                    from: {all: Forward {duration: 0.1}}
337                    apply: {
338                        draw_bg: {down: 0.0, hover: 0.0}
339                        draw_text: {down: 0.0, hover: 0.0}
340                    }
341                }
342                
343                on = {
344                    from: {
345                        all: Forward {duration: 0.1}
346                        down: Forward {duration: 0.01}
347                    }
348                    apply: {
349                        draw_bg: {down: 0.0, hover: [{time: 0.0, value: 1.0}],}
350                        draw_text: {down: 0.0, hover: [{time: 0.0, value: 1.0}],}
351                    }
352                }
353                
354                down = {
355                    from: {all: Forward {duration: 0.2}}
356                    apply: {
357                        draw_bg: {down: [{time: 0.0, value: 1.0}], hover: 1.0,}
358                        draw_text: {down: [{time: 0.0, value: 1.0}], hover: 1.0,}
359                    }
360                }
361            }
362            disabled = {
363                default: off,
364                off = {
365                    from: {all: Forward {duration: 0.}}
366                    apply: {
367                        draw_bg: {disabled: 0.0}
368                        draw_text: {disabled: 0.0}
369                        draw_selection: {disabled: 0.0}
370                        draw_cursor: {disabled: 0.0}
371                    }
372                }
373                on = {
374                    from: {all: Forward {duration: 0.2}}
375                    apply: {
376                        draw_bg: {disabled: 1.0}
377                        draw_text: {disabled: 1.0}
378                        draw_selection: {disabled: 1.0}
379                        draw_cursor: {disabled: 1.0}
380                    }
381                }
382            }
383            hover = {
384                default: off,
385                off = {
386                    from: {all: Forward {duration: 0.1}}
387                    apply: {
388                        draw_bg: {down: 0.0, hover: 0.0}
389                        draw_text: {down: 0.0, hover: 0.0}
390                    }
391                }
392                
393                on = {
394                    from: {
395                        all: Forward {duration: 0.1}
396                        down: Forward {duration: 0.01}
397                    }
398                    apply: {
399                        draw_bg: {down: 0.0, hover: [{time: 0.0, value: 1.0}],}
400                        draw_text: {down: 0.0, hover: [{time: 0.0, value: 1.0}],}
401                    }
402                }
403                
404                down = {
405                    from: {all: Forward {duration: 0.2}}
406                    apply: {
407                        draw_bg: {down: [{time: 0.0, value: 1.0}], hover: 1.0,}
408                        draw_text: {down: [{time: 0.0, value: 1.0}], hover: 1.0,}
409                    }
410                }
411            }
412            focus = {
413                default: off
414                off = {
415                    from: {
416                        all: Forward { duration: 0.25 }
417                    }
418                    apply: {
419                        draw_bg: { focus: 0.0 }
420                        draw_text: { focus: 0.0 },
421                        draw_cursor: { focus: 0.0 },
422                        draw_selection: { focus: 0.0 }
423                    }
424                }
425                on = {
426                    from: { all: Snap }
427                    apply: {
428                        draw_bg: { focus: 1.0 }
429                        draw_text: { focus: 1.0 }
430                        draw_cursor: { focus: 1.0 },
431                        draw_selection: { focus: 1.0 }
432                    }
433                }
434            }
435        }
436    }
437
438    pub TextInputFlat = <TextInput> {
439        draw_bg: {
440            border_color_1: (THEME_COLOR_BEVEL)
441            border_color_1_hover: (THEME_COLOR_BEVEL_HOVER)
442            border_color_1_focus: (THEME_COLOR_BEVEL_FOCUS)
443            border_color_1_down: (THEME_COLOR_BEVEL_DOWN)
444            border_color_1_empty: (THEME_COLOR_BEVEL_EMPTY)
445            border_color_1_disabled: (THEME_COLOR_BEVEL_DISABLED)
446
447            border_color_2: (THEME_COLOR_BEVEL)
448            border_color_2_hover: (THEME_COLOR_BEVEL_HOVER)
449            border_color_2_focus: (THEME_COLOR_BEVEL_FOCUS)
450            border_color_2_down: (THEME_COLOR_BEVEL_DOWN)
451            border_color_2_empty: (THEME_COLOR_BEVEL_EMPTY)
452            border_color_2_disabled: (THEME_COLOR_BEVEL_DISABLED)
453        }
454    }
455
456    pub TextInputFlatter = <TextInputFlat> { draw_bg: { border_size: 0. } }
457
458    pub TextInputGradientX = <TextInput> {
459        draw_bg: {
460            instance hover: 0.0
461            instance focus: 0.0
462            instance down: 0.0
463            instance disabled: 0.0
464            instance empty: 0.0
465
466            uniform border_radius: (THEME_CORNER_RADIUS)
467            uniform border_size: (THEME_BEVELING)
468
469            uniform color_dither: 1.0
470
471            uniform color_1: (THEME_COLOR_INSET_1)
472            uniform color_1_hover: (THEME_COLOR_INSET_1_HOVER)
473            uniform color_1_focus: (THEME_COLOR_INSET_1_FOCUS)
474            uniform color_1_down: (THEME_COLOR_INSET_1_DOWN)
475            uniform color_1_empty: (THEME_COLOR_INSET_1_EMPTY)
476            uniform color_1_disabled: (THEME_COLOR_INSET_1_DISABLED)
477
478            uniform color_2: (THEME_COLOR_INSET_2)
479            uniform color_2_hover: (THEME_COLOR_INSET_2_HOVER)
480            uniform color_2_focus: (THEME_COLOR_INSET_2_FOCUS)
481            uniform color_2_down: (THEME_COLOR_INSET_2_DOWN)
482            uniform color_2_empty: (THEME_COLOR_INSET_2_EMPTY)
483            uniform color_2_disabled: (THEME_COLOR_INSET_2_DISABLED)
484
485            uniform border_color_1: (THEME_COLOR_BEVEL_INSET_2)
486            uniform border_color_1_hover: (THEME_COLOR_BEVEL_INSET_2_HOVER)
487            uniform border_color_1_focus: (THEME_COLOR_BEVEL_INSET_2_FOCUS)
488            uniform border_color_1_down: (THEME_COLOR_BEVEL_INSET_2_DOWN)
489            uniform border_color_1_empty: (THEME_COLOR_BEVEL_INSET_2_EMPTY)
490            uniform border_color_1_disabled: (THEME_COLOR_BEVEL_INSET_2_DISABLED)
491
492            uniform border_color_2: (THEME_COLOR_BEVEL_INSET_1)
493            uniform border_color_2_hover: (THEME_COLOR_BEVEL_INSET_1_HOVER)
494            uniform border_color_2_focus: (THEME_COLOR_BEVEL_INSET_1_FOCUS)
495            uniform border_color_2_down: (THEME_COLOR_BEVEL_INSET_1_DOWN)
496            uniform border_color_2_empty: (THEME_COLOR_BEVEL_INSET_1_EMPTY)
497            uniform border_color_2_disabled: (THEME_COLOR_BEVEL_INSET_1_DISABLED)
498
499            fn pixel(self) -> vec4 {
500                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
501                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
502
503                let border_sz_uv = vec2(
504                    self.border_size / self.rect_size.x,
505                    self.border_size / self.rect_size.y
506                )
507
508                let scale_factor_border = vec2(
509                    self.rect_size.x / self.rect_size.x,
510                    self.rect_size.y / self.rect_size.y
511                );
512
513                let gradient_border = vec2(
514                    self.pos.x * scale_factor_border.x + dither,
515                    self.pos.y * scale_factor_border.y + dither
516                )
517
518                let sz_inner_px = vec2(
519                    self.rect_size.x - self.border_size * 2.,
520                    self.rect_size.y - self.border_size * 2.
521                );
522
523                let scale_factor_fill = vec2(
524                    self.rect_size.x / sz_inner_px.x,
525                    self.rect_size.y / sz_inner_px.y
526                );
527
528                let gradient_fill = vec2(
529                    self.pos.x * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
530                    self.pos.y * scale_factor_fill.y - border_sz_uv.y * 2. + dither
531                )
532                
533                sdf.box(
534                    self.border_size,
535                    self.border_size,
536                    self.rect_size.x - self.border_size * 2.,
537                    self.rect_size.y - self.border_size * 2.,
538                    self.border_radius
539                )
540
541                sdf.fill_keep(
542                    mix(
543                        mix(
544                            mix(
545                                mix(
546                                    mix(self.color_1, self.color_2, gradient_fill.x),
547                                    mix(self.color_1_empty, self.color_2_empty, gradient_fill.x),
548                                    self.empty
549                                ),
550                                mix(self.color_1_focus, self.color_2_focus, gradient_fill.x),
551                                self.focus
552                            ),
553                            mix(
554                                mix(self.color_1_hover, self.color_2_hover, gradient_fill.x),
555                                mix(self.color_1_down, self.color_2_down, gradient_fill.x),
556                                self.down
557                            ),
558                            self.hover
559                        ),
560                        mix(self.color_1_disabled, self.color_2_disabled, gradient_fill.x),
561                        self.disabled
562                    )
563                );
564
565                sdf.stroke(
566                    mix(
567                        mix(
568                            mix(
569                                mix(
570                                    mix(self.border_color_1, self.border_color_2, gradient_border.y),
571                                    mix(self.border_color_1_empty, self.border_color_2_empty, gradient_border.y),
572                                    self.empty
573                                ),
574                                mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
575                                self.focus
576                            ),
577                            mix(
578                                mix(self.border_color_1_hover, self.border_color_2_hover, gradient_border.y),
579                                mix(self.border_color_1_down, self.border_color_2_down, gradient_border.y),
580                                self.down
581                            ),
582                            self.hover
583                        ),
584                        mix(self.border_color_1_disabled, self.border_color_2_disabled, gradient_border.y),
585                        self.disabled
586                    ),
587                    self.border_size
588                );
589                
590                return sdf.result
591            }
592        }
593
594        draw_selection: {
595            instance hover: 0.0
596            instance focus: 0.0
597            instance down: 0.0
598            instance disabled: 0.0
599            instance empty: 0.0
600
601            uniform border_radius: (THEME_TEXTSELECTION_CORNER_RADIUS)
602
603            uniform color_1: (THEME_COLOR_SELECTION)
604            uniform color_1_hover: (THEME_COLOR_SELECTION_HOVER)
605            uniform color_1_focus: (THEME_COLOR_SELECTION_FOCUS)
606            uniform color_1_down: (THEME_COLOR_SELECTION_DOWN)
607            uniform color_1_empty: (THEME_COLOR_SELECTION_EMPTY)
608            uniform color_1_disabled: (THEME_COLOR_SELECTION_DISABLED)
609
610            uniform color_2: (THEME_COLOR_SELECTION)
611            uniform color_2_hover: (THEME_COLOR_SELECTION_HOVER)
612            uniform color_2_focus: (THEME_COLOR_SELECTION_FOCUS)
613            uniform color_2_down: (THEME_COLOR_SELECTION_DOWN)
614            uniform color_2_empty: (THEME_COLOR_SELECTION_EMPTY)
615            uniform color_2_disabled: (THEME_COLOR_SELECTION_DISABLED)
616
617            fn pixel(self) -> vec4 {
618                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
619
620                sdf.box(
621                    0.0,
622                    0.0,
623                    self.rect_size.x,
624                    self.rect_size.y,
625                    self.border_radius
626                )
627
628                sdf.fill(
629                    mix(
630                        mix(
631                            mix(
632                                mix(
633                                    mix(self.color_1, self.color_2, self.pos.x),
634                                    mix(self.color_1_empty, self.color_2_empty, self.pos.x),
635                                    self.empty
636                                ),
637                                mix(self.color_1_focus, self.color_2_focus, self.pos.x),
638                                self.focus
639                            ),
640                            mix(
641                                mix(self.color_1_hover, self.color_2_hover, self.pos.x),
642                                mix(self.color_1_down, self.color_2_down, self.pos.x),
643                                self.down
644                            ),
645                            self.hover
646                        ),
647                        mix(self.color_1_disabled, self.color_2_disabled, self.pos.x),
648                        self.disabled
649                    )
650                );
651
652                return sdf.result
653            }
654        }
655    }
656        
657
658    pub TextInputGradientY = <TextInputGradientX> {
659        draw_bg: {
660            fn pixel(self) -> vec4 {
661                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
662                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
663
664                let border_sz_uv = vec2(
665                    self.border_size / self.rect_size.x,
666                    self.border_size / self.rect_size.y
667                )
668
669                let scale_factor_border = vec2(
670                    self.rect_size.x / self.rect_size.x,
671                    self.rect_size.y / self.rect_size.y
672                );
673
674                let gradient_border = vec2(
675                    self.pos.x * scale_factor_border.x + dither,
676                    self.pos.y * scale_factor_border.y + dither
677                )
678
679                let sz_inner_px = vec2(
680                    self.rect_size.x - self.border_size * 2.,
681                    self.rect_size.y - self.border_size * 2.
682                );
683
684                let scale_factor_fill = vec2(
685                    self.rect_size.x / sz_inner_px.x,
686                    self.rect_size.y / sz_inner_px.y
687                );
688
689                let gradient_fill = vec2(
690                    self.pos.x * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
691                    self.pos.y * scale_factor_fill.y - border_sz_uv.y * 2. + dither
692                )
693                
694                sdf.box(
695                    self.border_size,
696                    self.border_size,
697                    self.rect_size.x - self.border_size * 2.,
698                    self.rect_size.y - self.border_size * 2.,
699                    self.border_radius
700                )
701
702                sdf.fill_keep(
703                    mix(
704                        mix(
705                            mix(
706                                mix(
707                                    mix(self.color_1, self.color_2, gradient_fill.y),
708                                    mix(self.color_1_empty, self.color_2_empty, gradient_fill.y),
709                                    self.empty
710                                ),
711                                mix(self.color_1_focus, self.color_2_focus, gradient_fill.y),
712                                self.focus
713                            ),
714                            mix(
715                                mix(self.color_1_hover, self.color_2_hover, gradient_fill.y),
716                                mix(self.color_1_down, self.color_2_down, gradient_fill.y),
717                                self.down
718                            ),
719                            self.hover
720                        ),
721                        mix(self.color_1_disabled, self.color_2_disabled, gradient_fill.y),
722                        self.disabled
723                    )
724                );
725
726                sdf.stroke(
727                    mix(
728                        mix(
729                            mix(
730                                mix(
731                                    mix(self.border_color_1, self.border_color_2, gradient_border.y),
732                                    mix(self.border_color_1_empty, self.border_color_2_empty, gradient_border.y),
733                                    self.empty
734                                ),
735                                mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
736                                self.focus
737                            ),
738                            mix(
739                                mix(self.border_color_1_hover, self.border_color_2_hover, gradient_border.y),
740                                mix(self.border_color_1_down, self.border_color_2_down, gradient_border.y),
741                                self.down
742                            ),
743                            self.hover
744                        ),
745                        mix(self.border_color_1_disabled, self.border_color_2_disabled, gradient_border.y),
746                        self.disabled
747                    ),
748                    self.border_size
749                );
750                
751                return sdf.result
752            }
753        }
754
755        draw_selection: {
756            fn pixel(self) -> vec4 {
757                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
758
759                sdf.box(
760                    0.0,
761                    0.0,
762                    self.rect_size.x,
763                    self.rect_size.y,
764                    self.border_radius
765                )
766
767                sdf.fill(
768                    mix(
769                        mix(
770                            mix(
771                                mix(
772                                    mix(self.color_1, self.color_2, self.pos.y),
773                                    mix(self.color_1_empty, self.color_2_empty, self.pos.y),
774                                    self.empty
775                                ),
776                                mix(self.color_1_focus, self.color_2_focus, self.pos.y),
777                                self.focus
778                            ),
779                            mix(
780                                mix(self.color_1_hover, self.color_2_hover, self.pos.y),
781                                mix(self.color_1_down, self.color_2_down, self.pos.y),
782                                self.down
783                            ),
784                            self.hover
785                        ),
786                        mix(self.color_1_disabled, self.color_2_disabled, self.pos.y),
787                        self.disabled
788                    )
789                );
790
791                return sdf.result
792            }
793        }
794    }
795}
796
797#[derive(Live, Widget)]
798pub struct TextInput {
799    #[animator] animator: Animator,
800
801    #[redraw] #[live] draw_bg: DrawColor,
802    #[live] draw_text: DrawText,
803    #[live] draw_selection: DrawQuad,
804    #[live] draw_cursor: DrawQuad,
805
806    #[layout] layout: Layout,
807    #[walk] walk: Walk,
808    #[live] label_align: Align,
809
810    #[live] is_password: bool,
811    #[live] is_read_only: bool,
812    #[live] is_numeric_only: bool,
813    #[live] empty_text: String,
814    #[rust] text: String,
815    #[live(0.5)] blink_speed: f64,
816
817    #[rust] password_text: String,
818    #[rust] laidout_text: Option<Rc<LaidoutText>>,
819    #[rust] text_area: Area,
820    #[rust] selection: Selection,
821    #[rust] history: History,
822    #[rust] blink_timer: Timer,
823}
824
825 impl LiveHook for TextInput{
826     fn apply_value_unknown(&mut self, cx: &mut Cx, apply: &mut Apply, index: usize, nodes: &[LiveNode]) -> usize {
827        if nodes[index].id == live_id!(text){
828            if !apply.from.is_update_from_doc(){
829                return self.text.apply(cx, apply, index, nodes)
830            }
831        }
832        else{
833            cx.apply_error_no_matching_field(live_error_origin!(), index, nodes);
834        }
835        nodes.skip_node(index)
836     }
837     fn after_new_from_doc(&mut self, cx:&mut Cx){
838         self.check_text_is_empty(cx);
839     }
840 }
841
842impl TextInput {
843    pub fn is_password(&self) -> bool {
844        self.is_password
845    }
846
847    pub fn set_is_password(&mut self, cx: &mut Cx, is_password: bool) {
848        self.is_password = is_password;
849        self.laidout_text = None;
850        self.draw_bg.redraw(cx);
851    }
852
853    pub fn toggle_is_password(&mut self, cx: &mut Cx) {
854        self.set_is_password(cx, !self.is_password);
855    }
856
857    pub fn is_read_only(&self) -> bool {
858        self.is_read_only
859    }
860
861    pub fn set_is_read_only(&mut self, cx: &mut Cx, is_read_only: bool) {
862        self.is_read_only = is_read_only;
863        self.laidout_text = None;
864        self.draw_bg.redraw(cx);
865    }
866
867    pub fn toggle_is_read_only(&mut self, cx: &mut Cx) {
868        self.set_is_read_only(cx, !self.is_read_only);
869    }
870
871    pub fn is_numeric_only(&self) -> bool {
872        self.is_numeric_only
873    }
874
875    pub fn set_is_numeric_only(&mut self, cx: &mut Cx, is_numeric_only: bool) {
876        self.is_numeric_only = is_numeric_only;
877        self.laidout_text = None;
878        self.draw_bg.redraw(cx);
879    }
880
881    pub fn toggle_is_numeric_only(&mut self, cx: &mut Cx) {
882        self.set_is_numeric_only(cx, !self.is_numeric_only);
883    }
884
885    pub fn empty_text(&self) -> &str {
886        &self.empty_text
887    }
888
889    pub fn set_empty_text(&mut self, cx: &mut Cx, empty_text: String) {
890        self.empty_text = empty_text;
891        if self.text.is_empty() {
892            self.draw_bg.redraw(cx);
893        }
894    }
895
896
897    pub fn selection(&self) -> Selection {
898        self.selection
899    }
900
901    pub fn set_selection(&mut self, cx: &mut Cx, selection: Selection) {
902        self.selection = selection;
903        self.history.force_new_edit_group();
904        self.draw_bg.redraw(cx);
905    }
906
907    pub fn cursor(&self) -> Cursor {
908        self.selection.cursor
909    }
910
911    pub fn set_cursor(&mut self, cx: &mut Cx, cursor: Cursor, keep_selection: bool) {
912        self.set_selection(
913            cx,
914            Selection {
915                anchor: if keep_selection {
916                    self.selection.anchor
917                } else {
918                    cursor
919                },
920                cursor
921            }
922        );
923    }
924    
925    pub fn selected_text(&self) -> &str {
926        &self.text[self.selection.start().index..self.selection.end().index]
927    }
928
929    pub fn reset_blink_timer(&mut self, cx: &mut Cx) {
930        self.animator_cut(cx, id!(blink.off));
931        if !self.is_read_only {
932            cx.stop_timer(self.blink_timer);
933            self.blink_timer = cx.start_timeout(self.blink_speed)
934        }
935    }
936
937    fn cursor_to_position(&self, cursor: Cursor) -> Result<CursorPosition, ()> {
938        let Some(laidout_text) = self.laidout_text.as_ref() else {
939            return Err(());
940        };
941        let position = laidout_text.cursor_to_position(self.cursor_to_password_cursor(cursor));
942        Ok(CursorPosition {
943            row_index: position.row_index,
944            x_in_lpxs: position.x_in_lpxs * self.draw_text.font_scale,
945        })
946    }
947
948    fn point_in_lpxs_to_cursor(&self, point_in_lpxs: Point<f32>) -> Result<Cursor, ()> {
949        let Some(laidout_text) = self.laidout_text.as_ref() else {
950            return Err(());
951        };
952        let cursor = laidout_text.point_in_lpxs_to_cursor(point_in_lpxs / self.draw_text.font_scale);
953        Ok(self.password_cursor_to_cursor(cursor))
954    }
955
956    fn position_to_cursor(&self, position: CursorPosition) -> Result<Cursor, ()> {
957        let Some(laidout_text) = self.laidout_text.as_ref() else {
958            return Err(());
959        };
960        let cursor = laidout_text.position_to_cursor(CursorPosition {
961            row_index: position.row_index,
962            x_in_lpxs: position.x_in_lpxs / self.draw_text.font_scale,
963        });
964        Ok(self.password_cursor_to_cursor(cursor))
965    }
966
967    fn selection_to_password_selection(&self, selection: Selection) -> Selection {
968        Selection {
969            cursor: self.cursor_to_password_cursor(selection.cursor),
970            anchor: self.cursor_to_password_cursor(selection.anchor),
971        }
972    }
973
974    fn cursor_to_password_cursor(&self, cursor: Cursor) -> Cursor {
975        Cursor {
976            index: self.index_to_password_index(cursor.index),
977            prefer_next_row: cursor.prefer_next_row,
978        }
979    }
980
981    fn password_cursor_to_cursor(&self, password_cursor: Cursor) -> Cursor {
982        Cursor {
983            index: self.password_index_to_index(password_cursor.index),
984            prefer_next_row: password_cursor.prefer_next_row,
985        }
986    }
987
988    fn index_to_password_index(&self, index: usize) -> usize {
989        if !self.is_password {
990            return index;
991        }
992        let grapheme_index = self.text[..index].graphemes(true).count();
993        self.password_text
994            .grapheme_indices(true)
995            .nth(grapheme_index).map_or(self.password_text.len(), |(index, _)| index)
996    }
997
998    fn password_index_to_index(&self, password_index: usize) -> usize {
999        if !self.is_password {
1000            return password_index;
1001        }
1002        let grapheme_index = self.password_text[..password_index].graphemes(true).count();
1003        self.text
1004            .grapheme_indices(true)
1005            .nth(grapheme_index).map_or(self.text.len(), |(index, _)| index)
1006    }
1007
1008    fn inner_walk(&self) -> Walk {
1009        if self.walk.width.is_fit() {
1010            Walk::fit()
1011        } else {
1012            Walk::fill_fit()
1013        }
1014    }
1015
1016    fn layout_text(&mut self, cx: &mut Cx2d) {
1017        if self.laidout_text.is_some() {
1018            return;
1019        }
1020        let text = if self.is_password {
1021            self.password_text.clear();
1022            for grapheme in self.text.graphemes(true) {
1023                self.password_text.push(if grapheme == "\n" {
1024                    '\n'
1025                } else {
1026                    '•'
1027                });
1028            }
1029            &self.password_text
1030        } else {
1031            &self.text
1032        };
1033        let turtle_rect = cx.turtle().padded_rect();
1034        let max_width_in_lpxs = if !turtle_rect.size.x.is_nan() {
1035            Some(turtle_rect.size.x as f32)
1036        } else {
1037            None
1038        };
1039        let wrap = cx.turtle().layout().flow == Flow::RightWrap;
1040        self.laidout_text = Some(self.draw_text.layout(
1041            cx,
1042            0.0,
1043            0.0,
1044            max_width_in_lpxs,
1045            wrap,
1046            self.label_align, 
1047            text
1048        ));
1049    }
1050
1051    fn draw_text(&mut self, cx: &mut Cx2d) -> Rect {
1052        let inner_walk = self.inner_walk();
1053        let text_rect = if self.text.is_empty() {
1054            self.draw_text.draw_walk(
1055                cx,
1056                inner_walk,
1057                self.label_align,
1058                &self.empty_text
1059            )
1060        } else {
1061            let laidout_text = self.laidout_text.as_ref().unwrap();
1062            self.draw_text.draw_walk_laidout(
1063                cx,
1064                inner_walk,
1065                laidout_text,
1066            )
1067        };
1068        cx.add_aligned_rect_area(&mut self.text_area, text_rect);
1069        text_rect
1070    }
1071
1072    fn draw_cursor(&mut self, cx: &mut Cx2d, text_rect: Rect) -> DVec2 {
1073        let CursorPosition {
1074            row_index,
1075            x_in_lpxs,
1076        } = self
1077            .cursor_to_position(self.selection.cursor)
1078            .ok()
1079            .expect("layout should not be `None` because we called `layout_text` in `draw_walk`");
1080        let laidout_text = self
1081            .laidout_text
1082            .as_ref()
1083            .expect("layout should not be `None` because we called `layout_text` in `draw_walk`");
1084        let row = &laidout_text.rows[row_index];
1085        let cursor_pos = dvec2(
1086            (x_in_lpxs - 1.0 * self.draw_text.font_scale) as f64,
1087            ((row.origin_in_lpxs.y - row.ascender_in_lpxs) * self.draw_text.font_scale) as f64,
1088        );
1089        self.draw_cursor.draw_abs(
1090            cx,
1091            rect(
1092                text_rect.pos.x + cursor_pos.x,
1093                text_rect.pos.y + cursor_pos.y,
1094                (2.0 * self.draw_text.font_scale) as f64,
1095                ((row.ascender_in_lpxs - row.descender_in_lpxs) * self.draw_text.font_scale) as f64,
1096            )
1097        );
1098        cursor_pos
1099    }
1100
1101    fn draw_selection(&mut self, cx: &mut Cx2d, text_rect: Rect) {
1102        let laidout_text = self
1103            .laidout_text
1104            .as_ref()
1105            .expect("layout should not be `None` because we called `layout_text` in `draw_walk`");
1106        
1107        self.draw_selection.begin_many_instances(cx);
1108        for rect_in_lpxs in laidout_text.selection_rects_in_lpxs(
1109            self.selection_to_password_selection(self.selection)
1110        ) {
1111            self.draw_selection.draw_abs(
1112                cx,
1113                rect(
1114                    text_rect.pos.x + (rect_in_lpxs.origin.x * self.draw_text.font_scale) as f64,
1115                    text_rect.pos.y + (rect_in_lpxs.origin.y * self.draw_text.font_scale) as f64,
1116                    (rect_in_lpxs.size.width * self.draw_text.font_scale) as f64,
1117                    (rect_in_lpxs.size.height * self.draw_text.font_scale) as f64,
1118                )
1119            );
1120        }
1121        self.draw_selection.end_many_instances(cx);
1122    }
1123
1124    pub fn move_cursor_left(&mut self, cx: &mut Cx, keep_selection: bool) {
1125        self.set_cursor(
1126            cx,
1127            Cursor {
1128                index: prev_grapheme_boundary(&self.text, self.selection.cursor.index),
1129                prefer_next_row: true,
1130            },
1131            keep_selection
1132        );
1133    }
1134
1135    pub fn move_cursor_right(&mut self, cx: &mut Cx, keep_selection: bool) {
1136        self.set_cursor(
1137            cx,
1138            Cursor {
1139                index: next_grapheme_boundary(&self.text, self.selection.cursor.index),
1140                prefer_next_row: false,
1141            },
1142            keep_selection,
1143        );
1144    }
1145
1146    pub fn move_cursor_up(&mut self, cx: &mut Cx, keep_selection: bool) -> Result<(), ()> {
1147        let position = self.cursor_to_position(self.selection.cursor)?;
1148        self.set_cursor(
1149            cx,
1150            self.position_to_cursor(CursorPosition {
1151                row_index: if position.row_index == 0 {
1152                    0
1153                } else {
1154                    position.row_index - 1
1155                },
1156                x_in_lpxs: position.x_in_lpxs,
1157            })?,
1158            keep_selection
1159        );
1160        Ok(())
1161    }
1162
1163    pub fn move_cursor_down(&mut self, cx: &mut Cx, keep_selection: bool) -> Result<(), ()> {
1164        let laidout_text = self.laidout_text.as_ref().unwrap();
1165        let position = self.cursor_to_position(self.selection.cursor)?;
1166        self.set_cursor(
1167            cx,
1168            self.position_to_cursor(CursorPosition {
1169                row_index: if position.row_index == laidout_text.rows.len() - 1 {
1170                    laidout_text.rows.len() - 1
1171                } else {
1172                    position.row_index + 1 
1173                },
1174                x_in_lpxs: position.x_in_lpxs,
1175            })?,
1176            keep_selection
1177        );
1178        Ok(())
1179    }
1180
1181    pub fn select_all(&mut self, cx: &mut Cx) {
1182        self.set_selection(
1183            cx,
1184            Selection {
1185                anchor: Cursor { index: 0, prefer_next_row: false },
1186                cursor: Cursor { index: self.text.len(), prefer_next_row: false },
1187            }
1188        );
1189    }
1190
1191    pub fn select_word(&mut self, cx: &mut Cx) {
1192        if self.selection.cursor.index < self.selection.anchor.index { 
1193            self.set_cursor(
1194                cx, 
1195                Cursor {
1196                    index: self.ceil_word_boundary(self.selection.cursor.index),
1197                    prefer_next_row: true,
1198                },
1199                true,
1200            );
1201        } else if self.selection.cursor.index > self.selection.anchor.index {
1202            self.set_cursor(
1203                cx,
1204                Cursor {
1205                    index: self.floor_word_boundary(self.selection.cursor.index),
1206                    prefer_next_row: false,
1207                },
1208                true,
1209            );
1210        } else {
1211            self.set_selection(
1212                cx,
1213                Selection {
1214                    anchor: Cursor {
1215                        index: self.ceil_word_boundary(self.selection.cursor.index),
1216                        prefer_next_row: true,
1217                    },
1218                    cursor: Cursor {
1219                        index: self.floor_word_boundary(self.selection.cursor.index),
1220                        prefer_next_row: false,
1221                    }
1222                },
1223            );
1224        }
1225    }
1226
1227    pub fn force_new_edit_group(&mut self) {
1228        self.history.force_new_edit_group();
1229    }
1230
1231    fn ceil_word_boundary(&self, index: usize) -> usize {
1232        let mut prev_word_boundary_index = 0;
1233        for (word_boundary_index, _) in self.text.split_word_bound_indices() {
1234            if word_boundary_index > index {
1235                return prev_word_boundary_index;
1236            }
1237            prev_word_boundary_index = word_boundary_index;
1238        }
1239        prev_word_boundary_index
1240    }
1241
1242    fn floor_word_boundary(&self, index: usize) -> usize {
1243        let mut prev_word_boundary_index = self.text.len();
1244        for (word_boundary_index, _) in self.text.split_word_bound_indices().rev() {
1245            if word_boundary_index < index {
1246                return prev_word_boundary_index;
1247            }
1248            prev_word_boundary_index = word_boundary_index;
1249        }
1250        prev_word_boundary_index
1251    }
1252
1253    fn filter_input(&self, input: &str, is_set_text: bool) -> String {
1254        if self.is_numeric_only {
1255            let mut contains_dot = if is_set_text {
1256                false   
1257            } else {
1258                let before_selection = self.text[..self.selection.start().index].to_string();
1259                let after_selection = self.text[self.selection.end().index..].to_string();
1260                before_selection.contains('.') || after_selection.contains('.')
1261            };
1262            input.chars().filter(|char| {
1263                match char {
1264                    '.' | ',' if !contains_dot => {
1265                        contains_dot = true;
1266                        true
1267                    },
1268                    char => char.is_ascii_digit(),
1269                }
1270            }).collect()
1271        } else {
1272            input.to_string()
1273        }
1274    }
1275
1276    fn create_or_extend_edit_group(&mut self, edit_kind: EditKind) {
1277        self.history.create_or_extend_edit_group(edit_kind, self.selection);
1278    }
1279
1280    fn apply_edit(&mut self, cx: &mut Cx, edit: Edit) {
1281        self.selection.cursor.index = edit.start + edit.replace_with.len();
1282        self.selection.anchor.index = self.selection.cursor.index;
1283        self.history.apply_edit(edit, &mut self.text);
1284        self.laidout_text = None;
1285        self.check_text_is_empty(cx);
1286    }
1287
1288    fn undo(&mut self, cx: &mut Cx) -> bool {
1289        if let Some(new_selection) = self.history.undo(self.selection, &mut self.text) {
1290            self.laidout_text = None;
1291            self.selection = new_selection;
1292            self.check_text_is_empty(cx);
1293            true
1294        } else {
1295            false
1296        }
1297    }
1298
1299    fn redo(&mut self, cx: &mut Cx) -> bool {
1300        if let Some(new_selection) = self.history.redo(self.selection, &mut self.text) {
1301            self.laidout_text = None;
1302            self.selection = new_selection;
1303            self.check_text_is_empty(cx);
1304            true
1305        } else {
1306            false
1307        }
1308    }
1309
1310    fn check_text_is_empty(&mut self, cx: &mut Cx) {
1311        if self.text.is_empty() {
1312            self.animator_play(cx, id!(empty.on));
1313        } else {
1314            self.animator_play(cx, id!(empty.off));
1315        }
1316    }
1317    
1318}
1319
1320impl Widget for TextInput {
1321        
1322    fn text(&self) -> String {
1323        self.text.clone()
1324    }
1325    
1326    fn set_text(&mut self, cx: &mut Cx, text: &str) {
1327        self.text = self.filter_input(text, true);
1328        self.set_selection(
1329            cx,
1330            Selection {
1331                anchor: Cursor {
1332                    index: self.selection.anchor.index.min(self.text.len()),
1333                    prefer_next_row: self.selection.anchor.prefer_next_row,
1334                },
1335                cursor: Cursor {
1336                    index: self.selection.cursor.index.min(self.text.len()),
1337                    prefer_next_row: self.selection.cursor.prefer_next_row,
1338                }
1339            }
1340        );
1341        self.history.clear();
1342        self.laidout_text = None;
1343        self.draw_bg.redraw(cx);
1344        self.check_text_is_empty(cx);
1345    }
1346    
1347    fn draw_walk(&mut self, cx: &mut Cx2d, _scope: &mut Scope, walk: Walk) -> DrawStep {
1348        self.draw_bg.begin(cx, walk, self.layout);
1349        self.draw_selection.append_to_draw_call(cx);
1350        self.layout_text(cx);
1351        let text_rect = self.draw_text(cx);
1352        let cursor_pos = self.draw_cursor(cx, text_rect);
1353        self.draw_selection(cx, text_rect);
1354        self.draw_bg.end(cx);
1355        if cx.has_key_focus(self.draw_bg.area()) {
1356            cx.show_text_ime(
1357                self.draw_bg.area(), 
1358                cursor_pos,
1359            );
1360        }
1361        cx.add_nav_stop(self.draw_bg.area(), NavRole::TextInput, Margin::default());
1362        DrawStep::done()
1363    }
1364
1365    fn set_disabled(&mut self, cx:&mut Cx, disabled:bool){
1366        self.animator_toggle(cx, disabled, Animate::Yes, id!(disabled.on), id!(disabled.off));
1367    }
1368                
1369    fn disabled(&self, cx:&Cx) -> bool {
1370        self.animator_in_state(cx, id!(disabled.on))
1371    }
1372
1373    fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
1374        if self.animator_handle_event(cx, event).must_redraw() {
1375            self.draw_bg.redraw(cx);
1376        }
1377
1378        if self.blink_timer.is_event(event).is_some() {
1379            if self.animator_in_state(cx, id!(blink.off)) {
1380                self.animator_play(cx, id!(blink.on));
1381            } else {
1382                self.animator_play(cx, id!(blink.off));
1383            }
1384            self.blink_timer = cx.start_timeout(self.blink_speed)
1385        }
1386
1387        let uid = self.widget_uid();
1388        match event.hits(cx, self.draw_bg.area()) {
1389            Hit::FingerHoverIn(_) => {
1390                self.animator_play(cx, id!(hover.on));
1391            }
1392            Hit::FingerHoverOut(_) => {
1393                self.animator_play(cx, id!(hover.off));
1394            }
1395            Hit::KeyFocus(_) => {
1396                self.animator_play(cx, id!(focus.on));
1397                self.reset_blink_timer(cx);
1398                cx.widget_action(uid, &scope.path, TextInputAction::KeyFocus);
1399            },
1400            Hit::KeyFocusLost(_) => {
1401                self.animator_play(cx, id!(focus.off));
1402                self.animator_play(cx, id!(blink.on));
1403                cx.stop_timer(self.blink_timer);
1404                cx.hide_text_ime();
1405                cx.widget_action(uid, &scope.path, TextInputAction::KeyFocusLost);
1406            }
1407            Hit::KeyDown(KeyEvent {
1408                key_code: KeyCode::ArrowLeft,
1409                modifiers: KeyModifiers {
1410                    shift: keep_selection,
1411                    logo: false,
1412                    alt: false,
1413                    control: false
1414                },
1415                ..
1416            }) => {
1417                self.reset_blink_timer(cx);
1418                self.move_cursor_left(cx, keep_selection);
1419            }
1420            Hit::KeyDown(KeyEvent {
1421                key_code: KeyCode::ArrowRight,
1422                modifiers: KeyModifiers {
1423                    shift: keep_selection,
1424                    logo: false,
1425                    alt: false,
1426                    control: false
1427                },
1428                ..
1429            }) => {
1430                self.reset_blink_timer(cx);
1431                self.move_cursor_right(cx, keep_selection);
1432            }
1433            Hit::KeyDown(KeyEvent {
1434                key_code: KeyCode::ArrowUp,
1435                modifiers: KeyModifiers {
1436                    shift: keep_selection,
1437                    logo: false,
1438                    alt: false,
1439                    control: false
1440                },
1441                ..
1442            }) => {
1443                self.reset_blink_timer(cx);
1444                if self.move_cursor_up(cx, keep_selection).is_err() {
1445                    warning!("can't move cursor because layout was invalidated by earlier event");
1446                }
1447            },
1448            Hit::KeyDown(KeyEvent {
1449                key_code: KeyCode::ArrowDown,
1450                modifiers: KeyModifiers {
1451                    shift: keep_selection,
1452                    logo: false,
1453                    alt: false,
1454                    control: false
1455                },
1456                ..
1457            }) => {
1458                self.reset_blink_timer(cx);
1459                if self.move_cursor_down(cx, keep_selection).is_err() {
1460                    warning!("can't move cursor because layout was invalidated by earlier event");
1461                }
1462            }
1463            Hit::KeyDown(KeyEvent {
1464                key_code: KeyCode::KeyA,
1465                modifiers,
1466                ..
1467            }) if modifiers.is_primary() => self.select_all(cx),
1468            Hit::FingerDown(FingerDownEvent {
1469                abs,
1470                tap_count,
1471                device,
1472                ..
1473            }) if device.is_primary_hit() => {
1474                self.reset_blink_timer(cx);
1475                self.set_key_focus(cx);
1476                let rel = abs - self.text_area.rect(cx).pos;
1477                let Ok(cursor) = self.point_in_lpxs_to_cursor(
1478                    Point::new(rel.x as f32, rel.y as f32)
1479                ) else {
1480                    warning!("can't move cursor because layout was invalidated by earlier event");
1481                    return;
1482                };
1483                self.set_cursor(
1484                    cx,
1485                    cursor,
1486                    false
1487                );
1488                match tap_count {
1489                    2 => self.select_word(cx),
1490                    3 => self.select_all(cx),
1491                    _ => {}
1492                }
1493
1494                self.animator_play(cx, id!(hover.down));
1495            }
1496            Hit::FingerUp(fe) => {
1497                if fe.is_over && fe.was_tap() {
1498                    if fe.has_hovers() {
1499                        self.animator_play(cx, id!(hover.on));
1500                    } else {
1501                        self.animator_play(cx, id!(hover.off));
1502                    }
1503                } else {
1504                    self.animator_play(cx, id!(hover.off));
1505                }
1506            }
1507            Hit::FingerMove(FingerMoveEvent {
1508                abs,
1509                tap_count,
1510                device,
1511                ..
1512            }) if device.is_primary_hit() => {
1513                self.reset_blink_timer(cx);
1514                self.set_key_focus(cx);
1515                let rel = abs - self.text_area.rect(cx).pos;
1516                let Ok(cursor) = self.point_in_lpxs_to_cursor(
1517                    Point::new(rel.x as f32, rel.y as f32)
1518                ) else {
1519                    warning!("can't move cursor because layout was invalidated by earlier event");
1520                    return;
1521                };
1522                self.set_cursor(
1523                    cx,
1524                    cursor,
1525                    true
1526                );
1527                match tap_count {
1528                    2 => self.select_word(cx),
1529                    3 => self.select_all(cx),
1530                    _ => {}
1531                }
1532            }
1533            Hit::KeyDown(KeyEvent {
1534                key_code: KeyCode::ReturnKey,
1535                modifiers: mods @ KeyModifiers {
1536                    shift: false,
1537                    ..
1538                },
1539                ..
1540            }) => {
1541                cx.hide_text_ime();
1542                cx.widget_action(
1543                    uid,
1544                    &scope.path,
1545                    TextInputAction::Returned(
1546                        self.text.clone(),
1547                        mods,
1548                    ),
1549                );
1550            },
1551
1552            Hit::KeyDown(KeyEvent {
1553                key_code: KeyCode::Escape,
1554                ..
1555            }) => {
1556                cx.widget_action(uid, &scope.path, TextInputAction::Escaped);
1557            }
1558            Hit::KeyDown(KeyEvent {
1559                key_code: KeyCode::ReturnKey,
1560                modifiers: KeyModifiers {
1561                    shift: true,
1562                    ..
1563                },
1564                ..
1565            }) if !self.is_read_only => {
1566                self.reset_blink_timer(cx);
1567                self.create_or_extend_edit_group(EditKind::Other);
1568                self.apply_edit(
1569                    cx,
1570                    Edit {
1571                        start: self.selection.start().index,
1572                        end: self.selection.end().index,
1573                        replace_with: "\n".to_string(),
1574                    }
1575                );
1576                self.draw_bg.redraw(cx);
1577                cx.widget_action(uid, &scope.path, TextInputAction::Changed(self.text.clone()));
1578            }
1579            Hit::KeyDown(KeyEvent {
1580                key_code: KeyCode::Backspace,
1581                ..
1582            }) if !self.is_read_only => {
1583                self.reset_blink_timer(cx);
1584                let mut start = self.selection.start().index;
1585                let end = self.selection.end().index;
1586                if start == end {
1587                    start = prev_grapheme_boundary(&self.text, start);
1588                }
1589                self.create_or_extend_edit_group(EditKind::Backspace);
1590                self.apply_edit(
1591                    cx,
1592                    Edit {
1593                        start,
1594                        end,
1595                        replace_with: String::new(),
1596                    }
1597                );
1598                self.draw_bg.redraw(cx);
1599                cx.widget_action(uid, &scope.path, TextInputAction::Changed(self.text.clone()));
1600            }
1601            Hit::KeyDown(KeyEvent {
1602                key_code: KeyCode::Delete,
1603                ..
1604            }) if !self.is_read_only => {
1605                self.reset_blink_timer(cx);
1606                let start = self.selection.start().index;
1607                let mut end = self.selection.end().index;
1608                if start == end {
1609                    end = next_grapheme_boundary(&self.text, end);
1610                }
1611                self.create_or_extend_edit_group(EditKind::Delete);
1612                self.apply_edit(
1613                    cx,
1614                    Edit {
1615                        start,
1616                        end,
1617                        replace_with: String::new(),
1618                    }
1619                );
1620                self.draw_bg.redraw(cx);
1621                cx.widget_action(uid, &scope.path, TextInputAction::Changed(self.text.clone()));
1622            }
1623            Hit::KeyDown(KeyEvent {
1624                key_code: KeyCode::KeyZ,
1625                modifiers: modifiers @ KeyModifiers {
1626                    shift: false,
1627                    ..
1628                },
1629                ..
1630            }) if modifiers.is_primary() && !self.is_read_only => {
1631                if !self.undo(cx) {
1632                    return;
1633                }
1634                self.draw_bg.redraw(cx);
1635                cx.widget_action(uid, &scope.path, TextInputAction::Changed(self.text.clone()));
1636            }
1637            Hit::KeyDown(KeyEvent {
1638                key_code: KeyCode::KeyZ,
1639                modifiers: modifiers @ KeyModifiers {
1640                    shift: true,
1641                    ..
1642                },
1643                ..
1644            }) if modifiers.is_primary() && !self.is_read_only => {
1645                if !self.redo(cx) {
1646                    return;
1647                }
1648                self.draw_bg.redraw(cx);
1649                cx.widget_action(uid, &scope.path, TextInputAction::Changed(self.text.clone()));
1650            }
1651            Hit::TextInput(TextInputEvent {
1652                input,
1653                replace_last,
1654                was_paste,
1655                ..
1656            }) if !self.is_read_only => {
1657                let input = self.filter_input(&input, false);
1658                if input.is_empty() {
1659                    return;
1660                }
1661                self.create_or_extend_edit_group(
1662                    if replace_last || was_paste {
1663                        EditKind::Other
1664                    } else {
1665                        EditKind::Insert
1666                    }
1667                );
1668                self.apply_edit(
1669                    cx,
1670                    Edit {
1671                        start: self.selection.start().index,
1672                        end: self.selection.end().index,
1673                        replace_with: input
1674                    }
1675                );
1676                self.animator_play(cx, id!(empty.off));
1677                self.draw_bg.redraw(cx);
1678                cx.widget_action(uid, &scope.path, TextInputAction::Changed(self.text.clone()));
1679            }
1680            Hit::TextCopy(event) => {
1681                *event.response.borrow_mut() = Some(self.selected_text().to_string());
1682            }
1683            Hit::TextCut(event) => {
1684                *event.response.borrow_mut() = Some(self.selected_text().to_string());
1685                if !self.selected_text().is_empty() {
1686                    self.history.create_or_extend_edit_group(EditKind::Other, self.selection);
1687                    self.apply_edit(
1688                        cx,
1689                        Edit {
1690                            start: self.selection.start().index,
1691                            end: self.selection.end().index,
1692                            replace_with: String::new(),
1693                        }
1694                    );
1695                    self.draw_bg.redraw(cx);
1696                    cx.widget_action(uid, &scope.path, TextInputAction::Changed(self.text.clone()));
1697                }
1698            }
1699            Hit::KeyDown(event) => {
1700                cx.widget_action(uid, &scope.path, TextInputAction::KeyDownUnhandled(event));
1701            }
1702            _ => {}
1703        }
1704    }
1705}
1706
1707impl TextInputRef {
1708    pub fn is_password(&self) -> bool {
1709        if let Some(inner) = self.borrow(){
1710            inner.is_password()
1711        }
1712        else{
1713            false
1714        }
1715    }
1716 
1717    pub fn set_is_password(&self, cx: &mut Cx, is_password: bool) {
1718        if let Some(mut inner) = self.borrow_mut(){
1719            inner.set_is_password(cx, is_password);
1720        }
1721    }
1722 
1723    pub fn toggle_is_password(&self, cx: &mut Cx) {
1724        if let Some(mut inner) = self.borrow_mut(){
1725            inner.toggle_is_password(cx);
1726        }
1727    }
1728
1729    pub fn is_read_only(&self) -> bool {
1730        if let Some(inner) = self.borrow(){
1731            inner.is_read_only()
1732        }
1733        else{
1734            false
1735        }
1736    }
1737
1738    pub fn set_is_read_only(&self, cx: &mut Cx, is_read_only: bool) {
1739        if let Some(mut inner) = self.borrow_mut(){
1740            inner.set_is_read_only(cx, is_read_only);
1741        }
1742    }
1743
1744    pub fn toggle_is_read_only(&self, cx: &mut Cx) {
1745        if let Some(mut inner) = self.borrow_mut(){
1746            inner.toggle_is_read_only(cx);
1747        }
1748    }
1749
1750    pub fn is_numeric_only(&self) -> bool {
1751        if let Some(inner) = self.borrow(){
1752            inner.is_numeric_only()
1753        }
1754        else{
1755            false
1756        }
1757    }
1758
1759    pub fn set_is_numeric_only(&self, cx: &mut Cx, is_numeric_only: bool) {
1760        if let Some(mut inner) = self.borrow_mut(){
1761            inner.set_is_numeric_only(cx, is_numeric_only);
1762        }
1763    }
1764
1765    pub fn toggle_is_numeric_only(&self, cx: &mut Cx) {
1766        if let Some(mut inner) = self.borrow_mut(){
1767            inner.toggle_is_numeric_only(cx);
1768        }
1769    }
1770
1771    pub fn empty_text(&self) -> String {
1772        if let Some(inner) = self.borrow(){
1773            inner.empty_text().to_string()
1774        }
1775        else{
1776            String::new()
1777        }
1778    }
1779
1780    pub fn set_empty_text(&self, cx: &mut Cx, empty_text: String) {
1781        if let Some(mut inner) = self.borrow_mut(){
1782            inner.set_empty_text(cx, empty_text);
1783        }
1784    }
1785
1786    pub fn selection(&self) -> Selection {
1787        if let Some(inner) = self.borrow(){
1788            inner.selection()
1789        }
1790        else{
1791            Default::default()
1792        }
1793    }
1794
1795    pub fn set_selection(&self, cx: &mut Cx, selection: Selection) {
1796        if let Some(mut inner) = self.borrow_mut(){
1797            inner.set_selection(cx, selection);
1798        }
1799    }
1800
1801    pub fn cursor(&self) -> Cursor {
1802        if let Some(inner) = self.borrow(){
1803            inner.cursor()
1804        }
1805        else{
1806            Default::default()
1807        }
1808    }
1809
1810    pub fn set_cursor(&self, cx: &mut Cx, cursor: Cursor, keep_selection: bool) {
1811        if let Some(mut inner) = self.borrow_mut(){
1812            inner.set_cursor(cx, cursor, keep_selection);
1813        }
1814    }
1815
1816    pub fn selected_text(&self) -> String {
1817        if let Some(inner) = self.borrow(){
1818            inner.selected_text().to_string()
1819        }
1820        else{
1821            String::new()
1822        }
1823    }
1824
1825    pub fn returned(&self, actions: &Actions) -> Option<(String, KeyModifiers)> {
1826        for action in actions.filter_widget_actions_cast::<TextInputAction>(self.widget_uid()){
1827            if let TextInputAction::Returned(text, modifiers) = action {
1828                return Some((text, modifiers));
1829            }
1830        }
1831        None
1832    }
1833    
1834    pub fn escaped(&self, actions: &Actions) -> bool {
1835        for action in actions.filter_widget_actions_cast::<TextInputAction>(self.widget_uid()){
1836            if let TextInputAction::Escaped = action {
1837                return true;
1838            }
1839        }
1840        false
1841    }
1842
1843    pub fn changed(&self, actions: &Actions) -> Option<String> {
1844        for action in actions.filter_widget_actions_cast::<TextInputAction>(self.widget_uid()){
1845            if let TextInputAction::Changed(text) = action{
1846                return Some(text);
1847            }
1848        }
1849        None
1850    }
1851
1852    pub fn key_down_unhandled(&self, actions: &Actions) -> Option<KeyEvent> {
1853        for action in actions.filter_widget_actions_cast::<TextInputAction>(self.widget_uid()){
1854            if let TextInputAction::KeyDownUnhandled(event) = action{
1855                return Some(event);
1856            }
1857        }
1858        None
1859    }
1860
1861    /// Saves the internal state of this text input widget
1862    /// to a new `TextInputState` object.
1863    pub fn save_state(&self) -> TextInputState {
1864        if let Some(inner) = self.borrow() {
1865            TextInputState {
1866                text: inner.text.clone(),
1867                password_text: inner.password_text.clone(),
1868                selection: inner.selection.clone(),
1869                history: inner.history.clone(),
1870            }
1871        } else {
1872            TextInputState::default()
1873        }
1874    }
1875
1876    /// Restores the internal state of this text input widget
1877    /// from the given `TextInputState` object.
1878    pub fn restore_state(&self, cx: &mut Cx, state: TextInputState) {
1879        if let Some(mut inner) = self.borrow_mut() {
1880            inner.set_text(cx, &state.text);
1881            inner.password_text = state.password_text;
1882            inner.history = state.history;
1883            inner.set_selection(cx, state.selection);
1884        }
1885    }
1886}
1887
1888/// The saved (checkpointed) state of a text input widget.
1889#[derive(Clone, Debug, Default)]
1890pub struct TextInputState {
1891    text: String,
1892    password_text: String,
1893    selection: Selection,
1894    history: History,
1895}
1896
1897#[derive(Clone, Debug, DefaultNone)]
1898pub enum TextInputAction {
1899    None,
1900    KeyFocus,
1901    KeyFocusLost,
1902    Returned(String, KeyModifiers),
1903    Escaped,
1904    Changed(String),
1905    KeyDownUnhandled(KeyEvent),
1906}
1907
1908#[derive(Clone, Debug, Default)]
1909struct History {
1910    current_edit_kind: Option<EditKind>,
1911    undo_stack: EditStack,
1912    redo_stack: EditStack,
1913}
1914
1915impl History {
1916    fn force_new_edit_group(&mut self) {
1917        self.current_edit_kind = None;
1918    }
1919
1920    fn create_or_extend_edit_group(&mut self, edit_kind: EditKind, selection: Selection) {
1921        if !self.current_edit_kind.map_or(false, |current_edit_kind| current_edit_kind.can_merge_with(edit_kind)) {
1922            self.undo_stack.push_edit_group(selection);
1923            self.current_edit_kind = Some(edit_kind);
1924        }
1925    }
1926
1927    fn apply_edit(&mut self, edit: Edit, text: &mut String) {
1928        let inverted_edit = edit.invert(&text);
1929        edit.apply(text);
1930        self.undo_stack.push_edit(inverted_edit);
1931        self.redo_stack.clear();
1932    }
1933
1934    fn undo(
1935        &mut self,
1936        selection: Selection,
1937        text: &mut String,
1938    ) -> Option<Selection> {
1939        if let Some((new_selection, edits)) = self.undo_stack.pop_edit_group() {
1940            self.redo_stack.push_edit_group(selection);
1941            for edit in &edits {
1942                let inverted_edit = edit.invert(text);
1943                edit.apply(text);
1944                self.redo_stack.push_edit(inverted_edit);
1945            }
1946            self.current_edit_kind = None;
1947            Some(new_selection)
1948        } else {
1949            None
1950        }
1951    }
1952
1953    fn redo(
1954        &mut self,
1955        selection: Selection,
1956        text: &mut String,
1957    ) -> Option<Selection> {
1958        if let Some((new_selection, edits)) = self.redo_stack.pop_edit_group() {
1959            self.undo_stack.push_edit_group(selection);
1960            for edit in &edits {
1961                let inverted_edit = edit.invert(text);
1962                edit.apply(text);
1963                self.undo_stack.push_edit(inverted_edit);
1964            }
1965            self.current_edit_kind = None;
1966            Some(new_selection)
1967        } else {
1968            None
1969        }
1970    }
1971
1972    fn clear(&mut self) {
1973        self.current_edit_kind = None;
1974        self.undo_stack.clear();
1975        self.redo_stack.clear();
1976    }
1977}
1978
1979#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1980enum EditKind {
1981    Insert,
1982    Backspace,
1983    Delete,
1984    Other,
1985}
1986
1987impl EditKind {
1988    fn can_merge_with(self, other: EditKind) -> bool {
1989        if self == Self::Other {
1990            false
1991        } else {
1992            self == other
1993        }
1994    }
1995}
1996
1997#[derive(Clone, Debug, Default)]
1998struct EditStack {
1999    edit_groups: Vec<EditGroup>,
2000    edits: Vec<Edit>,
2001}
2002
2003impl EditStack {
2004    fn push_edit_group(&mut self, selection: Selection) {
2005        self.edit_groups.push(EditGroup {
2006            selection,
2007            edit_start: self.edits.len(),
2008        });
2009    }
2010    
2011    fn push_edit(&mut self, edit: Edit) {
2012        self.edits.push(edit);
2013    }
2014    
2015    fn pop_edit_group(&mut self) -> Option<(Selection, Vec<Edit>)> {
2016        match self.edit_groups.pop() {
2017            Some(edit_group) => Some((
2018                edit_group.selection,
2019                self.edits.drain(edit_group.edit_start..).rev().collect()
2020            )),
2021            None => None,
2022        }
2023    }
2024    
2025    fn clear(&mut self) {
2026        self.edit_groups.clear();
2027        self.edits.clear();
2028    }
2029}
2030
2031#[derive(Clone, Copy, Debug)]
2032struct EditGroup {
2033    selection: Selection,
2034    edit_start: usize
2035}
2036
2037#[derive(Clone, Debug)]
2038struct Edit {
2039    start: usize,
2040    end: usize,
2041    replace_with: String,
2042}
2043
2044impl Edit {
2045    fn apply(&self, text: &mut String) {
2046        text.replace_range(self.start..self.end, &self.replace_with);
2047    }
2048
2049    fn invert(&self, text: &str) -> Self {
2050        Self {
2051            start: self.start,
2052            end: self.start + self.replace_with.len(),
2053            replace_with: text[self.start..self.end].to_string(),
2054        }
2055    }
2056}
2057
2058fn prev_grapheme_boundary(text: &str, index: usize) -> usize {
2059    let mut cursor = GraphemeCursor::new(index, text.len(), true);
2060    cursor.prev_boundary(text, 0).unwrap().unwrap_or(0)
2061}
2062
2063fn next_grapheme_boundary(text: &str, index: usize) -> usize {
2064    let mut cursor = GraphemeCursor::new(index, text.len(), true);
2065    cursor.next_boundary(text, 0).unwrap().unwrap_or(text.len())
2066}