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),
});
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 } => {
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 } => {
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)
}
}