Merge remote-tracking branch 'origin/master' into feat/multi-window-support

# Conflicts:
#	native/src/command/action.rs
#	native/src/window/action.rs
#	winit/src/window.rs
This commit is contained in:
Bingus 2023-02-15 14:55:02 -08:00
commit 63fb608d8b
No known key found for this signature in database
GPG key ID: 5F84D2AA40A9F170
55 changed files with 1218 additions and 224 deletions

View file

@ -11,6 +11,7 @@ use std::fmt;
use std::future::Future;
/// A set of asynchronous actions to be performed by some runtime.
#[must_use = "`Command` must be returned to runtime to take effect"]
pub struct Command<T>(iced_futures::Command<Action<T>>);
impl<T> Command<T> {

View file

@ -58,12 +58,12 @@ impl<T> fmt::Debug for Action<T> {
match self {
Self::Future(_) => write!(f, "Action::Future"),
Self::Clipboard(action) => {
write!(f, "Action::Clipboard({:?})", action)
write!(f, "Action::Clipboard({action:?})")
}
Self::Window(id, action) => {
write!(f, "Action::Window({:?}, {:?})", id, action)
write!(f, "Action::Window({id:?}, {action:?})")
}
Self::System(action) => write!(f, "Action::System({:?})", action),
Self::System(action) => write!(f, "Action::System({action:?})"),
Self::Widget(_action) => write!(f, "Action::Widget"),
}
}

View file

@ -133,7 +133,7 @@ impl Debug {
}
pub fn log_message<Message: std::fmt::Debug>(&mut self, message: &Message) {
self.last_messages.push_back(format!("{:?}", message));
self.last_messages.push_back(format!("{message:?}"));
if self.last_messages.len() > 10 {
let _ = self.last_messages.pop_front();
@ -150,7 +150,7 @@ impl Debug {
let mut lines = Vec::new();
fn key_value<T: std::fmt::Debug>(key: &str, value: T) -> String {
format!("{} {:?}", key, value)
format!("{key} {value:?}")
}
lines.push(format!(
@ -176,9 +176,9 @@ impl Debug {
lines.push(String::from("Last messages:"));
lines.extend(self.last_messages.iter().map(|msg| {
if msg.len() <= 100 {
format!(" {}", msg)
format!(" {msg}")
} else {
format!(" {:.100}...", msg)
format!(" {msg:.100}...")
}
}));

View file

@ -107,10 +107,10 @@ pub enum Data {
impl std::fmt::Debug for Data {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Data::Path(path) => write!(f, "Path({:?})", path),
Data::Path(path) => write!(f, "Path({path:?})"),
Data::Bytes(_) => write!(f, "Bytes(...)"),
Data::Rgba { width, height, .. } => {
write!(f, "Pixels({} * {})", width, height)
write!(f, "Pixels({width} * {height})")
}
}
}

View file

@ -1,9 +1,11 @@
//! Display interactive elements on top of other widgets.
mod element;
mod group;
pub mod menu;
pub use element::Element;
pub use group::Group;
pub use menu::Menu;
use crate::event::{self, Event};
@ -87,9 +89,17 @@ where
) -> mouse::Interaction {
mouse::Interaction::Idle
}
/// Returns true if the cursor is over the [`Overlay`].
///
/// 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 {
layout.bounds().contains(cursor_position)
}
}
/// Obtains the first overlay [`Element`] found in the given children.
/// Returns a [`Group`] of overlay [`Element`] children.
///
/// This method will generally only be used by advanced users that are
/// implementing the [`Widget`](crate::Widget) trait.
@ -102,12 +112,14 @@ pub fn from_children<'a, Message, Renderer>(
where
Renderer: crate::Renderer,
{
children
let children = children
.iter_mut()
.zip(&mut tree.children)
.zip(layout.children())
.filter_map(|((child, state), layout)| {
child.as_widget_mut().overlay(state, layout, renderer)
})
.next()
.collect::<Vec<_>>();
(!children.is_empty()).then(|| Group::with_children(children).overlay())
}

View file

@ -53,8 +53,14 @@ where
}
/// Computes the layout of the [`Element`] in the given bounds.
pub fn layout(&self, renderer: &Renderer, bounds: Size) -> layout::Node {
self.overlay.layout(renderer, bounds, self.position)
pub fn layout(
&self,
renderer: &Renderer,
bounds: Size,
translation: Vector,
) -> layout::Node {
self.overlay
.layout(renderer, bounds, self.position + translation)
}
/// Processes a runtime [`Event`].
@ -115,6 +121,11 @@ where
) {
self.overlay.operate(layout, renderer, operation);
}
/// 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)
}
}
struct Map<'a, A, B, Renderer> {
@ -252,4 +263,8 @@ where
self.content
.draw(renderer, theme, style, layout, cursor_position)
}
fn is_over(&self, layout: Layout<'_>, cursor_position: Point) -> bool {
self.content.is_over(layout, cursor_position)
}
}

174
native/src/overlay/group.rs Normal file
View file

@ -0,0 +1,174 @@
use iced_core::{Point, Rectangle, Size};
use crate::event;
use crate::layout;
use crate::mouse;
use crate::overlay;
use crate::renderer;
use crate::widget;
use crate::{Clipboard, Event, Layout, Overlay, Shell};
/// An [`Overlay`] container that displays multiple overlay [`overlay::Element`]
/// children.
#[allow(missing_debug_implementations)]
pub struct Group<'a, Message, Renderer> {
children: Vec<overlay::Element<'a, Message, Renderer>>,
}
impl<'a, Message, Renderer> Group<'a, Message, Renderer>
where
Renderer: 'a + crate::Renderer,
Message: 'a,
{
/// Creates an empty [`Group`].
pub fn new() -> Self {
Self::default()
}
/// Creates a [`Group`] with the given elements.
pub fn with_children(
children: Vec<overlay::Element<'a, Message, Renderer>>,
) -> Self {
Group { children }
}
/// Adds an [`overlay::Element`] to the [`Group`].
pub fn push(
mut self,
child: impl Into<overlay::Element<'a, Message, Renderer>>,
) -> Self {
self.children.push(child.into());
self
}
/// Turns the [`Group`] into an overlay [`overlay::Element`].
pub fn overlay(self) -> overlay::Element<'a, Message, Renderer> {
overlay::Element::new(Point::ORIGIN, Box::new(self))
}
}
impl<'a, Message, Renderer> Default for Group<'a, Message, Renderer>
where
Renderer: 'a + crate::Renderer,
Message: 'a,
{
fn default() -> Self {
Self::with_children(Vec::new())
}
}
impl<'a, Message, Renderer> Overlay<Message, Renderer>
for Group<'a, Message, Renderer>
where
Renderer: crate::Renderer,
{
fn layout(
&self,
renderer: &Renderer,
bounds: Size,
position: Point,
) -> layout::Node {
let translation = position - Point::ORIGIN;
layout::Node::with_children(
bounds,
self.children
.iter()
.map(|child| child.layout(renderer, bounds, translation))
.collect(),
)
}
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.children
.iter_mut()
.zip(layout.children())
.map(|(child, layout)| {
child.on_event(
event.clone(),
layout,
cursor_position,
renderer,
clipboard,
shell,
)
})
.fold(event::Status::Ignored, event::Status::merge)
}
fn draw(
&self,
renderer: &mut Renderer,
theme: &<Renderer as crate::Renderer>::Theme,
style: &renderer::Style,
layout: Layout<'_>,
cursor_position: Point,
) {
for (child, layout) in self.children.iter().zip(layout.children()) {
child.draw(renderer, theme, style, layout, cursor_position);
}
}
fn mouse_interaction(
&self,
layout: Layout<'_>,
cursor_position: Point,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
self.children
.iter()
.zip(layout.children())
.map(|(child, layout)| {
child.mouse_interaction(
layout,
cursor_position,
viewport,
renderer,
)
})
.max()
.unwrap_or_default()
}
fn operate(
&mut self,
layout: Layout<'_>,
renderer: &Renderer,
operation: &mut dyn widget::Operation<Message>,
) {
operation.container(None, &mut |operation| {
self.children.iter_mut().zip(layout.children()).for_each(
|(child, layout)| {
child.operate(layout, renderer, operation);
},
)
});
}
fn is_over(&self, layout: Layout<'_>, cursor_position: Point) -> bool {
self.children
.iter()
.zip(layout.children())
.any(|(child, layout)| child.is_over(layout, cursor_position))
}
}
impl<'a, Message, Renderer> From<Group<'a, Message, Renderer>>
for overlay::Element<'a, Message, Renderer>
where
Renderer: 'a + crate::Renderer,
Message: 'a,
{
fn from(group: Group<'a, Message, Renderer>) -> Self {
group.overlay()
}
}

View file

@ -281,10 +281,7 @@ where
renderer.fill_quad(
renderer::Quad {
bounds: Rectangle {
width: bounds.width - 1.0,
..bounds
},
bounds,
border_color: appearance.border_color,
border_width: appearance.border_width,
border_radius: appearance.border_radius.into(),

View file

@ -16,9 +16,9 @@ pub trait Renderer: Sized {
///
/// You should override this if you need to perform any operations before or
/// after layouting. For instance, trimming the measurements cache.
fn layout<'a, Message>(
fn layout<Message>(
&mut self,
element: &Element<'a, Message, Self>,
element: &Element<'_, Message, Self>,
limits: &layout::Limits,
) -> layout::Node {
element.as_widget().layout(self, limits)

View file

@ -25,6 +25,11 @@ impl<'a, Message> Shell<'a, Message> {
}
}
/// Returns true if the [`Shell`] contains no published messages
pub fn is_empty(&self) -> bool {
self.messages.is_empty()
}
/// Publish the given `Message` for an application to process it.
pub fn publish(&mut self, message: Message) {
self.messages.push(message);

View file

@ -71,7 +71,7 @@ pub enum Data {
impl std::fmt::Debug for Data {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Data::Path(path) => write!(f, "Path({:?})", path),
Data::Path(path) => write!(f, "Path({path:?})"),
Data::Bytes(_) => write!(f, "Bytes(...)"),
}
}

View file

@ -6,7 +6,9 @@ use crate::mouse;
use crate::renderer;
use crate::widget;
use crate::window;
use crate::{Clipboard, Element, Layout, Point, Rectangle, Shell, Size};
use crate::{
Clipboard, Element, Layout, Point, Rectangle, Shell, Size, Vector,
};
/// A set of interactive graphical elements with a specific [`Layout`].
///
@ -203,7 +205,7 @@ where
let bounds = self.bounds;
let mut overlay = manual_overlay.as_mut().unwrap();
let mut layout = overlay.layout(renderer, bounds);
let mut layout = overlay.layout(renderer, bounds, Vector::ZERO);
let mut event_statuses = Vec::new();
for event in events.iter().cloned() {
@ -252,7 +254,7 @@ where
overlay = manual_overlay.as_mut().unwrap();
shell.revalidate_layout(|| {
layout = overlay.layout(renderer, bounds);
layout = overlay.layout(renderer, bounds, Vector::ZERO);
});
}
@ -261,12 +263,16 @@ where
}
}
let base_cursor = if layout.bounds().contains(cursor_position) {
// TODO: Type-safe cursor availability
Point::new(-1.0, -1.0)
} else {
cursor_position
};
let base_cursor = manual_overlay
.as_ref()
.filter(|overlay| {
overlay.is_over(Layout::new(&layout), cursor_position)
})
.map(|_| {
// TODO: Type-safe cursor availability
Point::new(-1.0, -1.0)
})
.unwrap_or(cursor_position);
self.overlay = Some(layout);
@ -430,10 +436,9 @@ where
.as_widget_mut()
.overlay(&mut self.state, Layout::new(&self.base), renderer)
{
let overlay_layout = self
.overlay
.take()
.unwrap_or_else(|| overlay.layout(renderer, self.bounds));
let overlay_layout = self.overlay.take().unwrap_or_else(|| {
overlay.layout(renderer, self.bounds, Vector::ZERO)
});
let new_cursor_position =
if overlay_layout.bounds().contains(cursor_position) {
@ -504,7 +509,8 @@ where
);
});
if overlay_bounds.contains(cursor_position) {
if overlay.is_over(Layout::new(layout), cursor_position)
{
overlay_interaction
} else {
base_interaction
@ -533,7 +539,8 @@ where
renderer,
) {
if self.overlay.is_none() {
self.overlay = Some(overlay.layout(renderer, self.bounds));
self.overlay =
Some(overlay.layout(renderer, self.bounds, Vector::ZERO));
}
overlay.operate(

View file

@ -1,4 +1,6 @@
use crate::widget::operation::{self, Focusable, Operation, Scrollable};
use crate::widget::operation::{
self, Focusable, Operation, Scrollable, TextInput,
};
use crate::widget::Id;
use iced_futures::MaybeSend;
@ -86,6 +88,14 @@ where
self.operation.focusable(state, id);
}
fn text_input(
&mut self,
state: &mut dyn TextInput,
id: Option<&Id>,
) {
self.operation.text_input(state, id);
}
fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
self.operation.custom(state, id);
}

View file

@ -111,6 +111,45 @@ where
layout::Node::new(final_size)
}
/// Draws an [`Image`]
pub fn draw<Renderer, Handle>(
renderer: &mut Renderer,
layout: Layout<'_>,
handle: &Handle,
content_fit: ContentFit,
) where
Renderer: image::Renderer<Handle = Handle>,
Handle: Clone + Hash,
{
let Size { width, height } = renderer.dimensions(handle);
let image_size = Size::new(width as f32, height as f32);
let bounds = layout.bounds();
let adjusted_fit = content_fit.fit(image_size, bounds.size());
let render = |renderer: &mut Renderer| {
let offset = Vector::new(
(bounds.width - adjusted_fit.width).max(0.0) / 2.0,
(bounds.height - adjusted_fit.height).max(0.0) / 2.0,
);
let drawing_bounds = Rectangle {
width: adjusted_fit.width,
height: adjusted_fit.height,
..bounds
};
renderer.draw(handle.clone(), drawing_bounds + offset)
};
if adjusted_fit.width > bounds.width || adjusted_fit.height > bounds.height
{
renderer.with_layer(bounds, render);
} else {
render(renderer)
}
}
impl<Message, Renderer, Handle> Widget<Message, Renderer> for Image<Handle>
where
Renderer: image::Renderer<Handle = Handle>,
@ -149,34 +188,7 @@ where
_cursor_position: Point,
_viewport: &Rectangle,
) {
let Size { width, height } = renderer.dimensions(&self.handle);
let image_size = Size::new(width as f32, height as f32);
let bounds = layout.bounds();
let adjusted_fit = self.content_fit.fit(image_size, bounds.size());
let render = |renderer: &mut Renderer| {
let offset = Vector::new(
(bounds.width - adjusted_fit.width).max(0.0) / 2.0,
(bounds.height - adjusted_fit.height).max(0.0) / 2.0,
);
let drawing_bounds = Rectangle {
width: adjusted_fit.width,
height: adjusted_fit.height,
..bounds
};
renderer.draw(self.handle.clone(), drawing_bounds + offset)
};
if adjusted_fit.width > bounds.width
|| adjusted_fit.height > bounds.height
{
renderer.with_layer(bounds, render);
} else {
render(renderer)
}
draw(renderer, layout, &self.handle, self.content_fit)
}
}

View file

@ -62,7 +62,7 @@ where
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::None => write!(f, "Outcome::None"),
Self::Some(output) => write!(f, "Outcome::Some({:?})", output),
Self::Some(output) => write!(f, "Outcome::Some({output:?})"),
Self::Chain(_) => write!(f, "Outcome::Chain(...)"),
}
}

View file

@ -35,7 +35,7 @@ pub use iced_style::pane_grid::{Line, StyleSheet};
use crate::event::{self, Event};
use crate::layout;
use crate::mouse;
use crate::overlay;
use crate::overlay::{self, Group};
use crate::renderer;
use crate::touch;
use crate::widget;
@ -450,14 +450,17 @@ where
layout: Layout<'_>,
renderer: &Renderer,
) -> Option<overlay::Element<'_, Message, Renderer>> {
self.contents
let children = self
.contents
.iter_mut()
.zip(&mut tree.children)
.zip(layout.children())
.filter_map(|(((_, pane), tree), layout)| {
pane.overlay(tree, layout, renderer)
.filter_map(|(((_, content), state), layout)| {
content.overlay(state, layout, renderer)
})
.next()
.collect::<Vec<_>>();
(!children.is_empty()).then(|| Group::with_children(children).overlay())
}
}

View file

@ -20,60 +20,6 @@ use std::borrow::Cow;
pub use iced_style::pick_list::{Appearance, StyleSheet};
/// The handle to the right side of the [`PickList`].
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Handle<Renderer>
where
Renderer: text::Renderer,
{
/// Displays an arrow icon (▼).
///
/// This is the default.
Arrow {
/// Font size of the content.
size: Option<u16>,
},
/// A custom handle.
Custom {
/// Font that will be used to display the `text`,
font: Renderer::Font,
/// Text that will be shown.
text: String,
/// Font size of the content.
size: Option<u16>,
},
/// No handle will be shown.
None,
}
impl<Renderer> Default for Handle<Renderer>
where
Renderer: text::Renderer,
{
fn default() -> Self {
Self::Arrow { size: None }
}
}
impl<Renderer> Handle<Renderer>
where
Renderer: text::Renderer,
{
fn content(&self) -> Option<(Renderer::Font, String, Option<u16>)> {
match self {
Self::Arrow { size } => Some((
Renderer::ICON_FONT,
Renderer::ARROW_DOWN_ICON.to_string(),
*size,
)),
Self::Custom { font, text, size } => {
Some((font.clone(), text.clone(), *size))
}
Self::None => None,
}
}
}
/// A widget for selecting a single value from a list of options.
#[allow(missing_debug_implementations)]
pub struct PickList<'a, T, Message, Renderer>
@ -90,7 +36,7 @@ where
padding: Padding,
text_size: Option<u16>,
font: Renderer::Font,
handle: Handle<Renderer>,
handle: Handle<Renderer::Font>,
style: <Renderer::Theme as StyleSheet>::Style,
}
@ -161,7 +107,7 @@ where
}
/// Sets the [`Handle`] of the [`PickList`].
pub fn handle(mut self, handle: Handle<Renderer>) -> Self {
pub fn handle(mut self, handle: Handle<Renderer::Font>) -> Self {
self.handle = handle;
self
}
@ -258,7 +204,7 @@ where
fn draw(
&self,
_tree: &Tree,
tree: &Tree,
renderer: &mut Renderer,
theme: &Renderer::Theme,
_style: &renderer::Style,
@ -278,6 +224,7 @@ where
self.selected.as_ref(),
&self.handle,
&self.style,
|| tree.state.downcast_ref::<State<T>>(),
)
}
@ -349,6 +296,46 @@ impl<T> Default for State<T> {
}
}
/// The handle to the right side of the [`PickList`].
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Handle<Font> {
/// Displays an arrow icon (▼).
///
/// This is the default.
Arrow {
/// Font size of the content.
size: Option<u16>,
},
/// A custom static handle.
Static(Icon<Font>),
/// A custom dynamic handle.
Dynamic {
/// The [`Icon`] used when [`PickList`] is closed.
closed: Icon<Font>,
/// The [`Icon`] used when [`PickList`] is open.
open: Icon<Font>,
},
/// No handle will be shown.
None,
}
impl<Font> Default for Handle<Font> {
fn default() -> Self {
Self::Arrow { size: None }
}
}
/// The icon of a [`Handle`].
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Icon<Font> {
/// Font that will be used to display the `code_point`,
pub font: Font,
/// The unicode code point that will be used as the icon.
pub code_point: char,
/// Font size of the content.
pub size: Option<u16>,
}
/// Computes the layout of a [`PickList`].
pub fn layout<Renderer, T>(
renderer: &Renderer,
@ -568,7 +555,7 @@ where
}
/// Draws a [`PickList`].
pub fn draw<T, Renderer>(
pub fn draw<'a, T, Renderer>(
renderer: &mut Renderer,
theme: &Renderer::Theme,
layout: Layout<'_>,
@ -578,12 +565,13 @@ pub fn draw<T, Renderer>(
font: &Renderer::Font,
placeholder: Option<&str>,
selected: Option<&T>,
handle: &Handle<Renderer>,
handle: &Handle<Renderer::Font>,
style: &<Renderer::Theme as StyleSheet>::Style,
state: impl FnOnce() -> &'a State<T>,
) where
Renderer: text::Renderer,
Renderer::Theme: StyleSheet,
T: ToString,
T: ToString + 'a,
{
let bounds = layout.bounds();
let is_mouse_over = bounds.contains(cursor_position);
@ -605,11 +593,30 @@ pub fn draw<T, Renderer>(
style.background,
);
if let Some((font, text, size)) = handle.content() {
let handle = match handle {
Handle::Arrow { size } => {
Some((Renderer::ICON_FONT, Renderer::ARROW_DOWN_ICON, *size))
}
Handle::Static(Icon {
font,
code_point,
size,
}) => Some((font.clone(), *code_point, *size)),
Handle::Dynamic { open, closed } => {
if state().is_open {
Some((open.font.clone(), open.code_point, open.size))
} else {
Some((closed.font.clone(), closed.code_point, closed.size))
}
}
Handle::None => None,
};
if let Some((font, code_point, size)) = handle {
let size = f32::from(size.unwrap_or_else(|| renderer.default_size()));
renderer.fill_text(Text {
content: &text,
content: &code_point.to_string(),
size,
font,
color: style.handle_color,

View file

@ -389,8 +389,8 @@ where
let padding = padding.fit(Size::ZERO, limits.max());
let limits = limits
.pad(padding)
.width(width)
.pad(padding)
.height(Length::Units(text_size));
let mut text = layout::Node::new(limits.resolve(Size::ZERO));

View file

@ -1,4 +1,4 @@
use crate::window;
use crate::window::{Mode, UserAttention};
use iced_futures::MaybeSend;
use std::fmt;
@ -38,20 +38,21 @@ pub enum Action<T> {
/// The new logical y location of the window
y: i32,
},
/// Set the [`Mode`] of the window.
SetMode(window::Mode),
/// Change the [`Mode`] of the window.
ChangeMode(Mode),
/// Fetch the current [`Mode`] of the window.
FetchMode(Box<dyn FnOnce(window::Mode) -> T + 'static>),
/// Sets the window to maximized or back
FetchMode(Box<dyn FnOnce(Mode) -> T + 'static>),
/// Toggle the window to maximized or back
ToggleMaximize,
/// Toggles whether window has decorations
/// Toggle whether window has decorations.
///
/// ## Platform-specific
/// - **X11:** Not implemented.
/// - **Web:** Unsupported.
ToggleDecorations,
/// Requests user attention to the window, this has no effect if the application
/// Request user attention to the window, this has no effect if the application
/// is already focused. How requesting for user attention manifests is platform dependent,
/// see [`UserAttentionType`] for details.
/// see [`UserAttention`] for details.
///
/// Providing `None` will unset the request for user attention. Unsetting the request for
/// user attention might not be done automatically by the WM when the window receives input.
@ -62,8 +63,8 @@ pub enum Action<T> {
/// - **macOS:** `None` has no effect.
/// - **X11:** Requests for user attention must be manually cleared.
/// - **Wayland:** Requires `xdg_activation_v1` protocol, `None` has no effect.
RequestUserAttention(Option<window::UserAttention>),
/// Brings the window to the front and sets input focus. Has no effect if the window is
RequestUserAttention(Option<UserAttention>),
/// Bring the window to the front and sets input focus. Has no effect if the window is
/// already in focus, minimized, or not visible.
///
/// This method steals input focus from other applications. Do not use this method unless
@ -93,7 +94,7 @@ impl<T> Action<T> {
Self::Maximize(bool) => Action::Maximize(bool),
Self::Minimize(bool) => Action::Minimize(bool),
Self::Move { x, y } => Action::Move { x, y },
Self::SetMode(mode) => Action::SetMode(mode),
Self::ChangeMode(mode) => Action::ChangeMode(mode),
Self::FetchMode(o) => Action::FetchMode(Box::new(move |s| f(o(s)))),
Self::ToggleMaximize => Action::ToggleMaximize,
Self::ToggleDecorations => Action::ToggleDecorations,
@ -115,15 +116,14 @@ impl<T> fmt::Debug for Action<T> {
}
Self::Resize { width, height } => write!(
f,
"Action::Resize {{ widget: {}, height: {} }}",
width, height
"Action::Resize {{ widget: {width}, height: {height} }}"
),
Self::Maximize(value) => write!(f, "Action::Maximize({})", value),
Self::Minimize(value) => write!(f, "Action::Minimize({}", value),
Self::Maximize(value) => write!(f, "Action::Maximize({value})"),
Self::Minimize(value) => write!(f, "Action::Minimize({value}"),
Self::Move { x, y } => {
write!(f, "Action::Move {{ x: {}, y: {} }}", x, y)
write!(f, "Action::Move {{ x: {x}, y: {y} }}")
}
Self::SetMode(mode) => write!(f, "Action::SetMode({:?})", mode),
Self::ChangeMode(mode) => write!(f, "Action::SetMode({mode:?})"),
Self::FetchMode(_) => write!(f, "Action::FetchMode"),
Self::ToggleMaximize => write!(f, "Action::ToggleMaximize"),
Self::ToggleDecorations => write!(f, "Action::ToggleDecorations"),