1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
use std::borrow::{Borrow, Cow}; use std::fmt::Debug; use std::num::NonZeroI16; use tuifw_screen_base::{Vector, Point, Rect}; use tuifw_window::{RenderPort}; use dep_obj::{dep_type, DepObjBuilderCore}; use dyn_context::{Context, ContextExt}; use crate::view::base::*; use unicode_width::UnicodeWidthChar; use unicode_segmentation::UnicodeSegmentation; pub trait ViewBuilderLabelDecoratorExt { fn label_decorator( self, f: impl for<'a> FnOnce(LabelDecoratorBuilder<'a>) -> LabelDecoratorBuilder<'a> ) -> Self; } impl<'a> ViewBuilderLabelDecoratorExt for ViewBuilder<'a> { fn label_decorator( mut self, f: impl for<'b> FnOnce(LabelDecoratorBuilder<'b>) -> LabelDecoratorBuilder<'b> ) -> Self { let view = self.id(); let tree: &mut ViewTree = self.context_mut().get_mut(); LabelDecorator::new(tree, view); f(LabelDecoratorBuilder::new_priv(self)).core_priv() } } dep_type! { #[derive(Debug)] pub struct LabelDecorator become decorator in View { text: Cow<'static, str> = Cow::Borrowed(""), } type BuilderCore<'a> = ViewBuilder<'a>; } impl LabelDecorator { const BEHAVIOR: LabelDecoratorBehavior = LabelDecoratorBehavior; #[allow(clippy::new_ret_no_self)] pub fn new( tree: &mut ViewTree, view: View, ) { view.set_decorator(tree, LabelDecorator::new_priv()); view.decorator_on_changed(tree, LabelDecorator::TEXT, Self::invalidate_measure); } fn invalidate_measure<T>(context: &mut dyn Context, view: View, _old: &T) { let tree: &mut ViewTree = context.get_mut(); view.invalidate_measure(tree); } } impl Decorator for LabelDecorator { fn behavior(&self) -> &'static dyn DecoratorBehavior { &Self::BEHAVIOR } } struct LabelDecoratorBehavior; impl DecoratorBehavior for LabelDecoratorBehavior { fn children_measure_size( &self, _view: View, _tree: &mut ViewTree, _measure_size: (Option<i16>, Option<i16>) ) -> (Option<i16>, Option<i16>) { (Some(0), Some(0)) } fn desired_size(&self, view: View, tree: &mut ViewTree, _children_desired_size: Vector) -> Vector { let text: &str = view.decorator_get(tree, LabelDecorator::TEXT).borrow(); let width = text .graphemes(true) .map(|g| g .chars() .find_map(|c| NonZeroI16::new(c.width().unwrap_or(1) as u16 as i16)) .map_or(0, |x| x.get()) ) .sum(); Vector { x: width, y: 1 } } fn children_arrange_bounds(&self, _view: View, _tree: &mut ViewTree, _arrange_size: Vector) -> Rect { Rect { tl: Point { x: 0, y: 0}, size: Vector::null() } } fn render_bounds(&self, view: View, tree: &mut ViewTree, _children_render_bounds: Rect) -> Rect { let text: &str = view.decorator_get(tree, LabelDecorator::TEXT).borrow(); let width = text .graphemes(true) .map(|g| g .chars() .find_map(|c| NonZeroI16::new(c.width().unwrap_or(1) as u16 as i16)) .map_or(0, |x| x.get()) ) .sum(); Rect { tl: Point { x: 0, y: 0 }, size: Vector { x: width, y: 1 } } } fn render(&self, view: View, tree: &ViewTree, port: &mut RenderPort) { let text: &str = view.decorator_get(tree, LabelDecorator::TEXT).borrow(); let fg = view.actual_fg(tree); let bg = view.actual_bg(tree); let attr = view.actual_attr(tree); port.out(Point { y: 0, x: 0 }, fg, bg, attr, text); } }