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 13, 2025
1 parent 237f763 commit c59c1e2
Show file tree
Hide file tree
Showing 31 changed files with 1,501 additions and 1,318 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he
- **macros**: Added the `part_reader!` macro to generate a partial reader from a reference of a reader. (#688 @M-Adoo)
- **macros**: The `simple_declare` now supports the `stateless` meta attribute, `#[simple_declare(stateless)]`. (#688 @M-Adoo)
- **core**: Support extend custom event. (#pr @wjian23)
- **widgets**: Refactor `Input` Widget. (#pr @wjian23)

### Changed
- **core**: Rename `can_focus` field of FocusScope to `skip_host`. (#pr @wjian23)
Expand Down
47 changes: 46 additions & 1 deletion core/src/builtin_widgets/scrollable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,35 @@ pub enum Scrollable {
Both,
}

pub struct ScrollViewInfo {
pub scroll_pos: Point,
pub view_size: Size,

scroll_id: TrackId,
wnd: Sc<Window>,
}

impl ScrollViewInfo {
pub fn map_to_scroll_view(&self, p: Point, from: WidgetId) -> Point {
let pos = self.wnd.map_to_global(p, from);
let offset = self
.wnd
.map_to_global(Point::zero(), self.scroll_id.get().unwrap());
pos - offset.to_vector()
}
}

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

impl ScrollRequest {
pub fn new(f: impl FnMut(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
/// ScrollViewInfo 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,7 +91,23 @@ impl<'c> ComposeChild<'c> for ScrollableWidget {
.distinct_until_changed()
.subscribe(move |v| $this.write().set_page(v));

@Clip { @ $view { @ { child } } }
@Clip {
on_custom_concrete_event: move |e: &mut ScrollRequestEvent| {
let mut view_size = $view.layout_size();
let mut write_ref = $this.write();
let scroll_pos = write_ref.get_scroll_pos();
let wnd = e.window();
write_ref.jump_to((e.data_mut().0)(
ScrollViewInfo {
scroll_pos,
view_size,
scroll_id: $child.track_id(),
wnd,
}));
e.stop_propagation();
},
@ $view { @ { child } }
}
}
.into_widget()
}
Expand Down
45 changes: 34 additions & 11 deletions core/src/builtin_widgets/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,39 @@ pub struct Text {
glyphs: RefCell<Option<VisualGlyphs>>,
}

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

pub fn text_glyph(
text: Substr, text_style: &TextStyle, text_align: TextAlign, bounds: Size,
) -> VisualGlyphs {
AppCtx::typography_store()
.borrow_mut()
.typography(
text,
text_style,
bounds,
text_align,
GlyphBaseline::Middle,
PlaceLineDirection::TopToBottom,
)
}

pub fn paint_text(
painter: &mut Painter, glyphs: &VisualGlyphs, style: PaintingStyle, box_rect: Rect,
) {
if let PaintingStyle::Stroke(options) = style {
painter
.set_style(PathStyle::Stroke)
.set_strokes(options);
} else {
painter.set_style(PathStyle::Fill);
}

let font_db = AppCtx::font_db().clone();
painter.draw_glyphs_in_rect(glyphs, box_rect, &font_db.borrow());
}

impl Render for Text {
fn perform_layout(&self, clamp: BoxClamp, ctx: &mut LayoutCtx) -> Size {
let style = Provider::of::<TextStyle>(ctx).unwrap();
Expand Down Expand Up @@ -50,18 +83,8 @@ impl Render for Text {
};

let style = Provider::of::<PaintingStyle>(ctx).map(|p| p.clone());
let painter = ctx.painter();
if let Some(PaintingStyle::Stroke(options)) = style {
painter
.set_style(PathStyle::Stroke)
.set_strokes(options);
} else {
painter.set_style(PathStyle::Fill);
}

let visual_glyphs = self.glyphs().unwrap();
let font_db = AppCtx::font_db().clone();
painter.draw_glyphs_in_rect(&visual_glyphs, box_rect, &font_db.borrow());
paint_text(ctx.painter(), &visual_glyphs, style.unwrap_or(PaintingStyle::Fill), box_rect);
}
}

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
5 changes: 5 additions & 0 deletions core/src/widget_tree/layout_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ impl BoxClamp {
self
}

pub fn with_max_size(mut self, size: Size) -> Self {
self.max = size.max(self.min);
self
}

pub const fn with_fixed_height(mut self, height: f32) -> Self {
self.min.height = height;
self.max.height = height;
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
}
Loading

0 comments on commit c59c1e2

Please sign in to comment.