perf: inline public getters/setters, and use non-generic inner functions

To reduce compile-times and avoid some overhead to binary size, this will modify some of our
generic functions to use non-generic inner functions where possible. The inner functions are
marked carefully with `#[inline(never)]` to prevent being inlined by LLVM at their callsites

While looking for generic functions to optimize, I have also taken the opportunity to annotate
public non-generic getters and setters with `#[inline]` to ensure that LLVM will inline them
across crate boundaries. By default, only generic functions are automatically inlined, and
only when enabling fat LTO are constant functions reliably inlined across crate boundaries.
This commit is contained in:
Michael Aaron Murphy 2025-03-21 03:17:59 +01:00
parent c538d672df
commit 8cf372c9b9
No known key found for this signature in database
GPG key ID: B2732D4240C9212C
55 changed files with 702 additions and 255 deletions

View file

@ -20,6 +20,7 @@ pub struct Watcher {
impl Deref for Watcher { impl Deref for Watcher {
type Target = ConfigProxy<'static>; type Target = ConfigProxy<'static>;
#[inline]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.proxy &self.proxy
} }

View file

@ -40,6 +40,7 @@ pub enum Error {
} }
impl fmt::Display for Error { impl fmt::Display for Error {
#[cold]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
Self::AtomicWrites(err) => err.fmt(f), Self::AtomicWrites(err) => err.fmt(f),
@ -61,6 +62,7 @@ impl Error {
/// Whether the reason for the missing config is caused by an error. /// Whether the reason for the missing config is caused by an error.
/// ///
/// Useful for determining if it is appropriate to log as an error. /// Useful for determining if it is appropriate to log as an error.
#[inline]
pub fn is_err(&self) -> bool { pub fn is_err(&self) -> bool {
!matches!(self, Self::NoConfigDirectory | Self::NotFound) !matches!(self, Self::NoConfigDirectory | Self::NotFound)
} }
@ -134,11 +136,6 @@ fn sanitize_name(name: &str) -> Result<&Path, Error> {
} }
impl Config { impl Config {
/// Get the config for the libcosmic toolkit
pub fn libcosmic() -> Result<Self, Error> {
Self::new("com.system76.libcosmic", 1)
}
/// Get a system config for the given name and config version /// Get a system config for the given name and config version
pub fn system(name: &str, version: u64) -> Result<Self, Error> { pub fn system(name: &str, version: u64) -> Result<Self, Error> {
let path = sanitize_name(name)?.join(format!("v{version}")); let path = sanitize_name(name)?.join(format!("v{version}"));
@ -235,6 +232,7 @@ impl Config {
} }
// Start a transaction (to set multiple configs at the same time) // Start a transaction (to set multiple configs at the same time)
#[inline]
pub fn transaction(&self) -> ConfigTransaction { pub fn transaction(&self) -> ConfigTransaction {
ConfigTransaction { ConfigTransaction {
config: self, config: self,
@ -368,7 +366,7 @@ pub struct ConfigTransaction<'a> {
updates: Mutex<Vec<(PathBuf, String)>>, updates: Mutex<Vec<(PathBuf, String)>>,
} }
impl<'a> ConfigTransaction<'a> { impl ConfigTransaction<'_> {
/// Apply all pending changes from ConfigTransaction /// Apply all pending changes from ConfigTransaction
//TODO: apply all changes at once //TODO: apply all changes at once
pub fn commit(self) -> Result<(), Error> { pub fn commit(self) -> Result<(), Error> {
@ -386,7 +384,7 @@ impl<'a> ConfigTransaction<'a> {
// Setting any setting in this way will do one transaction for all settings // Setting any setting in this way will do one transaction for all settings
// when commit finishes that transaction // when commit finishes that transaction
impl<'a> ConfigSet for ConfigTransaction<'a> { impl ConfigSet for ConfigTransaction<'_> {
fn set<T: Serialize>(&self, key: &str, value: T) -> Result<(), Error> { fn set<T: Serialize>(&self, key: &str, value: T) -> Result<(), Error> {
//TODO: sanitize key (no slashes, cannot be . or ..) //TODO: sanitize key (no slashes, cannot be . or ..)
let key_path = self.config.key_path(key)?; let key_path = self.config.key_path(key)?;

View file

@ -16,6 +16,7 @@ pub enum ConfigUpdate<T> {
Failed, Failed,
} }
#[cold]
pub fn config_subscription< pub fn config_subscription<
I: 'static + Copy + Send + Sync + Hash, I: 'static + Copy + Send + Sync + Hash,
T: 'static + Send + Sync + PartialEq + Clone + CosmicConfigEntry, T: 'static + Send + Sync + PartialEq + Clone + CosmicConfigEntry,
@ -27,6 +28,7 @@ pub fn config_subscription<
iced_futures::Subscription::run_with_id(id, watcher_stream(config_id, config_version, false)) iced_futures::Subscription::run_with_id(id, watcher_stream(config_id, config_version, false))
} }
#[cold]
pub fn config_state_subscription< pub fn config_state_subscription<
I: 'static + Copy + Send + Sync + Hash, I: 'static + Copy + Send + Sync + Hash,
T: 'static + Send + Sync + PartialEq + Clone + CosmicConfigEntry, T: 'static + Send + Sync + PartialEq + Clone + CosmicConfigEntry,

View file

@ -19,6 +19,6 @@ pub mod composite;
pub mod steps; pub mod steps;
/// name of cosmic theme /// name of cosmic theme
pub const NAME: &'static str = "com.system76.CosmicTheme"; pub const NAME: &str = "com.system76.CosmicTheme";
pub use palette; pub use palette;

View file

@ -26,6 +26,7 @@ pub enum CosmicPalette {
impl CosmicPalette { impl CosmicPalette {
/// extract the inner palette /// extract the inner palette
#[inline]
pub fn inner(self) -> CosmicPaletteInner { pub fn inner(self) -> CosmicPaletteInner {
match self { match self {
CosmicPalette::Dark(p) => p, CosmicPalette::Dark(p) => p,
@ -37,6 +38,7 @@ impl CosmicPalette {
} }
impl AsMut<CosmicPaletteInner> for CosmicPalette { impl AsMut<CosmicPaletteInner> for CosmicPalette {
#[inline]
fn as_mut(&mut self) -> &mut CosmicPaletteInner { fn as_mut(&mut self) -> &mut CosmicPaletteInner {
match self { match self {
CosmicPalette::Dark(p) => p, CosmicPalette::Dark(p) => p,
@ -48,6 +50,7 @@ impl AsMut<CosmicPaletteInner> for CosmicPalette {
} }
impl AsRef<CosmicPaletteInner> for CosmicPalette { impl AsRef<CosmicPaletteInner> for CosmicPalette {
#[inline]
fn as_ref(&self) -> &CosmicPaletteInner { fn as_ref(&self) -> &CosmicPaletteInner {
match self { match self {
CosmicPalette::Dark(p) => p, CosmicPalette::Dark(p) => p,
@ -60,6 +63,7 @@ impl AsRef<CosmicPaletteInner> for CosmicPalette {
impl CosmicPalette { impl CosmicPalette {
/// check if the palette is dark /// check if the palette is dark
#[inline]
pub fn is_dark(&self) -> bool { pub fn is_dark(&self) -> bool {
match self { match self {
CosmicPalette::Dark(_) | CosmicPalette::HighContrastDark(_) => true, CosmicPalette::Dark(_) | CosmicPalette::HighContrastDark(_) => true,
@ -68,6 +72,7 @@ impl CosmicPalette {
} }
/// check if the palette is high_contrast /// check if the palette is high_contrast
#[inline]
pub fn is_high_contrast(&self) -> bool { pub fn is_high_contrast(&self) -> bool {
match self { match self {
CosmicPalette::HighContrastLight(_) | CosmicPalette::HighContrastDark(_) => true, CosmicPalette::HighContrastLight(_) | CosmicPalette::HighContrastDark(_) => true,
@ -77,6 +82,7 @@ impl CosmicPalette {
} }
impl Default for CosmicPalette { impl Default for CosmicPalette {
#[inline]
fn default() -> Self { fn default() -> Self {
CosmicPalette::Dark(Default::default()) CosmicPalette::Dark(Default::default())
} }
@ -164,6 +170,7 @@ pub struct CosmicPaletteInner {
impl CosmicPalette { impl CosmicPalette {
/// name of the palette /// name of the palette
#[inline]
pub fn name(&self) -> &str { pub fn name(&self) -> &str {
match &self { match &self {
CosmicPalette::Dark(p) => &p.name, CosmicPalette::Dark(p) => &p.name,

View file

@ -77,26 +77,31 @@ pub struct Component {
#[allow(clippy::must_use_candidate)] #[allow(clippy::must_use_candidate)]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
impl Component { impl Component {
#[inline]
/// get @hover_state_color /// get @hover_state_color
pub fn hover_state_color(&self) -> Srgba { pub fn hover_state_color(&self) -> Srgba {
self.hover self.hover
} }
#[inline]
/// get @pressed_state_color /// get @pressed_state_color
pub fn pressed_state_color(&self) -> Srgba { pub fn pressed_state_color(&self) -> Srgba {
self.pressed self.pressed
} }
#[inline]
/// get @selected_state_color /// get @selected_state_color
pub fn selected_state_color(&self) -> Srgba { pub fn selected_state_color(&self) -> Srgba {
self.selected self.selected
} }
#[inline]
/// get @selected_state_text_color /// get @selected_state_text_color
pub fn selected_state_text_color(&self) -> Srgba { pub fn selected_state_text_color(&self) -> Srgba {
self.selected_text self.selected_text
} }
#[inline]
/// get @focus_color /// get @focus_color
pub fn focus_color(&self) -> Srgba { pub fn focus_color(&self) -> Srgba {
self.focus self.focus

View file

@ -1,5 +1,4 @@
#[derive(Default)] #[derive(Default)]
pub struct Layout { pub struct Layout {
corner_radii: [u32;4], corner_radii: [u32; 4],
}
}

View file

@ -16,6 +16,7 @@ pub struct ThemeMode {
} }
impl Default for ThemeMode { impl Default for ThemeMode {
#[inline]
fn default() -> Self { fn default() -> Self {
Self { Self {
is_dark: true, is_dark: true,
@ -25,15 +26,19 @@ impl Default for ThemeMode {
} }
impl ThemeMode { impl ThemeMode {
#[inline]
/// Check if the theme is currently using dark mode /// Check if the theme is currently using dark mode
pub fn is_dark(config: &Config) -> Result<bool, cosmic_config::Error> { pub fn is_dark(config: &Config) -> Result<bool, cosmic_config::Error> {
config.get::<bool>("is_dark") config.get::<bool>("is_dark")
} }
#[inline]
/// The current version of the theme mode config.
pub const fn version() -> u64 { pub const fn version() -> u64 {
Self::VERSION Self::VERSION
} }
#[inline]
/// Get the config for the theme mode /// Get the config for the theme mode
pub fn config() -> Result<Config, cosmic_config::Error> { pub fn config() -> Result<Config, cosmic_config::Error> {
Config::new(THEME_MODE_ID, Self::VERSION) Config::new(THEME_MODE_ID, Self::VERSION)

View file

@ -103,6 +103,7 @@ pub struct Theme {
} }
impl Default for Theme { impl Default for Theme {
#[inline]
fn default() -> Self { fn default() -> Self {
Self::preferred_theme() Self::preferred_theme()
} }
@ -121,36 +122,43 @@ impl Theme {
NAME NAME
} }
#[inline]
/// Get the config for the current dark theme /// Get the config for the current dark theme
pub fn dark_config() -> Result<Config, cosmic_config::Error> { pub fn dark_config() -> Result<Config, cosmic_config::Error> {
Config::new(DARK_THEME_ID, Self::VERSION) Config::new(DARK_THEME_ID, Self::VERSION)
} }
#[inline]
/// Get the config for the current light theme /// Get the config for the current light theme
pub fn light_config() -> Result<Config, cosmic_config::Error> { pub fn light_config() -> Result<Config, cosmic_config::Error> {
Config::new(LIGHT_THEME_ID, Self::VERSION) Config::new(LIGHT_THEME_ID, Self::VERSION)
} }
#[inline]
/// get the built in light theme /// get the built in light theme
pub fn light_default() -> Self { pub fn light_default() -> Self {
LIGHT_PALETTE.clone().into() LIGHT_PALETTE.clone().into()
} }
#[inline]
/// get the built in dark theme /// get the built in dark theme
pub fn dark_default() -> Self { pub fn dark_default() -> Self {
DARK_PALETTE.clone().into() DARK_PALETTE.clone().into()
} }
#[inline]
/// get the built in high contrast dark theme /// get the built in high contrast dark theme
pub fn high_contrast_dark_default() -> Self { pub fn high_contrast_dark_default() -> Self {
CosmicPalette::HighContrastDark(DARK_PALETTE.as_ref().clone()).into() CosmicPalette::HighContrastDark(DARK_PALETTE.as_ref().clone()).into()
} }
#[inline]
/// get the built in high contrast light theme /// get the built in high contrast light theme
pub fn high_contrast_light_default() -> Self { pub fn high_contrast_light_default() -> Self {
CosmicPalette::HighContrastLight(LIGHT_PALETTE.as_ref().clone()).into() CosmicPalette::HighContrastLight(LIGHT_PALETTE.as_ref().clone()).into()
} }
#[inline]
/// Convert the theme to a high-contrast variant /// Convert the theme to a high-contrast variant
pub fn to_high_contrast(&self) -> Self { pub fn to_high_contrast(&self) -> Self {
todo!(); todo!();
@ -159,6 +167,7 @@ impl Theme {
// TODO convenient getter functions for each named color variable // TODO convenient getter functions for each named color variable
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @accent_color /// get @accent_color
pub fn accent_color(&self) -> Srgba { pub fn accent_color(&self) -> Srgba {
self.accent.base self.accent.base
@ -166,6 +175,7 @@ impl Theme {
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @success_color /// get @success_color
pub fn success_color(&self) -> Srgba { pub fn success_color(&self) -> Srgba {
self.success.base self.success.base
@ -173,6 +183,7 @@ impl Theme {
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @destructive_color /// get @destructive_color
pub fn destructive_color(&self) -> Srgba { pub fn destructive_color(&self) -> Srgba {
self.destructive.base self.destructive.base
@ -180,6 +191,7 @@ impl Theme {
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @warning_color /// get @warning_color
pub fn warning_color(&self) -> Srgba { pub fn warning_color(&self) -> Srgba {
self.warning.base self.warning.base
@ -187,6 +199,7 @@ impl Theme {
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @small_widget_divider /// get @small_widget_divider
pub fn small_widget_divider(&self) -> Srgba { pub fn small_widget_divider(&self) -> Srgba {
let mut neutral_9 = self.palette.neutral_9; let mut neutral_9 = self.palette.neutral_9;
@ -197,42 +210,55 @@ impl Theme {
// Containers // Containers
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @bg_color /// get @bg_color
pub fn bg_color(&self) -> Srgba { pub fn bg_color(&self) -> Srgba {
self.background.base self.background.base
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @bg_component_color /// get @bg_component_color
pub fn bg_component_color(&self) -> Srgba { pub fn bg_component_color(&self) -> Srgba {
self.background.component.base self.background.component.base
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @primary_container_color /// get @primary_container_color
pub fn primary_container_color(&self) -> Srgba { pub fn primary_container_color(&self) -> Srgba {
self.primary.base self.primary.base
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @primary_component_color /// get @primary_component_color
pub fn primary_component_color(&self) -> Srgba { pub fn primary_component_color(&self) -> Srgba {
self.primary.component.base self.primary.component.base
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @secondary_container_color /// get @secondary_container_color
pub fn secondary_container_color(&self) -> Srgba { pub fn secondary_container_color(&self) -> Srgba {
self.secondary.base self.secondary.base
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @secondary_component_color /// get @secondary_component_color
pub fn secondary_component_color(&self) -> Srgba { pub fn secondary_component_color(&self) -> Srgba {
self.secondary.component.base self.secondary.component.base
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @button_bg_color /// get @button_bg_color
pub fn button_bg_color(&self) -> Srgba { pub fn button_bg_color(&self) -> Srgba {
self.button.base self.button.base
@ -241,90 +267,119 @@ impl Theme {
// Text // Text
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @on_bg_color /// get @on_bg_color
pub fn on_bg_color(&self) -> Srgba { pub fn on_bg_color(&self) -> Srgba {
self.background.on self.background.on
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @on_bg_component_color /// get @on_bg_component_color
pub fn on_bg_component_color(&self) -> Srgba { pub fn on_bg_component_color(&self) -> Srgba {
self.background.component.on self.background.component.on
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @on_primary_color /// get @on_primary_color
pub fn on_primary_container_color(&self) -> Srgba { pub fn on_primary_container_color(&self) -> Srgba {
self.primary.on self.primary.on
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @on_primary_component_color /// get @on_primary_component_color
pub fn on_primary_component_color(&self) -> Srgba { pub fn on_primary_component_color(&self) -> Srgba {
self.primary.component.on self.primary.component.on
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @on_secondary_color /// get @on_secondary_color
pub fn on_secondary_container_color(&self) -> Srgba { pub fn on_secondary_container_color(&self) -> Srgba {
self.secondary.on self.secondary.on
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @on_secondary_component_color /// get @on_secondary_component_color
pub fn on_secondary_component_color(&self) -> Srgba { pub fn on_secondary_component_color(&self) -> Srgba {
self.secondary.component.on self.secondary.component.on
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @accent_text_color /// get @accent_text_color
pub fn accent_text_color(&self) -> Srgba { pub fn accent_text_color(&self) -> Srgba {
self.accent_text.unwrap_or(self.accent.base) self.accent_text.unwrap_or(self.accent.base)
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @success_text_color /// get @success_text_color
pub fn success_text_color(&self) -> Srgba { pub fn success_text_color(&self) -> Srgba {
self.success.base self.success.base
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @warning_text_color /// get @warning_text_color
pub fn warning_text_color(&self) -> Srgba { pub fn warning_text_color(&self) -> Srgba {
self.warning.base self.warning.base
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @destructive_text_color /// get @destructive_text_color
pub fn destructive_text_color(&self) -> Srgba { pub fn destructive_text_color(&self) -> Srgba {
self.destructive.base self.destructive.base
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @on_accent_color /// get @on_accent_color
pub fn on_accent_color(&self) -> Srgba { pub fn on_accent_color(&self) -> Srgba {
self.accent.on self.accent.on
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @on_success_color /// get @on_success_color
pub fn on_success_color(&self) -> Srgba { pub fn on_success_color(&self) -> Srgba {
self.success.on self.success.on
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @on_warning_color /// get @on_warning_color
pub fn on_warning_color(&self) -> Srgba { pub fn on_warning_color(&self) -> Srgba {
self.warning.on self.warning.on
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @on_destructive_color /// get @on_destructive_color
pub fn on_destructive_color(&self) -> Srgba { pub fn on_destructive_color(&self) -> Srgba {
self.destructive.on self.destructive.on
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @button_color /// get @button_color
pub fn button_color(&self) -> Srgba { pub fn button_color(&self) -> Srgba {
self.button.on self.button.on
@ -333,36 +388,47 @@ impl Theme {
// Borders and Dividers // Borders and Dividers
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @bg_divider /// get @bg_divider
pub fn bg_divider(&self) -> Srgba { pub fn bg_divider(&self) -> Srgba {
self.background.divider self.background.divider
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @bg_component_divider /// get @bg_component_divider
pub fn bg_component_divider(&self) -> Srgba { pub fn bg_component_divider(&self) -> Srgba {
self.background.component.divider self.background.component.divider
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @primary_container_divider /// get @primary_container_divider
pub fn primary_container_divider(&self) -> Srgba { pub fn primary_container_divider(&self) -> Srgba {
self.primary.divider self.primary.divider
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @primary_component_divider /// get @primary_component_divider
pub fn primary_component_divider(&self) -> Srgba { pub fn primary_component_divider(&self) -> Srgba {
self.primary.component.divider self.primary.component.divider
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @secondary_container_divider /// get @secondary_container_divider
pub fn secondary_container_divider(&self) -> Srgba { pub fn secondary_container_divider(&self) -> Srgba {
self.secondary.divider self.secondary.divider
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @button_divider /// get @button_divider
pub fn button_divider(&self) -> Srgba { pub fn button_divider(&self) -> Srgba {
self.button.divider self.button.divider
@ -370,6 +436,7 @@ impl Theme {
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @window_header_bg /// get @window_header_bg
pub fn window_header_bg(&self) -> Srgba { pub fn window_header_bg(&self) -> Srgba {
self.background.base self.background.base
@ -377,60 +444,79 @@ impl Theme {
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @space_none /// get @space_none
pub fn space_none(&self) -> u16 { pub fn space_none(&self) -> u16 {
self.spacing.space_none self.spacing.space_none
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @space_xxxs /// get @space_xxxs
pub fn space_xxxs(&self) -> u16 { pub fn space_xxxs(&self) -> u16 {
self.spacing.space_xxxs self.spacing.space_xxxs
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @space_xxs /// get @space_xxs
pub fn space_xxs(&self) -> u16 { pub fn space_xxs(&self) -> u16 {
self.spacing.space_xxs self.spacing.space_xxs
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @space_xs /// get @space_xs
pub fn space_xs(&self) -> u16 { pub fn space_xs(&self) -> u16 {
self.spacing.space_xs self.spacing.space_xs
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @space_s /// get @space_s
pub fn space_s(&self) -> u16 { pub fn space_s(&self) -> u16 {
self.spacing.space_s self.spacing.space_s
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @space_m /// get @space_m
pub fn space_m(&self) -> u16 { pub fn space_m(&self) -> u16 {
self.spacing.space_m self.spacing.space_m
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @space_l /// get @space_l
pub fn space_l(&self) -> u16 { pub fn space_l(&self) -> u16 {
self.spacing.space_l self.spacing.space_l
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @space_xl /// get @space_xl
pub fn space_xl(&self) -> u16 { pub fn space_xl(&self) -> u16 {
self.spacing.space_xl self.spacing.space_xl
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @space_xxl /// get @space_xxl
pub fn space_xxl(&self) -> u16 { pub fn space_xxl(&self) -> u16 {
self.spacing.space_xxl self.spacing.space_xxl
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @space_xxxl /// get @space_xxxl
pub fn space_xxxl(&self) -> u16 { pub fn space_xxxl(&self) -> u16 {
self.spacing.space_xxxl self.spacing.space_xxxl
@ -438,36 +524,47 @@ impl Theme {
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @radius_0 /// get @radius_0
pub fn radius_0(&self) -> [f32; 4] { pub fn radius_0(&self) -> [f32; 4] {
self.corner_radii.radius_0 self.corner_radii.radius_0
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @radius_xs /// get @radius_xs
pub fn radius_xs(&self) -> [f32; 4] { pub fn radius_xs(&self) -> [f32; 4] {
self.corner_radii.radius_xs self.corner_radii.radius_xs
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @radius_s /// get @radius_s
pub fn radius_s(&self) -> [f32; 4] { pub fn radius_s(&self) -> [f32; 4] {
self.corner_radii.radius_s self.corner_radii.radius_s
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @radius_m /// get @radius_m
pub fn radius_m(&self) -> [f32; 4] { pub fn radius_m(&self) -> [f32; 4] {
self.corner_radii.radius_m self.corner_radii.radius_m
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @radius_l /// get @radius_l
pub fn radius_l(&self) -> [f32; 4] { pub fn radius_l(&self) -> [f32; 4] {
self.corner_radii.radius_l self.corner_radii.radius_l
} }
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @radius_xl /// get @radius_xl
pub fn radius_xl(&self) -> [f32; 4] { pub fn radius_xl(&self) -> [f32; 4] {
self.corner_radii.radius_xl self.corner_radii.radius_xl
@ -475,6 +572,7 @@ impl Theme {
#[must_use] #[must_use]
#[allow(clippy::doc_markdown)] #[allow(clippy::doc_markdown)]
#[inline]
/// get @shade_color /// get @shade_color
pub fn shade_color(&self) -> Srgba { pub fn shade_color(&self) -> Srgba {
self.shade self.shade
@ -631,6 +729,7 @@ impl Default for ThemeBuilder {
} }
impl ThemeBuilder { impl ThemeBuilder {
#[inline]
/// Get a builder that is initialized with the default dark theme /// Get a builder that is initialized with the default dark theme
pub fn dark() -> Self { pub fn dark() -> Self {
Self { Self {
@ -639,6 +738,7 @@ impl ThemeBuilder {
} }
} }
#[inline]
/// Get a builder that is initialized with the default light theme /// Get a builder that is initialized with the default light theme
pub fn light() -> Self { pub fn light() -> Self {
Self { Self {
@ -647,6 +747,7 @@ impl ThemeBuilder {
} }
} }
#[inline]
/// Get a builder that is initialized with the default dark high contrast theme /// Get a builder that is initialized with the default dark high contrast theme
pub fn dark_high_contrast() -> Self { pub fn dark_high_contrast() -> Self {
let palette: CosmicPalette = DARK_PALETTE.to_owned(); let palette: CosmicPalette = DARK_PALETTE.to_owned();
@ -656,6 +757,7 @@ impl ThemeBuilder {
} }
} }
#[inline]
/// Get a builder that is initialized with the default light high contrast theme /// Get a builder that is initialized with the default light high contrast theme
pub fn light_high_contrast() -> Self { pub fn light_high_contrast() -> Self {
let palette: CosmicPalette = LIGHT_PALETTE.to_owned(); let palette: CosmicPalette = LIGHT_PALETTE.to_owned();
@ -665,6 +767,7 @@ impl ThemeBuilder {
} }
} }
#[inline]
/// Get a builder that is initialized with the provided palette /// Get a builder that is initialized with the provided palette
pub fn palette(palette: CosmicPalette) -> Self { pub fn palette(palette: CosmicPalette) -> Self {
Self { Self {
@ -673,60 +776,70 @@ impl ThemeBuilder {
} }
} }
#[inline]
/// set the spacing of the builder /// set the spacing of the builder
pub fn spacing(mut self, spacing: Spacing) -> Self { pub fn spacing(mut self, spacing: Spacing) -> Self {
self.spacing = spacing; self.spacing = spacing;
self self
} }
#[inline]
/// set the corner radii of the builder /// set the corner radii of the builder
pub fn corner_radii(mut self, corner_radii: CornerRadii) -> Self { pub fn corner_radii(mut self, corner_radii: CornerRadii) -> Self {
self.corner_radii = corner_radii; self.corner_radii = corner_radii;
self self
} }
#[inline]
/// apply a neutral tint to the palette /// apply a neutral tint to the palette
pub fn neutral_tint(mut self, tint: Srgb) -> Self { pub fn neutral_tint(mut self, tint: Srgb) -> Self {
self.neutral_tint = Some(tint); self.neutral_tint = Some(tint);
self self
} }
#[inline]
/// apply a text tint to the palette /// apply a text tint to the palette
pub fn text_tint(mut self, tint: Srgb) -> Self { pub fn text_tint(mut self, tint: Srgb) -> Self {
self.text_tint = Some(tint); self.text_tint = Some(tint);
self self
} }
#[inline]
/// apply a background color to the palette /// apply a background color to the palette
pub fn bg_color(mut self, c: Srgba) -> Self { pub fn bg_color(mut self, c: Srgba) -> Self {
self.bg_color = Some(c); self.bg_color = Some(c);
self self
} }
#[inline]
/// apply a primary container background color to the palette /// apply a primary container background color to the palette
pub fn primary_container_bg(mut self, c: Srgba) -> Self { pub fn primary_container_bg(mut self, c: Srgba) -> Self {
self.primary_container_bg = Some(c); self.primary_container_bg = Some(c);
self self
} }
#[inline]
/// apply a accent color to the palette /// apply a accent color to the palette
pub fn accent(mut self, c: Srgb) -> Self { pub fn accent(mut self, c: Srgb) -> Self {
self.accent = Some(c); self.accent = Some(c);
self self
} }
#[inline]
/// apply a success color to the palette /// apply a success color to the palette
pub fn success(mut self, c: Srgb) -> Self { pub fn success(mut self, c: Srgb) -> Self {
self.success = Some(c); self.success = Some(c);
self self
} }
#[inline]
/// apply a warning color to the palette /// apply a warning color to the palette
pub fn warning(mut self, c: Srgb) -> Self { pub fn warning(mut self, c: Srgb) -> Self {
self.warning = Some(c); self.warning = Some(c);
self self
} }
#[inline]
/// apply a destructive color to the palette /// apply a destructive color to the palette
pub fn destructive(mut self, c: Srgb) -> Self { pub fn destructive(mut self, c: Srgb) -> Self {
self.destructive = Some(c); self.destructive = Some(c);
@ -1139,11 +1252,13 @@ impl ThemeBuilder {
theme theme
} }
#[inline]
/// Get the builder for the dark config /// Get the builder for the dark config
pub fn dark_config() -> Result<Config, cosmic_config::Error> { pub fn dark_config() -> Result<Config, cosmic_config::Error> {
Config::new(DARK_THEME_BUILDER_ID, Self::VERSION) Config::new(DARK_THEME_BUILDER_ID, Self::VERSION)
} }
#[inline]
/// Get the builder for the light config /// Get the builder for the light config
pub fn light_config() -> Result<Config, cosmic_config::Error> { pub fn light_config() -> Result<Config, cosmic_config::Error> {
Config::new(LIGHT_THEME_BUILDER_ID, Self::VERSION) Config::new(LIGHT_THEME_BUILDER_ID, Self::VERSION)

View file

@ -11,6 +11,7 @@ use super::{to_rgba, OutputError};
impl Theme { impl Theme {
#[must_use] #[must_use]
#[cold]
/// turn the theme into css /// turn the theme into css
pub fn as_gtk4(&self) -> String { pub fn as_gtk4(&self) -> String {
let Self { let Self {
@ -145,6 +146,7 @@ impl Theme {
/// # Errors /// # Errors
/// ///
/// Returns an `OutputError` if there is an error writing the CSS file. /// Returns an `OutputError` if there is an error writing the CSS file.
#[cold]
pub fn write_gtk4(&self) -> Result<(), OutputError> { pub fn write_gtk4(&self) -> Result<(), OutputError> {
let css_str = self.as_gtk4(); let css_str = self.as_gtk4();
let Some(config_dir) = dirs::config_dir() else { let Some(config_dir) = dirs::config_dir() else {
@ -174,6 +176,7 @@ impl Theme {
/// # Errors /// # Errors
/// ///
/// Returns an `OutputError` if there is an error applying the CSS file. /// Returns an `OutputError` if there is an error applying the CSS file.
#[cold]
pub fn apply_gtk(is_dark: bool) -> Result<(), OutputError> { pub fn apply_gtk(is_dark: bool) -> Result<(), OutputError> {
let Some(config_dir) = dirs::config_dir() else { let Some(config_dir) = dirs::config_dir() else {
return Err(OutputError::MissingConfigDir); return Err(OutputError::MissingConfigDir);
@ -213,6 +216,7 @@ impl Theme {
/// # Errors /// # Errors
/// ///
/// Returns an `OutputError` if there is an error resetting the CSS file. /// Returns an `OutputError` if there is an error resetting the CSS file.
#[cold]
pub fn reset_gtk() -> Result<(), OutputError> { pub fn reset_gtk() -> Result<(), OutputError> {
let Some(config_dir) = dirs::config_dir() else { let Some(config_dir) = dirs::config_dir() else {
return Err(OutputError::MissingConfigDir); return Err(OutputError::MissingConfigDir);
@ -229,6 +233,7 @@ impl Theme {
res res
} }
#[cold]
fn backup_non_cosmic_css(path: &Path, cosmic_css: &Path) -> io::Result<()> { fn backup_non_cosmic_css(path: &Path, cosmic_css: &Path) -> io::Result<()> {
if !Self::is_cosmic_css(path, cosmic_css)?.unwrap_or(true) { if !Self::is_cosmic_css(path, cosmic_css)?.unwrap_or(true) {
let backup_path = path.with_extension("css.bak"); let backup_path = path.with_extension("css.bak");
@ -237,6 +242,7 @@ impl Theme {
Ok(()) Ok(())
} }
#[cold]
fn reset_cosmic_css(path: &Path, cosmic_css: &Path) -> io::Result<()> { fn reset_cosmic_css(path: &Path, cosmic_css: &Path) -> io::Result<()> {
if Self::is_cosmic_css(path, cosmic_css)?.unwrap_or_default() { if Self::is_cosmic_css(path, cosmic_css)?.unwrap_or_default() {
fs::remove_file(path)?; fs::remove_file(path)?;

View file

@ -19,6 +19,7 @@ pub enum OutputError {
} }
impl Theme { impl Theme {
#[inline]
pub fn apply_exports(&self) -> Result<(), OutputError> { pub fn apply_exports(&self) -> Result<(), OutputError> {
let gtk_res = Theme::apply_gtk(self.is_dark); let gtk_res = Theme::apply_gtk(self.is_dark);
let vs_res = self.clone().apply_vs_code(); let vs_res = self.clone().apply_vs_code();
@ -27,12 +28,14 @@ impl Theme {
Ok(()) Ok(())
} }
#[inline]
pub fn write_exports(&self) -> Result<(), OutputError> { pub fn write_exports(&self) -> Result<(), OutputError> {
let gtk_res = self.write_gtk4(); let gtk_res = self.write_gtk4();
gtk_res?; gtk_res?;
Ok(()) Ok(())
} }
#[inline]
pub fn reset_exports() -> Result<(), OutputError> { pub fn reset_exports() -> Result<(), OutputError> {
let gtk_res = Theme::reset_gtk(); let gtk_res = Theme::reset_gtk();
let vs_res = Theme::reset_vs_code(); let vs_res = Theme::reset_vs_code();

View file

@ -266,6 +266,7 @@ impl From<Theme> for VsTheme {
} }
impl Theme { impl Theme {
#[cold]
pub fn apply_vs_code(self) -> Result<(), OutputError> { pub fn apply_vs_code(self) -> Result<(), OutputError> {
let vs_theme = VsTheme::from(self); let vs_theme = VsTheme::from(self);
let config_dir = dirs::config_dir().ok_or(OutputError::MissingConfigDir)?; let config_dir = dirs::config_dir().ok_or(OutputError::MissingConfigDir)?;
@ -289,6 +290,7 @@ impl Theme {
Ok(()) Ok(())
} }
#[cold]
pub fn reset_vs_code() -> Result<(), OutputError> { pub fn reset_vs_code() -> Result<(), OutputError> {
let config_dir = dirs::config_dir().ok_or(OutputError::MissingConfigDir)?; let config_dir = dirs::config_dir().ok_or(OutputError::MissingConfigDir)?;
let vs_code_dir = config_dir.join("Code").join("User"); let vs_code_dir = config_dir.join("Code").join("User");

View file

@ -6,16 +6,16 @@ use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use super::{Action, Application, ApplicationExt, Subscription}; use super::{Action, Application, ApplicationExt, Subscription};
use crate::theme::{Theme, ThemeType, THEME}; use crate::theme::{THEME, Theme, ThemeType};
use crate::{keyboard_nav, Core, Element}; use crate::{Core, Element, keyboard_nav};
#[cfg(feature = "wayland")] #[cfg(feature = "wayland")]
use cctk::sctk::reexports::csd_frame::{WindowManagerCapabilities, WindowState}; use cctk::sctk::reexports::csd_frame::{WindowManagerCapabilities, WindowState};
use cosmic_theme::ThemeMode; use cosmic_theme::ThemeMode;
#[cfg(feature = "wayland")]
use iced::event::wayland;
#[cfg(not(any(feature = "multi-window", feature = "wayland")))] #[cfg(not(any(feature = "multi-window", feature = "wayland")))]
use iced::Application as IcedApplication; use iced::Application as IcedApplication;
use iced::{window, Task}; #[cfg(feature = "wayland")]
use iced::event::wayland;
use iced::{Task, window};
use iced_futures::event::listen_with; use iced_futures::event::listen_with;
use palette::color_difference::EuclideanDistance; use palette::color_difference::EuclideanDistance;
@ -243,6 +243,7 @@ where
} }
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
#[cold]
pub fn subscription(&self) -> Subscription<crate::Action<T::Message>> { pub fn subscription(&self) -> Subscription<crate::Action<T::Message>> {
let window_events = listen_with(|event, _, id| { let window_events = listen_with(|event, _, id| {
match event { match event {
@ -410,6 +411,7 @@ where
impl<T: Application> Cosmic<T> { impl<T: Application> Cosmic<T> {
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
#[cold]
pub fn close(&mut self) -> iced::Task<crate::Action<T::Message>> { pub fn close(&mut self) -> iced::Task<crate::Action<T::Message>> {
if let Some(id) = self.app.core().main_window_id() { if let Some(id) = self.app.core().main_window_id() {
iced::window::close(id) iced::window::close(id)
@ -490,10 +492,10 @@ impl<T: Application> Cosmic<T> {
Action::KeyboardNav(message) => match message { Action::KeyboardNav(message) => match message {
keyboard_nav::Action::FocusNext => { keyboard_nav::Action::FocusNext => {
return iced::widget::focus_next().map(crate::Action::Cosmic) return iced::widget::focus_next().map(crate::Action::Cosmic);
} }
keyboard_nav::Action::FocusPrevious => { keyboard_nav::Action::FocusPrevious => {
return iced::widget::focus_previous().map(crate::Action::Cosmic) return iced::widget::focus_previous().map(crate::Action::Cosmic);
} }
keyboard_nav::Action::Escape => return self.app.on_escape(), keyboard_nav::Action::Escape => return self.app.on_escape(),
keyboard_nav::Action::Search => return self.app.on_search(), keyboard_nav::Action::Search => return self.app.on_search(),

View file

@ -17,10 +17,10 @@ pub mod settings;
pub type Task<M> = iced::Task<crate::Action<M>>; pub type Task<M> = iced::Task<crate::Action<M>>;
pub use crate::Core;
use crate::prelude::*; use crate::prelude::*;
use crate::theme::THEME; use crate::theme::THEME;
use crate::widget::{container, horizontal_space, id_container, menu, nav_bar, popover}; use crate::widget::{container, horizontal_space, id_container, menu, nav_bar, popover};
pub use crate::Core;
use apply::Apply; use apply::Apply;
use context_drawer::ContextDrawer; use context_drawer::ContextDrawer;
use iced::window; use iced::window;
@ -28,6 +28,7 @@ use iced::{Length, Subscription};
pub use settings::Settings; pub use settings::Settings;
use std::borrow::Cow; use std::borrow::Cow;
#[cold]
pub(crate) fn iced_settings<App: Application>( pub(crate) fn iced_settings<App: Application>(
settings: Settings, settings: Settings,
flags: App::Flags, flags: App::Flags,
@ -681,11 +682,10 @@ impl<App: Application> ApplicationExt for App {
}; };
// Ensures visually aligned radii for content and window corners // Ensures visually aligned radii for content and window corners
let window_corner_radius = let window_corner_radius = crate::theme::active()
crate::theme::active() .cosmic()
.cosmic() .radius_s()
.radius_s() .map(|x| if x < 4.0 { x } else { x + 4.0 });
.map(|x| if x < 4.0 { x } else { x + 4.0 });
let view_column = crate::widget::column::with_capacity(2) let view_column = crate::widget::column::with_capacity(2)
.push_maybe(if core.window.show_headerbar { .push_maybe(if core.window.show_headerbar {
@ -811,6 +811,7 @@ const EMBEDDED_FONTS: &[&[u8]] = &[
include_bytes!("../../res/noto/NotoSansMono-Bold.ttf"), include_bytes!("../../res/noto/NotoSansMono-Bold.ttf"),
]; ];
#[cold]
fn preload_fonts() { fn preload_fonts() {
let mut font_system = iced::advanced::graphics::text::font_system() let mut font_system = iced::advanced::graphics::text::font_system()
.write() .write()

View file

@ -134,6 +134,7 @@ impl Default for CosmicTk {
} }
impl CosmicTk { impl CosmicTk {
#[inline]
pub fn config() -> Result<Config, cosmic_config::Error> { pub fn config() -> Result<Config, cosmic_config::Error> {
Config::new(ID, Self::VERSION) Config::new(ID, Self::VERSION)
} }

View file

@ -6,7 +6,7 @@ use std::collections::HashMap;
use crate::widget::nav_bar; use crate::widget::nav_bar;
use cosmic_config::CosmicConfigEntry; use cosmic_config::CosmicConfigEntry;
use cosmic_theme::ThemeMode; use cosmic_theme::ThemeMode;
use iced::{window, Limits, Size}; use iced::{Limits, Size, window};
use iced_core::window::Id; use iced_core::window::Id;
use palette::Srgba; use palette::Srgba;
use slotmap::Key; use slotmap::Key;
@ -161,45 +161,52 @@ impl Default for Core {
impl Core { impl Core {
/// Whether the window is too small for the nav bar + main content. /// Whether the window is too small for the nav bar + main content.
#[must_use] #[must_use]
pub fn is_condensed(&self) -> bool { #[inline]
pub const fn is_condensed(&self) -> bool {
self.is_condensed self.is_condensed
} }
/// The scaling factor used by the application. /// The scaling factor used by the application.
#[must_use] #[must_use]
pub fn scale_factor(&self) -> f32 { #[inline]
pub const fn scale_factor(&self) -> f32 {
self.scale_factor self.scale_factor
} }
/// Enable or disable keyboard navigation /// Enable or disable keyboard navigation
pub fn set_keyboard_nav(&mut self, enabled: bool) { #[inline]
pub const fn set_keyboard_nav(&mut self, enabled: bool) {
self.keyboard_nav = enabled; self.keyboard_nav = enabled;
} }
#[must_use]
/// Enable or disable keyboard navigation /// Enable or disable keyboard navigation
pub fn keyboard_nav(&self) -> bool { #[must_use]
#[inline]
pub const fn keyboard_nav(&self) -> bool {
self.keyboard_nav self.keyboard_nav
} }
/// Changes the scaling factor used by the application. /// Changes the scaling factor used by the application.
#[cold]
pub(crate) fn set_scale_factor(&mut self, factor: f32) { pub(crate) fn set_scale_factor(&mut self, factor: f32) {
self.scale_factor = factor; self.scale_factor = factor;
self.is_condensed_update(); self.is_condensed_update();
} }
/// Set header bar title /// Set header bar title
#[inline]
pub fn set_header_title(&mut self, title: String) { pub fn set_header_title(&mut self, title: String) {
self.window.header_title = title; self.window.header_title = title;
} }
#[inline]
/// Whether to show or hide the main window's content. /// Whether to show or hide the main window's content.
pub(crate) fn show_content(&self) -> bool { pub(crate) fn show_content(&self) -> bool {
!self.is_condensed || !self.nav_bar.toggled_condensed !self.is_condensed || !self.nav_bar.toggled_condensed
} }
/// Call this whenever the scaling factor or window width has changed.
#[allow(clippy::cast_precision_loss)] #[allow(clippy::cast_precision_loss)]
/// Call this whenever the scaling factor or window width has changed.
fn is_condensed_update(&mut self) { fn is_condensed_update(&mut self) {
// Nav bar (280px) + padding (8px) + content (360px) // Nav bar (280px) + padding (8px) + content (360px)
let mut breakpoint = 280.0 + 8.0 + 360.0; let mut breakpoint = 280.0 + 8.0 + 360.0;
@ -212,6 +219,7 @@ impl Core {
self.nav_bar_update(); self.nav_bar_update();
} }
#[inline]
fn condensed_conflict(&self) -> bool { fn condensed_conflict(&self) -> bool {
// There is a conflict if the view is condensed and both the nav bar and context drawer are open on the same layer // There is a conflict if the view is condensed and both the nav bar and context drawer are open on the same layer
self.is_condensed self.is_condensed
@ -220,6 +228,7 @@ impl Core {
&& !self.window.context_is_overlay && !self.window.context_is_overlay
} }
#[inline]
pub(crate) fn context_width(&self, has_nav: bool) -> f32 { pub(crate) fn context_width(&self, has_nav: bool) -> f32 {
let window_width = self.window.width / self.scale_factor; let window_width = self.window.width / self.scale_factor;
@ -230,12 +239,14 @@ impl Core {
reserved_width += 280.0 + 8.0; reserved_width += 280.0 + 8.0;
} }
#[allow(clippy::manual_clamp)]
// This logic is to ensure the context drawer does not take up too much of the content's space // This logic is to ensure the context drawer does not take up too much of the content's space
// The minimum width is 344px and the maximum with is 480px // The minimum width is 344px and the maximum with is 480px
// We want to keep the content at least 360px until going down to the minimum width // We want to keep the content at least 360px until going down to the minimum width
(window_width - reserved_width).min(480.0).max(344.0) (window_width - reserved_width).min(480.0).max(344.0)
} }
#[cold]
pub fn set_show_context(&mut self, show: bool) { pub fn set_show_context(&mut self, show: bool) {
self.window.show_context = show; self.window.show_context = show;
self.is_condensed_update(); self.is_condensed_update();
@ -246,38 +257,46 @@ impl Core {
} }
} }
#[inline]
pub fn main_window_is(&self, id: iced::window::Id) -> bool { pub fn main_window_is(&self, id: iced::window::Id) -> bool {
self.main_window_id().is_some_and(|main_id| main_id == id) self.main_window_id().is_some_and(|main_id| main_id == id)
} }
/// Whether the nav panel is visible or not /// Whether the nav panel is visible or not
#[must_use] #[must_use]
pub fn nav_bar_active(&self) -> bool { #[inline]
pub const fn nav_bar_active(&self) -> bool {
self.nav_bar.active self.nav_bar.active
} }
#[inline]
pub fn nav_bar_toggle(&mut self) { pub fn nav_bar_toggle(&mut self) {
self.nav_bar.toggled = !self.nav_bar.toggled; self.nav_bar.toggled = !self.nav_bar.toggled;
self.nav_bar_set_toggled_condensed(self.nav_bar.toggled); self.nav_bar_set_toggled_condensed(self.nav_bar.toggled);
} }
#[inline]
pub fn nav_bar_toggle_condensed(&mut self) { pub fn nav_bar_toggle_condensed(&mut self) {
self.nav_bar_set_toggled_condensed(!self.nav_bar.toggled_condensed); self.nav_bar_set_toggled_condensed(!self.nav_bar.toggled_condensed);
} }
pub(crate) fn nav_bar_context(&self) -> nav_bar::Id { #[inline]
pub(crate) const fn nav_bar_context(&self) -> nav_bar::Id {
self.nav_bar.context_id self.nav_bar.context_id
} }
#[inline]
pub(crate) fn nav_bar_set_context(&mut self, id: nav_bar::Id) { pub(crate) fn nav_bar_set_context(&mut self, id: nav_bar::Id) {
self.nav_bar.context_id = id; self.nav_bar.context_id = id;
} }
#[inline]
pub fn nav_bar_set_toggled(&mut self, toggled: bool) { pub fn nav_bar_set_toggled(&mut self, toggled: bool) {
self.nav_bar.toggled = toggled; self.nav_bar.toggled = toggled;
self.nav_bar_set_toggled_condensed(self.nav_bar.toggled); self.nav_bar_set_toggled_condensed(self.nav_bar.toggled);
} }
#[cold]
pub(crate) fn nav_bar_set_toggled_condensed(&mut self, toggled: bool) { pub(crate) fn nav_bar_set_toggled_condensed(&mut self, toggled: bool) {
self.nav_bar.toggled_condensed = toggled; self.nav_bar.toggled_condensed = toggled;
self.nav_bar_update(); self.nav_bar_update();
@ -293,6 +312,7 @@ impl Core {
} }
} }
#[inline]
pub(crate) fn nav_bar_update(&mut self) { pub(crate) fn nav_bar_update(&mut self) {
self.nav_bar.active = if self.is_condensed { self.nav_bar.active = if self.is_condensed {
self.nav_bar.toggled_condensed self.nav_bar.toggled_condensed
@ -301,25 +321,29 @@ impl Core {
}; };
} }
#[inline]
/// Set the height of the main window. /// Set the height of the main window.
pub(crate) fn set_window_height(&mut self, new_height: f32) { pub(crate) const fn set_window_height(&mut self, new_height: f32) {
self.window.height = new_height; self.window.height = new_height;
} }
#[inline]
/// Set the width of the main window. /// Set the width of the main window.
pub(crate) fn set_window_width(&mut self, new_width: f32) { pub(crate) fn set_window_width(&mut self, new_width: f32) {
self.window.width = new_width; self.window.width = new_width;
self.is_condensed_update(); self.is_condensed_update();
} }
#[inline]
/// Get the current system theme /// Get the current system theme
pub fn system_theme(&self) -> &Theme { pub const fn system_theme(&self) -> &Theme {
&self.system_theme &self.system_theme
} }
#[inline]
#[must_use] #[must_use]
/// Get the current system theme mode /// Get the current system theme mode
pub fn system_theme_mode(&self) -> ThemeMode { pub const fn system_theme_mode(&self) -> ThemeMode {
self.system_theme_mode self.system_theme_mode
} }
@ -359,12 +383,14 @@ impl Core {
/// Get the current focused window if it exists /// Get the current focused window if it exists
#[must_use] #[must_use]
pub fn focused_window(&self) -> Option<window::Id> { #[inline]
pub const fn focused_window(&self) -> Option<window::Id> {
self.focused_window self.focused_window
} }
/// Whether the application should use a dark theme, according to the system /// Whether the application should use a dark theme, according to the system
#[must_use] #[must_use]
#[inline]
pub fn system_is_dark(&self) -> bool { pub fn system_is_dark(&self) -> bool {
self.portal_is_dark self.portal_is_dark
.unwrap_or(self.system_theme_mode.is_dark) .unwrap_or(self.system_theme_mode.is_dark)
@ -372,11 +398,13 @@ impl Core {
/// The [`Id`] of the main window /// The [`Id`] of the main window
#[must_use] #[must_use]
#[inline]
pub fn main_window_id(&self) -> Option<window::Id> { pub fn main_window_id(&self) -> Option<window::Id> {
self.main_window.filter(|id| iced::window::Id::NONE != *id) self.main_window.filter(|id| iced::window::Id::NONE != *id)
} }
/// Reset the tracked main window to a new value /// Reset the tracked main window to a new value
#[inline]
pub fn set_main_window_id(&mut self, mut id: Option<window::Id>) -> Option<window::Id> { pub fn set_main_window_id(&mut self, mut id: Option<window::Id>) -> Option<window::Id> {
std::mem::swap(&mut self.main_window, &mut id); std::mem::swap(&mut self.main_window, &mut id);
id id

View file

@ -5,14 +5,15 @@ use {
crate::ApplicationExt, crate::ApplicationExt,
iced::Subscription, iced::Subscription,
iced_futures::futures::{ iced_futures::futures::{
channel::mpsc::{Receiver, Sender},
SinkExt, SinkExt,
channel::mpsc::{Receiver, Sender},
}, },
std::{any::TypeId, collections::HashMap}, std::{any::TypeId, collections::HashMap},
url::Url, url::Url,
zbus::{interface, proxy, zvariant::Value}, zbus::{interface, proxy, zvariant::Value},
}; };
#[cold]
pub fn subscription<App: ApplicationExt>() -> Subscription<crate::Action<App::Message>> { pub fn subscription<App: ApplicationExt>() -> Subscription<crate::Action<App::Message>> {
use iced_futures::futures::StreamExt; use iced_futures::futures::StreamExt;
iced_futures::Subscription::run_with_id( iced_futures::Subscription::run_with_id(
@ -105,10 +106,12 @@ pub struct DbusActivation(Option<Sender<Message>>);
impl DbusActivation { impl DbusActivation {
#[must_use] #[must_use]
#[inline]
pub fn new() -> Self { pub fn new() -> Self {
Self(None) Self(None)
} }
#[inline]
pub fn rx(&mut self) -> Receiver<Message> { pub fn rx(&mut self) -> Receiver<Message> {
let (tx, rx) = iced_futures::futures::channel::mpsc::channel(10); let (tx, rx) = iced_futures::futures::channel::mpsc::channel(10);
self.0 = Some(tx); self.0 = Some(tx);
@ -139,6 +142,7 @@ pub trait DbusActivationInterface {
#[interface(name = "org.freedesktop.DbusActivation")] #[interface(name = "org.freedesktop.DbusActivation")]
impl DbusActivation { impl DbusActivation {
#[cold]
async fn activate(&mut self, platform_data: HashMap<&str, Value<'_>>) { async fn activate(&mut self, platform_data: HashMap<&str, Value<'_>>) {
if let Some(tx) = &mut self.0 { if let Some(tx) = &mut self.0 {
let _ = tx let _ = tx
@ -159,6 +163,7 @@ impl DbusActivation {
} }
} }
#[cold]
async fn open(&mut self, uris: Vec<&str>, platform_data: HashMap<&str, Value<'_>>) { async fn open(&mut self, uris: Vec<&str>, platform_data: HashMap<&str, Value<'_>>) {
if let Some(tx) = &mut self.0 { if let Some(tx) = &mut self.0 {
let _ = tx let _ = tx
@ -181,6 +186,7 @@ impl DbusActivation {
} }
} }
#[cold]
async fn activate_action( async fn activate_action(
&mut self, &mut self,
action_name: &str, action_name: &str,

View file

@ -240,6 +240,7 @@ impl DesktopEntryData {
} }
#[cfg(not(windows))] #[cfg(not(windows))]
#[cold]
pub async fn spawn_desktop_exec<S, I, K, V>(exec: S, env_vars: I, app_id: Option<&str>) pub async fn spawn_desktop_exec<S, I, K, V>(exec: S, env_vars: I, app_id: Option<&str>)
where where
S: AsRef<str>, S: AsRef<str>,

View file

@ -6,10 +6,12 @@
pub use iced::Font; pub use iced::Font;
use iced_core::font::Weight; use iced_core::font::Weight;
#[inline]
pub fn default() -> Font { pub fn default() -> Font {
Font::from(crate::config::interface_font()) Font::from(crate::config::interface_font())
} }
#[inline]
pub fn light() -> Font { pub fn light() -> Font {
Font { Font {
weight: Weight::Light, weight: Weight::Light,
@ -17,6 +19,7 @@ pub fn light() -> Font {
} }
} }
#[inline]
pub fn semibold() -> Font { pub fn semibold() -> Font {
Font { Font {
weight: Weight::Semibold, weight: Weight::Semibold,
@ -24,6 +27,7 @@ pub fn semibold() -> Font {
} }
} }
#[inline]
pub fn bold() -> Font { pub fn bold() -> Font {
Font { Font {
weight: Weight::Bold, weight: Weight::Bold,
@ -31,6 +35,7 @@ pub fn bold() -> Font {
} }
} }
#[inline]
pub fn mono() -> Font { pub fn mono() -> Font {
Font::from(crate::config::monospace_font()) Font::from(crate::config::monospace_font())
} }

View file

@ -13,12 +13,14 @@ pub(crate) static DEFAULT: Mutex<Cow<'static, str>> = Mutex::new(Cow::Borrowed(C
/// The fallback icon theme to search if no icon theme was specified. /// The fallback icon theme to search if no icon theme was specified.
#[must_use] #[must_use]
#[allow(clippy::missing_panics_doc)] #[allow(clippy::missing_panics_doc)]
#[inline]
pub fn default() -> String { pub fn default() -> String {
DEFAULT.lock().unwrap().to_string() DEFAULT.lock().unwrap().to_string()
} }
/// Set the fallback icon theme to search when loading system icons. /// Set the fallback icon theme to search when loading system icons.
#[allow(clippy::missing_panics_doc)] #[allow(clippy::missing_panics_doc)]
#[cold]
pub fn set_default(name: impl Into<Cow<'static, str>>) { pub fn set_default(name: impl Into<Cow<'static, str>>) {
*DEFAULT.lock().unwrap() = name.into(); *DEFAULT.lock().unwrap() = name.into();
} }

View file

@ -3,7 +3,7 @@
//! Subscribe to common application keyboard shortcuts. //! Subscribe to common application keyboard shortcuts.
use iced::{event, keyboard, Event, Subscription}; use iced::{Event, Subscription, event, keyboard};
use iced_core::keyboard::key::Named; use iced_core::keyboard::key::Named;
use iced_futures::event::listen_raw; use iced_futures::event::listen_raw;
@ -16,6 +16,7 @@ pub enum Action {
Search, Search,
} }
#[cold]
pub fn subscription() -> Subscription<Action> { pub fn subscription() -> Subscription<Action> {
listen_raw(|event, status, _| { listen_raw(|event, status, _| {
if event::Status::Ignored != status { if event::Status::Ignored != status {

View file

@ -11,6 +11,7 @@ unsafe extern "C" {
fn mallopt(param: c_int, value: c_int) -> c_int; fn mallopt(param: c_int, value: c_int) -> c_int;
} }
#[inline]
pub fn trim(pad: usize) { pub fn trim(pad: usize) {
unsafe { unsafe {
malloc_trim(pad); malloc_trim(pad);
@ -18,6 +19,7 @@ pub fn trim(pad: usize) {
} }
/// Prevents glibc from hoarding memory via memory fragmentation. /// Prevents glibc from hoarding memory via memory fragmentation.
#[inline]
pub fn limit_mmap_threshold(threshold: i32) { pub fn limit_mmap_threshold(threshold: i32) {
unsafe { unsafe {
mallopt(M_MMAP_THRESHOLD, threshold as c_int); mallopt(M_MMAP_THRESHOLD, threshold as c_int);

View file

@ -5,7 +5,7 @@
use smol::io::AsyncReadExt; use smol::io::AsyncReadExt;
use std::io; use std::io;
use std::os::fd::OwnedFd; use std::os::fd::OwnedFd;
use std::process::{exit, Command, Stdio}; use std::process::{Command, Stdio, exit};
#[cfg(feature = "tokio")] #[cfg(feature = "tokio")]
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
@ -24,6 +24,7 @@ async fn read_from_pipe(read: OwnedFd) -> Option<u32> {
} }
/// Performs a double fork with setsid to spawn and detach a command. /// Performs a double fork with setsid to spawn and detach a command.
#[cold]
pub async fn spawn(mut command: Command) -> Option<u32> { pub async fn spawn(mut command: Command) -> Option<u32> {
// NOTE: Windows platform is not supported // NOTE: Windows platform is not supported
command command

View file

@ -50,6 +50,7 @@ pub enum Action {
} }
impl std::fmt::Debug for Action { impl std::fmt::Debug for Action {
#[cold]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::AppSubsurface(arg0, arg1) => f Self::AppSubsurface(arg0, arg1) => f

View file

@ -53,36 +53,41 @@ pub(crate) static THEME: Mutex<Theme> = Mutex::new(Theme {
}); });
/// Currently-defined theme. /// Currently-defined theme.
#[inline]
#[allow(clippy::missing_panics_doc)] #[allow(clippy::missing_panics_doc)]
pub fn active() -> Theme { pub fn active() -> Theme {
THEME.lock().unwrap().clone() THEME.lock().unwrap().clone()
} }
/// Currently-defined theme type. /// Currently-defined theme type.
#[inline]
#[allow(clippy::missing_panics_doc)] #[allow(clippy::missing_panics_doc)]
pub fn active_type() -> ThemeType { pub fn active_type() -> ThemeType {
THEME.lock().unwrap().theme_type.clone() THEME.lock().unwrap().theme_type.clone()
} }
/// Preferred interface spacing parameters defined by the active theme. /// Preferred interface spacing parameters defined by the active theme.
#[inline(always)] #[inline]
pub fn spacing() -> Spacing { pub fn spacing() -> Spacing {
active().cosmic().spacing active().cosmic().spacing
} }
/// Whether the active theme has a dark preference. /// Whether the active theme has a dark preference.
#[inline]
#[must_use] #[must_use]
pub fn is_dark() -> bool { pub fn is_dark() -> bool {
active_type().is_dark() active_type().is_dark()
} }
/// Whether the active theme is high contrast. /// Whether the active theme is high contrast.
#[inline]
#[must_use] #[must_use]
pub fn is_high_contrast() -> bool { pub fn is_high_contrast() -> bool {
active_type().is_high_contrast() active_type().is_high_contrast()
} }
/// Watches for changes to the system's theme preference. /// Watches for changes to the system's theme preference.
#[cold]
pub fn subscription(is_dark: bool) -> Subscription<crate::theme::Theme> { pub fn subscription(is_dark: bool) -> Subscription<crate::theme::Theme> {
config_subscription::<_, crate::cosmic_theme::Theme>( config_subscription::<_, crate::cosmic_theme::Theme>(
( (
@ -173,6 +178,7 @@ pub enum ThemeType {
impl ThemeType { impl ThemeType {
/// Whether the theme has a dark preference. /// Whether the theme has a dark preference.
#[must_use] #[must_use]
#[inline]
pub fn is_dark(&self) -> bool { pub fn is_dark(&self) -> bool {
match self { match self {
Self::Dark | Self::HighContrastDark => true, Self::Dark | Self::HighContrastDark => true,
@ -182,6 +188,7 @@ impl ThemeType {
} }
/// Whether the theme has a high contrast. /// Whether the theme has a high contrast.
#[inline]
#[must_use] #[must_use]
pub fn is_high_contrast(&self) -> bool { pub fn is_high_contrast(&self) -> bool {
match self { match self {
@ -191,6 +198,7 @@ impl ThemeType {
} }
} }
#[inline]
/// Prefer dark or light theme. /// Prefer dark or light theme.
/// If `None`, the system preference is used. /// If `None`, the system preference is used.
pub fn prefer_dark(&mut self, new_prefer_dark: Option<bool>) { pub fn prefer_dark(&mut self, new_prefer_dark: Option<bool>) {
@ -208,6 +216,7 @@ pub struct Theme {
} }
impl Theme { impl Theme {
#[inline]
pub fn cosmic(&self) -> &cosmic_theme::Theme { pub fn cosmic(&self) -> &cosmic_theme::Theme {
match self.theme_type { match self.theme_type {
ThemeType::Dark => &COSMIC_DARK, ThemeType::Dark => &COSMIC_DARK,
@ -218,6 +227,7 @@ impl Theme {
} }
} }
#[inline]
pub fn dark() -> Self { pub fn dark() -> Self {
Self { Self {
theme_type: ThemeType::Dark, theme_type: ThemeType::Dark,
@ -225,6 +235,7 @@ impl Theme {
} }
} }
#[inline]
pub fn light() -> Self { pub fn light() -> Self {
Self { Self {
theme_type: ThemeType::Light, theme_type: ThemeType::Light,
@ -232,6 +243,7 @@ impl Theme {
} }
} }
#[inline]
pub fn dark_hc() -> Self { pub fn dark_hc() -> Self {
Self { Self {
theme_type: ThemeType::HighContrastDark, theme_type: ThemeType::HighContrastDark,
@ -239,6 +251,7 @@ impl Theme {
} }
} }
#[inline]
pub fn light_hc() -> Self { pub fn light_hc() -> Self {
Self { Self {
theme_type: ThemeType::HighContrastLight, theme_type: ThemeType::HighContrastLight,
@ -246,6 +259,7 @@ impl Theme {
} }
} }
#[inline]
pub fn custom(theme: Arc<CosmicTheme>) -> Self { pub fn custom(theme: Arc<CosmicTheme>) -> Self {
Self { Self {
theme_type: ThemeType::Custom(theme), theme_type: ThemeType::Custom(theme),
@ -253,6 +267,7 @@ impl Theme {
} }
} }
#[inline]
pub fn system(theme: Arc<CosmicTheme>) -> Self { pub fn system(theme: Arc<CosmicTheme>) -> Self {
Self { Self {
theme_type: ThemeType::System { theme_type: ThemeType::System {
@ -263,6 +278,7 @@ impl Theme {
} }
} }
#[inline]
/// get current container /// get current container
/// can be used in a component that is intended to be a child of a `CosmicContainer` /// can be used in a component that is intended to be a child of a `CosmicContainer`
pub fn current_container(&self) -> &cosmic_theme::Container { pub fn current_container(&self) -> &cosmic_theme::Container {
@ -273,6 +289,7 @@ impl Theme {
} }
} }
#[inline]
/// set the theme /// set the theme
pub fn set_theme(&mut self, theme: ThemeType) { pub fn set_theme(&mut self, theme: ThemeType) {
self.theme_type = theme; self.theme_type = theme;
@ -280,6 +297,7 @@ impl Theme {
} }
impl LayeredTheme for Theme { impl LayeredTheme for Theme {
#[inline]
fn set_layer(&mut self, layer: cosmic_theme::Layer) { fn set_layer(&mut self, layer: cosmic_theme::Layer) {
self.layer = layer; self.layer = layer;
} }

View file

@ -1,6 +1,6 @@
use ashpd::desktop::settings::{ColorScheme, Contrast};
use ashpd::desktop::Color; use ashpd::desktop::Color;
use iced::futures::{self, select, FutureExt, SinkExt, StreamExt}; use ashpd::desktop::settings::{ColorScheme, Contrast};
use iced::futures::{self, FutureExt, SinkExt, StreamExt, select};
use iced_futures::stream; use iced_futures::stream;
use tracing::error; use tracing::error;
@ -11,6 +11,7 @@ pub enum Desktop {
Contrast(Contrast), Contrast(Contrast),
} }
#[cold]
pub fn desktop_settings() -> iced_futures::Subscription<Desktop> { pub fn desktop_settings() -> iced_futures::Subscription<Desktop> {
iced_futures::Subscription::run_with_id( iced_futures::Subscription::run_with_id(
std::any::TypeId::of::<Desktop>(), std::any::TypeId::of::<Desktop>(),

View file

@ -1,7 +1,7 @@
//! A container which constraints itself to a specific aspect ratio. //! A container which constraints itself to a specific aspect ratio.
use iced::widget::Container;
use iced::Size; use iced::Size;
use iced::widget::Container;
use iced_core::event::{self, Event}; use iced_core::event::{self, Event};
use iced_core::layout; use iced_core::layout;
use iced_core::mouse; use iced_core::mouse;
@ -76,6 +76,7 @@ where
/// Sets the width of the [`self.`]. /// Sets the width of the [`self.`].
#[must_use] #[must_use]
#[inline]
pub fn width(mut self, width: Length) -> Self { pub fn width(mut self, width: Length) -> Self {
self.container = self.container.width(width); self.container = self.container.width(width);
self self
@ -83,6 +84,7 @@ where
/// Sets the height of the [`Container`]. /// Sets the height of the [`Container`].
#[must_use] #[must_use]
#[inline]
pub fn height(mut self, height: Length) -> Self { pub fn height(mut self, height: Length) -> Self {
self.container = self.container.height(height); self.container = self.container.height(height);
self self
@ -90,6 +92,7 @@ where
/// Sets the maximum width of the [`Container`]. /// Sets the maximum width of the [`Container`].
#[must_use] #[must_use]
#[inline]
pub fn max_width(mut self, max_width: f32) -> Self { pub fn max_width(mut self, max_width: f32) -> Self {
self.container = self.container.max_width(max_width); self.container = self.container.max_width(max_width);
self self
@ -97,6 +100,7 @@ where
/// Sets the maximum height of the [`Container`] in pixels. /// Sets the maximum height of the [`Container`] in pixels.
#[must_use] #[must_use]
#[inline]
pub fn max_height(mut self, max_height: f32) -> Self { pub fn max_height(mut self, max_height: f32) -> Self {
self.container = self.container.max_height(max_height); self.container = self.container.max_height(max_height);
self self
@ -104,6 +108,7 @@ where
/// Sets the content alignment for the horizontal axis of the [`Container`]. /// Sets the content alignment for the horizontal axis of the [`Container`].
#[must_use] #[must_use]
#[inline]
pub fn align_x(mut self, alignment: Alignment) -> Self { pub fn align_x(mut self, alignment: Alignment) -> Self {
self.container = self.container.align_x(alignment); self.container = self.container.align_x(alignment);
self self
@ -111,6 +116,7 @@ where
/// Sets the content alignment for the vertical axis of the [`Container`]. /// Sets the content alignment for the vertical axis of the [`Container`].
#[must_use] #[must_use]
#[inline]
pub fn align_y(mut self, alignment: Alignment) -> Self { pub fn align_y(mut self, alignment: Alignment) -> Self {
self.container = self.container.align_y(alignment); self.container = self.container.align_y(alignment);
self self
@ -118,6 +124,7 @@ where
/// Centers the contents in the horizontal axis of the [`Container`]. /// Centers the contents in the horizontal axis of the [`Container`].
#[must_use] #[must_use]
#[inline]
pub fn center_x(mut self, width: Length) -> Self { pub fn center_x(mut self, width: Length) -> Self {
self.container = self.container.center_x(width); self.container = self.container.center_x(width);
self self
@ -125,6 +132,7 @@ where
/// Centers the contents in the vertical axis of the [`Container`]. /// Centers the contents in the vertical axis of the [`Container`].
#[must_use] #[must_use]
#[inline]
pub fn center_y(mut self, height: Length) -> Self { pub fn center_y(mut self, height: Length) -> Self {
self.container = self.container.center_y(height); self.container = self.container.center_y(height);
self self
@ -132,6 +140,7 @@ where
/// Centers the contents in the horizontal and vertical axis of the [`Container`]. /// Centers the contents in the horizontal and vertical axis of the [`Container`].
#[must_use] #[must_use]
#[inline]
pub fn center(mut self, length: Length) -> Self { pub fn center(mut self, length: Length) -> Self {
self.container = self.container.center(length); self.container = self.container.center(length);
self self

View file

@ -54,36 +54,43 @@ where
} }
} }
#[inline]
pub fn limits(mut self, limits: layout::Limits) -> Self { pub fn limits(mut self, limits: layout::Limits) -> Self {
self.limits = limits; self.limits = limits;
self self
} }
#[inline]
pub fn auto_width(mut self, auto_width: bool) -> Self { pub fn auto_width(mut self, auto_width: bool) -> Self {
self.auto_width = auto_width; self.auto_width = auto_width;
self self
} }
#[inline]
pub fn auto_height(mut self, auto_height: bool) -> Self { pub fn auto_height(mut self, auto_height: bool) -> Self {
self.auto_height = auto_height; self.auto_height = auto_height;
self self
} }
#[inline]
pub fn max_width(mut self, v: f32) -> Self { pub fn max_width(mut self, v: f32) -> Self {
self.limits = self.limits.max_width(v); self.limits = self.limits.max_width(v);
self self
} }
#[inline]
pub fn max_height(mut self, v: f32) -> Self { pub fn max_height(mut self, v: f32) -> Self {
self.limits = self.limits.max_height(v); self.limits = self.limits.max_height(v);
self self
} }
#[inline]
pub fn min_width(mut self, v: f32) -> Self { pub fn min_width(mut self, v: f32) -> Self {
self.limits = self.limits.min_width(v); self.limits = self.limits.min_width(v);
self self
} }
#[inline]
pub fn min_height(mut self, v: f32) -> Self { pub fn min_height(mut self, v: f32) -> Self {
self.limits = self.limits.min_height(v); self.limits = self.limits.min_height(v);
self self

View file

@ -2,13 +2,13 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
use super::{Builder, ButtonClass}; use super::{Builder, ButtonClass};
use crate::Element;
use crate::widget::{ use crate::widget::{
icon::{self, Handle}, icon::{self, Handle},
tooltip, tooltip,
}; };
use crate::Element;
use apply::Apply; use apply::Apply;
use iced_core::{font::Weight, text::LineHeight, widget::Id, Alignment, Length, Padding}; use iced_core::{Alignment, Length, Padding, font::Weight, text::LineHeight, widget::Id};
use std::borrow::Cow; use std::borrow::Cow;
pub type Button<'a, Message> = Builder<'a, Message, Icon>; pub type Button<'a, Message> = Builder<'a, Message, Icon>;
@ -114,11 +114,13 @@ impl<Message> Button<'_, Message> {
self self
} }
#[inline]
pub fn selected(mut self, selected: bool) -> Self { pub fn selected(mut self, selected: bool) -> Self {
self.variant.selected = selected; self.variant.selected = selected;
self self
} }
#[inline]
pub fn vertical(mut self, vertical: bool) -> Self { pub fn vertical(mut self, vertical: bool) -> Self {
self.variant.vertical = vertical; self.variant.vertical = vertical;
self.class = ButtonClass::IconVertical; self.class = ButtonClass::IconVertical;

View file

@ -3,10 +3,10 @@
use super::Builder; use super::Builder;
use crate::{ use crate::{
widget::{self, image::Handle},
Element, Element,
widget::{self, image::Handle},
}; };
use iced_core::{font::Weight, widget::Id, Length, Padding}; use iced_core::{Length, Padding, font::Weight, widget::Id};
use std::borrow::Cow; use std::borrow::Cow;
pub type Button<'a, Message> = Builder<'a, Message, Image<'a, Handle, Message>>; pub type Button<'a, Message> = Builder<'a, Message, Image<'a, Handle, Message>>;
@ -28,6 +28,7 @@ pub struct Image<'a, Handle, Message> {
} }
impl<'a, Message> Button<'a, Message> { impl<'a, Message> Button<'a, Message> {
#[inline]
pub fn new(variant: Image<'a, Handle, Message>) -> Self { pub fn new(variant: Image<'a, Handle, Message>) -> Self {
Self { Self {
id: Id::unique(), id: Id::unique(),
@ -47,16 +48,19 @@ impl<'a, Message> Button<'a, Message> {
} }
} }
#[inline]
pub fn on_remove(mut self, message: Message) -> Self { pub fn on_remove(mut self, message: Message) -> Self {
self.variant.on_remove = Some(message); self.variant.on_remove = Some(message);
self self
} }
#[inline]
pub fn on_remove_maybe(mut self, message: Option<Message>) -> Self { pub fn on_remove_maybe(mut self, message: Option<Message>) -> Self {
self.variant.on_remove = message; self.variant.on_remove = message;
self self
} }
#[inline]
pub fn selected(mut self, selected: bool) -> Self { pub fn selected(mut self, selected: bool) -> Self {
self.variant.selected = selected; self.variant.selected = selected;
self self

View file

@ -55,6 +55,7 @@ impl<'a, Message> Button<'a, Message> {
} }
} }
#[inline(never)]
pub fn icon() -> Handle { pub fn icon() -> Handle {
icon::from_svg_bytes(&include_bytes!("external-link.svg")[..]).symbolic(true) icon::from_svg_bytes(&include_bytes!("external-link.svg")[..]).symbolic(true)
} }

View file

@ -45,7 +45,7 @@ use std::borrow::Cow;
/// A button with a custom element for its content. /// 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>(content: impl Into<crate::Element<'a, Message>>) -> Button<'a, Message> {
Button::new(content) Button::new(content.into())
} }
/// An image button which may contain any widget as its content. /// An image button which may contain any widget as its content.
@ -53,7 +53,7 @@ pub fn custom_image_button<'a, Message>(
content: impl Into<crate::Element<'a, Message>>, content: impl Into<crate::Element<'a, Message>>,
on_remove: Option<Message>, on_remove: Option<Message>,
) -> Button<'a, Message> { ) -> Button<'a, Message> {
Button::new_image(content, on_remove) Button::new_image(content.into(), on_remove)
} }
/// A builder for constructing a custom [`Button`]. /// A builder for constructing a custom [`Button`].

View file

@ -3,8 +3,7 @@
use super::{Builder, ButtonClass}; use super::{Builder, ButtonClass};
use crate::widget::{icon, row, tooltip}; use crate::widget::{icon, row, tooltip};
use crate::{ext::CollectionWidget, Element}; use crate::{Apply, Element};
use apply::Apply;
use iced_core::{font::Weight, text::LineHeight, widget::Id, Alignment, Length, Padding}; use iced_core::{font::Weight, text::LineHeight, widget::Id, Alignment, Length, Padding};
use std::borrow::Cow; use std::borrow::Cow;

View file

@ -7,19 +7,19 @@
//! A [`Button`] has some local [`State`]. //! A [`Button`] has some local [`State`].
use iced_runtime::core::widget::Id; use iced_runtime::core::widget::Id;
use iced_runtime::{keyboard, task, Action, Task}; use iced_runtime::{Action, Task, keyboard, task};
use iced_core::event::{self, Event}; use iced_core::event::{self, Event};
use iced_core::renderer::{self, Quad, Renderer}; use iced_core::renderer::{self, Quad, Renderer};
use iced_core::touch; use iced_core::touch;
use iced_core::widget::tree::{self, Tree};
use iced_core::widget::Operation; use iced_core::widget::Operation;
use iced_core::{layout, svg}; use iced_core::widget::tree::{self, Tree};
use iced_core::{mouse, Border};
use iced_core::{overlay, Shadow};
use iced_core::{ use iced_core::{
Background, Clipboard, Color, Layout, Length, Padding, Point, Rectangle, Shell, Vector, Widget, Background, Clipboard, Color, Layout, Length, Padding, Point, Rectangle, Shell, Vector, Widget,
}; };
use iced_core::{Border, mouse};
use iced_core::{Shadow, overlay};
use iced_core::{layout, svg};
use iced_renderer::core::widget::operation; use iced_renderer::core::widget::operation;
use crate::theme::THEME; use crate::theme::THEME;
@ -118,24 +118,28 @@ impl<'a, Message> Button<'a, Message> {
} }
/// Sets the [`Id`] of the [`Button`]. /// Sets the [`Id`] of the [`Button`].
#[inline]
pub fn id(mut self, id: Id) -> Self { pub fn id(mut self, id: Id) -> Self {
self.id = id; self.id = id;
self self
} }
/// Sets the width of the [`Button`]. /// Sets the width of the [`Button`].
#[inline]
pub fn width(mut self, width: impl Into<Length>) -> Self { pub fn width(mut self, width: impl Into<Length>) -> Self {
self.width = width.into(); self.width = width.into();
self self
} }
/// Sets the height of the [`Button`]. /// Sets the height of the [`Button`].
#[inline]
pub fn height(mut self, height: impl Into<Length>) -> Self { pub fn height(mut self, height: impl Into<Length>) -> Self {
self.height = height.into(); self.height = height.into();
self self
} }
/// Sets the [`Padding`] of the [`Button`]. /// Sets the [`Padding`] of the [`Button`].
#[inline]
pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self { pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {
self.padding = padding.into(); self.padding = padding.into();
self self
@ -144,6 +148,7 @@ impl<'a, Message> Button<'a, Message> {
/// Sets the message that will be produced when the [`Button`] is pressed and released. /// 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. /// 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 { pub fn on_press(mut self, on_press: Message) -> Self {
self.on_press = Some(on_press); self.on_press = Some(on_press);
self self
@ -152,6 +157,7 @@ impl<'a, Message> Button<'a, Message> {
/// Sets the message that will be produced when the [`Button`] is pressed, /// 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. /// 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 { pub fn on_press_down(mut self, on_press: Message) -> Self {
self.on_press_down = Some(on_press); self.on_press_down = Some(on_press);
self self
@ -161,12 +167,14 @@ impl<'a, Message> Button<'a, Message> {
/// if `Some`. /// if `Some`.
/// ///
/// If `None`, the [`Button`] will be disabled. /// If `None`, the [`Button`] will be disabled.
#[inline]
pub fn on_press_maybe(mut self, on_press: Option<Message>) -> Self { pub fn on_press_maybe(mut self, on_press: Option<Message>) -> Self {
self.on_press = on_press; self.on_press = on_press;
self self
} }
/// Sets the the [`Button`] to enabled whether or not it has handlers for on press. /// Sets the the [`Button`] to enabled whether or not it has handlers for on press.
#[inline]
pub fn force_enabled(mut self, enabled: bool) -> Self { pub fn force_enabled(mut self, enabled: bool) -> Self {
self.force_enabled = enabled; self.force_enabled = enabled;
self self
@ -175,6 +183,7 @@ impl<'a, Message> Button<'a, Message> {
/// Sets the widget to a selected state. /// Sets the widget to a selected state.
/// ///
/// Displays a selection indicator on image buttons. /// Displays a selection indicator on image buttons.
#[inline]
pub fn selected(mut self, selected: bool) -> Self { pub fn selected(mut self, selected: bool) -> Self {
self.selected = selected; self.selected = selected;
@ -182,6 +191,7 @@ impl<'a, Message> Button<'a, Message> {
} }
/// Sets the style variant of this [`Button`]. /// Sets the style variant of this [`Button`].
#[inline]
pub fn class(mut self, style: crate::theme::Button) -> Self { pub fn class(mut self, style: crate::theme::Button) -> Self {
self.style = style; self.style = style;
self self
@ -579,8 +589,8 @@ impl<'a, Message: 'a + Clone> Widget<Message, crate::Theme, crate::Renderer>
p: mouse::Cursor, p: mouse::Cursor,
) -> iced_accessibility::A11yTree { ) -> iced_accessibility::A11yTree {
use iced_accessibility::{ use iced_accessibility::{
accesskit::{Action, DefaultActionVerb, NodeBuilder, NodeId, Rect, Role},
A11yNode, A11yTree, A11yNode, A11yTree,
accesskit::{Action, DefaultActionVerb, NodeBuilder, NodeId, Rect, Role},
}; };
// TODO why is state None sometimes? // TODO why is state None sometimes?
if matches!(state.state, iced_core::widget::tree::State::None) { if matches!(state.state, iced_core::widget::tree::State::None) {
@ -668,26 +678,31 @@ pub struct State {
impl State { impl State {
/// Creates a new [`State`]. /// Creates a new [`State`].
#[inline]
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
} }
/// Returns whether the [`Button`] is currently focused or not. /// Returns whether the [`Button`] is currently focused or not.
#[inline]
pub fn is_focused(self) -> bool { pub fn is_focused(self) -> bool {
self.is_focused self.is_focused
} }
/// Returns whether the [`Button`] is currently hovered or not. /// Returns whether the [`Button`] is currently hovered or not.
#[inline]
pub fn is_hovered(self) -> bool { pub fn is_hovered(self) -> bool {
self.is_hovered self.is_hovered
} }
/// Focuses the [`Button`]. /// Focuses the [`Button`].
#[inline]
pub fn focus(&mut self) { pub fn focus(&mut self) {
self.is_focused = true; self.is_focused = true;
} }
/// Unfocuses the [`Button`]. /// Unfocuses the [`Button`].
#[inline]
pub fn unfocus(&mut self) { pub fn unfocus(&mut self) {
self.is_focused = false; self.is_focused = false;
} }
@ -951,14 +966,17 @@ pub fn focus<Message: 'static>(id: Id) -> Task<Message> {
} }
impl operation::Focusable for State { impl operation::Focusable for State {
#[inline]
fn is_focused(&self) -> bool { fn is_focused(&self) -> bool {
Self::is_focused(*self) Self::is_focused(*self)
} }
#[inline]
fn focus(&mut self) { fn focus(&mut self) {
Self::focus(self); Self::focus(self);
} }
#[inline]
fn unfocus(&mut self) { fn unfocus(&mut self) {
Self::unfocus(self); Self::unfocus(self);
} }

View file

@ -6,7 +6,7 @@
use std::cmp; use std::cmp;
use crate::iced_core::{Alignment, Length, Padding}; use crate::iced_core::{Alignment, Length, Padding};
use crate::widget::{button, column, grid, icon, row, text, Grid}; use crate::widget::{Grid, button, column, grid, icon, row, text};
use chrono::{Datelike, Days, Local, Months, NaiveDate, Weekday}; use chrono::{Datelike, Days, Local, Months, NaiveDate, Weekday};
/// A widget that displays an interactive calendar. /// A widget that displays an interactive calendar.
@ -58,6 +58,7 @@ impl CalendarModel {
} }
} }
#[inline]
pub fn new(selected: NaiveDate, visible: NaiveDate) -> Self { pub fn new(selected: NaiveDate, visible: NaiveDate) -> Self {
CalendarModel { selected, visible } CalendarModel { selected, visible }
} }
@ -80,16 +81,19 @@ impl CalendarModel {
self.visible = next_month_date; self.visible = next_month_date;
} }
#[inline]
pub fn set_prev_month(&mut self) { pub fn set_prev_month(&mut self) {
self.show_prev_month(); self.show_prev_month();
self.selected = self.visible; self.selected = self.visible;
} }
#[inline]
pub fn set_next_month(&mut self) { pub fn set_next_month(&mut self) {
self.show_next_month(); self.show_next_month();
self.selected = self.visible; self.selected = self.visible;
} }
#[inline]
pub fn set_selected_visible(&mut self, selected: NaiveDate) { pub fn set_selected_visible(&mut self, selected: NaiveDate) {
self.selected = selected; self.selected = selected;
self.visible = self.selected; self.visible = self.selected;
@ -225,6 +229,7 @@ fn padded_control<'a, Message>(
.width(Length::Fill) .width(Length::Fill)
} }
#[inline]
fn menu_control_padding() -> Padding { fn menu_control_padding() -> Padding {
let guard = crate::theme::THEME.lock().unwrap(); let guard = crate::theme::THEME.lock().unwrap();
let cosmic = guard.cosmic(); let cosmic = guard.cosmic();

View file

@ -3,17 +3,17 @@
use std::borrow::Cow; use std::borrow::Cow;
use crate::widget::{button, column, container, icon, row, scrollable, text, LayerContainer}; use crate::widget::{LayerContainer, button, column, container, icon, row, scrollable, text};
use crate::{Apply, Element, Renderer, Theme}; use crate::{Apply, Element, Renderer, Theme};
use super::overlay::Overlay; use super::overlay::Overlay;
use iced_core::Alignment;
use iced_core::event::{self, Event}; use iced_core::event::{self, Event};
use iced_core::widget::{Operation, Tree}; use iced_core::widget::{Operation, Tree};
use iced_core::Alignment;
use iced_core::{ use iced_core::{
layout, mouse, overlay as iced_overlay, renderer, Clipboard, Layout, Length, Rectangle, Shell, Clipboard, Layout, Length, Rectangle, Shell, Vector, Widget, layout, mouse,
Vector, Widget, overlay as iced_overlay, renderer,
}; };
#[must_use] #[must_use]
@ -37,76 +37,97 @@ impl<'a, Message: Clone + 'static> ContextDrawer<'a, Message> {
where where
Drawer: Into<Element<'a, Message>>, Drawer: Into<Element<'a, Message>>,
{ {
let cosmic_theme::Spacing { #[inline(never)]
space_xxs, fn inner<'a, Message: Clone + 'static>(
space_s, title: Option<Cow<'a, str>>,
space_m, header_actions: Vec<Element<'a, Message>>,
space_l, header_opt: Option<Element<'a, Message>>,
.. footer_opt: Option<Element<'a, Message>>,
} = crate::theme::active().cosmic().spacing; drawer: Element<'a, Message>,
on_close: Message,
max_width: f32,
) -> Element<'a, Message> {
let cosmic_theme::Spacing {
space_xxs,
space_s,
space_m,
space_l,
..
} = crate::theme::active().cosmic().spacing;
let horizontal_padding = if max_width < 392.0 { space_s } else { space_l }; let horizontal_padding = if max_width < 392.0 { space_s } else { space_l };
let header_row = row::with_capacity(3) let header_row = row::with_capacity(3)
.width(Length::Fixed(480.0))
.align_y(Alignment::Center)
.push(
row::with_children(header_actions)
.spacing(space_xxs)
.width(Length::FillPortion(1)),
)
.push_maybe(
title.map(|title| text::heading(title).width(Length::FillPortion(1)).center()),
)
.push(
button::text("Close")
.trailing_icon(icon::from_name("go-next-symbolic"))
.on_press(on_close)
.apply(container)
.width(Length::FillPortion(1))
.align_x(Alignment::End),
);
let header = column::with_capacity(2)
.width(Length::Fixed(480.0))
.align_x(Alignment::Center)
.spacing(space_m)
.padding([space_m, horizontal_padding])
.push(header_row)
.push_maybe(header_opt);
let footer = footer_opt.map(|element| {
container(element)
.width(Length::Fixed(480.0)) .width(Length::Fixed(480.0))
.align_y(Alignment::Center) .align_y(Alignment::Center)
.padding([space_xxs, horizontal_padding]) .push(
}); row::with_children(header_actions)
let pane = column::with_capacity(3) .spacing(space_xxs)
.push(header) .width(Length::FillPortion(1)),
.push( )
scrollable(container(drawer.into()).padding([ .push_maybe(
0, title.map(|title| text::heading(title).width(Length::FillPortion(1)).center()),
horizontal_padding, )
if footer.is_some() { 0 } else { space_l }, .push(
horizontal_padding, button::text("Close")
])) .trailing_icon(icon::from_name("go-next-symbolic"))
.height(Length::Fill) .on_press(on_close)
.width(Length::Shrink), .apply(container)
) .width(Length::FillPortion(1))
.push_maybe(footer); .align_x(Alignment::End),
);
let header = column::with_capacity(2)
.width(Length::Fixed(480.0))
.align_x(Alignment::Center)
.spacing(space_m)
.padding([space_m, horizontal_padding])
.push(header_row)
.push_maybe(header_opt);
let footer = footer_opt.map(|element| {
container(element)
.width(Length::Fixed(480.0))
.align_y(Alignment::Center)
.padding([space_xxs, horizontal_padding])
});
let pane = column::with_capacity(3)
.push(header)
.push(
scrollable(container(drawer).padding([
0,
horizontal_padding,
if footer.is_some() { 0 } else { space_l },
horizontal_padding,
]))
.height(Length::Fill)
.width(Length::Shrink),
)
.push_maybe(footer);
// XXX new limits do not exactly handle the max width well for containers // XXX new limits do not exactly handle the max width well for containers
// XXX this is a hack to get around that // XXX this is a hack to get around that
container( container(
LayerContainer::new(pane) LayerContainer::new(pane)
.layer(cosmic_theme::Layer::Primary) .layer(cosmic_theme::Layer::Primary)
.class(crate::style::Container::ContextDrawer) .class(crate::style::Container::ContextDrawer)
.width(Length::Fill) .width(Length::Fill)
.height(Length::Fill) .height(Length::Fill)
.max_width(max_width), .max_width(max_width),
)
.width(Length::Fill)
.height(Length::Fill)
.align_x(Alignment::End)
.into()
}
inner(
title,
header_actions,
header_opt,
footer_opt,
drawer.into(),
on_close,
max_width,
) )
.width(Length::Fill)
.height(Length::Fill)
.align_x(Alignment::End)
.into()
} }
/// Creates an empty [`ContextDrawer`]. /// Creates an empty [`ContextDrawer`].
@ -149,6 +170,7 @@ impl<'a, Message: Clone + 'static> ContextDrawer<'a, Message> {
} }
// Optionally assigns message to `on_close` event. // Optionally assigns message to `on_close` event.
#[inline]
pub fn on_close_maybe(mut self, message: Option<Message>) -> Self { pub fn on_close_maybe(mut self, message: Option<Message>) -> Self {
self.on_close = message; self.on_close = message;
self self

View file

@ -6,8 +6,8 @@ use derive_setters::Setters;
use iced_core::event::{self, Event}; use iced_core::event::{self, Event};
use iced_core::widget::{Operation, Tree}; use iced_core::widget::{Operation, Tree};
use iced_core::{ use iced_core::{
layout, mouse, overlay, renderer, Clipboard, Layout, Length, Padding, Rectangle, Shell, Vector, Clipboard, Layout, Length, Padding, Rectangle, Shell, Vector, Widget, layout, mouse, overlay,
Widget, renderer,
}; };
/// Responsively generates rows and columns of widgets based on its dimensions. /// Responsively generates rows and columns of widgets based on its dimensions.
@ -78,6 +78,7 @@ impl<'a, Message> FlexRow<'a, Message> {
} }
/// Sets the space between each column and row. /// Sets the space between each column and row.
#[inline]
pub const fn spacing(mut self, spacing: u16) -> Self { pub const fn spacing(mut self, spacing: u16) -> Self {
self.column_spacing = spacing; self.column_spacing = spacing;
self.row_spacing = spacing; self.row_spacing = spacing;

View file

@ -10,17 +10,17 @@ use std::time::{Duration, Instant};
use ::image as image_rs; use ::image as image_rs;
use iced_core::image::Renderer as ImageRenderer; use iced_core::image::Renderer as ImageRenderer;
use iced_core::mouse::Cursor; use iced_core::mouse::Cursor;
use iced_core::widget::{tree, Tree}; use iced_core::widget::{Tree, tree};
use iced_core::{ use iced_core::{
event, layout, renderer, window, Clipboard, ContentFit, Element, Event, Layout, Length, Clipboard, ContentFit, Element, Event, Layout, Length, Rectangle, Shell, Size, Vector, Widget,
Rectangle, Shell, Size, Vector, Widget, event, layout, renderer, window,
}; };
use iced_runtime::Command; use iced_runtime::Command;
use iced_widget::image::{self, Handle}; use iced_widget::image::{self, Handle};
use image_rs::AnimationDecoder;
use image_rs::codecs::gif::GifDecoder; use image_rs::codecs::gif::GifDecoder;
use image_rs::codecs::png::PngDecoder; use image_rs::codecs::png::PngDecoder;
use image_rs::codecs::webp::WebPDecoder; use image_rs::codecs::webp::WebPDecoder;
use image_rs::AnimationDecoder;
#[cfg(not(feature = "tokio"))] #[cfg(not(feature = "tokio"))]
use iced_futures::futures::{AsyncRead, AsyncReadExt}; use iced_futures::futures::{AsyncRead, AsyncReadExt};
@ -61,6 +61,7 @@ pub struct Frames {
} }
impl fmt::Debug for Frames { impl fmt::Debug for Frames {
#[cold]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Frames").finish() f.debug_struct("Frames").finish()
} }
@ -95,31 +96,36 @@ impl Frames {
/// Load [`Frames`] from the supplied path /// Load [`Frames`] from the supplied path
pub fn load_from_path(path: impl AsRef<Path>) -> Command<Result<Frames, Error>> { pub fn load_from_path(path: impl AsRef<Path>) -> Command<Result<Frames, Error>> {
#[cfg(feature = "tokio")] #[inline(never)]
use tokio::fs::File; fn inner(path: &Path) -> Command<Result<Frames, Error>> {
#[cfg(feature = "tokio")] #[cfg(feature = "tokio")]
use tokio::io::BufReader; use tokio::fs::File;
#[cfg(feature = "tokio")]
use tokio::io::BufReader;
#[cfg(not(feature = "tokio"))] #[cfg(not(feature = "tokio"))]
use async_fs::File; use async_fs::File;
#[cfg(not(feature = "tokio"))] #[cfg(not(feature = "tokio"))]
use iced_futures::futures::io::BufReader; use iced_futures::futures::io::BufReader;
let path = path.as_ref().to_path_buf(); let path = path.as_ref().to_path_buf();
let f = async move { let f = async move {
let image_type = match &path.extension() { let image_type = match &path.extension() {
Some(ext) if ext == &OsStr::new("gif") => ImageType::Gif, Some(ext) if ext == &OsStr::new("gif") => ImageType::Gif,
Some(ext) if ext == &OsStr::new("apng") => ImageType::Apng, Some(ext) if ext == &OsStr::new("apng") => ImageType::Apng,
Some(ext) if ext == &OsStr::new("webp") => ImageType::WebP, Some(ext) if ext == &OsStr::new("webp") => ImageType::WebP,
_ => return Err(Error::Extension), _ => return Err(Error::Extension),
};
let reader = BufReader::new(File::open(path).await?);
Self::from_reader(reader, image_type).await
}; };
let reader = BufReader::new(File::open(path).await?);
Self::from_reader(reader, image_type).await Command::perform(f, std::convert::identity)
}; }
Command::perform(f, std::convert::identity) inner(path.as_ref())
} }
/// Decode [`Frames`] from the supplied async reader /// Decode [`Frames`] from the supplied async reader

View file

@ -105,6 +105,7 @@ impl<'a, Message> Grid<'a, Message> {
self self
} }
#[inline]
pub fn insert_row(mut self) -> Self { pub fn insert_row(mut self) -> Self {
self.row += 1; self.row += 1;
self.column = 1; self.column = 1;

View file

@ -2,11 +2,11 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
use crate::cosmic_theme::{Density, Spacing}; use crate::cosmic_theme::{Density, Spacing};
use crate::{theme, widget, Element}; use crate::{Element, theme, widget};
use apply::Apply; use apply::Apply;
use derive_setters::Setters; use derive_setters::Setters;
use iced::Length; use iced::Length;
use iced_core::{widget::tree, Vector, Widget}; use iced_core::{Vector, Widget, widget::tree};
use std::borrow::Cow; use std::borrow::Cow;
#[must_use] #[must_use]
@ -109,6 +109,7 @@ impl<'a, Message: Clone + 'static> HeaderBar<'a, Message> {
/// Build the widget /// Build the widget
#[must_use] #[must_use]
#[inline]
pub fn build(self) -> HeaderBarWidget<'a, Message> { pub fn build(self) -> HeaderBarWidget<'a, Message> {
HeaderBarWidget { HeaderBarWidget {
header_bar_inner: self.view(), header_bar_inner: self.view(),

View file

@ -17,6 +17,7 @@ pub struct Handle {
} }
impl Handle { impl Handle {
#[inline]
pub fn icon(self) -> Icon { pub fn icon(self) -> Icon {
super::icon(self) super::icon(self)
} }
@ -53,13 +54,17 @@ pub fn from_raster_bytes(
+ std::marker::Sync + std::marker::Sync
+ 'static, + 'static,
) -> Handle { ) -> Handle {
Handle { fn inner(bytes: Cow<'static, [u8]>) -> Handle {
symbolic: false, Handle {
data: match bytes.into() { symbolic: false,
Cow::Owned(b) => Data::Image(image::Handle::from_bytes(b)), data: match bytes {
Cow::Borrowed(b) => Data::Image(image::Handle::from_bytes(b)), Cow::Owned(b) => Data::Image(image::Handle::from_bytes(b)),
}, Cow::Borrowed(b) => Data::Image(image::Handle::from_bytes(b)),
},
}
} }
inner(bytes.into())
} }
/// Create an image handle from RGBA data, where you must define the width and height. /// Create an image handle from RGBA data, where you must define the width and height.
@ -71,13 +76,19 @@ pub fn from_raster_pixels(
+ std::marker::Send + std::marker::Send
+ std::marker::Sync, + std::marker::Sync,
) -> Handle { ) -> Handle {
Handle { fn inner(width: u32, height: u32, pixels: Cow<'static, [u8]>) -> Handle {
symbolic: false, Handle {
data: match pixels.into() { symbolic: false,
Cow::Owned(pixels) => Data::Image(image::Handle::from_rgba(width, height, pixels)), data: match pixels {
Cow::Borrowed(pixels) => Data::Image(image::Handle::from_rgba(width, height, pixels)), Cow::Owned(pixels) => Data::Image(image::Handle::from_rgba(width, height, pixels)),
}, Cow::Borrowed(pixels) => {
Data::Image(image::Handle::from_rgba(width, height, pixels))
}
},
}
} }
inner(width, height, pixels.into())
} }
/// Create a SVG handle from memory. /// Create a SVG handle from memory.

View file

@ -113,6 +113,7 @@ impl Named {
None None
} }
#[inline]
pub fn handle(self) -> Handle { pub fn handle(self) -> Handle {
Handle { Handle {
symbolic: self.symbolic, symbolic: self.symbolic,
@ -120,6 +121,7 @@ impl Named {
} }
} }
#[inline]
pub fn icon(self) -> Icon { pub fn icon(self) -> Icon {
let size = self.size; let size = self.size;
@ -133,18 +135,21 @@ impl Named {
} }
impl From<Named> for Handle { impl From<Named> for Handle {
#[inline]
fn from(builder: Named) -> Self { fn from(builder: Named) -> Self {
builder.handle() builder.handle()
} }
} }
impl From<Named> for Icon { impl From<Named> for Icon {
#[inline]
fn from(builder: Named) -> Self { fn from(builder: Named) -> Self {
builder.icon() builder.icon()
} }
} }
impl<Message: 'static> From<Named> for crate::Element<'_, Message> { impl<Message: 'static> From<Named> for crate::Element<'_, Message> {
#[inline]
fn from(builder: Named) -> Self { fn from(builder: Named) -> Self {
builder.icon().into() builder.icon().into()
} }

View file

@ -69,6 +69,7 @@ where
/// Sets the width of the [`self.`]. /// Sets the width of the [`self.`].
#[must_use] #[must_use]
#[inline]
pub fn width(mut self, width: Length) -> Self { pub fn width(mut self, width: Length) -> Self {
self.container = self.container.width(width); self.container = self.container.width(width);
self self
@ -76,6 +77,7 @@ where
/// Sets the height of the [`LayerContainer`]. /// Sets the height of the [`LayerContainer`].
#[must_use] #[must_use]
#[inline]
pub fn height(mut self, height: Length) -> Self { pub fn height(mut self, height: Length) -> Self {
self.container = self.container.height(height); self.container = self.container.height(height);
self self
@ -83,6 +85,7 @@ where
/// Sets the maximum width of the [`LayerContainer`]. /// Sets the maximum width of the [`LayerContainer`].
#[must_use] #[must_use]
#[inline]
pub fn max_width(mut self, max_width: f32) -> Self { pub fn max_width(mut self, max_width: f32) -> Self {
self.container = self.container.max_width(max_width); self.container = self.container.max_width(max_width);
self self
@ -90,6 +93,7 @@ where
/// Sets the maximum height of the [`LayerContainer`] in pixels. /// Sets the maximum height of the [`LayerContainer`] in pixels.
#[must_use] #[must_use]
#[inline]
pub fn max_height(mut self, max_height: f32) -> Self { pub fn max_height(mut self, max_height: f32) -> Self {
self.container = self.container.max_height(max_height); self.container = self.container.max_height(max_height);
self self
@ -97,6 +101,7 @@ where
/// Sets the content alignment for the horizontal axis of the [`LayerContainer`]. /// Sets the content alignment for the horizontal axis of the [`LayerContainer`].
#[must_use] #[must_use]
#[inline]
pub fn align_x(mut self, alignment: Alignment) -> Self { pub fn align_x(mut self, alignment: Alignment) -> Self {
self.container = self.container.align_x(alignment); self.container = self.container.align_x(alignment);
self self
@ -104,6 +109,7 @@ where
/// Sets the content alignment for the vertical axis of the [`LayerContainer`]. /// Sets the content alignment for the vertical axis of the [`LayerContainer`].
#[must_use] #[must_use]
#[inline]
pub fn align_y(mut self, alignment: Alignment) -> Self { pub fn align_y(mut self, alignment: Alignment) -> Self {
self.container = self.container.align_y(alignment); self.container = self.container.align_y(alignment);
self self
@ -111,6 +117,7 @@ where
/// Centers the contents in the horizontal axis of the [`LayerContainer`]. /// Centers the contents in the horizontal axis of the [`LayerContainer`].
#[must_use] #[must_use]
#[inline]
pub fn center_x(mut self, width: Length) -> Self { pub fn center_x(mut self, width: Length) -> Self {
self.container = self.container.center_x(width); self.container = self.container.center_x(width);
self self
@ -118,6 +125,7 @@ where
/// Centers the contents in the vertical axis of the [`LayerContainer`]. /// Centers the contents in the vertical axis of the [`LayerContainer`].
#[must_use] #[must_use]
#[inline]
pub fn center_y(mut self, height: Length) -> Self { pub fn center_y(mut self, height: Length) -> Self {
self.container = self.container.center_y(height); self.container = self.container.center_y(height);
self self
@ -125,6 +133,7 @@ where
/// Centers the contents in the horizontal and vertical axis of the [`Container`]. /// Centers the contents in the horizontal and vertical axis of the [`Container`].
#[must_use] #[must_use]
#[inline]
pub fn center(mut self, length: Length) -> Self { pub fn center(mut self, length: Length) -> Self {
self.container = self.container.center(length); self.container = self.container.center(length);
self self

View file

@ -5,11 +5,11 @@ use iced_core::Padding;
use iced_widget::container::Catalog; use iced_widget::container::Catalog;
use crate::{ use crate::{
theme, Apply, Element, theme,
widget::{container, divider, vertical_space}, widget::{container, divider, vertical_space},
Apply, Element,
}; };
#[inline]
pub fn list_column<'a, Message: 'static>() -> ListColumn<'a, Message> { pub fn list_column<'a, Message: 'static>() -> ListColumn<'a, Message> {
ListColumn::default() ListColumn::default()
} }
@ -42,48 +42,61 @@ impl<Message: 'static> Default for ListColumn<'_, Message> {
} }
impl<'a, Message: 'static> ListColumn<'a, Message> { impl<'a, Message: 'static> ListColumn<'a, Message> {
#[inline]
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
} }
#[allow(clippy::should_implement_trait)] #[allow(clippy::should_implement_trait)]
pub fn add(mut self, item: impl Into<Element<'a, Message>>) -> Self { pub fn add(self, item: impl Into<Element<'a, Message>>) -> Self {
if !self.children.is_empty() { #[inline(never)]
self.children.push( fn inner<'a, Message: 'static>(
container(divider::horizontal::default()) mut this: ListColumn<'a, Message>,
.padding([0, self.divider_padding]) item: Element<'a, Message>,
.into(), ) -> ListColumn<'a, Message> {
); if !this.children.is_empty() {
this.children.push(
container(divider::horizontal::default())
.padding([0, this.divider_padding])
.into(),
);
}
// Ensure a minimum height of 32.
let list_item = iced::widget::row![
container(item).align_y(iced::Alignment::Center),
vertical_space().height(iced::Length::Fixed(32.))
]
.padding(this.list_item_padding)
.align_y(iced::Alignment::Center);
this.children.push(list_item.into());
this
} }
// Ensure a minimum height of 32. inner(self, item.into())
let list_item = iced::widget::row![
container(item).align_y(iced::Alignment::Center),
vertical_space().height(iced::Length::Fixed(32.))
]
.padding(self.list_item_padding)
.align_y(iced::Alignment::Center);
self.children.push(list_item.into());
self
} }
#[inline]
pub fn spacing(mut self, spacing: u16) -> Self { pub fn spacing(mut self, spacing: u16) -> Self {
self.spacing = spacing; self.spacing = spacing;
self self
} }
/// Sets the style variant of this [`Circular`]. /// Sets the style variant of this [`Circular`].
#[inline]
pub fn style(mut self, style: <crate::Theme as Catalog>::Class<'a>) -> Self { pub fn style(mut self, style: <crate::Theme as Catalog>::Class<'a>) -> Self {
self.style = style; self.style = style;
self self
} }
#[inline]
pub fn padding(mut self, padding: impl Into<Padding>) -> Self { pub fn padding(mut self, padding: impl Into<Padding>) -> Self {
self.padding = padding.into(); self.padding = padding.into();
self self
} }
#[inline]
pub fn divider_padding(mut self, padding: u16) -> Self { pub fn divider_padding(mut self, padding: u16) -> Self {
self.divider_padding = padding; self.divider_padding = padding;
self self

View file

@ -7,13 +7,13 @@
use apply::Apply; use apply::Apply;
use iced::{ use iced::{
clipboard::{dnd::DndAction, mime::AllowedMimeTypes},
Background, Length, Background, Length,
clipboard::{dnd::DndAction, mime::AllowedMimeTypes},
}; };
use iced_core::{Border, Color, Shadow}; use iced_core::{Border, Color, Shadow};
use crate::widget::{container, menu, scrollable, segmented_button, Container, Icon}; use crate::widget::{Container, Icon, container, menu, scrollable, segmented_button};
use crate::{theme, Theme}; use crate::{Theme, theme};
use super::dnd_destination::DragId; use super::dnd_destination::DragId;
@ -62,16 +62,19 @@ pub struct NavBar<'a, Message> {
} }
impl<'a, Message: Clone + 'static> NavBar<'a, Message> { impl<'a, Message: Clone + 'static> NavBar<'a, Message> {
#[inline]
pub fn close_icon(mut self, close_icon: Icon) -> Self { pub fn close_icon(mut self, close_icon: Icon) -> Self {
self.segmented_button = self.segmented_button.close_icon(close_icon); self.segmented_button = self.segmented_button.close_icon(close_icon);
self self
} }
#[inline]
pub fn context_menu(mut self, context_menu: Option<Vec<menu::Tree<'a, Message>>>) -> Self { pub fn context_menu(mut self, context_menu: Option<Vec<menu::Tree<'a, Message>>>) -> Self {
self.segmented_button = self.segmented_button.context_menu(context_menu); self.segmented_button = self.segmented_button.context_menu(context_menu);
self self
} }
#[inline]
pub fn drag_id(mut self, id: DragId) -> Self { pub fn drag_id(mut self, id: DragId) -> Self {
self.segmented_button = self.segmented_button.drag_id(id); self.segmented_button = self.segmented_button.drag_id(id);
self self
@ -79,6 +82,7 @@ impl<'a, Message: Clone + 'static> NavBar<'a, Message> {
/// Pre-convert this widget into the [`Container`] widget that it becomes. /// Pre-convert this widget into the [`Container`] widget that it becomes.
#[must_use] #[must_use]
#[inline]
pub fn into_container(self) -> Container<'a, Message, crate::Theme, crate::Renderer> { pub fn into_container(self) -> Container<'a, Message, crate::Theme, crate::Renderer> {
Container::from(self) Container::from(self)
} }

View file

@ -16,7 +16,7 @@ pub struct NavBarToggle<Message> {
} }
#[must_use] #[must_use]
pub fn nav_bar_toggle<Message>() -> NavBarToggle<Message> { pub const fn nav_bar_toggle<Message>() -> NavBarToggle<Message> {
NavBarToggle { NavBarToggle {
active: false, active: false,
on_toggle: None, on_toggle: None,

View file

@ -1,15 +1,17 @@
use iced::{ use iced::{
futures::{
channel::mpsc::{unbounded, UnboundedReceiver},
stream, StreamExt,
},
Rectangle, Rectangle,
futures::{
StreamExt,
channel::mpsc::{UnboundedReceiver, unbounded},
stream,
},
}; };
use iced_futures::Subscription; use iced_futures::Subscription;
use std::{collections::HashMap, fmt::Debug, hash::Hash}; use std::{collections::HashMap, fmt::Debug, hash::Hash};
use super::RectangleTracker; use super::RectangleTracker;
#[cold]
pub fn rectangle_tracker_subscription< pub fn rectangle_tracker_subscription<
I: 'static + Hash + Copy + Send + Sync + Debug, I: 'static + Hash + Copy + Send + Sync + Debug,
R: 'static + Hash + Copy + Send + Sync + Debug + Eq, R: 'static + Hash + Copy + Send + Sync + Debug + Eq,

View file

@ -32,6 +32,7 @@ where
} }
/// Consumes the builder and returns the model. /// Consumes the builder and returns the model.
#[inline]
pub fn build(self) -> Model<SelectionMode> { pub fn build(self) -> Model<SelectionMode> {
self.0 self.0
} }
@ -43,6 +44,7 @@ where
{ {
/// Activates the newly-inserted item. /// Activates the newly-inserted item.
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)] #[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
#[inline]
pub fn activate(mut self) -> Self { pub fn activate(mut self) -> Self {
self.model.0.activate(self.id); self.model.0.activate(self.id);
self self
@ -50,6 +52,7 @@ where
/// Defines that the close button should appear /// Defines that the close button should appear
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)] #[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
#[inline]
pub fn closable(mut self) -> Self { pub fn closable(mut self) -> Self {
self.model.0.closable_set(self.id, true); self.model.0.closable_set(self.id, true);
self self
@ -60,6 +63,7 @@ where
/// The secondary map internally uses a `Vec`, so should only be used for data that /// The secondary map internally uses a `Vec`, so should only be used for data that
/// is commonly associated. /// is commonly associated.
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)] #[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
#[inline]
pub fn secondary<Data>(self, map: &mut SecondaryMap<Entity, Data>, data: Data) -> Self { pub fn secondary<Data>(self, map: &mut SecondaryMap<Entity, Data>, data: Data) -> Self {
map.insert(self.id, data); map.insert(self.id, data);
self self
@ -69,6 +73,7 @@ where
/// ///
/// Sparse maps internally use a `HashMap`, for data that is sparsely associated. /// Sparse maps internally use a `HashMap`, for data that is sparsely associated.
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)] #[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
#[inline]
pub fn secondary_sparse<Data>( pub fn secondary_sparse<Data>(
self, self,
map: &mut SparseSecondaryMap<Entity, Data>, map: &mut SparseSecondaryMap<Entity, Data>,
@ -90,11 +95,13 @@ where
/// .build() /// .build()
/// ``` /// ```
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)] #[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
#[inline]
pub fn data<Data: 'static>(mut self, data: Data) -> Self { pub fn data<Data: 'static>(mut self, data: Data) -> Self {
self.model.0.data_set(self.id, data); self.model.0.data_set(self.id, data);
self self
} }
#[inline]
pub fn divider_above(mut self) -> Self { pub fn divider_above(mut self) -> Self {
self.model.0.divider_above_set(self.id, true); self.model.0.divider_above_set(self.id, true);
self self
@ -115,6 +122,7 @@ where
/// Define the position of the newly-inserted item. /// Define the position of the newly-inserted item.
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)] #[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
#[inline]
pub fn position(mut self, position: u16) -> Self { pub fn position(mut self, position: u16) -> Self {
self.model.0.position_set(self.id, position); self.model.0.position_set(self.id, position);
self self
@ -122,6 +130,7 @@ where
/// Swap the position with another item in the model. /// Swap the position with another item in the model.
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)] #[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
#[inline]
pub fn position_swap(mut self, other: Entity) -> Self { pub fn position_swap(mut self, other: Entity) -> Self {
self.model.0.position_swap(self.id, other); self.model.0.position_swap(self.id, other);
self self

View file

@ -25,6 +25,7 @@ where
/// model.insert().text("Item A").activate(); /// model.insert().text("Item A").activate();
/// ``` /// ```
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)] #[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
#[inline]
pub fn activate(self) -> Self { pub fn activate(self) -> Self {
self.model.activate(self.id); self.model.activate(self.id);
self self
@ -40,6 +41,7 @@ where
/// model.insert().text("Item A").secondary(&mut secondary_data, String::new("custom data")); /// model.insert().text("Item A").secondary(&mut secondary_data, String::new("custom data"));
/// ``` /// ```
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)] #[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
#[inline]
pub fn secondary<Data>(self, map: &mut SecondaryMap<Entity, Data>, data: Data) -> Self { pub fn secondary<Data>(self, map: &mut SecondaryMap<Entity, Data>, data: Data) -> Self {
map.insert(self.id, data); map.insert(self.id, data);
self self
@ -54,6 +56,7 @@ where
/// model.insert().text("Item A").secondary(&mut secondary_data, String::new("custom data")); /// model.insert().text("Item A").secondary(&mut secondary_data, String::new("custom data"));
/// ``` /// ```
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)] #[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
#[inline]
pub fn secondary_sparse<Data>( pub fn secondary_sparse<Data>(
self, self,
map: &mut SparseSecondaryMap<Entity, Data>, map: &mut SparseSecondaryMap<Entity, Data>,
@ -65,6 +68,7 @@ where
/// Shows a close button for this item. /// Shows a close button for this item.
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)] #[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
#[inline]
pub fn closable(self) -> Self { pub fn closable(self) -> Self {
self.model.closable_set(self.id, true); self.model.closable_set(self.id, true);
self self
@ -78,12 +82,14 @@ where
/// model.insert().text("Item A").data(String::from("custom string")); /// model.insert().text("Item A").data(String::from("custom string"));
/// ``` /// ```
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)] #[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
#[inline]
pub fn data<Data: 'static>(self, data: Data) -> Self { pub fn data<Data: 'static>(self, data: Data) -> Self {
self.model.data_set(self.id, data); self.model.data_set(self.id, data);
self self
} }
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)] #[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
#[inline]
pub fn divider_above(self, divider_above: bool) -> Self { pub fn divider_above(self, divider_above: bool) -> Self {
self.model.divider_above_set(self.id, divider_above); self.model.divider_above_set(self.id, divider_above);
self self
@ -95,6 +101,7 @@ where
/// model.insert().text("Item A").icon(IconSource::from("icon-a")); /// model.insert().text("Item A").icon(IconSource::from("icon-a"));
/// ``` /// ```
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)] #[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
#[inline]
pub fn icon(self, icon: impl Into<Icon>) -> Self { pub fn icon(self, icon: impl Into<Icon>) -> Self {
self.model.icon_set(self.id, icon.into()); self.model.icon_set(self.id, icon.into());
self self
@ -106,11 +113,13 @@ where
/// let id = model.insert("Item A").id(); /// let id = model.insert("Item A").id();
/// ``` /// ```
#[must_use] #[must_use]
pub fn id(self) -> Entity { #[inline]
pub const fn id(self) -> Entity {
self.id self.id
} }
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)] #[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
#[inline]
pub fn indent(self, indent: u16) -> Self { pub fn indent(self, indent: u16) -> Self {
self.model.indent_set(self.id, indent); self.model.indent_set(self.id, indent);
self self
@ -118,6 +127,7 @@ where
/// Define the position of the item. /// Define the position of the item.
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)] #[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
#[inline]
pub fn position(self, position: u16) -> Self { pub fn position(self, position: u16) -> Self {
self.model.position_set(self.id, position); self.model.position_set(self.id, position);
self self
@ -125,6 +135,7 @@ where
/// Swap the position with another item in the model. /// Swap the position with another item in the model.
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)] #[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
#[inline]
pub fn position_swap(self, other: Entity) -> Self { pub fn position_swap(self, other: Entity) -> Self {
self.model.position_swap(self.id, other); self.model.position_swap(self.id, other);
self self

View file

@ -89,11 +89,13 @@ where
/// ```ignore /// ```ignore
/// model.activate(id); /// model.activate(id);
/// ``` /// ```
#[inline]
pub fn activate(&mut self, id: Entity) { pub fn activate(&mut self, id: Entity) {
Selectable::activate(self, id); Selectable::activate(self, id);
} }
/// Activates the item at the given position, returning true if it was activated. /// Activates the item at the given position, returning true if it was activated.
#[inline]
pub fn activate_position(&mut self, position: u16) -> bool { pub fn activate_position(&mut self, position: u16) -> bool {
if let Some(entity) = self.entity_at(position) { if let Some(entity) = self.entity_at(position) {
self.activate(entity); self.activate(entity);
@ -113,6 +115,7 @@ where
/// .build(); /// .build();
/// ``` /// ```
#[must_use] #[must_use]
#[inline]
pub fn builder() -> ModelBuilder<SelectionMode> { pub fn builder() -> ModelBuilder<SelectionMode> {
ModelBuilder::default() ModelBuilder::default()
} }
@ -126,6 +129,7 @@ where
/// ```ignore /// ```ignore
/// model.clear(); /// model.clear();
/// ``` /// ```
#[inline]
pub fn clear(&mut self) { pub fn clear(&mut self) {
for entity in self.order.clone() { for entity in self.order.clone() {
self.remove(entity); self.remove(entity);
@ -133,6 +137,7 @@ where
} }
/// Shows or hides the item's close button. /// Shows or hides the item's close button.
#[inline]
pub fn closable_set(&mut self, id: Entity, closable: bool) { pub fn closable_set(&mut self, id: Entity, closable: bool) {
if let Some(settings) = self.items.get_mut(id) { if let Some(settings) = self.items.get_mut(id) {
settings.closable = closable; settings.closable = closable;
@ -146,6 +151,7 @@ where
/// println!("ID is still valid"); /// println!("ID is still valid");
/// } /// }
/// ``` /// ```
#[inline]
pub fn contains_item(&self, id: Entity) -> bool { pub fn contains_item(&self, id: Entity) -> bool {
self.items.contains_key(id) self.items.contains_key(id)
} }
@ -203,6 +209,7 @@ where
.and_then(|storage| storage.remove(id)); .and_then(|storage| storage.remove(id));
} }
#[inline]
pub fn divider_above(&self, id: Entity) -> Option<bool> { pub fn divider_above(&self, id: Entity) -> Option<bool> {
self.divider_aboves.get(id).copied() self.divider_aboves.get(id).copied()
} }
@ -215,6 +222,7 @@ where
self.divider_aboves.insert(id, divider_above) self.divider_aboves.insert(id, divider_above)
} }
#[inline]
pub fn divider_above_remove(&mut self, id: Entity) -> Option<bool> { pub fn divider_above_remove(&mut self, id: Entity) -> Option<bool> {
self.divider_aboves.remove(id) self.divider_aboves.remove(id)
} }
@ -224,6 +232,7 @@ where
/// ```ignore /// ```ignore
/// model.enable(id, true); /// model.enable(id, true);
/// ``` /// ```
#[inline]
pub fn enable(&mut self, id: Entity, enable: bool) { pub fn enable(&mut self, id: Entity, enable: bool) {
if let Some(e) = self.items.get_mut(id) { if let Some(e) = self.items.get_mut(id) {
e.enabled = enable; e.enabled = enable;
@ -232,6 +241,7 @@ where
/// Get the item that is located at a given position. /// Get the item that is located at a given position.
#[must_use] #[must_use]
#[inline]
pub fn entity_at(&mut self, position: u16) -> Option<Entity> { pub fn entity_at(&mut self, position: u16) -> Option<Entity> {
self.order.get(position as usize).copied() self.order.get(position as usize).copied()
} }
@ -243,6 +253,7 @@ where
/// println!("has icon: {:?}", icon); /// println!("has icon: {:?}", icon);
/// } /// }
/// ``` /// ```
#[inline]
pub fn icon(&self, id: Entity) -> Option<&Icon> { pub fn icon(&self, id: Entity) -> Option<&Icon> {
self.icons.get(id) self.icons.get(id)
} }
@ -254,6 +265,7 @@ where
/// println!("previously had icon: {:?}", old_icon); /// println!("previously had icon: {:?}", old_icon);
/// } /// }
/// ``` /// ```
#[inline]
pub fn icon_set(&mut self, id: Entity, icon: Icon) -> Option<Icon> { pub fn icon_set(&mut self, id: Entity, icon: Icon) -> Option<Icon> {
if !self.contains_item(id) { if !self.contains_item(id) {
return None; return None;
@ -268,6 +280,7 @@ where
/// if let Some(old_icon) = model.icon_remove(id) { /// if let Some(old_icon) = model.icon_remove(id) {
/// println!("previously had icon: {:?}", old_icon); /// println!("previously had icon: {:?}", old_icon);
/// } /// }
#[inline]
pub fn icon_remove(&mut self, id: Entity) -> Option<Icon> { pub fn icon_remove(&mut self, id: Entity) -> Option<Icon> {
self.icons.remove(id) self.icons.remove(id)
} }
@ -278,6 +291,7 @@ where
/// let id = model.insert().text("Item A").icon("custom-icon").id(); /// let id = model.insert().text("Item A").icon("custom-icon").id();
/// ``` /// ```
#[must_use] #[must_use]
#[inline]
pub fn insert(&mut self) -> EntityMut<SelectionMode> { pub fn insert(&mut self) -> EntityMut<SelectionMode> {
let id = self.items.insert(Settings::default()); let id = self.items.insert(Settings::default());
self.order.push_back(id); self.order.push_back(id);
@ -286,14 +300,16 @@ where
/// Check if the given ID is the active ID. /// Check if the given ID is the active ID.
#[must_use] #[must_use]
#[inline]
pub fn is_active(&self, id: Entity) -> bool { pub fn is_active(&self, id: Entity) -> bool {
<Self as Selectable>::is_active(self, id) <Self as Selectable>::is_active(self, id)
} }
/// Whether the item should contain a close button. /// Whether the item should contain a close button.
#[must_use] #[must_use]
#[inline]
pub fn is_closable(&self, id: Entity) -> bool { pub fn is_closable(&self, id: Entity) -> bool {
self.items.get(id).map_or(false, |e| e.closable) self.items.get(id).map(|e| e.closable).unwrap_or_default()
} }
/// Check if the item is enabled. /// Check if the item is enabled.
@ -306,11 +322,13 @@ where
/// } /// }
/// ``` /// ```
#[must_use] #[must_use]
#[inline]
pub fn is_enabled(&self, id: Entity) -> bool { pub fn is_enabled(&self, id: Entity) -> bool {
self.items.get(id).map_or(false, |e| e.enabled) self.items.get(id).map(|e| e.enabled).unwrap_or_default()
} }
/// Get number of items in the model. /// Get number of items in the model.
#[inline]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.order.len() self.order.len()
} }
@ -320,10 +338,12 @@ where
self.order.iter().copied() self.order.iter().copied()
} }
#[inline]
pub fn indent(&self, id: Entity) -> Option<u16> { pub fn indent(&self, id: Entity) -> Option<u16> {
self.indents.get(id).copied() self.indents.get(id).copied()
} }
#[inline]
pub fn indent_set(&mut self, id: Entity, indent: u16) -> Option<u16> { pub fn indent_set(&mut self, id: Entity, indent: u16) -> Option<u16> {
if !self.contains_item(id) { if !self.contains_item(id) {
return None; return None;
@ -332,6 +352,7 @@ where
self.indents.insert(id, indent) self.indents.insert(id, indent)
} }
#[inline]
pub fn indent_remove(&mut self, id: Entity) -> Option<u16> { pub fn indent_remove(&mut self, id: Entity) -> Option<u16> {
self.indents.remove(id) self.indents.remove(id)
} }
@ -343,6 +364,7 @@ where
/// println!("found item at {}", position); /// println!("found item at {}", position);
/// } /// }
#[must_use] #[must_use]
#[inline]
pub fn position(&self, id: Entity) -> Option<u16> { pub fn position(&self, id: Entity) -> Option<u16> {
#[allow(clippy::cast_possible_truncation)] #[allow(clippy::cast_possible_truncation)]
self.order.iter().position(|k| *k == id).map(|v| v as u16) self.order.iter().position(|k| *k == id).map(|v| v as u16)
@ -356,9 +378,7 @@ where
/// } /// }
/// ``` /// ```
pub fn position_set(&mut self, id: Entity, position: u16) -> Option<usize> { pub fn position_set(&mut self, id: Entity, position: u16) -> Option<usize> {
let Some(index) = self.position(id) else { let index = self.position(id)?;
return None;
};
self.order.remove(index as usize); self.order.remove(index as usize);
@ -415,6 +435,7 @@ where
/// println!("{:?} has text {text}", id); /// println!("{:?} has text {text}", id);
/// } /// }
/// ``` /// ```
#[inline]
pub fn text(&self, id: Entity) -> Option<&str> { pub fn text(&self, id: Entity) -> Option<&str> {
self.text.get(id).map(Cow::as_ref) self.text.get(id).map(Cow::as_ref)
} }
@ -439,6 +460,7 @@ where
/// if let Some(old_text) = model.text_remove(id) { /// if let Some(old_text) = model.text_remove(id) {
/// println!("{:?} had text {}", id, old_text); /// println!("{:?} had text {}", id, old_text);
/// } /// }
#[inline]
pub fn text_remove(&mut self, id: Entity) -> Option<Cow<'static, str>> { pub fn text_remove(&mut self, id: Entity) -> Option<Cow<'static, str>> {
self.text.remove(id) self.text.remove(id)
} }

View file

@ -39,6 +39,7 @@ impl Selectable for Model<SingleSelect> {
} }
} }
#[inline]
fn is_active(&self, id: Entity) -> bool { fn is_active(&self, id: Entity) -> bool {
self.selection.active == id self.selection.active == id
} }
@ -47,23 +48,27 @@ impl Selectable for Model<SingleSelect> {
impl Model<SingleSelect> { impl Model<SingleSelect> {
/// Get an immutable reference to the data associated with the active item. /// Get an immutable reference to the data associated with the active item.
#[must_use] #[must_use]
#[inline]
pub fn active_data<Data: 'static>(&self) -> Option<&Data> { pub fn active_data<Data: 'static>(&self) -> Option<&Data> {
self.data(self.active()) self.data(self.active())
} }
/// Get a mutable reference to the data associated with the active item. /// Get a mutable reference to the data associated with the active item.
#[must_use] #[must_use]
#[inline]
pub fn active_data_mut<Data: 'static>(&mut self) -> Option<&mut Data> { pub fn active_data_mut<Data: 'static>(&mut self) -> Option<&mut Data> {
self.data_mut(self.active()) self.data_mut(self.active())
} }
/// Deactivates the active item. /// Deactivates the active item.
#[inline]
pub fn deactivate(&mut self) { pub fn deactivate(&mut self) {
Selectable::deactivate(self, Entity::default()); Selectable::deactivate(self, Entity::default());
} }
/// The ID of the active item. /// The ID of the active item.
#[must_use] #[must_use]
#[inline]
pub fn active(&self) -> Entity { pub fn active(&self) -> Entity {
self.selection.active self.selection.active
} }
@ -86,10 +91,12 @@ impl Selectable for Model<MultiSelect> {
} }
} }
#[inline]
fn deactivate(&mut self, id: Entity) { fn deactivate(&mut self, id: Entity) {
self.selection.active.remove(&id); self.selection.active.remove(&id);
} }
#[inline]
fn is_active(&self, id: Entity) -> bool { fn is_active(&self, id: Entity) -> bool {
self.selection.active.contains(&id) self.selection.active.contains(&id)
} }
@ -97,11 +104,13 @@ impl Selectable for Model<MultiSelect> {
impl Model<MultiSelect> { impl Model<MultiSelect> {
/// Deactivates the item in the model. /// Deactivates the item in the model.
#[inline]
pub fn deactivate(&mut self, id: Entity) { pub fn deactivate(&mut self, id: Entity) {
Selectable::deactivate(self, id); Selectable::deactivate(self, id);
} }
/// The IDs of the active items. /// The IDs of the active items.
#[inline]
pub fn active(&self) -> impl Iterator<Item = Entity> + '_ { pub fn active(&self) -> impl Iterator<Item = Entity> + '_ {
self.selection.active.iter().copied() self.selection.active.iter().copied()
} }

View file

@ -20,7 +20,7 @@ use iced::{
event, keyboard, mouse, touch, event, keyboard, mouse, touch,
}; };
use iced_core::mouse::ScrollDelta; use iced_core::mouse::ScrollDelta;
use iced_core::text::{LineHeight, Paragraph, Renderer as TextRenderer, Shaping, Wrapping}; use iced_core::text::{LineHeight, Renderer as TextRenderer, Shaping, Wrapping};
use iced_core::widget::{self, operation, tree}; use iced_core::widget::{self, operation, tree};
use iced_core::{Border, Gradient, Point, Renderer as IcedRenderer, Shadow, Text}; use iced_core::{Border, Gradient, Point, Renderer as IcedRenderer, Shadow, Text};
use iced_core::{Clipboard, Layout, Shell, Widget, layout, renderer, widget::Tree}; use iced_core::{Clipboard, Layout, Shell, Widget, layout, renderer, widget::Tree};
@ -158,6 +158,7 @@ where
Model<SelectionMode>: Selectable, Model<SelectionMode>: Selectable,
SelectionMode: Default, SelectionMode: Default,
{ {
#[inline]
pub fn new(model: &'a Model<SelectionMode>) -> Self { pub fn new(model: &'a Model<SelectionMode>) -> Self {
Self { Self {
model, model,
@ -1726,6 +1727,7 @@ impl Id {
/// ///
/// This function produces a different [`Id`] every time it is called. /// This function produces a different [`Id`] every time it is called.
#[must_use] #[must_use]
#[inline]
pub fn unique() -> Self { pub fn unique() -> Self {
Self(widget::Id::unique()) Self(widget::Id::unique())
} }

View file

@ -19,11 +19,19 @@ pub fn item<'a, Message: 'static>(
title: impl Into<Cow<'a, str>> + 'a, title: impl Into<Cow<'a, str>> + 'a,
widget: impl Into<Element<'a, Message>> + 'a, widget: impl Into<Element<'a, Message>> + 'a,
) -> Row<'a, Message> { ) -> Row<'a, Message> {
item_row(vec![ #[inline(never)]
text(title).wrapping(Wrapping::Word).into(), fn inner<'a, Message: 'static>(
horizontal_space().into(), title: Cow<'a, str>,
widget.into(), widget: Element<'a, Message>,
]) ) -> Row<'a, Message> {
item_row(vec![
text(title).wrapping(Wrapping::Word).into(),
horizontal_space().into(),
widget,
])
}
inner(title.into(), widget.into())
} }
/// A settings item aligned in a row /// A settings item aligned in a row
@ -41,13 +49,21 @@ pub fn flex_item<'a, Message: 'static>(
title: impl Into<Cow<'a, str>> + 'a, title: impl Into<Cow<'a, str>> + 'a,
widget: impl Into<Element<'a, Message>> + 'a, widget: impl Into<Element<'a, Message>> + 'a,
) -> FlexRow<'a, Message> { ) -> FlexRow<'a, Message> {
flex_item_row(vec![ #[inline(never)]
text(title) fn inner<'a, Message: 'static>(
.wrapping(Wrapping::Word) title: Cow<'a, str>,
.width(Length::Fill) widget: Element<'a, Message>,
.into(), ) -> FlexRow<'a, Message> {
container(widget).into(), flex_item_row(vec![
]) text(title)
.wrapping(Wrapping::Word)
.width(Length::Fill)
.into(),
container(widget).into(),
])
}
inner(title.into(), widget.into())
} }
/// A settings item aligned in a flex row /// A settings item aligned in a flex row
@ -88,15 +104,16 @@ pub struct Item<'a, Message> {
impl<'a, Message: 'static> Item<'a, Message> { impl<'a, Message: 'static> Item<'a, Message> {
/// Assigns a control to the item. /// Assigns a control to the item.
pub fn control(self, widget: impl Into<Element<'a, Message>>) -> Row<'a, Message> { pub fn control(self, widget: impl Into<Element<'a, Message>>) -> Row<'a, Message> {
item_row(self.control_(widget)) item_row(self.control_(widget.into()))
} }
/// Assigns a control which flexes. /// Assigns a control which flexes.
pub fn flex_control(self, widget: impl Into<Element<'a, Message>>) -> FlexRow<'a, Message> { pub fn flex_control(self, widget: impl Into<Element<'a, Message>>) -> FlexRow<'a, Message> {
flex_item_row(self.control_(widget)) flex_item_row(self.control_(widget.into()))
} }
fn control_(self, widget: impl Into<Element<'a, Message>>) -> Vec<Element<'a, Message>> { #[inline(never)]
fn control_(self, widget: Element<'a, Message>) -> Vec<Element<'a, Message>> {
let mut contents = Vec::with_capacity(4); let mut contents = Vec::with_capacity(4);
if let Some(icon) = self.icon { if let Some(icon) = self.icon {

View file

@ -26,72 +26,117 @@ pub enum Typography {
/// [`Text`] widget with the Title 1 typography preset. /// [`Text`] widget with the Title 1 typography preset.
pub fn title1<'a>(text: impl Into<Cow<'a, str>> + 'a) -> Text<'a, crate::Theme, Renderer> { pub fn title1<'a>(text: impl Into<Cow<'a, str>> + 'a) -> Text<'a, crate::Theme, Renderer> {
Text::new(text.into()) #[inline(never)]
.size(35.0) fn inner(text: Cow<str>) -> Text<crate::Theme, Renderer> {
.line_height(LineHeight::Absolute(52.0.into())) Text::new(text)
.font(crate::font::semibold()) .size(35.0)
.line_height(LineHeight::Absolute(52.0.into()))
.font(crate::font::semibold())
}
inner(text.into())
} }
/// [`Text`] widget with the Title 2 typography preset. /// [`Text`] widget with the Title 2 typography preset.
pub fn title2<'a>(text: impl Into<Cow<'a, str>> + 'a) -> Text<'a, crate::Theme, Renderer> { pub fn title2<'a>(text: impl Into<Cow<'a, str>> + 'a) -> Text<'a, crate::Theme, Renderer> {
Text::new(text.into()) #[inline(never)]
.size(29.0) fn inner(text: Cow<str>) -> Text<crate::Theme, Renderer> {
.line_height(LineHeight::Absolute(43.0.into())) Text::new(text)
.font(crate::font::semibold()) .size(29.0)
.line_height(LineHeight::Absolute(43.0.into()))
.font(crate::font::semibold())
}
inner(text.into())
} }
/// [`Text`] widget with the Title 3 typography preset. /// [`Text`] widget with the Title 3 typography preset.
pub fn title3<'a>(text: impl Into<Cow<'a, str>> + 'a) -> Text<'a, crate::Theme, Renderer> { pub fn title3<'a>(text: impl Into<Cow<'a, str>> + 'a) -> Text<'a, crate::Theme, Renderer> {
Text::new(text.into()) #[inline(never)]
.size(24.0) fn inner(text: Cow<str>) -> Text<crate::Theme, Renderer> {
.line_height(LineHeight::Absolute(36.0.into())) Text::new(text)
.font(crate::font::bold()) .size(24.0)
.line_height(LineHeight::Absolute(36.0.into()))
.font(crate::font::bold())
}
inner(text.into())
} }
/// [`Text`] widget with the Title 4 typography preset. /// [`Text`] widget with the Title 4 typography preset.
pub fn title4<'a>(text: impl Into<Cow<'a, str>> + 'a) -> Text<'a, crate::Theme, Renderer> { pub fn title4<'a>(text: impl Into<Cow<'a, str>> + 'a) -> Text<'a, crate::Theme, Renderer> {
Text::new(text.into()) #[inline(never)]
.size(20.0) fn inner(text: Cow<str>) -> Text<crate::Theme, Renderer> {
.line_height(LineHeight::Absolute(30.0.into())) Text::new(text)
.font(crate::font::bold()) .size(20.0)
.line_height(LineHeight::Absolute(30.0.into()))
.font(crate::font::bold())
}
inner(text.into())
} }
/// [`Text`] widget with the Heading typography preset. /// [`Text`] widget with the Heading typography preset.
pub fn heading<'a>(text: impl Into<Cow<'a, str>> + 'a) -> Text<'a, crate::Theme, Renderer> { pub fn heading<'a>(text: impl Into<Cow<'a, str>> + 'a) -> Text<'a, crate::Theme, Renderer> {
Text::new(text.into()) #[inline(never)]
.size(14.0) fn inner(text: Cow<str>) -> Text<crate::Theme, Renderer> {
.line_height(LineHeight::Absolute(iced::Pixels(21.0))) Text::new(text)
.font(crate::font::bold()) .size(14.0)
.line_height(LineHeight::Absolute(iced::Pixels(21.0)))
.font(crate::font::bold())
}
inner(text.into())
} }
/// [`Text`] widget with the Caption Heading typography preset. /// [`Text`] widget with the Caption Heading typography preset.
pub fn caption_heading<'a>(text: impl Into<Cow<'a, str>> + 'a) -> Text<'a, crate::Theme, Renderer> { pub fn caption_heading<'a>(text: impl Into<Cow<'a, str>> + 'a) -> Text<'a, crate::Theme, Renderer> {
Text::new(text.into()) #[inline(never)]
.size(12.0) fn inner(text: Cow<str>) -> Text<crate::Theme, Renderer> {
.line_height(LineHeight::Absolute(iced::Pixels(17.0))) Text::new(text)
.font(crate::font::semibold()) .size(12.0)
.line_height(LineHeight::Absolute(iced::Pixels(17.0)))
.font(crate::font::semibold())
}
inner(text.into())
} }
/// [`Text`] widget with the Body typography preset. /// [`Text`] widget with the Body typography preset.
pub fn body<'a>(text: impl Into<Cow<'a, str>> + 'a) -> Text<'a, crate::Theme, Renderer> { pub fn body<'a>(text: impl Into<Cow<'a, str>> + 'a) -> Text<'a, crate::Theme, Renderer> {
Text::new(text.into()) #[inline(never)]
.size(14.0) fn inner(text: Cow<str>) -> Text<crate::Theme, Renderer> {
.line_height(LineHeight::Absolute(21.0.into())) Text::new(text)
.font(crate::font::default()) .size(14.0)
.line_height(LineHeight::Absolute(21.0.into()))
.font(crate::font::default())
}
inner(text.into())
} }
/// [`Text`] widget with the Caption typography preset. /// [`Text`] widget with the Caption typography preset.
pub fn caption<'a>(text: impl Into<Cow<'a, str>> + 'a) -> Text<'a, crate::Theme, Renderer> { pub fn caption<'a>(text: impl Into<Cow<'a, str>> + 'a) -> Text<'a, crate::Theme, Renderer> {
Text::new(text.into()) #[inline(never)]
.size(12.0) fn inner(text: Cow<str>) -> Text<crate::Theme, Renderer> {
.line_height(LineHeight::Absolute(17.0.into())) Text::new(text)
.font(crate::font::default()) .size(12.0)
.line_height(LineHeight::Absolute(17.0.into()))
.font(crate::font::default())
}
inner(text.into())
} }
/// [`Text`] widget with the Monotext typography preset. /// [`Text`] widget with the Monotext typography preset.
pub fn monotext<'a>(text: impl Into<Cow<'a, str>> + 'a) -> Text<'a, crate::Theme, Renderer> { pub fn monotext<'a>(text: impl Into<Cow<'a, str>> + 'a) -> Text<'a, crate::Theme, Renderer> {
Text::new(text.into()) #[inline(never)]
.size(14.0) fn inner(text: Cow<str>) -> Text<crate::Theme, Renderer> {
.line_height(LineHeight::Absolute(20.0.into())) Text::new(text)
.font(crate::font::mono()) .size(14.0)
.line_height(LineHeight::Absolute(20.0.into()))
.font(crate::font::mono())
}
inner(text.into())
} }

View file

@ -6,16 +6,14 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use std::rc::Rc; use std::rc::Rc;
use crate::widget::container;
use crate::widget::Column; use crate::widget::Column;
use crate::widget::container;
use iced::Task; use iced::Task;
use iced_core::Element; use iced_core::Element;
use slotmap::new_key_type;
use slotmap::SlotMap; use slotmap::SlotMap;
use slotmap::new_key_type;
use widget::Toaster; use widget::Toaster;
use crate::ext::CollectionWidget;
use super::column; use super::column;
use super::{button, icon, row, text}; use super::{button, icon, row, text};
@ -106,6 +104,7 @@ pub struct Action<Message> {
} }
impl<Message> std::fmt::Debug for Action<Message> { impl<Message> std::fmt::Debug for Action<Message> {
#[cold]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Action") f.debug_struct("Action")
.field("description", &self.description) .field("description", &self.description)