use crate as deft;
use crate::base::Rect;
use crate::element::{Element, ElementBackend, ElementWeak};
use crate::event::TextUpdateEvent;
use crate::mrc::Mrc;
use crate::ok_or_return;
use crate::render::RenderFn;
use crate::style::StylePropKey;
use crate::text::textbox::{TextBox, TextElement, TextUnit};
use crate::text::TextAlign;
use deft_macros::{element_backend, js_methods};
use yoga::Size;
pub fn parse_align(align: &str) -> TextAlign {
match align {
"left" => TextAlign::Left,
"right" => TextAlign::Right,
"center" => TextAlign::Center,
_ => TextAlign::Left,
}
}
#[element_backend]
pub struct Label {
text: String,
state: Mrc<LabelState>,
element: ElementWeak,
}
struct LabelState {
text_box: TextBox,
layout_calculated: bool,
}
#[js_methods]
impl Label {
#[js_func]
pub fn set_text(&mut self, text: String) {
let old_text = self.get_text();
if old_text != text {
self.text = text.clone();
self.state.text_box.clear();
let text_unit = self.build_text_unit(text.clone());
self.state
.text_box
.add_line(vec![TextElement::Text(text_unit)]);
self.mark_dirty(true);
self.element.emit(TextUpdateEvent { value: text })
}
}
#[js_func]
pub fn get_text(&self) -> String {
self.text.clone()
}
fn mark_dirty(&mut self, layout_dirty: bool) {
self.element.mark_dirty(layout_dirty);
}
fn build_text_unit(&self, text: String) -> TextUnit {
TextUnit {
text,
font_families: None,
font_size: None,
color: None,
text_decoration_line: None,
weight: None,
background_color: None,
style: None,
}
}
}
impl ElementBackend for Label {
fn create(ele: &mut Element) -> Self {
let text = "".to_string();
let state = LabelState {
text_box: TextBox::new(),
layout_calculated: false,
};
let label = LabelData {
text,
state: Mrc::new(state),
element: ele.as_weak(),
}
.to_ref();
ele.style
.yoga_node
.set_measure_func(label.state.clone(), |state, params| {
state.text_box.set_layout_width(params.width);
state.text_box.layout();
state.layout_calculated = true;
let width = state.text_box.max_intrinsic_width();
let height = state.text_box.height();
return Size { width, height };
});
label
}
fn get_base_mut(&mut self) -> Option<&mut dyn ElementBackend> {
None
}
fn handle_style_changed(&mut self, key: StylePropKey) {
let element = ok_or_return!(self.element.upgrade());
match key {
StylePropKey::Color => {
let color = element.style.color;
self.state.text_box.set_color(color);
self.mark_dirty(true);
}
StylePropKey::FontSize => {
let font_size = element.style.font_size;
self.state.text_box.set_font_size(font_size);
self.mark_dirty(true);
}
StylePropKey::FontFamily => {
let font_families = element.style.font_family.clone();
self.state.text_box.set_font_families(font_families);
self.mark_dirty(true);
}
StylePropKey::FontWeight => {
let font_weight = element.style.font_weight;
self.state.text_box.set_font_weight(font_weight);
self.mark_dirty(true);
}
StylePropKey::FontStyle => {
let font_style = element.style.font_style.clone();
self.state.text_box.set_font_style(font_style);
self.mark_dirty(true);
}
StylePropKey::LineHeight => {
let line_height = element.style.line_height;
self.state.text_box.set_line_height(line_height);
self.mark_dirty(true);
}
_ => {}
}
}
fn render(&mut self) -> RenderFn {
let el = ok_or_return!(self.element.upgrade(), RenderFn::empty());
let (pt, _, _, pl) = el.get_padding();
let text_renderer = self.state.text_box.render();
RenderFn::new(move |painter| {
painter.canvas.translate((pl, pt));
text_renderer.run(painter);
})
}
fn before_layout(&mut self) {
self.state.layout_calculated = false;
}
fn handle_origin_bounds_change(&mut self, bounds: &Rect) {
if !self.state.layout_calculated {
self.state.text_box.set_layout_width(bounds.width);
self.state.text_box.layout();
self.state.layout_calculated = true;
}
}
}