2019-09-01 17:28:52 +00:00
|
|
|
use super::image_frame::ImageFrame;
|
2019-07-29 14:06:13 +00:00
|
|
|
use conrod_core::{
|
2019-09-01 17:28:52 +00:00
|
|
|
builder_method, builder_methods, image, input::global::Global, position::Dimension, text,
|
|
|
|
widget, widget_ids, Color, Colorable, FontSize, Positionable, Sizeable, Ui, UiCell, Widget,
|
|
|
|
WidgetCommon, WidgetStyle,
|
2019-07-29 14:06:13 +00:00
|
|
|
};
|
|
|
|
use std::time::{Duration, Instant};
|
|
|
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
struct Hover(widget::Id, [f64; 2]);
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
enum HoverState {
|
|
|
|
Hovering(Hover),
|
|
|
|
Fading(Instant, Hover, Option<(Instant, widget::Id)>),
|
|
|
|
Start(Instant, widget::Id),
|
|
|
|
None,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Spacing between the tooltip and mouse
|
|
|
|
const MOUSE_PAD_Y: f64 = 15.0;
|
|
|
|
|
|
|
|
pub struct TooltipManager {
|
|
|
|
tooltip_id: widget::Id,
|
|
|
|
state: HoverState,
|
|
|
|
// How long before a tooltip is displayed when hovering
|
|
|
|
hover_dur: Duration,
|
|
|
|
// How long it takes a tooltip to disappear
|
|
|
|
fade_dur: Duration,
|
|
|
|
// Current scaling of the ui
|
|
|
|
logical_scale_factor: f64,
|
|
|
|
}
|
|
|
|
impl TooltipManager {
|
|
|
|
pub fn new(
|
|
|
|
mut generator: widget::id::Generator,
|
|
|
|
hover_dur: Duration,
|
|
|
|
fade_dur: Duration,
|
|
|
|
logical_scale_factor: f64,
|
|
|
|
) -> Self {
|
|
|
|
Self {
|
|
|
|
tooltip_id: generator.next(),
|
|
|
|
state: HoverState::None,
|
|
|
|
hover_dur,
|
|
|
|
fade_dur,
|
|
|
|
logical_scale_factor,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn maintain(&mut self, input: &Global, logical_scale_factor: f64) {
|
|
|
|
self.logical_scale_factor = logical_scale_factor;
|
|
|
|
|
|
|
|
let current = &input.current;
|
|
|
|
|
|
|
|
if let Some(um_id) = current.widget_under_mouse {
|
|
|
|
match self.state {
|
|
|
|
HoverState::Hovering(hover) if um_id == hover.0 || um_id == self.tooltip_id => (),
|
|
|
|
HoverState::Hovering(hover) => {
|
|
|
|
self.state =
|
|
|
|
HoverState::Fading(Instant::now(), hover, Some((Instant::now(), um_id)))
|
|
|
|
}
|
|
|
|
HoverState::Fading(_, _, Some((_, id)))
|
|
|
|
if um_id == id || um_id == self.tooltip_id => {}
|
|
|
|
HoverState::Fading(start, hover, _) => {
|
|
|
|
self.state = HoverState::Fading(start, hover, Some((Instant::now(), um_id)))
|
|
|
|
}
|
|
|
|
HoverState::Start(_, id) if um_id == id || um_id == self.tooltip_id => (),
|
|
|
|
HoverState::Start(_, _) | HoverState::None => {
|
|
|
|
self.state = HoverState::Start(Instant::now(), um_id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
match self.state {
|
|
|
|
HoverState::Hovering(hover) => {
|
|
|
|
self.state = HoverState::Fading(Instant::now(), hover, None)
|
|
|
|
}
|
|
|
|
HoverState::Fading(start, hover, Some((_, _))) => {
|
|
|
|
self.state = HoverState::Fading(start, hover, None)
|
|
|
|
}
|
|
|
|
HoverState::Start(_, _) => self.state = HoverState::None,
|
|
|
|
HoverState::Fading(_, _, None) | HoverState::None => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle fade timing
|
|
|
|
if let HoverState::Fading(start, _, maybe_hover) = self.state {
|
|
|
|
if start.elapsed() > self.fade_dur {
|
|
|
|
self.state = match maybe_hover {
|
|
|
|
Some((start, hover)) => HoverState::Start(start, hover),
|
|
|
|
None => HoverState::None,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-09-01 19:27:33 +00:00
|
|
|
fn set_tooltip(
|
|
|
|
&mut self,
|
|
|
|
tooltip: &Tooltip,
|
|
|
|
title_text: &str,
|
|
|
|
desc_text: &str,
|
|
|
|
img_id: Option<image::Id>,
|
|
|
|
image_dims: Option<(f64, f64)>,
|
|
|
|
src_id: widget::Id,
|
|
|
|
ui: &mut UiCell,
|
|
|
|
) {
|
2019-07-29 14:06:13 +00:00
|
|
|
let tooltip_id = self.tooltip_id;
|
|
|
|
let mp_h = MOUSE_PAD_Y / self.logical_scale_factor;
|
|
|
|
|
|
|
|
let tooltip = |transparency, mouse_pos: [f64; 2], ui: &mut UiCell| {
|
2019-09-01 19:27:33 +00:00
|
|
|
// Fill in text and the potential image beforehand to get an accurate size for spacing
|
|
|
|
let tooltip = tooltip
|
|
|
|
.clone()
|
|
|
|
.title(title_text)
|
|
|
|
.desc(desc_text)
|
|
|
|
.image(img_id)
|
|
|
|
.image_dims(image_dims);
|
|
|
|
|
2019-07-29 14:06:13 +00:00
|
|
|
let [t_w, t_h] = tooltip.get_wh(ui).unwrap_or([0.0, 0.0]);
|
|
|
|
let [m_x, m_y] = mouse_pos;
|
|
|
|
let (w_w, w_h) = (ui.win_w, ui.win_h);
|
|
|
|
|
|
|
|
// Determine position based on size and mouse position
|
|
|
|
// Flow to the bottom right of the mouse
|
|
|
|
let x = (m_x + t_w / 2.0).min(w_w / 2.0 - t_w / 2.0);
|
|
|
|
let y = (m_y - mp_h - t_h / 2.0).max(-w_h / 2.0 + t_h / 2.0);
|
|
|
|
tooltip
|
|
|
|
.floating(true)
|
|
|
|
.transparency(transparency)
|
|
|
|
.x_y(x, y)
|
|
|
|
.set(tooltip_id, ui);
|
|
|
|
};
|
|
|
|
|
|
|
|
match self.state {
|
|
|
|
HoverState::Hovering(hover) => tooltip(1.0, hover.1, ui),
|
|
|
|
HoverState::Fading(start, hover, _) => tooltip(
|
|
|
|
(1.0f32 - start.elapsed().as_millis() as f32 / self.hover_dur.as_millis() as f32)
|
|
|
|
.max(0.0),
|
|
|
|
hover.1,
|
|
|
|
ui,
|
|
|
|
),
|
|
|
|
HoverState::Start(start, id) if id == src_id && start.elapsed() > self.hover_dur => {
|
|
|
|
let xy = ui.global_input().current.mouse.xy;
|
|
|
|
self.state = HoverState::Hovering(Hover(id, xy));
|
|
|
|
tooltip(1.0, xy, ui);
|
|
|
|
}
|
|
|
|
HoverState::Start(_, _) | HoverState::None => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Tooltipped<'a, W> {
|
|
|
|
inner: W,
|
|
|
|
tooltip_manager: &'a mut TooltipManager,
|
2019-09-01 19:27:33 +00:00
|
|
|
title_text: &'a str,
|
|
|
|
desc_text: &'a str,
|
|
|
|
img_id: Option<image::Id>,
|
|
|
|
image_dims: Option<(f64, f64)>,
|
|
|
|
tooltip: &'a Tooltip<'a>,
|
2019-07-29 14:06:13 +00:00
|
|
|
}
|
|
|
|
impl<'a, W: Widget> Tooltipped<'a, W> {
|
2019-09-01 19:27:33 +00:00
|
|
|
pub fn tooltip_image(mut self, img_id: image::Id) -> Self {
|
|
|
|
self.img_id = Some(img_id);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
pub fn tooltip_image_dims(mut self, dims: (f64, f64)) -> Self {
|
|
|
|
self.image_dims = Some(dims);
|
|
|
|
self
|
|
|
|
}
|
2019-07-29 14:06:13 +00:00
|
|
|
pub fn set(self, id: widget::Id, ui: &mut UiCell) -> W::Event {
|
|
|
|
let event = self.inner.set(id, ui);
|
2019-09-01 19:27:33 +00:00
|
|
|
self.tooltip_manager.set_tooltip(
|
|
|
|
self.tooltip,
|
|
|
|
self.title_text,
|
|
|
|
self.desc_text,
|
|
|
|
self.img_id,
|
|
|
|
self.image_dims,
|
|
|
|
id,
|
|
|
|
ui,
|
|
|
|
);
|
2019-07-29 14:06:13 +00:00
|
|
|
event
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait Tooltipable {
|
|
|
|
// If `Tooltip` is expensive to construct accept a closure here instead.
|
|
|
|
fn with_tooltip<'a>(
|
|
|
|
self,
|
|
|
|
tooltip_manager: &'a mut TooltipManager,
|
2019-09-01 19:27:33 +00:00
|
|
|
title_text: &'a str,
|
|
|
|
desc_text: &'a str,
|
|
|
|
tooltip: &'a Tooltip<'a>,
|
2019-07-29 14:06:13 +00:00
|
|
|
) -> Tooltipped<'a, Self>
|
|
|
|
where
|
|
|
|
Self: std::marker::Sized;
|
|
|
|
}
|
|
|
|
impl<W: Widget> Tooltipable for W {
|
|
|
|
fn with_tooltip<'a>(
|
|
|
|
self,
|
|
|
|
tooltip_manager: &'a mut TooltipManager,
|
2019-09-01 19:27:33 +00:00
|
|
|
title_text: &'a str,
|
|
|
|
desc_text: &'a str,
|
|
|
|
tooltip: &'a Tooltip<'a>,
|
2019-07-29 14:06:13 +00:00
|
|
|
) -> Tooltipped<'a, W> {
|
|
|
|
Tooltipped {
|
|
|
|
inner: self,
|
|
|
|
tooltip_manager,
|
2019-09-01 19:27:33 +00:00
|
|
|
title_text,
|
|
|
|
desc_text,
|
|
|
|
img_id: None,
|
|
|
|
image_dims: None,
|
2019-07-29 14:06:13 +00:00
|
|
|
tooltip,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-01 17:28:52 +00:00
|
|
|
/// Vertical spacing between elements of the tooltip
|
|
|
|
const V_PAD: f64 = 10.0;
|
|
|
|
/// Horizontal spacing between elements of the tooltip
|
|
|
|
const H_PAD: f64 = 10.0;
|
|
|
|
/// Default portion of inner width that goes to an image
|
|
|
|
const IMAGE_W_FRAC: f64 = 0.3;
|
|
|
|
/// Default width multiplied by the description font size
|
|
|
|
const DEFAULT_CHAR_W: f64 = 30.0;
|
2019-09-01 19:27:33 +00:00
|
|
|
/// Text vertical spacing factor to account for overhanging text
|
|
|
|
const TEXT_SPACE_FACTOR: f64 = 0.35;
|
2019-09-01 17:28:52 +00:00
|
|
|
|
2019-07-29 14:06:13 +00:00
|
|
|
/// A widget for displaying tooltips
|
|
|
|
#[derive(Clone, WidgetCommon)]
|
|
|
|
pub struct Tooltip<'a> {
|
|
|
|
#[conrod(common_builder)]
|
|
|
|
common: widget::CommonBuilder,
|
|
|
|
title_text: &'a str,
|
|
|
|
desc_text: &'a str,
|
2019-09-01 17:28:52 +00:00
|
|
|
image: Option<image::Id>,
|
|
|
|
image_dims: Option<(f64, f64)>,
|
2019-07-29 14:06:13 +00:00
|
|
|
style: Style,
|
|
|
|
transparency: f32,
|
2019-09-01 19:27:33 +00:00
|
|
|
image_frame: ImageFrame,
|
2019-07-29 14:06:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, Default, PartialEq, WidgetStyle)]
|
|
|
|
pub struct Style {
|
2019-09-01 17:28:52 +00:00
|
|
|
#[conrod(default = "Color::Rgba(1.0, 1.0, 1.0, 1.0)")]
|
2019-07-29 14:06:13 +00:00
|
|
|
pub color: Option<Color>,
|
|
|
|
title: widget::text::Style,
|
|
|
|
desc: widget::text::Style,
|
|
|
|
// add background imgs here
|
|
|
|
}
|
|
|
|
|
|
|
|
widget_ids! {
|
|
|
|
struct Ids {
|
|
|
|
title,
|
|
|
|
desc,
|
2019-09-01 17:28:52 +00:00
|
|
|
image_frame,
|
|
|
|
image,
|
2019-07-29 14:06:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct State {
|
|
|
|
ids: Ids,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Tooltip<'a> {
|
2019-09-01 19:27:33 +00:00
|
|
|
pub fn new(image_frame: ImageFrame) -> Self {
|
2019-07-29 14:06:13 +00:00
|
|
|
Tooltip {
|
|
|
|
common: widget::CommonBuilder::default(),
|
|
|
|
style: Style::default(),
|
2019-09-01 19:27:33 +00:00
|
|
|
title_text: "",
|
|
|
|
desc_text: "",
|
2019-07-29 14:06:13 +00:00
|
|
|
transparency: 1.0,
|
2019-09-01 17:28:52 +00:00
|
|
|
image_frame,
|
|
|
|
image: None,
|
|
|
|
image_dims: None,
|
2019-07-29 14:06:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Align the text to the left of its bounding **Rect**'s *x* axis range.
|
|
|
|
//pub fn left_justify(self) -> Self {
|
|
|
|
// self.justify(text::Justify::Left)
|
|
|
|
//}
|
|
|
|
|
|
|
|
/// Align the text to the middle of its bounding **Rect**'s *x* axis range.
|
|
|
|
//pub fn center_justify(self) -> Self {
|
|
|
|
// self.justify(text::Justify::Center)
|
|
|
|
//}
|
|
|
|
|
|
|
|
/// Align the text to the right of its bounding **Rect**'s *x* axis range.
|
|
|
|
//pub fn right_justify(self) -> Self {
|
|
|
|
// self.justify(text::Justify::Right)
|
|
|
|
//}
|
|
|
|
|
2019-09-01 20:30:26 +00:00
|
|
|
fn text_image_width(&self, total_width: f64) -> (f64, f64) {
|
2019-09-01 17:28:52 +00:00
|
|
|
let inner_width = (total_width - H_PAD * 2.0).max(0.0);
|
|
|
|
// Image defaults to 30% of the width
|
|
|
|
let image_w = if self.image.is_some() {
|
|
|
|
match self.image_dims {
|
|
|
|
Some((w, _)) => w,
|
|
|
|
None => (inner_width - H_PAD).max(0.0) * IMAGE_W_FRAC,
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
0.0
|
|
|
|
};
|
2019-09-01 20:30:26 +00:00
|
|
|
// Text gets the remaining width
|
|
|
|
let text_w = (inner_width
|
2019-09-01 17:28:52 +00:00
|
|
|
- if self.image.is_some() {
|
|
|
|
image_w + H_PAD
|
|
|
|
} else {
|
|
|
|
0.0
|
|
|
|
})
|
|
|
|
.max(0.0);
|
|
|
|
|
2019-09-01 20:30:26 +00:00
|
|
|
(text_w, image_w)
|
2019-09-01 17:28:52 +00:00
|
|
|
}
|
2019-07-29 14:06:13 +00:00
|
|
|
|
|
|
|
/// Specify the font used for displaying the text.
|
|
|
|
pub fn font_id(mut self, font_id: text::font::Id) -> Self {
|
|
|
|
self.style.title.font_id = Some(Some(font_id));
|
|
|
|
self.style.desc.font_id = Some(Some(font_id));
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
builder_methods! {
|
|
|
|
pub title_text_color { style.title.color = Some(Color) }
|
|
|
|
pub desc_text_color { style.desc.color = Some(Color) }
|
|
|
|
pub title_font_size { style.title.font_size = Some(FontSize) }
|
|
|
|
pub desc_font_size { style.desc.font_size = Some(FontSize) }
|
|
|
|
pub title_justify { style.title.justify = Some(text::Justify) }
|
|
|
|
pub desc_justify { style.desc.justify = Some(text::Justify) }
|
2019-09-01 19:27:33 +00:00
|
|
|
image { image = Option<image::Id> }
|
|
|
|
title { title_text = &'a str }
|
|
|
|
desc { desc_text = &'a str }
|
|
|
|
image_dims { image_dims = Option<(f64, f64)> }
|
2019-07-29 14:06:13 +00:00
|
|
|
transparency { transparency = f32 }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Widget for Tooltip<'a> {
|
|
|
|
type State = State;
|
|
|
|
type Style = Style;
|
|
|
|
type Event = ();
|
|
|
|
|
|
|
|
fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
|
|
|
|
State {
|
|
|
|
ids: Ids::new(id_gen),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn style(&self) -> Self::Style {
|
|
|
|
self.style.clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn update(self, args: widget::UpdateArgs<Self>) {
|
|
|
|
let widget::UpdateArgs {
|
|
|
|
id,
|
|
|
|
state,
|
|
|
|
rect,
|
|
|
|
style,
|
|
|
|
ui,
|
|
|
|
..
|
|
|
|
} = args;
|
|
|
|
|
2019-09-01 19:27:33 +00:00
|
|
|
// Widths
|
2019-09-01 20:30:26 +00:00
|
|
|
let (text_w, image_w) = self.text_image_width(rect.w());
|
2019-09-01 19:27:33 +00:00
|
|
|
|
2019-07-29 14:06:13 +00:00
|
|
|
// Apply transparency
|
|
|
|
let color = style.color(ui.theme()).alpha(self.transparency);
|
|
|
|
|
2019-09-01 17:28:52 +00:00
|
|
|
// Background image frame
|
|
|
|
self.image_frame
|
|
|
|
.wh(rect.dim())
|
2019-07-29 14:06:13 +00:00
|
|
|
.xy(rect.xy())
|
|
|
|
.graphics_for(id)
|
|
|
|
.parent(id)
|
|
|
|
.color(color)
|
2019-09-01 17:28:52 +00:00
|
|
|
.set(state.ids.image_frame, ui);
|
|
|
|
|
2019-09-01 20:30:26 +00:00
|
|
|
// Image
|
|
|
|
if let Some(img_id) = self.image {
|
|
|
|
widget::Image::new(img_id)
|
|
|
|
.w_h(image_w, self.image_dims.map_or(image_w, |(_, h)| h))
|
|
|
|
.graphics_for(id)
|
|
|
|
.parent(id)
|
|
|
|
.color(Some(color))
|
|
|
|
.top_left_with_margins_on(state.ids.image_frame, V_PAD, H_PAD)
|
|
|
|
.set(state.ids.image, ui);
|
|
|
|
}
|
|
|
|
|
2019-09-01 19:27:33 +00:00
|
|
|
// Spacing for overhanging text
|
|
|
|
let title_space = self.style.title.font_size(&ui.theme) as f64 * TEXT_SPACE_FACTOR;
|
2019-07-29 14:06:13 +00:00
|
|
|
|
|
|
|
// Title of tooltip
|
2019-09-01 19:27:33 +00:00
|
|
|
if !self.title_text.is_empty() {
|
2019-09-01 20:30:26 +00:00
|
|
|
let title = widget::Text::new(self.title_text)
|
|
|
|
.w(text_w)
|
2019-09-01 19:27:33 +00:00
|
|
|
.graphics_for(id)
|
|
|
|
.parent(id)
|
|
|
|
.with_style(self.style.title)
|
|
|
|
// Apply transparency
|
2019-09-01 20:30:26 +00:00
|
|
|
.color(style.title.color(ui.theme()).alpha(self.transparency));
|
2019-07-29 14:06:13 +00:00
|
|
|
|
2019-09-01 20:30:26 +00:00
|
|
|
if self.image.is_some() {
|
|
|
|
title
|
|
|
|
.right_from(state.ids.image, H_PAD)
|
|
|
|
.align_top_of(state.ids.image)
|
2019-09-01 19:27:33 +00:00
|
|
|
} else {
|
2019-09-01 20:30:26 +00:00
|
|
|
title.top_left_with_margins_on(state.ids.image_frame, V_PAD, H_PAD)
|
2019-09-01 19:27:33 +00:00
|
|
|
}
|
2019-09-01 20:30:26 +00:00
|
|
|
.set(state.ids.title, ui);
|
2019-09-01 17:28:52 +00:00
|
|
|
}
|
|
|
|
|
2019-07-29 14:06:13 +00:00
|
|
|
// Description of tooltip
|
2019-09-01 17:28:52 +00:00
|
|
|
let desc = widget::Text::new(self.desc_text)
|
2019-09-01 20:30:26 +00:00
|
|
|
.w(text_w)
|
2019-07-29 14:06:13 +00:00
|
|
|
.graphics_for(id)
|
|
|
|
.parent(id)
|
|
|
|
// Apply transparency
|
|
|
|
.color(style.desc.color(ui.theme()).alpha(self.transparency))
|
2019-09-01 17:28:52 +00:00
|
|
|
.with_style(self.style.desc);
|
|
|
|
|
2019-09-01 20:30:26 +00:00
|
|
|
if !self.title_text.is_empty() {
|
|
|
|
desc.down_from(state.ids.title, V_PAD * 0.5 + title_space)
|
|
|
|
.align_left_of(state.ids.title)
|
2019-09-01 17:28:52 +00:00
|
|
|
} else {
|
2019-09-01 20:30:26 +00:00
|
|
|
if self.image.is_some() {
|
|
|
|
desc.right_from(state.ids.image, H_PAD)
|
|
|
|
.align_top_of(state.ids.image)
|
2019-09-01 19:27:33 +00:00
|
|
|
} else {
|
|
|
|
desc.top_left_with_margins_on(state.ids.image_frame, V_PAD, H_PAD)
|
|
|
|
}
|
2019-09-01 17:28:52 +00:00
|
|
|
}
|
|
|
|
.set(state.ids.desc, ui);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Default width is based on the description font size unless the text is small enough to fit on a single line
|
|
|
|
fn default_x_dimension(&self, ui: &Ui) -> Dimension {
|
|
|
|
let single_line_title_w = widget::Text::new(self.title_text)
|
|
|
|
.with_style(self.style.title)
|
|
|
|
.get_w(ui)
|
|
|
|
.unwrap_or(0.0);
|
|
|
|
let single_line_desc_w = widget::Text::new(self.desc_text)
|
|
|
|
.with_style(self.style.desc)
|
|
|
|
.get_w(ui)
|
|
|
|
.unwrap_or(0.0);
|
2019-09-01 20:30:26 +00:00
|
|
|
|
|
|
|
let text_w = single_line_title_w.max(single_line_desc_w);
|
|
|
|
let inner_w = if self.image.is_some() {
|
2019-09-01 17:28:52 +00:00
|
|
|
match self.image_dims {
|
2019-09-01 20:30:26 +00:00
|
|
|
Some((w, _)) => w + text_w + H_PAD,
|
|
|
|
None => text_w / (1.0 - IMAGE_W_FRAC) + H_PAD,
|
2019-09-01 17:28:52 +00:00
|
|
|
}
|
|
|
|
} else {
|
2019-09-01 20:30:26 +00:00
|
|
|
text_w
|
2019-09-01 17:28:52 +00:00
|
|
|
};
|
|
|
|
|
2019-09-01 20:30:26 +00:00
|
|
|
let width =
|
|
|
|
inner_w.min(self.style.desc.font_size(&ui.theme) as f64 * DEFAULT_CHAR_W) + 2.0 * H_PAD;
|
2019-09-01 17:28:52 +00:00
|
|
|
Dimension::Absolute(width)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn default_y_dimension(&self, ui: &Ui) -> Dimension {
|
2019-09-01 20:30:26 +00:00
|
|
|
let (text_w, image_w) = self.text_image_width(self.get_w(ui).unwrap_or(0.0));
|
2019-09-01 19:27:33 +00:00
|
|
|
let title_h = if self.title_text.is_empty() {
|
|
|
|
0.0
|
|
|
|
} else {
|
|
|
|
widget::Text::new(self.title_text)
|
|
|
|
.with_style(self.style.title)
|
2019-09-01 20:30:26 +00:00
|
|
|
.w(text_w)
|
2019-09-01 19:27:33 +00:00
|
|
|
.get_h(ui)
|
|
|
|
.unwrap_or(0.0)
|
|
|
|
+ self.style.title.font_size(&ui.theme) as f64 * TEXT_SPACE_FACTOR
|
|
|
|
+ 0.5 * V_PAD
|
|
|
|
};
|
|
|
|
let desc_h = if self.desc_text.is_empty() {
|
|
|
|
0.0
|
|
|
|
} else {
|
|
|
|
widget::Text::new(self.desc_text)
|
|
|
|
.with_style(self.style.desc)
|
2019-09-01 20:30:26 +00:00
|
|
|
.w(text_w)
|
2019-09-01 19:27:33 +00:00
|
|
|
.get_h(ui)
|
|
|
|
.unwrap_or(0.0)
|
|
|
|
+ self.style.desc.font_size(&ui.theme) as f64 * TEXT_SPACE_FACTOR
|
|
|
|
};
|
2019-09-01 17:28:52 +00:00
|
|
|
// Image defaults to square shape
|
2019-09-01 20:30:26 +00:00
|
|
|
let image_h = self.image_dims.map_or(image_w, |(_, h)| h);
|
|
|
|
// Title height + desc height + padding/spacing
|
|
|
|
let height = (title_h + desc_h).max(image_h) + 2.0 * V_PAD;
|
2019-09-01 17:28:52 +00:00
|
|
|
Dimension::Absolute(height)
|
2019-07-29 14:06:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Colorable for Tooltip<'a> {
|
|
|
|
builder_method!(color { style.color = Some(Color) });
|
|
|
|
}
|