iris: a tap on an empty text field left no caret, so typing was silently dropped
TextEditCtx::select compared the tap against the laid-out text's own box and cleared the selection for anything outside it. An empty field lays out to a zero-width box, so tapping the composer granted focus and opened the keyboard with no caret, and insert_str returns early without one -- every keystroke went nowhere and no glyph was ever emitted. Parley clamps a point outside the layout by itself, and a press reaching select() has already been hit-tested to the widget, so there was nothing for the 'outside' branch to mean. insert_str now debug_asserts rather than dropping input silently, and UiRenderState::draw_started -- a re-entrancy guard whose test was written after its own remove(), so it could never fire, and which grew by one entry per widget ever drawn -- is restored to what it was meant to be: inserted around Widget::draw, removed when it returns, asserted empty at the top of every update.
This commit is contained in:
1 parent
d9872989fa
commit
c02152a4f4
8 files changed
+168
-47
No files matched your search
@@ -18,6 +18,18 @@ pub struct UiRenderState {
|
||||
|
||||
old_root: Option<WidgetId>,
|
||||
resized: bool,
|
||||
/// The widgets whose `Widget::draw` is on the stack right now -- so
|
||||
/// [`Self::redraw`] can tell "this widget needs drawing again" from
|
||||
/// "an ancestor is drawing it at this very moment", where a second
|
||||
/// draw would leave the first one's primitives behind with nothing
|
||||
/// owning them. An id is inserted immediately before `draw` is called
|
||||
/// and removed the moment it returns (both in `draw_inner`), so this
|
||||
/// is empty between frames -- asserted at the end of `update`.
|
||||
///
|
||||
/// It used to only ever be inserted into, and `redraw` removed the id
|
||||
/// *before* testing for it, which made the test constant `false`: the
|
||||
/// guard could never fire and the set grew by one entry per widget
|
||||
/// ever drawn and was never emptied.
|
||||
draw_started: HashSet<WidgetId>,
|
||||
|
||||
/// The widget currently holding exclusive pointer input, if any --
|
||||
@@ -115,6 +127,11 @@ impl UiRenderState {
|
||||
);
|
||||
}
|
||||
let root = root.into();
|
||||
debug_assert!(
|
||||
self.draw_started.is_empty(),
|
||||
"a previous frame left {} widget(s) marked as mid-draw",
|
||||
self.draw_started.len(),
|
||||
);
|
||||
if self.needs_redraw_all(root) {
|
||||
self.redraw_all(root, rsc);
|
||||
self.old_root = root.map(|r| r.id());
|
||||
@@ -213,7 +230,12 @@ impl UiRenderState {
|
||||
}
|
||||
|
||||
// draw widget
|
||||
self.draw_started.insert(id);
|
||||
let reentrant = !self.draw_started.insert(id);
|
||||
debug_assert!(
|
||||
!reentrant,
|
||||
"widget {id:?} is being drawn while its own draw is already on the stack; \
|
||||
the second draw's primitives would orphan the first's"
|
||||
);
|
||||
|
||||
let move_slot = match old_move_slot {
|
||||
// Reused across a real redraw of the same id: the fresh
|
||||
@@ -259,6 +281,7 @@ impl UiRenderState {
|
||||
painter.state.draw_count += 1;
|
||||
let size = widget.draw(&mut painter);
|
||||
drop(widget);
|
||||
painter.state.draw_started.remove(&id);
|
||||
|
||||
let Painter {
|
||||
state: _,
|
||||
@@ -535,7 +558,10 @@ impl UiRenderState {
|
||||
/// redraws a widget that's currently active (drawn)
|
||||
pub fn redraw(&mut self, id: WidgetId, rsc: &mut dyn UiRsc) {
|
||||
rsc.widgets_mut().needs_redraw.remove(&id);
|
||||
self.draw_started.remove(&id);
|
||||
// An ancestor is drawing this widget right now, and that draw is
|
||||
// about to write fresh primitives for it. Drawing it a second time
|
||||
// here would leave one of the two copies on screen with nothing
|
||||
// owning it -- see `draw_started`'s own doc.
|
||||
if self.draw_started.contains(&id) {
|
||||
return;
|
||||
}
|
||||
@@ -561,7 +587,6 @@ impl UiRenderState {
|
||||
Some(active.move_slot),
|
||||
rsc,
|
||||
);
|
||||
|
||||
// If this widget's own reported size changed, its parent's layout
|
||||
// (which placed it using the old size) is now stale and needs to
|
||||
// relay out too. Checked after the real draw, not before it --
|
||||
|
||||
Reference in new issue
Block a user