Use Rgba (4xf32) instead of Color32 in all interfaces

This simplifies a few things, but some benchmarks gets worse,
probably due to the increased memory use (and thus more cache misses).

I don't plan to merge this, but leave it here as an experiment
This commit is contained in:
Emil Ernerfeldt 2021-08-15 20:15:14 +02:00
parent 96c45716be
commit 5dd68337c4
42 changed files with 285 additions and 371 deletions

View file

@ -11,7 +11,7 @@ pub struct Frame {
pub margin: Vec2, pub margin: Vec2,
pub corner_radius: f32, pub corner_radius: f32,
pub shadow: Shadow, pub shadow: Shadow,
pub fill: Color32, pub fill: Rgba,
pub stroke: Stroke, pub stroke: Stroke,
} }
@ -85,7 +85,7 @@ impl Frame {
Self { Self {
margin: Vec2::new(10.0, 10.0), margin: Vec2::new(10.0, 10.0),
corner_radius: style.visuals.widgets.noninteractive.corner_radius, corner_radius: style.visuals.widgets.noninteractive.corner_radius,
fill: Color32::from_black_alpha(250), fill: Color32::from_black_alpha(250).into(),
stroke: style.visuals.window_stroke(), stroke: style.visuals.window_stroke(),
..Default::default() ..Default::default()
} }
@ -93,7 +93,7 @@ impl Frame {
} }
impl Frame { impl Frame {
pub fn fill(mut self, fill: Color32) -> Self { pub fn fill(mut self, fill: Rgba) -> Self {
self.fill = fill; self.fill = fill;
self self
} }
@ -120,9 +120,9 @@ impl Frame {
} }
pub fn multiply_with_opacity(mut self, opacity: f32) -> Self { pub fn multiply_with_opacity(mut self, opacity: f32) -> Self {
self.fill = self.fill.linear_multiply(opacity); self.fill = self.fill * opacity;
self.stroke.color = self.stroke.color.linear_multiply(opacity); self.stroke.color = self.stroke.color * opacity;
self.shadow.color = self.shadow.color.linear_multiply(opacity); self.shadow.color = self.shadow.color * opacity;
self self
} }
} }

View file

@ -303,12 +303,12 @@ impl Resize {
if ui.ctx().style().debug.show_resize { if ui.ctx().style().debug.show_resize {
ui.ctx().debug_painter().debug_rect( ui.ctx().debug_painter().debug_rect(
Rect::from_min_size(content_ui.min_rect().left_top(), state.desired_size), Rect::from_min_size(content_ui.min_rect().left_top(), state.desired_size),
Color32::GREEN, Rgba::GREEN,
"desired_size", "desired_size",
); );
ui.ctx().debug_painter().debug_rect( ui.ctx().debug_painter().debug_rect(
Rect::from_min_size(content_ui.min_rect().left_top(), state.last_content_size), Rect::from_min_size(content_ui.min_rect().left_top(), state.last_content_size),
Color32::LIGHT_BLUE, Rgba::LIGHT_BLUE,
"last_content_size", "last_content_size",
); );
} }

View file

@ -888,7 +888,7 @@ impl Context {
{ {
ui.ctx() ui.ctx()
.debug_painter() .debug_painter()
.debug_rect(area.rect(), Color32::RED, ""); .debug_rect(area.rect(), Rgba::RED, "");
} }
} }
} }

View file

@ -20,11 +20,7 @@ impl Widget for &epaint::Texture {
} }
let (rect, response) = ui.allocate_at_least(size, Sense::hover()); let (rect, response) = ui.allocate_at_least(size, Sense::hover());
let mut mesh = Mesh::default(); let mut mesh = Mesh::default();
mesh.add_rect_with_uv( mesh.add_rect_with_uv(rect, [pos2(0.0, 0.0), pos2(1.0, 1.0)].into(), Rgba::WHITE);
rect,
[pos2(0.0, 0.0), pos2(1.0, 1.0)].into(),
Color32::WHITE,
);
ui.painter().add(Shape::mesh(mesh)); ui.painter().add(Shape::mesh(mesh));
let (tex_w, tex_h) = (self.width as f32, self.height as f32); let (tex_w, tex_h) = (self.width as f32, self.height as f32);
@ -46,7 +42,7 @@ impl Widget for &epaint::Texture {
pos2((u + texel_radius) / tex_w, (v + texel_radius) / tex_h), pos2((u + texel_radius) / tex_w, (v + texel_radius) / tex_h),
); );
let mut mesh = Mesh::default(); let mut mesh = Mesh::default();
mesh.add_rect_with_uv(zoom_rect, uv_rect, Color32::WHITE); mesh.add_rect_with_uv(zoom_rect, uv_rect, Rgba::WHITE);
ui.painter().add(Shape::mesh(mesh)); ui.painter().add(Shape::mesh(mesh));
} }
}); });

View file

@ -43,11 +43,11 @@ pub fn bar<R>(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResp
ui.horizontal(|ui| { ui.horizontal(|ui| {
let mut style = (**ui.style()).clone(); let mut style = (**ui.style()).clone();
style.spacing.button_padding = vec2(2.0, 0.0); style.spacing.button_padding = vec2(2.0, 0.0);
// style.visuals.widgets.active.bg_fill = Color32::TRANSPARENT; // style.visuals.widgets.active.bg_fill = Rgba::TRANSPARENT;
style.visuals.widgets.active.bg_stroke = Stroke::none(); style.visuals.widgets.active.bg_stroke = Stroke::none();
// style.visuals.widgets.hovered.bg_fill = Color32::TRANSPARENT; // style.visuals.widgets.hovered.bg_fill = Rgba::TRANSPARENT;
style.visuals.widgets.hovered.bg_stroke = Stroke::none(); style.visuals.widgets.hovered.bg_stroke = Stroke::none();
style.visuals.widgets.inactive.bg_fill = Color32::TRANSPARENT; style.visuals.widgets.inactive.bg_fill = Rgba::TRANSPARENT;
style.visuals.widgets.inactive.bg_stroke = Stroke::none(); style.visuals.widgets.inactive.bg_stroke = Stroke::none();
ui.set_style(style); ui.set_style(style);
@ -114,11 +114,11 @@ fn menu_impl<'c, R>(
.show(ui, |ui| { .show(ui, |ui| {
let mut style = (**ui.style()).clone(); let mut style = (**ui.style()).clone();
style.spacing.button_padding = vec2(2.0, 0.0); style.spacing.button_padding = vec2(2.0, 0.0);
// style.visuals.widgets.active.bg_fill = Color32::TRANSPARENT; // style.visuals.widgets.active.bg_fill = Rgba::TRANSPARENT;
style.visuals.widgets.active.bg_stroke = Stroke::none(); style.visuals.widgets.active.bg_stroke = Stroke::none();
// style.visuals.widgets.hovered.bg_fill = Color32::TRANSPARENT; // style.visuals.widgets.hovered.bg_fill = Rgba::TRANSPARENT;
style.visuals.widgets.hovered.bg_stroke = Stroke::none(); style.visuals.widgets.hovered.bg_stroke = Stroke::none();
style.visuals.widgets.inactive.bg_fill = Color32::TRANSPARENT; style.visuals.widgets.inactive.bg_fill = Rgba::TRANSPARENT;
style.visuals.widgets.inactive.bg_stroke = Stroke::none(); style.visuals.widgets.inactive.bg_stroke = Stroke::none();
ui.set_style(style); ui.set_style(style);
ui.with_layout(Layout::top_down_justified(Align::LEFT), add_contents) ui.with_layout(Layout::top_down_justified(Align::LEFT), add_contents)

View file

@ -1,7 +1,7 @@
use crate::{ use crate::{
emath::{Align2, Pos2, Rect, Vec2}, emath::{Align2, Pos2, Rect, Vec2},
layers::{LayerId, PaintList, ShapeIdx}, layers::{LayerId, PaintList, ShapeIdx},
Color32, CtxRef, Color32, CtxRef, Rgba,
}; };
use epaint::{ use epaint::{
mutex::Mutex, mutex::Mutex,
@ -28,7 +28,7 @@ pub struct Painter {
/// If set, all shapes will have their colors modified to be closer to this. /// If set, all shapes will have their colors modified to be closer to this.
/// This is used to implement grayed out interfaces. /// This is used to implement grayed out interfaces.
fade_to_color: Option<Color32>, fade_to_color: Option<Rgba>,
} }
impl Painter { impl Painter {
@ -62,17 +62,17 @@ impl Painter {
} }
/// If set, colors will be modified to look like this /// If set, colors will be modified to look like this
pub(crate) fn set_fade_to_color(&mut self, fade_to_color: Option<Color32>) { pub(crate) fn set_fade_to_color(&mut self, fade_to_color: Option<Rgba>) {
self.fade_to_color = fade_to_color; self.fade_to_color = fade_to_color;
} }
pub(crate) fn visible(&self) -> bool { pub(crate) fn visible(&self) -> bool {
self.fade_to_color != Some(Color32::TRANSPARENT) self.fade_to_color != Some(Rgba::TRANSPARENT)
} }
/// If `false`, nothing added to the painter will be visible /// If `false`, nothing added to the painter will be visible
pub(crate) fn set_invisible(&mut self) { pub(crate) fn set_invisible(&mut self) {
self.fade_to_color = Some(Color32::TRANSPARENT) self.fade_to_color = Some(Rgba::TRANSPARENT)
} }
/// Create a painter for a sub-region of this `Painter`. /// Create a painter for a sub-region of this `Painter`.
@ -155,7 +155,7 @@ impl Painter {
/// Can be used for free painting. /// Can be used for free painting.
/// NOTE: all coordinates are screen coordinates! /// NOTE: all coordinates are screen coordinates!
pub fn add(&self, mut shape: Shape) -> ShapeIdx { pub fn add(&self, mut shape: Shape) -> ShapeIdx {
if self.fade_to_color == Some(Color32::TRANSPARENT) { if self.fade_to_color == Some(Rgba::TRANSPARENT) {
self.paint_list.lock().add(self.clip_rect, Shape::Noop) self.paint_list.lock().add(self.clip_rect, Shape::Noop)
} else { } else {
self.transform_shape(&mut shape); self.transform_shape(&mut shape);
@ -167,7 +167,7 @@ impl Painter {
/// ///
/// Calling this once is generally faster than calling [`Self::add`] multiple times. /// Calling this once is generally faster than calling [`Self::add`] multiple times.
pub fn extend(&self, mut shapes: Vec<Shape>) { pub fn extend(&self, mut shapes: Vec<Shape>) {
if self.fade_to_color == Some(Color32::TRANSPARENT) { if self.fade_to_color == Some(Rgba::TRANSPARENT) {
return; return;
} }
if !shapes.is_empty() { if !shapes.is_empty() {
@ -183,7 +183,7 @@ impl Painter {
/// Modify an existing [`Shape`]. /// Modify an existing [`Shape`].
pub fn set(&self, idx: ShapeIdx, mut shape: Shape) { pub fn set(&self, idx: ShapeIdx, mut shape: Shape) {
if self.fade_to_color == Some(Color32::TRANSPARENT) { if self.fade_to_color == Some(Rgba::TRANSPARENT) {
return; return;
} }
self.transform_shape(&mut shape); self.transform_shape(&mut shape);
@ -194,7 +194,7 @@ impl Painter {
/// ## Debug painting /// ## Debug painting
impl Painter { impl Painter {
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
pub fn debug_rect(&mut self, rect: Rect, color: Color32, text: impl ToString) { pub fn debug_rect(&mut self, rect: Rect, color: Rgba, text: impl ToString) {
self.rect_stroke(rect, 0.0, (1.0, color)); self.rect_stroke(rect, 0.0, (1.0, color));
let text_style = TextStyle::Monospace; let text_style = TextStyle::Monospace;
self.text( self.text(
@ -207,18 +207,12 @@ impl Painter {
} }
pub fn error(&self, pos: Pos2, text: impl std::fmt::Display) -> Rect { pub fn error(&self, pos: Pos2, text: impl std::fmt::Display) -> Rect {
self.debug_text(pos, Align2::LEFT_TOP, Color32::RED, format!("🔥 {}", text)) self.debug_text(pos, Align2::LEFT_TOP, Rgba::RED, format!("🔥 {}", text))
} }
/// text with a background /// text with a background
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
pub fn debug_text( pub fn debug_text(&self, pos: Pos2, anchor: Align2, color: Rgba, text: impl ToString) -> Rect {
&self,
pos: Pos2,
anchor: Align2,
color: Color32,
text: impl ToString,
) -> Rect {
let galley = self let galley = self
.fonts() .fonts()
.layout_no_wrap(TextStyle::Monospace, text.to_string()); .layout_no_wrap(TextStyle::Monospace, text.to_string());
@ -227,7 +221,7 @@ impl Painter {
self.add(Shape::Rect { self.add(Shape::Rect {
rect: frame_rect, rect: frame_rect,
corner_radius: 0.0, corner_radius: 0.0,
fill: Color32::from_black_alpha(240), fill: Color32::from_black_alpha(240).into(),
// stroke: Stroke::new(1.0, color), // stroke: Stroke::new(1.0, color),
stroke: Default::default(), stroke: Default::default(),
}); });
@ -249,7 +243,7 @@ impl Painter {
&self, &self,
center: Pos2, center: Pos2,
radius: f32, radius: f32,
fill_color: impl Into<Color32>, fill_color: impl Into<Rgba>,
stroke: impl Into<Stroke>, stroke: impl Into<Stroke>,
) { ) {
self.add(Shape::Circle { self.add(Shape::Circle {
@ -260,7 +254,7 @@ impl Painter {
}); });
} }
pub fn circle_filled(&self, center: Pos2, radius: f32, fill_color: impl Into<Color32>) { pub fn circle_filled(&self, center: Pos2, radius: f32, fill_color: impl Into<Rgba>) {
self.add(Shape::Circle { self.add(Shape::Circle {
center, center,
radius, radius,
@ -282,7 +276,7 @@ impl Painter {
&self, &self,
rect: Rect, rect: Rect,
corner_radius: f32, corner_radius: f32,
fill_color: impl Into<Color32>, fill_color: impl Into<Rgba>,
stroke: impl Into<Stroke>, stroke: impl Into<Stroke>,
) { ) {
self.add(Shape::Rect { self.add(Shape::Rect {
@ -293,7 +287,7 @@ impl Painter {
}); });
} }
pub fn rect_filled(&self, rect: Rect, corner_radius: f32, fill_color: impl Into<Color32>) { pub fn rect_filled(&self, rect: Rect, corner_radius: f32, fill_color: impl Into<Rgba>) {
self.add(Shape::Rect { self.add(Shape::Rect {
rect, rect,
corner_radius, corner_radius,
@ -341,7 +335,7 @@ impl Painter {
anchor: Align2, anchor: Align2,
text: impl ToString, text: impl ToString,
text_style: TextStyle, text_style: TextStyle,
text_color: Color32, text_color: Rgba,
) -> Rect { ) -> Rect {
let galley = self.layout_no_wrap(text_style, text.to_string()); let galley = self.layout_no_wrap(text_style, text.to_string());
let rect = anchor.anchor_rect(Rect::from_min_size(pos, galley.size)); let rect = anchor.anchor_rect(Rect::from_min_size(pos, galley.size));
@ -377,7 +371,7 @@ impl Painter {
/// ///
/// You can create the `Galley` with [`Self::layout_no_wrap`] or [`Self::layout_multiline`]. /// You can create the `Galley` with [`Self::layout_no_wrap`] or [`Self::layout_multiline`].
#[inline(always)] #[inline(always)]
pub fn galley(&self, pos: Pos2, galley: std::sync::Arc<Galley>, color: Color32) { pub fn galley(&self, pos: Pos2, galley: std::sync::Arc<Galley>, color: Rgba) {
self.galley_with_italics(pos, galley, color, false) self.galley_with_italics(pos, galley, color, false)
} }
@ -385,7 +379,7 @@ impl Painter {
&self, &self,
pos: Pos2, pos: Pos2,
galley: std::sync::Arc<Galley>, galley: std::sync::Arc<Galley>,
color: Color32, color: Rgba,
fake_italics: bool, fake_italics: bool,
) { ) {
if !galley.is_empty() { if !galley.is_empty() {
@ -399,8 +393,8 @@ impl Painter {
} }
} }
fn tint_shape_towards(shape: &mut Shape, target: Color32) { fn tint_shape_towards(shape: &mut Shape, target: Rgba) {
epaint::shape_transform::adjust_colors(shape, &|color| { epaint::shape_transform::adjust_colors(shape, &|color| {
*color = crate::color::tint_color_towards(*color, target); *color = crate::color::tint_rgba_towards(*color, target);
}); });
} }

View file

@ -189,7 +189,7 @@ pub struct Visuals {
/// so that `visuals.text_color` is always used, /// so that `visuals.text_color` is always used,
/// but its alpha may be different based on whether or not /// but its alpha may be different based on whether or not
/// it is disabled, non-interactive, hovered etc. /// it is disabled, non-interactive, hovered etc.
pub override_text_color: Option<Color32>, pub override_text_color: Option<Rgba>,
/// Visual styles of widgets /// Visual styles of widgets
pub widgets: Widgets, pub widgets: Widgets,
@ -197,19 +197,19 @@ pub struct Visuals {
pub selection: Selection, pub selection: Selection,
/// The color used for `Hyperlink`, /// The color used for `Hyperlink`,
pub hyperlink_color: Color32, pub hyperlink_color: Rgba,
/// Something just barely different from the background color. /// Something just barely different from the background color.
/// Used for [`crate::Grid::striped`]. /// Used for [`crate::Grid::striped`].
pub faint_bg_color: Color32, pub faint_bg_color: Rgba,
/// Very dark or light color (for corresponding theme). /// Very dark or light color (for corresponding theme).
/// Used as the background of text edits, scroll bars and others things /// Used as the background of text edits, scroll bars and others things
/// that needs to look different from other interactive stuff. /// that needs to look different from other interactive stuff.
pub extreme_bg_color: Color32, pub extreme_bg_color: Rgba,
/// Background color behind code-styled monospaced labels. /// Background color behind code-styled monospaced labels.
pub code_bg_color: Color32, pub code_bg_color: Rgba,
pub window_corner_radius: f32, pub window_corner_radius: f32,
pub window_shadow: Shadow, pub window_shadow: Shadow,
@ -237,20 +237,20 @@ impl Visuals {
&self.widgets.noninteractive &self.widgets.noninteractive
} }
pub fn text_color(&self) -> Color32 { pub fn text_color(&self) -> Rgba {
self.override_text_color self.override_text_color
.unwrap_or_else(|| self.widgets.noninteractive.text_color()) .unwrap_or_else(|| self.widgets.noninteractive.text_color())
} }
pub fn weak_text_color(&self) -> Color32 { pub fn weak_text_color(&self) -> Rgba {
crate::color::tint_color_towards(self.text_color(), self.window_fill()) crate::color::tint_rgba_towards(self.text_color(), self.window_fill())
} }
pub fn strong_text_color(&self) -> Color32 { pub fn strong_text_color(&self) -> Rgba {
self.widgets.active.text_color() self.widgets.active.text_color()
} }
pub fn window_fill(&self) -> Color32 { pub fn window_fill(&self) -> Rgba {
self.widgets.noninteractive.bg_fill self.widgets.noninteractive.bg_fill
} }
@ -264,7 +264,7 @@ impl Visuals {
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(default))] #[cfg_attr(feature = "persistence", serde(default))]
pub struct Selection { pub struct Selection {
pub bg_fill: Color32, pub bg_fill: Rgba,
pub stroke: Stroke, pub stroke: Stroke,
} }
@ -307,7 +307,7 @@ impl Widgets {
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub struct WidgetVisuals { pub struct WidgetVisuals {
/// Background color of widget. /// Background color of widget.
pub bg_fill: Color32, pub bg_fill: Rgba,
/// For surrounding rectangle of things that need it, /// For surrounding rectangle of things that need it,
/// like buttons, the box of the checkbox, etc. /// like buttons, the box of the checkbox, etc.
@ -325,7 +325,7 @@ pub struct WidgetVisuals {
} }
impl WidgetVisuals { impl WidgetVisuals {
pub fn text_color(&self) -> Color32 { pub fn text_color(&self) -> Rgba {
self.fg_stroke.color self.fg_stroke.color
} }
} }
@ -398,10 +398,10 @@ impl Visuals {
override_text_color: None, override_text_color: None,
widgets: Widgets::default(), widgets: Widgets::default(),
selection: Selection::default(), selection: Selection::default(),
hyperlink_color: Color32::from_rgb(90, 170, 255), hyperlink_color: Color32::from_rgb(90, 170, 255).into(),
faint_bg_color: Color32::from_gray(24), faint_bg_color: Color32::from_gray(24).into(),
extreme_bg_color: Color32::from_gray(10), extreme_bg_color: Color32::from_gray(10).into(),
code_bg_color: Color32::from_gray(64), code_bg_color: Color32::from_gray(64).into(),
window_corner_radius: 6.0, window_corner_radius: 6.0,
window_shadow: Shadow::big_dark(), window_shadow: Shadow::big_dark(),
popup_shadow: Shadow::small_dark(), popup_shadow: Shadow::small_dark(),
@ -420,10 +420,10 @@ impl Visuals {
dark_mode: false, dark_mode: false,
widgets: Widgets::light(), widgets: Widgets::light(),
selection: Selection::light(), selection: Selection::light(),
hyperlink_color: Color32::from_rgb(0, 155, 255), hyperlink_color: Color32::from_rgb(0, 155, 255).into(),
faint_bg_color: Color32::from_gray(240), faint_bg_color: Color32::from_gray(240).into(),
extreme_bg_color: Color32::from_gray(250), extreme_bg_color: Color32::from_gray(250).into(),
code_bg_color: Color32::from_gray(200), code_bg_color: Color32::from_gray(200).into(),
window_shadow: Shadow::big_light(), window_shadow: Shadow::big_light(),
popup_shadow: Shadow::small_light(), popup_shadow: Shadow::small_light(),
..Self::dark() ..Self::dark()
@ -440,13 +440,13 @@ impl Default for Visuals {
impl Selection { impl Selection {
fn dark() -> Self { fn dark() -> Self {
Self { Self {
bg_fill: Color32::from_rgb(0, 92, 128), bg_fill: Color32::from_rgb(0, 92, 128).into(),
stroke: Stroke::new(1.0, Color32::from_rgb(192, 222, 255)), stroke: Stroke::new(1.0, Color32::from_rgb(192, 222, 255)),
} }
} }
fn light() -> Self { fn light() -> Self {
Self { Self {
bg_fill: Color32::from_rgb(144, 209, 255), bg_fill: Color32::from_rgb(144, 209, 255).into(),
stroke: Stroke::new(1.0, Color32::from_rgb(0, 83, 125)), stroke: Stroke::new(1.0, Color32::from_rgb(0, 83, 125)),
} }
} }
@ -462,35 +462,35 @@ impl Widgets {
pub fn dark() -> Self { pub fn dark() -> Self {
Self { Self {
noninteractive: WidgetVisuals { noninteractive: WidgetVisuals {
bg_fill: Color32::from_gray(27), // window background bg_fill: Color32::from_gray(27).into(), // window background
bg_stroke: Stroke::new(1.0, Color32::from_gray(60)), // separators, indentation lines, windows outlines bg_stroke: Stroke::new(1.0, Color32::from_gray(60)), // separators, indentation lines, windows outlines
fg_stroke: Stroke::new(1.0, Color32::from_gray(140)), // normal text color fg_stroke: Stroke::new(1.0, Color32::from_gray(140)), // normal text color
corner_radius: 2.0, corner_radius: 2.0,
expansion: 0.0, expansion: 0.0,
}, },
inactive: WidgetVisuals { inactive: WidgetVisuals {
bg_fill: Color32::from_gray(60), // button background bg_fill: Color32::from_gray(60).into(), // button background
bg_stroke: Default::default(), bg_stroke: Default::default(),
fg_stroke: Stroke::new(1.0, Color32::from_gray(180)), // button text fg_stroke: Stroke::new(1.0, Color32::from_gray(180)), // button text
corner_radius: 2.0, corner_radius: 2.0,
expansion: 0.0, expansion: 0.0,
}, },
hovered: WidgetVisuals { hovered: WidgetVisuals {
bg_fill: Color32::from_gray(70), bg_fill: Color32::from_gray(70).into(),
bg_stroke: Stroke::new(1.0, Color32::from_gray(150)), // e.g. hover over window edge or button bg_stroke: Stroke::new(1.0, Color32::from_gray(150)), // e.g. hover over window edge or button
fg_stroke: Stroke::new(1.5, Color32::from_gray(240)), fg_stroke: Stroke::new(1.5, Color32::from_gray(240)),
corner_radius: 3.0, corner_radius: 3.0,
expansion: 1.0, expansion: 1.0,
}, },
active: WidgetVisuals { active: WidgetVisuals {
bg_fill: Color32::from_gray(55), bg_fill: Color32::from_gray(55).into(),
bg_stroke: Stroke::new(1.0, Color32::WHITE), bg_stroke: Stroke::new(1.0, Rgba::WHITE),
fg_stroke: Stroke::new(2.0, Color32::WHITE), fg_stroke: Stroke::new(2.0, Rgba::WHITE),
corner_radius: 2.0, corner_radius: 2.0,
expansion: 1.0, expansion: 1.0,
}, },
open: WidgetVisuals { open: WidgetVisuals {
bg_fill: Color32::from_gray(27), bg_fill: Color32::from_gray(27).into(),
bg_stroke: Stroke::new(1.0, Color32::from_gray(60)), bg_stroke: Stroke::new(1.0, Color32::from_gray(60)),
fg_stroke: Stroke::new(1.0, Color32::from_gray(210)), fg_stroke: Stroke::new(1.0, Color32::from_gray(210)),
corner_radius: 2.0, corner_radius: 2.0,
@ -502,37 +502,37 @@ impl Widgets {
pub fn light() -> Self { pub fn light() -> Self {
Self { Self {
noninteractive: WidgetVisuals { noninteractive: WidgetVisuals {
bg_fill: Color32::from_gray(235), // window background bg_fill: Color32::from_gray(235).into(), // window background
bg_stroke: Stroke::new(1.0, Color32::from_gray(190)), // separators, indentation lines, windows outlines bg_stroke: Stroke::new(1.0, Color32::from_gray(190)), // separators, indentation lines, windows outlines
fg_stroke: Stroke::new(1.0, Color32::from_gray(100)), // normal text color fg_stroke: Stroke::new(1.0, Color32::from_gray(100)), // normal text color
corner_radius: 2.0, corner_radius: 2.0,
expansion: 0.0, expansion: 0.0,
}, },
inactive: WidgetVisuals { inactive: WidgetVisuals {
bg_fill: Color32::from_gray(215), // button background bg_fill: Color32::from_gray(215).into(), // button background
bg_stroke: Default::default(), bg_stroke: Default::default(),
fg_stroke: Stroke::new(1.0, Color32::from_gray(80)), // button text fg_stroke: Stroke::new(1.0, Color32::from_gray(80)), // button text
corner_radius: 2.0, corner_radius: 2.0,
expansion: 0.0, expansion: 0.0,
}, },
hovered: WidgetVisuals { hovered: WidgetVisuals {
bg_fill: Color32::from_gray(210), bg_fill: Color32::from_gray(210).into(),
bg_stroke: Stroke::new(1.0, Color32::from_gray(105)), // e.g. hover over window edge or button bg_stroke: Stroke::new(1.0, Color32::from_gray(105)), // e.g. hover over window edge or button
fg_stroke: Stroke::new(1.5, Color32::BLACK), fg_stroke: Stroke::new(1.5, Rgba::BLACK),
corner_radius: 3.0, corner_radius: 3.0,
expansion: 1.0, expansion: 1.0,
}, },
active: WidgetVisuals { active: WidgetVisuals {
bg_fill: Color32::from_gray(165), bg_fill: Color32::from_gray(165).into(),
bg_stroke: Stroke::new(1.0, Color32::BLACK), bg_stroke: Stroke::new(1.0, Rgba::BLACK),
fg_stroke: Stroke::new(2.0, Color32::BLACK), fg_stroke: Stroke::new(2.0, Rgba::BLACK),
corner_radius: 2.0, corner_radius: 2.0,
expansion: 1.0, expansion: 1.0,
}, },
open: WidgetVisuals { open: WidgetVisuals {
bg_fill: Color32::from_gray(220), bg_fill: Color32::from_gray(220).into(),
bg_stroke: Stroke::new(1.0, Color32::from_gray(160)), bg_stroke: Stroke::new(1.0, Color32::from_gray(160)),
fg_stroke: Stroke::new(1.0, Color32::BLACK), fg_stroke: Stroke::new(1.0, Rgba::BLACK),
corner_radius: 2.0, corner_radius: 2.0,
expansion: 0.0, expansion: 0.0,
}, },
@ -934,9 +934,9 @@ fn slider_vec2<'a>(
} }
} }
fn ui_color(ui: &mut Ui, srgba: &mut Color32, text: impl Into<Label>) -> Response { fn ui_color(ui: &mut Ui, rgba: &mut Rgba, text: impl Into<Label>) -> Response {
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.color_edit_button_srgba(srgba); ui.color_edit_button_rgba(rgba);
ui.label(text); ui.label(text);
}) })
.response .response

View file

@ -945,11 +945,7 @@ impl Ui {
} }
/// Shortcut for `add(Label::new(text).text_color(color))` /// Shortcut for `add(Label::new(text).text_color(color))`
pub fn colored_label( pub fn colored_label(&mut self, color: impl Into<Rgba>, label: impl Into<Label>) -> Response {
&mut self,
color: impl Into<Color32>,
label: impl Into<Label>,
) -> Response {
label.into().text_color(color).ui(self) label.into().text_color(color).ui(self)
} }
@ -1172,6 +1168,12 @@ impl Ui {
/// # Colors /// # Colors
impl Ui { impl Ui {
/// Shows a button with the given color.
/// If the user clicks the button, a full color picker is shown.
pub fn color_edit_button_rgba(&mut self, rgba: &mut Rgba) -> Response {
color_picker::color_edit_button_rgba(self, rgba, 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_srgba(&mut self, srgba: &mut Color32) -> Response { pub fn color_edit_button_srgba(&mut self, srgba: &mut Color32) -> Response {

View file

@ -14,10 +14,10 @@ use crate::*;
#[must_use = "You should put this widget in an ui with `ui.add(widget);`"] #[must_use = "You should put this widget in an ui with `ui.add(widget);`"]
pub struct Button { pub struct Button {
text: String, text: String,
text_color: Option<Color32>, text_color: Option<Rgba>,
text_style: Option<TextStyle>, text_style: Option<TextStyle>,
/// None means default for interact /// None means default for interact
fill: Option<Color32>, fill: Option<Rgba>,
stroke: Option<Stroke>, stroke: Option<Stroke>,
sense: Sense, sense: Sense,
small: bool, small: bool,
@ -43,12 +43,12 @@ impl Button {
} }
} }
pub fn text_color(mut self, text_color: Color32) -> Self { pub fn text_color(mut self, text_color: impl Into<Rgba>) -> Self {
self.text_color = Some(text_color); self.text_color = Some(text_color.into());
self self
} }
pub fn text_color_opt(mut self, text_color: Option<Color32>) -> Self { pub fn text_color_opt(mut self, text_color: Option<Rgba>) -> Self {
self.text_color = text_color; self.text_color = text_color;
self self
} }
@ -60,7 +60,7 @@ impl Button {
/// Override background fill color. Note that this will override any on-hover effects. /// Override background fill color. Note that this will override any on-hover effects.
/// Calling this will also turn on the frame. /// Calling this will also turn on the frame.
pub fn fill(mut self, fill: impl Into<Color32>) -> Self { pub fn fill(mut self, fill: impl Into<Rgba>) -> Self {
self.fill = Some(fill.into()); self.fill = Some(fill.into());
self.frame = Some(true); self.frame = Some(true);
self self
@ -229,7 +229,7 @@ impl Widget for Button {
pub struct Checkbox<'a> { pub struct Checkbox<'a> {
checked: &'a mut bool, checked: &'a mut bool,
text: String, text: String,
text_color: Option<Color32>, text_color: Option<Rgba>,
text_style: Option<TextStyle>, text_style: Option<TextStyle>,
} }
@ -244,7 +244,7 @@ impl<'a> Checkbox<'a> {
} }
} }
pub fn text_color(mut self, text_color: Color32) -> Self { pub fn text_color(mut self, text_color: Rgba) -> Self {
self.text_color = Some(text_color); self.text_color = Some(text_color);
self self
} }
@ -351,7 +351,7 @@ impl<'a> Widget for Checkbox<'a> {
pub struct RadioButton { pub struct RadioButton {
checked: bool, checked: bool,
text: String, text: String,
text_color: Option<Color32>, text_color: Option<Rgba>,
text_style: Option<TextStyle>, text_style: Option<TextStyle>,
} }
@ -366,7 +366,7 @@ impl RadioButton {
} }
} }
pub fn text_color(mut self, text_color: Color32) -> Self { pub fn text_color(mut self, text_color: Rgba) -> Self {
self.text_color = Some(text_color); self.text_color = Some(text_color);
self self
} }
@ -475,7 +475,7 @@ impl ImageButton {
} }
/// Multiply image color with this. Default is WHITE (no tint). /// Multiply image color with this. Default is WHITE (no tint).
pub fn tint(mut self, tint: impl Into<Color32>) -> Self { pub fn tint(mut self, tint: impl Into<Rgba>) -> Self {
self.image = self.image.tint(tint); self.image = self.image.tint(tint);
self self
} }

View file

@ -23,8 +23,8 @@ fn background_checkers(painter: &Painter, rect: Rect) {
return; return;
} }
let mut top_color = Color32::from_gray(128); let mut top_color = Color32::from_gray(128).into();
let mut bottom_color = Color32::from_gray(32); let mut bottom_color = Color32::from_gray(32).into();
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;
@ -92,7 +92,7 @@ fn color_button(ui: &mut Ui, color: Color32, open: bool) -> Response {
response response
} }
fn color_slider_1d(ui: &mut Ui, value: &mut f32, color_at: impl Fn(f32) -> Color32) -> Response { fn color_slider_1d(ui: &mut Ui, value: &mut f32, color_at: impl Fn(f32) -> Rgba) -> Response {
#![allow(clippy::identity_op)] #![allow(clippy::identity_op)]
let desired_size = vec2( let desired_size = vec2(
@ -151,7 +151,7 @@ fn color_slider_2d(
ui: &mut Ui, ui: &mut Ui,
x_value: &mut f32, x_value: &mut f32,
y_value: &mut f32, y_value: &mut f32,
color_at: impl Fn(f32, f32) -> Color32, color_at: impl Fn(f32, f32) -> Rgba,
) -> Response { ) -> Response {
let desired_size = Vec2::splat(ui.spacing().slider_width); let desired_size = Vec2::splat(ui.spacing().slider_width);
let (rect, response) = ui.allocate_at_least(desired_size, Sense::click_and_drag()); let (rect, response) = ui.allocate_at_least(desired_size, Sense::click_and_drag());
@ -211,7 +211,7 @@ pub enum Alpha {
BlendOrAdditive, BlendOrAdditive,
} }
fn color_text_ui(ui: &mut Ui, color: impl Into<Color32>) { fn color_text_ui(ui: &mut Ui, color: impl Into<Rgba>) {
let color = color.into(); let color = color.into();
ui.horizontal(|ui| { ui.horizontal(|ui| {
let [r, g, b, a] = color.to_array(); let [r, g, b, a] = color.to_array();
@ -368,6 +368,17 @@ pub fn color_edit_button_hsva(ui: &mut Ui, hsva: &mut Hsva, alpha: Alpha) -> Res
button_response button_response
} }
/// Shows a button with the given color.
/// If the user clicks the button, a full color picker is shown.
pub fn color_edit_button_rgba(ui: &mut Ui, rgba: &mut Rgba, alpha: Alpha) -> Response {
let mut srgba = (*rgba).into();
let response = color_edit_button_srgba(ui, &mut srgba, alpha);
if response.changed() {
*rgba = srgba.into();
}
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, alpha: Alpha) -> Response { pub fn color_edit_button_srgba(ui: &mut Ui, srgba: &mut Color32, alpha: Alpha) -> Response {

View file

@ -18,8 +18,8 @@ pub struct Image {
texture_id: TextureId, texture_id: TextureId,
uv: Rect, uv: Rect,
size: Vec2, size: Vec2,
bg_fill: Color32, bg_fill: Rgba,
tint: Color32, tint: Rgba,
sense: Sense, sense: Sense,
} }
@ -30,7 +30,7 @@ impl Image {
uv: Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0)), uv: Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0)),
size: size.into(), size: size.into(),
bg_fill: Default::default(), bg_fill: Default::default(),
tint: Color32::WHITE, tint: Rgba::WHITE,
sense: Sense::hover(), sense: Sense::hover(),
} }
} }
@ -42,13 +42,13 @@ impl Image {
} }
/// A solid color to put behind the image. Useful for transparent images. /// A solid color to put behind the image. Useful for transparent images.
pub fn bg_fill(mut self, bg_fill: impl Into<Color32>) -> Self { pub fn bg_fill(mut self, bg_fill: impl Into<Rgba>) -> Self {
self.bg_fill = bg_fill.into(); self.bg_fill = bg_fill.into();
self self
} }
/// Multiply image color with this. Default is WHITE (no tint). /// Multiply image color with this. Default is WHITE (no tint).
pub fn tint(mut self, tint: impl Into<Color32>) -> Self { pub fn tint(mut self, tint: impl Into<Rgba>) -> Self {
self.tint = tint.into(); self.tint = tint.into();
self self
} }

View file

@ -8,7 +8,7 @@ use std::sync::Arc;
/// # let ui = &mut egui::Ui::__test(); /// # let ui = &mut egui::Ui::__test();
/// ui.label("Equivalent"); /// ui.label("Equivalent");
/// ui.add(egui::Label::new("Equivalent")); /// ui.add(egui::Label::new("Equivalent"));
/// ui.add(egui::Label::new("With Options").text_color(egui::Color32::RED)); /// ui.add(egui::Label::new("With Options").text_color(egui::Rgba::RED));
/// ``` /// ```
#[must_use = "You should put this widget in an ui with `ui.add(widget);`"] #[must_use = "You should put this widget in an ui with `ui.add(widget);`"]
pub struct Label { pub struct Label {
@ -16,8 +16,8 @@ pub struct Label {
pub(crate) text: String, pub(crate) text: String,
pub(crate) wrap: Option<bool>, pub(crate) wrap: Option<bool>,
pub(crate) text_style: Option<TextStyle>, pub(crate) text_style: Option<TextStyle>,
pub(crate) background_color: Color32, pub(crate) background_color: Rgba,
pub(crate) text_color: Option<Color32>, pub(crate) text_color: Option<Rgba>,
code: bool, code: bool,
strong: bool, strong: bool,
weak: bool, weak: bool,
@ -35,7 +35,7 @@ impl Label {
text: text.to_string(), text: text.to_string(),
wrap: None, wrap: None,
text_style: None, text_style: None,
background_color: Color32::TRANSPARENT, background_color: Rgba::TRANSPARENT,
text_color: None, text_color: None,
code: false, code: false,
strong: false, strong: false,
@ -135,12 +135,12 @@ impl Label {
} }
/// Fill-color behind the text /// Fill-color behind the text
pub fn background_color(mut self, background_color: impl Into<Color32>) -> Self { pub fn background_color(mut self, background_color: impl Into<Rgba>) -> Self {
self.background_color = background_color.into(); self.background_color = background_color.into();
self self
} }
pub fn text_color(mut self, text_color: impl Into<Color32>) -> Self { pub fn text_color(mut self, text_color: impl Into<Rgba>) -> Self {
self.text_color = Some(text_color.into()); self.text_color = Some(text_color.into());
self self
} }
@ -206,7 +206,7 @@ impl Label {
pos: Pos2, pos: Pos2,
galley: Arc<Galley>, galley: Arc<Galley>,
has_focus: bool, has_focus: bool,
response_color: Color32, response_color: Rgba,
) { ) {
let Self { let Self {
mut background_color, mut background_color,
@ -238,11 +238,11 @@ impl Label {
let mut lines = vec![]; let mut lines = vec![];
if strikethrough || underline || background_color != Color32::TRANSPARENT { if strikethrough || underline || background_color != Rgba::TRANSPARENT {
for row in &galley.rows { for row in &galley.rows {
let rect = row.rect().translate(pos.to_vec2()); let rect = row.rect().translate(pos.to_vec2());
if background_color != Color32::TRANSPARENT { if background_color != Rgba::TRANSPARENT {
let rect = rect.expand(1.0); // looks better let rect = rect.expand(1.0); // looks better
ui.painter().rect_filled(rect, 0.0, background_color); ui.painter().rect_filled(rect, 0.0, background_color);
} }

View file

@ -97,7 +97,7 @@ pub fn stroke_ui(ui: &mut crate::Ui, stroke: &mut epaint::Stroke, text: &str) {
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.add(DragValue::new(width).speed(0.1).clamp_range(0.0..=5.0)) ui.add(DragValue::new(width).speed(0.1).clamp_range(0.0..=5.0))
.on_hover_text("Width"); .on_hover_text("Width");
ui.color_edit_button_srgba(color); ui.color_edit_button_rgba(color);
ui.label(text); ui.label(text);
// stroke preview: // stroke preview:
@ -118,6 +118,6 @@ pub(crate) fn shadow_ui(ui: &mut Ui, shadow: &mut epaint::Shadow, text: &str) {
.clamp_range(0.0..=100.0), .clamp_range(0.0..=100.0),
) )
.on_hover_text("Extrusion"); .on_hover_text("Extrusion");
ui.color_edit_button_srgba(color); ui.color_edit_button_rgba(color);
}); });
} }

View file

@ -135,7 +135,7 @@ impl HLine {
pub fn new(y: impl Into<f64>) -> Self { pub fn new(y: impl Into<f64>) -> Self {
Self { Self {
y: y.into(), y: y.into(),
stroke: Stroke::new(1.0, Color32::TRANSPARENT), stroke: Stroke::new(1.0, Rgba::TRANSPARENT),
name: String::default(), name: String::default(),
highlight: false, highlight: false,
style: LineStyle::Solid, style: LineStyle::Solid,
@ -160,8 +160,8 @@ impl HLine {
self self
} }
/// Stroke color. Default is `Color32::TRANSPARENT` which means a color will be auto-assigned. /// Stroke color. Default is `Rgba::TRANSPARENT` which means a color will be auto-assigned.
pub fn color(mut self, color: impl Into<Color32>) -> Self { pub fn color(mut self, color: impl Into<Rgba>) -> Self {
self.stroke.color = color.into(); self.stroke.color = color.into();
self self
} }
@ -207,7 +207,7 @@ impl PlotItem for HLine {
&self.name &self.name
} }
fn color(&self) -> Color32 { fn color(&self) -> Rgba {
self.stroke.color self.stroke.color
} }
@ -245,7 +245,7 @@ impl VLine {
pub fn new(x: impl Into<f64>) -> Self { pub fn new(x: impl Into<f64>) -> Self {
Self { Self {
x: x.into(), x: x.into(),
stroke: Stroke::new(1.0, Color32::TRANSPARENT), stroke: Stroke::new(1.0, Rgba::TRANSPARENT),
name: String::default(), name: String::default(),
highlight: false, highlight: false,
style: LineStyle::Solid, style: LineStyle::Solid,
@ -270,8 +270,8 @@ impl VLine {
self self
} }
/// Stroke color. Default is `Color32::TRANSPARENT` which means a color will be auto-assigned. /// Stroke color. Default is `Rgba::TRANSPARENT` which means a color will be auto-assigned.
pub fn color(mut self, color: impl Into<Color32>) -> Self { pub fn color(mut self, color: impl Into<Rgba>) -> Self {
self.stroke.color = color.into(); self.stroke.color = color.into();
self self
} }
@ -317,7 +317,7 @@ impl PlotItem for VLine {
&self.name &self.name
} }
fn color(&self) -> Color32 { fn color(&self) -> Rgba {
self.stroke.color self.stroke.color
} }
@ -346,7 +346,7 @@ pub(super) trait PlotItem {
fn get_shapes(&self, ui: &mut Ui, transform: &ScreenTransform, shapes: &mut Vec<Shape>); fn get_shapes(&self, ui: &mut Ui, transform: &ScreenTransform, shapes: &mut Vec<Shape>);
fn initialize(&mut self, x_range: RangeInclusive<f64>); fn initialize(&mut self, x_range: RangeInclusive<f64>);
fn name(&self) -> &str; fn name(&self) -> &str;
fn color(&self) -> Color32; fn color(&self) -> Rgba;
fn highlight(&mut self); fn highlight(&mut self);
fn highlighted(&self) -> bool; fn highlighted(&self) -> bool;
fn values(&self) -> Option<&Values>; fn values(&self) -> Option<&Values>;
@ -552,7 +552,7 @@ impl Line {
pub fn new(series: Values) -> Self { pub fn new(series: Values) -> Self {
Self { Self {
series, series,
stroke: Stroke::new(1.0, Color32::TRANSPARENT), stroke: Stroke::new(1.0, Rgba::TRANSPARENT),
name: Default::default(), name: Default::default(),
highlight: false, highlight: false,
fill: None, fill: None,
@ -578,8 +578,8 @@ impl Line {
self self
} }
/// Stroke color. Default is `Color32::TRANSPARENT` which means a color will be auto-assigned. /// Stroke color. Default is `Rgba::TRANSPARENT` which means a color will be auto-assigned.
pub fn color(mut self, color: impl Into<Color32>) -> Self { pub fn color(mut self, color: impl Into<Rgba>) -> Self {
self.stroke.color = color.into(); self.stroke.color = color.into();
self self
} }
@ -684,7 +684,7 @@ impl PlotItem for Line {
self.name.as_str() self.name.as_str()
} }
fn color(&self) -> Color32 { fn color(&self) -> Rgba {
self.stroke.color self.stroke.color
} }
@ -719,7 +719,7 @@ impl Polygon {
pub fn new(series: Values) -> Self { pub fn new(series: Values) -> Self {
Self { Self {
series, series,
stroke: Stroke::new(1.0, Color32::TRANSPARENT), stroke: Stroke::new(1.0, Rgba::TRANSPARENT),
name: Default::default(), name: Default::default(),
highlight: false, highlight: false,
fill_alpha: DEFAULT_FILL_ALPHA, fill_alpha: DEFAULT_FILL_ALPHA,
@ -746,8 +746,8 @@ impl Polygon {
self self
} }
/// Stroke color. Default is `Color32::TRANSPARENT` which means a color will be auto-assigned. /// Stroke color. Default is `Rgba::TRANSPARENT` which means a color will be auto-assigned.
pub fn color(mut self, color: impl Into<Color32>) -> Self { pub fn color(mut self, color: impl Into<Rgba>) -> Self {
self.stroke.color = color.into(); self.stroke.color = color.into();
self self
} }
@ -819,7 +819,7 @@ impl PlotItem for Polygon {
self.name.as_str() self.name.as_str()
} }
fn color(&self) -> Color32 { fn color(&self) -> Rgba {
self.stroke.color self.stroke.color
} }
@ -847,7 +847,7 @@ pub struct Text {
pub(super) position: Value, pub(super) position: Value,
pub(super) name: String, pub(super) name: String,
pub(super) highlight: bool, pub(super) highlight: bool,
pub(super) color: Color32, pub(super) color: Rgba,
pub(super) anchor: Align2, pub(super) anchor: Align2,
} }
@ -860,7 +860,7 @@ impl Text {
position, position,
name: Default::default(), name: Default::default(),
highlight: false, highlight: false,
color: Color32::TRANSPARENT, color: Rgba::TRANSPARENT,
anchor: Align2::CENTER_CENTER, anchor: Align2::CENTER_CENTER,
} }
} }
@ -877,8 +877,8 @@ impl Text {
self self
} }
/// Text color. Default is `Color32::TRANSPARENT` which means a color will be auto-assigned. /// Text color. Default is `Rgba::TRANSPARENT` which means a color will be auto-assigned.
pub fn color(mut self, color: impl Into<Color32>) -> Self { pub fn color(mut self, color: impl Into<Rgba>) -> Self {
self.color = color.into(); self.color = color.into();
self self
} }
@ -904,7 +904,7 @@ impl Text {
impl PlotItem for Text { impl PlotItem for Text {
fn get_shapes(&self, ui: &mut Ui, transform: &ScreenTransform, shapes: &mut Vec<Shape>) { fn get_shapes(&self, ui: &mut Ui, transform: &ScreenTransform, shapes: &mut Vec<Shape>) {
let color = if self.color == Color32::TRANSPARENT { let color = if self.color == Rgba::TRANSPARENT {
ui.style().visuals.text_color() ui.style().visuals.text_color()
} else { } else {
self.color self.color
@ -937,7 +937,7 @@ impl PlotItem for Text {
self.name.as_str() self.name.as_str()
} }
fn color(&self) -> Color32 { fn color(&self) -> Rgba {
self.color self.color
} }
@ -964,8 +964,8 @@ impl PlotItem for Text {
pub struct Points { pub struct Points {
pub(super) series: Values, pub(super) series: Values,
pub(super) shape: MarkerShape, pub(super) shape: MarkerShape,
/// Color of the marker. `Color32::TRANSPARENT` means that it will be picked automatically. /// Color of the marker. `Rgba::TRANSPARENT` means that it will be picked automatically.
pub(super) color: Color32, pub(super) color: Rgba,
/// Whether to fill the marker. Does not apply to all types. /// Whether to fill the marker. Does not apply to all types.
pub(super) filled: bool, pub(super) filled: bool,
/// The maximum extent of the marker from its center. /// The maximum extent of the marker from its center.
@ -980,7 +980,7 @@ impl Points {
Self { Self {
series, series,
shape: MarkerShape::Circle, shape: MarkerShape::Circle,
color: Color32::TRANSPARENT, color: Rgba::TRANSPARENT,
filled: true, filled: true,
radius: 1.0, radius: 1.0,
name: Default::default(), name: Default::default(),
@ -1002,7 +1002,7 @@ impl Points {
} }
/// Set the marker's color. /// Set the marker's color.
pub fn color(mut self, color: impl Into<Color32>) -> Self { pub fn color(mut self, color: impl Into<Rgba>) -> Self {
self.color = color.into(); self.color = color.into();
self self
} }
@ -1200,7 +1200,7 @@ impl PlotItem for Points {
self.name.as_str() self.name.as_str()
} }
fn color(&self) -> Color32 { fn color(&self) -> Rgba {
self.color self.color
} }
@ -1225,7 +1225,7 @@ impl PlotItem for Points {
pub struct Arrows { pub struct Arrows {
pub(super) origins: Values, pub(super) origins: Values,
pub(super) tips: Values, pub(super) tips: Values,
pub(super) color: Color32, pub(super) color: Rgba,
pub(super) name: String, pub(super) name: String,
pub(super) highlight: bool, pub(super) highlight: bool,
} }
@ -1235,7 +1235,7 @@ impl Arrows {
Self { Self {
origins, origins,
tips, tips,
color: Color32::TRANSPARENT, color: Rgba::TRANSPARENT,
name: Default::default(), name: Default::default(),
highlight: false, highlight: false,
} }
@ -1248,7 +1248,7 @@ impl Arrows {
} }
/// Set the arrows' color. /// Set the arrows' color.
pub fn color(mut self, color: impl Into<Color32>) -> Self { pub fn color(mut self, color: impl Into<Rgba>) -> Self {
self.color = color.into(); self.color = color.into();
self self
} }
@ -1315,7 +1315,7 @@ impl PlotItem for Arrows {
self.name.as_str() self.name.as_str()
} }
fn color(&self) -> Color32 { fn color(&self) -> Rgba {
self.color self.color
} }
@ -1342,8 +1342,8 @@ pub struct PlotImage {
pub(super) texture_id: TextureId, pub(super) texture_id: TextureId,
pub(super) uv: Rect, pub(super) uv: Rect,
pub(super) size: Vec2, pub(super) size: Vec2,
pub(super) bg_fill: Color32, pub(super) bg_fill: Rgba,
pub(super) tint: Color32, pub(super) tint: Rgba,
pub(super) highlight: bool, pub(super) highlight: bool,
pub(super) name: String, pub(super) name: String,
} }
@ -1359,7 +1359,7 @@ impl PlotImage {
uv: Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0)), uv: Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0)),
size: size.into(), size: size.into(),
bg_fill: Default::default(), bg_fill: Default::default(),
tint: Color32::WHITE, tint: Rgba::WHITE,
} }
} }
@ -1376,13 +1376,13 @@ impl PlotImage {
} }
/// A solid color to put behind the image. Useful for transparent images. /// A solid color to put behind the image. Useful for transparent images.
pub fn bg_fill(mut self, bg_fill: impl Into<Color32>) -> Self { pub fn bg_fill(mut self, bg_fill: impl Into<Rgba>) -> Self {
self.bg_fill = bg_fill.into(); self.bg_fill = bg_fill.into();
self self
} }
/// Multiply image color with this. Default is WHITE (no tint). /// Multiply image color with this. Default is WHITE (no tint).
pub fn tint(mut self, tint: impl Into<Color32>) -> Self { pub fn tint(mut self, tint: impl Into<Rgba>) -> Self {
self.tint = tint.into(); self.tint = tint.into();
self self
} }
@ -1445,8 +1445,8 @@ impl PlotItem for PlotImage {
self.name.as_str() self.name.as_str()
} }
fn color(&self) -> Color32 { fn color(&self) -> Rgba {
Color32::TRANSPARENT Rgba::TRANSPARENT
} }
fn highlight(&mut self) { fn highlight(&mut self) {

View file

@ -69,13 +69,13 @@ impl Legend {
#[derive(Clone)] #[derive(Clone)]
struct LegendEntry { struct LegendEntry {
color: Color32, color: Rgba,
checked: bool, checked: bool,
hovered: bool, hovered: bool,
} }
impl LegendEntry { impl LegendEntry {
fn new(color: Color32, checked: bool) -> Self { fn new(color: Rgba, checked: bool) -> Self {
Self { Self {
color, color,
checked, checked,
@ -122,7 +122,7 @@ impl LegendEntry {
}); });
if *checked { if *checked {
let fill = if *color == Color32::TRANSPARENT { let fill = if *color == Rgba::TRANSPARENT {
ui.visuals().noninteractive().fg_stroke.color ui.visuals().noninteractive().fg_stroke.color
} else { } else {
*color *color
@ -179,7 +179,7 @@ impl LegendWidget {
.and_modify(|entry| { .and_modify(|entry| {
if entry.color != item.color() { if entry.color != item.color() {
// Multiple items with different colors // Multiple items with different colors
entry.color = Color32::TRANSPARENT; entry.color = Rgba::TRANSPARENT;
} }
}) })
.or_insert_with(|| { .or_insert_with(|| {

View file

@ -101,7 +101,7 @@ impl Plot {
} }
} }
fn auto_color(&mut self) -> Color32 { fn auto_color(&mut self) -> Rgba {
let i = self.next_auto_color_idx; let i = self.next_auto_color_idx;
self.next_auto_color_idx += 1; self.next_auto_color_idx += 1;
let golden_ratio = (5.0_f32.sqrt() - 1.0) / 2.0; // 0.61803398875 let golden_ratio = (5.0_f32.sqrt() - 1.0) / 2.0; // 0.61803398875
@ -116,7 +116,7 @@ impl Plot {
}; };
// Give the stroke an automatic color if no color has been assigned. // Give the stroke an automatic color if no color has been assigned.
if line.stroke.color == Color32::TRANSPARENT { if line.stroke.color == Rgba::TRANSPARENT {
line.stroke.color = self.auto_color(); line.stroke.color = self.auto_color();
} }
self.items.push(Box::new(line)); self.items.push(Box::new(line));
@ -130,7 +130,7 @@ impl Plot {
}; };
// Give the stroke an automatic color if no color has been assigned. // Give the stroke an automatic color if no color has been assigned.
if polygon.stroke.color == Color32::TRANSPARENT { if polygon.stroke.color == Rgba::TRANSPARENT {
polygon.stroke.color = self.auto_color(); polygon.stroke.color = self.auto_color();
} }
self.items.push(Box::new(polygon)); self.items.push(Box::new(polygon));
@ -154,7 +154,7 @@ impl Plot {
}; };
// Give the points an automatic color if no color has been assigned. // Give the points an automatic color if no color has been assigned.
if points.color == Color32::TRANSPARENT { if points.color == Rgba::TRANSPARENT {
points.color = self.auto_color(); points.color = self.auto_color();
} }
self.items.push(Box::new(points)); self.items.push(Box::new(points));
@ -168,7 +168,7 @@ impl Plot {
}; };
// Give the arrows an automatic color if no color has been assigned. // Give the arrows an automatic color if no color has been assigned.
if arrows.color == Color32::TRANSPARENT { if arrows.color == Rgba::TRANSPARENT {
arrows.color = self.auto_color(); arrows.color = self.auto_color();
} }
self.items.push(Box::new(arrows)); self.items.push(Box::new(arrows));
@ -185,7 +185,7 @@ impl Plot {
/// Can be useful e.g. to show min/max bounds or similar. /// Can be useful e.g. to show min/max bounds or similar.
/// Always fills the full width of the plot. /// Always fills the full width of the plot.
pub fn hline(mut self, mut hline: HLine) -> Self { pub fn hline(mut self, mut hline: HLine) -> Self {
if hline.stroke.color == Color32::TRANSPARENT { if hline.stroke.color == Rgba::TRANSPARENT {
hline.stroke.color = self.auto_color(); hline.stroke.color = self.auto_color();
} }
self.items.push(Box::new(hline)); self.items.push(Box::new(hline));
@ -196,7 +196,7 @@ impl Plot {
/// Can be useful e.g. to show min/max bounds or similar. /// Can be useful e.g. to show min/max bounds or similar.
/// Always fills the full height of the plot. /// Always fills the full height of the plot.
pub fn vline(mut self, mut vline: VLine) -> Self { pub fn vline(mut self, mut vline: VLine) -> Self {
if vline.stroke.color == Color32::TRANSPARENT { if vline.stroke.color == Rgba::TRANSPARENT {
vline.stroke.color = self.auto_color(); vline.stroke.color = self.auto_color();
} }
self.items.push(Box::new(vline)); self.items.push(Box::new(vline));
@ -634,7 +634,7 @@ impl Prepared {
} }
} }
fn color_from_alpha(ui: &Ui, alpha: f32) -> Color32 { fn color_from_alpha(ui: &Ui, alpha: f32) -> Rgba {
if ui.visuals().dark_mode { if ui.visuals().dark_mode {
Rgba::from_white_alpha(alpha).into() Rgba::from_white_alpha(alpha).into()
} else { } else {

View file

@ -94,7 +94,7 @@ impl Widget for ProgressBar {
ui.painter().rect( ui.painter().rect(
inner_rect, inner_rect,
corner_radius, corner_radius,
Color32::from(Rgba::from(visuals.selection.bg_fill) * color_factor as f32), Rgba::from(visuals.selection.bg_fill) * color_factor as f32,
Stroke::none(), Stroke::none(),
); );
@ -115,7 +115,7 @@ impl Widget for ProgressBar {
ui.painter().add(Shape::Path { ui.painter().add(Shape::Path {
points, points,
closed: false, closed: false,
fill: Color32::TRANSPARENT, fill: Rgba::TRANSPARENT,
stroke: Stroke::new(2.0, visuals.faint_bg_color), stroke: Stroke::new(2.0, visuals.faint_bg_color),
}); });
} }

View file

@ -61,7 +61,7 @@ pub struct Slider<'a> {
prefix: String, prefix: String,
suffix: String, suffix: String,
text: String, text: String,
text_color: Option<Color32>, text_color: Option<Rgba>,
min_decimals: usize, min_decimals: usize,
max_decimals: Option<usize>, max_decimals: Option<usize>,
} }
@ -180,7 +180,7 @@ impl<'a> Slider<'a> {
self self
} }
pub fn text_color(mut self, text_color: Color32) -> Self { pub fn text_color(mut self, text_color: Rgba) -> Self {
self.text_color = Some(text_color); self.text_color = Some(text_color);
self self
} }

View file

@ -229,7 +229,7 @@ pub struct TextEdit<'t, S: TextBuffer = String> {
id: Option<Id>, id: Option<Id>,
id_source: Option<Id>, id_source: Option<Id>,
text_style: Option<TextStyle>, text_style: Option<TextStyle>,
text_color: Option<Color32>, text_color: Option<Rgba>,
password: bool, password: bool,
frame: bool, frame: bool,
multiline: bool, multiline: bool,
@ -329,12 +329,12 @@ impl<'t, S: TextBuffer> TextEdit<'t, S> {
self self
} }
pub fn text_color(mut self, text_color: Color32) -> Self { pub fn text_color(mut self, text_color: Rgba) -> Self {
self.text_color = Some(text_color); self.text_color = Some(text_color);
self self
} }
pub fn text_color_opt(mut self, text_color: Option<Color32>) -> Self { pub fn text_color_opt(mut self, text_color: Option<Rgba>) -> Self {
self.text_color = text_color; self.text_color = text_color;
self self
} }

View file

@ -90,7 +90,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
fonts.texture().size(), fonts.texture().size(),
egui::Pos2::ZERO, egui::Pos2::ZERO,
&galley, &galley,
egui::Color32::WHITE, egui::Rgba::WHITE,
fake_italics, fake_italics,
&mut mesh, &mut mesh,
); );

View file

@ -303,7 +303,7 @@ fn vertex_gradient(ui: &mut Ui, bg_fill: Color32, gradient: &Gradient) -> Respon
let (rect, response) = ui.allocate_at_least(GRADIENT_SIZE, Sense::hover()); let (rect, response) = ui.allocate_at_least(GRADIENT_SIZE, Sense::hover());
if bg_fill != Default::default() { if bg_fill != Default::default() {
let mut mesh = Mesh::default(); let mut mesh = Mesh::default();
mesh.add_colored_rect(rect, bg_fill); mesh.add_colored_rect(rect, bg_fill.into());
ui.painter().add(Shape::mesh(mesh)); ui.painter().add(Shape::mesh(mesh));
} }
{ {
@ -313,8 +313,8 @@ fn vertex_gradient(ui: &mut Ui, bg_fill: Color32, gradient: &Gradient) -> Respon
for (i, &color) in gradient.0.iter().enumerate() { for (i, &color) in gradient.0.iter().enumerate() {
let t = i as f32 / (n as f32 - 1.0); let t = i as f32 / (n as f32 - 1.0);
let x = lerp(rect.x_range(), t); let x = lerp(rect.x_range(), t);
mesh.colored_vertex(pos2(x, rect.top()), color); mesh.colored_vertex(pos2(x, rect.top()), color.into());
mesh.colored_vertex(pos2(x, rect.bottom()), color); mesh.colored_vertex(pos2(x, rect.bottom()), color.into());
if i < n - 1 { if i < n - 1 {
let i = i as u32; let i = i as u32;
mesh.add_triangle(2 * i, 2 * i + 1, 2 * i + 2); mesh.add_triangle(2 * i, 2 * i + 1, 2 * i + 2);
@ -333,9 +333,11 @@ impl Gradient {
pub fn one_color(srgba: Color32) -> Self { pub fn one_color(srgba: Color32) -> Self {
Self(vec![srgba, srgba]) Self(vec![srgba, srgba])
} }
pub fn texture_gradient(left: Color32, right: Color32) -> Self { pub fn texture_gradient(left: Color32, right: Color32) -> Self {
Self(vec![left, right]) Self(vec![left, right])
} }
pub fn ground_truth_linear_gradient(left: Color32, right: Color32) -> Self { pub fn ground_truth_linear_gradient(left: Color32, right: Color32) -> Self {
let left = Rgba::from(left); let left = Rgba::from(left);
let right = Rgba::from(right); let right = Rgba::from(right);
@ -350,6 +352,7 @@ impl Gradient {
.collect(), .collect(),
) )
} }
/// This is how a bad person blends `sRGBA` /// This is how a bad person blends `sRGBA`
pub fn ground_truth_bad_srgba_gradient(left: Color32, right: Color32) -> Self { pub fn ground_truth_bad_srgba_gradient(left: Color32, right: Color32) -> Self {
let n = 255; let n = 255;

View file

@ -199,7 +199,7 @@ impl DemoWindows {
// Native: WrapApp uses a transparent window, so let's show that off: // Native: WrapApp uses a transparent window, so let's show that off:
// NOTE: the OS compositor assumes "normal" blending, so we need to hack it: // NOTE: the OS compositor assumes "normal" blending, so we need to hack it:
let [r, g, b, _] = fill.to_array(); let [r, g, b, _] = fill.to_array();
fill = egui::Color32::from_rgba_premultiplied(r, g, b, 180); fill = egui::Rgba::from_rgba_premultiplied(r, g, b, 0.70);
} }
let frame = egui::Frame::none().fill(fill); let frame = egui::Frame::none().fill(fill);
egui::CentralPanel::default().frame(frame).show(ctx, |_| {}); egui::CentralPanel::default().frame(frame).show(ctx, |_| {});

View file

@ -59,8 +59,8 @@ pub fn drop_target<R>(
let mut stroke = style.bg_stroke; let mut stroke = style.bg_stroke;
if is_being_dragged && !can_accept_what_is_being_dragged { if is_being_dragged && !can_accept_what_is_being_dragged {
// gray out: // gray out:
fill = color::tint_color_towards(fill, ui.visuals().window_fill()); fill = color::tint_rgba_towards(fill, ui.visuals().window_fill());
stroke.color = color::tint_color_towards(stroke.color, ui.visuals().window_fill()); stroke.color = color::tint_rgba_towards(stroke.color, ui.visuals().window_fill());
} }
ui.painter().set( ui.painter().set(

View file

@ -363,7 +363,7 @@ impl Tree {
fn children_ui(&mut self, ui: &mut Ui, depth: usize) -> Action { fn children_ui(&mut self, ui: &mut Ui, depth: usize) -> Action {
if depth > 0 if depth > 0
&& ui && ui
.add(Button::new("delete").text_color(Color32::RED)) .add(Button::new("delete").text_color(Rgba::RED))
.clicked() .clicked()
{ {
return Action::Delete; return Action::Delete;

View file

@ -504,7 +504,7 @@ impl EguiGlium {
pub fn on_event(&mut self, event: &glium::glutin::event::WindowEvent<'_>) { pub fn on_event(&mut self, event: &glium::glutin::event::WindowEvent<'_>) {
crate::input_to_egui( crate::input_to_egui(
self.egui_ctx.pixels_per_point(), self.egui_ctx.pixels_per_point(),
&event, event,
self.clipboard.as_mut(), self.clipboard.as_mut(),
&mut self.input_state, &mut self.input_state,
); );

View file

@ -127,9 +127,9 @@ impl Painter {
struct Vertex { struct Vertex {
a_pos: [f32; 2], a_pos: [f32; 2],
a_tc: [f32; 2], a_tc: [f32; 2],
a_srgba: [u8; 4], a_rgba: [f32; 4],
} }
implement_vertex!(Vertex, a_pos, a_tc, a_srgba); implement_vertex!(Vertex, a_pos, a_tc, a_rgba);
let vertices: Vec<Vertex> = mesh let vertices: Vec<Vertex> = mesh
.vertices .vertices
@ -137,7 +137,7 @@ impl Painter {
.map(|v| Vertex { .map(|v| Vertex {
a_pos: [v.pos.x, v.pos.y], a_pos: [v.pos.x, v.pos.y],
a_tc: [v.uv.x, v.uv.y], a_tc: [v.uv.x, v.uv.y],
a_srgba: v.color.to_array(), a_rgba: v.color.to_array(),
}) })
.collect(); .collect();

View file

@ -4,21 +4,10 @@ precision mediump float;
uniform vec2 u_screen_size; uniform vec2 u_screen_size;
attribute vec2 a_pos; attribute vec2 a_pos;
attribute vec2 a_tc; attribute vec2 a_tc;
attribute vec4 a_srgba; attribute vec4 a_rgba; // 0-1
varying vec4 v_rgba; varying vec4 v_rgba; // 0-1
varying vec2 v_tc; varying vec2 v_tc;
// 0-1 linear from 0-255 sRGB
vec3 linear_from_srgb(vec3 srgb) {
bvec3 cutoff = lessThan(srgb, vec3(10.31475));
vec3 lower = srgb / vec3(3294.6);
vec3 higher = pow((srgb + vec3(14.025)) / vec3(269.025), vec3(2.4));
return mix(higher, lower, vec3(cutoff));
}
vec4 linear_from_srgba(vec4 srgba) {
return vec4(linear_from_srgb(srgba.rgb), srgba.a / 255.0);
}
void main() { void main() {
gl_Position = vec4( gl_Position = vec4(
@ -26,7 +15,6 @@ void main() {
1.0 - 2.0 * a_pos.y / u_screen_size.y, 1.0 - 2.0 * a_pos.y / u_screen_size.y,
0.0, 0.0,
1.0); 1.0);
// egui encodes vertex colors in gamma spaces, so we must decode the colors here: v_rgba = a_srgba;
v_rgba = linear_from_srgba(a_srgba);
v_tc = a_tc; v_tc = a_tc;
} }

View file

@ -2,30 +2,17 @@
uniform vec2 u_screen_size; uniform vec2 u_screen_size;
attribute vec2 a_pos; attribute vec2 a_pos;
attribute vec4 a_srgba; // 0-255 sRGB
attribute vec2 a_tc; attribute vec2 a_tc;
varying vec4 v_rgba; attribute vec4 a_rgba; // 0-1
varying vec4 v_rgba; // 0-1
varying vec2 v_tc; varying vec2 v_tc;
// 0-1 linear from 0-255 sRGB
vec3 linear_from_srgb(vec3 srgb) {
bvec3 cutoff = lessThan(srgb, vec3(10.31475));
vec3 lower = srgb / vec3(3294.6);
vec3 higher = pow((srgb + vec3(14.025)) / vec3(269.025), vec3(2.4));
return mix(higher, lower, vec3(cutoff));
}
vec4 linear_from_srgba(vec4 srgba) {
return vec4(linear_from_srgb(srgba.rgb), srgba.a / 255.0);
}
void main() { void main() {
gl_Position = vec4( gl_Position = vec4(
2.0 * a_pos.x / u_screen_size.x - 1.0, 2.0 * a_pos.x / u_screen_size.x - 1.0,
1.0 - 2.0 * a_pos.y / u_screen_size.y, 1.0 - 2.0 * a_pos.y / u_screen_size.y,
0.0, 0.0,
1.0); 1.0);
// egui encodes vertex colors in gamma spaces, so we must decode the colors here: v_rgba = a_rgba;
v_rgba = linear_from_srgba(a_srgba);
v_tc = a_tc; v_tc = a_tc;
} }

View file

@ -2,30 +2,17 @@
uniform vec2 u_screen_size; uniform vec2 u_screen_size;
in vec2 a_pos; in vec2 a_pos;
in vec4 a_srgba; // 0-255 sRGB
in vec2 a_tc; in vec2 a_tc;
out vec4 v_rgba; in vec4 a_rgba; // 0-1
out vec4 v_rgba; // 0-1
out vec2 v_tc; out vec2 v_tc;
// 0-1 linear from 0-255 sRGB
vec3 linear_from_srgb(vec3 srgb) {
bvec3 cutoff = lessThan(srgb, vec3(10.31475));
vec3 lower = srgb / vec3(3294.6);
vec3 higher = pow((srgb + vec3(14.025)) / vec3(269.025), vec3(2.4));
return mix(higher, lower, cutoff);
}
vec4 linear_from_srgba(vec4 srgba) {
return vec4(linear_from_srgb(srgba.rgb), srgba.a / 255.0);
}
void main() { void main() {
gl_Position = vec4( gl_Position = vec4(
2.0 * a_pos.x / u_screen_size.x - 1.0, 2.0 * a_pos.x / u_screen_size.x - 1.0,
1.0 - 2.0 * a_pos.y / u_screen_size.y, 1.0 - 2.0 * a_pos.y / u_screen_size.y,
0.0, 0.0,
1.0); 1.0);
// egui encodes vertex colors in gamma spaces, so we must decode the colors here: v_rgba = a_rgba;
v_rgba = linear_from_srgba(a_srgba);
v_tc = a_tc; v_tc = a_tc;
} }

View file

@ -4,29 +4,16 @@ precision mediump float;
uniform vec2 u_screen_size; uniform vec2 u_screen_size;
attribute vec2 a_pos; attribute vec2 a_pos;
attribute vec2 a_tc; attribute vec2 a_tc;
attribute vec4 a_srgba; attribute vec4 a_rgba; // 0-1
varying vec4 v_rgba; varying vec4 v_rgba; // 0-1
varying vec2 v_tc; varying vec2 v_tc;
// 0-1 linear from 0-255 sRGB
vec3 linear_from_srgb(vec3 srgb) {
bvec3 cutoff = lessThan(srgb, vec3(10.31475));
vec3 lower = srgb / vec3(3294.6);
vec3 higher = pow((srgb + vec3(14.025)) / vec3(269.025), vec3(2.4));
return mix(higher, lower, vec3(cutoff));
}
vec4 linear_from_srgba(vec4 srgba) {
return vec4(linear_from_srgb(srgba.rgb), srgba.a / 255.0);
}
void main() { void main() {
gl_Position = vec4( gl_Position = vec4(
2.0 * a_pos.x / u_screen_size.x - 1.0, 2.0 * a_pos.x / u_screen_size.x - 1.0,
1.0 - 2.0 * a_pos.y / u_screen_size.y, 1.0 - 2.0 * a_pos.y / u_screen_size.y,
0.0, 0.0,
1.0); 1.0);
// egui encodes vertex colors in gamma spaces, so we must decode the colors here: v_rgba = a_rgba;
v_rgba = linear_from_srgba(a_srgba);
v_tc = a_tc; v_tc = a_tc;
} }

View file

@ -2,30 +2,16 @@ precision mediump float;
uniform vec2 u_screen_size; uniform vec2 u_screen_size;
attribute vec2 a_pos; attribute vec2 a_pos;
attribute vec2 a_tc; attribute vec2 a_tc;
attribute vec4 a_srgba; attribute vec4 a_rgba; // 0-1
varying vec4 v_rgba; varying vec4 v_rgba; // 0-1
varying vec2 v_tc; varying vec2 v_tc;
// 0-1 linear from 0-255 sRGB
vec3 linear_from_srgb(vec3 srgb) {
bvec3 cutoff = lessThan(srgb, vec3(10.31475));
vec3 lower = srgb / vec3(3294.6);
vec3 higher = pow((srgb + vec3(14.025)) / vec3(269.025), vec3(2.4));
return mix(higher, lower, vec3(cutoff));
}
// 0-1 linear from 0-255 sRGBA
vec4 linear_from_srgba(vec4 srgba) {
return vec4(linear_from_srgb(srgba.rgb), srgba.a / 255.0);
}
void main() { void main() {
gl_Position = vec4( gl_Position = vec4(
2.0 * a_pos.x / u_screen_size.x - 1.0, 2.0 * a_pos.x / u_screen_size.x - 1.0,
1.0 - 2.0 * a_pos.y / u_screen_size.y, 1.0 - 2.0 * a_pos.y / u_screen_size.y,
0.0, 0.0,
1.0); 1.0);
// egui encodes vertex colors in gamma spaces, so we must decode the colors here: v_rgba = a_rgba;
v_rgba = linear_from_srgba(a_srgba);
v_tc = a_tc; v_tc = a_tc;
} }

View file

@ -2,30 +2,16 @@ precision mediump float;
uniform vec2 u_screen_size; uniform vec2 u_screen_size;
attribute vec2 a_pos; attribute vec2 a_pos;
attribute vec2 a_tc; attribute vec2 a_tc;
attribute vec4 a_srgba; attribute vec4 a_rgba; // 0-1
varying vec4 v_rgba; varying vec4 v_rgba; // 0-1
varying vec2 v_tc; varying vec2 v_tc;
// 0-1 linear from 0-255 sRGB
vec3 linear_from_srgb(vec3 srgb) {
bvec3 cutoff = lessThan(srgb, vec3(10.31475));
vec3 lower = srgb / vec3(3294.6);
vec3 higher = pow((srgb + vec3(14.025)) / vec3(269.025), vec3(2.4));
return mix(higher, lower, vec3(cutoff));
}
// 0-1 linear from 0-255 sRGBA
vec4 linear_from_srgba(vec4 srgba) {
return vec4(linear_from_srgb(srgba.rgb), srgba.a / 255.0);
}
void main() { void main() {
gl_Position = vec4( gl_Position = vec4(
2.0 * a_pos.x / u_screen_size.x - 1.0, 2.0 * a_pos.x / u_screen_size.x - 1.0,
1.0 - 2.0 * a_pos.y / u_screen_size.y, 1.0 - 2.0 * a_pos.y / u_screen_size.y,
0.0, 0.0,
1.0); 1.0);
// egui encodes vertex colors in gamma spaces, so we must decode the colors here: v_rgba = a_rgba;
v_rgba = linear_from_srgba(a_srgba);
v_tc = a_tc; v_tc = a_tc;
} }

View file

@ -210,7 +210,7 @@ impl WebGlPainter {
let mut positions: Vec<f32> = Vec::with_capacity(2 * mesh.vertices.len()); let mut positions: Vec<f32> = Vec::with_capacity(2 * mesh.vertices.len());
let mut tex_coords: Vec<f32> = Vec::with_capacity(2 * mesh.vertices.len()); let mut tex_coords: Vec<f32> = Vec::with_capacity(2 * mesh.vertices.len());
let mut colors: Vec<u8> = Vec::with_capacity(4 * mesh.vertices.len()); let mut colors: Vec<f32> = Vec::with_capacity(4 * mesh.vertices.len());
for v in &mesh.vertices { for v in &mesh.vertices {
positions.push(v.pos.x); positions.push(v.pos.x);
positions.push(v.pos.y); positions.push(v.pos.y);
@ -289,29 +289,22 @@ impl WebGlPainter {
let colors_memory_buffer = wasm_bindgen::memory() let colors_memory_buffer = wasm_bindgen::memory()
.dyn_into::<WebAssembly::Memory>()? .dyn_into::<WebAssembly::Memory>()?
.buffer(); .buffer();
let colors_ptr = colors.as_ptr() as u32; let colors_ptr = colors.as_ptr() as u32 / 4;
let colors_array = js_sys::Uint8Array::new(&colors_memory_buffer) let colors_array = js_sys::Uint8Array::new(&colors_memory_buffer)
.subarray(colors_ptr, colors_ptr + colors.len() as u32); .subarray(colors_ptr, colors_ptr + colors.len() as u32);
gl.bind_buffer(Gl::ARRAY_BUFFER, Some(&self.color_buffer)); gl.bind_buffer(Gl::ARRAY_BUFFER, Some(&self.color_buffer));
gl.buffer_data_with_array_buffer_view(Gl::ARRAY_BUFFER, &colors_array, Gl::STREAM_DRAW); gl.buffer_data_with_array_buffer_view(Gl::ARRAY_BUFFER, &colors_array, Gl::STREAM_DRAW);
let a_srgba_loc = gl.get_attrib_location(&self.program, "a_srgba"); let a_rgba_loc = gl.get_attrib_location(&self.program, "a_rgba");
assert!(a_srgba_loc >= 0); assert!(a_rgba_loc >= 0);
let a_srgba_loc = a_srgba_loc as u32; let a_rgba_loc = a_rgba_loc as u32;
let normalize = false; let normalize = false;
let stride = 0; let stride = 0;
let offset = 0; let offset = 0;
gl.vertex_attrib_pointer_with_i32( gl.vertex_attrib_pointer_with_i32(a_rgba_loc, 4, Gl::FLOAT, normalize, stride, offset);
a_srgba_loc, gl.enable_vertex_attrib_array(a_rgba_loc);
4,
Gl::UNSIGNED_BYTE,
normalize,
stride,
offset,
);
gl.enable_vertex_attrib_array(a_srgba_loc);
// -------------------------------------------------------------------- // --------------------------------------------------------------------

View file

@ -211,7 +211,7 @@ impl WebGl2Painter {
let mut positions: Vec<f32> = Vec::with_capacity(2 * mesh.vertices.len()); let mut positions: Vec<f32> = Vec::with_capacity(2 * mesh.vertices.len());
let mut tex_coords: Vec<f32> = Vec::with_capacity(2 * mesh.vertices.len()); let mut tex_coords: Vec<f32> = Vec::with_capacity(2 * mesh.vertices.len());
let mut colors: Vec<u8> = Vec::with_capacity(4 * mesh.vertices.len()); let mut colors: Vec<f32> = Vec::with_capacity(4 * mesh.vertices.len());
for v in &mesh.vertices { for v in &mesh.vertices {
positions.push(v.pos.x); positions.push(v.pos.x);
positions.push(v.pos.y); positions.push(v.pos.y);
@ -290,29 +290,22 @@ impl WebGl2Painter {
let colors_memory_buffer = wasm_bindgen::memory() let colors_memory_buffer = wasm_bindgen::memory()
.dyn_into::<WebAssembly::Memory>()? .dyn_into::<WebAssembly::Memory>()?
.buffer(); .buffer();
let colors_ptr = colors.as_ptr() as u32; let colors_ptr = colors.as_ptr() as u32 / 4;
let colors_array = js_sys::Uint8Array::new(&colors_memory_buffer) let colors_array = js_sys::Uint8Array::new(&colors_memory_buffer)
.subarray(colors_ptr, colors_ptr + colors.len() as u32); .subarray(colors_ptr, colors_ptr + colors.len() as u32);
gl.bind_buffer(Gl::ARRAY_BUFFER, Some(&self.color_buffer)); gl.bind_buffer(Gl::ARRAY_BUFFER, Some(&self.color_buffer));
gl.buffer_data_with_array_buffer_view(Gl::ARRAY_BUFFER, &colors_array, Gl::STREAM_DRAW); gl.buffer_data_with_array_buffer_view(Gl::ARRAY_BUFFER, &colors_array, Gl::STREAM_DRAW);
let a_srgba_loc = gl.get_attrib_location(&self.program, "a_srgba"); let a_rgba_loc = gl.get_attrib_location(&self.program, "a_rgba");
assert!(a_srgba_loc >= 0); assert!(a_rgba_loc >= 0);
let a_srgba_loc = a_srgba_loc as u32; let a_rgba_loc = a_rgba_loc as u32;
let normalize = false; let normalize = false;
let stride = 0; let stride = 0;
let offset = 0; let offset = 0;
gl.vertex_attrib_pointer_with_i32( gl.vertex_attrib_pointer_with_i32(a_rgba_loc, 4, Gl::FLOAT, normalize, stride, offset);
a_srgba_loc, gl.enable_vertex_attrib_array(a_rgba_loc);
4,
Gl::UNSIGNED_BYTE,
normalize,
stride,
offset,
);
gl.enable_vertex_attrib_array(a_srgba_loc);
// -------------------------------------------------------------------- // --------------------------------------------------------------------

View file

@ -201,6 +201,7 @@ impl Rgba {
pub const RED: Rgba = Rgba::from_rgb(1.0, 0.0, 0.0); pub const RED: Rgba = Rgba::from_rgb(1.0, 0.0, 0.0);
pub const GREEN: Rgba = Rgba::from_rgb(0.0, 1.0, 0.0); pub const GREEN: Rgba = Rgba::from_rgb(0.0, 1.0, 0.0);
pub const BLUE: Rgba = Rgba::from_rgb(0.0, 0.0, 1.0); pub const BLUE: Rgba = Rgba::from_rgb(0.0, 0.0, 1.0);
pub const LIGHT_BLUE: Rgba = Rgba::from_rgb(0.26, 0.35, 1.0);
#[inline(always)] #[inline(always)]
pub const fn from_rgba_premultiplied(r: f32, g: f32, b: f32, a: f32) -> Self { pub const fn from_rgba_premultiplied(r: f32, g: f32, b: f32, a: f32) -> Self {
@ -753,10 +754,11 @@ impl From<Hsva> for HsvaGamma {
/// Cheap and ugly. /// Cheap and ugly.
/// Made for graying out disabled `Ui`:s. /// Made for graying out disabled `Ui`:s.
pub fn tint_color_towards(color: Color32, target: Color32) -> Color32 { pub fn tint_color32_towards(color: Color32, target: Color32) -> Color32 {
let [mut r, mut g, mut b, mut a] = color.to_array(); let [mut r, mut g, mut b, mut a] = color.to_array();
if a == 0 { if a == 0 {
// Additive color.
r /= 2; r /= 2;
g /= 2; g /= 2;
b /= 2; b /= 2;
@ -776,6 +778,11 @@ pub fn tint_color_towards(color: Color32, target: Color32) -> Color32 {
Color32::from_rgba_premultiplied(r, g, b, a) Color32::from_rgba_premultiplied(r, g, b, a)
} }
pub fn tint_rgba_towards(color: Rgba, target: Rgba) -> Rgba {
// sRGBA (gamma) is more of a perceptual color space, so we use that
tint_color32_towards(color.into(), target.into()).into()
}
#[cfg(feature = "cint")] #[cfg(feature = "cint")]
mod impl_cint { mod impl_cint {
use super::*; use super::*;

View file

@ -134,7 +134,7 @@ pub(crate) struct PaintRect {
pub rect: emath::Rect, pub rect: emath::Rect,
/// How rounded the corners are. Use `0.0` for no rounding. /// How rounded the corners are. Use `0.0` for no rounding.
pub corner_radius: f32, pub corner_radius: f32,
pub fill: Color32, pub fill: Rgba,
pub stroke: Stroke, pub stroke: Stroke,
} }

View file

@ -9,15 +9,15 @@ use emath::*;
pub struct Vertex { pub struct Vertex {
/// Logical pixel coordinates (points). /// Logical pixel coordinates (points).
/// (0,0) is the top left corner of the screen. /// (0,0) is the top left corner of the screen.
pub pos: Pos2, // 64 bit pub pos: Pos2, // 2xf32 (64 bit)
/// Normalized texture coordinates. /// Normalized texture coordinates.
/// (0, 0) is the top left corner of the texture. /// (0, 0) is the top left corner of the texture.
/// (1, 1) is the bottom right corner of the texture. /// (1, 1) is the bottom right corner of the texture.
pub uv: Pos2, // 64 bit pub uv: Pos2, // 2xf32 (64 bit)
/// sRGBA with premultiplied alpha /// Linear RGBA with premultiplied alpha
pub color: Color32, // 32 bit pub color: Rgba, // 4xf32 (128 bit)
} }
/// Textured triangles in two dimensions. /// Textured triangles in two dimensions.
@ -93,7 +93,7 @@ impl Mesh {
} }
#[inline(always)] #[inline(always)]
pub fn colored_vertex(&mut self, pos: Pos2, color: Color32) { pub fn colored_vertex(&mut self, pos: Pos2, color: Rgba) {
crate::epaint_assert!(self.texture_id == TextureId::Egui); crate::epaint_assert!(self.texture_id == TextureId::Egui);
self.vertices.push(Vertex { self.vertices.push(Vertex {
pos, pos,
@ -125,7 +125,7 @@ impl Mesh {
} }
/// Rectangle with a texture and color. /// Rectangle with a texture and color.
pub fn add_rect_with_uv(&mut self, rect: Rect, uv: Rect, color: Color32) { pub fn add_rect_with_uv(&mut self, rect: Rect, uv: Rect, color: Rgba) {
#![allow(clippy::identity_op)] #![allow(clippy::identity_op)]
let idx = self.vertices.len() as u32; let idx = self.vertices.len() as u32;
@ -156,7 +156,7 @@ impl Mesh {
/// Uniformly colored rectangle. /// Uniformly colored rectangle.
#[inline(always)] #[inline(always)]
pub fn add_colored_rect(&mut self, rect: Rect, color: Color32) { pub fn add_colored_rect(&mut self, rect: Rect, color: Rgba) {
crate::epaint_assert!(self.texture_id == TextureId::Egui); crate::epaint_assert!(self.texture_id == TextureId::Egui);
self.add_rect_with_uv(rect, [WHITE_UV, WHITE_UV].into(), color) self.add_rect_with_uv(rect, [WHITE_UV, WHITE_UV].into(), color)
} }

View file

@ -10,7 +10,7 @@ pub struct Shadow {
pub extrusion: f32, pub extrusion: f32,
/// Color of the opaque center of the shadow. /// Color of the opaque center of the shadow.
pub color: Color32, pub color: Rgba,
} }
impl Shadow { impl Shadow {
@ -18,7 +18,7 @@ impl Shadow {
pub fn small_dark() -> Self { pub fn small_dark() -> Self {
Self { Self {
extrusion: 16.0, extrusion: 16.0,
color: Color32::from_black_alpha(96), color: Color32::from_black_alpha(96).into(),
} }
} }
@ -26,7 +26,7 @@ impl Shadow {
pub fn small_light() -> Self { pub fn small_light() -> Self {
Self { Self {
extrusion: 16.0, extrusion: 16.0,
color: Color32::from_black_alpha(32), color: Color32::from_black_alpha(32).into(),
} }
} }
@ -34,7 +34,7 @@ impl Shadow {
pub fn big_dark() -> Self { pub fn big_dark() -> Self {
Self { Self {
extrusion: 32.0, extrusion: 32.0,
color: Color32::from_black_alpha(96), color: Color32::from_black_alpha(96).into(),
} }
} }
@ -42,7 +42,7 @@ impl Shadow {
pub fn big_light() -> Self { pub fn big_light() -> Self {
Self { Self {
extrusion: 32.0, extrusion: 32.0,
color: Color32::from_black_alpha(40), color: Color32::from_black_alpha(40).into(),
} }
} }

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
text::{Fonts, Galley, TextStyle}, text::{Fonts, Galley, TextStyle},
Color32, Mesh, Stroke, Mesh, Rgba, Stroke,
}; };
use emath::*; use emath::*;
@ -17,7 +17,7 @@ pub enum Shape {
Circle { Circle {
center: Pos2, center: Pos2,
radius: f32, radius: f32,
fill: Color32, fill: Rgba,
stroke: Stroke, stroke: Stroke,
}, },
LineSegment { LineSegment {
@ -30,14 +30,14 @@ pub enum Shape {
/// This is required if `fill != TRANSPARENT`. /// This is required if `fill != TRANSPARENT`.
closed: bool, closed: bool,
/// Fill is only supported for convex polygons. /// Fill is only supported for convex polygons.
fill: Color32, fill: Rgba,
stroke: Stroke, stroke: Stroke,
}, },
Rect { Rect {
rect: Rect, rect: Rect,
/// How rounded the corners are. Use `0.0` for no rounding. /// How rounded the corners are. Use `0.0` for no rounding.
corner_radius: f32, corner_radius: f32,
fill: Color32, fill: Rgba,
stroke: Stroke, stroke: Stroke,
}, },
Text { Text {
@ -46,7 +46,7 @@ pub enum Shape {
/// The layed out text. /// The layed out text.
galley: std::sync::Arc<Galley>, galley: std::sync::Arc<Galley>,
/// Text color (foreground). /// Text color (foreground).
color: Color32, color: Rgba,
/// If true, tilt the letters for a hacky italics effect. /// If true, tilt the letters for a hacky italics effect.
fake_italics: bool, fake_italics: bool,
}, },
@ -89,7 +89,7 @@ impl Shape {
/// Turn a line into equally spaced dots. /// Turn a line into equally spaced dots.
pub fn dotted_line( pub fn dotted_line(
points: &[Pos2], points: &[Pos2],
color: impl Into<Color32>, color: impl Into<Rgba>,
spacing: f32, spacing: f32,
radius: f32, radius: f32,
) -> Vec<Self> { ) -> Vec<Self> {
@ -113,7 +113,7 @@ impl Shape {
/// A convex polygon with a fill and optional stroke. /// A convex polygon with a fill and optional stroke.
pub fn convex_polygon( pub fn convex_polygon(
points: Vec<Pos2>, points: Vec<Pos2>,
fill: impl Into<Color32>, fill: impl Into<Rgba>,
stroke: impl Into<Stroke>, stroke: impl Into<Stroke>,
) -> Self { ) -> Self {
Self::Path { Self::Path {
@ -125,11 +125,11 @@ impl Shape {
} }
#[deprecated = "Renamed convex_polygon"] #[deprecated = "Renamed convex_polygon"]
pub fn polygon(points: Vec<Pos2>, fill: impl Into<Color32>, stroke: impl Into<Stroke>) -> Self { pub fn polygon(points: Vec<Pos2>, fill: impl Into<Rgba>, stroke: impl Into<Stroke>) -> Self {
Self::convex_polygon(points, fill, stroke) Self::convex_polygon(points, fill, stroke)
} }
pub fn circle_filled(center: Pos2, radius: f32, fill_color: impl Into<Color32>) -> Self { pub fn circle_filled(center: Pos2, radius: f32, fill_color: impl Into<Rgba>) -> Self {
Self::Circle { Self::Circle {
center, center,
radius, radius,
@ -147,7 +147,7 @@ impl Shape {
} }
} }
pub fn rect_filled(rect: Rect, corner_radius: f32, fill_color: impl Into<Color32>) -> Self { pub fn rect_filled(rect: Rect, corner_radius: f32, fill_color: impl Into<Rgba>) -> Self {
Self::Rect { Self::Rect {
rect, rect,
corner_radius, corner_radius,
@ -172,7 +172,7 @@ impl Shape {
anchor: Align2, anchor: Align2,
text: impl ToString, text: impl ToString,
text_style: TextStyle, text_style: TextStyle,
color: Color32, color: Rgba,
) -> Self { ) -> Self {
let galley = fonts.layout_multiline(text_style, text.to_string(), f32::INFINITY); let galley = fonts.layout_multiline(text_style, text.to_string(), f32::INFINITY);
let rect = anchor.anchor_rect(Rect::from_min_size(pos, galley.size)); let rect = anchor.anchor_rect(Rect::from_min_size(pos, galley.size));
@ -190,7 +190,7 @@ fn points_from_line(
line: &[Pos2], line: &[Pos2],
spacing: f32, spacing: f32,
radius: f32, radius: f32,
color: Color32, color: Rgba,
shapes: &mut Vec<Shape>, shapes: &mut Vec<Shape>,
) { ) {
let mut position_on_segment = 0.0; let mut position_on_segment = 0.0;

View file

@ -1,6 +1,6 @@
use crate::*; use crate::*;
pub fn adjust_colors(shape: &mut Shape, adjust_color: &impl Fn(&mut Color32)) { pub fn adjust_colors(shape: &mut Shape, adjust_color: &impl Fn(&mut Rgba)) {
#![allow(clippy::match_same_arms)] #![allow(clippy::match_same_arms)]
match shape { match shape {
Shape::Noop => {} Shape::Noop => {}

View file

@ -7,16 +7,16 @@ use super::*;
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub struct Stroke { pub struct Stroke {
pub width: f32, pub width: f32,
pub color: Color32, pub color: Rgba,
} }
impl Stroke { impl Stroke {
/// Same as [`Stroke::default`]. /// Same as [`Stroke::default`].
pub fn none() -> Self { pub fn none() -> Self {
Self::new(0.0, Color32::TRANSPARENT) Self::new(0.0, Rgba::TRANSPARENT)
} }
pub fn new(width: impl Into<f32>, color: impl Into<Color32>) -> Self { pub fn new(width: impl Into<f32>, color: impl Into<Rgba>) -> Self {
Self { Self {
width: width.into(), width: width.into(),
color: color.into(), color: color.into(),
@ -26,7 +26,7 @@ impl Stroke {
impl<Color> From<(f32, Color)> for Stroke impl<Color> From<(f32, Color)> for Stroke
where where
Color: Into<Color32>, Color: Into<Rgba>,
{ {
fn from((width, color): (f32, Color)) -> Stroke { fn from((width, color): (f32, Color)) -> Stroke {
Stroke::new(width, color) Stroke::new(width, color)

View file

@ -272,13 +272,8 @@ impl TessellationOptions {
} }
/// Tessellate the given convex area into a polygon. /// Tessellate the given convex area into a polygon.
fn fill_closed_path( fn fill_closed_path(path: &[PathPoint], color: Rgba, options: TessellationOptions, out: &mut Mesh) {
path: &[PathPoint], if color == Rgba::TRANSPARENT {
color: Color32,
options: TessellationOptions,
out: &mut Mesh,
) {
if color == Color32::TRANSPARENT {
return; return;
} }
@ -286,7 +281,7 @@ fn fill_closed_path(
if options.anti_alias { if options.anti_alias {
out.reserve_triangles(3 * n as usize); out.reserve_triangles(3 * n as usize);
out.reserve_vertices(2 * n as usize); out.reserve_vertices(2 * n as usize);
let color_outer = Color32::TRANSPARENT; let color_outer = Rgba::TRANSPARENT;
let idx_inner = out.vertices.len() as u32; let idx_inner = out.vertices.len() as u32;
let idx_outer = idx_inner + 1; let idx_outer = idx_inner + 1;
for i in 2..n { for i in 2..n {
@ -324,7 +319,7 @@ fn stroke_path(
options: TessellationOptions, options: TessellationOptions,
out: &mut Mesh, out: &mut Mesh,
) { ) {
if stroke.width <= 0.0 || stroke.color == Color32::TRANSPARENT { if stroke.width <= 0.0 || stroke.color == Rgba::TRANSPARENT {
return; return;
} }
@ -333,7 +328,7 @@ fn stroke_path(
if options.anti_alias { if options.anti_alias {
let color_inner = stroke.color; let color_inner = stroke.color;
let color_outer = Color32::TRANSPARENT; let color_outer = Rgba::TRANSPARENT;
let thin_line = stroke.width <= options.aa_size; let thin_line = stroke.width <= options.aa_size;
if thin_line { if thin_line {
@ -346,7 +341,7 @@ fn stroke_path(
// Fade out as it gets thinner: // Fade out as it gets thinner:
let color_inner = mul_color(color_inner, stroke.width / options.aa_size); let color_inner = mul_color(color_inner, stroke.width / options.aa_size);
if color_inner == Color32::TRANSPARENT { if color_inner == Rgba::TRANSPARENT {
return; return;
} }
@ -438,7 +433,7 @@ fn stroke_path(
// Fade out thin lines rather than making them thinner // Fade out thin lines rather than making them thinner
let radius = options.aa_size / 2.0; let radius = options.aa_size / 2.0;
let color = mul_color(stroke.color, stroke.width / options.aa_size); let color = mul_color(stroke.color, stroke.width / options.aa_size);
if color == Color32::TRANSPARENT { if color == Rgba::TRANSPARENT {
return; return;
} }
for p in path { for p in path {
@ -455,11 +450,10 @@ fn stroke_path(
} }
} }
fn mul_color(color: Color32, factor: f32) -> Color32 { #[inline]
fn mul_color(color: Rgba, factor: f32) -> Rgba {
crate::epaint_assert!(0.0 <= factor && factor <= 1.0); crate::epaint_assert!(0.0 <= factor && factor <= 1.0);
// As an unfortunate side-effect of using premultiplied alpha color * factor
// we need a somewhat expensive conversion to linear space and back.
color.linear_multiply(factor)
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -552,7 +546,7 @@ impl Tessellator {
path.add_open_points(&points); path.add_open_points(&points);
} }
if fill != Color32::TRANSPARENT { if fill != Rgba::TRANSPARENT {
crate::epaint_assert!( crate::epaint_assert!(
closed, closed,
"You asked to fill a path that is not closed. That makes no sense." "You asked to fill a path that is not closed. That makes no sense."
@ -634,11 +628,11 @@ impl Tessellator {
tex_size: [usize; 2], tex_size: [usize; 2],
pos: Pos2, pos: Pos2,
galley: &super::Galley, galley: &super::Galley,
color: Color32, color: Rgba,
fake_italics: bool, fake_italics: bool,
out: &mut Mesh, out: &mut Mesh,
) { ) {
if color == Color32::TRANSPARENT || galley.is_empty() { if color == Rgba::TRANSPARENT || galley.is_empty() {
return; return;
} }
if cfg!(any( if cfg!(any(