@lvl99dotcom/paintcanvas 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +131 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -0
- package/dist/lib/brushes/BrushTipCache/index.d.ts +32 -0
- package/dist/lib/brushes/BrushTipCache/index.js +60 -0
- package/dist/lib/brushes/StrokeEngine/index.d.ts +171 -0
- package/dist/lib/brushes/StrokeEngine/index.js +324 -0
- package/dist/lib/brushes/StrokePath/index.d.ts +53 -0
- package/dist/lib/brushes/StrokePath/index.js +161 -0
- package/dist/lib/brushes/StrokeSampler/index.d.ts +55 -0
- package/dist/lib/brushes/StrokeSampler/index.js +75 -0
- package/dist/lib/brushes/authors/index.d.ts +55 -0
- package/dist/lib/brushes/authors/index.js +60 -0
- package/dist/lib/brushes/configRanges/index.d.ts +52 -0
- package/dist/lib/brushes/configRanges/index.js +206 -0
- package/dist/lib/brushes/index.d.ts +5 -0
- package/dist/lib/brushes/index.js +19 -0
- package/dist/lib/brushes/params/index.d.ts +108 -0
- package/dist/lib/brushes/params/index.js +139 -0
- package/dist/lib/brushes/presetFile/index.d.ts +32 -0
- package/dist/lib/brushes/presetFile/index.js +55 -0
- package/dist/lib/brushes/presets/drawing/brush-pen.js +3 -0
- package/dist/lib/brushes/presets/drawing/felt-pen.js +3 -0
- package/dist/lib/brushes/presets/drawing/index.d.ts +13 -0
- package/dist/lib/brushes/presets/drawing/index.js +88 -0
- package/dist/lib/brushes/presets/drawing/pencil-2b.js +3 -0
- package/dist/lib/brushes/presets/drawing/pencil-hb.js +3 -0
- package/dist/lib/brushes/presets/painting/grass.js +3 -0
- package/dist/lib/brushes/presets/painting/hair.js +3 -0
- package/dist/lib/brushes/presets/painting/index.d.ts +18 -0
- package/dist/lib/brushes/presets/painting/index.js +118 -0
- package/dist/lib/brushes/presets/painting/splatter.js +3 -0
- package/dist/lib/brushes/presets/painting/textured-paint.js +3 -0
- package/dist/lib/brushes/presets/painting/watery-paint.js +3 -0
- package/dist/lib/brushes/presets/round/index.d.ts +9 -0
- package/dist/lib/brushes/presets/round/index.js +44 -0
- package/dist/lib/brushes/presets/round/round.js +3 -0
- package/dist/lib/brushes/presets/round/soft-round.js +3 -0
- package/dist/lib/brushes/presets/sized/index.d.ts +20 -0
- package/dist/lib/brushes/presets/sized/index.js +30 -0
- package/dist/lib/brushes/presets/sketching/index.d.ts +14 -0
- package/dist/lib/brushes/presets/sketching/index.js +107 -0
- package/dist/lib/brushes/presets/square/index.d.ts +7 -0
- package/dist/lib/brushes/presets/square/index.js +22 -0
- package/dist/lib/brushes/presets/square/square.js +3 -0
- package/dist/lib/brushes/shapeImage/index.d.ts +40 -0
- package/dist/lib/brushes/shapeImage/index.js +61 -0
- package/dist/lib/brushes/types/index.d.ts +243 -0
- package/dist/lib/brushes/types/index.js +20 -0
- package/dist/lib/classes/BackgroundWork/index.d.ts +55 -0
- package/dist/lib/classes/BackgroundWork/index.js +97 -0
- package/dist/lib/classes/BrushSettings/index.d.ts +91 -0
- package/dist/lib/classes/BrushSettings/index.js +152 -0
- package/dist/lib/classes/CustomPresets/index.d.ts +53 -0
- package/dist/lib/classes/CustomPresets/index.js +71 -0
- package/dist/lib/classes/ExternalSheets/index.d.ts +64 -0
- package/dist/lib/classes/ExternalSheets/index.js +112 -0
- package/dist/lib/classes/GestureTracker/index.d.ts +62 -0
- package/dist/lib/classes/GestureTracker/index.js +122 -0
- package/dist/lib/classes/History/index.d.ts +83 -0
- package/dist/lib/classes/History/index.js +126 -0
- package/dist/lib/classes/HistoryGuard/index.d.ts +58 -0
- package/dist/lib/classes/HistoryGuard/index.js +97 -0
- package/dist/lib/classes/InputSettings/index.d.ts +74 -0
- package/dist/lib/classes/InputSettings/index.js +101 -0
- package/dist/lib/classes/KeyboardShortcuts/index.d.ts +48 -0
- package/dist/lib/classes/KeyboardShortcuts/index.js +137 -0
- package/dist/lib/classes/Layer/index.d.ts +86 -0
- package/dist/lib/classes/Layer/index.js +111 -0
- package/dist/lib/classes/LayerAutosave/index.d.ts +180 -0
- package/dist/lib/classes/LayerAutosave/index.js +346 -0
- package/dist/lib/classes/LayerStack/index.d.ts +177 -0
- package/dist/lib/classes/LayerStack/index.js +394 -0
- package/dist/lib/classes/PaintCanvas/index.d.ts +537 -0
- package/dist/lib/classes/PaintCanvas/index.js +965 -0
- package/dist/lib/classes/StrokeLog/index.d.ts +149 -0
- package/dist/lib/classes/StrokeLog/index.js +257 -0
- package/dist/lib/classes/Viewport/index.d.ts +108 -0
- package/dist/lib/classes/Viewport/index.js +194 -0
- package/dist/lib/document/index.d.ts +17 -0
- package/dist/lib/document/index.js +25 -0
- package/dist/lib/document/schema.d.ts +132 -0
- package/dist/lib/document/schema.js +110 -0
- package/dist/lib/i18n/index.d.ts +94 -0
- package/dist/lib/i18n/index.js +182 -0
- package/dist/lib/image/index.d.ts +90 -0
- package/dist/lib/image/index.js +147 -0
- package/dist/lib/messages/PatchSender/index.d.ts +75 -0
- package/dist/lib/messages/PatchSender/index.js +125 -0
- package/dist/lib/messages/index.d.ts +26 -0
- package/dist/lib/messages/index.js +59 -0
- package/dist/lib/messages/schema.d.ts +1775 -0
- package/dist/lib/messages/schema.js +192 -0
- package/dist/lib/presets/index.d.ts +32 -0
- package/dist/lib/presets/index.js +35 -0
- package/dist/lib/presets/schema.d.ts +753 -0
- package/dist/lib/presets/schema.js +181 -0
- package/dist/lib/rendering/BrushTip/index.d.ts +63 -0
- package/dist/lib/rendering/BrushTip/index.js +112 -0
- package/dist/lib/rendering/checkerboard/index.d.ts +22 -0
- package/dist/lib/rendering/checkerboard/index.js +31 -0
- package/dist/lib/rendering/compositing/index.d.ts +64 -0
- package/dist/lib/rendering/compositing/index.js +124 -0
- package/dist/lib/rendering/cursor/index.d.ts +14 -0
- package/dist/lib/rendering/cursor/index.js +39 -0
- package/dist/lib/rendering/cursors/index.d.ts +18 -0
- package/dist/lib/rendering/cursors/index.js +23 -0
- package/dist/lib/rendering/maskOutline/index.d.ts +22 -0
- package/dist/lib/rendering/maskOutline/index.js +78 -0
- package/dist/lib/rendering/outline/index.d.ts +36 -0
- package/dist/lib/rendering/outline/index.js +120 -0
- package/dist/lib/rendering/sample/index.d.ts +55 -0
- package/dist/lib/rendering/sample/index.js +83 -0
- package/dist/lib/rendering/screenshot/index.d.ts +67 -0
- package/dist/lib/rendering/screenshot/index.js +96 -0
- package/dist/lib/rendering/transformBox/index.d.ts +10 -0
- package/dist/lib/rendering/transformBox/index.js +57 -0
- package/dist/lib/selection/Lasso/index.d.ts +70 -0
- package/dist/lib/selection/Lasso/index.js +156 -0
- package/dist/lib/selection/Selection/index.d.ts +86 -0
- package/dist/lib/selection/Selection/index.js +228 -0
- package/dist/lib/selection/geometry/index.d.ts +37 -0
- package/dist/lib/selection/geometry/index.js +57 -0
- package/dist/lib/storage/index.d.ts +63 -0
- package/dist/lib/storage/index.js +114 -0
- package/dist/lib/transform/Transformer/index.d.ts +124 -0
- package/dist/lib/transform/Transformer/index.js +286 -0
- package/dist/lib/transform/geometry/index.d.ts +95 -0
- package/dist/lib/transform/geometry/index.js +258 -0
- package/dist/lib/utils/array/index.d.ts +10 -0
- package/dist/lib/utils/array/index.js +21 -0
- package/dist/lib/utils/gestures/index.d.ts +35 -0
- package/dist/lib/utils/gestures/index.js +81 -0
- package/dist/lib/utils/navigation/index.d.ts +51 -0
- package/dist/lib/utils/navigation/index.js +59 -0
- package/dist/lib/utils/random/index.d.ts +18 -0
- package/dist/lib/utils/random/index.js +27 -0
- package/dist/lib/utils/shortcuts/index.d.ts +74 -0
- package/dist/lib/utils/shortcuts/index.js +189 -0
- package/dist/lib/validation/validators.generated.d.ts +27 -0
- package/dist/lib/validation/validators.generated.js +19826 -0
- package/dist/locales/en-GB.js +188 -0
- package/dist/locales/en-US.js +188 -0
- package/dist/locales/fr.js +188 -0
- package/dist/locales/ja.js +188 -0
- package/dist/locales/ko.js +188 -0
- package/dist/locales/zh-Hans.js +188 -0
- package/dist/locales/zh-Hant.js +188 -0
- package/dist/package.js +3 -0
- package/dist/testing/app.d.ts +7 -0
- package/dist/testing/app.js +16 -0
- package/dist/testing/elements.d.ts +42 -0
- package/dist/testing/elements.js +58 -0
- package/dist/testing/fakeCanvas.d.ts +21 -0
- package/dist/testing/fakeCanvas.js +26 -0
- package/dist/testing/layerStore.d.ts +26 -0
- package/dist/testing/layerStore.js +43 -0
- package/dist/testing/locks.d.ts +15 -0
- package/dist/testing/locks.js +41 -0
- package/dist/testing/recordingCanvas.d.ts +14 -0
- package/dist/testing/recordingCanvas.js +28 -0
- package/dist/testing/recordingContext.d.ts +10 -0
- package/dist/testing/recordingContext.js +19 -0
- package/dist/ui/ChangeController/index.d.ts +40 -0
- package/dist/ui/ChangeController/index.js +62 -0
- package/dist/ui/base/index.d.ts +69 -0
- package/dist/ui/base/index.js +94 -0
- package/dist/ui/elements/PaintCanvas/index.d.ts +249 -0
- package/dist/ui/elements/PaintCanvas/index.js +584 -0
- package/dist/ui/elements/PaintCanvas/style.js +3 -0
- package/dist/ui/elements/PcBrushConfig/index.d.ts +130 -0
- package/dist/ui/elements/PcBrushConfig/index.js +463 -0
- package/dist/ui/elements/PcBrushConfig/style.js +3 -0
- package/dist/ui/elements/PcBrushMenu/index.d.ts +121 -0
- package/dist/ui/elements/PcBrushMenu/index.js +362 -0
- package/dist/ui/elements/PcBrushMenu/style.js +3 -0
- package/dist/ui/elements/PcBrushTest/index.d.ts +71 -0
- package/dist/ui/elements/PcBrushTest/index.js +136 -0
- package/dist/ui/elements/PcBrushTest/style.js +3 -0
- package/dist/ui/elements/PcButton/index.d.ts +57 -0
- package/dist/ui/elements/PcButton/index.js +124 -0
- package/dist/ui/elements/PcButtonGroup/index.d.ts +44 -0
- package/dist/ui/elements/PcButtonGroup/index.js +93 -0
- package/dist/ui/elements/PcCanvas/index.d.ts +356 -0
- package/dist/ui/elements/PcCanvas/index.js +1004 -0
- package/dist/ui/elements/PcCanvas/style.js +3 -0
- package/dist/ui/elements/PcCanvasMap/index.d.ts +96 -0
- package/dist/ui/elements/PcCanvasMap/index.js +187 -0
- package/dist/ui/elements/PcCanvasMap/style.js +3 -0
- package/dist/ui/elements/PcContextMenu/index.d.ts +72 -0
- package/dist/ui/elements/PcContextMenu/index.js +148 -0
- package/dist/ui/elements/PcDialog/index.d.ts +63 -0
- package/dist/ui/elements/PcDialog/index.js +114 -0
- package/dist/ui/elements/PcIcon/index.d.ts +36 -0
- package/dist/ui/elements/PcIcon/index.js +43 -0
- package/dist/ui/elements/PcIconToggle/index.d.ts +46 -0
- package/dist/ui/elements/PcIconToggle/index.js +87 -0
- package/dist/ui/elements/PcInfoTip/index.d.ts +40 -0
- package/dist/ui/elements/PcInfoTip/index.js +95 -0
- package/dist/ui/elements/PcInputSettings/index.d.ts +69 -0
- package/dist/ui/elements/PcInputSettings/index.js +150 -0
- package/dist/ui/elements/PcLayerItem/index.d.ts +221 -0
- package/dist/ui/elements/PcLayerItem/index.js +561 -0
- package/dist/ui/elements/PcLayerItem/style.js +3 -0
- package/dist/ui/elements/PcLayersMenu/index.d.ts +108 -0
- package/dist/ui/elements/PcLayersMenu/index.js +208 -0
- package/dist/ui/elements/PcLayersMenu/style.js +3 -0
- package/dist/ui/elements/PcMatch/index.d.ts +31 -0
- package/dist/ui/elements/PcMatch/index.js +58 -0
- package/dist/ui/elements/PcPanel/index.d.ts +43 -0
- package/dist/ui/elements/PcPanel/index.js +51 -0
- package/dist/ui/elements/PcPopover/index.d.ts +48 -0
- package/dist/ui/elements/PcPopover/index.js +86 -0
- package/dist/ui/elements/PcSlider/index.d.ts +57 -0
- package/dist/ui/elements/PcSlider/index.js +88 -0
- package/dist/ui/elements/PcStats/index.d.ts +54 -0
- package/dist/ui/elements/PcStats/index.js +141 -0
- package/dist/ui/elements/PcThemePicker/index.d.ts +56 -0
- package/dist/ui/elements/PcThemePicker/index.js +134 -0
- package/dist/ui/elements/PcToast/index.d.ts +58 -0
- package/dist/ui/elements/PcToast/index.js +110 -0
- package/dist/ui/elements/PcToggleCheckbox/index.d.ts +37 -0
- package/dist/ui/elements/PcToggleCheckbox/index.js +105 -0
- package/dist/ui/elements/PcToolSettings/index.d.ts +128 -0
- package/dist/ui/elements/PcToolSettings/index.js +543 -0
- package/dist/ui/elements/PcToolSettings/style.js +3 -0
- package/dist/ui/elements/PcToolbar/index.d.ts +71 -0
- package/dist/ui/elements/PcToolbar/index.js +190 -0
- package/dist/ui/elements/PcToolbar/style.js +3 -0
- package/dist/ui/icons/images/brush.js +3 -0
- package/dist/ui/icons/images/circle-mask.js +3 -0
- package/dist/ui/icons/images/clipboard.js +3 -0
- package/dist/ui/icons/images/cursor.js +3 -0
- package/dist/ui/icons/images/eraser.js +3 -0
- package/dist/ui/icons/images/eyedropper.js +3 -0
- package/dist/ui/icons/images/flip-horizontal.js +3 -0
- package/dist/ui/icons/images/flip-vertical.js +3 -0
- package/dist/ui/icons/images/focus-pen.js +3 -0
- package/dist/ui/icons/images/freehand-mask.js +3 -0
- package/dist/ui/icons/images/hidden.js +3 -0
- package/dist/ui/icons/images/layers.js +3 -0
- package/dist/ui/icons/images/linked.js +3 -0
- package/dist/ui/icons/images/locked.js +3 -0
- package/dist/ui/icons/images/moon.js +3 -0
- package/dist/ui/icons/images/pan.js +3 -0
- package/dist/ui/icons/images/polygon-mask.js +3 -0
- package/dist/ui/icons/images/pressure.js +3 -0
- package/dist/ui/icons/images/randomise.js +3 -0
- package/dist/ui/icons/images/rectangle-mask.js +3 -0
- package/dist/ui/icons/images/redo.js +3 -0
- package/dist/ui/icons/images/rotate-90-left.js +3 -0
- package/dist/ui/icons/images/rotate-90-right.js +3 -0
- package/dist/ui/icons/images/smoothing-bezier-cubic.js +3 -0
- package/dist/ui/icons/images/smoothing-bezier-quad.js +3 -0
- package/dist/ui/icons/images/smoothing-linear.js +3 -0
- package/dist/ui/icons/images/star.js +3 -0
- package/dist/ui/icons/images/sun.js +3 -0
- package/dist/ui/icons/images/tilt.js +3 -0
- package/dist/ui/icons/images/undo.js +3 -0
- package/dist/ui/icons/images/unlinked.js +3 -0
- package/dist/ui/icons/images/unlocked.js +3 -0
- package/dist/ui/icons/images/visible.js +3 -0
- package/dist/ui/icons/images/zoom-in.js +3 -0
- package/dist/ui/icons/images/zoom-out.js +3 -0
- package/dist/ui/icons/images/zoom.js +3 -0
- package/dist/ui/icons/index.d.ts +42 -0
- package/dist/ui/icons/index.js +130 -0
- package/dist/ui/index.d.ts +21 -0
- package/dist/ui/index.js +22 -0
- package/dist/ui/layout/index.d.ts +88 -0
- package/dist/ui/layout/index.js +96 -0
- package/dist/ui/styles/index.d.ts +13 -0
- package/dist/ui/styles/index.js +195 -0
- package/dist/ui/tokens/index.d.ts +29 -0
- package/dist/ui/tokens/index.js +114 -0
- package/locales/en-GB.json +186 -0
- package/locales/en-US.json +186 -0
- package/locales/fr.json +186 -0
- package/locales/ja.json +186 -0
- package/locales/ko.json +186 -0
- package/locales/zh-Hans.json +186 -0
- package/locales/zh-Hant.json +186 -0
- package/package.json +97 -3
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { nothing } from "lit";
|
|
2
|
+
import { PcElement } from "../../base";
|
|
3
|
+
import "../PcBrushTest";
|
|
4
|
+
import type PaintCanvas from "../../../lib/classes/PaintCanvas";
|
|
5
|
+
import { SmoothingType, type BrushConfig } from "../../../lib/brushes/types";
|
|
6
|
+
import { type ShapeImage } from "../../../lib/brushes/shapeImage";
|
|
7
|
+
/** Asks the user to confirm; replaceable for tests */
|
|
8
|
+
export type ConfirmFn = (message: string) => boolean;
|
|
9
|
+
/** Asks the user for text; replaceable for tests */
|
|
10
|
+
export type PromptFn = (message: string, value: string) => string | null;
|
|
11
|
+
/** The smoothing choices, in the order shown: value, translation key of the name, and icon name */
|
|
12
|
+
export declare const SMOOTHING_CHOICES: readonly [{
|
|
13
|
+
readonly value: SmoothingType.Linear;
|
|
14
|
+
readonly label: "brushConfig.smoothingLinear";
|
|
15
|
+
readonly icon: "smoothingLinear";
|
|
16
|
+
}, {
|
|
17
|
+
readonly value: SmoothingType.BezierQuad;
|
|
18
|
+
readonly label: "brushConfig.smoothingQuadratic";
|
|
19
|
+
readonly icon: "smoothingBezierQuad";
|
|
20
|
+
}, {
|
|
21
|
+
readonly value: SmoothingType.BezierCubic;
|
|
22
|
+
readonly label: "brushConfig.smoothingCubic";
|
|
23
|
+
readonly icon: "smoothingBezierCubic";
|
|
24
|
+
}];
|
|
25
|
+
/**
|
|
26
|
+
* The brush (or eraser) configuration window: a testing area, the shape (upload or paste), smoothing, width, height,
|
|
27
|
+
* opacity, rotation, offsets, sample rate, spacing and snapping to the pixel grid. Width, height, opacity, rotation and the offsets can vary with
|
|
28
|
+
* pressure, tilt and randomness; when any is on, the setting has a min and max.
|
|
29
|
+
*
|
|
30
|
+
* Changes stay in the window until "Save" (fires `pc-save` with the settings, to apply to the current tool) or "Add to
|
|
31
|
+
* presets" (saves them as one of the user's presets, asking before replacing one with the same name, and selects it).
|
|
32
|
+
* "Delete preset…" shows when editing one of the user's presets. Fires `pc-close` when closed, and `pc-toast` with a
|
|
33
|
+
* message after adding or deleting a preset, or when a shape can't be used. Styling is structural only.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* html`<pc-brush-config .app=${app} kind="brush" .config=${app.brush.preset} @pc-save=${apply}></pc-brush-config>`
|
|
37
|
+
*/
|
|
38
|
+
export declare class PcBrushConfig extends PcElement {
|
|
39
|
+
static properties: {
|
|
40
|
+
app: {
|
|
41
|
+
attribute: boolean;
|
|
42
|
+
};
|
|
43
|
+
kind: {
|
|
44
|
+
type: StringConstructor;
|
|
45
|
+
};
|
|
46
|
+
config: {
|
|
47
|
+
attribute: boolean;
|
|
48
|
+
};
|
|
49
|
+
editingId: {
|
|
50
|
+
type: StringConstructor;
|
|
51
|
+
};
|
|
52
|
+
draft: {
|
|
53
|
+
state: boolean;
|
|
54
|
+
};
|
|
55
|
+
busy: {
|
|
56
|
+
state: boolean;
|
|
57
|
+
};
|
|
58
|
+
translations: {
|
|
59
|
+
attribute: boolean;
|
|
60
|
+
};
|
|
61
|
+
icons: {
|
|
62
|
+
attribute: boolean;
|
|
63
|
+
};
|
|
64
|
+
theme: {
|
|
65
|
+
type: StringConstructor;
|
|
66
|
+
reflect: boolean;
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
static styles: import("lit").CSSResultGroup[];
|
|
70
|
+
app?: PaintCanvas;
|
|
71
|
+
/** Which tool's settings are configured */
|
|
72
|
+
kind: "brush" | "eraser";
|
|
73
|
+
/** The settings to start from */
|
|
74
|
+
config?: BrushConfig;
|
|
75
|
+
/** The ID of the user's own preset being edited, if any (shows "Delete preset…") */
|
|
76
|
+
editingId?: string;
|
|
77
|
+
/** The settings as changed in the window */
|
|
78
|
+
draft?: BrushConfig;
|
|
79
|
+
/** Whether a preset is being saved or deleted */
|
|
80
|
+
busy: boolean;
|
|
81
|
+
confirm: ConfirmFn;
|
|
82
|
+
prompt: PromptFn;
|
|
83
|
+
/** Turns files into brush shapes (replaceable for tests) */
|
|
84
|
+
readShape: (file: File) => Promise<ShapeImage>;
|
|
85
|
+
/** Reads a brush shape from the clipboard (replaceable for tests) */
|
|
86
|
+
readClipboard: () => Promise<ShapeImage>;
|
|
87
|
+
private readonly onKeyDown;
|
|
88
|
+
constructor();
|
|
89
|
+
connectedCallback(): void;
|
|
90
|
+
disconnectedCallback(): void;
|
|
91
|
+
protected willUpdate(changed: Map<PropertyKey, unknown>): void;
|
|
92
|
+
/** Fire an event that crosses shadow DOM boundaries */
|
|
93
|
+
private emit;
|
|
94
|
+
/** Change the draft settings (only shown, and so only changed, once there is a draft) */
|
|
95
|
+
private change;
|
|
96
|
+
/**
|
|
97
|
+
* Change the width; with constrained proportions, the height and its variation follow.
|
|
98
|
+
*/
|
|
99
|
+
private changeWidth;
|
|
100
|
+
/** Apply changes to a setting */
|
|
101
|
+
private changeParam;
|
|
102
|
+
/**
|
|
103
|
+
* Close the window without applying anything.
|
|
104
|
+
*/
|
|
105
|
+
close(): void;
|
|
106
|
+
/**
|
|
107
|
+
* Apply the settings to the current tool.
|
|
108
|
+
*/
|
|
109
|
+
save(): void;
|
|
110
|
+
/** Use a shape, showing why if it can't be used */
|
|
111
|
+
private useShape;
|
|
112
|
+
/**
|
|
113
|
+
* Save the settings as one of the user's presets, asking for its name, and before replacing one of theirs with the
|
|
114
|
+
* same name. The new preset is selected.
|
|
115
|
+
*/
|
|
116
|
+
addToPresets(): Promise<void>;
|
|
117
|
+
/**
|
|
118
|
+
* Delete the preset being edited, after confirming.
|
|
119
|
+
*/
|
|
120
|
+
deletePreset(): Promise<void>;
|
|
121
|
+
/** Render a number input */
|
|
122
|
+
private number;
|
|
123
|
+
/** Render a range slider */
|
|
124
|
+
private slider;
|
|
125
|
+
/** Render a setting that can vary: its value (or min and max), and its pressure, tilt and randomise icon toggles */
|
|
126
|
+
private renderParam;
|
|
127
|
+
/** Render the shape and smoothing row */
|
|
128
|
+
private renderShape;
|
|
129
|
+
render(): import("lit").TemplateResult<1> | typeof nothing;
|
|
130
|
+
}
|
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
import style_default from "./style.js";
|
|
2
|
+
import { ICON_CONTROLS_CSS, PILLS_CSS, WINDOWS_CSS } from "../../styles/index.js";
|
|
3
|
+
import { iconLabel } from "../../icons/index.js";
|
|
4
|
+
import { PcElement, defineElement } from "../../base/index.js";
|
|
5
|
+
import { SmoothingType } from "../../../lib/brushes/types/index.js";
|
|
6
|
+
import { PARAM_LIMITS, VARIATION_SOURCES, readRange, toggleSource, writeRange } from "../../../lib/brushes/configRanges/index.js";
|
|
7
|
+
import { SHAPE_ERRORS, ShapeImageError, readClipboardShape, readShapeImage } from "../../../lib/brushes/shapeImage/index.js";
|
|
8
|
+
import "../../../lib/brushes/StrokeSampler/index.js";
|
|
9
|
+
import { html, nothing, unsafeCSS } from "lit";
|
|
10
|
+
import { styleMap } from "lit/directives/style-map.js";
|
|
11
|
+
// src/ui/elements/PcBrushConfig/index.ts
|
|
12
|
+
/** The smoothing choices, in the order shown: value, translation key of the name, and icon name */
|
|
13
|
+
var SMOOTHING_CHOICES = [
|
|
14
|
+
{
|
|
15
|
+
value: SmoothingType.Linear,
|
|
16
|
+
label: "brushConfig.smoothingLinear",
|
|
17
|
+
icon: "smoothingLinear"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
value: SmoothingType.BezierQuad,
|
|
21
|
+
label: "brushConfig.smoothingQuadratic",
|
|
22
|
+
icon: "smoothingBezierQuad"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
value: SmoothingType.BezierCubic,
|
|
26
|
+
label: "brushConfig.smoothingCubic",
|
|
27
|
+
icon: "smoothingBezierCubic"
|
|
28
|
+
}
|
|
29
|
+
];
|
|
30
|
+
/** Icon names of the variation sources */
|
|
31
|
+
var SOURCE_ICONS = {
|
|
32
|
+
pressure: "pressure",
|
|
33
|
+
tilt: "tilt",
|
|
34
|
+
randomise: "randomise"
|
|
35
|
+
};
|
|
36
|
+
/** Translation keys of the variation sources' names */
|
|
37
|
+
var SOURCE_LABELS = {
|
|
38
|
+
pressure: "toolSettings.pressure",
|
|
39
|
+
tilt: "toolSettings.tilt",
|
|
40
|
+
randomise: "brushConfig.randomise"
|
|
41
|
+
};
|
|
42
|
+
/** Translation keys of the brush shape error messages */
|
|
43
|
+
var SHAPE_ERROR_KEYS = {
|
|
44
|
+
[SHAPE_ERRORS.type]: "shape.notPng",
|
|
45
|
+
[SHAPE_ERRORS.size]: "shape.tooLarge",
|
|
46
|
+
[SHAPE_ERRORS.decode]: "shape.readFailed",
|
|
47
|
+
[SHAPE_ERRORS.noImage]: "shape.noPngToPaste"
|
|
48
|
+
};
|
|
49
|
+
/** Largest stamp spacing in pixels */
|
|
50
|
+
var MAX_SPACING = 200;
|
|
51
|
+
/** Read a number input, or undefined if it isn't a number */
|
|
52
|
+
var numberValue = (event) => {
|
|
53
|
+
const value = event.target.valueAsNumber;
|
|
54
|
+
return Number.isFinite(value) ? value : void 0;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* The brush (or eraser) configuration window: a testing area, the shape (upload or paste), smoothing, width, height,
|
|
58
|
+
* opacity, rotation, offsets, sample rate, spacing and snapping to the pixel grid. Width, height, opacity, rotation and the offsets can vary with
|
|
59
|
+
* pressure, tilt and randomness; when any is on, the setting has a min and max.
|
|
60
|
+
*
|
|
61
|
+
* Changes stay in the window until "Save" (fires `pc-save` with the settings, to apply to the current tool) or "Add to
|
|
62
|
+
* presets" (saves them as one of the user's presets, asking before replacing one with the same name, and selects it).
|
|
63
|
+
* "Delete preset…" shows when editing one of the user's presets. Fires `pc-close` when closed, and `pc-toast` with a
|
|
64
|
+
* message after adding or deleting a preset, or when a shape can't be used. Styling is structural only.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* html`<pc-brush-config .app=${app} kind="brush" .config=${app.brush.preset} @pc-save=${apply}></pc-brush-config>`
|
|
68
|
+
*/
|
|
69
|
+
var PcBrushConfig = class extends PcElement {
|
|
70
|
+
static properties = {
|
|
71
|
+
...PcElement.properties,
|
|
72
|
+
app: { attribute: false },
|
|
73
|
+
kind: { type: String },
|
|
74
|
+
config: { attribute: false },
|
|
75
|
+
editingId: { type: String },
|
|
76
|
+
draft: { state: true },
|
|
77
|
+
busy: { state: true }
|
|
78
|
+
};
|
|
79
|
+
static styles = [
|
|
80
|
+
PcElement.styles,
|
|
81
|
+
unsafeCSS(style_default),
|
|
82
|
+
unsafeCSS(WINDOWS_CSS),
|
|
83
|
+
unsafeCSS(ICON_CONTROLS_CSS),
|
|
84
|
+
unsafeCSS(PILLS_CSS)
|
|
85
|
+
];
|
|
86
|
+
confirm = (message) => window.confirm(message);
|
|
87
|
+
prompt = (message, value) => window.prompt(message, value);
|
|
88
|
+
/** Turns files into brush shapes (replaceable for tests) */
|
|
89
|
+
readShape = readShapeImage;
|
|
90
|
+
/** Reads a brush shape from the clipboard (replaceable for tests) */
|
|
91
|
+
readClipboard = () => readClipboardShape();
|
|
92
|
+
onKeyDown = (event) => {
|
|
93
|
+
if (event.key === "Escape") this.close();
|
|
94
|
+
};
|
|
95
|
+
constructor() {
|
|
96
|
+
super();
|
|
97
|
+
this.kind = "brush";
|
|
98
|
+
this.busy = false;
|
|
99
|
+
}
|
|
100
|
+
connectedCallback() {
|
|
101
|
+
super.connectedCallback();
|
|
102
|
+
window.addEventListener("keydown", this.onKeyDown);
|
|
103
|
+
}
|
|
104
|
+
disconnectedCallback() {
|
|
105
|
+
super.disconnectedCallback();
|
|
106
|
+
window.removeEventListener("keydown", this.onKeyDown);
|
|
107
|
+
}
|
|
108
|
+
willUpdate(changed) {
|
|
109
|
+
super.willUpdate(changed);
|
|
110
|
+
if (changed.has("config") && this.config) this.draft = structuredClone(this.config);
|
|
111
|
+
}
|
|
112
|
+
/** Fire an event that crosses shadow DOM boundaries */
|
|
113
|
+
emit(type, detail) {
|
|
114
|
+
this.dispatchEvent(new CustomEvent(type, {
|
|
115
|
+
detail,
|
|
116
|
+
bubbles: true,
|
|
117
|
+
composed: true
|
|
118
|
+
}));
|
|
119
|
+
}
|
|
120
|
+
/** Change the draft settings (only shown, and so only changed, once there is a draft) */
|
|
121
|
+
change(changes) {
|
|
122
|
+
this.draft = {
|
|
123
|
+
...this.draft,
|
|
124
|
+
...changes
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Change the width; with constrained proportions, the height and its variation follow.
|
|
129
|
+
*/
|
|
130
|
+
changeWidth(changes) {
|
|
131
|
+
const draft = this.draft;
|
|
132
|
+
if (!draft.constrainProportions) {
|
|
133
|
+
this.change(changes);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const ratio = (draft.height ?? draft.width ?? 1) / (draft.width ?? 1);
|
|
137
|
+
const width = changes.width ?? draft.width ?? 1;
|
|
138
|
+
this.change({
|
|
139
|
+
...changes,
|
|
140
|
+
height: Math.max(1, Math.round(width * ratio)),
|
|
141
|
+
heightConfig: changes.widthConfig ?? draft.widthConfig
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
/** Apply changes to a setting */
|
|
145
|
+
changeParam(param, changes) {
|
|
146
|
+
if (param === "width") this.changeWidth(changes);
|
|
147
|
+
else this.change(changes);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Close the window without applying anything.
|
|
151
|
+
*/
|
|
152
|
+
close() {
|
|
153
|
+
this.emit("pc-close");
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Apply the settings to the current tool.
|
|
157
|
+
*/
|
|
158
|
+
save() {
|
|
159
|
+
if (this.draft) this.emit("pc-save", this.draft);
|
|
160
|
+
}
|
|
161
|
+
/** Use a shape, showing why if it can't be used */
|
|
162
|
+
async useShape(read) {
|
|
163
|
+
try {
|
|
164
|
+
const shape = await read();
|
|
165
|
+
const width = this.draft?.width ?? shape.width;
|
|
166
|
+
this.change({
|
|
167
|
+
image: shape.image,
|
|
168
|
+
height: Math.max(1, Math.round(width * shape.height / shape.width))
|
|
169
|
+
});
|
|
170
|
+
} catch (error) {
|
|
171
|
+
this.emit("pc-toast", {
|
|
172
|
+
message: this.t(error instanceof ShapeImageError && SHAPE_ERROR_KEYS[error.message] || "brushConfig.shapeFailed"),
|
|
173
|
+
kind: "error"
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Save the settings as one of the user's presets, asking for its name, and before replacing one of theirs with the
|
|
179
|
+
* same name. The new preset is selected.
|
|
180
|
+
*/
|
|
181
|
+
async addToPresets() {
|
|
182
|
+
const app = this.app;
|
|
183
|
+
const draft = this.draft;
|
|
184
|
+
if (!app || !draft) return;
|
|
185
|
+
const name = this.prompt(this.t("brushConfig.presetName"), draft.name ?? "")?.trim();
|
|
186
|
+
if (!name) return;
|
|
187
|
+
const existing = app.customPresets.findOwn(name, app.authorHandle, app.names.unknownAuthor);
|
|
188
|
+
if (existing && !this.confirm(this.t("presets.replaceConfirm", { name }))) return;
|
|
189
|
+
const preset = {
|
|
190
|
+
...app.newPreset(draft, name),
|
|
191
|
+
...existing ? { id: existing.id } : {}
|
|
192
|
+
};
|
|
193
|
+
this.busy = true;
|
|
194
|
+
try {
|
|
195
|
+
await app.customPresets.save(preset);
|
|
196
|
+
(this.kind === "eraser" ? app.eraser : app.brush).select(preset.id);
|
|
197
|
+
this.emit("pc-toast", {
|
|
198
|
+
message: this.t("presets.saved", { name }),
|
|
199
|
+
kind: "success"
|
|
200
|
+
});
|
|
201
|
+
this.close();
|
|
202
|
+
} catch {
|
|
203
|
+
this.emit("pc-toast", {
|
|
204
|
+
message: this.t("presets.saveFailed", { name }),
|
|
205
|
+
kind: "error"
|
|
206
|
+
});
|
|
207
|
+
} finally {
|
|
208
|
+
this.busy = false;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Delete the preset being edited, after confirming.
|
|
213
|
+
*/
|
|
214
|
+
async deletePreset() {
|
|
215
|
+
const app = this.app;
|
|
216
|
+
const id = this.editingId;
|
|
217
|
+
if (!app || !id) return;
|
|
218
|
+
const name = app.customPresets.get(id)?.name ?? "this preset";
|
|
219
|
+
if (!this.confirm(this.t("presets.deleteConfirm", { name }))) return;
|
|
220
|
+
this.busy = true;
|
|
221
|
+
try {
|
|
222
|
+
await app.customPresets.remove(id);
|
|
223
|
+
this.emit("pc-toast", {
|
|
224
|
+
message: this.t("presets.deleted", { name }),
|
|
225
|
+
kind: "success"
|
|
226
|
+
});
|
|
227
|
+
this.close();
|
|
228
|
+
} catch {
|
|
229
|
+
this.emit("pc-toast", {
|
|
230
|
+
message: this.t("presets.deleteFailed", { name }),
|
|
231
|
+
kind: "error"
|
|
232
|
+
});
|
|
233
|
+
} finally {
|
|
234
|
+
this.busy = false;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/** Render a number input */
|
|
238
|
+
number(className, value, limits, onChange, disabled = false) {
|
|
239
|
+
return html`<input
|
|
240
|
+
type="number"
|
|
241
|
+
class=${className}
|
|
242
|
+
min=${limits.min}
|
|
243
|
+
max=${limits.max}
|
|
244
|
+
?disabled=${disabled || this.busy}
|
|
245
|
+
.value=${String(Math.round(value))}
|
|
246
|
+
@change=${(e) => {
|
|
247
|
+
const next = numberValue(e);
|
|
248
|
+
if (next !== void 0) onChange(next);
|
|
249
|
+
}}
|
|
250
|
+
/>`;
|
|
251
|
+
}
|
|
252
|
+
/** Render a range slider */
|
|
253
|
+
slider(className, value, limits, onChange, disabled = false) {
|
|
254
|
+
return html`<input
|
|
255
|
+
type="range"
|
|
256
|
+
class=${className}
|
|
257
|
+
min=${limits.min}
|
|
258
|
+
max=${limits.max}
|
|
259
|
+
?disabled=${disabled || this.busy}
|
|
260
|
+
.value=${String(value)}
|
|
261
|
+
@input=${(e) => onChange(e.target.valueAsNumber)}
|
|
262
|
+
/>`;
|
|
263
|
+
}
|
|
264
|
+
/** Render a setting that can vary: its value (or min and max), and its pressure, tilt and randomise icon toggles */
|
|
265
|
+
renderParam(draft, param, label, disabled = false) {
|
|
266
|
+
const range = readRange(draft, param);
|
|
267
|
+
const limits = PARAM_LIMITS[param];
|
|
268
|
+
const isOffset = param === "offsetX" || param === "offsetY";
|
|
269
|
+
const write = (values) => this.changeParam(param, writeRange(draft, param, values));
|
|
270
|
+
const values = range.varies ? html`${this.number(`${param} min`, range.min, limits, (min) => write({ min }), disabled)}
|
|
271
|
+
${this.slider(`${param} min`, range.min, limits, (min) => write({ min }), disabled)}
|
|
272
|
+
${this.slider(`${param} max`, range.max, limits, (max) => write({ max }), disabled)}
|
|
273
|
+
${this.number(`${param} max`, range.max, limits, (max) => write({ max }), disabled)}` : html`${this.number(param, range.value, limits, (value) => write({ value }), disabled || isOffset)}
|
|
274
|
+
${this.slider(param, range.value, limits, (value) => write({ value }), disabled || isOffset)}`;
|
|
275
|
+
return html`<div class="row" data-param=${param}>
|
|
276
|
+
<span class="label">${label}</span>
|
|
277
|
+
${values}
|
|
278
|
+
${VARIATION_SOURCES.map((source) => html`<label
|
|
279
|
+
class="icon-toggle"
|
|
280
|
+
title=${this.t(SOURCE_LABELS[source])}
|
|
281
|
+
>
|
|
282
|
+
<input
|
|
283
|
+
type="checkbox"
|
|
284
|
+
class=${`${param} ${source}`}
|
|
285
|
+
aria-label=${this.t("brushConfig.variation", {
|
|
286
|
+
param: label,
|
|
287
|
+
source: this.t(SOURCE_LABELS[source])
|
|
288
|
+
})}
|
|
289
|
+
.checked=${range.sources[source]}
|
|
290
|
+
?disabled=${disabled || this.busy}
|
|
291
|
+
@change=${(e) => this.changeParam(param, toggleSource(draft, param, source, e.target.checked))}
|
|
292
|
+
/>
|
|
293
|
+
${iconLabel(this.iconUrl(SOURCE_ICONS[source]), this.t(SOURCE_LABELS[source]))}
|
|
294
|
+
</label>`)}
|
|
295
|
+
</div>`;
|
|
296
|
+
}
|
|
297
|
+
/** Render the shape and smoothing row */
|
|
298
|
+
renderShape(draft) {
|
|
299
|
+
const smoothing = draft.smoothingType === SmoothingType.None || draft.smoothingType === void 0 ? SmoothingType.Linear : draft.smoothingType;
|
|
300
|
+
return html`<div class="row shape-row">
|
|
301
|
+
<span class="label">${this.t("brushConfig.shape")}</span>
|
|
302
|
+
<span
|
|
303
|
+
class=${draft.image ? "shape-preview image" : "shape-preview"}
|
|
304
|
+
style=${styleMap({ maskImage: typeof draft.image === "string" ? `url("${draft.image}")` : void 0 })}
|
|
305
|
+
></span>
|
|
306
|
+
<button
|
|
307
|
+
type="button"
|
|
308
|
+
class="pill upload"
|
|
309
|
+
?disabled=${this.busy}
|
|
310
|
+
@click=${() => this.renderRoot.querySelector("input.shape")?.click()}
|
|
311
|
+
>
|
|
312
|
+
${this.t("brushConfig.upload")}
|
|
313
|
+
</button>
|
|
314
|
+
<!-- Chosen through "Upload" -->
|
|
315
|
+
<label class="visually-hidden">
|
|
316
|
+
Upload a shape (PNG)
|
|
317
|
+
<input
|
|
318
|
+
type="file"
|
|
319
|
+
class="shape"
|
|
320
|
+
tabindex="-1"
|
|
321
|
+
accept="image/png"
|
|
322
|
+
?disabled=${this.busy}
|
|
323
|
+
@change=${(e) => {
|
|
324
|
+
const input = e.target;
|
|
325
|
+
const file = input.files?.[0];
|
|
326
|
+
input.value = "";
|
|
327
|
+
if (file) this.useShape(() => this.readShape(file));
|
|
328
|
+
}}
|
|
329
|
+
/>
|
|
330
|
+
</label>
|
|
331
|
+
<button
|
|
332
|
+
type="button"
|
|
333
|
+
class="icon-button paste"
|
|
334
|
+
title=${this.t("brushConfig.paste")}
|
|
335
|
+
?disabled=${this.busy}
|
|
336
|
+
@click=${() => void this.useShape(this.readClipboard)}
|
|
337
|
+
>
|
|
338
|
+
${iconLabel(this.iconUrl("clipboard"), this.t("brushConfig.paste"))}
|
|
339
|
+
</button>
|
|
340
|
+
<fieldset class="smoothing">
|
|
341
|
+
<legend>${this.t("brushConfig.smoothing")}</legend>
|
|
342
|
+
${SMOOTHING_CHOICES.map((choice) => html`<label class="icon-toggle" title=${this.t(choice.label)}>
|
|
343
|
+
<input
|
|
344
|
+
type="radio"
|
|
345
|
+
name="smoothing"
|
|
346
|
+
.value=${String(choice.value)}
|
|
347
|
+
.checked=${smoothing === choice.value}
|
|
348
|
+
?disabled=${this.busy}
|
|
349
|
+
@change=${() => this.change({ smoothingType: choice.value })}
|
|
350
|
+
/>
|
|
351
|
+
${iconLabel(this.iconUrl(choice.icon), this.t(choice.label))}
|
|
352
|
+
</label>`)}
|
|
353
|
+
</fieldset>
|
|
354
|
+
</div>`;
|
|
355
|
+
}
|
|
356
|
+
render() {
|
|
357
|
+
const draft = this.draft;
|
|
358
|
+
if (!draft) return nothing;
|
|
359
|
+
const constrained = draft.constrainProportions ?? false;
|
|
360
|
+
const sampleLimits = {
|
|
361
|
+
min: 5,
|
|
362
|
+
max: 400
|
|
363
|
+
};
|
|
364
|
+
const spacingLimits = {
|
|
365
|
+
min: 0,
|
|
366
|
+
max: MAX_SPACING
|
|
367
|
+
};
|
|
368
|
+
return html`<div
|
|
369
|
+
role="dialog"
|
|
370
|
+
aria-modal="true"
|
|
371
|
+
aria-label=${this.t(this.kind === "eraser" ? "brushConfig.eraserTitle" : "brushConfig.brushTitle")}
|
|
372
|
+
>
|
|
373
|
+
<div class="row header">
|
|
374
|
+
<label>
|
|
375
|
+
${this.t("brushConfig.name")}
|
|
376
|
+
<input
|
|
377
|
+
class="name"
|
|
378
|
+
.value=${draft.name ?? ""}
|
|
379
|
+
?disabled=${this.busy}
|
|
380
|
+
@input=${(e) => this.change({ name: e.target.value })}
|
|
381
|
+
/>
|
|
382
|
+
</label>
|
|
383
|
+
<button
|
|
384
|
+
type="button"
|
|
385
|
+
class="close dismiss"
|
|
386
|
+
@click=${() => this.close()}
|
|
387
|
+
>
|
|
388
|
+
${this.t("common.dismiss")}
|
|
389
|
+
</button>
|
|
390
|
+
</div>
|
|
391
|
+
<pc-brush-test .config=${draft} .tips=${this.app?.tips}></pc-brush-test>
|
|
392
|
+
${this.renderShape(draft)}
|
|
393
|
+
${this.renderParam(draft, "width", this.t("common.width"))}
|
|
394
|
+
<div class="row">
|
|
395
|
+
<span class="label"></span>
|
|
396
|
+
<label
|
|
397
|
+
class="icon-toggle"
|
|
398
|
+
title=${this.t("toolSettings.constrainProportions")}
|
|
399
|
+
>
|
|
400
|
+
<input
|
|
401
|
+
type="checkbox"
|
|
402
|
+
class="constrain"
|
|
403
|
+
.checked=${constrained}
|
|
404
|
+
?disabled=${this.busy}
|
|
405
|
+
@change=${(e) => this.change({ constrainProportions: e.target.checked })}
|
|
406
|
+
/>
|
|
407
|
+
${iconLabel(this.iconUrl(constrained ? "linked" : "unlinked"), this.t("toolSettings.constrainProportions"))}
|
|
408
|
+
</label>
|
|
409
|
+
</div>
|
|
410
|
+
${this.renderParam(draft, "height", this.t("common.height"), constrained)}
|
|
411
|
+
${this.renderParam(draft, "alpha", this.t("common.opacity"))}
|
|
412
|
+
${this.renderParam(draft, "rotation", this.t("brushConfig.rotation"))}
|
|
413
|
+
${this.renderParam(draft, "offsetX", this.t("brushConfig.offsetX"))}
|
|
414
|
+
${this.renderParam(draft, "offsetY", this.t("brushConfig.offsetY"))}
|
|
415
|
+
<div class="row">
|
|
416
|
+
<span class="label">${this.t("brushConfig.sampleRate")}</span>
|
|
417
|
+
${this.number("sample-rate", draft.sampleRate ?? 5, sampleLimits, (sampleRate) => this.change({ sampleRate }))}
|
|
418
|
+
${this.slider("sample-rate", draft.sampleRate ?? 5, sampleLimits, (sampleRate) => this.change({ sampleRate }))}
|
|
419
|
+
<span class="label">${this.t("brushConfig.spacing")}</span>
|
|
420
|
+
${this.number("spacing", draft.spacing ?? 5, spacingLimits, (spacing) => this.change({ spacing }))}
|
|
421
|
+
${this.slider("spacing", draft.spacing ?? 5, spacingLimits, (spacing) => this.change({ spacing }))}
|
|
422
|
+
</div>
|
|
423
|
+
<label>
|
|
424
|
+
<input
|
|
425
|
+
type="checkbox"
|
|
426
|
+
class="snap"
|
|
427
|
+
.checked=${draft.snapToPixelGrid ?? false}
|
|
428
|
+
?disabled=${this.busy}
|
|
429
|
+
@change=${(e) => this.change({ snapToPixelGrid: e.target.checked })}
|
|
430
|
+
/>
|
|
431
|
+
${this.t("brushConfig.snapToPixelGrid")}
|
|
432
|
+
</label>
|
|
433
|
+
<div class="row">
|
|
434
|
+
${this.editingId ? html`<button
|
|
435
|
+
type="button"
|
|
436
|
+
class="delete"
|
|
437
|
+
?disabled=${this.busy}
|
|
438
|
+
@click=${() => void this.deletePreset()}
|
|
439
|
+
>
|
|
440
|
+
${this.t("brushConfig.deletePreset")}
|
|
441
|
+
</button>` : nothing}
|
|
442
|
+
<button
|
|
443
|
+
type="button"
|
|
444
|
+
class="add affirmative"
|
|
445
|
+
?disabled=${this.busy}
|
|
446
|
+
@click=${() => void this.addToPresets()}
|
|
447
|
+
>
|
|
448
|
+
${this.t("brushConfig.addToPresets")}
|
|
449
|
+
</button>
|
|
450
|
+
<button
|
|
451
|
+
type="button"
|
|
452
|
+
class="save affirmative"
|
|
453
|
+
?disabled=${this.busy}
|
|
454
|
+
@click=${() => this.save()}
|
|
455
|
+
>
|
|
456
|
+
${this.t("common.save")}
|
|
457
|
+
</button>
|
|
458
|
+
</div>
|
|
459
|
+
</div>`;
|
|
460
|
+
}
|
|
461
|
+
};
|
|
462
|
+
defineElement("pc-brush-config", PcBrushConfig);
|
|
463
|
+
export { PcBrushConfig, SMOOTHING_CHOICES };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// src/ui/elements/PcBrushConfig/style.css?inline
|
|
2
|
+
var style_default = ":host {\n position: fixed;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--pc-backdrop);\n}\n[role=\"dialog\"] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n width: min(560px, 95vw);\n max-height: 95vh;\n overflow: auto;\n padding: 8px;\n background: var(--pc-surface);\n}\n.row {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n}\n.row > .label {\n width: 6em;\n}\ninput[type=\"number\"] {\n width: 4.5em;\n}\ninput[type=\"range\"] {\n flex: 1;\n min-width: 60px;\n}\n.shape-preview {\n display: inline-block;\n width: 40px;\n height: 40px;\n background: var(--pc-text);\n border-radius: 50%;\n}\n.shape-preview.image {\n border-radius: 0;\n mask-repeat: no-repeat;\n mask-size: contain;\n mask-position: center;\n}\n/* The name, with \"Close\" on the right */\n.header .close {\n margin-left: auto;\n}\n/* The shape (preview, Upload and Paste) and the smoothing icons on one row */\n.shape-row {\n flex-wrap: nowrap;\n}\n.shape-row .shape-preview {\n flex: none;\n}\nfieldset.smoothing {\n display: flex;\n align-items: center;\n gap: 4px;\n margin: 0 0 0 auto;\n padding: 0;\n border: 0;\n}\nfieldset.smoothing legend {\n float: left;\n margin-right: 4px;\n padding: 0;\n}\n";
|
|
3
|
+
export { style_default as default };
|