Cosmic advanced text (#103)
* wip: update to use cosmic-advanced-text * use cosmic-advanced-text branch of iced * fix: line height and spacing for segmented button and update to get svg fix * fix: spin button styling & spacing * update iced to fix segmented button border radius * feat: example improvements * feat: helper for loading fonts * feat: add focus style to button * fix: slider height and iced fixed * feat: hash icon width and height * cleanup * update ci * refactor: always use lazy feature of iced * update iced * update iced * cleanup & update iced * update iced: new slider & tiny-skia quad updates * update iced: fixes for tiny-skia quad rendering with edge case border radius * re-export iced_runtime & iced_widget * merge master * udpate iced * update iced * update iced * update iced * fix: make rectangle_tracker subscription only return update if there is some * feat: derive macro for loading a cosmic-config * feat (cosmic-config): iced subscription * fix (example): update to rectangle tracker subscription * fix (cosmic-config) * refactor(cosmic-config-derive): add support for types with generic parameters * fix (cosmic-config): feature gate updates for subscription helpers * feat: support for custom & system themes + move cosmic-theme to libcosmic * feat: sorta hacky way of creating header bars for libcosmic + update iced to get support for resizable windows in iced-sctk * update iced * update and reexport sctk * fix: applet border radius * feat (cosmic-theme): add id and name methods * fix(cosmic-theme): reexport palette from cosmic-theme * fix(cosmic-config-derive): allow use with reexported cosmic-config * feat: update iced with fix and refactor applet env vars * update iced
This commit is contained in:
parent
a173794bed
commit
e056e8c830
65 changed files with 3431 additions and 405 deletions
|
|
@ -1,16 +1,16 @@
|
|||
use cosmic_panel_config::{PanelAnchor, PanelSize};
|
||||
use cosmic_panel_config::{CosmicPanelBackground, PanelAnchor, PanelSize};
|
||||
use iced::{
|
||||
alignment::{Horizontal, Vertical},
|
||||
wayland::InitialSurface,
|
||||
widget::{self, Container},
|
||||
Color, Element, Length, Rectangle, Settings,
|
||||
};
|
||||
use iced_core::BorderRadius;
|
||||
use iced_native::command::platform_specific::wayland::{
|
||||
use iced_core::layout::Limits;
|
||||
use iced_style::{button::StyleSheet, container::Appearance};
|
||||
use iced_widget::runtime::command::platform_specific::wayland::{
|
||||
popup::{SctkPopupSettings, SctkPositioner},
|
||||
window::SctkWindowSettings,
|
||||
};
|
||||
use iced_style::{button::StyleSheet, container::Appearance};
|
||||
use sctk::reexports::protocols::xdg::shell::client::xdg_positioner::{Anchor, Gravity};
|
||||
|
||||
use crate::{theme::Button, Renderer};
|
||||
|
|
@ -19,14 +19,15 @@ pub use cosmic_panel_config;
|
|||
|
||||
const APPLET_PADDING: u32 = 8;
|
||||
|
||||
#[must_use]
|
||||
pub fn applet_button_theme() -> Button {
|
||||
Button::Custom {
|
||||
active: Box::new(|t| iced_style::button::Appearance {
|
||||
border_radius: BorderRadius::from(0.0),
|
||||
border_radius: 0.0,
|
||||
..t.active(&Button::Text)
|
||||
}),
|
||||
hover: Box::new(|t| iced_style::button::Appearance {
|
||||
border_radius: BorderRadius::from(0.0),
|
||||
border_radius: 0.0,
|
||||
..t.hovered(&Button::Text)
|
||||
}),
|
||||
}
|
||||
|
|
@ -36,6 +37,8 @@ pub fn applet_button_theme() -> Button {
|
|||
pub struct CosmicAppletHelper {
|
||||
pub size: Size,
|
||||
pub anchor: PanelAnchor,
|
||||
pub background: CosmicPanelBackground,
|
||||
pub output_name: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
@ -51,18 +54,24 @@ impl Default for CosmicAppletHelper {
|
|||
size: Size::PanelSize(
|
||||
std::env::var("COSMIC_PANEL_SIZE")
|
||||
.ok()
|
||||
.and_then(|size| size.parse::<PanelSize>().ok())
|
||||
.and_then(|size| ron::from_str(size.as_str()).ok())
|
||||
.unwrap_or(PanelSize::S),
|
||||
),
|
||||
anchor: std::env::var("COSMIC_PANEL_ANCHOR")
|
||||
.ok()
|
||||
.and_then(|size| size.parse::<PanelAnchor>().ok())
|
||||
.and_then(|size| ron::from_str(size.as_str()).ok())
|
||||
.unwrap_or(PanelAnchor::Top),
|
||||
background: std::env::var("COSMIC_PANEL_BACKGROUND")
|
||||
.ok()
|
||||
.and_then(|size| ron::from_str(size.as_str()).ok())
|
||||
.unwrap_or(CosmicPanelBackground::ThemeDefault),
|
||||
output_name: std::env::var("COSMIC_PANEL_OUTPUT").unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CosmicAppletHelper {
|
||||
#[must_use]
|
||||
pub fn suggested_size(&self) -> (u16, u16) {
|
||||
match &self.size {
|
||||
Size::PanelSize(size) => match size {
|
||||
|
|
@ -87,18 +96,20 @@ impl CosmicAppletHelper {
|
|||
}
|
||||
|
||||
#[must_use]
|
||||
#[allow(clippy::cast_precision_loss)]
|
||||
pub fn window_settings_with_flags<F>(&self, flags: F) -> Settings<F> {
|
||||
let (width, height) = self.suggested_size();
|
||||
let width = u32::from(width);
|
||||
let height = u32::from(height);
|
||||
Settings {
|
||||
initial_surface: InitialSurface::XdgWindow(SctkWindowSettings {
|
||||
iced_settings: iced_native::window::Settings {
|
||||
size: (width + APPLET_PADDING * 2, height + APPLET_PADDING * 2),
|
||||
min_size: Some((width + APPLET_PADDING * 2, height + APPLET_PADDING * 2)),
|
||||
max_size: Some((width + APPLET_PADDING * 2, height + APPLET_PADDING * 2)),
|
||||
..Default::default()
|
||||
},
|
||||
size: (width + APPLET_PADDING * 2, height + APPLET_PADDING * 2),
|
||||
size_limits: Limits::NONE
|
||||
.min_height(height as f32 + APPLET_PADDING as f32 * 2.0)
|
||||
.max_height(height as f32 + APPLET_PADDING as f32 * 2.0)
|
||||
.min_width(width as f32 + APPLET_PADDING as f32 * 2.0)
|
||||
.max_width(width as f32 + APPLET_PADDING as f32 * 2.0),
|
||||
resizable: None,
|
||||
..Default::default()
|
||||
}),
|
||||
..crate::settings_with_flags(flags)
|
||||
|
|
@ -124,7 +135,7 @@ impl CosmicAppletHelper {
|
|||
&self,
|
||||
content: impl Into<Element<'a, Message, Renderer>>,
|
||||
) -> Container<'a, Message, Renderer> {
|
||||
let (valign, halign) = match self.anchor {
|
||||
let (vertical_align, horizontal_align) = match self.anchor {
|
||||
PanelAnchor::Left => (Vertical::Center, Horizontal::Left),
|
||||
PanelAnchor::Right => (Vertical::Center, Horizontal::Right),
|
||||
PanelAnchor::Top => (Vertical::Top, Horizontal::Center),
|
||||
|
|
@ -135,22 +146,23 @@ impl CosmicAppletHelper {
|
|||
crate::theme::Container::custom(|theme| Appearance {
|
||||
text_color: Some(theme.cosmic().background.on.into()),
|
||||
background: Some(Color::from(theme.cosmic().background.base).into()),
|
||||
border_radius: 12.0,
|
||||
border_radius: 12.0.into(),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
}),
|
||||
))
|
||||
.width(Length::Shrink)
|
||||
.height(Length::Shrink)
|
||||
.align_x(halign)
|
||||
.align_y(valign)
|
||||
.align_x(horizontal_align)
|
||||
.align_y(vertical_align)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
pub fn get_popup_settings(
|
||||
&self,
|
||||
parent: iced_native::window::Id,
|
||||
id: iced_native::window::Id,
|
||||
parent: iced_core::window::Id,
|
||||
id: iced_core::window::Id,
|
||||
size: Option<(u32, u32)>,
|
||||
width_padding: Option<i32>,
|
||||
height_padding: Option<i32>,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use std::future::Future;
|
|||
pub struct Executor(tokio::runtime::Runtime);
|
||||
|
||||
#[cfg(feature = "tokio")]
|
||||
impl iced_native::Executor for Executor {
|
||||
impl iced::Executor for Executor {
|
||||
fn new() -> Result<Self, iced::futures::io::Error> {
|
||||
Ok(Self(
|
||||
tokio::runtime::Builder::new_multi_thread()
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use std::future::Future;
|
|||
pub struct Executor(tokio::runtime::Runtime);
|
||||
|
||||
#[cfg(feature = "tokio")]
|
||||
impl iced_native::Executor for Executor {
|
||||
impl iced::Executor for Executor {
|
||||
fn new() -> Result<Self, iced::futures::io::Error> {
|
||||
// Current thread executor requires calling `block_on` to actually run
|
||||
// futures. Main thread is busy with things other than running futures,
|
||||
|
|
|
|||
30
src/font.rs
30
src/font.rs
|
|
@ -2,18 +2,24 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
pub use iced::Font;
|
||||
|
||||
pub const FONT: Font = Font::External {
|
||||
name: "Fira Sans Regular",
|
||||
bytes: include_bytes!("../res/Fira/FiraSans-Regular.otf"),
|
||||
use iced::{
|
||||
font::{load, Error},
|
||||
Command,
|
||||
};
|
||||
|
||||
pub const FONT_LIGHT: Font = Font::External {
|
||||
name: "Fira Sans Light",
|
||||
bytes: include_bytes!("../res/Fira/FiraSans-Light.otf"),
|
||||
};
|
||||
pub const FONT: Font = Font::with_name("Fira Sans Regular");
|
||||
pub const FONT_DATA: &[u8] = include_bytes!("../res/Fira/FiraSans-Regular.otf");
|
||||
|
||||
pub const FONT_SEMIBOLD: Font = Font::External {
|
||||
name: "Fira Sans SemiBold",
|
||||
bytes: include_bytes!("../res/Fira/FiraSans-SemiBold.otf"),
|
||||
};
|
||||
pub const FONT_LIGHT: Font = Font::with_name("Fira Sans Light");
|
||||
pub const FONT_LIGHT_DATA: &[u8] = include_bytes!("../res/Fira/FiraSans-Light.otf");
|
||||
|
||||
pub const FONT_SEMIBOLD: Font = Font::with_name("Fira Sans SemiBold");
|
||||
pub const FONT_SEMIBOLD_DATA: &[u8] = include_bytes!("../res/Fira/FiraSans-SemiBold.otf");
|
||||
|
||||
pub fn load_fonts() -> Command<Result<(), Error>> {
|
||||
Command::batch(vec![
|
||||
load(FONT_DATA),
|
||||
load(FONT_LIGHT_DATA),
|
||||
load(FONT_SEMIBOLD_DATA),
|
||||
])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use iced::{
|
|||
keyboard::{self, KeyCode},
|
||||
mouse, subscription, Command, Event, Subscription,
|
||||
};
|
||||
use iced_native::widget::{operation, Id, Operation};
|
||||
use iced_core::widget::{operation, Id, Operation};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Message {
|
||||
|
|
@ -14,7 +14,6 @@ pub enum Message {
|
|||
Search,
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn subscription() -> Subscription<Message> {
|
||||
subscription::events_with(|event, status| match (event, status) {
|
||||
// Focus
|
||||
|
|
@ -61,7 +60,6 @@ pub fn subscription() -> Subscription<Message> {
|
|||
}
|
||||
|
||||
/// Unfocuses any actively-focused widget.
|
||||
#[must_use]
|
||||
pub fn unfocus<Message: 'static>() -> Command<Message> {
|
||||
Command::<Message>::widget(unfocus_operation())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,18 @@
|
|||
|
||||
#![allow(clippy::module_name_repetitions)]
|
||||
|
||||
pub use cosmic_config;
|
||||
pub use cosmic_theme;
|
||||
pub use iced;
|
||||
pub use iced_lazy;
|
||||
pub use iced_native;
|
||||
pub use iced_runtime;
|
||||
#[cfg(feature = "wayland")]
|
||||
pub use iced_sctk;
|
||||
pub use iced_style;
|
||||
pub use iced_widget;
|
||||
#[cfg(feature = "winit")]
|
||||
pub use iced_winit;
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
pub use sctk;
|
||||
#[cfg(feature = "applet")]
|
||||
pub mod applet;
|
||||
pub mod executor;
|
||||
|
|
|
|||
|
|
@ -27,11 +27,8 @@ pub fn settings<Flags: Default>() -> iced::Settings<Flags> {
|
|||
#[must_use]
|
||||
pub fn settings_with_flags<Flags>(flags: Flags) -> iced::Settings<Flags> {
|
||||
iced::Settings {
|
||||
default_font: match font::FONT {
|
||||
iced::Font::Default => None,
|
||||
iced::Font::External { bytes, .. } => Some(bytes),
|
||||
},
|
||||
default_text_size: 18,
|
||||
default_font: font::FONT,
|
||||
default_text_size: 18.0,
|
||||
..iced::Settings::with_flags(flags)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
114
src/theme/mod.rs
114
src/theme/mod.rs
|
|
@ -7,12 +7,13 @@ mod segmented_button;
|
|||
use std::hash::Hash;
|
||||
use std::hash::Hasher;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use self::segmented_button::SegmentedButton;
|
||||
|
||||
use cosmic_theme::Component;
|
||||
use cosmic_theme::LayeredTheme;
|
||||
use iced_core::BorderRadius;
|
||||
use iced_core::renderer::BorderRadius;
|
||||
use iced_style::application;
|
||||
use iced_style::button;
|
||||
use iced_style::checkbox;
|
||||
|
|
@ -25,18 +26,18 @@ use iced_style::radio;
|
|||
use iced_style::rule;
|
||||
use iced_style::scrollable;
|
||||
use iced_style::slider;
|
||||
use iced_style::slider::Rail;
|
||||
use iced_style::svg;
|
||||
use iced_style::text;
|
||||
use iced_style::text_input;
|
||||
use iced_style::toggler;
|
||||
|
||||
use iced_core::{Background, Color};
|
||||
use palette::Srgba;
|
||||
|
||||
type CosmicColor = ::palette::rgb::Srgba;
|
||||
type CosmicComponent = cosmic_theme::Component<CosmicColor>;
|
||||
type CosmicTheme = cosmic_theme::Theme<CosmicColor>;
|
||||
type CosmicThemeCss = cosmic_theme::Theme<cosmic_theme::util::CssColor>;
|
||||
pub type CosmicColor = ::palette::rgb::Srgba;
|
||||
pub type CosmicComponent = cosmic_theme::Component<CosmicColor>;
|
||||
pub type CosmicTheme = cosmic_theme::Theme<CosmicColor>;
|
||||
pub type CosmicThemeCss = cosmic_theme::Theme<cosmic_theme::util::CssColor>;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref COSMIC_DARK: CosmicTheme = CosmicThemeCss::dark_default().into_srgba();
|
||||
|
|
@ -57,16 +58,17 @@ lazy_static::lazy_static! {
|
|||
};
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||
pub enum ThemeType {
|
||||
#[default]
|
||||
Dark,
|
||||
Light,
|
||||
HighContrastDark,
|
||||
HighContrastLight,
|
||||
Custom(Arc<CosmicTheme>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||
pub struct Theme {
|
||||
pub theme_type: ThemeType,
|
||||
pub layer: cosmic_theme::Layer,
|
||||
|
|
@ -80,6 +82,7 @@ impl Theme {
|
|||
ThemeType::Light => &COSMIC_LIGHT,
|
||||
ThemeType::HighContrastDark => &COSMIC_HC_DARK,
|
||||
ThemeType::HighContrastLight => &COSMIC_HC_LIGHT,
|
||||
ThemeType::Custom(ref t) => t.as_ref(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -115,6 +118,14 @@ impl Theme {
|
|||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn custom(theme: Arc<CosmicTheme>) -> Self {
|
||||
Self {
|
||||
theme_type: ThemeType::Custom(theme),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// get current container
|
||||
/// can be used in a component that is intended to be a child of a `CosmicContainer`
|
||||
#[must_use]
|
||||
|
|
@ -218,8 +229,8 @@ impl button::StyleSheet for Theme {
|
|||
let component = style.cosmic(self);
|
||||
button::Appearance {
|
||||
border_radius: match style {
|
||||
Button::Link => BorderRadius::from(0.0),
|
||||
_ => BorderRadius::from(24.0),
|
||||
Button::Link => 0.0,
|
||||
_ => 24.0,
|
||||
},
|
||||
background: match style {
|
||||
Button::Link | Button::Text => None,
|
||||
|
|
@ -301,7 +312,7 @@ impl checkbox::StyleSheet for Theme {
|
|||
} else {
|
||||
palette.background.base.into()
|
||||
}),
|
||||
checkmark_color: palette.accent.on.into(),
|
||||
icon_color: palette.accent.on.into(),
|
||||
border_radius: 4.0,
|
||||
border_width: if is_checked { 0.0 } else { 1.0 },
|
||||
border_color: if is_checked {
|
||||
|
|
@ -318,7 +329,7 @@ impl checkbox::StyleSheet for Theme {
|
|||
} else {
|
||||
palette.background.base.into()
|
||||
}),
|
||||
checkmark_color: palette.background.on.into(),
|
||||
icon_color: palette.background.on.into(),
|
||||
border_radius: 4.0,
|
||||
border_width: if is_checked { 0.0 } else { 1.0 },
|
||||
border_color: neutral_7.into(),
|
||||
|
|
@ -330,7 +341,7 @@ impl checkbox::StyleSheet for Theme {
|
|||
} else {
|
||||
palette.background.base.into()
|
||||
}),
|
||||
checkmark_color: palette.success.on.into(),
|
||||
icon_color: palette.success.on.into(),
|
||||
border_radius: 4.0,
|
||||
border_width: if is_checked { 0.0 } else { 1.0 },
|
||||
border_color: if is_checked {
|
||||
|
|
@ -347,7 +358,7 @@ impl checkbox::StyleSheet for Theme {
|
|||
} else {
|
||||
palette.background.base.into()
|
||||
}),
|
||||
checkmark_color: palette.destructive.on.into(),
|
||||
icon_color: palette.destructive.on.into(),
|
||||
border_radius: 4.0,
|
||||
border_width: if is_checked { 0.0 } else { 1.0 },
|
||||
border_color: if is_checked {
|
||||
|
|
@ -374,7 +385,7 @@ impl checkbox::StyleSheet for Theme {
|
|||
} else {
|
||||
neutral_10.into()
|
||||
}),
|
||||
checkmark_color: palette.accent.on.into(),
|
||||
icon_color: palette.accent.on.into(),
|
||||
border_radius: 4.0,
|
||||
border_width: if is_checked { 0.0 } else { 1.0 },
|
||||
border_color: if is_checked {
|
||||
|
|
@ -391,7 +402,7 @@ impl checkbox::StyleSheet for Theme {
|
|||
} else {
|
||||
neutral_10.into()
|
||||
}),
|
||||
checkmark_color: self.current_container().on.into(),
|
||||
icon_color: self.current_container().on.into(),
|
||||
border_radius: 4.0,
|
||||
border_width: if is_checked { 0.0 } else { 1.0 },
|
||||
border_color: if is_checked {
|
||||
|
|
@ -408,7 +419,7 @@ impl checkbox::StyleSheet for Theme {
|
|||
} else {
|
||||
neutral_10.into()
|
||||
}),
|
||||
checkmark_color: palette.success.on.into(),
|
||||
icon_color: palette.success.on.into(),
|
||||
border_radius: 4.0,
|
||||
border_width: if is_checked { 0.0 } else { 1.0 },
|
||||
border_color: if is_checked {
|
||||
|
|
@ -425,7 +436,7 @@ impl checkbox::StyleSheet for Theme {
|
|||
} else {
|
||||
neutral_10.into()
|
||||
}),
|
||||
checkmark_color: palette.destructive.on.into(),
|
||||
icon_color: palette.destructive.on.into(),
|
||||
border_radius: 4.0,
|
||||
border_width: if is_checked { 0.0 } else { 1.0 },
|
||||
border_color: if is_checked {
|
||||
|
|
@ -474,6 +485,7 @@ pub enum Container {
|
|||
Secondary,
|
||||
#[default]
|
||||
Transparent,
|
||||
HeaderBar,
|
||||
Custom(Box<dyn Fn(&Theme) -> container::Appearance>),
|
||||
}
|
||||
|
||||
|
|
@ -496,7 +508,18 @@ impl container::StyleSheet for Theme {
|
|||
container::Appearance {
|
||||
text_color: Some(Color::from(palette.background.on)),
|
||||
background: Some(iced::Background::Color(palette.background.base.into())),
|
||||
border_radius: 2.0,
|
||||
border_radius: 2.0.into(),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
}
|
||||
}
|
||||
Container::HeaderBar => {
|
||||
let palette = self.cosmic();
|
||||
|
||||
container::Appearance {
|
||||
text_color: Some(Color::from(palette.background.on)),
|
||||
background: Some(iced::Background::Color(palette.background.base.into())),
|
||||
border_radius: BorderRadius::from([16.0, 16.0, 0.0, 0.0]),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
}
|
||||
|
|
@ -507,7 +530,7 @@ impl container::StyleSheet for Theme {
|
|||
container::Appearance {
|
||||
text_color: Some(Color::from(palette.primary.on)),
|
||||
background: Some(iced::Background::Color(palette.primary.base.into())),
|
||||
border_radius: 2.0,
|
||||
border_radius: 2.0.into(),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
}
|
||||
|
|
@ -518,7 +541,7 @@ impl container::StyleSheet for Theme {
|
|||
container::Appearance {
|
||||
text_color: Some(Color::from(palette.secondary.on)),
|
||||
background: Some(iced::Background::Color(palette.secondary.base.into())),
|
||||
border_radius: 2.0,
|
||||
border_radius: 2.0.into(),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
}
|
||||
|
|
@ -538,11 +561,15 @@ impl slider::StyleSheet for Theme {
|
|||
|
||||
//TODO: no way to set rail thickness
|
||||
slider::Appearance {
|
||||
rail_colors: (
|
||||
cosmic.accent.base.into(),
|
||||
//TODO: no way to set color before/after slider
|
||||
Color::TRANSPARENT,
|
||||
),
|
||||
rail: Rail {
|
||||
colors: (
|
||||
cosmic.accent.base.into(),
|
||||
//TODO: no way to set color before/after slider
|
||||
Color::TRANSPARENT,
|
||||
),
|
||||
width: 4.0,
|
||||
},
|
||||
|
||||
handle: slider::Handle {
|
||||
shape: slider::HandleShape::Circle { radius: 10.0 },
|
||||
color: cosmic.accent.base.into(),
|
||||
|
|
@ -610,7 +637,8 @@ impl pick_list::StyleSheet for Theme {
|
|||
border_radius: 24.0,
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
icon_size: 0.7,
|
||||
// icon_size: 0.7, // TODO: how to replace
|
||||
handle_color: cosmic.on_bg_color().into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -856,7 +884,11 @@ impl scrollable::StyleSheet for Theme {
|
|||
}
|
||||
}
|
||||
|
||||
fn hovered(&self, _style: &Self::Style) -> scrollable::Scrollbar {
|
||||
fn hovered(
|
||||
&self,
|
||||
_style: &Self::Style,
|
||||
_is_mouse_over_scrollbar: bool,
|
||||
) -> scrollable::Scrollbar {
|
||||
let theme = self.cosmic();
|
||||
|
||||
scrollable::Scrollbar {
|
||||
|
|
@ -948,7 +980,7 @@ pub enum Text {
|
|||
Default,
|
||||
Color(Color),
|
||||
// TODO: Can't use dyn Fn since this must be copy
|
||||
Custom(fn(&Theme) -> text::Appearance),
|
||||
Custom(fn(&Theme) -> iced_widget::text::Appearance),
|
||||
}
|
||||
|
||||
impl From<Color> for Text {
|
||||
|
|
@ -957,16 +989,16 @@ impl From<Color> for Text {
|
|||
}
|
||||
}
|
||||
|
||||
impl text::StyleSheet for Theme {
|
||||
impl iced_widget::text::StyleSheet for Theme {
|
||||
type Style = Text;
|
||||
|
||||
fn appearance(&self, style: Self::Style) -> text::Appearance {
|
||||
fn appearance(&self, style: Self::Style) -> iced_widget::text::Appearance {
|
||||
match style {
|
||||
Text::Accent => text::Appearance {
|
||||
Text::Accent => iced_widget::text::Appearance {
|
||||
color: Some(self.cosmic().accent.base.into()),
|
||||
},
|
||||
Text::Default => text::Appearance { color: None },
|
||||
Text::Color(c) => text::Appearance { color: Some(c) },
|
||||
Text::Default => iced_widget::text::Appearance { color: None },
|
||||
Text::Color(c) => iced_widget::text::Appearance { color: Some(c) },
|
||||
Text::Custom(f) => f(self),
|
||||
}
|
||||
}
|
||||
|
|
@ -995,12 +1027,14 @@ impl text_input::StyleSheet for Theme {
|
|||
border_radius: 8.0,
|
||||
border_width: 1.0,
|
||||
border_color: self.current_container().component.divider.into(),
|
||||
icon_color: self.current_container().on.into(),
|
||||
},
|
||||
TextInput::Search => text_input::Appearance {
|
||||
background: Color::from(bg).into(),
|
||||
border_radius: 24.0,
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
icon_color: self.current_container().on.into(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -1016,12 +1050,14 @@ impl text_input::StyleSheet for Theme {
|
|||
border_radius: 8.0,
|
||||
border_width: 1.0,
|
||||
border_color: palette.accent.base.into(),
|
||||
icon_color: self.current_container().on.into(),
|
||||
},
|
||||
TextInput::Search => text_input::Appearance {
|
||||
background: Color::from(bg).into(),
|
||||
border_radius: 24.0,
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
icon_color: self.current_container().on.into(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -1037,12 +1073,14 @@ impl text_input::StyleSheet for Theme {
|
|||
border_radius: 8.0,
|
||||
border_width: 1.0,
|
||||
border_color: palette.accent.base.into(),
|
||||
icon_color: self.current_container().on.into(),
|
||||
},
|
||||
TextInput::Search => text_input::Appearance {
|
||||
background: Color::from(bg).into(),
|
||||
border_radius: 24.0,
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
icon_color: self.current_container().on.into(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -1065,4 +1103,12 @@ impl text_input::StyleSheet for Theme {
|
|||
|
||||
palette.accent.base.into()
|
||||
}
|
||||
|
||||
fn disabled_color(&self, _style: &Self::Style) -> Color {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn disabled(&self, _style: &Self::Style) -> text_input::Appearance {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
use crate::widget::segmented_button::{Appearance, ItemAppearance, StyleSheet};
|
||||
use crate::{theme::Theme, widget::segmented_button::ItemStatusAppearance};
|
||||
use iced_core::{Background, BorderRadius};
|
||||
use iced_core::{renderer::BorderRadius, Background};
|
||||
use palette::{rgb::Rgb, Alpha};
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
@ -141,7 +141,7 @@ impl StyleSheet for Theme {
|
|||
|
||||
mod horizontal {
|
||||
use crate::widget::segmented_button::{ItemAppearance, ItemStatusAppearance};
|
||||
use iced_core::{Background, BorderRadius};
|
||||
use iced_core::{renderer::BorderRadius, Background};
|
||||
use palette::{rgb::Rgb, Alpha};
|
||||
|
||||
pub fn selection_active(cosmic: &cosmic_theme::Theme<Alpha<Rgb, f32>>) -> ItemStatusAppearance {
|
||||
|
|
@ -222,7 +222,7 @@ pub fn hover(
|
|||
|
||||
mod vertical {
|
||||
use crate::widget::segmented_button::{ItemAppearance, ItemStatusAppearance};
|
||||
use iced_core::{Background, BorderRadius};
|
||||
use iced_core::{renderer::BorderRadius, Background};
|
||||
use palette::{rgb::Rgb, Alpha};
|
||||
|
||||
pub fn selection_active(cosmic: &cosmic_theme::Theme<Alpha<Rgb, f32>>) -> ItemStatusAppearance {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
use iced::widget::Container;
|
||||
use iced::Size;
|
||||
use iced_native::alignment;
|
||||
use iced_native::event::{self, Event};
|
||||
use iced_native::layout;
|
||||
use iced_native::mouse;
|
||||
use iced_native::overlay;
|
||||
use iced_native::renderer;
|
||||
use iced_native::widget::{Operation, Tree};
|
||||
use iced_native::{Clipboard, Element, Layout, Length, Padding, Point, Rectangle, Shell, Widget};
|
||||
use iced_core::alignment;
|
||||
use iced_core::event::{self, Event};
|
||||
use iced_core::layout;
|
||||
use iced_core::mouse;
|
||||
use iced_core::overlay;
|
||||
use iced_core::renderer;
|
||||
use iced_core::widget::Tree;
|
||||
use iced_core::{Clipboard, Element, Layout, Length, Padding, Point, Rectangle, Shell, Widget};
|
||||
|
||||
pub use iced_style::container::{Appearance, StyleSheet};
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ where
|
|||
#[allow(missing_debug_implementations)]
|
||||
pub struct AspectRatio<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::Renderer,
|
||||
Renderer: iced_core::Renderer,
|
||||
Renderer::Theme: StyleSheet,
|
||||
{
|
||||
ratio: f32,
|
||||
|
|
@ -36,7 +36,7 @@ where
|
|||
|
||||
impl<'a, Message, Renderer> AspectRatio<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::Renderer,
|
||||
Renderer: iced_core::Renderer,
|
||||
Renderer::Theme: StyleSheet,
|
||||
{
|
||||
fn constrain_limits(&self, size: Size) -> Size {
|
||||
|
|
@ -55,7 +55,7 @@ where
|
|||
|
||||
impl<'a, Message, Renderer> AspectRatio<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::Renderer,
|
||||
Renderer: iced_core::Renderer,
|
||||
Renderer::Theme: StyleSheet,
|
||||
{
|
||||
/// Creates an empty [`Container`].
|
||||
|
|
@ -92,14 +92,14 @@ where
|
|||
|
||||
/// Sets the maximum width of the [`Container`].
|
||||
#[must_use]
|
||||
pub fn max_width(mut self, max_width: u32) -> Self {
|
||||
pub fn max_width(mut self, max_width: f32) -> Self {
|
||||
self.container = self.container.max_width(max_width);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the maximum height of the [`Container`] in pixels.
|
||||
#[must_use]
|
||||
pub fn max_height(mut self, max_height: u32) -> Self {
|
||||
pub fn max_height(mut self, max_height: f32) -> Self {
|
||||
self.container = self.container.max_height(max_height);
|
||||
self
|
||||
}
|
||||
|
|
@ -142,14 +142,14 @@ where
|
|||
|
||||
impl<'a, Message, Renderer> Widget<Message, Renderer> for AspectRatio<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::Renderer,
|
||||
Renderer: iced_core::Renderer,
|
||||
Renderer::Theme: StyleSheet,
|
||||
{
|
||||
fn children(&self) -> Vec<Tree> {
|
||||
self.container.children()
|
||||
}
|
||||
|
||||
fn diff(&self, tree: &mut Tree) {
|
||||
fn diff(&mut self, tree: &mut Tree) {
|
||||
self.container.diff(tree);
|
||||
}
|
||||
|
||||
|
|
@ -169,8 +169,16 @@ where
|
|||
self.container.layout(renderer, &custom_limits)
|
||||
}
|
||||
|
||||
fn operate(&self, tree: &mut Tree, layout: Layout<'_>, operation: &mut dyn Operation<Message>) {
|
||||
self.container.operate(tree, layout, operation);
|
||||
fn operate(
|
||||
&self,
|
||||
tree: &mut Tree,
|
||||
layout: Layout<'_>,
|
||||
renderer: &Renderer,
|
||||
operation: &mut dyn iced_core::widget::Operation<
|
||||
iced_core::widget::OperationOutputWrapper<Message>,
|
||||
>,
|
||||
) {
|
||||
self.container.operate(tree, layout, renderer, operation);
|
||||
}
|
||||
|
||||
fn on_event(
|
||||
|
|
@ -228,7 +236,7 @@ where
|
|||
}
|
||||
|
||||
fn overlay<'b>(
|
||||
&'b self,
|
||||
&'b mut self,
|
||||
tree: &'b mut Tree,
|
||||
layout: Layout<'_>,
|
||||
renderer: &Renderer,
|
||||
|
|
@ -241,7 +249,7 @@ impl<'a, Message, Renderer> From<AspectRatio<'a, Message, Renderer>>
|
|||
for Element<'a, Message, Renderer>
|
||||
where
|
||||
Message: 'a,
|
||||
Renderer: 'a + iced_native::Renderer,
|
||||
Renderer: 'a + iced_core::Renderer,
|
||||
Renderer::Theme: StyleSheet,
|
||||
{
|
||||
fn from(column: AspectRatio<'a, Message, Renderer>) -> Element<'a, Message, Renderer> {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
use cosmic_theme::LayeredTheme;
|
||||
use iced::widget::Container;
|
||||
use iced_native::alignment;
|
||||
use iced_native::event::{self, Event};
|
||||
use iced_native::layout;
|
||||
use iced_native::mouse;
|
||||
use iced_native::overlay;
|
||||
use iced_native::renderer;
|
||||
use iced_native::widget::{Operation, Tree};
|
||||
use iced_native::{Clipboard, Element, Layout, Length, Padding, Point, Rectangle, Shell, Widget};
|
||||
use iced_core::alignment;
|
||||
use iced_core::event::{self, Event};
|
||||
use iced_core::layout;
|
||||
use iced_core::mouse;
|
||||
use iced_core::overlay;
|
||||
use iced_core::renderer;
|
||||
use iced_core::widget::Tree;
|
||||
use iced_core::{Clipboard, Element, Layout, Length, Padding, Point, Rectangle, Shell, Widget};
|
||||
pub use iced_style::container::{Appearance, StyleSheet};
|
||||
|
||||
pub fn container<'a, Message: 'static, T>(
|
||||
|
|
@ -25,7 +25,7 @@ where
|
|||
#[allow(missing_debug_implementations)]
|
||||
pub struct LayerContainer<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::Renderer,
|
||||
Renderer: iced_core::Renderer,
|
||||
Renderer::Theme: StyleSheet + Clone + cosmic_theme::LayeredTheme,
|
||||
{
|
||||
layer: Option<cosmic_theme::Layer>,
|
||||
|
|
@ -34,7 +34,7 @@ where
|
|||
|
||||
impl<'a, Message, Renderer> LayerContainer<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::Renderer,
|
||||
Renderer: iced_core::Renderer,
|
||||
Renderer::Theme: StyleSheet + Clone + cosmic_theme::LayeredTheme,
|
||||
<Renderer::Theme as StyleSheet>::Style: std::convert::From<crate::theme::Container>,
|
||||
{
|
||||
|
|
@ -83,14 +83,14 @@ where
|
|||
|
||||
/// Sets the maximum width of the [`LayerContainer`].
|
||||
#[must_use]
|
||||
pub fn max_width(mut self, max_width: u32) -> Self {
|
||||
pub fn max_width(mut self, max_width: f32) -> Self {
|
||||
self.container = self.container.max_width(max_width);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the maximum height of the [`LayerContainer`] in pixels.
|
||||
#[must_use]
|
||||
pub fn max_height(mut self, max_height: u32) -> Self {
|
||||
pub fn max_height(mut self, max_height: f32) -> Self {
|
||||
self.container = self.container.max_height(max_height);
|
||||
self
|
||||
}
|
||||
|
|
@ -133,14 +133,14 @@ where
|
|||
|
||||
impl<'a, Message, Renderer> Widget<Message, Renderer> for LayerContainer<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::Renderer,
|
||||
Renderer: iced_core::Renderer,
|
||||
Renderer::Theme: StyleSheet + Clone + cosmic_theme::LayeredTheme,
|
||||
{
|
||||
fn children(&self) -> Vec<Tree> {
|
||||
self.container.children()
|
||||
}
|
||||
|
||||
fn diff(&self, tree: &mut Tree) {
|
||||
fn diff(&mut self, tree: &mut Tree) {
|
||||
self.container.diff(tree);
|
||||
}
|
||||
|
||||
|
|
@ -156,8 +156,16 @@ where
|
|||
self.container.layout(renderer, limits)
|
||||
}
|
||||
|
||||
fn operate(&self, tree: &mut Tree, layout: Layout<'_>, operation: &mut dyn Operation<Message>) {
|
||||
self.container.operate(tree, layout, operation);
|
||||
fn operate(
|
||||
&self,
|
||||
tree: &mut Tree,
|
||||
layout: Layout<'_>,
|
||||
renderer: &Renderer,
|
||||
operation: &mut dyn iced_core::widget::Operation<
|
||||
iced_core::widget::OperationOutputWrapper<Message>,
|
||||
>,
|
||||
) {
|
||||
self.container.operate(tree, layout, renderer, operation);
|
||||
}
|
||||
|
||||
fn on_event(
|
||||
|
|
@ -222,7 +230,7 @@ where
|
|||
}
|
||||
|
||||
fn overlay<'b>(
|
||||
&'b self,
|
||||
&'b mut self,
|
||||
tree: &'b mut Tree,
|
||||
layout: Layout<'_>,
|
||||
renderer: &Renderer,
|
||||
|
|
@ -235,7 +243,7 @@ impl<'a, Message, Renderer> From<LayerContainer<'a, Message, Renderer>>
|
|||
for Element<'a, Message, Renderer>
|
||||
where
|
||||
Message: 'a,
|
||||
Renderer: 'a + iced_native::Renderer,
|
||||
Renderer: 'a + iced_core::Renderer,
|
||||
Renderer::Theme: StyleSheet + Clone + cosmic_theme::LayeredTheme,
|
||||
{
|
||||
fn from(column: LayerContainer<'a, Message, Renderer>) -> Element<'a, Message, Renderer> {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use crate::{theme, Element};
|
|||
use apply::Apply;
|
||||
use derive_setters::Setters;
|
||||
use iced::{self, widget, Length};
|
||||
use iced_core::renderer::BorderRadius;
|
||||
use std::borrow::Cow;
|
||||
|
||||
#[must_use]
|
||||
|
|
@ -74,12 +75,13 @@ impl<'a, Message: Clone + 'static> HeaderBar<'a, Message> {
|
|||
});
|
||||
|
||||
let mut widget = widget::row(packed)
|
||||
.height(Length::Units(50))
|
||||
.height(Length::Fixed(50.0))
|
||||
.padding(8)
|
||||
.spacing(8)
|
||||
.apply(widget::container)
|
||||
.style(crate::theme::Container::HeaderBar)
|
||||
.center_y()
|
||||
.apply(widget::mouse_listener);
|
||||
.apply(widget::mouse_area);
|
||||
|
||||
if let Some(message) = self.on_drag.clone() {
|
||||
widget = widget.on_press(message);
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ impl<'a> IconSource<'a> {
|
|||
let handle = if let Some(path) = icon {
|
||||
svg::Handle::from_path(path)
|
||||
} else {
|
||||
eprintln!("svg icon '{:?}' size {} not found", self, size);
|
||||
eprintln!("svg icon '{self:?}' size {size} not found");
|
||||
svg::Handle::from_memory(Vec::new())
|
||||
};
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ impl<'a> IconSource<'a> {
|
|||
} else if let Some(icon) = icon {
|
||||
Handle::Image(icon.into())
|
||||
} else {
|
||||
eprintln!("icon '{:?}' size {} not found", self, size);
|
||||
eprintln!("icon '{self:?}' size {size} not found");
|
||||
Handle::Image(image::Handle::from_memory(Vec::new()))
|
||||
}
|
||||
}
|
||||
|
|
@ -90,7 +90,13 @@ impl<'a> IconSource<'a> {
|
|||
}
|
||||
|
||||
/// Get a handle to a raster image from memory.
|
||||
pub fn raster_from_memory(bytes: impl Into<Cow<'static, [u8]>>) -> Self {
|
||||
pub fn raster_from_memory(
|
||||
bytes: impl Into<Cow<'static, [u8]>>
|
||||
+ std::convert::AsRef<[u8]>
|
||||
+ std::marker::Send
|
||||
+ std::marker::Sync
|
||||
+ 'static,
|
||||
) -> Self {
|
||||
IconSource::Handle(Handle::Image(image::Handle::from_memory(bytes)))
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +104,11 @@ impl<'a> IconSource<'a> {
|
|||
pub fn raster_from_pixels(
|
||||
width: u32,
|
||||
height: u32,
|
||||
pixels: impl Into<Cow<'static, [u8]>>,
|
||||
pixels: impl Into<Cow<'static, [u8]>>
|
||||
+ std::convert::AsRef<[u8]>
|
||||
+ std::marker::Send
|
||||
+ std::marker::Sync
|
||||
+ 'static,
|
||||
) -> Self {
|
||||
IconSource::Handle(Handle::Image(image::Handle::from_pixels(
|
||||
width, height, pixels,
|
||||
|
|
@ -165,7 +175,7 @@ impl From<svg::Handle> for IconSource<'static> {
|
|||
}
|
||||
|
||||
/// A lazily-generated icon.
|
||||
#[derive(Hash, Setters)]
|
||||
#[derive(Setters)]
|
||||
pub struct Icon<'a> {
|
||||
#[setters(skip)]
|
||||
source: IconSource<'a>,
|
||||
|
|
@ -181,6 +191,33 @@ pub struct Icon<'a> {
|
|||
force_svg: bool,
|
||||
}
|
||||
|
||||
// XXX Hopefully this will be enough precision
|
||||
impl Hash for Icon<'_> {
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.source.hash(state);
|
||||
self.theme.hash(state);
|
||||
self.style.hash(state);
|
||||
self.size.hash(state);
|
||||
self.content_fit.hash(state);
|
||||
self.force_svg.hash(state);
|
||||
match self.width {
|
||||
Some(Length::Fill) => 0.hash(state),
|
||||
Some(Length::Shrink) => 1.hash(state),
|
||||
Some(Length::Fixed(v)) => ((v * 1000.0) as i32).hash(state),
|
||||
Some(Length::FillPortion(p)) => p.hash(state),
|
||||
None => 2.hash(state),
|
||||
}
|
||||
match self.height {
|
||||
Some(Length::Fill) => 0.hash(state),
|
||||
Some(Length::Shrink) => 1.hash(state),
|
||||
Some(Length::Fixed(v)) => ((v * 1000.0) as i32).hash(state),
|
||||
Some(Length::FillPortion(p)) => p.hash(state),
|
||||
None => 2.hash(state),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A lazily-generated icon.
|
||||
#[must_use]
|
||||
pub fn icon<'a>(source: impl Into<IconSource<'a>>, size: u16) -> Icon<'a> {
|
||||
|
|
@ -199,8 +236,8 @@ pub fn icon<'a>(source: impl Into<IconSource<'a>>, size: u16) -> Icon<'a> {
|
|||
impl<'a> Icon<'a> {
|
||||
fn raster_element<Message: 'static>(&self, handle: image::Handle) -> Element<'static, Message> {
|
||||
Image::new(handle)
|
||||
.width(self.width.unwrap_or(Length::Units(self.size)))
|
||||
.height(self.height.unwrap_or(Length::Units(self.size)))
|
||||
.width(self.width.unwrap_or(Length::Fixed(f32::from(self.size))))
|
||||
.height(self.height.unwrap_or(Length::Fixed(f32::from(self.size))))
|
||||
.content_fit(self.content_fit)
|
||||
.into()
|
||||
}
|
||||
|
|
@ -208,8 +245,8 @@ impl<'a> Icon<'a> {
|
|||
fn svg_element<Message: 'static>(&self, handle: svg::Handle) -> Element<'static, Message> {
|
||||
svg::Svg::<Renderer>::new(handle)
|
||||
.style(self.style.clone())
|
||||
.width(self.width.unwrap_or(Length::Units(self.size)))
|
||||
.height(self.height.unwrap_or(Length::Units(self.size)))
|
||||
.width(self.width.unwrap_or(Length::Fixed(f32::from(self.size))))
|
||||
.height(self.height.unwrap_or(Length::Fixed(f32::from(self.size))))
|
||||
.content_fit(self.content_fit)
|
||||
.into()
|
||||
}
|
||||
|
|
@ -228,7 +265,7 @@ impl<'a> Icon<'a> {
|
|||
let mut source = IconSource::Name(Cow::Borrowed(""));
|
||||
std::mem::swap(&mut source, &mut self.source);
|
||||
|
||||
iced_lazy::lazy(hash, move || -> Element<Message> {
|
||||
iced::widget::lazy(hash, move |_| -> Element<Message> {
|
||||
match source.load(self.size, self.theme.as_deref(), self.force_svg) {
|
||||
Handle::Svg(handle) => self.svg_element(handle),
|
||||
Handle::Image(handle) => self.raster_element(handle),
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ pub fn style(theme: &crate::Theme) -> iced::widget::container::Appearance {
|
|||
iced::widget::container::Appearance {
|
||||
text_color: Some(container.on.into()),
|
||||
background: Some(Background::Color(container.base.into())),
|
||||
border_radius: 8.0,
|
||||
border_radius: 8.0.into(),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ pub fn nav_bar_style(theme: &Theme) -> iced_style::container::Appearance {
|
|||
iced_style::container::Appearance {
|
||||
text_color: Some(cosmic.on_bg_color().into()),
|
||||
background: Some(Background::Color(cosmic.primary.base.into())),
|
||||
border_radius: 8.0,
|
||||
border_radius: 8.0.into(),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@
|
|||
|
||||
//! A widget showing a popup in an overlay positioned relative to another widget.
|
||||
|
||||
use iced_native::event::{self, Event};
|
||||
use iced_native::layout;
|
||||
use iced_native::mouse;
|
||||
use iced_native::overlay;
|
||||
use iced_native::renderer;
|
||||
use iced_native::widget::{Operation, Tree};
|
||||
use iced_native::{Clipboard, Element, Layout, Length, Point, Rectangle, Shell, Size, Widget};
|
||||
use iced_core::event::{self, Event};
|
||||
use iced_core::layout;
|
||||
use iced_core::mouse;
|
||||
use iced_core::overlay;
|
||||
use iced_core::renderer;
|
||||
use iced_core::widget::{Operation, OperationOutputWrapper, Tree};
|
||||
use iced_core::{Clipboard, Element, Layout, Length, Point, Rectangle, Shell, Size, Widget};
|
||||
use std::cell::RefCell;
|
||||
|
||||
pub use iced_style::container::{Appearance, StyleSheet};
|
||||
|
|
@ -43,15 +43,15 @@ impl<'a, Message, Renderer> Popover<'a, Message, Renderer> {
|
|||
|
||||
impl<'a, Message, Renderer> Widget<Message, Renderer> for Popover<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::Renderer,
|
||||
Renderer: iced_core::Renderer,
|
||||
Renderer::Theme: StyleSheet,
|
||||
{
|
||||
fn children(&self) -> Vec<Tree> {
|
||||
vec![Tree::new(&self.content), Tree::new(&*self.popup.borrow())]
|
||||
}
|
||||
|
||||
fn diff(&self, tree: &mut Tree) {
|
||||
tree.diff_children(&[&self.content, &self.popup.borrow()])
|
||||
fn diff(&mut self, tree: &mut Tree) {
|
||||
tree.diff_children(&mut [&mut self.content, &mut self.popup.borrow_mut()]);
|
||||
}
|
||||
|
||||
fn width(&self) -> Length {
|
||||
|
|
@ -66,10 +66,16 @@ where
|
|||
self.content.as_widget().layout(renderer, limits)
|
||||
}
|
||||
|
||||
fn operate(&self, tree: &mut Tree, layout: Layout<'_>, operation: &mut dyn Operation<Message>) {
|
||||
fn operate(
|
||||
&self,
|
||||
tree: &mut Tree,
|
||||
layout: Layout<'_>,
|
||||
renderer: &Renderer,
|
||||
operation: &mut dyn Operation<OperationOutputWrapper<Message>>,
|
||||
) {
|
||||
self.content
|
||||
.as_widget()
|
||||
.operate(&mut tree.children[0], layout, operation)
|
||||
.operate(&mut tree.children[0], layout, renderer, operation);
|
||||
}
|
||||
|
||||
fn on_event(
|
||||
|
|
@ -128,11 +134,11 @@ where
|
|||
layout,
|
||||
cursor_position,
|
||||
viewport,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
fn overlay<'b>(
|
||||
&'b self,
|
||||
&'b mut self,
|
||||
tree: &'b mut Tree,
|
||||
layout: Layout<'_>,
|
||||
_renderer: &Renderer,
|
||||
|
|
@ -155,7 +161,7 @@ where
|
|||
impl<'a, Message, Renderer> From<Popover<'a, Message, Renderer>> for Element<'a, Message, Renderer>
|
||||
where
|
||||
Message: 'static,
|
||||
Renderer: iced_native::Renderer + 'static,
|
||||
Renderer: iced_core::Renderer + 'static,
|
||||
Renderer::Theme: StyleSheet,
|
||||
{
|
||||
fn from(popover: Popover<'a, Message, Renderer>) -> Self {
|
||||
|
|
@ -171,7 +177,7 @@ struct Overlay<'a, 'b, Message, Renderer> {
|
|||
impl<'a, 'b, Message, Renderer> overlay::Overlay<Message, Renderer>
|
||||
for Overlay<'a, 'b, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::Renderer,
|
||||
Renderer: iced_core::Renderer,
|
||||
{
|
||||
fn layout(&self, renderer: &Renderer, bounds: Size, mut position: Point) -> layout::Node {
|
||||
// Position is set to the center bottom of the lower widget
|
||||
|
|
@ -186,11 +192,16 @@ where
|
|||
node
|
||||
}
|
||||
|
||||
fn operate(&mut self, layout: Layout<'_>, operation: &mut dyn Operation<Message>) {
|
||||
fn operate(
|
||||
&mut self,
|
||||
layout: Layout<'_>,
|
||||
renderer: &Renderer,
|
||||
operation: &mut dyn Operation<OperationOutputWrapper<Message>>,
|
||||
) {
|
||||
self.content
|
||||
.borrow()
|
||||
.as_widget()
|
||||
.operate(self.tree, layout, operation)
|
||||
.operate(self.tree, layout, renderer, operation);
|
||||
}
|
||||
|
||||
fn on_event(
|
||||
|
|
@ -246,6 +257,6 @@ where
|
|||
layout,
|
||||
cursor_position,
|
||||
&bounds,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@ use iced::futures::channel::mpsc::UnboundedSender;
|
|||
use iced::widget::Container;
|
||||
pub use subscription::*;
|
||||
|
||||
use iced_native::alignment;
|
||||
use iced_native::event::{self, Event};
|
||||
use iced_native::layout;
|
||||
use iced_native::mouse;
|
||||
use iced_native::overlay;
|
||||
use iced_native::renderer;
|
||||
use iced_native::widget::{Operation, Tree};
|
||||
use iced_native::{Clipboard, Element, Layout, Length, Padding, Point, Rectangle, Shell, Widget};
|
||||
use iced_core::alignment;
|
||||
use iced_core::event::{self, Event};
|
||||
use iced_core::layout;
|
||||
use iced_core::mouse;
|
||||
use iced_core::overlay;
|
||||
use iced_core::renderer;
|
||||
use iced_core::widget::Tree;
|
||||
use iced_core::{Clipboard, Element, Layout, Length, Padding, Point, Rectangle, Shell, Widget};
|
||||
use std::{fmt::Debug, hash::Hash};
|
||||
|
||||
pub use iced_style::container::{Appearance, StyleSheet};
|
||||
|
|
@ -44,7 +44,7 @@ where
|
|||
#[allow(missing_debug_implementations)]
|
||||
pub struct RectangleTrackingContainer<'a, Message, Renderer, I>
|
||||
where
|
||||
Renderer: iced_native::Renderer,
|
||||
Renderer: iced_core::Renderer,
|
||||
Renderer::Theme: StyleSheet,
|
||||
{
|
||||
tx: UnboundedSender<(I, Rectangle)>,
|
||||
|
|
@ -54,7 +54,7 @@ where
|
|||
|
||||
impl<'a, Message, Renderer, I> RectangleTrackingContainer<'a, Message, Renderer, I>
|
||||
where
|
||||
Renderer: iced_native::Renderer,
|
||||
Renderer: iced_core::Renderer,
|
||||
Renderer::Theme: StyleSheet,
|
||||
I: 'a + Hash + Copy + Send + Sync + Debug,
|
||||
{
|
||||
|
|
@ -93,14 +93,14 @@ where
|
|||
|
||||
/// Sets the maximum width of the [`Container`].
|
||||
#[must_use]
|
||||
pub fn max_width(mut self, max_width: u32) -> Self {
|
||||
pub fn max_width(mut self, max_width: f32) -> Self {
|
||||
self.container = self.container.max_width(max_width);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the maximum height of the [`Container`] in pixels.
|
||||
#[must_use]
|
||||
pub fn max_height(mut self, max_height: u32) -> Self {
|
||||
pub fn max_height(mut self, max_height: f32) -> Self {
|
||||
self.container = self.container.max_height(max_height);
|
||||
self
|
||||
}
|
||||
|
|
@ -144,7 +144,7 @@ where
|
|||
impl<'a, Message, Renderer, I> Widget<Message, Renderer>
|
||||
for RectangleTrackingContainer<'a, Message, Renderer, I>
|
||||
where
|
||||
Renderer: iced_native::Renderer,
|
||||
Renderer: iced_core::Renderer,
|
||||
Renderer::Theme: StyleSheet,
|
||||
I: 'a + Hash + Copy + Send + Sync + Debug,
|
||||
{
|
||||
|
|
@ -152,7 +152,7 @@ where
|
|||
self.container.children()
|
||||
}
|
||||
|
||||
fn diff(&self, tree: &mut Tree) {
|
||||
fn diff(&mut self, tree: &mut Tree) {
|
||||
self.container.diff(tree);
|
||||
}
|
||||
|
||||
|
|
@ -168,8 +168,16 @@ where
|
|||
self.container.layout(renderer, limits)
|
||||
}
|
||||
|
||||
fn operate(&self, tree: &mut Tree, layout: Layout<'_>, operation: &mut dyn Operation<Message>) {
|
||||
self.container.operate(tree, layout, operation);
|
||||
fn operate(
|
||||
&self,
|
||||
tree: &mut Tree,
|
||||
layout: Layout<'_>,
|
||||
renderer: &Renderer,
|
||||
operation: &mut dyn iced_core::widget::Operation<
|
||||
iced_core::widget::OperationOutputWrapper<Message>,
|
||||
>,
|
||||
) {
|
||||
self.container.operate(tree, layout, renderer, operation);
|
||||
}
|
||||
|
||||
fn on_event(
|
||||
|
|
@ -229,7 +237,7 @@ where
|
|||
}
|
||||
|
||||
fn overlay<'b>(
|
||||
&'b self,
|
||||
&'b mut self,
|
||||
tree: &'b mut Tree,
|
||||
layout: Layout<'_>,
|
||||
renderer: &Renderer,
|
||||
|
|
@ -242,7 +250,7 @@ impl<'a, Message, Renderer, I> From<RectangleTrackingContainer<'a, Message, Rend
|
|||
for Element<'a, Message, Renderer>
|
||||
where
|
||||
Message: 'a,
|
||||
Renderer: 'a + iced_native::Renderer,
|
||||
Renderer: 'a + iced_core::Renderer,
|
||||
Renderer::Theme: StyleSheet,
|
||||
I: 'a + Hash + Copy + Send + Sync + Debug,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,44 +26,51 @@ pub enum State<I> {
|
|||
|
||||
async fn start_listening<I: Copy, R: 'static + Hash + Copy + Send + Sync + Debug + Eq>(
|
||||
id: I,
|
||||
state: State<R>,
|
||||
) -> (Option<(I, RectangleUpdate<R>)>, State<R>) {
|
||||
match state {
|
||||
State::Ready => {
|
||||
let (tx, rx) = unbounded();
|
||||
mut state: State<R>,
|
||||
) -> ((I, RectangleUpdate<R>), State<R>) {
|
||||
loop {
|
||||
let (update, new_state) = match state {
|
||||
State::Ready => {
|
||||
let (tx, rx) = unbounded();
|
||||
|
||||
(
|
||||
Some((id, RectangleUpdate::Init(RectangleTracker { tx }))),
|
||||
State::Waiting(rx, HashMap::new()),
|
||||
)
|
||||
}
|
||||
State::Waiting(mut rx, mut map) => match rx.next().await {
|
||||
Some(u) => {
|
||||
if let Some(prev) = map.get(&u.0) {
|
||||
let new = u.1;
|
||||
if prev.width != new.width
|
||||
|| prev.height != new.height
|
||||
|| prev.x != new.x
|
||||
|| prev.y != new.y
|
||||
{
|
||||
map.insert(u.0, new);
|
||||
return (
|
||||
(
|
||||
Some((id, RectangleUpdate::Init(RectangleTracker { tx }))),
|
||||
State::Waiting(rx, HashMap::new()),
|
||||
)
|
||||
}
|
||||
State::Waiting(mut rx, mut map) => match rx.next().await {
|
||||
Some(u) => {
|
||||
if let Some(prev) = map.get(&u.0) {
|
||||
let new = u.1;
|
||||
if (prev.width - new.width).abs() > 0.1
|
||||
|| (prev.height - new.height).abs() > 0.1
|
||||
|| (prev.x - new.x).abs() > 0.1
|
||||
|| (prev.y - new.y).abs() > 0.1
|
||||
{
|
||||
map.insert(u.0, new);
|
||||
(
|
||||
Some((id, RectangleUpdate::Rectangle(u))),
|
||||
State::Waiting(rx, map),
|
||||
)
|
||||
} else {
|
||||
(None, State::Waiting(rx, map))
|
||||
}
|
||||
} else {
|
||||
map.insert(u.0, u.1);
|
||||
(
|
||||
Some((id, RectangleUpdate::Rectangle(u))),
|
||||
State::Waiting(rx, map),
|
||||
);
|
||||
)
|
||||
}
|
||||
} else {
|
||||
map.insert(u.0, u.1);
|
||||
return (
|
||||
Some((id, RectangleUpdate::Rectangle(u))),
|
||||
State::Waiting(rx, map),
|
||||
);
|
||||
}
|
||||
(None, State::Waiting(rx, map))
|
||||
}
|
||||
None => (None, State::Finished),
|
||||
},
|
||||
State::Finished => iced::futures::future::pending().await,
|
||||
None => (None, State::Finished),
|
||||
},
|
||||
State::Finished => iced::futures::future::pending().await,
|
||||
};
|
||||
state = new_state;
|
||||
if let Some(u) = update {
|
||||
return (u, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,6 @@ pub fn scrollable<'a, Message>(
|
|||
element: impl Into<Element<'a, Message>>,
|
||||
) -> widget::Scrollable<'a, Message, Renderer> {
|
||||
widget::scrollable(element)
|
||||
.scrollbar_width(8)
|
||||
.scroller_width(8)
|
||||
// .scrollbar_width(8) TODO add these back
|
||||
// .scroller_width(8)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use apply::Apply;
|
|||
|
||||
/// A search field for COSMIC applications.
|
||||
pub fn field<Message: 'static + Clone>(
|
||||
id: iced::widget::text_input::Id,
|
||||
id: iced_core::id::Id,
|
||||
phrase: &str,
|
||||
on_change: fn(String) -> Message,
|
||||
on_clear: Message,
|
||||
|
|
@ -29,7 +29,7 @@ pub fn field<Message: 'static + Clone>(
|
|||
/// A search field for COSMIC applications.
|
||||
#[must_use]
|
||||
pub struct Field<'a, Message: 'static + Clone> {
|
||||
id: iced::widget::text_input::Id,
|
||||
id: iced_core::id::Id,
|
||||
phrase: &'a str,
|
||||
on_change: fn(String) -> Message,
|
||||
on_clear: Message,
|
||||
|
|
@ -38,7 +38,8 @@ pub struct Field<'a, Message: 'static + Clone> {
|
|||
|
||||
impl<'a, Message: 'static + Clone> Field<'a, Message> {
|
||||
pub fn into_element(mut self) -> crate::Element<'a, Message> {
|
||||
let mut input = iced::widget::text_input("", self.phrase, self.on_change)
|
||||
let mut input = iced::widget::text_input("", self.phrase)
|
||||
.on_input(self.on_change)
|
||||
.style(crate::theme::TextInput::Search)
|
||||
.width(Length::Fill)
|
||||
.id(self.id);
|
||||
|
|
@ -52,8 +53,8 @@ impl<'a, Message: 'static + Clone> Field<'a, Message> {
|
|||
input,
|
||||
clear_button().on_press(self.on_clear)
|
||||
)
|
||||
.width(Length::Units(300))
|
||||
.height(Length::Units(38))
|
||||
.width(Length::Fixed(300.0))
|
||||
.height(Length::Fixed(38.0))
|
||||
.padding([0, 16])
|
||||
.spacing(8)
|
||||
.align_items(iced::Alignment::Center)
|
||||
|
|
@ -84,7 +85,7 @@ fn active_style(theme: &crate::Theme) -> container::Appearance {
|
|||
iced::widget::container::Appearance {
|
||||
text_color: Some(cosmic.palette.neutral_9.into()),
|
||||
background: Some(Background::Color(neutral_7.into())),
|
||||
border_radius: 24.0,
|
||||
border_radius: 24.0.into(),
|
||||
border_width: 2.0,
|
||||
border_color: cosmic.accent.focus.into(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,14 +6,13 @@ use crate::iced;
|
|||
|
||||
/// A model for managing the state of a search widget.
|
||||
pub struct Model {
|
||||
pub input_id: iced::widget::text_input::Id,
|
||||
pub input_id: iced_core::id::Id,
|
||||
pub phrase: String,
|
||||
pub state: State,
|
||||
}
|
||||
|
||||
impl Model {
|
||||
/// Focuses the search field.
|
||||
#[must_use]
|
||||
pub fn focus<Message: 'static>(&mut self) -> crate::iced::Command<Message> {
|
||||
self.state = State::Active;
|
||||
iced::widget::text_input::focus(self.input_id.clone())
|
||||
|
|
@ -29,7 +28,7 @@ impl Model {
|
|||
impl Default for Model {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
input_id: iced::widget::text_input::Id::unique(),
|
||||
input_id: iced_core::id::Id::unique(),
|
||||
phrase: String::with_capacity(32),
|
||||
state: State::Inactive,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use super::style::StyleSheet;
|
|||
use super::widget::{SegmentedButton, SegmentedVariant};
|
||||
|
||||
use iced::{Length, Rectangle, Size};
|
||||
use iced_native::layout;
|
||||
use iced_core::layout;
|
||||
|
||||
/// Horizontal [`SegmentedButton`].
|
||||
pub type HorizontalSegmentedButton<'a, SelectionMode, Message, Renderer> =
|
||||
|
|
@ -25,10 +25,10 @@ pub fn horizontal<SelectionMode: Default, Message, Renderer>(
|
|||
model: &Model<SelectionMode>,
|
||||
) -> SegmentedButton<Horizontal, SelectionMode, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::Renderer
|
||||
+ iced_native::text::Renderer
|
||||
+ iced_native::image::Renderer
|
||||
+ iced_native::svg::Renderer,
|
||||
Renderer: iced_core::Renderer
|
||||
+ iced_core::text::Renderer
|
||||
+ iced_core::image::Renderer
|
||||
+ iced_core::svg::Renderer,
|
||||
Renderer::Theme: StyleSheet,
|
||||
Model<SelectionMode>: Selectable,
|
||||
{
|
||||
|
|
@ -38,10 +38,10 @@ where
|
|||
impl<'a, SelectionMode, Message, Renderer> SegmentedVariant
|
||||
for SegmentedButton<'a, Horizontal, SelectionMode, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::Renderer
|
||||
+ iced_native::text::Renderer
|
||||
+ iced_native::image::Renderer
|
||||
+ iced_native::svg::Renderer,
|
||||
Renderer: iced_core::Renderer
|
||||
+ iced_core::text::Renderer
|
||||
+ iced_core::image::Renderer
|
||||
+ iced_core::svg::Renderer,
|
||||
Renderer::Theme: StyleSheet,
|
||||
Model<SelectionMode>: Selectable,
|
||||
SelectionMode: Default,
|
||||
|
|
@ -49,8 +49,8 @@ where
|
|||
type Renderer = Renderer;
|
||||
|
||||
fn variant_appearance(
|
||||
theme: &<Self::Renderer as iced_native::Renderer>::Theme,
|
||||
style: &<<Self::Renderer as iced_native::Renderer>::Theme as StyleSheet>::Style,
|
||||
theme: &<Self::Renderer as iced_core::Renderer>::Theme,
|
||||
style: &<<Self::Renderer as iced_core::Renderer>::Theme as StyleSheet>::Style,
|
||||
) -> super::Appearance {
|
||||
theme.horizontal(style)
|
||||
}
|
||||
|
|
@ -85,7 +85,7 @@ where
|
|||
}
|
||||
|
||||
let size = limits
|
||||
.height(Length::Units(height as u16))
|
||||
.height(Length::Fixed(height))
|
||||
.resolve(Size::new(width, height));
|
||||
|
||||
layout::Node::new(size)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright 2022 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use iced_core::{Background, BorderRadius, Color};
|
||||
use iced_core::{renderer::BorderRadius, Background, Color};
|
||||
|
||||
/// Appearance of the segmented button.
|
||||
#[derive(Default, Clone, Copy)]
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use super::style::StyleSheet;
|
|||
use super::widget::{SegmentedButton, SegmentedVariant};
|
||||
|
||||
use iced::{Length, Rectangle, Size};
|
||||
use iced_native::layout;
|
||||
use iced_core::layout;
|
||||
|
||||
/// A type marker defining the vertical variant of a [`SegmentedButton`].
|
||||
pub struct Vertical;
|
||||
|
|
@ -25,10 +25,10 @@ pub fn vertical<SelectionMode, Message, Renderer>(
|
|||
model: &Model<SelectionMode>,
|
||||
) -> SegmentedButton<Vertical, SelectionMode, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::Renderer
|
||||
+ iced_native::text::Renderer
|
||||
+ iced_native::image::Renderer
|
||||
+ iced_native::svg::Renderer,
|
||||
Renderer: iced_core::Renderer
|
||||
+ iced_core::text::Renderer
|
||||
+ iced_core::image::Renderer
|
||||
+ iced_core::svg::Renderer,
|
||||
Renderer::Theme: StyleSheet,
|
||||
Model<SelectionMode>: Selectable,
|
||||
SelectionMode: Default,
|
||||
|
|
@ -39,10 +39,10 @@ where
|
|||
impl<'a, SelectionMode, Message, Renderer> SegmentedVariant
|
||||
for SegmentedButton<'a, Vertical, SelectionMode, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::Renderer
|
||||
+ iced_native::text::Renderer
|
||||
+ iced_native::image::Renderer
|
||||
+ iced_native::svg::Renderer,
|
||||
Renderer: iced_core::Renderer
|
||||
+ iced_core::text::Renderer
|
||||
+ iced_core::image::Renderer
|
||||
+ iced_core::svg::Renderer,
|
||||
Renderer::Theme: StyleSheet,
|
||||
Model<SelectionMode>: Selectable,
|
||||
SelectionMode: Default,
|
||||
|
|
@ -50,8 +50,8 @@ where
|
|||
type Renderer = Renderer;
|
||||
|
||||
fn variant_appearance(
|
||||
theme: &<Self::Renderer as iced_native::Renderer>::Theme,
|
||||
style: &<<Self::Renderer as iced_native::Renderer>::Theme as StyleSheet>::Style,
|
||||
theme: &<Self::Renderer as iced_core::Renderer>::Theme,
|
||||
style: &<<Self::Renderer as iced_core::Renderer>::Theme as StyleSheet>::Style,
|
||||
) -> super::Appearance {
|
||||
theme.vertical(style)
|
||||
}
|
||||
|
|
@ -86,7 +86,7 @@ where
|
|||
}
|
||||
|
||||
let size = limits
|
||||
.height(Length::Units(height as u16))
|
||||
.height(Length::Fixed(height))
|
||||
.resolve(Size::new(width, height));
|
||||
|
||||
layout::Node::new(size)
|
||||
|
|
|
|||
|
|
@ -10,9 +10,10 @@ use iced::{
|
|||
alignment, event, keyboard, mouse, touch, Background, Color, Command, Element, Event, Length,
|
||||
Point, Rectangle, Size,
|
||||
};
|
||||
use iced_core::BorderRadius;
|
||||
use iced_native::widget::{self, operation, tree, Operation};
|
||||
use iced_native::{layout, renderer, widget::Tree, Clipboard, Layout, Shell, Widget};
|
||||
use iced_core::renderer::BorderRadius;
|
||||
use iced_core::text::{LineHeight, Shaping};
|
||||
use iced_core::widget::{self, operation, tree};
|
||||
use iced_core::{layout, renderer, widget::Tree, Clipboard, Layout, Shell, Widget};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// State that is maintained by each individual widget.
|
||||
|
|
@ -46,15 +47,15 @@ impl operation::Focusable for LocalState {
|
|||
|
||||
/// Isolates variant-specific behaviors from [`SegmentedButton`].
|
||||
pub trait SegmentedVariant {
|
||||
type Renderer: iced_native::Renderer;
|
||||
type Renderer: iced_core::Renderer;
|
||||
|
||||
/// Get the appearance for this variant of the widget.
|
||||
fn variant_appearance(
|
||||
theme: &<Self::Renderer as iced_native::Renderer>::Theme,
|
||||
style: &<<Self::Renderer as iced_native::Renderer>::Theme as StyleSheet>::Style,
|
||||
theme: &<Self::Renderer as iced_core::Renderer>::Theme,
|
||||
style: &<<Self::Renderer as iced_core::Renderer>::Theme as StyleSheet>::Style,
|
||||
) -> super::Appearance
|
||||
where
|
||||
<Self::Renderer as iced_native::Renderer>::Theme: StyleSheet;
|
||||
<Self::Renderer as iced_core::Renderer>::Theme: StyleSheet;
|
||||
|
||||
/// Calculates the bounds for the given button by its position.
|
||||
fn variant_button_bounds(&self, bounds: Rectangle, position: usize) -> Rectangle;
|
||||
|
|
@ -67,10 +68,10 @@ pub trait SegmentedVariant {
|
|||
#[derive(Setters)]
|
||||
pub struct SegmentedButton<'a, Variant, SelectionMode, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::Renderer
|
||||
+ iced_native::text::Renderer
|
||||
+ iced_native::image::Renderer
|
||||
+ iced_native::svg::Renderer,
|
||||
Renderer: iced_core::Renderer
|
||||
+ iced_core::text::Renderer
|
||||
+ iced_core::image::Renderer
|
||||
+ iced_core::svg::Renderer,
|
||||
Renderer::Theme: StyleSheet,
|
||||
Model<SelectionMode>: Selectable,
|
||||
SelectionMode: Default,
|
||||
|
|
@ -91,13 +92,13 @@ where
|
|||
/// Spacing between icon and text in button.
|
||||
pub(super) button_spacing: u16,
|
||||
/// Desired font for active tabs.
|
||||
pub(super) font_active: Renderer::Font,
|
||||
pub(super) font_active: Option<Renderer::Font>,
|
||||
/// Desired font for hovered tabs.
|
||||
pub(super) font_hovered: Renderer::Font,
|
||||
pub(super) font_hovered: Option<Renderer::Font>,
|
||||
/// Desired font for inactive tabs.
|
||||
pub(super) font_inactive: Renderer::Font,
|
||||
pub(super) font_inactive: Option<Renderer::Font>,
|
||||
/// Size of the font.
|
||||
pub(super) font_size: u16,
|
||||
pub(super) font_size: f32,
|
||||
/// Size of icon
|
||||
pub(super) icon_size: u16,
|
||||
/// Desired width of the widget.
|
||||
|
|
@ -106,6 +107,8 @@ where
|
|||
pub(super) height: Length,
|
||||
/// Desired spacing between items.
|
||||
pub(super) spacing: u16,
|
||||
/// LineHeight of the font.
|
||||
pub(super) line_height: LineHeight,
|
||||
/// Style to draw the widget in.
|
||||
#[setters(into)]
|
||||
pub(super) style: <Renderer::Theme as StyleSheet>::Style,
|
||||
|
|
@ -122,10 +125,10 @@ where
|
|||
impl<'a, Variant, SelectionMode, Message, Renderer>
|
||||
SegmentedButton<'a, Variant, SelectionMode, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::Renderer
|
||||
+ iced_native::text::Renderer
|
||||
+ iced_native::image::Renderer
|
||||
+ iced_native::svg::Renderer,
|
||||
Renderer: iced_core::Renderer
|
||||
+ iced_core::text::Renderer
|
||||
+ iced_core::image::Renderer
|
||||
+ iced_core::svg::Renderer,
|
||||
Renderer::Theme: StyleSheet,
|
||||
Self: SegmentedVariant<Renderer = Renderer>,
|
||||
Model<SelectionMode>: Selectable,
|
||||
|
|
@ -141,14 +144,15 @@ where
|
|||
button_padding: [4, 4, 4, 4],
|
||||
button_height: 32,
|
||||
button_spacing: 4,
|
||||
font_active: Renderer::Font::default(),
|
||||
font_hovered: Renderer::Font::default(),
|
||||
font_inactive: Renderer::Font::default(),
|
||||
font_size: 17,
|
||||
font_active: None,
|
||||
font_hovered: None,
|
||||
font_inactive: None,
|
||||
font_size: 17.0,
|
||||
icon_size: 16,
|
||||
height: Length::Shrink,
|
||||
width: Length::Fill,
|
||||
spacing: 0,
|
||||
line_height: LineHeight::default(),
|
||||
style: <Renderer::Theme as StyleSheet>::Style::default(),
|
||||
on_activate: None,
|
||||
on_close: None,
|
||||
|
|
@ -212,6 +216,7 @@ where
|
|||
pub(super) fn max_button_dimensions(&self, renderer: &Renderer, bounds: Size) -> (f32, f32) {
|
||||
let mut width = 0.0f32;
|
||||
let mut height = 0.0f32;
|
||||
let font = renderer.default_font();
|
||||
|
||||
for key in self.model.order.iter().copied() {
|
||||
let mut button_width = 0.0f32;
|
||||
|
|
@ -219,7 +224,14 @@ where
|
|||
|
||||
// Add text to measurement if text was given.
|
||||
if let Some(text) = self.model.text(key) {
|
||||
let (w, h) = renderer.measure(text, self.font_size, Default::default(), bounds);
|
||||
let (w, h) = renderer.measure(
|
||||
text,
|
||||
self.font_size,
|
||||
self.line_height,
|
||||
font,
|
||||
bounds,
|
||||
Shaping::Advanced,
|
||||
);
|
||||
|
||||
button_width = w;
|
||||
button_height = h;
|
||||
|
|
@ -253,10 +265,10 @@ where
|
|||
impl<'a, Variant, SelectionMode, Message, Renderer> Widget<Message, Renderer>
|
||||
for SegmentedButton<'a, Variant, SelectionMode, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::Renderer
|
||||
+ iced_native::text::Renderer
|
||||
+ iced_native::image::Renderer
|
||||
+ iced_native::svg::Renderer,
|
||||
Renderer: iced_core::Renderer
|
||||
+ iced_core::text::Renderer
|
||||
+ iced_core::image::Renderer
|
||||
+ iced_core::svg::Renderer,
|
||||
Renderer::Theme: StyleSheet,
|
||||
Self: SegmentedVariant<Renderer = Renderer>,
|
||||
Model<SelectionMode>: Selectable,
|
||||
|
|
@ -379,7 +391,10 @@ where
|
|||
&self,
|
||||
tree: &mut Tree,
|
||||
_layout: Layout<'_>,
|
||||
operation: &mut dyn Operation<Message>,
|
||||
_renderer: &Renderer,
|
||||
operation: &mut dyn iced_core::widget::Operation<
|
||||
iced_core::widget::OperationOutputWrapper<Message>,
|
||||
>,
|
||||
) {
|
||||
let state = tree.state.downcast_mut::<LocalState>();
|
||||
operation.focusable(state, self.id.as_ref().map(|id| &id.0));
|
||||
|
|
@ -392,7 +407,7 @@ where
|
|||
cursor_position: iced::Point,
|
||||
_viewport: &iced::Rectangle,
|
||||
_renderer: &Renderer,
|
||||
) -> iced_native::mouse::Interaction {
|
||||
) -> iced_core::mouse::Interaction {
|
||||
let bounds = layout.bounds();
|
||||
|
||||
if bounds.contains(cursor_position) {
|
||||
|
|
@ -402,15 +417,15 @@ where
|
|||
.contains(cursor_position)
|
||||
{
|
||||
return if self.model.items[key].enabled {
|
||||
iced_native::mouse::Interaction::Pointer
|
||||
iced_core::mouse::Interaction::Pointer
|
||||
} else {
|
||||
iced_native::mouse::Interaction::Idle
|
||||
iced_core::mouse::Interaction::Idle
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iced_native::mouse::Interaction::Idle
|
||||
iced_core::mouse::Interaction::Idle
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
|
|
@ -418,7 +433,7 @@ where
|
|||
&self,
|
||||
tree: &Tree,
|
||||
renderer: &mut Renderer,
|
||||
theme: &<Renderer as iced_native::Renderer>::Theme,
|
||||
theme: &<Renderer as iced_core::Renderer>::Theme,
|
||||
_style: &renderer::Style,
|
||||
layout: Layout<'_>,
|
||||
_cursor_position: iced::Point,
|
||||
|
|
@ -458,6 +473,7 @@ where
|
|||
} else {
|
||||
(appearance.inactive, &self.font_inactive)
|
||||
};
|
||||
let font = font.unwrap_or_else(|| renderer.default_font());
|
||||
|
||||
let button_appearance = if nth == 0 {
|
||||
status_appearance.first
|
||||
|
|
@ -536,7 +552,7 @@ where
|
|||
unimplemented!()
|
||||
}
|
||||
icon::Handle::Svg(handle) => {
|
||||
iced_native::svg::Renderer::draw(renderer, handle, icon_color, icon_bounds);
|
||||
iced_core::svg::Renderer::draw(renderer, handle, icon_color, icon_bounds);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -550,14 +566,16 @@ where
|
|||
bounds.y = y;
|
||||
|
||||
// Draw the text in this button.
|
||||
renderer.fill_text(iced_native::text::Text {
|
||||
renderer.fill_text(iced_core::text::Text {
|
||||
content: text,
|
||||
size: f32::from(self.font_size),
|
||||
size: self.font_size,
|
||||
bounds,
|
||||
color: status_appearance.text_color,
|
||||
font: font.clone(),
|
||||
font,
|
||||
horizontal_alignment,
|
||||
vertical_alignment: alignment::Vertical::Center,
|
||||
shaping: Shaping::Advanced,
|
||||
line_height: self.line_height,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -575,7 +593,7 @@ where
|
|||
unimplemented!()
|
||||
}
|
||||
icon::Handle::Svg(handle) => {
|
||||
iced_native::svg::Renderer::draw(
|
||||
iced_core::svg::Renderer::draw(
|
||||
renderer,
|
||||
handle,
|
||||
Some(status_appearance.text_color),
|
||||
|
|
@ -588,11 +606,11 @@ where
|
|||
}
|
||||
|
||||
fn overlay<'b>(
|
||||
&'b self,
|
||||
&'b mut self,
|
||||
_tree: &'b mut Tree,
|
||||
_layout: iced_native::Layout<'_>,
|
||||
_layout: iced_core::Layout<'_>,
|
||||
_renderer: &Renderer,
|
||||
) -> Option<iced_native::overlay::Element<'b, Message, Renderer>> {
|
||||
) -> Option<iced_core::overlay::Element<'b, Message, Renderer>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
@ -601,10 +619,10 @@ impl<'a, Variant, SelectionMode, Message, Renderer>
|
|||
From<SegmentedButton<'a, Variant, SelectionMode, Message, Renderer>>
|
||||
for Element<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::Renderer
|
||||
+ iced_native::text::Renderer
|
||||
+ iced_native::image::Renderer
|
||||
+ iced_native::svg::Renderer
|
||||
Renderer: iced_core::Renderer
|
||||
+ iced_core::text::Renderer
|
||||
+ iced_core::image::Renderer
|
||||
+ iced_core::svg::Renderer
|
||||
+ 'a,
|
||||
Renderer::Theme: StyleSheet,
|
||||
SegmentedButton<'a, Variant, SelectionMode, Message, Renderer>:
|
||||
|
|
@ -624,7 +642,6 @@ where
|
|||
}
|
||||
|
||||
/// A command that focuses a segmented item stored in a widget.
|
||||
#[must_use]
|
||||
pub fn focus<Message: 'static>(id: Id) -> Command<Message> {
|
||||
Command::widget(operation::focusable::focus(id.0))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ where
|
|||
.button_padding([16, 0, 16, 0])
|
||||
.button_height(32)
|
||||
.style(crate::theme::SegmentedButton::Selection)
|
||||
.font_active(crate::font::FONT_SEMIBOLD)
|
||||
.font_active(Some(crate::font::FONT_SEMIBOLD))
|
||||
}
|
||||
|
||||
/// A selection of multiple choices appearing as a conjoined button.
|
||||
|
|
@ -45,5 +45,5 @@ where
|
|||
.button_padding([16, 0, 16, 0])
|
||||
.button_height(32)
|
||||
.style(crate::theme::SegmentedButton::Selection)
|
||||
.font_active(crate::font::FONT_SEMIBOLD)
|
||||
.font_active(Some(crate::font::FONT_SEMIBOLD))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,43 +46,41 @@ impl<'a, Message: 'static> SpinButton<'a, Message> {
|
|||
icon("list-remove-symbolic", 24)
|
||||
.style(theme::Svg::Symbolic)
|
||||
.apply(container)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.width(Length::Fixed(32.0))
|
||||
.height(Length::Fixed(32.0))
|
||||
.align_x(Horizontal::Center)
|
||||
.align_y(Vertical::Center)
|
||||
.apply(button)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.width(Length::Fixed(32.0))
|
||||
.height(Length::Fixed(32.0))
|
||||
.style(theme::Button::Text)
|
||||
.on_press(model::Message::Decrement),
|
||||
text(label)
|
||||
.vertical_alignment(Vertical::Center)
|
||||
.apply(container)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.align_x(Horizontal::Center)
|
||||
.align_y(Vertical::Center),
|
||||
icon("list-add-symbolic", 24)
|
||||
.style(theme::Svg::Symbolic)
|
||||
.apply(container)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.width(Length::Fixed(32.0))
|
||||
.height(Length::Fixed(32.0))
|
||||
.align_x(Horizontal::Center)
|
||||
.align_y(Vertical::Center)
|
||||
.apply(button)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.width(Length::Fixed(32.0))
|
||||
.height(Length::Fixed(32.0))
|
||||
.style(theme::Button::Text)
|
||||
.on_press(model::Message::Increment),
|
||||
]
|
||||
.width(Length::Fill)
|
||||
.height(Length::Units(32))
|
||||
.width(Length::Shrink)
|
||||
.height(Length::Fixed(32.0))
|
||||
.spacing(4.0)
|
||||
.align_items(Alignment::Center),
|
||||
)
|
||||
.padding([4, 4])
|
||||
.align_y(Vertical::Center)
|
||||
.width(Length::Units(95))
|
||||
.height(Length::Units(32))
|
||||
.width(Length::Shrink)
|
||||
.height(Length::Fixed(32.0))
|
||||
.style(theme::Container::custom(container_style))
|
||||
.apply(Element::from)
|
||||
.map(on_change)
|
||||
|
|
@ -104,7 +102,7 @@ fn container_style(theme: &crate::Theme) -> iced_style::container::Appearance {
|
|||
iced_style::container::Appearance {
|
||||
text_color: Some(basic.palette.neutral_10.into()),
|
||||
background: Some(Background::Color(neutral_10.into())),
|
||||
border_radius: 24.0,
|
||||
border_radius: 24.0.into(),
|
||||
border_width: 0.0,
|
||||
border_color: accent.base.into(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ pub use iced::widget::Text;
|
|||
/// [`Text`]: widget::Text
|
||||
pub fn text<'a, Renderer>(text: impl Into<Cow<'a, str>>) -> Text<'a, Renderer>
|
||||
where
|
||||
Renderer: iced_native::text::Renderer,
|
||||
Renderer: iced_core::text::Renderer,
|
||||
Renderer::Theme: iced::widget::text::StyleSheet,
|
||||
{
|
||||
Text::new(text)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ pub fn toggler<'a, Message>(
|
|||
is_checked: bool,
|
||||
f: impl Fn(bool) -> Message + 'a,
|
||||
) -> widget::Toggler<'a, Message, Renderer> {
|
||||
widget::Toggler::new(is_checked, label, f)
|
||||
widget::Toggler::new(label, is_checked, f)
|
||||
.size(24)
|
||||
.spacing(12)
|
||||
.width(Length::Shrink)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ where
|
|||
.button_padding([16, 0, 16, 0])
|
||||
.button_height(48)
|
||||
.style(crate::theme::SegmentedButton::ViewSwitcher)
|
||||
.font_active(crate::font::FONT_SEMIBOLD)
|
||||
.font_active(Some(crate::font::FONT_SEMIBOLD))
|
||||
}
|
||||
|
||||
/// A collection of tabs for developing a tabbed interface.
|
||||
|
|
@ -45,5 +45,5 @@ where
|
|||
.button_padding([16, 0, 16, 0])
|
||||
.button_height(48)
|
||||
.style(crate::theme::SegmentedButton::ViewSwitcher)
|
||||
.font_active(crate::font::FONT_SEMIBOLD)
|
||||
.font_active(Some(crate::font::FONT_SEMIBOLD))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,11 +64,12 @@ impl<'a, Message: 'static + Clone> From<Warning<'a, Message>> for Element<'a, Me
|
|||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn warning_container(theme: &Theme) -> widget::container::Appearance {
|
||||
widget::container::Appearance {
|
||||
text_color: Some(theme.cosmic().warning.on.into()),
|
||||
background: Some(Background::Color(theme.cosmic().warning_color().into())),
|
||||
border_radius: 0.0,
|
||||
border_radius: 0.0.into(),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue