Skip to main content

iced_widget/
lib.rs

1//! Use the built-in widgets or create your own.
2#![doc(
3    html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
4)]
5#![cfg_attr(docsrs, feature(doc_cfg))]
6pub use iced_renderer as renderer;
7pub use iced_renderer::core;
8pub use iced_renderer::graphics;
9
10pub use core::widget::{Id, Void};
11
12mod action;
13mod column;
14mod hover;
15mod mouse_area;
16mod pin;
17mod responsive;
18mod stack;
19mod themer;
20
21pub mod button;
22pub mod checkbox;
23pub mod combo_box;
24pub mod component;
25pub mod container;
26pub mod float;
27pub mod grid;
28pub mod keyed;
29pub mod lazy;
30pub mod overlay;
31pub mod pane_grid;
32pub mod pick_list;
33pub mod progress_bar;
34pub mod radio;
35pub mod row;
36pub mod rule;
37pub mod scrollable;
38pub mod sensor;
39pub mod slider;
40pub mod space;
41pub mod sticky;
42pub mod table;
43pub mod text;
44pub mod text_editor;
45pub mod text_input;
46pub mod toggler;
47pub mod tooltip;
48pub mod transition;
49pub mod vertical_slider;
50
51mod helpers;
52
53pub use helpers::*;
54
55#[doc(no_inline)]
56pub use button::Button;
57#[doc(no_inline)]
58pub use checkbox::Checkbox;
59#[doc(no_inline)]
60pub use column::Column;
61#[doc(no_inline)]
62pub use combo_box::ComboBox;
63#[doc(no_inline)]
64pub use component::Component;
65#[doc(no_inline)]
66pub use container::Container;
67#[doc(no_inline)]
68pub use float::Float;
69#[doc(no_inline)]
70pub use grid::Grid;
71#[doc(no_inline)]
72pub use hover::Hover;
73#[doc(no_inline)]
74pub use lazy::Lazy;
75#[doc(no_inline)]
76pub use mouse_area::MouseArea;
77#[doc(no_inline)]
78pub use pane_grid::PaneGrid;
79#[doc(no_inline)]
80pub use pick_list::PickList;
81#[doc(no_inline)]
82pub use pin::Pin;
83#[doc(no_inline)]
84pub use progress_bar::ProgressBar;
85#[doc(no_inline)]
86pub use radio::Radio;
87#[doc(no_inline)]
88pub use responsive::Responsive;
89#[doc(no_inline)]
90pub use row::Row;
91#[doc(no_inline)]
92pub use rule::Rule;
93#[doc(no_inline)]
94pub use scrollable::Scrollable;
95#[doc(no_inline)]
96pub use sensor::Sensor;
97#[doc(no_inline)]
98pub use slider::Slider;
99#[doc(no_inline)]
100pub use space::Space;
101#[doc(no_inline)]
102pub use stack::Stack;
103#[doc(no_inline)]
104pub use sticky::Sticky;
105#[doc(no_inline)]
106pub use text::Text;
107#[doc(no_inline)]
108pub use text_editor::TextEditor;
109#[doc(no_inline)]
110pub use text_input::TextInput;
111#[doc(no_inline)]
112pub use themer::Themer;
113#[doc(no_inline)]
114pub use toggler::Toggler;
115#[doc(no_inline)]
116pub use tooltip::Tooltip;
117#[doc(no_inline)]
118pub use vertical_slider::VerticalSlider;
119
120#[cfg(feature = "wgpu")]
121pub mod shader;
122
123#[cfg(feature = "wgpu")]
124#[doc(no_inline)]
125pub use shader::Shader;
126
127#[cfg(feature = "svg")]
128pub mod svg;
129
130#[cfg(feature = "svg")]
131#[doc(no_inline)]
132pub use svg::Svg;
133
134#[cfg(feature = "image")]
135pub mod image;
136
137#[cfg(feature = "image")]
138#[doc(no_inline)]
139pub use image::Image;
140
141#[cfg(feature = "canvas")]
142pub mod canvas;
143
144#[cfg(feature = "canvas")]
145#[doc(no_inline)]
146pub use canvas::Canvas;
147
148#[cfg(feature = "qr_code")]
149pub mod qr_code;
150
151#[cfg(feature = "qr_code")]
152#[doc(no_inline)]
153pub use qr_code::QRCode;
154
155#[cfg(feature = "markdown")]
156pub mod markdown;
157
158pub use crate::core::theme::{self, Theme};
159pub use action::Action;
160pub use renderer::Renderer;
161
162use crate::core::layout::{self, Layout};
163use crate::core::mouse;
164use crate::core::widget::tree;
165use crate::core::widget::{self, Tree};
166use crate::core::{Border, Color, Event, Length, Rectangle, Shell, Size, Vector};
167
168/// A boxed [`Widget`].
169///
170/// This is an alias of [`core::Element`] with default `Theme` and
171/// `Renderer` parameters.
172pub type Element<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> =
173    crate::core::Element<'a, Message, Theme, Renderer>;
174
175/// A widget that can be rendered by iced.
176///
177/// This trait extends [`core::Widget`] with a few convenient methods—like
178/// [`Widget::map`], [`Widget::boxed`], and [`Widget::explain`]—and defaults
179/// the `Theme` and `Renderer` parameters to iced's.
180pub trait Widget<Message, Theme = crate::Theme, Renderer = crate::Renderer>:
181    core::Widget<Message, Theme, Renderer>
182{
183    /// Applies a transformation to the produced message of this [`Widget`].
184    ///
185    /// This method is useful when you want to decouple different parts of your
186    /// UI and make them __composable__.
187    ///
188    /// # Example
189    /// Imagine we want to use [our counter](index.html#usage). But instead of
190    /// showing a single counter, we want to display many of them. We can reuse
191    /// the `Counter` type as it is!
192    ///
193    /// We use composition to model the __state__ of our new application:
194    ///
195    /// ```
196    /// # mod counter {
197    /// #     pub struct Counter;
198    /// # }
199    /// use counter::Counter;
200    ///
201    /// struct ManyCounters {
202    ///     counters: Vec<Counter>,
203    /// }
204    /// ```
205    ///
206    /// We can store the state of multiple counters now. However, the
207    /// __messages__ we implemented before describe the user interactions
208    /// of a __single__ counter. Right now, we need to also identify which
209    /// counter is receiving user interactions. Can we use composition again?
210    /// Yes.
211    ///
212    /// ```
213    /// # mod counter {
214    /// #     #[derive(Debug, Clone, Copy)]
215    /// #     pub enum Message {}
216    /// # }
217    /// #[derive(Debug, Clone, Copy)]
218    /// pub enum Message {
219    ///     Counter(usize, counter::Message)
220    /// }
221    /// ```
222    ///
223    /// We compose the previous __messages__ with the index of the counter
224    /// producing them. Let's implement our __view logic__ now:
225    ///
226    /// ```no_run
227    /// # mod iced {
228    /// #     pub use iced_widget::core::Function;
229    /// #     pub use iced_widget::Widget;
230    /// #     pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::core::Theme, ()>;
231    /// #
232    /// #     pub mod widget {
233    /// #         pub fn row<'a, Message>(iter: impl IntoIterator<Item = super::Element<'a, Message>>) -> super::Element<'a, Message> {
234    /// #             unimplemented!()
235    /// #         }
236    /// #     }
237    /// # }
238    /// #
239    /// # mod counter {
240    /// #     #[derive(Debug, Clone, Copy)]
241    /// #     pub enum Message {}
242    /// #     pub struct Counter;
243    /// #
244    /// #     pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::core::Theme, ()>;
245    /// #
246    /// #     impl Counter {
247    /// #         pub fn view(&self) -> Element<Message> {
248    /// #             unimplemented!()
249    /// #         }
250    /// #     }
251    /// # }
252    /// #
253    /// use counter::Counter;
254    ///
255    /// use iced::widget::row;
256    /// use iced::{Function, Widget};
257    ///
258    /// struct ManyCounters {
259    ///     counters: Vec<Counter>,
260    /// }
261    ///
262    /// #[derive(Debug, Clone, Copy)]
263    /// pub enum Message {
264    ///     Counter(usize, counter::Message),
265    /// }
266    ///
267    /// impl ManyCounters {
268    ///     pub fn view(&self) -> impl Widget<Message, iced_widget::Theme, ()> {
269    ///         // We can quickly populate a `row` by mapping our counters
270    ///         row(
271    ///             self.counters
272    ///                 .iter()
273    ///                 .map(Counter::view)
274    ///                 .enumerate()
275    ///                 .map(|(index, counter)| {
276    ///                     // Here we turn our `Element<counter::Message>` into
277    ///                     // an `Element<Message>` by combining the `index` and the
278    ///                     // message of the `element`.
279    ///                     counter.map(Message::Counter.with(index)).boxed()
280    ///                 }),
281    ///         )
282    ///     }
283    /// }
284    /// ```
285    ///
286    /// Finally, our __update logic__ is pretty straightforward: simple
287    /// delegation.
288    ///
289    /// ```
290    /// # mod counter {
291    /// #     #[derive(Debug, Clone, Copy)]
292    /// #     pub enum Message {}
293    /// #     pub struct Counter;
294    /// #
295    /// #     impl Counter {
296    /// #         pub fn update(&mut self, _message: Message) {}
297    /// #     }
298    /// # }
299    /// #
300    /// # use counter::Counter;
301    /// #
302    /// # struct ManyCounters {
303    /// #     counters: Vec<Counter>,
304    /// # }
305    /// #
306    /// # #[derive(Debug, Clone, Copy)]
307    /// # pub enum Message {
308    /// #    Counter(usize, counter::Message)
309    /// # }
310    /// impl ManyCounters {
311    ///     pub fn update(&mut self, message: Message) {
312    ///         match message {
313    ///             Message::Counter(index, counter_msg) => {
314    ///                 if let Some(counter) = self.counters.get_mut(index) {
315    ///                     counter.update(counter_msg);
316    ///                 }
317    ///             }
318    ///         }
319    ///     }
320    /// }
321    /// ```
322    fn map<F, B>(self, f: F) -> widget::Map<Self, F, Message>
323    where
324        Self: Sized,
325        F: Fn(Message) -> B,
326    {
327        core::Widget::_map(self, f)
328    }
329
330    /// Boxes this [`Widget`], turning it into a generic [`Element`].
331    fn boxed<'a>(self) -> Element<'a, Message, Theme, Renderer>
332    where
333        Self: Sized + 'a,
334    {
335        core::Widget::_boxed(self)
336    }
337
338    /// Marks this [`Widget`] as _to-be-explained_.
339    ///
340    /// The [`Renderer`] will explain its layout graphically.
341    /// This can be very useful for debugging your layout!
342    ///
343    /// [`Renderer`]: crate::Renderer
344    fn explain(self, color: impl Into<Color>) -> impl core::Widget<Message, Theme, Renderer>
345    where
346        Self: Sized,
347        Renderer: core::Renderer,
348    {
349        Explain {
350            widget: self,
351            color: color.into(),
352        }
353    }
354}
355
356impl<T, Message, Theme, Renderer> Widget<Message, Theme, Renderer> for T where
357    T: core::Widget<Message, Theme, Renderer>
358{
359}
360
361/// A [`Widget`] that explains the layout of its child.
362///
363/// The [`Renderer`] will explain the layout graphically. This can be very
364/// useful for debugging your layout!
365///
366/// This widget is returned by [`Widget::explain`].
367///
368/// [`Renderer`]: crate::Renderer
369pub struct Explain<W> {
370    widget: W,
371    color: Color,
372}
373
374impl<W> widget::Meta for Explain<W> {}
375
376impl<W, Message, Theme, Renderer> core::Widget<Message, Theme, Renderer> for Explain<W>
377where
378    W: core::Widget<Message, Theme, Renderer>,
379    Renderer: core::Renderer,
380{
381    fn size(&self) -> Size<Length> {
382        self.widget.size()
383    }
384
385    fn tag(&self) -> tree::Tag {
386        self.widget.tag()
387    }
388
389    fn state(&self) -> tree::State {
390        self.widget.state()
391    }
392
393    fn diff(&mut self, tree: &mut Tree) {
394        self.widget.diff(tree);
395    }
396
397    fn layout(&mut self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits) {
398        self.widget.layout(tree, renderer, limits);
399    }
400
401    fn operate(
402        &mut self,
403        tree: &mut Tree,
404        layout: Layout,
405        viewport: &Rectangle,
406        renderer: &Renderer,
407        operation: &mut dyn widget::Operation,
408    ) {
409        self.widget
410            .operate(tree, layout, viewport, renderer, operation);
411    }
412
413    fn update(
414        &mut self,
415        tree: &mut Tree,
416        event: &Event,
417        layout: Layout,
418        cursor: mouse::Cursor,
419        renderer: &Renderer,
420        shell: &mut Shell<'_, Message>,
421        viewport: &Rectangle,
422    ) {
423        self.widget
424            .update(tree, event, layout, cursor, renderer, shell, viewport);
425    }
426
427    fn draw(
428        &self,
429        tree: &Tree,
430        renderer: &mut Renderer,
431        theme: &Theme,
432        style: &core::renderer::Style,
433        layout: Layout,
434        cursor: mouse::Cursor,
435        viewport: &Rectangle,
436    ) {
437        fn explain_layout<Renderer: core::Renderer>(
438            tree: &Tree,
439            renderer: &mut Renderer,
440            color: Color,
441            layout: Layout,
442        ) {
443            renderer.fill_quad(
444                core::renderer::Quad {
445                    bounds: layout.bounds(),
446                    border: Border {
447                        color,
448                        width: 1.0,
449                        ..Border::default()
450                    },
451                    ..core::renderer::Quad::default()
452                },
453                Color::TRANSPARENT,
454            );
455
456            for (layout, tree) in layout.iter(&tree.children) {
457                explain_layout(tree, renderer, color, layout);
458            }
459        }
460
461        self.widget
462            .draw(tree, renderer, theme, style, layout, cursor, viewport);
463
464        renderer.with_layer(Rectangle::INFINITE, |renderer| {
465            explain_layout(tree, renderer, self.color, layout);
466        });
467    }
468
469    fn mouse_interaction(
470        &self,
471        tree: &Tree,
472        layout: Layout,
473        cursor: mouse::Cursor,
474        viewport: &Rectangle,
475        renderer: &Renderer,
476    ) -> mouse::Interaction {
477        self.widget
478            .mouse_interaction(tree, layout, cursor, viewport, renderer)
479    }
480
481    fn overlay<'b>(
482        &'b mut self,
483        tree: &'b mut Tree,
484        layout: Layout,
485        renderer: &Renderer,
486        viewport: &Rectangle,
487        translation: Vector,
488        window: Size,
489    ) -> Vec<core::overlay::Element<'b, Message, Theme, Renderer>> {
490        self.widget
491            .overlay(tree, layout, renderer, viewport, translation, window)
492    }
493}