#![allow(dead_code)] use egui::{
NumExt, Response, RichText, Sense, TextStyle, Ui, Widget, WidgetInfo, WidgetText, WidgetType,
};
use crate::prelude::*;
pub struct BorderedButton<'a> {
text: WidgetText,
wrap: Option<bool>,
sense: Sense,
min_size: Vec2,
focus_on_hover: bool,
default_border: Option<&'a BorderImageMeta>,
on_focus_border: Option<&'a BorderImageMeta>,
on_click_border: Option<&'a BorderImageMeta>,
margin: egui::style::Margin,
padding: egui::style::Margin,
}
impl<'a> BorderedButton<'a> {
#[must_use = "You must call .show() to render the button"]
pub fn new(text: impl Into<WidgetText>) -> Self {
Self {
text: text.into(),
sense: Sense::click(),
min_size: Vec2::ZERO,
focus_on_hover: true,
wrap: None,
default_border: None,
on_focus_border: None,
on_click_border: None,
margin: Default::default(),
padding: Default::default(),
}
}
#[must_use = "You must call .show() to render the button"]
pub fn themed(
button_theme: &'a ButtonThemeMeta,
label: impl Into<RichText>,
) -> BorderedButton<'a> {
BorderedButton::new(
label
.into()
.font(button_theme.font.id())
.color(button_theme.font.color),
)
.border(&button_theme.borders.default)
.on_click_border(Some(&button_theme.borders.clicked))
.on_focus_border(Some(&button_theme.borders.focused))
.padding(button_theme.padding)
}
pub fn focus_on_hover(mut self, focus_on_hover: bool) -> Self {
self.focus_on_hover = focus_on_hover;
self
}
#[inline]
#[must_use = "You must call .show() to render the button"]
pub fn wrap(mut self, wrap: bool) -> Self {
self.wrap = Some(wrap);
self
}
#[must_use = "You must call .show() to render the button"]
pub fn margin(mut self, margin: impl Into<egui::style::Margin>) -> Self {
self.margin = margin.into();
self
}
#[must_use = "You must call .show() to render the button"]
pub fn padding(mut self, padding: impl Into<egui::style::Margin>) -> Self {
self.padding = padding.into();
self
}
#[must_use = "You must call .show() to render the button"]
pub fn border(mut self, border: &'a BorderImageMeta) -> Self {
self.default_border = Some(border);
self
}
#[must_use = "You must call .show() to render the button"]
pub fn on_focus_border(mut self, border: Option<&'a BorderImageMeta>) -> Self {
self.on_focus_border = border;
self
}
#[must_use = "You must call .show() to render the button"]
pub fn on_click_border(mut self, border: Option<&'a BorderImageMeta>) -> Self {
self.on_click_border = border;
self
}
#[must_use = "You must call .show() to render the button"]
pub fn sense(mut self, sense: Sense) -> Self {
self.sense = sense;
self
}
#[must_use = "You must call .show() to render the button"]
pub fn min_size(mut self, min_size: Vec2) -> Self {
self.min_size = min_size;
self
}
#[must_use = "You must call .show() to render the button"]
pub fn show(self, ui: &mut Ui) -> egui::Response {
self.ui(ui)
}
}
impl<'a> Widget for BorderedButton<'a> {
fn ui(self, ui: &mut Ui) -> Response {
let BorderedButton {
text,
sense,
min_size,
focus_on_hover,
wrap,
default_border,
on_focus_border,
on_click_border,
margin,
padding,
}: BorderedButton = self;
let total_extra = padding.sum() + margin.sum();
let wrap_width = ui.available_width() - total_extra.x;
let text = text.into_galley(ui, wrap, wrap_width, TextStyle::Button);
let mut desired_size = text.size() + total_extra;
desired_size = desired_size.at_least(egui::vec2(min_size.x, min_size.y));
let (rect, response) = ui.allocate_at_least(desired_size, sense);
response.widget_info(|| WidgetInfo::labeled(WidgetType::Button, text.text()));
if response.hovered()
&& ui.ctx().input(|i| i.pointer.velocity().length_sq() > 0.0)
&& focus_on_hover
{
response.request_focus();
}
if ui.is_rect_visible(rect) {
let visuals = ui.style().interact(&response);
let mut text_rect = rect;
text_rect.min += padding.left_top() + margin.left_top();
text_rect.max -= padding.right_bottom() + margin.right_bottom();
text_rect.max.x = text_rect.max.x.max(text_rect.min.x);
text_rect.max.y = text_rect.max.y.max(text_rect.min.y);
let label_pos = ui
.layout()
.align_size_within_rect(text.size(), text_rect)
.min;
let border = if response.is_pointer_button_down_on() {
on_click_border.or(default_border)
} else if response.has_focus() || response.hovered() {
on_focus_border.or(default_border)
} else {
default_border
};
let mut border_rect = rect;
border_rect.min += margin.left_top();
border_rect.max -= margin.right_bottom();
border_rect.max.x = border_rect.max.x.max(border_rect.min.x);
border_rect.max.y = border_rect.max.y.max(border_rect.min.y);
if let Some(border) = border {
let texture = ui.data(|map| {
map.get_temp::<AtomicResource<EguiTextures>>(egui::Id::null())
.unwrap()
.borrow()
.unwrap()
.get(border.image)
});
ui.painter()
.add(BorderedFrame::new(border).paint(texture, border_rect));
}
text.paint_with_visuals(ui.painter(), label_pos, visuals);
}
response
}
}