1use crate::common::*;
2
3use femtovg::{renderer::OpenGl, Align, Baseline, Canvas, Color, Paint, Path, Solidity};
4
5use crate::Key;
6
7#[derive(Debug, Clone, PartialEq)]
8pub enum TextboxEvent {
9 SetValue(String),
10 ValueChanged(String),
11 ResetValue,
12 Clear,
13}
14
15pub struct Textbox {
18 entity: Entity,
19 pub text: String,
20
21 buffer: String,
22
23 units: String,
24 select_pos: u32,
27 cursor_pos: u32,
28 edit: bool,
29 hitx: f32,
30 dragx: f32,
31
32 on_change: Option<Box<dyn Fn(&mut Self, &mut State, Entity)>>,
34 on_submit: Option<Box<dyn Fn(&mut Self, &mut State, Entity)>>,
35}
36
37impl Textbox {
38 pub fn new(text: &str) -> Self {
39 Textbox {
43 entity: Entity::null(),
44
45 text: text.to_string(),
46
47 buffer: String::new(),
48
49 units: String::new(),
50
51 select_pos: 0,
54 cursor_pos: 0,
55 edit: false,
56 hitx: -1.0,
57 dragx: -1.0,
58
59 on_change: None,
60 on_submit: None,
61 }
62 }
63
64 pub fn with_units(mut self, uints: &str) -> Self {
65 self.units = uints.to_string();
66
67 self
68 }
69
70 pub fn on_change<F>(mut self, on_change: F) -> Self
71 where
72 F: 'static + Fn(&mut Self, &mut State, Entity),
73 {
74 self.on_change = Some(Box::new(on_change));
75
76 self
77 }
78
79 pub fn on_submit<F>(mut self, on_submit: F) -> Self
80 where
81 F: 'static + Fn(&mut Self, &mut State, Entity),
82 {
83 self.on_submit = Some(Box::new(on_submit));
84
85 self
86 }
87 }
97
98impl Widget for Textbox {
99 type Ret = Entity;
100 type Data = String;
101 fn on_build(&mut self, state: &mut State, entity: Entity) -> Self::Ret {
102 entity.set_text(state, &(self.text.to_owned() + &self.units));
103
104 self.entity = entity;
105
106 entity.set_clip_widget(state, entity);
107
108 entity.set_element(state, "textbox")
109 }
110
111 fn on_event(&mut self, state: &mut State, entity: Entity, event: &mut Event) {
112 if let Some(textbox_event) = event.message.downcast::<TextboxEvent>() {
113 match textbox_event {
114 TextboxEvent::SetValue(val) => {
115 if event.target == entity {
116 entity.set_text(state, &(val.to_owned() + &self.units));
117
118 state.insert_event(Event::new(WindowEvent::Redraw).target(Entity::root()));
123 }
124 }
125
126 TextboxEvent::Clear => {
127 self.text.clear();
128 self.buffer.clear();
129 entity.set_text(state, "");
130 state.insert_event(Event::new(WindowEvent::Redraw).target(Entity::root()));
131 }
132
133 _ => {}
139 }
140 }
141
142 let text_data = state.style.text.get(entity).cloned().unwrap_or_default();
143
144 if let Some(window_event) = event.message.downcast::<WindowEvent>() {
145 match window_event {
146 WindowEvent::MouseMove(x, _) => {
147 if self.hitx != -1.0 {
148 self.dragx = *x;
149
150 state.insert_event(Event::new(WindowEvent::Redraw).target(Entity::root()));
155 }
156 }
157
158 WindowEvent::MouseDown(button) => {
159 if entity == state.hovered {
160 if self.edit == false && !entity.is_disabled(state) {
161 self.cursor_pos = text_data.len() as u32;
162 self.select_pos = 0;
163 self.buffer = text_data.clone();
164 state.capture(entity);
166 entity.set_active(state, true);
168 state.set_focus(entity);
169
170 }
171 if self.edit == true {
172 self.hitx = state.mouse.cursorx;
173 self.dragx = state.mouse.cursorx;
174 }
175 self.edit = true;
176
177 state.insert_event(Event::new(WindowEvent::Redraw).target(Entity::root()));
182 } else {
183
184 self.edit = false;
185 entity.set_active(state, false);
186
187 state.insert_event(
188 Event::new(TextboxEvent::ValueChanged(text_data.clone()))
189 .target(entity),
190 );
191
192 state.insert_event(Event::new(WindowEvent::Redraw).target(Entity::root()));
197
198 if state.captured == entity {
199 state.insert_event(
200 Event::new(WindowEvent::MouseDown(*button)).target(state.hovered),
201 );
202 }
203
204 state.release(entity);
206 }
207 }
208
209 WindowEvent::MouseUp(_) => {
210 self.hitx = -1.0;
211 }
212
213 WindowEvent::KeyDown(_, key) => {
214 if *key == Some(Key::ArrowLeft) {
218 if self.edit {
219 self.hitx = -1.0;
220 if self.cursor_pos > 0 {
221 self.cursor_pos -= 1;
222 }
223 if !state.modifiers.shift {
224 self.select_pos = self.cursor_pos;
225 }
226
227 state.insert_event(
232 Event::new(WindowEvent::Redraw).target(Entity::root()),
233 );
234 }
235 }
236
237 if *key == Some(Key::ArrowRight) {
238 if self.edit {
239 self.hitx = -1.0;
240 if self.cursor_pos < text_data.len() as u32 {
241 self.cursor_pos += 1;
242 }
243 if !state.modifiers.shift {
244 self.select_pos = self.cursor_pos;
245 }
246
247 state.insert_event(
252 Event::new(WindowEvent::Redraw).target(Entity::root()),
253 );
254 }
255 }
256 if *key == Some(Key::Backspace) || *key == Some(Key::Delete) {
257 if self.edit {
258 let start = std::cmp::min(self.select_pos, self.cursor_pos) as usize;
259 let end = std::cmp::max(self.select_pos, self.cursor_pos) as usize;
260
261 if start == end && self.cursor_pos > 0 {
264 if *key == Some(Key::Backspace) {
265 if let Some(txt) = state.style.text.get_mut(entity) {
266 txt.remove((self.cursor_pos - 1) as usize);
267 }
269 self.cursor_pos -= 1;
270 self.select_pos -= 1;
271
272 } else {
273 if (self.cursor_pos as usize) < (self.text.len()) {
274 if let Some(txt) = state.style.text.get_mut(entity) {
275 txt.remove((self.cursor_pos) as usize);
276 }
278 }
279 }
280
281
282
283 } else {
284
285 if let Some(txt) = state.style.text.get_mut(entity) {
286 txt.replace_range(start..end, "");
287 }
288 self.cursor_pos = start as u32;
289 self.select_pos = start as u32;
290 }
291
292 self.text = state.style.text.get(entity).unwrap().to_owned();
293
294 if let Some(callback) = self.on_change.take() {
299 (callback)(self, state, entity);
300 self.on_change = Some(callback);
301 }
302
303 state.insert_event(
304 Event::new(WindowEvent::Redraw).target(Entity::root()),
305 );
306 }
307 }
308 if *key == Some(Key::Enter) {
309 if self.edit {
310 state.insert_event(
312 Event::new(TextboxEvent::ValueChanged(text_data.clone()))
313 .target(entity),
314 );
315
316 if let Some(callback) = self.on_submit.take() {
317 (callback)(self, state, entity);
318 self.on_submit = Some(callback);
319 }
320
321 self.edit = false;
322 entity.set_active(state, false);
323 state.release(entity);
324
325
326 state.insert_event(
327 Event::new(WindowEvent::Redraw).target(Entity::root()),
328 );
329 }
330 }
331 if *key == Some(Key::Escape) {
332 if self.edit {
333 self.text = self.buffer.clone();
334 self.edit = false;
335 entity.set_active(state, false);
336
337 state.insert_event(
348 Event::new(WindowEvent::Redraw).target(Entity::root()),
349 );
350 }
351 }
352 }
353
354 WindowEvent::CharInput(input) => {
355 if *input as u8 != 8 && *input as u8 != 13 && *input as u8 != 127 {
356 if state.modifiers.ctrl {
358 return;
359 }
360 if self.edit {
361 let start = std::cmp::min(self.select_pos, self.cursor_pos) as usize;
363 let end = std::cmp::max(self.select_pos, self.cursor_pos) as usize;
364 if start == end {
367 if let Some(txt) = state.style.text.get_mut(entity) {
368 txt.insert(start, *input);
369 }
370
371 self.cursor_pos += 1;
373 self.select_pos += 1;
374 } else {
375 if let Some(txt) = state.style.text.get_mut(entity) {
376 txt.replace_range(start..end, &input.to_string());
377 }
378 self.cursor_pos = (start + 1) as u32;
379 self.select_pos = (start + 1) as u32;
380 }
381
382 self.text = state.style.text.get(entity).unwrap().to_owned();
383
384 if let Some(callback) = self.on_change.take() {
385 (callback)(self, state, entity);
386 self.on_change = Some(callback);
387 }
388
389 state.insert_event(
394 Event::new(WindowEvent::Redraw).target(Entity::root()),
395 );
396 }
397 }
398 }
399
400 WindowEvent::FocusIn => {
401 if !self.edit {
402 self.cursor_pos = text_data.len() as u32;
403 self.select_pos = 0;
404 self.buffer = text_data.clone();
405 self.edit = true;
406 }
407 }
408
409
410 WindowEvent::FocusOut => {
411 self.edit = false;
412 entity.set_active(state, false);
413
414 state.release(entity);
415
416 state.insert_event(
423 Event::new(WindowEvent::Redraw).target(Entity::root()),
424 );
425 }
426
427 WindowEvent::MouseCaptureOutEvent => {
428 self.edit = false;
430 entity.set_active(state, false);
431 state.insert_event(
440 Event::new(WindowEvent::Redraw).target(Entity::root()),
441 );
442 }
443
444 _ => {}
445 }
446 }
447 }
448
449
450 fn on_update(&mut self, state: &mut State, entity: Entity, data: &Self::Data) {
451 self.text = data.to_string();
452 entity.set_text(state, &self.text);
453 }
454
455 fn on_draw(
456 &mut self,
457 state: &mut State,
458 entity: Entity,
459 canvas: &mut Canvas<OpenGl>,
460 ) {
462 if entity == Entity::root() {
464 return;
465 }
466
467 if state.data.get_visibility(entity) == Visibility::Invisible {
469 return;
471 }
472
473 if state.data.get_opacity(entity) == 0.0 {
475 return;
477 }
478
479 let posx = state.data.get_posx(entity);
480 let posy = state.data.get_posy(entity);
481 let width = state.data.get_width(entity);
482 let height = state.data.get_height(entity);
483
484 let padding_left = match state.style.child_left.get(entity).unwrap_or(&Units::Auto) {
485 Units::Pixels(val) => val,
486 _ => &0.0,
487 };
488
489 let padding_right = match state.style.child_right.get(entity).unwrap_or(&Units::Auto) {
490 Units::Pixels(val) => val,
491 _ => &0.0,
492 };
493
494 let background_color = state
505 .style
506 .background_color
507 .get(entity)
508 .cloned()
509 .unwrap_or_default();
510
511 let font_color = state
512 .style
513 .font_color
514 .get(entity)
515 .cloned()
516 .unwrap_or(crate::Color::rgb(255, 255, 255));
517
518 let border_color = state
519 .style
520 .border_color
521 .get(entity)
522 .cloned()
523 .unwrap_or_default();
524
525 let parent = state
526 .tree
527 .get_parent(entity)
528 .expect("Failed to find parent somehow");
529
530 let parent_width = state.data.get_width(parent);
531 let parent_height = state.data.get_height(parent);
532
533 let border_radius_top_left = match state
534 .style
535 .border_radius_top_left
536 .get(entity)
537 .cloned()
538 .unwrap_or_default()
539 {
540 Units::Pixels(val) => val,
541 Units::Percentage(val) => parent_width * val,
542 _ => 0.0,
543 };
544
545 let border_radius_top_right = match state
546 .style
547 .border_radius_top_right
548 .get(entity)
549 .cloned()
550 .unwrap_or_default()
551 {
552 Units::Pixels(val) => val,
553 Units::Percentage(val) => parent_width * val,
554 _ => 0.0,
555 };
556
557 let border_radius_bottom_left = match state
558 .style
559 .border_radius_bottom_left
560 .get(entity)
561 .cloned()
562 .unwrap_or_default()
563 {
564 Units::Pixels(val) => val,
565 Units::Percentage(val) => parent_width * val,
566 _ => 0.0,
567 };
568
569 let border_radius_bottom_right = match state
570 .style
571 .border_radius_bottom_right
572 .get(entity)
573 .cloned()
574 .unwrap_or_default()
575 {
576 Units::Pixels(val) => val,
577 Units::Percentage(val) => parent_width * val,
578 _ => 0.0,
579 };
580
581 let opacity = state.data.get_opacity(entity);
582
583 let mut background_color: femtovg::Color = background_color.into();
584 background_color.set_alphaf(background_color.a * opacity);
585
586 let mut border_color: femtovg::Color = border_color.into();
587 border_color.set_alphaf(border_color.a * opacity);
588
589 let border_width = match state
590 .style
591 .border_width
592 .get(entity)
593 .cloned()
594 .unwrap_or_default()
595 {
596 Units::Pixels(val) => val,
597 Units::Percentage(val) => parent_width * val,
598 _ => 0.0,
599 };
600
601 if width == 0.0 || height == 0.0 {
603 return;
604 }
605
606 canvas.save();
610
611 canvas.translate(posx, posy);
613
614 let outer_shadow_h_offset = match state
630 .style
631 .outer_shadow_h_offset
632 .get(entity)
633 .cloned()
634 .unwrap_or_default()
635 {
636 Units::Pixels(val) => val,
637 Units::Percentage(val) => parent_width * val,
638 _ => 0.0,
639 };
640
641 let outer_shadow_v_offset = match state
642 .style
643 .outer_shadow_v_offset
644 .get(entity)
645 .cloned()
646 .unwrap_or_default()
647 {
648 Units::Pixels(val) => val,
649 Units::Percentage(val) => parent_height * val,
650 _ => 0.0,
651 };
652
653 let outer_shadow_blur = match state
654 .style
655 .outer_shadow_blur
656 .get(entity)
657 .cloned()
658 .unwrap_or_default()
659 {
660 Units::Pixels(val) => val,
661 Units::Percentage(val) => parent_height * val,
662 _ => 0.0,
663 };
664
665 let outer_shadow_color = state
666 .style
667 .outer_shadow_color
668 .get(entity)
669 .cloned()
670 .unwrap_or_default();
671
672 let mut outer_shadow_color: femtovg::Color = outer_shadow_color.into();
673 outer_shadow_color.set_alphaf(outer_shadow_color.a * opacity);
674
675 let inner_shadow_h_offset = match state
676 .style
677 .inner_shadow_h_offset
678 .get(entity)
679 .cloned()
680 .unwrap_or_default()
681 {
682 Units::Pixels(val) => val,
683 Units::Percentage(val) => parent_width * val,
684 _ => 0.0,
685 };
686
687 let inner_shadow_v_offset = match state
688 .style
689 .inner_shadow_v_offset
690 .get(entity)
691 .cloned()
692 .unwrap_or_default()
693 {
694 Units::Pixels(val) => val,
695 Units::Percentage(val) => parent_height * val,
696 _ => 0.0,
697 };
698
699 let inner_shadow_blur = match state
700 .style
701 .inner_shadow_blur
702 .get(entity)
703 .cloned()
704 .unwrap_or_default()
705 {
706 Units::Pixels(val) => val,
707 Units::Percentage(val) => parent_height * val,
708 _ => 0.0,
709 };
710
711 let inner_shadow_color = state
712 .style
713 .inner_shadow_color
714 .get(entity)
715 .cloned()
716 .unwrap_or_default();
717
718 let mut inner_shadow_color: femtovg::Color = inner_shadow_color.into();
719 inner_shadow_color.set_alphaf(inner_shadow_color.a * opacity);
720
721 let mut path = Path::new();
723 path.rect(
724 0.0 - outer_shadow_blur + outer_shadow_h_offset,
725 0.0 - outer_shadow_blur + outer_shadow_v_offset,
726 width + 2.0 * outer_shadow_blur,
727 height + 2.0 * outer_shadow_blur,
728 );
729 path.rounded_rect_varying(
730 0.0,
731 0.0,
732 width,
733 height,
734 border_radius_top_left,
735 border_radius_top_right,
736 border_radius_bottom_right,
737 border_radius_bottom_left,
738 );
739 path.solidity(Solidity::Hole);
740
741 let paint = Paint::box_gradient(
742 0.0 + outer_shadow_h_offset,
743 0.0 + outer_shadow_v_offset,
744 width,
745 height,
746 border_radius_top_left,
747 outer_shadow_blur,
748 outer_shadow_color,
749 femtovg::Color::rgba(0, 0, 0, 0),
750 );
751
752 canvas.fill_path(&mut path, paint);
753
754 let mut path = Path::new();
755
756 if border_radius_bottom_left == (width - 2.0 * border_width) / 2.0
757 && border_radius_bottom_right == (width - 2.0 * border_width) / 2.0
758 && border_radius_top_left == (width - 2.0 * border_width) / 2.0
759 && border_radius_top_right == (width - 2.0 * border_width) / 2.0
760 {
761 path.circle(
762 0.0 + (border_width / 2.0) + (width - border_width) / 2.0,
763 0.0 + (border_width / 2.0) + (height - border_width) / 2.0,
764 width / 2.0,
765 );
766 } else {
767 path.rounded_rect_varying(
769 0.0 + (border_width / 2.0),
770 0.0 + (border_width / 2.0),
771 width - border_width,
772 height - border_width,
773 border_radius_top_left,
774 border_radius_top_right,
775 border_radius_bottom_right,
776 border_radius_bottom_left,
777 );
778 }
779
780 let mut paint = Paint::color(background_color);
782
783 if let Some(background_gradient) = state.style.background_gradient.get_mut(entity) {
785 let (start_x, start_y, end_x, end_y) = match background_gradient.direction {
786 Direction::LeftToRight => (0.0, 0.0, width, 0.0),
787 Direction::TopToBottom => (0.0, 0.0, 0.0, height),
788 _ => (0.0, 0.0, width, 0.0),
789 };
790
791 paint = Paint::linear_gradient_stops(
792 start_x,
793 start_y,
794 end_x,
795 end_y,
796 background_gradient
797 .get_stops(parent_width)
798 .iter()
799 .map(|stop| {
800 let col: femtovg::Color = stop.1.into();
801 (stop.0, col)
802 })
803 .collect::<Vec<_>>()
804 .as_slice(),
805 );
806 }
807
808 canvas.fill_path(&mut path, paint);
810
811 let mut paint = Paint::color(border_color);
813 paint.set_line_width(border_width);
814 canvas.stroke_path(&mut path, paint);
815
816 let mut path = Path::new();
818 path.rounded_rect_varying(
819 0.0,
820 0.0,
821 width,
822 height,
823 border_radius_top_left,
824 border_radius_top_right,
825 border_radius_bottom_left,
826 border_radius_bottom_right,
827 );
828
829 let paint = Paint::box_gradient(
830 0.0 + inner_shadow_h_offset,
831 0.0 + inner_shadow_v_offset,
832 width,
833 height,
834 border_radius_top_left,
835 inner_shadow_blur,
836 femtovg::Color::rgba(0, 0, 0, 0),
837 inner_shadow_color,
838 );
839 canvas.fill_path(&mut path, paint);
840
841 let mut font_color: femtovg::Color = font_color.into();
842 font_color.set_alphaf(font_color.a * opacity);
843
844 canvas.translate(-posx, -posy);
845 canvas.restore();
846
847 canvas.save();
848 if let Some(text) = state.style.text.get_mut(entity) {
852 let font = state.style.font.get(entity).cloned().unwrap_or_default();
853
854 let font_id = match font.as_ref() {
855 "sans" => state.fonts.regular.unwrap(),
856 "icons" => state.fonts.icons.unwrap(),
857 _ => state.fonts.regular.unwrap(),
858 };
859
860 let mut x = posx;
861 let mut y = posy;
862 let mut sy = posy;
864
865 let text_string = text.to_owned();
866
867 let font_size = state.style.font_size.get(entity).cloned().unwrap_or(16.0);
868
869 let mut paint = Paint::color(font_color);
870 paint.set_font_size(font_size);
871 paint.set_font(&[font_id]);
872
873 let font_metrics = canvas
874 .measure_font(paint)
875 .expect("Failed to read font metrics");
876
877 let child_left = state
879 .style
880 .child_left
881 .get(entity)
882 .cloned()
883 .unwrap_or_default();
884 let child_right = state
885 .style
886 .child_right
887 .get(entity)
888 .cloned()
889 .unwrap_or_default();
890 let child_top = state
891 .style
892 .child_top
893 .get(entity)
894 .cloned()
895 .unwrap_or_default();
896 let child_bottom = state
897 .style
898 .child_bottom
899 .get(entity)
900 .cloned()
901 .unwrap_or_default();
902
903 let align = match child_left {
904 Units::Pixels(val) => match child_right {
905 Units::Stretch(_) => {
906 x += val + border_width;
907 Align::Left
908 }
909
910 _ => Align::Left,
911 },
912
913 Units::Stretch(_) => match child_right {
914 Units::Pixels(val) => {
915 x += width - val - border_width;
916 Align::Right
917 }
918
919 Units::Stretch(_) => {
920 x += 0.5 * width;
921 Align::Center
922 }
923
924 _ => Align::Right,
925 },
926
927 _ => Align::Left,
928 };
929
930 let baseline = match child_top {
931 Units::Pixels(val) => match child_bottom {
932 Units::Stretch(_) => {
933 y += val + border_width;
934 Baseline::Top
935 }
936
937 _ => Baseline::Top,
938 },
939
940 Units::Stretch(_) => match child_bottom {
941 Units::Pixels(val) => {
942 y += height - val - border_width;
943 sy = y - font_metrics.height();
944 Baseline::Bottom
945 }
946
947 Units::Stretch(_) => {
948 y += 0.5 * height;
949 sy = y - font_metrics.height() * 0.5;
950 Baseline::Middle
951 }
952
953 _ => Baseline::Top,
954 },
955
956 _ => Baseline::Top,
957 };
958
959 paint.set_text_align(align);
960 paint.set_text_baseline(baseline);
961
962 if let Ok(res) = canvas.fill_text(x, y, &text_string, paint) {
963 let text_width = res.width();
964 let mut caretx = x;
967
968 let mut selectx = caretx;
969
970 if self.edit {
971 let startx = if let Some(first_glyph) = res.glyphs.first() {
972 first_glyph.x
973 } else {
974 0.0 + padding_right
975 };
976 let endx = startx + text_width;
978
979 if self.hitx != -1.0 {
980 selectx = if self.hitx < startx + text_width / 2.0 {
983 self.select_pos = 0;
984 startx
985 } else {
986 self.select_pos = text.len() as u32;
987 endx
988 };
989
990 caretx = if self.dragx < startx + text_width / 2.0 {
991 self.cursor_pos = 0;
992 startx
993 } else {
994 self.cursor_pos = text.len() as u32;
995 endx
996 };
997
998 let mut n = 0;
999 let mut px = x + padding_left;
1000
1001 for glyph in res.glyphs.iter() {
1002 let left_edge = glyph.x;
1003 let right_edge = left_edge + glyph.width;
1004 let gx = left_edge * 0.3 + right_edge * 0.7;
1005
1006 if self.hitx >= px && self.hitx < gx {
1027 selectx = left_edge;
1028
1029 self.select_pos = n;
1030 }
1031
1032 if self.dragx >= px && self.dragx < gx {
1033 caretx = left_edge;
1034
1035 self.cursor_pos = n;
1036 }
1037
1038 px = gx;
1039 n += 1;
1040 }
1041 } else {
1042 let mut n = 0;
1043 for glyph in res.glyphs.iter() {
1047 if n == self.cursor_pos {
1048 caretx = glyph.x;
1049 }
1050
1051 if n == self.select_pos {
1052 selectx = glyph.x;
1053 }
1054
1055 n += 1;
1056 }
1057
1058 if self.cursor_pos as usize == text.len() && text.len() != 0 {
1059 caretx = endx;
1060 }
1061
1062 if self.select_pos as usize == text.len() && text.len() != 0 {
1063 selectx = endx;
1064 }
1065 }
1066
1067 let select_width = (caretx - selectx).abs();
1069 if selectx > caretx {
1070 let mut path = Path::new();
1071 path.rect(caretx, sy, select_width, font_metrics.height());
1072 canvas.fill_path(&mut path, Paint::color(Color::rgba(0, 0, 0, 64)));
1073 } else if caretx > selectx {
1074 let mut path = Path::new();
1075 path.rect(selectx, sy, select_width, font_metrics.height());
1076 canvas.fill_path(&mut path, Paint::color(Color::rgba(0, 0, 0, 64)));
1077 }
1078
1079 let mut path = Path::new();
1081 path.rect(caretx.floor(), sy, 1.0, font_metrics.height());
1082 canvas.fill_path(&mut path, Paint::color(Color::rgba(247, 76, 0, 255)));
1083
1084 }
1088 }
1089 }
1090 canvas.restore();
1091 }
1092}