First commit. Version 0.1.0
This commit is contained in:
107
src/theme/surface.rs
Normal file
107
src/theme/surface.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>
|
||||
|
||||
//! Composite surfaces: fill + outer shadows + inset shadows.
|
||||
//!
|
||||
//! A [`Surface`] is the richest kind of theme slot. It packages together a
|
||||
//! fill (possibly a gradient), an elevation stack, and inset shadows with
|
||||
//! their own blend modes. Widgets that only need a flat colour or a plain
|
||||
//! gradient do not construct [`Surface`] values directly; slot promotion
|
||||
//! (in `theme::slots`) hands them a [`Surface`] with empty decorations when
|
||||
//! they ask for one against a simpler slot.
|
||||
|
||||
use super::paint::Paint;
|
||||
use super::shadow::{ InsetShadow, ShadowsRef };
|
||||
use crate::types::Color;
|
||||
|
||||
// ─── Surface ─────────────────────────────────────────────────────────────────
|
||||
|
||||
/// A composite theme surface: fill, elevation, insets.
|
||||
///
|
||||
/// All decorations are optional. A surface with `fill: Paint::Solid(...)`,
|
||||
/// no shadows and no insets behaves exactly like a flat-colour fill, which
|
||||
/// is why the promotion path from a `color` slot to a [`Surface`] is trivial.
|
||||
#[ derive( Debug, Clone, PartialEq ) ]
|
||||
pub struct Surface
|
||||
{
|
||||
/// What the surface is filled with.
|
||||
pub fill: Paint,
|
||||
/// Outer shadow stack. When `Some`, can reference another slot by name
|
||||
/// or inline the full list.
|
||||
pub shadows: Option<ShadowsRef>,
|
||||
/// Inset shadows, in back-to-front order. Each entry carries its own
|
||||
/// [`crate::theme::BlendMode`].
|
||||
pub inset_shadows: Vec<InsetShadow>,
|
||||
}
|
||||
|
||||
impl Surface
|
||||
{
|
||||
/// Build a surface from just a [`Paint`], with no shadows or insets.
|
||||
pub fn from_paint( paint: Paint ) -> Self
|
||||
{
|
||||
Self
|
||||
{
|
||||
fill: paint,
|
||||
shadows: None,
|
||||
inset_shadows: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Paint> for Surface
|
||||
{
|
||||
fn from( p: Paint ) -> Self { Surface::from_paint( p ) }
|
||||
}
|
||||
|
||||
impl From<Color> for Surface
|
||||
{
|
||||
fn from( c: Color ) -> Self { Surface::from_paint( Paint::Solid( c ) ) }
|
||||
}
|
||||
|
||||
// ─── Tests ───────────────────────────────────────────────────────────────────
|
||||
|
||||
#[ cfg( test ) ]
|
||||
mod tests
|
||||
{
|
||||
use super::*;
|
||||
use crate::types::Color;
|
||||
use crate::theme::shadow::{ BlendMode, InsetShadow, Shadow, ShadowsRef };
|
||||
|
||||
#[ test ]
|
||||
fn surface_promotes_from_color()
|
||||
{
|
||||
let s: Surface = Color::hex( 0x04, 0xD9, 0xFE ).into();
|
||||
assert_eq!( s.fill, Paint::Solid( Color::hex( 0x04, 0xD9, 0xFE ) ) );
|
||||
assert!( s.shadows.is_none() );
|
||||
assert!( s.inset_shadows.is_empty() );
|
||||
}
|
||||
|
||||
#[ test ]
|
||||
fn glass_accent_shape_composes()
|
||||
{
|
||||
let s = Surface
|
||||
{
|
||||
fill: Paint::Solid( Color::hex( 0x04, 0xD9, 0xFE ) ),
|
||||
shadows: Some( ShadowsRef::Named( "shadows-glass".to_string() ) ),
|
||||
inset_shadows: vec!
|
||||
[
|
||||
InsetShadow { offset: [ -3.6, -3.6 ], blur: 13.5, spread: 0.0, color: Color::hex( 0x55, 0x55, 0x55 ), blend: BlendMode::PlusLighter },
|
||||
InsetShadow { offset: [ 1.8, 1.8 ], blur: 1.8, spread: 0.0, color: Color::hex( 0x55, 0x55, 0x55 ), blend: BlendMode::PlusLighter },
|
||||
InsetShadow { offset: [ 0.45, 0.45 ], blur: 0.9, spread: 0.0, color: Color::BLACK, blend: BlendMode::Overlay },
|
||||
InsetShadow { offset: [ 1.8, 1.8 ], blur: 7.2, spread: 0.0, color: Color::rgba( 0.0, 0.0, 0.0, 0.15 ), blend: BlendMode::Normal },
|
||||
],
|
||||
};
|
||||
assert_eq!( s.inset_shadows.len(), 4 );
|
||||
assert_eq!( s.inset_shadows[0].blend, BlendMode::PlusLighter );
|
||||
assert_eq!( s.inset_shadows[2].blend, BlendMode::Overlay );
|
||||
|
||||
let _ = Shadow
|
||||
{
|
||||
offset: [ 0.0, 0.0 ],
|
||||
blur: 9.0,
|
||||
spread: 0.0,
|
||||
color: Color::rgba( 33.0 / 255.0, 33.0 / 255.0, 33.0 / 255.0, 0.25 ),
|
||||
blend: BlendMode::Normal,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user