use super::update::*;
use super::canvas_state::*;
use super::super::diff::*;
use super::super::control::*;
use super::super::controller::*;
use super::super::diff_viewmodel::*;
use binding::*;
use std::mem;
use std::sync::*;
pub struct UiSessionState {
ui: Option<Control>,
view_model_diff: Option<DiffViewModel>,
view_model_watcher: Option<WatchViewModel>,
canvas_state: Option<CanvasState>
}
impl UiSessionState {
pub fn new() -> UiSessionState {
UiSessionState {
ui: None,
view_model_diff: None,
view_model_watcher: None,
canvas_state: None
}
}
pub fn update_ui(&mut self, new_ui: &Control) -> Option<UiUpdate> {
let update = if let Some(ref old_ui) = self.ui {
let differences = diff_tree(old_ui, new_ui);
if differences.len() == 0 {
None
} else {
let diffs = differences.into_iter()
.map(|diff| UiDiff {
address: diff.address().clone(),
new_ui: diff.replacement().clone()
})
.collect();
Some(UiUpdate::UpdateUi(diffs))
}
} else {
Some(UiUpdate::UpdateUi(vec![UiDiff {
address: vec![],
new_ui: new_ui.clone()
}]))
};
if update.is_some() {
self.ui = Some(new_ui.clone());
}
update
}
pub fn watch_viewmodel(&mut self, controller: Arc<Controller>) {
let new_diff = DiffViewModel::new(controller);
let watcher = new_diff.watch();
self.view_model_diff = Some(new_diff);
self.view_model_watcher = Some(watcher);
}
pub fn get_viewmodel_update(&mut self) -> Option<UiUpdate> {
let mut watcher = None;
mem::swap(&mut watcher, &mut self.view_model_watcher);
if let Some((diff, watcher)) = self.view_model_diff.as_ref().and_then(|diff| watcher.map(move |watch| (diff, watch))) {
let (differences, new_watcher) = diff.rotate_watch(watcher);
self.view_model_watcher = Some(new_watcher);
if differences.len() == 0 {
None
} else {
Some(UiUpdate::UpdateViewModel(differences))
}
} else {
None
}
}
pub fn watch_canvases(&mut self, ui_binding: &BindRef<Control>) {
self.canvas_state = Some(CanvasState::new(ui_binding));
}
pub fn get_canvas_update(&mut self) -> Option<UiUpdate> {
if let Some(ref canvas_state) = self.canvas_state {
let updates = canvas_state.latest_updates();
if updates.len() == 0 {
None
} else {
Some(UiUpdate::UpdateCanvas(updates))
}
} else {
None
}
}
pub fn get_updates(&mut self, ui_binding: &BindRef<Control>) -> Vec<UiUpdate> {
let ui_updates = self.update_ui(&ui_binding.get());
let viewmodel_updates = self.get_viewmodel_update();
let canvas_updates = self.get_canvas_update();
let mut combined_updates = vec![];
if let Some(ui_updates) = ui_updates { combined_updates.push(ui_updates); }
if let Some(viewmodel_updates) = viewmodel_updates { combined_updates.push(viewmodel_updates); }
if let Some(canvas_updates) = canvas_updates { combined_updates.push(canvas_updates); }
combined_updates
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn initial_ui_diff_contains_everything() {
let mut state = UiSessionState::new();
assert!(state.update_ui(&Control::empty()) == Some(UiUpdate::UpdateUi(vec![UiDiff { address: vec![], new_ui: Control::empty() }])));
}
#[test]
fn update_ui_with_no_difference_returns_no_updates() {
let mut state = UiSessionState::new();
state.update_ui(&Control::empty());
assert!(state.update_ui(&Control::empty()) == None);
}
#[test]
fn changing_ui_generates_differences() {
let mut state = UiSessionState::new();
state.update_ui(&Control::empty()
.with(vec![
Control::label().with("Test1")
]));
assert!(state.update_ui(&Control::empty()
.with(vec![
Control::label().with("Test2")
])) == Some(UiUpdate::UpdateUi(vec![
UiDiff {
address: vec![0],
new_ui: Control::label().with("Test2")
}
])));
}
}