mirror of
https://github.com/penpot/penpot.git
synced 2025-06-24 13:47:01 +02:00
Merge pull request #6578 from penpot/ladybenko-11105-cap-fills
🎉 Disable adding fills in UI when limit has been reached
This commit is contained in:
commit
50cc70201d
14 changed files with 415 additions and 51 deletions
|
@ -127,7 +127,8 @@
|
|||
:render-wasm-dpr
|
||||
:hide-release-modal
|
||||
:subscriptions
|
||||
:subscriptions-old})
|
||||
:subscriptions-old
|
||||
:frontend-binary-fills})
|
||||
|
||||
(def all-flags
|
||||
(set/union email login varia))
|
||||
|
|
|
@ -762,4 +762,7 @@
|
|||
(cond-> (cfh/text-shape? shape) (patch-text-props props))
|
||||
(cond-> (cfh/frame-shape? shape) (patch-layout-props props)))))
|
||||
|
||||
;; FIXME: Get these from the wasm module, and tweak the values
|
||||
;; (we'd probably want 12 stops at most)
|
||||
(def MAX-GRADIENT-STOPS 16)
|
||||
(def MAX-FILLS 8)
|
||||
|
|
318
frontend/playwright/data/design/get-file-fills-limit.json
Normal file
318
frontend/playwright/data/design/get-file-fills-limit.json
Normal file
|
@ -0,0 +1,318 @@
|
|||
{
|
||||
"~:features": {
|
||||
"~#set": [
|
||||
"fdata/path-data",
|
||||
"plugins/runtime",
|
||||
"design-tokens/v1",
|
||||
"layout/grid",
|
||||
"styles/v2",
|
||||
"fdata/pointer-map",
|
||||
"fdata/objects-map",
|
||||
"components/v2",
|
||||
"fdata/shape-data-type"
|
||||
]
|
||||
},
|
||||
"~:team-id": "~ua78f45d1-6166-80e4-8006-37f8ef82b13c",
|
||||
"~:permissions": {
|
||||
"~:type": "~:membership",
|
||||
"~:is-owner": true,
|
||||
"~:is-admin": true,
|
||||
"~:can-edit": true,
|
||||
"~:can-read": true,
|
||||
"~:is-logged": true
|
||||
},
|
||||
"~:has-media-trimmed": false,
|
||||
"~:comment-thread-seqn": 0,
|
||||
"~:name": "Cap fills",
|
||||
"~:revn": 2,
|
||||
"~:modified-at": "~m1748504366715",
|
||||
"~:vern": 0,
|
||||
"~:id": "~ud2847136-a651-80ac-8006-4202d9214aa7",
|
||||
"~:is-shared": false,
|
||||
"~:migrations": {
|
||||
"~#ordered-set": [
|
||||
"legacy-2",
|
||||
"legacy-3",
|
||||
"legacy-5",
|
||||
"legacy-6",
|
||||
"legacy-7",
|
||||
"legacy-8",
|
||||
"legacy-9",
|
||||
"legacy-10",
|
||||
"legacy-11",
|
||||
"legacy-12",
|
||||
"legacy-13",
|
||||
"legacy-14",
|
||||
"legacy-16",
|
||||
"legacy-17",
|
||||
"legacy-18",
|
||||
"legacy-19",
|
||||
"legacy-25",
|
||||
"legacy-26",
|
||||
"legacy-27",
|
||||
"legacy-28",
|
||||
"legacy-29",
|
||||
"legacy-31",
|
||||
"legacy-32",
|
||||
"legacy-33",
|
||||
"legacy-34",
|
||||
"legacy-36",
|
||||
"legacy-37",
|
||||
"legacy-38",
|
||||
"legacy-39",
|
||||
"legacy-40",
|
||||
"legacy-41",
|
||||
"legacy-42",
|
||||
"legacy-43",
|
||||
"legacy-44",
|
||||
"legacy-45",
|
||||
"legacy-46",
|
||||
"legacy-47",
|
||||
"legacy-48",
|
||||
"legacy-49",
|
||||
"legacy-50",
|
||||
"legacy-51",
|
||||
"legacy-52",
|
||||
"legacy-53",
|
||||
"legacy-54",
|
||||
"legacy-55",
|
||||
"legacy-56",
|
||||
"legacy-57",
|
||||
"legacy-59",
|
||||
"legacy-62",
|
||||
"legacy-65",
|
||||
"legacy-66",
|
||||
"legacy-67",
|
||||
"0001-remove-tokens-from-groups",
|
||||
"0002-normalize-bool-content",
|
||||
"0002-clean-shape-interactions",
|
||||
"0003-fix-root-shape",
|
||||
"0003-convert-path-content"
|
||||
]
|
||||
},
|
||||
"~:version": 67,
|
||||
"~:project-id": "~ua78f45d1-6166-80e4-8006-37f8ef83114f",
|
||||
"~:created-at": "~m1748504346802",
|
||||
"~:data": {
|
||||
"~:pages": [
|
||||
"~ud2847136-a651-80ac-8006-4202d9214aa8"
|
||||
],
|
||||
"~:pages-index": {
|
||||
"~ud2847136-a651-80ac-8006-4202d9214aa8": {
|
||||
"~:objects": {
|
||||
"~u00000000-0000-0000-0000-000000000000": {
|
||||
"~#shape": {
|
||||
"~:y": 0,
|
||||
"~:hide-fill-on-export": false,
|
||||
"~:transform": {
|
||||
"~#matrix": {
|
||||
"~:a": 1.0,
|
||||
"~:b": 0.0,
|
||||
"~:c": 0.0,
|
||||
"~:d": 1.0,
|
||||
"~:e": 0.0,
|
||||
"~:f": 0.0
|
||||
}
|
||||
},
|
||||
"~:rotation": 0,
|
||||
"~:name": "Root Frame",
|
||||
"~:width": 0.01,
|
||||
"~:type": "~:frame",
|
||||
"~:points": [
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 0.0,
|
||||
"~:y": 0.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 0.01,
|
||||
"~:y": 0.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 0.01,
|
||||
"~:y": 0.01
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 0.0,
|
||||
"~:y": 0.01
|
||||
}
|
||||
}
|
||||
],
|
||||
"~:r2": 0,
|
||||
"~:proportion-lock": false,
|
||||
"~:transform-inverse": {
|
||||
"~#matrix": {
|
||||
"~:a": 1.0,
|
||||
"~:b": 0.0,
|
||||
"~:c": 0.0,
|
||||
"~:d": 1.0,
|
||||
"~:e": 0.0,
|
||||
"~:f": 0.0
|
||||
}
|
||||
},
|
||||
"~:r3": 0,
|
||||
"~:r1": 0,
|
||||
"~:id": "~u00000000-0000-0000-0000-000000000000",
|
||||
"~:parent-id": "~u00000000-0000-0000-0000-000000000000",
|
||||
"~:frame-id": "~u00000000-0000-0000-0000-000000000000",
|
||||
"~:strokes": [],
|
||||
"~:x": 0,
|
||||
"~:proportion": 1.0,
|
||||
"~:r4": 0,
|
||||
"~:selrect": {
|
||||
"~#rect": {
|
||||
"~:x": 0,
|
||||
"~:y": 0,
|
||||
"~:width": 0.01,
|
||||
"~:height": 0.01,
|
||||
"~:x1": 0,
|
||||
"~:y1": 0,
|
||||
"~:x2": 0.01,
|
||||
"~:y2": 0.01
|
||||
}
|
||||
},
|
||||
"~:fills": [
|
||||
{
|
||||
"~:fill-color": "#FFFFFF",
|
||||
"~:fill-opacity": 1
|
||||
}
|
||||
],
|
||||
"~:flip-x": null,
|
||||
"~:height": 0.01,
|
||||
"~:flip-y": null,
|
||||
"~:shapes": [
|
||||
"~u0ade1723-2e87-80b6-8006-4202db189b25"
|
||||
]
|
||||
}
|
||||
},
|
||||
"~u0ade1723-2e87-80b6-8006-4202db189b25": {
|
||||
"~#shape": {
|
||||
"~:y": 406,
|
||||
"~:transform": {
|
||||
"~#matrix": {
|
||||
"~:a": 1.0,
|
||||
"~:b": 0.0,
|
||||
"~:c": 0.0,
|
||||
"~:d": 1.0,
|
||||
"~:e": 0.0,
|
||||
"~:f": 0.0
|
||||
}
|
||||
},
|
||||
"~:rotation": 0,
|
||||
"~:grow-type": "~:fixed",
|
||||
"~:hide-in-viewer": false,
|
||||
"~:name": "Rectangle",
|
||||
"~:width": 170,
|
||||
"~:type": "~:rect",
|
||||
"~:points": [
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 716,
|
||||
"~:y": 406
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 886,
|
||||
"~:y": 406
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 886,
|
||||
"~:y": 528
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 716,
|
||||
"~:y": 528
|
||||
}
|
||||
}
|
||||
],
|
||||
"~:r2": 0,
|
||||
"~:proportion-lock": false,
|
||||
"~:transform-inverse": {
|
||||
"~#matrix": {
|
||||
"~:a": 1.0,
|
||||
"~:b": 0.0,
|
||||
"~:c": 0.0,
|
||||
"~:d": 1.0,
|
||||
"~:e": 0.0,
|
||||
"~:f": 0.0
|
||||
}
|
||||
},
|
||||
"~:r3": 0,
|
||||
"~:r1": 0,
|
||||
"~:id": "~u0ade1723-2e87-80b6-8006-4202db189b25",
|
||||
"~:parent-id": "~u00000000-0000-0000-0000-000000000000",
|
||||
"~:frame-id": "~u00000000-0000-0000-0000-000000000000",
|
||||
"~:strokes": [],
|
||||
"~:x": 716,
|
||||
"~:proportion": 1,
|
||||
"~:r4": 0,
|
||||
"~:selrect": {
|
||||
"~#rect": {
|
||||
"~:x": 716,
|
||||
"~:y": 406,
|
||||
"~:width": 170,
|
||||
"~:height": 122,
|
||||
"~:x1": 716,
|
||||
"~:y1": 406,
|
||||
"~:x2": 886,
|
||||
"~:y2": 528
|
||||
}
|
||||
},
|
||||
"~:fills": [
|
||||
{
|
||||
"~:fill-color": "#B1B2B5",
|
||||
"~:fill-opacity": 1
|
||||
},
|
||||
{
|
||||
"~:fill-color": "#B1B2B5",
|
||||
"~:fill-opacity": 1
|
||||
},
|
||||
{
|
||||
"~:fill-color": "#B1B2B5",
|
||||
"~:fill-opacity": 1
|
||||
},
|
||||
{
|
||||
"~:fill-color": "#B1B2B5",
|
||||
"~:fill-opacity": 1
|
||||
},
|
||||
{
|
||||
"~:fill-color": "#B1B2B5",
|
||||
"~:fill-opacity": 1
|
||||
},
|
||||
{
|
||||
"~:fill-color": "#B1B2B5",
|
||||
"~:fill-opacity": 1
|
||||
},
|
||||
{
|
||||
"~:fill-color": "#B1B2B5",
|
||||
"~:fill-opacity": 1
|
||||
}
|
||||
],
|
||||
"~:flip-x": null,
|
||||
"~:height": 122,
|
||||
"~:flip-y": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"~:id": "~ud2847136-a651-80ac-8006-4202d9214aa8",
|
||||
"~:name": "Page 1"
|
||||
}
|
||||
},
|
||||
"~:id": "~ud2847136-a651-80ac-8006-4202d9214aa7",
|
||||
"~:options": {
|
||||
"~:components-v2": true,
|
||||
"~:base-font-size": "16px"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -153,7 +153,7 @@ test("Create a RADIAL gradient", async ({ page }) => {
|
|||
|
||||
test("Gradient stops limit", async ({ page }) => {
|
||||
const workspacePage = new WorkspacePage(page);
|
||||
await workspacePage.mockConfigFlags(["enable-binary-fills"]);
|
||||
await workspacePage.mockConfigFlags(["enable-frontend-binary-fills"]);
|
||||
await workspacePage.setupEmptyFile(page);
|
||||
await workspacePage.mockRPC(
|
||||
"get-file-fragment?file-id=*&fragment-id=*",
|
||||
|
|
|
@ -66,6 +66,31 @@ test.describe("Constraints", () => {
|
|||
});
|
||||
});
|
||||
|
||||
test.describe("Shape attributes", () => {
|
||||
test("Cannot add a new fill when the limit has been reached", async ({
|
||||
page,
|
||||
}) => {
|
||||
const workspace = new WorkspacePage(page);
|
||||
await workspace.mockConfigFlags(["enable-frontend-binary-fills"]);
|
||||
await workspace.setupEmptyFile();
|
||||
await workspace.mockRPC(/get\-file\?/, "design/get-file-fills-limit.json");
|
||||
|
||||
await workspace.goToWorkspace({
|
||||
fileId: "d2847136-a651-80ac-8006-4202d9214aa7",
|
||||
pageId: "d2847136-a651-80ac-8006-4202d9214aa8",
|
||||
});
|
||||
|
||||
await workspace.clickLeafLayer("Rectangle");
|
||||
|
||||
await workspace.page.getByTestId("add-fill").click();
|
||||
await expect(
|
||||
workspace.page.getByRole("button", { name: "#B1B2B5" }),
|
||||
).toHaveCount(8);
|
||||
|
||||
await expect(workspace.page.getByTestId("add-fill")).toBeDisabled();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Multiple shapes attributes", () => {
|
||||
test("User selects multiple shapes with sames fills, strokes, shadows and blur", async ({
|
||||
page,
|
||||
|
|
|
@ -222,7 +222,6 @@
|
|||
(update :fills #(into [attrs] %))))
|
||||
undo-id
|
||||
(js/Symbol)]
|
||||
|
||||
(rx/concat
|
||||
(rx/of (dwu/start-undo-transaction undo-id))
|
||||
(transform-fill state ids color change-fn options)
|
||||
|
@ -823,7 +822,7 @@
|
|||
(update [_ state]
|
||||
(update state :colorpicker
|
||||
(fn [{:keys [stops editing-stop] :as state}]
|
||||
(let [cap-stops? (or (features/active-feature? state "render-wasm/v1") (contains? cfg/flags :binary-fills))
|
||||
(let [cap-stops? (or (features/active-feature? state "render-wasm/v1") (contains? cfg/flags :frontend-binary-fills))
|
||||
can-add-stop? (or (not cap-stops?) (< (count stops) shp/MAX-GRADIENT-STOPS))]
|
||||
(if can-add-stop?
|
||||
(if (cc/uniform-spread? stops)
|
||||
|
@ -869,7 +868,7 @@
|
|||
(update state :colorpicker
|
||||
(fn [state]
|
||||
(let [stops (:stops state)
|
||||
cap-stops? (or (features/active-feature? state "render-wasm/v1") (contains? cfg/flags :binary-fills))
|
||||
cap-stops? (or (features/active-feature? state "render-wasm/v1") (contains? cfg/flags :frontend-binary-fills))
|
||||
can-add-stop? (or (not cap-stops?) (< (count stops) shp/MAX-GRADIENT-STOPS))]
|
||||
(if can-add-stop? (let [new-stop (-> (cc/interpolate-gradient stops offset)
|
||||
(split-color-components))
|
||||
|
@ -890,7 +889,7 @@
|
|||
(update state :colorpicker
|
||||
(fn [state]
|
||||
(let [stop (or (:editing-stop state) 0)
|
||||
cap-stops? (or (features/active-feature? state "render-wasm/v1") (contains? cfg/flags :binary-fills))
|
||||
cap-stops? (or (features/active-feature? state "render-wasm/v1") (contains? cfg/flags :frontend-binary-fills))
|
||||
stops (mapv split-color-components (if cap-stops? (take shp/MAX-GRADIENT-STOPS stops) stops))]
|
||||
(-> state
|
||||
(assoc :current-color (get stops stop))
|
||||
|
|
|
@ -338,7 +338,7 @@
|
|||
(fn [value]
|
||||
(st/emit! (dc/update-colorpicker-gradient-opacity (/ value 100)))))
|
||||
|
||||
cap-stops? (or (features/use-feature "render-wasm/v1") (contains? cfg/flags :binary-fills))
|
||||
cap-stops? (or (features/use-feature "render-wasm/v1") (contains? cfg/flags :frontend-binary-fills))
|
||||
|
||||
tabs
|
||||
#js [#js {:aria-label (tr "workspace.libraries.colors.rgba")
|
||||
|
|
|
@ -287,7 +287,7 @@
|
|||
(fn []
|
||||
(when on-reverse-stops
|
||||
(on-reverse-stops))))
|
||||
cap-stops? (or (features/use-feature "render-wasm/v1") (contains? cfg/flags :binary-fills))
|
||||
cap-stops? (or (features/use-feature "render-wasm/v1") (contains? cfg/flags :frontend-binary-fills))
|
||||
add-stop-disabled? (when cap-stops? (>= (count stops) shp/MAX-GRADIENT-STOPS))]
|
||||
|
||||
[:div {:class (stl/css :gradient-panel)}
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
[app.common.colors :as clr]
|
||||
[app.common.data :as d]
|
||||
[app.common.types.color :as ctc]
|
||||
[app.common.types.shape :as shp]
|
||||
[app.common.types.shape.attrs :refer [default-color]]
|
||||
[app.config :as cfg]
|
||||
[app.main.data.workspace.colors :as dc]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.title-bar :refer [title-bar]]
|
||||
|
@ -44,7 +46,7 @@
|
|||
|
||||
(mf/defc fill-menu
|
||||
{::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values"]))]}
|
||||
[{:keys [ids type values disable-remove?] :as props}]
|
||||
[{:keys [ids type values] :as props}]
|
||||
(let [label (case type
|
||||
:multiple (tr "workspace.options.selection-fill")
|
||||
:group (tr "workspace.options.group-fill")
|
||||
|
@ -52,9 +54,14 @@
|
|||
|
||||
;; Excluding nil values
|
||||
values (d/without-nils values)
|
||||
fills (:fills values)
|
||||
fills (if (contains? cfg/flags :frontend-binary-fills)
|
||||
(take shp/MAX-FILLS (d/nilv (:fills values) []))
|
||||
(:fills values))
|
||||
has-fills? (or (= :multiple fills) (some? (seq fills)))
|
||||
|
||||
can-add-fills? (if (contains? cfg/flags :frontend-binary-fills)
|
||||
(and (not (= :multiple fills))
|
||||
(< (count fills) shp/MAX-FILLS))
|
||||
(not (= :multiple fills)))
|
||||
|
||||
state* (mf/use-state has-fills?)
|
||||
open? (deref state*)
|
||||
|
@ -73,12 +80,12 @@
|
|||
(mf/use-fn
|
||||
(mf/deps ids fills)
|
||||
(fn [_]
|
||||
(st/emit! (dc/add-fill ids {:color default-color
|
||||
:opacity 1}))
|
||||
|
||||
(when (or (= :multiple fills)
|
||||
(not (some? (seq fills))))
|
||||
(open-content))))
|
||||
(when can-add-fills?
|
||||
(st/emit! (dc/add-fill ids {:color default-color
|
||||
:opacity 1}))
|
||||
(when (or (= :multiple fills)
|
||||
(not (some? (seq fills))))
|
||||
(open-content)))))
|
||||
|
||||
on-change
|
||||
(fn [index]
|
||||
|
@ -146,11 +153,12 @@
|
|||
:title label
|
||||
:class (stl/css-case :title-spacing-fill (not has-fills?))}
|
||||
|
||||
(when (and (not disable-remove?) (not (= :multiple fills)))
|
||||
(when (not (= :multiple fills))
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "workspace.options.fill.add-fill")
|
||||
:on-click on-add
|
||||
:data-testid "add-fill"
|
||||
:disabled (not can-add-fills?)
|
||||
:icon "add"}])]]
|
||||
|
||||
(when open?
|
||||
|
@ -167,7 +175,7 @@
|
|||
|
||||
(seq fills)
|
||||
[:& h/sortable-container {}
|
||||
(for [[index value] (d/enumerate (:fills values []))]
|
||||
(for [[index value] (d/enumerate fills)]
|
||||
[:> color-row* {:color (ctc/fill->shape-color value)
|
||||
:key index
|
||||
:index index
|
||||
|
|
|
@ -134,7 +134,7 @@
|
|||
|
||||
handler-state (mf/use-state {:display? false :offset 0 :hover nil})
|
||||
|
||||
cap-stops? (or (features/use-feature "render-wasm/v1") (contains? cfg/flags :binary-fills))
|
||||
cap-stops? (or (features/use-feature "render-wasm/v1") (contains? cfg/flags :frontend-binary-fills))
|
||||
can-add-stop? (if cap-stops? (< (count stops) shp/MAX-GRADIENT-STOPS) true)
|
||||
|
||||
endpoint-on-pointer-down
|
||||
|
@ -525,7 +525,7 @@
|
|||
shape (mf/deref shape-ref)
|
||||
state (mf/deref refs/colorpicker)
|
||||
gradient (:gradient state)
|
||||
cap-stops? (or (features/use-feature "render-wasm/v1") (contains? cfg/flags :binary-fills))
|
||||
cap-stops? (or (features/use-feature "render-wasm/v1") (contains? cfg/flags :frontend-binary-fills))
|
||||
stops (if cap-stops?
|
||||
(vec (take shp/MAX-GRADIENT-STOPS (:stops state)))
|
||||
(:stops state))
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.types.path :as path]
|
||||
[app.common.types.shape :as shp]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.config :as cf]
|
||||
|
@ -241,33 +242,24 @@
|
|||
[fills]
|
||||
(h/call wasm/internal-module "_clear_shape_fills")
|
||||
(keep (fn [fill]
|
||||
(let [opacity (or (:fill-opacity fill) 1.0)
|
||||
color (:fill-color fill)
|
||||
gradient (:fill-color-gradient fill)
|
||||
image (:fill-image fill)
|
||||
offset (mem/alloc-bytes sr-fills/FILL-BYTE-SIZE)
|
||||
(let [offset (mem/alloc-bytes sr-fills/FILL-BYTE-SIZE)
|
||||
heap (mem/get-heap-u8)
|
||||
dview (js/DataView. (.-buffer heap))]
|
||||
(cond
|
||||
(some? color)
|
||||
(do
|
||||
(sr-fills/write-solid-fill! offset dview (sr-clr/hex->u32argb color opacity))
|
||||
(h/call wasm/internal-module "_add_shape_fill"))
|
||||
|
||||
(some? gradient)
|
||||
(do
|
||||
(sr-fills/write-gradient-fill! offset dview gradient opacity)
|
||||
(h/call wasm/internal-module "_add_shape_fill"))
|
||||
|
||||
(some? image)
|
||||
(let [id (dm/get-prop image :id)
|
||||
buffer (uuid/get-u32 id)
|
||||
cached-image? (h/call wasm/internal-module "_is_image_cached" (aget buffer 0) (aget buffer 1) (aget buffer 2) (aget buffer 3))]
|
||||
(sr-fills/write-image-fill! offset dview id opacity (dm/get-prop image :width) (dm/get-prop image :height))
|
||||
(h/call wasm/internal-module "_add_shape_fill")
|
||||
(when (== cached-image? 0)
|
||||
dview (js/DataView. (.-buffer heap))
|
||||
image (:fill-image fill)]
|
||||
(sr-fills/write-fill! offset dview fill)
|
||||
(h/call wasm/internal-module "_add_shape_fill")
|
||||
;; store image for image fills if not cached
|
||||
(when (some? image)
|
||||
(let [id (dm/get-prop image :id)
|
||||
buffer (uuid/get-u32 id)
|
||||
cached-image? (h/call wasm/internal-module "_is_image_cached"
|
||||
(aget buffer 0)
|
||||
(aget buffer 1)
|
||||
(aget buffer 2)
|
||||
(aget buffer 3))]
|
||||
(when (zero? cached-image?)
|
||||
(store-image id))))))
|
||||
fills))
|
||||
(take shp/MAX-FILLS fills)))
|
||||
|
||||
(defn set-shape-strokes
|
||||
[strokes]
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
(ns app.render-wasm.serializers.fills
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.types.shape :as shp]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.render-wasm.serializers.color :as clr]))
|
||||
|
||||
(def ^:private GRADIENT-STOP-SIZE 8)
|
||||
|
||||
|
||||
(def GRADIENT-BYTE-SIZE 156)
|
||||
(def SOLID-BYTE-SIZE 4)
|
||||
(def IMAGE-BYTE-SIZE 28)
|
||||
|
@ -14,6 +14,7 @@
|
|||
;; FIXME: get it from the wasm module
|
||||
(def FILL-BYTE-SIZE (+ 4 (max GRADIENT-BYTE-SIZE IMAGE-BYTE-SIZE SOLID-BYTE-SIZE)))
|
||||
|
||||
|
||||
(defn write-solid-fill!
|
||||
[offset dview argb]
|
||||
(.setUint8 dview offset 0x00 true)
|
||||
|
@ -61,3 +62,20 @@
|
|||
(.setUint32 dview loop-offset argb true)
|
||||
(.setFloat32 dview (+ loop-offset 4) stop-offset true)
|
||||
(recur (rest stops) (+ loop-offset GRADIENT-STOP-SIZE)))))))
|
||||
|
||||
(defn write-fill!
|
||||
[offset dview fill]
|
||||
(let [opacity (or (:fill-opacity fill) 1.0)
|
||||
color (:fill-color fill)
|
||||
gradient (:fill-color-gradient fill)
|
||||
image (:fill-image fill)]
|
||||
(cond
|
||||
(some? color)
|
||||
(write-solid-fill! offset dview (clr/hex->u32argb color opacity))
|
||||
|
||||
(some? gradient)
|
||||
(write-gradient-fill! offset dview gradient opacity)
|
||||
|
||||
(some? image)
|
||||
(let [id (dm/get-prop image :id)]
|
||||
(write-image-fill! offset dview id opacity (dm/get-prop image :width) (dm/get-prop image :height))))))
|
|
@ -5617,7 +5617,7 @@ msgstr "Fill"
|
|||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:151
|
||||
msgid "workspace.options.fill.add-fill"
|
||||
msgstr "Add fill color"
|
||||
msgstr "Add fill"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:164
|
||||
msgid "workspace.options.fill.remove-fill"
|
||||
|
|
|
@ -5646,7 +5646,7 @@ msgstr "Relleno"
|
|||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:151
|
||||
msgid "workspace.options.fill.add-fill"
|
||||
msgstr "Añadir color de relleno"
|
||||
msgstr "Añadir relleno"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:164
|
||||
msgid "workspace.options.fill.remove-fill"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue