From 8f5b422dd9271a320a0f1a0edd478b56df36c747 Mon Sep 17 00:00:00 2001 From: Adoo Date: Fri, 4 Aug 2023 18:28:17 +0800 Subject: [PATCH] =?UTF-8?q?fix(text):=20=F0=9F=90=9B=20input=20crash=20cau?= =?UTF-8?q?sed=20by=20`DynWidget`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/events/pointers.rs | 64 +++++++++++++++++---- widgets/src/input/selected_text.rs | 2 +- widgets/src/input/text_selectable.rs | 84 ++++++++++------------------ widgets/src/text.rs | 11 +--- 4 files changed, 87 insertions(+), 74 deletions(-) diff --git a/core/src/events/pointers.rs b/core/src/events/pointers.rs index 85c16bc94..6827e4a8d 100644 --- a/core/src/events/pointers.rs +++ b/core/src/events/pointers.rs @@ -179,36 +179,35 @@ impl PointerListenerDeclarer { } pub fn on_x_times_tap( - mut self, + self, (times, handler): (usize, impl FnMut(&mut PointerEvent) + 'static), ) -> Self { - self.on_x_times_tap_impl(times, MULTI_TAP_DURATION, false, handler); - self + self.on_x_times_tap_impl(times, MULTI_TAP_DURATION, false, handler) } pub fn on_x_times_tap_capture( - mut self, + self, (times, handler): (usize, impl FnMut(&mut PointerEvent) + 'static), ) -> Self { - self.on_x_times_tap_impl(times, MULTI_TAP_DURATION, true, handler); - self + self.on_x_times_tap_impl(times, MULTI_TAP_DURATION, true, handler) } fn on_x_times_tap_impl( - &mut self, + mut self, times: usize, dur: Duration, capture: bool, handler: impl FnMut(&mut PointerEvent) + 'static, - ) { + ) -> Self { self .subject() .filter_map(x_times_tap_map_filter(times, dur, capture)) .subscribe(handler); + self } } -impl PointerListener { +impl PointerListenerDeclarer2 { pub fn on_double_tap(self, handler: impl FnMut(&mut PointerEvent) + 'static) -> Self { self.on_x_times_tap((2, handler)) } @@ -229,16 +228,57 @@ impl PointerListener { self, (times, handler): (usize, impl FnMut(&mut PointerEvent) + 'static), ) -> Self { - self.on_x_times_tap_impl(times, MULTI_TAP_DURATION, false, handler); - self + self.on_x_times_tap_impl(times, MULTI_TAP_DURATION, false, handler) } pub fn on_x_times_tap_capture( self, (times, handler): (usize, impl FnMut(&mut PointerEvent) + 'static), ) -> Self { - self.on_x_times_tap_impl(times, MULTI_TAP_DURATION, true, handler); + self.on_x_times_tap_impl(times, MULTI_TAP_DURATION, true, handler) + } + + fn on_x_times_tap_impl( + mut self, + times: usize, + dur: Duration, + capture: bool, + handler: impl FnMut(&mut PointerEvent) + 'static, + ) -> Self { self + .subject() + .filter_map(x_times_tap_map_filter(times, dur, capture)) + .subscribe(handler); + self + } +} + +impl PointerListener { + pub fn on_double_tap(self, handler: impl FnMut(&mut PointerEvent) + 'static) { + self.on_x_times_tap((2, handler)) + } + + pub fn on_double_tap_capture(self, handler: impl FnMut(&mut PointerEvent) + 'static) { + self.on_x_times_tap_capture((2, handler)) + } + + pub fn on_triple_tap(self, handler: impl FnMut(&mut PointerEvent) + 'static) { + self.on_x_times_tap((3, handler)) + } + + pub fn on_triple_tap_capture(self, handler: impl FnMut(&mut PointerEvent) + 'static) { + self.on_x_times_tap_capture((3, handler)) + } + + pub fn on_x_times_tap(self, (times, handler): (usize, impl FnMut(&mut PointerEvent) + 'static)) { + self.on_x_times_tap_impl(times, MULTI_TAP_DURATION, false, handler); + } + + pub fn on_x_times_tap_capture( + self, + (times, handler): (usize, impl FnMut(&mut PointerEvent) + 'static), + ) { + self.on_x_times_tap_impl(times, MULTI_TAP_DURATION, true, handler); } fn on_x_times_tap_impl( diff --git a/widgets/src/input/selected_text.rs b/widgets/src/input/selected_text.rs index 7e4bc3b1c..20fbd586f 100644 --- a/widgets/src/input/selected_text.rs +++ b/widgets/src/input/selected_text.rs @@ -1,7 +1,7 @@ use crate::layout::{Container, Stack}; use ribir_core::prelude::*; -#[derive(Declare)] +#[derive(Declare, Declare2)] pub(crate) struct SelectedText { pub(crate) rects: Vec, } diff --git a/widgets/src/input/text_selectable.rs b/widgets/src/input/text_selectable.rs index c9e46f521..215ecc850 100644 --- a/widgets/src/input/text_selectable.rs +++ b/widgets/src/input/text_selectable.rs @@ -14,17 +14,17 @@ pub struct TextSelectable { impl ComposeChild for TextSelectable { type Child = State; - fn compose_child(this: State, text: Self::Child) -> Widget { - let this = this.into_writable(); - widget! { - states { - this: this.clone(), - text: text.into_readonly(), - } - Stack { - id: host, - fit: StackFit::Passthrough, + fn compose_child(mut this: State, mut text: Self::Child) -> Widget { + fn_widget! { + let mut host = @Stack { fit: StackFit::Passthrough }; + let mut selected = @SelectedText { + visible: pipe!($host.has_focus()), + rects: pipe!($this.selected_rect()), + }; + + @$host { on_pointer_move: move |e| { + let mut this = $this; if let CaretState::Selecting(begin, _) = this.caret { if e.point_type == PointerType::Mouse && e.mouse_buttons() == MouseButtons::PRIMARY { @@ -36,9 +36,9 @@ impl ComposeChild for TextSelectable { }, on_pointer_down: move |e| { let position = e.position(); - let cluster = this.helper.cluster_from_pos(position.x, position.y); + let cluster = $this.helper.cluster_from_pos(position.x, position.y); let begin = if e.with_shift_key() { - match this.caret { + match $this.caret { CaretState::Caret(begin) | CaretState::Select(begin, _) | CaretState::Selecting(begin, _) => begin, @@ -46,9 +46,10 @@ impl ComposeChild for TextSelectable { } else { cluster }; - this.caret = CaretState::Selecting(begin, cluster); + $this.caret = CaretState::Selecting(begin, cluster); }, on_pointer_up: move |_| { + let mut this = $this; if let CaretState::Selecting(begin, end) = this.caret { this.caret = if begin == end { CaretState::Caret(begin) @@ -59,34 +60,19 @@ impl ComposeChild for TextSelectable { }, on_double_tap: move |e| { let position = e.position(); - let cluster = this.helper.cluster_from_pos(position.x, position.y); - let rg = select_word(&text.text, cluster); - this.caret = CaretState::Select(rg.start, rg.end); + let cluster = $this.helper.cluster_from_pos(position.x, position.y); + let rg = select_word(&$text.text, cluster); + $this.caret = CaretState::Select(rg.start, rg.end); }, - - on_key_down: move |event| key_handle(&mut this, &text.text, event), - SelectedText { - id: selected, - visible: host.has_focus(), - rects: vec![], - } - DynWidget { - dyns: text.clone(), - on_performed_layout: move |ctx| { - let bound = ctx.layout_clamp().expect("layout info must exit in performed_layout"); - this.helper.glyphs = Some(text.text_layout( - AppCtx::typography_store(), - bound.max, - )); - this.forget_modifies(); - } - } - } - finally { - this.modifies() - .subscribe(move |_| { - selected.rects = this.selected_rect(); - }); + on_key_down: move |event| key_handle(&mut $this, &$text.text, event), + on_performed_layout: move |e: &mut LifecycleEvent| { + let mut this = $this; + let bound = e.layout_clamp().expect("layout info must exit in performed_layout"); + this.helper.glyphs = Some($text.text_layout(bound.max)); + this.forget_modifies(); + }, + @ { selected } + @ { text } } } .into() @@ -99,11 +85,7 @@ impl TextSelectable { fn selected_rect(&self) -> Vec { self.helper.selection(&self.caret.select_range()) } } -fn key_handle( - this: &mut StatefulRef, - text: &CowArc, - event: &mut KeyboardEvent, -) { +fn key_handle(this: &mut StateRef, text: &CowArc, event: &mut KeyboardEvent) { let mut deal = false; if event.with_command_key() { deal = deal_with_command(this, text, event); @@ -115,7 +97,7 @@ fn key_handle( } fn deal_with_command( - this: &mut StatefulRef, + this: &mut StateRef, text: &CowArc, event: &mut KeyboardEvent, ) -> bool { @@ -143,21 +125,17 @@ fn is_move_by_word(event: &KeyboardEvent) -> bool { return event.with_ctrl_key(); } -fn move_to_line_begin(this: &mut StatefulRef) { +fn move_to_line_begin(this: &mut StateRef) { let (row, _) = this.helper.glyph_position(this.caret.offset()); this.caret = this.helper.cluster_from_glyph_position(row, 0).into(); } -fn move_to_line_end(this: &mut StatefulRef) { +fn move_to_line_end(this: &mut StateRef) { let (row, _) = this.helper.glyph_position(this.caret.offset()); this.caret = this.helper.cluster_from_glyph_position(row + 1, 0).into(); } -fn deal_with_selection( - this: &mut StatefulRef, - text: &str, - event: &mut KeyboardEvent, -) { +fn deal_with_selection(this: &mut StateRef, text: &str, event: &mut KeyboardEvent) { let old_caret = this.caret; match event.key { VirtualKeyCode::Left => { diff --git a/widgets/src/text.rs b/widgets/src/text.rs index 569cd4596..0e645c10b 100644 --- a/widgets/src/text.rs +++ b/widgets/src/text.rs @@ -24,7 +24,7 @@ pub struct Text { } impl Text { - pub fn text_layout(&self, t_store: &TypographyStore, bound: Size) -> VisualGlyphs { + pub fn text_layout(&self, bound: Size) -> VisualGlyphs { let TextStyle { font_size, letter_space, @@ -35,8 +35,7 @@ impl Text { let width: Em = Pixel(bound.width.into()).into(); let height: Em = Pixel(bound.height.into()).into(); - - t_store.typography( + AppCtx::typography_store().typography( self.text.substr(..), font_size, font_face, @@ -54,11 +53,7 @@ impl Text { impl Render for Text { fn perform_layout(&self, clamp: BoxClamp, _: &mut LayoutCtx) -> Size { - self - .text_layout(AppCtx::typography_store(), clamp.max) - .visual_rect() - .size - .cast_unit() + self.text_layout(clamp.max).visual_rect().size.cast_unit() } #[inline]