Skip to content

Commit 0214404

Browse files
xarvicChristoph
andauthored
Unified origin (#2149)
* quicksafe * - remove WidgetPod::viewport_offset and Event::with_scroll_offset - add set_layout_dyn - changed clipbox implementation * - created LifeCycle::ViewStateChanged - removed LifeCycle::ParentWindowOrigin - moved HotState handling from layout to LifeCycle::ViewStateChanged * fixed errors * reformat * Added a modified version of context_traits (#1611). * reformat * update z-stack for unified origin * reformat * fix docs & clippy lints * remove AnyCtx rename CommandCtx to ChangeCtx * update CHANGELOG.md * fixed doc comments * - fixed doc comments - removed data and ctx from set_origin * - updated CHANGELOG.md - fixed window.rs * fixed examples * removed lifetimes added comments * update window_origin docs * reformat Co-authored-by: Christoph <xarvix@web.de>
1 parent ac38151 commit 0214404

30 files changed

+533
-332
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ You can find its changes [documented below](#070---2021-01-01).
7474
- Added `compute_max_intrinsic` method to the `Widget` trait, which determines the maximum useful dimension of the widget ([#2172] by [@sjoshid])
7575
- Windows: Dark mode support for the title bar ([#2196] by [@dristic])
7676
- `ZStack` widget ([#2235] by [@xarvic])
77+
- `Lifecycle::ViewStateChanged`, `InternalLifecycle::RouteViewStateChanged`, `ChangeCtx`, and `RequestCtx` ([#2149] by [@xarvic])
7778

7879
### Changed
7980

@@ -105,6 +106,8 @@ You can find its changes [documented below](#070---2021-01-01).
105106
- `RadioGroup` widgets are now constructed with new `row()`, `column()`, and `for_axis()` methods ([#2157] by [@twitchyliquid64])
106107
- Replace `info_span!` with `trace_span!` ([#2203] by [@NickLarsenNZ])
107108
- `WidgetPod::event` propagates handled mouse events to active children ([#2235] by [@xarvic])
109+
- changing hot state is now done in `Lifecycle::ChangeViewState` instead of `layout` ([#2149] by [@xarvic])
110+
- `WidgetPod::set_origin` no longer takes `data` and `env` as parameters. ([#2149] by [@xarvic])
108111

109112
### Deprecated
110113

@@ -856,6 +859,7 @@ Last release without a changelog :(
856859
[#2117]: https://github.com/linebender/druid/pull/2141
857860
[#2145]: https://github.com/linebender/druid/pull/2145
858861
[#2148]: https://github.com/linebender/druid/pull/2148
862+
[#2149]: https://github.com/linebender/druid/pull/2149
859863
[#2151]: https://github.com/linebender/druid/pull/2151
860864
[#2157]: https://github.com/linebender/druid/pull/2157
861865
[#2158]: https://github.com/linebender/druid/pull/2158

druid/examples/timer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ impl Widget<u32> for TimerWidget {
7676

7777
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints, data: &u32, env: &Env) -> Size {
7878
self.simple_box.layout(ctx, &bc.loosen(), data, env);
79-
self.simple_box.set_origin(ctx, data, env, self.pos);
79+
self.simple_box.set_origin(ctx, self.pos);
8080
bc.constrain((500.0, 500.0))
8181
}
8282

druid/examples/value_formatting/src/widgets.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ impl<T, W: Widget<Option<ValidationError>>> Widget<T> for ErrorController<W> {
169169

170170
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints, _: &T, env: &Env) -> Size {
171171
let size = self.child.layout(ctx, bc, &self.error, env);
172-
self.child.set_origin(ctx, &self.error, env, Point::ZERO);
172+
self.child.set_origin(ctx, Point::ZERO);
173173
size
174174
}
175175

druid/examples/widget_gallery.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ impl<T: Data> Widget<T> for SquaresGrid<T> {
369369
data,
370370
env,
371371
);
372-
widget.set_origin(ctx, data, env, Point::new(x_position, y_position));
372+
widget.set_origin(ctx, Point::new(x_position, y_position));
373373
// Increment position for the next cell
374374
x_position += self.cell_size.width + self.spacing;
375375
// If we can't fit in another cell in this row ...

druid/src/contexts.rs

Lines changed: 205 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,17 @@ macro_rules! impl_context_method {
5151
};
5252
}
5353

54+
/// A macro for implementing context traits for multiple contexts.
55+
macro_rules! impl_context_trait {
56+
($tr:ty => $ty:ty, { $($method:item)+ } ) => {
57+
impl $tr for $ty { $($method)+ }
58+
};
59+
($tr:ty => $ty:ty, $($more:ty),+, { $($method:item)+ } ) => {
60+
impl_context_trait!($tr => $ty, { $($method)+ });
61+
impl_context_trait!($tr => $($more),+, { $($method)+ });
62+
};
63+
}
64+
5465
/// Static state that is shared between most contexts.
5566
pub(crate) struct ContextState<'a> {
5667
pub(crate) command_queue: &'a mut CommandQueue,
@@ -114,7 +125,6 @@ pub struct UpdateCtx<'a, 'b> {
114125
pub struct LayoutCtx<'a, 'b> {
115126
pub(crate) state: &'a mut ContextState<'b>,
116127
pub(crate) widget_state: &'a mut WidgetState,
117-
pub(crate) mouse_pos: Option<Point>,
118128
}
119129

120130
/// Z-order paint operations with transformations.
@@ -142,6 +152,171 @@ pub struct PaintCtx<'a, 'b, 'c> {
142152
pub(crate) depth: u32,
143153
}
144154

155+
/// The state of a widget and its global context.
156+
pub struct State<'a> {
157+
// currently the only method using the State struct is set_origin.
158+
// the context state could be included into this struct to allow changes to context state
159+
// changes from Context traits
160+
// pub(crate) state: &'a mut ContextState<'b>,
161+
pub(crate) widget_state: &'a mut WidgetState,
162+
}
163+
164+
/// Convenience trait for code generic over contexts.
165+
///
166+
/// Methods that deal with commands and timers.
167+
/// Available to all contexts but [`PaintCtx`].
168+
///
169+
/// [`PaintCtx`](PaintCtx)
170+
pub trait ChangeCtx {
171+
/// Submit a [`Command`] to be run after this event is handled. See [`submit_command`].
172+
///
173+
/// [`submit_command`]: EventCtx::submit_command
174+
fn submit_command(&mut self, cmd: impl Into<Command>);
175+
/// Returns an [`ExtEventSink`] for submitting commands from other threads. See ['get_external_handle'].
176+
///
177+
/// [`get_external_handle`]: EventCtx::get_external_handle
178+
fn get_external_handle(&self) -> ExtEventSink;
179+
/// Request a timer event. See [`request_timer`]
180+
///
181+
/// [`request_timer`]: EventCtx::request_timer
182+
fn request_timer(&mut self, deadline: Duration) -> TimerToken;
183+
184+
/// Returns the state of the widget.
185+
///
186+
/// This method should only be used by the framework to do mergeups.
187+
fn state(&mut self) -> State;
188+
}
189+
190+
/// Convenience trait for invalidation and request methods available on multiple contexts.
191+
///
192+
/// These methods are available on [`EventCtx`], [`LifeCycleCtx`], and [`UpdateCtx`].
193+
pub trait RequestCtx: ChangeCtx {
194+
/// Request a [`paint`] pass. See ['request_paint']
195+
///
196+
/// ['request_paint']: EventCtx::request_paint
197+
/// [`paint`]: Widget::paint
198+
fn request_paint(&mut self);
199+
/// Request a [`paint`] pass for redrawing a rectangle. See [`request_paint_rect`].
200+
///
201+
/// [`request_paint_rect`]: EventCtx::request_paint_rect
202+
/// [`paint`]: Widget::paint
203+
fn request_paint_rect(&mut self, rect: Rect);
204+
/// Request a layout pass. See [`request_layout`].
205+
///
206+
/// [`request_layout`]: EventCtx::request_layout
207+
fn request_layout(&mut self);
208+
/// Request an animation frame. See [`request_anim_frame`].
209+
///
210+
/// [`request_anim_frame`]: EventCtx::request_anim_frame
211+
fn request_anim_frame(&mut self);
212+
/// Indicate that your children have changed. See [`children_changed`].
213+
///
214+
/// [`children_changed`]: EventCtx::children_changed
215+
fn children_changed(&mut self);
216+
/// Create a new sub-window. See [`new_sub_window`].
217+
///
218+
/// [`new_sub_window`]: EventCtx::new_sub_window
219+
fn new_sub_window<W: Widget<U> + 'static, U: Data>(
220+
&mut self,
221+
window_config: WindowConfig,
222+
widget: W,
223+
data: U,
224+
env: Env,
225+
) -> WindowId;
226+
/// Change the disabled state of this widget. See [`set_disabled`].
227+
///
228+
/// [`set_disabled`]: EventCtx::set_disabled
229+
fn set_disabled(&mut self, disabled: bool);
230+
/// Indicate that text input state has changed. See [`invalidate_text_input`].
231+
///
232+
/// [`invalidate_text_input`]: EventCtx::invalidate_text_input
233+
fn invalidate_text_input(&mut self, event: ImeInvalidation);
234+
/// Scrolls this widget into view.
235+
///
236+
/// [`scroll_to_view`]: EventCtx::scroll_to_view
237+
fn scroll_to_view(&mut self);
238+
/// Scrolls the area into view. See [`scroll_area_to_view`].
239+
///
240+
/// [`scroll_area_to_view`]: EventCtx::scroll_area_to_view
241+
fn scroll_area_to_view(&mut self, area: Rect);
242+
}
243+
244+
impl_context_trait!(
245+
ChangeCtx => EventCtx<'_, '_>, UpdateCtx<'_, '_>, LifeCycleCtx<'_, '_>, LayoutCtx<'_, '_>,
246+
{
247+
248+
fn submit_command(&mut self, cmd: impl Into<Command>) {
249+
Self::submit_command(self, cmd)
250+
}
251+
252+
fn get_external_handle(&self) -> ExtEventSink {
253+
Self::get_external_handle(self)
254+
}
255+
256+
fn request_timer(&mut self, deadline: Duration) -> TimerToken {
257+
Self::request_timer(self, deadline)
258+
}
259+
260+
fn state(&mut self) -> State {
261+
State {
262+
//state: &mut *self.state,
263+
widget_state: &mut *self.widget_state,
264+
}
265+
}
266+
}
267+
);
268+
269+
impl_context_trait!(
270+
RequestCtx => EventCtx<'_, '_>, UpdateCtx<'_, '_>, LifeCycleCtx<'_, '_>,
271+
{
272+
fn request_paint(&mut self) {
273+
Self::request_paint(self)
274+
}
275+
276+
fn request_paint_rect(&mut self, rect: Rect) {
277+
Self::request_paint_rect(self, rect)
278+
}
279+
280+
fn request_layout(&mut self) {
281+
Self::request_layout(self)
282+
}
283+
284+
fn request_anim_frame(&mut self) {
285+
Self::request_anim_frame(self)
286+
}
287+
288+
fn children_changed(&mut self) {
289+
Self::children_changed(self)
290+
}
291+
292+
fn new_sub_window<W: Widget<U> + 'static, U: Data>(
293+
&mut self,
294+
window_config: WindowConfig,
295+
widget: W,
296+
data: U,
297+
env: Env,
298+
) -> WindowId {
299+
Self::new_sub_window(self, window_config, widget, data, env)
300+
}
301+
302+
fn set_disabled(&mut self, disabled: bool) {
303+
Self::set_disabled(self, disabled)
304+
}
305+
306+
fn invalidate_text_input(&mut self, event: ImeInvalidation) {
307+
Self::invalidate_text_input(self, event)
308+
}
309+
310+
fn scroll_to_view(&mut self) {
311+
Self::scroll_to_view(self)
312+
}
313+
314+
fn scroll_area_to_view(&mut self, area: Rect) {
315+
Self::scroll_area_to_view(self, area)
316+
}
317+
}
318+
);
319+
145320
// methods on everyone
146321
impl_context_method!(
147322
EventCtx<'_, '_>,
@@ -275,7 +450,7 @@ impl_context_method!(
275450
/// Returns `true` if either this specific widget or any one of its descendants is focused.
276451
/// To check if only this specific widget is focused use [`is_focused`],
277452
///
278-
/// [`is_focused`]: #method.is_focused
453+
/// [`is_focused`]: crate::EventCtx::is_focused
279454
pub fn has_focus(&self) -> bool {
280455
self.widget_state.has_focus
281456
}
@@ -292,7 +467,7 @@ impl_context_method!(
292467
/// For an example the decrease button of a counter of type `usize` should be disabled if the
293468
/// value is `0`.
294469
///
295-
/// [`set_disabled`]: EventCtx::set_disabled
470+
/// [`set_disabled`]: crate::EventCtx::set_disabled
296471
pub fn is_disabled(&self) -> bool {
297472
self.widget_state.is_disabled()
298473
}
@@ -307,10 +482,10 @@ impl_context_method!(EventCtx<'_, '_>, UpdateCtx<'_, '_>, {
307482
/// cursor, the child widget's cursor will take precedence. (If that isn't what you want, use
308483
/// [`override_cursor`] instead.)
309484
///
310-
/// [`clear_cursor`]: EventCtx::clear_cursor
311-
/// [`override_cursor`]: EventCtx::override_cursor
312-
/// [`hot`]: EventCtx::is_hot
313-
/// [`active`]: EventCtx::is_active
485+
/// [`clear_cursor`]: crate::EventCtx::clear_cursor
486+
/// [`override_cursor`]: crate::EventCtx::override_cursor
487+
/// [`hot`]: crate::EventCtx::is_hot
488+
/// [`active`]: crate::EventCtx::is_active
314489
pub fn set_cursor(&mut self, cursor: &Cursor) {
315490
trace!("set_cursor {:?}", cursor);
316491
self.widget_state.cursor_change = CursorChange::Set(cursor.clone());
@@ -322,10 +497,10 @@ impl_context_method!(EventCtx<'_, '_>, UpdateCtx<'_, '_>, {
322497
/// effect when this widget is either [`hot`] or [`active`]. This will override the cursor
323498
/// preferences of a child widget. (If that isn't what you want, use [`set_cursor`] instead.)
324499
///
325-
/// [`clear_cursor`]: EventCtx::clear_cursor
326-
/// [`set_cursor`]: EventCtx::override_cursor
327-
/// [`hot`]: EventCtx::is_hot
328-
/// [`active`]: EventCtx::is_active
500+
/// [`clear_cursor`]: crate::EventCtx::clear_cursor
501+
/// [`set_cursor`]: crate::EventCtx::set_cursor
502+
/// [`hot`]: crate::EventCtx::is_hot
503+
/// [`active`]: crate::EventCtx::is_active
329504
pub fn override_cursor(&mut self, cursor: &Cursor) {
330505
trace!("override_cursor {:?}", cursor);
331506
self.widget_state.cursor_change = CursorChange::Override(cursor.clone());
@@ -335,14 +510,31 @@ impl_context_method!(EventCtx<'_, '_>, UpdateCtx<'_, '_>, {
335510
///
336511
/// This undoes the effect of [`set_cursor`] and [`override_cursor`].
337512
///
338-
/// [`override_cursor`]: EventCtx::override_cursor
339-
/// [`set_cursor`]: EventCtx::set_cursor
513+
/// [`override_cursor`]: crate::EventCtx::override_cursor
514+
/// [`set_cursor`]: crate::EventCtx::set_cursor
340515
pub fn clear_cursor(&mut self) {
341516
trace!("clear_cursor");
342517
self.widget_state.cursor_change = CursorChange::Default;
343518
}
344519
});
345520

521+
// methods on event, update and layout.
522+
impl_context_method!(EventCtx<'_, '_>, UpdateCtx<'_, '_>, LayoutCtx<'_, '_>, {
523+
/// Indicate that your [`ViewContext`] has changed.
524+
///
525+
/// This event is sent after layout is done and before paint is called. Note that you can still
526+
/// receive this event even if there was no prior call to layout.
527+
///
528+
/// Widgets must call this method after changing the clip region of their children.
529+
/// Changes to the other parts of [`ViewContext`] (cursor position and global origin) are tracked
530+
/// internally.
531+
///
532+
/// [`ViewContext`]: crate::ViewContext
533+
pub fn view_context_changed(&mut self) {
534+
self.widget_state.view_context_changed = true;
535+
}
536+
});
537+
346538
// methods on event, update, and lifecycle
347539
impl_context_method!(EventCtx<'_, '_>, UpdateCtx<'_, '_>, LifeCycleCtx<'_, '_>, {
348540
/// Request a [`paint`] pass. This is equivalent to calling
@@ -885,18 +1077,6 @@ impl<'a, 'b> LayoutCtx<'a, 'b> {
8851077
trace!("set_baseline_offset {}", baseline);
8861078
self.widget_state.baseline_offset = baseline
8871079
}
888-
889-
/// Creates a new LayoutCtx for a widget that maybe is hidden by another widget.
890-
///
891-
/// If ignore is `true` the child will not set its hot state to `true` even if the cursor
892-
/// is inside its bounds.
893-
pub fn ignore_hot<'c>(&'c mut self, ignore: bool) -> LayoutCtx<'c, 'b> {
894-
LayoutCtx {
895-
state: self.state,
896-
widget_state: self.widget_state,
897-
mouse_pos: if ignore { None } else { self.mouse_pos },
898-
}
899-
}
9001080
}
9011081

9021082
impl PaintCtx<'_, '_, '_> {

0 commit comments

Comments
 (0)