use crate::{BoundingBox, Entity, Event, TreeExt, IntoParentIterator, State, WindowEvent};
use crate::tree::*;
use crate::state::animation::*;
pub fn apply_z_ordering(state: &mut State, tree: &Tree) {
for entity in tree.into_iter() {
if entity == Entity::root() {
continue;
}
let parent = tree.get_parent(entity).unwrap();
if let Some(z_order) = state.style.z_order.get(entity) {
state.data.set_z_order(entity, *z_order);
} else {
let parent_z_order = state.data.get_z_order(parent);
state.data.set_z_order(entity, parent_z_order);
}
}
}
pub fn apply_clipping(state: &mut State, tree: &Tree) {
for entity in tree.into_iter() {
if entity == Entity::root() {
continue;
}
let parent = tree.get_parent(entity).unwrap();
let mut parent_clip_region = state.data.get_clip_region(parent);
let parent_border_width = state.style.border_width.get(parent).cloned().unwrap_or_default().value_or(0.0, 0.0);
parent_clip_region.x += parent_border_width / 2.0;
parent_clip_region.y += parent_border_width / 2.0;
parent_clip_region.w -= parent_border_width;
parent_clip_region.h -= parent_border_width;
let root_clip_region = state.data.get_clip_region(Entity::root());
if entity.get_overflow(state) == Overflow::Hidden {
if let Some(clip_widget) = state.style.clip_widget.get(entity).cloned() {
let clip_widget_border_width = state.style.border_width.get(clip_widget).cloned().unwrap_or_default().value_or(0.0, 0.0);
let clip_x = state.data.get_posx(clip_widget) + clip_widget_border_width;
let clip_y = state.data.get_posy(clip_widget) + clip_widget_border_width;
let clip_w = state.data.get_width(clip_widget) - 2.0 * clip_widget_border_width;
let clip_h = state.data.get_height(clip_widget) - 2.0 * clip_widget_border_width;
let mut intersection = BoundingBox::default();
intersection.x = clip_x.max(parent_clip_region.x);
intersection.y = clip_y.max(parent_clip_region.y);
intersection.w = if clip_x + clip_w < parent_clip_region.x + parent_clip_region.w {
clip_x + clip_w - intersection.x
} else {
parent_clip_region.x + parent_clip_region.w - intersection.x
};
intersection.h = if clip_y + clip_h < parent_clip_region.y + parent_clip_region.h {
clip_y + clip_h - intersection.y
} else {
parent_clip_region.y + parent_clip_region.h - intersection.y
};
state.data.set_clip_region(entity, intersection);
} else {
state.data.set_clip_region(entity, parent_clip_region);
}
} else {
state.data.set_clip_region(entity, root_clip_region);
}
}
}
pub fn apply_visibility(state: &mut State, tree: &Tree) {
let mut draw_tree: Vec<Entity> = tree.into_iter().collect();
draw_tree.sort_by_cached_key(|entity| state.data.get_z_order(*entity));
for widget in draw_tree.into_iter() {
let visibility = state
.style
.visibility
.get(widget)
.cloned()
.unwrap_or_default();
state.data.set_visibility(widget, visibility);
let opacity = state.style.opacity.get(widget).cloned().unwrap_or_default();
state.data.set_opacity(widget, opacity.0);
let display = state.style.display.get(widget).cloned().unwrap_or_default();
if display == Display::None {
state.data.set_visibility(widget, Visibility::Invisible);
}
if let Some(parent) = widget.parent(tree) {
let parent_visibility = state.data.get_visibility(parent);
if parent_visibility == Visibility::Invisible {
state.data.set_visibility(widget, Visibility::Invisible);
}
let parent_display = state.style.display.get(parent).cloned().unwrap_or_default();
if parent_display == Display::None {
state.data.set_visibility(widget, Visibility::Invisible);
}
let parent_opacity = state.data.get_opacity(parent);
let opacity = state.style.opacity.get(widget).cloned().unwrap_or_default();
state.data.set_opacity(widget, opacity.0 * parent_opacity);
}
}
}
fn check_match(state: &State, entity: Entity, selector: &Selector) -> bool {
let mut entity_selector = Selector::new();
entity_selector.element = state.style.elements.get(entity).cloned();
if let Some(class_list) = state.style.classes.get(entity) {
entity_selector.classes = class_list.clone();
}
entity_selector.pseudo_classes = state
.style
.pseudo_classes
.get(entity)
.cloned()
.unwrap_or_default();
if state.active == entity {
entity_selector.pseudo_classes.insert(PseudoClasses::ACTIVE);
}
entity_selector.pseudo_classes.set(PseudoClasses::FOCUS, state.focused == entity);
return selector.matches(&entity_selector);
}
pub fn apply_styles(state: &mut State, tree: &Tree) {
for entity in tree.into_iter() {
if entity == Entity::root() {
continue;
}
let mut matched_rules: Vec<usize> = Vec::new();
'rule_loop: for (index, rule) in state.style.rules.iter().enumerate() {
let mut relation_entity = entity;
'selector_loop: for rule_selector in rule.selectors.iter().rev() {
match rule_selector.relation {
Relation::None => {
if !check_match(state, entity, rule_selector) {
continue 'rule_loop;
}
}
Relation::Parent => {
if let Some(parent) = relation_entity.parent(tree) {
if !check_match(state, parent, rule_selector) {
continue 'rule_loop;
}
relation_entity = parent;
} else {
continue 'rule_loop;
}
}
Relation::Ancestor => {
for ancestor in relation_entity.parent_iter(tree) {
if ancestor == relation_entity {
continue;
}
if check_match(state, ancestor, rule_selector) {
relation_entity = ancestor;
continue 'selector_loop;
}
}
continue 'rule_loop;
}
}
}
matched_rules.push(index);
}
if matched_rules.len() == 0 {
continue;
}
let mut should_relayout = false;
let mut should_redraw = false;
if state.style.display.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
if state.style.visibility.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
if state.style.z_order.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
state.style.overflow.link_rule(entity, &matched_rules);
if state.style.opacity.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
if state.style.left.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
if state.style.right.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
if state.style.top.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
if state.style.bottom.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
if state.style.width.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
if state.style.height.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
if state.style.max_width.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
if state.style.min_width.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
if state.style.max_height.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
if state.style.min_height.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
if state.style.border_width.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
if state.style.border_color.link_rule(entity, &matched_rules) {
should_redraw = true;
}
if state.style.border_shape_top_left.link_rule(entity, &matched_rules) {
should_redraw = true;
}
if state.style.border_shape_top_right.link_rule(entity, &matched_rules) {
should_redraw = true;
}
if state.style.border_shape_bottom_left.link_rule(entity, &matched_rules) {
should_redraw = true;
}
if state.style.border_shape_bottom_right.link_rule(entity, &matched_rules) {
should_redraw = true;
}
if state
.style
.border_radius_top_left
.link_rule(entity, &matched_rules)
{
should_redraw = true;
}
if state
.style
.border_radius_top_right
.link_rule(entity, &matched_rules)
{
should_redraw = true;
}
if state
.style
.border_radius_bottom_left
.link_rule(entity, &matched_rules)
{
should_redraw = true;
}
if state
.style
.border_radius_bottom_right
.link_rule(entity, &matched_rules)
{
should_redraw = true;
}
if state.style.layout_type.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
if state
.style
.positioning_type
.link_rule(entity, &matched_rules)
{
should_relayout = true;
should_redraw = true;
}
if state
.style
.background_color
.link_rule(entity, &matched_rules)
{
should_redraw = true;
}
if state
.style
.background_image
.link_rule(entity, &matched_rules)
{
should_redraw = true;
}
if state.style.font_color.link_rule(entity, &matched_rules) {
should_redraw = true;
}
if state.style.font_size.link_rule(entity, &matched_rules) {
should_redraw = true;
}
if state
.style
.outer_shadow_h_offset
.link_rule(entity, &matched_rules)
{
should_redraw = true;
}
if state
.style
.outer_shadow_v_offset
.link_rule(entity, &matched_rules)
{
should_redraw = true;
}
if state
.style
.outer_shadow_blur
.link_rule(entity, &matched_rules)
{
should_redraw = true;
}
if state
.style
.outer_shadow_color
.link_rule(entity, &matched_rules)
{
should_redraw = true;
}
if state
.style
.inner_shadow_h_offset
.link_rule(entity, &matched_rules)
{
should_redraw = true;
}
if state
.style
.inner_shadow_v_offset
.link_rule(entity, &matched_rules)
{
should_redraw = true;
}
if state
.style
.inner_shadow_blur
.link_rule(entity, &matched_rules)
{
should_redraw = true;
}
if state
.style
.inner_shadow_color
.link_rule(entity, &matched_rules)
{
should_redraw = true;
}
if state.style.child_left.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
if state.style.child_right.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
if state.style.child_top.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
if state.style.child_bottom.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
if state.style.row_between.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
if state.style.col_between.link_rule(entity, &matched_rules) {
should_relayout = true;
should_redraw = true;
}
for rule_index in matched_rules.iter() {
if let Some(rule) = state.style.rules.get(*rule_index as usize).cloned() {
for property in rule.properties.iter() {
match property {
Property::Unknown(ident, prop) => {
if let Some(mut event_handler) = state.event_handlers.remove(&entity) {
event_handler.on_style(state, entity, (ident.clone(), prop.clone()));
state.event_handlers.insert(entity, event_handler);
}
}
_=> {}
}
}
}
}
if should_relayout {
state.insert_event(Event::new(WindowEvent::Relayout).target(Entity::root()));
}
if should_redraw {
state.insert_event(Event::new(WindowEvent::Relayout).target(Entity::root()));
}
}
}