use super::{TextElement, TextElementImpl};
use crate::Control;
use ferroui_base::media::text_formatting::{GenericTextRunProperties, TextRun, TextRunProperties};
use ferroui_base::media::{BaselineAlignment, IBrush, TextDecorationCollection, Typeface};
use ferroui_base::{
ferro_class, ferro_property, AttachedProperty, FerroObjectImpl, FerroObjectImplExt, FerroProperty,
FerroPropertyChangedEventArgs, Size, StyledElementImpl, StyledProperty, StyledPropertyOptions,
};
use std::rc::Rc;
#[repr(C)]
pub struct Inline {
base: TextElement,
}
ferro_class! {
Inline: TextElement, virtuals InlineImpl: TextElementImpl {
#[doc(hidden)]
fn build_text_run(this, text_runs: &mut Vec<Rc<dyn TextRun>>);
#[doc(hidden)]
fn measure_embedded_controls(this, block_size: Size) -> bool;
#[doc(hidden)]
fn append_text(this, string_builder: &mut String);
}
}
ferroui_base::ferro_impl_classes!(Inline: StyledElementImpl);
ferroui_base::ferro_impl_classes!(Inline: TextElementImpl);
impl FerroObjectImpl for Inline {
fn on_property_changed(this: &Self, change: &FerroPropertyChangedEventArgs<'_>) {
Self::parent_on_property_changed(this, change);
match change.property().name() {
"TextDecorations" | "BaselineAlignment" => {
if let Some(host) = this.inline_host() {
host.invalidate();
}
}
_ => {}
}
}
}
impl InlineImpl for Inline {
fn build_text_run(_this: &Self, _text_runs: &mut Vec<Rc<dyn TextRun>>) {
panic!("Inline is abstract.")
}
fn measure_embedded_controls(_this: &Self, _block_size: Size) -> bool {
false
}
fn append_text(_this: &Self, _string_builder: &mut String) {
panic!("Inline is abstract.")
}
}
ferroui_base::ferro_properties! { impl Inline {
ferro_property!(
pub fn text_decorations_property() -> AttachedProperty<Option<TextDecorationCollection>> {
FerroProperty::register_attached_with::<Inline, Inline, _>(
"TextDecorations",
StyledPropertyOptions::new(None).inherits(true),
)
}
);
ferro_property!(
pub fn baseline_alignment_property() -> StyledProperty<BaselineAlignment> {
FerroProperty::register::<Inline, _>("BaselineAlignment", BaselineAlignment::Baseline)
}
);
} }
impl Inline {
pub fn construct() -> Self {
Self { base: TextElement::construct() }
}
pub fn text_decorations(&self) -> Option<TextDecorationCollection> {
self.get_value(Self::text_decorations_property())
}
pub fn set_text_decorations(&self, value: Option<TextDecorationCollection>) {
self.set_value(Self::text_decorations_property(), value)
}
pub fn baseline_alignment(&self) -> BaselineAlignment {
self.get_value(Self::baseline_alignment_property())
}
pub fn set_baseline_alignment(&self, value: BaselineAlignment) {
self.set_value(Self::baseline_alignment_property(), value)
}
pub fn get_text_decorations(control: &Control) -> Option<TextDecorationCollection> {
control.get_value(Self::text_decorations_property())
}
pub fn set_text_decorations_on(control: &Control, value: Option<TextDecorationCollection>) {
control.set_value(Self::text_decorations_property(), value)
}
pub fn create_text_run_properties(&self) -> Rc<dyn TextRunProperties> {
let parent_or_self_background = self.background().or_else(|| self.find_parent_background());
let typeface =
Typeface::with_style(self.font_family(), self.font_style(), self.font_weight(), self.font_stretch());
Rc::new(GenericTextRunProperties::with_all(
typeface,
self.font_size(),
self.text_decorations(),
self.foreground(),
parent_or_self_background,
self.baseline_alignment(),
None,
self.font_features(),
))
}
fn find_parent_background(&self) -> Option<Rc<dyn IBrush>> {
let mut parent = self.parent();
while let Some(inline) = parent.and_then(|parent| parent.cast::<Inline>()) {
if let Some(background) = inline.background() {
return Some(background);
}
parent = inline.parent();
}
None
}
}