Refactored touch carets (de)init.

This commit is contained in:
Samuel Guerra 2023-10-26 01:24:31 -03:00
parent 33be98e7db
commit c643a38bd8
3 changed files with 47 additions and 65 deletions

View File

@ -99,7 +99,7 @@ impl Text {
self.widget_builder().push_build_action(|wgt| {
let child = nodes::render_text();
let child = nodes::render_caret(child);
let child = nodes::touch_caret(child);
let child = nodes::touch_carets(child);
let child = nodes::render_overlines(child);
let child = nodes::render_strikethroughs(child);
let child = nodes::render_underlines(child);

View File

@ -2013,7 +2013,7 @@ pub fn render_caret(child: impl UiNode) -> impl UiNode {
/// An Ui node that renders the touch carets and implement interaction.
///
/// Caret visuals defined by [`CARET_TOUCH_SHAPE_VAR`].
pub fn touch_caret(child: impl UiNode) -> impl UiNode {
pub fn touch_carets(child: impl UiNode) -> impl UiNode {
// is [child] or [child, SelectionLeft, SelectionRight] or [child, Insert]
let children = vec![child.boxed()];
@ -2022,82 +2022,64 @@ pub fn touch_caret(child: impl UiNode) -> impl UiNode {
match_node_list(children, move |c, op| match op {
UiNodeOp::Init => {
WIDGET.sub_var(&CARET_TOUCH_SHAPE_VAR);
let r_txt = ResolvedText::get();
let caret = r_txt.caret.lock();
if caret.index.is_some() {
let children = c.children();
let s = CARET_TOUCH_SHAPE_VAR.get();
if caret.selection_index.is_some() {
children.push(s(CaretShape::SelectionLeft));
children.push(s(CaretShape::SelectionRight));
} else {
children.push(s(CaretShape::Insert));
}
}
}
UiNodeOp::Deinit => {
c.deinit_all();
c.children().truncate(1);
}
UiNodeOp::Update { updates } => {
let r_txt = ResolvedText::get();
let caret = r_txt.caret.lock();
if caret.index.is_some() {
if caret.selection_index.is_some() {
let children = c.children();
if children.len() != 3 {
if children.len() == 2 {
children.remove(1).deinit();
}
let s = CARET_TOUCH_SHAPE_VAR.get();
children.push(s(CaretShape::SelectionLeft));
children.push(s(CaretShape::SelectionRight));
}
} // !!: Improve this, and add else case
}
if let Some(s) = CARET_TOUCH_SHAPE_VAR.get_new() {
let children = c.children();
if children.len() >= 2 {
children[1].deinit();
if children.len() == 2 {
children[1] = s(CaretShape::Insert);
} else {
debug_assert_eq!(children.len(), 3);
children[2].deinit();
children[1] = s(CaretShape::SelectionLeft);
children[2] = s(CaretShape::SelectionRight);
children[2].init();
}
children[1].init();
WIDGET.layout().render();
children[0].update(updates);
c.delegated();
UiNodeOp::Update { .. } => {
if CARET_TOUCH_SHAPE_VAR.is_new() {
for caret in &mut c.children()[1..] {
caret.deinit();
}
c.children().truncate(1);
WIDGET.layout();
}
}
UiNodeOp::Layout { wl, final_size } => {
let children = c.children();
let r_txt = ResolvedText::get();
c.delegated();
let children = c.children();
*final_size = children[0].layout(wl);
let caret = r_txt.caret.lock();
let mut expected_len = 1; // 1 child
if caret.index.is_some() && FOCUS.focused().with(|p| matches!(p, Some(p) if p.widget_id() == WIDGET.id())) {
if caret.selection_index.is_some() {
expected_len = 3;
} else {
expected_len = 2;
}
}
if expected_len != children.len() {
// children.len changed OR caret shape changed
for caret in &mut children[1..] {
caret.deinit();
}
children.truncate(1);
let shape = CARET_TOUCH_SHAPE_VAR.get();
if expected_len == 2 {
children.push(shape(CaretShape::Insert));
} else if expected_len == 3 {
children.push(shape(CaretShape::SelectionLeft));
children.push(shape(CaretShape::SelectionRight));
}
for caret in &mut children[1..] {
caret.init();
}
WIDGET.render();
}
for (caret, size) in children[1..].iter_mut().zip(&mut sizes) {
*size = caret.layout(wl);
}
c.delegated();
}
UiNodeOp::Render { frame } => {
let _ = frame;

View File

@ -1152,7 +1152,7 @@ pub fn caret_color(child: impl UiNode, color: impl IntoVar<Rgba>) -> impl UiNode
/// Defines custom caret shapes for touch caret.
///
/// The `caret` node is not interactive, interaction is implemented by [`nodes::touch_caret`], it must
/// The `caret` node is not interactive, interaction is implemented by [`nodes::touch_carets`], it must
/// render the visual and layout to the size of the interaction area.
///
/// The caret is aligned depending on the shape, `CaretShape::SelectionLeft` aligns the top-right of the shape
@ -1160,7 +1160,7 @@ pub fn caret_color(child: impl UiNode, color: impl IntoVar<Rgba>) -> impl UiNode
/// of the shape to the top-right of the last line selection rectangle, `CaretShape::Insert` aligns the top-center
/// of the shape with the insert position.
///
/// [`nodes::touch_caret`]: super::nodes::touch_caret
/// [`nodes::touch_carets`]: super::nodes::touch_carets
#[property(CONTEXT, default(CARET_TOUCH_SHAPE_VAR), widget_impl(TextEditMix<P>))]
pub fn caret_touch_shape(child: impl UiNode, shape: impl IntoVar<WidgetFn<CaretShape>>) -> impl UiNode {
with_context_var(child, CARET_TOUCH_SHAPE_VAR, shape)