Skip to content

Commit

Permalink
Merge branch 'master' into fix-progressbar-rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
xStrom authored May 17, 2020
2 parents b93ddf5 + 4af2709 commit 155783c
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 46 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,12 @@ This means that druid no longer requires cairo on macOS and uses Core Graphics i
- `MouseButtons` to `MouseEvent` to track which buttons are being held down during an event. ([#843] by [@xStrom])
- `Env` and `Key` gained methods for inspecting an `Env` at runtime ([#880] by [@Zarenor])
- `UpdateCtx::request_timer` and `UpdateCtx::request_anim_frame`. ([#898] by [@finnerale])
- `LifeCycleCtx::request_timer`. ([#954] by [@xStrom])
- `UpdateCtx::size` and `LifeCycleCtx::size`. ([#917] by [@jneem])
- `WidgetExt::debug_widget_id`, for displaying widget ids on hover. ([#876] by [@cmyr])
- `im` feature, with `Data` support for the [`im` crate](https://docs.rs/im/) collections. ([#924] by [@cmyr])
- `im::Vector` support for the `List` widget. ([#940] by [@xStrom])
- `LifeCycle::Size` event to inform widgets that their size changed. ([#953] by [@xStrom])

### Changed

Expand Down Expand Up @@ -95,6 +97,7 @@ This means that druid no longer requires cairo on macOS and uses Core Graphics i
- X11: Support key and mouse button state. ([#920] by [@jneem])
- Routing `LifeCycle::FocusChanged` to descendant widgets. ([#925] by [@yrns])
- Built-in open and save menu items now show the correct label and submit the right commands. ([#930] by [@finnerale])
- Wheel events now properly update hot state. ([#951] by [@xStrom])

### Visual

Expand Down Expand Up @@ -194,6 +197,9 @@ This means that druid no longer requires cairo on macOS and uses Core Graphics i
[#942]: https://github.com/xi-editor/druid/pull/942
[#943]: https://github.com/xi-editor/druid/pull/943
[#949]: https://github.com/xi-editor/druid/pull/949
[#951]: https://github.com/xi-editor/druid/pull/951
[#953]: https://github.com/xi-editor/druid/pull/953
[#954]: https://github.com/xi-editor/druid/pull/954

## [0.5.0] - 2020-04-01

Expand Down
12 changes: 6 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion druid/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fnv = "1.0.3"
instant = { version = "0.1", features = ["wasm-bindgen"] }

# Optional dependencies
im = { version = "14.0", optional = true }
im = { version = "15.0", optional = true }
usvg = { version = "0.9.0", optional = true }
image = { version = "0.23.2", optional = true }

Expand Down
8 changes: 6 additions & 2 deletions druid/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,15 @@ impl<T: Data> AppLauncher<T> {
/// Initialize a minimal logger for printing logs out to stderr.
///
/// Meant for use during development only.
///
/// # Panics
///
/// Panics if the logger fails to initialize.
pub fn use_simple_logger(self) -> Self {
#[cfg(not(target_arch = "wasm32"))]
simple_logger::init().ok();
simple_logger::init().expect("Failed to init simple logger");
#[cfg(target_arch = "wasm32")]
console_log::init_with_level(log::Level::Trace).ok();
console_log::init_with_level(log::Level::Trace).expect("Failed to init simple logger");
self
}

Expand Down
13 changes: 13 additions & 0 deletions druid/src/contexts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ pub struct LifeCycleCtx<'a> {
pub(crate) command_queue: &'a mut CommandQueue,
pub(crate) base_state: &'a mut BaseState,
pub(crate) window_id: WindowId,
pub(crate) window: &'a WindowHandle,
}

/// A mutable context provided to data update methods of widgets.
Expand Down Expand Up @@ -91,6 +92,7 @@ pub struct LayoutCtx<'a, 'b: 'a> {
pub(crate) base_state: &'a mut BaseState,
pub(crate) text_factory: &'a mut Text<'b>,
pub(crate) window_id: WindowId,
pub(crate) window: &'a WindowHandle,
pub(crate) mouse_pos: Option<Point>,
}

Expand Down Expand Up @@ -548,6 +550,17 @@ impl<'a> LifeCycleCtx<'a> {
self.request_paint();
}

/// Request a timer event.
///
/// The return value is a token, which can be used to associate the
/// request with the event.
pub fn request_timer(&mut self, deadline: Duration) -> TimerToken {
self.base_state.request_timer = true;
let timer_token = self.window.request_timer(deadline);
self.base_state.add_timer(timer_token);
timer_token
}

/// The layout size.
///
/// This is the layout size as ultimately determined by the parent
Expand Down
82 changes: 70 additions & 12 deletions druid/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::piet::{
use crate::{
BoxConstraints, Color, Command, Data, Env, Event, EventCtx, InternalEvent, InternalLifeCycle,
LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, Region, Target, TimerToken, UpdateCtx, Widget,
WidgetId, WindowId,
WidgetId, WindowHandle, WindowId,
};

/// Our queue type
Expand Down Expand Up @@ -188,23 +188,53 @@ impl<T, W: Widget<T>> WidgetPod<T, W> {
self.state.id
}

/// Set layout rectangle.
/// Set the layout [`Rect`].
///
/// Intended to be called on child widget in container's `layout`
/// implementation.
/// A container widget should call the [`Widget::layout`] method on its children in
/// its own [`Widget::layout`] implementation, then possibly modify the returned [`Size`], and
/// finally call this `set_layout_rect` method on the child to set the final layout [`Rect`].
///
/// The child will receive the [`LifeCycle::Size`] event informing them of the final [`Size`].
///
/// [`Widget::layout`]: trait.Widget.html#tymethod.layout
/// [`Rect`]: struct.Rect.html
/// [`Size`]: struct.Size.html
/// [`LifeCycle::Size`]: enum.LifeCycle.html#variant.Size
pub fn set_layout_rect(&mut self, ctx: &mut LayoutCtx, data: &T, env: &Env, layout_rect: Rect) {
let mut needs_merge = false;

let old_size = self.state.layout_rect.map(|r| r.size());
let new_size = layout_rect.size();

self.state.layout_rect = Some(layout_rect);

if old_size.is_none() || old_size.unwrap() != new_size {
let mut child_ctx = LifeCycleCtx {
command_queue: ctx.command_queue,
base_state: &mut self.state,
window_id: ctx.window_id,
window: ctx.window,
};
let size_event = LifeCycle::Size(new_size);
self.inner.lifecycle(&mut child_ctx, &size_event, data, env);
needs_merge = true;
}

if WidgetPod::set_hot_state(
&mut self.inner,
ctx.command_queue,
&mut self.state,
ctx.window_id,
ctx.window,
layout_rect,
ctx.mouse_pos,
data,
env,
) {
needs_merge = true;
}

if needs_merge {
ctx.base_state.merge_up(&self.state);
}
}
Expand All @@ -215,9 +245,12 @@ impl<T, W: Widget<T>> WidgetPod<T, W> {
self.layout_rect()
}

/// The layout rectangle.
/// Returns the layout [`Rect`].
///
/// This will be same value as set by `set_layout_rect`.
/// This will be the same [`Rect`] that was set by [`set_layout_rect`].
///
/// [`Rect`]: struct.Rect.html
/// [`set_layout_rect`]: #method.set_layout_rect
pub fn layout_rect(&self) -> Rect {
self.state.layout_rect.unwrap_or_default()
}
Expand Down Expand Up @@ -303,6 +336,7 @@ impl<T, W: Widget<T>> WidgetPod<T, W> {
command_queue: &mut CommandQueue,
child_state: &mut BaseState,
window_id: WindowId,
window: &WindowHandle,
rect: Rect,
mouse_pos: Option<Point>,
data: &T,
Expand All @@ -319,6 +353,7 @@ impl<T, W: Widget<T>> WidgetPod<T, W> {
command_queue,
base_state: child_state,
window_id,
window,
};
child.lifecycle(&mut child_ctx, &hot_changed_event, data, env);
// if hot changes and we're showing widget ids, always repaint
Expand Down Expand Up @@ -484,6 +519,7 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
command_queue: ctx.command_queue,
base_state: &mut self.state,
window_id: ctx.window_id,
window: ctx.window,
text_factory: ctx.text_factory,
mouse_pos: child_mouse_pos,
};
Expand Down Expand Up @@ -569,6 +605,7 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
child_ctx.command_queue,
child_ctx.base_state,
child_ctx.window_id,
child_ctx.window,
rect,
None,
data,
Expand Down Expand Up @@ -616,6 +653,7 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
child_ctx.command_queue,
child_ctx.base_state,
child_ctx.window_id,
child_ctx.window,
rect,
Some(mouse_event.pos),
data,
Expand All @@ -632,6 +670,7 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
child_ctx.command_queue,
child_ctx.base_state,
child_ctx.window_id,
child_ctx.window,
rect,
Some(mouse_event.pos),
data,
Expand All @@ -648,6 +687,7 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
child_ctx.command_queue,
child_ctx.base_state,
child_ctx.window_id,
child_ctx.window,
rect,
Some(mouse_event.pos),
data,
Expand All @@ -658,6 +698,23 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
mouse_event.pos -= rect.origin().to_vec2();
Event::MouseMove(mouse_event)
}
Event::Wheel(mouse_event) => {
WidgetPod::set_hot_state(
&mut self.inner,
child_ctx.command_queue,
child_ctx.base_state,
child_ctx.window_id,
child_ctx.window,
rect,
Some(mouse_event.pos),
data,
env,
);
recurse = had_active || child_ctx.base_state.is_hot;
let mut mouse_event = mouse_event.clone();
mouse_event.pos -= rect.origin().to_vec2();
Event::Wheel(mouse_event)
}
Event::KeyDown(e) => {
recurse = child_ctx.has_focus();
Event::KeyDown(*e)
Expand All @@ -670,12 +727,6 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
recurse = child_ctx.has_focus();
Event::Paste(e.clone())
}
Event::Wheel(wheel_event) => {
recurse = had_active || child_ctx.base_state.is_hot;
let mut wheel_event = wheel_event.clone();
wheel_event.pos -= rect.origin().to_vec2();
Event::Wheel(wheel_event)
}
Event::Zoom(zoom) => {
recurse = had_active || child_ctx.base_state.is_hot;
Event::Zoom(*zoom)
Expand Down Expand Up @@ -780,6 +831,11 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {

true
}
LifeCycle::Size(_) => {
// We are a descendant of a widget that received the Size event.
// This event was meant only for our parent, so don't recurse.
false
}
//NOTE: this is not sent here, but from the special set_hot_state method
LifeCycle::HotChanged(_) => false,
LifeCycle::FocusChanged(_) => {
Expand All @@ -793,6 +849,7 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
command_queue: ctx.command_queue,
base_state: &mut self.state,
window_id: ctx.window_id,
window: ctx.window,
};

if recurse {
Expand Down Expand Up @@ -959,6 +1016,7 @@ mod tests {
command_queue: &mut command_queue,
base_state: &mut state,
window_id: WindowId::next(),
window: &WindowHandle::default(),
};

let env = Env::default();
Expand Down
19 changes: 4 additions & 15 deletions druid/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,27 +381,16 @@ impl Data for piet::Color {
}
}

//FIXME Vector::ptr_eq is not currently reliable; this is a temporary impl?
#[cfg(feature = "im")]
impl<T: Data> Data for im::Vector<T> {
fn same(&self, other: &Self) -> bool {
// for reasons outlined in https://github.com/bodil/im-rs/issues/129,
// ptr_eq always returns false for small collections. This heuristic
// falls back to using equality for collections below some threshold.
// There may be a possibility of this returning false negatives, but
// not false positives; that's an acceptable outcome.

/* this is the impl I expected to use
const INLINE_LEN: usize = 48; // bytes available before first allocation;
let inline_capacity: usize = INLINE_LEN / std::mem::size_of::<T>();
if self.len() == other.len() && self.len() <= inline_capacity {
self.iter().zip(other.iter()).all(|(a, b)| a.same(b))
// if a vec is small enough that it doesn't require an allocation
// it is 'inline'; in this case a pointer comparison is meaningless.
if self.is_inline() {
self.len() == other.len() && self.iter().zip(other.iter()).all(|(a, b)| a.same(b))
} else {
self.ptr_eq(other)
}
*/

self.len() == other.len() && self.iter().zip(other.iter()).all(|(a, b)| a.same(b))
}
}

Expand Down
8 changes: 8 additions & 0 deletions druid/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,14 @@ pub enum LifeCycle {
/// [`WidgetPod`]: struct.WidgetPod.html
/// [`LifeCycleCtx::register_for_focus`]: struct.LifeCycleCtx.html#method.register_for_focus
WidgetAdded,
/// Called when the size of the widget changes.
///
/// The [`Size`] is derived from the [`Rect`] that was set with [`WidgetPod::set_layout_rect`].
///
/// [`Size`]: struct.Size.html
/// [`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`
Expand Down
Loading

0 comments on commit 155783c

Please sign in to comment.