Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revise fn Tile::identify; various bug fixes #481

Merged
merged 7 commits into from
Feb 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/kas-core/src/core/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ impl Clone for DefaultCoreType {
DefaultCoreType {
_rect: self._rect,
_id: Default::default(),
#[cfg(debug_assertions)]
status: self.status,
}
}
Expand Down
10 changes: 3 additions & 7 deletions crates/kas-core/src/core/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
//! Widget method implementations

use crate::event::{ConfigCx, Event, EventCx, FocusSource, IsUsed, Scroll, Unused};
#[cfg(debug_assertions)] use crate::util::IdentifyWidget;
use crate::{Events, Id, NavAdvance, Node, Tile, Widget};

/// Generic implementation of [`Widget::_send`]
Expand Down Expand Up @@ -53,7 +52,7 @@ pub fn _send<W: Events>(
// so we ignore in release builds.
log::error!(
"_send: {} found index {index} for {id} but not child",
IdentifyWidget(widget.widget_name(), widget.id_ref())
widget.identify()
);
}

Expand Down Expand Up @@ -91,7 +90,7 @@ pub fn _replay<W: Events>(widget: &mut W, cx: &mut EventCx, data: &<W as Widget>
// so we ignore in release builds.
log::error!(
"_replay: {} found index {index} for {id} but not child",
IdentifyWidget(widget.widget_name(), widget.id_ref())
widget.identify()
);
}

Expand All @@ -108,10 +107,7 @@ pub fn _replay<W: Events>(widget: &mut W, cx: &mut EventCx, data: &<W as Widget>
// This implies use of push_async / push_spawn from a widget which was
// unmapped or removed.
#[cfg(debug_assertions)]
log::debug!(
"_replay: {} cannot find path to {id}",
IdentifyWidget(widget.widget_name(), widget.id_ref())
);
log::debug!("_replay: {} cannot find path to {id}", widget.identify());
}
}

Expand Down
12 changes: 4 additions & 8 deletions crates/kas-core/src/core/tile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,12 @@ pub trait Tile: Layout {
self.id_ref().clone()
}

/// Get the name of the widget struct
/// Return a [`Display`]-able widget identifier
///
/// This method is implemented by the `#[widget]` macro.
fn widget_name(&self) -> &'static str {
///
/// [`Display`]: std::fmt::Display
fn identify(&self) -> IdentifyWidget<'_> {
unimplemented!() // make rustdoc show that this is a provided method
}

Expand Down Expand Up @@ -228,12 +230,6 @@ pub trait TileExt: Tile {
*self.id_ref() == rhs
}

/// Display as "StructName#Id"
#[inline]
fn identify(&self) -> IdentifyWidget {
IdentifyWidget(self.widget_name(), self.id_ref())
}

/// Check whether `id` is self or a descendant
///
/// This function assumes that `id` is a valid widget.
Expand Down
2 changes: 1 addition & 1 deletion crates/kas-core/src/theme/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ impl<T: FormattableText> Layout for Text<T> {
} else {
self.set_max_status(Status::Wrapped);
}
self.rect = rect;
}
self.rect = rect;
self.prepare().expect("not configured");
}

Expand Down
94 changes: 79 additions & 15 deletions crates/kas-core/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,48 @@
use crate::geom::Coord;
#[cfg(all(feature = "image", feature = "winit"))]
use crate::Icon;
use crate::{Id, Tile, TileExt};
use crate::{Id, Tile};
use std::fmt;

enum IdentifyContents<'a> {
Simple(&'a Id),
Wrapping(&'a dyn Tile),
}

/// Helper to display widget identification (e.g. `MyWidget#01`)
///
/// Constructed by [`crate::TileExt::identify`].
pub struct IdentifyWidget<'a>(pub(crate) &'static str, pub(crate) &'a Id);
/// Constructed by [`crate::Tile::identify`].
pub struct IdentifyWidget<'a>(&'a str, IdentifyContents<'a>);
impl<'a> IdentifyWidget<'a> {
/// Construct for a simple widget
pub fn simple(name: &'a str, id: &'a Id) -> Self {
IdentifyWidget(name, IdentifyContents::Simple(id))
}

/// Construct for a wrapping widget
pub fn wrapping(name: &'a str, inner: &'a dyn Tile) -> Self {
IdentifyWidget(name, IdentifyContents::Wrapping(inner))
}
}
impl<'a> fmt::Display for IdentifyWidget<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}{}", self.0, self.1)
match self.1 {
IdentifyContents::Simple(id) => write!(f, "{}{}", self.0, id),
IdentifyContents::Wrapping(inner) => write!(f, "{}<{}>", self.0, inner.identify()),
}
}
}

struct Trail<'a> {
parent: Option<&'a Trail<'a>>,
trail: &'static str,
}
impl<'a> fmt::Display for Trail<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
if let Some(p) = self.parent {
p.fmt(f)?;
}
write!(f, "{}", self.trail)
}
}

Expand All @@ -27,29 +59,44 @@ impl<'a> fmt::Display for IdentifyWidget<'a> {
pub struct WidgetHierarchy<'a> {
widget: &'a dyn Tile,
filter: Option<Id>,
trail: Trail<'a>,
indent: usize,
have_next_sibling: bool,
}
impl<'a> WidgetHierarchy<'a> {
pub fn new(widget: &'a dyn Tile, filter: Option<Id>) -> Self {
WidgetHierarchy {
widget,
filter,
trail: Trail {
parent: None,
trail: "",
},
indent: 0,
have_next_sibling: false,
}
}
}
impl<'a> fmt::Display for WidgetHierarchy<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let len = 43 - 2 * self.indent;
let trail = "| ".repeat(self.indent);
let len = 51 - 2 * self.indent;
let trail = &self.trail;
let (hook, trail_hook) = match self.indent >= 1 {
false => ("", ""),
true if self.have_next_sibling => ("├ ", "│ "),
true => ("└ ", " "),
};
// Note: pre-format some items to ensure correct alignment
let identify = format!("{}", self.widget.identify());
let r = self.widget.rect();
let Coord(x1, y1) = r.pos;
let Coord(x2, y2) = r.pos + r.size;
let xr = format!("x={x1}..{x2}");
let xrlen = xr.len().max(12);
write!(f, "\n{trail}{identify:<len$} {xr:<xrlen$} y={y1}..{y2}")?;
write!(
f,
"\n{trail}{hook}{identify:<len$} {xr:<xrlen$} y={y1}..{y2}"
)?;

let indent = self.indent + 1;

Expand All @@ -59,19 +106,36 @@ impl<'a> fmt::Display for WidgetHierarchy<'a> {
return write!(f, "{}", WidgetHierarchy {
widget,
filter: self.filter.clone(),
indent
trail: Trail {
parent: Some(trail),
trail: trail_hook,
},
indent,
have_next_sibling: false,
});
}
}
}

self.widget.for_children_try(|widget| {
write!(f, "{}", WidgetHierarchy {
widget,
filter: None,
indent
})
})?;
let num_children = self.widget.num_children();
for index in 0..num_children {
if let Some(widget) = self.widget.get_child(index) {
if !widget.id_ref().is_valid() {
continue;
}

write!(f, "{}", WidgetHierarchy {
widget,
filter: None,
trail: Trail {
parent: Some(trail),
trail: trail_hook,
},
indent,
have_next_sibling: index + 1 < num_children,
})?;
}
}
Ok(())
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/kas-macros/src/widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -816,8 +816,8 @@ pub fn required_tile_methods(name: &str, core_path: &Toks) -> Toks {
}

#[inline]
fn widget_name(&self) -> &'static str {
#name
fn identify(&self) -> ::kas::util::IdentifyWidget<'_> {
::kas::util::IdentifyWidget::simple(#name, self.id_ref())
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/kas-macros/src/widget_derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ pub fn widget(_attr_span: Span, args: WidgetArgs, scope: &mut Scope) -> Result<(
}

#[inline]
fn widget_name(&self) -> &'static str {
#widget_name
fn identify(&self) -> ::kas::util::IdentifyWidget<'_> {
::kas::util::IdentifyWidget::wrapping(#widget_name, self.#inner.as_tile())
}

#[inline]
Expand Down
8 changes: 7 additions & 1 deletion crates/kas-widgets/src/menu/menubar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,13 @@ impl_scope! {
frame_rules.surround(rules).0
});
}
solver.for_child(&mut self.layout_store, len, |_| SizeRules::EMPTY.with_stretch(Stretch::Maximize));
solver.for_child(&mut self.layout_store, len, |axis| {
let mut rules = SizeRules::EMPTY;
if axis.is_horizontal() {
rules.set_stretch(Stretch::Maximize);
}
rules
});
solver.finish(&mut self.layout_store)
}

Expand Down
2 changes: 1 addition & 1 deletion crates/kas-widgets/src/scroll_label.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ impl_scope! {
if axis.is_vertical() {
rules.reduce_min_to(sizer.text_line_height(&self.text) * 4);
}
rules
rules.with_stretch(Stretch::Low)
}

fn set_rect(&mut self, cx: &mut ConfigCx, mut rect: Rect, hints: AlignHints) {
Expand Down
2 changes: 1 addition & 1 deletion crates/kas-widgets/src/scroll_text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ impl_scope! {
if axis.is_vertical() {
rules.reduce_min_to(sizer.text_line_height(&self.text) * 4);
}
rules
rules.with_stretch(Stretch::Low)
}

fn set_rect(&mut self, cx: &mut ConfigCx, mut rect: Rect, hints: AlignHints) {
Expand Down
2 changes: 1 addition & 1 deletion examples/gallery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ KAS_CONFIG_MODE=readwrite
)
.unwrap();

let ui = column![ScrollLabel::new(desc), Separator::new(), EventConfig::new(),]
let ui = column![ScrollLabel::new(desc), Separator::new(), EventConfig::new()]
.map_any()
.on_update(|cx, _, data: &AppData| cx.set_disabled(data.disabled));
Box::new(ui)
Expand Down