Skip to content

Commit

Permalink
feat(core): 🎸 Added the builtin widget of tooltips
Browse files Browse the repository at this point in the history
  • Loading branch information
wjian23 authored and rchangelog[bot] committed Dec 3, 2024
1 parent 8609f1b commit 6e9925b
Show file tree
Hide file tree
Showing 20 changed files with 174 additions and 15 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he
- **core**: Added `OverrideClass` to override a single class within a subtree. (#657 @M-Adoo)
- **widgets**: Added `LinearProgress` and `SpinnerProgress` widgets along with their respective material themes. (#630 @wjian23 @M-Adoo)
- **painter**: SVG now supports switching the default color, allowing for icon color changes. (#661 @M-Adoo)
- **core**: Added the builtin widget of tooltips (#664 @wjian23)

### Changed

Expand Down
2 changes: 1 addition & 1 deletion core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ web-time.workspace = true
colored.workspace = true
paste.workspace = true
ribir_dev_helper = {path = "../dev-helper"}
ribir = { path = "../ribir" }
ribir = { path = "../ribir", features = ["material", "slim"] }

[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
tokio = { workspace = true, features = ["full"]}
Expand Down
21 changes: 21 additions & 0 deletions core/src/builtin_widgets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ pub use smooth_layout::*;

mod track_widget_id;
pub use track_widget_id::*;
mod text;
pub use text::*;
mod tooltips;
pub use tooltips::*;

use crate::prelude::*;

Expand Down Expand Up @@ -131,6 +135,7 @@ pub struct FatObj<T> {
painting_style: Option<State<PaintingStyleWidget>>,
text_style: Option<State<TextStyleWidget>>,
keep_alive: Option<State<KeepAlive>>,
tooltips: Option<State<Tooltips>>,
keep_alive_unsubscribe_handle: Option<Box<dyn Any>>,
}

Expand Down Expand Up @@ -165,6 +170,7 @@ impl<T> FatObj<T> {
text_style: self.text_style,
visibility: self.visibility,
opacity: self.opacity,
tooltips: self.tooltips,
keep_alive: self.keep_alive,
keep_alive_unsubscribe_handle: self.keep_alive_unsubscribe_handle,
}
Expand Down Expand Up @@ -195,6 +201,7 @@ impl<T> FatObj<T> {
&& self.visibility.is_none()
&& self.opacity.is_none()
&& self.keep_alive.is_none()
&& self.tooltips.is_none()
}

/// Return the host object of the FatObj.
Expand Down Expand Up @@ -415,6 +422,14 @@ impl<T> FatObj<T> {
.keep_alive
.get_or_insert_with(|| State::value(<_>::default()))
}

/// Returns the `State<Tooltips>` widget from the FatObj. If it doesn't
/// exist, a new one is created.
pub fn get_tooltips_widget(&mut self) -> &State<Tooltips> {
self
.tooltips
.get_or_insert_with(|| State::value(<_>::default()))
}
}

macro_rules! on_mixin {
Expand Down Expand Up @@ -827,6 +842,11 @@ impl<T> FatObj<T> {
self.declare_builtin_init(v, Self::get_opacity_widget, |m, v| m.opacity = v)
}

/// Initializes the tooltips of the widget.
pub fn tooltips<const M: u8>(self, v: impl DeclareInto<CowArc<str>, M>) -> Self {
self.declare_builtin_init(v, Self::get_tooltips_widget, |m, v| m.tooltips = v)
}

/// Initializes the `keep_alive` value of the `KeepAlive` widget.
pub fn keep_alive<const M: u8>(mut self, v: impl DeclareInto<bool, M>) -> Self {
let (v, o) = v.declare_into().unzip();
Expand Down Expand Up @@ -914,6 +934,7 @@ impl<'a> FatObj<Widget<'a>> {
class,
cursor,
constrained_box,
tooltips,
margin,
transform,
opacity,
Expand Down
11 changes: 5 additions & 6 deletions widgets/src/text.rs → core/src/builtin_widgets/text.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::cell::{Ref, RefCell};

use ribir_core::prelude::*;
use typography::PlaceLineDirection;

use crate::prelude::*;

pub type TextInit = DeclareInit<CowArc<str>>;
/// The text widget display text with a single style.
#[derive(Declare)]
Expand Down Expand Up @@ -91,19 +92,17 @@ define_text_with_theme_style!(H4, title_large);
define_text_with_theme_style!(H5, title_medium);
define_text_with_theme_style!(H6, title_small);

#[cfg(test)]
#[cfg(all(test, not(target_arch = "wasm32")))]
mod tests {
use ribir_core::test_helper::*;
use ribir::{core::test_helper::*, material as ribir_material, prelude::*, slim as ribir_slim};
use ribir_dev_helper::*;

use super::*;
use crate::layout::SizedBox;
const WND_SIZE: Size = Size::new(164., 64.);

widget_test_suit!(
text_clip,
WidgetTester::new(fn_widget! {
@SizedBox {
@ MockBox {
size: Size::new(50., 45.),
@Text {
text: "hello world,\rnice to meet you.",
Expand Down
80 changes: 80 additions & 0 deletions core/src/builtin_widgets/tooltips.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use crate::prelude::*;

class_names! {
#[doc = "Class name for the tooltips"]
TOOLTIPS,
}

/// Add attributes of tooltips to Widget Declarer.
///
/// ### Example:
/// ```no_run
/// use ribir::prelude::*;
///
/// let w = fn_widget! {
/// @FilledButton{
/// text: "hover to show tooltips!",
/// tooltips: "this is tooltips",
/// }
/// };
/// App::run(w);
/// ```
#[derive(Default)]
pub struct Tooltips {
pub tooltips: CowArc<str>,
}

impl Declare for Tooltips {
type Builder = FatObj<()>;
fn declarer() -> Self::Builder { FatObj::new(()) }
}

impl Tooltips {
fn tooltips(&self) -> &CowArc<str> { &self.tooltips }
}

impl<'c> ComposeChild<'c> for Tooltips {
type Child = Widget<'c>;
fn compose_child(this: impl StateWriter<Value = Self>, child: Self::Child) -> Widget<'c> {
fn_widget! {
let wnd = BuildCtx::get().window();
let mut child = FatObj::new(child);

watch!($child.is_hover())
.distinct_until_changed()
.filter(|v| *v)
.subscribe(move |_| {
let this = this.clone_writer();
let overlay = Overlay::new(
text! {
text: pipe!($this.tooltips().clone()),
class: TOOLTIPS,
}, OverlayStyle {
auto_close_policy: AutoClosePolicy::NOT_AUTO_CLOSE,
mask: None,
});

overlay.clone().show_map(move |w: Widget| {
let overlay = overlay.clone();
watch!($child.is_hover())
.distinct_until_changed()
.filter(|v| !v)
.take(1)
.subscribe(move |_| overlay.close());
let mut w = FatObj::new(w);
let anchor_widget = w.get_global_anchor_widget().clone_writer();
@ $w {
anchor: pipe!(Anchor::left(-$w.layout_size().width / 2.)),
on_mounted: move|e| {
let wid = $child.track_id();
anchor_widget.bottom_align_to(wid.clone(), $child.layout_size().height, e.window());
anchor_widget.left_align_to(wid, $child.layout_size().width / 2., e.window());
}
}.into_widget()
}, wnd.clone());
});
@ { child }
}
.into_widget()
}
}
7 changes: 7 additions & 0 deletions macros/src/declare_derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,13 @@ pub(crate) fn declare_derive(input: &mut syn::DeriveInput) -> syn::Result<TokenS
self.fat_obj = self.fat_obj.track_id();
self
}

#[doc="Initializes the `tooltips` value of the `Tooltips` widget."]
#vis fn tooltips<const _M: u8>(mut self, v: impl DeclareInto<CowArc<str>, _M>) -> Self
{
self.fat_obj = self.fat_obj.tooltips(v);
self
}
}
}
};
Expand Down
2 changes: 2 additions & 0 deletions macros/src/variable_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ pub static BUILTIN_INFOS: phf::Map<&'static str, BuiltinMember> = phf_map! {
"opacity" => builtin_member!{"Opacity", Field, "opacity"},
// KeepAlive
"keep_alive" => builtin_member!{"KeepAlive", Field, "keep_alive"},
// Tooltips
"tooltips" => builtin_member!{"Tooltips", Field, "tooltips"},
// TrackWidgetId
"track_id" => builtin_member!{"TrackWidgetId", Method, "track_id"},
};
2 changes: 2 additions & 0 deletions themes/material/src/classes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod icon_cls;
mod progress_cls;
mod radio_cls;
mod scrollbar_cls;
mod tooltips_cls;

pub fn initd_classes() -> Classes {
let mut classes = Classes::default();
Expand All @@ -14,6 +15,7 @@ pub fn initd_classes() -> Classes {
radio_cls::init(&mut classes);
progress_cls::init(&mut classes);
checkbox_cls::init(&mut classes);
tooltips_cls::init(&mut classes);

classes
}
52 changes: 52 additions & 0 deletions themes/material/src/classes/tooltips_cls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use ribir_core::prelude::*;

class_names! {
TOOLTIPS_BASE,
}

pub(super) fn init(classes: &mut Classes) {
classes.insert(TOOLTIPS_BASE, |w| {
fn_widget! {
let w = FatObj::new(w);
@BoxDecoration {
background: Palette::of(BuildCtx::get()).inverse_surface(),
margin: EdgeInsets::only_bottom(4.),
border_radius: Radius::all(4.),
@ $w {
margin: EdgeInsets::new(4., 8., 4., 8.),
foreground: Palette::of(BuildCtx::get()).inverse_on_surface(),
v_align: VAlign::Center,
h_align: HAlign::Center,
}
}
}
.into_widget()
});

classes.insert(TOOLTIPS, |w| {
fn_widget! {
let w = FatObj::new(w);
let mut w = @ $w {
class: TOOLTIPS_BASE,
};
$w.write().keep_alive = true;

let animate = part_writer!(&mut w.opacity)
.transition(transitions::LINEAR.of(BuildCtx::get()));
@ $w {
on_disposed: move |_| {
$w.write().opacity = 0.;
let _ = watch!($animate.is_running())
.distinct_until_changed()
.pairwise()
.filter(|(old, new)| *old && !*new )
.take(1)
.subscribe(move|_| {
$w.write().keep_alive = false;
});
}
}
}
.into_widget()
});
}
3 changes: 1 addition & 2 deletions widgets/src/checkbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ use svg::named_svgs;

use crate::{
common_widget::{Leading, Trailing},
prelude::{Icon, Row, Text},
text::TextInit,
prelude::{Icon, Row},
};

class_names! {
Expand Down
2 changes: 0 additions & 2 deletions widgets/src/icon.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use ribir_core::prelude::*;

use crate::text::*;

/// An icon widget represents an icon.
///
/// It can accept either text or another widget as its child. If the child is
Expand Down
1 change: 0 additions & 1 deletion widgets/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ use crate::{
text_selectable::{SelectableText, bind_point_listener, select_key_handle},
},
layout::{OnlySizedByParent, Stack, StackFit},
prelude::Text,
};

pub struct Placeholder(DeclareInit<CowArc<str>>);
Expand Down
1 change: 0 additions & 1 deletion widgets/src/layout/sized_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ mod tests {
use ribir_dev_helper::*;

use super::*;
use crate::prelude::*;

widget_layout_test!(
fix_size,
Expand Down
4 changes: 2 additions & 2 deletions widgets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ pub mod progress;
pub mod radio;
pub mod scrollbar;
pub mod tabs;
pub mod text;
pub mod text_field;

pub mod transform_box;
pub mod prelude {
pub use super::{
avatar::*, buttons::*, checkbox::*, common_widget::*, divider::*, grid_view::*, icon::*,
input::*, label::*, layout::*, link::*, lists::*, path::*, progress::*, radio::*, scrollbar::*,
tabs::*, text::*, text_field::*, transform_box::*,
tabs::*, text_field::*, transform_box::*,
};
}

0 comments on commit 6e9925b

Please sign in to comment.