66//! Layout, Tile and TileExt traits
77
88use crate :: event:: ConfigCx ;
9- use crate :: geom:: { Coord , Offset , Rect } ;
9+ use crate :: geom:: { Coord , Rect } ;
1010use crate :: layout:: { AlignHints , AxisInfo , SizeRules } ;
1111use crate :: theme:: { DrawCx , SizeCx } ;
12- use crate :: util:: IdentifyWidget ;
13- use crate :: { HasId , Id } ;
12+ use crate :: Id ;
1413use kas_macros:: autoimpl;
1514
16- #[ allow( unused) ] use super :: { Events , Widget } ;
17- #[ allow( unused) ]
18- use crate :: layout:: { self , AlignPair , LayoutVisitor } ;
15+ #[ allow( unused) ] use super :: { Events , Tile , Widget } ;
16+ #[ allow( unused) ] use crate :: layout:: { self , AlignPair } ;
1917#[ allow( unused) ] use kas_macros as macros;
2018
2119/// Positioning and drawing routines for [`Widget`]s
@@ -86,11 +84,8 @@ pub trait Layout {
8684 ///
8785 /// ## Default implementation
8886 ///
89- /// The `#[widget]` macro
90- /// [may generate a default implementation](macros::widget#layout-1) by
91- /// implementing [`LayoutVisitor`] for `Self`.
92- /// In this case the default impl of this method is
93- /// `self.layout_visitor().size_rules(/* ... */)`.
87+ /// The `#[widget]` macro may implement this method as a wrapper over
88+ /// the corresponding [`MacroDefinedLayout`].
9489 fn size_rules ( & mut self , sizer : SizeCx , axis : AxisInfo ) -> SizeRules ;
9590
9691 /// Set size and position
@@ -126,11 +121,8 @@ pub trait Layout {
126121 ///
127122 /// ## Default implementation
128123 ///
129- /// The `#[widget]` macro
130- /// [may generate a default implementation](macros::widget#layout-1) by
131- /// implementing [`LayoutVisitor`] for `Self`.
132- /// In this case the default impl of this method is
133- /// `self.layout_visitor().set_rect(/* ... */)`.
124+ /// The `#[widget]` macro may implement this method as a wrapper over
125+ /// the corresponding [`MacroDefinedLayout`].
134126 ///
135127 /// [`Stretch`]: crate::layout::Stretch
136128 fn set_rect ( & mut self , cx : & mut ConfigCx , rect : Rect , hints : AlignHints ) ;
@@ -185,11 +177,8 @@ pub trait Layout {
185177 ///
186178 /// ## Default implementation
187179 ///
188- /// The `#[widget]` macro
189- /// [may generate a default implementation](macros::widget#layout-1) by
190- /// implementing [`LayoutVisitor`] for `Self`.
191- /// In this case the default impl of this method is
192- /// `self.layout_visitor().draw(/* ... */)`.
180+ /// The `#[widget]` macro may implement this method as a wrapper over
181+ /// the corresponding [`MacroDefinedLayout`].
193182 ///
194183 /// ## Method modification
195184 ///
@@ -203,297 +192,24 @@ pub trait Layout {
203192 fn draw ( & mut self , draw : DrawCx ) ;
204193}
205194
206- /// Positioning and drawing routines for [`Widget`]s
207- ///
208- /// `Tile` is a super-trait of [`Widget`] which:
209- ///
210- /// - Has no [`Data`](Widget::Data) parameter
211- /// - Supports read-only tree reflection: [`Self::get_child`]
212- /// - Provides some basic operations: [`Self::id_ref`], [`Self::rect`]
213- /// - Covers sizing and drawing operations from [`Layout`]
214- ///
215- /// `Tile` may not be implemented directly; it will be implemented by the
216- /// [`#widget`] macro.
195+ /// Macro-defined layout
217196///
218- /// # Tree reflection
197+ /// This trait is a copy of [`Layout`], implemented automatically for custom
198+ /// widgets with macro-defined layout. It may be useful for small hacks where
199+ /// the macro-generated layout implementations should still be used, but with
200+ /// some addition or modification of inputs.
219201///
220- /// `Tile` offers a reflection API over the widget tree via
221- /// [`Tile::get_child`]. This is limited to read-only functions, and thus
222- /// cannot directly violate the widget lifecycle, however note that the
223- /// [`id_ref`](Self::id_ref) could be invalid or could be valid but refer to a
224- /// node which has not yet been sized and positioned (and thus which it is not
225- /// valid to send events to).
226- ///
227- /// [`#widget`]: macros::widget
228- #[ autoimpl( for <T : trait + ?Sized > & ' _ mut T , Box <T >) ]
229- pub trait Tile : Layout {
230- /// Get as a `dyn Tile`
231- ///
232- /// This method is implemented by the `#[widget]` macro.
233- fn as_tile ( & self ) -> & dyn Tile {
234- unimplemented ! ( ) // make rustdoc show that this is a provided method
235- }
236-
237- /// Get a reference to the widget's identifier
238- ///
239- /// The widget identifier is assigned when the widget is configured (see
240- /// [`Events::configure`] and [`Events::configure_recurse`]). In case the
241- /// [`Id`] is accessed before this, it will be [invalid](Id#invalid-state).
242- /// The identifier *may* change when widgets which are descendants of some
243- /// dynamic layout are reconfigured.
244- ///
245- /// This method is implemented by the `#[widget]` macro.
246- fn id_ref ( & self ) -> & Id {
247- unimplemented ! ( ) // make rustdoc show that this is a provided method
248- }
249-
250- /// Get the widget's identifier
251- ///
252- /// This method returns a [`Clone`] of [`Self::id_ref`]. Since cloning an
253- /// `Id` is [very cheap](Id#representation), this can mostly be ignored.
254- ///
255- /// The widget identifier is assigned when the widget is configured (see
256- /// [`Events::configure`] and [`Events::configure_recurse`]). In case the
257- /// [`Id`] is accessed before this, it will be [invalid](Id#invalid-state).
258- /// The identifier *may* change when widgets which are descendants of some
259- /// dynamic layout are reconfigured.
260- #[ inline]
261- fn id ( & self ) -> Id {
262- self . id_ref ( ) . clone ( )
263- }
264-
265- /// Get the widget's region, relative to its parent.
266- ///
267- /// This method is usually implemented by the `#[widget]` macro.
268- /// See also [`kas::widget_set_rect`].
269- fn rect ( & self ) -> Rect ;
270-
271- /// Get the name of the widget struct
272- ///
273- /// This method is implemented by the `#[widget]` macro.
274- fn widget_name ( & self ) -> & ' static str {
275- unimplemented ! ( ) // make rustdoc show that this is a provided method
276- }
277-
278- /// Get the number of child widgets
279- ///
280- /// Every value in the range `0..self.num_children()` is a valid child
281- /// index.
282- ///
283- /// This method is usually implemented automatically by the `#[widget]`
284- /// macro. It should be implemented directly if and only if
285- /// [`Tile::get_child`] and [`Widget::for_child_node`] are
286- /// implemented directly.
287- fn num_children ( & self ) -> usize {
288- unimplemented ! ( ) // make rustdoc show that this is a provided method
289- }
290-
291- /// Access a child as a `dyn Tile`
292- ///
293- /// This method returns `None` exactly when `index >= self.num_children()`.
294- ///
295- /// This method is usually implemented automatically by the `#[widget]`
296- /// macro.
297- fn get_child ( & self , index : usize ) -> Option < & dyn Tile > {
298- let _ = index;
299- unimplemented ! ( ) // make rustdoc show that this is a provided method
300- }
301-
302- /// Find the child which is an ancestor of this `id`, if any
303- ///
304- /// If `Some(index)` is returned, this is *probably* but not guaranteed
305- /// to be a valid child index.
306- ///
307- /// The default implementation simply uses [`Id::next_key_after`].
308- /// Widgets may choose to assign children custom keys by overriding this
309- /// method and [`Events::make_child_id`].
310- #[ inline]
311- fn find_child_index ( & self , id : & Id ) -> Option < usize > {
312- id. next_key_after ( self . id_ref ( ) )
313- }
314-
315- /// Navigation in spatial order
316- ///
317- /// Controls <kbd>Tab</kbd> navigation order of children.
318- /// This method should:
319- ///
320- /// - Return `None` if there is no (next) navigable child
321- /// - In the case there are navigable children and `from == None`, return
322- /// the index of the first (or last if `reverse`) navigable child
323- /// - In the case there are navigable children and `from == Some(index)`,
324- /// it may be expected that `from` is the output of a previous call to
325- /// this method; the method should return the next (or previous if
326- /// `reverse`) navigable child (if any)
327- ///
328- /// The return value mut be `None` or `Some(index)` where
329- /// `self.get_child(index).is_some()` (see [`Tile::get_child`]).
330- ///
331- /// It is not required that all children (all indices `i` for
332- /// `i < self.num_children()`) are returnable from this method.
333- ///
334- /// Default (macro generated) implementation:
335- ///
336- /// - Generated from `#[widget]`'s layout property, if used (not always possible!)
337- /// - Otherwise, iterate through children in order of definition
338- fn nav_next ( & self , reverse : bool , from : Option < usize > ) -> Option < usize > {
339- let _ = ( reverse, from) ;
340- unimplemented ! ( ) // make rustdoc show that this is a provided method
341- }
202+ /// TODO: add an example
203+ pub trait MacroDefinedLayout {
204+ /// Get size rules for the given axis
205+ fn size_rules ( & mut self , sizer : SizeCx , axis : AxisInfo ) -> SizeRules ;
342206
343- /// Get translation of children relative to this widget
344- ///
345- /// Usually this is zero; only widgets with scrollable or offset content
346- /// *and* child widgets need to implement this.
347- /// Such widgets must also implement [`Events::handle_scroll`].
348- ///
349- /// Affects event handling via [`Tile::probe`] and affects the positioning
350- /// of pop-up menus. [`Layout::draw`] must be implemented directly using
351- /// [`DrawCx::with_clip_region`] to offset contents.
352- ///
353- /// Default implementation: return [`Offset::ZERO`]
354- #[ inline]
355- fn translation ( & self ) -> Offset {
356- Offset :: ZERO
357- }
207+ /// Set size and position
208+ fn set_rect ( & mut self , cx : & mut ConfigCx , rect : Rect , hints : AlignHints ) ;
358209
359210 /// Probe a coordinate for a widget's [`Id`]
360- ///
361- /// Returns the [`Id`] of the widget expected to handle clicks and touch
362- /// events at the given `coord`. Typically this is the lowest descendant in
363- /// the widget tree at the given `coord`, but it is not required to be; e.g.
364- /// a `Button` may use an inner widget as a label but return its own [`Id`]
365- /// to indicate that the button (not the inner label) handles clicks.
366- ///
367- /// # Calling
368- ///
369- /// **Prefer to call [`Layout::try_probe`] instead**.
370- ///
371- /// ## Call order
372- ///
373- /// It is expected that [`Layout::set_rect`] is called before this method,
374- /// but failure to do so should not cause a fatal error.
375- ///
376- /// # Implementation
377- ///
378- /// The callee may usually assume that it occupies `coord` and may thus
379- /// return its own [`Id`] when no child occupies the input `coord`.
380- ///
381- /// ## Default implementation
382- ///
383- /// ## Default implementation
384- ///
385- /// The `#[widget]` macro
386- /// [may generate a default implementation](macros::widget#layout-1) by
387- /// implementing [`LayoutVisitor`] for `Self`.
388- /// In this case the default impl of this method is
389- /// `self.layout_visitor().set_rect(/* ... */)`.
390- /// The underlying implementation considers all children of the `layout`
391- /// property and of fields, like this:
392- /// ```ignore
393- /// let coord = coord + self.translation();
394- /// for child in ITER_OVER_CHILDREN {
395- /// if let Some(id) = child.try_probe(coord) {
396- /// return Some(id);
397- /// }
398- /// }
399- /// self.id()
400- /// ```
401- fn probe ( & mut self , coord : Coord ) -> Id
402- where
403- Self : Sized ,
404- {
405- let _ = coord;
406- unimplemented ! ( ) // make rustdoc show that this is a provided method
407- }
408- }
409-
410- impl < W : Tile + ?Sized > HasId for & W {
411- #[ inline]
412- fn has_id ( self ) -> Id {
413- self . id_ref ( ) . clone ( )
414- }
415- }
416-
417- impl < W : Tile + ?Sized > HasId for & mut W {
418- #[ inline]
419- fn has_id ( self ) -> Id {
420- self . id_ref ( ) . clone ( )
421- }
422- }
423-
424- /// Extension trait over widgets
425- pub trait TileExt : Tile {
426- /// Test widget identifier for equality
427- ///
428- /// This method may be used to test against `Id`, `Option<Id>`
429- /// and `Option<&Id>`.
430- #[ inline]
431- fn eq_id < T > ( & self , rhs : T ) -> bool
432- where
433- Id : PartialEq < T > ,
434- {
435- * self . id_ref ( ) == rhs
436- }
437-
438- /// Display as "StructName#Id"
439- #[ inline]
440- fn identify ( & self ) -> IdentifyWidget {
441- IdentifyWidget ( self . widget_name ( ) , self . id_ref ( ) )
442- }
443-
444- /// Check whether `id` is self or a descendant
445- ///
446- /// This function assumes that `id` is a valid widget.
447- #[ inline]
448- fn is_ancestor_of ( & self , id : & Id ) -> bool {
449- self . id_ref ( ) . is_ancestor_of ( id)
450- }
451-
452- /// Check whether `id` is not self and is a descendant
453- ///
454- /// This function assumes that `id` is a valid widget.
455- #[ inline]
456- fn is_strict_ancestor_of ( & self , id : & Id ) -> bool {
457- !self . eq_id ( id) && self . id_ref ( ) . is_ancestor_of ( id)
458- }
459-
460- /// Run a closure on all children
461- fn for_children ( & self , mut f : impl FnMut ( & dyn Tile ) ) {
462- for index in 0 ..self . num_children ( ) {
463- if let Some ( child) = self . get_child ( index) {
464- f ( child) ;
465- }
466- }
467- }
468-
469- /// Run a fallible closure on all children
470- ///
471- /// Returns early in case of error.
472- fn for_children_try < E > ( & self , mut f : impl FnMut ( & dyn Tile ) -> Result < ( ) , E > ) -> Result < ( ) , E > {
473- let mut result = Ok ( ( ) ) ;
474- for index in 0 ..self . num_children ( ) {
475- if let Some ( child) = self . get_child ( index) {
476- result = f ( child) ;
477- }
478- if result. is_err ( ) {
479- break ;
480- }
481- }
482- result
483- }
211+ fn try_probe ( & mut self , coord : Coord ) -> Option < Id > ;
484212
485- /// Find the descendant with this `id`, if any
486- ///
487- /// Since `id` represents a path, this operation is normally `O(d)` where
488- /// `d` is the depth of the path (depending on widget implementations).
489- fn find_widget ( & self , id : & Id ) -> Option < & dyn Tile > {
490- if let Some ( child) = self . find_child_index ( id) . and_then ( |i| self . get_child ( i) ) {
491- child. find_widget ( id)
492- } else if self . eq_id ( id) {
493- Some ( self . as_tile ( ) )
494- } else {
495- None
496- }
497- }
213+ /// Draw a widget and its children
214+ fn draw ( & mut self , draw : DrawCx ) ;
498215}
499- impl < W : Tile + ?Sized > TileExt for W { }
0 commit comments