mirror of
https://github.com/penpot/penpot.git
synced 2025-06-11 22:51:40 +02:00
Merge pull request #6585 from penpot/alotor-scale-content
✨ Add scale content to render wasm
This commit is contained in:
commit
04a1f8475d
18 changed files with 282 additions and 33 deletions
|
@ -456,9 +456,9 @@
|
||||||
(mapcat
|
(mapcat
|
||||||
(fn [[parent-id data]]
|
(fn [[parent-id data]]
|
||||||
(when (ctm/has-structure? (:modifiers data))
|
(when (ctm/has-structure? (:modifiers data))
|
||||||
(->> data
|
(->> (concat
|
||||||
:modifiers
|
(get-in data [:modifiers :structure-parent])
|
||||||
:structure-parent
|
(get-in data [:modifiers :structure-child]))
|
||||||
(mapcat
|
(mapcat
|
||||||
(fn [modifier]
|
(fn [modifier]
|
||||||
(case (:type modifier)
|
(case (:type modifier)
|
||||||
|
@ -468,7 +468,8 @@
|
||||||
{:type :remove-children
|
{:type :remove-children
|
||||||
:parent parent-id
|
:parent parent-id
|
||||||
:id child-id
|
:id child-id
|
||||||
:index 0})))
|
:index 0
|
||||||
|
:value 0})))
|
||||||
|
|
||||||
:add-children
|
:add-children
|
||||||
(->> (:value modifier)
|
(->> (:value modifier)
|
||||||
|
@ -476,7 +477,15 @@
|
||||||
{:type :add-children
|
{:type :add-children
|
||||||
:parent parent-id
|
:parent parent-id
|
||||||
:id child-id
|
:id child-id
|
||||||
:index (:index modifier)})))
|
:index (:index modifier)
|
||||||
|
:value 0})))
|
||||||
|
|
||||||
|
:scale-content
|
||||||
|
[{:type :scale-content
|
||||||
|
:parent parent-id
|
||||||
|
:id parent-id
|
||||||
|
:index 0
|
||||||
|
:value (:value modifier)}]
|
||||||
nil)))))))
|
nil)))))))
|
||||||
modif-tree))
|
modif-tree))
|
||||||
|
|
||||||
|
@ -554,6 +563,29 @@
|
||||||
(rx/of (set-temporary-selrect selrect)
|
(rx/of (set-temporary-selrect selrect)
|
||||||
(set-temporary-modifiers modifiers)))))))))
|
(set-temporary-modifiers modifiers)))))))))
|
||||||
|
|
||||||
|
(defn propagate-structure-modifiers
|
||||||
|
[modif-tree objects]
|
||||||
|
(letfn [(propagate-children
|
||||||
|
[modif-tree parent-id modifiers]
|
||||||
|
(let [new-modifiers (ctm/select-child-structre-modifiers modifiers)]
|
||||||
|
(->> (get-in objects [parent-id :shapes])
|
||||||
|
(reduce
|
||||||
|
#(update-in %1 [%2 :modifiers] ctm/add-modifiers new-modifiers)
|
||||||
|
modif-tree))))]
|
||||||
|
(loop [pending (into [] (keys modif-tree))
|
||||||
|
modif-tree modif-tree]
|
||||||
|
(if-let [next (first pending)]
|
||||||
|
(let [pending (rest pending)
|
||||||
|
modifiers (get-in modif-tree [next :modifiers])
|
||||||
|
|
||||||
|
[pending modif-tree]
|
||||||
|
(if (ctm/has-structure-child? modifiers)
|
||||||
|
[(into pending (get-in objects [next :shapes]))
|
||||||
|
(propagate-children modif-tree next modifiers)]
|
||||||
|
[pending modif-tree])]
|
||||||
|
(recur pending modif-tree))
|
||||||
|
modif-tree))))
|
||||||
|
|
||||||
#_:clj-kondo/ignore
|
#_:clj-kondo/ignore
|
||||||
(defn apply-wasm-modifiers
|
(defn apply-wasm-modifiers
|
||||||
[modif-tree & {:keys [ignore-constraints ignore-snap-pixel snap-ignore-axis undo-group]
|
[modif-tree & {:keys [ignore-constraints ignore-snap-pixel snap-ignore-axis undo-group]
|
||||||
|
@ -574,6 +606,9 @@
|
||||||
(map (fn [{:keys [id transform]}] [id transform]))
|
(map (fn [{:keys [id transform]}] [id transform]))
|
||||||
(wasm.api/propagate-modifiers geometry-entries snap-pixel?))
|
(wasm.api/propagate-modifiers geometry-entries snap-pixel?))
|
||||||
|
|
||||||
|
modif-tree
|
||||||
|
(propagate-structure-modifiers modif-tree (dsh/lookup-page-objects state))
|
||||||
|
|
||||||
ids
|
ids
|
||||||
(into (set (keys modif-tree)) (keys transforms))
|
(into (set (keys modif-tree)) (keys transforms))
|
||||||
|
|
||||||
|
@ -585,7 +620,6 @@
|
||||||
(-> shape
|
(-> shape
|
||||||
(gsh/apply-transform transform)
|
(gsh/apply-transform transform)
|
||||||
(ctm/apply-structure-modifiers modifiers))))]
|
(ctm/apply-structure-modifiers modifiers))))]
|
||||||
|
|
||||||
(rx/of
|
(rx/of
|
||||||
(clear-local-transform)
|
(clear-local-transform)
|
||||||
(dwsh/update-shapes ids update-shape))))))
|
(dwsh/update-shapes ids update-shape))))))
|
||||||
|
|
|
@ -793,17 +793,19 @@
|
||||||
(defn set-structure-modifiers
|
(defn set-structure-modifiers
|
||||||
[entries]
|
[entries]
|
||||||
(when-not (empty? entries)
|
(when-not (empty? entries)
|
||||||
(let [offset (mem/alloc-bytes-32 (mem/get-list-size entries 40))
|
(let [offset (mem/alloc-bytes-32 (mem/get-list-size entries 44))
|
||||||
heapu32 (mem/get-heap-u32)]
|
heapu32 (mem/get-heap-u32)
|
||||||
|
heapf32 (mem/get-heap-f32)]
|
||||||
(loop [entries (seq entries)
|
(loop [entries (seq entries)
|
||||||
current-offset offset]
|
current-offset offset]
|
||||||
(when-not (empty? entries)
|
(when-not (empty? entries)
|
||||||
(let [{:keys [type parent id index] :as entry} (first entries)]
|
(let [{:keys [type parent id index value] :as entry} (first entries)]
|
||||||
(sr/heapu32-set-u32 (sr/translate-structure-modifier-type type) heapu32 (+ current-offset 0))
|
(sr/heapu32-set-u32 (sr/translate-structure-modifier-type type) heapu32 (+ current-offset 0))
|
||||||
(sr/heapu32-set-u32 (or index 0) heapu32 (+ current-offset 1))
|
(sr/heapu32-set-u32 (or index 0) heapu32 (+ current-offset 1))
|
||||||
(sr/heapu32-set-uuid parent heapu32 (+ current-offset 2))
|
(sr/heapu32-set-uuid parent heapu32 (+ current-offset 2))
|
||||||
(sr/heapu32-set-uuid id heapu32 (+ current-offset 6))
|
(sr/heapu32-set-uuid id heapu32 (+ current-offset 6))
|
||||||
(recur (rest entries) (+ current-offset 10)))))
|
(aset heapf32 (+ current-offset 10) value)
|
||||||
|
(recur (rest entries) (+ current-offset 11)))))
|
||||||
(h/call wasm/internal-module "_set_structure_modifiers"))))
|
(h/call wasm/internal-module "_set_structure_modifiers"))))
|
||||||
|
|
||||||
(defn propagate-modifiers
|
(defn propagate-modifiers
|
||||||
|
|
|
@ -281,7 +281,8 @@
|
||||||
[type]
|
[type]
|
||||||
(case type
|
(case type
|
||||||
:remove-children 1
|
:remove-children 1
|
||||||
:add-children 2))
|
:add-children 2
|
||||||
|
:scale-content 3))
|
||||||
|
|
||||||
(defn translate-grow-type
|
(defn translate-grow-type
|
||||||
[grow-type]
|
[grow-type]
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
(ns app.render-wasm.shape
|
(ns app.render-wasm.shape
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
[app.common.transit :as t]
|
[app.common.transit :as t]
|
||||||
[app.common.types.shape :as shape]
|
[app.common.types.shape :as shape]
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
|
@ -132,6 +133,12 @@
|
||||||
:constraints-h (api/set-constraints-h v)
|
:constraints-h (api/set-constraints-h v)
|
||||||
:constraints-v (api/set-constraints-v v)
|
:constraints-v (api/set-constraints-v v)
|
||||||
|
|
||||||
|
(:r1 :r2 :r3 :r4)
|
||||||
|
(api/set-shape-corners [(dm/get-prop shape :r1)
|
||||||
|
(dm/get-prop shape :r2)
|
||||||
|
(dm/get-prop shape :r3)
|
||||||
|
(dm/get-prop shape :r4)])
|
||||||
|
|
||||||
:svg-attrs
|
:svg-attrs
|
||||||
(when (= (:type shape) :path)
|
(when (= (:type shape) :path)
|
||||||
(api/set-shape-path-attrs v))
|
(api/set-shape-path-attrs v))
|
||||||
|
|
|
@ -5115,9 +5115,14 @@ msgstr "File"
|
||||||
msgid "workspace.header.menu.option.help-info"
|
msgid "workspace.header.menu.option.help-info"
|
||||||
msgstr "Help & info"
|
msgstr "Help & info"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/main_menu.cljs:881
|
||||||
|
msgid "workspace.header.menu.option.preferences"
|
||||||
|
msgstr "Preferences"
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/main_menu.cljs:916
|
#: src/app/main/ui/workspace/main_menu.cljs:916
|
||||||
msgid "workspace.header.menu.option.power-up"
|
msgid "workspace.header.menu.option.power-up"
|
||||||
msgstr "Power up your plan"
|
msgstr "Power up your plan"
|
||||||
|
|
||||||
msgid "workspace.header.menu.option.view"
|
msgid "workspace.header.menu.option.view"
|
||||||
msgstr "View"
|
msgstr "View"
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,9 @@ mod wasm;
|
||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
use math::{Bounds, Matrix};
|
use math::{Bounds, Matrix};
|
||||||
use mem::SerializableResult;
|
use mem::SerializableResult;
|
||||||
use shapes::{BoolType, ConstraintH, ConstraintV, StructureEntry, TransformEntry, Type};
|
use shapes::{
|
||||||
|
BoolType, ConstraintH, ConstraintV, StructureEntry, StructureEntryType, TransformEntry, Type,
|
||||||
|
};
|
||||||
use skia_safe as skia;
|
use skia_safe as skia;
|
||||||
use state::State;
|
use state::State;
|
||||||
use utils::uuid_from_u32_quartet;
|
use utils::uuid_from_u32_quartet;
|
||||||
|
@ -424,18 +426,30 @@ pub extern "C" fn set_structure_modifiers() {
|
||||||
let bytes = mem::bytes();
|
let bytes = mem::bytes();
|
||||||
|
|
||||||
let entries: Vec<_> = bytes
|
let entries: Vec<_> = bytes
|
||||||
.chunks(40)
|
.chunks(44)
|
||||||
.map(|data| StructureEntry::from_bytes(data.try_into().unwrap()))
|
.map(|data| StructureEntry::from_bytes(data.try_into().unwrap()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
with_state!(state, {
|
with_state!(state, {
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
state.structure.entry(entry.parent).or_insert_with(Vec::new);
|
match entry.entry_type {
|
||||||
state
|
StructureEntryType::ScaleContent => {
|
||||||
.structure
|
let Some(shape) = state.shapes.get(&entry.id) else {
|
||||||
.get_mut(&entry.parent)
|
continue;
|
||||||
.expect("Parent not found for entry")
|
};
|
||||||
.push(entry);
|
for id in shape.all_children_with_self(&state.shapes) {
|
||||||
|
state.scale_content.insert(id, entry.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
state.structure.entry(entry.parent).or_insert_with(Vec::new);
|
||||||
|
state
|
||||||
|
.structure
|
||||||
|
.get_mut(&entry.parent)
|
||||||
|
.expect("Parent not found for entry")
|
||||||
|
.push(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -446,6 +460,7 @@ pub extern "C" fn set_structure_modifiers() {
|
||||||
pub extern "C" fn clean_modifiers() {
|
pub extern "C" fn clean_modifiers() {
|
||||||
with_state!(state, {
|
with_state!(state, {
|
||||||
state.structure.clear();
|
state.structure.clear();
|
||||||
|
state.scale_content.clear();
|
||||||
state.modifiers.clear();
|
state.modifiers.clear();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -327,10 +327,17 @@ impl RenderState {
|
||||||
|
|
||||||
pub fn render_shape(
|
pub fn render_shape(
|
||||||
&mut self,
|
&mut self,
|
||||||
shape: &mut Shape,
|
shape: &Shape,
|
||||||
modifiers: Option<&Matrix>,
|
modifiers: Option<&Matrix>,
|
||||||
|
scale_content: Option<&f32>,
|
||||||
clip_bounds: Option<(Rect, Option<Corners>, Matrix)>,
|
clip_bounds: Option<(Rect, Option<Corners>, Matrix)>,
|
||||||
) {
|
) {
|
||||||
|
let shape = if let Some(scale_content) = scale_content {
|
||||||
|
&shape.scale_content(*scale_content)
|
||||||
|
} else {
|
||||||
|
shape
|
||||||
|
};
|
||||||
|
|
||||||
let surface_ids = &[
|
let surface_ids = &[
|
||||||
SurfaceId::Fills,
|
SurfaceId::Fills,
|
||||||
SurfaceId::Strokes,
|
SurfaceId::Strokes,
|
||||||
|
@ -542,6 +549,7 @@ impl RenderState {
|
||||||
tree: &mut HashMap<Uuid, &mut Shape>,
|
tree: &mut HashMap<Uuid, &mut Shape>,
|
||||||
modifiers: &HashMap<Uuid, Matrix>,
|
modifiers: &HashMap<Uuid, Matrix>,
|
||||||
structure: &HashMap<Uuid, Vec<StructureEntry>>,
|
structure: &HashMap<Uuid, Vec<StructureEntry>>,
|
||||||
|
scale_content: &HashMap<Uuid, f32>,
|
||||||
timestamp: i32,
|
timestamp: i32,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let scale = self.get_scale();
|
let scale = self.get_scale();
|
||||||
|
@ -585,7 +593,7 @@ impl RenderState {
|
||||||
self.current_tile = None;
|
self.current_tile = None;
|
||||||
self.render_in_progress = true;
|
self.render_in_progress = true;
|
||||||
self.apply_drawing_to_render_canvas(None);
|
self.apply_drawing_to_render_canvas(None);
|
||||||
self.process_animation_frame(tree, modifiers, structure, timestamp)?;
|
self.process_animation_frame(tree, modifiers, structure, scale_content, timestamp)?;
|
||||||
performance::end_measure!("start_render_loop");
|
performance::end_measure!("start_render_loop");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -595,11 +603,12 @@ impl RenderState {
|
||||||
tree: &mut HashMap<Uuid, &mut Shape>,
|
tree: &mut HashMap<Uuid, &mut Shape>,
|
||||||
modifiers: &HashMap<Uuid, Matrix>,
|
modifiers: &HashMap<Uuid, Matrix>,
|
||||||
structure: &HashMap<Uuid, Vec<StructureEntry>>,
|
structure: &HashMap<Uuid, Vec<StructureEntry>>,
|
||||||
|
scale_content: &HashMap<Uuid, f32>,
|
||||||
timestamp: i32,
|
timestamp: i32,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
performance::begin_measure!("process_animation_frame");
|
performance::begin_measure!("process_animation_frame");
|
||||||
if self.render_in_progress {
|
if self.render_in_progress {
|
||||||
self.render_shape_tree(tree, modifiers, structure, timestamp)?;
|
self.render_shape_tree(tree, modifiers, structure, scale_content, timestamp)?;
|
||||||
self.flush_and_submit();
|
self.flush_and_submit();
|
||||||
|
|
||||||
if self.render_in_progress {
|
if self.render_in_progress {
|
||||||
|
@ -709,6 +718,7 @@ impl RenderState {
|
||||||
tree: &mut HashMap<Uuid, &mut Shape>,
|
tree: &mut HashMap<Uuid, &mut Shape>,
|
||||||
modifiers: &HashMap<Uuid, Matrix>,
|
modifiers: &HashMap<Uuid, Matrix>,
|
||||||
structure: &HashMap<Uuid, Vec<StructureEntry>>,
|
structure: &HashMap<Uuid, Vec<StructureEntry>>,
|
||||||
|
scale_content: &HashMap<Uuid, f32>,
|
||||||
timestamp: i32,
|
timestamp: i32,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if !self.render_in_progress {
|
if !self.render_in_progress {
|
||||||
|
@ -815,7 +825,12 @@ impl RenderState {
|
||||||
|
|
||||||
self.render_shape_enter(element, mask);
|
self.render_shape_enter(element, mask);
|
||||||
if !node_render_state.id.is_nil() {
|
if !node_render_state.id.is_nil() {
|
||||||
self.render_shape(element, modifiers.get(&element.id), clip_bounds);
|
self.render_shape(
|
||||||
|
element,
|
||||||
|
modifiers.get(&element.id),
|
||||||
|
scale_content.get(&element.id),
|
||||||
|
clip_bounds,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
self.apply_drawing_to_render_canvas(Some(element));
|
self.apply_drawing_to_render_canvas(Some(element));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ use crate::render::BlendMode;
|
||||||
use crate::uuid::Uuid;
|
use crate::uuid::Uuid;
|
||||||
use std::cell::OnceCell;
|
use std::cell::OnceCell;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::iter::once;
|
||||||
|
|
||||||
mod blurs;
|
mod blurs;
|
||||||
mod bools;
|
mod bools;
|
||||||
|
@ -108,6 +109,29 @@ impl Type {
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn scale_content(&mut self, value: f32) {
|
||||||
|
match self {
|
||||||
|
Type::Rect(Rect {
|
||||||
|
corners: Some(corners),
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
corners::scale_corners(corners, value);
|
||||||
|
}
|
||||||
|
Type::Frame(Frame { corners, layout }) => {
|
||||||
|
if let Some(corners) = corners {
|
||||||
|
corners::scale_corners(corners, value);
|
||||||
|
}
|
||||||
|
if let Some(layout) = layout {
|
||||||
|
layout.scale_content(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type::Text(TextContent { paragraphs, .. }) => {
|
||||||
|
paragraphs.iter_mut().for_each(|p| p.scale_content(value));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||||
|
@ -208,6 +232,25 @@ impl Shape {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn scale_content(&self, value: f32) -> Self {
|
||||||
|
let mut result = self.clone();
|
||||||
|
result.shape_type.scale_content(value);
|
||||||
|
result
|
||||||
|
.strokes
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|s| s.scale_content(value));
|
||||||
|
result
|
||||||
|
.shadows
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|s| s.scale_content(value));
|
||||||
|
result.blur.scale_content(value);
|
||||||
|
result
|
||||||
|
.layout_item
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|i| i.scale_content(value));
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
fn invalidate_extrect(&mut self) {
|
fn invalidate_extrect(&mut self) {
|
||||||
self.extrect = OnceCell::new();
|
self.extrect = OnceCell::new();
|
||||||
}
|
}
|
||||||
|
@ -364,7 +407,7 @@ impl Shape {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: These arguments could be grouped or simplified
|
// FIXME: These argumoents could be grouped or simplified
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn set_grid_layout_data(
|
pub fn set_grid_layout_data(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -687,6 +730,17 @@ impl Shape {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn all_children_with_self(&self, shapes: &HashMap<Uuid, &mut Shape>) -> IndexSet<Uuid> {
|
||||||
|
once(self.id)
|
||||||
|
.chain(self.children_ids().into_iter().flat_map(|id| {
|
||||||
|
shapes
|
||||||
|
.get(&id)
|
||||||
|
.map(|s| s.all_children_with_self(shapes))
|
||||||
|
.unwrap_or_default()
|
||||||
|
}))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn image_filter(&self, scale: f32) -> Option<skia::ImageFilter> {
|
pub fn image_filter(&self, scale: f32) -> Option<skia::ImageFilter> {
|
||||||
if !self.blur.hidden {
|
if !self.blur.hidden {
|
||||||
match self.blur.blur_type {
|
match self.blur.blur_type {
|
||||||
|
@ -873,6 +927,7 @@ pub fn modified_children_ids(
|
||||||
StructureEntryType::RemoveChild => {
|
StructureEntryType::RemoveChild => {
|
||||||
to_remove.insert(&st.id);
|
to_remove.insert(&st.id);
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,4 +35,8 @@ impl Blur {
|
||||||
value,
|
value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn scale_content(&mut self, value: f32) {
|
||||||
|
self.value *= value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,3 +21,14 @@ pub fn make_corners(raw_corners: (f32, f32, f32, f32)) -> Option<Corners> {
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn scale_corners(corners: &mut Corners, value: f32) {
|
||||||
|
corners[0].x *= value;
|
||||||
|
corners[0].y *= value;
|
||||||
|
corners[1].x *= value;
|
||||||
|
corners[1].y *= value;
|
||||||
|
corners[2].x *= value;
|
||||||
|
corners[2].y *= value;
|
||||||
|
corners[3].x *= value;
|
||||||
|
corners[3].y *= value;
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,20 @@ pub enum Layout {
|
||||||
GridLayout(LayoutData, GridData),
|
GridLayout(LayoutData, GridData),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Layout {
|
||||||
|
pub fn scale_content(&mut self, value: f32) {
|
||||||
|
match self {
|
||||||
|
Layout::FlexLayout(layout_data, _) => {
|
||||||
|
layout_data.scale_content(value);
|
||||||
|
}
|
||||||
|
Layout::GridLayout(layout_data, grid_data) => {
|
||||||
|
layout_data.scale_content(value);
|
||||||
|
grid_data.scale_content(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum FlexDirection {
|
pub enum FlexDirection {
|
||||||
Row,
|
Row,
|
||||||
|
@ -184,6 +198,12 @@ impl GridTrack {
|
||||||
value: f32::from_le_bytes(raw.value),
|
value: f32::from_le_bytes(raw.value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn scale_content(&mut self, value: f32) {
|
||||||
|
if self.track_type == GridTrackType::Fixed {
|
||||||
|
self.value *= value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
@ -260,6 +280,17 @@ pub struct LayoutData {
|
||||||
pub column_gap: f32,
|
pub column_gap: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LayoutData {
|
||||||
|
pub fn scale_content(&mut self, value: f32) {
|
||||||
|
self.padding_top *= value;
|
||||||
|
self.padding_right *= value;
|
||||||
|
self.padding_bottom *= value;
|
||||||
|
self.padding_left *= value;
|
||||||
|
self.row_gap *= value;
|
||||||
|
self.column_gap *= value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub enum AlignSelf {
|
pub enum AlignSelf {
|
||||||
Auto,
|
Auto,
|
||||||
|
@ -324,9 +355,7 @@ impl FlexData {
|
||||||
FlexDirection::RowReverse | FlexDirection::Row
|
FlexDirection::RowReverse | FlexDirection::Row
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl FlexData {
|
|
||||||
pub fn is_wrap(&self) -> bool {
|
pub fn is_wrap(&self) -> bool {
|
||||||
matches!(self.wrap_type, WrapType::Wrap)
|
matches!(self.wrap_type, WrapType::Wrap)
|
||||||
}
|
}
|
||||||
|
@ -349,6 +378,11 @@ impl GridData {
|
||||||
cells: vec![],
|
cells: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn scale_content(&mut self, value: f32) {
|
||||||
|
self.rows.iter_mut().for_each(|t| t.scale_content(value));
|
||||||
|
self.columns.iter_mut().for_each(|t| t.scale_content(value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -424,3 +458,16 @@ pub struct LayoutItem {
|
||||||
pub z_index: i32,
|
pub z_index: i32,
|
||||||
pub align_self: Option<AlignSelf>,
|
pub align_self: Option<AlignSelf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LayoutItem {
|
||||||
|
pub fn scale_content(&mut self, value: f32) {
|
||||||
|
self.margin_top *= value;
|
||||||
|
self.margin_right *= value;
|
||||||
|
self.margin_bottom *= value;
|
||||||
|
self.margin_left *= value;
|
||||||
|
self.max_h = self.max_h.map(|max_h| max_h * value);
|
||||||
|
self.min_h = self.max_h.map(|max_h| max_h * value);
|
||||||
|
self.max_w = self.max_h.map(|max_h| max_h * value);
|
||||||
|
self.min_w = self.max_h.map(|max_h| max_h * value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ use crate::shapes::{
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use crate::uuid::Uuid;
|
use crate::uuid::Uuid;
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn propagate_children(
|
fn propagate_children(
|
||||||
shape: &Shape,
|
shape: &Shape,
|
||||||
shapes: &HashMap<Uuid, &mut Shape>,
|
shapes: &HashMap<Uuid, &mut Shape>,
|
||||||
|
@ -22,6 +23,7 @@ fn propagate_children(
|
||||||
transform: Matrix,
|
transform: Matrix,
|
||||||
bounds: &HashMap<Uuid, Bounds>,
|
bounds: &HashMap<Uuid, Bounds>,
|
||||||
structure: &HashMap<Uuid, Vec<StructureEntry>>,
|
structure: &HashMap<Uuid, Vec<StructureEntry>>,
|
||||||
|
scale_content: &HashMap<Uuid, f32>,
|
||||||
) -> VecDeque<Modifier> {
|
) -> VecDeque<Modifier> {
|
||||||
let children_ids = modified_children_ids(shape, structure.get(&shape.id));
|
let children_ids = modified_children_ids(shape, structure.get(&shape.id));
|
||||||
|
|
||||||
|
@ -36,6 +38,8 @@ fn propagate_children(
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let ignore_constraints = scale_content.contains_key(child_id);
|
||||||
|
|
||||||
let child_bounds = bounds.find(child);
|
let child_bounds = bounds.find(child);
|
||||||
|
|
||||||
let constraint_h = match &shape.shape_type {
|
let constraint_h = match &shape.shape_type {
|
||||||
|
@ -73,6 +77,7 @@ fn propagate_children(
|
||||||
constraint_h,
|
constraint_h,
|
||||||
constraint_v,
|
constraint_v,
|
||||||
transform,
|
transform,
|
||||||
|
ignore_constraints,
|
||||||
);
|
);
|
||||||
|
|
||||||
result.push_back(Modifier::transform(*child_id, transform));
|
result.push_back(Modifier::transform(*child_id, transform));
|
||||||
|
@ -200,6 +205,7 @@ pub fn propagate_modifiers(
|
||||||
transform,
|
transform,
|
||||||
&bounds,
|
&bounds,
|
||||||
&state.structure,
|
&state.structure,
|
||||||
|
&state.scale_content,
|
||||||
);
|
);
|
||||||
entries.append(&mut children);
|
entries.append(&mut children);
|
||||||
}
|
}
|
||||||
|
@ -309,6 +315,12 @@ pub fn propagate_modifiers(
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let shape = if let Some(scale_content) = state.scale_content.get(id) {
|
||||||
|
&shape.scale_content(*scale_content)
|
||||||
|
} else {
|
||||||
|
shape
|
||||||
|
};
|
||||||
|
|
||||||
let Type::Frame(frame_data) = &shape.shape_type else {
|
let Type::Frame(frame_data) = &shape.shape_type else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
@ -388,6 +400,7 @@ mod tests {
|
||||||
transform,
|
transform,
|
||||||
&HashMap::new(),
|
&HashMap::new(),
|
||||||
&HashMap::new(),
|
&HashMap::new(),
|
||||||
|
&HashMap::new(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(result.len(), 1);
|
assert_eq!(result.len(), 1);
|
||||||
|
|
|
@ -104,10 +104,12 @@ pub fn propagate_shape_constraints(
|
||||||
constraint_h: ConstraintH,
|
constraint_h: ConstraintH,
|
||||||
constraint_v: ConstraintV,
|
constraint_v: ConstraintV,
|
||||||
transform: Matrix,
|
transform: Matrix,
|
||||||
|
ignore_constrainst: bool,
|
||||||
) -> Matrix {
|
) -> Matrix {
|
||||||
// if the constrains are scale & scale or the transform has only moves we
|
// if the constrains are scale & scale or the transform has only moves we
|
||||||
// can propagate as is
|
// can propagate as is
|
||||||
if (constraint_h == ConstraintH::Scale && constraint_v == ConstraintV::Scale)
|
if (ignore_constrainst
|
||||||
|
|| constraint_h == ConstraintH::Scale && constraint_v == ConstraintV::Scale)
|
||||||
|| transform.is_translate()
|
|| transform.is_translate()
|
||||||
{
|
{
|
||||||
return transform;
|
return transform;
|
||||||
|
|
|
@ -125,4 +125,11 @@ impl Shadow {
|
||||||
|
|
||||||
filter
|
filter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn scale_content(&mut self, value: f32) {
|
||||||
|
self.blur *= value;
|
||||||
|
self.spread *= value;
|
||||||
|
self.offset.0 *= value;
|
||||||
|
self.offset.1 *= value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,10 @@ impl Stroke {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn scale_content(&mut self, value: f32) {
|
||||||
|
self.width *= value;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn delta(&self) -> f32 {
|
pub fn delta(&self) -> f32 {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
StrokeKind::Inner => 0.,
|
StrokeKind::Inner => 0.,
|
||||||
|
|
|
@ -34,9 +34,9 @@ impl GrowType {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct TextContent {
|
pub struct TextContent {
|
||||||
paragraphs: Vec<Paragraph>,
|
pub paragraphs: Vec<Paragraph>,
|
||||||
bounds: Rect,
|
pub bounds: Rect,
|
||||||
grow_type: GrowType,
|
pub grow_type: GrowType,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_paragraphs_width(width: f32, paragraphs: &mut Vec<Vec<skia::textlayout::Paragraph>>) {
|
pub fn set_paragraphs_width(width: f32, paragraphs: &mut Vec<Vec<skia::textlayout::Paragraph>>) {
|
||||||
|
@ -284,6 +284,13 @@ impl Paragraph {
|
||||||
});
|
});
|
||||||
style
|
style
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn scale_content(&mut self, value: f32) {
|
||||||
|
self.letter_spacing *= value;
|
||||||
|
self.children
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|l| l.scale_content(value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
@ -388,6 +395,10 @@ impl TextLeaf {
|
||||||
_ => self.text.clone(),
|
_ => self.text.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn scale_content(&mut self, value: f32) {
|
||||||
|
self.font_size *= value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const RAW_PARAGRAPH_DATA_SIZE: usize = std::mem::size_of::<RawParagraphData>();
|
const RAW_PARAGRAPH_DATA_SIZE: usize = std::mem::size_of::<RawParagraphData>();
|
||||||
|
|
|
@ -102,6 +102,7 @@ impl SerializableResult for TransformEntry {
|
||||||
pub enum StructureEntryType {
|
pub enum StructureEntryType {
|
||||||
RemoveChild,
|
RemoveChild,
|
||||||
AddChild,
|
AddChild,
|
||||||
|
ScaleContent,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StructureEntryType {
|
impl StructureEntryType {
|
||||||
|
@ -109,6 +110,7 @@ impl StructureEntryType {
|
||||||
match value {
|
match value {
|
||||||
1 => Self::RemoveChild,
|
1 => Self::RemoveChild,
|
||||||
2 => Self::AddChild,
|
2 => Self::AddChild,
|
||||||
|
3 => Self::ScaleContent,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,19 +123,27 @@ pub struct StructureEntry {
|
||||||
pub index: u32,
|
pub index: u32,
|
||||||
pub parent: Uuid,
|
pub parent: Uuid,
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
|
pub value: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StructureEntry {
|
impl StructureEntry {
|
||||||
pub fn new(entry_type: StructureEntryType, index: u32, parent: Uuid, id: Uuid) -> Self {
|
pub fn new(
|
||||||
|
entry_type: StructureEntryType,
|
||||||
|
index: u32,
|
||||||
|
parent: Uuid,
|
||||||
|
id: Uuid,
|
||||||
|
value: f32,
|
||||||
|
) -> Self {
|
||||||
StructureEntry {
|
StructureEntry {
|
||||||
entry_type,
|
entry_type,
|
||||||
index,
|
index,
|
||||||
parent,
|
parent,
|
||||||
id,
|
id,
|
||||||
|
value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_bytes(bytes: [u8; 40]) -> Self {
|
pub fn from_bytes(bytes: [u8; 44]) -> Self {
|
||||||
let entry_type = StructureEntryType::from_u32(u32::from_le_bytes([
|
let entry_type = StructureEntryType::from_u32(u32::from_le_bytes([
|
||||||
bytes[0], bytes[1], bytes[2], bytes[3],
|
bytes[0], bytes[1], bytes[2], bytes[3],
|
||||||
]));
|
]));
|
||||||
|
@ -154,7 +164,9 @@ impl StructureEntry {
|
||||||
u32::from_le_bytes([bytes[36], bytes[37], bytes[38], bytes[39]]),
|
u32::from_le_bytes([bytes[36], bytes[37], bytes[38], bytes[39]]),
|
||||||
);
|
);
|
||||||
|
|
||||||
StructureEntry::new(entry_type, index, parent, id)
|
let value = f32::from_le_bytes([bytes[40], bytes[41], bytes[42], bytes[43]]);
|
||||||
|
|
||||||
|
StructureEntry::new(entry_type, index, parent, id, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,7 @@ pub(crate) struct State<'a> {
|
||||||
pub current_shape: Option<&'a mut Shape>,
|
pub current_shape: Option<&'a mut Shape>,
|
||||||
pub shapes: HashMap<Uuid, &'a mut Shape>,
|
pub shapes: HashMap<Uuid, &'a mut Shape>,
|
||||||
pub modifiers: HashMap<Uuid, skia::Matrix>,
|
pub modifiers: HashMap<Uuid, skia::Matrix>,
|
||||||
|
pub scale_content: HashMap<Uuid, f32>,
|
||||||
pub structure: HashMap<Uuid, Vec<StructureEntry>>,
|
pub structure: HashMap<Uuid, Vec<StructureEntry>>,
|
||||||
pub shapes_pool: ShapesPool,
|
pub shapes_pool: ShapesPool,
|
||||||
}
|
}
|
||||||
|
@ -81,6 +82,7 @@ impl<'a> State<'a> {
|
||||||
current_shape: None,
|
current_shape: None,
|
||||||
shapes: HashMap::with_capacity(capacity),
|
shapes: HashMap::with_capacity(capacity),
|
||||||
modifiers: HashMap::new(),
|
modifiers: HashMap::new(),
|
||||||
|
scale_content: HashMap::new(),
|
||||||
structure: HashMap::new(),
|
structure: HashMap::new(),
|
||||||
shapes_pool: ShapesPool::new(),
|
shapes_pool: ShapesPool::new(),
|
||||||
}
|
}
|
||||||
|
@ -99,6 +101,7 @@ impl<'a> State<'a> {
|
||||||
&mut self.shapes,
|
&mut self.shapes,
|
||||||
&self.modifiers,
|
&self.modifiers,
|
||||||
&self.structure,
|
&self.structure,
|
||||||
|
&self.scale_content,
|
||||||
timestamp,
|
timestamp,
|
||||||
)?;
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -109,6 +112,7 @@ impl<'a> State<'a> {
|
||||||
&mut self.shapes,
|
&mut self.shapes,
|
||||||
&self.modifiers,
|
&self.modifiers,
|
||||||
&self.structure,
|
&self.structure,
|
||||||
|
&self.scale_content,
|
||||||
timestamp,
|
timestamp,
|
||||||
)?;
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue