mirror of
https://github.com/emilk/egui.git
synced 2026-08-30 13:20:05 -04:00
Make text underline and strikethrough pixel perfect crisp (#5857)
Small visual fix: pixel-align any text underline or strikethrough. Before they could be often be blurry.
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
use std::{fmt::Debug, sync::Arc};
|
||||
|
||||
use emath::GuiRounding as _;
|
||||
|
||||
use super::{emath, Color32, ColorMode, Pos2, Rect};
|
||||
|
||||
/// Describes the width and color of a line.
|
||||
@@ -34,6 +36,46 @@ impl Stroke {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.width <= 0.0 || self.color == Color32::TRANSPARENT
|
||||
}
|
||||
|
||||
/// For vertical or horizontal lines:
|
||||
/// round the stroke center to produce a sharp, pixel-aligned line.
|
||||
pub fn round_center_to_pixel(&self, pixels_per_point: f32, coord: &mut f32) {
|
||||
// If the stroke is an odd number of pixels wide,
|
||||
// we want to round the center of it to the center of a pixel.
|
||||
//
|
||||
// If however it is an even number of pixels wide,
|
||||
// we want to round the center to be between two pixels.
|
||||
//
|
||||
// We also want to treat strokes that are _almost_ odd as it it was odd,
|
||||
// to make it symmetric. Same for strokes that are _almost_ even.
|
||||
//
|
||||
// For strokes less than a pixel wide we also round to the center,
|
||||
// because it will rendered as a single row of pixels by the tessellator.
|
||||
|
||||
let pixel_size = 1.0 / pixels_per_point;
|
||||
|
||||
if self.width <= pixel_size || is_nearest_integer_odd(pixels_per_point * self.width) {
|
||||
*coord = coord.round_to_pixel_center(pixels_per_point);
|
||||
} else {
|
||||
*coord = coord.round_to_pixels(pixels_per_point);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn round_rect_to_pixel(&self, pixels_per_point: f32, rect: &mut Rect) {
|
||||
// We put odd-width strokes in the center of pixels.
|
||||
// To understand why, see `fn round_center_to_pixel`.
|
||||
|
||||
let pixel_size = 1.0 / pixels_per_point;
|
||||
|
||||
let width = self.width;
|
||||
if width <= 0.0 {
|
||||
*rect = rect.round_to_pixels(pixels_per_point);
|
||||
} else if width <= pixel_size || is_nearest_integer_odd(pixels_per_point * width) {
|
||||
*rect = rect.round_to_pixel_center(pixels_per_point);
|
||||
} else {
|
||||
*rect = rect.round_to_pixels(pixels_per_point);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Color> From<(f32, Color)> for Stroke
|
||||
@@ -182,3 +224,21 @@ impl From<Stroke> for PathStroke {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the nearest integer is odd.
|
||||
fn is_nearest_integer_odd(x: f32) -> bool {
|
||||
(x * 0.5 + 0.25).fract() > 0.5
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_nearest_integer_odd() {
|
||||
assert!(is_nearest_integer_odd(0.6));
|
||||
assert!(is_nearest_integer_odd(1.0));
|
||||
assert!(is_nearest_integer_odd(1.4));
|
||||
assert!(!is_nearest_integer_odd(1.6));
|
||||
assert!(!is_nearest_integer_odd(2.0));
|
||||
assert!(!is_nearest_integer_odd(2.4));
|
||||
assert!(is_nearest_integer_odd(2.6));
|
||||
assert!(is_nearest_integer_odd(3.0));
|
||||
assert!(is_nearest_integer_odd(3.4));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user