mirror of
https://github.com/danbulant/cushy
synced 2026-06-16 04:51:17 +00:00
parent
1ea9938198
commit
353db9dc39
8 changed files with 108 additions and 12 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -1062,7 +1062,7 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
|||
[[package]]
|
||||
name = "kludgine"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/khonsulabs/kludgine#90d2035c22bd92ddc5e7edf6c933886c55749bd3"
|
||||
source = "git+https://github.com/khonsulabs/kludgine#2fffa618dda72fae415b2d25faf9dfe461662246"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"alot",
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ impl Object for Player {
|
|||
context.draw_texture(
|
||||
frame,
|
||||
Rect::new(center - zoomed_size / 2, Size::squared(zoomed_size)),
|
||||
1.,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ pub mod easings;
|
|||
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::ops::{ControlFlow, Deref, Div, Mul, Sub};
|
||||
use std::ops::{ControlFlow, Deref, Div, DivAssign, Mul, MulAssign, Sub};
|
||||
use std::panic::{RefUnwindSafe, UnwindSafe};
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Mutex, MutexGuard, OnceLock};
|
||||
|
|
@ -1250,6 +1250,12 @@ impl Mul for ZeroToOne {
|
|||
}
|
||||
}
|
||||
|
||||
impl MulAssign for ZeroToOne {
|
||||
fn mul_assign(&mut self, rhs: Self) {
|
||||
self.0 *= rhs.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl Div for ZeroToOne {
|
||||
type Output = Self;
|
||||
|
||||
|
|
@ -1258,6 +1264,12 @@ impl Div for ZeroToOne {
|
|||
}
|
||||
}
|
||||
|
||||
impl DivAssign for ZeroToOne {
|
||||
fn div_assign(&mut self, rhs: Self) {
|
||||
self.0 /= rhs.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<f32> for ZeroToOne {
|
||||
type Output = Self;
|
||||
|
||||
|
|
@ -1271,6 +1283,29 @@ impl Ranged for ZeroToOne {
|
|||
const MIN: Self = Self::ZERO;
|
||||
}
|
||||
|
||||
impl RequireInvalidation for ZeroToOne {
|
||||
fn requires_invalidation(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Component> for ZeroToOne {
|
||||
type Error = Component;
|
||||
|
||||
fn try_from(value: Component) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
Component::Percent(value) => Ok(value),
|
||||
other => Err(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ZeroToOne> for Component {
|
||||
fn from(value: ZeroToOne) -> Self {
|
||||
Component::Percent(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// An easing function for customizing animations.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum EasingFunction {
|
||||
|
|
|
|||
|
|
@ -14,11 +14,12 @@ use kludgine::figures::{IntoSigned, Point, Px2D, Rect, Round, ScreenScale, Size,
|
|||
use kludgine::shapes::{Shape, StrokeOptions};
|
||||
use kludgine::{Color, Kludgine};
|
||||
|
||||
use crate::animation::ZeroToOne;
|
||||
use crate::context::sealed::WindowHandle;
|
||||
use crate::graphics::Graphics;
|
||||
use crate::styles::components::{
|
||||
CornerRadius, FontFamily, FontStyle, FontWeight, HighlightColor, LayoutOrder, LineHeight,
|
||||
TextSize, WidgetBackground,
|
||||
Opacity, TextSize, WidgetBackground,
|
||||
};
|
||||
use crate::styles::{ComponentDefinition, Styles, Theme, ThemePair};
|
||||
use crate::utils::IgnorePoison;
|
||||
|
|
@ -555,19 +556,31 @@ impl<'context, 'window, 'clip, 'gfx, 'pass> GraphicsContext<'context, 'window, '
|
|||
Widget: ManageWidget,
|
||||
Widget::Managed: MapManagedWidget<GraphicsContext<'child, 'window, 'child, 'gfx, 'pass>>,
|
||||
{
|
||||
let opacity = self.get(&Opacity);
|
||||
widget.manage(self).map(|widget| {
|
||||
let widget = self.widget.for_other(&widget);
|
||||
let layout = widget.last_layout().map_or_else(
|
||||
|| Rect::from(self.gfx.clip_rect().size).into_signed(),
|
||||
|rect| rect - self.gfx.region().origin,
|
||||
);
|
||||
let mut gfx = self.gfx.clipped_to(layout);
|
||||
gfx.opacity *= opacity;
|
||||
GraphicsContext {
|
||||
widget,
|
||||
gfx: Exclusive::Owned(self.gfx.clipped_to(layout)),
|
||||
gfx: Exclusive::Owned(gfx),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Updates `self` to have `opacity`.
|
||||
///
|
||||
/// This setting will be mixed with the current opacity value.
|
||||
#[must_use]
|
||||
pub fn with_opacity(mut self, opacity: impl Into<ZeroToOne>) -> Self {
|
||||
self.gfx.opacity *= opacity.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns a new graphics context that renders to the `clip` rectangle.
|
||||
pub fn clipped_to(&mut self, clip: Rect<Px>) -> GraphicsContext<'_, 'window, '_, 'gfx, 'pass> {
|
||||
GraphicsContext {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use kludgine::{
|
|||
cosmic_text, ClipGuard, Color, Drawable, Kludgine, ShaderScalable, ShapeSource, TextureSource,
|
||||
};
|
||||
|
||||
use crate::animation::ZeroToOne;
|
||||
use crate::styles::FontFamilyList;
|
||||
|
||||
/// A 2d graphics context
|
||||
|
|
@ -20,6 +21,7 @@ pub struct Graphics<'clip, 'gfx, 'pass> {
|
|||
renderer: RenderContext<'clip, 'gfx, 'pass>,
|
||||
region: Rect<Px>,
|
||||
font_state: &'clip mut FontState,
|
||||
pub(crate) opacity: ZeroToOne,
|
||||
}
|
||||
|
||||
enum RenderContext<'clip, 'gfx, 'pass> {
|
||||
|
|
@ -35,6 +37,7 @@ impl<'clip, 'gfx, 'pass> Graphics<'clip, 'gfx, 'pass> {
|
|||
region: renderer.clip_rect().into_signed(),
|
||||
renderer: RenderContext::Renderer(renderer),
|
||||
font_state,
|
||||
opacity: ZeroToOne::ONE,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -112,6 +115,7 @@ impl<'clip, 'gfx, 'pass> Graphics<'clip, 'gfx, 'pass> {
|
|||
renderer: RenderContext::Clipped(self.renderer.clipped_to(new_clip)),
|
||||
region,
|
||||
font_state: &mut *self.font_state,
|
||||
opacity: self.opacity,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -173,6 +177,11 @@ impl<'clip, 'gfx, 'pass> Graphics<'clip, 'gfx, 'pass> {
|
|||
Unit: Zero + ShaderScalable + figures::ScreenUnit + Copy,
|
||||
{
|
||||
let mut shape = shape.into();
|
||||
shape.opacity = Some(
|
||||
shape
|
||||
.opacity
|
||||
.map_or(*self.opacity, |opacity| opacity * *self.opacity),
|
||||
);
|
||||
shape.translation += Point::<Unit>::from_px(self.translation(), self.scale());
|
||||
self.renderer.draw_shape(shape);
|
||||
}
|
||||
|
|
@ -184,7 +193,8 @@ impl<'clip, 'gfx, 'pass> Graphics<'clip, 'gfx, 'pass> {
|
|||
i32: From<<Unit as IntoSigned>::Signed>,
|
||||
{
|
||||
let translate = Point::<Unit>::from_px(self.translation(), self.scale());
|
||||
self.renderer.draw_texture(texture, destination + translate);
|
||||
self.renderer
|
||||
.draw_texture(texture, destination + translate, *self.opacity);
|
||||
}
|
||||
|
||||
/// Draws a shape that was created with texture coordinates, applying the
|
||||
|
|
@ -199,6 +209,11 @@ impl<'clip, 'gfx, 'pass> Graphics<'clip, 'gfx, 'pass> {
|
|||
Shape: ShapeSource<Unit, true> + 'shape,
|
||||
{
|
||||
let mut shape = shape.into();
|
||||
shape.opacity = Some(
|
||||
shape
|
||||
.opacity
|
||||
.map_or(*self.opacity, |opacity| opacity * *self.opacity),
|
||||
);
|
||||
shape.translation += Point::<Unit>::from_px(self.translation(), self.scale());
|
||||
self.renderer.draw_textured_shape(shape, texture);
|
||||
}
|
||||
|
|
@ -219,6 +234,10 @@ impl<'clip, 'gfx, 'pass> Graphics<'clip, 'gfx, 'pass> {
|
|||
Unit: ScreenUnit,
|
||||
{
|
||||
let mut text = text.into();
|
||||
text.opacity = Some(
|
||||
text.opacity
|
||||
.map_or(*self.opacity, |opacity| opacity * *self.opacity),
|
||||
);
|
||||
text.translation += Point::<Unit>::from_px(self.translation(), self.scale());
|
||||
self.renderer.draw_text(text);
|
||||
}
|
||||
|
|
@ -239,6 +258,11 @@ impl<'clip, 'gfx, 'pass> Graphics<'clip, 'gfx, 'pass> {
|
|||
Unit: ScreenUnit,
|
||||
{
|
||||
let mut buffer = buffer.into();
|
||||
buffer.opacity = Some(
|
||||
buffer
|
||||
.opacity
|
||||
.map_or(*self.opacity, |opacity| opacity * *self.opacity),
|
||||
);
|
||||
buffer.translation += Point::<Unit>::from_px(self.translation(), self.scale());
|
||||
self.renderer
|
||||
.draw_text_buffer(buffer, default_color, origin);
|
||||
|
|
@ -272,6 +296,10 @@ impl<'clip, 'gfx, 'pass> Graphics<'clip, 'gfx, 'pass> {
|
|||
Unit: ScreenUnit,
|
||||
{
|
||||
let mut text = text.into();
|
||||
text.opacity = Some(
|
||||
text.opacity
|
||||
.map_or(*self.opacity, |opacity| opacity * *self.opacity),
|
||||
);
|
||||
text.translation += Point::<Unit>::from_px(self.translation(), self.scale());
|
||||
self.renderer.draw_measured_text(text, origin);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use kludgine::shapes::CornerRadii;
|
|||
use kludgine::Color;
|
||||
|
||||
use crate::animation::easings::{EaseInOutQuadradic, EaseInQuadradic, EaseOutQuadradic};
|
||||
use crate::animation::EasingFunction;
|
||||
use crate::animation::{EasingFunction, ZeroToOne};
|
||||
use crate::styles::{Dimension, FocusableWidgets, FontFamilyList, VisualOrder};
|
||||
|
||||
/// Defines a set of style components for Gooey.
|
||||
|
|
@ -235,5 +235,8 @@ define_components! {
|
|||
Heading5FontFamily(FontFamilyList, "heading_font_family_5", @HeadingFontFamily)
|
||||
/// The [`FontFamilyList`] to apply to h6 headings.
|
||||
Heading6FontFamily(FontFamilyList, "heading_font_family_6", @HeadingFontFamily)
|
||||
|
||||
/// The opaqueness of drawing calls
|
||||
Opacity(ZeroToOne, "opacity", ZeroToOne::ONE)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//! Widgets that stack in the Z-direction.
|
||||
|
||||
use std::fmt;
|
||||
use std::time::Duration;
|
||||
|
||||
use alot::{LotId, OrderedLots};
|
||||
use gooey::widget::{RootBehavior, WidgetInstance};
|
||||
|
|
@ -8,6 +9,8 @@ use intentional::Assert;
|
|||
use kludgine::figures::units::{Px, UPx};
|
||||
use kludgine::figures::{IntoSigned, IntoUnsigned, Point, Rect, Size, Zero};
|
||||
|
||||
use crate::animation::easings::{EaseInQuadradic, EaseOutQuadradic};
|
||||
use crate::animation::{AnimationTarget, Spawn, ZeroToOne};
|
||||
use crate::context::{AsEventContext, EventContext, GraphicsContext, LayoutContext};
|
||||
use crate::value::{Dynamic, DynamicGuard, Generation, IntoValue, Value};
|
||||
use crate::widget::{
|
||||
|
|
@ -47,7 +50,7 @@ impl Layers {
|
|||
if self
|
||||
.mounted
|
||||
.get(index)
|
||||
.map_or(true, |child| child != widget)
|
||||
.map_or(true, |child| &child.widget != widget)
|
||||
{
|
||||
// These entries do not match. See if we can find the
|
||||
// new id somewhere else, if so we can swap the entries.
|
||||
|
|
@ -56,7 +59,7 @@ impl Layers {
|
|||
.iter()
|
||||
.enumerate()
|
||||
.skip(index + 1)
|
||||
.find(|(_, child)| *child == widget)
|
||||
.find(|(_, child)| &child.widget == widget)
|
||||
{
|
||||
self.mounted.swap(index, swap_index);
|
||||
} else {
|
||||
|
|
@ -81,8 +84,8 @@ impl Widget for Layers {
|
|||
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||
self.synchronize_children(&mut context.as_event_context());
|
||||
|
||||
for child in &self.mounted {
|
||||
context.for_other(child).redraw();
|
||||
for mounted in &self.mounted {
|
||||
context.for_other(mounted).redraw();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -186,6 +189,7 @@ impl OverlayLayer {
|
|||
requires_hover: false,
|
||||
on_dismiss: None,
|
||||
layout: None,
|
||||
opacity: Dynamic::default(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -200,7 +204,8 @@ impl Widget for OverlayLayer {
|
|||
continue;
|
||||
};
|
||||
|
||||
context.for_other(mounted).redraw();
|
||||
let opacity = child.opacity.get_tracking_refresh(context);
|
||||
context.for_other(mounted).with_opacity(opacity).redraw();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -611,6 +616,7 @@ impl OverlayBuilder<'_> {
|
|||
/// Shows this overlay, returning a handle that to the displayed overlay.
|
||||
#[must_use]
|
||||
pub fn show(self) -> OverlayHandle {
|
||||
self.fade_in();
|
||||
self.overlay.state.map_mut(|state| {
|
||||
state.new_overlays += 1;
|
||||
OverlayHandle {
|
||||
|
|
@ -620,11 +626,21 @@ impl OverlayBuilder<'_> {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn fade_in(&self) {
|
||||
self.layout
|
||||
.opacity
|
||||
.transition_to(ZeroToOne::ONE)
|
||||
.over(Duration::from_millis(250))
|
||||
.with_easing(EaseOutQuadradic)
|
||||
.launch();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
struct OverlayLayout {
|
||||
widget: WidgetRef,
|
||||
opacity: Dynamic<ZeroToOne>,
|
||||
relative_to: Option<WidgetId>,
|
||||
direction: Direction,
|
||||
requires_hover: bool,
|
||||
|
|
|
|||
|
|
@ -769,7 +769,7 @@ where
|
|||
_window: kludgine::app::Window<'_, WindowCommand>,
|
||||
graphics: &mut kludgine::RenderingGraphics<'_, 'pass>,
|
||||
) -> bool {
|
||||
self.contents.render(graphics);
|
||||
self.contents.render(1., graphics);
|
||||
|
||||
!self.should_close
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue