Skip to content

Commit

Permalink
Associate timers with widget ids (#831)
Browse files Browse the repository at this point in the history
  • Loading branch information
sjoshid authored Apr 28, 2020
1 parent c50ecfe commit 6d1ff52
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 9 deletions.
4 changes: 3 additions & 1 deletion druid/src/contexts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,9 @@ impl<'a> EventCtx<'a> {
/// request with the event.
pub fn request_timer(&mut self, deadline: Duration) -> TimerToken {
self.base_state.request_timer = true;
self.window.request_timer(deadline)
let timer_token = self.window.request_timer(deadline);
self.base_state.add_timer(timer_token);
timer_token
}

/// The layout size.
Expand Down
31 changes: 25 additions & 6 deletions druid/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@

//! The fundamental druid types.
use std::collections::VecDeque;
use std::collections::{HashMap, VecDeque};

use crate::bloom::Bloom;
use crate::kurbo::{Affine, Insets, Point, Rect, Shape, Size, Vec2};
use crate::piet::RenderContext;
use crate::{
BoxConstraints, Command, Data, Env, Event, EventCtx, InternalEvent, InternalLifeCycle,
LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, Region, Target, UpdateCtx, Widget, WidgetId,
WindowId,
LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, Region, Target, TimerToken, UpdateCtx, Widget,
WidgetId, WindowId,
};

/// Our queue type
Expand Down Expand Up @@ -109,6 +109,8 @@ pub(crate) struct BaseState {
pub(crate) request_focus: Option<FocusChange>,
pub(crate) children: Bloom<WidgetId>,
pub(crate) children_changed: bool,
/// Associate timers with widgets that requested them.
pub(crate) timers: HashMap<TimerToken, WidgetId>,
}

/// Methods by which a widget can attempt to change focus state.
Expand Down Expand Up @@ -516,6 +518,15 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
}
}
}
InternalEvent::RouteTimer(token, widget_id) => {
let widget_id = *widget_id;
if widget_id != child_ctx.base_state.id {
recurse = child_ctx.base_state.children.may_contain(&widget_id);
Event::Internal(InternalEvent::RouteTimer(*token, widget_id))
} else {
Event::Timer(*token)
}
}
},
Event::WindowConnected => Event::WindowConnected,
Event::WindowSize(size) => {
Expand Down Expand Up @@ -591,9 +602,9 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
recurse = had_active || child_ctx.base_state.is_hot;
Event::Zoom(*zoom)
}
Event::Timer(id) => {
recurse = child_ctx.base_state.request_timer;
Event::Timer(*id)
Event::Timer(token) => {
recurse = false;
Event::Timer(*token)
}
Event::Command(cmd) => Event::Command(cmd.clone()),
};
Expand All @@ -604,6 +615,8 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
};

ctx.base_state.merge_up(&child_ctx.base_state);
// Clear current widget's timers after merging with parent.
child_ctx.base_state.timers.clear();
ctx.is_handled |= child_ctx.is_handled;
}

Expand Down Expand Up @@ -788,9 +801,14 @@ impl BaseState {
focus_chain: Vec::new(),
children: Bloom::new(),
children_changed: false,
timers: HashMap::new(),
}
}

pub(crate) fn add_timer(&mut self, timer_token: TimerToken) {
self.timers.insert(timer_token, self.id);
}

/// Update to incorporate state changes from a child.
fn merge_up(&mut self, child_state: &BaseState) {
let mut child_region = child_state.invalid.clone();
Expand All @@ -809,6 +827,7 @@ impl BaseState {
self.has_focus |= child_state.has_focus;
self.children_changed |= child_state.children_changed;
self.request_focus = self.request_focus.or(child_state.request_focus);
self.timers.extend(&child_state.timers);
}

#[inline]
Expand Down
2 changes: 2 additions & 0 deletions druid/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ pub enum InternalEvent {
MouseLeave,
/// A command still in the process of being dispatched.
TargetedCommand(Target, Command),
/// Used for routing timer events.
RouteTimer(TimerToken, WidgetId),
}

/// Application life cycle events.
Expand Down
26 changes: 24 additions & 2 deletions druid/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

//! Management of multiple windows.
use std::collections::HashMap;
use std::mem;

// Automatically defaults to std::time::Instant on non Wasm platforms
Expand All @@ -28,8 +29,8 @@ use crate::widget::LabelText;
use crate::win_handler::RUN_COMMANDS_TOKEN;
use crate::{
BoxConstraints, Command, Data, Env, Event, EventCtx, InternalEvent, InternalLifeCycle,
LayoutCtx, LifeCycle, LifeCycleCtx, MenuDesc, PaintCtx, UpdateCtx, Widget, WidgetId, WidgetPod,
WindowDesc,
LayoutCtx, LifeCycle, LifeCycleCtx, MenuDesc, PaintCtx, TimerToken, UpdateCtx, Widget,
WidgetId, WidgetPod, WindowDesc,
};

/// A unique identifier for a window.
Expand All @@ -48,6 +49,7 @@ pub struct Window<T> {
pub(crate) last_mouse_pos: Option<Point>,
pub(crate) focus: Option<WidgetId>,
pub(crate) handle: WindowHandle,
pub(crate) timers: HashMap<TimerToken, WidgetId>,
// delegate?
}

Expand All @@ -64,6 +66,7 @@ impl<T> Window<T> {
last_mouse_pos: None,
focus: None,
handle,
timers: HashMap::new(),
}
}
}
Expand Down Expand Up @@ -171,6 +174,14 @@ impl<T: Data> Window<T> {
self.size = Size::new(size.width * scale, size.height * scale);
Event::WindowSize(self.size)
}
Event::Timer(token) => {
if let Some(widget_id) = self.timers.get(&token) {
Event::Internal(InternalEvent::RouteTimer(token, *widget_id))
} else {
log::error!("No widget found for timer {:?}", token);
return false;
}
}
other => other,
};

Expand Down Expand Up @@ -215,6 +226,17 @@ impl<T: Data> Window<T> {

self.post_event_processing(queue, data, env, false);

//In some platforms, timer tokens are reused. So it is necessary to remove the token from
//the window's timer map before adding new tokens to it.
if let Event::Internal(InternalEvent::RouteTimer(token, _)) = event {
self.timers.remove(&token);
}

//If at least one widget requested a timer, add all the requested timers to window's timers map.
if base_state.request_timer {
self.timers.extend(base_state.timers);
}

is_handled
}

Expand Down

0 comments on commit 6d1ff52

Please sign in to comment.