Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 57 additions & 45 deletions examples/applet/src/window.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use cosmic::app::{Core, Task};

use cosmic::iced::window::Id;
use cosmic::iced::Length;
use cosmic::iced::{Length, Rectangle};
use cosmic::iced_runtime::core::window;
use cosmic::surface::action::{app_popup, destroy_popup};
use cosmic::widget::{dropdown::popup_dropdown, list_column, settings, toggler};
Expand Down Expand Up @@ -85,50 +85,62 @@ impl cosmic::Application for Window {
}

fn view(&self) -> Element<Message> {
let btn = self.core.applet.icon_button("display-symbolic").on_press(
if let Some(id) = self.popup {
Message::Surface(destroy_popup(id))
} else {
Message::Surface(app_popup::<Window>(
|state: &mut Window| {
let new_id = Id::unique();
state.popup = Some(new_id);
let popup_settings = state.core.applet.get_popup_settings(
state.core.main_window_id().unwrap(),
new_id,
None,
None,
None,
);

popup_settings
},
Some(Box::new(move |state: &Window| {
let content_list = list_column()
.padding(5)
.spacing(0)
.add(settings::item(
"Example row",
cosmic::widget::container(
toggler(state.example_row)
.on_toggle(|value| Message::ToggleExampleRow(value)),
)
.height(Length::Fixed(50.)),
))
.add(popup_dropdown(
&["1", "asdf", "hello", "test"],
state.selected,
Message::Selected,
state.popup.unwrap_or(Id::NONE),
Message::Surface,
|m| m,
));
Element::from(state.core.applet.popup_container(content_list))
.map(cosmic::Action::App)
})),
))
},
);
let have_popup = self.popup.clone();
let btn = self
.core
.applet
.icon_button("display-symbolic")
.on_press_with_rectangle(move |offset, bounds| {
if let Some(id) = have_popup {
Message::Surface(destroy_popup(id))
} else {
Message::Surface(app_popup::<Window>(
move |state: &mut Window| {
let new_id = Id::unique();
state.popup = Some(new_id);
let mut popup_settings = state.core.applet.get_popup_settings(
state.core.main_window_id().unwrap(),
new_id,
None,
None,
None,
);

popup_settings.positioner.anchor_rect = Rectangle {
x: (bounds.x - offset.x) as i32,
y: (bounds.y - offset.y) as i32,
width: bounds.width as i32,
height: bounds.height as i32,
};

popup_settings
},
Some(Box::new(move |state: &Window| {
let content_list = list_column()
.padding(5)
.spacing(0)
.add(settings::item(
"Example row",
cosmic::widget::container(
toggler(state.example_row)
.on_toggle(|value| Message::ToggleExampleRow(value)),
)
.height(Length::Fixed(50.)),
))
.add(popup_dropdown(
&["1", "asdf", "hello", "test"],
state.selected,
Message::Selected,
state.popup.unwrap_or(Id::NONE),
Message::Surface,
|m| m,
));
Element::from(state.core.applet.popup_container(content_list))
.map(cosmic::Action::App)
})),
))
}
});

Element::from(self.core.applet.applet_tooltip::<Message>(
btn,
Expand Down
6 changes: 3 additions & 3 deletions src/applet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ impl Context {
matches!(self.anchor, PanelAnchor::Top | PanelAnchor::Bottom)
}

pub fn icon_button_from_handle<'a, Message: 'static>(
pub fn icon_button_from_handle<'a, Message: Clone + 'static>(
&self,
icon: widget::icon::Handle,
) -> crate::widget::Button<'a, Message> {
Expand Down Expand Up @@ -206,7 +206,7 @@ impl Context {
.class(Button::AppletIcon)
}

pub fn icon_button<'a, Message: 'static>(
pub fn icon_button<'a, Message: Clone + 'static>(
&self,
icon_name: &'a str,
) -> crate::widget::Button<'a, Message> {
Expand Down Expand Up @@ -503,7 +503,7 @@ pub fn style() -> iced_runtime::Appearance {
}
}

pub fn menu_button<'a, Message>(
pub fn menu_button<'a, Message: Clone + 'a>(
content: impl Into<Element<'a, Message>>,
) -> crate::widget::Button<'a, Message> {
crate::widget::button::custom(content)
Expand Down
6 changes: 4 additions & 2 deletions src/widget/button/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ use iced_core::{Length, Padding};
use std::borrow::Cow;

/// A button with a custom element for its content.
pub fn custom<'a, Message>(content: impl Into<crate::Element<'a, Message>>) -> Button<'a, Message> {
pub fn custom<'a, Message: Clone + 'a>(
content: impl Into<crate::Element<'a, Message>>,
) -> Button<'a, Message> {
Button::new(content.into())
}

/// An image button which may contain any widget as its content.
pub fn custom_image_button<'a, Message>(
pub fn custom_image_button<'a, Message: Clone + 'a>(
content: impl Into<crate::Element<'a, Message>>,
on_remove: Option<Message>,
) -> Button<'a, Message> {
Expand Down
102 changes: 87 additions & 15 deletions src/widget/button/widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ pub struct Button<'a, Message> {
#[cfg(feature = "a11y")]
label: Option<Vec<iced_accessibility::accesskit::NodeId>>,
content: crate::Element<'a, Message>,
on_press: Option<Message>,
on_press_down: Option<Message>,
on_press: Option<Box<dyn Fn(Vector, Rectangle) -> Message + 'a>>,
on_press_down: Option<Box<dyn Fn(Vector, Rectangle) -> Message + 'a>>,
width: Length,
height: Length,
padding: Padding,
Expand All @@ -58,7 +58,7 @@ pub struct Button<'a, Message> {
force_enabled: bool,
}

impl<'a, Message> Button<'a, Message> {
impl<'a, Message: Clone + 'a> Button<'a, Message> {
/// Creates a new [`Button`] with the given content.
pub(super) fn new(content: impl Into<crate::Element<'a, Message>>) -> Self {
Self {
Expand Down Expand Up @@ -150,7 +150,19 @@ impl<'a, Message> Button<'a, Message> {
/// Unless `on_press` or `on_press_down` is called, the [`Button`] will be disabled.
#[inline]
pub fn on_press(mut self, on_press: Message) -> Self {
self.on_press = Some(on_press);
self.on_press = Some(Box::new(move |_, _| on_press.clone()));
self
}

/// Sets the message that will be produced when the [`Button`] is pressed and released.
///
/// Unless `on_press` or `on_press_down` is called, the [`Button`] will be disabled.
#[inline]
pub fn on_press_with_rectangle(
mut self,
on_press: impl Fn(Vector, Rectangle) -> Message + 'a,
) -> Self {
self.on_press = Some(Box::new(on_press));
self
}

Expand All @@ -159,7 +171,19 @@ impl<'a, Message> Button<'a, Message> {
/// Unless `on_press` or `on_press_down` is called, the [`Button`] will be disabled.
#[inline]
pub fn on_press_down(mut self, on_press: Message) -> Self {
self.on_press_down = Some(on_press);
self.on_press_down = Some(Box::new(move |_, _| on_press.clone()));
self
}

/// Sets the message that will be produced when the [`Button`] is pressed,
///
/// Unless `on_press` or `on_press_down` is called, the [`Button`] will be disabled.
#[inline]
pub fn on_press_down_with_rectange(
mut self,
on_press: impl Fn(Vector, Rectangle) -> Message + 'a,
) -> Self {
self.on_press_down = Some(Box::new(on_press));
self
}

Expand All @@ -169,7 +193,49 @@ impl<'a, Message> Button<'a, Message> {
/// If `None`, the [`Button`] will be disabled.
#[inline]
pub fn on_press_maybe(mut self, on_press: Option<Message>) -> Self {
self.on_press = on_press;
if let Some(m) = on_press {
self.on_press(m)
} else {
self.on_press = None;
self
}
}

/// Sets the message that will be produced when the [`Button`] is pressed and released.
///
/// Unless `on_press` or `on_press_down` is called, the [`Button`] will be disabled.
#[inline]
pub fn on_press_maybe_with_rectangle(
mut self,
on_press: impl Fn(Vector, Rectangle) -> Message + 'a,
) -> Self {
self.on_press = Some(Box::new(on_press));
self
}

/// Sets the message that will be produced when the [`Button`] is pressed,
/// if `Some`.
///
/// If `None`, the [`Button`] will be disabled.
#[inline]
pub fn on_press_down_maybe(mut self, on_press: Option<Message>) -> Self {
if let Some(m) = on_press {
self.on_press(m)
} else {
self.on_press_down = None;
self
}
}

/// Sets the message that will be produced when the [`Button`] is pressed and released.
///
/// Unless `on_press` or `on_press_down` is called, the [`Button`] will be disabled.
#[inline]
pub fn on_press_down_maybe_with_rectangle(
mut self,
on_press: impl Fn(Vector, Rectangle) -> Message + 'a,
) -> Self {
self.on_press_down = Some(Box::new(on_press));
self
}

Expand Down Expand Up @@ -350,8 +416,8 @@ impl<'a, Message: 'a + Clone> Widget<Message, crate::Theme, crate::Renderer>
layout,
cursor,
shell,
&self.on_press,
&self.on_press_down,
self.on_press.as_deref(),
self.on_press_down.as_deref(),
|| tree.state.downcast_mut::<State>(),
)
}
Expand Down Expand Up @@ -710,15 +776,15 @@ impl State {

/// Processes the given [`Event`] and updates the [`State`] of a [`Button`]
/// accordingly.
#[allow(clippy::needless_pass_by_value)]
#[allow(clippy::needless_pass_by_value, clippy::too_many_arguments)]
pub fn update<'a, Message: Clone>(
_id: Id,
event: Event,
layout: Layout<'_>,
cursor: mouse::Cursor,
shell: &mut Shell<'_, Message>,
on_press: &Option<Message>,
on_press_down: &Option<Message>,
on_press: Option<&dyn Fn(Vector, Rectangle) -> Message>,
on_press_down: Option<&dyn Fn(Vector, Rectangle) -> Message>,
state: impl FnOnce() -> &'a mut State,
) -> event::Status {
match event {
Expand All @@ -735,7 +801,8 @@ pub fn update<'a, Message: Clone>(
state.is_pressed = true;

if let Some(on_press_down) = on_press_down {
shell.publish(on_press_down.clone());
let msg = (on_press_down)(layout.virtual_offset(), layout.bounds());
shell.publish(msg);
}

return event::Status::Captured;
Expand All @@ -753,7 +820,8 @@ pub fn update<'a, Message: Clone>(
let bounds = layout.bounds();

if cursor.is_over(bounds) {
shell.publish(on_press);
let msg = (on_press)(layout.virtual_offset(), layout.bounds());
shell.publish(msg);
}

return event::Status::Captured;
Expand All @@ -771,7 +839,9 @@ pub fn update<'a, Message: Clone>(
.then(|| on_press.clone())
{
state.is_pressed = false;
shell.publish(on_press);
let msg = (on_press)(layout.virtual_offset(), layout.bounds());

shell.publish(msg);
}
return event::Status::Captured;
}
Expand All @@ -780,7 +850,9 @@ pub fn update<'a, Message: Clone>(
let state = state();
if state.is_focused && key == keyboard::Key::Named(keyboard::key::Named::Enter) {
state.is_pressed = true;
shell.publish(on_press);
let msg = (on_press)(layout.virtual_offset(), layout.bounds());

shell.publish(msg);
return event::Status::Captured;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/widget/calendar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ where
}
}

fn date_button<Message>(
fn date_button<Message: Clone + 'static>(
date: NaiveDate,
is_currently_viewed_month: bool,
is_currently_selected_day: bool,
Expand Down
8 changes: 6 additions & 2 deletions src/widget/color_picker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,11 @@ impl ColorPickerModel {

/// Get a color picker button that displays the applied color
///
pub fn picker_button<'a, Message: 'static, T: Fn(ColorPickerUpdate) -> Message>(
pub fn picker_button<
'a,
Message: 'static + std::clone::Clone,
T: Fn(ColorPickerUpdate) -> Message,
>(
&self,
f: T,
icon_portion: Option<u16>,
Expand Down Expand Up @@ -888,7 +892,7 @@ fn color_to_string(c: palette::Hsv, is_hex: bool) -> String {

#[allow(clippy::too_many_lines)]
/// A button for selecting a color from a color picker.
pub fn color_button<'a, Message: 'static>(
pub fn color_button<'a, Message: Clone + 'static>(
on_press: Option<Message>,
color: Option<Color>,
icon_portion: Length,
Expand Down
Loading
Loading