Having `Box<dyn Widget>` implement the `Widget` trait is a crutch that
makes a bunch of things more complicated.
It leads to double-boxing in cases when the `dyn Widget` is itself a
`Box<dyn Widget>` (especially since the arena's current implementation
boxes all widgets by default), makes it harder to reason about
downcasting, and ends up producing a lot of code to handle the edge
cases.
On the xilem side, `Box<dyn Widget>` is slightly redundant with
`DynWidget`.
This PR still leaves a lot of boxing. On the long term, we'd like for
the arena to pack arbitrary widgets efficiently using some kind of
archetype scheme, but in the meantime, boxing will have to do.
Changes in this PR:
- New `FromDynWidget` trait that maybe-downcasts widgets to a
maybe-sized `Widget` type.
- Most places that accept `Widget` now accept `Widget + ?Sized`.
- Remove `impl Widget for Box<dyn Widget>`.
- Replace all instances of `WidgetPod<Box<dyn Widget>>` with
`WidgetPod<dyn Widget>`.
- Replace all instances of `xilem::Pod<Box<dyn Widget>>` with
`xilem::Pod<dyn Widget>`.
- Rename WidgetPod to WidgetBox in xilem_core example to avoid
ambiguity.
Move `#[allow(missing_docs)]` to two modules. Missing docs now warn
everywhere else by default.
Remove `#[expect(rustdoc::broken_intra_doc_links)]` and fix all broken
links.
I've had a try at implementing the unsafe `tree_arena` in a separate lib
(but in the same workspace for now) - haven't thought of a good way to
make non root access not O(depth), without slowing down insertion or
using more memory, though have improved accessing nodes from the root to
O(1) from O(depth) and accessing direct children to O(1) from
O(children)
The biggest remaining issue in this PR is that IME support is not
present.
However, I think landing this is *better* than not landing it, because:
1) If we don't land it, it's going to languish again
2) Getting IME support back can be parallelised (cc @tomcur)
3) Getting Vello 0.3.0 and Parley 0.2.0 unlocks real advantages,
including full emoji support (#420).
To be clear, my first follow-up priority will be connecting the IME back
up. I do not however think this should block on Parley 0.3.0.
Discussion in
https://xi.zulipchat.com/#narrow/channel/317477-masonry/topic/Updating.20Parley.20dependency
This allows exceptions to be burned down on a per-crate basis, rather
than needing to be addressed across the whole codebase at once.
Additionally, this now follows completely the Linebender lint set,
except for the unexpected-cfgs. I don't think I've introduced any
behaviour changes in this PR.
* Treat doc warnings as errors. Historically we've not done so due to
various `rustdoc` bugs giving false positives but I got it to pass
without failure right now, so perhaps better times have arrived.
* Target only `x86_64-unknown-linux-gnu` on docs.rs as we don't have any
platform specific docs.
* Properly enable example scraping for `xilem`, `xilem_core`, and
`masonry`. Fully disable it for `xilem_web` which does not have examples
as Cargo defines them.
* Pass `--all-features` at docs.rs to match our CI and reduce the
maintenance burden of manually syncing the features list.
* Enable the `doc_auto_cfg` feature for docs.rs which will show a little
tip next to feature gated functionality informing of the crate feature
flag.
* Replaced `[!TIP]` with `💡 Tip` that was inside `<div
class="rustdoc-hidden" />`. The GitHub specific tip causes a `rustdoc`
error and [didn't even render
properly](ac2ca38785/masonry/src/doc/01_creating_app.md).
* Updated `01_creating_app.md` just enough to get `rustdoc` to pass, but
that file needs a bunch of more work, as it is outdated.
This is a pub enum within `render_root` and is required for creating a
`RenderRootOptions` which is already exported. This is needed for people
embedding masonry in a non-Xilem way.
This is a very messy, very basic skeleton of what Masonry documentation
will eventually look like.
Main points are:
- Dedicated documentation modules.
- Re-using most of the language from the RFCs.
Next steps are:
- Flesh out the Widget documentation.
- Rewrite all those docs in a less placeholder-y way.
- Add chapter about the widget arena.
- Spread out that pass documentation to the respective pass files.
- Rewrite ARCHITECTURE.md.
- Add screenshots.
Fixes#376 and #389.
---------
Co-authored-by: Daniel McNab <36049421+DJMcNab@users.noreply.github.com>
See discussion here https://github.com/linebender/xilem/pull/663 and [on
zulip](https://xi.zulipchat.com/#narrow/channel/317477-masonry/topic/Improving.20docs.20for.20WidgetMut).
Basically, previous code was using `WidgetMut<MyWidget>` as a receiver.
This can be done when WidgetMut is a local type, but external users
wouldn't be able to do it. The result would be that users importing
Masonry as a dependency but copy-pasting code from one of our widgets
would get compile errors.
This PR switches to a syntax that external crates will be able to use
when declaring widgets. It's a more verbose, less readable syntax, but
it's unambiguous and doesn't require clever tricks.
We can consider switching back to WidgetMut-as-a-receiver when
`#![feature(arbitrary_self_types)]` or some equivalent gets stabilized.
See
https://github.com/rust-lang/rust/issues/44874#issuecomment-2122179688
for current progress.
This is very useful for debugging performance issues. I've already used
it to debug [#masonry>`to_do_list`: Horrendous
performance](https://xi.zulipchat.com/#narrow/stream/317477-masonry/topic/to_do_list.3A.20Horrendous.20performance).
Setting a feature works on a workspace-wide basis. I.e `cargo run
--example mason --features tracy` works.
Some weirdness:
- Tracy seems to assume we know when a frame will "start", but we only
know if we'll repaint once processing for an event has finished.
- Something seems to be starting a default "Frame", which isn't really
right. We don't have any continuous frames. Maybe we should always
request a redraw if tracy is enabled.
Either way, I think this feature is useful to land *now*, so am not
planning on resolving these in this PR unless someone provides a
solution.
The `Widget::get_child_at_pos` has a default linear search
implementation, upholding some conditions (e.g., picking the last child
in "z-order" in case of overlap). Widgets can override this with a
custom implementation (e.g., a widget with many children that maintains
a quadtree to search through). Custom implementations should uphold the
same conditions, we can add some debug assertions to check this in a
later PR.
This introduces a `QueryCtx`, allowing widget methods access to the
global state, widget state, and widget subtree. `QueryCtx` is similar to
the other (mutable) context types, but can be shared.
This also changes `WidgetRef` to consist of a `Widget` and a `QueryCtx`,
similar to `WidgetMut` consisting of a `Widget` and `MutateCtx`. This
required changing where `WidgetRef` can be constructed.
This resolves code comment
ac95f2524a/masonry/src/widget/widget_ref.rs (L192-L199)
The `SizedBox` widget in Masonry had the option to set a background
brush that was not exposed in its corresponding view in Xilem. The
`SizedBox` view now exposes the option.
Incidentally, `BackgroundBrush::PainterFn` variant had the wrong type,
as such it was not usable. A `scene` parameter is added and the closure
now requires to be `Send + Sync`.
---------
Co-authored-by: Daniel McNab <36049421+DJMcNab@users.noreply.github.com>
Rather than have to keep a dependency on `kurbo` at the correct version,
always use it via `vello`.
This makes this match how `peniko` is already used within `masonry`.
This is part of the "Pass Specification" RFC:
https://github.com/linebender/rfcs/pull/7
Rename WidgetCtx to MutateCtx.
Add a mutate pass.
Add a `mutate_later` context method to trigger that pass.
Refactor `edit_root_widget` to use a version of that pass.
Add a separate constructor for the synthetic WidgetState created in
RenderRoot.
---------
Co-authored-by: Philipp Mildenberger <philipp@mildenberger.me>
Co-authored-by: Daniel McNab <36049421+DJMcNab@users.noreply.github.com>
This is a first step in implementing the "Pass Specification" RFC:
https://github.com/linebender/rfcs/pull/7
Create a `passes` module.
Create event passes.
Create the update_pointer pass.
Remove `WidgetPod::update_hot_state` method.
Move mouse-cursor-handling code to update_pointer pass.
Implement pointer capture.
Refactor the TreeArena code.
---------
Co-authored-by: Daniel McNab <36049421+DJMcNab@users.noreply.github.com>
These either aren't used, aren't implemented, or are just stubs. A new
implementation may or may not take the same approach given changes
within the ecosystem, and if we want these back, they're in the history.
This was remarkably painless.
I especially appreciate @taiki-e providing an install-action which does
90% of the CI work for us.
---------
Co-authored-by: Daniel McNab <36049421+DJMcNab@users.noreply.github.com>
See discussion in [#linebender > Standard Lint
set](https://xi.zulipchat.com/#narrow/stream/419691-linebender/topic/Standard.20Lint.20set)
Of note: I have taken steps to ensure that this can be practically
reviewed by *not* applying most of the lints.
The commented out lints make good follow-ups
---------
Co-authored-by: Olivier FAURE <couteaubleu@gmail.com>
Related to #44
We don't have any necessary unsafe code, and I don't think any of us
want to lose that.
(Vello is also no longer laundering the unsafety wrt surface creation
thanks to a recent wgpu release)
In most cases, you want a button which only actuates when the primary
mouse button is pressed, so the easy case is still that. This is a short
term hack, because e.g. the active state is still based on any button
being pressed, not just those we are interested in.
That is, we probably need to represent a set of buttons we are
interested in. However, this change minimally unblocks additional work
with Xilem. In particular, see [#xilem > Minesweeper converted from Iced
to
Xilem](https://xi.zulipchat.com/#narrow/stream/354396-xilem/topic/Minesweeper.20converted.20from.20Iced.20to.20Xilem).
This was initially a supposed to be a small documentation pass, which
grew into a few changes:
- Adding back a to-do-list example.
- Fixing the bugs revealed by that example (infinite bounding boxes,
wrong accessibility handling in Portal, etc).
- Making sure all widgets return the correct spans instead of the
less-useful default one.
- Adding a trace to the layout pass for easier debugging.
Overall I'm pretty happy with this!
This allows for running `masonry` with an externally managed event loop
for integrating with an application that is already running an event
loop.
* Expose `PointerState` to allow creating `PointerEvent`
* Expose `WindowEvent` to allow managing window size and scale factor.
* Make `DriverCtx` usable from outside the crate. While this struct was
already `pub`, the sole member of it was not.
This removes a class of dependencies from within both `masonry` and
`xilem` on the `winit` crate where we can just use `dpi` directly
instead.
The `dpi` crate is meant (like `cursor_icon`) to be a shared ecosystem
crate rather than only for usage with `winit`.