Skip to content

Commit

Permalink
Merge pull request #473 from kas-gui/work
Browse files Browse the repository at this point in the history
Move fn Events::probe to Tile with where Self: Sized clause
  • Loading branch information
dhardy authored Jan 29, 2025
2 parents 91ed8dd + 47c220e commit 12ade4c
Show file tree
Hide file tree
Showing 27 changed files with 421 additions and 402 deletions.
54 changes: 52 additions & 2 deletions crates/kas-core/src/core/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ pub trait Layout {
///
/// # Implementation
///
/// Widgets should implement [`Events::probe`] instead, in which case an
/// Widgets should implement [`Tile::probe`] instead, in which case an
/// implemention of this method will be provided:
/// ```ignore
/// self.rect().contains(coord).then(|| self.probe(coord))
Expand Down Expand Up @@ -340,7 +340,7 @@ pub trait Tile: Layout {
/// *and* child widgets need to implement this.
/// Such widgets must also implement [`Events::handle_scroll`].
///
/// Affects event handling via [`Events::probe`] and affects the positioning
/// Affects event handling via [`Tile::probe`] and affects the positioning
/// of pop-up menus. [`Layout::draw`] must be implemented directly using
/// [`DrawCx::with_clip_region`] to offset contents.
///
Expand All @@ -349,6 +349,56 @@ pub trait Tile: Layout {
fn translation(&self) -> Offset {
Offset::ZERO
}

/// Probe a coordinate for a widget's [`Id`]
///
/// Returns the [`Id`] of the widget expected to handle clicks and touch
/// events at the given `coord`. Typically this is the lowest descendant in
/// the widget tree at the given `coord`, but it is not required to be; e.g.
/// a `Button` may use an inner widget as a label but return its own [`Id`]
/// to indicate that the button (not the inner label) handles clicks.
///
/// # Calling
///
/// **Prefer to call [`Layout::try_probe`] instead**.
///
/// ## Call order
///
/// It is expected that [`Layout::set_rect`] is called before this method,
/// but failure to do so should not cause a fatal error.
///
/// # Implementation
///
/// The callee may usually assume that it occupies `coord` and may thus
/// return its own [`Id`] when no child occupies the input `coord`.
///
/// ## Default implementation
///
/// ## Default implementation
///
/// The `#[widget]` macro
/// [may generate a default implementation](macros::widget#layout-1) by
/// implementing [`LayoutVisitor`] for `Self`.
/// In this case the default impl of this method is
/// `self.layout_visitor().set_rect(/* ... */)`.
/// The underlying implementation considers all children of the `layout`
/// property and of fields, like this:
/// ```ignore
/// let coord = coord + self.translation();
/// for child in ITER_OVER_CHILDREN {
/// if let Some(id) = child.try_probe(coord) {
/// return Some(id);
/// }
/// }
/// self.id()
/// ```
fn probe(&mut self, coord: Coord) -> Id
where
Self: Sized,
{
let _ = coord;
unimplemented!() // make rustdoc show that this is a provided method
}
}

impl<W: Tile + ?Sized> HasId for &W {
Expand Down
50 changes: 1 addition & 49 deletions crates/kas-core/src/core/widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use super::{Node, Tile};
#[allow(unused)] use crate::event::Used;
use crate::event::{ConfigCx, Event, EventCx, IsUsed, Scroll, Unused};
use crate::geom::Coord;
#[allow(unused)] use crate::layout::LayoutVisitor;
use crate::Id;
#[allow(unused)] use kas_macros as macros;
Expand Down Expand Up @@ -143,53 +142,6 @@ pub trait Events: Widget + Sized {
false
}

/// Probe a coordinate for a widget's [`Id`]
///
/// Returns the [`Id`] of the widget expected to handle clicks and touch
/// events at the given `coord`. Typically this is the lowest descendant in
/// the widget tree at the given `coord`, but it is not required to be; e.g.
/// a `Button` may use an inner widget as a label but return its own [`Id`]
/// to indicate that the button (not the inner label) handles clicks.
///
/// # Calling
///
/// **Prefer to call [`Layout::try_probe`] instead**.
///
/// ## Call order
///
/// It is expected that [`Layout::set_rect`] is called before this method,
/// but failure to do so should not cause a fatal error.
///
/// # Implementation
///
/// The callee may usually assume that it occupies `coord` and may thus
/// return its own [`Id`] when no child occupies the input `coord`.
///
/// ## Default implementation
///
/// ## Default implementation
///
/// The `#[widget]` macro
/// [may generate a default implementation](macros::widget#layout-1) by
/// implementing [`LayoutVisitor`] for `Self`.
/// In this case the default impl of this method is
/// `self.layout_visitor().set_rect(/* ... */)`.
/// The underlying implementation considers all children of the `layout`
/// property and of fields, like this:
/// ```ignore
/// let coord = coord + self.translation();
/// for child in ITER_OVER_CHILDREN {
/// if let Some(id) = child.try_probe(coord) {
/// return Some(id);
/// }
/// }
/// self.id()
/// ```
fn probe(&mut self, coord: Coord) -> Id {
let _ = coord;
unimplemented!() // make rustdoc show that this is a provided method
}

/// Mouse focus handler
///
/// Called when mouse hover state changes.
Expand Down Expand Up @@ -362,7 +314,7 @@ pub enum NavAdvance {
/// - **Layout** is specified either via [layout syntax](macros::widget#layout-1)
/// or via implementation of at least [`Layout::size_rules`] and
/// [`Layout::draw`] (optionally also `set_rect`, `nav_next`, `translation`
/// and [`Events::probe`]).
/// and [`Tile::probe`]).
///- **Event handling** is optional, implemented through [`Events`].
///
/// For examples, check the source code of widgets in the widgets library
Expand Down
4 changes: 0 additions & 4 deletions crates/kas-core/src/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,10 +210,6 @@ impl_scope! {
}
}

fn probe(&mut self, _: Coord) -> Id {
unimplemented!()
}

fn handle_event(&mut self, cx: &mut EventCx, _: &Self::Data, event: Event) -> IsUsed {
match event {
Event::PressStart { .. } if self.drag_anywhere => {
Expand Down
6 changes: 3 additions & 3 deletions crates/kas-macros/src/make_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ impl Tree {
}

fn try_probe(&mut self, coord: ::kas::geom::Coord) -> Option<::kas::Id> {
::kas::Tile::rect(self).contains(coord).then(|| ::kas::Events::probe(self, coord))
::kas::Tile::rect(self).contains(coord).then(|| ::kas::Tile::probe(self, coord))
}

fn draw(&mut self, mut draw: ::kas::theme::DrawCx) {
Expand All @@ -206,9 +206,7 @@ impl Tree {
fn nav_next(&self, reverse: bool, from: Option<usize>) -> Option<usize> {
#nav_next
}
}

impl #impl_generics ::kas::Events for #impl_target {
#[inline]
fn probe(&mut self, coord: ::kas::geom::Coord) -> ::kas::Id {
#[cfg(debug_assertions)]
Expand All @@ -219,7 +217,9 @@ impl Tree {
.try_probe(coord)
.unwrap_or_else(|| ::kas::Tile::id(self))
}
}

impl #impl_generics ::kas::Events for #impl_target {
fn handle_event(
&mut self,
_: &mut ::kas::event::EventCx,
Expand Down
13 changes: 6 additions & 7 deletions crates/kas-macros/src/widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -506,16 +506,11 @@ pub fn widget(attr_span: Span, mut args: WidgetArgs, scope: &mut Scope) -> Resul
if let Some(index) = events_impl {
let events_impl = &mut scope.impls[index];
let item_idents = collect_idents(events_impl);
let has_item = |name| item_idents.iter().any(|(_, ident)| ident == name);

if let Some(method) = fn_navigable {
events_impl.items.push(Verbatim(method));
}

if !has_item("probe") {
events_impl.items.push(Verbatim(fn_probe));
}

events_impl.items.push(Verbatim(fn_handle_hover));

if let Some((index, _)) = item_idents
Expand All @@ -538,7 +533,6 @@ pub fn widget(attr_span: Span, mut args: WidgetArgs, scope: &mut Scope) -> Resul
scope.generated.push(quote! {
impl #impl_generics ::kas::Events for #impl_target {
#fn_navigable
#fn_probe
#fn_handle_hover
#fn_handle_event
}
Expand All @@ -550,7 +544,7 @@ pub fn widget(attr_span: Span, mut args: WidgetArgs, scope: &mut Scope) -> Resul
#[cfg(debug_assertions)]
self.#core.status.require_rect(&self.#core._id);

::kas::Tile::rect(self).contains(coord).then(|| ::kas::Events::probe(self, coord))
::kas::Tile::rect(self).contains(coord).then(|| ::kas::Tile::probe(self, coord))
}
};

Expand Down Expand Up @@ -655,6 +649,10 @@ pub fn widget(attr_span: Span, mut args: WidgetArgs, scope: &mut Scope) -> Resul
}
}
}

if !has_item("probe") {
tile_impl.items.push(Verbatim(fn_probe));
}
} else {
let fn_nav_next = match fn_nav_next {
Ok(method) => Some(method),
Expand All @@ -668,6 +666,7 @@ pub fn widget(attr_span: Span, mut args: WidgetArgs, scope: &mut Scope) -> Resul
impl #impl_generics ::kas::Tile for #impl_target {
#required_tile_methods
#fn_nav_next
#fn_probe
}
});
}
Expand Down
78 changes: 39 additions & 39 deletions crates/kas-view/src/list_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,33 +419,6 @@ impl_scope! {
}
}

impl Tile for Self {
#[inline]
fn num_children(&self) -> usize {
self.cur_len.cast()
}
fn get_child(&self, index: usize) -> Option<&dyn Tile> {
self.widgets.get(index).map(|w| w.widget.as_tile())
}
fn find_child_index(&self, id: &Id) -> Option<usize> {
let key = A::Key::reconstruct_key(self.id_ref(), id);
if key.is_some() {
self.widgets
.iter()
.enumerate()
.filter_map(|(i, w)| (key == w.key).then_some(i))
.next()
} else {
None
}
}

#[inline]
fn translation(&self) -> Offset {
self.scroll_offset()
}
}

impl Layout for Self {
fn size_rules(&mut self, sizer: SizeCx, mut axis: AxisInfo) -> SizeRules {
// We use an invisible frame for highlighting selections, drawing into the margin
Expand Down Expand Up @@ -570,6 +543,45 @@ impl_scope! {
}
}

impl Tile for Self {
#[inline]
fn num_children(&self) -> usize {
self.cur_len.cast()
}
fn get_child(&self, index: usize) -> Option<&dyn Tile> {
self.widgets.get(index).map(|w| w.widget.as_tile())
}
fn find_child_index(&self, id: &Id) -> Option<usize> {
let key = A::Key::reconstruct_key(self.id_ref(), id);
if key.is_some() {
self.widgets
.iter()
.enumerate()
.filter_map(|(i, w)| (key == w.key).then_some(i))
.next()
} else {
None
}
}

#[inline]
fn translation(&self) -> Offset {
self.scroll_offset()
}

fn probe(&mut self, coord: Coord) -> Id {
let coord = coord + self.scroll.offset();
for child in &mut self.widgets[..self.cur_len.cast()] {
if child.key.is_some() {
if let Some(id) = child.widget.try_probe(coord) {
return id;
}
}
}
self.id()
}
}

impl Events for Self {
#[inline]
fn make_child_id(&mut self, _: usize) -> Id {
Expand Down Expand Up @@ -616,18 +628,6 @@ impl_scope! {

fn update_recurse(&mut self, _: &mut ConfigCx, _: &Self::Data) {}

fn probe(&mut self, coord: Coord) -> Id {
let coord = coord + self.scroll.offset();
for child in &mut self.widgets[..self.cur_len.cast()] {
if child.key.is_some() {
if let Some(id) = child.widget.try_probe(coord) {
return id;
}
}
}
self.id()
}

fn handle_event(&mut self, cx: &mut EventCx, data: &A, event: Event) -> IsUsed {
let is_used = match event {
Event::Command(cmd, _) => {
Expand Down
Loading

0 comments on commit 12ade4c

Please sign in to comment.