use std::any::Any;
use std::cell::RefCell;
use std::rc::Rc;
use crate::control::*;
use crate::events::{ControlEvent, EventContext};
use crate::view::ViewContext;
use crate::{FuiDrawingContext, Point, Rect, Size};
pub struct CompositeControl {
context: ControlContext,
visual_tree: RefCell<Option<Rc<dyn ControlObject>>>,
}
impl CompositeControl {
pub fn new<F>(context: ViewContext, builder: F) -> Rc<Self>
where
F: FnOnce(&ControlContext) -> Rc<dyn ControlObject> + 'static,
{
let control = Rc::new(CompositeControl {
context: ControlContext::new(context),
visual_tree: RefCell::new(None),
});
let control_weak = Rc::downgrade(&control);
control.context.set_self(control_weak);
let control_clone = control.clone();
control.context.set_on_parent_attached(move |ctx| {
let visual_tree = builder(ctx);
let control_as_dyn: Rc<dyn ControlObject> = control_clone.clone();
visual_tree.get_context().set_parent(&control_as_dyn);
visual_tree.get_context().set_services(ctx.get_services());
visual_tree.setup();
*control_clone.visual_tree.borrow_mut() = Some(visual_tree);
});
control
}
pub fn get_context(&self) -> &ControlContext {
&self.context
}
fn with_visual_tree<F, R>(&self, f: F) -> R
where
F: FnOnce(&Rc<dyn ControlObject>) -> R,
{
let visual_tree = self.visual_tree.borrow();
if let Some(ref vt) = *visual_tree {
f(vt)
} else {
panic!("CompositeControl: visual tree not yet initialized");
}
}
}
impl ControlObject for CompositeControl {
fn as_any(&self) -> &dyn Any {
self
}
fn get_context(&self) -> &ControlContext {
&self.context
}
}
impl ControlBehavior for CompositeControl {
fn parent_attached(&self) {
let services = self.context.get_services();
self.with_visual_tree(|vt| {
vt.get_context().set_services(services);
vt.get_context().attach_tree();
});
}
fn parent_detached(&self) {
self.with_visual_tree(|vt| vt.get_context().detach_tree());
}
fn setup(&self) {
self.with_visual_tree(|vt| vt.setup());
}
fn handle_event(
&self,
drawing_context: &mut FuiDrawingContext,
event_context: &mut dyn EventContext,
event: ControlEvent,
) {
self.with_visual_tree(|vt| {
vt.handle_event(drawing_context, event_context, event);
});
}
fn measure(&self, drawing_context: &mut FuiDrawingContext, size: Size) {
self.with_visual_tree(|vt| {
vt.measure(drawing_context, size);
});
}
fn set_rect(&self, drawing_context: &mut FuiDrawingContext, rect: Rect) {
self.context.set_rect(rect);
self.with_visual_tree(|vt| {
vt.set_rect(drawing_context, rect);
});
}
fn get_rect(&self) -> Rect {
self.with_visual_tree(|vt| vt.get_rect())
}
fn hit_test(&self, point: Point) -> Option<Rc<dyn ControlObject>> {
self.with_visual_tree(|vt| vt.hit_test(point))
}
fn draw(&self, drawing_context: &mut FuiDrawingContext) {
self.with_visual_tree(|vt| vt.draw(drawing_context));
}
}