use binding::*;
use super::image::*;
use super::control::*;
use super::viewmodel::*;
use super::binding_canvas::*;
use super::resource_manager::*;
use std::sync::*;
pub trait Controller : Send+Sync {
fn ui(&self) -> BindRef<Control>;
fn get_viewmodel(&self) -> Option<Arc<ViewModel>> { None }
fn get_subcontroller(&self, _id: &str) -> Option<Arc<Controller>> { None }
fn action(&self, _action_id: &str, _action_data: &ActionParameter) { }
fn get_image_resources(&self) -> Option<Arc<ResourceManager<Image>>> { None }
fn get_canvas_resources(&self) -> Option<Arc<ResourceManager<BindingCanvas>>> { None }
fn tick(&self) { }
}
fn get_full_ui_tree(base_controller: &Arc<Controller>) -> Control {
let base_ui = base_controller.ui();
base_ui.get().map(&|control| {
if let Some(controller_id) = control.controller() {
let subcontroller = base_controller.get_subcontroller(controller_id);
if let Some(subcontroller) = subcontroller {
let subassembly = get_full_ui_tree(&subcontroller);
control.clone().with(vec![subassembly])
} else {
control.clone()
}
} else {
control.clone()
}
})
}
pub fn controller_path_for_address<'a>(ui_tree: &'a Control, address: &Vec<u32>) -> Vec<&'a str> {
let mut result = vec![];
let mut current_node = ui_tree;
for index in address.iter() {
if let Some(controller) = current_node.controller() {
result.push(controller);
}
if let Some(subcomponents) = current_node.subcomponents() {
current_node = &subcomponents[*index as usize];
}
}
result
}
pub fn assemble_ui(base_controller: Arc<Controller>) -> BindRef<Control> {
let weak_controller = Arc::downgrade(&base_controller);
return BindRef::from(computed(move || {
if let Some(base_controller) = weak_controller.upgrade() {
get_full_ui_tree(&base_controller)
} else {
Control::empty()
}
}));
}
pub struct NullController {
}
impl NullController {
pub fn new() -> NullController {
NullController { }
}
}
impl Controller for NullController {
fn ui(&self) -> BindRef<Control> {
BindRef::from(bind(Control::empty()))
}
fn get_subcontroller(&self, _id: &str) -> Option<Arc<Controller>> {
None
}
}
#[cfg(test)]
mod test {
use super::*;
struct TestController {
pub label_controller: Arc<LabelController>,
view_model: Arc<NullViewModel>,
ui: BindRef<Control>
}
struct LabelController {
pub label_text: Binding<String>,
view_model: Arc<NullViewModel>,
ui: BindRef<Control>
}
impl TestController {
pub fn new() -> TestController {
TestController {
label_controller: Arc::new(LabelController::new()),
view_model: Arc::new(NullViewModel::new()),
ui: BindRef::from(bind(Control::container().with_controller("Test")))
}
}
}
impl LabelController {
pub fn new() -> LabelController {
let text = bind("Test".to_string());
let label_text = text.clone();
LabelController {
label_text: label_text,
view_model: Arc::new(NullViewModel::new()),
ui: BindRef::from(computed(move || {
let text = text.get();
Control::label().with(text)
}))
}
}
}
impl Controller for TestController {
fn ui(&self) -> BindRef<Control> {
BindRef::clone(&self.ui)
}
fn get_subcontroller(&self, _id: &str) -> Option<Arc<Controller>> {
Some(self.label_controller.clone())
}
fn get_viewmodel(&self) -> Option<Arc<ViewModel>> {
Some(self.view_model.clone())
}
}
impl Controller for LabelController {
fn ui(&self) -> BindRef<Control> {
BindRef::clone(&self.ui)
}
fn get_subcontroller(&self, _id: &str) -> Option<Arc<Controller>> {
None
}
fn get_viewmodel(&self) -> Option<Arc<ViewModel>> {
Some(self.view_model.clone())
}
}
#[test]
fn can_assemble_simple_label() {
let label_controller = Arc::new(LabelController::new());
let assembly = assemble_ui(label_controller.clone());
assert!(assembly.get() == Control::label().with("Test"));
}
#[test]
fn can_assemble_with_subassembly() {
let test_controller = Arc::new(TestController::new());
let assembly = assemble_ui(test_controller.clone());
assert!(assembly.get() == Control::container()
.with_controller("Test")
.with(vec![
Control::label().with("Test")
]));
}
#[test]
fn label_binding_updates() {
let label_controller = Arc::new(LabelController::new());
let assembly = assemble_ui(label_controller.clone());
assert!(assembly.get() == Control::label().with("Test"));
label_controller.label_text.clone().set("Changed".to_string());
assert!(assembly.get() == Control::label().with("Changed"));
}
#[test]
fn subassembly_binding_updates() {
let test_controller = Arc::new(TestController::new());
let assembly = assemble_ui(test_controller.clone());
assert!(assembly.get() == Control::container()
.with_controller("Test")
.with(vec![
Control::label().with("Test")
]));
test_controller.label_controller.label_text.clone().set("Changed".to_string());
assert!(assembly.get() == Control::container()
.with_controller("Test")
.with(vec![
Control::label().with("Changed")
]));
}
#[test]
fn subassembly_binding_updates_after_reassembly() {
let test_controller = Arc::new(TestController::new());
let assembly = assemble_ui(test_controller.clone());
assert!(assembly.get() == Control::container()
.with_controller("Test")
.with(vec![
Control::label().with("Test")
]));
test_controller.label_controller.label_text.clone().set("Changed".to_string());
let assembly = assemble_ui(test_controller.clone());
assert!(assembly.get() == Control::container()
.with_controller("Test")
.with(vec![
Control::label().with("Changed")
]));
}
#[test]
fn controller_path_for_empty_address_is_empty() {
let control = Control::container()
.with_controller("Test1")
.with(vec![
Control::empty(),
Control::container()
.with_controller("Test2")
.with(vec![
Control::empty(),
Control::empty(),
Control::container()
.with_controller("Test3")
.with(vec![
Control::empty()
])
])
]);
assert!(controller_path_for_address(&control, &vec![]).len() == 0);
}
#[test]
fn controller_path_for_specific_control_is_right() {
let control = Control::container()
.with_controller("Test1")
.with(vec![
Control::empty(),
Control::container()
.with_controller("Test2")
.with(vec![
Control::empty(),
Control::empty(),
Control::container()
.with_controller("Test3")
.with(vec![
Control::empty()
])
])
]);
assert!(controller_path_for_address(&control, &vec![0]) == vec!["Test1"]);
}
#[test]
fn controller_path_for_control_with_controller_skips_controller() {
let control = Control::container()
.with_controller("Test1")
.with(vec![
Control::empty(),
Control::container()
.with_controller("Test2")
.with(vec![
Control::empty(),
Control::empty(),
Control::container()
.with_controller("Test3")
.with(vec![
Control::empty()
])
])
]);
assert!(controller_path_for_address(&control, &vec![1, 2]) == vec!["Test1", "Test2"]);
assert!(controller_path_for_address(&control, &vec![1, 2, 0]) == vec!["Test1", "Test2", "Test3"]);
}
}