use std::sync::Arc;
use indexmap::IndexMap;
use crate::html::css_parse::DynamicState;
use crate::tdom::node::NodeId;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SelectionMode {
Flow,
Block,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct DirtyInfo {
pub nodes: Vec<crate::tdom::node::NodeId>,
pub injected_css: IndexMap<crate::tdom::node::NodeId, String>,
}
impl DirtyInfo {
pub fn is_empty(&self) -> bool {
self.nodes.is_empty() && self.injected_css.is_empty()
}
}
#[derive(Debug, Clone)]
pub enum RenderCmd {
Rerender {
scroll_y: u32,
},
Redraw {
scroll_y: u32,
zoom: f32,
},
RenderArena {
arena: Arc<crate::tdom::node::NodeArena>,
root_id: crate::tdom::node::NodeId,
scroll_y: u32,
zoom: f32,
dynamic: DynamicState,
dirty: DirtyInfo,
},
RenderHtml {
html: Arc<str>,
},
Hover {
node_id: Option<NodeId>,
},
Focus {
node_id: Option<NodeId>,
},
RenderInput {
node_id: NodeId,
value: String,
cursor: usize,
focused: bool,
selection: Option<(usize, usize)>,
},
FocusRequest {
node_id: NodeId,
},
BlurRequest {
node_id: NodeId,
},
SelectOpen {
node_id: NodeId,
filter: Option<String>,
},
SelectClose {
node_id: NodeId,
},
SelectMove {
node_id: NodeId,
highlight: usize,
},
TextSelection {
anchor: Option<(u32, u32)>,
end: Option<(u32, u32)>,
mode: SelectionMode,
},
Quit,
}
impl RenderCmd {
pub fn refresh_dynamic_focus(&mut self, focused: Option<NodeId>) {
if let RenderCmd::RenderArena { dynamic, .. } = self {
dynamic.focused = focused;
}
}
}
#[derive(Debug, Default)]
pub struct DrainedBatch {
inputs: Vec<RenderCmd>,
selects: Vec<RenderCmd>,
text_selection: Option<RenderCmd>,
hover: Option<RenderCmd>,
snapshot: Option<RenderCmd>,
quit: bool,
}
impl DrainedBatch {
pub fn new() -> Self {
Self::default()
}
pub fn absorb(&mut self, cmd: RenderCmd) {
match cmd {
RenderCmd::RenderInput { .. } => self.inputs.push(cmd),
sel @ (RenderCmd::SelectOpen { .. }
| RenderCmd::SelectClose { .. }
| RenderCmd::SelectMove { .. }) => self.selects.push(sel),
other @ RenderCmd::TextSelection { .. } => {
self.text_selection = Some(other);
}
other @ RenderCmd::Hover { .. }
if matches!(self.snapshot, Some(RenderCmd::RenderArena { .. })) =>
{
self.hover = Some(other);
}
RenderCmd::Focus { node_id }
if matches!(self.snapshot, Some(RenderCmd::RenderArena { .. })) =>
{
if let Some(snapshot) = self.snapshot.as_mut() {
snapshot.refresh_dynamic_focus(node_id);
}
}
other => {
self.quit |= matches!(other, RenderCmd::Quit);
self.snapshot = Some(other);
}
}
}
pub fn quit_requested(&self) -> bool {
self.quit
}
pub fn drain_inputs(&mut self) -> impl Iterator<Item = RenderCmd> {
std::mem::take(&mut self.inputs).into_iter()
}
pub fn drain_selects(&mut self) -> impl Iterator<Item = RenderCmd> {
std::mem::take(&mut self.selects).into_iter()
}
pub fn take_text_selection(&mut self) -> Option<RenderCmd> {
self.text_selection.take()
}
pub fn take_snapshot(&mut self) -> Option<RenderCmd> {
self.snapshot.take()
}
pub fn take_hover(&mut self) -> Option<RenderCmd> {
self.hover.take()
}
}