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