Skip to content

Commit

Permalink
refactor(widgets): 💡 Refactor Input Widget
Browse files Browse the repository at this point in the history
  • Loading branch information
wjian23 committed Jan 3, 2025
1 parent e53c910 commit 2596841
Show file tree
Hide file tree
Showing 25 changed files with 946 additions and 957 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he

- **core**: Refactor TextStyleWidget to support the setting of some font style fields. (#pr @wjian23)
- **core**: Rename `can_focus` field of FocusScope to `skip_host`. (#pr @wjian23)

- **widgets**: Refactor `Input` Widget. (#pr @wjian23)


## [0.4.0-alpha.20] - 2024-12-25
Expand Down
27 changes: 27 additions & 0 deletions core/src/builtin_widgets/scrollable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,22 @@ pub enum Scrollable {
Both,
}

pub struct ScrollViewInfo {
pub current: Point,
pub global_view: Rect,
}

pub struct ScrollRequest(Box<dyn Fn(ScrollViewInfo) -> Point>);

impl ScrollRequest {
pub fn new(f: impl Fn(ScrollViewInfo) -> Point + 'static) -> Self { Self(Box::new(f)) }
}

/// A event request scroll to the given position.
/// The event will include a ScrollRequest which is a callback that receive the
/// current scroll position and return the new scroll position.
pub type ScrollRequestEvent = CustomEvent<ScrollRequest>;

/// Helper struct for builtin scrollable field.
#[derive(Default)]
pub struct ScrollableWidget {
Expand Down Expand Up @@ -62,6 +78,17 @@ impl<'c> ComposeChild<'c> for ScrollableWidget {
.subscribe(move |v| $this.write().set_page(v));

@Clip {
on_custom_event: move |e: &mut ScrollRequestEvent| {
let mut view = $view.layout_rect();
let mut write_ref = $this.write();
view.origin = e.window().map_to_global(view.origin, e.current_target());
let current = write_ref.get_scroll_pos();
write_ref.jump_to((e.data().0)(ScrollViewInfo {
current,
global_view: view,
}));
e.stop_propagation();
},
@ $view {
on_wheel: move |e| $this.write().scroll(-e.delta_x, -e.delta_y),
@ { child }
Expand Down
3 changes: 3 additions & 0 deletions core/src/builtin_widgets/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ pub struct Text {
glyphs: RefCell<Option<VisualGlyphs>>,
}

impl ChildOfCompose for FatObj<State<Text>> {}
impl ChildOfCompose for Stateful<Text> {}

impl Render for Text {
fn perform_layout(&self, clamp: BoxClamp, ctx: &mut LayoutCtx) -> Size {
let style = ctx.text_style();
Expand Down
9 changes: 9 additions & 0 deletions core/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@ pub trait StateWatcher: StateReader {
fn clone_watcher(&self) -> Watcher<Self::Reader> {
Watcher::new(self.clone_reader(), self.raw_modifies())
}

/// Return a new watcher by applying a function to the contained value.
fn map_watcher<V: ?Sized, M>(&self, part_map: M) -> Watcher<MapReader<Self::Reader, M>>
where
M: Fn(&Self::Value) -> PartData<V> + Clone,
{
let reader = self.map_reader(part_map);
Watcher::new(reader, self.raw_modifies())
}
}

pub trait StateWriter: StateWatcher {
Expand Down
2 changes: 1 addition & 1 deletion docs/en/practice_todos_app/develop_a_todos_app.md
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ impl Compose for Todos {
$input.write().set_text("");
}
},
@{ Placeholder::new("What do you want to do ?") }
@Text { text:"What do you want to do ?" }
}
}
@Tabs {
Expand Down
2 changes: 1 addition & 1 deletion docs/zh/practice_todos_app/develop_a_todos_app.md
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ impl Compose for Todos {
$input.write().set_text("");
}
},
@{ Placeholder::new("What do you want to do ?") }
@Text { text: "What do you want to do ?" }
}
}
@Tabs {
Expand Down
34 changes: 20 additions & 14 deletions examples/todos/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,20 +108,26 @@ fn input(
if let Some(text) = text {
$input.write().set_text(&text);
}
@ $input {
margin: EdgeInsets::horizontal(24.),
h_align: HAlign::Stretch,
border: {
let color = Palette::of(BuildCtx::get()).surface_variant().into();
Border::only_bottom(BorderSide { width: 2., color })
},
on_key_down: move |e| {
if e.key_code() == &PhysicalKey::Code(KeyCode::Enter) {
on_submit($input.text().clone());
$input.write().set_text("");
}
},
@{ Placeholder::new("What do you want to do ?") }
@ Stack {
padding: EdgeInsets::horizontal(24.),
@Text {
h_align: HAlign::Stretch,
visible: pipe!($input.text().is_empty()),
text: "What do you want to do ?"
}
@ $input {
h_align: HAlign::Stretch,
border: {
let color = Palette::of(BuildCtx::get()).surface_variant().into();
Border::only_bottom(BorderSide { width: 2., color })
},
on_key_down: move |e| {
if e.key_code() == &PhysicalKey::Code(KeyCode::Enter) {
on_submit($input.text().clone());
$input.write().set_text("");
}
},
}
}
}
.into_widget()
Expand Down
86 changes: 44 additions & 42 deletions painter/src/text/typography_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ impl VisualGlyphs {
),
},
|glyph| {
let orign = Point::new(
let origin = Point::new(
self.to_pixel_value(glyph.x_offset + line.x),
self.to_pixel_value(glyph.y_offset + line.y),
);
Expand All @@ -327,7 +327,7 @@ impl VisualGlyphs {
Size::new(self.to_pixel_value(glyph.x_advance), self.to_pixel_value(line.height))
}
};
Rect::new(orign, size)
Rect::new(origin, size)
},
);
rc.origin += Point::new(self.to_pixel_value(self.x), self.to_pixel_value(self.y)).to_vector();
Expand All @@ -343,51 +343,53 @@ impl VisualGlyphs {
}

pub fn select_range(&self, rg: &Range<usize>) -> Vec<Rect> {
struct TypoRectJointer {
acc: Vec<Rect>,
cur: Option<Rect>,
}

impl TypoRectJointer {
fn new() -> Self { Self { acc: vec![], cur: None } }
fn join_x(&mut self, next: Rect) {
if let Some(rc) = &mut self.cur {
rc.size.width = next.max_x() - rc.min_x();
} else {
self.cur = Some(next);
}
}
fn new_rect(&mut self) {
let cur = self.cur.take();
if let Some(rc) = cur {
self.acc.push(rc);
}
}
fn rects(self) -> Vec<Rect> { self.acc }
}
let mut jointer = TypoRectJointer::new();
let mut rects = vec![];
for line in &self.visual_info.visual_lines {
let height = self.to_pixel_value(line.height);
let offset_x = self.x + line.x;
let offset_y = self.y + line.y;
for glyph in &line.glyphs {
let mut inline: Vec<(usize, usize)> = vec![];
for (i, glyph) in line.glyphs.iter().enumerate() {
if rg.contains(&(glyph.cluster as usize)) {
let glyph = glyph.clone().cast_to(self.font_size);
let rc = Rect::new(
Point::new(
self.to_pixel_value(glyph.x_offset + offset_x),
self.to_pixel_value(glyph.y_offset + offset_y),
),
Size::new(self.to_pixel_value(glyph.x_advance), height),
);
jointer.join_x(rc);
} else {
jointer.new_rect();
if let Some((_, end)) = inline
.last_mut()
.filter(|(_, end)| (*end + 1) == i)
{
*end += 1;
} else {
inline.push((i, i));
}
}
}
jointer.new_rect();

if !inline.is_empty() {
let is_horizontal = !self.visual_info.line_dir.is_horizontal();
let offset_x = self.x + line.x;
let offset_y = self.y + line.y;
inline.into_iter().for_each(|(start, end)| {
let (x_min, x_max, y_min, y_max) = if is_horizontal {
(
line.glyphs[start].x_offset,
line.glyphs[end].x_offset + line.glyphs[end].x_advance,
GlyphUnit::ZERO,
line.height,
)
} else {
(
GlyphUnit::ZERO,
line.width,
line.glyphs[start].y_offset,
line.glyphs[end].y_offset + line.glyphs[end].y_advance,
)
};
let rect = Rect::from_points([
Point::new(self.to_pixel_value(x_min), self.to_pixel_value(y_min)),
Point::new(self.to_pixel_value(x_max), self.to_pixel_value(y_max)),
]);
rects.push(
rect.translate((self.to_pixel_value(offset_x), self.to_pixel_value(offset_y)).into()),
);
});
}
}
jointer.rects()
rects
}

fn to_pixel_value(&self, v: GlyphUnit) -> f32 { v.cast_to(self.font_size).into_pixel() }
Expand Down
3 changes: 2 additions & 1 deletion themes/material/src/classes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ use ribir_core::prelude::Classes;

mod buttons_cls;
mod checkbox_cls;
mod input_cls;
mod progress_cls;
mod radio_cls;
mod scrollbar_cls;
mod slider_cls;
mod tooltips_cls;

pub fn initd_classes() -> Classes {
let mut classes = Classes::default();

Expand All @@ -18,6 +18,7 @@ pub fn initd_classes() -> Classes {
checkbox_cls::init(&mut classes);
tooltips_cls::init(&mut classes);
slider_cls::init(&mut classes);
input_cls::init(&mut classes);

classes
}
27 changes: 27 additions & 0 deletions themes/material/src/classes/input_cls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use ribir_core::prelude::*;
use ribir_widgets::{input::TEXT_CARET, prelude::*};

use crate::md;

pub(super) fn init(classes: &mut Classes) {
classes.insert(TEXT_CARET, |_w| {
fn_widget! {
let mut w = @ FittedBox {
box_fit: BoxFit::CoverY,
@ { svgs::TEXT_CARET }
};
let blink_interval = Duration::from_millis(500);
let unsub = interval(blink_interval, AppCtx::scheduler())
.subscribe(move |idx| $w.write().opacity = (idx % 2) as f32);
@ $w {
on_disposed: move |_| unsub.unsubscribe()
}
}
.into_widget()
});

classes.insert(TEXT_HIGH_LIGHT, style_class! {
background: Color::from_rgb(181, 215, 254),
border_radius: md::RADIUS_2,
});
}
16 changes: 0 additions & 16 deletions themes/material/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,6 @@ const AVATAR_RADIUS: f32 = 20.;
const LIST_IMAGE_ITEM_SIZE: f32 = 56.;

fn init_custom_style(theme: &mut Theme) {
theme
.custom_styles
.set_custom_style(InputStyle { size: Some(20.) });
theme
.custom_styles
.set_custom_style(TextAreaStyle { rows: Some(2.), cols: Some(20.) });
theme
.custom_styles
.set_custom_style(SelectedHighLightStyle { brush: Color::from_rgb(181, 215, 254).into() });

theme.custom_styles.set_custom_style(TabsStyle {
extent_with_both: 64.,
extent_only_label: 48.,
Expand Down Expand Up @@ -153,12 +143,6 @@ fn init_custom_style(theme: &mut Theme) {
},
},
});
theme
.custom_styles
.set_custom_style(PlaceholderStyle {
foreground: theme.palette.on_surface_variant().into(),
text_style: theme.typography_theme.body_medium.text.clone(),
});
}

fn override_compose_decorator(theme: &mut Theme) {
Expand Down
Loading

0 comments on commit 2596841

Please sign in to comment.