1use std::any::Any;
2use std::cell::Cell;
3use std::rc::Rc;
4
5use sequoia_core::{Color, Dirty, ImageSource, Point, Rect, RenderList, Size, Vec2, WindowId};
6use sequoia_draw::ShapeCache;
7use sequoia_input::{CursorIcon, Event, EventPhase, Modifiers, PenTool};
8use sequoia_layout::{
9 ContainerStyle, DockStyle, GridPlacement, GridStyle, LayoutCtx, LayoutStyle, MasonryStyle,
10 WrapStyle,
11};
12use sequoia_reactive::Environment;
13use sequoia_style::{BoxStyle, Theme, VisualState};
14use sequoia_text::{
15 ElideMode, FontStyle, FontWeight, LetterSpacing, LineHeight, RichAlign, RichParagraph,
16 ShapedText, TextSpan, TextSystem, WrapMode,
17};
18
19use crate::any::AnyView;
20use crate::dnd::{DragEnd, DragOptions, DragPayload, DragSession, DropPosition};
21use crate::live::Prop;
22use crate::overlay::{OverlayEntry, OverlayId};
23use crate::runtime::{ElementId, Runtime};
24use crate::surface::SurfaceInputBinding;
25
26pub trait View {
27 fn body(&self) -> impl View + 'static;
28
29 #[doc(hidden)]
30 fn is_leaf(&self) -> bool {
31 false
32 }
33
34 #[doc(hidden)]
35 fn children_override(&self) -> Option<Vec<AnyView>> {
36 None
37 }
38
39 #[doc(hidden)]
40 fn keyed_children(&self) -> Option<Vec<(u64, AnyView)>> {
41 None
42 }
43
44 #[doc(hidden)]
45 fn layout_style(&self) -> LayoutStyle {
46 LayoutStyle::default()
47 }
48
49 fn layout_style_ctx(&self, _rt: &Runtime, _el: ElementId) -> LayoutStyle {
50 self.layout_style()
51 }
52
53 #[doc(hidden)]
59 fn signal_dirty(&self) -> Dirty {
60 Dirty::LAYOUT | Dirty::CHILDREN
61 }
62
63 #[doc(hidden)]
64 fn has_visual_state(&self) -> bool {
65 false
66 }
67
68 #[doc(hidden)]
69 fn wants_hover_updates(&self) -> bool {
70 false
71 }
72
73 fn accessibility(&self) -> Option<crate::a11y::Accessible> {
74 None
75 }
76
77 #[doc(hidden)]
78 fn container(&self) -> Option<ContainerStyle> {
79 None
80 }
81
82 #[doc(hidden)]
83 fn grid(&self) -> Option<GridStyle> {
84 None
85 }
86
87 #[doc(hidden)]
88 fn dock(&self) -> Option<DockStyle> {
89 None
90 }
91
92 #[doc(hidden)]
93 fn wrap(&self) -> Option<WrapStyle> {
94 None
95 }
96
97 #[doc(hidden)]
98 fn masonry(&self) -> Option<MasonryStyle> {
99 None
100 }
101
102 #[doc(hidden)]
103 fn flex_weights(&self) -> Option<&[f32]> {
104 None
105 }
106
107 #[doc(hidden)]
108 fn grid_placement(&self) -> Option<GridPlacement> {
109 None
110 }
111
112 #[doc(hidden)]
113 fn grid_placements(&self) -> Option<Vec<GridPlacement>> {
114 None
115 }
116
117 #[doc(hidden)]
118 fn intrinsic_size(&self, _ctx: &mut LayoutCtx) -> Option<Size> {
119 None
120 }
121
122 #[doc(hidden)]
126 fn baseline_offset(&self, _ctx: &mut LayoutCtx, _width: f32) -> Option<f32> {
127 None
128 }
129
130 #[doc(hidden)]
131 fn contain_size(&self) -> bool {
132 false
133 }
134
135 fn arrange_override(
136 &self,
137 _rt: &Runtime,
138 _el: ElementId,
139 _rect: Rect,
140 _ctx: &mut LayoutCtx,
141 ) -> bool {
142 false
143 }
144
145 fn clip_self(&self) -> bool {
146 false
147 }
148
149 fn clip_radius(&self) -> f32 {
150 0.0
151 }
152
153 fn paint_opacity(&self) -> Option<f32> {
154 None
155 }
156
157 fn cache_layer(&self) -> bool {
163 false
164 }
165
166 fn paint_opacity_ctx(&self, _rt: &Runtime, _el: ElementId) -> Option<f32> {
167 self.paint_opacity()
168 }
169
170 fn paint_offset(&self) -> Vec2 {
171 Vec2::ZERO
172 }
173
174 fn paint_offset_ctx(&self, _rt: &Runtime, _el: ElementId) -> Vec2 {
175 self.paint_offset()
176 }
177
178 fn paint_scale(&self) -> f32 {
179 1.0
180 }
181
182 fn paint_scale_ctx(&self, _rt: &Runtime, _el: ElementId) -> f32 {
183 self.paint_scale()
184 }
185
186 fn paint_rotation(&self) -> f32 {
187 0.0
188 }
189
190 fn paint_rotation_ctx(&self, _rt: &Runtime, _el: ElementId) -> f32 {
191 self.paint_rotation()
192 }
193
194 fn foreground_filter(&self) -> Option<sequoia_style::Filter> {
195 None
196 }
197
198 #[doc(hidden)]
199 fn surface_target(&self) -> Option<Rc<dyn Any>> {
200 None
201 }
202
203 #[doc(hidden)]
204 fn surface_input(&self) -> Option<SurfaceInputBinding> {
205 None
206 }
207
208 #[doc(hidden)]
209 fn on_event(&self, _event: &Event, _ctx: &mut EventCtx) {}
210
211 #[doc(hidden)]
212 fn captures_pointer(&self) -> bool {
213 false
214 }
215
216 fn captures_pointer_ctx(&self, _rt: &Runtime, _el: ElementId) -> bool {
217 self.captures_pointer()
218 }
219
220 fn reuse_state(&self, _old: &Self) {}
221
222 fn hit_testable(&self) -> bool {
223 true
224 }
225
226 fn test_id(&self) -> Option<String> {
227 None
228 }
229
230 #[doc(hidden)]
231 fn focusable(&self) -> bool {
232 false
233 }
234
235 fn focus_trap(&self) -> bool {
236 false
237 }
238
239 fn accepts_tab(&self) -> bool {
240 false
241 }
242
243 fn accepts_text_input(&self) -> bool {
249 false
250 }
251
252 fn ime_caret_rect(&self) -> Option<Rect> {
257 None
258 }
259
260 #[doc(hidden)]
261 fn cursor_icon(&self, _state: VisualState) -> CursorIcon {
262 CursorIcon::Default
263 }
264
265 #[doc(hidden)]
266 fn paint_self(&self, _ctx: &mut PaintCtx) {}
267
268 fn paint_foreground(&self, _ctx: &mut PaintCtx) {}
269
270 fn accepts_drop(&self, _payload: &DragPayload) -> bool {
271 false
272 }
273
274 fn on_drag_over(&self, _pos: DropPosition, _ctx: &mut EventCtx) {}
275
276 fn on_drop(&self, _pos: DropPosition, _ctx: &mut EventCtx) {}
277
278 fn on_drag_start(&self, _ctx: &mut EventCtx) {}
279
280 fn on_drag_end(&self, _end: DragEnd, _ctx: &mut EventCtx) {}
281
282 #[doc(hidden)]
283 fn on_mount(&self) {}
284
285 #[doc(hidden)]
286 fn on_unmount(&self) {}
287}
288
289pub struct EventCtx<'a> {
290 pub phase: EventPhase,
291 pub element: ElementId,
292 pub state: VisualState,
293 pub hover_self: bool,
294 pub pos: Point,
295 pub rect: Rect,
296 pub environment: &'a Environment,
297 pub window: WindowId,
298 pub(crate) stopped: &'a Cell<bool>,
299 pub(crate) handled: &'a Cell<bool>,
300 pub(crate) capture_req: &'a Cell<Option<ElementId>>,
301 pub(crate) release_req: &'a Cell<bool>,
302 pub(crate) focus_req: &'a Cell<bool>,
303 pub(crate) text: &'a mut TextSystem,
304 pub(crate) runtime: &'a Runtime,
305}
306
307impl EventCtx<'_> {
308 pub fn local_pos(&self) -> Point {
309 Point::new(self.pos.x - self.rect.left(), self.pos.y - self.rect.top())
310 }
311
312 pub fn stop_propagation(&mut self) {
313 self.stopped.set(true);
314 }
315
316 pub fn handled(&mut self) {
317 self.handled.set(true);
318 self.stopped.set(true);
319 }
320
321 pub fn capture_pointer(&mut self) {
322 self.capture_req.set(Some(self.element));
323 self.release_req.set(false);
324 }
325
326 pub fn release_pointer(&mut self) {
327 self.release_req.set(true);
328 self.capture_req.set(None);
329 }
330
331 pub fn request_focus(&mut self) {
332 self.focus_req.set(true);
333 }
334
335 pub fn begin_drag<T: 'static>(&self, payload: T, options: DragOptions) {
336 self.runtime.begin_pending(
337 self.element,
338 DragPayload::new(payload),
339 self.pos,
340 self.rect,
341 options,
342 );
343 }
344
345 pub fn drag_session(&self) -> Option<DragSession> {
346 self.runtime.current_drag()
347 }
348
349 pub fn drop_position(&self, modifiers: Modifiers) -> DropPosition {
350 DropPosition::in_rect(self.pos, self.rect, modifiers)
351 }
352
353 pub fn cancel_drag(&mut self) {
354 self.runtime.cancel_drag(&mut *self.text);
355 }
356
357 pub fn pressure(&self) -> f32 {
358 self.runtime.pointer_pressure()
359 }
360
361 pub fn tool(&self) -> PenTool {
362 self.runtime.pointer_tool()
363 }
364
365 pub fn text_width(&mut self, text: &str, size: f32) -> f32 {
366 self.text.text_width(text, size)
367 }
368
369 pub fn text_width_weighted(&mut self, text: &str, size: f32, weight: FontWeight) -> f32 {
370 self.text.text_width_weighted(text, size, weight)
371 }
372
373 pub fn text_width_weighted_spaced(
374 &mut self,
375 text: &str,
376 size: f32,
377 weight: FontWeight,
378 spacing: LetterSpacing,
379 ) -> f32 {
380 self.text
381 .text_width_weighted_spaced(text, size, weight, spacing)
382 }
383
384 pub fn caret_positions(&mut self, text: &str, size: f32, weight: FontWeight) -> Vec<f32> {
385 self.text.caret_positions(text, size, weight)
386 }
387
388 pub fn caret_positions_spaced(
389 &mut self,
390 text: &str,
391 size: f32,
392 weight: FontWeight,
393 spacing: LetterSpacing,
394 ) -> Vec<f32> {
395 self.text
396 .caret_positions_spaced(text, size, weight, spacing)
397 }
398
399 pub fn char_index_from_x(
400 &mut self,
401 text: &str,
402 size: f32,
403 weight: FontWeight,
404 x: f32,
405 ) -> usize {
406 self.text.char_index_from_x(text, size, weight, x)
407 }
408
409 pub fn char_index_from_x_spaced(
410 &mut self,
411 text: &str,
412 size: f32,
413 weight: FontWeight,
414 x: f32,
415 spacing: LetterSpacing,
416 ) -> usize {
417 self.text
418 .char_index_from_x_spaced(text, size, weight, x, spacing)
419 }
420
421 pub fn shape_rich_full(
422 &mut self,
423 spans: &[TextSpan],
424 size: f32,
425 width: f32,
426 mode: WrapMode,
427 spacing: LetterSpacing,
428 align: RichAlign,
429 ) -> std::rc::Rc<RichParagraph> {
430 self.text
431 .shape_rich_full(spans, size, width, mode, spacing, align)
432 }
433
434 pub fn request_frame(&self) {
435 self.runtime.request_frame();
436 }
437
438 pub fn hide_overlay(&self, id: OverlayId) -> bool {
439 self.runtime.overlay_hide(id)
440 }
441
442 pub fn has_overlay(&self, id: OverlayId) -> bool {
443 self.runtime.overlay_exists(id)
444 }
445
446 pub fn overlay_rect(&self, id: OverlayId) -> Option<Rect> {
447 self.runtime.overlay_rect(id)
448 }
449
450 pub fn overlay_set_position(&self, id: OverlayId, x: f32, y: f32) -> bool {
451 self.runtime.overlay_set_position(id, x, y)
452 }
453
454 pub fn has_focus_within(&self) -> bool {
455 self.runtime.focus_in_subtree(self.element)
456 }
457
458 pub fn window_rect(&self) -> Rect {
459 self.runtime.window_rect()
460 }
461
462 pub fn window_size(&self) -> Size {
463 self.runtime.window_size_value()
464 }
465
466 pub fn scale(&self) -> f32 {
467 self.runtime.scale()
468 }
469
470 pub fn safe_insets(&self) -> sequoia_core::Edges {
471 self.runtime.safe_insets()
472 }
473
474 pub fn runtime(&self) -> &Runtime {
475 self.runtime
476 }
477
478 pub fn element(&self) -> ElementId {
479 self.element
480 }
481}
482
483#[derive(Clone, Copy, Debug, Default, PartialEq)]
484pub struct TextMetrics {
485 pub width: f32,
488
489 pub height: f32,
492
493 pub ascent: f32,
495
496 pub descent: f32,
498
499 pub line_gap: f32,
502}
503
504fn metrics_from_shaped(shaped: &ShapedText) -> TextMetrics {
505 let line_height = shaped.line_height();
506 let ascent = shaped.first_baseline();
507 TextMetrics {
508 width: shaped.width(),
509 height: shaped.height(),
510 ascent,
511 descent: (line_height - ascent).max(0.0),
512 line_gap: 0.0,
513 }
514}
515
516pub struct PaintCtx<'a> {
517 pub(crate) list: &'a mut RenderList,
518 pub(crate) text: &'a mut TextSystem,
519
520 pub environment: &'a Environment,
521
522 pub rect: Rect,
523
524 pub element: ElementId,
525
526 pub state: VisualState,
527
528 pub window: WindowId,
529
530 pub hovered_subtree: bool,
531 pub(crate) runtime: &'a Runtime,
532
533 pub(crate) shapes: &'a ShapeCache,
534
535 pub(crate) draw_offset: Vec2,
536
537 pub(crate) offset_stack: Vec<Vec2>,
538}
539
540impl PaintCtx<'_> {
541 pub fn theme(&self) -> Theme {
542 self.environment.get::<Theme>().unwrap_or_else(Theme::dark)
543 }
544
545 pub fn runtime(&self) -> &Runtime {
546 self.runtime
547 }
548
549 pub fn window_rect(&self) -> Rect {
550 self.runtime.window_rect()
551 }
552
553 pub fn window_size(&self) -> Size {
554 self.runtime.window_size_value()
555 }
556
557 pub fn scale(&self) -> f32 {
558 self.runtime.scale()
559 }
560
561 pub fn safe_insets(&self) -> sequoia_core::Edges {
562 self.runtime.safe_insets()
563 }
564
565 pub fn element(&self) -> ElementId {
566 self.element
567 }
568
569 pub fn measure_text(&mut self, text: &str, size: f32) -> TextMetrics {
571 if text.is_empty() || !(size > 0.0) {
572 return TextMetrics::default();
573 }
574 let shaped = self.text.shape(text, size);
575 metrics_from_shaped(&shaped)
576 }
577
578 pub fn text_metrics(&mut self, size: f32) -> TextMetrics {
584 if !(size > 0.0) {
585 return TextMetrics::default();
586 }
587 let shaped = self.text.shape("Mg", size);
588 TextMetrics {
589 width: 0.0,
590 ..metrics_from_shaped(&shaped)
591 }
592 }
593
594 pub fn baseline_centered(rect_top: f32, rect_h: f32, size: f32) -> f32 {
599 rect_top + rect_h * 0.5 + size * 0.35
600 }
601
602 pub fn baseline_top(rect_top: f32, size: f32) -> f32 {
606 rect_top + size * 1.35 * 0.5 + size * 0.35
607 }
608
609 pub fn quad(&mut self, rect: Rect, color: Color, radius: f32) {
610 let rect = if rect.is_empty() {
611 Rect::from_xywh(rect.origin.x, rect.origin.y, 1.0, 1.0)
612 } else {
613 rect
614 };
615 self.list.push_quad(rect, color, radius);
616 }
617
618 pub fn bordered_quad(
619 &mut self,
620 rect: Rect,
621 background: Color,
622 radius: f32,
623 border_width: f32,
624 border_color: Color,
625 ) {
626 self.list
627 .push_bordered_quad(rect, background, radius, border_width, border_color);
628 }
629
630 pub fn paint_box(&mut self, style: BoxStyle) {
631 let rect = self.rect;
632 self.paint_box_in(style, rect);
633 }
634
635 pub fn paint_box_in(&mut self, style: BoxStyle, rect: Rect) {
636 style.paint(self.list, rect);
637 }
638
639 pub fn push_clip(&mut self, rect: Rect) {
640 self.list.push_clip(rect);
641 }
642 pub fn pop_clip(&mut self) {
643 self.list.pop_clip();
644 }
645 pub fn push_rounded_clip(&mut self, rect: Rect, radius: f32) {
646 self.list.push_rounded_clip(rect, radius);
647 }
648
649 pub fn list_clip_depth(&self) -> usize {
650 self.list.clip_depth()
651 }
652
653 pub fn push_backdrop(&mut self, rect: Rect, backdrop: sequoia_style::Backdrop) {
654 if backdrop.is_empty() {
655 return;
656 }
657 self.list.push_backdrop(
658 rect,
659 backdrop.radius,
660 backdrop.blur_px(),
661 backdrop.dim,
662 backdrop.noise,
663 backdrop.span_mask(),
664 );
665 }
666
667 pub fn draw_text(&mut self, text: &str, origin: (f32, f32), size: f32, color: Color) {
673 self.draw_text_weighted(text, origin, size, FontWeight::NORMAL, color);
674 }
675
676 pub fn draw_text_tl(&mut self, text: &str, top_left: (f32, f32), size: f32, color: Color) {
681 if text.is_empty() || !(size > 0.0) {
682 return;
683 }
684 let ascent = self.text_metrics(size).ascent;
685 self.draw_text(text, (top_left.0, top_left.1 + ascent), size, color);
686 }
687
688 pub fn draw_text_weighted(
689 &mut self,
690 text: &str,
691 origin: (f32, f32),
692 size: f32,
693 weight: FontWeight,
694 color: Color,
695 ) {
696 let shaped = self.text.shape_weighted(text, size, weight);
697 self.text.draw(&shaped, origin, color, self.list);
698 }
699
700 pub fn draw_text_wrapped(
701 &mut self,
702 text: &str,
703 origin: (f32, f32),
704 size: f32,
705 weight: FontWeight,
706 width: f32,
707 mode: WrapMode,
708 color: Color,
709 ) {
710 self.draw_text_wrapped_spaced(text, origin, size, weight, width, mode, 0.0, color);
711 }
712
713 pub fn draw_text_wrapped_spaced(
714 &mut self,
715 text: &str,
716 origin: (f32, f32),
717 size: f32,
718 weight: FontWeight,
719 width: f32,
720 mode: WrapMode,
721 spacing: LetterSpacing,
722 color: Color,
723 ) {
724 let shaped = self
725 .text
726 .shape_wrapped_spaced(text, size, weight, width, mode, spacing);
727 self.text.draw(&shaped, origin, color, self.list);
728 }
729
730 pub fn draw_text_spaced(
731 &mut self,
732 text: &str,
733 origin: (f32, f32),
734 size: f32,
735 spacing: LetterSpacing,
736 color: Color,
737 ) {
738 self.draw_text_weighted_spaced(text, origin, size, FontWeight::NORMAL, spacing, color);
739 }
740
741 pub fn draw_text_weighted_spaced(
742 &mut self,
743 text: &str,
744 origin: (f32, f32),
745 size: f32,
746 weight: FontWeight,
747 spacing: LetterSpacing,
748 color: Color,
749 ) {
750 let shaped = self.text.shape_spaced(text, size, weight, spacing);
751 self.text.draw(&shaped, origin, color, self.list);
752 }
753
754 pub fn draw_text_styled_spaced(
755 &mut self,
756 text: &str,
757 origin: (f32, f32),
758 size: f32,
759 weight: FontWeight,
760 spacing: LetterSpacing,
761 family: Option<&str>,
762 style: FontStyle,
763 color: Color,
764 ) {
765 let shaped = self
766 .text
767 .shape_spaced_styled(text, size, weight, spacing, family, style);
768 self.text.draw(&shaped, origin, color, self.list);
769 }
770
771 pub fn draw_text_wrapped_styled_spaced(
772 &mut self,
773 text: &str,
774 origin: (f32, f32),
775 size: f32,
776 weight: FontWeight,
777 width: f32,
778 mode: WrapMode,
779 spacing: LetterSpacing,
780 family: Option<&str>,
781 style: FontStyle,
782 color: Color,
783 ) {
784 let shaped = self
785 .text
786 .shape_wrapped_styled_spaced(text, size, weight, width, mode, spacing, family, style);
787 self.text.draw(&shaped, origin, color, self.list);
788 }
789
790 #[allow(clippy::too_many_arguments)]
791 pub fn shape_wrapped_styled_spaced_lh(
792 &mut self,
793 text: &str,
794 size: f32,
795 weight: FontWeight,
796 width: f32,
797 mode: WrapMode,
798 spacing: LetterSpacing,
799 family: Option<&str>,
800 style: FontStyle,
801 line_height: LineHeight,
802 ) -> Rc<ShapedText> {
803 self.text.shape_wrapped_styled_spaced_lh(
804 text,
805 size,
806 weight,
807 width,
808 mode,
809 spacing,
810 family,
811 style,
812 line_height,
813 )
814 }
815
816 pub fn draw_shaped(&mut self, shaped: &ShapedText, origin: (f32, f32), color: Color) {
817 self.text.draw(shaped, origin, color, self.list);
818 }
819
820 #[allow(clippy::too_many_arguments)]
821 pub fn shape_rich_full_lh(
822 &mut self,
823 spans: &[TextSpan],
824 size: f32,
825 width: f32,
826 mode: WrapMode,
827 spacing: LetterSpacing,
828 align: RichAlign,
829 line_height: LineHeight,
830 ) -> Rc<RichParagraph> {
831 self.text
832 .shape_rich_full_lh(spans, size, width, mode, spacing, align, line_height)
833 }
834
835 #[allow(clippy::too_many_arguments)]
836 pub fn elide_lines_styled_spaced(
837 &mut self,
838 text: &str,
839 size: f32,
840 weight: FontWeight,
841 width: f32,
842 mode: WrapMode,
843 spacing: LetterSpacing,
844 family: Option<&str>,
845 style: FontStyle,
846 line_height: LineHeight,
847 max_lines: usize,
848 ) -> String {
849 self.text.elide_lines_styled_spaced(
850 text,
851 size,
852 weight,
853 width,
854 mode,
855 spacing,
856 family,
857 style,
858 line_height,
859 max_lines,
860 )
861 }
862
863 #[allow(clippy::too_many_arguments)]
864 pub fn elide_rich_lines(
865 &mut self,
866 spans: &[TextSpan],
867 size: f32,
868 width: f32,
869 mode: WrapMode,
870 spacing: LetterSpacing,
871 align: RichAlign,
872 line_height: LineHeight,
873 max_lines: usize,
874 ) -> Vec<TextSpan> {
875 self.text.elide_rich_lines(
876 spans,
877 size,
878 width,
879 mode,
880 spacing,
881 align,
882 line_height,
883 max_lines,
884 )
885 }
886
887 pub fn draw_rich(&mut self, rich: &RichParagraph, origin: (f32, f32), default_color: Color) {
888 self.text.draw_rich(rich, origin, default_color, self.list);
889 }
890
891 pub fn draw_rich_spans(
892 &mut self,
893 spans: &[TextSpan],
894 origin: (f32, f32),
895 size: f32,
896 width: f32,
897 mode: WrapMode,
898 spacing: LetterSpacing,
899 align: RichAlign,
900 default_color: Color,
901 ) {
902 let rich = self
903 .text
904 .shape_rich_full(spans, size, width, mode, spacing, align);
905 self.text.draw_rich(&rich, origin, default_color, self.list);
906 }
907
908 pub fn text_width(&mut self, text: &str, size: f32) -> f32 {
909 self.text.shape(text, size).width()
910 }
911
912 pub fn text_width_weighted(&mut self, text: &str, size: f32, weight: FontWeight) -> f32 {
913 self.text.shape_weighted(text, size, weight).width()
914 }
915
916 pub fn text_width_weighted_spaced(
917 &mut self,
918 text: &str,
919 size: f32,
920 weight: FontWeight,
921 spacing: LetterSpacing,
922 ) -> f32 {
923 self.text.shape_spaced(text, size, weight, spacing).width()
924 }
925
926 pub fn text_width_styled_spaced(
927 &mut self,
928 text: &str,
929 size: f32,
930 weight: FontWeight,
931 spacing: LetterSpacing,
932 family: Option<&str>,
933 style: FontStyle,
934 ) -> f32 {
935 self.text
936 .text_width_styled_spaced(text, size, weight, spacing, family, style)
937 }
938
939 pub fn elide_spaced(
940 &mut self,
941 text: &str,
942 size: f32,
943 weight: FontWeight,
944 max_width: f32,
945 mode: ElideMode,
946 spacing: LetterSpacing,
947 ) -> String {
948 self.text
949 .elide_spaced(text, size, weight, max_width, mode, spacing)
950 }
951
952 pub fn elide_styled_spaced(
953 &mut self,
954 text: &str,
955 size: f32,
956 weight: FontWeight,
957 max_width: f32,
958 mode: ElideMode,
959 spacing: LetterSpacing,
960 family: Option<&str>,
961 style: FontStyle,
962 ) -> String {
963 self.text
964 .elide_styled_spaced(text, size, weight, max_width, mode, spacing, family, style)
965 }
966
967 pub fn caret_positions(&mut self, text: &str, size: f32, weight: FontWeight) -> Vec<f32> {
968 self.text.caret_positions(text, size, weight)
969 }
970
971 pub fn caret_positions_spaced(
972 &mut self,
973 text: &str,
974 size: f32,
975 weight: FontWeight,
976 spacing: LetterSpacing,
977 ) -> Vec<f32> {
978 self.text
979 .caret_positions_spaced(text, size, weight, spacing)
980 }
981
982 pub fn shape_rich_full(
983 &mut self,
984 spans: &[TextSpan],
985 size: f32,
986 width: f32,
987 mode: WrapMode,
988 spacing: LetterSpacing,
989 align: RichAlign,
990 ) -> std::rc::Rc<RichParagraph> {
991 self.text
992 .shape_rich_full(spans, size, width, mode, spacing, align)
993 }
994
995 pub fn scale_factor(&self) -> f32 {
996 self.text.scale_factor()
997 }
998
999 pub fn request_frame(&self) {
1000 self.runtime.request_frame();
1001 }
1002
1003 pub fn live_color_exp(&self, prop: Prop, target: Color, rate: f32) -> Color {
1004 self.runtime
1005 .live_color_exp(self.element, prop, target, rate)
1006 .0
1007 }
1008
1009 pub fn draw_sprite(
1010 &mut self,
1011 key: u64,
1012 width: u32,
1013 height: u32,
1014 alpha: &[u8],
1015 rect: Rect,
1016 color: Color,
1017 ) {
1018 self.text
1019 .draw_sprite(key, width, height, alpha, rect, color, self.list);
1020 }
1021
1022 pub fn image(&mut self, rect: Rect, uv: [f32; 4], source: ImageSource) {
1023 self.list.push_image(rect, uv, source);
1024 }
1025
1026 pub fn show_overlay(&self, entry: OverlayEntry) -> OverlayId {
1027 self.runtime.overlay_show(entry.owned_by(self.element))
1028 }
1029
1030 pub fn hide_overlay(&self, id: OverlayId) -> bool {
1031 self.runtime.overlay_hide(id)
1032 }
1033
1034 pub fn has_overlay(&self, id: OverlayId) -> bool {
1035 self.runtime.overlay_exists(id)
1036 }
1037
1038 pub fn overlay_rect(&self, id: OverlayId) -> Option<Rect> {
1039 self.runtime.overlay_rect(id)
1040 }
1041
1042 pub fn drag_session(&self) -> Option<DragSession> {
1043 self.runtime.current_drag()
1044 }
1045
1046 pub fn is_drag_target(&self) -> bool {
1047 self.runtime.drag_target_contains(self.element)
1048 }
1049
1050 pub fn has_focus_within(&self) -> bool {
1051 self.runtime.focus_in_subtree(self.element)
1052 }
1053}
1054
1055pub trait CustomLayout {
1056 fn arrange(&self, rt: &Runtime, el: ElementId, rect: Rect, ctx: &mut LayoutCtx) -> bool;
1057}