// Copyright 2023 System76 // SPDX-License-Identifier: MPL-2.0 use super::{Builder, Style}; use crate::widget::{ icon::{self, Handle}, tooltip, }; use crate::Element; use apply::Apply; use iced_core::{font::Weight, text::LineHeight, widget::Id, Alignment, Length, Padding}; use std::borrow::Cow; pub type Button<'a, Message> = Builder<'a, Message, Icon>; /// The icon variant of a button. pub struct Icon { handle: Handle, vertical: bool, selected: bool, } /// A button constructed from an icon handle, using icon button styling. pub fn icon<'a, Message>(handle: impl Into) -> Button<'a, Message> { Button::new(Icon { handle: handle.into(), vertical: false, selected: false, }) } impl<'a, Message> Button<'a, Message> { pub fn new(icon: Icon) -> Self { 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, style: Style::Icon, variant: icon, } } /// Applies the **Extra Small** button size preset. pub fn extra_small(mut self) -> Self { 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(); self } /// Applies the **Medium** button size preset. pub fn medium(mut self) -> Self { 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(); self } /// Applies the **Large** button size preset. pub fn large(mut self) -> Self { 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(); self } /// Applies the **Extra Large** button size preset. pub fn extra_large(mut self) -> Self { 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(); self } pub fn selected(mut self, selected: bool) -> Self { self.variant.selected = selected; self } pub fn vertical(mut self, vertical: bool) -> Self { self.variant.vertical = vertical; self.style = Style::IconVertical; self } } impl<'a, Message: Clone + 'static> From> for Element<'a, Message> { fn from(mut builder: Button<'a, Message>) -> Element<'a, Message> { let mut content = Vec::with_capacity(2); if let icon::Data::Name(ref mut named) = builder.variant.handle.data { named.size = Some(builder.icon_size); } 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())) .font(crate::font::Font { weight: builder.font_weight, ..crate::font::default() }) .into(), ); } let button = if builder.variant.vertical { crate::widget::column::with_children(content) .padding(builder.padding) .spacing(builder.spacing) .align_items(Alignment::Center) .apply(super::custom) } else { crate::widget::row::with_children(content) .padding(builder.padding) .width(builder.width) .height(builder.height) .spacing(builder.spacing) .align_items(Alignment::Center) .apply(super::custom) }; let button = button .padding(0) .id(builder.id) .on_press_maybe(builder.on_press) .selected(builder.variant.selected) .style(builder.style); if builder.tooltip.is_empty() { button.into() } else { tooltip(button, builder.tooltip, tooltip::Position::Top) .size(builder.font_size) .font(crate::font::Font { weight: builder.font_weight, ..crate::font::default() }) .into() } } }