use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use slint::ComponentHandle;
use a2ui_base::catalog::function_api::FunctionImplementation;
use a2ui_base::components::dispatch_event;
use a2ui_base::event::{InputEvent, InputKey};
use a2ui_base::focus::FocusManager;
use a2ui_base::interaction::apply_event_result;
use a2ui_base::message_processor::MessageProcessor;
use a2ui_base::model::component_context::ComponentContext;
use a2ui_base::protocol::server_to_client::A2uiMessage;
use crate::live_tree::build_nodes;
use crate::ui::{Events, LiveNode, SampleEntry, Surface};
pub struct SurfaceHost {
state: Rc<HostState>,
}
struct HostState {
surface: Surface,
processor: RefCell<MessageProcessor>,
functions: HashMap<String, Box<dyn FunctionImplementation>>,
focus: RefCell<FocusManager>,
samples: RefCell<Vec<(String, Vec<A2uiMessage>)>>,
}
impl SurfaceHost {
pub fn new(
catalogs: Vec<a2ui_base::catalog::Catalog>,
functions: HashMap<String, Box<dyn FunctionImplementation>>,
) -> Result<Self, slint::PlatformError> {
let processor = MessageProcessor::new(catalogs);
let focus = FocusManager::new();
let surface = Surface::new()?;
let state = Rc::new(HostState {
surface,
processor: RefCell::new(processor),
functions,
focus: RefCell::new(focus),
samples: RefCell::new(Vec::new()),
});
{
let s = Rc::clone(&state);
state
.surface
.global::<Events>()
.on_activate(move |node_id| s.handle_activate(node_id.as_str()));
}
{
let s = Rc::clone(&state);
state
.surface
.on_select_sample(move |idx| s.select(idx as usize));
}
state.redraw();
Ok(SurfaceHost { state })
}
pub fn set_samples(&self, samples: Vec<(String, Vec<A2uiMessage>)>, initial: usize) {
let entries: Vec<SampleEntry> = samples
.iter()
.map(|(name, _)| SampleEntry { name: name.as_str().into() })
.collect();
let model = slint::ModelRc::new(Rc::new(slint::VecModel::from(entries)));
self.state.surface.set_samples(model);
self.state.samples.borrow_mut().clear();
self.state.samples.borrow_mut().extend(samples);
self.state.select(initial);
}
pub fn process_message(&self, message: A2uiMessage) {
let _ = self.state.processor.borrow_mut().process_message(message);
self.rebuild_focus();
self.state.redraw();
}
pub fn rebuild_focus(&self) {
let proc = self.state.processor.borrow();
if let Some(surface) = proc.model.surfaces().next() {
let components = surface.components.borrow();
self.state.focus.borrow_mut().rebuild_from_components(&components);
}
}
pub fn focus_next(&self) {
self.state.focus.borrow_mut().focus_next();
self.state.redraw();
}
pub fn focus_prev(&self) {
self.state.focus.borrow_mut().focus_prev();
self.state.redraw();
}
pub fn run(&self) -> Result<(), slint::PlatformError> {
self.state.surface.run()
}
}
impl HostState {
fn redraw(&self) {
let proc = self.processor.borrow();
let Some(surface) = proc.model.surfaces().next() else {
return;
};
let focused = self.focus.borrow().focused_id().map(str::to_string);
let nodes = build_nodes(surface, &self.functions, focused.as_deref());
self.surface.set_nodes(to_node_model(nodes));
}
fn handle_activate(&self, node_id: &str) {
let result = {
let proc = self.processor.borrow();
let Some(surface) = proc.model.surfaces().next() else {
return;
};
let comp_type = match surface.components.borrow().get(node_id) {
Some(m) => m.component_type.clone(),
None => return,
};
let data_model = surface.data_model.borrow();
let components = surface.components.borrow();
let ctx = ComponentContext::new(
node_id.to_string(),
surface.id.clone(),
&data_model,
&components,
&self.functions,
"",
Some(node_id.to_string()),
);
dispatch_event(
&comp_type,
&ctx,
&InputEvent::KeyPress { key: InputKey::Enter },
)
};
if let Some(result) = result {
let mut proc = self.processor.borrow_mut();
let _ = apply_event_result(&mut proc, result);
}
self.redraw();
}
fn select(&self, idx: usize) {
let messages = self
.samples
.borrow()
.get(idx)
.map(|(_, msgs)| msgs.clone());
let Some(messages) = messages else {
return;
};
let mut proc = self.processor.borrow_mut();
proc.reset();
for msg in &messages {
let _ = proc.process_message(msg.clone());
}
drop(proc);
self.focus.borrow_mut().reset();
{
let proc = self.processor.borrow();
if let Some(surface) = proc.model.surfaces().next() {
let components = surface.components.borrow();
self.focus.borrow_mut().rebuild_from_components(&components);
}
}
self.surface.set_selected_sample(idx as i32);
self.redraw();
}
}
fn to_node_model(nodes: Vec<LiveNode>) -> slint::ModelRc<LiveNode> {
slint::ModelRc::new(Rc::new(slint::VecModel::from(nodes)))
}