mirror of
https://github.com/penpot/penpot.git
synced 2026-08-07 05:18:36 +00:00
🐛 Fix several problems with layouts and texts
This commit is contained in:
parent
8a72eb64c3
commit
53c2acb3e6
@ -407,17 +407,19 @@
|
|||||||
(defn change-text
|
(defn change-text
|
||||||
"Changes the content of the text shape to use the text as argument. Will use the styles of the
|
"Changes the content of the text shape to use the text as argument. Will use the styles of the
|
||||||
first paragraph and text that is present in the shape (and override the rest)"
|
first paragraph and text that is present in the shape (and override the rest)"
|
||||||
[content text]
|
[content text & {:as styles}]
|
||||||
(let [root-styles (select-keys content root-attrs)
|
(let [root-styles (select-keys content root-attrs)
|
||||||
|
|
||||||
paragraph-style
|
paragraph-style
|
||||||
(merge
|
(merge
|
||||||
default-text-attrs
|
default-text-attrs
|
||||||
|
styles
|
||||||
(select-keys (->> content (node-seq is-paragraph-node?) first) text-all-attrs))
|
(select-keys (->> content (node-seq is-paragraph-node?) first) text-all-attrs))
|
||||||
|
|
||||||
text-style
|
text-style
|
||||||
(merge
|
(merge
|
||||||
default-text-attrs
|
default-text-attrs
|
||||||
|
styles
|
||||||
(select-keys (->> content (node-seq is-text-node?) first) text-all-attrs))
|
(select-keys (->> content (node-seq is-text-node?) first) text-all-attrs))
|
||||||
|
|
||||||
paragraph-texts
|
paragraph-texts
|
||||||
|
|||||||
@ -104,7 +104,7 @@
|
|||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [page-id (or page-id (:current-page-id state))
|
(let [page-id (or page-id (:current-page-id state))
|
||||||
objects (dsh/lookup-page-objects state page-id)
|
objects (dsh/lookup-page-objects state page-id)
|
||||||
ids (->> ids (filter #(contains? objects %)))]
|
ids (->> ids (remove uuid/zero?) (filter #(contains? objects %)))]
|
||||||
(if (d/not-empty? ids)
|
(if (d/not-empty? ids)
|
||||||
(let [modif-tree (dwm/create-modif-tree ids (ctm/reflow-modifiers))]
|
(let [modif-tree (dwm/create-modif-tree ids (ctm/reflow-modifiers))]
|
||||||
(if (features/active-feature? state "render-wasm/v1")
|
(if (features/active-feature? state "render-wasm/v1")
|
||||||
|
|||||||
@ -776,11 +776,7 @@
|
|||||||
(rx/of (v2-update-text-editor-styles id attrs)))
|
(rx/of (v2-update-text-editor-styles id attrs)))
|
||||||
|
|
||||||
(when (features/active-feature? state "render-wasm/v1")
|
(when (features/active-feature? state "render-wasm/v1")
|
||||||
;; This delay is to give time for the font to be correctly rendered
|
(rx/of (dwwt/resize-wasm-text-debounce id)))))))
|
||||||
;; in wasm.
|
|
||||||
(cond->> (rx/of (dwwt/resize-wasm-text id))
|
|
||||||
(contains? attrs :font-id)
|
|
||||||
(rx/delay 200)))))))
|
|
||||||
|
|
||||||
ptk/EffectEvent
|
ptk/EffectEvent
|
||||||
(effect [_ state _]
|
(effect [_ state _]
|
||||||
|
|||||||
@ -62,6 +62,65 @@
|
|||||||
(rx/of (dwm/apply-wasm-modifiers (resize-wasm-text-modifiers shape)))
|
(rx/of (dwm/apply-wasm-modifiers (resize-wasm-text-modifiers shape)))
|
||||||
(rx/empty))))))
|
(rx/empty))))))
|
||||||
|
|
||||||
|
(defn resize-wasm-text-debounce-commit
|
||||||
|
[]
|
||||||
|
(ptk/reify ::resize-wasm-text
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state _]
|
||||||
|
(let [ids (get state ::resize-wasm-text-debounce-ids)
|
||||||
|
objects (dsh/lookup-page-objects state)
|
||||||
|
|
||||||
|
modifiers
|
||||||
|
(reduce
|
||||||
|
(fn [modifiers id]
|
||||||
|
(let [shape (get objects id)]
|
||||||
|
(cond-> modifiers
|
||||||
|
(and (some? shape)
|
||||||
|
(cfh/text-shape? shape)
|
||||||
|
(not= :fixed (:grow-type shape)))
|
||||||
|
(merge (resize-wasm-text-modifiers shape)))))
|
||||||
|
{}
|
||||||
|
ids)]
|
||||||
|
(if (not (empty? modifiers))
|
||||||
|
(rx/of (dwm/apply-wasm-modifiers modifiers))
|
||||||
|
(rx/empty))))))
|
||||||
|
|
||||||
|
;; This event will debounce the resize events so, if there are many, they
|
||||||
|
;; are processed at the same time and not one-by-one. This will improve
|
||||||
|
;; performance because it's better to make only one layout calculation instead
|
||||||
|
;; of (potentialy) hundreds.
|
||||||
|
(defn resize-wasm-text-debounce
|
||||||
|
[id]
|
||||||
|
(let [cur-event (js/Symbol)]
|
||||||
|
(ptk/reify ::resize-wasm-text-debounce
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(-> state
|
||||||
|
(update ::resize-wasm-text-debounce-ids (fnil conj []) id)
|
||||||
|
(cond-> (nil? (::resize-wasm-text-debounce-event state))
|
||||||
|
(assoc ::resize-wasm-text-debounce-event cur-event))))
|
||||||
|
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(if (= (::resize-wasm-text-debounce-event state) cur-event)
|
||||||
|
(let [stopper (->> stream (rx/filter (ptk/type? :app.main.data.workspace/finalize)))]
|
||||||
|
(rx/concat
|
||||||
|
(rx/merge
|
||||||
|
(->> stream
|
||||||
|
(rx/filter (ptk/type? ::resize-wasm-text-debounce))
|
||||||
|
(rx/debounce 20)
|
||||||
|
(rx/take 1)
|
||||||
|
(rx/delay 200)
|
||||||
|
(rx/map #(resize-wasm-text-debounce-commit))
|
||||||
|
(rx/take-until stopper))
|
||||||
|
|
||||||
|
(rx/of (resize-wasm-text-debounce id)))
|
||||||
|
|
||||||
|
(rx/of #(dissoc %
|
||||||
|
::resize-wasm-text-debounce-ids
|
||||||
|
::resize-wasm-text-debounce-event))))
|
||||||
|
(rx/empty))))))
|
||||||
|
|
||||||
(defn resize-wasm-text-all
|
(defn resize-wasm-text-all
|
||||||
"Resize all text shapes (auto-width/auto-height) from a collection of ids."
|
"Resize all text shapes (auto-width/auto-height) from a collection of ids."
|
||||||
[ids]
|
[ids]
|
||||||
|
|||||||
@ -75,32 +75,31 @@
|
|||||||
[{:keys [points] :as shape} zoom grid-edition?]
|
[{:keys [points] :as shape} zoom grid-edition?]
|
||||||
(let [leftmost (->> points (reduce left?))
|
(let [leftmost (->> points (reduce left?))
|
||||||
topmost (->> points (remove #{leftmost}) (reduce top?))
|
topmost (->> points (remove #{leftmost}) (reduce top?))
|
||||||
rightmost (->> points (remove #{leftmost topmost}) (reduce right?))
|
rightmost (->> points (remove #{leftmost topmost}) (reduce right?))]
|
||||||
|
(when (and (some? leftmost) (some? topmost) (some? rightmost))
|
||||||
|
(let [left-top (gpt/to-vec leftmost topmost)
|
||||||
|
left-top-angle (gpt/angle left-top)
|
||||||
|
|
||||||
left-top (gpt/to-vec leftmost topmost)
|
top-right (gpt/to-vec topmost rightmost)
|
||||||
left-top-angle (gpt/angle left-top)
|
top-right-angle (gpt/angle top-right)
|
||||||
|
|
||||||
top-right (gpt/to-vec topmost rightmost)
|
;; Choose the position that creates the less angle between left-side and top-side
|
||||||
top-right-angle (gpt/angle top-right)
|
[label-pos angle h-pos v-pos]
|
||||||
|
(if (< (mth/abs left-top-angle) (mth/abs top-right-angle))
|
||||||
|
[leftmost left-top-angle left-top (gpt/perpendicular left-top)]
|
||||||
|
[topmost top-right-angle top-right (gpt/perpendicular top-right)])
|
||||||
|
|
||||||
;; Choose the position that creates the less angle between left-side and top-side
|
delta-x (if grid-edition? 40 0)
|
||||||
[label-pos angle h-pos v-pos]
|
delta-y (if grid-edition? 50 10)
|
||||||
(if (< (mth/abs left-top-angle) (mth/abs top-right-angle))
|
|
||||||
[leftmost left-top-angle left-top (gpt/perpendicular left-top)]
|
|
||||||
[topmost top-right-angle top-right (gpt/perpendicular top-right)])
|
|
||||||
|
|
||||||
delta-x (if grid-edition? 40 0)
|
label-pos
|
||||||
delta-y (if grid-edition? 50 10)
|
(-> label-pos
|
||||||
|
(gpt/subtract (gpt/scale (gpt/unit v-pos) (/ delta-y zoom)))
|
||||||
label-pos
|
(gpt/subtract (gpt/scale (gpt/unit h-pos) (/ delta-x zoom))))]
|
||||||
(-> label-pos
|
(dm/fmt "rotate(% %,%) scale(%, %) translate(%, %)"
|
||||||
(gpt/subtract (gpt/scale (gpt/unit v-pos) (/ delta-y zoom)))
|
;; rotate
|
||||||
(gpt/subtract (gpt/scale (gpt/unit h-pos) (/ delta-x zoom))))]
|
angle (:x label-pos) (:y label-pos)
|
||||||
|
;; scale
|
||||||
(dm/fmt "rotate(% %,%) scale(%, %) translate(%, %)"
|
(/ 1 zoom) (/ 1 zoom)
|
||||||
;; rotate
|
;; translate
|
||||||
angle (:x label-pos) (:y label-pos)
|
(* zoom (:x label-pos)) (* zoom (:y label-pos)))))))
|
||||||
;; scale
|
|
||||||
(/ 1 zoom) (/ 1 zoom)
|
|
||||||
;; translate
|
|
||||||
(* zoom (:x label-pos)) (* zoom (:y label-pos)))))
|
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
[app.main.data.workspace.groups :as dwg]
|
[app.main.data.workspace.groups :as dwg]
|
||||||
[app.main.data.workspace.media :as dwm]
|
[app.main.data.workspace.media :as dwm]
|
||||||
[app.main.data.workspace.selection :as dws]
|
[app.main.data.workspace.selection :as dws]
|
||||||
|
[app.main.data.workspace.wasm-text :as dwwt]
|
||||||
[app.main.fonts :refer [fetch-font-css]]
|
[app.main.fonts :refer [fetch-font-css]]
|
||||||
[app.main.router :as rt]
|
[app.main.router :as rt]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
@ -338,9 +339,14 @@
|
|||||||
|
|
||||||
:else
|
:else
|
||||||
(let [page (dsh/lookup-page @st/state)
|
(let [page (dsh/lookup-page @st/state)
|
||||||
shape (-> (cts/setup-shape {:type :text :x 0 :y 0 :grow-type :auto-width})
|
shape (-> (cts/setup-shape {:type :text
|
||||||
(update :content txt/change-text text)
|
:x 0 :y 0
|
||||||
(assoc :position-data nil))
|
:width 1 :height 1
|
||||||
|
:grow-type :auto-width})
|
||||||
|
(update :content txt/change-text text
|
||||||
|
;; Text should be given a color by default
|
||||||
|
{:fills [{:fill-color "#000000" :fill-opacity 1}]})
|
||||||
|
(dissoc :position-data))
|
||||||
|
|
||||||
changes
|
changes
|
||||||
(-> (cb/empty-changes)
|
(-> (cb/empty-changes)
|
||||||
@ -348,7 +354,9 @@
|
|||||||
(cb/with-objects (:objects page))
|
(cb/with-objects (:objects page))
|
||||||
(cb/add-object shape))]
|
(cb/add-object shape))]
|
||||||
|
|
||||||
(st/emit! (ch/commit-changes changes))
|
(st/emit!
|
||||||
|
(ch/commit-changes changes)
|
||||||
|
(dwwt/resize-wasm-text-debounce (:id shape)))
|
||||||
(shape/shape-proxy plugin-id (:id shape)))))
|
(shape/shape-proxy plugin-id (:id shape)))))
|
||||||
|
|
||||||
:createShapeFromSvg
|
:createShapeFromSvg
|
||||||
|
|||||||
@ -190,11 +190,13 @@
|
|||||||
(defn update-text-rect!
|
(defn update-text-rect!
|
||||||
[id]
|
[id]
|
||||||
(when wasm/context-initialized?
|
(when wasm/context-initialized?
|
||||||
(mw/emit!
|
(let [dimensions (get-text-dimensions id)
|
||||||
{:cmd :index/update-text-rect
|
page-id (:current-page-id @st/state)]
|
||||||
:page-id (:current-page-id @st/state)
|
(mw/emit!
|
||||||
:shape-id id
|
{:cmd :index/update-text-rect
|
||||||
:dimensions (get-text-dimensions id)})))
|
:page-id page-id
|
||||||
|
:shape-id id
|
||||||
|
:dimensions dimensions}))))
|
||||||
|
|
||||||
|
|
||||||
(defn- ensure-text-content
|
(defn- ensure-text-content
|
||||||
@ -1564,7 +1566,7 @@
|
|||||||
:text-decoration (get element :text-decoration)
|
:text-decoration (get element :text-decoration)
|
||||||
:letter-spacing (get element :letter-spacing)
|
:letter-spacing (get element :letter-spacing)
|
||||||
:font-style (get element :font-style)
|
:font-style (get element :font-style)
|
||||||
:fills (get element :fills)
|
:fills (d/nilv (get element :fills) [{:fill-color "#000000"}])
|
||||||
:text text}))))))]
|
:text text}))))))]
|
||||||
(mem/free)
|
(mem/free)
|
||||||
|
|
||||||
|
|||||||
@ -1074,6 +1074,10 @@ impl Shape {
|
|||||||
self.children.first()
|
self.children.first()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn children_count(&self) -> usize {
|
||||||
|
self.children_ids_iter(false).count()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn children_ids(&self, include_hidden: bool) -> Vec<Uuid> {
|
pub fn children_ids(&self, include_hidden: bool) -> Vec<Uuid> {
|
||||||
if include_hidden {
|
if include_hidden {
|
||||||
return self.children.iter().rev().copied().collect();
|
return self.children.iter().rev().copied().collect();
|
||||||
|
|||||||
@ -264,7 +264,7 @@ fn propagate_transform(
|
|||||||
|
|
||||||
// If this is a layout and we're only moving don't need to reflow
|
// If this is a layout and we're only moving don't need to reflow
|
||||||
if shape.has_layout() && is_resize {
|
if shape.has_layout() && is_resize {
|
||||||
entries.push_back(Modifier::reflow(shape.id));
|
entries.push_back(Modifier::reflow(shape.id, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(parent) = shape.parent_id.and_then(|id| shapes.get(&id)) {
|
if let Some(parent) = shape.parent_id.and_then(|id| shapes.get(&id)) {
|
||||||
@ -272,7 +272,7 @@ fn propagate_transform(
|
|||||||
// if the current transformation is not a move propagation.
|
// if the current transformation is not a move propagation.
|
||||||
// If it's a move propagation we don't need to reflow, the parent is already changed.
|
// If it's a move propagation we don't need to reflow, the parent is already changed.
|
||||||
if (parent.has_layout() || parent.is_group_like()) && (is_resize || !is_propagate) {
|
if (parent.has_layout() || parent.is_group_like()) && (is_resize || !is_propagate) {
|
||||||
entries.push_back(Modifier::reflow(parent.id));
|
entries.push_back(Modifier::reflow(parent.id, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -282,7 +282,7 @@ fn propagate_reflow(
|
|||||||
state: &State,
|
state: &State,
|
||||||
entries: &mut VecDeque<Modifier>,
|
entries: &mut VecDeque<Modifier>,
|
||||||
bounds: &mut HashMap<Uuid, Bounds>,
|
bounds: &mut HashMap<Uuid, Bounds>,
|
||||||
layout_reflows: &mut Vec<Uuid>,
|
layout_reflows: &mut HashSet<Uuid>,
|
||||||
reflown: &mut HashSet<Uuid>,
|
reflown: &mut HashSet<Uuid>,
|
||||||
modifiers: &HashMap<Uuid, Matrix>,
|
modifiers: &HashMap<Uuid, Matrix>,
|
||||||
) {
|
) {
|
||||||
@ -300,20 +300,7 @@ fn propagate_reflow(
|
|||||||
Type::Frame(Frame {
|
Type::Frame(Frame {
|
||||||
layout: Some(_), ..
|
layout: Some(_), ..
|
||||||
}) => {
|
}) => {
|
||||||
let mut skip_reflow = false;
|
layout_reflows.insert(*id);
|
||||||
if shape.is_layout_horizontal_fill() || shape.is_layout_vertical_fill() {
|
|
||||||
if let Some(parent_id) = shape.parent_id {
|
|
||||||
if parent_id != Uuid::nil() && !reflown.contains(&parent_id) {
|
|
||||||
// If this is a fill layout but the parent has not been reflown yet
|
|
||||||
// we wait for the next iteration for reflow
|
|
||||||
skip_reflow = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !skip_reflow {
|
|
||||||
layout_reflows.push(*id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Type::Group(Group { masked: true }) => {
|
Type::Group(Group { masked: true }) => {
|
||||||
let children_ids = shape.children_ids(true);
|
let children_ids = shape.children_ids(true);
|
||||||
@ -340,7 +327,7 @@ fn propagate_reflow(
|
|||||||
|
|
||||||
if let Some(parent) = shape.parent_id.and_then(|id| shapes.get(&id)) {
|
if let Some(parent) = shape.parent_id.and_then(|id| shapes.get(&id)) {
|
||||||
if parent.has_layout() || parent.is_group_like() {
|
if parent.has_layout() || parent.is_group_like() {
|
||||||
entries.push_back(Modifier::reflow(parent.id));
|
entries.push_back(Modifier::reflow(parent.id, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -382,19 +369,20 @@ pub fn propagate_modifiers(
|
|||||||
let mut entries: VecDeque<_> = modifiers
|
let mut entries: VecDeque<_> = modifiers
|
||||||
.iter()
|
.iter()
|
||||||
.map(|entry| {
|
.map(|entry| {
|
||||||
// If we receibe a identity matrix we force a reflow
|
// If we receive a identity matrix we force a reflow
|
||||||
if math::identitish(&entry.transform) {
|
if math::identitish(&entry.transform) {
|
||||||
Modifier::Reflow(entry.id)
|
Modifier::Reflow(entry.id, false)
|
||||||
} else {
|
} else {
|
||||||
Modifier::Transform(*entry)
|
Modifier::Transform(*entry)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
let shapes = &state.shapes;
|
||||||
let mut modifiers = HashMap::<Uuid, Matrix>::new();
|
let mut modifiers = HashMap::<Uuid, Matrix>::new();
|
||||||
let mut bounds = HashMap::<Uuid, Bounds>::new();
|
let mut bounds = HashMap::<Uuid, Bounds>::new();
|
||||||
let mut reflown = HashSet::<Uuid>::new();
|
let mut reflown = HashSet::<Uuid>::new();
|
||||||
let mut layout_reflows = Vec::<Uuid>::new();
|
let mut layout_reflows = HashSet::<Uuid>::new();
|
||||||
|
|
||||||
// We first propagate the transforms to the children and then after
|
// We first propagate the transforms to the children and then after
|
||||||
// recalculate the layouts. The layout can create further transforms that
|
// recalculate the layouts. The layout can create further transforms that
|
||||||
@ -412,25 +400,43 @@ pub fn propagate_modifiers(
|
|||||||
&mut bounds,
|
&mut bounds,
|
||||||
&mut modifiers,
|
&mut modifiers,
|
||||||
),
|
),
|
||||||
Modifier::Reflow(id) => propagate_reflow(
|
Modifier::Reflow(id, force_reflow) => {
|
||||||
&id,
|
if force_reflow {
|
||||||
state,
|
reflown.remove(&id);
|
||||||
&mut entries,
|
}
|
||||||
&mut bounds,
|
|
||||||
&mut layout_reflows,
|
propagate_reflow(
|
||||||
&mut reflown,
|
&id,
|
||||||
&modifiers,
|
state,
|
||||||
),
|
&mut entries,
|
||||||
|
&mut bounds,
|
||||||
|
&mut layout_reflows,
|
||||||
|
&mut reflown,
|
||||||
|
&modifiers,
|
||||||
|
)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for id in layout_reflows.iter() {
|
let mut layout_reflows_vec: Vec<Uuid> = layout_reflows.into_iter().collect();
|
||||||
|
|
||||||
|
// We sort the reflows so they are process first the ones that are more
|
||||||
|
// deep in the tree structure. This way we can be sure that the children layouts
|
||||||
|
// are already reflowed.
|
||||||
|
layout_reflows_vec.sort_unstable_by(|id_a, id_b| {
|
||||||
|
let da = shapes.get_depth(id_a);
|
||||||
|
let db = shapes.get_depth(id_b);
|
||||||
|
db.cmp(&da)
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut bounds_temp = bounds.clone();
|
||||||
|
for id in layout_reflows_vec.iter() {
|
||||||
if reflown.contains(id) {
|
if reflown.contains(id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
reflow_shape(id, state, &mut reflown, &mut entries, &mut bounds);
|
reflow_shape(id, state, &mut reflown, &mut entries, &mut bounds_temp);
|
||||||
}
|
}
|
||||||
layout_reflows = Vec::new();
|
layout_reflows = HashSet::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
modifiers
|
modifiers
|
||||||
|
|||||||
@ -61,6 +61,7 @@ impl LayoutAxis {
|
|||||||
layout_data: &LayoutData,
|
layout_data: &LayoutData,
|
||||||
flex_data: &FlexData,
|
flex_data: &FlexData,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let num_child = shape.children_count();
|
||||||
if flex_data.is_row() {
|
if flex_data.is_row() {
|
||||||
Self {
|
Self {
|
||||||
main_size: layout_bounds.width(),
|
main_size: layout_bounds.width(),
|
||||||
@ -73,8 +74,8 @@ impl LayoutAxis {
|
|||||||
padding_across_end: layout_data.padding_bottom,
|
padding_across_end: layout_data.padding_bottom,
|
||||||
gap_main: layout_data.column_gap,
|
gap_main: layout_data.column_gap,
|
||||||
gap_across: layout_data.row_gap,
|
gap_across: layout_data.row_gap,
|
||||||
is_auto_main: shape.is_layout_horizontal_auto(),
|
is_auto_main: num_child > 0 && shape.is_layout_horizontal_auto(),
|
||||||
is_auto_across: shape.is_layout_vertical_auto(),
|
is_auto_across: num_child > 0 && shape.is_layout_vertical_auto(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Self {
|
Self {
|
||||||
@ -88,8 +89,8 @@ impl LayoutAxis {
|
|||||||
padding_across_end: layout_data.padding_right,
|
padding_across_end: layout_data.padding_right,
|
||||||
gap_main: layout_data.row_gap,
|
gap_main: layout_data.row_gap,
|
||||||
gap_across: layout_data.column_gap,
|
gap_across: layout_data.column_gap,
|
||||||
is_auto_main: shape.is_layout_vertical_auto(),
|
is_auto_main: num_child > 0 && shape.is_layout_vertical_auto(),
|
||||||
is_auto_across: shape.is_layout_horizontal_auto(),
|
is_auto_across: num_child > 0 && shape.is_layout_horizontal_auto(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -345,7 +346,10 @@ fn distribute_fill_across_space(layout_axis: &LayoutAxis, tracks: &mut [TrackDat
|
|||||||
let mut size =
|
let mut size =
|
||||||
track.across_size - child.margin_across_start - child.margin_across_end;
|
track.across_size - child.margin_across_start - child.margin_across_end;
|
||||||
size = size.clamp(child.min_across_size, child.max_across_size);
|
size = size.clamp(child.min_across_size, child.max_across_size);
|
||||||
size = f32::min(size, layout_axis.across_space());
|
|
||||||
|
if !layout_axis.is_auto_across {
|
||||||
|
size = f32::min(size, layout_axis.across_space());
|
||||||
|
}
|
||||||
child.across_size = size;
|
child.across_size = size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -620,9 +624,12 @@ pub fn reflow_flex_layout(
|
|||||||
|
|
||||||
let mut transform = Matrix::default();
|
let mut transform = Matrix::default();
|
||||||
|
|
||||||
|
let mut force_reflow = false;
|
||||||
if (new_width - child_bounds.width()).abs() > MIN_SIZE
|
if (new_width - child_bounds.width()).abs() > MIN_SIZE
|
||||||
|| (new_height - child_bounds.height()).abs() > MIN_SIZE
|
|| (new_height - child_bounds.height()).abs() > MIN_SIZE
|
||||||
{
|
{
|
||||||
|
// When the child is fill we need to force a reflow
|
||||||
|
force_reflow = true;
|
||||||
transform.post_concat(&math::resize_matrix(
|
transform.post_concat(&math::resize_matrix(
|
||||||
layout_bounds,
|
layout_bounds,
|
||||||
child_bounds,
|
child_bounds,
|
||||||
@ -637,7 +644,7 @@ pub fn reflow_flex_layout(
|
|||||||
|
|
||||||
result.push_back(Modifier::transform_propagate(child.id, transform));
|
result.push_back(Modifier::transform_propagate(child.id, transform));
|
||||||
if child.has_layout() {
|
if child.has_layout() {
|
||||||
result.push_back(Modifier::reflow(child.id));
|
result.push_back(Modifier::reflow(child.id, force_reflow));
|
||||||
}
|
}
|
||||||
|
|
||||||
shape_anchor = next_anchor(
|
shape_anchor = next_anchor(
|
||||||
|
|||||||
@ -765,9 +765,12 @@ pub fn reflow_grid_layout(
|
|||||||
|
|
||||||
let mut transform = Matrix::default();
|
let mut transform = Matrix::default();
|
||||||
|
|
||||||
|
let mut force_reflow = false;
|
||||||
if (new_width - child_bounds.width()).abs() > MIN_SIZE
|
if (new_width - child_bounds.width()).abs() > MIN_SIZE
|
||||||
|| (new_height - child_bounds.height()).abs() > MIN_SIZE
|
|| (new_height - child_bounds.height()).abs() > MIN_SIZE
|
||||||
{
|
{
|
||||||
|
// When the child is a fill it needs to be reflown
|
||||||
|
force_reflow = true;
|
||||||
transform.post_concat(&math::resize_matrix(
|
transform.post_concat(&math::resize_matrix(
|
||||||
&layout_bounds,
|
&layout_bounds,
|
||||||
&child_bounds,
|
&child_bounds,
|
||||||
@ -793,7 +796,7 @@ pub fn reflow_grid_layout(
|
|||||||
|
|
||||||
result.push_back(Modifier::transform_propagate(child.id, transform));
|
result.push_back(Modifier::transform_propagate(child.id, transform));
|
||||||
if child.has_layout() {
|
if child.has_layout() {
|
||||||
result.push_back(Modifier::reflow(child.id));
|
result.push_back(Modifier::reflow(child.id, force_reflow));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@ use skia::Matrix;
|
|||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
pub enum Modifier {
|
pub enum Modifier {
|
||||||
Transform(TransformEntry),
|
Transform(TransformEntry),
|
||||||
Reflow(Uuid),
|
Reflow(Uuid, bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Modifier {
|
impl Modifier {
|
||||||
@ -18,8 +18,8 @@ impl Modifier {
|
|||||||
pub fn parent(id: Uuid, transform: Matrix) -> Self {
|
pub fn parent(id: Uuid, transform: Matrix) -> Self {
|
||||||
Modifier::Transform(TransformEntry::parent(id, transform))
|
Modifier::Transform(TransformEntry::parent(id, transform))
|
||||||
}
|
}
|
||||||
pub fn reflow(id: Uuid) -> Self {
|
pub fn reflow(id: Uuid, force_reflow: bool) -> Self {
|
||||||
Modifier::Reflow(id)
|
Modifier::Reflow(id, force_reflow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -177,6 +177,26 @@ impl ShapesPoolImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Given an id, returns the depth in the tree-shaped structure
|
||||||
|
// of shapes.
|
||||||
|
pub fn get_depth(&self, id: &Uuid) -> usize {
|
||||||
|
if id == &Uuid::nil() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(idx) = self.uuid_to_idx.get(id) else {
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
let shape = &self.shapes[*idx];
|
||||||
|
|
||||||
|
let Some(parent_id) = shape.parent_id else {
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.get_depth(&parent_id) + 1
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn iter(&self) -> std::slice::Iter<'_, Shape> {
|
pub fn iter(&self) -> std::slice::Iter<'_, Shape> {
|
||||||
self.shapes.iter()
|
self.shapes.iter()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user