@@ -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.
5566pub ( crate ) struct ContextState < ' a > {
5667 pub ( crate ) command_queue : & ' a mut CommandQueue ,
@@ -114,7 +125,6 @@ pub struct UpdateCtx<'a, 'b> {
114125pub 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
146321impl_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
347539impl_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
9021082impl PaintCtx < ' _ , ' _ , ' _ > {
0 commit comments