mirror of
https://github.com/danbulant/cushy
synced 2026-06-20 23:11:12 +00:00
Align + Overlay + Shadow fixes
- Blur no longer expands the shadow geometry, but instead is clamped to avoid overlapping drawing calls. - Overlay now handles hit tests correctly with regards to the original relative widget. - Align was using an Into conversion that wasn't actually correct, causing the contents to not actually get aligned in some situations.
This commit is contained in:
parent
79a09ee614
commit
5c720e6009
7 changed files with 69 additions and 54 deletions
|
|
@ -4,7 +4,6 @@ use gooey::value::{Dynamic, MapEachCloned};
|
|||
use gooey::widget::MakeWidget;
|
||||
use gooey::widgets::container::ContainerShadow;
|
||||
use gooey::widgets::slider::Slidable;
|
||||
use gooey::widgets::Space;
|
||||
use gooey::Run;
|
||||
use kludgine::figures::units::Lp;
|
||||
use kludgine::figures::{Point, Size};
|
||||
|
|
@ -63,15 +62,18 @@ fn main() -> gooey::Result {
|
|||
.and(
|
||||
"Preview"
|
||||
.h3()
|
||||
.align_left()
|
||||
.and(
|
||||
Space::clear()
|
||||
"Hello, World!"
|
||||
.size(Size::squared(Lp::inches(2)))
|
||||
.contain()
|
||||
.shadow(shadow)
|
||||
.with(&CornerRadius, corners),
|
||||
.with(&CornerRadius, corners)
|
||||
.centered()
|
||||
.contain()
|
||||
.expand(),
|
||||
)
|
||||
.into_rows(),
|
||||
.into_rows()
|
||||
.expand(),
|
||||
)
|
||||
.into_columns()
|
||||
.expand()
|
||||
|
|
|
|||
|
|
@ -59,5 +59,5 @@ fn set_of_containers(repeat: usize, theme_mode: Dynamic<ThemeMode>) -> WidgetIns
|
|||
}
|
||||
|
||||
fn drop_shadow() -> ContainerShadow<Lp> {
|
||||
ContainerShadow::new(Point::new(Lp::ZERO, Lp::mm(1))).spread(Lp::mm_f(1.))
|
||||
ContainerShadow::new(Point::new(Lp::ZERO, Lp::mm(1))).spread(Lp::mm(1))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
use std::panic::UnwindSafe;
|
||||
|
||||
use gooey::widget::{MakeWidget, MakeWidgetWithId, WidgetTag};
|
||||
use gooey::widgets::container::ContainerShadow;
|
||||
use gooey::widgets::layers::{OverlayBuilder, OverlayLayer};
|
||||
use gooey::Run;
|
||||
use kludgine::figures::units::Lp;
|
||||
use kludgine::figures::Point;
|
||||
use kludgine::Color;
|
||||
use rand::{thread_rng, Rng};
|
||||
|
||||
|
|
@ -31,12 +34,18 @@ fn test_widget(overlay: &OverlayLayer, is_root: bool) -> impl MakeWidget {
|
|||
.contain();
|
||||
|
||||
if !is_root {
|
||||
buttons = buttons.background_color(Color::new(
|
||||
thread_rng().gen(),
|
||||
thread_rng().gen(),
|
||||
thread_rng().gen(),
|
||||
255,
|
||||
))
|
||||
buttons = buttons
|
||||
.background_color(Color::new(
|
||||
thread_rng().gen(),
|
||||
thread_rng().gen(),
|
||||
thread_rng().gen(),
|
||||
255,
|
||||
))
|
||||
.shadow(
|
||||
ContainerShadow::new(Point::new(Lp::ZERO, Lp::mm(2)))
|
||||
.blur_radius(Lp::mm(1))
|
||||
.spread(Lp::mm(1)),
|
||||
);
|
||||
}
|
||||
|
||||
buttons.pad().make_with_id(my_tag)
|
||||
|
|
|
|||
|
|
@ -260,19 +260,10 @@ pub enum RootBehavior {
|
|||
pub struct WrappedLayout {
|
||||
/// The region the child widget occupies within its parent.
|
||||
pub child: Rect<Px>,
|
||||
/// The size the wrapper widget should report as.q
|
||||
/// The size the wrapper widget should report as.
|
||||
pub size: Size<UPx>,
|
||||
}
|
||||
|
||||
impl From<Rect<Px>> for WrappedLayout {
|
||||
fn from(child: Rect<Px>) -> Self {
|
||||
WrappedLayout {
|
||||
child,
|
||||
size: child.size.into_unsigned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Size<Px>> for WrappedLayout {
|
||||
fn from(size: Size<Px>) -> Self {
|
||||
WrappedLayout {
|
||||
|
|
|
|||
|
|
@ -190,11 +190,13 @@ impl WrapperWidget for Align {
|
|||
) -> WrappedLayout {
|
||||
let layout = self.measure(available_space, context);
|
||||
|
||||
Rect::new(
|
||||
Point::new(layout.margin.left, layout.margin.top).into_signed(),
|
||||
layout.content.into_signed(),
|
||||
)
|
||||
.into()
|
||||
WrappedLayout {
|
||||
child: Rect::new(
|
||||
Point::new(layout.margin.left, layout.margin.top).into_signed(),
|
||||
layout.content.into_signed(),
|
||||
),
|
||||
size: layout.content + layout.margin.size(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ impl Widget for Container {
|
|||
|
||||
// check if the shadow would be obscured before we try to draw it.
|
||||
if child_area.origin != Point::ZERO || child_size != context.gfx.region().size {
|
||||
render_shadow(&child_area, &corner_radii, &shadow, background, context);
|
||||
render_shadow(&child_area, corner_radii, &shadow, background, context);
|
||||
}
|
||||
|
||||
context.gfx.draw_shape(&Shape::filled_round_rect(
|
||||
|
|
@ -246,8 +246,33 @@ impl Widget for Container {
|
|||
) -> Size<UPx> {
|
||||
let child = self.child.mounted(context);
|
||||
|
||||
let padding = self.padding(context).into_upx(context.gfx.scale());
|
||||
let corner_radii = context.get(&CornerRadius).into_upx(context.gfx.scale());
|
||||
|
||||
let max_space = available_space.map(ConstraintLimit::max);
|
||||
let min_dimension = max_space.width.min(max_space.height);
|
||||
let max_corner_radii = min_dimension / 2;
|
||||
|
||||
let corner_radii = corner_radii.map(|r| r.min(max_corner_radii));
|
||||
|
||||
let mut padding = self.padding(context).into_upx(context.gfx.scale());
|
||||
padding.left = padding
|
||||
.left
|
||||
.max(corner_radii.top_left / std::f32::consts::PI)
|
||||
.max(corner_radii.bottom_left / std::f32::consts::PI);
|
||||
padding.right = padding
|
||||
.right
|
||||
.max(corner_radii.top_right / std::f32::consts::PI)
|
||||
.max(corner_radii.bottom_right / std::f32::consts::PI);
|
||||
padding.top = padding
|
||||
.top
|
||||
.max(corner_radii.top_right / std::f32::consts::PI)
|
||||
.max(corner_radii.top_left / std::f32::consts::PI);
|
||||
padding.bottom = padding
|
||||
.bottom
|
||||
.max(corner_radii.bottom_right / std::f32::consts::PI)
|
||||
.max(corner_radii.bottom_left / std::f32::consts::PI);
|
||||
let padding_amount = padding.size();
|
||||
|
||||
let shadow = self.effective_shadow(context).into_px(context.gfx.scale());
|
||||
let shadow_spread = shadow.spread.into_unsigned();
|
||||
|
||||
|
|
@ -266,21 +291,7 @@ impl Widget for Container {
|
|||
.into_signed(),
|
||||
);
|
||||
|
||||
let corner_radii = context.get(&CornerRadius).into_upx(context.gfx.scale());
|
||||
let max_corner = corner_radii
|
||||
.top_left
|
||||
.max(corner_radii.top_right)
|
||||
.max(corner_radii.bottom_left)
|
||||
.max(corner_radii.bottom_right);
|
||||
let max_blur = (child_size
|
||||
.width
|
||||
.min(child_size.height)
|
||||
.saturating_sub(shadow.spread.into_unsigned())
|
||||
/ 2)
|
||||
.saturating_sub(max_corner);
|
||||
let blur_overage = shadow.blur_radius.into_unsigned().saturating_sub(max_blur);
|
||||
|
||||
child_size + padding_amount + child_shadow_offset_amount + shadow_spread * 2 + blur_overage
|
||||
child_size + padding_amount + child_shadow_offset_amount + shadow_spread * 2
|
||||
}
|
||||
|
||||
fn root_behavior(
|
||||
|
|
@ -320,7 +331,7 @@ impl Widget for Container {
|
|||
#[allow(clippy::too_many_lines)]
|
||||
fn render_shadow(
|
||||
child_area: &Rect<Px>,
|
||||
corner_radii: &CornerRadii<Px>,
|
||||
mut corner_radii: CornerRadii<Px>,
|
||||
shadow: &ContainerShadow<Px>,
|
||||
background: Color,
|
||||
context: &mut GraphicsContext<'_, '_, '_, '_, '_>,
|
||||
|
|
@ -329,15 +340,19 @@ fn render_shadow(
|
|||
let shadow_color =
|
||||
shadow_color.with_alpha_f32(shadow_color.alpha_f32() * background.alpha_f32());
|
||||
|
||||
let min_dimension = child_area.size.width.min(child_area.size.height);
|
||||
let max_corner_radii = min_dimension / 2;
|
||||
|
||||
corner_radii = corner_radii.map(|r| r.min(max_corner_radii));
|
||||
|
||||
let max_corner = corner_radii
|
||||
.top_left
|
||||
.max(corner_radii.top_right)
|
||||
.max(corner_radii.bottom_left)
|
||||
.max(corner_radii.bottom_right);
|
||||
|
||||
let max_blur =
|
||||
(child_area.size.width.min(child_area.size.height) - shadow.spread) / 2 - max_corner;
|
||||
let blur = shadow.blur_radius.min(max_blur);
|
||||
let max_blur = min_dimension / 2 - max_corner;
|
||||
let blur = shadow.blur_radius.min(max_blur).max(Px::ZERO);
|
||||
let gradient_size = shadow.spread + blur;
|
||||
|
||||
if gradient_size > 0 {
|
||||
|
|
@ -544,7 +559,7 @@ fn render_shadow(
|
|||
} else {
|
||||
context.gfx.draw_shape(&Shape::filled_round_rect(
|
||||
Rect::new(shadow.offset.max(Point::ZERO), child_area.size),
|
||||
*corner_radii,
|
||||
corner_radii,
|
||||
shadow_color,
|
||||
));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -250,11 +250,7 @@ impl Widget for OverlayLayer {
|
|||
|
||||
fn hit_test(&mut self, location: Point<Px>, context: &mut EventContext<'_, '_>) -> bool {
|
||||
let state = self.state.lock();
|
||||
if let Some(index) = state.test_point(location, false, context) {
|
||||
index > 0
|
||||
} else {
|
||||
!(state.overlays.is_empty() || state.point_is_in_root_relative(location, context))
|
||||
}
|
||||
state.test_point(location, false, context).is_some()
|
||||
}
|
||||
|
||||
fn hover(
|
||||
|
|
|
|||
Loading…
Reference in a new issue