Files
Glint-Runtime/src/app.rs

123 lines
4.5 KiB
Rust

use iced::widget::{column, container};
use iced::{Length, Theme};
use crate::interpreter::{Document, Element, Interpreter, RheiContext, Value};
use crate::renderer::render_element;
use crate::Message;
pub struct GlintApp {
pub doc: Document<'static>,
pub vdom_roots: Vec<Element<'static>>,
pub rhei: RheiContext,
}
impl GlintApp {
pub fn title(&self) -> String {
"Glint Runtime - Native Renderer".to_string()
}
pub fn update(&mut self, message: Message) -> iced::Task<Message> {
match message {
Message::WindowScrolled(y) => {
let var = "__scroll_y".to_string();
self.doc.variables.insert(var.clone(), Value::Float(y as f64));
self.doc.tracker.on_variable_changed(&var);
}
Message::EventTriggered(script) => {
if !script.is_empty() {
let old_vars: Vec<String> = self.doc.variables.keys().cloned().collect();
self.rhei.execute_action(&script, &mut self.doc.variables);
let new_vars: Vec<String> = self.doc.variables.keys().cloned().collect();
for v in &new_vars {
if !old_vars.contains(v) || self.doc.variables.get(v) != old_vars.iter().find_map(|k| if k == v { self.doc.variables.get(k) } else { None }) {
self.doc.tracker.on_variable_changed(v);
}
}
}
}
Message::InputChanged(Some(var), val) => {
self.doc.variables.insert(var.clone(), Value::from(val));
self.doc.tracker.on_variable_changed(&var);
}
Message::ToggleChanged(Some(var), val) => {
self.doc.variables.insert(var.clone(), Value::Bool(val));
self.doc.tracker.on_variable_changed(&var);
}
Message::SliderChanged(Some(var), val) => {
self.doc.variables.insert(var.clone(), Value::Float(val));
self.doc.tracker.on_variable_changed(&var);
if var == "volume_level" {
self.doc.variables.insert("age".to_string(), Value::Float(val));
self.doc.tracker.on_variable_changed("age");
}
}
_ => {}
}
let dirty_set = self.doc.tracker.take_dirty_set();
let root_refs: Vec<&Element<'static>> = self.doc.roots.iter().collect();
self.vdom_roots = Interpreter::evaluate_vdom_incr(
&root_refs,
&mut self.doc.variables,
&self.doc.components,
&self.rhei,
&self.doc.stylesheet,
&[],
&dirty_set,
);
iced::Task::none()
}
pub fn view(&self) -> iced::Element<'_, Message, Theme, iced::Renderer> {
let mut content = column![]
.width(Length::Fill)
.height(Length::Fill);
let mut global_fixed_layers = Vec::new();
let mut global_abs_layers = Vec::new();
let mut global_sticky_layers = Vec::new();
let _scroll_y = self.doc.variables.get("__scroll_y")
.and_then(|v| if let Value::Float(f) = v { Some(*f as f32) } else { None })
.unwrap_or(0.0);
for root in &self.vdom_roots {
if let Some(el) = render_element(root, None, None, None, &mut global_fixed_layers, &mut global_abs_layers, &mut global_sticky_layers, &self.doc.stylesheet) {
content = content.push(el);
}
}
let layout = column![
content,
iced::widget::rule::horizontal(1),
]
.width(Length::Fill)
.height(Length::Fill);
let main_flow = container(layout)
.width(Length::Fill)
.height(Length::Fill);
let has_abs = !global_abs_layers.is_empty();
let has_sticky = !global_sticky_layers.is_empty();
let has_fixed = !global_fixed_layers.is_empty();
if !has_abs && !has_sticky && !has_fixed {
main_flow.into()
} else {
let mut stack_widget = iced::widget::stack![main_flow];
for layer in global_abs_layers {
stack_widget = stack_widget.push(layer);
}
for layer in global_sticky_layers {
stack_widget = stack_widget.push(layer);
}
for layer in global_fixed_layers {
stack_widget = stack_widget.push(layer);
}
stack_widget.into()
}
}
}