1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
use dioxus::prelude::*;
use freya_elements as dioxus_elements;
use freya_hooks::use_platform;
pub use winit::window::CursorIcon;
/// Properties for the [`CursorArea`] component.
#[derive(Props, Clone, PartialEq)]
pub struct CursorAreaProps {
/// Cursor icon that will be used when hovering this area.
icon: CursorIcon,
/// Inner children for the CursorArea.
children: Element,
}
/// Change the cursor icon when it's hovering over this component.
///
/// # Example
///
/// ```no_run
/// # use freya::prelude::*;
/// # use winit::window::CursorIcon;
/// fn app() -> Element {
/// rsx!(
/// CursorArea {
/// icon: CursorIcon::Progress,
/// label {
/// height: "100%",
/// width: "100%",
/// "Loading"
/// }
/// }
/// )
/// }
/// ```
#[allow(non_snake_case)]
pub fn CursorArea(CursorAreaProps { children, icon }: CursorAreaProps) -> Element {
let platform = use_platform();
let mut is_hovering = use_signal(|| false);
let onmouseover = move |_| {
*is_hovering.write() = true;
platform.set_cursor(icon);
};
let onmouseleave = move |_| {
*is_hovering.write() = false;
platform.set_cursor(CursorIcon::default());
};
use_drop(move || {
if *is_hovering.peek() {
platform.set_cursor(CursorIcon::default());
}
});
rsx!(
rect {
onmouseover,
onmouseleave,
{children}
}
)
}
#[cfg(test)]
mod test {
use freya::prelude::*;
use freya_testing::prelude::*;
use winit::{
event::MouseButton,
window::CursorIcon,
};
#[tokio::test]
pub async fn cursor_area() {
fn cursor_area_app() -> Element {
rsx!(
CursorArea {
icon: CursorIcon::Progress,
rect {
height: "50%",
width: "100%",
}
}
CursorArea {
icon: CursorIcon::Pointer,
rect {
height: "50%",
width: "100%",
}
}
)
}
let mut utils = launch_test(cursor_area_app);
// Initial cursor
assert_eq!(utils.cursor_icon(), CursorIcon::default());
utils.push_event(PlatformEvent::Mouse {
name: EventName::MouseOver,
cursor: (100., 100.).into(),
button: Some(MouseButton::Left),
});
utils.wait_for_update().await;
// Cursor after hovering the first half
assert_eq!(utils.cursor_icon(), CursorIcon::Progress);
utils.push_event(PlatformEvent::Mouse {
name: EventName::MouseOver,
cursor: (100., 300.).into(),
button: Some(MouseButton::Left),
});
utils.wait_for_update().await;
// Cursor after hovering the second half
assert_eq!(utils.cursor_icon(), CursorIcon::Pointer);
utils.push_event(PlatformEvent::Mouse {
name: EventName::MouseOver,
cursor: (-1., -1.).into(),
button: Some(MouseButton::Left),
});
utils.wait_for_update().await;
// Cursor after leaving the window
assert_eq!(utils.cursor_icon(), CursorIcon::default());
}
}