diff options
| author | 2022-08-06 00:32:57 +0200 | |
|---|---|---|
| committer | 2022-08-06 00:32:57 +0200 | |
| commit | 1923dbf7f0769d55e5283f572fde0ce752e28b86 (patch) | |
| tree | 7be9b36f941f6e13ddc8884f715c04555b1e77db /pure | |
| parent | 1b4f38c71f6e05e26599ee75ea9c91dde96e71ae (diff) | |
| parent | c23ed7e4a0a2b62a0d7cabe6e35d7323eac543d2 (diff) | |
| download | iced-1923dbf7f0769d55e5283f572fde0ce752e28b86.tar.gz iced-1923dbf7f0769d55e5283f572fde0ce752e28b86.tar.bz2 iced-1923dbf7f0769d55e5283f572fde0ce752e28b86.zip  | |
Merge pull request #1393 from iced-rs/deprecate-stateful-widgets
Replace stateful widgets with the new `iced_pure` API
Diffstat (limited to 'pure')
29 files changed, 0 insertions, 5796 deletions
diff --git a/pure/Cargo.toml b/pure/Cargo.toml deleted file mode 100644 index b57e4c5a..00000000 --- a/pure/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "iced_pure" -version = "0.2.2" -edition = "2021" -description = "Pure widgets for Iced" -license = "MIT" -repository = "https://github.com/iced-rs/iced" -documentation = "https://docs.rs/iced_pure" -keywords = ["gui", "ui", "graphics", "interface", "widgets"] -categories = ["gui"] - -[dependencies] -iced_native = { version = "0.5", path = "../native" } -iced_style = { version = "0.4", path = "../style" } -num-traits = "0.2" diff --git a/pure/src/element.rs b/pure/src/element.rs deleted file mode 100644 index 35c68716..00000000 --- a/pure/src/element.rs +++ /dev/null @@ -1,346 +0,0 @@ -use crate::overlay; -use crate::widget::tree::{self, Tree}; -use crate::widget::Widget; - -use iced_native::event::{self, Event}; -use iced_native::layout::{self, Layout}; -use iced_native::mouse; -use iced_native::renderer; -use iced_native::{Clipboard, Length, Point, Rectangle, Shell}; - -use std::borrow::Borrow; - -/// A generic [`Widget`]. -/// -/// It is useful to build composable user interfaces that do not leak -/// implementation details in their __view logic__. -/// -/// If you have a [built-in widget], you should be able to use `Into<Element>` -/// to turn it into an [`Element`]. -/// -/// [built-in widget]: crate::widget -pub struct Element<'a, Message, Renderer> { -    widget: Box<dyn Widget<Message, Renderer> + 'a>, -} - -impl<'a, Message, Renderer> Element<'a, Message, Renderer> { -    /// Creates a new [`Element`] containing the given [`Widget`]. -    pub fn new(widget: impl Widget<Message, Renderer> + 'a) -> Self -    where -        Renderer: iced_native::Renderer, -    { -        Self { -            widget: Box::new(widget), -        } -    } - -    /// Returns a reference to the [`Widget`] of the [`Element`], -    pub fn as_widget(&self) -> &dyn Widget<Message, Renderer> { -        self.widget.as_ref() -    } - -    /// Returns a mutable reference to the [`Widget`] of the [`Element`], -    pub fn as_widget_mut(&mut self) -> &mut dyn Widget<Message, Renderer> { -        self.widget.as_mut() -    } - -    /// Applies a transformation to the produced message of the [`Element`]. -    /// -    /// This method is useful when you want to decouple different parts of your -    /// UI and make them __composable__. -    /// -    /// # Example -    /// Imagine we want to use [our counter](index.html#usage). But instead of -    /// showing a single counter, we want to display many of them. We can reuse -    /// the `Counter` type as it is! -    /// -    /// We use composition to model the __state__ of our new application: -    /// -    /// ``` -    /// # mod counter { -    /// #     pub struct Counter; -    /// # } -    /// use counter::Counter; -    /// -    /// struct ManyCounters { -    ///     counters: Vec<Counter>, -    /// } -    /// ``` -    /// -    /// We can store the state of multiple counters now. However, the -    /// __messages__ we implemented before describe the user interactions -    /// of a __single__ counter. Right now, we need to also identify which -    /// counter is receiving user interactions. Can we use composition again? -    /// Yes. -    /// -    /// ``` -    /// # mod counter { -    /// #     #[derive(Debug, Clone, Copy)] -    /// #     pub enum Message {} -    /// # } -    /// #[derive(Debug, Clone, Copy)] -    /// pub enum Message { -    ///     Counter(usize, counter::Message) -    /// } -    /// ``` -    /// -    /// We compose the previous __messages__ with the index of the counter -    /// producing them. Let's implement our __view logic__ now: -    /// -    /// ``` -    /// # mod counter { -    /// #     type Text = iced_pure::widget::Text<iced_native::renderer::Null>; -    /// # -    /// #     #[derive(Debug, Clone, Copy)] -    /// #     pub enum Message {} -    /// #     pub struct Counter; -    /// # -    /// #     impl Counter { -    /// #         pub fn view(&mut self) -> Text { -    /// #             Text::new("") -    /// #         } -    /// #     } -    /// # } -    /// # -    /// # mod iced_wgpu { -    /// #     pub use iced_native::renderer::Null as Renderer; -    /// # } -    /// # -    /// # use counter::Counter; -    /// # -    /// # struct ManyCounters { -    /// #     counters: Vec<Counter>, -    /// # } -    /// # -    /// # #[derive(Debug, Clone, Copy)] -    /// # pub enum Message { -    /// #    Counter(usize, counter::Message) -    /// # } -    /// use iced_pure::Element; -    /// use iced_pure::widget::Row; -    /// use iced_wgpu::Renderer; -    /// -    /// impl ManyCounters { -    ///     pub fn view(&mut self) -> Row<Message, Renderer> { -    ///         // We can quickly populate a `Row` by folding over our counters -    ///         self.counters.iter_mut().enumerate().fold( -    ///             Row::new().spacing(20), -    ///             |row, (index, counter)| { -    ///                 // We display the counter -    ///                 let element: Element<counter::Message, Renderer> = -    ///                     counter.view().into(); -    /// -    ///                 row.push( -    ///                     // Here we turn our `Element<counter::Message>` into -    ///                     // an `Element<Message>` by combining the `index` and the -    ///                     // message of the `element`. -    ///                     element.map(move |message| Message::Counter(index, message)) -    ///                 ) -    ///             } -    ///         ) -    ///     } -    /// } -    /// ``` -    /// -    /// Finally, our __update logic__ is pretty straightforward: simple -    /// delegation. -    /// -    /// ``` -    /// # mod counter { -    /// #     #[derive(Debug, Clone, Copy)] -    /// #     pub enum Message {} -    /// #     pub struct Counter; -    /// # -    /// #     impl Counter { -    /// #         pub fn update(&mut self, _message: Message) {} -    /// #     } -    /// # } -    /// # -    /// # use counter::Counter; -    /// # -    /// # struct ManyCounters { -    /// #     counters: Vec<Counter>, -    /// # } -    /// # -    /// # #[derive(Debug, Clone, Copy)] -    /// # pub enum Message { -    /// #    Counter(usize, counter::Message) -    /// # } -    /// impl ManyCounters { -    ///     pub fn update(&mut self, message: Message) { -    ///         match message { -    ///             Message::Counter(index, counter_msg) => { -    ///                 if let Some(counter) = self.counters.get_mut(index) { -    ///                     counter.update(counter_msg); -    ///                 } -    ///             } -    ///         } -    ///     } -    /// } -    /// ``` -    pub fn map<B>( -        self, -        f: impl Fn(Message) -> B + 'a, -    ) -> Element<'a, B, Renderer> -    where -        Message: 'a, -        Renderer: iced_native::Renderer + 'a, -        B: 'a, -    { -        Element::new(Map::new(self.widget, f)) -    } -} - -struct Map<'a, A, B, Renderer> { -    widget: Box<dyn Widget<A, Renderer> + 'a>, -    mapper: Box<dyn Fn(A) -> B + 'a>, -} - -impl<'a, A, B, Renderer> Map<'a, A, B, Renderer> { -    pub fn new<F>( -        widget: Box<dyn Widget<A, Renderer> + 'a>, -        mapper: F, -    ) -> Map<'a, A, B, Renderer> -    where -        F: 'a + Fn(A) -> B, -    { -        Map { -            widget, -            mapper: Box::new(mapper), -        } -    } -} - -impl<'a, A, B, Renderer> Widget<B, Renderer> for Map<'a, A, B, Renderer> -where -    Renderer: iced_native::Renderer + 'a, -    A: 'a, -    B: 'a, -{ -    fn tag(&self) -> tree::Tag { -        self.widget.tag() -    } - -    fn state(&self) -> tree::State { -        self.widget.state() -    } - -    fn children(&self) -> Vec<Tree> { -        self.widget.children() -    } - -    fn diff(&self, tree: &mut Tree) { -        self.widget.diff(tree) -    } - -    fn width(&self) -> Length { -        self.widget.width() -    } - -    fn height(&self) -> Length { -        self.widget.height() -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        self.widget.layout(renderer, limits) -    } - -    fn on_event( -        &mut self, -        tree: &mut Tree, -        event: Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, B>, -    ) -> event::Status { -        let mut local_messages = Vec::new(); -        let mut local_shell = Shell::new(&mut local_messages); - -        let status = self.widget.on_event( -            tree, -            event, -            layout, -            cursor_position, -            renderer, -            clipboard, -            &mut local_shell, -        ); - -        shell.merge(local_shell, &self.mapper); - -        status -    } - -    fn draw( -        &self, -        tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -    ) { -        self.widget.draw( -            tree, -            renderer, -            theme, -            style, -            layout, -            cursor_position, -            viewport, -        ) -    } - -    fn mouse_interaction( -        &self, -        tree: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -        renderer: &Renderer, -    ) -> mouse::Interaction { -        self.widget.mouse_interaction( -            tree, -            layout, -            cursor_position, -            viewport, -            renderer, -        ) -    } - -    fn overlay<'b>( -        &'b self, -        tree: &'b mut Tree, -        layout: Layout<'_>, -        renderer: &Renderer, -    ) -> Option<overlay::Element<'b, B, Renderer>> { -        let mapper = &self.mapper; - -        self.widget -            .overlay(tree, layout, renderer) -            .map(move |overlay| overlay.map(mapper)) -    } -} - -impl<'a, Message, Renderer> Borrow<dyn Widget<Message, Renderer> + 'a> -    for Element<'a, Message, Renderer> -{ -    fn borrow(&self) -> &(dyn Widget<Message, Renderer> + 'a) { -        self.widget.borrow() -    } -} - -impl<'a, Message, Renderer> Borrow<dyn Widget<Message, Renderer> + 'a> -    for &Element<'a, Message, Renderer> -{ -    fn borrow(&self) -> &(dyn Widget<Message, Renderer> + 'a) { -        self.widget.borrow() -    } -} diff --git a/pure/src/flex.rs b/pure/src/flex.rs deleted file mode 100644 index 3f65a28b..00000000 --- a/pure/src/flex.rs +++ /dev/null @@ -1,232 +0,0 @@ -//! Distribute elements using a flex-based layout. -// This code is heavily inspired by the [`druid`] codebase. -// -// [`druid`]: https://github.com/xi-editor/druid -// -// Copyright 2018 The xi-editor Authors, Héctor Ramón -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -//     http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -use crate::Element; - -use iced_native::layout::{Limits, Node}; -use iced_native::{Alignment, Padding, Point, Size}; - -/// The main axis of a flex layout. -#[derive(Debug)] -pub enum Axis { -    /// The horizontal axis -    Horizontal, - -    /// The vertical axis -    Vertical, -} - -impl Axis { -    fn main(&self, size: Size) -> f32 { -        match self { -            Axis::Horizontal => size.width, -            Axis::Vertical => size.height, -        } -    } - -    fn cross(&self, size: Size) -> f32 { -        match self { -            Axis::Horizontal => size.height, -            Axis::Vertical => size.width, -        } -    } - -    fn pack(&self, main: f32, cross: f32) -> (f32, f32) { -        match self { -            Axis::Horizontal => (main, cross), -            Axis::Vertical => (cross, main), -        } -    } -} - -/// Computes the flex layout with the given axis and limits, applying spacing, -/// padding and alignment to the items as needed. -/// -/// It returns a new layout [`Node`]. -pub fn resolve<Message, Renderer>( -    axis: Axis, -    renderer: &Renderer, -    limits: &Limits, -    padding: Padding, -    spacing: f32, -    align_items: Alignment, -    items: &[Element<'_, Message, Renderer>], -) -> Node -where -    Renderer: iced_native::Renderer, -{ -    let limits = limits.pad(padding); -    let total_spacing = spacing * items.len().saturating_sub(1) as f32; -    let max_cross = axis.cross(limits.max()); - -    let mut fill_sum = 0; -    let mut cross = axis.cross(limits.min()).max(axis.cross(limits.fill())); -    let mut available = axis.main(limits.max()) - total_spacing; - -    let mut nodes: Vec<Node> = Vec::with_capacity(items.len()); -    nodes.resize(items.len(), Node::default()); - -    if align_items == Alignment::Fill { -        let mut fill_cross = axis.cross(limits.min()); - -        items.iter().for_each(|child| { -            let cross_fill_factor = match axis { -                Axis::Horizontal => child.as_widget().height(), -                Axis::Vertical => child.as_widget().width(), -            } -            .fill_factor(); - -            if cross_fill_factor == 0 { -                let (max_width, max_height) = axis.pack(available, max_cross); - -                let child_limits = -                    Limits::new(Size::ZERO, Size::new(max_width, max_height)); - -                let layout = child.as_widget().layout(renderer, &child_limits); -                let size = layout.size(); - -                fill_cross = fill_cross.max(axis.cross(size)); -            } -        }); - -        cross = fill_cross; -    } - -    for (i, child) in items.iter().enumerate() { -        let fill_factor = match axis { -            Axis::Horizontal => child.as_widget().width(), -            Axis::Vertical => child.as_widget().height(), -        } -        .fill_factor(); - -        if fill_factor == 0 { -            let (min_width, min_height) = if align_items == Alignment::Fill { -                axis.pack(0.0, cross) -            } else { -                axis.pack(0.0, 0.0) -            }; - -            let (max_width, max_height) = if align_items == Alignment::Fill { -                axis.pack(available, cross) -            } else { -                axis.pack(available, max_cross) -            }; - -            let child_limits = Limits::new( -                Size::new(min_width, min_height), -                Size::new(max_width, max_height), -            ); - -            let layout = child.as_widget().layout(renderer, &child_limits); -            let size = layout.size(); - -            available -= axis.main(size); - -            if align_items != Alignment::Fill { -                cross = cross.max(axis.cross(size)); -            } - -            nodes[i] = layout; -        } else { -            fill_sum += fill_factor; -        } -    } - -    let remaining = available.max(0.0); - -    for (i, child) in items.iter().enumerate() { -        let fill_factor = match axis { -            Axis::Horizontal => child.as_widget().width(), -            Axis::Vertical => child.as_widget().height(), -        } -        .fill_factor(); - -        if fill_factor != 0 { -            let max_main = remaining * fill_factor as f32 / fill_sum as f32; -            let min_main = if max_main.is_infinite() { -                0.0 -            } else { -                max_main -            }; - -            let (min_width, min_height) = if align_items == Alignment::Fill { -                axis.pack(min_main, cross) -            } else { -                axis.pack(min_main, axis.cross(limits.min())) -            }; - -            let (max_width, max_height) = if align_items == Alignment::Fill { -                axis.pack(max_main, cross) -            } else { -                axis.pack(max_main, max_cross) -            }; - -            let child_limits = Limits::new( -                Size::new(min_width, min_height), -                Size::new(max_width, max_height), -            ); - -            let layout = child.as_widget().layout(renderer, &child_limits); - -            if align_items != Alignment::Fill { -                cross = cross.max(axis.cross(layout.size())); -            } - -            nodes[i] = layout; -        } -    } - -    let pad = axis.pack(padding.left as f32, padding.top as f32); -    let mut main = pad.0; - -    for (i, node) in nodes.iter_mut().enumerate() { -        if i > 0 { -            main += spacing; -        } - -        let (x, y) = axis.pack(main, pad.1); - -        node.move_to(Point::new(x, y)); - -        match axis { -            Axis::Horizontal => { -                node.align( -                    Alignment::Start, -                    align_items, -                    Size::new(0.0, cross), -                ); -            } -            Axis::Vertical => { -                node.align( -                    align_items, -                    Alignment::Start, -                    Size::new(cross, 0.0), -                ); -            } -        } - -        let size = node.size(); - -        main += axis.main(size); -    } - -    let (width, height) = axis.pack(main - pad.0, cross); -    let size = limits.resolve(Size::new(width, height)); - -    Node::with_children(size.pad(padding), nodes) -} diff --git a/pure/src/helpers.rs b/pure/src/helpers.rs deleted file mode 100644 index 88598f9b..00000000 --- a/pure/src/helpers.rs +++ /dev/null @@ -1,247 +0,0 @@ -//! Helper functions to create pure widgets. -use crate::widget; -use crate::Element; - -use iced_native::Length; -use std::borrow::Cow; -use std::ops::RangeInclusive; - -/// Creates a new [`Container`] with the provided content. -/// -/// [`Container`]: widget::Container -pub fn container<'a, Message, Renderer>( -    content: impl Into<Element<'a, Message, Renderer>>, -) -> widget::Container<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: widget::container::StyleSheet, -{ -    widget::Container::new(content) -} - -/// Creates a new [`Column`]. -/// -/// [`Column`]: widget::Column -pub fn column<'a, Message, Renderer>() -> widget::Column<'a, Message, Renderer> -{ -    widget::Column::new() -} - -/// Creates a new [`Row`]. -/// -/// [`Row`]: widget::Row -pub fn row<'a, Message, Renderer>() -> widget::Row<'a, Message, Renderer> { -    widget::Row::new() -} - -/// Creates a new [`Scrollable`] with the provided content. -/// -/// [`Scrollable`]: widget::Scrollable -pub fn scrollable<'a, Message, Renderer>( -    content: impl Into<Element<'a, Message, Renderer>>, -) -> widget::Scrollable<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: widget::scrollable::StyleSheet, -{ -    widget::Scrollable::new(content) -} - -/// Creates a new [`Button`] with the provided content. -/// -/// [`Button`]: widget::Button -pub fn button<'a, Message, Renderer>( -    content: impl Into<Element<'a, Message, Renderer>>, -) -> widget::Button<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: widget::button::StyleSheet, -{ -    widget::Button::new(content) -} - -/// Creates a new [`Tooltip`] with the provided content, tooltip text, and [`tooltip::Position`]. -/// -/// [`Tooltip`]: widget::Tooltip -/// [`tooltip::Position`]: widget::tooltip::Position -pub fn tooltip<'a, Message, Renderer>( -    content: impl Into<Element<'a, Message, Renderer>>, -    tooltip: impl ToString, -    position: widget::tooltip::Position, -) -> widget::Tooltip<'a, Message, Renderer> -where -    Renderer: iced_native::text::Renderer, -    Renderer::Theme: widget::container::StyleSheet + widget::text::StyleSheet, -{ -    widget::Tooltip::new(content, tooltip, position) -} - -/// Creates a new [`Text`] widget with the provided content. -/// -/// [`Text`]: widget::Text -pub fn text<Renderer>(text: impl Into<String>) -> widget::Text<Renderer> -where -    Renderer: iced_native::text::Renderer, -    Renderer::Theme: widget::text::StyleSheet, -{ -    widget::Text::new(text) -} - -/// Creates a new [`Checkbox`]. -/// -/// [`Checkbox`]: widget::Checkbox -pub fn checkbox<'a, Message, Renderer>( -    label: impl Into<String>, -    is_checked: bool, -    f: impl Fn(bool) -> Message + 'a, -) -> widget::Checkbox<'a, Message, Renderer> -where -    Renderer: iced_native::text::Renderer, -    Renderer::Theme: widget::checkbox::StyleSheet + widget::text::StyleSheet, -{ -    widget::Checkbox::new(is_checked, label, f) -} - -/// Creates a new [`Radio`]. -/// -/// [`Radio`]: widget::Radio -pub fn radio<Message, Renderer, V>( -    label: impl Into<String>, -    value: V, -    selected: Option<V>, -    on_click: impl FnOnce(V) -> Message, -) -> widget::Radio<Message, Renderer> -where -    Message: Clone, -    Renderer: iced_native::text::Renderer, -    Renderer::Theme: widget::radio::StyleSheet, -    V: Copy + Eq, -{ -    widget::Radio::new(value, label, selected, on_click) -} - -/// Creates a new [`Toggler`]. -/// -/// [`Toggler`]: widget::Toggler -pub fn toggler<'a, Message, Renderer>( -    label: impl Into<Option<String>>, -    is_checked: bool, -    f: impl Fn(bool) -> Message + 'a, -) -> widget::Toggler<'a, Message, Renderer> -where -    Renderer: iced_native::text::Renderer, -    Renderer::Theme: widget::toggler::StyleSheet, -{ -    widget::Toggler::new(is_checked, label, f) -} - -/// Creates a new [`TextInput`]. -/// -/// [`TextInput`]: widget::TextInput -pub fn text_input<'a, Message, Renderer>( -    placeholder: &str, -    value: &str, -    on_change: impl Fn(String) -> Message + 'a, -) -> widget::TextInput<'a, Message, Renderer> -where -    Message: Clone, -    Renderer: iced_native::text::Renderer, -    Renderer::Theme: widget::text_input::StyleSheet, -{ -    widget::TextInput::new(placeholder, value, on_change) -} - -/// Creates a new [`Slider`]. -/// -/// [`Slider`]: widget::Slider -pub fn slider<'a, T, Message, Renderer>( -    range: std::ops::RangeInclusive<T>, -    value: T, -    on_change: impl Fn(T) -> Message + 'a, -) -> widget::Slider<'a, T, Message, Renderer> -where -    T: Copy + From<u8> + std::cmp::PartialOrd, -    Message: Clone, -    Renderer: iced_native::Renderer, -    Renderer::Theme: widget::slider::StyleSheet, -{ -    widget::Slider::new(range, value, on_change) -} - -/// Creates a new [`PickList`]. -/// -/// [`PickList`]: widget::PickList -pub fn pick_list<'a, Message, Renderer, T>( -    options: impl Into<Cow<'a, [T]>>, -    selected: Option<T>, -    on_selected: impl Fn(T) -> Message + 'a, -) -> widget::PickList<'a, T, Message, Renderer> -where -    T: ToString + Eq + 'static, -    [T]: ToOwned<Owned = Vec<T>>, -    Renderer: iced_native::text::Renderer, -    Renderer::Theme: widget::pick_list::StyleSheet, -{ -    widget::PickList::new(options, selected, on_selected) -} - -/// Creates a new [`Image`]. -/// -/// [`Image`]: widget::Image -pub fn image<Handle>(handle: impl Into<Handle>) -> widget::Image<Handle> { -    widget::Image::new(handle.into()) -} - -/// Creates a new horizontal [`Space`] with the given [`Length`]. -/// -/// [`Space`]: widget::Space -pub fn horizontal_space(width: Length) -> widget::Space { -    widget::Space::with_width(width) -} - -/// Creates a new vertical [`Space`] with the given [`Length`]. -/// -/// [`Space`]: widget::Space -pub fn vertical_space(height: Length) -> widget::Space { -    widget::Space::with_height(height) -} - -/// Creates a horizontal [`Rule`] with the given height. -/// -/// [`Rule`]: widget::Rule -pub fn horizontal_rule<Renderer>(height: u16) -> widget::Rule<Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: widget::rule::StyleSheet, -{ -    widget::Rule::horizontal(height) -} - -/// Creates a vertical [`Rule`] with the given width. -/// -/// [`Rule`]: widget::Rule -pub fn vertical_rule<Renderer>(width: u16) -> widget::Rule<Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: widget::rule::StyleSheet, -{ -    widget::Rule::vertical(width) -} - -/// Creates a new [`ProgressBar`]. -/// -/// It expects: -///   * an inclusive range of possible values, and -///   * the current value of the [`ProgressBar`]. -/// -/// [`ProgressBar`]: widget::ProgressBar -pub fn progress_bar<Renderer>( -    range: RangeInclusive<f32>, -    value: f32, -) -> widget::ProgressBar<Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: widget::progress_bar::StyleSheet, -{ -    widget::ProgressBar::new(range, value) -} diff --git a/pure/src/lib.rs b/pure/src/lib.rs deleted file mode 100644 index 9c5f3bc8..00000000 --- a/pure/src/lib.rs +++ /dev/null @@ -1,292 +0,0 @@ -//! Stateless, pure widgets for iced. -//! -//! # The Elm Architecture, purity, and continuity -//! As you may know, applications made with `iced` use [The Elm Architecture]. -//! -//! In a nutshell, this architecture defines the initial state of the application, a way to `view` it, and a way to `update` it after a user interaction. The `update` logic is called after a meaningful user interaction, which in turn updates the state of the application. Then, the `view` logic is executed to redisplay the application. -//! -//! Since `view` logic is only run after an `update`, all of the mutations to the application state must only happen in the `update` logic. If the application state changes anywhere else, the `view` logic will not be rerun and, therefore, the previously generated `view` may stay outdated. -//! -//! However, the `Application` trait in `iced` defines `view` as: -//! -//! ```ignore -//! pub trait Application { -//!     fn view(&mut self) -> Element<Self::Message>; -//! } -//! ``` -//! -//! As a consequence, the application state can be mutated in `view` logic. The `view` logic in `iced` is __impure__. -//! -//! This impurity is necessary because `iced` puts the burden of widget __continuity__ on its users. In other words, it's up to you to provide `iced` with the internal state of each widget every time `view` is called. -//! -//! If we take a look at the classic `counter` example: -//! -//! ```ignore -//! struct Counter { -//!     value: i32, -//!     increment_button: button::State, -//!     decrement_button: button::State, -//! } -//! -//! // ... -//! -//! impl Counter { -//!     pub fn view(&mut self) -> Column<Message> { -//!         Column::new() -//!             .push( -//!                 Button::new(&mut self.increment_button, Text::new("+")) -//!                     .on_press(Message::IncrementPressed), -//!             ) -//!             .push(Text::new(self.value.to_string()).size(50)) -//!             .push( -//!                 Button::new(&mut self.decrement_button, Text::new("-")) -//!                     .on_press(Message::DecrementPressed), -//!             ) -//!     } -//! } -//! ``` -//! -//! We can see how we need to keep track of the `button::State` of each `Button` in our `Counter` state and provide a mutable reference to the widgets in our `view` logic. The widgets produced by `view` are __stateful__. -//! -//! While this approach forces users to keep track of widget state and causes impurity, I originally chose it because it allows `iced` to directly consume the widget tree produced by `view`. Since there is no internal state decoupled from `view` maintained by the runtime, `iced` does not need to compare (e.g. reconciliate) widget trees in order to ensure continuity. -//! -//! # Stateless widgets -//! As the library matures, the need for some kind of persistent widget data (see #553) between `view` calls becomes more apparent (e.g. incremental rendering, animations, accessibility, etc.). -//! -//! If we are going to end up having persistent widget data anyways... There is no reason to have impure, stateful widgets anymore! -//! -//! And so I started exploring and ended up creating a new subcrate called `iced_pure`, which introduces a completely stateless implementation for every widget in `iced`. -//! -//! With the help of this crate, we can now write a pure `counter` example: -//! -//! ```ignore -//! struct Counter { -//!     value: i32, -//! } -//! -//! // ... -//! -//! impl Counter { -//!     fn view(&self) -> Column<Message> { -//!         Column::new() -//!             .push(Button::new("Increment").on_press(Message::IncrementPressed)) -//!             .push(Text::new(self.value.to_string()).size(50)) -//!             .push(Button::new("Decrement").on_press(Message::DecrementPressed)) -//!     } -//! } -//! ``` -//! -//! Notice how we no longer need to keep track of the `button::State`! The widgets in `iced_pure` do not take any mutable application state in `view`. They are __stateless__ widgets. As a consequence, we do not need mutable access to `self` in `view` anymore. `view` becomes __pure__. -//! -//! [The Elm Architecture]: https://guide.elm-lang.org/architecture/ -#![doc( -    html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg" -)] -#![deny( -    missing_docs, -    unused_results, -    clippy::extra_unused_lifetimes, -    clippy::from_over_into, -    clippy::needless_borrow, -    clippy::new_without_default, -    clippy::useless_conversion -)] -#![forbid(rust_2018_idioms, unsafe_code)] -#![allow(clippy::inherent_to_string, clippy::type_complexity)] -#![cfg_attr(docsrs, feature(doc_cfg))] - -pub mod flex; -pub mod helpers; -pub mod overlay; -pub mod widget; - -mod element; - -pub use element::Element; -pub use helpers::*; -pub use widget::Widget; - -use iced_native::event::{self, Event}; -use iced_native::layout::{self, Layout}; -use iced_native::mouse; -use iced_native::renderer; -use iced_native::{Clipboard, Length, Point, Rectangle, Shell}; - -/// A bridge between impure and pure widgets. -/// -/// If you already have an existing `iced` application, you do not need to switch completely to the new traits in order to benefit from the `pure` module. Instead, you can leverage the new `Pure` widget to include `pure` widgets in your impure `Application`. -/// -/// For instance, let's say we want to use our pure `Counter` in an impure application: -/// -/// ```ignore -/// use iced_pure::{self, Pure}; -/// -/// struct Impure { -///     state: pure::State, -///     counter: Counter, -/// } -/// -/// impl Sandbox for Impure { -///     // ... -/// -///     pub fn view(&mut self) -> Element<Self::Message> { -///         Pure::new(&mut self.state, self.counter.view()).into() -///     } -/// } -/// ``` -/// -/// [`Pure`] acts as a bridge between pure and impure widgets. It is completely opt-in and can be used to slowly migrate your application to the new architecture. -/// -/// The purification of your application may trigger a bunch of important refactors, since it's far easier to keep your data decoupled from the GUI state with stateless widgets. For this reason, I recommend starting small in the most nested views of your application and slowly expand the purity upwards. -pub struct Pure<'a, Message, Renderer> { -    state: &'a mut State, -    element: Element<'a, Message, Renderer>, -} - -impl<'a, Message, Renderer> Pure<'a, Message, Renderer> -where -    Message: 'a, -    Renderer: iced_native::Renderer + 'a, -{ -    /// Creates a new [`Pure`] widget with the given [`State`] and impure [`Element`]. -    pub fn new( -        state: &'a mut State, -        content: impl Into<Element<'a, Message, Renderer>>, -    ) -> Self { -        let element = content.into(); -        state.diff(&element); - -        Self { state, element } -    } -} - -/// The internal state of a [`Pure`] widget. -pub struct State { -    state_tree: widget::Tree, -} - -impl Default for State { -    fn default() -> Self { -        Self::new() -    } -} - -impl State { -    /// Creates a new [`State`] for a [`Pure`] widget. -    pub fn new() -> Self { -        Self { -            state_tree: widget::Tree::empty(), -        } -    } - -    fn diff<Message, Renderer>( -        &mut self, -        new_element: &Element<'_, Message, Renderer>, -    ) where -        Renderer: iced_native::Renderer, -    { -        self.state_tree.diff(new_element); -    } -} - -impl<'a, Message, Renderer> iced_native::Widget<Message, Renderer> -    for Pure<'a, Message, Renderer> -where -    Message: 'a, -    Renderer: iced_native::Renderer + 'a, -{ -    fn width(&self) -> Length { -        self.element.as_widget().width() -    } - -    fn height(&self) -> Length { -        self.element.as_widget().height() -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        self.element.as_widget().layout(renderer, limits) -    } - -    fn on_event( -        &mut self, -        event: Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        self.element.as_widget_mut().on_event( -            &mut self.state.state_tree, -            event, -            layout, -            cursor_position, -            renderer, -            clipboard, -            shell, -        ) -    } - -    fn draw( -        &self, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -    ) { -        self.element.as_widget().draw( -            &self.state.state_tree, -            renderer, -            theme, -            style, -            layout, -            cursor_position, -            viewport, -        ) -    } - -    fn mouse_interaction( -        &self, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -        renderer: &Renderer, -    ) -> mouse::Interaction { -        self.element.as_widget().mouse_interaction( -            &self.state.state_tree, -            layout, -            cursor_position, -            viewport, -            renderer, -        ) -    } - -    fn overlay( -        &mut self, -        layout: Layout<'_>, -        renderer: &Renderer, -    ) -> Option<overlay::Element<'_, Message, Renderer>> { -        self.element.as_widget_mut().overlay( -            &mut self.state.state_tree, -            layout, -            renderer, -        ) -    } -} - -impl<'a, Message, Renderer> From<Pure<'a, Message, Renderer>> -    for iced_native::Element<'a, Message, Renderer> -where -    Message: 'a, -    Renderer: iced_native::Renderer + 'a, -{ -    fn from(pure: Pure<'a, Message, Renderer>) -> Self { -        Self::new(pure) -    } -} diff --git a/pure/src/overlay.rs b/pure/src/overlay.rs deleted file mode 100644 index b82d8a67..00000000 --- a/pure/src/overlay.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Display interactive elements on top of other widgets. -use crate::widget::Tree; - -use iced_native::Layout; - -pub use iced_native::overlay::*; - -/// Obtains the first overlay [`Element`] found in the given children. -/// -/// This method will generally only be used by advanced users that are -/// implementing the [`Widget`](crate::Widget) trait. -pub fn from_children<'a, Message, Renderer>( -    children: &'a [crate::Element<'_, Message, Renderer>], -    tree: &'a mut Tree, -    layout: Layout<'_>, -    renderer: &Renderer, -) -> Option<Element<'a, Message, Renderer>> -where -    Renderer: iced_native::Renderer, -{ -    children -        .iter() -        .zip(&mut tree.children) -        .zip(layout.children()) -        .filter_map(|((child, state), layout)| { -            child.as_widget().overlay(state, layout, renderer) -        }) -        .next() -} diff --git a/pure/src/widget.rs b/pure/src/widget.rs deleted file mode 100644 index cd825ad8..00000000 --- a/pure/src/widget.rs +++ /dev/null @@ -1,149 +0,0 @@ -//! Use the built-in widgets or create your own. -pub mod button; -pub mod checkbox; -pub mod container; -pub mod image; -pub mod pane_grid; -pub mod pick_list; -pub mod progress_bar; -pub mod radio; -pub mod rule; -pub mod scrollable; -pub mod slider; -pub mod svg; -pub mod text; -pub mod text_input; -pub mod toggler; -pub mod tooltip; -pub mod tree; - -mod column; -mod row; -mod space; - -pub use button::Button; -pub use checkbox::Checkbox; -pub use column::Column; -pub use container::Container; -pub use image::Image; -pub use pane_grid::PaneGrid; -pub use pick_list::PickList; -pub use progress_bar::ProgressBar; -pub use radio::Radio; -pub use row::Row; -pub use rule::Rule; -pub use scrollable::Scrollable; -pub use slider::Slider; -pub use space::Space; -pub use svg::Svg; -pub use text::Text; -pub use text_input::TextInput; -pub use toggler::Toggler; -pub use tooltip::{Position, Tooltip}; -pub use tree::Tree; - -use iced_native::event::{self, Event}; -use iced_native::layout::{self, Layout}; -use iced_native::mouse; -use iced_native::overlay; -use iced_native::renderer; -use iced_native::{Clipboard, Length, Point, Rectangle, Shell}; - -/// A component that displays information and allows interaction. -/// -/// If you want to build your own widgets, you will need to implement this -/// trait. -pub trait Widget<Message, Renderer> -where -    Renderer: iced_native::Renderer, -{ -    /// Returns the width of the [`Widget`]. -    fn width(&self) -> Length; - -    /// Returns the height of the [`Widget`]. -    fn height(&self) -> Length; - -    /// Returns the [`layout::Node`] of the [`Widget`]. -    /// -    /// This [`layout::Node`] is used by the runtime to compute the [`Layout`] of the -    /// user interface. -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node; - -    /// Draws the [`Widget`] using the associated `Renderer`. -    fn draw( -        &self, -        state: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -    ); - -    /// Returns the [`Tag`] of the [`Widget`]. -    /// -    /// [`Tag`]: tree::Tag -    fn tag(&self) -> tree::Tag { -        tree::Tag::stateless() -    } - -    /// Returns the [`State`] of the [`Widget`]. -    /// -    /// [`State`]: tree::State -    fn state(&self) -> tree::State { -        tree::State::None -    } - -    /// Returns the state [`Tree`] of the children of the [`Widget`]. -    fn children(&self) -> Vec<Tree> { -        Vec::new() -    } - -    /// Reconciliates the [`Widget`] with the provided [`Tree`]. -    fn diff(&self, _tree: &mut Tree) {} - -    /// Processes a runtime [`Event`]. -    /// -    /// By default, it does nothing. -    fn on_event( -        &mut self, -        _state: &mut Tree, -        _event: Event, -        _layout: Layout<'_>, -        _cursor_position: Point, -        _renderer: &Renderer, -        _clipboard: &mut dyn Clipboard, -        _shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        event::Status::Ignored -    } - -    /// Returns the current [`mouse::Interaction`] of the [`Widget`]. -    /// -    /// By default, it returns [`mouse::Interaction::Idle`]. -    fn mouse_interaction( -        &self, -        _state: &Tree, -        _layout: Layout<'_>, -        _cursor_position: Point, -        _viewport: &Rectangle, -        _renderer: &Renderer, -    ) -> mouse::Interaction { -        mouse::Interaction::Idle -    } - -    /// Returns the overlay of the [`Widget`], if there is any. -    fn overlay<'a>( -        &'a self, -        _state: &'a mut Tree, -        _layout: Layout<'_>, -        _renderer: &Renderer, -    ) -> Option<overlay::Element<'a, Message, Renderer>> { -        None -    } -} diff --git a/pure/src/widget/button.rs b/pure/src/widget/button.rs deleted file mode 100644 index eb174e57..00000000 --- a/pure/src/widget/button.rs +++ /dev/null @@ -1,274 +0,0 @@ -//! Allow your users to perform actions by pressing a button. -use crate::overlay; -use crate::widget::tree::{self, Tree}; -use crate::{Element, Widget}; - -use iced_native::event::{self, Event}; -use iced_native::layout; -use iced_native::mouse; -use iced_native::renderer; -use iced_native::widget::button; -use iced_native::{ -    Clipboard, Layout, Length, Padding, Point, Rectangle, Shell, -}; - -pub use iced_style::button::{Appearance, StyleSheet}; - -use button::State; - -/// A generic widget that produces a message when pressed. -/// -/// ``` -/// # type Button<'a, Message> = -/// #     iced_pure::widget::Button<'a, Message, iced_native::renderer::Null>; -/// # -/// #[derive(Clone)] -/// enum Message { -///     ButtonPressed, -/// } -/// -/// let button = Button::new("Press me!").on_press(Message::ButtonPressed); -/// ``` -/// -/// If a [`Button::on_press`] handler is not set, the resulting [`Button`] will -/// be disabled: -/// -/// ``` -/// # type Button<'a, Message> = -/// #     iced_pure::widget::Button<'a, Message, iced_native::renderer::Null>; -/// # -/// #[derive(Clone)] -/// enum Message { -///     ButtonPressed, -/// } -/// -/// fn disabled_button<'a>() -> Button<'a, Message> { -///     Button::new("I'm disabled!") -/// } -/// -/// fn enabled_button<'a>() -> Button<'a, Message> { -///     disabled_button().on_press(Message::ButtonPressed) -/// } -/// ``` -pub struct Button<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: StyleSheet, -{ -    content: Element<'a, Message, Renderer>, -    on_press: Option<Message>, -    width: Length, -    height: Length, -    padding: Padding, -    style: <Renderer::Theme as StyleSheet>::Style, -} - -impl<'a, Message, Renderer> Button<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: StyleSheet, -{ -    /// Creates a new [`Button`] with the given content. -    pub fn new(content: impl Into<Element<'a, Message, Renderer>>) -> Self { -        Button { -            content: content.into(), -            on_press: None, -            width: Length::Shrink, -            height: Length::Shrink, -            padding: Padding::new(5), -            style: <Renderer::Theme as StyleSheet>::Style::default(), -        } -    } - -    /// Sets the width of the [`Button`]. -    pub fn width(mut self, width: Length) -> Self { -        self.width = width; -        self -    } - -    /// Sets the height of the [`Button`]. -    pub fn height(mut self, height: Length) -> Self { -        self.height = height; -        self -    } - -    /// Sets the [`Padding`] of the [`Button`]. -    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self { -        self.padding = padding.into(); -        self -    } - -    /// Sets the message that will be produced when the [`Button`] is pressed. -    /// -    /// Unless `on_press` is called, the [`Button`] will be disabled. -    pub fn on_press(mut self, msg: Message) -> Self { -        self.on_press = Some(msg); -        self -    } - -    /// Sets the style variant of this [`Button`]. -    pub fn style( -        mut self, -        style: <Renderer::Theme as StyleSheet>::Style, -    ) -> Self { -        self.style = style; -        self -    } -} - -impl<'a, Message, Renderer> Widget<Message, Renderer> -    for Button<'a, Message, Renderer> -where -    Message: 'a + Clone, -    Renderer: 'a + iced_native::Renderer, -    Renderer::Theme: StyleSheet, -{ -    fn tag(&self) -> tree::Tag { -        tree::Tag::of::<State>() -    } - -    fn state(&self) -> tree::State { -        tree::State::new(State::new()) -    } - -    fn children(&self) -> Vec<Tree> { -        vec![Tree::new(&self.content)] -    } - -    fn diff(&self, tree: &mut Tree) { -        tree.diff_children(std::slice::from_ref(&self.content)) -    } - -    fn width(&self) -> Length { -        self.width -    } - -    fn height(&self) -> Length { -        self.height -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        button::layout( -            renderer, -            limits, -            self.width, -            self.height, -            self.padding, -            |renderer, limits| { -                self.content.as_widget().layout(renderer, limits) -            }, -        ) -    } - -    fn on_event( -        &mut self, -        tree: &mut Tree, -        event: Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        if let event::Status::Captured = self.content.as_widget_mut().on_event( -            &mut tree.children[0], -            event.clone(), -            layout.children().next().unwrap(), -            cursor_position, -            renderer, -            clipboard, -            shell, -        ) { -            return event::Status::Captured; -        } - -        button::update( -            event, -            layout, -            cursor_position, -            shell, -            &self.on_press, -            || tree.state.downcast_mut::<State>(), -        ) -    } - -    fn draw( -        &self, -        tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        _style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        _viewport: &Rectangle, -    ) { -        let bounds = layout.bounds(); -        let content_layout = layout.children().next().unwrap(); - -        let styling = button::draw( -            renderer, -            bounds, -            cursor_position, -            self.on_press.is_some(), -            theme, -            self.style, -            || tree.state.downcast_ref::<State>(), -        ); - -        self.content.as_widget().draw( -            &tree.children[0], -            renderer, -            theme, -            &renderer::Style { -                text_color: styling.text_color, -            }, -            content_layout, -            cursor_position, -            &bounds, -        ); -    } - -    fn mouse_interaction( -        &self, -        _tree: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        _viewport: &Rectangle, -        _renderer: &Renderer, -    ) -> mouse::Interaction { -        button::mouse_interaction( -            layout, -            cursor_position, -            self.on_press.is_some(), -        ) -    } - -    fn overlay<'b>( -        &'b self, -        tree: &'b mut Tree, -        layout: Layout<'_>, -        renderer: &Renderer, -    ) -> Option<overlay::Element<'b, Message, Renderer>> { -        self.content.as_widget().overlay( -            &mut tree.children[0], -            layout.children().next().unwrap(), -            renderer, -        ) -    } -} - -impl<'a, Message, Renderer> From<Button<'a, Message, Renderer>> -    for Element<'a, Message, Renderer> -where -    Message: Clone + 'a, -    Renderer: iced_native::Renderer + 'a, -    Renderer::Theme: StyleSheet, -{ -    fn from(button: Button<'a, Message, Renderer>) -> Self { -        Self::new(button) -    } -} diff --git a/pure/src/widget/checkbox.rs b/pure/src/widget/checkbox.rs deleted file mode 100644 index e0f9b764..00000000 --- a/pure/src/widget/checkbox.rs +++ /dev/null @@ -1,109 +0,0 @@ -//! Show toggle controls using checkboxes. -use crate::widget::Tree; -use crate::{Element, Widget}; - -use iced_native::event::{self, Event}; -use iced_native::layout::{self, Layout}; -use iced_native::mouse; -use iced_native::renderer; -use iced_native::text; -use iced_native::widget; -use iced_native::{Clipboard, Length, Point, Rectangle, Shell}; - -pub use iced_native::widget::checkbox::{Appearance, Checkbox, StyleSheet}; - -impl<'a, Message, Renderer> Widget<Message, Renderer> -    for Checkbox<'a, Message, Renderer> -where -    Renderer: text::Renderer, -    Renderer::Theme: StyleSheet + widget::text::StyleSheet, -{ -    fn width(&self) -> Length { -        <Self as iced_native::Widget<Message, Renderer>>::width(self) -    } - -    fn height(&self) -> Length { -        <Self as iced_native::Widget<Message, Renderer>>::height(self) -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        <Self as iced_native::Widget<Message, Renderer>>::layout( -            self, renderer, limits, -        ) -    } - -    fn on_event( -        &mut self, -        _state: &mut Tree, -        event: Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        <Self as iced_native::Widget<Message, Renderer>>::on_event( -            self, -            event, -            layout, -            cursor_position, -            renderer, -            clipboard, -            shell, -        ) -    } - -    fn draw( -        &self, -        _tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -    ) { -        <Self as iced_native::Widget<Message, Renderer>>::draw( -            self, -            renderer, -            theme, -            style, -            layout, -            cursor_position, -            viewport, -        ) -    } - -    fn mouse_interaction( -        &self, -        _state: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -        renderer: &Renderer, -    ) -> mouse::Interaction { -        <Self as iced_native::Widget<Message, Renderer>>::mouse_interaction( -            self, -            layout, -            cursor_position, -            viewport, -            renderer, -        ) -    } -} - -impl<'a, Message, Renderer> From<Checkbox<'a, Message, Renderer>> -    for Element<'a, Message, Renderer> -where -    Message: 'a, -    Renderer: text::Renderer + 'a, -    Renderer::Theme: StyleSheet + widget::text::StyleSheet, -{ -    fn from(checkbox: Checkbox<'a, Message, Renderer>) -> Self { -        Self::new(checkbox) -    } -} diff --git a/pure/src/widget/column.rs b/pure/src/widget/column.rs deleted file mode 100644 index 027eff0a..00000000 --- a/pure/src/widget/column.rs +++ /dev/null @@ -1,246 +0,0 @@ -use crate::flex; -use crate::overlay; -use crate::widget::Tree; -use crate::{Element, Widget}; - -use iced_native::event::{self, Event}; -use iced_native::layout::{self, Layout}; -use iced_native::mouse; -use iced_native::renderer; -use iced_native::{ -    Alignment, Clipboard, Length, Padding, Point, Rectangle, Shell, -}; - -use std::u32; - -/// A container that distributes its contents vertically. -pub struct Column<'a, Message, Renderer> { -    spacing: u16, -    padding: Padding, -    width: Length, -    height: Length, -    max_width: u32, -    align_items: Alignment, -    children: Vec<Element<'a, Message, Renderer>>, -} - -impl<'a, Message, Renderer> Column<'a, Message, Renderer> { -    /// Creates an empty [`Column`]. -    pub fn new() -> Self { -        Self::with_children(Vec::new()) -    } - -    /// Creates a [`Column`] with the given elements. -    pub fn with_children( -        children: Vec<Element<'a, Message, Renderer>>, -    ) -> Self { -        Column { -            spacing: 0, -            padding: Padding::ZERO, -            width: Length::Shrink, -            height: Length::Shrink, -            max_width: u32::MAX, -            align_items: Alignment::Start, -            children, -        } -    } - -    /// Sets the vertical spacing _between_ elements. -    /// -    /// Custom margins per element do not exist in iced. You should use this -    /// method instead! While less flexible, it helps you keep spacing between -    /// elements consistent. -    pub fn spacing(mut self, units: u16) -> Self { -        self.spacing = units; -        self -    } - -    /// Sets the [`Padding`] of the [`Column`]. -    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self { -        self.padding = padding.into(); -        self -    } - -    /// Sets the width of the [`Column`]. -    pub fn width(mut self, width: Length) -> Self { -        self.width = width; -        self -    } - -    /// Sets the height of the [`Column`]. -    pub fn height(mut self, height: Length) -> Self { -        self.height = height; -        self -    } - -    /// Sets the maximum width of the [`Column`]. -    pub fn max_width(mut self, max_width: u32) -> Self { -        self.max_width = max_width; -        self -    } - -    /// Sets the horizontal alignment of the contents of the [`Column`] . -    pub fn align_items(mut self, align: Alignment) -> Self { -        self.align_items = align; -        self -    } - -    /// Adds an element to the [`Column`]. -    pub fn push( -        mut self, -        child: impl Into<Element<'a, Message, Renderer>>, -    ) -> Self { -        self.children.push(child.into()); -        self -    } -} - -impl<'a, Message, Renderer> Default for Column<'a, Message, Renderer> { -    fn default() -> Self { -        Self::new() -    } -} - -impl<'a, Message, Renderer> Widget<Message, Renderer> -    for Column<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -{ -    fn children(&self) -> Vec<Tree> { -        self.children.iter().map(Tree::new).collect() -    } - -    fn diff(&self, tree: &mut Tree) { -        tree.diff_children(&self.children); -    } - -    fn width(&self) -> Length { -        self.width -    } - -    fn height(&self) -> Length { -        self.height -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        let limits = limits -            .max_width(self.max_width) -            .width(self.width) -            .height(self.height); - -        flex::resolve( -            flex::Axis::Vertical, -            renderer, -            &limits, -            self.padding, -            self.spacing as f32, -            self.align_items, -            &self.children, -        ) -    } - -    fn on_event( -        &mut self, -        tree: &mut Tree, -        event: Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        self.children -            .iter_mut() -            .zip(&mut tree.children) -            .zip(layout.children()) -            .map(|((child, state), layout)| { -                child.as_widget_mut().on_event( -                    state, -                    event.clone(), -                    layout, -                    cursor_position, -                    renderer, -                    clipboard, -                    shell, -                ) -            }) -            .fold(event::Status::Ignored, event::Status::merge) -    } - -    fn mouse_interaction( -        &self, -        tree: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -        renderer: &Renderer, -    ) -> mouse::Interaction { -        self.children -            .iter() -            .zip(&tree.children) -            .zip(layout.children()) -            .map(|((child, state), layout)| { -                child.as_widget().mouse_interaction( -                    state, -                    layout, -                    cursor_position, -                    viewport, -                    renderer, -                ) -            }) -            .max() -            .unwrap_or_default() -    } - -    fn draw( -        &self, -        tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -    ) { -        for ((child, state), layout) in self -            .children -            .iter() -            .zip(&tree.children) -            .zip(layout.children()) -        { -            child.as_widget().draw( -                state, -                renderer, -                theme, -                style, -                layout, -                cursor_position, -                viewport, -            ); -        } -    } - -    fn overlay<'b>( -        &'b self, -        tree: &'b mut Tree, -        layout: Layout<'_>, -        renderer: &Renderer, -    ) -> Option<overlay::Element<'b, Message, Renderer>> { -        overlay::from_children(&self.children, tree, layout, renderer) -    } -} - -impl<'a, Message, Renderer> From<Column<'a, Message, Renderer>> -    for Element<'a, Message, Renderer> -where -    Message: 'a, -    Renderer: iced_native::Renderer + 'a, -{ -    fn from(column: Column<'a, Message, Renderer>) -> Self { -        Self::new(column) -    } -} diff --git a/pure/src/widget/container.rs b/pure/src/widget/container.rs deleted file mode 100644 index 44ffff8c..00000000 --- a/pure/src/widget/container.rs +++ /dev/null @@ -1,263 +0,0 @@ -//! Decorate content and apply alignment. -use crate::widget::Tree; -use crate::{Element, Widget}; - -use iced_native::alignment; -use iced_native::event::{self, Event}; -use iced_native::layout; -use iced_native::mouse; -use iced_native::overlay; -use iced_native::renderer; -use iced_native::widget::container; -use iced_native::{ -    Clipboard, Layout, Length, Padding, Point, Rectangle, Shell, -}; - -use std::u32; - -pub use iced_style::container::{Appearance, StyleSheet}; - -/// An element decorating some content. -/// -/// It is normally used for alignment purposes. -#[allow(missing_debug_implementations)] -pub struct Container<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: container::StyleSheet, -{ -    padding: Padding, -    width: Length, -    height: Length, -    max_width: u32, -    max_height: u32, -    horizontal_alignment: alignment::Horizontal, -    vertical_alignment: alignment::Vertical, -    style: <Renderer::Theme as StyleSheet>::Style, -    content: Element<'a, Message, Renderer>, -} - -impl<'a, Message, Renderer> Container<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: container::StyleSheet, -{ -    /// Creates an empty [`Container`]. -    pub fn new<T>(content: T) -> Self -    where -        T: Into<Element<'a, Message, Renderer>>, -    { -        Container { -            padding: Padding::ZERO, -            width: Length::Shrink, -            height: Length::Shrink, -            max_width: u32::MAX, -            max_height: u32::MAX, -            horizontal_alignment: alignment::Horizontal::Left, -            vertical_alignment: alignment::Vertical::Top, -            style: Default::default(), -            content: content.into(), -        } -    } - -    /// Sets the [`Padding`] of the [`Container`]. -    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self { -        self.padding = padding.into(); -        self -    } - -    /// Sets the width of the [`Container`]. -    pub fn width(mut self, width: Length) -> Self { -        self.width = width; -        self -    } - -    /// Sets the height of the [`Container`]. -    pub fn height(mut self, height: Length) -> Self { -        self.height = height; -        self -    } - -    /// Sets the maximum width of the [`Container`]. -    pub fn max_width(mut self, max_width: u32) -> Self { -        self.max_width = max_width; -        self -    } - -    /// Sets the maximum height of the [`Container`] in pixels. -    pub fn max_height(mut self, max_height: u32) -> Self { -        self.max_height = max_height; -        self -    } - -    /// Sets the content alignment for the horizontal axis of the [`Container`]. -    pub fn align_x(mut self, alignment: alignment::Horizontal) -> Self { -        self.horizontal_alignment = alignment; -        self -    } - -    /// Sets the content alignment for the vertical axis of the [`Container`]. -    pub fn align_y(mut self, alignment: alignment::Vertical) -> Self { -        self.vertical_alignment = alignment; -        self -    } - -    /// Centers the contents in the horizontal axis of the [`Container`]. -    pub fn center_x(mut self) -> Self { -        self.horizontal_alignment = alignment::Horizontal::Center; -        self -    } - -    /// Centers the contents in the vertical axis of the [`Container`]. -    pub fn center_y(mut self) -> Self { -        self.vertical_alignment = alignment::Vertical::Center; -        self -    } - -    /// Sets the style of the [`Container`]. -    pub fn style( -        mut self, -        style: impl Into<<Renderer::Theme as StyleSheet>::Style>, -    ) -> Self { -        self.style = style.into(); -        self -    } -} - -impl<'a, Message, Renderer> Widget<Message, Renderer> -    for Container<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: StyleSheet, -{ -    fn children(&self) -> Vec<Tree> { -        vec![Tree::new(&self.content)] -    } - -    fn diff(&self, tree: &mut Tree) { -        tree.diff_children(std::slice::from_ref(&self.content)) -    } - -    fn width(&self) -> Length { -        self.width -    } - -    fn height(&self) -> Length { -        self.height -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        container::layout( -            renderer, -            limits, -            self.width, -            self.height, -            self.max_width, -            self.max_height, -            self.padding, -            self.horizontal_alignment, -            self.vertical_alignment, -            |renderer, limits| { -                self.content.as_widget().layout(renderer, limits) -            }, -        ) -    } - -    fn on_event( -        &mut self, -        tree: &mut Tree, -        event: Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        self.content.as_widget_mut().on_event( -            &mut tree.children[0], -            event, -            layout.children().next().unwrap(), -            cursor_position, -            renderer, -            clipboard, -            shell, -        ) -    } - -    fn mouse_interaction( -        &self, -        tree: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -        renderer: &Renderer, -    ) -> mouse::Interaction { -        self.content.as_widget().mouse_interaction( -            &tree.children[0], -            layout.children().next().unwrap(), -            cursor_position, -            viewport, -            renderer, -        ) -    } - -    fn draw( -        &self, -        tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        renderer_style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -    ) { -        let style = theme.appearance(self.style); - -        container::draw_background(renderer, &style, layout.bounds()); - -        self.content.as_widget().draw( -            &tree.children[0], -            renderer, -            theme, -            &renderer::Style { -                text_color: style -                    .text_color -                    .unwrap_or(renderer_style.text_color), -            }, -            layout.children().next().unwrap(), -            cursor_position, -            viewport, -        ); -    } - -    fn overlay<'b>( -        &'b self, -        tree: &'b mut Tree, -        layout: Layout<'_>, -        renderer: &Renderer, -    ) -> Option<overlay::Element<'b, Message, Renderer>> { -        self.content.as_widget().overlay( -            &mut tree.children[0], -            layout.children().next().unwrap(), -            renderer, -        ) -    } -} - -impl<'a, Message, Renderer> From<Container<'a, Message, Renderer>> -    for Element<'a, Message, Renderer> -where -    Message: 'a, -    Renderer: 'a + iced_native::Renderer, -    Renderer::Theme: StyleSheet, -{ -    fn from( -        column: Container<'a, Message, Renderer>, -    ) -> Element<'a, Message, Renderer> { -        Element::new(column) -    } -} diff --git a/pure/src/widget/image.rs b/pure/src/widget/image.rs deleted file mode 100644 index 58f81a6f..00000000 --- a/pure/src/widget/image.rs +++ /dev/null @@ -1,69 +0,0 @@ -//! Display images in your user interface. -use crate::widget::{Tree, Widget}; -use crate::Element; - -use iced_native::layout::{self, Layout}; -use iced_native::renderer; -use iced_native::widget::image; -use iced_native::{Length, Point, Rectangle}; - -use std::hash::Hash; - -pub use image::Image; - -impl<Message, Renderer, Handle> Widget<Message, Renderer> for Image<Handle> -where -    Handle: Clone + Hash, -    Renderer: iced_native::image::Renderer<Handle = Handle>, -{ -    fn width(&self) -> Length { -        <Self as iced_native::Widget<Message, Renderer>>::width(self) -    } - -    fn height(&self) -> Length { -        <Self as iced_native::Widget<Message, Renderer>>::height(self) -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        <Self as iced_native::Widget<Message, Renderer>>::layout( -            self, renderer, limits, -        ) -    } - -    fn draw( -        &self, -        _tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -    ) { -        <Self as iced_native::Widget<Message, Renderer>>::draw( -            self, -            renderer, -            theme, -            style, -            layout, -            cursor_position, -            viewport, -        ) -    } -} - -impl<'a, Message, Renderer, Handle> From<Image<Handle>> -    for Element<'a, Message, Renderer> -where -    Message: Clone + 'a, -    Renderer: iced_native::image::Renderer<Handle = Handle> + 'a, -    Handle: Clone + Hash + 'a, -{ -    fn from(image: Image<Handle>) -> Self { -        Self::new(image) -    } -} diff --git a/pure/src/widget/pane_grid.rs b/pure/src/widget/pane_grid.rs deleted file mode 100644 index 69150aa8..00000000 --- a/pure/src/widget/pane_grid.rs +++ /dev/null @@ -1,414 +0,0 @@ -//! Let your users split regions of your application and organize layout dynamically. -//! -//! [](https://gfycat.com/mixedflatjellyfish) -//! -//! # Example -//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing, -//! drag and drop, and hotkey support. -//! -//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.4/examples/pane_grid -mod content; -mod title_bar; - -pub use content::Content; -pub use title_bar::TitleBar; - -pub use iced_native::widget::pane_grid::{ -    Axis, Configuration, Direction, DragEvent, Node, Pane, ResizeEvent, Split, -    State, -}; - -use crate::overlay; -use crate::widget::container; -use crate::widget::tree::{self, Tree}; -use crate::{Element, Widget}; - -use iced_native::event::{self, Event}; -use iced_native::layout; -use iced_native::mouse; -use iced_native::renderer; -use iced_native::widget::pane_grid; -use iced_native::widget::pane_grid::state; -use iced_native::{Clipboard, Layout, Length, Point, Rectangle, Shell}; - -pub use iced_style::pane_grid::{Line, StyleSheet}; - -/// A collection of panes distributed using either vertical or horizontal splits -/// to completely fill the space available. -/// -/// [](https://gfycat.com/frailfreshairedaleterrier) -/// -/// This distribution of space is common in tiling window managers (like -/// [`awesome`](https://awesomewm.org/), [`i3`](https://i3wm.org/), or even -/// [`tmux`](https://github.com/tmux/tmux)). -/// -/// A [`PaneGrid`] supports: -/// -/// * Vertical and horizontal splits -/// * Tracking of the last active pane -/// * Mouse-based resizing -/// * Drag and drop to reorganize panes -/// * Hotkey support -/// * Configurable modifier keys -/// * [`State`] API to perform actions programmatically (`split`, `swap`, `resize`, etc.) -/// -/// ## Example -/// -/// ``` -/// # use iced_pure::widget::pane_grid; -/// # use iced_pure::text; -/// # -/// # type PaneGrid<'a, Message> = -/// #     iced_pure::widget::PaneGrid<'a, Message, iced_native::renderer::Null>; -/// # -/// enum PaneState { -///     SomePane, -///     AnotherKindOfPane, -/// } -/// -/// enum Message { -///     PaneDragged(pane_grid::DragEvent), -///     PaneResized(pane_grid::ResizeEvent), -/// } -/// -/// let (mut state, _) = pane_grid::State::new(PaneState::SomePane); -/// -/// let pane_grid = -///     PaneGrid::new(&state, |pane, state| { -///         pane_grid::Content::new(match state { -///             PaneState::SomePane => text("This is some pane"), -///             PaneState::AnotherKindOfPane => text("This is another kind of pane"), -///         }) -///     }) -///     .on_drag(Message::PaneDragged) -///     .on_resize(10, Message::PaneResized); -/// ``` -#[allow(missing_debug_implementations)] -pub struct PaneGrid<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: StyleSheet + container::StyleSheet, -{ -    state: &'a state::Internal, -    elements: Vec<(Pane, Content<'a, Message, Renderer>)>, -    width: Length, -    height: Length, -    spacing: u16, -    on_click: Option<Box<dyn Fn(Pane) -> Message + 'a>>, -    on_drag: Option<Box<dyn Fn(DragEvent) -> Message + 'a>>, -    on_resize: Option<(u16, Box<dyn Fn(ResizeEvent) -> Message + 'a>)>, -    style: <Renderer::Theme as StyleSheet>::Style, -} - -impl<'a, Message, Renderer> PaneGrid<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: StyleSheet + container::StyleSheet, -{ -    /// Creates a [`PaneGrid`] with the given [`State`] and view function. -    /// -    /// The view function will be called to display each [`Pane`] present in the -    /// [`State`]. -    pub fn new<T>( -        state: &'a State<T>, -        view: impl Fn(Pane, &'a T) -> Content<'a, Message, Renderer>, -    ) -> Self { -        let elements = { -            state -                .panes -                .iter() -                .map(|(pane, pane_state)| (*pane, view(*pane, pane_state))) -                .collect() -        }; - -        Self { -            elements, -            state: &state.internal, -            width: Length::Fill, -            height: Length::Fill, -            spacing: 0, -            on_click: None, -            on_drag: None, -            on_resize: None, -            style: Default::default(), -        } -    } - -    /// Sets the width of the [`PaneGrid`]. -    pub fn width(mut self, width: Length) -> Self { -        self.width = width; -        self -    } - -    /// Sets the height of the [`PaneGrid`]. -    pub fn height(mut self, height: Length) -> Self { -        self.height = height; -        self -    } - -    /// Sets the spacing _between_ the panes of the [`PaneGrid`]. -    pub fn spacing(mut self, units: u16) -> Self { -        self.spacing = units; -        self -    } - -    /// Sets the message that will be produced when a [`Pane`] of the -    /// [`PaneGrid`] is clicked. -    pub fn on_click<F>(mut self, f: F) -> Self -    where -        F: 'a + Fn(Pane) -> Message, -    { -        self.on_click = Some(Box::new(f)); -        self -    } - -    /// Enables the drag and drop interactions of the [`PaneGrid`], which will -    /// use the provided function to produce messages. -    pub fn on_drag<F>(mut self, f: F) -> Self -    where -        F: 'a + Fn(DragEvent) -> Message, -    { -        self.on_drag = Some(Box::new(f)); -        self -    } - -    /// Enables the resize interactions of the [`PaneGrid`], which will -    /// use the provided function to produce messages. -    /// -    /// The `leeway` describes the amount of space around a split that can be -    /// used to grab it. -    /// -    /// The grabbable area of a split will have a length of `spacing + leeway`, -    /// properly centered. In other words, a length of -    /// `(spacing + leeway) / 2.0` on either side of the split line. -    pub fn on_resize<F>(mut self, leeway: u16, f: F) -> Self -    where -        F: 'a + Fn(ResizeEvent) -> Message, -    { -        self.on_resize = Some((leeway, Box::new(f))); -        self -    } - -    /// Sets the style of the [`PaneGrid`]. -    pub fn style( -        mut self, -        style: impl Into<<Renderer::Theme as StyleSheet>::Style>, -    ) -> Self { -        self.style = style.into(); -        self -    } -} - -impl<'a, Message, Renderer> Widget<Message, Renderer> -    for PaneGrid<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: StyleSheet + container::StyleSheet, -{ -    fn tag(&self) -> tree::Tag { -        tree::Tag::of::<state::Action>() -    } - -    fn state(&self) -> tree::State { -        tree::State::new(state::Action::Idle) -    } - -    fn children(&self) -> Vec<Tree> { -        self.elements -            .iter() -            .map(|(_, content)| content.state()) -            .collect() -    } - -    fn diff(&self, tree: &mut Tree) { -        tree.diff_children_custom( -            &self.elements, -            |state, (_, content)| content.diff(state), -            |(_, content)| content.state(), -        ) -    } - -    fn width(&self) -> Length { -        self.width -    } - -    fn height(&self) -> Length { -        self.height -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        pane_grid::layout( -            renderer, -            limits, -            self.state, -            self.width, -            self.height, -            self.spacing, -            self.elements.iter().map(|(pane, content)| (*pane, content)), -            |element, renderer, limits| element.layout(renderer, limits), -        ) -    } - -    fn on_event( -        &mut self, -        tree: &mut Tree, -        event: Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        let action = tree.state.downcast_mut::<state::Action>(); - -        let event_status = pane_grid::update( -            action, -            self.state, -            &event, -            layout, -            cursor_position, -            shell, -            self.spacing, -            self.elements.iter().map(|(pane, content)| (*pane, content)), -            &self.on_click, -            &self.on_drag, -            &self.on_resize, -        ); - -        let picked_pane = action.picked_pane().map(|(pane, _)| pane); - -        self.elements -            .iter_mut() -            .zip(&mut tree.children) -            .zip(layout.children()) -            .map(|(((pane, content), tree), layout)| { -                let is_picked = picked_pane == Some(*pane); - -                content.on_event( -                    tree, -                    event.clone(), -                    layout, -                    cursor_position, -                    renderer, -                    clipboard, -                    shell, -                    is_picked, -                ) -            }) -            .fold(event_status, event::Status::merge) -    } - -    fn mouse_interaction( -        &self, -        tree: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -        renderer: &Renderer, -    ) -> mouse::Interaction { -        pane_grid::mouse_interaction( -            tree.state.downcast_ref(), -            self.state, -            layout, -            cursor_position, -            self.spacing, -            self.on_resize.as_ref().map(|(leeway, _)| *leeway), -        ) -        .unwrap_or_else(|| { -            self.elements -                .iter() -                .zip(&tree.children) -                .zip(layout.children()) -                .map(|(((_pane, content), tree), layout)| { -                    content.mouse_interaction( -                        tree, -                        layout, -                        cursor_position, -                        viewport, -                        renderer, -                    ) -                }) -                .max() -                .unwrap_or_default() -        }) -    } - -    fn draw( -        &self, -        tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -    ) { -        pane_grid::draw( -            tree.state.downcast_ref(), -            self.state, -            layout, -            cursor_position, -            renderer, -            theme, -            style, -            viewport, -            self.spacing, -            self.on_resize.as_ref().map(|(leeway, _)| *leeway), -            self.style, -            self.elements -                .iter() -                .zip(&tree.children) -                .map(|((pane, content), tree)| (*pane, (content, tree))), -            |(content, tree), -             renderer, -             style, -             layout, -             cursor_position, -             rectangle| { -                content.draw( -                    tree, -                    renderer, -                    theme, -                    style, -                    layout, -                    cursor_position, -                    rectangle, -                ); -            }, -        ) -    } - -    fn overlay<'b>( -        &'b self, -        tree: &'b mut Tree, -        layout: Layout<'_>, -        renderer: &Renderer, -    ) -> Option<overlay::Element<'_, Message, Renderer>> { -        self.elements -            .iter() -            .zip(&mut tree.children) -            .zip(layout.children()) -            .filter_map(|(((_, pane), tree), layout)| { -                pane.overlay(tree, layout, renderer) -            }) -            .next() -    } -} - -impl<'a, Message, Renderer> From<PaneGrid<'a, Message, Renderer>> -    for Element<'a, Message, Renderer> -where -    Message: 'a, -    Renderer: 'a + iced_native::Renderer, -    Renderer::Theme: StyleSheet + container::StyleSheet, -{ -    fn from( -        pane_grid: PaneGrid<'a, Message, Renderer>, -    ) -> Element<'a, Message, Renderer> { -        Element::new(pane_grid) -    } -} diff --git a/pure/src/widget/pane_grid/content.rs b/pure/src/widget/pane_grid/content.rs deleted file mode 100644 index 9c2a0f4a..00000000 --- a/pure/src/widget/pane_grid/content.rs +++ /dev/null @@ -1,345 +0,0 @@ -use crate::widget::pane_grid::TitleBar; -use crate::widget::tree::Tree; -use crate::Element; - -use iced_native::event::{self, Event}; -use iced_native::layout; -use iced_native::mouse; -use iced_native::overlay; -use iced_native::renderer; -use iced_native::widget::container; -use iced_native::widget::pane_grid::Draggable; -use iced_native::{Clipboard, Layout, Point, Rectangle, Shell, Size}; - -/// The content of a [`Pane`]. -/// -/// [`Pane`]: crate::widget::pane_grid::Pane -#[allow(missing_debug_implementations)] -pub struct Content<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: container::StyleSheet, -{ -    title_bar: Option<TitleBar<'a, Message, Renderer>>, -    body: Element<'a, Message, Renderer>, -    style: <Renderer::Theme as container::StyleSheet>::Style, -} - -impl<'a, Message, Renderer> Content<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: container::StyleSheet, -{ -    /// Creates a new [`Content`] with the provided body. -    pub fn new(body: impl Into<Element<'a, Message, Renderer>>) -> Self { -        Self { -            title_bar: None, -            body: body.into(), -            style: Default::default(), -        } -    } - -    /// Sets the [`TitleBar`] of this [`Content`]. -    pub fn title_bar( -        mut self, -        title_bar: TitleBar<'a, Message, Renderer>, -    ) -> Self { -        self.title_bar = Some(title_bar); -        self -    } - -    /// Sets the style of the [`Content`]. -    pub fn style( -        mut self, -        style: impl Into<<Renderer::Theme as container::StyleSheet>::Style>, -    ) -> Self { -        self.style = style.into(); -        self -    } -} - -impl<'a, Message, Renderer> Content<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: container::StyleSheet, -{ -    pub(super) fn state(&self) -> Tree { -        let children = if let Some(title_bar) = self.title_bar.as_ref() { -            vec![Tree::new(&self.body), title_bar.state()] -        } else { -            vec![Tree::new(&self.body), Tree::empty()] -        }; - -        Tree { -            children, -            ..Tree::empty() -        } -    } - -    pub(super) fn diff(&self, tree: &mut Tree) { -        if tree.children.len() == 2 { -            if let Some(title_bar) = self.title_bar.as_ref() { -                title_bar.diff(&mut tree.children[1]); -            } - -            tree.children[0].diff(&self.body); -        } else { -            *tree = self.state(); -        } -    } - -    /// Draws the [`Content`] with the provided [`Renderer`] and [`Layout`]. -    /// -    /// [`Renderer`]: iced_native::Renderer -    pub fn draw( -        &self, -        tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -    ) { -        use container::StyleSheet; - -        let bounds = layout.bounds(); - -        { -            let style = theme.appearance(self.style); - -            container::draw_background(renderer, &style, bounds); -        } - -        if let Some(title_bar) = &self.title_bar { -            let mut children = layout.children(); -            let title_bar_layout = children.next().unwrap(); -            let body_layout = children.next().unwrap(); - -            let show_controls = bounds.contains(cursor_position); - -            title_bar.draw( -                &tree.children[1], -                renderer, -                theme, -                style, -                title_bar_layout, -                cursor_position, -                viewport, -                show_controls, -            ); - -            self.body.as_widget().draw( -                &tree.children[0], -                renderer, -                theme, -                style, -                body_layout, -                cursor_position, -                viewport, -            ); -        } else { -            self.body.as_widget().draw( -                &tree.children[0], -                renderer, -                theme, -                style, -                layout, -                cursor_position, -                viewport, -            ); -        } -    } - -    pub(crate) fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        if let Some(title_bar) = &self.title_bar { -            let max_size = limits.max(); - -            let title_bar_layout = title_bar -                .layout(renderer, &layout::Limits::new(Size::ZERO, max_size)); - -            let title_bar_size = title_bar_layout.size(); - -            let mut body_layout = self.body.as_widget().layout( -                renderer, -                &layout::Limits::new( -                    Size::ZERO, -                    Size::new( -                        max_size.width, -                        max_size.height - title_bar_size.height, -                    ), -                ), -            ); - -            body_layout.move_to(Point::new(0.0, title_bar_size.height)); - -            layout::Node::with_children( -                max_size, -                vec![title_bar_layout, body_layout], -            ) -        } else { -            self.body.as_widget().layout(renderer, limits) -        } -    } - -    pub(crate) fn on_event( -        &mut self, -        tree: &mut Tree, -        event: Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -        is_picked: bool, -    ) -> event::Status { -        let mut event_status = event::Status::Ignored; - -        let body_layout = if let Some(title_bar) = &mut self.title_bar { -            let mut children = layout.children(); - -            event_status = title_bar.on_event( -                &mut tree.children[1], -                event.clone(), -                children.next().unwrap(), -                cursor_position, -                renderer, -                clipboard, -                shell, -            ); - -            children.next().unwrap() -        } else { -            layout -        }; - -        let body_status = if is_picked { -            event::Status::Ignored -        } else { -            self.body.as_widget_mut().on_event( -                &mut tree.children[0], -                event, -                body_layout, -                cursor_position, -                renderer, -                clipboard, -                shell, -            ) -        }; - -        event_status.merge(body_status) -    } - -    pub(crate) fn mouse_interaction( -        &self, -        tree: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -        renderer: &Renderer, -    ) -> mouse::Interaction { -        let (body_layout, title_bar_interaction) = -            if let Some(title_bar) = &self.title_bar { -                let mut children = layout.children(); -                let title_bar_layout = children.next().unwrap(); - -                let is_over_pick_area = title_bar -                    .is_over_pick_area(title_bar_layout, cursor_position); - -                if is_over_pick_area { -                    return mouse::Interaction::Grab; -                } - -                let mouse_interaction = title_bar.mouse_interaction( -                    &tree.children[1], -                    title_bar_layout, -                    cursor_position, -                    viewport, -                    renderer, -                ); - -                (children.next().unwrap(), mouse_interaction) -            } else { -                (layout, mouse::Interaction::default()) -            }; - -        self.body -            .as_widget() -            .mouse_interaction( -                &tree.children[0], -                body_layout, -                cursor_position, -                viewport, -                renderer, -            ) -            .max(title_bar_interaction) -    } - -    pub(crate) fn overlay<'b>( -        &'b self, -        tree: &'b mut Tree, -        layout: Layout<'_>, -        renderer: &Renderer, -    ) -> Option<overlay::Element<'b, Message, Renderer>> { -        if let Some(title_bar) = self.title_bar.as_ref() { -            let mut children = layout.children(); -            let title_bar_layout = children.next()?; - -            let mut states = tree.children.iter_mut(); -            let body_state = states.next().unwrap(); -            let title_bar_state = states.next().unwrap(); - -            match title_bar.overlay(title_bar_state, title_bar_layout, renderer) -            { -                Some(overlay) => Some(overlay), -                None => self.body.as_widget().overlay( -                    body_state, -                    children.next()?, -                    renderer, -                ), -            } -        } else { -            self.body.as_widget().overlay( -                &mut tree.children[0], -                layout, -                renderer, -            ) -        } -    } -} - -impl<'a, Message, Renderer> Draggable for &Content<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: container::StyleSheet, -{ -    fn can_be_dragged_at( -        &self, -        layout: Layout<'_>, -        cursor_position: Point, -    ) -> bool { -        if let Some(title_bar) = &self.title_bar { -            let mut children = layout.children(); -            let title_bar_layout = children.next().unwrap(); - -            title_bar.is_over_pick_area(title_bar_layout, cursor_position) -        } else { -            false -        } -    } -} - -impl<'a, T, Message, Renderer> From<T> for Content<'a, Message, Renderer> -where -    T: Into<Element<'a, Message, Renderer>>, -    Renderer: iced_native::Renderer, -    Renderer::Theme: container::StyleSheet, -{ -    fn from(element: T) -> Self { -        Self::new(element) -    } -} diff --git a/pure/src/widget/pane_grid/title_bar.rs b/pure/src/widget/pane_grid/title_bar.rs deleted file mode 100644 index de9591a2..00000000 --- a/pure/src/widget/pane_grid/title_bar.rs +++ /dev/null @@ -1,388 +0,0 @@ -use crate::widget::Tree; -use crate::Element; - -use iced_native::event::{self, Event}; -use iced_native::layout; -use iced_native::mouse; -use iced_native::overlay; -use iced_native::renderer; -use iced_native::widget::container; -use iced_native::{Clipboard, Layout, Padding, Point, Rectangle, Shell, Size}; - -/// The title bar of a [`Pane`]. -/// -/// [`Pane`]: crate::widget::pane_grid::Pane -#[allow(missing_debug_implementations)] -pub struct TitleBar<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: container::StyleSheet, -{ -    content: Element<'a, Message, Renderer>, -    controls: Option<Element<'a, Message, Renderer>>, -    padding: Padding, -    always_show_controls: bool, -    style: <Renderer::Theme as container::StyleSheet>::Style, -} - -impl<'a, Message, Renderer> TitleBar<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: container::StyleSheet, -{ -    /// Creates a new [`TitleBar`] with the given content. -    pub fn new<E>(content: E) -> Self -    where -        E: Into<Element<'a, Message, Renderer>>, -    { -        Self { -            content: content.into(), -            controls: None, -            padding: Padding::ZERO, -            always_show_controls: false, -            style: Default::default(), -        } -    } - -    /// Sets the controls of the [`TitleBar`]. -    pub fn controls( -        mut self, -        controls: impl Into<Element<'a, Message, Renderer>>, -    ) -> Self { -        self.controls = Some(controls.into()); -        self -    } - -    /// Sets the [`Padding`] of the [`TitleBar`]. -    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self { -        self.padding = padding.into(); -        self -    } - -    /// Sets the style of the [`TitleBar`]. -    pub fn style( -        mut self, -        style: impl Into<<Renderer::Theme as container::StyleSheet>::Style>, -    ) -> Self { -        self.style = style.into(); -        self -    } - -    /// Sets whether or not the [`controls`] attached to this [`TitleBar`] are -    /// always visible. -    /// -    /// By default, the controls are only visible when the [`Pane`] of this -    /// [`TitleBar`] is hovered. -    /// -    /// [`controls`]: Self::controls -    /// [`Pane`]: crate::widget::pane_grid::Pane -    pub fn always_show_controls(mut self) -> Self { -        self.always_show_controls = true; -        self -    } -} - -impl<'a, Message, Renderer> TitleBar<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: container::StyleSheet, -{ -    pub(super) fn state(&self) -> Tree { -        let children = if let Some(controls) = self.controls.as_ref() { -            vec![Tree::new(&self.content), Tree::new(controls)] -        } else { -            vec![Tree::new(&self.content), Tree::empty()] -        }; - -        Tree { -            children, -            ..Tree::empty() -        } -    } - -    pub(super) fn diff(&self, tree: &mut Tree) { -        if tree.children.len() == 2 { -            if let Some(controls) = self.controls.as_ref() { -                tree.children[1].diff(controls); -            } - -            tree.children[0].diff(&self.content); -        } else { -            *tree = self.state(); -        } -    } - -    /// Draws the [`TitleBar`] with the provided [`Renderer`] and [`Layout`]. -    /// -    /// [`Renderer`]: iced_native::Renderer -    pub fn draw( -        &self, -        tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        inherited_style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -        show_controls: bool, -    ) { -        use container::StyleSheet; - -        let bounds = layout.bounds(); -        let style = theme.appearance(self.style); -        let inherited_style = renderer::Style { -            text_color: style.text_color.unwrap_or(inherited_style.text_color), -        }; - -        container::draw_background(renderer, &style, bounds); - -        let mut children = layout.children(); -        let padded = children.next().unwrap(); - -        let mut children = padded.children(); -        let title_layout = children.next().unwrap(); -        let mut show_title = true; - -        if let Some(controls) = &self.controls { -            let controls_layout = children.next().unwrap(); -            if title_layout.bounds().width + controls_layout.bounds().width -                > padded.bounds().width -            { -                show_title = false; -            } - -            if show_controls || self.always_show_controls { -                controls.as_widget().draw( -                    &tree.children[1], -                    renderer, -                    theme, -                    &inherited_style, -                    controls_layout, -                    cursor_position, -                    viewport, -                ); -            } -        } - -        if show_title { -            self.content.as_widget().draw( -                &tree.children[0], -                renderer, -                theme, -                &inherited_style, -                title_layout, -                cursor_position, -                viewport, -            ); -        } -    } - -    /// Returns whether the mouse cursor is over the pick area of the -    /// [`TitleBar`] or not. -    /// -    /// The whole [`TitleBar`] is a pick area, except its controls. -    pub fn is_over_pick_area( -        &self, -        layout: Layout<'_>, -        cursor_position: Point, -    ) -> bool { -        if layout.bounds().contains(cursor_position) { -            let mut children = layout.children(); -            let padded = children.next().unwrap(); -            let mut children = padded.children(); -            let title_layout = children.next().unwrap(); - -            if self.controls.is_some() { -                let controls_layout = children.next().unwrap(); - -                !controls_layout.bounds().contains(cursor_position) -                    && !title_layout.bounds().contains(cursor_position) -            } else { -                !title_layout.bounds().contains(cursor_position) -            } -        } else { -            false -        } -    } - -    pub(crate) fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        let limits = limits.pad(self.padding); -        let max_size = limits.max(); - -        let title_layout = self -            .content -            .as_widget() -            .layout(renderer, &layout::Limits::new(Size::ZERO, max_size)); - -        let title_size = title_layout.size(); - -        let mut node = if let Some(controls) = &self.controls { -            let mut controls_layout = controls -                .as_widget() -                .layout(renderer, &layout::Limits::new(Size::ZERO, max_size)); - -            let controls_size = controls_layout.size(); -            let space_before_controls = max_size.width - controls_size.width; - -            let height = title_size.height.max(controls_size.height); - -            controls_layout.move_to(Point::new(space_before_controls, 0.0)); - -            layout::Node::with_children( -                Size::new(max_size.width, height), -                vec![title_layout, controls_layout], -            ) -        } else { -            layout::Node::with_children( -                Size::new(max_size.width, title_size.height), -                vec![title_layout], -            ) -        }; - -        node.move_to(Point::new( -            self.padding.left.into(), -            self.padding.top.into(), -        )); - -        layout::Node::with_children(node.size().pad(self.padding), vec![node]) -    } - -    pub(crate) fn on_event( -        &mut self, -        tree: &mut Tree, -        event: Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        let mut children = layout.children(); -        let padded = children.next().unwrap(); - -        let mut children = padded.children(); -        let title_layout = children.next().unwrap(); -        let mut show_title = true; - -        let control_status = if let Some(controls) = &mut self.controls { -            let controls_layout = children.next().unwrap(); -            if title_layout.bounds().width + controls_layout.bounds().width -                > padded.bounds().width -            { -                show_title = false; -            } - -            controls.as_widget_mut().on_event( -                &mut tree.children[1], -                event.clone(), -                controls_layout, -                cursor_position, -                renderer, -                clipboard, -                shell, -            ) -        } else { -            event::Status::Ignored -        }; - -        let title_status = if show_title { -            self.content.as_widget_mut().on_event( -                &mut tree.children[0], -                event, -                title_layout, -                cursor_position, -                renderer, -                clipboard, -                shell, -            ) -        } else { -            event::Status::Ignored -        }; - -        control_status.merge(title_status) -    } - -    pub(crate) fn mouse_interaction( -        &self, -        tree: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -        renderer: &Renderer, -    ) -> mouse::Interaction { -        let mut children = layout.children(); -        let padded = children.next().unwrap(); - -        let mut children = padded.children(); -        let title_layout = children.next().unwrap(); - -        let title_interaction = self.content.as_widget().mouse_interaction( -            &tree.children[0], -            title_layout, -            cursor_position, -            viewport, -            renderer, -        ); - -        if let Some(controls) = &self.controls { -            let controls_layout = children.next().unwrap(); -            let controls_interaction = controls.as_widget().mouse_interaction( -                &tree.children[1], -                controls_layout, -                cursor_position, -                viewport, -                renderer, -            ); - -            if title_layout.bounds().width + controls_layout.bounds().width -                > padded.bounds().width -            { -                controls_interaction -            } else { -                controls_interaction.max(title_interaction) -            } -        } else { -            title_interaction -        } -    } - -    pub(crate) fn overlay<'b>( -        &'b self, -        tree: &'b mut Tree, -        layout: Layout<'_>, -        renderer: &Renderer, -    ) -> Option<overlay::Element<'b, Message, Renderer>> { -        let mut children = layout.children(); -        let padded = children.next()?; - -        let mut children = padded.children(); -        let title_layout = children.next()?; - -        let Self { -            content, controls, .. -        } = self; - -        let mut states = tree.children.iter_mut(); -        let title_state = states.next().unwrap(); -        let controls_state = states.next().unwrap(); - -        content -            .as_widget() -            .overlay(title_state, title_layout, renderer) -            .or_else(move || { -                controls.as_ref().and_then(|controls| { -                    let controls_layout = children.next()?; - -                    controls.as_widget().overlay( -                        controls_state, -                        controls_layout, -                        renderer, -                    ) -                }) -            }) -    } -} diff --git a/pure/src/widget/pick_list.rs b/pure/src/widget/pick_list.rs deleted file mode 100644 index 9264544a..00000000 --- a/pure/src/widget/pick_list.rs +++ /dev/null @@ -1,240 +0,0 @@ -//! Display a dropdown list of selectable values. -use crate::widget::tree::{self, Tree}; -use crate::{Element, Widget}; - -use iced_native::event::{self, Event}; -use iced_native::layout; -use iced_native::mouse; -use iced_native::overlay; -use iced_native::renderer; -use iced_native::text; -use iced_native::widget::pick_list; -use iced_native::{ -    Clipboard, Layout, Length, Padding, Point, Rectangle, Shell, -}; - -use std::borrow::Cow; - -pub use iced_style::pick_list::{Appearance, StyleSheet}; - -/// A widget for selecting a single value from a list of options. -#[allow(missing_debug_implementations)] -pub struct PickList<'a, T, Message, Renderer> -where -    [T]: ToOwned<Owned = Vec<T>>, -    Renderer: text::Renderer, -    Renderer::Theme: StyleSheet, -{ -    on_selected: Box<dyn Fn(T) -> Message + 'a>, -    options: Cow<'a, [T]>, -    placeholder: Option<String>, -    selected: Option<T>, -    width: Length, -    padding: Padding, -    text_size: Option<u16>, -    font: Renderer::Font, -    style: <Renderer::Theme as StyleSheet>::Style, -} - -impl<'a, T: 'a, Message, Renderer> PickList<'a, T, Message, Renderer> -where -    T: ToString + Eq, -    [T]: ToOwned<Owned = Vec<T>>, -    Renderer: text::Renderer, -    Renderer::Theme: StyleSheet, -{ -    /// The default padding of a [`PickList`]. -    pub const DEFAULT_PADDING: Padding = Padding::new(5); - -    /// Creates a new [`PickList`] with the given list of options, the current -    /// selected value, and the message to produce when an option is selected. -    pub fn new( -        options: impl Into<Cow<'a, [T]>>, -        selected: Option<T>, -        on_selected: impl Fn(T) -> Message + 'a, -    ) -> Self { -        Self { -            on_selected: Box::new(on_selected), -            options: options.into(), -            placeholder: None, -            selected, -            width: Length::Shrink, -            text_size: None, -            padding: Self::DEFAULT_PADDING, -            font: Default::default(), -            style: Default::default(), -        } -    } - -    /// Sets the placeholder of the [`PickList`]. -    pub fn placeholder(mut self, placeholder: impl Into<String>) -> Self { -        self.placeholder = Some(placeholder.into()); -        self -    } - -    /// Sets the width of the [`PickList`]. -    pub fn width(mut self, width: Length) -> Self { -        self.width = width; -        self -    } - -    /// Sets the [`Padding`] of the [`PickList`]. -    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self { -        self.padding = padding.into(); -        self -    } - -    /// Sets the text size of the [`PickList`]. -    pub fn text_size(mut self, size: u16) -> Self { -        self.text_size = Some(size); -        self -    } - -    /// Sets the font of the [`PickList`]. -    pub fn font(mut self, font: Renderer::Font) -> Self { -        self.font = font; -        self -    } - -    /// Sets the style of the [`PickList`]. -    pub fn style( -        mut self, -        style: impl Into<<Renderer::Theme as StyleSheet>::Style>, -    ) -> Self { -        self.style = style.into(); -        self -    } -} - -impl<'a, T: 'a, Message, Renderer> Widget<Message, Renderer> -    for PickList<'a, T, Message, Renderer> -where -    T: Clone + ToString + Eq + 'static, -    [T]: ToOwned<Owned = Vec<T>>, -    Message: 'a, -    Renderer: text::Renderer + 'a, -    Renderer::Theme: StyleSheet, -{ -    fn tag(&self) -> tree::Tag { -        tree::Tag::of::<pick_list::State<T>>() -    } - -    fn state(&self) -> tree::State { -        tree::State::new(pick_list::State::<T>::new()) -    } - -    fn width(&self) -> Length { -        self.width -    } - -    fn height(&self) -> Length { -        Length::Shrink -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        pick_list::layout( -            renderer, -            limits, -            self.width, -            self.padding, -            self.text_size, -            &self.font, -            self.placeholder.as_deref(), -            &self.options, -        ) -    } - -    fn on_event( -        &mut self, -        tree: &mut Tree, -        event: Event, -        layout: Layout<'_>, -        cursor_position: Point, -        _renderer: &Renderer, -        _clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        pick_list::update( -            event, -            layout, -            cursor_position, -            shell, -            self.on_selected.as_ref(), -            self.selected.as_ref(), -            &self.options, -            || tree.state.downcast_mut::<pick_list::State<T>>(), -        ) -    } - -    fn mouse_interaction( -        &self, -        _tree: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        _viewport: &Rectangle, -        _renderer: &Renderer, -    ) -> mouse::Interaction { -        pick_list::mouse_interaction(layout, cursor_position) -    } - -    fn draw( -        &self, -        _tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        _style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        _viewport: &Rectangle, -    ) { -        pick_list::draw( -            renderer, -            theme, -            layout, -            cursor_position, -            self.padding, -            self.text_size, -            &self.font, -            self.placeholder.as_deref(), -            self.selected.as_ref(), -            self.style, -        ) -    } - -    fn overlay<'b>( -        &'b self, -        tree: &'b mut Tree, -        layout: Layout<'_>, -        _renderer: &Renderer, -    ) -> Option<overlay::Element<'b, Message, Renderer>> { -        let state = tree.state.downcast_mut::<pick_list::State<T>>(); - -        pick_list::overlay( -            layout, -            state, -            self.padding, -            self.text_size, -            self.font.clone(), -            &self.options, -            self.style, -        ) -    } -} - -impl<'a, T: 'a, Message, Renderer> From<PickList<'a, T, Message, Renderer>> -    for Element<'a, Message, Renderer> -where -    T: Clone + ToString + Eq + 'static, -    [T]: ToOwned<Owned = Vec<T>>, -    Message: 'a, -    Renderer: text::Renderer + 'a, -    Renderer::Theme: StyleSheet, -{ -    fn from(pick_list: PickList<'a, T, Message, Renderer>) -> Self { -        Self::new(pick_list) -    } -} diff --git a/pure/src/widget/progress_bar.rs b/pure/src/widget/progress_bar.rs deleted file mode 100644 index c9644853..00000000 --- a/pure/src/widget/progress_bar.rs +++ /dev/null @@ -1,105 +0,0 @@ -//! Provide progress feedback to your users. -use crate::widget::Tree; -use crate::{Element, Widget}; - -use iced_native::event::{self, Event}; -use iced_native::layout::{self, Layout}; -use iced_native::mouse; -use iced_native::renderer; -use iced_native::{Clipboard, Length, Point, Rectangle, Shell}; - -pub use iced_native::widget::progress_bar::*; - -impl<Message, Renderer> Widget<Message, Renderer> for ProgressBar<Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: StyleSheet, -{ -    fn width(&self) -> Length { -        <Self as iced_native::Widget<Message, Renderer>>::width(self) -    } - -    fn height(&self) -> Length { -        <Self as iced_native::Widget<Message, Renderer>>::height(self) -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        <Self as iced_native::Widget<Message, Renderer>>::layout( -            self, renderer, limits, -        ) -    } - -    fn on_event( -        &mut self, -        _state: &mut Tree, -        event: Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        <Self as iced_native::Widget<Message, Renderer>>::on_event( -            self, -            event, -            layout, -            cursor_position, -            renderer, -            clipboard, -            shell, -        ) -    } - -    fn draw( -        &self, -        _tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -    ) { -        <Self as iced_native::Widget<Message, Renderer>>::draw( -            self, -            renderer, -            theme, -            style, -            layout, -            cursor_position, -            viewport, -        ) -    } - -    fn mouse_interaction( -        &self, -        _state: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -        renderer: &Renderer, -    ) -> mouse::Interaction { -        <Self as iced_native::Widget<Message, Renderer>>::mouse_interaction( -            self, -            layout, -            cursor_position, -            viewport, -            renderer, -        ) -    } -} - -impl<'a, Message, Renderer> From<ProgressBar<Renderer>> -    for Element<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer + 'a, -    Renderer::Theme: StyleSheet, -{ -    fn from(progress_bar: ProgressBar<Renderer>) -> Self { -        Self::new(progress_bar) -    } -} diff --git a/pure/src/widget/radio.rs b/pure/src/widget/radio.rs deleted file mode 100644 index 604c2785..00000000 --- a/pure/src/widget/radio.rs +++ /dev/null @@ -1,109 +0,0 @@ -//! Create choices using radio buttons. -use crate::widget::Tree; -use crate::{Element, Widget}; - -use iced_native::event::{self, Event}; -use iced_native::layout::{self, Layout}; -use iced_native::mouse; -use iced_native::renderer; -use iced_native::text; -use iced_native::widget; -use iced_native::{Clipboard, Length, Point, Rectangle, Shell}; - -pub use iced_native::widget::radio::{Appearance, Radio, StyleSheet}; - -impl<Message, Renderer> Widget<Message, Renderer> for Radio<Message, Renderer> -where -    Message: Clone, -    Renderer: text::Renderer, -    Renderer::Theme: StyleSheet + widget::text::StyleSheet, -{ -    fn width(&self) -> Length { -        <Self as iced_native::Widget<Message, Renderer>>::width(self) -    } - -    fn height(&self) -> Length { -        <Self as iced_native::Widget<Message, Renderer>>::height(self) -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        <Self as iced_native::Widget<Message, Renderer>>::layout( -            self, renderer, limits, -        ) -    } - -    fn on_event( -        &mut self, -        _state: &mut Tree, -        event: Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        <Self as iced_native::Widget<Message, Renderer>>::on_event( -            self, -            event, -            layout, -            cursor_position, -            renderer, -            clipboard, -            shell, -        ) -    } - -    fn draw( -        &self, -        _tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -    ) { -        <Self as iced_native::Widget<Message, Renderer>>::draw( -            self, -            renderer, -            theme, -            style, -            layout, -            cursor_position, -            viewport, -        ) -    } - -    fn mouse_interaction( -        &self, -        _state: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -        renderer: &Renderer, -    ) -> mouse::Interaction { -        <Self as iced_native::Widget<Message, Renderer>>::mouse_interaction( -            self, -            layout, -            cursor_position, -            viewport, -            renderer, -        ) -    } -} - -impl<'a, Message, Renderer> From<Radio<Message, Renderer>> -    for Element<'a, Message, Renderer> -where -    Message: 'a + Clone, -    Renderer: text::Renderer + 'a, -    Renderer::Theme: StyleSheet + widget::text::StyleSheet, -{ -    fn from(radio: Radio<Message, Renderer>) -> Self { -        Self::new(radio) -    } -} diff --git a/pure/src/widget/row.rs b/pure/src/widget/row.rs deleted file mode 100644 index a288a68d..00000000 --- a/pure/src/widget/row.rs +++ /dev/null @@ -1,233 +0,0 @@ -use crate::flex; -use crate::overlay; -use crate::widget::Tree; -use crate::{Element, Widget}; - -use iced_native::event::{self, Event}; -use iced_native::layout::{self, Layout}; -use iced_native::mouse; -use iced_native::renderer; -use iced_native::{ -    Alignment, Clipboard, Length, Padding, Point, Rectangle, Shell, -}; - -/// A container that distributes its contents horizontally. -pub struct Row<'a, Message, Renderer> { -    spacing: u16, -    padding: Padding, -    width: Length, -    height: Length, -    align_items: Alignment, -    children: Vec<Element<'a, Message, Renderer>>, -} - -impl<'a, Message, Renderer> Row<'a, Message, Renderer> { -    /// Creates an empty [`Row`]. -    pub fn new() -> Self { -        Self::with_children(Vec::new()) -    } - -    /// Creates a [`Row`] with the given elements. -    pub fn with_children( -        children: Vec<Element<'a, Message, Renderer>>, -    ) -> Self { -        Row { -            spacing: 0, -            padding: Padding::ZERO, -            width: Length::Shrink, -            height: Length::Shrink, -            align_items: Alignment::Start, -            children, -        } -    } - -    /// Sets the horizontal spacing _between_ elements. -    /// -    /// Custom margins per element do not exist in iced. You should use this -    /// method instead! While less flexible, it helps you keep spacing between -    /// elements consistent. -    pub fn spacing(mut self, units: u16) -> Self { -        self.spacing = units; -        self -    } - -    /// Sets the [`Padding`] of the [`Row`]. -    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self { -        self.padding = padding.into(); -        self -    } - -    /// Sets the width of the [`Row`]. -    pub fn width(mut self, width: Length) -> Self { -        self.width = width; -        self -    } - -    /// Sets the height of the [`Row`]. -    pub fn height(mut self, height: Length) -> Self { -        self.height = height; -        self -    } - -    /// Sets the vertical alignment of the contents of the [`Row`] . -    pub fn align_items(mut self, align: Alignment) -> Self { -        self.align_items = align; -        self -    } - -    /// Adds an [`Element`] to the [`Row`]. -    pub fn push( -        mut self, -        child: impl Into<Element<'a, Message, Renderer>>, -    ) -> Self { -        self.children.push(child.into()); -        self -    } -} - -impl<'a, Message, Renderer> Default for Row<'a, Message, Renderer> { -    fn default() -> Self { -        Self::new() -    } -} - -impl<'a, Message, Renderer> Widget<Message, Renderer> -    for Row<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -{ -    fn children(&self) -> Vec<Tree> { -        self.children.iter().map(Tree::new).collect() -    } - -    fn diff(&self, tree: &mut Tree) { -        tree.diff_children(&self.children) -    } - -    fn width(&self) -> Length { -        self.width -    } - -    fn height(&self) -> Length { -        self.height -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        let limits = limits.width(self.width).height(self.height); - -        flex::resolve( -            flex::Axis::Horizontal, -            renderer, -            &limits, -            self.padding, -            self.spacing as f32, -            self.align_items, -            &self.children, -        ) -    } - -    fn on_event( -        &mut self, -        tree: &mut Tree, -        event: Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        self.children -            .iter_mut() -            .zip(&mut tree.children) -            .zip(layout.children()) -            .map(|((child, state), layout)| { -                child.as_widget_mut().on_event( -                    state, -                    event.clone(), -                    layout, -                    cursor_position, -                    renderer, -                    clipboard, -                    shell, -                ) -            }) -            .fold(event::Status::Ignored, event::Status::merge) -    } - -    fn mouse_interaction( -        &self, -        tree: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -        renderer: &Renderer, -    ) -> mouse::Interaction { -        self.children -            .iter() -            .zip(&tree.children) -            .zip(layout.children()) -            .map(|((child, state), layout)| { -                child.as_widget().mouse_interaction( -                    state, -                    layout, -                    cursor_position, -                    viewport, -                    renderer, -                ) -            }) -            .max() -            .unwrap_or_default() -    } - -    fn draw( -        &self, -        tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -    ) { -        for ((child, state), layout) in self -            .children -            .iter() -            .zip(&tree.children) -            .zip(layout.children()) -        { -            child.as_widget().draw( -                state, -                renderer, -                theme, -                style, -                layout, -                cursor_position, -                viewport, -            ); -        } -    } - -    fn overlay<'b>( -        &'b self, -        tree: &'b mut Tree, -        layout: Layout<'_>, -        renderer: &Renderer, -    ) -> Option<overlay::Element<'b, Message, Renderer>> { -        overlay::from_children(&self.children, tree, layout, renderer) -    } -} - -impl<'a, Message, Renderer> From<Row<'a, Message, Renderer>> -    for Element<'a, Message, Renderer> -where -    Message: 'a, -    Renderer: iced_native::Renderer + 'a, -{ -    fn from(row: Row<'a, Message, Renderer>) -> Self { -        Self::new(row) -    } -} diff --git a/pure/src/widget/rule.rs b/pure/src/widget/rule.rs deleted file mode 100644 index 0fb4ebab..00000000 --- a/pure/src/widget/rule.rs +++ /dev/null @@ -1,105 +0,0 @@ -//! Display a horizontal or vertical rule for dividing content. -use crate::widget::Tree; -use crate::{Element, Widget}; - -use iced_native::event::{self, Event}; -use iced_native::layout::{self, Layout}; -use iced_native::mouse; -use iced_native::renderer; -use iced_native::{Clipboard, Length, Point, Rectangle, Shell}; - -pub use iced_native::widget::rule::*; - -impl<Message, Renderer> Widget<Message, Renderer> for Rule<Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: StyleSheet, -{ -    fn width(&self) -> Length { -        <Self as iced_native::Widget<Message, Renderer>>::width(self) -    } - -    fn height(&self) -> Length { -        <Self as iced_native::Widget<Message, Renderer>>::height(self) -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        <Self as iced_native::Widget<Message, Renderer>>::layout( -            self, renderer, limits, -        ) -    } - -    fn on_event( -        &mut self, -        _state: &mut Tree, -        event: Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        <Self as iced_native::Widget<Message, Renderer>>::on_event( -            self, -            event, -            layout, -            cursor_position, -            renderer, -            clipboard, -            shell, -        ) -    } - -    fn draw( -        &self, -        _tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -    ) { -        <Self as iced_native::Widget<Message, Renderer>>::draw( -            self, -            renderer, -            theme, -            style, -            layout, -            cursor_position, -            viewport, -        ) -    } - -    fn mouse_interaction( -        &self, -        _state: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -        renderer: &Renderer, -    ) -> mouse::Interaction { -        <Self as iced_native::Widget<Message, Renderer>>::mouse_interaction( -            self, -            layout, -            cursor_position, -            viewport, -            renderer, -        ) -    } -} - -impl<'a, Message, Renderer> From<Rule<Renderer>> -    for Element<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer + 'a, -    Renderer::Theme: StyleSheet, -{ -    fn from(rule: Rule<Renderer>) -> Self { -        Self::new(rule) -    } -} diff --git a/pure/src/widget/scrollable.rs b/pure/src/widget/scrollable.rs deleted file mode 100644 index 4118b67e..00000000 --- a/pure/src/widget/scrollable.rs +++ /dev/null @@ -1,278 +0,0 @@ -//! Navigate an endless amount of content with a scrollbar. -use crate::overlay; -use crate::widget::tree::{self, Tree}; -use crate::{Element, Widget}; - -use iced_native::event::{self, Event}; -use iced_native::layout::{self, Layout}; -use iced_native::mouse; -use iced_native::renderer; -use iced_native::widget::scrollable; -use iced_native::{Clipboard, Length, Point, Rectangle, Shell, Vector}; - -pub use iced_style::scrollable::{Scrollbar, Scroller, StyleSheet}; - -/// A widget that can vertically display an infinite amount of content with a -/// scrollbar. -#[allow(missing_debug_implementations)] -pub struct Scrollable<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: StyleSheet, -{ -    height: Length, -    scrollbar_width: u16, -    scrollbar_margin: u16, -    scroller_width: u16, -    content: Element<'a, Message, Renderer>, -    on_scroll: Option<Box<dyn Fn(f32) -> Message + 'a>>, -    style: <Renderer::Theme as StyleSheet>::Style, -} - -impl<'a, Message, Renderer> Scrollable<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: StyleSheet, -{ -    /// Creates a new [`Scrollable`]. -    pub fn new(content: impl Into<Element<'a, Message, Renderer>>) -> Self { -        Scrollable { -            height: Length::Shrink, -            scrollbar_width: 10, -            scrollbar_margin: 0, -            scroller_width: 10, -            content: content.into(), -            on_scroll: None, -            style: Default::default(), -        } -    } - -    /// Sets the height of the [`Scrollable`]. -    pub fn height(mut self, height: Length) -> Self { -        self.height = height; -        self -    } - -    /// Sets the scrollbar width of the [`Scrollable`] . -    /// Silently enforces a minimum value of 1. -    pub fn scrollbar_width(mut self, scrollbar_width: u16) -> Self { -        self.scrollbar_width = scrollbar_width.max(1); -        self -    } - -    /// Sets the scrollbar margin of the [`Scrollable`] . -    pub fn scrollbar_margin(mut self, scrollbar_margin: u16) -> Self { -        self.scrollbar_margin = scrollbar_margin; -        self -    } - -    /// Sets the scroller width of the [`Scrollable`] . -    /// -    /// It silently enforces a minimum value of 1. -    pub fn scroller_width(mut self, scroller_width: u16) -> Self { -        self.scroller_width = scroller_width.max(1); -        self -    } - -    /// Sets a function to call when the [`Scrollable`] is scrolled. -    /// -    /// The function takes the new relative offset of the [`Scrollable`] -    /// (e.g. `0` means top, while `1` means bottom). -    pub fn on_scroll(mut self, f: impl Fn(f32) -> Message + 'a) -> Self { -        self.on_scroll = Some(Box::new(f)); -        self -    } - -    /// Sets the style of the [`Scrollable`] . -    pub fn style( -        mut self, -        style: impl Into<<Renderer::Theme as StyleSheet>::Style>, -    ) -> Self { -        self.style = style.into(); -        self -    } -} - -impl<'a, Message, Renderer> Widget<Message, Renderer> -    for Scrollable<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: StyleSheet, -{ -    fn tag(&self) -> tree::Tag { -        tree::Tag::of::<scrollable::State>() -    } - -    fn state(&self) -> tree::State { -        tree::State::new(scrollable::State::new()) -    } - -    fn children(&self) -> Vec<Tree> { -        vec![Tree::new(&self.content)] -    } - -    fn diff(&self, tree: &mut Tree) { -        tree.diff_children(std::slice::from_ref(&self.content)) -    } - -    fn width(&self) -> Length { -        self.content.as_widget().width() -    } - -    fn height(&self) -> Length { -        self.height -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        scrollable::layout( -            renderer, -            limits, -            Widget::<Message, Renderer>::width(self), -            self.height, -            u32::MAX, -            |renderer, limits| { -                self.content.as_widget().layout(renderer, limits) -            }, -        ) -    } - -    fn on_event( -        &mut self, -        tree: &mut Tree, -        event: Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        scrollable::update( -            tree.state.downcast_mut::<scrollable::State>(), -            event, -            layout, -            cursor_position, -            clipboard, -            shell, -            self.scrollbar_width, -            self.scrollbar_margin, -            self.scroller_width, -            &self.on_scroll, -            |event, layout, cursor_position, clipboard, shell| { -                self.content.as_widget_mut().on_event( -                    &mut tree.children[0], -                    event, -                    layout, -                    cursor_position, -                    renderer, -                    clipboard, -                    shell, -                ) -            }, -        ) -    } - -    fn draw( -        &self, -        tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        _viewport: &Rectangle, -    ) { -        scrollable::draw( -            tree.state.downcast_ref::<scrollable::State>(), -            renderer, -            theme, -            layout, -            cursor_position, -            self.scrollbar_width, -            self.scrollbar_margin, -            self.scroller_width, -            self.style, -            |renderer, layout, cursor_position, viewport| { -                self.content.as_widget().draw( -                    &tree.children[0], -                    renderer, -                    theme, -                    style, -                    layout, -                    cursor_position, -                    viewport, -                ) -            }, -        ) -    } - -    fn mouse_interaction( -        &self, -        tree: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        _viewport: &Rectangle, -        renderer: &Renderer, -    ) -> mouse::Interaction { -        scrollable::mouse_interaction( -            tree.state.downcast_ref::<scrollable::State>(), -            layout, -            cursor_position, -            self.scrollbar_width, -            self.scrollbar_margin, -            self.scroller_width, -            |layout, cursor_position, viewport| { -                self.content.as_widget().mouse_interaction( -                    &tree.children[0], -                    layout, -                    cursor_position, -                    viewport, -                    renderer, -                ) -            }, -        ) -    } - -    fn overlay<'b>( -        &'b self, -        tree: &'b mut Tree, -        layout: Layout<'_>, -        renderer: &Renderer, -    ) -> Option<overlay::Element<'b, Message, Renderer>> { -        self.content -            .as_widget() -            .overlay( -                &mut tree.children[0], -                layout.children().next().unwrap(), -                renderer, -            ) -            .map(|overlay| { -                let bounds = layout.bounds(); -                let content_layout = layout.children().next().unwrap(); -                let content_bounds = content_layout.bounds(); -                let offset = tree -                    .state -                    .downcast_ref::<scrollable::State>() -                    .offset(bounds, content_bounds); - -                overlay.translate(Vector::new(0.0, -(offset as f32))) -            }) -    } -} - -impl<'a, Message, Renderer> From<Scrollable<'a, Message, Renderer>> -    for Element<'a, Message, Renderer> -where -    Message: 'a + Clone, -    Renderer: 'a + iced_native::Renderer, -    Renderer::Theme: StyleSheet, -{ -    fn from( -        text_input: Scrollable<'a, Message, Renderer>, -    ) -> Element<'a, Message, Renderer> { -        Element::new(text_input) -    } -} diff --git a/pure/src/widget/slider.rs b/pure/src/widget/slider.rs deleted file mode 100644 index fed979e5..00000000 --- a/pure/src/widget/slider.rs +++ /dev/null @@ -1,255 +0,0 @@ -//! Display an interactive selector of a single value from a range of values. -use crate::widget::tree::{self, Tree}; -use crate::{Element, Widget}; - -use iced_native::event::{self, Event}; -use iced_native::layout; -use iced_native::mouse; -use iced_native::renderer; -use iced_native::widget::slider; -use iced_native::{Clipboard, Layout, Length, Point, Rectangle, Shell, Size}; - -use std::ops::RangeInclusive; - -pub use iced_style::slider::{Appearance, Handle, HandleShape, StyleSheet}; - -/// An horizontal bar and a handle that selects a single value from a range of -/// values. -/// -/// A [`Slider`] will try to fill the horizontal space of its container. -/// -/// The [`Slider`] range of numeric values is generic and its step size defaults -/// to 1 unit. -/// -/// # Example -/// ``` -/// # use iced_pure::widget::slider; -/// # use iced_native::renderer::Null; -/// # -/// # type Slider<'a, T, Message> = slider::Slider<'a, T, Message, Null>; -/// # -/// #[derive(Clone)] -/// pub enum Message { -///     SliderChanged(f32), -/// } -/// -/// let value = 50.0; -/// -/// Slider::new(0.0..=100.0, value, Message::SliderChanged); -/// ``` -/// -///  -#[allow(missing_debug_implementations)] -pub struct Slider<'a, T, Message, Renderer> -where -    Renderer: iced_native::Renderer, -    Renderer::Theme: StyleSheet, -{ -    range: RangeInclusive<T>, -    step: T, -    value: T, -    on_change: Box<dyn Fn(T) -> Message + 'a>, -    on_release: Option<Message>, -    width: Length, -    height: u16, -    style: <Renderer::Theme as StyleSheet>::Style, -} - -impl<'a, T, Message, Renderer> Slider<'a, T, Message, Renderer> -where -    T: Copy + From<u8> + std::cmp::PartialOrd, -    Message: Clone, -    Renderer: iced_native::Renderer, -    Renderer::Theme: StyleSheet, -{ -    /// The default height of a [`Slider`]. -    pub const DEFAULT_HEIGHT: u16 = 22; - -    /// Creates a new [`Slider`]. -    /// -    /// It expects: -    ///   * an inclusive range of possible values -    ///   * the current value of the [`Slider`] -    ///   * a function that will be called when the [`Slider`] is dragged. -    ///   It receives the new value of the [`Slider`] and must produce a -    ///   `Message`. -    pub fn new<F>(range: RangeInclusive<T>, value: T, on_change: F) -> Self -    where -        F: 'a + Fn(T) -> Message, -    { -        let value = if value >= *range.start() { -            value -        } else { -            *range.start() -        }; - -        let value = if value <= *range.end() { -            value -        } else { -            *range.end() -        }; - -        Slider { -            value, -            range, -            step: T::from(1), -            on_change: Box::new(on_change), -            on_release: None, -            width: Length::Fill, -            height: Self::DEFAULT_HEIGHT, -            style: Default::default(), -        } -    } - -    /// Sets the release message of the [`Slider`]. -    /// This is called when the mouse is released from the slider. -    /// -    /// Typically, the user's interaction with the slider is finished when this message is produced. -    /// This is useful if you need to spawn a long-running task from the slider's result, where -    /// the default on_change message could create too many events. -    pub fn on_release(mut self, on_release: Message) -> Self { -        self.on_release = Some(on_release); -        self -    } - -    /// Sets the width of the [`Slider`]. -    pub fn width(mut self, width: Length) -> Self { -        self.width = width; -        self -    } - -    /// Sets the height of the [`Slider`]. -    pub fn height(mut self, height: u16) -> Self { -        self.height = height; -        self -    } - -    /// Sets the style of the [`Slider`]. -    pub fn style( -        mut self, -        style: impl Into<<Renderer::Theme as StyleSheet>::Style>, -    ) -> Self { -        self.style = style.into(); -        self -    } - -    /// Sets the step size of the [`Slider`]. -    pub fn step(mut self, step: T) -> Self { -        self.step = step; -        self -    } -} - -impl<'a, T, Message, Renderer> Widget<Message, Renderer> -    for Slider<'a, T, Message, Renderer> -where -    T: Copy + Into<f64> + num_traits::FromPrimitive, -    Message: Clone, -    Renderer: iced_native::Renderer, -    Renderer::Theme: StyleSheet, -{ -    fn tag(&self) -> tree::Tag { -        tree::Tag::of::<slider::State>() -    } - -    fn state(&self) -> tree::State { -        tree::State::new(slider::State::new()) -    } - -    fn width(&self) -> Length { -        self.width -    } - -    fn height(&self) -> Length { -        Length::Shrink -    } - -    fn layout( -        &self, -        _renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        let limits = -            limits.width(self.width).height(Length::Units(self.height)); - -        let size = limits.resolve(Size::ZERO); - -        layout::Node::new(size) -    } - -    fn on_event( -        &mut self, -        tree: &mut Tree, -        event: Event, -        layout: Layout<'_>, -        cursor_position: Point, -        _renderer: &Renderer, -        _clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        slider::update( -            event, -            layout, -            cursor_position, -            shell, -            tree.state.downcast_mut::<slider::State>(), -            &mut self.value, -            &self.range, -            self.step, -            self.on_change.as_ref(), -            &self.on_release, -        ) -    } - -    fn draw( -        &self, -        tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        _style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        _viewport: &Rectangle, -    ) { -        slider::draw( -            renderer, -            layout, -            cursor_position, -            tree.state.downcast_ref::<slider::State>(), -            self.value, -            &self.range, -            theme, -            self.style, -        ) -    } - -    fn mouse_interaction( -        &self, -        tree: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        _viewport: &Rectangle, -        _renderer: &Renderer, -    ) -> mouse::Interaction { -        slider::mouse_interaction( -            layout, -            cursor_position, -            tree.state.downcast_ref::<slider::State>(), -        ) -    } -} - -impl<'a, T, Message, Renderer> From<Slider<'a, T, Message, Renderer>> -    for Element<'a, Message, Renderer> -where -    T: 'a + Copy + Into<f64> + num_traits::FromPrimitive, -    Message: 'a + Clone, -    Renderer: 'a + iced_native::Renderer, -    Renderer::Theme: StyleSheet, -{ -    fn from( -        slider: Slider<'a, T, Message, Renderer>, -    ) -> Element<'a, Message, Renderer> { -        Element::new(slider) -    } -} diff --git a/pure/src/widget/space.rs b/pure/src/widget/space.rs deleted file mode 100644 index 408cb647..00000000 --- a/pure/src/widget/space.rs +++ /dev/null @@ -1,101 +0,0 @@ -use crate::widget::Tree; -use crate::{Element, Widget}; - -use iced_native::event::{self, Event}; -use iced_native::layout::{self, Layout}; -use iced_native::mouse; -use iced_native::renderer; -use iced_native::{Clipboard, Length, Point, Rectangle, Shell}; - -pub use iced_native::widget::Space; - -impl<Message, Renderer> Widget<Message, Renderer> for Space -where -    Renderer: iced_native::Renderer, -{ -    fn width(&self) -> Length { -        <Self as iced_native::Widget<Message, Renderer>>::width(self) -    } - -    fn height(&self) -> Length { -        <Self as iced_native::Widget<Message, Renderer>>::height(self) -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        <Self as iced_native::Widget<Message, Renderer>>::layout( -            self, renderer, limits, -        ) -    } - -    fn on_event( -        &mut self, -        _state: &mut Tree, -        event: Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        <Self as iced_native::Widget<Message, Renderer>>::on_event( -            self, -            event, -            layout, -            cursor_position, -            renderer, -            clipboard, -            shell, -        ) -    } - -    fn draw( -        &self, -        _tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -    ) { -        <Self as iced_native::Widget<Message, Renderer>>::draw( -            self, -            renderer, -            theme, -            style, -            layout, -            cursor_position, -            viewport, -        ) -    } - -    fn mouse_interaction( -        &self, -        _state: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -        renderer: &Renderer, -    ) -> mouse::Interaction { -        <Self as iced_native::Widget<Message, Renderer>>::mouse_interaction( -            self, -            layout, -            cursor_position, -            viewport, -            renderer, -        ) -    } -} - -impl<'a, Message, Renderer> From<Space> for Element<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer + 'a, -{ -    fn from(space: Space) -> Self { -        Self::new(space) -    } -} diff --git a/pure/src/widget/svg.rs b/pure/src/widget/svg.rs deleted file mode 100644 index ae4e8cff..00000000 --- a/pure/src/widget/svg.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! Display vector graphics in your application. -use crate::widget::{Tree, Widget}; -use crate::Element; - -use iced_native::layout::{self, Layout}; -use iced_native::renderer; -use iced_native::widget::svg; -use iced_native::{Length, Point, Rectangle}; - -pub use iced_native::svg::Handle; -pub use svg::Svg; - -impl<Message, Renderer> Widget<Message, Renderer> for Svg -where -    Renderer: iced_native::svg::Renderer, -{ -    fn width(&self) -> Length { -        <Self as iced_native::Widget<Message, Renderer>>::width(self) -    } - -    fn height(&self) -> Length { -        <Self as iced_native::Widget<Message, Renderer>>::height(self) -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        <Self as iced_native::Widget<Message, Renderer>>::layout( -            self, renderer, limits, -        ) -    } - -    fn draw( -        &self, -        _tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -    ) { -        <Self as iced_native::Widget<Message, Renderer>>::draw( -            self, -            renderer, -            theme, -            style, -            layout, -            cursor_position, -            viewport, -        ) -    } -} - -impl<'a, Message, Renderer> From<Svg> for Element<'a, Message, Renderer> -where -    Message: Clone + 'a, -    Renderer: iced_native::svg::Renderer + 'a, -{ -    fn from(svg: Svg) -> Self { -        Self::new(svg) -    } -} diff --git a/pure/src/widget/text.rs b/pure/src/widget/text.rs deleted file mode 100644 index 7c6f6ce9..00000000 --- a/pure/src/widget/text.rs +++ /dev/null @@ -1,77 +0,0 @@ -//! Write some text for your users to read. -use crate::widget::Tree; -use crate::{Element, Widget}; - -use iced_native::layout::{self, Layout}; -use iced_native::renderer; -use iced_native::text; -use iced_native::widget; -use iced_native::{Length, Point, Rectangle}; - -pub use iced_native::widget::text::{Appearance, StyleSheet, Text}; - -impl<Message, Renderer> Widget<Message, Renderer> for Text<Renderer> -where -    Renderer: text::Renderer, -    Renderer::Theme: widget::text::StyleSheet, -{ -    fn width(&self) -> Length { -        <Self as iced_native::Widget<Message, Renderer>>::width(self) -    } - -    fn height(&self) -> Length { -        <Self as iced_native::Widget<Message, Renderer>>::height(self) -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        <Self as iced_native::Widget<Message, Renderer>>::layout( -            self, renderer, limits, -        ) -    } - -    fn draw( -        &self, -        _tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -    ) { -        <Self as iced_native::Widget<Message, Renderer>>::draw( -            self, -            renderer, -            theme, -            style, -            layout, -            cursor_position, -            viewport, -        ) -    } -} - -impl<'a, Message, Renderer> From<Text<Renderer>> -    for Element<'a, Message, Renderer> -where -    Renderer: text::Renderer + 'a, -    Renderer::Theme: widget::text::StyleSheet, -{ -    fn from(text: Text<Renderer>) -> Self { -        Self::new(text) -    } -} - -impl<'a, Message, Renderer> From<&'a str> for Element<'a, Message, Renderer> -where -    Renderer: text::Renderer + 'a, -    Renderer::Theme: widget::text::StyleSheet, -{ -    fn from(contents: &'a str) -> Self { -        Text::new(contents).into() -    } -} diff --git a/pure/src/widget/text_input.rs b/pure/src/widget/text_input.rs deleted file mode 100644 index 514a6795..00000000 --- a/pure/src/widget/text_input.rs +++ /dev/null @@ -1,285 +0,0 @@ -//! Display fields that can be filled with text. -use crate::widget::tree::{self, Tree}; -use crate::{Element, Widget}; - -use iced_native::event::{self, Event}; -use iced_native::layout::{self, Layout}; -use iced_native::mouse; -use iced_native::renderer; -use iced_native::text; -use iced_native::widget::text_input; -use iced_native::{Clipboard, Length, Padding, Point, Rectangle, Shell}; - -pub use iced_style::text_input::{Appearance, StyleSheet}; - -/// A field that can be filled with text. -/// -/// # Example -/// ``` -/// # pub type TextInput<'a, Message> = iced_pure::widget::TextInput<'a, Message, iced_native::renderer::Null>; -/// #[derive(Debug, Clone)] -/// enum Message { -///     TextInputChanged(String), -/// } -/// -/// let value = "Some text"; -/// -/// let input = TextInput::new( -///     "This is the placeholder...", -///     value, -///     Message::TextInputChanged, -/// ) -/// .padding(10); -/// ``` -///  -#[allow(missing_debug_implementations)] -pub struct TextInput<'a, Message, Renderer> -where -    Renderer: text::Renderer, -    Renderer::Theme: StyleSheet, -{ -    placeholder: String, -    value: text_input::Value, -    is_secure: bool, -    font: Renderer::Font, -    width: Length, -    padding: Padding, -    size: Option<u16>, -    on_change: Box<dyn Fn(String) -> Message + 'a>, -    on_paste: Option<Box<dyn Fn(String) -> Message + 'a>>, -    on_submit: Option<Message>, -    style: <Renderer::Theme as StyleSheet>::Style, -} - -impl<'a, Message, Renderer> TextInput<'a, Message, Renderer> -where -    Message: Clone, -    Renderer: text::Renderer, -    Renderer::Theme: StyleSheet, -{ -    /// Creates a new [`TextInput`]. -    /// -    /// It expects: -    /// - a placeholder, -    /// - the current value, and -    /// - a function that produces a message when the [`TextInput`] changes. -    pub fn new<F>(placeholder: &str, value: &str, on_change: F) -> Self -    where -        F: 'a + Fn(String) -> Message, -    { -        TextInput { -            placeholder: String::from(placeholder), -            value: text_input::Value::new(value), -            is_secure: false, -            font: Default::default(), -            width: Length::Fill, -            padding: Padding::ZERO, -            size: None, -            on_change: Box::new(on_change), -            on_paste: None, -            on_submit: None, -            style: Default::default(), -        } -    } - -    /// Converts the [`TextInput`] into a secure password input. -    pub fn password(mut self) -> Self { -        self.is_secure = true; -        self -    } - -    /// Sets the message that should be produced when some text is pasted into -    /// the [`TextInput`]. -    pub fn on_paste( -        mut self, -        on_paste: impl Fn(String) -> Message + 'a, -    ) -> Self { -        self.on_paste = Some(Box::new(on_paste)); -        self -    } - -    /// Sets the [`Font`] of the [`TextInput`]. -    /// -    /// [`Font`]: text::Renderer::Font -    pub fn font(mut self, font: Renderer::Font) -> Self { -        self.font = font; -        self -    } -    /// Sets the width of the [`TextInput`]. -    pub fn width(mut self, width: Length) -> Self { -        self.width = width; -        self -    } - -    /// Sets the [`Padding`] of the [`TextInput`]. -    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self { -        self.padding = padding.into(); -        self -    } - -    /// Sets the text size of the [`TextInput`]. -    pub fn size(mut self, size: u16) -> Self { -        self.size = Some(size); -        self -    } - -    /// Sets the message that should be produced when the [`TextInput`] is -    /// focused and the enter key is pressed. -    pub fn on_submit(mut self, message: Message) -> Self { -        self.on_submit = Some(message); -        self -    } - -    /// Sets the style of the [`TextInput`]. -    pub fn style( -        mut self, -        style: impl Into<<Renderer::Theme as StyleSheet>::Style>, -    ) -> Self { -        self.style = style.into(); -        self -    } - -    /// Draws the [`TextInput`] with the given [`Renderer`], overriding its -    /// [`text_input::Value`] if provided. -    /// -    /// [`Renderer`]: text::Renderer -    pub fn draw( -        &self, -        tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        layout: Layout<'_>, -        cursor_position: Point, -        value: Option<&text_input::Value>, -    ) { -        text_input::draw( -            renderer, -            theme, -            layout, -            cursor_position, -            tree.state.downcast_ref::<text_input::State>(), -            value.unwrap_or(&self.value), -            &self.placeholder, -            self.size, -            &self.font, -            self.is_secure, -            self.style, -        ) -    } -} - -impl<'a, Message, Renderer> Widget<Message, Renderer> -    for TextInput<'a, Message, Renderer> -where -    Message: Clone, -    Renderer: text::Renderer, -    Renderer::Theme: StyleSheet, -{ -    fn tag(&self) -> tree::Tag { -        tree::Tag::of::<text_input::State>() -    } - -    fn state(&self) -> tree::State { -        tree::State::new(text_input::State::new()) -    } - -    fn width(&self) -> Length { -        self.width -    } - -    fn height(&self) -> Length { -        Length::Shrink -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        text_input::layout( -            renderer, -            limits, -            self.width, -            self.padding, -            self.size, -        ) -    } - -    fn on_event( -        &mut self, -        tree: &mut Tree, -        event: Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        text_input::update( -            event, -            layout, -            cursor_position, -            renderer, -            clipboard, -            shell, -            &mut self.value, -            self.size, -            &self.font, -            self.is_secure, -            self.on_change.as_ref(), -            self.on_paste.as_deref(), -            &self.on_submit, -            || tree.state.downcast_mut::<text_input::State>(), -        ) -    } - -    fn draw( -        &self, -        tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        _style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        _viewport: &Rectangle, -    ) { -        text_input::draw( -            renderer, -            theme, -            layout, -            cursor_position, -            tree.state.downcast_ref::<text_input::State>(), -            &self.value, -            &self.placeholder, -            self.size, -            &self.font, -            self.is_secure, -            self.style, -        ) -    } - -    fn mouse_interaction( -        &self, -        _state: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        _viewport: &Rectangle, -        _renderer: &Renderer, -    ) -> mouse::Interaction { -        text_input::mouse_interaction(layout, cursor_position) -    } -} - -impl<'a, Message, Renderer> From<TextInput<'a, Message, Renderer>> -    for Element<'a, Message, Renderer> -where -    Message: 'a + Clone, -    Renderer: 'a + text::Renderer, -    Renderer::Theme: StyleSheet, -{ -    fn from( -        text_input: TextInput<'a, Message, Renderer>, -    ) -> Element<'a, Message, Renderer> { -        Element::new(text_input) -    } -} diff --git a/pure/src/widget/toggler.rs b/pure/src/widget/toggler.rs deleted file mode 100644 index 8d0044d2..00000000 --- a/pure/src/widget/toggler.rs +++ /dev/null @@ -1,109 +0,0 @@ -//! Show toggle controls using togglers. -use crate::widget::{Tree, Widget}; -use crate::Element; - -use iced_native::event::{self, Event}; -use iced_native::layout::{self, Layout}; -use iced_native::mouse; -use iced_native::renderer; -use iced_native::text; -use iced_native::widget; -use iced_native::{Clipboard, Length, Point, Rectangle, Shell}; - -pub use iced_native::widget::toggler::{Appearance, StyleSheet, Toggler}; - -impl<'a, Message, Renderer> Widget<Message, Renderer> -    for Toggler<'a, Message, Renderer> -where -    Renderer: text::Renderer, -    Renderer::Theme: StyleSheet + widget::text::StyleSheet, -{ -    fn width(&self) -> Length { -        <Self as iced_native::Widget<Message, Renderer>>::width(self) -    } - -    fn height(&self) -> Length { -        <Self as iced_native::Widget<Message, Renderer>>::height(self) -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        <Self as iced_native::Widget<Message, Renderer>>::layout( -            self, renderer, limits, -        ) -    } - -    fn draw( -        &self, -        _state: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -    ) { -        <Self as iced_native::Widget<Message, Renderer>>::draw( -            self, -            renderer, -            theme, -            style, -            layout, -            cursor_position, -            viewport, -        ) -    } - -    fn mouse_interaction( -        &self, -        _state: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -        renderer: &Renderer, -    ) -> mouse::Interaction { -        <Self as iced_native::Widget<Message, Renderer>>::mouse_interaction( -            self, -            layout, -            cursor_position, -            viewport, -            renderer, -        ) -    } - -    fn on_event( -        &mut self, -        _state: &mut Tree, -        event: Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        <Self as iced_native::Widget<Message, Renderer>>::on_event( -            self, -            event, -            layout, -            cursor_position, -            renderer, -            clipboard, -            shell, -        ) -    } -} - -impl<'a, Message, Renderer> From<Toggler<'a, Message, Renderer>> -    for Element<'a, Message, Renderer> -where -    Message: 'a, -    Renderer: text::Renderer + 'a, -    Renderer::Theme: StyleSheet + widget::text::StyleSheet, -{ -    fn from(toggler: Toggler<'a, Message, Renderer>) -> Self { -        Self::new(toggler) -    } -} diff --git a/pure/src/widget/tooltip.rs b/pure/src/widget/tooltip.rs deleted file mode 100644 index cbc34722..00000000 --- a/pure/src/widget/tooltip.rs +++ /dev/null @@ -1,240 +0,0 @@ -//! Display a widget over another. -use crate::widget::Tree; -use crate::{Element, Widget}; -use iced_native::event::{self, Event}; -use iced_native::layout; -use iced_native::mouse; -use iced_native::overlay; -use iced_native::renderer; -use iced_native::text; -use iced_native::widget::container; -use iced_native::widget::tooltip; -use iced_native::widget::{self, Text}; -use iced_native::{Clipboard, Layout, Length, Point, Rectangle, Shell}; - -pub use iced_style::container::{Appearance, StyleSheet}; -pub use tooltip::Position; - -/// An element to display a widget over another. -#[allow(missing_debug_implementations)] -pub struct Tooltip<'a, Message, Renderer: text::Renderer> -where -    Renderer: text::Renderer, -    Renderer::Theme: container::StyleSheet + widget::text::StyleSheet, -{ -    content: Element<'a, Message, Renderer>, -    tooltip: Text<Renderer>, -    position: Position, -    gap: u16, -    padding: u16, -    style: <Renderer::Theme as container::StyleSheet>::Style, -} - -impl<'a, Message, Renderer> Tooltip<'a, Message, Renderer> -where -    Renderer: text::Renderer, -    Renderer::Theme: container::StyleSheet + widget::text::StyleSheet, -{ -    /// The default padding of a [`Tooltip`] drawn by this renderer. -    const DEFAULT_PADDING: u16 = 5; - -    /// Creates a new [`Tooltip`]. -    /// -    /// [`Tooltip`]: struct.Tooltip.html -    pub fn new( -        content: impl Into<Element<'a, Message, Renderer>>, -        tooltip: impl ToString, -        position: Position, -    ) -> Self { -        Tooltip { -            content: content.into(), -            tooltip: Text::new(tooltip.to_string()), -            position, -            gap: 0, -            padding: Self::DEFAULT_PADDING, -            style: Default::default(), -        } -    } - -    /// Sets the size of the text of the [`Tooltip`]. -    pub fn size(mut self, size: u16) -> Self { -        self.tooltip = self.tooltip.size(size); -        self -    } - -    /// Sets the font of the [`Tooltip`]. -    /// -    /// [`Font`]: Renderer::Font -    pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self { -        self.tooltip = self.tooltip.font(font); -        self -    } - -    /// Sets the gap between the content and its [`Tooltip`]. -    pub fn gap(mut self, gap: u16) -> Self { -        self.gap = gap; -        self -    } - -    /// Sets the padding of the [`Tooltip`]. -    pub fn padding(mut self, padding: u16) -> Self { -        self.padding = padding; -        self -    } - -    /// Sets the style of the [`Tooltip`]. -    pub fn style( -        mut self, -        style: impl Into<<Renderer::Theme as container::StyleSheet>::Style>, -    ) -> Self { -        self.style = style.into(); -        self -    } -} - -impl<'a, Message, Renderer> Widget<Message, Renderer> -    for Tooltip<'a, Message, Renderer> -where -    Renderer: text::Renderer, -    Renderer::Theme: container::StyleSheet + widget::text::StyleSheet, -{ -    fn children(&self) -> Vec<Tree> { -        vec![Tree::new(&self.content)] -    } - -    fn diff(&self, tree: &mut Tree) { -        tree.diff_children(std::slice::from_ref(&self.content)) -    } - -    fn width(&self) -> Length { -        self.content.as_widget().width() -    } - -    fn height(&self) -> Length { -        self.content.as_widget().height() -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        self.content.as_widget().layout(renderer, limits) -    } - -    fn on_event( -        &mut self, -        tree: &mut Tree, -        event: Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        self.content.as_widget_mut().on_event( -            &mut tree.children[0], -            event, -            layout, -            cursor_position, -            renderer, -            clipboard, -            shell, -        ) -    } - -    fn mouse_interaction( -        &self, -        tree: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -        renderer: &Renderer, -    ) -> mouse::Interaction { -        self.content.as_widget().mouse_interaction( -            &tree.children[0], -            layout.children().next().unwrap(), -            cursor_position, -            viewport, -            renderer, -        ) -    } - -    fn draw( -        &self, -        tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        inherited_style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -    ) { -        self.content.as_widget().draw( -            &tree.children[0], -            renderer, -            theme, -            inherited_style, -            layout, -            cursor_position, -            viewport, -        ); - -        let tooltip = &self.tooltip; - -        tooltip::draw( -            renderer, -            theme, -            inherited_style, -            layout, -            cursor_position, -            viewport, -            self.position, -            self.gap, -            self.padding, -            self.style, -            |renderer, limits| { -                Widget::<(), Renderer>::layout(tooltip, renderer, limits) -            }, -            |renderer, defaults, layout, cursor_position, viewport| { -                Widget::<(), Renderer>::draw( -                    tooltip, -                    &Tree::empty(), -                    renderer, -                    theme, -                    defaults, -                    layout, -                    cursor_position, -                    viewport, -                ); -            }, -        ); -    } - -    fn overlay<'b>( -        &'b self, -        tree: &'b mut Tree, -        layout: Layout<'_>, -        renderer: &Renderer, -    ) -> Option<overlay::Element<'b, Message, Renderer>> { -        self.content.as_widget().overlay( -            &mut tree.children[0], -            layout, -            renderer, -        ) -    } -} - -impl<'a, Message, Renderer> From<Tooltip<'a, Message, Renderer>> -    for Element<'a, Message, Renderer> -where -    Message: 'a, -    Renderer: 'a + text::Renderer, -    Renderer::Theme: container::StyleSheet + widget::text::StyleSheet, -{ -    fn from( -        tooltip: Tooltip<'a, Message, Renderer>, -    ) -> Element<'a, Message, Renderer> { -        Element::new(tooltip) -    } -} diff --git a/pure/src/widget/tree.rs b/pure/src/widget/tree.rs deleted file mode 100644 index 2f876523..00000000 --- a/pure/src/widget/tree.rs +++ /dev/null @@ -1,176 +0,0 @@ -//! Store internal widget state in a state tree to ensure continuity. -use crate::Widget; - -use std::any::{self, Any}; -use std::borrow::Borrow; - -/// A persistent state widget tree. -/// -/// A [`Tree`] is normally associated with a specific widget in the widget tree. -pub struct Tree { -    /// The tag of the [`Tree`]. -    pub tag: Tag, - -    /// The [`State`] of the [`Tree`]. -    pub state: State, - -    /// The children of the root widget of the [`Tree`]. -    pub children: Vec<Tree>, -} - -impl Tree { -    /// Creates an empty, stateless [`Tree`] with no children. -    pub fn empty() -> Self { -        Self { -            tag: Tag::stateless(), -            state: State::None, -            children: Vec::new(), -        } -    } - -    /// Creates a new [`Tree`] for the provided [`Element`]. -    pub fn new<'a, Message, Renderer>( -        widget: impl Borrow<dyn Widget<Message, Renderer> + 'a>, -    ) -> Self -    where -        Renderer: iced_native::Renderer, -    { -        let widget = widget.borrow(); - -        Self { -            tag: widget.tag(), -            state: widget.state(), -            children: widget.children(), -        } -    } - -    /// Reconciliates the current tree with the provided [`Element`]. -    /// -    /// If the tag of the [`Element`] matches the tag of the [`Tree`], then the -    /// [`Element`] proceeds with the reconciliation (i.e. [`Widget::diff`] is called). -    /// -    /// Otherwise, the whole [`Tree`] is recreated. -    /// -    /// [`Widget::diff`]: crate::Widget::diff -    pub fn diff<'a, Message, Renderer>( -        &mut self, -        new: impl Borrow<dyn Widget<Message, Renderer> + 'a>, -    ) where -        Renderer: iced_native::Renderer, -    { -        if self.tag == new.borrow().tag() { -            new.borrow().diff(self) -        } else { -            *self = Self::new(new); -        } -    } - -    /// Reconciliates the children of the tree with the provided list of [`Element`]. -    pub fn diff_children<'a, Message, Renderer>( -        &mut self, -        new_children: &[impl Borrow<dyn Widget<Message, Renderer> + 'a>], -    ) where -        Renderer: iced_native::Renderer, -    { -        self.diff_children_custom( -            new_children, -            |tree, widget| tree.diff(widget.borrow()), -            |widget| Self::new(widget.borrow()), -        ) -    } - -    /// Reconciliates the children of the tree with the provided list of [`Element`] using custom -    /// logic both for diffing and creating new widget state. -    pub fn diff_children_custom<T>( -        &mut self, -        new_children: &[T], -        diff: impl Fn(&mut Tree, &T), -        new_state: impl Fn(&T) -> Self, -    ) { -        if self.children.len() > new_children.len() { -            self.children.truncate(new_children.len()); -        } - -        for (child_state, new) in -            self.children.iter_mut().zip(new_children.iter()) -        { -            diff(child_state, new); -        } - -        if self.children.len() < new_children.len() { -            self.children.extend( -                new_children[self.children.len()..].iter().map(new_state), -            ); -        } -    } -} - -/// The identifier of some widget state. -#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)] -pub struct Tag(any::TypeId); - -impl Tag { -    /// Creates a [`Tag`] for a state of type `T`. -    pub fn of<T>() -> Self -    where -        T: 'static, -    { -        Self(any::TypeId::of::<T>()) -    } - -    /// Creates a [`Tag`] for a stateless widget. -    pub fn stateless() -> Self { -        Self::of::<()>() -    } -} - -/// The internal [`State`] of a widget. -pub enum State { -    /// No meaningful internal state. -    None, - -    /// Some meaningful internal state. -    Some(Box<dyn Any>), -} - -impl State { -    /// Creates a new [`State`]. -    pub fn new<T>(state: T) -> Self -    where -        T: 'static, -    { -        State::Some(Box::new(state)) -    } - -    /// Downcasts the [`State`] to `T` and returns a reference to it. -    /// -    /// # Panics -    /// This method will panic if the downcast fails or the [`State`] is [`State::None`]. -    pub fn downcast_ref<T>(&self) -> &T -    where -        T: 'static, -    { -        match self { -            State::None => panic!("Downcast on stateless state"), -            State::Some(state) => { -                state.downcast_ref().expect("Downcast widget state") -            } -        } -    } - -    /// Downcasts the [`State`] to `T` and returns a mutable reference to it. -    /// -    /// # Panics -    /// This method will panic if the downcast fails or the [`State`] is [`State::None`]. -    pub fn downcast_mut<T>(&mut self) -> &mut T -    where -        T: 'static, -    { -        match self { -            State::None => panic!("Downcast on stateless state"), -            State::Some(state) => { -                state.downcast_mut().expect("Downcast widget state") -            } -        } -    } -}  | 
