Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix accent text #807

Merged
merged 2 commits into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 107 additions & 75 deletions cosmic-theme/src/model/theme.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::{
composite::over,
steps::{color_index, get_surface_color, get_text, steps},
steps::{color_index, get_index, get_small_widget_color, get_surface_color, get_text, steps},
Component, Container, CornerRadii, CosmicPalette, CosmicPaletteInner, Spacing, ThemeMode,
DARK_PALETTE, LIGHT_PALETTE, NAME,
};
use cosmic_config::{Config, CosmicConfigEntry};
use palette::{rgb::Rgb, IntoColor, Oklcha, Srgb, Srgba};
use palette::{color_difference::Wcag21RelativeContrast, rgb::Rgb, IntoColor, Oklcha, Srgb, Srgba};
use serde::{Deserialize, Serialize};
use std::num::NonZeroUsize;

Expand Down Expand Up @@ -97,6 +97,9 @@ pub struct Theme {
pub is_frosted: bool,
/// shade color for dialogs
pub shade: Srgba,
/// accent text colors
/// If None, accent base color is the accent text color.
pub accent_text: Option<Srgba>,
}

impl Default for Theme {
Expand Down Expand Up @@ -276,7 +279,7 @@ impl Theme {
#[allow(clippy::doc_markdown)]
/// get @accent_text_color
pub fn accent_text_color(&self) -> Srgba {
self.accent.base
self.accent_text.unwrap_or(self.accent.base)
}
#[must_use]
#[allow(clippy::doc_markdown)]
Expand Down Expand Up @@ -844,9 +847,102 @@ impl ThemeBuilder {
color_index(bg_component, step_array.len()),
&step_array,
&p_ref.neutral_8,
text_steps_array.as_ref(),
text_steps_array.as_deref(),
);

let primary = {
let container_bg = if let Some(primary_container_bg_color) = primary_container_bg {
primary_container_bg_color
} else {
get_surface_color(bg_index, 5, &step_array, is_dark, &p_ref.neutral_1)
};

let base_index: usize = color_index(container_bg, step_array.len());
let component_base =
get_surface_color(base_index, 6, &step_array, is_dark, &p_ref.neutral_3);

component_hovered_overlay = if base_index < 91 {
p_ref.neutral_10
} else {
p_ref.neutral_0
};
component_hovered_overlay.alpha = 0.1;

component_pressed_overlay = component_hovered_overlay;
component_pressed_overlay.alpha = 0.2;

let container = Container::new(
Component::component(
component_base,
accent,
get_text(
color_index(component_base, step_array.len()),
&step_array,
&p_ref.neutral_8,
text_steps_array.as_deref(),
),
component_hovered_overlay,
component_pressed_overlay,
is_high_contrast,
p_ref.neutral_8,
),
container_bg,
get_text(
base_index,
&step_array,
&p_ref.neutral_8,
text_steps_array.as_deref(),
),
get_small_widget_color(base_index, 5, &neutral_steps, &p_ref.neutral_6),
);

container
};

let accent_text = if is_dark {
(primary.base.relative_contrast(accent.color) < 4.).then(|| {
let step_array = steps(accent, NonZeroUsize::new(100).unwrap());
let primary_color_index = color_index(primary.base, 100);
let steps = if is_high_contrast { 60 } else { 50 };
let accent_text = get_surface_color(
primary_color_index,
steps,
&step_array,
is_dark,
&Srgba::new(1., 1., 1., 1.),
);
if primary.base.relative_contrast(accent_text.color) < 4. {
Srgba::new(1., 1., 1., 1.)
} else {
accent_text
}
})
} else {
let darkest = if bg.relative_luminance().luma < primary.base.relative_luminance().luma {
bg
} else {
primary.base
};

(darkest.relative_contrast(accent.color) < 4.).then(|| {
let step_array = steps(accent, NonZeroUsize::new(100).unwrap());
let primary_color_index = color_index(darkest, 100);
let steps = if is_high_contrast { 60 } else { 50 };
let accent_text = get_surface_color(
primary_color_index,
steps,
&step_array,
is_dark,
&Srgba::new(1., 1., 1., 1.),
);
if darkest.relative_contrast(accent_text.color) < 4. {
Srgba::new(0., 0., 0., 1.)
} else {
accent_text
}
})
};

let mut theme: Theme = Theme {
name: palette.name().to_string(),
shade: if palette.is_dark() {
Expand All @@ -869,70 +965,11 @@ impl ThemeBuilder {
bg_index,
&step_array,
&p_ref.neutral_8,
text_steps_array.as_ref(),
),
get_surface_color(
bg_index,
5,
&neutral_steps,
bg_index <= 65,
&p_ref.neutral_6,
text_steps_array.as_deref(),
),
get_small_widget_color(bg_index, 5, &neutral_steps, &p_ref.neutral_6),
),
primary: {
let container_bg = if let Some(primary_container_bg_color) = primary_container_bg {
primary_container_bg_color
} else {
get_surface_color(bg_index, 5, &step_array, is_dark, &p_ref.neutral_1)
};

let base_index: usize = color_index(container_bg, step_array.len());
let component_base =
get_surface_color(base_index, 6, &step_array, is_dark, &p_ref.neutral_3);

component_hovered_overlay = if base_index < 91 {
p_ref.neutral_10
} else {
p_ref.neutral_0
};
component_hovered_overlay.alpha = 0.1;

component_pressed_overlay = component_hovered_overlay;
component_pressed_overlay.alpha = 0.2;

let container = Container::new(
Component::component(
component_base,
accent,
get_text(
color_index(component_base, step_array.len()),
&step_array,
&p_ref.neutral_8,
text_steps_array.as_ref(),
),
component_hovered_overlay,
component_pressed_overlay,
is_high_contrast,
p_ref.neutral_8,
),
container_bg,
get_text(
base_index,
&step_array,
&p_ref.neutral_8,
text_steps_array.as_ref(),
),
get_surface_color(
base_index,
5,
&neutral_steps,
base_index <= 65,
&p_ref.neutral_6,
),
);

container
},
primary,
secondary: {
let container_bg = if let Some(secondary_container_bg) = secondary_container_bg {
secondary_container_bg
Expand Down Expand Up @@ -962,7 +999,7 @@ impl ThemeBuilder {
color_index(secondary_component, step_array.len()),
&step_array,
&p_ref.neutral_8,
text_steps_array.as_ref(),
text_steps_array.as_deref(),
),
component_hovered_overlay,
component_pressed_overlay,
Expand All @@ -974,15 +1011,9 @@ impl ThemeBuilder {
base_index,
&step_array,
&p_ref.neutral_8,
text_steps_array.as_ref(),
),
get_surface_color(
base_index,
5,
&neutral_steps,
base_index <= 65,
&p_ref.neutral_6,
text_steps_array.as_deref(),
),
get_small_widget_color(base_index, 5, &neutral_steps, &p_ref.neutral_6),
)
},
accent: Component::colored_component(
Expand Down Expand Up @@ -1098,6 +1129,7 @@ impl ThemeBuilder {
active_hint,
window_hint,
is_frosted,
accent_text,
};
theme.spacing = spacing;
theme.corner_radii = corner_radii;
Expand Down
34 changes: 30 additions & 4 deletions cosmic-theme/src/steps.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::num::NonZeroUsize;

use almost::equal;
use palette::{convert::FromColorUnclamped, ClampAssign, FromColor, Oklcha, Srgb, Srgba};
use palette::{convert::FromColorUnclamped, ClampAssign, FromColor, Lch, Oklcha, Srgb, Srgba};

/// Get an array of 100 colors with a specific hue and chroma
/// over the full range of lightness.
Expand Down Expand Up @@ -35,7 +35,7 @@ pub fn get_index(base_index: usize, steps: usize, step_len: usize, is_dark: bool
pub fn get_surface_color(
base_index: usize,
steps: usize,
step_array: &Vec<Srgba>,
step_array: &[Srgba],
mut is_dark: bool,
fallback: &Srgba,
) -> Srgba {
Expand All @@ -48,12 +48,38 @@ pub fn get_surface_color(
.unwrap_or(fallback)
}

/// get surface color given a base and some steps
#[must_use]
pub fn get_small_widget_color(
base_index: usize,
steps: usize,
step_array: &[Srgba],
fallback: &Srgba,
) -> Srgba {
assert!(step_array.len() == 100);

let is_dark = base_index <= 40 || (base_index > 51 && base_index < 65);

let res = *get_index(base_index, steps, step_array.len(), is_dark)
.and_then(|i| step_array.get(i))
.unwrap_or(fallback);

let mut lch = Lch::from_color(res);
if lch.chroma / Lch::<f32>::max_chroma() > 0.03 {
lch.chroma = 0.03 * Lch::<f32>::max_chroma();
lch.clamp_assign();
Srgba::from_color(lch)
} else {
res
}
}

/// get text color given a base background color
pub fn get_text(
base_index: usize,
step_array: &Vec<Srgba>,
step_array: &[Srgba],
fallback: &Srgba,
tint_array: Option<&Vec<Srgba>>,
tint_array: Option<&[Srgba]>,
) -> Srgba {
assert!(step_array.len() == 100);
let step_array = if let Some(tint_array) = tint_array {
Expand Down
2 changes: 1 addition & 1 deletion iced
Submodule iced updated 1 files
+34 −1 widget/src/text_editor.rs
Loading