Support additive colors in color picker
This commit is contained in:
parent
5c8df6925d
commit
10a23d18e1
17 changed files with 239 additions and 106 deletions
|
@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
### Changed 🔧
|
### Changed 🔧
|
||||||
|
|
||||||
* Renamed `Srgba` to `Color32`.
|
* Renamed `Srgba` to `Color32`.
|
||||||
|
* All color contructions now starts with `from_`, e.g. `Color32::from_rgb`.
|
||||||
* Renamed `FontFamily::VariableWidth` to `FontFamily::Proportional`.
|
* Renamed `FontFamily::VariableWidth` to `FontFamily::Proportional`.
|
||||||
* Removed `pixels_per_point` from `FontDefinitions`.
|
* Removed `pixels_per_point` from `FontDefinitions`.
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ impl Frame {
|
||||||
Self {
|
Self {
|
||||||
margin: Vec2::new(10.0, 10.0),
|
margin: Vec2::new(10.0, 10.0),
|
||||||
corner_radius: 5.0,
|
corner_radius: 5.0,
|
||||||
fill: Color32::black_alpha(250),
|
fill: Color32::from_black_alpha(250),
|
||||||
stroke: style.visuals.widgets.noninteractive.bg_stroke,
|
stroke: style.visuals.widgets.noninteractive.bg_stroke,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,19 +70,19 @@ impl Color32 {
|
||||||
Self([r, g, b, a])
|
Self([r, g, b, a])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn gray(l: u8) -> Self {
|
pub const fn from_gray(l: u8) -> Self {
|
||||||
Self([l, l, l, 255])
|
Self([l, l, l, 255])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn black_alpha(a: u8) -> Self {
|
pub const fn from_black_alpha(a: u8) -> Self {
|
||||||
Self([0, 0, 0, a])
|
Self([0, 0, 0, a])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn white_alpha(a: u8) -> Self {
|
pub fn from_white_alpha(a: u8) -> Self {
|
||||||
Rgba::white_alpha(linear_from_alpha_byte(a)).into()
|
Rgba::from_white_alpha(linear_from_alpha_byte(a)).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn additive_luminance(l: u8) -> Self {
|
pub const fn from_additive_luminance(l: u8) -> Self {
|
||||||
Self([l, l, l, 0])
|
Self([l, l, l, 0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,43 +138,49 @@ impl std::ops::IndexMut<usize> for Rgba {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rgba {
|
impl Rgba {
|
||||||
pub const TRANSPARENT: Rgba = Rgba::new(0.0, 0.0, 0.0, 0.0);
|
pub const TRANSPARENT: Rgba = Rgba::from_rgba_premultiplied(0.0, 0.0, 0.0, 0.0);
|
||||||
pub const BLACK: Rgba = Rgba::new(0.0, 0.0, 0.0, 1.0);
|
pub const BLACK: Rgba = Rgba::from_rgb(0.0, 0.0, 0.0);
|
||||||
pub const WHITE: Rgba = Rgba::new(1.0, 1.0, 1.0, 1.0);
|
pub const WHITE: Rgba = Rgba::from_rgb(1.0, 1.0, 1.0);
|
||||||
pub const RED: Rgba = Rgba::new(1.0, 0.0, 0.0, 1.0);
|
pub const RED: Rgba = Rgba::from_rgb(1.0, 0.0, 0.0);
|
||||||
pub const GREEN: Rgba = Rgba::new(0.0, 1.0, 0.0, 1.0);
|
pub const GREEN: Rgba = Rgba::from_rgb(0.0, 1.0, 0.0);
|
||||||
pub const BLUE: Rgba = Rgba::new(0.0, 0.0, 1.0, 1.0);
|
pub const BLUE: Rgba = Rgba::from_rgb(0.0, 0.0, 1.0);
|
||||||
|
|
||||||
pub const fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
|
pub const fn from_rgba_premultiplied(r: f32, g: f32, b: f32, a: f32) -> Self {
|
||||||
Self([r, g, b, a])
|
Self([r, g, b, a])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn rgb(r: f32, g: f32, b: f32) -> Self {
|
pub const fn from_rgb(r: f32, g: f32, b: f32) -> Self {
|
||||||
Self([r, g, b, 1.0])
|
Self([r, g, b, 1.0])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn gray(l: f32) -> Self {
|
pub const fn from_gray(l: f32) -> Self {
|
||||||
Self([l, l, l, 1.0])
|
Self([l, l, l, 1.0])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn luminance_alpha(l: f32, a: f32) -> Self {
|
pub fn from_luminance_alpha(l: f32, a: f32) -> Self {
|
||||||
debug_assert!(0.0 <= l && l <= 1.0);
|
debug_assert!(0.0 <= l && l <= 1.0);
|
||||||
debug_assert!(0.0 <= a && a <= 1.0);
|
debug_assert!(0.0 <= a && a <= 1.0);
|
||||||
Self([l * a, l * a, l * a, a])
|
Self([l * a, l * a, l * a, a])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transparent black
|
/// Transparent black
|
||||||
pub fn black_alpha(a: f32) -> Self {
|
pub fn from_black_alpha(a: f32) -> Self {
|
||||||
debug_assert!(0.0 <= a && a <= 1.0);
|
debug_assert!(0.0 <= a && a <= 1.0);
|
||||||
Self([0.0, 0.0, 0.0, a])
|
Self([0.0, 0.0, 0.0, a])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transparent white
|
/// Transparent white
|
||||||
pub fn white_alpha(a: f32) -> Self {
|
pub fn from_white_alpha(a: f32) -> Self {
|
||||||
debug_assert!(0.0 <= a && a <= 1.0);
|
debug_assert!(0.0 <= a && a <= 1.0);
|
||||||
Self([a, a, a, a])
|
Self([a, a, a, a])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return an additive version of this color (alpha = 0)
|
||||||
|
pub fn additive(self) -> Self {
|
||||||
|
let [r, g, b, _] = self.0;
|
||||||
|
Self([r, g, b, 0.0])
|
||||||
|
}
|
||||||
|
|
||||||
/// Multiply with e.g. 0.5 to make us half transparent
|
/// Multiply with e.g. 0.5 to make us half transparent
|
||||||
pub fn multiply(self, alpha: f32) -> Self {
|
pub fn multiply(self, alpha: f32) -> Self {
|
||||||
Self([
|
Self([
|
||||||
|
@ -206,11 +212,11 @@ impl Rgba {
|
||||||
/// Returns an opaque version of self
|
/// Returns an opaque version of self
|
||||||
pub fn to_opaque(&self) -> Self {
|
pub fn to_opaque(&self) -> Self {
|
||||||
if self.a() == 0.0 {
|
if self.a() == 0.0 {
|
||||||
// additive or fully transparent
|
// Additive or fully transparent black.
|
||||||
Self::new(self.r(), self.g(), self.b(), 1.0)
|
Self::from_rgba_premultiplied(self.r(), self.g(), self.b(), 1.0)
|
||||||
} else {
|
} else {
|
||||||
// un-multiply alpha
|
// un-multiply alpha:
|
||||||
Self::new(
|
Self::from_rgba_premultiplied(
|
||||||
self.r() / self.a(),
|
self.r() / self.a(),
|
||||||
self.g() / self.a(),
|
self.g() / self.a(),
|
||||||
self.b() / self.a(),
|
self.b() / self.a(),
|
||||||
|
@ -345,7 +351,7 @@ pub struct Hsva {
|
||||||
pub s: f32,
|
pub s: f32,
|
||||||
/// value 0-1
|
/// value 0-1
|
||||||
pub v: f32,
|
pub v: f32,
|
||||||
/// alpha 0-1
|
/// alpha 0-1. A negative value signifies an additive color (and alpha is ignored).
|
||||||
pub a: f32,
|
pub a: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,33 +381,79 @@ impl Hsva {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// From linear RGBA with premultiplied alpha
|
/// From linear RGBA with premultiplied alpha
|
||||||
pub fn from_rgba_premultiplied(rgba: [f32; 4]) -> Self {
|
pub fn from_rgba_premultiplied([r, g, b, a]: [f32; 4]) -> Self {
|
||||||
#![allow(clippy::many_single_char_names)]
|
#![allow(clippy::many_single_char_names)]
|
||||||
let [r, g, b, a] = rgba;
|
|
||||||
if a == 0.0 {
|
if a == 0.0 {
|
||||||
Hsva::default()
|
if r == 0.0 && b == 0.0 && a == 0.0 {
|
||||||
|
Hsva::default()
|
||||||
|
} else {
|
||||||
|
Hsva::from_additive_rgb([r, g, b])
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let (h, s, v) = hsv_from_rgb((r / a, g / a, b / a));
|
let (h, s, v) = hsv_from_rgb([r / a, g / a, b / a]);
|
||||||
Hsva { h, s, v, a }
|
Hsva { h, s, v, a }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// From linear RGBA without premultiplied alpha
|
/// From linear RGBA without premultiplied alpha
|
||||||
pub fn from_rgba_unmultiplied(rgba: [f32; 4]) -> Self {
|
pub fn from_rgba_unmultiplied([r, g, b, a]: [f32; 4]) -> Self {
|
||||||
#![allow(clippy::many_single_char_names)]
|
#![allow(clippy::many_single_char_names)]
|
||||||
let [r, g, b, a] = rgba;
|
let (h, s, v) = hsv_from_rgb([r, g, b]);
|
||||||
let (h, s, v) = hsv_from_rgb((r, g, b));
|
|
||||||
Hsva { h, s, v, a }
|
Hsva { h, s, v, a }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_additive_rgb(rgb: [f32; 3]) -> Self {
|
||||||
|
let (h, s, v) = hsv_from_rgb(rgb);
|
||||||
|
Hsva {
|
||||||
|
h,
|
||||||
|
s,
|
||||||
|
v,
|
||||||
|
a: -0.5, // anything negative is treated as additive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_rgb(rgb: [f32; 3]) -> Self {
|
||||||
|
let (h, s, v) = hsv_from_rgb(rgb);
|
||||||
|
Hsva { h, s, v, a: 1.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_srgb([r, g, b]: [u8; 3]) -> Self {
|
||||||
|
Self::from_rgb([
|
||||||
|
linear_from_gamma_byte(r),
|
||||||
|
linear_from_gamma_byte(g),
|
||||||
|
linear_from_gamma_byte(b),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
pub fn to_rgb(&self) -> [f32; 3] {
|
||||||
|
rgb_from_hsv((self.h, self.s, self.v))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_srgb(&self) -> [u8; 3] {
|
||||||
|
let [r, g, b] = self.to_rgb();
|
||||||
|
[
|
||||||
|
gamma_byte_from_linear(r),
|
||||||
|
gamma_byte_from_linear(g),
|
||||||
|
gamma_byte_from_linear(b),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_rgba_premultiplied(&self) -> [f32; 4] {
|
pub fn to_rgba_premultiplied(&self) -> [f32; 4] {
|
||||||
let [r, g, b, a] = self.to_rgba_unmultiplied();
|
let [r, g, b, a] = self.to_rgba_unmultiplied();
|
||||||
[a * r, a * g, a * b, a]
|
let additive = a < 0.0;
|
||||||
|
if additive {
|
||||||
|
[r, g, b, 0.0]
|
||||||
|
} else {
|
||||||
|
[a * r, a * g, a * b, a]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents additive colors using a negative alpha.
|
||||||
pub fn to_rgba_unmultiplied(&self) -> [f32; 4] {
|
pub fn to_rgba_unmultiplied(&self) -> [f32; 4] {
|
||||||
let Hsva { h, s, v, a } = *self;
|
let Hsva { h, s, v, a } = *self;
|
||||||
let (r, g, b) = rgb_from_hsv((h, s, v));
|
let [r, g, b] = rgb_from_hsv((h, s, v));
|
||||||
[r, g, b, a]
|
[r, g, b, a]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,7 +473,7 @@ impl Hsva {
|
||||||
gamma_byte_from_linear(r),
|
gamma_byte_from_linear(r),
|
||||||
gamma_byte_from_linear(g),
|
gamma_byte_from_linear(g),
|
||||||
gamma_byte_from_linear(b),
|
gamma_byte_from_linear(b),
|
||||||
alpha_byte_from_linear(a),
|
alpha_byte_from_linear(a.abs()),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -449,7 +501,7 @@ impl From<Color32> for Hsva {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All ranges in 0-1, rgb is linear.
|
/// All ranges in 0-1, rgb is linear.
|
||||||
pub fn hsv_from_rgb((r, g, b): (f32, f32, f32)) -> (f32, f32, f32) {
|
pub fn hsv_from_rgb([r, g, b]: [f32; 3]) -> (f32, f32, f32) {
|
||||||
#![allow(clippy::float_cmp)]
|
#![allow(clippy::float_cmp)]
|
||||||
#![allow(clippy::many_single_char_names)]
|
#![allow(clippy::many_single_char_names)]
|
||||||
let min = r.min(g.min(b));
|
let min = r.min(g.min(b));
|
||||||
|
@ -473,7 +525,7 @@ pub fn hsv_from_rgb((r, g, b): (f32, f32, f32)) -> (f32, f32, f32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All ranges in 0-1, rgb is linear.
|
/// All ranges in 0-1, rgb is linear.
|
||||||
pub fn rgb_from_hsv((h, s, v): (f32, f32, f32)) -> (f32, f32, f32) {
|
pub fn rgb_from_hsv((h, s, v): (f32, f32, f32)) -> [f32; 3] {
|
||||||
#![allow(clippy::many_single_char_names)]
|
#![allow(clippy::many_single_char_names)]
|
||||||
let h = (h.fract() + 1.0).fract(); // wrap
|
let h = (h.fract() + 1.0).fract(); // wrap
|
||||||
let s = clamp(s, 0.0..=1.0);
|
let s = clamp(s, 0.0..=1.0);
|
||||||
|
@ -484,12 +536,12 @@ pub fn rgb_from_hsv((h, s, v): (f32, f32, f32)) -> (f32, f32, f32) {
|
||||||
let t = v * (1.0 - (1.0 - f) * s);
|
let t = v * (1.0 - (1.0 - f) * s);
|
||||||
|
|
||||||
match (h * 6.0).floor() as i32 % 6 {
|
match (h * 6.0).floor() as i32 % 6 {
|
||||||
0 => (v, t, p),
|
0 => [v, t, p],
|
||||||
1 => (q, v, p),
|
1 => [q, v, p],
|
||||||
2 => (p, v, t),
|
2 => [p, v, t],
|
||||||
3 => (p, q, v),
|
3 => [p, q, v],
|
||||||
4 => (t, p, v),
|
4 => [t, p, v],
|
||||||
5 => (v, p, q),
|
5 => [v, p, q],
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ impl Shadow {
|
||||||
pub fn small() -> Self {
|
pub fn small() -> Self {
|
||||||
Self {
|
Self {
|
||||||
extrusion: 8.0,
|
extrusion: 8.0,
|
||||||
color: Color32::black_alpha(64),
|
color: Color32::from_black_alpha(64),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ impl Shadow {
|
||||||
pub fn big() -> Self {
|
pub fn big() -> Self {
|
||||||
Self {
|
Self {
|
||||||
extrusion: 32.0,
|
extrusion: 32.0,
|
||||||
color: Color32::black_alpha(96),
|
color: Color32::from_black_alpha(96),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ pub struct Texture {
|
||||||
pub version: u64,
|
pub version: u64,
|
||||||
pub width: usize,
|
pub width: usize,
|
||||||
pub height: usize,
|
pub height: usize,
|
||||||
/// luminance and alpha, linear space 0-255
|
/// White color with the given alpha (linear space 0-255).
|
||||||
pub pixels: Vec<u8>,
|
pub pixels: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,8 @@ impl Texture {
|
||||||
/// Returns the textures as `sRGBA` premultiplied pixels, row by row, top to bottom.
|
/// Returns the textures as `sRGBA` premultiplied pixels, row by row, top to bottom.
|
||||||
pub fn srgba_pixels(&'_ self) -> impl Iterator<Item = super::Color32> + '_ {
|
pub fn srgba_pixels(&'_ self) -> impl Iterator<Item = super::Color32> + '_ {
|
||||||
use super::Color32;
|
use super::Color32;
|
||||||
let srgba_from_luminance_lut: Vec<Color32> = (0..=255).map(Color32::white_alpha).collect();
|
let srgba_from_luminance_lut: Vec<Color32> =
|
||||||
|
(0..=255).map(Color32::from_white_alpha).collect();
|
||||||
self.pixels
|
self.pixels
|
||||||
.iter()
|
.iter()
|
||||||
.map(move |&l| srgba_from_luminance_lut[l as usize])
|
.map(move |&l| srgba_from_luminance_lut[l as usize])
|
||||||
|
@ -47,7 +48,7 @@ impl std::ops::IndexMut<(usize, usize)> for Texture {
|
||||||
pub struct TextureAtlas {
|
pub struct TextureAtlas {
|
||||||
texture: Texture,
|
texture: Texture,
|
||||||
|
|
||||||
/// Used for when adding new rects
|
/// Used for when allocating new rectangles.
|
||||||
cursor: (usize, usize),
|
cursor: (usize, usize),
|
||||||
row_height: usize,
|
row_height: usize,
|
||||||
}
|
}
|
||||||
|
@ -78,7 +79,7 @@ impl TextureAtlas {
|
||||||
pub fn allocate(&mut self, (w, h): (usize, usize)) -> (usize, usize) {
|
pub fn allocate(&mut self, (w, h): (usize, usize)) -> (usize, usize) {
|
||||||
/// On some low-precision GPUs (my old iPad) characters get muddled up
|
/// On some low-precision GPUs (my old iPad) characters get muddled up
|
||||||
/// if we don't add some empty pixels between the characters.
|
/// if we don't add some empty pixels between the characters.
|
||||||
/// On modern high-precision GPUs this is not be needed.
|
/// On modern high-precision GPUs this is not needed.
|
||||||
const PADDING: usize = 1;
|
const PADDING: usize = 1;
|
||||||
|
|
||||||
assert!(w <= self.texture.width);
|
assert!(w <= self.texture.width);
|
||||||
|
|
|
@ -147,7 +147,7 @@ impl Painter {
|
||||||
self.add(PaintCmd::Rect {
|
self.add(PaintCmd::Rect {
|
||||||
rect: frame_rect,
|
rect: frame_rect,
|
||||||
corner_radius: 0.0,
|
corner_radius: 0.0,
|
||||||
fill: Color32::black_alpha(240),
|
fill: Color32::from_black_alpha(240),
|
||||||
stroke: Stroke::new(1.0, Color32::RED),
|
stroke: Stroke::new(1.0, Color32::RED),
|
||||||
});
|
});
|
||||||
self.galley(rect.min, galley, text_style, Color32::RED);
|
self.galley(rect.min, galley, text_style, Color32::RED);
|
||||||
|
|
|
@ -279,7 +279,7 @@ impl Default for Visuals {
|
||||||
override_text_color: None,
|
override_text_color: None,
|
||||||
widgets: Default::default(),
|
widgets: Default::default(),
|
||||||
selection: Default::default(),
|
selection: Default::default(),
|
||||||
dark_bg_color: Color32::black_alpha(140),
|
dark_bg_color: Color32::from_black_alpha(140),
|
||||||
hyperlink_color: Color32::from_rgb(90, 170, 255),
|
hyperlink_color: Color32::from_rgb(90, 170, 255),
|
||||||
window_corner_radius: 10.0,
|
window_corner_radius: 10.0,
|
||||||
window_shadow: Shadow::big(),
|
window_shadow: Shadow::big(),
|
||||||
|
@ -296,8 +296,11 @@ impl Default for Visuals {
|
||||||
impl Default for Selection {
|
impl Default for Selection {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
bg_fill: Rgba::new(0.0, 0.5, 1.0, 0.0).multiply(0.15).into(), // additive!
|
bg_fill: Rgba::from_rgb(0.0, 0.5, 1.0)
|
||||||
stroke: Stroke::new(1.0, Rgba::new(0.3, 0.6, 1.0, 1.0)),
|
.additive()
|
||||||
|
.multiply(0.10)
|
||||||
|
.into(),
|
||||||
|
stroke: Stroke::new(1.0, Rgba::from_rgb(0.3, 0.6, 1.0)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -306,39 +309,39 @@ impl Default for Widgets {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
active: WidgetVisuals {
|
active: WidgetVisuals {
|
||||||
bg_fill: Rgba::luminance_alpha(0.10, 0.5).into(),
|
bg_fill: Rgba::from_luminance_alpha(0.10, 0.5).into(),
|
||||||
bg_stroke: Stroke::new(2.0, Color32::WHITE),
|
bg_stroke: Stroke::new(2.0, Color32::WHITE),
|
||||||
corner_radius: 4.0,
|
corner_radius: 4.0,
|
||||||
fg_fill: Color32::from_rgb(120, 120, 200),
|
fg_fill: Color32::from_rgb(120, 120, 200),
|
||||||
fg_stroke: Stroke::new(2.0, Color32::WHITE),
|
fg_stroke: Stroke::new(2.0, Color32::WHITE),
|
||||||
},
|
},
|
||||||
hovered: WidgetVisuals {
|
hovered: WidgetVisuals {
|
||||||
bg_fill: Rgba::luminance_alpha(0.06, 0.5).into(),
|
bg_fill: Rgba::from_luminance_alpha(0.06, 0.5).into(),
|
||||||
bg_stroke: Stroke::new(1.0, Rgba::white_alpha(0.5)),
|
bg_stroke: Stroke::new(1.0, Rgba::from_white_alpha(0.5)),
|
||||||
corner_radius: 4.0,
|
corner_radius: 4.0,
|
||||||
fg_fill: Color32::from_rgb(100, 100, 150),
|
fg_fill: Color32::from_rgb(100, 100, 150),
|
||||||
fg_stroke: Stroke::new(1.5, Color32::gray(240)),
|
fg_stroke: Stroke::new(1.5, Color32::from_gray(240)),
|
||||||
},
|
},
|
||||||
inactive: WidgetVisuals {
|
inactive: WidgetVisuals {
|
||||||
bg_fill: Rgba::luminance_alpha(0.04, 0.5).into(),
|
bg_fill: Rgba::from_luminance_alpha(0.04, 0.5).into(),
|
||||||
bg_stroke: Stroke::new(1.0, Rgba::white_alpha(0.06)), // default window outline. Should be pretty readable
|
bg_stroke: Stroke::new(1.0, Rgba::from_white_alpha(0.06)), // default window outline. Should be pretty readable
|
||||||
corner_radius: 4.0,
|
corner_radius: 4.0,
|
||||||
fg_fill: Color32::from_rgb(60, 60, 80),
|
fg_fill: Color32::from_rgb(60, 60, 80),
|
||||||
fg_stroke: Stroke::new(1.0, Color32::gray(200)), // Should NOT look grayed out!
|
fg_stroke: Stroke::new(1.0, Color32::from_gray(200)), // Should NOT look grayed out!
|
||||||
},
|
},
|
||||||
disabled: WidgetVisuals {
|
disabled: WidgetVisuals {
|
||||||
bg_fill: Rgba::luminance_alpha(0.02, 0.5).into(),
|
bg_fill: Rgba::from_luminance_alpha(0.02, 0.5).into(),
|
||||||
bg_stroke: Stroke::new(0.5, Color32::gray(70)),
|
bg_stroke: Stroke::new(0.5, Color32::from_gray(70)),
|
||||||
corner_radius: 4.0,
|
corner_radius: 4.0,
|
||||||
fg_fill: Color32::from_rgb(50, 50, 50),
|
fg_fill: Color32::from_rgb(50, 50, 50),
|
||||||
fg_stroke: Stroke::new(1.0, Color32::gray(140)), // Should look grayed out
|
fg_stroke: Stroke::new(1.0, Color32::from_gray(140)), // Should look grayed out
|
||||||
},
|
},
|
||||||
noninteractive: WidgetVisuals {
|
noninteractive: WidgetVisuals {
|
||||||
bg_stroke: Stroke::new(1.0, Rgba::white_alpha(0.06)),
|
bg_stroke: Stroke::new(1.0, Rgba::from_white_alpha(0.06)),
|
||||||
bg_fill: Rgba::luminance_alpha(0.010, 0.975).into(), // window background
|
bg_fill: Rgba::from_luminance_alpha(0.010, 0.975).into(), // window background
|
||||||
corner_radius: 4.0,
|
corner_radius: 4.0,
|
||||||
fg_fill: Default::default(),
|
fg_fill: Default::default(),
|
||||||
fg_stroke: Stroke::new(1.0, Color32::gray(160)), // text color
|
fg_stroke: Stroke::new(1.0, Color32::from_gray(160)), // text color
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -814,13 +814,35 @@ impl Ui {
|
||||||
/// Shows a button with the given color.
|
/// Shows a button with the given color.
|
||||||
/// If the user clicks the button, a full color picker is shown.
|
/// If the user clicks the button, a full color picker is shown.
|
||||||
pub fn color_edit_button_srgba(&mut self, srgba: &mut Color32) -> Response {
|
pub fn color_edit_button_srgba(&mut self, srgba: &mut Color32) -> Response {
|
||||||
widgets::color_picker::color_edit_button_srgba(self, srgba)
|
color_picker::color_edit_button_srgba(self, srgba, color_picker::Alpha::BlendOrAdditive)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shows a button with the given color.
|
/// Shows a button with the given color.
|
||||||
/// If the user clicks the button, a full color picker is shown.
|
/// If the user clicks the button, a full color picker is shown.
|
||||||
pub fn color_edit_button_hsva(&mut self, hsva: &mut Hsva) -> Response {
|
pub fn color_edit_button_hsva(&mut self, hsva: &mut Hsva) -> Response {
|
||||||
widgets::color_picker::color_edit_button_hsva(self, hsva)
|
color_picker::color_edit_button_hsva(self, hsva, color_picker::Alpha::BlendOrAdditive)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shows a button with the given color.
|
||||||
|
/// If the user clicks the button, a full color picker is shown.
|
||||||
|
/// The given color is in `sRGB` space.
|
||||||
|
pub fn color_edit_button_srgb(&mut self, srgb: &mut [u8; 3]) -> Response {
|
||||||
|
let mut hsva = Hsva::from_srgb(*srgb);
|
||||||
|
let response =
|
||||||
|
color_picker::color_edit_button_hsva(self, &mut hsva, color_picker::Alpha::Opaque);
|
||||||
|
*srgb = hsva.to_srgb();
|
||||||
|
response
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shows a button with the given color.
|
||||||
|
/// If the user clicks the button, a full color picker is shown.
|
||||||
|
/// The given color is in linear RGB space.
|
||||||
|
pub fn color_edit_button_rgb(&mut self, rgb: &mut [f32; 3]) -> Response {
|
||||||
|
let mut hsva = Hsva::from_rgb(*rgb);
|
||||||
|
let response =
|
||||||
|
color_picker::color_edit_button_hsva(self, &mut hsva, color_picker::Alpha::Opaque);
|
||||||
|
*rgb = hsva.to_rgb();
|
||||||
|
response
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shows a button with the given color.
|
/// Shows a button with the given color.
|
||||||
|
@ -839,7 +861,8 @@ impl Ui {
|
||||||
/// If unsure, what "premultiplied alpha" is, then this is probably the function you want to use.
|
/// If unsure, what "premultiplied alpha" is, then this is probably the function you want to use.
|
||||||
pub fn color_edit_button_srgba_unmultiplied(&mut self, srgba: &mut [u8; 4]) -> Response {
|
pub fn color_edit_button_srgba_unmultiplied(&mut self, srgba: &mut [u8; 4]) -> Response {
|
||||||
let mut hsva = Hsva::from_srgba_unmultiplied(*srgba);
|
let mut hsva = Hsva::from_srgba_unmultiplied(*srgba);
|
||||||
let response = self.color_edit_button_hsva(&mut hsva);
|
let response =
|
||||||
|
color_picker::color_edit_button_hsva(self, &mut hsva, color_picker::Alpha::OnlyBlend);
|
||||||
*srgba = hsva.to_srgba_unmultiplied();
|
*srgba = hsva.to_srgba_unmultiplied();
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
|
@ -849,7 +872,11 @@ impl Ui {
|
||||||
/// The given color is in linear RGBA space with premultiplied alpha
|
/// The given color is in linear RGBA space with premultiplied alpha
|
||||||
pub fn color_edit_button_rgba_premultiplied(&mut self, rgba: &mut [f32; 4]) -> Response {
|
pub fn color_edit_button_rgba_premultiplied(&mut self, rgba: &mut [f32; 4]) -> Response {
|
||||||
let mut hsva = Hsva::from_rgba_premultiplied(*rgba);
|
let mut hsva = Hsva::from_rgba_premultiplied(*rgba);
|
||||||
let response = self.color_edit_button_hsva(&mut hsva);
|
let response = color_picker::color_edit_button_hsva(
|
||||||
|
self,
|
||||||
|
&mut hsva,
|
||||||
|
color_picker::Alpha::BlendOrAdditive,
|
||||||
|
);
|
||||||
*rgba = hsva.to_rgba_premultiplied();
|
*rgba = hsva.to_rgba_premultiplied();
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
|
@ -860,7 +887,8 @@ impl Ui {
|
||||||
/// If unsure, what "premultiplied alpha" is, then this is probably the function you want to use.
|
/// If unsure, what "premultiplied alpha" is, then this is probably the function you want to use.
|
||||||
pub fn color_edit_button_rgba_unmultiplied(&mut self, rgba: &mut [f32; 4]) -> Response {
|
pub fn color_edit_button_rgba_unmultiplied(&mut self, rgba: &mut [f32; 4]) -> Response {
|
||||||
let mut hsva = Hsva::from_rgba_unmultiplied(*rgba);
|
let mut hsva = Hsva::from_rgba_unmultiplied(*rgba);
|
||||||
let response = self.color_edit_button_hsva(&mut hsva);
|
let response =
|
||||||
|
color_picker::color_edit_button_hsva(self, &mut hsva, color_picker::Alpha::OnlyBlend);
|
||||||
*rgba = hsva.to_rgba_unmultiplied();
|
*rgba = hsva.to_rgba_unmultiplied();
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,11 +16,11 @@ fn contrast_color(color: impl Into<Rgba>) -> Color32 {
|
||||||
/// Number of vertices per dimension in the color sliders.
|
/// Number of vertices per dimension in the color sliders.
|
||||||
/// We need at least 6 for hues, and more for smooth 2D areas.
|
/// We need at least 6 for hues, and more for smooth 2D areas.
|
||||||
/// Should always be a multiple of 6 to hit the peak hues in HSV/HSL (every 60°).
|
/// Should always be a multiple of 6 to hit the peak hues in HSV/HSL (every 60°).
|
||||||
const N: u32 = 6 * 3;
|
const N: u32 = 6 * 6;
|
||||||
|
|
||||||
fn background_checkers(painter: &Painter, rect: Rect) {
|
fn background_checkers(painter: &Painter, rect: Rect) {
|
||||||
let mut top_color = Color32::gray(128);
|
let mut top_color = Color32::from_gray(128);
|
||||||
let mut bottom_color = Color32::gray(32);
|
let mut bottom_color = Color32::from_gray(32);
|
||||||
let checker_size = Vec2::splat(rect.height() / 2.0);
|
let checker_size = Vec2::splat(rect.height() / 2.0);
|
||||||
let n = (rect.width() / checker_size.x).round() as u32;
|
let n = (rect.width() / checker_size.x).round() as u32;
|
||||||
|
|
||||||
|
@ -184,20 +184,68 @@ fn color_slider_2d(
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
|
|
||||||
fn color_picker_hsvag_2d(ui: &mut Ui, hsva: &mut HsvaGamma) {
|
/// What options to show for alpha
|
||||||
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
|
pub enum Alpha {
|
||||||
|
// Set alpha to 1.0, and show no option for it.
|
||||||
|
Opaque,
|
||||||
|
// Only show normal blend options for it.
|
||||||
|
OnlyBlend,
|
||||||
|
// Show both blend and additive options.
|
||||||
|
BlendOrAdditive,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn color_picker_hsvag_2d(ui: &mut Ui, hsva: &mut HsvaGamma, alpha: Alpha) {
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
let current_color_size = vec2(
|
let current_color_size = vec2(
|
||||||
ui.style().spacing.slider_width,
|
ui.style().spacing.slider_width,
|
||||||
ui.style().spacing.interact_size.y * 2.0,
|
ui.style().spacing.interact_size.y * 2.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
show_color(ui, *hsva, current_color_size).on_hover_text("Current color");
|
|
||||||
|
|
||||||
show_color(ui, HsvaGamma { a: 1.0, ..*hsva }, current_color_size)
|
|
||||||
.on_hover_text("Current color (opaque)");
|
|
||||||
|
|
||||||
let opaque = HsvaGamma { a: 1.0, ..*hsva };
|
let opaque = HsvaGamma { a: 1.0, ..*hsva };
|
||||||
let HsvaGamma { h, s, v, a } = hsva;
|
|
||||||
|
if alpha == Alpha::Opaque {
|
||||||
|
hsva.a = 1.0;
|
||||||
|
show_color(ui, *hsva, current_color_size).on_hover_text("Current color");
|
||||||
|
} else {
|
||||||
|
let a = &mut hsva.a;
|
||||||
|
|
||||||
|
// We signal additive blending by storing a negative alpha (a bit ironic).
|
||||||
|
let mut additive = *a < 0.0;
|
||||||
|
|
||||||
|
if alpha == Alpha::OnlyBlend {
|
||||||
|
if additive {
|
||||||
|
*a = 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
color_slider_1d(ui, a, |a| HsvaGamma { a, ..opaque }.into()).on_hover_text("Alpha");
|
||||||
|
} else {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label("Blending:");
|
||||||
|
ui.radio_value(&mut additive, false, "Normal");
|
||||||
|
ui.radio_value(&mut additive, true, "Additive");
|
||||||
|
|
||||||
|
if additive {
|
||||||
|
*a = -a.abs();
|
||||||
|
}
|
||||||
|
|
||||||
|
if !additive {
|
||||||
|
*a = a.abs();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if !additive {
|
||||||
|
color_slider_1d(ui, a, |a| HsvaGamma { a, ..opaque }.into())
|
||||||
|
.on_hover_text("Alpha");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
show_color(ui, *hsva, current_color_size).on_hover_text("Current color");
|
||||||
|
show_color(ui, opaque, current_color_size).on_hover_text("Current color (opaque)");
|
||||||
|
}
|
||||||
|
|
||||||
|
let HsvaGamma { h, s, v, a: _ } = hsva;
|
||||||
|
|
||||||
color_slider_2d(ui, h, s, |h, s| HsvaGamma::new(h, s, 1.0, 1.0).into())
|
color_slider_2d(ui, h, s, |h, s| HsvaGamma::new(h, s, 1.0, 1.0).into())
|
||||||
.on_hover_text("Hue - Saturation");
|
.on_hover_text("Hue - Saturation");
|
||||||
color_slider_2d(ui, v, s, |v, s| HsvaGamma { v, s, ..opaque }.into())
|
color_slider_2d(ui, v, s, |v, s| HsvaGamma { v, s, ..opaque }.into())
|
||||||
|
@ -205,17 +253,16 @@ fn color_picker_hsvag_2d(ui: &mut Ui, hsva: &mut HsvaGamma) {
|
||||||
color_slider_1d(ui, h, |h| HsvaGamma { h, ..opaque }.into()).on_hover_text("Hue");
|
color_slider_1d(ui, h, |h| HsvaGamma { h, ..opaque }.into()).on_hover_text("Hue");
|
||||||
color_slider_1d(ui, s, |s| HsvaGamma { s, ..opaque }.into()).on_hover_text("Saturation");
|
color_slider_1d(ui, s, |s| HsvaGamma { s, ..opaque }.into()).on_hover_text("Saturation");
|
||||||
color_slider_1d(ui, v, |v| HsvaGamma { v, ..opaque }.into()).on_hover_text("Value");
|
color_slider_1d(ui, v, |v| HsvaGamma { v, ..opaque }.into()).on_hover_text("Value");
|
||||||
color_slider_1d(ui, a, |a| HsvaGamma { a, ..opaque }.into()).on_hover_text("Alpha");
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn color_picker_hsva_2d(ui: &mut Ui, hsva: &mut Hsva) {
|
fn color_picker_hsva_2d(ui: &mut Ui, hsva: &mut Hsva, alpha: Alpha) {
|
||||||
let mut hsvag = HsvaGamma::from(*hsva);
|
let mut hsvag = HsvaGamma::from(*hsva);
|
||||||
color_picker_hsvag_2d(ui, &mut hsvag);
|
color_picker_hsvag_2d(ui, &mut hsvag, alpha);
|
||||||
*hsva = Hsva::from(hsvag);
|
*hsva = Hsva::from(hsvag);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn color_edit_button_hsva(ui: &mut Ui, hsva: &mut Hsva) -> Response {
|
pub fn color_edit_button_hsva(ui: &mut Ui, hsva: &mut Hsva, alpha: Alpha) -> Response {
|
||||||
let pupup_id = ui.auto_id_with("popup");
|
let pupup_id = ui.auto_id_with("popup");
|
||||||
let button_response = color_button(ui, (*hsva).into()).on_hover_text("Click to edit color");
|
let button_response = color_button(ui, (*hsva).into()).on_hover_text("Click to edit color");
|
||||||
|
|
||||||
|
@ -228,8 +275,9 @@ pub fn color_edit_button_hsva(ui: &mut Ui, hsva: &mut Hsva) -> Response {
|
||||||
.order(Order::Foreground)
|
.order(Order::Foreground)
|
||||||
.default_pos(button_response.rect.max)
|
.default_pos(button_response.rect.max)
|
||||||
.show(ui.ctx(), |ui| {
|
.show(ui.ctx(), |ui| {
|
||||||
|
ui.style_mut().spacing.slider_width = 256.0;
|
||||||
Frame::popup(ui.style()).show(ui, |ui| {
|
Frame::popup(ui.style()).show(ui, |ui| {
|
||||||
color_picker_hsva_2d(ui, hsva);
|
color_picker_hsva_2d(ui, hsva, alpha);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -246,7 +294,7 @@ pub fn color_edit_button_hsva(ui: &mut Ui, hsva: &mut Hsva) -> Response {
|
||||||
|
|
||||||
/// Shows a button with the given color.
|
/// Shows a button with the given color.
|
||||||
/// If the user clicks the button, a full color picker is shown.
|
/// If the user clicks the button, a full color picker is shown.
|
||||||
pub fn color_edit_button_srgba(ui: &mut Ui, srgba: &mut Color32) -> Response {
|
pub fn color_edit_button_srgba(ui: &mut Ui, srgba: &mut Color32, alpha: Alpha) -> Response {
|
||||||
// To ensure we keep hue slider when `srgba` is grey we store the
|
// To ensure we keep hue slider when `srgba` is grey we store the
|
||||||
// full `Hsva` in a cache:
|
// full `Hsva` in a cache:
|
||||||
|
|
||||||
|
@ -258,7 +306,7 @@ pub fn color_edit_button_srgba(ui: &mut Ui, srgba: &mut Color32) -> Response {
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or_else(|| Hsva::from(*srgba));
|
.unwrap_or_else(|| Hsva::from(*srgba));
|
||||||
|
|
||||||
let response = color_edit_button_hsva(ui, &mut hsva);
|
let response = color_edit_button_hsva(ui, &mut hsva, alpha);
|
||||||
|
|
||||||
*srgba = Color32::from(hsva);
|
*srgba = Color32::from(hsva);
|
||||||
|
|
||||||
|
@ -279,7 +327,7 @@ struct HsvaGamma {
|
||||||
pub s: f32,
|
pub s: f32,
|
||||||
/// value 0-1, in gamma-space (perceptually even)
|
/// value 0-1, in gamma-space (perceptually even)
|
||||||
pub v: f32,
|
pub v: f32,
|
||||||
/// alpha 0-1
|
/// alpha 0-1. A negative value signifies an additive color (and alpha is ignored).
|
||||||
pub a: f32,
|
pub a: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,8 +39,9 @@ impl epi::App for ColorTest {
|
||||||
if frame.is_web() {
|
if frame.is_web() {
|
||||||
ui.colored_label(
|
ui.colored_label(
|
||||||
RED,
|
RED,
|
||||||
"NOTE: The current WebGL backend does NOT pass the color test!",
|
"NOTE: The WebGL backend does NOT pass the color test."
|
||||||
);
|
);
|
||||||
|
ui.small("This is because WebGL does not support a linear framebuffer blending (not even WebGL2!).\nMaybe when WebGL3 becomes mainstream in 2030 the web can finally get colors right?");
|
||||||
ui.separator();
|
ui.separator();
|
||||||
}
|
}
|
||||||
ScrollArea::auto_sized().show(ui, |ui| {
|
ScrollArea::auto_sized().show(ui, |ui| {
|
||||||
|
@ -56,8 +57,7 @@ impl ColorTest {
|
||||||
ui: &mut Ui,
|
ui: &mut Ui,
|
||||||
mut tex_allocator: &mut Option<&mut dyn epi::TextureAllocator>,
|
mut tex_allocator: &mut Option<&mut dyn epi::TextureAllocator>,
|
||||||
) {
|
) {
|
||||||
ui.label("This is made to test if your Egui painter backend is set up correctly");
|
ui.label("This is made to test that the Egui painter backend is set up correctly, so that all colors are interpolated and blended in linear space with premultiplied alpha.");
|
||||||
ui.label("It is meant to ensure you do proper sRGBA decoding of both texture and vertex colors, and blend using premultiplied alpha.");
|
|
||||||
ui.label("If everything is set up correctly, all groups of gradients will look uniform");
|
ui.label("If everything is set up correctly, all groups of gradients will look uniform");
|
||||||
|
|
||||||
ui.checkbox(&mut self.vertex_gradients, "Vertex gradients");
|
ui.checkbox(&mut self.vertex_gradients, "Vertex gradients");
|
||||||
|
@ -85,8 +85,8 @@ impl ColorTest {
|
||||||
ui.wrap(|ui| {
|
ui.wrap(|ui| {
|
||||||
ui.style_mut().spacing.item_spacing.y = 0.0; // No spacing between gradients
|
ui.style_mut().spacing.item_spacing.y = 0.0; // No spacing between gradients
|
||||||
|
|
||||||
let tex_color = Rgba::new(1.0, 0.25, 0.25, 1.0);
|
let tex_color = Rgba::from_rgb(1.0, 0.25, 0.25);
|
||||||
let vertex_color = Rgba::new(0.5, 0.75, 0.75, 1.0);
|
let vertex_color = Rgba::from_rgb(0.5, 0.75, 0.75);
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let color_size = ui.style().spacing.interact_size;
|
let color_size = ui.style().spacing.interact_size;
|
||||||
|
|
|
@ -57,7 +57,7 @@ impl super::View for DancingStrings {
|
||||||
let thickness = 10.0 / mode;
|
let thickness = 10.0 / mode;
|
||||||
cmds.push(paint::PaintCmd::line(
|
cmds.push(paint::PaintCmd::line(
|
||||||
points,
|
points,
|
||||||
Stroke::new(thickness, Color32::additive_luminance(196)),
|
Stroke::new(thickness, Color32::from_additive_luminance(196)),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,7 @@ impl DemoWindow {
|
||||||
let painter = ui.painter();
|
let painter = ui.painter();
|
||||||
let c = response.rect.center();
|
let c = response.rect.center();
|
||||||
let r = response.rect.width() / 2.0 - 1.0;
|
let r = response.rect.width() / 2.0 - 1.0;
|
||||||
let color = Color32::gray(128);
|
let color = Color32::from_gray(128);
|
||||||
let stroke = Stroke::new(1.0, color);
|
let stroke = Stroke::new(1.0, color);
|
||||||
painter.circle_stroke(c, r, stroke);
|
painter.circle_stroke(c, r, stroke);
|
||||||
painter.line_segment([c - vec2(0.0, r), c + vec2(0.0, r)], stroke);
|
painter.line_segment([c - vec2(0.0, r), c + vec2(0.0, r)], stroke);
|
||||||
|
@ -210,7 +210,7 @@ impl BoxPainting {
|
||||||
ui.painter().rect(
|
ui.painter().rect(
|
||||||
response.rect,
|
response.rect,
|
||||||
self.corner_radius,
|
self.corner_radius,
|
||||||
Color32::gray(64),
|
Color32::from_gray(64),
|
||||||
Stroke::new(self.stroke_width, Color32::WHITE),
|
Stroke::new(self.stroke_width, Color32::WHITE),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,8 +40,8 @@ pub fn toggle(ui: &mut egui::Ui, on: &mut bool) -> egui::Response {
|
||||||
// "how should something that is being interacted with be painted?".
|
// "how should something that is being interacted with be painted?".
|
||||||
// This will, for instance, give us different colors when the widget is hovered or clicked.
|
// This will, for instance, give us different colors when the widget is hovered or clicked.
|
||||||
let visuals = ui.style().interact(&response);
|
let visuals = ui.style().interact(&response);
|
||||||
let off_bg_fill = egui::Rgba::new(0.0, 0.0, 0.0, 0.0);
|
let off_bg_fill = egui::Rgba::TRANSPARENT;
|
||||||
let on_bg_fill = egui::Rgba::new(0.0, 0.5, 0.25, 1.0);
|
let on_bg_fill = egui::Rgba::from_rgb(0.0, 0.5, 0.25);
|
||||||
let bg_fill = egui::lerp(off_bg_fill..=on_bg_fill, how_on);
|
let bg_fill = egui::lerp(off_bg_fill..=on_bg_fill, how_on);
|
||||||
// All coordinates are in absolute screen coordinates so we use `rect` to place the elements.
|
// All coordinates are in absolute screen coordinates so we use `rect` to place the elements.
|
||||||
let rect = response.rect;
|
let rect = response.rect;
|
||||||
|
@ -67,8 +67,8 @@ fn toggle_compact(ui: &mut egui::Ui, on: &mut bool) -> egui::Response {
|
||||||
|
|
||||||
let how_on = ui.ctx().animate_bool(response.id, *on);
|
let how_on = ui.ctx().animate_bool(response.id, *on);
|
||||||
let visuals = ui.style().interact(&response);
|
let visuals = ui.style().interact(&response);
|
||||||
let off_bg_fill = egui::Rgba::new(0.0, 0.0, 0.0, 0.0);
|
let off_bg_fill = egui::Rgba::TRANSPARENT;
|
||||||
let on_bg_fill = egui::Rgba::new(0.0, 0.5, 0.25, 1.0);
|
let on_bg_fill = egui::Rgba::from_rgb(0.0, 0.5, 0.25);
|
||||||
let bg_fill = egui::lerp(off_bg_fill..=on_bg_fill, how_on);
|
let bg_fill = egui::lerp(off_bg_fill..=on_bg_fill, how_on);
|
||||||
let rect = response.rect;
|
let rect = response.rect;
|
||||||
let radius = 0.5 * rect.height();
|
let radius = 0.5 * rect.height();
|
||||||
|
|
|
@ -35,7 +35,7 @@ impl Default for Widgets {
|
||||||
count: 0,
|
count: 0,
|
||||||
sliders: Default::default(),
|
sliders: Default::default(),
|
||||||
angle: std::f32::consts::TAU / 3.0,
|
angle: std::f32::consts::TAU / 3.0,
|
||||||
color: (Rgba::new(0.0, 1.0, 0.5, 1.0) * 0.75).into(),
|
color: (Rgba::from_rgb(0.0, 1.0, 0.5) * 0.75).into(),
|
||||||
single_line_text_input: "Hello World!".to_owned(),
|
single_line_text_input: "Hello World!".to_owned(),
|
||||||
multiline_text_input: "Text can both be so wide that it needs a line break, but you can also add manual line break by pressing enter, creating new paragraphs.\nThis is the start of the next paragraph.\n\nClick me to edit me!".to_owned(),
|
multiline_text_input: "Text can both be so wide that it needs a line break, but you can also add manual line break by pressing enter, creating new paragraphs.\nThis is the start of the next paragraph.\n\nClick me to edit me!".to_owned(),
|
||||||
toggle_switch: false,
|
toggle_switch: false,
|
||||||
|
|
|
@ -58,7 +58,7 @@ impl FractalClock {
|
||||||
ui.expand_to_include_rect(painter.clip_rect());
|
ui.expand_to_include_rect(painter.clip_rect());
|
||||||
|
|
||||||
Frame::popup(ui.style())
|
Frame::popup(ui.style())
|
||||||
.fill(Rgba::luminance_alpha(0.02, 0.5).into())
|
.fill(Rgba::from_luminance_alpha(0.02, 0.5).into())
|
||||||
.stroke(Stroke::none())
|
.stroke(Stroke::none())
|
||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
ui.set_max_width(270.0);
|
ui.set_max_width(270.0);
|
||||||
|
@ -160,7 +160,7 @@ impl FractalClock {
|
||||||
for (i, hand) in hands.iter().enumerate() {
|
for (i, hand) in hands.iter().enumerate() {
|
||||||
let center = pos2(0.0, 0.0);
|
let center = pos2(0.0, 0.0);
|
||||||
let end = center + hand.vec;
|
let end = center + hand.vec;
|
||||||
paint_line([center, end], Color32::additive_luminance(255), width);
|
paint_line([center, end], Color32::from_additive_luminance(255), width);
|
||||||
if i < 2 {
|
if i < 2 {
|
||||||
nodes.push(Node {
|
nodes.push(Node {
|
||||||
pos: end,
|
pos: end,
|
||||||
|
@ -190,7 +190,7 @@ impl FractalClock {
|
||||||
};
|
};
|
||||||
paint_line(
|
paint_line(
|
||||||
[a.pos, b.pos],
|
[a.pos, b.pos],
|
||||||
Color32::additive_luminance(luminance_u8),
|
Color32::from_additive_luminance(luminance_u8),
|
||||||
width,
|
width,
|
||||||
);
|
);
|
||||||
new_nodes.push(b);
|
new_nodes.push(b);
|
||||||
|
|
|
@ -78,7 +78,7 @@ impl FrameHistory {
|
||||||
}];
|
}];
|
||||||
|
|
||||||
let rect = rect.shrink(4.0);
|
let rect = rect.shrink(4.0);
|
||||||
let line_stroke = Stroke::new(1.0, Color32::additive_luminance(128));
|
let line_stroke = Stroke::new(1.0, Color32::from_additive_luminance(128));
|
||||||
|
|
||||||
if let Some(mouse_pos) = ui.input().mouse.pos {
|
if let Some(mouse_pos) = ui.input().mouse.pos {
|
||||||
if rect.contains(mouse_pos) {
|
if rect.contains(mouse_pos) {
|
||||||
|
@ -100,7 +100,7 @@ impl FrameHistory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let circle_color = Color32::additive_luminance(196);
|
let circle_color = Color32::from_additive_luminance(196);
|
||||||
let radius = 2.0;
|
let radius = 2.0;
|
||||||
let right_side_time = ui.input().time; // Time at right side of screen
|
let right_side_time = ui.input().time; // Time at right side of screen
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,7 @@ impl Painter {
|
||||||
.chunks(texture.width as usize)
|
.chunks(texture.width as usize)
|
||||||
.map(|row| {
|
.map(|row| {
|
||||||
row.iter()
|
row.iter()
|
||||||
.map(|&a| Color32::white_alpha(a).to_tuple())
|
.map(|&a| Color32::from_white_alpha(a).to_tuple())
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
Loading…
Reference in a new issue