Skip to content

Commit eb21125

Browse files
authored
Merge branch 'iced-rs:master' into master
2 parents 62a1fd1 + 9d56b48 commit eb21125

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+668
-582
lines changed

.github/workflows/test.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
strategy:
1010
matrix:
1111
os: [ubuntu-latest, windows-latest, macOS-latest]
12-
rust: [stable, beta, "1.85"]
12+
rust: [stable, beta, "1.88"]
1313
steps:
1414
- uses: hecrj/setup-rust-action@v2
1515
with:
@@ -23,5 +23,7 @@ jobs:
2323
sudo apt-get install -y libxkbcommon-dev libgtk-3-dev
2424
- name: Run tests
2525
run: |
26+
cargo test --verbose --workspace
2627
cargo test --verbose --workspace -- --ignored
28+
cargo test --verbose --workspace --all-features
2729
cargo test --verbose --workspace --all-features -- --ignored

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ all-features = true
2222
maintenance = { status = "actively-developed" }
2323

2424
[features]
25-
default = ["wgpu", "tiny-skia", "web-colors", "auto-detect-theme", "thread-pool"]
25+
default = ["wgpu", "tiny-skia", "crisp", "web-colors", "auto-detect-theme", "thread-pool"]
2626
# Enables the `wgpu` GPU-accelerated renderer backend
2727
wgpu = ["iced_renderer/wgpu", "iced_widget/wgpu"]
2828
# Enables the `tiny-skia` software renderer backend
@@ -145,7 +145,7 @@ repository = "https://github.com/iced-rs/iced"
145145
homepage = "https://iced.rs"
146146
categories = ["gui"]
147147
keywords = ["gui", "ui", "graphics", "interface", "widgets"]
148-
rust-version = "1.85"
148+
rust-version = "1.88"
149149

150150
[workspace.dependencies]
151151
iced = { version = "0.14.0-dev", path = "." }

core/src/color.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,12 @@ impl Color {
9090
}
9191
}
9292

93-
Self {
94-
r: gamma_component(r),
95-
g: gamma_component(g),
96-
b: gamma_component(b),
93+
Self::new(
94+
gamma_component(r),
95+
gamma_component(g),
96+
gamma_component(b),
9797
a,
98-
}
98+
)
9999
}
100100

101101
/// Parses a [`Color`] from a hex string.
@@ -195,6 +195,13 @@ impl Color {
195195
..self
196196
}
197197
}
198+
199+
/// Returns the relative luminance of the [`Color`].
200+
/// https://www.w3.org/TR/WCAG21/#dfn-relative-luminance
201+
pub fn relative_luminance(self) -> f32 {
202+
let linear = self.into_linear();
203+
0.2126 * linear[0] + 0.7152 * linear[1] + 0.0722 * linear[2]
204+
}
198205
}
199206

200207
impl From<[f32; 3]> for Color {

core/src/theme/palette.rs

Lines changed: 99 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ impl Palette {
2828
text: Color::BLACK,
2929
primary: color!(0x5865F2),
3030
success: color!(0x12664f),
31-
warning: color!(0xffc14e),
31+
warning: color!(0xb77e33),
3232
danger: color!(0xc3423f),
3333
};
3434

@@ -453,9 +453,15 @@ pub struct Background {
453453
/// The weakest version of the base background color.
454454
pub weakest: Pair,
455455
/// A weaker version of the base background color.
456+
pub weaker: Pair,
457+
/// A weak version of the base background color.
456458
pub weak: Pair,
457-
/// A stronger version of the base background color.
459+
/// A neutral version of the base background color, between weak and strong.
460+
pub neutral: Pair,
461+
/// A strong version of the base background color.
458462
pub strong: Pair,
463+
/// A stronger version of the base background color.
464+
pub stronger: Pair,
459465
/// The strongest version of the base background color.
460466
pub strongest: Pair,
461467
}
@@ -464,15 +470,21 @@ impl Background {
464470
/// Generates a set of [`Background`] colors from the base and text colors.
465471
pub fn new(base: Color, text: Color) -> Self {
466472
let weakest = deviate(base, 0.03);
467-
let weak = muted(deviate(base, 0.1));
468-
let strong = muted(deviate(base, 0.2));
469-
let strongest = muted(deviate(base, 0.3));
473+
let weaker = deviate(base, 0.07);
474+
let weak = deviate(base, 0.1);
475+
let neutral = deviate(base, 0.125);
476+
let strong = deviate(base, 0.15);
477+
let stronger = deviate(base, 0.175);
478+
let strongest = deviate(base, 0.20);
470479

471480
Self {
472481
base: Pair::new(base, text),
473482
weakest: Pair::new(weakest, text),
483+
weaker: Pair::new(weaker, text),
474484
weak: Pair::new(weak, text),
485+
neutral: Pair::new(neutral, text),
475486
strong: Pair::new(strong, text),
487+
stronger: Pair::new(stronger, text),
476488
strongest: Pair::new(strongest, text),
477489
}
478490
}
@@ -517,9 +529,11 @@ pub struct Secondary {
517529
impl Secondary {
518530
/// Generates a set of [`Secondary`] colors from the base and text colors.
519531
pub fn generate(base: Color, text: Color) -> Self {
520-
let base = mix(base, text, 0.2);
521-
let weak = mix(base, text, 0.1);
522-
let strong = mix(base, text, 0.3);
532+
let factor = if is_dark(base) { 0.2 } else { 0.4 };
533+
534+
let weak = mix(deviate(base, 0.1), text, factor);
535+
let strong = mix(deviate(base, 0.3), text, factor);
536+
let base = mix(deviate(base, 0.2), text, factor);
523537

524538
Self {
525539
base: Pair::new(base, text),
@@ -604,53 +618,55 @@ impl Danger {
604618
}
605619
}
606620

607-
struct Hsl {
608-
h: f32,
609-
s: f32,
621+
struct Oklch {
610622
l: f32,
623+
c: f32,
624+
h: f32,
611625
a: f32,
612626
}
613627

614628
fn darken(color: Color, amount: f32) -> Color {
615-
let mut hsl = to_hsl(color);
629+
let mut oklch = to_oklch(color);
630+
631+
// We try to bump the chroma a bit for more colorful palettes
632+
if oklch.c > 0.0 && oklch.c < (1.0 - oklch.l) / 2.0 {
633+
// Formula empirically and cluelessly derived
634+
oklch.c *= 1.0 + (0.2 / oklch.c).min(100.0) * amount;
635+
}
616636

617-
hsl.l = if hsl.l - amount < 0.0 {
637+
oklch.l = if oklch.l - amount < 0.0 {
618638
0.0
619639
} else {
620-
hsl.l - amount
640+
oklch.l - amount
621641
};
622642

623-
from_hsl(hsl)
643+
from_oklch(oklch)
624644
}
625645

626646
fn lighten(color: Color, amount: f32) -> Color {
627-
let mut hsl = to_hsl(color);
647+
let mut oklch = to_oklch(color);
648+
649+
// We try to bump the chroma a bit for more colorful palettes
650+
// Formula empirically and cluelessly derived
651+
oklch.c *= 1.0 + 2.0 * amount / oklch.l.max(0.05);
628652

629-
hsl.l = if hsl.l + amount > 1.0 {
653+
oklch.l = if oklch.l + amount > 1.0 {
630654
1.0
631655
} else {
632-
hsl.l + amount
656+
oklch.l + amount
633657
};
634658

635-
from_hsl(hsl)
659+
from_oklch(oklch)
636660
}
637661

638662
fn deviate(color: Color, amount: f32) -> Color {
639663
if is_dark(color) {
640664
lighten(color, amount)
641665
} else {
642-
darken(color, amount * 0.8)
666+
darken(color, amount)
643667
}
644668
}
645669

646-
fn muted(color: Color) -> Color {
647-
let mut hsl = to_hsl(color);
648-
649-
hsl.s = hsl.s.min(0.5);
650-
651-
from_hsl(hsl)
652-
}
653-
654670
fn mix(a: Color, b: Color, factor: f32) -> Color {
655671
let b_amount = factor.clamp(0.0, 1.0);
656672
let a_amount = 1.0 - b_amount;
@@ -680,6 +696,12 @@ fn readable(background: Color, text: Color) -> Color {
680696
return candidate;
681697
}
682698

699+
let candidate = improve(text, 0.2);
700+
701+
if is_readable(background, candidate) {
702+
return candidate;
703+
}
704+
683705
let white_contrast = relative_contrast(background, Color::WHITE);
684706
let black_contrast = relative_contrast(background, Color::BLACK);
685707

@@ -691,85 +713,71 @@ fn readable(background: Color, text: Color) -> Color {
691713
}
692714

693715
fn is_dark(color: Color) -> bool {
694-
to_hsl(color).l < 0.6
716+
to_oklch(color).l < 0.6
695717
}
696718

697719
fn is_readable(a: Color, b: Color) -> bool {
698-
relative_contrast(a, b) >= 7.0
720+
relative_contrast(a, b) >= 6.0
699721
}
700722

701723
// https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio
702724
fn relative_contrast(a: Color, b: Color) -> f32 {
703-
let lum_a = relative_luminance(a);
704-
let lum_b = relative_luminance(b);
725+
let lum_a = a.relative_luminance();
726+
let lum_b = b.relative_luminance();
705727
(lum_a.max(lum_b) + 0.05) / (lum_a.min(lum_b) + 0.05)
706728
}
707729

708-
// https://www.w3.org/TR/WCAG21/#dfn-relative-luminance
709-
fn relative_luminance(color: Color) -> f32 {
710-
let linear = color.into_linear();
711-
0.2126 * linear[0] + 0.7152 * linear[1] + 0.0722 * linear[2]
712-
}
730+
// https://en.wikipedia.org/wiki/Oklab_color_space#Conversions_between_color_spaces
731+
fn to_oklch(color: Color) -> Oklch {
732+
let [r, g, b, alpha] = color.into_linear();
713733

714-
// https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB
715-
fn to_hsl(color: Color) -> Hsl {
716-
let x_max = color.r.max(color.g).max(color.b);
717-
let x_min = color.r.min(color.g).min(color.b);
718-
let c = x_max - x_min;
719-
let l = x_max.midpoint(x_min);
734+
// linear RGB → LMS
735+
let l = 0.41222146 * r + 0.53633255 * g + 0.051445995 * b;
736+
let m = 0.2119035 * r + 0.6806995 * g + 0.10739696 * b;
737+
let s = 0.08830246 * r + 0.28171885 * g + 0.6299787 * b;
720738

721-
let h = if c == 0.0 {
722-
0.0
723-
} else if x_max == color.r {
724-
60.0 * ((color.g - color.b) / c).rem_euclid(6.0)
725-
} else if x_max == color.g {
726-
60.0 * (((color.b - color.r) / c) + 2.0)
727-
} else {
728-
// x_max == color.b
729-
60.0 * (((color.r - color.g) / c) + 4.0)
730-
};
739+
// Nonlinear transform (cube root)
740+
let l_ = l.cbrt();
741+
let m_ = m.cbrt();
742+
let s_ = s.cbrt();
731743

732-
let s = if l == 0.0 || l == 1.0 {
733-
0.0
734-
} else {
735-
(x_max - l) / l.min(1.0 - l)
736-
};
744+
// LMS → Oklab
745+
let l = 0.21045426 * l_ + 0.7936178 * m_ - 0.004072047 * s_;
746+
let a = 1.9779985 * l_ - 2.4285922 * m_ + 0.4505937 * s_;
747+
let b = 0.025904037 * l_ + 0.78277177 * m_ - 0.80867577 * s_;
737748

738-
Hsl {
739-
h,
740-
s,
741-
l,
742-
a: color.a,
743-
}
749+
// Oklab → Oklch
750+
let c = (a * a + b * b).sqrt();
751+
let h = b.atan2(a); // radians
752+
753+
Oklch { l, c, h, a: alpha }
744754
}
745755

746-
// https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB
747-
fn from_hsl(hsl: Hsl) -> Color {
748-
let c = (1.0 - (2.0 * hsl.l - 1.0).abs()) * hsl.s;
749-
let h = hsl.h / 60.0;
750-
let x = c * (1.0 - (h.rem_euclid(2.0) - 1.0).abs());
751-
752-
let (r1, g1, b1) = if h < 1.0 {
753-
(c, x, 0.0)
754-
} else if h < 2.0 {
755-
(x, c, 0.0)
756-
} else if h < 3.0 {
757-
(0.0, c, x)
758-
} else if h < 4.0 {
759-
(0.0, x, c)
760-
} else if h < 5.0 {
761-
(x, 0.0, c)
762-
} else {
763-
// h < 6.0
764-
(c, 0.0, x)
765-
};
756+
// https://en.wikipedia.org/wiki/Oklab_color_space#Conversions_between_color_spaces
757+
fn from_oklch(oklch: Oklch) -> Color {
758+
let Oklch { l, c, h, a: alpha } = oklch;
766759

767-
let m = hsl.l - (c / 2.0);
760+
let a = c * h.cos();
761+
let b = c * h.sin();
768762

769-
Color {
770-
r: r1 + m,
771-
g: g1 + m,
772-
b: b1 + m,
773-
a: hsl.a,
774-
}
763+
// Oklab → LMS (nonlinear)
764+
let l_ = l + 0.39633778 * a + 0.21580376 * b;
765+
let m_ = l - 0.105561346 * a - 0.06385417 * b;
766+
let s_ = l - 0.08948418 * a - 1.2914855 * b;
767+
768+
// Cubing back
769+
let l = l_ * l_ * l_;
770+
let m = m_ * m_ * m_;
771+
let s = s_ * s_ * s_;
772+
773+
let r = 4.0767417 * l - 3.3077116 * m + 0.23096994 * s;
774+
let g = -1.268438 * l + 2.6097574 * m - 0.34131938 * s;
775+
let b = -0.0041960863 * l - 0.7034186 * m + 1.7076147 * s;
776+
777+
Color::from_linear_rgba(
778+
r.clamp(0.0, 1.0),
779+
g.clamp(0.0, 1.0),
780+
b.clamp(0.0, 1.0),
781+
alpha,
782+
)
775783
}

core/src/widget/text.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ pub fn primary(theme: &Theme) -> Style {
441441
/// Text conveying some secondary information, like a footnote.
442442
pub fn secondary(theme: &Theme) -> Style {
443443
Style {
444-
color: Some(theme.extended_palette().secondary.strong.color),
444+
color: Some(theme.extended_palette().secondary.base.color),
445445
}
446446
}
447447

examples/editor/src/main.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,10 @@ impl Editor {
119119

120120
let mut text = self.content.text();
121121

122-
if let Some(ending) = self.content.line_ending() {
123-
if !text.ends_with(ending.as_str()) {
124-
text.push_str(ending.as_str());
125-
}
122+
if let Some(ending) = self.content.line_ending()
123+
&& !text.ends_with(ending.as_str())
124+
{
125+
text.push_str(ending.as_str());
126126
}
127127

128128
Task::perform(

examples/gallery/src/civitai.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ impl Image {
2929
.get("https://civitai.com/api/v1/images")
3030
.query(&[
3131
("sort", "Most Reactions"),
32-
("period", "Week"),
32+
("period", "Month"),
3333
("nsfw", "None"),
3434
("limit", &Image::LIMIT.to_string()),
3535
])

0 commit comments

Comments
 (0)