Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nested overlays #1719

Merged
merged 13 commits into from
Jun 14, 2023
16 changes: 15 additions & 1 deletion core/src/overlay.rs
Expand Up @@ -91,9 +91,23 @@ where
///
/// By default, it returns true if the bounds of the `layout` contain
/// the `cursor_position`.
fn is_over(&self, layout: Layout<'_>, cursor_position: Point) -> bool {
fn is_over(
&self,
layout: Layout<'_>,
_renderer: &Renderer,
cursor_position: Point,
) -> bool {
layout.bounds().contains(cursor_position)
}

/// Returns the nested overlay of the [`Overlay`], if there is any.
fn overlay<'a>(
&'a mut self,
_layout: Layout<'_>,
_renderer: &Renderer,
) -> Option<Element<'a, Message, Renderer>> {
None
}
}

/// Returns a [`Group`] of overlay [`Element`] children.
Expand Down
37 changes: 33 additions & 4 deletions core/src/overlay/element.rs
Expand Up @@ -112,8 +112,22 @@ where
}

/// Returns true if the cursor is over the [`Element`].
pub fn is_over(&self, layout: Layout<'_>, cursor_position: Point) -> bool {
self.overlay.is_over(layout, cursor_position)
pub fn is_over(
&self,
layout: Layout<'_>,
renderer: &Renderer,
cursor_position: Point,
) -> bool {
self.overlay.is_over(layout, renderer, cursor_position)
}

/// Returns the nested overlay of the [`Element`], if there is any.
pub fn overlay<'b>(
&'b mut self,
layout: Layout<'_>,
renderer: &Renderer,
) -> Option<Element<'b, Message, Renderer>> {
self.overlay.overlay(layout, renderer)
}
}

Expand Down Expand Up @@ -248,7 +262,22 @@ where
self.content.draw(renderer, theme, style, layout, cursor)
}

fn is_over(&self, layout: Layout<'_>, cursor_position: Point) -> bool {
self.content.is_over(layout, cursor_position)
fn is_over(
&self,
layout: Layout<'_>,
renderer: &Renderer,
cursor_position: Point,
) -> bool {
self.content.is_over(layout, renderer, cursor_position)
}

fn overlay<'b>(
&'b mut self,
layout: Layout<'_>,
renderer: &Renderer,
) -> Option<Element<'b, B, Renderer>> {
self.content
.overlay(layout, renderer)
.map(|overlay| overlay.map(self.mapper))
}
}
26 changes: 24 additions & 2 deletions core/src/overlay/group.rs
Expand Up @@ -147,11 +147,33 @@ where
});
}

fn is_over(&self, layout: Layout<'_>, cursor_position: Point) -> bool {
fn is_over(
&self,
layout: Layout<'_>,
renderer: &Renderer,
cursor_position: Point,
) -> bool {
self.children
.iter()
.zip(layout.children())
.any(|(child, layout)| child.is_over(layout, cursor_position))
.any(|(child, layout)| {
child.is_over(layout, renderer, cursor_position)
})
}

fn overlay<'b>(
&'b mut self,
layout: Layout<'_>,
renderer: &Renderer,
) -> Option<overlay::Element<'b, Message, Renderer>> {
let children = self
.children
.iter_mut()
.zip(layout.children())
.filter_map(|(child, layout)| child.overlay(layout, renderer))
.collect::<Vec<_>>();

(!children.is_empty()).then(|| Group::with_children(children).overlay())
}
}

Expand Down
57 changes: 55 additions & 2 deletions examples/modal/src/main.rs
Expand Up @@ -3,11 +3,13 @@ use iced::keyboard;
use iced::subscription::{self, Subscription};
use iced::theme;
use iced::widget::{
self, button, column, container, horizontal_space, row, text, text_input,
self, button, column, container, horizontal_space, pick_list, row, text,
text_input,
};
use iced::{Alignment, Application, Command, Element, Event, Length, Settings};

use self::modal::Modal;
use modal::Modal;
use std::fmt;

pub fn main() -> iced::Result {
App::run(Settings::default())
Expand All @@ -18,6 +20,7 @@ struct App {
show_modal: bool,
email: String,
password: String,
plan: Plan,
}

#[derive(Debug, Clone)]
Expand All @@ -26,6 +29,7 @@ enum Message {
HideModal,
Email(String),
Password(String),
Plan(Plan),
Submit,
Event(Event),
}
Expand Down Expand Up @@ -66,6 +70,10 @@ impl Application for App {
self.password = password;
Command::none()
}
Message::Plan(plan) => {
self.plan = plan;
Command::none()
}
Message::Submit => {
if !self.email.is_empty() && !self.password.is_empty() {
self.hide_modal();
Expand Down Expand Up @@ -149,6 +157,16 @@ impl Application for App {
.padding(5),
]
.spacing(5),
column![
text("Plan").size(12),
pick_list(
Plan::ALL,
Some(self.plan),
Message::Plan
)
.padding(5),
]
.spacing(5),
button(text("Submit")).on_press(Message::HideModal),
]
.spacing(10)
Expand Down Expand Up @@ -176,6 +194,29 @@ impl App {
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
enum Plan {
#[default]
Basic,
Pro,
Enterprise,
}

impl Plan {
pub const ALL: &[Self] = &[Self::Basic, Self::Pro, Self::Enterprise];
}

impl fmt::Display for Plan {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Plan::Basic => "Basic",
Plan::Pro => "Pro",
Plan::Enterprise => "Enterprise",
}
.fmt(f)
}
}

mod modal {
use iced::advanced::layout::{self, Layout};
use iced::advanced::overlay;
Expand Down Expand Up @@ -469,6 +510,18 @@ mod modal {
renderer,
)
}

fn overlay<'c>(
&'c mut self,
layout: Layout<'_>,
renderer: &Renderer,
) -> Option<overlay::Element<'c, Message, Renderer>> {
self.content.as_widget_mut().overlay(
self.tree,
layout.children().next().unwrap(),
renderer,
)
}
}

impl<'a, Message, Renderer> From<Modal<'a, Message, Renderer>>
Expand Down
7 changes: 6 additions & 1 deletion examples/toast/src/main.rs
Expand Up @@ -650,7 +650,12 @@ mod toast {
.unwrap_or_default()
}

fn is_over(&self, layout: Layout<'_>, cursor_position: Point) -> bool {
fn is_over(
&self,
layout: Layout<'_>,
_renderer: &Renderer,
cursor_position: Point,
) -> bool {
layout
.children()
.any(|layout| layout.bounds().contains(cursor_position))
Expand Down
1 change: 1 addition & 0 deletions runtime/src/lib.rs
Expand Up @@ -47,6 +47,7 @@ pub mod clipboard;
pub mod command;
pub mod font;
pub mod keyboard;
pub mod overlay;
pub mod program;
pub mod system;
pub mod user_interface;
Expand Down
4 changes: 4 additions & 0 deletions runtime/src/overlay.rs
@@ -0,0 +1,4 @@
//! Overlays for user interfaces.
mod nested;

pub use nested::Nested;