143 lines
3.3 KiB
Rust
143 lines
3.3 KiB
Rust
use super::constrain_size_preserving_aspect_ratio;
|
|
use crate::json::ToJson;
|
|
use crate::{
|
|
color::Color,
|
|
geometry::{
|
|
rect::RectF,
|
|
vector::{vec2f, Vector2F},
|
|
},
|
|
scene, Element, LayoutContext, SceneBuilder, SizeConstraint, View, ViewContext,
|
|
};
|
|
use schemars::JsonSchema;
|
|
use serde_derive::Deserialize;
|
|
use serde_json::json;
|
|
use std::{borrow::Cow, ops::Range};
|
|
|
|
pub struct Svg {
|
|
path: Cow<'static, str>,
|
|
color: Color,
|
|
}
|
|
|
|
impl Svg {
|
|
pub fn new(path: impl Into<Cow<'static, str>>) -> Self {
|
|
Self {
|
|
path: path.into(),
|
|
color: Color::black(),
|
|
}
|
|
}
|
|
|
|
pub fn for_style<V: View>(style: SvgStyle) -> impl Element<V> {
|
|
Self::new(style.asset)
|
|
.with_color(style.color)
|
|
.constrained()
|
|
.with_width(style.dimensions.width)
|
|
.with_height(style.dimensions.height)
|
|
}
|
|
|
|
pub fn with_color(mut self, color: Color) -> Self {
|
|
self.color = color;
|
|
self
|
|
}
|
|
}
|
|
|
|
impl<V: View> Element<V> for Svg {
|
|
type LayoutState = Option<usvg::Tree>;
|
|
type PaintState = ();
|
|
|
|
fn layout(
|
|
&mut self,
|
|
constraint: SizeConstraint,
|
|
_: &mut V,
|
|
cx: &mut LayoutContext<V>,
|
|
) -> (Vector2F, Self::LayoutState) {
|
|
match cx.asset_cache.svg(&self.path) {
|
|
Ok(tree) => {
|
|
let size = constrain_size_preserving_aspect_ratio(
|
|
constraint.max,
|
|
from_usvg_rect(tree.svg_node().view_box.rect).size(),
|
|
);
|
|
(size, Some(tree))
|
|
}
|
|
Err(_error) => {
|
|
#[cfg(not(any(test, feature = "test-support")))]
|
|
log::error!("{}", _error);
|
|
(constraint.min, None)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn paint(
|
|
&mut self,
|
|
scene: &mut SceneBuilder,
|
|
bounds: RectF,
|
|
_visible_bounds: RectF,
|
|
svg: &mut Self::LayoutState,
|
|
_: &mut V,
|
|
_: &mut ViewContext<V>,
|
|
) {
|
|
if let Some(svg) = svg.clone() {
|
|
scene.push_icon(scene::Icon {
|
|
bounds,
|
|
svg,
|
|
path: self.path.clone(),
|
|
color: self.color,
|
|
});
|
|
}
|
|
}
|
|
|
|
fn rect_for_text_range(
|
|
&self,
|
|
_: Range<usize>,
|
|
_: RectF,
|
|
_: RectF,
|
|
_: &Self::LayoutState,
|
|
_: &Self::PaintState,
|
|
_: &V,
|
|
_: &ViewContext<V>,
|
|
) -> Option<RectF> {
|
|
None
|
|
}
|
|
|
|
fn debug(
|
|
&self,
|
|
bounds: RectF,
|
|
_: &Self::LayoutState,
|
|
_: &Self::PaintState,
|
|
_: &V,
|
|
_: &ViewContext<V>,
|
|
) -> serde_json::Value {
|
|
json!({
|
|
"type": "Svg",
|
|
"bounds": bounds.to_json(),
|
|
"path": self.path,
|
|
"color": self.color.to_json(),
|
|
})
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
|
pub struct SvgStyle {
|
|
pub color: Color,
|
|
pub asset: String,
|
|
pub dimensions: Dimensions,
|
|
}
|
|
|
|
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
|
pub struct Dimensions {
|
|
pub width: f32,
|
|
pub height: f32,
|
|
}
|
|
|
|
impl Dimensions {
|
|
pub fn to_vec(&self) -> Vector2F {
|
|
vec2f(self.width, self.height)
|
|
}
|
|
}
|
|
|
|
fn from_usvg_rect(rect: usvg::Rect) -> RectF {
|
|
RectF::new(
|
|
vec2f(rect.x() as f32, rect.y() as f32),
|
|
vec2f(rect.width() as f32, rect.height() as f32),
|
|
)
|
|
}
|