Skip to content
This repository has been archived by the owner on Jul 11, 2023. It is now read-only.

Commit

Permalink
Add AddEventListener widget to get button hover events
Browse files Browse the repository at this point in the history
  • Loading branch information
valpackett committed Jun 8, 2020
1 parent a5569c0 commit aa74cc5
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 1 deletion.
12 changes: 11 additions & 1 deletion shell/src/dock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ pub const DOCK_AND_GAP_HEIGHT: u16 =
#[derive(Debug, Clone)]
pub enum Msg {
ActivateApp(usize),
HoverApp(usize),
UnhoverApp(usize),
}

// #[derive(Debug, Clone)]
Expand All @@ -26,6 +28,7 @@ struct DockApp {
app: apps::App,
icon: icons::IconHandle,
button: iced_native::button::State,
evl: addeventlistener::State,
}

impl DockApp {
Expand All @@ -38,6 +41,7 @@ impl DockApp {
app,
icon,
button: Default::default(),
evl: Default::default(),
}
}

Expand All @@ -57,7 +61,11 @@ impl DockApp {
.padding(APP_PADDING)
.on_press(Msg::ActivateApp(position));

Container::new(big_button)
let listener = AddEventListener::new(&mut self.evl, big_button)
.on_pointer_enter(Msg::HoverApp(position))
.on_pointer_leave(Msg::UnhoverApp(position));

Container::new(listener)
.style(style::Dock)
.center_x()
.center_y()
Expand Down Expand Up @@ -227,6 +235,8 @@ impl IcedWidget for Dock {
.launch::<gio::AppLaunchContext>(&[], None)
.unwrap()
}
Msg::HoverApp(id) => eprintln!("TODO handle: hover {}", id),
Msg::UnhoverApp(id) => eprintln!("TODO handle: unhover {}", id),
}
}

Expand Down
3 changes: 3 additions & 0 deletions wstk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ pub use toplevels::*;
pub mod iced;
pub use iced::*;

pub mod widgets;
pub use widgets::*;

pub mod handle;

pub use iced_core;
Expand Down
2 changes: 2 additions & 0 deletions wstk/src/widgets.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod addeventlistener;
pub use addeventlistener::*;
155 changes: 155 additions & 0 deletions wstk/src/widgets/addeventlistener.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
//! The antidote to iced's annoying rigidity and inflexibility,
//! the equivalent of anything.addEventListener('mouseover', ..) :P
use iced_native::*;
use std::hash::Hash;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct State {
is_hovered: bool,
}

pub struct AddEventListener<'a, Message, Renderer: self::Renderer> {
state: &'a mut State,
content: Element<'a, Message, Renderer>,
pointer_enter: Option<Message>,
pointer_leave: Option<Message>,
}

impl<'a, Message, Renderer> AddEventListener<'a, Message, Renderer>
where
Renderer: self::Renderer,
{
pub fn new<T>(state: &'a mut State, content: T) -> Self
where
T: Into<Element<'a, Message, Renderer>>,
{
AddEventListener {
state,
content: content.into(),
pointer_enter: None,
pointer_leave: None,
}
}

pub fn on_pointer_enter(mut self, msg: Message) -> Self {
self.pointer_enter = Some(msg);
self
}

pub fn on_pointer_leave(mut self, msg: Message) -> Self {
self.pointer_leave = Some(msg);
self
}
}

impl<'a, Message, Renderer> Widget<Message, Renderer> for AddEventListener<'a, Message, Renderer>
where
Renderer: self::Renderer,
Message: Clone,
{
fn width(&self) -> Length {
Length::Shrink
}

fn height(&self) -> Length {
Length::Shrink
}

fn layout(&self, renderer: &Renderer, limits: &layout::Limits) -> layout::Node {
let content = self.content.layout(renderer, &limits.loose());
let size = limits.resolve(content.size());
layout::Node::with_children(size, vec![content])
}

fn on_event(
&mut self,
event: Event,
layout: Layout<'_>,
cursor_position: Point,
messages: &mut Vec<Message>,
renderer: &Renderer,
clipboard: Option<&dyn Clipboard>,
) {
let bounds = layout.bounds();
let is_mouse_over = bounds.contains(cursor_position);
if is_mouse_over && !self.state.is_hovered {
if let Some(ref msg) = self.pointer_enter {
messages.push(msg.clone());
}
}
if !is_mouse_over && self.state.is_hovered {
if let Some(ref msg) = self.pointer_leave {
messages.push(msg.clone());
}
}
self.state.is_hovered = is_mouse_over;

self.content.on_event(
event,
layout.children().next().unwrap(),
cursor_position,
messages,
renderer,
clipboard,
)
}

fn draw(
&self,
renderer: &mut Renderer,
defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
) -> Renderer::Output {
renderer.draw(
defaults,
cursor_position,
&self.content,
layout.children().next().unwrap(),
)
}

fn hash_layout(&self, state: &mut Hasher) {
struct Marker;
std::any::TypeId::of::<Marker>().hash(state);

self.content.hash_layout(state);
}
}

pub trait Renderer: iced_native::Renderer {
fn draw<Message>(
&mut self,
defaults: &Self::Defaults,
cursor_position: Point,
content: &Element<'_, Message, Self>,
content_layout: Layout<'_>,
) -> Self::Output;
}

impl<'a, Message, Renderer> From<AddEventListener<'a, Message, Renderer>>
for Element<'a, Message, Renderer>
where
Renderer: 'a + self::Renderer,
Message: 'a + Clone,
{
fn from(x: AddEventListener<'a, Message, Renderer>) -> Element<'a, Message, Renderer> {
Element::new(x)
}
}

impl<B> Renderer for iced_graphics::Renderer<B>
where
B: iced_graphics::Backend,
{
fn draw<Message>(
&mut self,
defaults: &iced_graphics::Defaults,
cursor_position: Point,
content: &Element<'_, Message, Self>,
content_layout: Layout<'_>,
) -> Self::Output {
content.draw(self, defaults, content_layout, cursor_position)
}
}

0 comments on commit aa74cc5

Please sign in to comment.