8000 add an optional custom shadow implemention setting by lictex · Pull Request #2564 · emilk/egui · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
8000

add an optional custom shadow implemention setting #2564

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG

## Unreleased
### Added ⭐
* Add `Context::(set_)shadow_painter` for overriding the default shadow implementation with custom one ([#2564](https://github.com/emilk/egui/pull/2564)).
* `Event::Key` now has a `repeat` field that is set to `true` if the event was the result of a key-repeat ([#2435](https://github.com/emilk/egui/pull/2435)).
* Add `Slider::drag_value_speed`, which lets you ask for finer precision when dragging the slider value rather than the actual slider.
* Add `Memory::any_popup_open`, which returns true if any popup is currently open ([#2464](https://github.com/emilk/egui/pull/2464)).
Expand All @@ -14,6 +15,7 @@ NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG
* Add `Response::on_hover_and_drag_cursor`.

### Changed 🔧
* `Frame::paint` now takes an extra `&Context` argument ([#2564](https://github.com/emilk/egui/pull/2564)).
* Improved plot grid appearance ([#2412](https://github.com/emilk/egui/pull/2412)).
* Improved the algorithm for picking the number of decimals to show when hovering values in the `Plot`.

Expand Down
14 changes: 10 additions & 4 deletions crates/egui/src/containers/area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ impl Area {
// Rect::from_center_size(area_rect.center(), visibility_factor * area_rect.size());

let frame = frame.multiply_with_opacity(visibility_factor);
painter.add(frame.paint(area_rect));
painter.add(frame.paint(ctx, area_rect));
}
}
}
Expand Down Expand Up @@ -378,10 +378,16 @@ impl Prepared {
bounds.max.at_least(self.state.pos + Vec2::splat(32.0)),
);

let shadow_radius = ctx.style().visuals.window_shadow.extrusion; // hacky
let clip_rect_margin = ctx.style().visuals.clip_rect_margin.max(shadow_radius);
let shadow = ctx.style().visuals.window_shadow; // hacky
let clip_rect_margin = ctx.style().visuals.clip_rect_margin;

let clip_rect = Rect::from_min_max(self.state.pos, bounds.max)
let clip_rect = ctx
.shadow_painter()
.shadow_clip_rect(
shadow,
Rect::from_min_max(self.state.pos, bounds.max),
Rounding::none(),
)
.expand(clip_rect_margin)
.intersect(bounds);

Expand Down
7 changes: 3 additions & 4 deletions crates/egui/src/containers/fram 10000 e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ impl Frame {
InnerResponse::new(ret, response)
}

pub fn paint(&self, outer_rect: Rect) -> Shape {
pub fn paint(&self, ctx: &Context, outer_rect: Rect) -> Shape {
let Self {
inner_margin: _,
outer_margin: _,
Expand All @@ -242,8 +242,7 @@ impl Frame {
if shadow == Default::default() {
frame_shape
} else {
let shadow = shadow.tessellate(outer_rect, rounding);
let shadow = Shape::Mesh(shadow);
let shadow = ctx.shadow_painter().paint(shadow, outer_rect, rounding);
Shape::Vec(vec![shadow, frame_shape])
}
}
Expand Down Expand Up @@ -274,7 +273,7 @@ impl Prepared {
} = self;

if ui.is_rect_visible(paint_rect) {
let shape = frame.paint(paint_rect);
let shape = frame.paint(ui.ctx(), paint_rect);
ui.painter().set(where_to_put_background, shape);
}

Expand Down
10 changes: 10 additions & 0 deletions crates/egui/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ struct ContextImpl {

#[cfg(feature = "accesskit")]
is_accesskit_enabled: bool,

shadow_painter: ShadowPainter,
}

impl ContextImpl {
Expand Down Expand Up @@ -1024,6 +1026,14 @@ impl Context {

Rect::from_min_size(pos, window.size())
}

pub fn shadow_painter(&self) -> RwLockReadGuard<'_, ShadowPainter> {
RwLockReadGuard::map(self.read(), |f| &f.shadow_painter)
}

pub fn set_shadow_painter(&self, custom_shadow: ShadowPainter) {
self.write().shadow_painter = custom_shadow;
}
}

impl Context {
Expand Down
1 change: 1 addition & 0 deletions crates/epaint/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ All notable changes to the epaint crate will be documented in this file.


## Unreleased
* Add `ShadowPainter` struct to support custom shadow implementions ([#2564](https://github.com/emilk/egui/pull/2564)).
* Improve the look of thin white lines ([#2437](https://github.com/emilk/egui/pull/2437)).
* Don't render `\r` (Carriage Return) ([#2452](https://github.com/emilk/egui/pull/2452)).
* Fix bug in `Mesh::split_to_u16` ([#2459](https://github.com/emilk/egui/pull/2459)).
Expand Down
2 changes: 1 addition & 1 deletion crates/epaint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub use {
bezier::{CubicBezierShape, QuadraticBezierShape},
image::{ColorImage, FontImage, ImageData, ImageDelta},
mesh::{Mesh, Mesh16, Vertex},
shadow::Shadow,
shadow::{Shadow, ShadowPainter},
shape::{
CircleShape, PaintCallback, PaintCallbackInfo, PathShape, RectShape, Rounding, Shape,
TextShape,
Expand Down
88 changes: 61 additions & 27 deletions crates/epaint/src/shadow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,38 +50,72 @@ impl Shadow {
color: Color32::from_black_alpha(16),
}
}
}

/// Functions for painting shadows
pub struct ShadowPainter {
clip_rect: std::sync::Arc<dyn Fn(Shadow, Rect, Rounding) -> Rect + Send + Sync>,
paint: std::sync::Arc<dyn Fn(Shadow, Rect, Rounding) -> Shape + Send + Sync>,
}
impl ShadowPainter {
/// Create a custom [`ShadowPainter`].
/// For arguments, see [`Self::shadow_clip_rect`] and [`Self::paint`]
pub fn new(
clip_rect: impl Fn(Shadow, Rect, Rounding) -> Rect + Send + Sync + 'static,
paint: impl Fn(Shadow, Rect, Rounding) -> Shape + Send + Sync + 'static,
) -> Self {
Self {
clip_rect: std::sync::Arc::new(clip_rect),
paint: std::sync::Arc::new(paint),
}
}

/// Transform (typically expand) a clip rect to fit the given shadow
pub fn shadow_clip_rect(&self, shadow: Shadow, content_rect: Rect, rounding: Rounding) -> Rect {
(self.clip_rect)(shadow, content_rect, rounding)
}

pub fn tessellate(&self, rect: Rect, rounding: impl Into<Rounding>) -> Mesh {
// tessellator.clip_rect = clip_rect; // TODO(emilk): culling
/// Convert a shadow into a [`Shape`]
pub fn paint(&self, shadow: Shadow, content_rect: Rect, rounding: Rounding) -> Shape {
(self.paint)(shadow, content_rect, rounding)
}
}
impl Default for ShadowPainter {
fn default() -> Self {
Self::new(
|shadow, rect, _| rect.expand(shadow.extrusion),
|shadow, rect, rounding| {
// tessellator.clip_rect = clip_rect; // TODO(emilk): culling

let Self { extrusion, color } = *self;
let Shadow { extrusion, color } = shadow;

let rounding: Rounding = rounding.into();
let half_ext = 0.5 * extrusion;
let half_ext = 0.5 * extrusion;

let ext_rounding = Rounding {
nw: rounding.nw + half_ext,
ne: rounding.ne + half_ext,
sw: rounding.sw + half_ext,
se: rounding.se + half_ext,
};
let ext_rounding = Rounding {
nw: rounding.nw + half_ext,
ne: rounding.ne + half_ext,
sw: rounding.sw + half_ext,
se: rounding.se + half_ext,
};

use crate::tessellator::*;
let rect = RectShape::filled(rect.expand(half_ext), ext_rounding, color);
let pixels_per_point = 1.0; // doesn't matter here
let font_tex_size = [1; 2]; // unused size we are not tessellating text.
let mut tessellator = Tessellator::new(
pixels_per_point,
TessellationOptions {
feathering: true,
feathering_size_in_pixels: extrusion * pixels_per_point,
..Default::default()
use crate::tessellator::*;
let rect = RectShape::filled(rect.expand(half_ext), ext_rounding, color);
let pixels_per_point = 1.0; // doesn't matter here
let font_tex_size = [1; 2]; // unused size we are not tessellating text.
let mut tessellator = Tessellator::new(
pixels_per_point,
TessellationOptions {
feathering: true,
feathering_size_in_pixels: extrusion * pixels_per_point,
..Default::default()
},
font_tex_size,
vec![],
);
let mut mesh = Mesh::default();
tessellator.tessellate_rect(&rect, &mut mesh);
Shape::Mesh(mesh)
},
font_tex_size,
vec![],
);
let mut mesh = Mesh::default();
tessellator.tessellate_rect(&rect, &mut mesh);
mesh
)
}
}
0