mirror of
https://github.com/emilk/egui.git
synced 2026-06-26 22:53:14 -04:00
Fade out the edges of ScrollAreas (#8018)
## Before: <img width="381" height="307" alt="image" src="https://github.com/user-attachments/assets/0528ae2a-44bf-4d9e-89a4-c3f4ab438eb2" /> It is very hard here to realize this is a scrollable area ## After <img width="383" height="310" alt="image" src="https://github.com/user-attachments/assets/9e0ee6de-8b96-4e5c-a505-f57977010990" /> The fade at the bottom tells the user they should try scrolling. You can turn if off with `style.spacing.scroll.fade.enabled`
This commit is contained in:
27
crates/epaint/src/direction.rs
Normal file
27
crates/epaint/src/direction.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
/// A cardinal direction, one of [`LeftToRight`](Direction::LeftToRight), [`RightToLeft`](Direction::RightToLeft), [`TopDown`](Direction::TopDown), [`BottomUp`](Direction::BottomUp).
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub enum Direction {
|
||||
LeftToRight,
|
||||
RightToLeft,
|
||||
TopDown,
|
||||
BottomUp,
|
||||
}
|
||||
|
||||
impl Direction {
|
||||
#[inline(always)]
|
||||
pub fn is_horizontal(self) -> bool {
|
||||
match self {
|
||||
Self::LeftToRight | Self::RightToLeft => true,
|
||||
Self::TopDown | Self::BottomUp => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_vertical(self) -> bool {
|
||||
match self {
|
||||
Self::LeftToRight | Self::RightToLeft => false,
|
||||
Self::TopDown | Self::BottomUp => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ mod brush;
|
||||
pub mod color;
|
||||
mod corner_radius;
|
||||
mod corner_radius_f32;
|
||||
mod direction;
|
||||
pub mod image;
|
||||
mod margin;
|
||||
mod margin_f32;
|
||||
@@ -50,6 +51,7 @@ pub use self::{
|
||||
color::ColorMode,
|
||||
corner_radius::CornerRadius,
|
||||
corner_radius_f32::CornerRadiusF32,
|
||||
direction::Direction,
|
||||
image::{AlphaFromCoverage, ColorImage, ImageData, ImageDelta},
|
||||
margin::Margin,
|
||||
margin_f32::*,
|
||||
|
||||
@@ -23,6 +23,18 @@ pub struct Vertex {
|
||||
pub color: Color32, // 32 bit
|
||||
}
|
||||
|
||||
impl Vertex {
|
||||
/// An untextured vertex
|
||||
#[inline]
|
||||
pub fn untextured(pos: Pos2, color: Color32) -> Self {
|
||||
Self {
|
||||
pos,
|
||||
uv: WHITE_UV,
|
||||
color,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
#[cfg(all(feature = "unity", not(feature = "_override_unity")))]
|
||||
@@ -159,11 +171,7 @@ impl Mesh {
|
||||
self.texture_id == TextureId::default(),
|
||||
"Mesh has an assigned texture"
|
||||
);
|
||||
self.vertices.push(Vertex {
|
||||
pos,
|
||||
uv: WHITE_UV,
|
||||
color,
|
||||
});
|
||||
self.vertices.push(Vertex::untextured(pos, color));
|
||||
}
|
||||
|
||||
/// Add a triangle.
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::sync::Arc;
|
||||
use emath::{Align2, Pos2, Rangef, Rect, TSTransform, Vec2, pos2};
|
||||
|
||||
use crate::{
|
||||
Color32, CornerRadius, Mesh, Stroke, StrokeKind, TextureId,
|
||||
Color32, CornerRadius, Direction, Mesh, Stroke, StrokeKind, TextureId, Vertex,
|
||||
stroke::PathStroke,
|
||||
text::{FontId, FontsView, Galley},
|
||||
};
|
||||
@@ -297,6 +297,32 @@ impl Shape {
|
||||
Self::Rect(RectShape::stroke(rect, corner_radius, stroke, stroke_kind))
|
||||
}
|
||||
|
||||
/// Paints a gradient rectangle that transitions from `color_from` to `color_to`
|
||||
/// along the given `direction`.
|
||||
///
|
||||
/// For example, [`Direction::TopDown`] paints `color_from` at the top edge fading
|
||||
/// to `color_to` at the bottom edge.
|
||||
#[inline]
|
||||
pub fn gradient_rect(rect: Rect, direction: Direction, [from, to]: [Color32; 2]) -> Self {
|
||||
let (left_top, right_top, left_bottom, right_bottom) = match direction {
|
||||
Direction::TopDown => (from, from, to, to),
|
||||
Direction::BottomUp => (to, to, from, from),
|
||||
Direction::LeftToRight => (from, to, from, to),
|
||||
Direction::RightToLeft => (to, from, to, from),
|
||||
};
|
||||
|
||||
Self::from(Mesh {
|
||||
indices: vec![0, 1, 2, 2, 1, 3],
|
||||
vertices: vec![
|
||||
Vertex::untextured(rect.left_top(), left_top),
|
||||
Vertex::untextured(rect.right_top(), right_top),
|
||||
Vertex::untextured(rect.left_bottom(), left_bottom),
|
||||
Vertex::untextured(rect.right_bottom(), right_bottom),
|
||||
],
|
||||
texture_id: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
#[expect(clippy::needless_pass_by_value)]
|
||||
pub fn text(
|
||||
fonts: &mut FontsView<'_>,
|
||||
|
||||
@@ -10,8 +10,8 @@ use emath::{GuiRounding as _, NumExt as _, Pos2, Rect, Rot2, Vec2, pos2, remap,
|
||||
use crate::{
|
||||
CircleShape, ClippedPrimitive, ClippedShape, Color32, CornerRadiusF32, CubicBezierShape,
|
||||
EllipseShape, Mesh, PathShape, Primitive, QuadraticBezierShape, RectShape, Shape, Stroke,
|
||||
StrokeKind, TextShape, TextureId, Vertex, WHITE_UV, color::ColorMode, emath,
|
||||
stroke::PathStroke, texture_atlas::PreparedDisc,
|
||||
StrokeKind, TextShape, TextureId, Vertex, color::ColorMode, emath, stroke::PathStroke,
|
||||
texture_atlas::PreparedDisc,
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -809,11 +809,8 @@ fn fill_closed_path(feathering: f32, path: &mut [PathPoint], fill_color: Color32
|
||||
} else {
|
||||
out.reserve_triangles(n as usize);
|
||||
let idx = out.vertices.len() as u32;
|
||||
out.vertices.extend(path.iter().map(|p| Vertex {
|
||||
pos: p.pos,
|
||||
uv: WHITE_UV,
|
||||
color: fill_color,
|
||||
}));
|
||||
out.vertices
|
||||
.extend(path.iter().map(|p| Vertex::untextured(p.pos, fill_color)));
|
||||
for i in 2..n {
|
||||
out.add_triangle(idx, idx + i - 1, idx + i);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user