Files
Graphite/editor/src/document/layer_panel.rs
0HyperCube a26679b96c Font selection for text layers (#585)
* Add font dropdown

* Add fonts

* Font tool options

* Fix tests

* Replace http with https

* Add variant selection

* Do not embed default font

* Use proxied font list API

* Change default font to Merriweather

* Remove outdated comment

* Specify font once & load font into foreignobject

* Fix tests

* Rename variant to font_style

* Change TextAreaInput to use FieldInput (WIP, breaks functionality)

* Fix textarea functionality

* Fix types

* Add weight name mapping

* Change labeling of "Italic"

* Remove commented HTML node

* Rename font "name" to "font_family" and "file" "font_file"

* Fix errors

* Fix fmt

Co-authored-by: Keavon Chambers <keavon@keavon.com>
2022-04-21 09:50:44 +01:00

132 lines
3.8 KiB
Rust

use graphene::document::FontCache;
use graphene::layers::blend_mode::BlendMode;
use graphene::layers::layer_info::{Layer, LayerData, LayerDataType};
use graphene::layers::style::ViewMode;
use graphene::LayerId;
use glam::{DAffine2, DVec2};
use serde::ser::SerializeStruct;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Copy)]
pub struct LayerMetadata {
pub selected: bool,
pub expanded: bool,
}
impl LayerMetadata {
pub fn new(expanded: bool) -> LayerMetadata {
LayerMetadata { selected: false, expanded }
}
}
pub fn layer_panel_entry(layer_metadata: &LayerMetadata, transform: DAffine2, layer: &Layer, path: Vec<LayerId>, font_cache: &FontCache) -> LayerPanelEntry {
let name = layer.name.clone().unwrap_or_else(|| String::from(""));
let arr = layer.data.bounding_box(transform, font_cache).unwrap_or([DVec2::ZERO, DVec2::ZERO]);
let arr = arr.iter().map(|x| (*x).into()).collect::<Vec<(f64, f64)>>();
let mut thumbnail = String::new();
let mut svg_defs = String::new();
layer.data.clone().render(&mut thumbnail, &mut svg_defs, &mut vec![transform], ViewMode::Normal, font_cache);
let transform = transform.to_cols_array().iter().map(ToString::to_string).collect::<Vec<_>>().join(",");
let thumbnail = if let [(x_min, y_min), (x_max, y_max)] = arr.as_slice() {
format!(
r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="{} {} {} {}"><defs>{}</defs><g transform="matrix({})">{}</g></svg>"#,
x_min,
y_min,
x_max - x_min,
y_max - y_min,
svg_defs,
transform,
thumbnail,
)
} else {
String::new()
};
LayerPanelEntry {
name,
visible: layer.visible,
blend_mode: layer.blend_mode,
opacity: layer.opacity,
layer_type: (&layer.data).into(),
layer_metadata: *layer_metadata,
path,
thumbnail,
}
}
#[derive(Debug, Clone, Deserialize, PartialEq)]
pub struct RawBuffer(Vec<u8>);
impl From<Vec<u64>> for RawBuffer {
fn from(iter: Vec<u64>) -> Self {
// https://github.com/rust-lang/rust-clippy/issues/4484
let v_from_raw: Vec<u8> = unsafe {
// prepare for an auto-forget of the initial vec:
let v_orig: &mut Vec<_> = &mut *std::mem::ManuallyDrop::new(iter);
Vec::from_raw_parts(v_orig.as_mut_ptr() as *mut u8, v_orig.len() * 8, v_orig.capacity() * 8)
// v_orig is never used again, so no aliasing issue
};
Self(v_from_raw)
}
}
impl Serialize for RawBuffer {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut buffer = serializer.serialize_struct("Buffer", 2)?;
buffer.serialize_field("pointer", &(self.0.as_ptr() as usize))?;
buffer.serialize_field("length", &(self.0.len()))?;
buffer.end()
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct LayerPanelEntry {
pub name: String,
pub visible: bool,
pub blend_mode: BlendMode,
pub opacity: f64,
pub layer_type: LayerDataTypeDiscriminant,
pub layer_metadata: LayerMetadata,
pub path: Vec<LayerId>,
pub thumbnail: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum LayerDataTypeDiscriminant {
Folder,
Shape,
Text,
Image,
}
impl fmt::Display for LayerDataTypeDiscriminant {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let name = match self {
LayerDataTypeDiscriminant::Folder => "Folder",
LayerDataTypeDiscriminant::Shape => "Shape",
LayerDataTypeDiscriminant::Text => "Text",
LayerDataTypeDiscriminant::Image => "Image",
};
formatter.write_str(name)
}
}
impl From<&LayerDataType> for LayerDataTypeDiscriminant {
fn from(data: &LayerDataType) -> Self {
use LayerDataType::*;
match data {
Folder(_) => LayerDataTypeDiscriminant::Folder,
Shape(_) => LayerDataTypeDiscriminant::Shape,
Text(_) => LayerDataTypeDiscriminant::Text,
Image(_) => LayerDataTypeDiscriminant::Image,
}
}
}