cosmic/widget/button/
text.rs
1use super::{Builder, ButtonClass};
5use crate::widget::{icon, row, tooltip};
6use crate::{Apply, Element};
7use iced_core::{Alignment, Length, Padding, font::Weight, text::LineHeight, widget::Id};
8use std::borrow::Cow;
9
10pub type Button<'a, Message> = Builder<'a, Message, Text>;
11
12pub fn destructive<'a, Message>(label: impl Into<Cow<'a, str>>) -> Button<'a, Message> {
14 Button::new(Text::new())
15 .label(label)
16 .class(ButtonClass::Destructive)
17}
18
19pub fn suggested<'a, Message>(label: impl Into<Cow<'a, str>>) -> Button<'a, Message> {
21 Button::new(Text::new())
22 .label(label)
23 .class(ButtonClass::Suggested)
24}
25
26pub fn standard<'a, Message>(label: impl Into<Cow<'a, str>>) -> Button<'a, Message> {
28 Button::new(Text::new()).label(label)
29}
30
31pub fn text<'a, Message>(label: impl Into<Cow<'a, str>>) -> Button<'a, Message> {
33 Button::new(Text::new())
34 .label(label)
35 .class(ButtonClass::Text)
36}
37
38pub struct Text {
40 pub(super) leading_icon: Option<icon::Handle>,
41 pub(super) trailing_icon: Option<icon::Handle>,
42}
43
44impl Default for Text {
45 fn default() -> Self {
46 Self::new()
47 }
48}
49
50impl Text {
51 pub const fn new() -> Self {
52 Self {
53 leading_icon: None,
54 trailing_icon: None,
55 }
56 }
57}
58
59impl<Message> Button<'_, Message> {
60 pub fn new(text: Text) -> Self {
61 let guard = crate::theme::THEME.lock().unwrap();
62 let theme = guard.cosmic();
63 Self {
64 id: Id::unique(),
65 label: Cow::Borrowed(""),
66 tooltip: Cow::Borrowed(""),
67 on_press: None,
68 width: Length::Shrink,
69 height: Length::Fixed(theme.space_l().into()),
70 padding: Padding::from([0, theme.space_s()]),
71 spacing: theme.space_xxxs(),
72 icon_size: 16,
73 line_height: 20,
74 font_size: 14,
75 font_weight: Weight::Normal,
76 class: ButtonClass::Standard,
77 variant: text,
78 }
79 }
80
81 pub fn leading_icon(mut self, icon: impl Into<icon::Handle>) -> Self {
82 self.variant.leading_icon = Some(icon.into());
83 self
84 }
85
86 pub fn trailing_icon(mut self, icon: impl Into<icon::Handle>) -> Self {
87 self.variant.trailing_icon = Some(icon.into());
88 self
89 }
90}
91
92impl<'a, Message: Clone + 'static> From<Button<'a, Message>> for Element<'a, Message> {
93 fn from(mut builder: Button<'a, Message>) -> Element<'a, Message> {
94 let trailing_icon = builder.variant.trailing_icon.map(|mut i| {
95 if let icon::Data::Name(ref mut named) = i.data {
96 named.size = Some(builder.icon_size);
97 }
98
99 i.icon()
100 });
101
102 let leading_icon = builder.variant.leading_icon.map(|mut i| {
103 if let icon::Data::Name(ref mut named) = i.data {
104 named.size = Some(builder.icon_size);
105 }
106
107 i.icon()
108 });
109
110 let label: Option<Element<'_, _>> = (!builder.label.is_empty()).then(|| {
111 let font = crate::font::Font {
112 weight: builder.font_weight,
113 ..crate::font::default()
114 };
115
116 crate::widget::text(builder.label.to_string())
118 .size(builder.font_size)
119 .line_height(LineHeight::Absolute(builder.line_height.into()))
120 .font(font)
121 .into()
122 });
123
124 let mut button: super::Button<'a, Message> = row::with_capacity(3)
125 .push_maybe(leading_icon)
127 .push_maybe(label)
129 .push_maybe(trailing_icon)
131 .padding(builder.padding)
132 .width(builder.width)
133 .height(builder.height)
134 .spacing(builder.spacing)
135 .align_y(Alignment::Center)
136 .apply(super::custom)
137 .padding(0)
138 .id(builder.id)
139 .on_press_maybe(builder.on_press.take())
140 .class(builder.class);
141
142 #[cfg(feature = "a11y")]
143 {
144 if !builder.label.is_empty() {
145 button = button.name(builder.label);
146 }
147 }
148
149 if builder.tooltip.is_empty() {
150 button.into()
151 } else {
152 tooltip(
153 button,
154 crate::widget::text(builder.tooltip)
155 .size(builder.font_size)
156 .font(crate::font::Font {
157 weight: builder.font_weight,
158 ..crate::font::default()
159 }),
160 tooltip::Position::Top,
161 )
162 .into()
163 }
164 }
165}