Merge pull request #390 from wlx-team/staging

Tooltip improvements
This commit is contained in:
oo8dev
2026-01-13 18:08:38 +01:00
committed by GitHub
11 changed files with 212 additions and 62 deletions

View File

@@ -37,18 +37,18 @@
<Separator /> <Separator />
<label translation="APP_LAUNCHER.ASPECT_TITLE" /> <label translation="APP_LAUNCHER.ASPECT_TITLE" />
<RadioGroup id="radio_orientation" flex_direction="row" gap="16"> <RadioGroup id="radio_orientation" flex_direction="row" gap="16">
<RadioBox translation="APP_LAUNCHER.ASPECT.WIDE" value="Wide" tooltip="16:9" checked="1" /> <RadioBox translation="APP_LAUNCHER.ASPECT.WIDE" value="Wide" tooltip_str="16:9" checked="1" />
<RadioBox translation="APP_LAUNCHER.ASPECT.SEMI_WIDE" value="SemiWide" tooltip="3:2" /> <RadioBox translation="APP_LAUNCHER.ASPECT.SEMI_WIDE" value="SemiWide" tooltip_str="3:2" />
<RadioBox translation="APP_LAUNCHER.ASPECT.SQUARE" value="Square" tooltip="1:1" /> <RadioBox translation="APP_LAUNCHER.ASPECT.SQUARE" value="Square" tooltip_str="1:1" />
<RadioBox translation="APP_LAUNCHER.ASPECT.SEMI_TALL" value="SemiTall" tooltip="2:3" /> <RadioBox translation="APP_LAUNCHER.ASPECT.SEMI_TALL" value="SemiTall" tooltip_str="2:3" />
<RadioBox translation="APP_LAUNCHER.ASPECT.TALL" value="Tall" tooltip="9:16" /> <RadioBox translation="APP_LAUNCHER.ASPECT.TALL" value="Tall" tooltip_str="9:16" />
</RadioGroup> </RadioGroup>
<!-- Separator /> // saved settings override this, so let's hide it for now <!-- Separator /> // saved settings override this, so let's hide it for now
<label translation="APP_LAUNCHER.POS_TITLE" /> <label translation="APP_LAUNCHER.POS_TITLE" />
<RadioGroup id="radio_pos" flex_direction="row" gap="16"> <RadioGroup id="radio_pos" flex_direction="row" gap="16">
<RadioBox translation="APP_LAUNCHER.POS.FLOATING" value="Floating" tooltip="APP_LAUNCHER.POS.FLOATING_HELP" /> <RadioBox translation="APP_LAUNCHER.POS.FLOATING" value="Floating" tooltip_str="APP_LAUNCHER.POS.FLOATING_HELP" />
<RadioBox translation="APP_LAUNCHER.POS.ANCHORED" value="Anchored" tooltip="APP_LAUNCHER.POS.ANCHORED_HELP" checked="1" /> <RadioBox translation="APP_LAUNCHER.POS.ANCHORED" value="Anchored" tooltip_str="APP_LAUNCHER.POS.ANCHORED_HELP" checked="1" />
<RadioBox translation="APP_LAUNCHER.POS.STATIC" value="Static" tooltip="APP_LAUNCHER.POS.STATIC_HELP" /> <RadioBox translation="APP_LAUNCHER.POS.STATIC" value="Static" tooltip_str="APP_LAUNCHER.POS.STATIC_HELP" />
</RadioGroup --> </RadioGroup -->
<Separator /> <Separator />
<div flex_direction="row" justify_content="space_between" gap="16"> <div flex_direction="row" justify_content="space_between" gap="16">
@@ -61,4 +61,4 @@
</div> </div>
</div> </div>
</elements> </elements>
</layout> </layout>

View File

@@ -1,11 +1,14 @@
use crate::{ use crate::{
animation::{Animation, AnimationEasing}, animation::{Animation, AnimationEasing},
assets::AssetPath, assets::AssetPath,
components::{self, Component, ComponentBase, ComponentTrait, RefreshData, tooltip::ComponentTooltip}, components::{
self, Component, ComponentBase, ComponentTrait, RefreshData,
tooltip::{ComponentTooltip, TooltipTrait},
},
drawing::{self, Boundary, Color}, drawing::{self, Boundary, Color},
event::{CallbackDataCommon, EventListenerCollection, EventListenerID, EventListenerKind}, event::{CallbackDataCommon, EventListenerCollection, EventListenerID, EventListenerKind},
i18n::Translation, i18n::Translation,
layout::{LayoutTask, WidgetID, WidgetPair}, layout::{WidgetID, WidgetPair},
renderer_vk::{ renderer_vk::{
text::{FontWeight, TextStyle, custom_glyph::CustomGlyphData}, text::{FontWeight, TextStyle, custom_glyph::CustomGlyphData},
util::centered_matrix, util::centered_matrix,
@@ -90,6 +93,12 @@ struct State {
last_pressed: Instant, last_pressed: Instant,
} }
impl TooltipTrait for State {
fn get(&mut self) -> &mut Option<Rc<ComponentTooltip>> {
&mut self.active_tooltip
}
}
struct Data { struct Data {
id_label: WidgetID, // Label id_label: WidgetID, // Label
id_rect: WidgetID, // Rectangle id_rect: WidgetID, // Rectangle
@@ -268,7 +277,7 @@ fn register_event_mouse_enter(
data: Rc<Data>, data: Rc<Data>,
state: Rc<RefCell<State>>, state: Rc<RefCell<State>>,
listeners: &mut EventListenerCollection, listeners: &mut EventListenerCollection,
info: Option<components::tooltip::TooltipInfo>, tooltip_info: Option<components::tooltip::TooltipInfo>,
anim_mult: f32, anim_mult: f32,
) -> EventListenerID { ) -> EventListenerID {
listeners.register( listeners.register(
@@ -281,17 +290,7 @@ fn register_event_mouse_enter(
.alterables .alterables
.animate(anim_hover_create(state.clone(), event_data.widget_id, true, anim_mult)); .animate(anim_hover_create(state.clone(), event_data.widget_id, true, anim_mult));
if let Some(info) = info.clone() { ComponentTooltip::register_hover_in(common, &tooltip_info, data.id_rect, state.clone());
common.alterables.tasks.push(LayoutTask::ModifyLayoutState({
let widget_to_watch = data.id_rect;
let state = state.clone();
Box::new(move |m| {
state.borrow_mut().active_tooltip =
Some(components::tooltip::show(m.layout, widget_to_watch, info.clone())?);
Ok(())
})
}));
}
state.borrow_mut().hovered = true; state.borrow_mut().hovered = true;
Ok(EventResult::Pass) Ok(EventResult::Pass)

View File

@@ -9,7 +9,11 @@ use taffy::{
use crate::{ use crate::{
animation::{Animation, AnimationEasing}, animation::{Animation, AnimationEasing},
components::{Component, ComponentBase, ComponentTrait, RefreshData, radio_group::ComponentRadioGroup}, components::{
Component, ComponentBase, ComponentTrait, RefreshData,
radio_group::ComponentRadioGroup,
tooltip::{self, ComponentTooltip, TooltipTrait},
},
drawing::Color, drawing::Color,
event::{CallbackDataCommon, EventListenerCollection, EventListenerID, EventListenerKind}, event::{CallbackDataCommon, EventListenerCollection, EventListenerID, EventListenerKind},
i18n::Translation, i18n::Translation,
@@ -31,6 +35,7 @@ pub struct Params {
pub checked: bool, pub checked: bool,
pub radio_group: Option<Rc<ComponentRadioGroup>>, pub radio_group: Option<Rc<ComponentRadioGroup>>,
pub value: Option<Rc<str>>, pub value: Option<Rc<str>>,
pub tooltip: Option<tooltip::TooltipInfo>,
} }
impl Default for Params { impl Default for Params {
@@ -42,6 +47,7 @@ impl Default for Params {
checked: false, checked: false,
radio_group: None, radio_group: None,
value: None, value: None,
tooltip: None,
} }
} }
} }
@@ -59,6 +65,13 @@ struct State {
down: bool, down: bool,
on_toggle: Option<CheckboxToggleCallback>, on_toggle: Option<CheckboxToggleCallback>,
self_ref: Weak<ComponentCheckbox>, self_ref: Weak<ComponentCheckbox>,
active_tooltip: Option<Rc<ComponentTooltip>>,
}
impl TooltipTrait for State {
fn get(&mut self) -> &mut Option<Rc<ComponentTooltip>> {
&mut self.active_tooltip
}
} }
#[allow(clippy::struct_field_names)] #[allow(clippy::struct_field_names)]
@@ -181,6 +194,7 @@ fn anim_hover_out(state: Rc<RefCell<State>>, widget_id: WidgetID, anim_mult: f32
fn register_event_mouse_enter( fn register_event_mouse_enter(
state: Rc<RefCell<State>>, state: Rc<RefCell<State>>,
listeners: &mut EventListenerCollection, listeners: &mut EventListenerCollection,
tooltip_info: Option<tooltip::TooltipInfo>,
anim_mult: f32, anim_mult: f32,
) -> EventListenerID { ) -> EventListenerID {
listeners.register( listeners.register(
@@ -190,6 +204,9 @@ fn register_event_mouse_enter(
common common
.alterables .alterables
.animate(anim_hover_in(state.clone(), event_data.widget_id, anim_mult)); .animate(anim_hover_in(state.clone(), event_data.widget_id, anim_mult));
ComponentTooltip::register_hover_in(common, &tooltip_info, event_data.widget_id, state.clone());
state.borrow_mut().hovered = true; state.borrow_mut().hovered = true;
Ok(EventResult::Pass) Ok(EventResult::Pass)
}), }),
@@ -208,7 +225,13 @@ fn register_event_mouse_leave(
common common
.alterables .alterables
.animate(anim_hover_out(state.clone(), event_data.widget_id, anim_mult)); .animate(anim_hover_out(state.clone(), event_data.widget_id, anim_mult));
state.borrow_mut().hovered = false;
{
let mut state = state.borrow_mut();
state.hovered = false;
state.active_tooltip = None;
}
Ok(EventResult::Pass) Ok(EventResult::Pass)
}), }),
) )
@@ -402,6 +425,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
hovered: false, hovered: false,
on_toggle: None, on_toggle: None,
self_ref: Weak::new(), self_ref: Weak::new(),
active_tooltip: None,
})); }));
let base = ComponentBase { let base = ComponentBase {
@@ -410,7 +434,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
let mut widget = ess.layout.state.widgets.get(id_container).unwrap().state(); let mut widget = ess.layout.state.widgets.get(id_container).unwrap().state();
let anim_mult = ess.layout.state.globals.defaults().animation_mult; let anim_mult = ess.layout.state.globals.defaults().animation_mult;
vec![ vec![
register_event_mouse_enter(state.clone(), &mut widget.event_listeners, anim_mult), register_event_mouse_enter(state.clone(), &mut widget.event_listeners, params.tooltip, anim_mult),
register_event_mouse_leave(state.clone(), &mut widget.event_listeners, anim_mult), register_event_mouse_leave(state.clone(), &mut widget.event_listeners, anim_mult),
register_event_mouse_press(state.clone(), &mut widget.event_listeners), register_event_mouse_press(state.clone(), &mut widget.event_listeners),
register_event_mouse_release(data.clone(), state.clone(), &mut widget.event_listeners), register_event_mouse_release(data.clone(), state.clone(), &mut widget.event_listeners),

View File

@@ -5,7 +5,10 @@ use taffy::prelude::{length, percent};
use crate::{ use crate::{
animation::{Animation, AnimationEasing}, animation::{Animation, AnimationEasing},
components::{Component, ComponentBase, ComponentTrait, RefreshData}, components::{
Component, ComponentBase, ComponentTrait, RefreshData,
tooltip::{self, ComponentTooltip, TooltipTrait},
},
drawing::{self}, drawing::{self},
event::{ event::{
self, CallbackDataCommon, CallbackMetadata, EventAlterables, EventListenerCollection, EventListenerKind, self, CallbackDataCommon, CallbackMetadata, EventAlterables, EventListenerCollection, EventListenerKind,
@@ -70,6 +73,7 @@ pub struct Params {
pub style: taffy::Style, pub style: taffy::Style,
pub values: ValuesMinMax, pub values: ValuesMinMax,
pub show_value: bool, pub show_value: bool,
pub tooltip: Option<tooltip::TooltipInfo>,
} }
struct State { struct State {
@@ -77,6 +81,13 @@ struct State {
hovered: bool, hovered: bool,
values: ValuesMinMax, values: ValuesMinMax,
on_value_changed: Option<SliderValueChangedCallback>, on_value_changed: Option<SliderValueChangedCallback>,
active_tooltip: Option<Rc<ComponentTooltip>>,
}
impl TooltipTrait for State {
fn get(&mut self) -> &mut Option<Rc<ComponentTooltip>> {
&mut self.active_tooltip
}
} }
struct Data { struct Data {
@@ -304,14 +315,18 @@ fn register_event_mouse_enter(
data: Rc<Data>, data: Rc<Data>,
state: Rc<RefCell<State>>, state: Rc<RefCell<State>>,
listeners: &mut EventListenerCollection, listeners: &mut EventListenerCollection,
tooltip_info: Option<tooltip::TooltipInfo>,
anim_mult: f32, anim_mult: f32,
) -> event::EventListenerID { ) -> event::EventListenerID {
listeners.register( listeners.register(
EventListenerKind::MouseEnter, EventListenerKind::MouseEnter,
Box::new(move |common, _data, (), ()| { Box::new(move |common, event_data, (), ()| {
common.alterables.trigger_haptics(); common.alterables.trigger_haptics();
state.borrow_mut().hovered = true; state.borrow_mut().hovered = true;
on_enter_anim(common, data.slider_handle_rect_id, anim_mult); on_enter_anim(common, data.slider_handle_rect_id, anim_mult);
ComponentTooltip::register_hover_in(common, &tooltip_info, event_data.widget_id, state.clone());
Ok(EventResult::Pass) Ok(EventResult::Pass)
}), }),
) )
@@ -327,8 +342,14 @@ fn register_event_mouse_leave(
EventListenerKind::MouseLeave, EventListenerKind::MouseLeave,
Box::new(move |common, _data, (), ()| { Box::new(move |common, _data, (), ()| {
common.alterables.trigger_haptics(); common.alterables.trigger_haptics();
state.borrow_mut().hovered = false;
{
let mut state = state.borrow_mut();
state.hovered = false;
state.active_tooltip = None;
}
on_leave_anim(common, data.slider_handle_rect_id, anim_mult); on_leave_anim(common, data.slider_handle_rect_id, anim_mult);
Ok(EventResult::Pass) Ok(EventResult::Pass)
}), }),
) )
@@ -474,6 +495,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
hovered: false, hovered: false,
values: params.values, values: params.values,
on_value_changed: None, on_value_changed: None,
active_tooltip: None,
}; };
let globals = ess.layout.state.globals.clone(); let globals = ess.layout.state.globals.clone();
@@ -515,7 +537,13 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
let mut widget = ess.layout.state.widgets.get(body_id).unwrap().state(); let mut widget = ess.layout.state.widgets.get(body_id).unwrap().state();
let anim_mult = ess.layout.state.globals.defaults().animation_mult; let anim_mult = ess.layout.state.globals.defaults().animation_mult;
vec![ vec![
register_event_mouse_enter(data.clone(), state.clone(), &mut widget.event_listeners, anim_mult), register_event_mouse_enter(
data.clone(),
state.clone(),
&mut widget.event_listeners,
params.tooltip,
anim_mult,
),
register_event_mouse_leave(data.clone(), state.clone(), &mut widget.event_listeners, anim_mult), register_event_mouse_leave(data.clone(), state.clone(), &mut widget.event_listeners, anim_mult),
register_event_mouse_motion(data.clone(), state.clone(), &mut widget.event_listeners), register_event_mouse_motion(data.clone(), state.clone(), &mut widget.event_listeners),
register_event_mouse_press(data.clone(), state.clone(), &mut widget.event_listeners), register_event_mouse_press(data.clone(), state.clone(), &mut widget.event_listeners),

View File

@@ -1,10 +1,12 @@
use glam::{Mat4, Vec3}; use glam::{Mat4, Vec2, Vec3};
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use taffy::prelude::length; use taffy::prelude::length;
use crate::{ use crate::{
animation::{Animation, AnimationEasing},
components::{self, Component, ComponentBase, ComponentTrait, RefreshData}, components::{self, Component, ComponentBase, ComponentTrait, RefreshData},
drawing::Color, drawing::Color,
event::CallbackDataCommon,
i18n::Translation, i18n::Translation,
layout::{self, LayoutTask, LayoutTasks, WidgetID, WidgetPair}, layout::{self, LayoutTask, LayoutTasks, WidgetID, WidgetPair},
renderer_vk::text::{FontWeight, TextStyle}, renderer_vk::text::{FontWeight, TextStyle},
@@ -17,6 +19,30 @@ use crate::{
}, },
}; };
pub trait TooltipTrait {
fn get(&mut self) -> &mut Option<Rc<ComponentTooltip>>;
}
impl ComponentTooltip {
pub fn register_hover_in(
common: &mut CallbackDataCommon,
tooltip_info: &Option<TooltipInfo>,
widget_to_watch: WidgetID,
state: Rc<RefCell<dyn TooltipTrait>>,
) {
let Some(info) = tooltip_info.clone() else {
return;
};
common.alterables.tasks.push(LayoutTask::ModifyLayoutState({
Box::new(move |m| {
let mut state = state.borrow_mut();
*state.get() = Some(components::tooltip::show(m.layout, widget_to_watch, info.clone())?);
Ok(())
})
}));
}
}
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub enum TooltipSide { pub enum TooltipSide {
Left, Left,
@@ -78,8 +104,6 @@ impl ComponentTrait for ComponentTooltip {
} }
} }
impl ComponentTooltip {}
impl Drop for ComponentTooltip { impl Drop for ComponentTooltip {
fn drop(&mut self) { fn drop(&mut self) {
self.tasks.push(LayoutTask::RemoveWidget(self.data.id_root)); self.tasks.push(LayoutTask::RemoveWidget(self.data.id_root));
@@ -180,7 +204,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
}, },
)?; )?;
let (_label, _) = ess.layout.add_child( let (label, _) = ess.layout.add_child(
rect.id, rect.id,
WidgetLabel::create( WidgetLabel::create(
&mut globals.get(), &mut globals.get(),
@@ -208,6 +232,35 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
tasks: ess.layout.tasks.clone(), tasks: ess.layout.tasks.clone(),
}); });
let direction = match params.info.side {
TooltipSide::Left => Vec2::new(-1.0, 0.0),
TooltipSide::Right => Vec2::new(1.0, 0.0),
TooltipSide::Top => Vec2::new(0.0, -1.0),
TooltipSide::Bottom => Vec2::new(0.0, 1.0),
};
let anim_mult = ess.layout.state.globals.defaults().animation_mult;
ess.layout.animations.add(Animation::new(
rect.id,
(10.0 * anim_mult) as u32,
AnimationEasing::OutQuad,
Box::new(move |common, data| {
let rect = data.obj.get_as_mut::<WidgetRectangle>().unwrap(); /* safe */
let alpha = data.pos;
rect.params.color.a = alpha;
rect.params.border_color.a = alpha;
let dir_mult = (1.0 - data.pos) * 5.0;
data.data.transform = Mat4::from_translation(Vec3::new(direction.x * dir_mult, direction.y * dir_mult, 0.0));
if let Some(mut label) = common.state.widgets.get_as::<WidgetLabel>(label.id) {
label.set_color(common, Color::new(1.0, 1.0, 1.0, alpha), true);
}
common.alterables.mark_redraw();
}),
));
ess.layout.defer_component_refresh(Component(tooltip.clone())); ess.layout.defer_component_refresh(Component(tooltip.clone()));
Ok((div, tooltip)) Ok((div, tooltip))
} }

View File

@@ -130,7 +130,7 @@ pub struct LayoutUpdateResult {
pub sounds_to_play: Vec<WguiSoundType>, pub sounds_to_play: Vec<WguiSoundType>,
} }
pub type ModifyLayoutStateFunc = Box<dyn Fn(ModifyLayoutStateData) -> anyhow::Result<()>>; pub type ModifyLayoutStateFunc = Box<dyn FnOnce(ModifyLayoutStateData) -> anyhow::Result<()>>;
pub enum LayoutTask { pub enum LayoutTask {
RemoveWidget(WidgetID), RemoveWidget(WidgetID),
@@ -690,7 +690,7 @@ impl Layout {
self.remove_widget(widget_id); self.remove_widget(widget_id);
} }
LayoutTask::ModifyLayoutState(callback) => { LayoutTask::ModifyLayoutState(callback) => {
(*callback)(ModifyLayoutStateData { layout: self })?; callback(ModifyLayoutStateData { layout: self })?;
} }
LayoutTask::PlaySound(sound) => { LayoutTask::PlaySound(sound) => {
if !self.sounds_to_play_once.contains(&sound) { if !self.sounds_to_play_once.contains(&sound) {

View File

@@ -5,7 +5,9 @@ use crate::{
i18n::Translation, i18n::Translation,
layout::WidgetID, layout::WidgetID,
parser::{ parser::{
AttribPair, ParserContext, ParserFile, get_asset_path_from_kv, parse_children, parse_f32, process_component, AttribPair, ParserContext, ParserFile, get_asset_path_from_kv,
helpers::{TooltipAttribs, parse_attrib_tooltip},
parse_children, parse_f32, process_component,
style::{parse_color_opt, parse_round, parse_style, parse_text_style}, style::{parse_color_opt, parse_round, parse_style, parse_text_style},
}, },
widget::util::WLength, widget::util::WLength,
@@ -25,8 +27,7 @@ pub fn parse_component_button<'a>(
let mut hover_color: Option<Color> = None; let mut hover_color: Option<Color> = None;
let mut hover_border_color: Option<Color> = None; let mut hover_border_color: Option<Color> = None;
let mut round = WLength::Units(4.0); let mut round = WLength::Units(4.0);
let mut tooltip: Option<Translation> = None; let mut tooltip = TooltipAttribs::default();
let mut tooltip_side: Option<tooltip::TooltipSide> = None;
let mut sticky: bool = false; let mut sticky: bool = false;
let mut long_press_time = 0.0; let mut long_press_time = 0.0;
let mut sprite_src: Option<AssetPath> = None; let mut sprite_src: Option<AssetPath> = None;
@@ -81,20 +82,6 @@ pub fn parse_component_button<'a>(
sprite_src = Some(asset_path); sprite_src = Some(asset_path);
} }
} }
"tooltip" if !value.is_empty() => tooltip = Some(Translation::from_translation_key(value)),
"tooltip_str" if !value.is_empty() => tooltip = Some(Translation::from_raw_text(value)),
"tooltip_side" => {
tooltip_side = match value {
"left" => Some(tooltip::TooltipSide::Left),
"right" => Some(tooltip::TooltipSide::Right),
"top" => Some(tooltip::TooltipSide::Top),
"bottom" => Some(tooltip::TooltipSide::Bottom),
_ => {
ctx.print_invalid_attrib(tag_name, key, value);
None
}
}
}
"sticky" => { "sticky" => {
let mut sticky_i32 = 0; let mut sticky_i32 = 0;
sticky = ctx.parse_check_i32(tag_name, key, value, &mut sticky_i32) && sticky_i32 == 1; sticky = ctx.parse_check_i32(tag_name, key, value, &mut sticky_i32) && sticky_i32 == 1;
@@ -102,7 +89,9 @@ pub fn parse_component_button<'a>(
"long_press_time" => { "long_press_time" => {
long_press_time = parse_f32(value).unwrap_or(long_press_time); long_press_time = parse_f32(value).unwrap_or(long_press_time);
} }
_ => {} _ => {
parse_attrib_tooltip(ctx, tag_name, pair, &mut tooltip);
}
} }
} }
@@ -118,10 +107,7 @@ pub fn parse_component_button<'a>(
style, style,
text_style, text_style,
round, round,
tooltip: tooltip.map(|text| tooltip::TooltipInfo { tooltip: tooltip.get_info(),
side: tooltip_side.map_or(tooltip::TooltipSide::Top, |f| f),
text,
}),
sticky, sticky,
long_press_time, long_press_time,
sprite_src, sprite_src,

View File

@@ -2,9 +2,15 @@ use crate::{
components::{Component, checkbox, radio_group::ComponentRadioGroup}, components::{Component, checkbox, radio_group::ComponentRadioGroup},
i18n::Translation, i18n::Translation,
layout::WidgetID, layout::WidgetID,
parser::{AttribPair, Fetchable, ParserContext, process_component, style::parse_style}, parser::{
AttribPair, Fetchable, ParserContext,
helpers::{TooltipAttribs, parse_attrib_tooltip},
process_component,
style::parse_style,
},
}; };
#[derive(Clone, Copy)]
pub enum CheckboxKind { pub enum CheckboxKind {
CheckBox, CheckBox,
RadioBox, RadioBox,
@@ -21,6 +27,7 @@ pub fn parse_component_checkbox(
let mut translation = Translation::default(); let mut translation = Translation::default();
let mut checked = 0; let mut checked = 0;
let mut component_value = None; let mut component_value = None;
let mut tooltip = TooltipAttribs::default();
let style = parse_style(ctx, attribs, tag_name); let style = parse_style(ctx, attribs, tag_name);
@@ -46,7 +53,9 @@ pub fn parse_component_checkbox(
"checked" => { "checked" => {
ctx.parse_check_i32(tag_name, key, value, &mut checked); ctx.parse_check_i32(tag_name, key, value, &mut checked);
} }
_ => {} _ => {
parse_attrib_tooltip(ctx, tag_name, pair, &mut tooltip);
}
} }
} }
@@ -81,6 +90,7 @@ pub fn parse_component_checkbox(
style, style,
radio_group, radio_group,
value: component_value, value: component_value,
tooltip: tooltip.get_info(),
}, },
)?; )?;

View File

@@ -1,7 +1,12 @@
use crate::{ use crate::{
components::{Component, slider}, components::{Component, slider},
layout::WidgetID, layout::WidgetID,
parser::{AttribPair, ParserContext, process_component, style::parse_style}, parser::{
AttribPair, ParserContext,
helpers::{TooltipAttribs, parse_attrib_tooltip},
process_component,
style::parse_style,
},
widget::ConstructEssentials, widget::ConstructEssentials,
}; };
@@ -16,6 +21,7 @@ pub fn parse_component_slider(
let mut initial_value = 0.5; let mut initial_value = 0.5;
let mut step = 1.0; let mut step = 1.0;
let mut show_value = 1; let mut show_value = 1;
let mut tooltip = TooltipAttribs::default();
let style = parse_style(ctx, attribs, tag_name); let style = parse_style(ctx, attribs, tag_name);
@@ -37,7 +43,9 @@ pub fn parse_component_slider(
"show_value" => { "show_value" => {
ctx.parse_check_i32(tag_name, key, value, &mut show_value); ctx.parse_check_i32(tag_name, key, value, &mut show_value);
} }
_ => {} _ => {
parse_attrib_tooltip(ctx, tag_name, pair, &mut tooltip);
}
} }
} }
@@ -55,6 +63,7 @@ pub fn parse_component_slider(
step, step,
}, },
show_value: show_value != 0, show_value: show_value != 0,
tooltip: tooltip.get_info(),
}, },
)?; )?;

View File

@@ -0,0 +1,40 @@
use crate::{
components::tooltip,
i18n::Translation,
parser::{AttribPair, ParserContext},
};
#[derive(Default)]
pub struct TooltipAttribs {
tooltip: Option<Translation>,
tooltip_side: Option<tooltip::TooltipSide>,
}
impl TooltipAttribs {
pub fn get_info(self) -> Option<tooltip::TooltipInfo> {
self.tooltip.map(|text| tooltip::TooltipInfo {
text,
side: self.tooltip_side.map_or(tooltip::TooltipSide::Top, |f| f),
})
}
}
pub fn parse_attrib_tooltip(ctx: &mut ParserContext, tag_name: &str, pair: &AttribPair, tooltip: &mut TooltipAttribs) {
match pair.attrib.as_ref() {
"tooltip" if !pair.value.is_empty() => tooltip.tooltip = Some(Translation::from_translation_key(&pair.value)),
"tooltip_str" if !pair.value.is_empty() => tooltip.tooltip = Some(Translation::from_raw_text(&pair.value)),
"tooltip_side" => {
tooltip.tooltip_side = match pair.value.as_ref() {
"left" => Some(tooltip::TooltipSide::Left),
"right" => Some(tooltip::TooltipSide::Right),
"top" => Some(tooltip::TooltipSide::Top),
"bottom" => Some(tooltip::TooltipSide::Bottom),
_ => {
ctx.print_invalid_attrib(tag_name, &pair.attrib, &pair.value);
None
}
}
}
_ => {}
}
}

View File

@@ -3,6 +3,7 @@ mod component_checkbox;
mod component_radio_group; mod component_radio_group;
mod component_slider; mod component_slider;
mod component_tabs; mod component_tabs;
mod helpers;
mod style; mod style;
mod widget_div; mod widget_div;
mod widget_image; mod widget_image;