Skip to main content

iced_aw/widget/
helpers.rs

1//! widget Helpers.
2//!
3//!
4#[cfg(feature = "selection_list")]
5use crate::style::{Status, StyleFn};
6#[allow(unused_imports)]
7use iced_core::{self, Color, Element, Padding, renderer};
8
9#[cfg(feature = "number_input")]
10use num_traits::bounds::Bounded;
11#[allow(unused_imports)]
12use std::{borrow::Cow, fmt::Display, hash::Hash, ops::RangeBounds};
13
14/// Creates a horizontal [`Wrap`] with the given children.
15///
16/// [`Wrap`]: crate::Wrap
17#[cfg(feature = "wrap")]
18#[macro_export]
19macro_rules! wrap_horizontal {
20    () => (
21        $crate::Wrap::new()
22    );
23    ($($x:expr),+ $(,)?) => (
24        $crate::Wrap::with_elements(vec![$($crate::Element::from($x)),+])
25    );
26}
27
28/// Creates a vertical [`Wrap`] with the given children.
29///
30/// [`Wrap`]: crate::Wrap
31#[cfg(feature = "wrap")]
32#[macro_export]
33macro_rules! wrap_vertical {
34    () => (
35        $crate::Wrap::new_vertical()
36    );
37    ($($x:expr),+ $(,)?) => (
38        $crate::Wrap::with_elements_vertical(vec![$($crate::Element::from($x)),+])
39    );
40}
41
42/// Creates a vec of menu [`Item`]s
43///
44/// [`Item`]: crate::menu::Item
45///
46/// Syntax:
47/// ```ignore
48/// menu_items!(
49///     (widget),
50///     (widget, menu),
51///     expression,
52///     ...
53/// )
54/// ```
55#[cfg(feature = "menu")]
56#[macro_export]
57macro_rules! menu_items {
58    // base case
59    (@process [$($output:expr,)*]) => {
60        vec![$($output),*]
61    };
62
63    // rule for (widget, menu)
64    (@process [$($output:expr,)*] ($i:expr, $m:expr) , $($rest:tt)*) => {
65        $crate::menu_items!(@process [$($output,)* $crate::menu::Item::with_menu($i, $m),] $($rest)*)
66    };
67    (@process [$($output:expr,)*] ($i:expr, $m:expr)) => {
68        $crate::menu_items!(@process [$($output,)* $crate::menu::Item::with_menu($i, $m),])
69    };
70
71    // rule for (widget)
72    (@process [$($output:expr,)*] ($i:expr) , $($rest:tt)*) => {
73        $crate::menu_items!(@process [$($output,)* $crate::menu::Item::new($i),] $($rest)*)
74    };
75    (@process [$($output:expr,)*] ($i:expr)) => {
76        $crate::menu_items!(@process [$($output,)* $crate::menu::Item::new($i),])
77    };
78
79    // rule for expr
80    (@process [$($output:expr,)*] $item:expr , $($rest:tt)*) => {
81        $crate::menu_items!(@process [$($output,)* $item,] $($rest)*)
82    };
83    (@process [$($output:expr,)*] $item:expr) => {
84        $crate::menu_items!(@process [$($output,)* $item,])
85    };
86
87    // entry point
88    ($($input:tt)*) => {
89        $crate::menu_items!(@process [] $($input)*)
90    };
91}
92
93/// Creates a [`Menu`] with the given items.
94///
95/// [`Menu`]: crate::menu::Menu
96///
97/// Syntax:
98/// ```ignore
99/// menu!(
100///     (widget),
101///     (widget, menu),
102///     expression,
103///     ...
104/// )
105/// ```
106#[cfg(feature = "menu")]
107#[macro_export]
108macro_rules! menu {
109    ($($x:tt)+) => {
110        $crate::menu::Menu::new( $crate::menu_items!( $($x)+ ) )
111    }
112}
113
114/// Creates a [`MenuBar`] with the given children.
115///
116/// [`MenuBar`]: crate::menu::MenuBar
117///
118/// Syntax:
119/// ```ignore
120/// menu_bar!(
121///     (widget),
122///     (widget, menu),
123///     expression,
124///     ...
125/// )
126/// ```
127#[cfg(feature = "menu")]
128#[macro_export]
129macro_rules! menu_bar {
130    ($($input:tt)+) => (
131        $crate::menu::MenuBar::new($crate::menu_items!( $($input)+ ))
132    );
133}
134
135#[cfg(feature = "badge")]
136/// Shortcut helper to create a [`Badge`] Widget.
137///
138/// [`Badge`]: crate::Badge
139pub fn badge<'a, Message, Theme, Renderer>(
140    content: impl Into<Element<'a, Message, Theme, Renderer>>,
141) -> crate::Badge<'a, Message, Theme, Renderer>
142where
143    Renderer: renderer::Renderer,
144    Theme: crate::style::badge::Catalog,
145{
146    crate::Badge::new(content)
147}
148
149#[cfg(feature = "card")]
150/// Shortcut helper to create a [`Card`] Widget.
151///
152/// [`Card`]: crate::Card
153pub fn card<'a, Message, Theme, Renderer>(
154    head: impl Into<Element<'a, Message, Theme, Renderer>>,
155    body: impl Into<Element<'a, Message, Theme, Renderer>>,
156) -> crate::Card<'a, Message, Theme, Renderer>
157where
158    Renderer: renderer::Renderer,
159    Theme: crate::style::card::Catalog,
160{
161    crate::Card::new(head, body)
162}
163
164#[cfg(feature = "color_picker")]
165/// Shortcut helper to create a [`ColorPicker`] Widget.
166///
167/// [`ColorPicker`]: crate::ColorPicker
168pub fn color_picker<'a, Message, Theme, F>(
169    show_picker: bool,
170    color: Color,
171    underlay: impl Into<Element<'a, Message, Theme, iced_widget::Renderer>>,
172    on_cancel: Message,
173    on_submit: F,
174) -> crate::ColorPicker<'a, Message, Theme>
175where
176    Message: 'a + Clone,
177    Theme: 'a
178        + crate::style::color_picker::Catalog
179        + iced_widget::button::Catalog
180        + iced_widget::text::Catalog,
181    F: 'static + Fn(Color) -> Message,
182{
183    crate::ColorPicker::new(show_picker, color, underlay, on_cancel, on_submit)
184}
185
186#[cfg(feature = "color_picker")]
187/// Shortcut helper to create a [`ColorPicker`] Widget with real-time color change callback.
188///
189/// [`ColorPicker`]: crate::ColorPicker
190pub fn color_picker_with_change<'a, Message, Theme, F, G>(
191    show_picker: bool,
192    color: Color,
193    underlay: impl Into<Element<'a, Message, Theme, iced_widget::Renderer>>,
194    on_cancel: Message,
195    on_submit: F,
196    on_color_change: G,
197) -> crate::ColorPicker<'a, Message, Theme>
198where
199    Message: 'a + Clone,
200    Theme: 'a
201        + crate::style::color_picker::Catalog
202        + iced_widget::button::Catalog
203        + iced_widget::text::Catalog,
204    F: 'static + Fn(Color) -> Message,
205    G: 'static + Fn(Color) -> Message,
206{
207    crate::ColorPicker::new(show_picker, color, underlay, on_cancel, on_submit)
208        .on_color_change(on_color_change)
209}
210
211#[cfg(feature = "date_picker")]
212/// Shortcut helper to create a [`DatePicker`] Widget.
213///
214/// [`DatePicker`]: crate::DatePicker
215pub fn date_picker<'a, Message, Theme, F>(
216    show_picker: bool,
217    date: impl Into<crate::core::date::Date>,
218    underlay: impl Into<Element<'a, Message, Theme, iced_widget::Renderer>>,
219    on_cancel: Message,
220    on_submit: F,
221) -> crate::DatePicker<'a, Message, Theme>
222where
223    Message: 'a + Clone,
224    Theme: 'a
225        + crate::style::date_picker::Catalog
226        + iced_widget::button::Catalog
227        + iced_widget::text::Catalog
228        + iced_widget::container::Catalog,
229    F: 'static + Fn(crate::core::date::Date) -> Message,
230{
231    crate::DatePicker::new(show_picker, date, underlay, on_cancel, on_submit)
232}
233
234#[cfg(feature = "time_picker")]
235/// Shortcut helper to create a [`DatePicker`] Widget.
236///
237/// [`DatePicker`]: crate::DatePicker
238pub fn time_picker<'a, Message, Theme, U, F>(
239    show_picker: bool,
240    time: impl Into<crate::core::time::Time>,
241    underlay: U,
242    on_cancel: Message,
243    on_submit: F,
244) -> crate::TimePicker<'a, Message, Theme>
245where
246    Message: 'a + Clone,
247    Theme: 'a
248        + crate::style::time_picker::Catalog
249        + iced_widget::button::Catalog
250        + iced_widget::text::Catalog,
251    U: Into<Element<'a, Message, Theme, iced_widget::Renderer>>,
252    F: 'static + Fn(crate::core::time::Time) -> Message,
253{
254    crate::TimePicker::new(show_picker, time, underlay, on_cancel, on_submit)
255}
256
257#[cfg(feature = "wrap")]
258/// Shortcut helper to create a horizontal [`Wrap`] Widget.
259///
260/// [`Wrap`]: crate::Wrap
261#[must_use]
262pub fn wrap_horizontal<Message, Theme, Renderer>(
263    children: Vec<Element<Message, Theme, Renderer>>,
264) -> crate::Wrap<Message, crate::direction::Horizontal, Theme, Renderer>
265where
266    Renderer: renderer::Renderer,
267{
268    crate::Wrap::with_elements(children)
269}
270
271#[cfg(feature = "wrap")]
272/// Shortcut helper to create a vertical [`Wrap`] Widget.
273///
274/// [`Wrap`]: crate::Wrap
275#[must_use]
276pub fn wrap_vertical<Message, Theme, Renderer>(
277    children: Vec<Element<Message, Theme, Renderer>>,
278) -> crate::Wrap<Message, crate::direction::Vertical, Theme, Renderer>
279where
280    Renderer: renderer::Renderer,
281{
282    crate::Wrap::with_elements_vertical(children)
283}
284
285#[cfg(feature = "number_input")]
286/// Shortcut helper to create a [`NumberInput`] Widget.
287///
288/// [`NumberInput`]: crate::NumberInput
289#[must_use]
290pub fn number_input<'a, T, Message, Theme, Renderer, F>(
291    value: &T,
292    bounds: impl RangeBounds<T>,
293    on_change: F,
294) -> crate::NumberInput<'a, T, Message, Theme, Renderer>
295where
296    Message: Clone + 'a,
297    Renderer: iced_core::text::Renderer<Font = iced_core::Font>,
298    Theme: crate::style::number_input::ExtendedCatalog,
299    F: 'a + Fn(T) -> Message + Copy,
300    T: 'a
301        + num_traits::Num
302        + num_traits::NumAssignOps
303        + PartialOrd
304        + std::fmt::Display
305        + std::str::FromStr
306        + Copy
307        + Bounded,
308{
309    crate::NumberInput::new(value, bounds, on_change)
310}
311
312#[cfg(feature = "typed_input")]
313/// Shortcut helper to create a [`TypedInput`] Widget.
314///
315/// [`TypedInput`]: crate::TypedInput
316#[must_use]
317pub fn typed_input<'a, T, Message, Theme, Renderer, F>(
318    value: &T,
319    on_change: F,
320) -> crate::TypedInput<'a, T, Message, Theme, Renderer>
321where
322    Message: Clone,
323    Renderer: iced_core::text::Renderer<Font = iced_core::Font>,
324    Theme: iced_widget::text_input::Catalog,
325    F: 'static + Fn(T) -> Message + Copy,
326    T: 'static + std::fmt::Display + std::str::FromStr + Clone,
327{
328    crate::TypedInput::new("", value).on_input(on_change)
329}
330
331#[cfg(feature = "selection_list")]
332/// Shortcut helper to create a [`SelectionList`] Widget.
333///
334/// [`SelectionList`]: crate::SelectionList
335#[must_use]
336pub fn selection_list_with<'a, T, Message, Theme, Renderer>(
337    options: &'a [T],
338    on_selected: impl Fn(usize, T) -> Message + 'static,
339    text_size: f32,
340    padding: impl Into<Padding>,
341    style: impl Fn(&Theme, Status) -> crate::style::selection_list::Style + 'a + Clone,
342    selected: Option<usize>,
343    font: iced_core::Font,
344) -> crate::SelectionList<'a, T, Message, Theme, Renderer>
345where
346    Message: 'a + Clone,
347    Renderer: 'a + renderer::Renderer + iced_core::text::Renderer<Font = iced_core::Font>,
348    Theme: 'a
349        + crate::style::selection_list::Catalog
350        + iced_widget::container::Catalog
351        + iced_widget::scrollable::Catalog
352        + iced_widget::text::Catalog,
353    T: Clone + Display + Eq + Hash,
354    [T]: ToOwned<Owned = Vec<T>>,
355    <Theme as crate::style::selection_list::Catalog>::Class<'a>:
356        From<StyleFn<'a, Theme, crate::style::selection_list::Style>>,
357{
358    crate::SelectionList::new_with(
359        options,
360        on_selected,
361        text_size,
362        padding,
363        style,
364        selected,
365        font,
366    )
367}
368
369#[cfg(feature = "selection_list")]
370/// Shortcut helper to create a [`SelectionList`] Widget.
371///
372/// [`SelectionList`]: crate::SelectionList
373#[must_use]
374pub fn selection_list<'a, T, Message, Theme, Renderer>(
375    options: &'a [T],
376    on_selected: impl Fn(usize, T) -> Message + 'static,
377) -> crate::SelectionList<'a, T, Message, Theme, Renderer>
378where
379    Message: 'a + Clone,
380    Renderer: 'a + renderer::Renderer + iced_core::text::Renderer<Font = iced_core::Font>,
381    Theme: 'a
382        + crate::style::selection_list::Catalog
383        + iced_widget::container::Catalog
384        + iced_widget::scrollable::Catalog
385        + iced_widget::text::Catalog,
386    T: Clone + Display + Eq + Hash,
387    [T]: ToOwned<Owned = Vec<T>>,
388{
389    crate::SelectionList::new(options, on_selected)
390}