mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-17 23:38:06 +08:00
thumbnails
This commit is contained in:
@@ -21,7 +21,7 @@ pub mod ui_context;
|
||||
#[node_macro::node(skip_impl)]
|
||||
pub fn generate_nodes(_: impl Ctx, mut node_graph_overlay_data: NodeGraphOverlayData) -> Table<Graphic> {
|
||||
let mut nodes_and_wires = Table::new();
|
||||
let (layers, side_ports) = draw_layers(&node_graph_overlay_data.nodes_to_render);
|
||||
let (layers, side_ports) = draw_layers(&mut node_graph_overlay_data);
|
||||
nodes_and_wires.extend(layers);
|
||||
|
||||
let wires = draw_wires(&mut node_graph_overlay_data.nodes_to_render);
|
||||
|
||||
@@ -8,13 +8,14 @@ use crate::{
|
||||
consts::SOURCE_SANS_FONT_DATA,
|
||||
node_graph_overlay::{
|
||||
consts::*,
|
||||
types::{FrontendGraphDataType, FrontendNodeToRender},
|
||||
types::{FrontendGraphDataType, FrontendNodeToRender, NodeGraphOverlayData},
|
||||
},
|
||||
table::{Table, TableRow},
|
||||
text::{self, TextAlign, TypesettingConfig},
|
||||
transform::ApplyTransform,
|
||||
vector::{
|
||||
Vector,
|
||||
style::{Fill, Stroke},
|
||||
style::{Fill, Stroke, StrokeAlign},
|
||||
},
|
||||
};
|
||||
@@ -211,10 +212,10 @@ pub fn draw_nodes(nodes: &Vec<FrontendNodeToRender>) -> Table<Graphic> {
|
||||
node_table
|
||||
}
|
||||
|
||||
pub fn draw_layers(nodes: &Vec<FrontendNodeToRender>) -> (Table<Graphic>, Table<Graphic>) {
|
||||
pub fn draw_layers(nodes: &mut NodeGraphOverlayData) -> (Table<Graphic>, Table<Graphic>) {
|
||||
let mut layer_table = Table::new();
|
||||
let mut side_ports_table = Table::new();
|
||||
for node_to_render in nodes {
|
||||
for node_to_render in &nodes.nodes_to_render {
|
||||
if let Some(frontend_layer) = node_to_render.node_or_layer.layer.as_ref() {
|
||||
// The layer position is the top left of the thumbnail
|
||||
let layer_position = DVec2::new(frontend_layer.position.x as f64 * GRID_SIZE + 12., frontend_layer.position.y as f64 * GRID_SIZE);
|
||||
@@ -360,7 +361,7 @@ pub fn draw_layers(nodes: &Vec<FrontendNodeToRender>) -> (Table<Graphic>, Table<
|
||||
}
|
||||
let bottom_port = BezPath::from_svg("M0,0H8V8L5.479,6.319a2.666,2.666,0,0,0-2.959,0L0,8Z").unwrap();
|
||||
let mut vector = Vector::from_bezpath(bottom_port);
|
||||
let mut bottom_port_fill = if frontend_layer.bottom_input.connected_to_node.is_some() {
|
||||
let bottom_port_fill = if frontend_layer.bottom_input.connected_to_node.is_some() {
|
||||
frontend_layer.bottom_input.data_type.data_color()
|
||||
} else {
|
||||
frontend_layer.bottom_input.data_type.data_color_dim()
|
||||
@@ -457,10 +458,34 @@ pub fn draw_layers(nodes: &Vec<FrontendNodeToRender>) -> (Table<Graphic>, Table<
|
||||
inner_thumbnail_table.push(TableRow::new_from_element(vector));
|
||||
}
|
||||
}
|
||||
let mut thumbnail_row = TableRow::new_from_element(Graphic::Vector(inner_thumbnail_table));
|
||||
thumbnail_row.alpha_blending.clip = true;
|
||||
let graphic_table = Table::new_from_row(thumbnail_row);
|
||||
layer_table.push(TableRow::new_from_element(Graphic::Graphic(graphic_table)));
|
||||
let mut thumbnail_grid_row = TableRow::new_from_element(Graphic::Vector(inner_thumbnail_table));
|
||||
thumbnail_grid_row.alpha_blending.clip = true;
|
||||
let mut clipped_thumbnail_table = Table::new();
|
||||
clipped_thumbnail_table.push(thumbnail_grid_row);
|
||||
if let Some(thumbnail_graphic) = nodes.thumbnails.get_mut(&node_to_render.metadata.node_id) {
|
||||
let thumbnail_graphic = std::mem::take(thumbnail_graphic);
|
||||
let bbox = thumbnail_graphic.bounding_box(DAffine2::default(), false);
|
||||
if let RenderBoundingBox::Rectangle(rect) = bbox {
|
||||
let rect_size = rect[1] - rect[0];
|
||||
let target_size = DVec2::new(68., 44.);
|
||||
// uniform scale that fits in target box
|
||||
let scale_x = target_size.x / rect_size.x;
|
||||
let scale_y = target_size.y / rect_size.y;
|
||||
let scale = scale_x.min(scale_y);
|
||||
|
||||
let translation = rect[0] * -scale;
|
||||
let scaled_size = rect_size * scale;
|
||||
let offset_to_center = (target_size - scaled_size) / 2.;
|
||||
|
||||
let mut thumbnail_graphic_row = TableRow::new_from_element(thumbnail_graphic);
|
||||
thumbnail_graphic_row.transform = DAffine2::from_translation(layer_position + offset_to_center) * DAffine2::from_scale_angle_translation(DVec2::splat(scale), 0., translation);
|
||||
thumbnail_graphic_row.alpha_blending.clip = true;
|
||||
|
||||
clipped_thumbnail_table.push(thumbnail_graphic_row);
|
||||
}
|
||||
}
|
||||
|
||||
layer_table.push(TableRow::new_from_element(Graphic::Graphic(clipped_thumbnail_table)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,11 @@ use glam::{DAffine2, DVec2};
|
||||
use graphene_core_shaders::color::Color;
|
||||
use kurbo::BezPath;
|
||||
|
||||
use crate::{node_graph_overlay::consts::*, uuid::NodeId};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use crate::{Graphic, node_graph_overlay::consts::*, uuid::NodeId};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
hash::{Hash, Hasher},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, dyn_any::DynAny, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||
pub struct NodeGraphTransform {
|
||||
@@ -27,13 +30,28 @@ impl NodeGraphTransform {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Hash, dyn_any::DynAny, serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, Debug, Default, PartialEq, dyn_any::DynAny, serde::Serialize, serde::Deserialize)]
|
||||
pub struct NodeGraphOverlayData {
|
||||
pub nodes_to_render: Vec<FrontendNodeToRender>,
|
||||
pub open: bool,
|
||||
pub in_selected_network: bool,
|
||||
// Displays a dashed border around the node
|
||||
pub previewed_node: Option<NodeId>,
|
||||
pub thumbnails: HashMap<NodeId, Graphic>,
|
||||
}
|
||||
|
||||
impl Hash for NodeGraphOverlayData {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.nodes_to_render.hash(state);
|
||||
self.open.hash(state);
|
||||
self.in_selected_network.hash(state);
|
||||
self.previewed_node.hash(state);
|
||||
let mut entries: Vec<_> = self.thumbnails.iter().collect();
|
||||
entries.sort_by(|a, b| a.0.cmp(b.0));
|
||||
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
||||
entries.hash(&mut hasher);
|
||||
hasher.finish();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, dyn_any::DynAny, serde::Serialize, serde::Deserialize)]
|
||||
|
||||
@@ -9,6 +9,7 @@ use graphene_core::color::Color;
|
||||
use graphene_core::gradient::GradientStops;
|
||||
use graphene_core::gradient::GradientType;
|
||||
use graphene_core::math::quad::Quad;
|
||||
use graphene_core::node_graph_overlay::consts::BEZ_PATH_TOLERANCE;
|
||||
use graphene_core::raster::BitmapMut;
|
||||
use graphene_core::raster::Image;
|
||||
use graphene_core::raster_types::{CPU, GPU, Raster};
|
||||
@@ -23,6 +24,8 @@ use graphene_core::vector::click_target::{ClickTarget, FreePoint};
|
||||
use graphene_core::vector::style::{Fill, PaintOrder, Stroke, StrokeAlign, ViewMode};
|
||||
use graphene_core::{Artboard, Graphic};
|
||||
use kurbo::Affine;
|
||||
use kurbo::Rect;
|
||||
use kurbo::Shape;
|
||||
use num_traits::Zero;
|
||||
use skrifa::MetadataProvider;
|
||||
use skrifa::attribute::Style;
|
||||
@@ -247,6 +250,8 @@ pub trait Render: BoundingBox + RenderComplexity {
|
||||
#[cfg(feature = "vello")]
|
||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, _render_params: &RenderParams);
|
||||
|
||||
fn to_graphic(self) -> Graphic;
|
||||
|
||||
/// The upstream click targets for each layer are collected during the render so that they do not have to be calculated for each click detection.
|
||||
fn add_upstream_click_targets(&self, _click_targets: &mut Vec<ClickTarget>) {}
|
||||
|
||||
@@ -289,6 +294,17 @@ impl Render for Graphic {
|
||||
}
|
||||
}
|
||||
|
||||
fn to_graphic(self) -> Graphic {
|
||||
match self {
|
||||
Graphic::Graphic(table) => table.to_graphic(),
|
||||
Graphic::Vector(table) => table.to_graphic(),
|
||||
Graphic::RasterCPU(table) => table.to_graphic(),
|
||||
Graphic::RasterGPU(table) => table.to_graphic(),
|
||||
Graphic::Color(table) => table.to_graphic(),
|
||||
Graphic::Gradient(table) => table.to_graphic(),
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, element_id: Option<NodeId>) {
|
||||
if let Some(element_id) = element_id {
|
||||
match self {
|
||||
@@ -467,6 +483,23 @@ impl Render for Artboard {
|
||||
}
|
||||
}
|
||||
|
||||
fn to_graphic(self) -> Graphic {
|
||||
let bg = Rect::new(
|
||||
self.location.x as f64,
|
||||
self.location.y as f64,
|
||||
self.location.x as f64 + self.dimensions.x as f64,
|
||||
self.location.y as f64 + self.dimensions.y as f64,
|
||||
);
|
||||
let mut bg_vector = Vector::from_bezpath(bg.to_path(BEZ_PATH_TOLERANCE));
|
||||
bg_vector.style.fill = Fill::Solid(self.background);
|
||||
let mut graphic_table = Table::new();
|
||||
graphic_table.push(TableRow::new_from_element(Graphic::Graphic(Table::new_from_element(Graphic::Vector(Table::new_from_element(
|
||||
bg_vector,
|
||||
))))));
|
||||
graphic_table.push(TableRow::new_from_element(Graphic::Graphic(self.content)));
|
||||
Graphic::Graphic(graphic_table)
|
||||
}
|
||||
|
||||
fn collect_metadata(&self, metadata: &mut RenderMetadata, mut footprint: Footprint, element_id: Option<NodeId>) {
|
||||
if let Some(element_id) = element_id {
|
||||
let subpath = Subpath::new_rect(DVec2::ZERO, self.dimensions.as_dvec2());
|
||||
@@ -505,6 +538,20 @@ impl Render for Table<Artboard> {
|
||||
}
|
||||
}
|
||||
|
||||
fn to_graphic(self) -> Graphic {
|
||||
let mut graphic_table = Table::new();
|
||||
for item in self.into_iter() {
|
||||
let graphic = item.element.to_graphic();
|
||||
let graphic_row = TableRow {
|
||||
element: graphic,
|
||||
transform: item.transform,
|
||||
alpha_blending: item.alpha_blending,
|
||||
source_node_id: item.source_node_id,
|
||||
};
|
||||
graphic_table.push(graphic_row);
|
||||
}
|
||||
Graphic::Graphic(graphic_table)
|
||||
}
|
||||
fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, _element_id: Option<NodeId>) {
|
||||
for row in self.iter() {
|
||||
row.element.collect_metadata(metadata, footprint, *row.source_node_id);
|
||||
@@ -643,6 +690,10 @@ impl Render for Table<Graphic> {
|
||||
}
|
||||
}
|
||||
|
||||
fn to_graphic(self) -> Graphic {
|
||||
Graphic::Graphic(self)
|
||||
}
|
||||
|
||||
fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, element_id: Option<NodeId>) {
|
||||
for row in self.iter() {
|
||||
if let Some(element_id) = row.source_node_id {
|
||||
@@ -1141,6 +1192,10 @@ impl Render for Table<Vector> {
|
||||
}
|
||||
}
|
||||
|
||||
fn to_graphic(self) -> Graphic {
|
||||
Graphic::Vector(self)
|
||||
}
|
||||
|
||||
fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>) {
|
||||
for row in self.iter() {
|
||||
let stroke_width = row.element.style.stroke().as_ref().map_or(0., Stroke::effective_width);
|
||||
@@ -1318,6 +1373,10 @@ impl Render for Table<Raster<CPU>> {
|
||||
}
|
||||
}
|
||||
|
||||
fn to_graphic(self) -> Graphic {
|
||||
Graphic::RasterCPU(self)
|
||||
}
|
||||
|
||||
fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>) {
|
||||
let subpath = Subpath::new_rect(DVec2::ZERO, DVec2::ONE);
|
||||
click_targets.push(ClickTarget::new_with_subpath(subpath, 0.));
|
||||
@@ -1364,6 +1423,10 @@ impl Render for Table<Raster<GPU>> {
|
||||
}
|
||||
}
|
||||
|
||||
fn to_graphic(self) -> Graphic {
|
||||
Graphic::RasterGPU(self)
|
||||
}
|
||||
|
||||
fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, element_id: Option<NodeId>) {
|
||||
let Some(element_id) = element_id else { return };
|
||||
let subpath = Subpath::new_rect(DVec2::ZERO, DVec2::ONE);
|
||||
@@ -1444,6 +1507,10 @@ impl Render for Table<Color> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_graphic(self) -> Graphic {
|
||||
Graphic::Color(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for Table<GradientStops> {
|
||||
@@ -1544,6 +1611,10 @@ impl Render for Table<GradientStops> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_graphic(self) -> Graphic {
|
||||
Graphic::Gradient(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for Table<Typography> {
|
||||
|
||||
Reference in New Issue
Block a user