use std::cell::Cell;
use std::ops::Deref;
use std::rc::Rc;
use crate::bitset::BitSet;
use crate::draw::Primitive;
use crate::event::{Event, Key, NodeEvent};
use crate::layout::*;
use crate::stylesheet::tree::Query;
use crate::stylesheet::*;
pub use self::button::Button;
pub use self::column::Column;
pub use self::drag_drop::{Drag, Drop};
pub use self::dropdown::Dropdown;
pub use self::dummy::Dummy;
pub use self::frame::Frame;
pub use self::image::Image;
pub use self::input::Input;
pub use self::layers::Layers;
pub use self::menu::Menu;
pub use self::panel::Panel;
pub use self::progress::Progress;
pub use self::row::Row;
pub use self::scroll::Scroll;
pub use self::space::Space;
pub use self::text::Text;
pub use self::toggle::Toggle;
pub use self::window::Window;
use smallvec::SmallVec;
use std::sync::Arc;
pub mod button;
pub mod column;
pub mod drag_drop;
pub mod dropdown;
pub mod dummy;
pub mod frame;
pub mod image;
pub mod input;
pub mod layers;
pub mod menu;
pub mod panel;
pub mod progress;
pub mod row;
pub mod scroll;
pub mod space;
pub mod text;
pub mod toggle;
pub mod window;
pub trait Widget<'a, Message> {
fn widget(&self) -> &'static str;
fn state(&self) -> StateVec {
StateVec::new()
}
fn len(&self) -> usize;
fn visit_children(&mut self, visitor: &mut dyn FnMut(&mut Node<'a, Message>));
fn size(&self, style: &Stylesheet) -> (Size, Size);
fn hit(&self, layout: Rectangle, clip: Rectangle, _style: &Stylesheet, x: f32, y: f32) -> bool {
layout.point_inside(x, y) && clip.point_inside(x, y)
}
fn focused(&self) -> bool {
false
}
fn event(
&mut self,
_layout: Rectangle,
_clip: Rectangle,
_style: &Stylesheet,
_event: Event,
_context: &mut Context<Message>,
) {
}
fn node_event(
&mut self,
_layout: Rectangle,
_style: &Stylesheet,
_event: NodeEvent,
_context: &mut Context<Message>,
) {
}
fn draw(&mut self, layout: Rectangle, clip: Rectangle, style: &Stylesheet) -> Vec<Primitive<'a>>;
}
pub trait IntoNode<'a, Message: 'a>: 'a + Sized {
fn into_node(self) -> Node<'a, Message>;
fn class(self, class: &'a str) -> Node<'a, Message> {
self.into_node().class(class)
}
fn on_event(self, event: NodeEvent, f: impl 'a + Fn(&mut Context<Message>)) -> Node<'a, Message> {
self.into_node().on_event(event, f)
}
}
pub type StateVec = SmallVec<[StyleState<&'static str>; 3]>;
pub struct Node<'a, Message> {
widget: Box<dyn Widget<'a, Message> + 'a>,
event_handlers: Vec<(NodeEvent, Box<dyn 'a + Fn(&mut Context<Message>)>)>,
clicks: Vec<Key>,
hovered: bool,
size: Cell<Option<(Size, Size)>>,
focused: Cell<Option<bool>>,
position: (usize, usize),
style: Option<Rc<Style>>,
selector_matches: BitSet,
stylesheet: Option<Arc<Stylesheet>>,
class: Option<&'a str>,
state: StateVec,
}
pub struct Context<Message> {
cursor: (f32, f32),
redraw: bool,
messages: Vec<Message>,
}
impl<'a, Message> Node<'a, Message> {
pub fn new<T: 'a + Widget<'a, Message>>(widget: T) -> Self {
Node {
widget: Box::new(widget),
event_handlers: Vec::new(),
clicks: Vec::new(),
hovered: false,
size: Cell::new(None),
focused: Cell::new(None),
position: (0, 1),
style: None,
selector_matches: BitSet::new(),
stylesheet: None,
class: None,
state: SmallVec::new(),
}
}
pub fn class(mut self, class: &'a str) -> Self {
self.class = Some(class);
self
}
pub fn on_event(mut self, event: NodeEvent, f: impl 'a + Fn(&mut Context<Message>)) -> Self {
self.event_handlers.push((event, Box::new(f)));
self
}
fn state(&self) -> StateVec {
let mut result = self.widget.state();
if self.hovered {
result.push(StyleState::Hover);
}
if self.clicks.len() > 0 {
result.push(StyleState::Pressed);
}
result
}
pub(crate) fn style(&mut self, query: &mut Query) {
self.style = Some(query.style.clone());
self.state = self.state();
self.selector_matches = query.match_widget(
self.widget.widget(),
self.class.unwrap_or(""),
self.state.as_slice(),
self.position.0,
self.position.1,
);
self.stylesheet.replace(query.style.get(&self.selector_matches));
query.ancestors.push(self.selector_matches.clone());
let own_siblings = std::mem::replace(&mut query.siblings, Vec::new());
let mut i = 0;
let len = self.widget.len();
self.widget.visit_children(&mut |child| {
child.position = (i, len);
child.style(&mut *query);
i += 1;
});
query.siblings = own_siblings;
query.siblings.push(query.ancestors.pop().unwrap());
}
fn add_matches(&mut self, query: &mut Query) {
let additions = query.match_widget(
self.widget.widget(),
self.class.unwrap_or(""),
self.state.as_slice(),
self.position.0,
self.position.1,
);
let new_style = self.selector_matches.union(&additions);
if new_style != self.selector_matches {
self.selector_matches = new_style;
self.stylesheet
.replace(self.style.as_ref().unwrap().get(&self.selector_matches));
}
query.ancestors.push(additions);
let own_siblings = std::mem::replace(&mut query.siblings, Vec::new());
self.widget.visit_children(&mut |child| child.add_matches(&mut *query));
query.siblings = own_siblings;
query.siblings.push(query.ancestors.pop().unwrap());
}
fn remove_matches(&mut self, query: &mut Query) {
let removals = query.match_widget(
self.widget.widget(),
self.class.unwrap_or(""),
self.state.as_slice(),
self.position.0,
self.position.1,
);
let new_style = self.selector_matches.difference(&removals);
if new_style != self.selector_matches {
self.selector_matches = new_style;
self.stylesheet
.replace(self.style.as_ref().unwrap().get(&self.selector_matches));
}
query.ancestors.push(removals);
let own_siblings = std::mem::replace(&mut query.siblings, Vec::new());
self.widget
.visit_children(&mut |child| child.remove_matches(&mut *query));
query.siblings = own_siblings;
query.siblings.push(query.ancestors.pop().unwrap());
}
pub fn size(&self) -> (Size, Size) {
if self.size.get().is_none() {
let style = self.stylesheet.as_ref().unwrap().deref();
let mut size = self.widget.size(style);
size.0 = match size.0 {
Size::Exact(size) => Size::Exact(size + style.margin.left + style.margin.right),
other => other,
};
size.1 = match size.1 {
Size::Exact(size) => Size::Exact(size + style.margin.top + style.margin.bottom),
other => other,
};
self.size.replace(Some(size));
}
self.size.get().unwrap()
}
pub fn hit(&self, layout: Rectangle, clip: Rectangle, x: f32, y: f32) -> bool {
let stylesheet = self.stylesheet.as_ref().unwrap().deref();
let layout = layout.after_padding(stylesheet.margin);
self.widget.hit(layout, clip, stylesheet, x, y)
}
pub fn focused(&self) -> bool {
if self.focused.get().is_none() {
self.focused.replace(Some(self.widget.focused()));
}
self.focused.get().unwrap()
}
fn dispatch(&mut self, layout: Rectangle, event: NodeEvent, context: &mut Context<Message>) {
self.widget
.node_event(layout, self.stylesheet.as_ref().unwrap().deref(), event, context);
for (handler_event, handler) in self.event_handlers.iter_mut() {
if *handler_event == event {
(handler)(context);
}
}
}
pub fn event(&mut self, layout: Rectangle, clip: Rectangle, event: Event, context: &mut Context<Message>) {
match event {
Event::Cursor(x, y) => {
let hovered = self.hit(layout, clip, x, y);
if hovered != self.hovered {
self.hovered = hovered;
if hovered {
self.dispatch(layout, NodeEvent::MouseEnter, context);
} else {
self.dispatch(layout, NodeEvent::MouseLeave, context);
self.clicks.clear();
}
}
}
Event::Press(button) if self.hovered => {
self.dispatch(layout, NodeEvent::MouseDown(button), context);
self.clicks.push(button);
}
Event::Release(button) if self.hovered => {
self.dispatch(layout, NodeEvent::MouseUp(button), context);
let len = self.clicks.len();
self.clicks.retain(|click| click != &button);
if len != self.clicks.len() {
self.dispatch(layout, NodeEvent::MouseClick(button), context);
}
}
_ => (),
}
let stylesheet = self.stylesheet.as_ref().unwrap().deref();
let layout = layout.after_padding(stylesheet.margin);
self.widget.event(layout, clip, stylesheet, event, context);
self.focused.replace(Some(self.widget.focused()));
let next_state = self.state();
if next_state != self.state {
self.state = next_state;
let new_style = self.style.as_ref().unwrap().rule_tree().rematch(
&self.selector_matches,
self.state.as_slice(),
self.class.unwrap_or(""),
self.position.0,
self.position.1,
);
if new_style != self.selector_matches {
context.redraw();
let difference = new_style.difference(&self.selector_matches);
let additions = difference.intersection(&new_style);
let removals = difference.intersection(&self.selector_matches);
if !additions.is_empty() {
let mut query = Query {
style: self.style.clone().unwrap(),
ancestors: vec![additions],
siblings: vec![],
};
self.widget.visit_children(&mut |child| child.add_matches(&mut query));
}
if !removals.is_empty() {
let mut query = Query {
style: self.style.clone().unwrap(),
ancestors: vec![removals],
siblings: vec![],
};
self.widget
.visit_children(&mut |child| child.remove_matches(&mut query));
}
self.selector_matches = new_style;
self.stylesheet
.replace(self.style.as_ref().unwrap().get(&self.selector_matches));
}
}
}
pub fn draw(&mut self, layout: Rectangle, clip: Rectangle) -> Vec<Primitive<'a>> {
let stylesheet = self.stylesheet.as_ref().unwrap().deref();
let layout = layout.after_padding(stylesheet.margin);
self.widget.draw(layout, clip, stylesheet)
}
}
impl<'a, Message: 'a> IntoNode<'a, Message> for Node<'a, Message> {
fn into_node(self) -> Node<'a, Message> {
self
}
}
impl<Message> Context<Message> {
pub(crate) fn new(redraw: bool, cursor: (f32, f32)) -> Self {
Self {
cursor,
redraw,
messages: Vec::new(),
}
}
pub fn push(&mut self, message: Message) {
self.messages.push(message);
}
pub fn extend<I: IntoIterator<Item = Message>>(&mut self, iter: I) {
self.messages.extend(iter);
}
pub fn redraw(&mut self) {
self.redraw = true;
}
pub fn redraw_requested(&self) -> bool {
self.redraw
}
pub fn cursor(&self) -> (f32, f32) {
self.cursor
}
}
impl<Message> IntoIterator for Context<Message> {
type Item = Message;
type IntoIter = std::vec::IntoIter<Message>;
fn into_iter(self) -> Self::IntoIter {
self.messages.into_iter()
}
}