From 4c6037136abdbd5a5dd39004146809f089600c77 Mon Sep 17 00:00:00 2001 From: George Atkinson Date: Fri, 18 Mar 2022 10:48:31 +0000 Subject: [PATCH] Property Animations (#76) * Make bindings the parent of their contents and remove children when updating Rename perf test to a permanent fixture Hack around textbox expecting bindings to not be parents Incredibly low-effort implementation of attribute bindings Make lenses fallible, again! fix captured widget being destroyed but not releasing its status as captured Make bindings ignored by layout * Remove Display::Contents; only use tree.is_ignored() * Final fixes for determining layout ancestry; add test for layout iter * Fix warnings * Allow prop setters to take a lens and generate a binding * Fix slider, knob, and label * Fix popup and dropdown * Fmt and fix warnings * Add some more safeguards for fallible lenses * Allow deriving Lens on enums! * fmt * Remove debug print * Add `TreeDepthIterator` for debugging + Fix `overflow` not being removed when entity is removed * Fix warnings * Quick fix for text autosize glitch * Fix property bindings replacing first child of view * Fix textbox_list * Add concept of 'duplicated' and 'deduplicated' lenses * Remove observer from stored lenses when entity is removed. Remove stored lenses when they have no observers. + fmt and warnings fix * Quick fix for panic when removing list items in crud example * Start adding style transitions * Apply animations after styling * Make opacity animatable and update default style for popups * fmt * Add transitions to default theme * Animate all animatable properties * Clean up style module and rename theme.rs to parser.rs * Update context.rs * Add animation builder * Small style changes * Fix animations to reset unless persistent * Fmt * Fix warnings * Actually fix the warnings this time * Changes to radiobutton widget. Fixes transitions when animation is already playing. * fmt+ fix warnings Co-authored-by: Audrey Dutcher --- baseview/src/application.rs | 20 + core/src/animation/anim_ext.rs | 97 ++- core/src/animation/animation_builder.rs | 276 ++++---- core/src/animation/interpolator.rs | 6 + core/src/animation/mod.rs | 8 +- core/src/cache.rs | 4 +- core/src/context.rs | 126 +++- core/src/default_theme.css | 132 ++-- core/src/handle.rs | 1 + core/src/input/mouse.rs | 4 +- core/src/storage/animatable_set.rs | 33 +- core/src/style/mod.rs | 861 +++--------------------- core/src/style/{theme.rs => parser.rs} | 0 core/src/style/prop.rs | 2 +- core/src/style/transform.rs | 4 +- core/src/views/button.rs | 2 +- core/src/views/dropdown.rs | 14 +- core/src/views/popup.rs | 5 +- core/src/views/radio_buttons.rs | 61 +- core/src/views/slider.rs | 43 +- core/src/views/textbox.rs | 3 + examples/animation.rs | 49 ++ examples/controls/checkbox.rs | 63 +- examples/controls/dropdown.rs | 108 ++- examples/controls/popup.rs | 4 - examples/controls/radiobutton.rs | 32 +- examples/controls/slider.rs | 48 +- examples/controls/support/mod.rs | 103 --- examples/controls/widget_gallery.rs | 15 +- examples/modal.rs | 46 +- examples/test.rs | 63 +- examples/transform.rs | 3 +- winit/src/application.rs | 26 + 33 files changed, 819 insertions(+), 1443 deletions(-) rename core/src/style/{theme.rs => parser.rs} (100%) create mode 100644 examples/animation.rs delete mode 100644 examples/controls/support/mod.rs diff --git a/baseview/src/application.rs b/baseview/src/application.rs index 77c4f9f28..af95e8ed5 100644 --- a/baseview/src/application.rs +++ b/baseview/src/application.rs @@ -245,6 +245,26 @@ impl ApplicationRunner { } self.context.process_data_updates(); + self.context.process_style_updates(); + + // if self.context.has_animations() { + // if let Some(window_event_handler) = self.context.views.remove(&Entity::root()) { + // if let Some(window) = window_event_handler.downcast_ref::() { + // window.handle.window().request_redraw(); + // } + + // context.views.insert(Entity::root(), window_event_handler); + // } + // } else { + // if should_poll { + // *control_flow = ControlFlow::Poll; + // } else { + // *control_flow = ControlFlow::Wait; + // } + // } + + self.context.apply_animations(); + self.context.process_visual_updates(); if self.context.style.needs_redraw { diff --git a/core/src/animation/anim_ext.rs b/core/src/animation/anim_ext.rs index cdc4e6c6e..85dc00d36 100644 --- a/core/src/animation/anim_ext.rs +++ b/core/src/animation/anim_ext.rs @@ -1,92 +1,87 @@ -use crate::{Animation, AsEntity, State}; +use crate::{Animation, AsEntity, Context}; /// Trait which provides methods for entities to manipulate linked animations pub trait AnimExt: AsEntity + Sized { - /// Play an animation on the entity. /// /// Internally this generates an active animation and links the entity to it for each animated property. /// /// # Example - /// Create an animation which animates the `left` property from 0 to 100 pixels in 5 seconds + /// Create an animation which animates the `left` property from 0 to 100 pixels in 5 seconds /// and play the animation on an entity: - /// ``` - /// let animation_id = state.create_animation(instant::Duration::from_secs(5)) + /// ```ignore + /// let animation_id = cx.create_animation(instant::Duration::from_secs(5)) /// .add_keyframe(0.0, |keyframe| keyframe.set_left(Pixels(0.0))) /// .add_keyframe(1.0, |keyframe| keyframe.set_left(Pixels(100.0))) - /// .build(); + /// .build(); /// - /// entity.play_animation(state, animation_id); + /// entity.play_animation(cx, animation_id); /// ``` - fn play_animation(self, state: &mut State, animation: Animation) -> Self { - + fn play_animation(self, cx: &mut Context, animation: Animation) -> Self { // Background - state.style.background_color.play_animation(self.entity(), animation); + cx.style.background_color.play_animation(self.entity(), animation); // Space - state.style.left.play_animation(self.entity(), animation); - state.style.right.play_animation(self.entity(), animation); - state.style.top.play_animation(self.entity(), animation); - state.style.bottom.play_animation(self.entity(), animation); + cx.style.left.play_animation(self.entity(), animation); + cx.style.right.play_animation(self.entity(), animation); + cx.style.top.play_animation(self.entity(), animation); + cx.style.bottom.play_animation(self.entity(), animation); // Min/Max Space - state.style.min_left.play_animation(self.entity(), animation); - state.style.min_right.play_animation(self.entity(), animation); - state.style.min_top.play_animation(self.entity(), animation); - state.style.min_bottom.play_animation(self.entity(), animation); - state.style.max_left.play_animation(self.entity(), animation); - state.style.max_right.play_animation(self.entity(), animation); - state.style.max_top.play_animation(self.entity(), animation); - state.style.max_bottom.play_animation(self.entity(), animation); + cx.style.min_left.play_animation(self.entity(), animation); + cx.style.min_right.play_animation(self.entity(), animation); + cx.style.min_top.play_animation(self.entity(), animation); + cx.style.min_bottom.play_animation(self.entity(), animation); + cx.style.max_left.play_animation(self.entity(), animation); + cx.style.max_right.play_animation(self.entity(), animation); + cx.style.max_top.play_animation(self.entity(), animation); + cx.style.max_bottom.play_animation(self.entity(), animation); // Child Space - state.style.child_left.play_animation(self.entity(), animation); - state.style.child_right.play_animation(self.entity(), animation); - state.style.child_top.play_animation(self.entity(), animation); - state.style.child_bottom.play_animation(self.entity(), animation); + cx.style.child_left.play_animation(self.entity(), animation); + cx.style.child_right.play_animation(self.entity(), animation); + cx.style.child_top.play_animation(self.entity(), animation); + cx.style.child_bottom.play_animation(self.entity(), animation); // Size - state.style.width.play_animation(self.entity(), animation); - state.style.height.play_animation(self.entity(), animation); + cx.style.width.play_animation(self.entity(), animation); + cx.style.height.play_animation(self.entity(), animation); // Min/Max Size - state.style.min_width.play_animation(self.entity(), animation); - state.style.min_height.play_animation(self.entity(), animation); - state.style.max_width.play_animation(self.entity(), animation); - state.style.max_height.play_animation(self.entity(), animation); + cx.style.min_width.play_animation(self.entity(), animation); + cx.style.min_height.play_animation(self.entity(), animation); + cx.style.max_width.play_animation(self.entity(), animation); + cx.style.max_height.play_animation(self.entity(), animation); // Border - state.style.border_color.play_animation(self.entity(), animation); - state.style.border_width.play_animation(self.entity(), animation); - state.style.border_radius_bottom_left.play_animation(self.entity(), animation); - state.style.border_radius_top_left.play_animation(self.entity(), animation); - state.style.border_radius_bottom_right.play_animation(self.entity(), animation); - state.style.border_radius_top_right.play_animation(self.entity(), animation); + cx.style.border_color.play_animation(self.entity(), animation); + cx.style.border_width.play_animation(self.entity(), animation); + cx.style.border_radius_bottom_left.play_animation(self.entity(), animation); + cx.style.border_radius_top_left.play_animation(self.entity(), animation); + cx.style.border_radius_bottom_right.play_animation(self.entity(), animation); + cx.style.border_radius_top_right.play_animation(self.entity(), animation); // Transform - state.style.rotate.play_animation(self.entity(), animation); - // state.style.translate.play_animation(self.entity(), animation); - state.style.scale.play_animation(self.entity(), animation); + cx.style.rotate.play_animation(self.entity(), animation); + // cx.style.translate.play_animation(self.entity(), animation); + cx.style.scale.play_animation(self.entity(), animation); // Display - state.style.opacity.play_animation(self.entity(), animation); - + cx.style.opacity.play_animation(self.entity(), animation); self } /// Returns true if there is an active animation with the given id. - /// + /// /// # Example - /// ``` + /// ```ignore /// let test = entity.is_animation(animation_id); /// ``` - fn is_animating(self, state: &mut State, animation: Animation) -> bool { - state.style.height.is_animating(self.entity(), animation) || - state.style.width.is_animating(self.entity(), animation) + fn is_animating(self, cx: &mut Context, animation: Animation) -> bool { + cx.style.height.is_animating(self.entity(), animation) + || cx.style.width.is_animating(self.entity(), animation) } } -impl AnimExt for T { - -} +impl AnimExt for T {} diff --git a/core/src/animation/animation_builder.rs b/core/src/animation/animation_builder.rs index a897d9ed0..13b2ac9a2 100644 --- a/core/src/animation/animation_builder.rs +++ b/core/src/animation/animation_builder.rs @@ -1,6 +1,6 @@ use morphorm::Units; -use crate::{Animation, AnimationState, Color, Opacity, State}; +use crate::{style::Opacity, Animation, AnimationState, Color, Context}; pub(crate) struct AnimationDescription { duration: instant::Duration, @@ -10,17 +10,17 @@ pub(crate) struct AnimationDescription { /// A builder for constructing animations. /// -/// Returned from `state.create_animation(duration)`. +/// Returned from `cx.create_animation(duration)`. /// /// # Example -/// ``` -/// let animation_id = state.create_animation(instant::Duration::from_secs(1)) -/// .add_keyframe(0.0, |keyframe| +/// ```ignore +/// let animation_id = cx.create_animation(std::time::Duration::from_secs(1)) +/// .add_keyframe(0.0, |keyframe| /// keyframe /// .set_background_color(Color::red()) /// .set_border_color(Color::blue()) /// ) -/// .add_keyframe(1.0, |keyframe| +/// .add_keyframe(1.0, |keyframe| /// keyframe /// .set_background_color(Color::blue())) /// .set_border_color(Color::red()) @@ -28,25 +28,24 @@ pub(crate) struct AnimationDescription { /// ``` pub struct AnimationBuilder<'a> { id: Animation, - state: &'a mut State, + cx: &'a mut Context, animation_description: AnimationDescription, } impl<'a> AnimationBuilder<'a> { - pub fn new(id: Animation, state: &'a mut State, duration: instant::Duration) -> Self { + pub fn new(id: Animation, cx: &'a mut Context, duration: std::time::Duration) -> Self { Self { - id, - state, + id, + cx, animation_description: AnimationDescription { duration, delay: instant::Duration::from_secs(0), persistent: false, - } + }, } } - - /// Sets the delay before the animation will play. + /// Sets the delay before the animation will play. /// /// Needs to be called before setting keyframes. pub fn with_delay(mut self, delay: instant::Duration) -> Self { @@ -57,7 +56,7 @@ impl<'a> AnimationBuilder<'a> { /// Sets the animation to persist after completion. /// - /// Normally, after an animation is finished, the animated property will return to the the previous value + /// Normally, after an animation is finished, the animated property will return to the the previous value /// before the animation was played. Setting an animation to persistent causes the property to be set to the last /// value of the animation. pub fn persistent(mut self) -> Self { @@ -68,26 +67,26 @@ impl<'a> AnimationBuilder<'a> { /// Adds a keyframe to the animation. /// - /// - pub fn add_keyframe(self, time: f32, keyframe: F) -> KeyframeBuilder<'a> - where F: FnOnce(KeyframeBuilder<'a>) -> KeyframeBuilder<'a> + /// + pub fn add_keyframe(self, time: f32, keyframe: F) -> KeyframeBuilder<'a> + where + F: FnOnce(KeyframeBuilder<'a>) -> KeyframeBuilder<'a>, { - (keyframe)(KeyframeBuilder::new(self.id, self.state, time, self.animation_description)) + (keyframe)(KeyframeBuilder::new(self.id, self.cx, time, self.animation_description)) } } - /// A builder for constructing keyframes. -/// +/// /// # Example -/// ``` -/// let animation_id = state.create_animation(instant::Duration::from_secs(1)) -/// .add_keyframe(0.0, |keyframe| +/// ```ignore +/// let animation_id = cx.create_animation(std::time::Duration::from_secs(1)) +/// .add_keyframe(0.0, |keyframe| /// keyframe /// .set_background_color(Color::red()) /// .set_border_color(Color::blue()) /// ) -/// .add_keyframe(1.0, |keyframe| +/// .add_keyframe(1.0, |keyframe| /// keyframe /// .set_background_color(Color::blue())) /// .set_border_color(Color::red()) @@ -95,20 +94,20 @@ impl<'a> AnimationBuilder<'a> { /// ``` pub struct KeyframeBuilder<'a> { id: Animation, - state: &'a mut State, + cx: &'a mut Context, time: f32, animation_description: AnimationDescription, } impl<'a> KeyframeBuilder<'a> { - pub(crate) fn new(id: Animation, state: &'a mut State, time: f32, animation_description: AnimationDescription) -> Self { - Self { - id, - state, - time, - animation_description, - } - } + pub(crate) fn new( + id: Animation, + cx: &'a mut Context, + time: f32, + animation_description: AnimationDescription, + ) -> Self { + Self { id, cx, time, animation_description } + } /// Finish building the animation, returning an [Animation] id. pub fn build(self) -> Animation { @@ -116,317 +115,290 @@ impl<'a> KeyframeBuilder<'a> { } /// Add another keyframe to the animation. - pub fn add_keyframe(self, time: f32, keyframe: F) -> Self - where F: FnOnce(KeyframeBuilder<'a>) -> KeyframeBuilder<'a> + pub fn add_keyframe(self, time: f32, keyframe: F) -> Self + where + F: FnOnce(KeyframeBuilder<'a>) -> KeyframeBuilder<'a>, { - (keyframe)(KeyframeBuilder::new(self.id, self.state, time, self.animation_description)) + (keyframe)(KeyframeBuilder::new(self.id, self.cx, time, self.animation_description)) } /// Adds a background-color property to the keyframe. - /// + /// /// # Example - /// ``` + /// ```ignore /// .add_keyframe(0.0, |keyframe| keyframe.set_background_color(Color::red())) /// ``` pub fn set_background_color(self, color: Color) -> Self { - - if let Some(anim_state) = self.state.style.background_color.get_animation_mut(self.id) { - anim_state.keyframes.push((self.time, color)); + if let Some(anim_cx) = self.cx.style.background_color.get_animation_mut(self.id) { + anim_cx.keyframes.push((self.time, color)); } else { - let anim_state = AnimationState::new(self.id) + let anim_cx = AnimationState::new(self.id) .with_duration(self.animation_description.duration) .with_delay(self.animation_description.delay) .set_persistent(self.animation_description.persistent) .with_keyframe((self.time, color)); - - self.state.style.background_color.insert_animation(self.id, anim_state); + self.cx.style.background_color.insert_animation(self.id, anim_cx); } self - } /// Adds a left property to the keyframe. - /// + /// /// # Example - /// ``` + /// ```ignore /// .add_keyframe(0.0, |keyframe| keyframe.set_left(Pixels(50.0))) /// ``` pub fn set_left(self, value: Units) -> Self { - - if let Some(anim_state) = self.state.style.left.get_animation_mut(self.id) { - anim_state.keyframes.push((self.time, value)); + if let Some(anim_cx) = self.cx.style.left.get_animation_mut(self.id) { + anim_cx.keyframes.push((self.time, value)); } else { - let anim_state = AnimationState::new(self.id) + let anim_cx = AnimationState::new(self.id) .with_duration(self.animation_description.duration) .with_delay(self.animation_description.delay) .set_persistent(self.animation_description.persistent) .with_keyframe((self.time, value)); - - self.state.style.left.insert_animation(self.id, anim_state); + self.cx.style.left.insert_animation(self.id, anim_cx); } - self + self } /// Adds a right property to the keyframe. - /// + /// /// # Example - /// ``` + /// ```ignore /// .add_keyframe(0.0, |keyframe| keyframe.set_right(Pixels(50.0))) /// ``` pub fn set_right(self, value: Units) -> Self { - - if let Some(anim_state) = self.state.style.right.get_animation_mut(self.id) { - anim_state.keyframes.push((self.time, value)); + if let Some(anim_cx) = self.cx.style.right.get_animation_mut(self.id) { + anim_cx.keyframes.push((self.time, value)); } else { - let anim_state = AnimationState::new(self.id) + let anim_cx = AnimationState::new(self.id) .with_duration(self.animation_description.duration) .with_delay(self.animation_description.delay) .set_persistent(self.animation_description.persistent) .with_keyframe((self.time, value)); - - self.state.style.right.insert_animation(self.id, anim_state); + self.cx.style.right.insert_animation(self.id, anim_cx); } - self + self } /// Adds a top property to the keyframe. - /// + /// /// # Example - /// ``` + /// ```ignore /// .add_keyframe(0.0, |keyframe| keyframe.set_top(Pixels(50.0))) /// ``` pub fn set_top(self, value: Units) -> Self { - - if let Some(anim_state) = self.state.style.top.get_animation_mut(self.id) { - anim_state.keyframes.push((self.time, value)); + if let Some(anim_cx) = self.cx.style.top.get_animation_mut(self.id) { + anim_cx.keyframes.push((self.time, value)); } else { - let anim_state = AnimationState::new(self.id) + let anim_cx = AnimationState::new(self.id) .with_duration(self.animation_description.duration) .with_delay(self.animation_description.delay) .set_persistent(self.animation_description.persistent) .with_keyframe((self.time, value)); - - self.state.style.top.insert_animation(self.id, anim_state); + self.cx.style.top.insert_animation(self.id, anim_cx); } - self + self } /// Adds a bottom property to the keyframe. - /// + /// /// # Example - /// ``` + /// ```ignore /// .add_keyframe(0.0, |keyframe| keyframe.set_bottom(Pixels(50.0))) /// ``` pub fn set_bottom(self, value: Units) -> Self { - - if let Some(anim_state) = self.state.style.bottom.get_animation_mut(self.id) { - anim_state.keyframes.push((self.time, value)); + if let Some(anim_cx) = self.cx.style.bottom.get_animation_mut(self.id) { + anim_cx.keyframes.push((self.time, value)); } else { - let anim_state = AnimationState::new(self.id) + let anim_cx = AnimationState::new(self.id) .with_duration(self.animation_description.duration) .with_delay(self.animation_description.delay) .set_persistent(self.animation_description.persistent) .with_keyframe((self.time, value)); - - self.state.style.bottom.insert_animation(self.id, anim_state); + self.cx.style.bottom.insert_animation(self.id, anim_cx); } - self + self } /// Adds a width property to the keyframe. - /// + /// /// # Example - /// ``` + /// ```ignore /// .add_keyframe(0.0, |keyframe| keyframe.set_width(Pixels(50.0))) /// ``` pub fn set_width(self, value: Units) -> Self { - - if let Some(anim_state) = self.state.style.width.get_animation_mut(self.id) { - anim_state.keyframes.push((self.time, value)); + if let Some(anim_cx) = self.cx.style.width.get_animation_mut(self.id) { + anim_cx.keyframes.push((self.time, value)); } else { - let anim_state = AnimationState::new(self.id) + let anim_cx = AnimationState::new(self.id) .with_duration(self.animation_description.duration) .with_delay(self.animation_description.delay) .set_persistent(self.animation_description.persistent) .with_keyframe((self.time, value)); - - self.state.style.width.insert_animation(self.id, anim_state); + self.cx.style.width.insert_animation(self.id, anim_cx); } - self + self } /// Adds a height property to the keyframe. - /// + /// /// # Example - /// ``` + /// ```ignore /// .add_keyframe(0.0, |keyframe| keyframe.set_height(Pixels(50.0))) /// ``` pub fn set_height(self, value: Units) -> Self { - - if let Some(anim_state) = self.state.style.height.get_animation_mut(self.id) { - anim_state.keyframes.push((self.time, value)); + if let Some(anim_cx) = self.cx.style.height.get_animation_mut(self.id) { + anim_cx.keyframes.push((self.time, value)); } else { - let anim_state = AnimationState::new(self.id) + let anim_cx = AnimationState::new(self.id) .with_duration(self.animation_description.duration) .with_delay(self.animation_description.delay) .set_persistent(self.animation_description.persistent) .with_keyframe((self.time, value)); - - self.state.style.height.insert_animation(self.id, anim_state); + self.cx.style.height.insert_animation(self.id, anim_cx); } - self + self } /// Adds a child-left property to the keyframe. - /// + /// /// # Example - /// ``` + /// ```ignore /// .add_keyframe(0.0, |keyframe| keyframe.set_child_left(Pixels(50.0))) /// ``` pub fn set_child_left(self, value: Units) -> Self { - - if let Some(anim_state) = self.state.style.child_left.get_animation_mut(self.id) { - anim_state.keyframes.push((self.time, value)); + if let Some(anim_cx) = self.cx.style.child_left.get_animation_mut(self.id) { + anim_cx.keyframes.push((self.time, value)); } else { - let anim_state = AnimationState::new(self.id) + let anim_cx = AnimationState::new(self.id) .with_duration(self.animation_description.duration) .with_delay(self.animation_description.delay) .set_persistent(self.animation_description.persistent) .with_keyframe((self.time, value)); - - self.state.style.child_left.insert_animation(self.id, anim_state); + self.cx.style.child_left.insert_animation(self.id, anim_cx); } - self + self } /// Adds a child-right property to the keyframe. - /// + /// /// # Example - /// ``` + /// ```ignore /// .add_keyframe(0.0, |keyframe| keyframe.set_child_right(Pixels(50.0))) /// ``` pub fn set_child_right(self, value: Units) -> Self { - - if let Some(anim_state) = self.state.style.child_right.get_animation_mut(self.id) { - anim_state.keyframes.push((self.time, value)); + if let Some(anim_cx) = self.cx.style.child_right.get_animation_mut(self.id) { + anim_cx.keyframes.push((self.time, value)); } else { - let anim_state = AnimationState::new(self.id) + let anim_cx = AnimationState::new(self.id) .with_duration(self.animation_description.duration) .with_delay(self.animation_description.delay) .set_persistent(self.animation_description.persistent) .with_keyframe((self.time, value)); - - self.state.style.child_right.insert_animation(self.id, anim_state); + self.cx.style.child_right.insert_animation(self.id, anim_cx); } - self + self } /// Adds a child-top property to the keyframe. - /// + /// /// # Example - /// ``` + /// ```ignore /// .add_keyframe(0.0, |keyframe| keyframe.set_child_top(Pixels(50.0))) /// ``` pub fn set_child_top(self, value: Units) -> Self { - - if let Some(anim_state) = self.state.style.child_top.get_animation_mut(self.id) { - anim_state.keyframes.push((self.time, value)); + if let Some(anim_cx) = self.cx.style.child_top.get_animation_mut(self.id) { + anim_cx.keyframes.push((self.time, value)); } else { - let anim_state = AnimationState::new(self.id) + let anim_cx = AnimationState::new(self.id) .with_duration(self.animation_description.duration) .with_delay(self.animation_description.delay) .set_persistent(self.animation_description.persistent) .with_keyframe((self.time, value)); - - self.state.style.child_top.insert_animation(self.id, anim_state); + self.cx.style.child_top.insert_animation(self.id, anim_cx); } - self + self } /// Adds a child-bottom property to the keyframe. - /// + /// /// # Example - /// ``` + /// ```ignore /// .add_keyframe(0.0, |keyframe| keyframe.set_child_bottom(Pixels(50.0))) /// ``` pub fn set_child_bottom(self, value: Units) -> Self { - - if let Some(anim_state) = self.state.style.child_bottom.get_animation_mut(self.id) { - anim_state.keyframes.push((self.time, value)); + if let Some(anim_cx) = self.cx.style.child_bottom.get_animation_mut(self.id) { + anim_cx.keyframes.push((self.time, value)); } else { - let anim_state = AnimationState::new(self.id) + let anim_cx = AnimationState::new(self.id) .with_duration(self.animation_description.duration) .with_delay(self.animation_description.delay) .set_persistent(self.animation_description.persistent) .with_keyframe((self.time, value)); - - self.state.style.child_bottom.insert_animation(self.id, anim_state); + self.cx.style.child_bottom.insert_animation(self.id, anim_cx); } - self + self } /// Adds a rotate transform property to the keyframe. - /// + /// /// # Example - /// ``` + /// ```ignore /// .add_keyframe(0.0, |keyframe| keyframe.set_rotate(Pixels(50.0))) /// ``` pub fn set_rotate(self, value: f32) -> Self { - if let Some(anim_state) = self.state.style.rotate.get_animation_mut(self.id) { - anim_state.keyframes.push((self.time, value)); + if let Some(anim_cx) = self.cx.style.rotate.get_animation_mut(self.id) { + anim_cx.keyframes.push((self.time, value)); } else { - - let anim_state = AnimationState::new(self.id) + let anim_cx = AnimationState::new(self.id) .with_duration(self.animation_description.duration) .with_delay(self.animation_description.delay) .set_persistent(self.animation_description.persistent) .with_keyframe((self.time, value)); - self.state.style.rotate.insert_animation(self.id, anim_state); - + self.cx.style.rotate.insert_animation(self.id, anim_cx); } - self + self } pub fn set_opacity(self, value: f32) -> Self { - if let Some(anim_state) = self.state.style.opacity.get_animation_mut(self.id) { - anim_state.keyframes.push((self.time, Opacity(value))); + if let Some(anim_cx) = self.cx.style.opacity.get_animation_mut(self.id) { + anim_cx.keyframes.push((self.time, Opacity(value))); } else { - let anim_state = AnimationState::new(self.id) + let anim_cx = AnimationState::new(self.id) .with_duration(self.animation_description.duration) .with_delay(self.animation_description.delay) .set_persistent(self.animation_description.persistent) .with_keyframe((self.time, Opacity(value))); - - self.state.style.opacity.insert_animation(self.id, anim_state); + self.cx.style.opacity.insert_animation(self.id, anim_cx); } - self + self } - - } diff --git a/core/src/animation/interpolator.rs b/core/src/animation/interpolator.rs index f2528a6cd..7b67c46da 100644 --- a/core/src/animation/interpolator.rs +++ b/core/src/animation/interpolator.rs @@ -16,3 +16,9 @@ impl Interpolator for i32 { return ((start + (end - start)) as f32 * t).round() as i32; } } + +impl Interpolator for (f32, f32) { + fn interpolate(start: &Self, end: &Self, t: f32) -> Self { + return (f32::interpolate(&start.0, &end.0, t), f32::interpolate(&start.1, &end.1, t)); + } +} diff --git a/core/src/animation/mod.rs b/core/src/animation/mod.rs index 637e8e2b4..97ccbd774 100644 --- a/core/src/animation/mod.rs +++ b/core/src/animation/mod.rs @@ -54,8 +54,8 @@ pub(crate) use interpolator::Interpolator; mod transition; pub(crate) use transition::Transition; -// mod animation_builder; -// pub use animation_builder::*; +mod animation_builder; +pub use animation_builder::*; -// mod anim_ext; -// pub use anim_ext::AnimExt; +mod anim_ext; +pub use anim_ext::AnimExt; diff --git a/core/src/cache.rs b/core/src/cache.rs index 93b0b21ab..bbde0b283 100644 --- a/core/src/cache.rs +++ b/core/src/cache.rs @@ -793,10 +793,10 @@ impl CachedData { } } - pub(crate) fn set_scale(&mut self, entity: Entity, val: f32) { + pub(crate) fn set_scale(&mut self, entity: Entity, val: (f32, f32)) { if let Some(transform) = self.transform.get_mut(entity) { let mut t = Transform2D::identity(); - t.scale(val, val); + t.scale(val.0, val.1); transform.premultiply(&t); } } diff --git a/core/src/context.rs b/core/src/context.rs index e84ad0f40..35d549ff3 100644 --- a/core/src/context.rs +++ b/core/src/context.rs @@ -22,6 +22,7 @@ use crate::{ MouseState, PropSet, Propagation, ResourceManager, StoredImage, Style, Tree, TreeDepthIterator, TreeExt, TreeIterator, View, ViewHandler, Visibility, WindowEvent, }; +use crate::{AnimExt, Animation, AnimationBuilder}; static DEFAULT_THEME: &str = include_str!("default_theme.css"); const DOUBLE_CLICK_INTERVAL: Duration = Duration::from_millis(500); @@ -265,6 +266,111 @@ impl Context { Ok(()) } + pub fn has_animations(&self) -> bool { + self.style.display.has_animations() + | self.style.visibility.has_animations() + | self.style.opacity.has_animations() + | self.style.rotate.has_animations() + | self.style.translate.has_animations() + | self.style.scale.has_animations() + | self.style.border_width.has_animations() + | self.style.border_color.has_animations() + | self.style.border_radius_top_left.has_animations() + | self.style.border_radius_top_right.has_animations() + | self.style.border_radius_bottom_left.has_animations() + | self.style.border_radius_bottom_right.has_animations() + | self.style.background_color.has_animations() + | self.style.outer_shadow_h_offset.has_animations() + | self.style.outer_shadow_v_offset.has_animations() + | self.style.outer_shadow_blur.has_animations() + | self.style.outer_shadow_color.has_animations() + | self.style.font_color.has_animations() + | self.style.font_size.has_animations() + | self.style.left.has_animations() + | self.style.right.has_animations() + | self.style.top.has_animations() + | self.style.bottom.has_animations() + | self.style.width.has_animations() + | self.style.height.has_animations() + | self.style.max_width.has_animations() + | self.style.max_height.has_animations() + | self.style.min_width.has_animations() + | self.style.min_height.has_animations() + | self.style.min_left.has_animations() + | self.style.max_left.has_animations() + | self.style.min_right.has_animations() + | self.style.max_right.has_animations() + | self.style.min_top.has_animations() + | self.style.max_top.has_animations() + | self.style.min_bottom.has_animations() + | self.style.max_bottom.has_animations() + | self.style.row_between.has_animations() + | self.style.col_between.has_animations() + | self.style.child_left.has_animations() + | self.style.child_right.has_animations() + | self.style.child_top.has_animations() + | self.style.child_bottom.has_animations() + } + + pub fn apply_animations(&mut self) { + let time = std::time::Instant::now(); + + self.style.display.tick(time); + self.style.visibility.tick(time); + self.style.opacity.tick(time); + self.style.rotate.tick(time); + self.style.translate.tick(time); + self.style.scale.tick(time); + self.style.border_width.tick(time); + self.style.border_color.tick(time); + self.style.border_radius_top_left.tick(time); + self.style.border_radius_top_right.tick(time); + self.style.border_radius_bottom_left.tick(time); + self.style.border_radius_bottom_right.tick(time); + self.style.background_color.tick(time); + self.style.outer_shadow_h_offset.tick(time); + self.style.outer_shadow_v_offset.tick(time); + self.style.outer_shadow_blur.tick(time); + self.style.outer_shadow_color.tick(time); + self.style.font_color.tick(time); + self.style.font_size.tick(time); + self.style.left.tick(time); + self.style.right.tick(time); + self.style.top.tick(time); + self.style.bottom.tick(time); + self.style.width.tick(time); + self.style.height.tick(time); + self.style.max_width.tick(time); + self.style.max_height.tick(time); + self.style.min_width.tick(time); + self.style.min_height.tick(time); + self.style.min_left.tick(time); + self.style.max_left.tick(time); + self.style.min_right.tick(time); + self.style.max_right.tick(time); + self.style.min_top.tick(time); + self.style.max_top.tick(time); + self.style.min_bottom.tick(time); + self.style.max_bottom.tick(time); + self.style.row_between.tick(time); + self.style.col_between.tick(time); + self.style.child_left.tick(time); + self.style.child_right.tick(time); + self.style.child_top.tick(time); + self.style.child_bottom.tick(time); + + self.style.needs_relayout = true; + } + + pub fn add_animation(&mut self, duration: std::time::Duration) -> AnimationBuilder { + let id = self.style.animation_manager.create(); + AnimationBuilder::new(id, self, duration) + } + + pub fn play_animation(&mut self, animation: Animation) { + self.current.play_animation(self, animation); + } + pub fn reload_styles(&mut self) -> Result<(), std::io::Error> { if self.resource_manager.themes.is_empty() && self.resource_manager.stylesheets.is_empty() { return Ok(()); @@ -274,7 +380,7 @@ impl Context { self.style.rules.clear(); - self.style.remove_all(); + self.style.clear_style_rules(); let mut overall_theme = String::new(); @@ -296,13 +402,7 @@ impl Context { self.style.parse_theme(&overall_theme); - // self.enviroment.needs_rebuild = true; - - self.style.needs_restyle = true; - - // Entity::root().restyle(self); - // Entity::root().relayout(self); - // Entity::root().redraw(self); + //self.enviroment.needs_rebuild = true; Ok(()) } @@ -452,8 +552,7 @@ impl Context { } } - /// Massages the style system until everything is coherent - pub fn process_visual_updates(&mut self) { + pub fn process_style_updates(&mut self) { // Not ideal let tree = self.tree.clone(); @@ -465,6 +564,13 @@ impl Context { } apply_shared_inheritance(self, &tree); + } + + /// Massages the style system until everything is coherent + pub fn process_visual_updates(&mut self) { + // Not ideal + let tree = self.tree.clone(); + apply_z_ordering(self, &tree); apply_visibility(self, &tree); diff --git a/core/src/default_theme.css b/core/src/default_theme.css index 9d56c48f2..343f65a45 100644 --- a/core/src/default_theme.css +++ b/core/src/default_theme.css @@ -9,8 +9,8 @@ button { height: 30px; border-radius: 3px; child-space: 1s; - child-left: 5px; - child-right: 5px; + child-left: 10px; + child-right: 10px; border-width: 1px; border-color: #e5e5e5; outer-shadow: 0 1 1 #00000055; @@ -28,7 +28,6 @@ button:over { } button:active { - /* outer-shadow: 0 0 0 #00000055; */ overflow: hidden; } @@ -39,7 +38,6 @@ button:active label { button.accent { background-color: #005a9e; border-width: 0px; - /* border-color: #3076ae */ border-color: #3076ae; outer-shadow: 0 1 0 #00365f; } @@ -61,19 +59,36 @@ button.accent:active label { } checkbox { - width: 25px; - height: 25px; - border-radius: 5px; + width: 20px; + height: 20px; + border-radius: 3px; + border-width: 1px; border-color: #838383; + color: #ffffff00; + background-color: #ffffff00; + child-space: 1s; + transition: background-color 0.1 0.0; + transition: color 0.1 0.0; + transition: color 0.1 0.0; } checkbox:hover { background-color: #e5e5e5; + transition: background-color 0.05 0.0; } checkbox:active { border-color: #b6b6b6; background-color: #dcdcdc; + transition: background-color 0.1 0.0; +} + +checkbox:checked { + background-color: #005a9e; + border-color: #005a9e; + color: #f5f5f5; + transition: background-color 0.1 0.0; + transition: color 0.1 0.0; } label.icon { @@ -87,7 +102,8 @@ textbox { overflow: hidden; color: black; border-width: 1px; - border-color: #9e9e9e; + border-color: #e5e5e5; + background-color: white; child-top: 1s; child-bottom: 1s; child-left: 5px; @@ -96,7 +112,7 @@ textbox { } textbox:hover { - border-color: black; + background-color: #f6f6f6; } textbox:checked { @@ -166,12 +182,6 @@ image { height: auto; } -checkbox { - /* color: black; */ - width: 20px; - height: 20px; -} - hstack { width: 1s; height: 1s; @@ -186,46 +196,44 @@ zstack>* { position-type: self-directed; } -checkbox { +radiobutton { + width: 20px; + height: 20px; border-width: 1px; - border-color: black; - font: icons; + border-radius: 50%; + border-color: #888888; + background-color: white; child-space: 1s; } -checkbox:disabled { - color: gray; - border-color: gray; -} - -radiobutton { - width: 20px; - height: 20px; - border-width: 6%; - right: 4px; - color: black; - border-color: black; +radiobutton:checked { + border-color: #005a9e; + background-color: #005a9e; + transition: background-color 0.1 0.0; } -dropdown .title { +radiobutton .inner { + width: 8px; + height: 8px; + border-radius: 50%; background-color: white; - border-width: 1px; - border-color: black; + display: none; } -radiobutton:checked { - color: #003080; - border-color: #003080; +radiobutton:checked .inner { + display: flex; + width: 12px; + height: 12px; + transition: width 0.1 0.0; + transition: height 0.1 0.0; } dropdown .title { - background-color: #FFFFFF; child-space: 1s; child-left: 5px; } dropdown>popup { - background-color: #AAAAAA; outer-shadow: 0 3 5 #00000055; } @@ -244,12 +252,12 @@ dropdown vstack { } slider { - height: 10px; + height: 5px; top: 1s; bottom: 1s; width: 1s; - background-color: #dfdfdf; - border-radius: 4.5px; + background-color: #868686; + border-radius: 3px; } slider.vertical { @@ -263,7 +271,7 @@ slider track { } slider .active { - background-color: #f74c00; + background-color: #005a9e; border-radius: 4.5px; } @@ -272,10 +280,34 @@ slider .thumb { top: 1s; bottom: 1s; border-radius: 14.5px; - border-color: #757575; + border-color: #cccccc; border-width: 1px; - width: 40px; - height: 40px; + width: 26px; + height: 26px; + child-space: 1s; +} + +slider .thumb>.inner { + width: 14px; + height: 14px; + border-radius: 50%; + background-color: #005a9e; + transition: width 0.1 0.0; + transition: height 0.1 0.0; +} + +slider .thumb:hover>.inner { + width: 18px; + height: 18px; + transition: width 0.1 0.0; + transition: height 0.1 0.0; +} + +slider:active .thumb>.inner { + width: 10px; + height: 10px; + transition: width 0.1 0.0; + transition: height 0.1 0.0; } scrollbar { @@ -328,6 +360,16 @@ list { height: auto; } +popup { + display: none; + opacity: 0.0; +} + +popup:checked { + display: flex; + opacity: 1.0; + transition: opacity 0.1 0.0; +} menucontroller { width: 0px; height: 0px; diff --git a/core/src/handle.rs b/core/src/handle.rs index 4d11e2610..fdb224214 100644 --- a/core/src/handle.rs +++ b/core/src/handle.rs @@ -364,6 +364,7 @@ impl<'a, T> Handle<'a, T> { set_style!(rotate, f32); set_style!(translate, (f32, f32)); + set_style!(scale, (f32, f32)); set_style!(border_shape_top_left, BorderCornerShape); set_style!(border_shape_top_right, BorderCornerShape); diff --git a/core/src/input/mouse.rs b/core/src/input/mouse.rs index 9f8187030..36dbd5389 100644 --- a/core/src/input/mouse.rs +++ b/core/src/input/mouse.rs @@ -57,8 +57,8 @@ pub struct MouseState { impl Default for MouseState { fn default() -> Self { MouseState { - cursorx: 0.0, - cursory: 0.0, + cursorx: -1.0, + cursory: -1.0, left: MouseButtonData::default(), right: MouseButtonData::default(), middle: MouseButtonData::default(), diff --git a/core/src/storage/animatable_set.rs b/core/src/storage/animatable_set.rs index 2c8dfe50b..51f17c87d 100644 --- a/core/src/storage/animatable_set.rs +++ b/core/src/storage/animatable_set.rs @@ -288,6 +288,7 @@ where } pub fn play_animation(&mut self, entity: Entity, animation: Animation) { + //println!("Play Animation: {:?}", animation); let entity_index = entity.index(); if !self.animations.contains(animation) { @@ -387,6 +388,7 @@ where state.output = Some(T::interpolate(&start.1, &end.1, 1.0)); if !state.persistent { + //state.output = Some(T::interpolate(&start.1, &end.1, 0.0)); state.t = 1.0; state.active = false; } else { @@ -551,9 +553,12 @@ where //if let Some(transition_state) = self.animations.get_mut(rule_animation) { let entity_anim_index = self.inline_data.sparse[entity_index].anim_index as usize; if entity_anim_index < self.active_animations.len() { + // Already animating + let current_value = self.get(entity).cloned().unwrap_or_default(); let current_anim_state = &mut self.active_animations[entity_anim_index]; let rule_data_index = shared_data_index.data_index as usize; if rule_data_index == current_anim_state.from_rule { + // Transitioning back to previous rule current_anim_state.from_rule = current_anim_state.to_rule; current_anim_state.to_rule = rule_data_index; *current_anim_state.keyframes.first_mut().unwrap() = ( @@ -564,14 +569,24 @@ where (1.0, self.shared_data.dense[current_anim_state.to_rule].value.clone()); current_anim_state.delay = current_anim_state.t - 1.0; current_anim_state.start_time = instant::Instant::now(); + } else { + // Transitioning to new rule + current_anim_state.to_rule = rule_data_index; + *current_anim_state.keyframes.first_mut().unwrap() = (0.0, current_value); + *current_anim_state.keyframes.last_mut().unwrap() = + (1.0, self.shared_data.dense[current_anim_state.to_rule].value.clone()); + current_anim_state.t = 0.0; + current_anim_state.t0 = 0.0; + current_anim_state.start_time = instant::Instant::now(); } } else { - if rule_animation.index() < self.animations.dense.len() { - let transition_state = - &mut self.animations.dense[rule_animation.index()].value; + if let Some(transition_state) = self.animations.get_mut(rule_animation) { + //if rule_animation.index() < self.animations.dense.len() { + // let transition_state = + // &mut self.animations.dense[rule_animation.index()].value; + //let transition_state = self.animations.get_mut(rule_animation).unwrap(); // Safe to unwrap because already checked that the rule exists let end = self.shared_data.get(*rule).unwrap(); - //println!("End: {:?}", end); let entity_data_index = self.inline_data.sparse[entity_index].data_index; @@ -589,8 +604,8 @@ where transition_state.from_rule = self.inline_data.sparse[entity_index].data_index.index(); transition_state.to_rule = shared_data_index.index(); - self.play_animation(entity, rule_animation); + //} } } //} @@ -624,10 +639,12 @@ where pub fn clear_rules(&mut self) { // Remove transitions (TODO) - for _index in self.shared_data.sparse.iter() { - //let anim_index = index.anim_index as usize; + for index in self.shared_data.sparse.iter() { + let animation = index.animation; + self.animations.remove(animation); } - + self.animations.clear(); + self.active_animations.clear(); self.shared_data.clear(); for index in self.inline_data.sparse.iter_mut() { diff --git a/core/src/style/mod.rs b/core/src/style/mod.rs index 3529ff83c..2684998ed 100644 --- a/core/src/style/mod.rs +++ b/core/src/style/mod.rs @@ -1,4 +1,4 @@ -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use morphorm::{LayoutType, PositionType, Units}; @@ -24,8 +24,8 @@ pub use display::*; mod transform; pub use transform::*; -mod theme; -pub use theme::*; +mod parser; +pub use parser::*; mod style_rule; use style_rule::StyleRule; @@ -48,199 +48,6 @@ use shadow::*; mod prop; pub use prop::*; -use morphorm::Units::*; - -// #[derive(Default)] -// pub struct Style { - -// pub classes: SparseSet>, - -// pub position_type: StyleSet, -// pub layout_type: StyleSet, - -// pub left: AnimatableSet, -// pub right: AnimatableSet, -// pub top: AnimatableSet, -// pub bottom: AnimatableSet, - -// pub min_left: AnimatableSet, -// pub max_left: AnimatableSet, -// pub min_right: AnimatableSet, -// pub max_right: AnimatableSet, -// pub min_top: AnimatableSet, -// pub max_top: AnimatableSet, -// pub min_bottom: AnimatableSet, -// pub max_bottom: AnimatableSet, - -// pub width: AnimatableSet, -// pub height: AnimatableSet, - -// pub min_width: AnimatableSet, -// pub max_width: AnimatableSet, -// pub min_height: AnimatableSet, -// pub max_height: AnimatableSet, - -// pub child_left: AnimatableSet, -// pub child_right: AnimatableSet, -// pub child_top: AnimatableSet, -// pub child_bottom: AnimatableSet, - -// pub row_between: AnimatableSet, -// pub col_between: AnimatableSet, - -// pub grid_rows: StyleSet>, -// pub grid_cols: StyleSet>, - -// pub row_index: StyleSet, -// pub row_span: StyleSet, -// pub col_index: StyleSet, -// pub col_span: StyleSet, - -// // Border -// pub border_width: AnimatableSet, -// pub border_color: AnimatableSet, - -// // Border Shape -// pub border_shape_top_left: StyleSet, -// pub border_shape_top_right: StyleSet, -// pub border_shape_bottom_left: StyleSet, -// pub border_shape_bottom_right: StyleSet, - -// // Border Radius -// pub border_radius_top_left: AnimatableSet, -// pub border_radius_top_right: AnimatableSet, -// pub border_radius_bottom_left: AnimatableSet, -// pub border_radius_bottom_right: AnimatableSet, - -// pub background_color: AnimatableSet, - -// pub text: StyleSet, -// } - -// impl Style { -// pub fn remove(&mut self, entity: Entity) { -// self.classes.remove(entity); - -// self.position_type.remove(entity); -// self.layout_type.remove(entity); - -// self.left.remove(entity); -// self.right.remove(entity); -// self.top.remove(entity); -// self.bottom.remove(entity); -// self.min_left.remove(entity); -// self.max_left.remove(entity); -// self.min_right.remove(entity); -// self.max_right.remove(entity); -// self.min_top.remove(entity); -// self.max_top.remove(entity); -// self.min_bottom.remove(entity); -// self.max_bottom.remove(entity); -// self.width.remove(entity); -// self.height.remove(entity); -// self.min_width.remove(entity); -// self.max_width.remove(entity); -// self.min_height.remove(entity); -// self.max_height.remove(entity); -// self.child_left.remove(entity); -// self.child_right.remove(entity); -// self.child_top.remove(entity); -// self.child_bottom.remove(entity); -// self.row_between.remove(entity); -// self.col_between.remove(entity); -// self.grid_rows.remove(entity); -// self.grid_cols.remove(entity); -// self.row_index.remove(entity); -// self.row_span.remove(entity); -// self.col_index.remove(entity); -// self.col_span.remove(entity); -// self.border_width.remove(entity); -// self.border_color.remove(entity); -// self.border_radius_top_left.remove(entity); -// self.border_radius_top_right.remove(entity); -// self.border_radius_bottom_left.remove(entity); -// self.border_radius_bottom_right.remove(entity); -// self.border_shape_top_left.remove(entity); -// self.border_shape_top_right.remove(entity); -// self.border_shape_bottom_left.remove(entity); -// self.border_shape_bottom_right.remove(entity); -// self.background_color.remove(entity); -// self.text.remove(entity); -// } -// } - -// //! Style Data -// //! -// //! The [Style] struct is responsible for storing all of the style properties for all of the entities, -// //! as well as storing style rule definitions created by the user or parsed from stylesheets. - -// use cssparser::{Parser, ParserInput}; - -// use std::collections::HashSet; - -// use crate::{Animation, CursorIcon, IdManager}; -// use crate::{Entity, Transition}; - -// use crate::Interpolator; - -// use crate::AnimationState; - -// mod themes; - -// mod theme; -// pub use theme::StyleParseError; - -// mod prop; -// pub use prop::{PropGet, PropSet}; - -// mod prop_set; -// pub use prop_set::PropSet2; - -// mod layout; -// pub use layout::*; - -// pub use morphorm::{LayoutType, PositionType, Units}; -// pub use Units::*; - -// mod units; - -// mod gradient; -// pub use gradient::*; - -// mod shadow; -// pub(crate) use shadow::*; - -// mod display; -// pub use display::*; - -// mod property; -// pub use property::*; - -// mod selector; -// pub use selector::*; - -// mod specificity; -// pub(crate) use specificity::*; - -// mod style_rule; -// pub(crate) use style_rule::*; - -// mod rule; -// pub use rule::Rule; - -// mod color; -// pub use color::Color; - -// mod transform; -// pub use transform::*; - -// use std::rc::Rc; - -// use super::storage::animatable_set::AnimatableSet; -// use super::storage::sparse_set::SparseSet; -// use super::storage::style_set::StyleSet; - -// use bimap::BiMap; use bitflags::bitflags; bitflags! { @@ -268,6 +75,8 @@ pub struct Style { pub(crate) rules: Vec, + pub transitions: HashMap, + pub default_font: String, pub elements: SparseSet, @@ -294,8 +103,8 @@ pub struct Style { // Transform pub rotate: AnimatableSet, - pub translate: StyleSet<(f32, f32)>, - pub scale: AnimatableSet, + pub translate: AnimatableSet<(f32, f32)>, + pub scale: AnimatableSet<(f32, f32)>, pub overflow: StyleSet, // TODO //pub scroll: DenseStorage, // TODO @@ -424,12 +233,16 @@ impl Style { for rule in self.rules.iter() { self.rule_manager.destroy(rule.id); } + + for (_, animation) in self.transitions.iter() { + self.animation_manager.destroy(*animation); + } } pub fn parse_theme(&mut self, stylesheet: &str) { let mut input = ParserInput::new(stylesheet); let mut parser = Parser::new(&mut input); - let rule_parser = theme::RuleParser::new(); + let rule_parser = parser::RuleParser::new(); let rules = { let rule_list_parser = @@ -464,7 +277,7 @@ impl Style { // print!("{}", rule); // } - self.remove_all(); + self.clear_style_rules(); self.set_style_properties(); } @@ -555,13 +368,6 @@ impl Style { // Size Property::Width(value) => { - match value { - Percentage(val) => { - println!("{:?} {}", rule, val); - } - - _ => {} - } self.width.insert_rule(rule_id, value); } @@ -747,7 +553,6 @@ impl Style { // Transitions Property::Transition(transitions) => { for transition in transitions { - println!("{:?}", transition); match transition.property.as_ref() { "background-color" => { let animation = self.animation_manager.create(); @@ -756,6 +561,7 @@ impl Style { self.add_transition(transition), ); self.background_color.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "left" => { @@ -765,6 +571,7 @@ impl Style { self.add_transition(transition), ); self.left.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "top" => { @@ -774,6 +581,7 @@ impl Style { self.add_transition(transition), ); self.top.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "right" => { @@ -783,6 +591,7 @@ impl Style { self.add_transition(transition), ); self.right.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "bottom" => { @@ -792,6 +601,7 @@ impl Style { self.add_transition(transition), ); self.bottom.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "min-left" => { @@ -801,6 +611,7 @@ impl Style { self.add_transition(transition), ); self.min_left.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "max-left" => { @@ -810,6 +621,7 @@ impl Style { self.add_transition(transition), ); self.max_left.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "min-right" => { @@ -819,6 +631,7 @@ impl Style { self.add_transition(transition), ); self.min_right.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "max-right" => { @@ -828,6 +641,7 @@ impl Style { self.add_transition(transition), ); self.max_right.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "min-top" => { @@ -837,6 +651,7 @@ impl Style { self.add_transition(transition), ); self.min_top.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "max-top" => { @@ -846,6 +661,7 @@ impl Style { self.add_transition(transition), ); self.max_top.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "min-bottom" => { @@ -855,6 +671,7 @@ impl Style { self.add_transition(transition), ); self.min_bottom.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "max-bottom" => { @@ -864,6 +681,7 @@ impl Style { self.add_transition(transition), ); self.max_bottom.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "width" => { @@ -873,6 +691,7 @@ impl Style { self.add_transition(transition), ); self.width.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "height" => { @@ -882,6 +701,7 @@ impl Style { self.add_transition(transition), ); self.height.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "min-width" => { @@ -891,6 +711,7 @@ impl Style { self.add_transition(transition), ); self.min_width.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "max-width" => { @@ -900,6 +721,7 @@ impl Style { self.add_transition(transition), ); self.max_width.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "min-height" => { @@ -909,6 +731,7 @@ impl Style { self.add_transition(transition), ); self.min_height.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "max-height" => { @@ -918,6 +741,7 @@ impl Style { self.add_transition(transition), ); self.max_height.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "child-left" => { @@ -927,6 +751,7 @@ impl Style { self.add_transition(transition), ); self.child_left.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "child-right" => { @@ -936,6 +761,7 @@ impl Style { self.add_transition(transition), ); self.child_right.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "child-top" => { @@ -945,6 +771,7 @@ impl Style { self.add_transition(transition), ); self.child_top.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "child-bottom" => { @@ -954,6 +781,7 @@ impl Style { self.add_transition(transition), ); self.child_bottom.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "opacity" => { @@ -963,6 +791,7 @@ impl Style { self.add_transition(transition), ); self.opacity.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } "outer-shadow-color" => { @@ -972,6 +801,7 @@ impl Style { self.add_transition(transition), ); self.outer_shadow_color.insert_transition(rule_id, animation); + self.transitions.insert(rule_id, animation); } _ => {} @@ -1002,512 +832,13 @@ impl Style { .with_keyframe((1.0, Default::default())) } - /* - pub fn parse_theme2(&mut self, stylesheet: &str) { - let mut input = ParserInput::new(stylesheet); - let mut parser = Parser::new(&mut input); - let rule_parser = theme::RuleParser::new(); - - let rules = { - let rule_list_parser = - cssparser::RuleListParser::new_for_stylesheet(&mut parser, rule_parser); - rule_list_parser.collect::>() - }; - - let mut rule_list: Vec = - rules.into_iter().filter_map(|rule| rule.ok()).collect(); - rule_list.sort_by_key(|rule| rule.specificity()); - rule_list.reverse(); - - for rule in rule_list.iter() { - let rule_id = self.rules.len(); - //println!("Rule: {}, Specificity: {:?}, rule: {:?}", rule_id, rule.specificity(), rule); - //self.rule_selectors.push(rule.selectors.clone()); - self.rules.push(rule.clone()); - //self.rules.push(rule_id); - for property in rule.properties.clone() { - match property { - Property::Display(value) => { - self.display.insert_rule(rule_id, value); - } - - Property::Visibility(value) => { - self.visibility.insert_rule(rule_id, value); - } - - Property::Opacity(value) => { - self.opacity.insert_rule(rule_id, Opacity(value)); - } - - Property::Overflow(value) => { - self.overflow.insert_rule(rule_id, value); - } - - Property::TextAlign(value) => { - self.text_align.insert_rule(rule_id, value); - } - - Property::TextJustify(value) => { - self.text_justify.insert_rule(rule_id, value); - } - - Property::Position(value) => { - self.position.insert_rule(rule_id, value); - } - - Property::Left(value) => { - self.left.insert_rule(rule_id, value); - } - - Property::Right(value) => { - self.right.insert_rule(rule_id, value); - } - - Property::Top(value) => { - self.top.insert_rule(rule_id, value); - } - - Property::Bottom(value) => { - self.bottom.insert_rule(rule_id, value); - } - - Property::Width(value) => { - self.width.insert_rule(rule_id, value); - } - - Property::Height(value) => { - self.height.insert_rule(rule_id, value); - } - - Property::MaxWidth(value) => { - self.max_width.insert_rule(rule_id, value); - } - - Property::MinWidth(value) => { - self.min_width.insert_rule(rule_id, value); - } - - Property::MaxHeight(value) => { - self.max_height.insert_rule(rule_id, value); - } - - Property::MinHeight(value) => { - self.min_height.insert_rule(rule_id, value); - } - - Property::Padding(value) => { - self.padding_left.insert_rule(rule_id, value); - self.padding_right.insert_rule(rule_id, value); - self.padding_top.insert_rule(rule_id, value); - self.padding_bottom.insert_rule(rule_id, value); - } - - Property::PaddingLeft(value) => { - self.padding_left.insert_rule(rule_id, value); - } - - Property::PaddingRight(value) => { - self.padding_right.insert_rule(rule_id, value); - } - - Property::PaddingTop(value) => { - self.padding_top.insert_rule(rule_id, value); - } - - Property::PaddingBottom(value) => { - self.padding_bottom.insert_rule(rule_id, value); - } - - // Border - Property::BorderWidth(value) => { - self.border_width.insert_rule(rule_id, value); - } - - Property::BorderColor(value) => { - self.border_color.insert_rule(rule_id, value); - } - - Property::BorderRadius(value) => { - self.border_radius_top_left.insert_rule(rule_id, value); - self.border_radius_top_right.insert_rule(rule_id, value); - self.border_radius_bottom_left.insert_rule(rule_id, value); - self.border_radius_bottom_right.insert_rule(rule_id, value); - } - - Property::BorderTopLeftRadius(value) => { - self.border_radius_top_left.insert_rule(rule_id, value); - } - - Property::BorderTopRightRadius(value) => { - self.border_radius_top_right.insert_rule(rule_id, value); - } - - Property::BorderBottomLeftRadius(value) => { - self.border_radius_bottom_left.insert_rule(rule_id, value); - } - - Property::BorderBottomRightRadius(value) => { - self.border_radius_bottom_right.insert_rule(rule_id, value); - } - - Property::FontSize(value) => { - self.font_size.insert_rule(rule_id, value); - } - - Property::FontColor(value) => { - self.font_color.insert_rule(rule_id, value); - } - - Property::BackgroundColor(value) => { - self.background_color.insert_rule(rule_id, value); - } - - // Property::BackgroundImage(value) => { - // self.background_image.insert_rule(rule_id, value); - // } - - // Flex Container - Property::FlexDirection(value) => { - self.flex_direction.insert_rule(rule_id, value); - } - Property::JustifyContent(value) => { - self.justify_content.insert_rule(rule_id, value); - } - Property::AlignContent(value) => { - self.align_content.insert_rule(rule_id, value); - } - Property::AlignItems(value) => { - self.align_items.insert_rule(rule_id, value); - } - - Property::AlignSelf(value) => { - self.align_self.insert_rule(rule_id, value); - } - - // Flex Item - Property::FlexGrow(value) => { - self.flex_grow.insert_rule(rule_id, value); - } - - Property::FlexShrink(value) => { - self.flex_shrink.insert_rule(rule_id, value); - } - - Property::FlexBasis(value) => { - self.flex_basis.insert_rule(rule_id, value); - } - - Property::ZIndex(value) => { - self.z_order.insert_rule(rule_id, value); - } - - Property::OuterShadow(box_shadow) => { - self.outer_shadow_h_offset - .insert_rule(rule_id, box_shadow.horizontal_offset); - self.outer_shadow_v_offset - .insert_rule(rule_id, box_shadow.vertical_offset); - self.outer_shadow_blur - .insert_rule(rule_id, box_shadow.blur_radius); - self.outer_shadow_color - .insert_rule(rule_id, box_shadow.color); - } - - Property::InnerShadow(box_shadow) => { - self.inner_shadow_h_offset - .insert_rule(rule_id, box_shadow.horizontal_offset); - self.inner_shadow_v_offset - .insert_rule(rule_id, box_shadow.vertical_offset); - self.inner_shadow_blur - .insert_rule(rule_id, box_shadow.blur_radius); - self.inner_shadow_color - .insert_rule(rule_id, box_shadow.color); - } - - Property::Transition(transitions) => { - for transition in transitions { - match transition.property.as_ref() { - "background-color" => { - self.background_color.insert_transition( - rule_id, - AnimationState::new() - .with_duration(instant::Duration::from_secs_f32( - transition.duration, - )) - .with_delay(instant::Duration::from_secs_f32( - transition.delay, - )) - .with_keyframe((0.0, Default::default())) - .with_keyframe((1.0, Default::default())), - ); - } - - "flex-basis" => { - self.flex_basis.insert_transition( - rule_id, - AnimationState::new() - .with_duration(instant::Duration::from_secs_f32( - transition.duration, - )) - .with_delay(instant::Duration::from_secs_f32( - transition.delay, - )) - .with_keyframe((0.0, Default::default())) - .with_keyframe((1.0, Default::default())), - ); - } - - "left" => { - self.left.insert_transition( - rule_id, - AnimationState::new() - .with_duration(instant::Duration::from_secs_f32( - transition.duration, - )) - .with_delay(instant::Duration::from_secs_f32( - transition.delay, - )) - .with_keyframe((0.0, Default::default())) - .with_keyframe((1.0, Default::default())), - ); - } - - "top" => { - self.top.insert_transition( - rule_id, - AnimationState::new() - .with_duration(instant::Duration::from_secs_f32( - transition.duration, - )) - .with_delay(instant::Duration::from_secs_f32( - transition.delay, - )) - .with_keyframe((0.0, Default::default())) - .with_keyframe((1.0, Default::default())), - ); - } - - "right" => { - self.right.insert_transition( - rule_id, - AnimationState::new() - .with_duration(instant::Duration::from_secs_f32( - transition.duration, - )) - .with_delay(instant::Duration::from_secs_f32( - transition.delay, - )) - .with_keyframe((0.0, Default::default())) - .with_keyframe((1.0, Default::default())), - ); - } - - "bottom" => { - self.bottom.insert_transition( - rule_id, - AnimationState::new() - .with_duration(instant::Duration::from_secs_f32( - transition.duration, - )) - .with_delay(instant::Duration::from_secs_f32( - transition.delay, - )) - .with_keyframe((0.0, Default::default())) - .with_keyframe((1.0, Default::default())), - ); - } - - "width" => { - self.width.insert_transition( - rule_id, - AnimationState::new() - .with_duration(instant::Duration::from_secs_f32( - transition.duration, - )) - .with_delay(instant::Duration::from_secs_f32( - transition.delay, - )) - .with_keyframe((0.0, Default::default())) - .with_keyframe((1.0, Default::default())), - ); - } - - "height" => { - self.height.insert_transition( - rule_id, - AnimationState::new() - .with_duration(instant::Duration::from_secs_f32( - transition.duration, - )) - .with_delay(instant::Duration::from_secs_f32( - transition.delay, - )) - .with_keyframe((0.0, Default::default())) - .with_keyframe((1.0, Default::default())), - ); - } - - "margin-bottom" => { - self.margin_bottom.insert_transition( - rule_id, - AnimationState::new() - .with_duration(instant::Duration::from_secs_f32( - transition.duration, - )) - .with_delay(instant::Duration::from_secs_f32( - transition.delay, - )) - .with_keyframe((0.0, Default::default())) - .with_keyframe((1.0, Default::default())), - ); - } - - "margin-top" => { - self.margin_top.insert_transition( - rule_id, - AnimationState::new() - .with_duration(instant::Duration::from_secs_f32( - transition.duration, - )) - .with_delay(instant::Duration::from_secs_f32( - transition.delay, - )) - .with_keyframe((0.0, Default::default())) - .with_keyframe((1.0, Default::default())), - ); - } - - "margin-left" => { - self.margin_left.insert_transition( - rule_id, - AnimationState::new() - .with_duration(instant::Duration::from_secs_f32( - transition.duration, - )) - .with_delay(instant::Duration::from_secs_f32( - transition.delay, - )) - .with_keyframe((0.0, Default::default())) - .with_keyframe((1.0, Default::default())), - ); - } - - "margin-right" => { - self.margin_right.insert_transition( - rule_id, - AnimationState::new() - .with_duration(instant::Duration::from_secs_f32( - transition.duration, - )) - .with_delay(instant::Duration::from_secs_f32( - transition.delay, - )) - .with_keyframe((0.0, Default::default())) - .with_keyframe((1.0, Default::default())), - ); - } - - "padding-left" => { - self.padding_left.insert_transition( - rule_id, - AnimationState::new() - .with_duration(instant::Duration::from_secs_f32( - transition.duration, - )) - .with_delay(instant::Duration::from_secs_f32( - transition.delay, - )) - .with_keyframe((0.0, Default::default())) - .with_keyframe((1.0, Default::default())), - ); - } - - "padding-right" => { - self.padding_right.insert_transition( - rule_id, - AnimationState::new() - .with_duration(instant::Duration::from_secs_f32( - transition.duration, - )) - .with_delay(instant::Duration::from_secs_f32( - transition.delay, - )) - .with_keyframe((0.0, Default::default())) - .with_keyframe((1.0, Default::default())), - ); - } - - "padding-top" => { - self.padding_top.insert_transition( - rule_id, - AnimationState::new() - .with_duration(instant::Duration::from_secs_f32( - transition.duration, - )) - .with_delay(instant::Duration::from_secs_f32( - transition.delay, - )) - .with_keyframe((0.0, Default::default())) - .with_keyframe((1.0, Default::default())), - ); - } - - "padding-bottom" => { - self.padding_bottom.insert_transition( - rule_id, - AnimationState::new() - .with_duration(instant::Duration::from_secs_f32( - transition.duration, - )) - .with_delay(instant::Duration::from_secs_f32( - transition.delay, - )) - .with_keyframe((0.0, Default::default())) - .with_keyframe((1.0, Default::default())), - ); - } - - "opacity" => { - self.opacity.insert_transition( - rule_id, - AnimationState::new() - .with_duration(instant::Duration::from_secs_f32( - transition.duration, - )) - .with_delay(instant::Duration::from_secs_f32( - transition.delay, - )) - .with_keyframe((0.0, Default::default())) - .with_keyframe((1.0, Default::default())), - ); - } - - _ => {} - } - } - } - _ => {} - } - } - } - } - */ - - // TODO - //pub fn set_property(&mut self, entity: Entity, propert: Property) {} - // Add style data to an entity pub fn add(&mut self, entity: Entity) { self.pseudo_classes .insert(entity, PseudoClass::default()) .expect("Failed to add pseudoclasses"); self.classes.insert(entity, HashSet::new()).expect("Failed to add class list"); - self.abilities.insert(entity, Abilities::default()).expect("Failed to add abilities"); - //self.z_order.insert(entity, 0); - - //self.overflow.insert(entity, Default::default()); - //self.scroll.insert(entity, Default::default()); - self.visibility.insert(entity, Default::default()); self.focus_order.insert(entity, Default::default()).unwrap(); } @@ -1626,32 +957,70 @@ impl Style { self.image.remove(entity); } - pub fn remove_all(&mut self) { + pub fn clear_style_rules(&mut self) { + //self.disabled.clear_rules(entity); + //self.abilities.clear_rules(entity); + // Display + self.display.clear_rules(); + // Visibility + self.visibility.clear_rules(); + // Opacity + self.opacity.clear_rules(); + // Z Order self.z_order.clear_rules(); - self.rotate.clear_rules(); + + // Transform self.translate.clear_rules(); + self.rotate.clear_rules(); self.scale.clear_rules(); + self.overflow.clear_rules(); - // Remove all non-inline style data + // Border + self.border_width.clear_rules(); + self.border_color.clear_rules(); + + // Border Shape + self.border_shape_bottom_left.clear_rules(); + self.border_shape_bottom_right.clear_rules(); + self.border_shape_top_left.clear_rules(); + self.border_shape_top_right.clear_rules(); + + // Border Radius + self.border_radius_bottom_left.clear_rules(); + self.border_radius_bottom_right.clear_rules(); + self.border_radius_top_left.clear_rules(); + self.border_radius_bottom_right.clear_rules(); + + // Background self.background_color.clear_rules(); self.background_image.clear_rules(); self.background_gradient.clear_rules(); - self.font_color.clear_rules(); - self.font.clear_rules(); - self.font_size.clear_rules(); + self.outer_shadow_h_offset.clear_rules(); + self.outer_shadow_v_offset.clear_rules(); + self.outer_shadow_blur.clear_rules(); + self.outer_shadow_color.clear_rules(); + + self.inner_shadow_h_offset.clear_rules(); + self.inner_shadow_v_offset.clear_rules(); + self.inner_shadow_blur.clear_rules(); + self.inner_shadow_color.clear_rules(); - self.position_type.clear_rules(); self.layout_type.clear_rules(); + self.position_type.clear_rules(); - // Position + // Space self.left.clear_rules(); self.right.clear_rules(); self.top.clear_rules(); self.bottom.clear_rules(); - // Position Constraints + // Size + self.width.clear_rules(); + self.height.clear_rules(); + + // Space Constraints self.min_left.clear_rules(); self.max_left.clear_rules(); self.min_right.clear_rules(); @@ -1661,62 +1030,36 @@ impl Style { self.min_bottom.clear_rules(); self.max_bottom.clear_rules(); - // Size - self.width.clear_rules(); - self.height.clear_rules(); - // Size Constraints self.min_width.clear_rules(); self.max_width.clear_rules(); self.min_height.clear_rules(); self.max_height.clear_rules(); + self.content_width.clear_rules(); + self.content_height.clear_rules(); - // + // Child Space self.child_left.clear_rules(); self.child_right.clear_rules(); self.child_top.clear_rules(); self.child_bottom.clear_rules(); - - // Border - self.border_width.clear_rules(); - self.border_color.clear_rules(); - - // Border Radius - self.border_radius_top_left.clear_rules(); - self.border_radius_top_right.clear_rules(); - self.border_radius_bottom_left.clear_rules(); - self.border_radius_bottom_right.clear_rules(); - - self.border_shape_top_left.clear_rules(); - self.border_shape_top_right.clear_rules(); - self.border_shape_bottom_left.clear_rules(); - self.border_shape_bottom_right.clear_rules(); - - // Display - self.display.clear_rules(); - self.visibility.clear_rules(); - self.opacity.clear_rules(); - - // Inner Shadow - self.inner_shadow_h_offset.clear_rules(); - self.inner_shadow_v_offset.clear_rules(); - self.inner_shadow_blur.clear_rules(); - self.inner_shadow_color.clear_rules(); - - // Outer Shadow - self.outer_shadow_h_offset.clear_rules(); - self.outer_shadow_v_offset.clear_rules(); - self.outer_shadow_blur.clear_rules(); - self.outer_shadow_color.clear_rules(); - - self.grid_rows.clear_rules(); - self.grid_cols.clear_rules(); - self.row_between.clear_rules(); self.col_between.clear_rules(); + self.row_between.clear_rules(); - self.row_index.clear_rules(); + // Grid + self.grid_cols.clear_rules(); + self.grid_rows.clear_rules(); self.col_index.clear_rules(); - self.row_span.clear_rules(); self.col_span.clear_rules(); + self.row_index.clear_rules(); + self.row_span.clear_rules(); + + // Text and Font + self.text.clear_rules(); + self.font.clear_rules(); + self.font_color.clear_rules(); + self.font_size.clear_rules(); + + self.image.clear_rules(); } } diff --git a/core/src/style/theme.rs b/core/src/style/parser.rs similarity index 100% rename from core/src/style/theme.rs rename to core/src/style/parser.rs diff --git a/core/src/style/prop.rs b/core/src/style/prop.rs index 0d00c9bf8..b7465060f 100644 --- a/core/src/style/prop.rs +++ b/core/src/style/prop.rs @@ -503,7 +503,7 @@ pub trait PropSet: AsEntity + Sized { self.entity() } - fn set_scale(self, cx: &mut Context, value: f32) -> Entity { + fn set_scale(self, cx: &mut Context, value: (f32, f32)) -> Entity { cx.style.scale.insert(self.entity(), value); cx.style.needs_redraw = true; diff --git a/core/src/style/transform.rs b/core/src/style/transform.rs index 693d3efe9..8b0a777ed 100644 --- a/core/src/style/transform.rs +++ b/core/src/style/transform.rs @@ -140,11 +140,11 @@ pub fn apply_transform(cx: &mut Context, tree: &Tree) { } //println!("End"); - if let Some(scale) = cx.style.scale.get(entity) { + if let Some((scalex, scaley)) = cx.style.scale.get(entity) { let x = bounds.x + (bounds.w / 2.0); let y = bounds.y + (bounds.h / 2.0); cx.cache.set_translate(entity, (x, y)); - cx.cache.set_scale(entity, *scale); + cx.cache.set_scale(entity, (*scalex, *scaley)); cx.cache.set_translate(entity, (-x, -y)); } } diff --git a/core/src/views/button.rs b/core/src/views/button.rs index 3e8db2879..4c7cd2680 100644 --- a/core/src/views/button.rs +++ b/core/src/views/button.rs @@ -16,7 +16,7 @@ impl Button { Label: 'static + View, { Self { action: Some(Box::new(action)) }.build2(cx, move |cx| { - (label)(cx).focusable(false); + (label)(cx).hoverable(false).focusable(false); }) } } diff --git a/core/src/views/dropdown.rs b/core/src/views/dropdown.rs index eece8ecbe..df2ef51e4 100644 --- a/core/src/views/dropdown.rs +++ b/core/src/views/dropdown.rs @@ -1,5 +1,5 @@ use crate::{ - Actions, Context, Handle, Model, Overflow, Popup, PopupData, PopupEvent, Units::*, View, + Button, Context, Handle, Model, Overflow, Popup, PopupData, PopupEvent, Units::*, View, }; pub const ICON_DOWN_OPEN: &str = "\u{e75c}"; @@ -9,7 +9,7 @@ pub struct Dropdown {} impl Dropdown { pub fn new(cx: &mut Context, label: L, builder: F) -> Handle where - L: FnOnce(&mut Context) -> Handle