2021-08-03 19:48:58 +00:00
|
|
|
use serde::Deserialize;
|
2021-04-07 05:50:13 +00:00
|
|
|
use serde_json::json;
|
2021-08-03 19:48:58 +00:00
|
|
|
use std::borrow::Cow;
|
2021-04-07 05:50:13 +00:00
|
|
|
|
2021-03-23 14:15:41 +00:00
|
|
|
use crate::{
|
2021-08-03 19:48:58 +00:00
|
|
|
color::Color,
|
2021-03-23 14:15:41 +00:00
|
|
|
fonts::{FontId, GlyphId},
|
|
|
|
geometry::{rect::RectF, vector::Vector2F},
|
2021-04-07 05:50:13 +00:00
|
|
|
json::ToJson,
|
2021-03-23 14:15:41 +00:00
|
|
|
};
|
2021-03-21 15:19:12 +00:00
|
|
|
|
2021-03-19 19:31:25 +00:00
|
|
|
pub struct Scene {
|
|
|
|
scale_factor: f32,
|
2021-08-30 15:15:09 +00:00
|
|
|
stacking_contexts: Vec<StackingContext>,
|
|
|
|
active_stacking_context_stack: Vec<usize>,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct StackingContext {
|
2021-03-19 19:31:25 +00:00
|
|
|
layers: Vec<Layer>,
|
2021-08-30 15:15:09 +00:00
|
|
|
active_layer_stack: Vec<usize>,
|
2021-03-19 19:31:25 +00:00
|
|
|
}
|
|
|
|
|
2021-04-06 11:44:38 +00:00
|
|
|
#[derive(Default)]
|
2021-03-21 04:15:04 +00:00
|
|
|
pub struct Layer {
|
2021-03-19 19:31:25 +00:00
|
|
|
clip_bounds: Option<RectF>,
|
|
|
|
quads: Vec<Quad>,
|
2021-03-22 17:05:16 +00:00
|
|
|
shadows: Vec<Shadow>,
|
2021-03-23 14:15:41 +00:00
|
|
|
glyphs: Vec<Glyph>,
|
2021-04-06 11:44:38 +00:00
|
|
|
icons: Vec<Icon>,
|
2021-03-30 04:46:26 +00:00
|
|
|
paths: Vec<Path>,
|
2021-03-19 19:31:25 +00:00
|
|
|
}
|
|
|
|
|
2021-03-21 04:15:04 +00:00
|
|
|
#[derive(Default, Debug)]
|
2021-03-19 19:31:25 +00:00
|
|
|
pub struct Quad {
|
|
|
|
pub bounds: RectF,
|
2021-08-03 19:48:58 +00:00
|
|
|
pub background: Option<Color>,
|
2021-03-19 19:31:25 +00:00
|
|
|
pub border: Border,
|
2021-03-21 17:38:23 +00:00
|
|
|
pub corner_radius: f32,
|
2021-03-19 19:31:25 +00:00
|
|
|
}
|
|
|
|
|
2021-03-23 02:54:52 +00:00
|
|
|
#[derive(Debug)]
|
2021-03-22 17:05:16 +00:00
|
|
|
pub struct Shadow {
|
|
|
|
pub bounds: RectF,
|
|
|
|
pub corner_radius: f32,
|
|
|
|
pub sigma: f32,
|
2021-08-03 19:48:58 +00:00
|
|
|
pub color: Color,
|
2021-03-22 17:05:16 +00:00
|
|
|
}
|
|
|
|
|
2021-03-23 14:15:41 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Glyph {
|
|
|
|
pub font_id: FontId,
|
|
|
|
pub font_size: f32,
|
2021-03-23 18:11:56 +00:00
|
|
|
pub id: GlyphId,
|
2021-03-23 14:15:41 +00:00
|
|
|
pub origin: Vector2F,
|
2021-08-03 19:48:58 +00:00
|
|
|
pub color: Color,
|
2021-03-23 14:15:41 +00:00
|
|
|
}
|
|
|
|
|
2021-04-06 11:44:38 +00:00
|
|
|
pub struct Icon {
|
|
|
|
pub bounds: RectF,
|
|
|
|
pub svg: usvg::Tree,
|
2021-04-27 17:58:59 +00:00
|
|
|
pub path: Cow<'static, str>,
|
2021-08-03 19:48:58 +00:00
|
|
|
pub color: Color,
|
2021-04-06 11:44:38 +00:00
|
|
|
}
|
|
|
|
|
2021-08-05 00:19:30 +00:00
|
|
|
#[derive(Clone, Copy, Default, Debug)]
|
2021-03-19 19:31:25 +00:00
|
|
|
pub struct Border {
|
|
|
|
pub width: f32,
|
2021-08-05 00:19:30 +00:00
|
|
|
pub color: Color,
|
2021-03-19 19:31:25 +00:00
|
|
|
pub top: bool,
|
|
|
|
pub right: bool,
|
|
|
|
pub bottom: bool,
|
|
|
|
pub left: bool,
|
|
|
|
}
|
|
|
|
|
2021-08-05 00:19:30 +00:00
|
|
|
impl<'de> Deserialize<'de> for Border {
|
|
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
|
|
where
|
|
|
|
D: serde::Deserializer<'de>,
|
|
|
|
{
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
struct BorderData {
|
|
|
|
pub width: f32,
|
|
|
|
pub color: Color,
|
|
|
|
#[serde(default)]
|
|
|
|
pub top: bool,
|
|
|
|
#[serde(default)]
|
|
|
|
pub right: bool,
|
|
|
|
#[serde(default)]
|
|
|
|
pub bottom: bool,
|
|
|
|
#[serde(default)]
|
|
|
|
pub left: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
let data = BorderData::deserialize(deserializer)?;
|
|
|
|
let mut border = Border {
|
|
|
|
width: data.width,
|
|
|
|
color: data.color,
|
|
|
|
top: data.top,
|
|
|
|
bottom: data.bottom,
|
|
|
|
left: data.left,
|
|
|
|
right: data.right,
|
|
|
|
};
|
|
|
|
if !border.top && !border.bottom && !border.left && !border.right {
|
|
|
|
border.top = true;
|
|
|
|
border.bottom = true;
|
|
|
|
border.left = true;
|
|
|
|
border.right = true;
|
|
|
|
}
|
|
|
|
Ok(border)
|
|
|
|
}
|
2021-08-03 20:36:58 +00:00
|
|
|
}
|
|
|
|
|
2021-03-29 23:28:35 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Path {
|
2021-03-30 04:46:26 +00:00
|
|
|
pub bounds: RectF,
|
2021-08-03 19:48:58 +00:00
|
|
|
pub color: Color,
|
2021-03-29 23:28:35 +00:00
|
|
|
pub vertices: Vec<PathVertex>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct PathVertex {
|
|
|
|
pub xy_position: Vector2F,
|
|
|
|
pub st_position: Vector2F,
|
|
|
|
}
|
|
|
|
|
2021-03-19 19:31:25 +00:00
|
|
|
impl Scene {
|
|
|
|
pub fn new(scale_factor: f32) -> Self {
|
2021-08-30 15:15:09 +00:00
|
|
|
let stacking_context = StackingContext::new(None);
|
2021-03-19 19:31:25 +00:00
|
|
|
Scene {
|
|
|
|
scale_factor,
|
2021-08-30 15:15:09 +00:00
|
|
|
stacking_contexts: vec![stacking_context],
|
|
|
|
active_stacking_context_stack: vec![0],
|
2021-03-19 19:31:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-21 15:19:12 +00:00
|
|
|
pub fn scale_factor(&self) -> f32 {
|
|
|
|
self.scale_factor
|
|
|
|
}
|
|
|
|
|
2021-08-30 13:41:16 +00:00
|
|
|
pub fn layers(&self) -> impl Iterator<Item = &Layer> {
|
2021-08-30 15:15:09 +00:00
|
|
|
self.stacking_contexts.iter().flat_map(|s| &s.layers)
|
2021-03-19 19:31:25 +00:00
|
|
|
}
|
|
|
|
|
2021-08-30 15:15:09 +00:00
|
|
|
pub fn push_stacking_context(&mut self, clip_bounds: Option<RectF>) {
|
|
|
|
self.active_stacking_context_stack
|
|
|
|
.push(self.stacking_contexts.len());
|
|
|
|
self.stacking_contexts
|
|
|
|
.push(StackingContext::new(clip_bounds))
|
2021-08-30 13:41:16 +00:00
|
|
|
}
|
|
|
|
|
2021-08-30 15:15:09 +00:00
|
|
|
pub fn pop_stacking_context(&mut self) {
|
|
|
|
self.active_stacking_context_stack.pop();
|
|
|
|
assert!(!self.active_stacking_context_stack.is_empty());
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn push_layer(&mut self, clip_bounds: Option<RectF>) {
|
|
|
|
self.active_stacking_context().push_layer(clip_bounds);
|
2021-03-22 17:55:53 +00:00
|
|
|
}
|
2021-03-21 04:15:04 +00:00
|
|
|
|
2021-03-22 17:55:53 +00:00
|
|
|
pub fn pop_layer(&mut self) {
|
2021-08-30 15:15:09 +00:00
|
|
|
self.active_stacking_context().pop_layer();
|
2021-03-22 17:55:53 +00:00
|
|
|
}
|
2021-03-21 04:15:04 +00:00
|
|
|
|
2021-03-19 19:31:25 +00:00
|
|
|
pub fn push_quad(&mut self, quad: Quad) {
|
|
|
|
self.active_layer().push_quad(quad)
|
|
|
|
}
|
|
|
|
|
2021-03-22 17:05:16 +00:00
|
|
|
pub fn push_shadow(&mut self, shadow: Shadow) {
|
|
|
|
self.active_layer().push_shadow(shadow)
|
|
|
|
}
|
|
|
|
|
2021-03-23 14:15:41 +00:00
|
|
|
pub fn push_glyph(&mut self, glyph: Glyph) {
|
|
|
|
self.active_layer().push_glyph(glyph)
|
|
|
|
}
|
|
|
|
|
2021-04-06 11:44:38 +00:00
|
|
|
pub fn push_icon(&mut self, icon: Icon) {
|
|
|
|
self.active_layer().push_icon(icon)
|
|
|
|
}
|
|
|
|
|
2021-03-30 04:46:26 +00:00
|
|
|
pub fn push_path(&mut self, path: Path) {
|
|
|
|
self.active_layer().push_path(path);
|
2021-03-29 23:28:35 +00:00
|
|
|
}
|
|
|
|
|
2021-08-30 15:15:09 +00:00
|
|
|
fn active_stacking_context(&mut self) -> &mut StackingContext {
|
|
|
|
let ix = *self.active_stacking_context_stack.last().unwrap();
|
|
|
|
&mut self.stacking_contexts[ix]
|
|
|
|
}
|
|
|
|
|
2021-03-19 19:31:25 +00:00
|
|
|
fn active_layer(&mut self) -> &mut Layer {
|
2021-08-30 15:15:09 +00:00
|
|
|
self.active_stacking_context().active_layer()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl StackingContext {
|
|
|
|
fn new(clip_bounds: Option<RectF>) -> Self {
|
|
|
|
Self {
|
|
|
|
layers: vec![Layer::new(clip_bounds)],
|
|
|
|
active_layer_stack: vec![0],
|
2021-08-30 13:41:16 +00:00
|
|
|
}
|
2021-03-19 19:31:25 +00:00
|
|
|
}
|
2021-08-30 15:15:09 +00:00
|
|
|
|
|
|
|
fn active_layer(&mut self) -> &mut Layer {
|
|
|
|
&mut self.layers[*self.active_layer_stack.last().unwrap()]
|
|
|
|
}
|
|
|
|
|
|
|
|
fn push_layer(&mut self, clip_bounds: Option<RectF>) {
|
|
|
|
let clip_bounds = clip_bounds.map(|clip_bounds| {
|
|
|
|
clip_bounds
|
|
|
|
.intersection(self.active_layer().clip_bounds.unwrap_or(clip_bounds))
|
|
|
|
.unwrap_or_else(|| {
|
|
|
|
log::warn!("specified clip bounds are disjoint from parent layer");
|
|
|
|
RectF::default()
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
|
|
|
let ix = self.layers.len();
|
|
|
|
self.layers.push(Layer::new(clip_bounds));
|
|
|
|
self.active_layer_stack.push(ix);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn pop_layer(&mut self) {
|
|
|
|
self.active_layer_stack.pop().unwrap();
|
|
|
|
assert!(!self.active_layer_stack.is_empty());
|
|
|
|
}
|
2021-03-19 19:31:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Layer {
|
2021-03-26 09:28:05 +00:00
|
|
|
pub fn new(clip_bounds: Option<RectF>) -> Self {
|
|
|
|
Self {
|
|
|
|
clip_bounds,
|
|
|
|
quads: Vec::new(),
|
|
|
|
shadows: Vec::new(),
|
|
|
|
glyphs: Vec::new(),
|
2021-04-06 11:44:38 +00:00
|
|
|
icons: Vec::new(),
|
2021-03-29 23:28:35 +00:00
|
|
|
paths: Vec::new(),
|
2021-03-26 09:28:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn clip_bounds(&self) -> Option<RectF> {
|
|
|
|
self.clip_bounds
|
|
|
|
}
|
|
|
|
|
2021-03-19 19:31:25 +00:00
|
|
|
fn push_quad(&mut self, quad: Quad) {
|
|
|
|
self.quads.push(quad);
|
|
|
|
}
|
2021-03-21 04:15:04 +00:00
|
|
|
|
|
|
|
pub fn quads(&self) -> &[Quad] {
|
|
|
|
self.quads.as_slice()
|
|
|
|
}
|
2021-03-22 17:05:16 +00:00
|
|
|
|
|
|
|
fn push_shadow(&mut self, shadow: Shadow) {
|
|
|
|
self.shadows.push(shadow);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn shadows(&self) -> &[Shadow] {
|
|
|
|
self.shadows.as_slice()
|
|
|
|
}
|
2021-03-23 14:15:41 +00:00
|
|
|
|
|
|
|
fn push_glyph(&mut self, glyph: Glyph) {
|
|
|
|
self.glyphs.push(glyph);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn glyphs(&self) -> &[Glyph] {
|
|
|
|
self.glyphs.as_slice()
|
|
|
|
}
|
2021-03-29 23:28:35 +00:00
|
|
|
|
2021-04-06 11:44:38 +00:00
|
|
|
pub fn push_icon(&mut self, icon: Icon) {
|
|
|
|
self.icons.push(icon);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn icons(&self) -> &[Icon] {
|
|
|
|
self.icons.as_slice()
|
|
|
|
}
|
|
|
|
|
2021-03-30 04:46:26 +00:00
|
|
|
fn push_path(&mut self, path: Path) {
|
2021-04-02 11:49:44 +00:00
|
|
|
if !path.bounds.is_empty() {
|
|
|
|
self.paths.push(path);
|
|
|
|
}
|
2021-03-29 23:28:35 +00:00
|
|
|
}
|
|
|
|
|
2021-03-30 04:46:26 +00:00
|
|
|
pub fn paths(&self) -> &[Path] {
|
2021-03-29 23:28:35 +00:00
|
|
|
self.paths.as_slice()
|
|
|
|
}
|
2021-03-19 19:31:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Border {
|
2021-08-03 19:48:58 +00:00
|
|
|
pub fn new(width: f32, color: Color) -> Self {
|
2021-03-19 19:31:25 +00:00
|
|
|
Self {
|
|
|
|
width,
|
2021-08-05 00:19:30 +00:00
|
|
|
color,
|
2021-03-19 19:31:25 +00:00
|
|
|
top: false,
|
|
|
|
left: false,
|
|
|
|
bottom: false,
|
|
|
|
right: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-03 19:48:58 +00:00
|
|
|
pub fn all(width: f32, color: Color) -> Self {
|
2021-03-19 19:31:25 +00:00
|
|
|
Self {
|
|
|
|
width,
|
2021-08-05 00:19:30 +00:00
|
|
|
color,
|
2021-03-19 19:31:25 +00:00
|
|
|
top: true,
|
|
|
|
left: true,
|
|
|
|
bottom: true,
|
|
|
|
right: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-03 19:48:58 +00:00
|
|
|
pub fn top(width: f32, color: Color) -> Self {
|
2021-03-19 19:31:25 +00:00
|
|
|
let mut border = Self::new(width, color);
|
|
|
|
border.top = true;
|
|
|
|
border
|
|
|
|
}
|
|
|
|
|
2021-08-03 19:48:58 +00:00
|
|
|
pub fn left(width: f32, color: Color) -> Self {
|
2021-03-19 19:31:25 +00:00
|
|
|
let mut border = Self::new(width, color);
|
|
|
|
border.left = true;
|
|
|
|
border
|
|
|
|
}
|
|
|
|
|
2021-08-03 19:48:58 +00:00
|
|
|
pub fn bottom(width: f32, color: Color) -> Self {
|
2021-03-19 19:31:25 +00:00
|
|
|
let mut border = Self::new(width, color);
|
|
|
|
border.bottom = true;
|
|
|
|
border
|
|
|
|
}
|
|
|
|
|
2021-08-03 19:48:58 +00:00
|
|
|
pub fn right(width: f32, color: Color) -> Self {
|
2021-03-19 19:31:25 +00:00
|
|
|
let mut border = Self::new(width, color);
|
|
|
|
border.right = true;
|
|
|
|
border
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn with_sides(mut self, top: bool, left: bool, bottom: bool, right: bool) -> Self {
|
|
|
|
self.top = top;
|
|
|
|
self.left = left;
|
|
|
|
self.bottom = bottom;
|
|
|
|
self.right = right;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-04-01 04:58:12 +00:00
|
|
|
pub fn top_width(&self) -> f32 {
|
|
|
|
if self.top {
|
|
|
|
self.width
|
|
|
|
} else {
|
|
|
|
0.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn left_width(&self) -> f32 {
|
|
|
|
if self.left {
|
|
|
|
self.width
|
|
|
|
} else {
|
|
|
|
0.0
|
|
|
|
}
|
|
|
|
}
|
2021-03-19 19:31:25 +00:00
|
|
|
}
|
2021-04-07 05:50:13 +00:00
|
|
|
|
|
|
|
impl ToJson for Border {
|
|
|
|
fn to_json(&self) -> serde_json::Value {
|
|
|
|
let mut value = json!({});
|
|
|
|
if self.top {
|
|
|
|
value["top"] = json!(self.width);
|
|
|
|
}
|
|
|
|
if self.right {
|
|
|
|
value["right"] = json!(self.width);
|
|
|
|
}
|
|
|
|
if self.bottom {
|
|
|
|
value["bottom"] = json!(self.width);
|
|
|
|
}
|
|
|
|
if self.left {
|
|
|
|
value["left"] = json!(self.width);
|
|
|
|
}
|
|
|
|
value
|
|
|
|
}
|
|
|
|
}
|