diff --git a/Cargo.toml b/Cargo.toml index 041f86eea..3d55e4b51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ dioxus-core = { version = "0.4" } dioxus-hot-reload = { version = "0.4", features = ["file_watcher"] } dioxus-router = { version = "0.4" } -skia-safe = { version = "0.63.0", features = ["gl", "textlayout", "svg"] } +skia-safe = { version = "0.66.3", features = ["gl", "textlayout", "svg"] } gl = "0.14.0" glutin = "0.30.6" diff --git a/book/src/differences_with_dioxus.md b/book/src/differences_with_dioxus.md index 72cc46c02..21013e6b9 100644 --- a/book/src/differences_with_dioxus.md +++ b/book/src/differences_with_dioxus.md @@ -7,7 +7,7 @@ These are the main differences between Freya and the different Dioxus renderers | Category | Freya | Dioxus | |--------------------------------------|------------------|---------------------------------| | **Elements, attributes and events** | Custom | HTML | -| **Layout** | Custom ([`torin`](https://github.com/marc2332/freya/tree/main/torin)) | WebView and [`taffy`](https://github.com/DioxusLabs/taffy) | +| **Layout** | [`Torin`](https://github.com/marc2332/freya/tree/main/crates/torin) | WebView and [`Taffy`](https://github.com/DioxusLabs/taffy) | | **Renderer** | Skia | WebView or WGPU | | **Components library** | Custom | None, but can use CSS libraries | | **Devtools** | Custom | Provided in Webview | diff --git a/book/src/guides/animating.md b/book/src/guides/animating.md index d6ff62cee..9afdf8808 100644 --- a/book/src/guides/animating.md +++ b/book/src/guides/animating.md @@ -19,13 +19,12 @@ fn main() { } fn app(cx: Scope) -> Element { - let animation = use_animation(cx, 0.0); + let animation = use_animation(cx, || 0.0); let progress = animation.value(); - use_effect(cx, (), move |_| { + use_memo(cx, (), move |_| { animation.start(Animation::new_linear(0.0..=100.0, 50)); - async move {} }); render!(rect { diff --git a/book/src/guides/components.md b/book/src/guides/components.md index 08005dd77..c869b6205 100644 --- a/book/src/guides/components.md +++ b/book/src/guides/components.md @@ -20,3 +20,4 @@ Freya comes with a set of ready to use components: - [`Slider`](https://docs.rs/freya/latest/freya/components/fn.Slider.html) - [`ThemeProvider`](https://docs.rs/freya/latest/freya/components/fn.ThemeProvider.html) - [`Tooltip`](https://docs.rs/freya/latest/freya/components/fn.Tooltip.html) +- [`ProgressBar`](https://docs.rs/freya/latest/freya/components/fn.ProgressBar.html) diff --git a/crates/components/Cargo.toml b/crates/components/Cargo.toml index 8c6d2eeca..623f65f77 100644 --- a/crates/components/Cargo.toml +++ b/crates/components/Cargo.toml @@ -31,6 +31,7 @@ dioxus-router = { workspace = true } winit = { workspace = true } tokio = { workspace = true } +tracing = { workspace = true } open = "1" reqwest = { version = "0.11.13", features = ["json"] } diff --git a/crates/components/src/accordion.rs b/crates/components/src/accordion.rs index bd82e459c..9dd41c17e 100644 --- a/crates/components/src/accordion.rs +++ b/crates/components/src/accordion.rs @@ -1,7 +1,7 @@ use dioxus::prelude::*; use freya_elements::elements as dioxus_elements; use freya_elements::events::MouseEvent; -use freya_hooks::{use_animation, use_get_theme, use_node, Animation}; +use freya_hooks::{use_animation, use_get_theme, use_node, AccordionTheme, Animation}; /// [`Accordion`] component properties. #[derive(Props)] @@ -23,15 +23,15 @@ pub struct AccordionProps<'a> { #[allow(non_snake_case)] pub fn Accordion<'a>(cx: Scope<'a, AccordionProps<'a>>) -> Element<'a> { let theme = use_get_theme(cx); - let accordion_theme = &theme.accordion; - let animation = use_animation(cx, 0.0); + let animation = use_animation(cx, || 0.0); let open = use_state(cx, || false); let (node_ref, size) = use_node(cx); let animation_value = animation.value(); + let AccordionTheme { background, color } = theme.accordion; // Adapt the accordion if the body size changes - use_effect( + use_memo( cx, &( size.area.width(), @@ -44,7 +44,6 @@ pub fn Accordion<'a>(cx: Scope<'a, AccordionProps<'a>>) -> Element<'a> { if (height as f64) < animation.value() && !animating { animation.set_value(size.area.height() as f64); } - async move {} } }, ); @@ -62,12 +61,12 @@ pub fn Accordion<'a>(cx: Scope<'a, AccordionProps<'a>>) -> Element<'a> { render!( rect { overflow: "clip", - color: "{accordion_theme.color}", + color: "{color}", padding: "10", corner_radius: "3", width: "100%", height: "auto", - background: "{accordion_theme.background}", + background: "{background}", onclick: onclick, &cx.props.summary rect { diff --git a/crates/components/src/dropdown.rs b/crates/components/src/dropdown.rs index 4b09127e7..1c11d6317 100644 --- a/crates/components/src/dropdown.rs +++ b/crates/components/src/dropdown.rs @@ -170,9 +170,8 @@ where let color = theme.dropdown.font_theme.color; // Update the provided value if the passed value changes - use_effect(cx, &cx.props.value, move |value| { + use_memo(cx, &cx.props.value, move |value| { *selected.write() = value; - async move {} }); // Close the dropdown if clicked anywhere diff --git a/crates/components/src/external_link.rs b/crates/components/src/external_link.rs index 3bdd75571..ba35751d6 100644 --- a/crates/components/src/external_link.rs +++ b/crates/components/src/external_link.rs @@ -47,7 +47,6 @@ pub struct ExternalLinkProps<'a> { #[allow(non_snake_case)] pub fn ExternalLink<'a>(cx: Scope<'a, ExternalLinkProps<'a>>) -> Element { let theme = use_get_theme(cx); - let theme = &theme.external_link; let is_hovering = use_state(cx, || false); let show_tooltip = cx.props.show_tooltip.unwrap_or(true); @@ -68,7 +67,7 @@ pub fn ExternalLink<'a>(cx: Scope<'a, ExternalLinkProps<'a>>) -> Element { }; let color = if *is_hovering.get() { - theme.highlight_color + theme.external_link.highlight_color } else { "inherit" }; diff --git a/crates/components/src/gesture_area.rs b/crates/components/src/gesture_area.rs index 112dde036..8d7785274 100644 --- a/crates/components/src/gesture_area.rs +++ b/crates/components/src/gesture_area.rs @@ -62,7 +62,7 @@ type EventsQueue = VecDeque<(Instant, TouchEvent)>; pub fn GestureArea<'a>(cx: Scope<'a, GestureAreaProps<'a>>) -> Element { let touch_events = use_ref::(cx, VecDeque::new); - use_effect(cx, touch_events, move |_| { + use_memo(cx, touch_events, move |_| { // Keep the touch events queue under a certain size if touch_events.read().len() > MAX_EVENTS_QUEUE { touch_events.write_silent().pop_front(); @@ -132,8 +132,6 @@ pub fn GestureArea<'a>(cx: Scope<'a, GestureAreaProps<'a>>) -> Element { _ => {} } } - - async move {} }); let ontouchcancel = |e: TouchEvent| { diff --git a/crates/components/src/graph.rs b/crates/components/src/graph.rs index 9611eb379..3552b5e48 100644 --- a/crates/components/src/graph.rs +++ b/crates/components/src/graph.rs @@ -45,7 +45,7 @@ pub struct GraphProps { pub fn Graph(cx: Scope) -> Element { let platform = use_platform(cx); - use_effect(cx, (cx.props,), move |_| async move { + use_memo(cx, (cx.props,), move |_| { platform.send(EventMessage::RequestRerender) }); diff --git a/crates/components/src/input.rs b/crates/components/src/input.rs index 5ab00d32f..e53143920 100644 --- a/crates/components/src/input.rs +++ b/crates/components/src/input.rs @@ -3,6 +3,8 @@ use crate::ScrollView; use dioxus::prelude::*; use freya_elements::elements as dioxus_elements; use freya_elements::events::{KeyboardData, MouseEvent}; +use freya_hooks::ButtonTheme; +use freya_hooks::FontTheme; use freya_hooks::{ use_editable, use_focus, use_get_theme, EditableConfig, EditableEvent, EditableMode, TextEditor, }; @@ -66,20 +68,18 @@ pub fn Input<'a>(cx: Scope<'a, InputProps<'a>>) -> Element { let focus_manager = use_focus(cx); let text = &cx.props.value; - let button_theme = &theme.button; let cursor_attr = editable.cursor_attr(cx); let highlights_attr = editable.highlights_attr(cx, 0); let width = &cx.props.width; let height = &cx.props.height; let max_lines = &cx.props.max_lines; - use_effect(cx, &(cx.props.value.to_string(),), { + use_memo(cx, &(cx.props.value.to_string(),), { to_owned![editable]; move |(text,)| { editable.editor().with_mut(|editor| { editor.set(&text); }); - async move {} } }); @@ -122,8 +122,11 @@ pub fn Input<'a>(cx: Scope<'a, InputProps<'a>>) -> Element { } else { "none".to_string() }; - let background = button_theme.background; - let color = button_theme.font_theme.color; + let ButtonTheme { + background, + font_theme: FontTheme { color, .. }, + .. + } = theme.button; render!( CursorArea { diff --git a/crates/components/src/lib.rs b/crates/components/src/lib.rs index 5b940ddbd..ae3ad2aab 100644 --- a/crates/components/src/lib.rs +++ b/crates/components/src/lib.rs @@ -13,6 +13,7 @@ mod graph; mod input; mod loader; mod network_image; +mod progress_bar; mod scroll_views; mod slider; mod switch; @@ -31,6 +32,7 @@ pub use graph::*; pub use input::*; pub use loader::*; pub use network_image::*; +pub use progress_bar::*; pub use scroll_views::*; pub use slider::*; pub use switch::*; diff --git a/crates/components/src/loader.rs b/crates/components/src/loader.rs index 0c58e8579..baa72892b 100644 --- a/crates/components/src/loader.rs +++ b/crates/components/src/loader.rs @@ -2,7 +2,7 @@ use std::time::Duration; use dioxus::prelude::*; use freya_elements::elements as dioxus_elements; -use freya_hooks::use_get_theme; +use freya_hooks::{use_get_theme, LoaderTheme}; use tokio::time::interval; /// [`Loader`] component properties. Currently empty. @@ -22,7 +22,10 @@ pub fn Loader(cx: Scope) -> Element { let theme = use_get_theme(cx); let degrees = use_state(cx, || 0); - let loader_theme = theme.loader; + let LoaderTheme { + primary_color, + secondary_color, + } = theme.loader; use_effect(cx, (), move |_| { to_owned![degrees]; @@ -45,8 +48,8 @@ pub fn Loader(cx: Scope) -> Element { height: "31", svg_content: r#" - - + + "# }) diff --git a/crates/components/src/progress_bar.rs b/crates/components/src/progress_bar.rs new file mode 100644 index 000000000..df8df6930 --- /dev/null +++ b/crates/components/src/progress_bar.rs @@ -0,0 +1,92 @@ +use dioxus::prelude::*; +use freya_elements::elements as dioxus_elements; +use freya_hooks::{use_get_theme, ProgressBarTheme}; + +/// [`ProgressBar`] component properties. +#[derive(Props, PartialEq)] +pub struct ProgressBarProps { + /// Show a label with the current progress. Default to false. + #[props(default = false)] + show_progress: bool, + + /// Width of the progress bar. Default to 100%. + #[props(default = "100%".to_string(), into)] + width: String, + + /// Height of the progress bar. Default to 20px. + #[props(default = "20".to_string(), into)] + height: String, + /// Percentage of the progress bar. + pub progress: f32, +} + +/// `ProgressBar` component. +/// +/// # Props +/// See [`ProgressBarProps`]. +/// +/// # Styling +/// Inherits the [`ProgressBarTheme`](freya_hooks::ProgressBarTheme) theme. +/// +/// # Example +/// +/// ```no_run +/// # use freya::prelude::*; +/// fn app(cx: Scope) -> Element { +/// render!( +/// ProgressBar { +/// progress: 75.0 +/// } +/// ) +/// } +/// ``` +/// +#[allow(non_snake_case)] +pub fn ProgressBar(cx: Scope) -> Element { + let theme = use_get_theme(cx); + + let ProgressBarTheme { + background, + progress_background, + } = theme.progress_bar; + let width = &cx.props.width; + let height = &cx.props.height; + let show_progress = cx.props.show_progress; + let progress = cx.props.progress; + + render!( + rect { + width: "{width}", + height: "{height}", + padding: "2", + rect { + corner_radius: "999", + width: "100%", + height: "100%", + shadow: "0 2 10 1 rgb(0, 0, 0, 45)", + background: "{background}", + font_size: "13", + direction: "horizontal", + rect { + corner_radius: "999", + width: "{progress}%", + height: "100%", + background: "{progress_background}", + display: "center", + overflow: "clip", + if show_progress { + rsx!( + label { + align: "center", + width: "100%", + color: "white", + max_lines: "1", + "{progress.floor()}%" + } + ) + } + } + } + } + ) +} diff --git a/crates/components/src/scroll_views/scroll_bar.rs b/crates/components/src/scroll_views/scroll_bar.rs index 66a23f45f..c45477a5f 100644 --- a/crates/components/src/scroll_views/scroll_bar.rs +++ b/crates/components/src/scroll_views/scroll_bar.rs @@ -1,6 +1,6 @@ use dioxus::prelude::*; use freya_elements::elements as dioxus_elements; -use freya_hooks::use_get_theme; +use freya_hooks::{use_get_theme, ScrollbarTheme}; #[derive(Props)] pub struct ScrollBarProps<'a> { @@ -22,7 +22,8 @@ pub struct ScrollBarProps<'a> { #[allow(non_snake_case)] pub fn ScrollBar<'a>(cx: Scope<'a, ScrollBarProps<'a>>) -> Element<'a> { let theme = use_get_theme(cx); - let scrollbar_theme = &theme.scrollbar; + let ScrollbarTheme { background, .. } = &theme.scrollbar; + render!( rect { overflow: "clip", @@ -31,7 +32,7 @@ pub fn ScrollBar<'a>(cx: Scope<'a, ScrollBarProps<'a>>) -> Element<'a> { height: "{cx.props.height}", offset_x: "{cx.props.offset_x}", offset_y: "{cx.props.offset_y}", - background: "{scrollbar_theme.background}", + background: "{background}", &cx.props.children } ) diff --git a/crates/components/src/scroll_views/scroll_thumb.rs b/crates/components/src/scroll_views/scroll_thumb.rs index 5aa2f2d1b..4fcc1b6b4 100644 --- a/crates/components/src/scroll_views/scroll_thumb.rs +++ b/crates/components/src/scroll_views/scroll_thumb.rs @@ -1,7 +1,7 @@ use dioxus::prelude::*; use freya_elements::elements as dioxus_elements; use freya_elements::events::MouseEvent; -use freya_hooks::use_get_theme; +use freya_hooks::{use_get_theme, ScrollbarTheme}; #[derive(Props)] pub struct ScrollThumbProps<'a> { @@ -15,7 +15,10 @@ pub struct ScrollThumbProps<'a> { #[allow(non_snake_case)] pub fn ScrollThumb<'a>(cx: Scope<'a, ScrollThumbProps<'a>>) -> Element<'a> { let theme = use_get_theme(cx); - let scrollbar_theme = &theme.scrollbar; + let ScrollbarTheme { + thumb_background, .. + } = &theme.scrollbar; + render!( rect { onmousedown: |e| { @@ -28,7 +31,7 @@ pub fn ScrollThumb<'a>(cx: Scope<'a, ScrollThumbProps<'a>>) -> Element<'a> { width: "100%", height: "100%", corner_radius: "8", - background: "{scrollbar_theme.thumb_background}", + background: "{thumb_background}", } } ) diff --git a/crates/components/src/slider.rs b/crates/components/src/slider.rs index 261d15e3f..e54c66235 100644 --- a/crates/components/src/slider.rs +++ b/crates/components/src/slider.rs @@ -2,6 +2,7 @@ use dioxus::prelude::*; use freya_elements::elements as dioxus_elements; use freya_elements::events::{MouseEvent, WheelEvent}; use freya_hooks::{use_get_theme, use_node_ref}; +use tracing::info; /// [`Slider`] component properties. #[derive(Props)] @@ -17,11 +18,10 @@ pub struct SliderProps<'a> { #[inline] fn ensure_correct_slider_range(value: f64) -> f64 { if value < 0.0 { - // TODO: Better logging - println!("Slider value is less than 0.0, setting to 0.0"); + info!("Slider value is less than 0.0, setting to 0.0"); 0.0 } else if value > 100.0 { - println!("Slider value is greater than 100.0, setting to 100.0"); + info!("Slider value is greater than 100.0, setting to 100.0"); 100.0 } else { value diff --git a/crates/components/src/switch.rs b/crates/components/src/switch.rs index 16ec1b133..31ce004b1 100644 --- a/crates/components/src/switch.rs +++ b/crates/components/src/switch.rs @@ -40,7 +40,7 @@ pub struct SwitchProps<'a> { /// #[allow(non_snake_case)] pub fn Switch<'a>(cx: Scope<'a, SwitchProps<'a>>) -> Element<'a> { - let animation = use_animation(cx, 0.0); + let animation = use_animation(cx, || 0.0); let theme = use_get_theme(cx); let hovering = use_state(cx, || false); let clicking = use_state(cx, || false); @@ -80,13 +80,12 @@ pub fn Switch<'a>(cx: Scope<'a, SwitchProps<'a>>) -> Element<'a> { } }; - use_effect(cx, &cx.props.enabled, move |enabled| { + use_memo(cx, &cx.props.enabled, move |enabled| { if enabled { animation.start(Animation::new_sine_in_out(0.0..=25.0, 200)); } else if animation.value() > 0.0 { animation.start(Animation::new_sine_in_out(25.0..=0.0, 200)); } - async move {} }); render!( diff --git a/crates/components/src/tooltip.rs b/crates/components/src/tooltip.rs index 507a176d8..757103de4 100644 --- a/crates/components/src/tooltip.rs +++ b/crates/components/src/tooltip.rs @@ -1,6 +1,6 @@ use dioxus::prelude::*; use freya_elements::elements as dioxus_elements; -use freya_hooks::use_get_theme; +use freya_hooks::{use_get_theme, TooltipTheme}; /// [`Tooltip`] component properties. #[derive(Props)] @@ -20,7 +20,8 @@ pub struct TooltipProps<'a> { #[allow(non_snake_case)] pub fn Tooltip<'a>(cx: Scope<'a, TooltipProps<'a>>) -> Element { let theme = use_get_theme(cx); - let theme = &theme.tooltip; + let TooltipTheme { background, color } = &theme.tooltip; + render!( rect { height: "30", @@ -33,11 +34,11 @@ pub fn Tooltip<'a>(cx: Scope<'a, TooltipProps<'a>>) -> Element { height: "100%", shadow: "0 0 10 5 rgb(0, 0, 0, 50)", corner_radius: "8", - background: "{theme.background}", + background: "{background}", display: "center", label { max_lines: "1", - color: "{theme.color}", + color: "{color}", "{cx.props.url}" } } diff --git a/crates/engine/src/mocked.rs b/crates/engine/src/mocked.rs index f32e12557..6eb0e1690 100644 --- a/crates/engine/src/mocked.rs +++ b/crates/engine/src/mocked.rs @@ -1435,10 +1435,47 @@ impl DirectContext { use std::ffi::c_void; +#[repr(u8)] +pub enum Protected { + No, + Yes, +} + #[derive(Clone, Copy)] pub struct FramebufferInfo { pub fboid: i32, pub format: Format, + pub protected: Protected, +} + +impl Default for FramebufferInfo { + fn default() -> Self { + Self { + fboid: 0, + format: 0, + protected: Protected::No, + } + } +} + +pub fn wrap_backend_render_target( + context: &mut RecordingContext, + backend_render_target: &BackendRenderTarget, + origin: SurfaceOrigin, + color_type: ColorType, + color_space: impl Into>, + surface_props: Option<&SurfaceProps>, +) -> Option { + Surface::from_ptr(unsafe { + sb::C_SkSurfaces_WrapBackendRenderTarget( + context.native_mut(), + backend_render_target.native(), + origin, + color_type.into_native(), + color_space.into().into_ptr_or_null(), + surface_props.native_ptr_or_null(), + ) + }) } pub struct Interface; diff --git a/crates/engine/src/skia.rs b/crates/engine/src/skia.rs index 22aa0053d..3877e9b54 100644 --- a/crates/engine/src/skia.rs +++ b/crates/engine/src/skia.rs @@ -2,7 +2,7 @@ pub use skia_safe::{ font_style::{Slant, Weight, Width}, gpu::{ gl::{Format, FramebufferInfo, Interface}, - BackendRenderTarget, DirectContext, RecordingContext, SurfaceOrigin, + BackendRenderTarget, DirectContext, RecordingContext, SurfaceOrigin,surfaces::wrap_backend_render_target }, gradient_shader::GradientShaderColors, path::ArcSize, diff --git a/crates/hooks/src/use_accessibility.rs b/crates/hooks/src/use_accessibility.rs index 84c9bf2a7..5467aa6cb 100644 --- a/crates/hooks/src/use_accessibility.rs +++ b/crates/hooks/src/use_accessibility.rs @@ -1,5 +1,5 @@ use dioxus_core::ScopeState; -use dioxus_hooks::{to_owned, use_effect, use_shared_state}; +use dioxus_hooks::{to_owned, use_effect, use_memo, use_shared_state}; use freya_common::EventMessage; use freya_core::FocusReceiver; @@ -11,13 +11,12 @@ pub fn use_init_accessibility(cx: &ScopeState) { let focused_id = use_shared_state::>(cx).unwrap(); let current_focused_id = *focused_id.read(); - use_effect(cx, &(current_focused_id,), move |(focused_id,)| { + use_memo(cx, &(current_focused_id,), move |(focused_id,)| { if let Some(focused_id) = focused_id { platform .send(EventMessage::FocusAccessibilityNode(focused_id)) .unwrap(); } - async move {} }); use_effect(cx, (), { diff --git a/crates/hooks/src/use_animation.rs b/crates/hooks/src/use_animation.rs index 6b9feacda..672b0eb53 100644 --- a/crates/hooks/src/use_animation.rs +++ b/crates/hooks/src/use_animation.rs @@ -80,13 +80,12 @@ impl<'a> AnimationManager<'a> { /// ```rust /// # use freya::prelude::*; /// fn app(cx: Scope) -> Element { -/// let animation = use_animation(cx, 0.0); +/// let animation = use_animation(cx, || 0.0); /// /// let progress = animation.value(); /// -/// use_effect(cx, (), move |_| { +/// use_memo(cx, (), move |_| { /// animation.start(Animation::new_linear(0.0..=100.0, 50)); -/// async move {} /// }); /// /// render!( @@ -97,8 +96,9 @@ impl<'a> AnimationManager<'a> { /// } /// ``` /// -pub fn use_animation(cx: &ScopeState, init_value: f64) -> AnimationManager { +pub fn use_animation(cx: &ScopeState, init_value: impl FnOnce() -> f64) -> AnimationManager { let current_animation_id = use_state(cx, || None); + let init_value = *cx.use_hook(init_value); let value = use_state(cx, || init_value); AnimationManager { @@ -114,7 +114,7 @@ mod test { use std::time::Duration; use crate::{use_animation, Animation}; - use dioxus_hooks::{to_owned, use_effect}; + use dioxus_hooks::{to_owned, use_memo}; use freya::prelude::*; use freya_testing::{launch_test, FreyaEvent, MouseButton}; use tokio::time::sleep; @@ -122,13 +122,12 @@ mod test { #[tokio::test] pub async fn track_progress() { fn use_animation_app(cx: Scope) -> Element { - let animation = use_animation(cx, 0.0); + let animation = use_animation(cx, || 0.0); let progress = animation.value(); - use_effect(cx, (), move |_| { + use_memo(cx, (), move |_| { animation.start(Animation::new_linear(0.0..=100.0, 50)); - async move {} }); render!(rect { @@ -163,7 +162,7 @@ mod test { #[tokio::test] pub async fn restart_progress() { fn use_animation_app(cx: Scope) -> Element { - let animation = use_animation(cx, 10.0); + let animation = use_animation(cx, || 10.0); let progress = animation.value(); @@ -174,9 +173,8 @@ mod test { } }; - use_effect(cx, (), move |_| { + use_memo(cx, (), move |_| { animation.start(Animation::new_linear(10.0..=100.0, 50)); - async move {} }); render!(rect { diff --git a/crates/hooks/src/use_animation_transition.rs b/crates/hooks/src/use_animation_transition.rs index aa5c43035..e456ecb48 100644 --- a/crates/hooks/src/use_animation_transition.rs +++ b/crates/hooks/src/use_animation_transition.rs @@ -1,5 +1,5 @@ use dioxus_core::ScopeState; -use dioxus_hooks::{use_effect, use_memo, use_state, UseFutureDep, UseState}; +use dioxus_hooks::{use_memo, use_state, UseFutureDep, UseState}; use freya_engine::prelude::Color; use freya_node_state::Parse; use std::time::Duration; @@ -252,9 +252,8 @@ impl<'a> TransitionsManager<'a> { /// /// let progress = animation.get(0).unwrap().as_size(); /// -/// use_effect(cx, (), move |_| { +/// use_memo(cx, (), move |_| { /// animation.start(); -/// async move {} /// }); /// /// render!( @@ -278,11 +277,10 @@ where let transitions = use_memo(cx, dependencies.clone(), &mut init); let transitions_storage = use_state(cx, || animations_map(transitions)); - use_effect(cx, dependencies, { + use_memo(cx, dependencies, { let storage_setter = transitions_storage.setter(); move |v| { storage_setter(animations_map(&init(v))); - async move {} } }); @@ -322,9 +320,8 @@ mod test { let progress = animation.get(0).unwrap().as_size(); - use_effect(cx, (), move |_| { + use_memo(cx, (), move |_| { animation.start(); - async move {} }); render!(rect { diff --git a/crates/hooks/src/use_theme.rs b/crates/hooks/src/use_theme.rs index b4ddb0d37..34b50ecd5 100644 --- a/crates/hooks/src/use_theme.rs +++ b/crates/hooks/src/use_theme.rs @@ -115,6 +115,13 @@ pub struct LoaderTheme { pub secondary_color: &'static str, } +/// Theming properties for ProgressBar component. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ProgressBarTheme { + pub background: &'static str, + pub progress_background: &'static str, +} + /// Theming properties for Themes. #[derive(Clone, Debug, PartialEq, Eq)] pub struct Theme { @@ -130,6 +137,7 @@ pub struct Theme { pub dropdown_item: DropdownItemTheme, pub accordion: AccordionTheme, pub loader: LoaderTheme, + pub progress_bar: ProgressBarTheme, } impl Default for Theme { @@ -198,6 +206,10 @@ pub const LIGHT_THEME: Theme = Theme { primary_color: "rgb(50, 50, 50)", secondary_color: "rgb(150, 150, 150)", }, + progress_bar: ProgressBarTheme { + background: "rgb(210, 210, 210)", + progress_background: "rgb(103, 80, 164)", + }, }; /// `Dark` theme @@ -254,4 +266,8 @@ pub const DARK_THEME: Theme = Theme { primary_color: "rgb(150, 150, 150)", secondary_color: "rgb(255, 255, 255)", }, + progress_bar: ProgressBarTheme { + background: "rgb(60, 60, 60)", + progress_background: "rgb(255, 95, 0)", + }, }; diff --git a/crates/renderer/src/window.rs b/crates/renderer/src/window.rs index 1d689aef5..f0ced3b0d 100644 --- a/crates/renderer/src/window.rs +++ b/crates/renderer/src/window.rs @@ -152,6 +152,7 @@ impl WindowEnv { FramebufferInfo { fboid: fboid.try_into().unwrap(), format: Format::RGBA8.into(), + ..Default::default() } }; @@ -307,8 +308,7 @@ fn create_surface( ); let backend_render_target = BackendRenderTarget::new_gl(size, num_samples, stencil_size, fb_info); - - Surface::from_backend_render_target( + wrap_backend_render_target( gr_context, &backend_render_target, SurfaceOrigin::BottomLeft, diff --git a/crates/state/src/font_style.rs b/crates/state/src/font_style.rs index 9cc0965e6..46949f876 100644 --- a/crates/state/src/font_style.rs +++ b/crates/state/src/font_style.rs @@ -62,7 +62,7 @@ impl From<&FontStyleState> for TextStyle { text_style.add_shadow(*shadow); } - *text_style.decoration_mut() = value.decoration; + text_style.set_decoration(&value.decoration); text_style } diff --git a/crates/testing/tests/test.rs b/crates/testing/tests/test.rs index 7fae0ac5f..ca00f5533 100644 --- a/crates/testing/tests/test.rs +++ b/crates/testing/tests/test.rs @@ -24,9 +24,8 @@ async fn with_state() { fn stateful_app(cx: Scope) -> Element { let state = use_state(cx, || false); - use_effect(cx, (), |_| { + use_memo(cx, (), |_| { state.set(true); - async move {} }); render!( diff --git a/examples/animation.rs b/examples/animation.rs index 91b32f0e0..b43a01106 100644 --- a/examples/animation.rs +++ b/examples/animation.rs @@ -14,7 +14,7 @@ const TIME: i32 = 500; const TARGET: f64 = 500.0; fn app(cx: Scope) -> Element { - let animation = use_animation(cx, 0.0); + let animation = use_animation(cx, || 0.0); let progress = animation.value(); diff --git a/examples/canvas.rs b/examples/canvas.rs index b97ace7cd..0e2f1e55f 100644 --- a/examples/canvas.rs +++ b/examples/canvas.rs @@ -174,12 +174,8 @@ fn Editor(cx: Scope) -> Element { let font_style = if *is_italic.get() { "italic" } else { "normal" }; let font_weight = if *is_bold.get() { "bold" } else { "normal" }; - use_effect(cx, (), { - to_owned![focus_manager]; - move |_| { - focus_manager.focus(); - async move {} - } + use_memo(cx, (), |_| { + focus_manager.focus(); }); let onclick = { diff --git a/examples/progress_bar.rs b/examples/progress_bar.rs new file mode 100644 index 000000000..cbe86d4d4 --- /dev/null +++ b/examples/progress_bar.rs @@ -0,0 +1,92 @@ +#![cfg_attr( + all(not(debug_assertions), target_os = "windows"), + windows_subsystem = "windows" +)] + +use freya::prelude::*; + +fn main() { + launch(app); +} + +fn app(cx: Scope) -> Element { + let progress_anim = use_animation(cx, || 0.0); + let progress = progress_anim.value() as f32; + + let set_to_max = { + to_owned![progress_anim]; + move |_: MouseEvent| { + progress_anim.start(Animation::new_linear(progress_anim.value()..=100.0, 400)); + } + }; + + let onmoved = move |value: f64| { + progress_anim.set_value(value); + }; + + render!( + ProgressBar { + show_progress: true, + progress: progress + } + ProgressBar { + show_progress: true, + progress: progress * 0.75 + } + ProgressBar { + show_progress: true, + progress: progress * 0.50 + } + ProgressBar { + show_progress: true, + progress: progress * 0.35 + } + ProgressBar { + show_progress: true, + progress: progress * 0.15 + } + ProgressBar { + show_progress: true, + progress: progress * 0.90 + } + ProgressBar { + show_progress: true, + progress: progress * 0.70 + } + ProgressBar { + show_progress: true, + progress: progress * 0.65 + } + ProgressBar { + show_progress: true, + progress: progress * 0.30 + } + ProgressBar { + show_progress: true, + progress: progress * 0.85 + } + ProgressBar { + show_progress: true, + progress: progress * 0.60 + } + ProgressBar { + show_progress: true, + progress: progress * 0.45 + } + ProgressBar { + show_progress: true, + progress: progress * 0.20 + } + Slider { + width: 300.0, + value: progress as f64, + onmoved: onmoved + } + Button { + onclick: set_to_max, + label { + "Set to 100%" + } + } + ) +}