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

Move AnimFrame from lifecycle to event. #1155

Merged
merged 5 commits into from
Sep 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ You can find its changes [documented below](#060---2020-06-01).
- Replaced uses of `Option<Target>` with the new `Target::Auto`. ([#1185] by [@finnerale])
- Moved `Target` parameter from `submit_command` to `Command::new` and `Command::to`. ([#1185] by [@finnerale])
- `Movement::RightOfLine` to `Movement::NextLineBreak`, and `Movement::LeftOfLine` to `Movement::PrecedingLineBreak`. ([#1092] by [@sysint64])
- `AnimFrame` was moved from `lifecycle` to `event` ([#1155] by [@jneem])

### Deprecated

Expand Down Expand Up @@ -414,6 +415,7 @@ Last release without a changelog :(
[#1145]: https://github.com/linebender/druid/pull/1145
[#1151]: https://github.com/linebender/druid/pull/1151
[#1152]: https://github.com/linebender/druid/pull/1152
[#1155]: https://github.com/linebender/druid/pull/1155
[#1157]: https://github.com/linebender/druid/pull/1157
[#1171]: https://github.com/linebender/druid/pull/1171
[#1172]: https://github.com/linebender/druid/pull/1172
Expand Down
24 changes: 13 additions & 11 deletions druid/examples/anim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,24 @@ struct AnimWidget {

impl Widget<u32> for AnimWidget {
fn event(&mut self, ctx: &mut EventCtx, event: &Event, _data: &mut u32, _env: &Env) {
if let Event::MouseDown(_) = event {
self.t = 0.0;
ctx.request_anim_frame();
}
}

fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, _data: &u32, _env: &Env) {
if let LifeCycle::AnimFrame(interval) = event {
ctx.request_paint();
self.t += (*interval as f64) * 1e-9;
if self.t < 1.0 {
match event {
Event::MouseDown(_) => {
self.t = 0.0;
ctx.request_anim_frame();
}
Event::AnimFrame(interval) => {
ctx.request_paint();
self.t += (*interval as f64) * 1e-9;
if self.t < 1.0 {
ctx.request_anim_frame();
}
}
_ => (),
}
}

fn lifecycle(&mut self, _ctx: &mut LifeCycleCtx, _event: &LifeCycle, _data: &u32, _env: &Env) {}

fn update(&mut self, _ctx: &mut UpdateCtx, _old_data: &u32, _data: &u32, _env: &Env) {}

fn layout(
Expand Down
21 changes: 10 additions & 11 deletions druid/examples/invalidation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,24 +93,23 @@ impl Widget<Vector<Circle>> for CircleView {
});
}
ctx.request_anim_frame();
} else if let Event::AnimFrame(_) = ev {
for c in &*data {
ctx.request_paint_rect(kurbo::Circle::new(c.pos, RADIUS).bounding_box());
}
if !data.is_empty() {
ctx.request_anim_frame();
}
}
}

fn lifecycle(
&mut self,
ctx: &mut LifeCycleCtx,
ev: &LifeCycle,
data: &Vector<Circle>,
_ctx: &mut LifeCycleCtx,
_ev: &LifeCycle,
_data: &Vector<Circle>,
_env: &Env,
) {
if let LifeCycle::AnimFrame(_) = ev {
for c in data {
ctx.request_paint_rect(kurbo::Circle::new(c.pos, RADIUS).bounding_box());
}
if !data.is_empty() {
ctx.request_anim_frame();
}
}
}

fn update(
Expand Down
10 changes: 5 additions & 5 deletions druid/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,11 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
false
}
}
Event::AnimFrame(_) => {
let r = self.state.request_anim;
self.state.request_anim = false;
r
}
Event::KeyDown(_) => self.state.has_focus,
Event::KeyUp(_) => self.state.has_focus,
Event::Paste(_) => self.state.has_focus,
Expand Down Expand Up @@ -786,11 +791,6 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
true
}
},
LifeCycle::AnimFrame(_) => {
let r = self.state.request_anim;
self.state.request_anim = false;
r
}
LifeCycle::WidgetAdded => {
assert!(self.old_data.is_none());

Expand Down
17 changes: 11 additions & 6 deletions druid/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,17 @@ pub enum Event {
///
/// [`EventCtx::request_timer()`]: struct.EventCtx.html#method.request_timer
Timer(TimerToken),
/// Called at the beginning of a new animation frame.
///
/// On the first frame when transitioning from idle to animating, `interval`
/// will be 0. (This logic is presently per-window but might change to
/// per-widget to make it more consistent). Otherwise it is in nanoseconds.
///
/// The `paint` method will be called shortly after this event is finished.
/// As a result, you should try to avoid doing anything computationally
/// intensive in response to an `AnimFrame` event: it might make Druid miss
/// the monitor's refresh, causing lag or jerky animation.
AnimFrame(u64),
/// Called with an arbitrary [`Command`], submitted from elsewhere in
/// the application.
///
Expand Down Expand Up @@ -182,12 +193,6 @@ pub enum LifeCycle {
/// [`Rect`]: struct.Rect.html
/// [`WidgetPod::set_layout_rect`]: struct.WidgetPod.html#method.set_layout_rect
Size(Size),
/// Called at the beginning of a new animation frame.
///
/// On the first frame when transitioning from idle to animating, `interval`
/// will be 0. (This logic is presently per-window but might change to
/// per-widget to make it more consistent). Otherwise it is in nanoseconds.
AnimFrame(u64),
/// Called when the "hot" status changes.
///
/// This will always be called _before_ the event that triggered it; that is,
Expand Down
58 changes: 27 additions & 31 deletions druid/src/scroll_component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,31 @@ impl ScrollComponent {
self.scrollbars.timer_id = TimerToken::INVALID;
ctx.set_handled();
}
Event::AnimFrame(interval) => {
// Guard by the timer id being invalid, otherwise the scroll bars would fade
// immediately if some other widget started animating.
if self.scrollbars.timer_id == TimerToken::INVALID {
// Animate scroll bars opacity
let diff = 2.0 * (*interval as f64) * 1e-9;
self.scrollbars.opacity -= diff;
if self.scrollbars.opacity > 0.0 {
ctx.request_anim_frame();
}

let viewport = ctx.size().to_rect();
if viewport.width() < self.content_size.width {
ctx.request_paint_rect(
self.calc_horizontal_bar_bounds(viewport, env) - self.scroll_offset,
);
}
if viewport.height() < self.content_size.height {
ctx.request_paint_rect(
self.calc_vertical_bar_bounds(viewport, env) - self.scroll_offset,
);
}
}
}

_ => (),
}
}
Expand All @@ -445,38 +470,9 @@ impl ScrollComponent {
///
/// Make sure to call on every lifecycle event
pub fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, env: &Env) {
match event {
LifeCycle::AnimFrame(interval) => {
// Guard by the timer id being invalid, otherwise the scroll bars would fade
// immediately if some other widget started animating.
if self.scrollbars.timer_id == TimerToken::INVALID {
// Animate scroll bars opacity
let diff = 2.0 * (*interval as f64) * 1e-9;
self.scrollbars.opacity -= diff;
if self.scrollbars.opacity > 0.0 {
ctx.request_anim_frame();
}

let viewport = ctx.size().to_rect();
if viewport.width() < self.content_size.width {
ctx.request_paint_rect(
self.calc_horizontal_bar_bounds(viewport, env) - self.scroll_offset,
);
}
if viewport.height() < self.content_size.height {
ctx.request_paint_rect(
self.calc_vertical_bar_bounds(viewport, env) - self.scroll_offset,
);
}
}
}

if let LifeCycle::Size(_) = event {
// Show the scrollbars any time our size changes
LifeCycle::Size(_) => {
self.reset_scrollbar_fade(|d| ctx.request_timer(d), &env);
}

_ => {}
self.reset_scrollbar_fade(|d| ctx.request_timer(d), &env);
}
}

Expand Down
18 changes: 9 additions & 9 deletions druid/src/widget/spinner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,8 @@ impl Default for Spinner {
}

impl<T: Data> Widget<T> for Spinner {
fn event(&mut self, _ctx: &mut EventCtx, _event: &Event, _data: &mut T, _env: &Env) {}

fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, _data: &T, _env: &Env) {
if let LifeCycle::WidgetAdded = event {
ctx.request_anim_frame();
ctx.request_paint();
}

if let LifeCycle::AnimFrame(interval) = event {
fn event(&mut self, ctx: &mut EventCtx, event: &Event, _data: &mut T, _env: &Env) {
if let Event::AnimFrame(interval) = event {
self.t += (*interval as f64) * 1e-9;
if self.t >= 1.0 {
self.t = 0.0;
Expand All @@ -85,6 +78,13 @@ impl<T: Data> Widget<T> for Spinner {
}
}

fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, _data: &T, _env: &Env) {
if let LifeCycle::WidgetAdded = event {
ctx.request_anim_frame();
ctx.request_paint();
}
}

fn update(&mut self, _ctx: &mut UpdateCtx, _old_data: &T, _data: &T, _env: &Env) {}

fn layout(
Expand Down
55 changes: 28 additions & 27 deletions druid/src/widget/switch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,37 +137,38 @@ impl Widget<bool> for Switch {
}
ctx.request_paint();
}
Event::AnimFrame(interval) => {
let delta = Duration::from_nanos(*interval).as_secs_f64();
let switch_height = env.get(theme::BORDERED_WIDGET_HEIGHT);
let switch_width = switch_height * SWITCH_WIDTH_RATIO;
let knob_size = switch_height - 2. * SWITCH_PADDING;
let on_pos = switch_width - knob_size / 2. - SWITCH_PADDING;
let off_pos = knob_size / 2. + SWITCH_PADDING;

// move knob to right position depending on the value
if self.animation_in_progress {
let change_time = if *data {
SWITCH_CHANGE_TIME
} else {
-SWITCH_CHANGE_TIME
};
let change = (switch_width / change_time) * delta;
self.knob_pos.x = (self.knob_pos.x + change).min(on_pos).max(off_pos);

if (self.knob_pos.x > off_pos && !*data) || (self.knob_pos.x < on_pos && *data)
{
ctx.request_anim_frame();
} else {
self.animation_in_progress = false;
}
ctx.request_paint();
}
}
_ => (),
}
}

fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, data: &bool, env: &Env) {
if let LifeCycle::AnimFrame(interval) = event {
let delta = Duration::from_nanos(*interval).as_secs_f64();
let switch_height = env.get(theme::BORDERED_WIDGET_HEIGHT);
let switch_width = switch_height * SWITCH_WIDTH_RATIO;
let knob_size = switch_height - 2. * SWITCH_PADDING;
let on_pos = switch_width - knob_size / 2. - SWITCH_PADDING;
let off_pos = knob_size / 2. + SWITCH_PADDING;

// move knob to right position depending on the value
if self.animation_in_progress {
let change_time = if *data {
SWITCH_CHANGE_TIME
} else {
-SWITCH_CHANGE_TIME
};
let change = (switch_width / change_time) * delta;
self.knob_pos.x = (self.knob_pos.x + change).min(on_pos).max(off_pos);

if (self.knob_pos.x > off_pos && !*data) || (self.knob_pos.x < on_pos && *data) {
ctx.request_anim_frame();
} else {
self.animation_in_progress = false;
}
ctx.request_paint();
}
}
fn lifecycle(&mut self, _ctx: &mut LifeCycleCtx, _event: &LifeCycle, _data: &bool, _env: &Env) {
}

fn update(&mut self, ctx: &mut UpdateCtx, old_data: &bool, data: &bool, _env: &Env) {
Expand Down
4 changes: 2 additions & 2 deletions druid/src/win_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,9 +294,9 @@ impl<T: Data> Inner<T> {

fn prepare_paint(&mut self, window_id: WindowId) {
if let Some(win) = self.windows.get_mut(window_id) {
win.prepare_paint(&mut self.command_queue, &self.data, &self.env);
win.prepare_paint(&mut self.command_queue, &mut self.data, &self.env);
}
self.invalidate_and_finalize();
self.do_update();
}

fn paint(&mut self, window_id: WindowId, piet: &mut Piet, invalid: &Region) {
Expand Down
Loading