use azul_core::{
callbacks::{CoreCallback, CoreCallbackData, Update},
dom::{Dom, EventFilter, HoverEventFilter, IdOrClass, IdOrClass::Class, IdOrClassVec},
refany::{OptionRefAny, RefAny},
};
use azul_css::dynamic_selector::{CssPropertyWithConditions, CssPropertyWithConditionsVec};
use azul_css::{
props::{
basic::{color::ColorU, StyleFontSize},
layout::{LayoutDisplay, LayoutPosition, LayoutFlexGrow, LayoutTop, LayoutLeft, LayoutPaddingLeft, LayoutPaddingRight, LayoutPaddingTop, LayoutPaddingBottom},
property::{CssProperty, StyleWhiteSpaceValue},
style::{StyleBackgroundContent, StyleBackgroundContentVec, StyleBorderTopLeftRadius, StyleBorderTopRightRadius, StyleBorderBottomLeftRadius, StyleBorderBottomRightRadius, StyleTextColor, StyleWhiteSpace, StyleOpacity},
},
AzString,
};
use crate::callbacks::CallbackInfo;
static TOOLTIP_WRAPPER_CLASS: &[IdOrClass] =
&[Class(AzString::from_const_str("__azul-native-tooltip"))];
static TOOLTIP_TIP_CLASS: &[IdOrClass] =
&[Class(AzString::from_const_str("__azul-native-tooltip-tip"))];
const TIP_OFFSET_Y: isize = 22;
const TIP_RADIUS: isize = 4;
const TIP_BG_COLOR: ColorU = ColorU {
r: 51,
g: 51,
b: 51,
a: 240,
};
const TIP_TEXT_COLOR: ColorU = ColorU {
r: 255,
g: 255,
b: 255,
a: 255,
};
const TIP_BG_ITEMS: &[StyleBackgroundContent] = &[StyleBackgroundContent::Color(TIP_BG_COLOR)];
const TIP_BG: StyleBackgroundContentVec = StyleBackgroundContentVec::from_const_slice(TIP_BG_ITEMS);
static TOOLTIP_WRAPPER_STYLE: &[CssPropertyWithConditions] = &[
CssPropertyWithConditions::simple(CssProperty::const_display(LayoutDisplay::InlineBlock)),
CssPropertyWithConditions::simple(CssProperty::const_position(LayoutPosition::Relative)),
CssPropertyWithConditions::simple(CssProperty::const_flex_grow(LayoutFlexGrow::const_new(0))),
];
static TOOLTIP_TIP_STYLE: &[CssPropertyWithConditions] = &[
CssPropertyWithConditions::simple(CssProperty::const_position(LayoutPosition::Absolute)),
CssPropertyWithConditions::simple(CssProperty::const_top(LayoutTop::const_px(TIP_OFFSET_Y))),
CssPropertyWithConditions::simple(CssProperty::const_left(LayoutLeft::const_px(0))),
CssPropertyWithConditions::simple(CssProperty::const_padding_left(LayoutPaddingLeft::const_px(
8,
))),
CssPropertyWithConditions::simple(CssProperty::const_padding_right(
LayoutPaddingRight::const_px(8),
)),
CssPropertyWithConditions::simple(CssProperty::const_padding_top(LayoutPaddingTop::const_px(4))),
CssPropertyWithConditions::simple(CssProperty::const_padding_bottom(
LayoutPaddingBottom::const_px(4),
)),
CssPropertyWithConditions::simple(CssProperty::const_border_top_left_radius(
StyleBorderTopLeftRadius::const_px(TIP_RADIUS),
)),
CssPropertyWithConditions::simple(CssProperty::const_border_top_right_radius(
StyleBorderTopRightRadius::const_px(TIP_RADIUS),
)),
CssPropertyWithConditions::simple(CssProperty::const_border_bottom_left_radius(
StyleBorderBottomLeftRadius::const_px(TIP_RADIUS),
)),
CssPropertyWithConditions::simple(CssProperty::const_border_bottom_right_radius(
StyleBorderBottomRightRadius::const_px(TIP_RADIUS),
)),
CssPropertyWithConditions::simple(CssProperty::const_background_content(TIP_BG)),
CssPropertyWithConditions::simple(CssProperty::const_text_color(StyleTextColor {
inner: TIP_TEXT_COLOR,
})),
CssPropertyWithConditions::simple(CssProperty::const_font_size(StyleFontSize::const_px(12))),
CssPropertyWithConditions::simple(CssProperty::WhiteSpace(StyleWhiteSpaceValue::Exact(
StyleWhiteSpace::Nowrap,
))),
CssPropertyWithConditions::simple(CssProperty::const_opacity(StyleOpacity::const_new(0))),
];
#[derive(Debug, Clone, PartialEq, Eq)]
#[repr(C)]
pub struct Tooltip {
pub anchor: Dom,
pub text: AzString,
pub wrapper_style: CssPropertyWithConditionsVec,
pub tip_style: CssPropertyWithConditionsVec,
}
impl Default for Tooltip {
fn default() -> Self {
Self::new(Dom::default(), AzString::from_const_str(""))
}
}
impl Tooltip {
#[must_use] pub fn new(anchor: Dom, text: AzString) -> Self {
Self {
anchor,
text,
wrapper_style: CssPropertyWithConditionsVec::from_const_slice(TOOLTIP_WRAPPER_STYLE),
tip_style: CssPropertyWithConditionsVec::from_const_slice(TOOLTIP_TIP_STYLE),
}
}
#[inline]
pub fn set_text(&mut self, text: AzString) {
self.text = text;
}
#[inline]
#[must_use] pub fn with_text(mut self, text: AzString) -> Self {
self.set_text(text);
self
}
#[inline]
pub fn set_tip_style(&mut self, style: CssPropertyWithConditionsVec) {
self.tip_style = style;
}
#[inline]
#[must_use] pub fn with_tip_style(mut self, style: CssPropertyWithConditionsVec) -> Self {
self.set_tip_style(style);
self
}
#[inline]
#[must_use] pub fn swap_with_default(&mut self) -> Self {
let mut s = Self::default();
core::mem::swap(&mut s, self);
s
}
#[must_use] pub fn dom(self) -> Dom {
let marker = RefAny::new(());
let tip = Dom::create_text(self.text)
.with_ids_and_classes(IdOrClassVec::from_const_slice(TOOLTIP_TIP_CLASS))
.with_css_props(self.tip_style);
Dom::create_div()
.with_ids_and_classes(IdOrClassVec::from_const_slice(TOOLTIP_WRAPPER_CLASS))
.with_css_props(self.wrapper_style)
.with_callbacks(
vec![
CoreCallbackData {
event: EventFilter::Hover(HoverEventFilter::MouseEnter),
callback: CoreCallback {
cb: on_tooltip_enter as usize,
ctx: OptionRefAny::None,
},
refany: marker.clone(),
},
CoreCallbackData {
event: EventFilter::Hover(HoverEventFilter::MouseLeave),
callback: CoreCallback {
cb: on_tooltip_leave as usize,
ctx: OptionRefAny::None,
},
refany: marker,
},
]
.into(),
)
.with_children(vec![self.anchor, tip].into())
}
}
fn tip_of_wrapper(info: &CallbackInfo) -> Option<azul_core::dom::DomNodeId> {
let wrapper = info.get_hit_node();
let anchor = info.get_first_child(wrapper)?;
info.get_next_sibling(anchor)
}
extern "C" fn on_tooltip_enter(_data: RefAny, mut info: CallbackInfo) -> Update {
if let Some(tip) = tip_of_wrapper(&info) {
info.set_css_property(tip, CssProperty::const_opacity(StyleOpacity::const_new(100)));
}
Update::DoNothing
}
extern "C" fn on_tooltip_leave(_data: RefAny, mut info: CallbackInfo) -> Update {
if let Some(tip) = tip_of_wrapper(&info) {
info.set_css_property(tip, CssProperty::const_opacity(StyleOpacity::const_new(0)));
}
Update::DoNothing
}
impl From<Tooltip> for Dom {
fn from(t: Tooltip) -> Self {
t.dom()
}
}