From 99a3f25c5f95a144fee7d25b4607f7275abcfaa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Fri, 9 Feb 2024 23:42:36 +0100 Subject: [PATCH 01/19] Update `async-tungstenite` dependency in `websocket` example --- examples/websocket/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/websocket/Cargo.toml b/examples/websocket/Cargo.toml index 8f1b876a0e..c7075fb301 100644 --- a/examples/websocket/Cargo.toml +++ b/examples/websocket/Cargo.toml @@ -13,7 +13,7 @@ once_cell.workspace = true warp = "0.3" [dependencies.async-tungstenite] -version = "0.24" +version = "0.25" features = ["tokio-rustls-webpki-roots"] [dependencies.tokio] From c2d82833a0d56660b66bb06a9fb6360f425416af Mon Sep 17 00:00:00 2001 From: Clark Moody Date: Thu, 1 Feb 2024 16:23:41 -0600 Subject: [PATCH 02/19] Styling for QR Code using theme framework --- style/src/lib.rs | 1 + style/src/qr_code.rs | 20 +++++++++++++++++ style/src/theme.rs | 41 ++++++++++++++++++++++++++++++++++ widget/src/qr_code.rs | 52 ++++++++++++++++++++++++++----------------- 4 files changed, 94 insertions(+), 20 deletions(-) create mode 100644 style/src/qr_code.rs diff --git a/style/src/lib.rs b/style/src/lib.rs index e4097434c1..3c2865ebeb 100644 --- a/style/src/lib.rs +++ b/style/src/lib.rs @@ -24,6 +24,7 @@ pub mod menu; pub mod pane_grid; pub mod pick_list; pub mod progress_bar; +pub mod qr_code; pub mod radio; pub mod rule; pub mod scrollable; diff --git a/style/src/qr_code.rs b/style/src/qr_code.rs new file mode 100644 index 0000000000..a024506ca7 --- /dev/null +++ b/style/src/qr_code.rs @@ -0,0 +1,20 @@ +//! Change the appearance of a QR code. +use crate::core::Color; + +/// The appearance of a QR code. +#[derive(Debug, Clone, Copy)] +pub struct Appearance { + /// The color of the QR code data cells + pub cell: Color, + /// The color of the QR code background + pub background: Color, +} + +/// A set of rules that dictate the style of a QR code. +pub trait StyleSheet { + /// The supported style of the [`StyleSheet`]. + type Style: Default; + + /// Produces the style of a QR code. + fn appearance(&self, style: &Self::Style) -> Appearance; +} diff --git a/style/src/theme.rs b/style/src/theme.rs index e579a1c20d..afb4d02768 100644 --- a/style/src/theme.rs +++ b/style/src/theme.rs @@ -12,6 +12,7 @@ use crate::menu; use crate::pane_grid; use crate::pick_list; use crate::progress_bar; +use crate::qr_code; use crate::radio; use crate::rule; use crate::scrollable; @@ -956,6 +957,46 @@ impl progress_bar::Appearance> progress_bar::StyleSheet for T { } } +/// The style of a QR Code. +#[derive(Default)] +pub enum QRCode { + /// The default style. + #[default] + Default, + /// A custom style. + Custom(Box>), +} + +impl qr_code::Appearance + 'static> From for QRCode { + fn from(f: T) -> Self { + Self::Custom(Box::new(f)) + } +} + +impl qr_code::StyleSheet for Theme { + type Style = QRCode; + + fn appearance(&self, style: &Self::Style) -> qr_code::Appearance { + let palette = self.palette(); + + match style { + QRCode::Default => qr_code::Appearance { + cell: palette.text, + background: palette.background, + }, + QRCode::Custom(custom) => custom.appearance(self), + } + } +} + +impl qr_code::Appearance> qr_code::StyleSheet for T { + type Style = Theme; + + fn appearance(&self, style: &Self::Style) -> qr_code::Appearance { + (self)(style) + } +} + /// The style of a rule. #[derive(Default)] pub enum Rule { diff --git a/widget/src/qr_code.rs b/widget/src/qr_code.rs index 6a748e6396..b6c60bf6a1 100644 --- a/widget/src/qr_code.rs +++ b/widget/src/qr_code.rs @@ -5,51 +5,59 @@ use crate::core::mouse; use crate::core::renderer::{self, Renderer as _}; use crate::core::widget::Tree; use crate::core::{ - Color, Element, Layout, Length, Point, Rectangle, Size, Vector, Widget, + Element, Layout, Length, Point, Rectangle, Size, Vector, Widget, }; use crate::graphics::geometry::Renderer as _; use crate::Renderer; use thiserror::Error; +pub use crate::style::qr_code::StyleSheet; + const DEFAULT_CELL_SIZE: u16 = 4; const QUIET_ZONE: usize = 2; /// A type of matrix barcode consisting of squares arranged in a grid which /// can be read by an imaging device, such as a camera. #[derive(Debug)] -pub struct QRCode<'a> { +pub struct QRCode<'a, Theme = crate::Theme> +where + Theme: StyleSheet, +{ state: &'a State, - dark: Color, - light: Color, cell_size: u16, + style: Theme::Style, } -impl<'a> QRCode<'a> { +impl<'a, Theme> QRCode<'a, Theme> +where + Theme: StyleSheet, +{ /// Creates a new [`QRCode`] with the provided [`State`]. pub fn new(state: &'a State) -> Self { Self { cell_size: DEFAULT_CELL_SIZE, - dark: Color::BLACK, - light: Color::WHITE, state, + style: Default::default(), } } - /// Sets both the dark and light [`Color`]s of the [`QRCode`]. - pub fn color(mut self, dark: Color, light: Color) -> Self { - self.dark = dark; - self.light = light; - self - } - /// Sets the size of the squares of the grid cell of the [`QRCode`]. pub fn cell_size(mut self, cell_size: u16) -> Self { self.cell_size = cell_size; self } + + /// Sets the style of the [`QRCode`]. + pub fn style(mut self, style: impl Into) -> Self { + self.style = style.into(); + self + } } -impl<'a, Message, Theme> Widget for QRCode<'a> { +impl<'a, Message, Theme> Widget for QRCode<'a, Theme> +where + Theme: StyleSheet, +{ fn size(&self) -> Size { Size { width: Length::Shrink, @@ -73,7 +81,7 @@ impl<'a, Message, Theme> Widget for QRCode<'a> { &self, _state: &Tree, renderer: &mut Renderer, - _theme: &Theme, + theme: &Theme, _style: &renderer::Style, layout: Layout<'_>, _cursor: mouse::Cursor, @@ -82,6 +90,8 @@ impl<'a, Message, Theme> Widget for QRCode<'a> { let bounds = layout.bounds(); let side_length = self.state.width + 2 * QUIET_ZONE; + let style = theme.appearance(&self.style); + // Reuse cache if possible let geometry = self.state.cache.draw(renderer, bounds.size(), |frame| { @@ -92,7 +102,7 @@ impl<'a, Message, Theme> Widget for QRCode<'a> { frame.fill_rectangle( Point::ORIGIN, Size::new(side_length as f32, side_length as f32), - self.light, + style.background, ); // Avoid drawing on the quiet zone @@ -114,7 +124,7 @@ impl<'a, Message, Theme> Widget for QRCode<'a> { frame.fill_rectangle( Point::new(column as f32, row as f32), Size::UNIT, - self.dark, + style.cell, ); }); }); @@ -128,10 +138,12 @@ impl<'a, Message, Theme> Widget for QRCode<'a> { } } -impl<'a, Message, Theme> From> +impl<'a, Message, Theme> From> for Element<'a, Message, Theme, Renderer> +where + Theme: StyleSheet + 'a, { - fn from(qr_code: QRCode<'a>) -> Self { + fn from(qr_code: QRCode<'a, Theme>) -> Self { Self::new(qr_code) } } From 4c6ea3cfe2f6023a2f92d8ebfc227f0381c8ac78 Mon Sep 17 00:00:00 2001 From: Clark Moody Date: Fri, 2 Feb 2024 10:45:37 -0600 Subject: [PATCH 03/19] Update `qr_code` example with theme selector --- examples/qr_code/src/main.rs | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/examples/qr_code/src/main.rs b/examples/qr_code/src/main.rs index 867ebfa415..68bbf2605b 100644 --- a/examples/qr_code/src/main.rs +++ b/examples/qr_code/src/main.rs @@ -1,6 +1,6 @@ use iced::widget::qr_code::{self, QRCode}; -use iced::widget::{column, container, text, text_input}; -use iced::{Alignment, Color, Element, Length, Sandbox, Settings}; +use iced::widget::{column, container, pick_list, row, text, text_input}; +use iced::{Alignment, Element, Length, Sandbox, Settings, Theme}; pub fn main() -> iced::Result { QRGenerator::run(Settings::default()) @@ -10,11 +10,13 @@ pub fn main() -> iced::Result { struct QRGenerator { data: String, qr_code: Option, + theme: Theme, } #[derive(Debug, Clone)] enum Message { DataChanged(String), + ThemeChanged(Theme), } impl Sandbox for QRGenerator { @@ -41,13 +43,18 @@ impl Sandbox for QRGenerator { self.data = data; } + Message::ThemeChanged(theme) => { + self.theme = theme; + + if self.qr_code.is_some() { + self.qr_code = qr_code::State::new(&self.data).ok(); + } + } } } fn view(&self) -> Element { - let title = text("QR Code Generator") - .size(70) - .style(Color::from([0.5, 0.5, 0.5])); + let title = text("QR Code Generator").size(70); let input = text_input("Type the data of your QR code here...", &self.data) @@ -55,7 +62,18 @@ impl Sandbox for QRGenerator { .size(30) .padding(15); - let mut content = column![title, input] + let choose_theme = row![ + text("Theme:"), + pick_list( + Theme::ALL, + Some(self.theme.clone()), + Message::ThemeChanged, + ) + ] + .spacing(10) + .align_items(Alignment::Center); + + let mut content = column![title, input, choose_theme] .width(700) .spacing(20) .align_items(Alignment::Center); @@ -72,4 +90,8 @@ impl Sandbox for QRGenerator { .center_y() .into() } + + fn theme(&self) -> Theme { + self.theme.clone() + } } From b535f7ae385658829f57f742eb1cc6f2f40cddf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Fri, 9 Feb 2024 23:57:11 +0100 Subject: [PATCH 04/19] Invalidate `QRCode` cache on `Appearance` change --- examples/qr_code/src/main.rs | 8 +-- style/src/qr_code.rs | 2 +- widget/src/qr_code.rs | 118 ++++++++++++++++++++--------------- 3 files changed, 72 insertions(+), 56 deletions(-) diff --git a/examples/qr_code/src/main.rs b/examples/qr_code/src/main.rs index 68bbf2605b..8b2e950020 100644 --- a/examples/qr_code/src/main.rs +++ b/examples/qr_code/src/main.rs @@ -9,7 +9,7 @@ pub fn main() -> iced::Result { #[derive(Default)] struct QRGenerator { data: String, - qr_code: Option, + qr_code: Option, theme: Theme, } @@ -38,17 +38,13 @@ impl Sandbox for QRGenerator { self.qr_code = if data.is_empty() { None } else { - qr_code::State::new(&data).ok() + qr_code::Data::new(&data).ok() }; self.data = data; } Message::ThemeChanged(theme) => { self.theme = theme; - - if self.qr_code.is_some() { - self.qr_code = qr_code::State::new(&self.data).ok(); - } } } } diff --git a/style/src/qr_code.rs b/style/src/qr_code.rs index a024506ca7..02c4709a5f 100644 --- a/style/src/qr_code.rs +++ b/style/src/qr_code.rs @@ -2,7 +2,7 @@ use crate::core::Color; /// The appearance of a QR code. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub struct Appearance { /// The color of the QR code data cells pub cell: Color, diff --git a/widget/src/qr_code.rs b/widget/src/qr_code.rs index b6c60bf6a1..ece9b9e104 100644 --- a/widget/src/qr_code.rs +++ b/widget/src/qr_code.rs @@ -3,15 +3,17 @@ use crate::canvas; use crate::core::layout; use crate::core::mouse; use crate::core::renderer::{self, Renderer as _}; -use crate::core::widget::Tree; +use crate::core::widget::tree::{self, Tree}; use crate::core::{ Element, Layout, Length, Point, Rectangle, Size, Vector, Widget, }; use crate::graphics::geometry::Renderer as _; use crate::Renderer; + +use std::cell::RefCell; use thiserror::Error; -pub use crate::style::qr_code::StyleSheet; +pub use crate::style::qr_code::{Appearance, StyleSheet}; const DEFAULT_CELL_SIZE: u16 = 4; const QUIET_ZONE: usize = 2; @@ -23,7 +25,7 @@ pub struct QRCode<'a, Theme = crate::Theme> where Theme: StyleSheet, { - state: &'a State, + data: &'a Data, cell_size: u16, style: Theme::Style, } @@ -32,11 +34,11 @@ impl<'a, Theme> QRCode<'a, Theme> where Theme: StyleSheet, { - /// Creates a new [`QRCode`] with the provided [`State`]. - pub fn new(state: &'a State) -> Self { + /// Creates a new [`QRCode`] with the provided [`Data`]. + pub fn new(data: &'a Data) -> Self { Self { + data, cell_size: DEFAULT_CELL_SIZE, - state, style: Default::default(), } } @@ -58,6 +60,14 @@ impl<'a, Message, Theme> Widget for QRCode<'a, Theme> where Theme: StyleSheet, { + fn tag(&self) -> tree::Tag { + tree::Tag::of::() + } + + fn state(&self) -> tree::State { + tree::State::new(State::default()) + } + fn size(&self) -> Size { Size { width: Length::Shrink, @@ -71,7 +81,7 @@ where _renderer: &Renderer, _limits: &layout::Limits, ) -> layout::Node { - let side_length = (self.state.width + 2 * QUIET_ZONE) as f32 + let side_length = (self.data.width + 2 * QUIET_ZONE) as f32 * f32::from(self.cell_size); layout::Node::new(Size::new(side_length, side_length)) @@ -79,7 +89,7 @@ where fn draw( &self, - _state: &Tree, + tree: &Tree, renderer: &mut Renderer, theme: &Theme, _style: &renderer::Style, @@ -87,47 +97,52 @@ where _cursor: mouse::Cursor, _viewport: &Rectangle, ) { + let state = tree.state.downcast_ref::(); + let bounds = layout.bounds(); - let side_length = self.state.width + 2 * QUIET_ZONE; + let side_length = self.data.width + 2 * QUIET_ZONE; + + let appearance = theme.appearance(&self.style); + let mut last_appearance = state.last_appearance.borrow_mut(); + + if Some(appearance) != *last_appearance { + self.data.cache.clear(); - let style = theme.appearance(&self.style); + *last_appearance = Some(appearance); + } // Reuse cache if possible - let geometry = - self.state.cache.draw(renderer, bounds.size(), |frame| { - // Scale units to cell size - frame.scale(self.cell_size); - - // Draw background - frame.fill_rectangle( - Point::ORIGIN, - Size::new(side_length as f32, side_length as f32), - style.background, - ); - - // Avoid drawing on the quiet zone - frame.translate(Vector::new( - QUIET_ZONE as f32, - QUIET_ZONE as f32, - )); - - // Draw contents - self.state - .contents - .iter() - .enumerate() - .filter(|(_, value)| **value == qrcode::Color::Dark) - .for_each(|(index, _)| { - let row = index / self.state.width; - let column = index % self.state.width; - - frame.fill_rectangle( - Point::new(column as f32, row as f32), - Size::UNIT, - style.cell, - ); - }); - }); + let geometry = self.data.cache.draw(renderer, bounds.size(), |frame| { + // Scale units to cell size + frame.scale(self.cell_size); + + // Draw background + frame.fill_rectangle( + Point::ORIGIN, + Size::new(side_length as f32, side_length as f32), + appearance.background, + ); + + // Avoid drawing on the quiet zone + frame.translate(Vector::new(QUIET_ZONE as f32, QUIET_ZONE as f32)); + + // Draw contents + self.data + .contents + .iter() + .enumerate() + .filter(|(_, value)| **value == qrcode::Color::Dark) + .for_each(|(index, _)| { + let row = index / self.data.width; + let column = index % self.data.width; + + frame.fill_rectangle( + Point::new(column as f32, row as f32), + Size::UNIT, + appearance.cell, + ); + }); + }); renderer.with_translation( bounds.position() - Point::ORIGIN, @@ -148,17 +163,17 @@ where } } -/// The state of a [`QRCode`]. +/// The data of a [`QRCode`]. /// -/// It stores the data that will be displayed. +/// It stores the contents that will be displayed. #[derive(Debug)] -pub struct State { +pub struct Data { contents: Vec, width: usize, cache: canvas::Cache, } -impl State { +impl Data { /// Creates a new [`State`] with the provided data. /// /// This method uses an [`ErrorCorrection::Medium`] and chooses the smallest @@ -310,3 +325,8 @@ impl From for Error { } } } + +#[derive(Default)] +struct State { + last_appearance: RefCell>, +} From 8b14f88f5ffa2125908fa53a4fa955ac7818e12e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Fri, 9 Feb 2024 23:59:43 +0100 Subject: [PATCH 05/19] Update `CHANGELOG` --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8660cc5a01..8f0f96a39a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `hovered` styling for `Svg` widget. [#2163](https://github.com/iced-rs/iced/pull/2163) - `height` method for `TextEditor`. [#2221](https://github.com/iced-rs/iced/pull/2221) - Customizable style for `TextEditor`. [#2159](https://github.com/iced-rs/iced/pull/2159) +- Customizable style for `QRCode`. [#2229](https://github.com/iced-rs/iced/pull/2229) - Border width styling for `Toggler`. [#2219](https://github.com/iced-rs/iced/pull/2219) - `RawText` variant for `Primitive` in `iced_graphics`. [#2158](https://github.com/iced-rs/iced/pull/2158) - `Stream` support for `Command`. [#2150](https://github.com/iced-rs/iced/pull/2150) @@ -116,6 +117,7 @@ Many thanks to... - @Calastrophe - @casperstorm - @cfrenette +- @clarkmoody - @Davidster - @Decodetalkers - @derezzedex From 564ad95806efd1259a2244a685b648346b460abf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Sat, 10 Feb 2024 00:02:17 +0100 Subject: [PATCH 06/19] Fix leftover mentions of `State` in `QRCode` docs --- widget/src/qr_code.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/widget/src/qr_code.rs b/widget/src/qr_code.rs index ece9b9e104..eeb1526f9c 100644 --- a/widget/src/qr_code.rs +++ b/widget/src/qr_code.rs @@ -174,7 +174,7 @@ pub struct Data { } impl Data { - /// Creates a new [`State`] with the provided data. + /// Creates a new [`Data`] with the provided data. /// /// This method uses an [`ErrorCorrection::Medium`] and chooses the smallest /// size to display the data. @@ -184,7 +184,7 @@ impl Data { Ok(Self::build(encoded)) } - /// Creates a new [`State`] with the provided [`ErrorCorrection`]. + /// Creates a new [`Data`] with the provided [`ErrorCorrection`]. pub fn with_error_correction( data: impl AsRef<[u8]>, error_correction: ErrorCorrection, @@ -197,7 +197,7 @@ impl Data { Ok(Self::build(encoded)) } - /// Creates a new [`State`] with the provided [`Version`] and + /// Creates a new [`Data`] with the provided [`Version`] and /// [`ErrorCorrection`]. pub fn with_version( data: impl AsRef<[u8]>, @@ -276,7 +276,7 @@ impl From for qrcode::EcLevel { } } -/// An error that occurred when building a [`State`] for a [`QRCode`]. +/// An error that occurred when building a [`Data`] for a [`QRCode`]. #[derive(Debug, Clone, Copy, PartialEq, Eq, Error)] pub enum Error { /// The data is too long to encode in a QR code for the chosen [`Version`]. From 712c8e53f2385ed425173cab327e06a214248579 Mon Sep 17 00:00:00 2001 From: Daniel Yoon <101683475+Koranir@users.noreply.github.com> Date: Sat, 3 Feb 2024 17:27:24 +1100 Subject: [PATCH 07/19] Fix alpha mode configuration in `iced_wgpu` --- examples/gradient/src/main.rs | 53 ++++++++++++++++++++++++++++--- wgpu/src/window/compositor.rs | 60 +++++++++++++++++++++++------------ 2 files changed, 88 insertions(+), 25 deletions(-) diff --git a/examples/gradient/src/main.rs b/examples/gradient/src/main.rs index 1bf5822dc3..5fbf1c5406 100644 --- a/examples/gradient/src/main.rs +++ b/examples/gradient/src/main.rs @@ -1,11 +1,20 @@ -use iced::gradient; -use iced::widget::{column, container, horizontal_space, row, slider, text}; +use iced::theme::Palette; +use iced::widget::{ + checkbox, column, container, horizontal_space, row, slider, text, +}; +use iced::{gradient, window}; use iced::{ Alignment, Background, Color, Element, Length, Radians, Sandbox, Settings, }; pub fn main() -> iced::Result { - Gradient::run(Settings::default()) + Gradient::run(Settings { + window: window::Settings { + transparent: true, + ..Default::default() + }, + ..Default::default() + }) } #[derive(Debug, Clone, Copy)] @@ -13,6 +22,7 @@ struct Gradient { start: Color, end: Color, angle: Radians, + transparent_window: bool, } #[derive(Debug, Clone, Copy)] @@ -20,6 +30,7 @@ enum Message { StartChanged(Color), EndChanged(Color), AngleChanged(Radians), + SetTransparent(bool), } impl Sandbox for Gradient { @@ -30,6 +41,7 @@ impl Sandbox for Gradient { start: Color::WHITE, end: Color::new(0.0, 0.0, 1.0, 1.0), angle: Radians(0.0), + transparent_window: false, } } @@ -42,11 +54,19 @@ impl Sandbox for Gradient { Message::StartChanged(color) => self.start = color, Message::EndChanged(color) => self.end = color, Message::AngleChanged(angle) => self.angle = angle, + Message::SetTransparent(transparent) => { + self.transparent_window = transparent; + } } } fn view(&self) -> Element { - let Self { start, end, angle } = *self; + let Self { + start, + end, + angle, + transparent_window, + } = *self; let gradient_box = container(horizontal_space(Length::Fill)) .width(Length::Fill) @@ -72,14 +92,35 @@ impl Sandbox for Gradient { .padding(8) .align_items(Alignment::Center); + let transparency_toggle = iced::widget::Container::new( + checkbox("Transparent window", transparent_window) + .on_toggle(Message::SetTransparent), + ) + .padding(8); + column![ color_picker("Start", self.start).map(Message::StartChanged), color_picker("End", self.end).map(Message::EndChanged), angle_picker, - gradient_box + transparency_toggle, + gradient_box, ] .into() } + + fn theme(&self) -> iced::Theme { + if self.transparent_window { + iced::Theme::custom( + String::new(), + Palette { + background: Color::TRANSPARENT, + ..iced::Theme::default().palette() + }, + ) + } else { + iced::Theme::default() + } + } } fn color_picker(label: &str, color: Color) -> Element<'_, Color> { @@ -91,6 +132,8 @@ fn color_picker(label: &str, color: Color) -> Element<'_, Color> { .step(0.01), slider(0.0..=1.0, color.b, move |b| { Color { b, ..color } }) .step(0.01), + slider(0.0..=1.0, color.a, move |a| { Color { a, ..color } }) + .step(0.01), ] .spacing(8) .padding(8) diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 58f3f65410..3e329362bd 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -15,6 +15,7 @@ pub struct Compositor { device: wgpu::Device, queue: wgpu::Queue, format: wgpu::TextureFormat, + alpha_mode: wgpu::CompositeAlphaMode, } impl Compositor { @@ -61,25 +62,43 @@ impl Compositor { log::info!("Selected: {:#?}", adapter.get_info()); - let format = compatible_surface.as_ref().and_then(|surface| { - let capabilities = surface.get_capabilities(&adapter); - - let mut formats = capabilities.formats.iter().copied(); - - let format = if color::GAMMA_CORRECTION { - formats.find(wgpu::TextureFormat::is_srgb) - } else { - formats.find(|format| !wgpu::TextureFormat::is_srgb(format)) - }; - - format.or_else(|| { - log::warn!("No format found!"); - - capabilities.formats.first().copied() - }) - })?; - - log::info!("Selected format: {format:?}"); + let (format, alpha_mode) = + compatible_surface.as_ref().and_then(|surface| { + let capabilities = surface.get_capabilities(&adapter); + + let mut formats = capabilities.formats.iter().copied(); + + let format = if color::GAMMA_CORRECTION { + formats.find(wgpu::TextureFormat::is_srgb) + } else { + formats.find(|format| !wgpu::TextureFormat::is_srgb(format)) + }; + + let format = format.or_else(|| { + log::warn!("No format found!"); + + capabilities.formats.first().copied() + }); + + let alphas = capabilities.alpha_modes; + let preferred_alpha = if alphas + .contains(&wgpu::CompositeAlphaMode::PostMultiplied) + { + wgpu::CompositeAlphaMode::PostMultiplied + } else if alphas + .contains(&wgpu::CompositeAlphaMode::PreMultiplied) + { + wgpu::CompositeAlphaMode::PreMultiplied + } else { + wgpu::CompositeAlphaMode::Auto + }; + + format.zip(Some(preferred_alpha)) + })?; + + log::info!( + "Selected format: {format:?} with alpha mode: {alpha_mode:?}" + ); #[cfg(target_arch = "wasm32")] let limits = [wgpu::Limits::downlevel_webgl2_defaults() @@ -120,6 +139,7 @@ impl Compositor { device, queue, format, + alpha_mode, }) } @@ -249,7 +269,7 @@ impl graphics::Compositor for Compositor { present_mode: self.settings.present_mode, width, height, - alpha_mode: wgpu::CompositeAlphaMode::Auto, + alpha_mode: self.alpha_mode, view_formats: vec![], desired_maximum_frame_latency: 2, }, From 81bed94148dfdc60997d14db603a4c7f2d13bb51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Sat, 10 Feb 2024 00:32:03 +0100 Subject: [PATCH 08/19] Use custom `Application::style` to enable transparency --- examples/gradient/src/main.rs | 38 +++++++++++++++++------------------ style/src/theme.rs | 17 ++++++++-------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/examples/gradient/src/main.rs b/examples/gradient/src/main.rs index 5fbf1c5406..5eacd7a6e3 100644 --- a/examples/gradient/src/main.rs +++ b/examples/gradient/src/main.rs @@ -1,4 +1,5 @@ -use iced::theme::Palette; +use iced::application; +use iced::theme::{self, Theme}; use iced::widget::{ checkbox, column, container, horizontal_space, row, slider, text, }; @@ -22,7 +23,7 @@ struct Gradient { start: Color, end: Color, angle: Radians, - transparent_window: bool, + transparent: bool, } #[derive(Debug, Clone, Copy)] @@ -30,7 +31,7 @@ enum Message { StartChanged(Color), EndChanged(Color), AngleChanged(Radians), - SetTransparent(bool), + TransparentToggled(bool), } impl Sandbox for Gradient { @@ -41,7 +42,7 @@ impl Sandbox for Gradient { start: Color::WHITE, end: Color::new(0.0, 0.0, 1.0, 1.0), angle: Radians(0.0), - transparent_window: false, + transparent: false, } } @@ -54,8 +55,8 @@ impl Sandbox for Gradient { Message::StartChanged(color) => self.start = color, Message::EndChanged(color) => self.end = color, Message::AngleChanged(angle) => self.angle = angle, - Message::SetTransparent(transparent) => { - self.transparent_window = transparent; + Message::TransparentToggled(transparent) => { + self.transparent = transparent; } } } @@ -65,7 +66,7 @@ impl Sandbox for Gradient { start, end, angle, - transparent_window, + transparent, } = *self; let gradient_box = container(horizontal_space(Length::Fill)) @@ -93,8 +94,8 @@ impl Sandbox for Gradient { .align_items(Alignment::Center); let transparency_toggle = iced::widget::Container::new( - checkbox("Transparent window", transparent_window) - .on_toggle(Message::SetTransparent), + checkbox("Transparent window", transparent) + .on_toggle(Message::TransparentToggled), ) .padding(8); @@ -108,17 +109,16 @@ impl Sandbox for Gradient { .into() } - fn theme(&self) -> iced::Theme { - if self.transparent_window { - iced::Theme::custom( - String::new(), - Palette { - background: Color::TRANSPARENT, - ..iced::Theme::default().palette() - }, - ) + fn style(&self) -> theme::Application { + if self.transparent { + theme::Application::custom(|theme: &Theme| { + application::Appearance { + background_color: Color::TRANSPARENT, + text_color: theme.palette().text, + } + }) } else { - iced::Theme::default() + theme::Application::Default } } } diff --git a/style/src/theme.rs b/style/src/theme.rs index afb4d02768..235aecbd03 100644 --- a/style/src/theme.rs +++ b/style/src/theme.rs @@ -172,6 +172,15 @@ pub enum Application { Custom(Box>), } +impl Application { + /// Creates a custom [`Application`] style. + pub fn custom( + custom: impl application::StyleSheet