Conversation
DJMcNab
left a comment
There was a problem hiding this comment.
Apart from the pointer event TODO comment, this seems reasonable as an addition to Masonry.
masonry/src/widgets/canvas.rs
Outdated
| // --- MARK: IMPL WIDGET --- | ||
| impl Widget for Canvas { | ||
| fn on_pointer_event(&mut self, _ctx: &mut EventCtx, _event: &PointerEvent) { | ||
| // TODO: ensure coordinates are correct and pass to callback |
There was a problem hiding this comment.
This comment is misleading. Something has gone wrong if the canvas widget is managing the pointer event. At that point, the user should be writing their own widget, I believe.
A canvas is basically equivalent to an Image, but containing a vector scene (ish).
masonry/src/widgets/canvas.rs
Outdated
| } | ||
|
|
||
| fn accessibility(&mut self, _ctx: &mut AccessCtx, _node: &mut Node) { | ||
| // TODO: should probably give the caller the opportunity to handle accessibility |
There was a problem hiding this comment.
This would probably just be an alt-text like mechanism, although maybe we should also be strongly encouraging that a caption exist?
We haven't handled this for Image, which this is very similar to.
|
One question I have: can a scene fragment be retained and appended to the scene on paint? |
|
Masonry is already doing that internally; your paint callback will only be called once, except when it gets replaced or the layout changes |
594c48d to
0326db5
Compare
|
OK ready for review. |
|
How is the CI so fast!?!?! |
| fn accepts_pointer_interaction(&self) -> bool { | ||
| false | ||
| } |
There was a problem hiding this comment.
I don't think you should set this flag to false. It makes Canvas transparent to pointers, meaning for example that if there's a widget behind the canvas, that widget will get pointer events, affect the pointer icon, etc.
There was a problem hiding this comment.
I'm not certain that I agree; I can see arguments either way (since the canvas isn't filled by default, for example). But since if it did intercept pointer events, they would still bubble up to the parents, then either way is fine.
There was a problem hiding this comment.
I suggest setting it to true for now, then seeing how that works in practice.
masonry/src/widgets/canvas.rs
Outdated
| fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { | ||
| (self.draw)(scene, ctx.size()); | ||
| } |
There was a problem hiding this comment.
So, to be clear, this is a static canvas, right? The draw function isn't expected to paint different things from frame to frame?
There was a problem hiding this comment.
I think so - it could be used for things like icons. But what should be different if it were more dynamic?
Co-authored-by: Olivier FAURE <couteaubleu@gmail.com>
fb12fbe to
ec5c653
Compare
|
Should be ready for review again (assuming CI is green). I will squash before merging, as I don't think there is anything to be gained by keeping the commits. |
Not necessary though, as this is the default anyways when merging (with the title/text in the PR top comment as commit description), so keeping the commits should give a better timeline of this PR shouldn't it? |
| /// A non-interactive text element. | ||
| /// # Example | ||
| /// | ||
| /// ```ignore | ||
| /// use xilem::palette; | ||
| /// use xilem::view::label; | ||
| /// use masonry::TextAlignment; | ||
| /// use masonry::parley::fontique; | ||
| /// | ||
| /// label("Text example.") | ||
| /// .brush(palette::css::RED) | ||
| /// .alignment(TextAlignment::Middle) | ||
| /// .text_size(24.0) | ||
| /// .weight(FontWeight::BOLD) | ||
| /// .with_font(fontique::GenericFamily::Serif) | ||
| /// ``` |
There was a problem hiding this comment.
I don't think these docs are right...
There was a problem hiding this comment.
Oops sorry I missed this!
| _ctx: &mut ViewCtx, | ||
| element: Mut<Self::Element>, | ||
| ) { | ||
| if !Arc::ptr_eq(&self.draw, &prev.draw) { |
There was a problem hiding this comment.
This is... always true, because canvas always allocates. I think the only sound way to handle this currently is to force the user to provide an already Arced function. That's... far from ideal from an ergonomics perspective, but it matches the semantics you need.
Essentially, you'd need to combine it with something like memoize for this API to be reasonable; it's the unfortunate ergonomics papercut around closures being incomparable (rust-lang/rfcs#3538)
| let mut harness = TestHarness::create(canvas); | ||
|
|
||
| assert_debug_snapshot!(harness.root_widget()); | ||
| assert_render_snapshot!(harness, "hello"); |
There was a problem hiding this comment.
| assert_render_snapshot!(harness, "hello"); | |
| assert_render_snapshot!(harness, "stroked_triangle"); |
(I'm not sure if _ or - is more idiomatic here)
| this.ctx.request_render(); | ||
| } | ||
|
|
||
| pub fn set_alt_text(mut this: WidgetMut<'_, Self>, alt_text: String) { |
There was a problem hiding this comment.
This not getting a warning for missing_docs suggests that something is wrong here. (It's fine for the docs to just point to Canvas::with_alt_text)
| } | ||
|
|
||
| pub fn remove_alt_text(mut this: WidgetMut<'_, Self>) { | ||
| this.widget.alt_text = None; |
There was a problem hiding this comment.
What are the semantics of no alt text as opposed to setting it to ""? (cc @PoignardAzur, as you suggest setting it to Some(String::new()) if it's not a semantically meaningful canvas)
There was a problem hiding this comment.
You'd have to ask @mwcampbell for an authoritative answer, but from what I remember:
- Setting no alt-text means you "forgot" to add it, and some screen reader tools might add a default one for you.
- Setting an empty alt text means you consider that the item shouldn't be described by screen readers.
At least I think that's how ARIA treats it.
| /// Users are encouraged to set alt text for the canvas. | ||
| /// If possible, the alt-text should succinctly describe what the canvas represents. | ||
| /// | ||
| /// If the canvas is decorative or too hard to describe through text, users should set alt text to `""`. |
There was a problem hiding this comment.
@PoignardAzur, do you have an example of something which is "too hard" to describe through text, but which should be a canvas?
That is, if the "too hard" clause is for highly dynamic content, then it probably should be a bespoke widget with a proper accessibility implementation, and so the "too hard" clause doesn't apply. Would it be better for the alt text to say "we've chosen not to make this accessible because we can't be bothered" in that case?
There was a problem hiding this comment.
The canonical way to say "We've chosen to not include this in the accessibility tree" is to add an empty string as alt-text.
Would it be better for the alt text to say "we've chosen not to make this accessible because we can't be bothered" in that case?
For this kind of question, you must keep in the mind the experience of reading a page with a screen reader. Like, if you're reading an article or using an app, does it make sense to have the reader say "Menu, Help, Files, New Project, Open Project, We're sorry but we've chosen to not make this app accessible"? Does it help you navigate the app better?
I don't have answers for the general case, and I'd advise against giving one. I want to discourage the mode of thinking that making an app accessible is about giving each widget a maximally descriptive alt text.
There was a problem hiding this comment.
It's a good point. My thinking here does need to be focused on the user experience, and having a snarky message isn't that. But I still think there is an important distinction between the two cases, and using the same handling for both is doing a disservice to the end user. That is, the cases are:
- Not in the accessibility tree/only for visual display purposes. In that case setting to the empty string is the right behaviour. I agree completely with that.
- The content of this widget is potentially important to all users, but we've decided not to make it accessible because doing so would be "too hard". Add Canvas widget #875 (comment) seems to answer this; that if it's "too hard" to add alt text, then we should just not add it. That would then use the screen reader's default handling of "developer didn't bother to make this accessible".
This sentence in the docs conflates those two cases, I think. Having both be the same case has one of two consequences:
- It just completely hides that important information is missing from the user; i.e. creates an unknown unknown; OR
- It forces the user to doubt all items which are indicated as display-only
There was a problem hiding this comment.
This comment is entirely correct.
There was a problem hiding this comment.
Which one? You mean Daniel's?
There was a problem hiding this comment.
Yes. You were also correct about the distinction between no alt text and empty alt text.
| panic!("Snapshot test '{test_name}' failed: No reference file"); | ||
| panic!( | ||
| "Snapshot test '{test_name}' failed: No reference file\n\ | ||
| New screenshot created with `.new.png` extension. If correct, change to `.png`" |
There was a problem hiding this comment.
I think it would be slightly better style to indent this to match the start of the string, rather than the panic
DJMcNab
left a comment
There was a problem hiding this comment.
(Marking as request changes for the sake of GitHub's UI, to indicate that this is waiting on the author)
Any new widget code needs to have full docs. Not having `missing_docs` trigger by default for new widgets is quite bad. See #875 and #882 for cases where this over-broad allow has bitten us. The comment about not using `expect(missing_docs)` because of rust-analyzer is confusing to me; I don't run into an issue. It might have been rust-lang/rust#130021, which is now fixed. That comment should have had a link to an upstream issue for more context.
|
Superseded by #1519 |
I'm playing with making a vector path editor in
xilem. This requires some extra stuff over what is currently available so I'm going to maintain a fork. I will try to merge upstream anything I think is more widely useful.This PR allows the user to draw directly onto the scene fragment for a widget. Currently, the user must recreate the draw function every time there is a change in state. I wonder if there should be separated out state and draw parts, so the function needs to be updated less often.