2023-09-01 07:29:19 +02:00
|
|
|
// Copyright 2023 System76 <info@system76.com>
|
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
|
2024-10-16 20:36:46 -04:00
|
|
|
use super::{Builder, ButtonClass};
|
2025-03-21 03:17:59 +01:00
|
|
|
use crate::Element;
|
2023-09-13 15:47:32 +02:00
|
|
|
use crate::widget::{
|
|
|
|
|
icon::{self, Handle},
|
|
|
|
|
tooltip,
|
|
|
|
|
};
|
2023-09-01 07:29:19 +02:00
|
|
|
use apply::Apply;
|
2025-03-21 03:17:59 +01:00
|
|
|
use iced_core::{Alignment, Length, Padding, font::Weight, text::LineHeight, widget::Id};
|
2023-09-01 07:29:19 +02:00
|
|
|
use std::borrow::Cow;
|
|
|
|
|
|
|
|
|
|
pub type Button<'a, Message> = Builder<'a, Message, Icon>;
|
|
|
|
|
|
2024-05-20 20:01:47 +02:00
|
|
|
/// The icon variant of a button.
|
2023-09-01 07:29:19 +02:00
|
|
|
pub struct Icon {
|
|
|
|
|
handle: Handle,
|
|
|
|
|
vertical: bool,
|
2024-03-11 15:21:48 -04:00
|
|
|
selected: bool,
|
2023-09-01 07:29:19 +02:00
|
|
|
}
|
|
|
|
|
|
2024-05-20 20:01:47 +02:00
|
|
|
/// A button constructed from an icon handle, using icon button styling.
|
2023-09-13 15:47:32 +02:00
|
|
|
pub fn icon<'a, Message>(handle: impl Into<Handle>) -> Button<'a, Message> {
|
2023-09-01 07:29:19 +02:00
|
|
|
Button::new(Icon {
|
|
|
|
|
handle: handle.into(),
|
|
|
|
|
vertical: false,
|
2024-03-11 15:21:48 -04:00
|
|
|
selected: false,
|
2023-09-01 07:29:19 +02:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 11:56:21 -04:00
|
|
|
impl<Message> Button<'_, Message> {
|
2023-09-01 07:29:19 +02:00
|
|
|
pub fn new(icon: Icon) -> Self {
|
2024-08-02 20:00:16 +02:00
|
|
|
let guard = crate::theme::THEME.lock().unwrap();
|
|
|
|
|
let theme = guard.cosmic();
|
|
|
|
|
let padding = theme.space_xxs();
|
|
|
|
|
|
|
|
|
|
Self {
|
|
|
|
|
id: Id::unique(),
|
|
|
|
|
label: Cow::Borrowed(""),
|
|
|
|
|
tooltip: Cow::Borrowed(""),
|
|
|
|
|
on_press: None,
|
|
|
|
|
width: Length::Shrink,
|
|
|
|
|
height: Length::Shrink,
|
|
|
|
|
padding: Padding::from(padding),
|
|
|
|
|
spacing: theme.space_xxxs(),
|
|
|
|
|
icon_size: if icon.handle.symbolic { 16 } else { 24 },
|
|
|
|
|
line_height: 20,
|
|
|
|
|
font_size: 14,
|
|
|
|
|
font_weight: Weight::Normal,
|
2024-10-16 20:36:46 -04:00
|
|
|
class: ButtonClass::Icon,
|
2024-08-02 20:00:16 +02:00
|
|
|
variant: icon,
|
|
|
|
|
}
|
2023-09-01 07:29:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Applies the **Extra Small** button size preset.
|
|
|
|
|
pub fn extra_small(mut self) -> Self {
|
2024-08-02 20:00:16 +02:00
|
|
|
let guard = crate::theme::THEME.lock().unwrap();
|
|
|
|
|
let theme = guard.cosmic();
|
|
|
|
|
|
|
|
|
|
self.font_size = 14;
|
|
|
|
|
self.font_weight = Weight::Normal;
|
|
|
|
|
self.icon_size = 16;
|
|
|
|
|
self.line_height = 20;
|
|
|
|
|
self.padding = Padding::from(theme.space_xxs());
|
|
|
|
|
self.spacing = theme.space_xxxs();
|
2023-09-01 07:29:19 +02:00
|
|
|
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Applies the **Medium** button size preset.
|
|
|
|
|
pub fn medium(mut self) -> Self {
|
2024-08-02 20:00:16 +02:00
|
|
|
let guard = crate::theme::THEME.lock().unwrap();
|
|
|
|
|
let theme = guard.cosmic();
|
|
|
|
|
|
|
|
|
|
self.font_size = 24;
|
|
|
|
|
self.font_weight = Weight::Normal;
|
|
|
|
|
self.icon_size = 32;
|
|
|
|
|
self.line_height = 32;
|
|
|
|
|
self.padding = Padding::from(theme.space_xs());
|
|
|
|
|
self.spacing = theme.space_xxs();
|
2023-09-01 07:29:19 +02:00
|
|
|
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Applies the **Large** button size preset.
|
|
|
|
|
pub fn large(mut self) -> Self {
|
2024-08-02 20:00:16 +02:00
|
|
|
let guard = crate::theme::THEME.lock().unwrap();
|
|
|
|
|
let theme = guard.cosmic();
|
|
|
|
|
|
|
|
|
|
self.font_size = 28;
|
|
|
|
|
self.font_weight = Weight::Normal;
|
|
|
|
|
self.icon_size = 40;
|
|
|
|
|
self.line_height = 36;
|
|
|
|
|
self.padding = Padding::from(theme.space_xs());
|
|
|
|
|
self.spacing = theme.space_xxs();
|
2023-09-01 07:29:19 +02:00
|
|
|
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Applies the **Extra Large** button size preset.
|
|
|
|
|
pub fn extra_large(mut self) -> Self {
|
2024-08-02 20:00:16 +02:00
|
|
|
let guard = crate::theme::THEME.lock().unwrap();
|
|
|
|
|
let theme = guard.cosmic();
|
|
|
|
|
let padding = theme.space_xs();
|
|
|
|
|
|
|
|
|
|
self.font_size = 32;
|
|
|
|
|
self.font_weight = Weight::Light;
|
|
|
|
|
self.icon_size = 56;
|
|
|
|
|
self.line_height = 44;
|
|
|
|
|
self.padding = Padding::from(padding);
|
|
|
|
|
self.spacing = theme.space_xxs();
|
2023-09-01 07:29:19 +02:00
|
|
|
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
2024-03-11 15:21:48 -04:00
|
|
|
pub fn selected(mut self, selected: bool) -> Self {
|
|
|
|
|
self.variant.selected = selected;
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
2023-09-13 15:47:32 +02:00
|
|
|
pub fn vertical(mut self, vertical: bool) -> Self {
|
|
|
|
|
self.variant.vertical = vertical;
|
2024-10-16 20:36:46 -04:00
|
|
|
self.class = ButtonClass::IconVertical;
|
2023-09-01 07:29:19 +02:00
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a, Message: Clone + 'static> From<Button<'a, Message>> for Element<'a, Message> {
|
2023-09-13 15:47:32 +02:00
|
|
|
fn from(mut builder: Button<'a, Message>) -> Element<'a, Message> {
|
2023-09-01 07:29:19 +02:00
|
|
|
let mut content = Vec::with_capacity(2);
|
|
|
|
|
|
2023-09-13 15:47:32 +02:00
|
|
|
if let icon::Data::Name(ref mut named) = builder.variant.handle.data {
|
|
|
|
|
named.size = Some(builder.icon_size);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-01 07:29:19 +02:00
|
|
|
content.push(
|
|
|
|
|
crate::widget::icon(builder.variant.handle.clone())
|
|
|
|
|
.size(builder.icon_size)
|
|
|
|
|
.into(),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if !builder.label.is_empty() {
|
|
|
|
|
content.push(
|
|
|
|
|
crate::widget::text(builder.label)
|
|
|
|
|
.size(builder.font_size)
|
|
|
|
|
.line_height(LineHeight::Absolute(builder.line_height.into()))
|
2024-10-03 21:27:06 +02:00
|
|
|
.font(crate::font::Font {
|
|
|
|
|
weight: builder.font_weight,
|
|
|
|
|
..crate::font::default()
|
2023-09-01 07:29:19 +02:00
|
|
|
})
|
|
|
|
|
.into(),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let button = if builder.variant.vertical {
|
|
|
|
|
crate::widget::column::with_children(content)
|
|
|
|
|
.padding(builder.padding)
|
|
|
|
|
.spacing(builder.spacing)
|
2024-10-16 20:36:46 -04:00
|
|
|
.align_x(Alignment::Center)
|
2024-09-16 19:11:29 +02:00
|
|
|
.apply(super::custom)
|
2023-09-01 07:29:19 +02:00
|
|
|
} else {
|
|
|
|
|
crate::widget::row::with_children(content)
|
|
|
|
|
.padding(builder.padding)
|
|
|
|
|
.width(builder.width)
|
|
|
|
|
.height(builder.height)
|
|
|
|
|
.spacing(builder.spacing)
|
2024-10-16 20:36:46 -04:00
|
|
|
.align_y(Alignment::Center)
|
2024-09-16 19:11:29 +02:00
|
|
|
.apply(super::custom)
|
2023-09-01 07:29:19 +02:00
|
|
|
};
|
|
|
|
|
|
2023-09-13 15:47:32 +02:00
|
|
|
let button = button
|
2023-09-01 07:29:19 +02:00
|
|
|
.padding(0)
|
|
|
|
|
.id(builder.id)
|
|
|
|
|
.on_press_maybe(builder.on_press)
|
2024-03-11 15:21:48 -04:00
|
|
|
.selected(builder.variant.selected)
|
2024-10-16 20:36:46 -04:00
|
|
|
.class(builder.class);
|
2023-09-13 15:47:32 +02:00
|
|
|
|
|
|
|
|
if builder.tooltip.is_empty() {
|
|
|
|
|
button.into()
|
|
|
|
|
} else {
|
2024-10-16 20:36:46 -04:00
|
|
|
tooltip(
|
|
|
|
|
button,
|
|
|
|
|
crate::widget::text(builder.tooltip)
|
|
|
|
|
.size(builder.font_size)
|
|
|
|
|
.font(crate::font::Font {
|
|
|
|
|
weight: builder.font_weight,
|
|
|
|
|
..crate::font::default()
|
|
|
|
|
}),
|
|
|
|
|
tooltip::Position::Top,
|
|
|
|
|
)
|
|
|
|
|
.into()
|
2023-09-13 15:47:32 +02:00
|
|
|
}
|
2023-09-01 07:29:19 +02:00
|
|
|
}
|
|
|
|
|
}
|