Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Associate timers with widget ids #831

Merged
merged 12 commits into from
Apr 28, 2020
11 changes: 10 additions & 1 deletion druid/src/contexts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use crate::{
Affine, Command, Cursor, Insets, Rect, Size, Target, Text, TimerToken, WidgetId, WindowHandle,
WindowId,
};
use std::collections::HashMap;

/// A mutable context provided to event handling methods of widgets.
///
Expand All @@ -46,6 +47,8 @@ pub struct EventCtx<'a> {
pub(crate) had_active: bool,
pub(crate) is_handled: bool,
pub(crate) is_root: bool,
/// Map of TimerTokens and WidgetIds that requested them.
pub(crate) timers: &'a HashMap<TimerToken, WidgetId>,
}

/// A mutable context provided to the [`lifecycle`] method on widgets.
Expand Down Expand Up @@ -349,7 +352,13 @@ impl<'a> EventCtx<'a> {
/// request with the event.
pub fn request_timer(&mut self, deadline: Instant) -> 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
}

pub fn remove_timer(&mut self, timer_token: &TimerToken) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After widgets are done processing timer events, should we all ask them to remove map entry?
This is not used anywhere in examples.
I think framework needs to remove it rather than forcing widgets to remove it themselves.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After merging up, Im clearing the map of BaseState. So remove is not needed when event is handled.

self.base_state.remove_timer(timer_token);
}

/// The layout size.
Expand Down
27 changes: 24 additions & 3 deletions druid/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

//! The fundamental druid types.

use std::collections::VecDeque;
use std::collections::{HashMap, VecDeque};

use log;

Expand All @@ -23,7 +23,7 @@ use crate::kurbo::{Affine, Insets, Rect, Shape, Size};
use crate::piet::RenderContext;
use crate::{
BoxConstraints, Command, Data, Env, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx,
PaintCtx, Target, UpdateCtx, Widget, WidgetId,
PaintCtx, Target, TimerToken, UpdateCtx, Widget, WidgetId,
};

/// Our queue type
Expand Down Expand Up @@ -99,6 +99,7 @@ pub(crate) struct BaseState {
pub(crate) request_focus: Option<FocusChange>,
pub(crate) children: Bloom<WidgetId>,
pub(crate) children_changed: bool,
pub(crate) timers: HashMap<TimerToken, WidgetId>,
}

/// Methods by which a widget can attempt to change focus state.
Expand Down Expand Up @@ -376,6 +377,7 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
is_handled: false,
is_root: false,
focus_widget: ctx.focus_widget,
timers: &ctx.timers,
};
let rect = child_ctx.base_state.layout_rect;
// Note: could also represent this as `Option<Event>`.
Expand Down Expand Up @@ -438,7 +440,14 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
Event::Zoom(*zoom)
}
Event::Timer(id) => {
recurse = child_ctx.base_state.request_timer;
if let Some(widget_id) = child_ctx.timers.get(id) {
if *widget_id != child_ctx.base_state.id {
recurse = child_ctx.base_state.children.may_contain(widget_id);
}
} else {
log::error!("Timer Token must be in timers map.");
recurse = false;
}
Event::Timer(*id)
}
Event::Command(cmd) => Event::Command(cmd.clone()),
Expand Down Expand Up @@ -467,6 +476,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 @@ -630,9 +641,18 @@ 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);
}

pub(crate) fn remove_timer(&mut self, timer_token: &TimerToken) {
self.timers.remove(timer_token);
}

/// Update to incorporate state changes from a child.
fn merge_up(&mut self, child_state: &BaseState) {
self.needs_inval |= child_state.needs_inval;
Expand All @@ -642,6 +662,7 @@ impl BaseState {
self.has_active |= child_state.has_active;
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
15 changes: 12 additions & 3 deletions druid/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,19 @@

//! Management of multiple windows.

use std::collections::HashMap;
use std::mem;
use std::time::Instant;

use crate::core::{BaseState, CommandQueue, FocusChange};
use crate::kurbo::{Insets, Point, Rect, Size};
use crate::piet::{Piet, RenderContext};
use crate::shell::{Counter, Cursor, WindowHandle};

use crate::core::{BaseState, CommandQueue, FocusChange};
use crate::win_handler::RUN_COMMANDS_TOKEN;
use crate::{
BoxConstraints, Command, Data, Env, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx,
LocalizedString, MenuDesc, PaintCtx, UpdateCtx, Widget, WidgetId, WidgetPod, WindowDesc,
LocalizedString, MenuDesc, PaintCtx, TimerToken, UpdateCtx, Widget, WidgetId, WidgetPod,
WindowDesc,
};

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

Expand All @@ -58,6 +60,7 @@ impl<T> Window<T> {
last_anim: None,
focus: None,
handle,
timers: HashMap::new(),
}
}
}
Expand Down Expand Up @@ -145,6 +148,7 @@ impl<T: Data> Window<T> {
window: &self.handle,
window_id: self.id,
focus_widget: self.focus,
timers: &self.timers,
};

self.root.event(&mut ctx, &event, data, env);
Expand All @@ -169,6 +173,11 @@ impl<T: Data> Window<T> {
self.lifecycle(queue, &LifeCycle::RouteWidgetAdded, data, env);
}

//If at least one widget requested timer, collect those timers from widgets and add to window's timers map.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If at least one widget requested a timer, collect those timers from widgets and 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