Clarify constructor failures and borrowed API contracts
This commit is contained in:
1 parent
23e280a6b4
commit
a7fcd69897
55 files changed
+332
-102
No files matched your search
@@ -45,6 +45,7 @@ pub(crate) fn accent_button_style(
|
||||
}
|
||||
|
||||
/// Filled accent buttons and selected rows share this per-state contrast policy.
|
||||
#[must_use]
|
||||
pub fn accent_button() -> theme::Button {
|
||||
theme::Button::Custom {
|
||||
active: Box::new(|focused, theme| accent_button_style(theme, State::Active, focused)),
|
||||
|
||||
@@ -5,6 +5,7 @@ use cosmic::widget::{column, container, row};
|
||||
use cosmic::{Element, theme};
|
||||
use jiff::Zoned;
|
||||
|
||||
#[must_use]
|
||||
pub fn format_bar_time(now: &Zoned) -> String {
|
||||
let months = [
|
||||
"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sept", "oct", "nov", "dec",
|
||||
@@ -20,6 +21,7 @@ pub fn format_bar_time(now: &Zoned) -> String {
|
||||
if hour < 12 { "am" } else { "pm" }
|
||||
)
|
||||
}
|
||||
#[must_use]
|
||||
pub fn month(today: jiff::civil::Date, offset: i32) -> (jiff::civil::Date, usize, usize) {
|
||||
let month_index = i32::from(today.year()) * 12 + i32::from(today.month()) - 1 + offset;
|
||||
let year = month_index.div_euclid(12) as i16;
|
||||
@@ -30,6 +32,7 @@ pub fn month(today: jiff::civil::Date, offset: i32) -> (jiff::civil::Date, usize
|
||||
(first, start, days)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn grid<'a, M: Clone + 'a>(
|
||||
today: jiff::civil::Date,
|
||||
offset: i32,
|
||||
@@ -41,6 +44,7 @@ pub fn grid<'a, M: Clone + 'a>(
|
||||
grid_with_density(today, offset, palette, font, opacity, navigation, false)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn compact_grid<'a, M: Clone + 'a>(
|
||||
today: jiff::civil::Date,
|
||||
offset: i32,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use cosmic::iced::Color;
|
||||
|
||||
#[must_use]
|
||||
pub fn luminance(color: Color) -> f32 {
|
||||
let linear = |v: f32| {
|
||||
if v <= 0.04045 {
|
||||
@@ -11,6 +12,7 @@ pub fn luminance(color: Color) -> f32 {
|
||||
0.2126 * linear(color.r) + 0.7152 * linear(color.g) + 0.0722 * linear(color.b)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn contrast(a: Color, b: Color) -> f32 {
|
||||
let (a, b) = (luminance(a), luminance(b));
|
||||
(a.max(b) + 0.05) / (a.min(b) + 0.05)
|
||||
@@ -19,6 +21,7 @@ pub fn contrast(a: Color, b: Color) -> f32 {
|
||||
/// Resolve a control fill against its surface before selecting its foreground.
|
||||
/// The returned fill is opaque, so wallpaper and translucent panels cannot change
|
||||
/// the contrast of a small, filled control.
|
||||
#[must_use]
|
||||
pub fn composite(fill: Color, surface: Color) -> Color {
|
||||
let a = fill.a.clamp(0., 1.);
|
||||
Color::from_rgb(
|
||||
@@ -30,6 +33,7 @@ pub fn composite(fill: Color, surface: Color) -> Color {
|
||||
|
||||
/// Preserve the user's preferred color when it passes normal-text contrast.
|
||||
/// Otherwise black or white always provides at least 4.5:1 on an opaque sRGB fill.
|
||||
#[must_use]
|
||||
pub fn foreground(background: Color, preferred: Color) -> Color {
|
||||
let preferred = composite(preferred, background);
|
||||
if contrast(background, preferred) >= 4.5 {
|
||||
@@ -44,6 +48,7 @@ pub fn foreground(background: Color, preferred: Color) -> Color {
|
||||
|
||||
/// Prefer the theme's foreground for filled controls by adjusting the accent's
|
||||
/// brightness until the text has enough contrast.
|
||||
#[must_use]
|
||||
pub fn accent_pair(background: Color, preferred: Color) -> (Color, Color) {
|
||||
let on = composite(preferred, background);
|
||||
let shade = if luminance(on) > luminance(background) {
|
||||
@@ -67,6 +72,7 @@ pub fn accent_pair(background: Color, preferred: Color) -> (Color, Color) {
|
||||
}
|
||||
|
||||
/// Resolve configured accent transparency before passing an opaque color to a toolkit.
|
||||
#[must_use]
|
||||
pub fn accent_color(accent: Color, surface: Color) -> cosmic::cosmic_theme::palette::Srgb {
|
||||
rgba(composite(accent, surface)).color
|
||||
}
|
||||
|
||||
@@ -5,23 +5,28 @@ use cosmic::{theme, widget};
|
||||
|
||||
use crate::{Palette, mix};
|
||||
|
||||
#[must_use]
|
||||
pub fn surface(background: Color, radius: f32) -> theme::Container<'static> {
|
||||
theme::Container::custom(move |_| surface_appearance(background, radius))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn button_style(p: Palette, selected: bool) -> theme::Button {
|
||||
button_style_with_focus(p, selected, true)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn button_style_with_focus(p: Palette, selected: bool, focus_visible: bool) -> theme::Button {
|
||||
styled_button(p, selected, false, 1.0, focus_visible)
|
||||
}
|
||||
|
||||
/// Selection cards share native button states while revealing the modal material.
|
||||
#[must_use]
|
||||
pub fn material_button_style(p: Palette, selected: bool, material_opacity: f32) -> theme::Button {
|
||||
material_button_style_with_focus(p, selected, material_opacity, true)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn material_button_style_with_focus(
|
||||
p: Palette,
|
||||
selected: bool,
|
||||
@@ -101,10 +106,12 @@ pub(crate) fn switch_colors(palette: Palette, enabled: bool, hovered: bool) -> (
|
||||
(track, thumb)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn navigation_style(p: Palette, selected: bool) -> theme::Button {
|
||||
styled_button(p, selected, true, 1.0, true)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn settings_input(p: Palette) -> theme::TextInput {
|
||||
let appearance = move |focused: bool, hovered: bool| cosmic::widget::text_input::Appearance {
|
||||
shape: Some(BorderShape::Continuous),
|
||||
@@ -229,6 +236,7 @@ fn styled_button(
|
||||
|
||||
/// Authentication actions use normal text while enabled and muted text while disabled.
|
||||
/// Keep the disabled fill neutral so contrast correction cannot make it look active.
|
||||
#[must_use]
|
||||
pub fn authentication_button(palette: Palette) -> theme::Button {
|
||||
let paint = move |enabled: bool, interaction: f32, focused: bool| {
|
||||
let (fill, foreground) = if enabled {
|
||||
@@ -260,6 +268,7 @@ pub fn authentication_button(palette: Palette) -> theme::Button {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn authentication_input(palette: Palette) -> theme::TextInput {
|
||||
let text = palette.text;
|
||||
let muted = palette.muted;
|
||||
@@ -293,6 +302,7 @@ pub fn authentication_input(palette: Palette) -> theme::TextInput {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn lock_input(
|
||||
radius: f32,
|
||||
accent: cosmic::iced::Color,
|
||||
@@ -361,6 +371,7 @@ pub fn shell_button(
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn surface_appearance(background: Color, radius: f32) -> container::Style {
|
||||
container::Style {
|
||||
background: Some(Background::Color(background)),
|
||||
@@ -373,6 +384,7 @@ pub fn surface_appearance(background: Color, radius: f32) -> container::Style {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn notification_button(
|
||||
foreground: Color,
|
||||
hover: Color,
|
||||
@@ -396,6 +408,7 @@ pub fn notification_button(
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn filled_button(fill: Color, foreground: Color, radius: f32, opacity: f32) -> theme::Button {
|
||||
let paint = move |outline| button::Style {
|
||||
shape: Some(BorderShape::Continuous),
|
||||
|
||||
@@ -174,6 +174,7 @@ fn desktop(p: &Palette) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn svg(
|
||||
family: &Family,
|
||||
variant: Option<Appearance>,
|
||||
@@ -274,6 +275,7 @@ fn svg_with_radius(
|
||||
result
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn neighbor(index: usize, count: usize, key: &keyboard::key::Named) -> Option<usize> {
|
||||
use keyboard::key::Named::*;
|
||||
if count == 0 {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/// Radius of a circular inset. Squircle insets retain an `Outline` and its distance offset.
|
||||
#[must_use]
|
||||
pub fn inner_radius(outer: f32, padding: f32) -> f32 {
|
||||
(outer - padding).max(0.0)
|
||||
}
|
||||
|
||||
@@ -186,6 +186,7 @@ pub fn accented(source: &'static [u8], size: u16, foreground: Color, accent: Col
|
||||
}))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn tint_svg(source: &[u8], foreground: Color, accent: Color) -> Vec<u8> {
|
||||
let rgba = |foreground: Color| {
|
||||
format!(
|
||||
|
||||
@@ -37,6 +37,7 @@ pub fn heading<'a, M: 'a>(
|
||||
.align_y(Alignment::Center)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn badge<'a, M: 'a>(
|
||||
content: Element<'a, M>,
|
||||
accent: Color,
|
||||
@@ -55,6 +56,7 @@ pub fn badge<'a, M: 'a>(
|
||||
.into()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn section<'a, M: 'a>(
|
||||
content: Element<'a, M>,
|
||||
foreground: Color,
|
||||
@@ -84,6 +86,7 @@ pub fn section_label<'a>(
|
||||
.class(cosmic::theme::Text::Color(muted))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn separator<'a, M: 'a>(foreground: Color, opacity: f32) -> Element<'a, M> {
|
||||
container(cosmic::widget::Space::new().width(Length::Fill).height(1))
|
||||
.class(crate::controls::surface(
|
||||
@@ -93,6 +96,7 @@ pub fn separator<'a, M: 'a>(foreground: Color, opacity: f32) -> Element<'a, M> {
|
||||
.into()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn switch<'a, M: 'a>(enabled: bool, palette: crate::Palette, opacity: f32) -> Element<'a, M> {
|
||||
let (track, thumb) = crate::controls::switch_colors(palette, enabled, false);
|
||||
let track_radius = 10.;
|
||||
@@ -123,6 +127,7 @@ pub fn switch<'a, M: 'a>(enabled: bool, palette: crate::Palette, opacity: f32) -
|
||||
.into()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn slider(foreground: Color, opacity: f32) -> cosmic::theme::iced::Slider {
|
||||
let style = std::rc::Rc::new(move |_: &cosmic::Theme| {
|
||||
use cosmic::iced::widget::slider::{Breakpoint, Handle, HandleShape, Rail, Style};
|
||||
|
||||
@@ -19,6 +19,7 @@ pub struct Palette {
|
||||
}
|
||||
|
||||
impl Palette {
|
||||
#[must_use]
|
||||
pub fn from_resolved(theme: &ferese_theme_model::ResolvedTheme) -> Self {
|
||||
let color = |value: &str| parse_color(value).expect("validated resolved theme color");
|
||||
Self {
|
||||
@@ -50,6 +51,7 @@ impl Palette {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn flat(mut self) -> Self {
|
||||
self.background = self.sidebar;
|
||||
self.card = self.sidebar;
|
||||
@@ -138,6 +140,7 @@ impl Palette {
|
||||
cosmic::Theme::custom(std::sync::Arc::new(native)).corner_shape(BorderShape::Continuous)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn application_style(self, background: Color) -> cosmic::iced::theme::Style {
|
||||
cosmic::iced::theme::Style {
|
||||
background_color: background,
|
||||
@@ -147,6 +150,7 @@ impl Palette {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn parse_color(value: &str) -> Option<Color> {
|
||||
let hex = value.strip_prefix('#')?;
|
||||
let packed = u32::from_str_radix(hex, 16).ok()?;
|
||||
@@ -163,6 +167,7 @@ pub fn parse_color(value: &str) -> Option<Color> {
|
||||
))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn mix(a: Color, b: Color, t: f32) -> Color {
|
||||
Color::from_rgb(
|
||||
a.r + (b.r - a.r) * t,
|
||||
@@ -171,6 +176,7 @@ pub fn mix(a: Color, b: Color, t: f32) -> Color {
|
||||
)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn surface_shade(base: Color) -> Color {
|
||||
if crate::luminance(base) > 0.5 {
|
||||
Color::BLACK
|
||||
@@ -179,6 +185,7 @@ pub fn surface_shade(base: Color) -> Color {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn material_opacity(theme: &ferese_theme_model::ResolvedTheme) -> f32 {
|
||||
if theme.tokens.material.style == "translucent" {
|
||||
theme.tokens.material.opacity as f32
|
||||
|
||||
@@ -107,7 +107,7 @@ impl<M> Surface<'_, M> {
|
||||
&mut collector,
|
||||
);
|
||||
let size = layout.bounds().size();
|
||||
let scene = PixelGrid::new(self.options.scale)
|
||||
let scene = PixelGrid::try_new(self.options.scale)
|
||||
.and_then(|grid| {
|
||||
ferese_panel::scene::derive(
|
||||
self.options.parameters,
|
||||
|
||||
@@ -16,6 +16,7 @@ pub struct Workspace<'a> {
|
||||
pub visible_elsewhere: bool,
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn width(style: WorkspaceStyle) -> f32 {
|
||||
match style {
|
||||
WorkspaceStyle::Numbers | WorkspaceStyle::Dots => 24.,
|
||||
@@ -25,6 +26,7 @@ pub fn width(style: WorkspaceStyle) -> f32 {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn tooltip_label(workspace: &Workspace<'_>) -> String {
|
||||
let name = if workspace.name.is_empty() || workspace.name == workspace.index.to_string() {
|
||||
String::new()
|
||||
@@ -44,6 +46,7 @@ pub fn tooltip_label(workspace: &Workspace<'_>) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn indicator<'a, M: 'a>(
|
||||
style: WorkspaceStyle,
|
||||
workspace: Workspace<'a>,
|
||||
@@ -193,6 +196,7 @@ pub fn indicator<'a, M: 'a>(
|
||||
.into()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn sample<'a, M: 'a>(
|
||||
style: WorkspaceStyle,
|
||||
palette: Palette,
|
||||
|
||||
Reference in new issue
Block a user