fui_core 0.19.2

Core library of FUI MVVM UI Framework
Documentation
use crate::events::ControlEvent;
use crate::FuiDrawingContext;
use std::any::Any;
use std::cell::RefCell;
use std::rc::Rc;

use crate::common::*;
use crate::control::*;
use crate::observable::*;
use crate::style::*;
use crate::{view::ViewContext, EventContext};

pub struct StyledControl<D> {
    pub data: RefCell<D>,
    pub style: RefCell<Box<dyn Style<D>>>,
    pub control_context: ControlContext,
}

impl<D: 'static> StyledControl<D> {
    pub fn new(data: D, style: Box<dyn Style<D>>, view_context: ViewContext) -> Rc<Self> {
        let control = Rc::new(StyledControl {
            data: RefCell::new(data),
            style: RefCell::new(style),
            control_context: ControlContext::new(view_context),
        });

        // set self
        let control_weak = Rc::downgrade(&control);
        control.control_context.set_self(control_weak);

        let control_clone: Rc<dyn ControlObject> = control.clone();
        let handler = Box::new(move |changed_args: VecDiff<Rc<dyn ControlObject>>| {
            match changed_args {
                VecDiff::Clear { values } => {
                    for child in values {
                        child.get_context().detach_tree();
                    }
                }
                VecDiff::InsertAt { index: _, value } => {
                    // dynamically created controls require to set services
                    let services = control_clone.get_context().get_services();
                    value.get_context().set_services(services);

                    value.get_context().set_parent(&control_clone);
                }
                VecDiff::RemoveAt { index: _, value } => {
                    value.get_context().detach_tree();
                }
                VecDiff::Move {
                    old_index: _,
                    new_index: _,
                } => {}
                VecDiff::Pop { value } => {
                    value.get_context().detach_tree();
                }
                VecDiff::Push { value } => {
                    // dynamically created controls require to set services
                    let services = control_clone.get_context().get_services();
                    value.get_context().set_services(services);

                    value.get_context().set_parent(&control_clone);
                }
            };

            control_clone.get_context().set_is_dirty(true);
        });
        let subscription = control.get_context().get_children().on_changed(handler);

        control
            .get_context()
            .set_children_collection_changed_event_subscription(subscription);

        for child in control.get_context().get_children().into_iter() {
            let control: Rc<dyn ControlObject> = control.clone();

            child.get_context().set_parent(&control);
        }

        control.setup();

        control
    }

    pub fn get_context(&self) -> &ControlContext {
        &self.control_context
    }
}

impl<D: 'static> ControlObject for StyledControl<D> {
    fn as_any(&self) -> &dyn Any {
        self
    }

    fn get_context(&self) -> &ControlContext {
        self.get_context()
    }
}

impl<D: 'static> ControlBehavior for StyledControl<D> {
    fn setup(&self) {
        self.control_context.dirty_watch_attached_properties();
        self.style
            .borrow_mut()
            .setup(&mut *self.data.borrow_mut(), &self.control_context);
    }

    fn parent_attached(&self) {
        self.style
            .borrow_mut()
            .parent_attached(&mut *self.data.borrow_mut(), &self.control_context);
    }

    fn parent_detached(&self) {
        self.style
            .borrow_mut()
            .parent_detached(&mut *self.data.borrow_mut(), &self.control_context);
    }

    fn handle_event(
        &self,
        drawing_context: &mut FuiDrawingContext,
        event_context: &mut dyn EventContext,
        event: ControlEvent,
    ) {
        self.style.borrow_mut().handle_event(
            &mut *self.data.borrow_mut(),
            &self.control_context,
            drawing_context,
            event_context,
            event,
        )
    }

    fn measure(&self, drawing_context: &mut FuiDrawingContext, mut size: Size) {
        if let Some(visible) = self.control_context.get_attached_value::<Visible>() {
            if !visible.get() {
                self.control_context.set_rect(Rect::empty());
                return;
            }
        }

        size = Margin::remove_from_size(
            size,
            self.control_context
                .get_attached_value::<Margin>()
                .as_deref(),
        );

        let mut measured_size = self.style.borrow_mut().measure(
            &mut *self.data.borrow_mut(),
            &self.control_context,
            drawing_context,
            size,
        );

        measured_size = Margin::add_to_size(
            measured_size,
            self.control_context
                .get_attached_value::<Margin>()
                .as_deref(),
        );

        self.control_context.set_rect(Rect::new(
            0.0f32,
            0.0f32,
            measured_size.width,
            measured_size.height,
        ));
    }

    fn set_rect(&self, drawing_context: &mut FuiDrawingContext, rect: Rect) {
        if let Some(visible) = self.control_context.get_attached_value::<Visible>() {
            if !visible.get() {
                self.control_context.set_rect(Rect::empty());
                return;
            }
        }

        let control_rect = self.control_context.get_rect();
        let measured_size = Size::new(control_rect.width, control_rect.height);

        let mut new_rect = Alignment::apply(
            measured_size,
            rect,
            self.control_context
                .get_attached_value::<HorizontalAlignment>()
                .as_deref(),
            self.control_context
                .get_attached_value::<VerticalAlignment>()
                .as_deref(),
            Alignment::Stretch,
            Alignment::Stretch,
        );
        new_rect = Margin::remove_from_rect(
            new_rect,
            self.control_context
                .get_attached_value::<Margin>()
                .as_deref(),
        );

        self.control_context.set_rect(new_rect);
        self.style.borrow_mut().set_rect(
            &mut *self.data.borrow_mut(),
            &self.control_context,
            drawing_context,
            new_rect,
        );
    }

    fn get_rect(&self) -> Rect {
        self.control_context.get_rect()
    }

    fn hit_test(&self, point: Point) -> Option<Rc<dyn ControlObject>> {
        let rect = self.control_context.get_rect();
        if rect.width == 0.0f32 || rect.height == 0.0f32 {
            return None;
        }

        self.style
            .borrow()
            .hit_test(&self.data.borrow(), &self.control_context, point)
    }

    fn draw(&self, drawing_context: &mut FuiDrawingContext) {
        let rect = self.control_context.get_rect();
        if rect.width == 0.0f32 || rect.height == 0.0f32 {
            return;
        }

        self.style
            .borrow_mut()
            .draw(&self.data.borrow(), &self.control_context, drawing_context)
    }
}