@lvl99dotcom/paintcanvas 0.6.0 → 0.8.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/README.md +3 -2
- package/dist/lib/assets/index.d.ts +92 -0
- package/dist/lib/assets/index.js +106 -0
- package/dist/lib/assets/schema.d.ts +151 -0
- package/dist/lib/assets/schema.js +76 -0
- package/dist/lib/brushes/presetFile/index.d.ts +6 -27
- package/dist/lib/brushes/presetFile/index.js +34 -47
- package/dist/lib/brushes/types/index.d.ts +2 -11
- package/dist/lib/classes/AssetSync/index.d.ts +45 -0
- package/dist/lib/classes/AssetSync/index.js +80 -0
- package/dist/lib/classes/ColourPalettes/index.d.ts +83 -0
- package/dist/lib/classes/ColourPalettes/index.js +165 -0
- package/dist/lib/classes/CustomPresets/index.d.ts +14 -15
- package/dist/lib/classes/CustomPresets/index.js +25 -10
- package/dist/lib/classes/LayerAutosave/index.d.ts +9 -2
- package/dist/lib/classes/LayerAutosave/index.js +16 -6
- package/dist/lib/classes/PaintCanvas/index.d.ts +124 -28
- package/dist/lib/classes/PaintCanvas/index.js +228 -63
- package/dist/lib/classes/Palette/index.d.ts +3 -2
- package/dist/lib/classes/Palette/index.js +3 -2
- package/dist/lib/classes/ProfileGraphs/index.d.ts +13 -2
- package/dist/lib/classes/ProfileGraphs/index.js +22 -2
- package/dist/lib/classes/RemoteDocumentAutosave/index.d.ts +73 -0
- package/dist/lib/classes/RemoteDocumentAutosave/index.js +119 -0
- package/dist/lib/classes/SettingsAutosave/index.d.ts +7 -3
- package/dist/lib/classes/SettingsAutosave/index.js +28 -7
- package/dist/lib/classes/SettingsExtensions/index.d.ts +67 -0
- package/dist/lib/classes/SettingsExtensions/index.js +88 -0
- package/dist/lib/classes/UiSettings/index.d.ts +24 -2
- package/dist/lib/classes/UiSettings/index.js +32 -7
- package/dist/lib/document/index.d.ts +61 -4
- package/dist/lib/document/index.js +173 -4
- package/dist/lib/document/schema.d.ts +154 -39
- package/dist/lib/document/schema.js +91 -25
- package/dist/lib/messages/schema.d.ts +176 -74
- package/dist/lib/messages/schema.js +2 -1
- package/dist/lib/palette/index.d.ts +8 -42
- package/dist/lib/palette/index.js +26 -59
- package/dist/lib/palette/schema.d.ts +111 -22
- package/dist/lib/palette/schema.js +51 -26
- package/dist/lib/presets/index.d.ts +1 -9
- package/dist/lib/presets/index.js +4 -10
- package/dist/lib/presets/schema.d.ts +118 -73
- package/dist/lib/presets/schema.js +28 -60
- package/dist/lib/profiles/profileFile/index.d.ts +10 -0
- package/dist/lib/profiles/profileFile/index.js +19 -0
- package/dist/lib/profiles/schema.d.ts +96 -3
- package/dist/lib/profiles/schema.js +31 -7
- package/dist/lib/schemas/index.d.ts +42 -0
- package/dist/lib/schemas/index.js +60 -0
- package/dist/lib/settings/index.d.ts +37 -22
- package/dist/lib/settings/index.js +78 -37
- package/dist/lib/settings/schema.d.ts +202 -77
- package/dist/lib/settings/schema.js +93 -86
- package/dist/lib/storage/index.d.ts +108 -3
- package/dist/lib/storage/index.js +119 -5
- package/dist/lib/validation/validators.generated.d.ts +19 -8
- package/dist/lib/validation/validators.generated.js +44723 -18889
- package/dist/lib/version/index.d.ts +25 -0
- package/dist/lib/version/index.js +35 -0
- package/dist/locales/en-GB.js +28 -5
- package/dist/locales/en-US.js +28 -5
- package/dist/locales/fr.js +28 -5
- package/dist/locales/ja.js +28 -5
- package/dist/locales/ko.js +28 -5
- package/dist/locales/zh-Hans.js +28 -5
- package/dist/locales/zh-Hant.js +28 -5
- package/dist/package.js +1 -1
- package/dist/testing/app.d.ts +6 -2
- package/dist/testing/app.js +7 -2
- package/dist/testing/documentStore.d.ts +26 -0
- package/dist/testing/documentStore.js +31 -0
- package/dist/ui/elements/PaintCanvas/index.d.ts +19 -5
- package/dist/ui/elements/PaintCanvas/index.js +41 -10
- package/dist/ui/elements/PcAppSettings/index.d.ts +14 -7
- package/dist/ui/elements/PcAppSettings/index.js +58 -33
- package/dist/ui/elements/PcBrushConfig/index.d.ts +1 -0
- package/dist/ui/elements/PcBrushConfig/index.js +8 -9
- package/dist/ui/elements/PcBrushTest/index.d.ts +1 -0
- package/dist/ui/elements/PcBrushTest/index.js +8 -7
- package/dist/ui/elements/PcBrushTest/style.js +1 -1
- package/dist/ui/elements/PcButtonMenu/index.d.ts +88 -0
- package/dist/ui/elements/PcButtonMenu/index.js +125 -0
- package/dist/ui/elements/PcCanvas/index.d.ts +9 -0
- package/dist/ui/elements/PcCanvas/index.js +33 -17
- package/dist/ui/elements/PcClipboardTools/index.d.ts +7 -4
- package/dist/ui/elements/PcClipboardTools/index.js +20 -26
- package/dist/ui/elements/PcInputSettings/index.d.ts +2 -1
- package/dist/ui/elements/PcInputSettings/index.js +9 -15
- package/dist/ui/elements/PcLayerItem/index.d.ts +21 -6
- package/dist/ui/elements/PcLayerItem/index.js +53 -26
- package/dist/ui/elements/PcLayerItem/style.js +1 -1
- package/dist/ui/elements/PcPanelBrushes/index.d.ts +1 -1
- package/dist/ui/elements/PcPanelBrushes/index.js +22 -28
- package/dist/ui/elements/PcPanelBrushes/style.js +1 -1
- package/dist/ui/elements/PcPanelColours/index.d.ts +56 -19
- package/dist/ui/elements/PcPanelColours/index.js +251 -104
- package/dist/ui/elements/PcPanelColours/style.js +1 -1
- package/dist/ui/elements/PcSliderRange/index.js +3 -2
- package/dist/ui/elements/PcStats/index.d.ts +8 -4
- package/dist/ui/elements/PcStats/index.js +39 -5
- package/dist/ui/elements/PcToggleCheckbox/index.d.ts +13 -2
- package/dist/ui/elements/PcToggleCheckbox/index.js +27 -8
- package/dist/ui/elements/PcToolSettings/index.d.ts +1 -0
- package/dist/ui/elements/PcToolSettings/index.js +8 -8
- package/dist/ui/elements/PcVersion/index.d.ts +12 -0
- package/dist/ui/elements/PcVersion/index.js +43 -0
- package/dist/ui/index.d.ts +3 -1
- package/dist/ui/index.js +4 -2
- package/dist/ui/layout/index.d.ts +2 -2
- package/dist/ui/layout/index.js +2 -2
- package/locales/en-GB.json +28 -5
- package/locales/en-US.json +28 -5
- package/locales/fr.json +28 -5
- package/locales/ja.json +28 -5
- package/locales/ko.json +28 -5
- package/locales/zh-Hans.json +28 -5
- package/locales/zh-Hant.json +28 -5
- package/package.json +3 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import style_default from "./style.js";
|
|
2
2
|
import { PILLS_CSS } from "../../styles/index.js";
|
|
3
3
|
import { PcElement, defineElement } from "../../base/index.js";
|
|
4
|
+
import "../PcToggleCheckbox/index.js";
|
|
4
5
|
import StrokeEngine from "../../../lib/brushes/StrokeEngine/index.js";
|
|
5
6
|
import Layer, { createOffscreenCanvas } from "../../../lib/classes/Layer/index.js";
|
|
6
7
|
import { html, unsafeCSS } from "lit";
|
|
@@ -193,14 +194,14 @@ var PcBrushTest = class extends PcElement {
|
|
|
193
194
|
<button type="button" class="pill clear" @click=${() => this.clear()}>
|
|
194
195
|
${this.t("paintCanvas.common.clear")}
|
|
195
196
|
</button>
|
|
196
|
-
<
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
197
|
+
<pc-toggle-checkbox
|
|
198
|
+
class="show-points"
|
|
199
|
+
size="s"
|
|
200
|
+
.checked=${this.showPoints}
|
|
201
|
+
@change=${(e) => this.setShowPoints(e.detail.checked)}
|
|
202
|
+
>
|
|
202
203
|
${this.t("paintCanvas.brushConfig.showStrokePoints")}
|
|
203
|
-
</
|
|
204
|
+
</pc-toggle-checkbox>
|
|
204
205
|
</div>
|
|
205
206
|
`;
|
|
206
207
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// src/ui/elements/PcBrushTest/style.css?inline
|
|
2
|
-
var style_default = ":host {\n display: block;\n}\ncanvas {\n display: block;\n width: 100%;\n background: #fff;\n border: 1px solid var(--pc-border);\n touch-action: none;\n}\n/* \"Clear\", then \"Show stroke points\" */\n.actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 12px;\n margin-top: 6px;\n}\n.show-points {\n display: inline-flex;\n
|
|
2
|
+
var style_default = ":host {\n display: block;\n}\ncanvas {\n display: block;\n width: 100%;\n background: #fff;\n border: 1px solid var(--pc-border);\n touch-action: none;\n}\n/* \"Clear\", then \"Show stroke points\" */\n.actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 12px;\n margin-top: 6px;\n}\n.show-points {\n display: inline-flex;\n}\n/* \"Clear\": a red pill */\nbutton.pill.clear {\n background: var(--pc-red);\n color: #ffffff;\n}\n";
|
|
3
3
|
export { style_default as default };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { PcElement } from "../../base";
|
|
2
|
+
import { type PillSize } from "../../styles";
|
|
3
|
+
import type { MenuItem } from "../PcMenu";
|
|
4
|
+
import "../PcContextMenu";
|
|
5
|
+
/** An action in a button menu: what `pc-select` gives, its label and whether it can be done now */
|
|
6
|
+
export type ButtonMenuItem = Pick<MenuItem, "value" | "label" | "disabled">;
|
|
7
|
+
/**
|
|
8
|
+
* Whether the window is narrower than a width (CSS pixels). False without a width or `matchMedia`.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* isNarrowerThan(900); // true in a 600px-wide window
|
|
12
|
+
*/
|
|
13
|
+
export declare const isNarrowerThan: (width: number | undefined, matchMedia?: ((query: string) => {
|
|
14
|
+
matches: boolean;
|
|
15
|
+
}) | undefined) => boolean;
|
|
16
|
+
/**
|
|
17
|
+
* A row of pill buttons for actions, which can become one ⋮ menu (`pc-context-menu`): while `menu` is set, or while the
|
|
18
|
+
* window is narrower than `menu-below` (CSS pixels; only when set). Fires `pc-select` (detail: `{ value }`) when an
|
|
19
|
+
* action is chosen either way.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* html`<pc-button-menu label="More actions" menu-below="900" size="pill-s"
|
|
23
|
+
* .items=${[{ value: "cut", label: "Cut" }, { value: "paste", label: "Paste", disabled: true }]}
|
|
24
|
+
* @pc-select=${(e) => run(e.detail.value)}></pc-button-menu>`
|
|
25
|
+
*/
|
|
26
|
+
export declare class PcButtonMenu extends PcElement {
|
|
27
|
+
static properties: {
|
|
28
|
+
items: {
|
|
29
|
+
attribute: boolean;
|
|
30
|
+
};
|
|
31
|
+
label: {
|
|
32
|
+
type: StringConstructor;
|
|
33
|
+
};
|
|
34
|
+
size: {
|
|
35
|
+
type: StringConstructor;
|
|
36
|
+
};
|
|
37
|
+
menu: {
|
|
38
|
+
type: BooleanConstructor;
|
|
39
|
+
reflect: boolean;
|
|
40
|
+
};
|
|
41
|
+
menuBelow: {
|
|
42
|
+
type: NumberConstructor;
|
|
43
|
+
attribute: string;
|
|
44
|
+
};
|
|
45
|
+
narrowWindow: {
|
|
46
|
+
state: boolean;
|
|
47
|
+
};
|
|
48
|
+
translations: {
|
|
49
|
+
attribute: boolean;
|
|
50
|
+
};
|
|
51
|
+
icons: {
|
|
52
|
+
attribute: boolean;
|
|
53
|
+
};
|
|
54
|
+
theme: {
|
|
55
|
+
type: StringConstructor;
|
|
56
|
+
reflect: boolean;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
static styles: import("lit").CSSResultGroup[];
|
|
60
|
+
/** The actions, in order */
|
|
61
|
+
items: ButtonMenuItem[];
|
|
62
|
+
/** What the ⋮ button is called (e.g. "More actions") */
|
|
63
|
+
label: string;
|
|
64
|
+
/** The buttons' pill size (`pill` by default) */
|
|
65
|
+
size: PillSize;
|
|
66
|
+
/** Whether the actions are always one ⋮ menu */
|
|
67
|
+
menu: boolean;
|
|
68
|
+
/** Window width (CSS pixels) below which the actions are one ⋮ menu; none by default */
|
|
69
|
+
menuBelow?: number;
|
|
70
|
+
/** Whether the window is narrower than `menuBelow` */
|
|
71
|
+
narrowWindow: boolean;
|
|
72
|
+
/** Follows the window's width while `menuBelow` is set */
|
|
73
|
+
private query?;
|
|
74
|
+
private readonly onQueryChange;
|
|
75
|
+
constructor();
|
|
76
|
+
/** Whether the actions show as one ⋮ menu now */
|
|
77
|
+
get showsMenu(): boolean;
|
|
78
|
+
connectedCallback(): void;
|
|
79
|
+
disconnectedCallback(): void;
|
|
80
|
+
protected willUpdate(changed: Map<PropertyKey, unknown>): void;
|
|
81
|
+
/** Follow whether the window is narrower than `menuBelow` (when set and the browser can tell) */
|
|
82
|
+
private watchWidth;
|
|
83
|
+
/** Stop following the window's width */
|
|
84
|
+
private stopWatchingWidth;
|
|
85
|
+
/** Tell listeners an action was chosen */
|
|
86
|
+
private select;
|
|
87
|
+
render(): import("lit").TemplateResult<1> | import("lit").TemplateResult<1>[];
|
|
88
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { PcElement, defineElement, emit } from "../../base/index.js";
|
|
2
|
+
import { PILLS_CSS } from "../../styles/index.js";
|
|
3
|
+
import "../PcContextMenu/index.js";
|
|
4
|
+
import { css, html, unsafeCSS } from "lit";
|
|
5
|
+
// src/ui/elements/PcButtonMenu/index.ts
|
|
6
|
+
/**
|
|
7
|
+
* Whether the window is narrower than a width (CSS pixels). False without a width or `matchMedia`.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* isNarrowerThan(900); // true in a 600px-wide window
|
|
11
|
+
*/
|
|
12
|
+
var isNarrowerThan = (width, matchMedia = typeof window.matchMedia === "function" ? (query) => window.matchMedia(query) : void 0) => width !== void 0 && width > 0 && matchMedia !== void 0 && matchMedia(`(width < ${width}px)`).matches;
|
|
13
|
+
/**
|
|
14
|
+
* A row of pill buttons for actions, which can become one ⋮ menu (`pc-context-menu`): while `menu` is set, or while the
|
|
15
|
+
* window is narrower than `menu-below` (CSS pixels; only when set). Fires `pc-select` (detail: `{ value }`) when an
|
|
16
|
+
* action is chosen either way.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* html`<pc-button-menu label="More actions" menu-below="900" size="pill-s"
|
|
20
|
+
* .items=${[{ value: "cut", label: "Cut" }, { value: "paste", label: "Paste", disabled: true }]}
|
|
21
|
+
* @pc-select=${(e) => run(e.detail.value)}></pc-button-menu>`
|
|
22
|
+
*/
|
|
23
|
+
var PcButtonMenu = class extends PcElement {
|
|
24
|
+
static properties = {
|
|
25
|
+
...PcElement.properties,
|
|
26
|
+
items: { attribute: false },
|
|
27
|
+
label: { type: String },
|
|
28
|
+
size: { type: String },
|
|
29
|
+
menu: {
|
|
30
|
+
type: Boolean,
|
|
31
|
+
reflect: true
|
|
32
|
+
},
|
|
33
|
+
menuBelow: {
|
|
34
|
+
type: Number,
|
|
35
|
+
attribute: "menu-below"
|
|
36
|
+
},
|
|
37
|
+
narrowWindow: { state: true }
|
|
38
|
+
};
|
|
39
|
+
static styles = [
|
|
40
|
+
PcElement.styles,
|
|
41
|
+
unsafeCSS(PILLS_CSS),
|
|
42
|
+
css`
|
|
43
|
+
:host {
|
|
44
|
+
display: flex;
|
|
45
|
+
align-items: center;
|
|
46
|
+
gap: var(--pc-space-2);
|
|
47
|
+
}
|
|
48
|
+
:host([hidden]) {
|
|
49
|
+
display: none;
|
|
50
|
+
}
|
|
51
|
+
`
|
|
52
|
+
];
|
|
53
|
+
/** Follows the window's width while `menuBelow` is set */
|
|
54
|
+
query;
|
|
55
|
+
onQueryChange = (event) => {
|
|
56
|
+
this.narrowWindow = event.matches;
|
|
57
|
+
};
|
|
58
|
+
constructor() {
|
|
59
|
+
super();
|
|
60
|
+
this.items = [];
|
|
61
|
+
this.label = "";
|
|
62
|
+
this.size = "pill";
|
|
63
|
+
this.menu = false;
|
|
64
|
+
this.narrowWindow = false;
|
|
65
|
+
}
|
|
66
|
+
/** Whether the actions show as one ⋮ menu now */
|
|
67
|
+
get showsMenu() {
|
|
68
|
+
return this.menu || this.narrowWindow;
|
|
69
|
+
}
|
|
70
|
+
connectedCallback() {
|
|
71
|
+
super.connectedCallback();
|
|
72
|
+
this.watchWidth();
|
|
73
|
+
}
|
|
74
|
+
disconnectedCallback() {
|
|
75
|
+
super.disconnectedCallback();
|
|
76
|
+
this.stopWatchingWidth();
|
|
77
|
+
}
|
|
78
|
+
willUpdate(changed) {
|
|
79
|
+
super.willUpdate(changed);
|
|
80
|
+
if (changed.has("menuBelow") && this.isConnected) this.watchWidth();
|
|
81
|
+
}
|
|
82
|
+
/** Follow whether the window is narrower than `menuBelow` (when set and the browser can tell) */
|
|
83
|
+
watchWidth() {
|
|
84
|
+
this.stopWatchingWidth();
|
|
85
|
+
this.narrowWindow = isNarrowerThan(this.menuBelow);
|
|
86
|
+
if (!this.menuBelow || typeof window.matchMedia !== "function") return;
|
|
87
|
+
this.query = window.matchMedia(`(width < ${this.menuBelow}px)`);
|
|
88
|
+
this.query.addEventListener?.("change", this.onQueryChange);
|
|
89
|
+
}
|
|
90
|
+
/** Stop following the window's width */
|
|
91
|
+
stopWatchingWidth() {
|
|
92
|
+
this.query?.removeEventListener?.("change", this.onQueryChange);
|
|
93
|
+
this.query = void 0;
|
|
94
|
+
}
|
|
95
|
+
/** Tell listeners an action was chosen */
|
|
96
|
+
select(value) {
|
|
97
|
+
emit(this, "pc-select", { value });
|
|
98
|
+
}
|
|
99
|
+
render() {
|
|
100
|
+
if (this.showsMenu) return html`<pc-context-menu
|
|
101
|
+
class="more"
|
|
102
|
+
label=${this.label}
|
|
103
|
+
.items=${this.items.map(({ value, label, disabled }) => ({
|
|
104
|
+
value,
|
|
105
|
+
label,
|
|
106
|
+
disabled
|
|
107
|
+
}))}
|
|
108
|
+
@pc-select=${(event) => {
|
|
109
|
+
event.stopPropagation();
|
|
110
|
+
this.select(event.detail.value);
|
|
111
|
+
}}
|
|
112
|
+
></pc-context-menu>`;
|
|
113
|
+
return this.items.map(({ value, label, disabled }) => html`<button
|
|
114
|
+
type="button"
|
|
115
|
+
class="${this.size} ${value}"
|
|
116
|
+
data-value=${value}
|
|
117
|
+
?disabled=${disabled}
|
|
118
|
+
@click=${() => this.select(value)}
|
|
119
|
+
>
|
|
120
|
+
${label}
|
|
121
|
+
</button>`);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
defineElement("pc-button-menu", PcButtonMenu);
|
|
125
|
+
export { PcButtonMenu, isNarrowerThan };
|
|
@@ -121,6 +121,8 @@ export declare class PcCanvas extends PcElement {
|
|
|
121
121
|
private antsOffset;
|
|
122
122
|
/** Viewport that has been fitted once (so resizing doesn't refit) */
|
|
123
123
|
private fittedViewport?;
|
|
124
|
+
/** The screen canvas whose 2D context has been made (see `prepareScene`) */
|
|
125
|
+
private preparedCanvas?;
|
|
124
126
|
private frame;
|
|
125
127
|
/** Animation frame drawing only the brush cursor, if requested */
|
|
126
128
|
private overlayFrame;
|
|
@@ -168,6 +170,13 @@ export declare class PcCanvas extends PcElement {
|
|
|
168
170
|
connectedCallback(): void;
|
|
169
171
|
disconnectedCallback(): void;
|
|
170
172
|
firstUpdated(): void;
|
|
173
|
+
/**
|
|
174
|
+
* Make a new screen canvas's 2D context where the app's canvases draw (see `PaintCanvas.rendering`). Drawn from layers
|
|
175
|
+
* kept in regular memory (`cpu`), keeping the screen canvas there too means each frame copies only the area that
|
|
176
|
+
* changed, instead of sending whole layers to the GPU. The first context decides that; later `getContext("2d")` calls
|
|
177
|
+
* get this one, so the screen canvas is made again when the app's rendering differs (see `render`).
|
|
178
|
+
*/
|
|
179
|
+
private prepareScene;
|
|
171
180
|
/**
|
|
172
181
|
* Note what changed: the stroke in progress (and the area it changed), or anything else.
|
|
173
182
|
*/
|
|
@@ -21,6 +21,7 @@ import "../../../lib/rendering/sample/index.js";
|
|
|
21
21
|
import { gestureAction } from "../../../lib/utils/gestures/index.js";
|
|
22
22
|
import { snapToPixelGrid } from "../../../lib/brushes/params/index.js";
|
|
23
23
|
import { html, unsafeCSS } from "lit";
|
|
24
|
+
import { keyed } from "lit/directives/keyed.js";
|
|
24
25
|
// src/ui/elements/PcCanvas/index.ts
|
|
25
26
|
/** Toolbar width in CSS pixels (kept clear when fitting the canvas) */
|
|
26
27
|
var TOOLBAR_WIDTH = 50;
|
|
@@ -172,6 +173,8 @@ var PcCanvas = class extends PcElement {
|
|
|
172
173
|
antsOffset = 0;
|
|
173
174
|
/** Viewport that has been fitted once (so resizing doesn't refit) */
|
|
174
175
|
fittedViewport;
|
|
176
|
+
/** The screen canvas whose 2D context has been made (see `prepareScene`) */
|
|
177
|
+
preparedCanvas;
|
|
175
178
|
frame = 0;
|
|
176
179
|
/** Animation frame drawing only the brush cursor, if requested */
|
|
177
180
|
overlayFrame = 0;
|
|
@@ -247,7 +250,7 @@ var PcCanvas = class extends PcElement {
|
|
|
247
250
|
this.frame = 0;
|
|
248
251
|
}
|
|
249
252
|
firstUpdated() {
|
|
250
|
-
this.
|
|
253
|
+
this.prepareScene();
|
|
251
254
|
if (typeof ResizeObserver !== "undefined") {
|
|
252
255
|
this.resizeObserver = new ResizeObserver(() => this.syncSize());
|
|
253
256
|
this.resizeObserver.observe(this);
|
|
@@ -255,6 +258,18 @@ var PcCanvas = class extends PcElement {
|
|
|
255
258
|
this.syncSize();
|
|
256
259
|
}
|
|
257
260
|
/**
|
|
261
|
+
* Make a new screen canvas's 2D context where the app's canvases draw (see `PaintCanvas.rendering`). Drawn from layers
|
|
262
|
+
* kept in regular memory (`cpu`), keeping the screen canvas there too means each frame copies only the area that
|
|
263
|
+
* changed, instead of sending whole layers to the GPU. The first context decides that; later `getContext("2d")` calls
|
|
264
|
+
* get this one, so the screen canvas is made again when the app's rendering differs (see `render`).
|
|
265
|
+
*/
|
|
266
|
+
prepareScene() {
|
|
267
|
+
const canvas = this.canvas;
|
|
268
|
+
if (!canvas || canvas === this.preparedCanvas) return;
|
|
269
|
+
this.preparedCanvas = canvas;
|
|
270
|
+
canvas.getContext("2d", { willReadFrequently: this.app?.rendering !== "gpu" });
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
258
273
|
* Note what changed: the stroke in progress (and the area it changed), or anything else.
|
|
259
274
|
*/
|
|
260
275
|
sceneChanged(target) {
|
|
@@ -266,6 +281,7 @@ var PcCanvas = class extends PcElement {
|
|
|
266
281
|
} else if (!(this.committing && target === app?.layers)) this.fullChange = true;
|
|
267
282
|
}
|
|
268
283
|
updated(changed) {
|
|
284
|
+
this.prepareScene();
|
|
269
285
|
const resized = this.syncSize();
|
|
270
286
|
const onlyStroke = changed.size === 0 && !this.fullChange && !resized;
|
|
271
287
|
this.requestDraw(onlyStroke ? this.strokeArea : void 0);
|
|
@@ -1031,22 +1047,22 @@ var PcCanvas = class extends PcElement {
|
|
|
1031
1047
|
});
|
|
1032
1048
|
}
|
|
1033
1049
|
render() {
|
|
1034
|
-
return html`<canvas
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
+
return html`${keyed(this.app?.rendering ?? "cpu", html`<canvas
|
|
1051
|
+
class="scene"
|
|
1052
|
+
aria-label=${this.t("paintCanvas.canvas.label")}
|
|
1053
|
+
@pointerdown=${this.onPointerDown}
|
|
1054
|
+
@pointermove=${this.onPointerMove}
|
|
1055
|
+
@pointerup=${this.onPointerUp}
|
|
1056
|
+
@pointercancel=${this.onPointerCancel}
|
|
1057
|
+
@touchstart=${this.onTouchStart}
|
|
1058
|
+
@pointerleave=${this.onPointerLeave}
|
|
1059
|
+
@wheel=${this.onWheel}
|
|
1060
|
+
@gesturestart=${this.onGestureStart}
|
|
1061
|
+
@gesturechange=${this.onGestureChange}
|
|
1062
|
+
@gestureend=${(e) => e.preventDefault()}
|
|
1063
|
+
@dblclick=${() => this.app?.applyLasso(this.app.lasso.close())}
|
|
1064
|
+
@contextmenu=${(e) => e.preventDefault()}
|
|
1065
|
+
></canvas>`)}
|
|
1050
1066
|
<canvas class="outlines" aria-hidden="true"></canvas>
|
|
1051
1067
|
<canvas class="overlay" aria-hidden="true"></canvas>
|
|
1052
1068
|
<canvas class="sampler" aria-hidden="true"></canvas>`;
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { nothing } from "lit";
|
|
2
2
|
import { PcElement } from "../../base";
|
|
3
3
|
import PaintCanvas, { Tool } from "../../../lib/classes/PaintCanvas";
|
|
4
|
-
import "../
|
|
4
|
+
import "../PcButtonMenu";
|
|
5
5
|
/** The tools that cut, copy and paste are shown for: the brush, eraser, lassos and Move tool */
|
|
6
6
|
export declare const CLIPBOARD_TOOLS: readonly Tool[];
|
|
7
|
+
/** Window width (CSS pixels) below which the clipboard tools are one ⋮ menu */
|
|
8
|
+
export declare const CLIPBOARD_MENU_BELOW = 900;
|
|
7
9
|
/**
|
|
8
10
|
* Cut, copy, copy merged and paste buttons for the canvas's masked image data, shown for the brush, eraser, lassos and
|
|
9
11
|
* Move tool (see `CLIPBOARD_TOOLS`). "Copy merged" copies the shown layers mixed as shown (see `PaintCanvas.copyMerged`).
|
|
10
12
|
* Cut and both copies work while there's a mask and no transform is pending; paste while there's copied image data.
|
|
11
|
-
*
|
|
13
|
+
* They're one ⋮ menu instead while the window is narrower than `CLIPBOARD_MENU_BELOW` (900px), or while `narrow` (see
|
|
14
|
+
* `pc-button-menu`).
|
|
12
15
|
*
|
|
13
16
|
* `<paint-canvas>` puts it at the end of its top pane, after the tool settings.
|
|
14
17
|
*
|
|
@@ -37,7 +40,7 @@ export declare class PcClipboardTools extends PcElement {
|
|
|
37
40
|
};
|
|
38
41
|
static styles: import("lit").CSSResultGroup[];
|
|
39
42
|
app?: PaintCanvas;
|
|
40
|
-
/** Whether the buttons are one ⋮ menu (e.g. while the layout is narrow) */
|
|
43
|
+
/** Whether the buttons are one ⋮ menu whatever the window's width (e.g. while the layout is narrow) */
|
|
41
44
|
narrow: boolean;
|
|
42
45
|
private changes;
|
|
43
46
|
constructor();
|
|
@@ -45,5 +48,5 @@ export declare class PcClipboardTools extends PcElement {
|
|
|
45
48
|
private actions;
|
|
46
49
|
/** Hide for tools without clipboard actions (e.g. zoom) */
|
|
47
50
|
protected willUpdate(): void;
|
|
48
|
-
render(): import("lit").TemplateResult<1> | typeof nothing
|
|
51
|
+
render(): import("lit").TemplateResult<1> | typeof nothing;
|
|
49
52
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { Tool } from "../../../lib/classes/PaintCanvas/tool.js";
|
|
2
2
|
import { PcElement, defineElement } from "../../base/index.js";
|
|
3
3
|
import ChangeController from "../../ChangeController/index.js";
|
|
4
|
-
import { PILLS_CSS } from "../../styles/index.js";
|
|
5
4
|
import "../../../lib/classes/PaintCanvas/index.js";
|
|
6
|
-
import "../
|
|
7
|
-
import { css, html, nothing
|
|
5
|
+
import "../PcButtonMenu/index.js";
|
|
6
|
+
import { css, html, nothing } from "lit";
|
|
8
7
|
// src/ui/elements/PcClipboardTools/index.ts
|
|
9
8
|
/** The tools that cut, copy and paste are shown for: the brush, eraser, lassos and Move tool */
|
|
10
9
|
var CLIPBOARD_TOOLS = [
|
|
@@ -16,11 +15,14 @@ var CLIPBOARD_TOOLS = [
|
|
|
16
15
|
Tool.FreeformLasso,
|
|
17
16
|
Tool.Move
|
|
18
17
|
];
|
|
18
|
+
/** Window width (CSS pixels) below which the clipboard tools are one ⋮ menu */
|
|
19
|
+
var CLIPBOARD_MENU_BELOW = 900;
|
|
19
20
|
/**
|
|
20
21
|
* Cut, copy, copy merged and paste buttons for the canvas's masked image data, shown for the brush, eraser, lassos and
|
|
21
22
|
* Move tool (see `CLIPBOARD_TOOLS`). "Copy merged" copies the shown layers mixed as shown (see `PaintCanvas.copyMerged`).
|
|
22
23
|
* Cut and both copies work while there's a mask and no transform is pending; paste while there's copied image data.
|
|
23
|
-
*
|
|
24
|
+
* They're one ⋮ menu instead while the window is narrower than `CLIPBOARD_MENU_BELOW` (900px), or while `narrow` (see
|
|
25
|
+
* `pc-button-menu`).
|
|
24
26
|
*
|
|
25
27
|
* `<paint-canvas>` puts it at the end of its top pane, after the tool settings.
|
|
26
28
|
*
|
|
@@ -36,15 +38,11 @@ var PcClipboardTools = class extends PcElement {
|
|
|
36
38
|
reflect: true
|
|
37
39
|
}
|
|
38
40
|
};
|
|
39
|
-
static styles = [
|
|
40
|
-
PcElement.styles,
|
|
41
|
-
unsafeCSS(PILLS_CSS),
|
|
42
|
-
css`
|
|
41
|
+
static styles = [PcElement.styles, css`
|
|
43
42
|
:host {
|
|
44
43
|
display: flex;
|
|
45
44
|
flex: none;
|
|
46
45
|
align-items: center;
|
|
47
|
-
gap: 8px;
|
|
48
46
|
padding: 4px 8px;
|
|
49
47
|
background: var(--pc-bar);
|
|
50
48
|
border-bottom: 1px solid var(--pc-surface-active);
|
|
@@ -52,8 +50,7 @@ var PcClipboardTools = class extends PcElement {
|
|
|
52
50
|
:host([hidden]) {
|
|
53
51
|
display: none;
|
|
54
52
|
}
|
|
55
|
-
`
|
|
56
|
-
];
|
|
53
|
+
`];
|
|
57
54
|
changes = new ChangeController(this, () => this.app ? [
|
|
58
55
|
this.app,
|
|
59
56
|
this.app.selection,
|
|
@@ -101,25 +98,22 @@ var PcClipboardTools = class extends PcElement {
|
|
|
101
98
|
const app = this.app;
|
|
102
99
|
if (!app || this.hidden) return nothing;
|
|
103
100
|
const actions = this.actions(app);
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
101
|
+
return html`<pc-button-menu
|
|
102
|
+
size="pill-s"
|
|
103
|
+
label=${this.t("paintCanvas.toolSettings.moreActions")}
|
|
104
|
+
menu-below=${900}
|
|
105
|
+
?menu=${this.narrow}
|
|
106
|
+
.items=${actions.map(({ name, label, disabled }) => ({
|
|
108
107
|
value: name,
|
|
109
108
|
label,
|
|
110
109
|
disabled
|
|
111
110
|
}))}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
?disabled=${action.disabled}
|
|
118
|
-
@click=${action.run}
|
|
119
|
-
>
|
|
120
|
-
${action.label}
|
|
121
|
-
</button>`);
|
|
111
|
+
@pc-select=${(event) => {
|
|
112
|
+
event.stopPropagation();
|
|
113
|
+
actions.find((action) => action.name === event.detail.value)?.run();
|
|
114
|
+
}}
|
|
115
|
+
></pc-button-menu>`;
|
|
122
116
|
}
|
|
123
117
|
};
|
|
124
118
|
defineElement("pc-clipboard-tools", PcClipboardTools);
|
|
125
|
-
export { CLIPBOARD_TOOLS, PcClipboardTools };
|
|
119
|
+
export { CLIPBOARD_MENU_BELOW, CLIPBOARD_TOOLS, PcClipboardTools };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { nothing } from "lit";
|
|
2
2
|
import { PcElement } from "../../base";
|
|
3
|
+
import "../PcToggleCheckbox";
|
|
3
4
|
import { type InputSettingsData } from "../../../lib/classes/InputSettings";
|
|
4
5
|
import type { UiSettingsLike } from "../../../lib/classes/UiSettings";
|
|
5
6
|
/** Settings `pc-input-settings` can change: PaintCanvas's `InputSettings`, or anything with the same data and `update` */
|
|
@@ -69,7 +70,7 @@ export declare class PcInputSettings extends PcElement {
|
|
|
69
70
|
constructor();
|
|
70
71
|
/** Use the kept language when it changes */
|
|
71
72
|
protected willUpdate(): void;
|
|
72
|
-
/** A
|
|
73
|
+
/** A switch for an on/off setting */
|
|
73
74
|
private toggle;
|
|
74
75
|
/**
|
|
75
76
|
* The touch gestures: which gesture undoes, redoes, copies and pastes. Choosing a gesture another action uses swaps
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { PcElement, defineElement, emit } from "../../base/index.js";
|
|
2
2
|
import ChangeController from "../../ChangeController/index.js";
|
|
3
|
+
import "../PcToggleCheckbox/index.js";
|
|
3
4
|
import { languageName } from "../../../lib/i18n/index.js";
|
|
4
5
|
import { isTouchDevice, zoomModifierName } from "../../../lib/classes/InputSettings/index.js";
|
|
5
6
|
import { GESTURE_ACTIONS, TOUCH_GESTURES, assignGesture } from "../../../lib/utils/gestures/index.js";
|
|
@@ -57,13 +58,7 @@ var PcInputSettings = class extends PcElement {
|
|
|
57
58
|
font-weight: bold;
|
|
58
59
|
}
|
|
59
60
|
.toggle {
|
|
60
|
-
display: flex;
|
|
61
61
|
grid-column: 1 / -1;
|
|
62
|
-
gap: var(--pc-space-2);
|
|
63
|
-
align-items: center;
|
|
64
|
-
}
|
|
65
|
-
input[type="checkbox"] {
|
|
66
|
-
accent-color: var(--pc-accent);
|
|
67
62
|
}
|
|
68
63
|
input:focus-visible,
|
|
69
64
|
select:focus-visible {
|
|
@@ -88,17 +83,16 @@ var PcInputSettings = class extends PcElement {
|
|
|
88
83
|
this.usedLocale = locale;
|
|
89
84
|
if (locale !== this.translations.locale) this.translations.setLocale(locale);
|
|
90
85
|
}
|
|
91
|
-
/** A
|
|
86
|
+
/** A switch for an on/off setting */
|
|
92
87
|
toggle(data, key, label) {
|
|
93
|
-
return html`<
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
/>
|
|
88
|
+
return html`<pc-toggle-checkbox
|
|
89
|
+
class="toggle"
|
|
90
|
+
data-setting=${key}
|
|
91
|
+
.checked=${data[key]}
|
|
92
|
+
@change=${(e) => this.settings?.update({ [key]: e.detail.checked })}
|
|
93
|
+
>
|
|
100
94
|
${label}
|
|
101
|
-
</
|
|
95
|
+
</pc-toggle-checkbox>`;
|
|
102
96
|
}
|
|
103
97
|
/**
|
|
104
98
|
* The touch gestures: which gesture undoes, redoes, copies and pastes. Choosing a gesture another action uses swaps
|
|
@@ -2,6 +2,8 @@ import { PcElement } from "../../base";
|
|
|
2
2
|
import { BlendMode, type default as Layer } from "../../../lib/classes/Layer";
|
|
3
3
|
import type LayerStack from "../../../lib/classes/LayerStack";
|
|
4
4
|
import "../PcDialog";
|
|
5
|
+
import "../PcSliderRange";
|
|
6
|
+
import { type PromptFn } from "../../ask";
|
|
5
7
|
import "../PcContextMenu";
|
|
6
8
|
import { MENU_MARGIN, menuTop } from "../PcContextMenu";
|
|
7
9
|
import { type DialogChoice } from "../PcDialog";
|
|
@@ -12,7 +14,7 @@ export declare const BLEND_MODE_OPTIONS: readonly {
|
|
|
12
14
|
label: string;
|
|
13
15
|
}[];
|
|
14
16
|
/** Actions in the reorder handle's context menu */
|
|
15
|
-
export type LayerAction = "mask" | "duplicate" | "merge" | "clear" | "delete" | "up" | "top" | "down" | "bottom";
|
|
17
|
+
export type LayerAction = "rename" | "mask" | "duplicate" | "merge" | "clear" | "delete" | "up" | "top" | "down" | "bottom";
|
|
16
18
|
/** Context menu options in display order, with the translation keys of their labels */
|
|
17
19
|
export declare const LAYER_ACTIONS: readonly {
|
|
18
20
|
action: LayerAction;
|
|
@@ -61,7 +63,9 @@ export interface LayerDragDetail {
|
|
|
61
63
|
/** Where the layer actions menu goes and how close to the window's edges (see `pc-context-menu`) */
|
|
62
64
|
export { MENU_MARGIN, menuTop };
|
|
63
65
|
/**
|
|
64
|
-
* One row in the layers menu: reorder handle, thumbnail and name (then opacity and blend mode under them), alpha lock
|
|
66
|
+
* One row in the layers menu: reorder handle, thumbnail and name (then opacity and blend mode under them), alpha lock
|
|
67
|
+
* (padlock) and visibility (eye) icons. Pressing anywhere on the row (its controls too) selects the layer, which is then
|
|
68
|
+
* shown with a purple background (`active`). "Rename…" in the actions menu asks for a new name.
|
|
65
69
|
* Dragging the handle (with mouse, pen or touch) reorders the layer: the row fires {@link LAYER_DRAG_EVENT} and the
|
|
66
70
|
* layers menu shows where it will land. Clicking or tapping the handle, pressing Enter or Space on it, or right-clicking
|
|
67
71
|
* it opens the layer's actions menu (which can also reorder it). Cmd/Ctrl + click on the thumbnail or name (or "Create
|
|
@@ -96,6 +100,10 @@ export declare class PcLayerItem extends PcElement {
|
|
|
96
100
|
attribute: string;
|
|
97
101
|
reflect: boolean;
|
|
98
102
|
};
|
|
103
|
+
active: {
|
|
104
|
+
type: BooleanConstructor;
|
|
105
|
+
reflect: boolean;
|
|
106
|
+
};
|
|
99
107
|
translations: {
|
|
100
108
|
attribute: boolean;
|
|
101
109
|
};
|
|
@@ -116,6 +124,10 @@ export declare class PcLayerItem extends PcElement {
|
|
|
116
124
|
menuOpen: boolean;
|
|
117
125
|
/** The action the user is being asked to confirm, if any */
|
|
118
126
|
confirming?: ConfirmedAction;
|
|
127
|
+
/** Whether this row's layer is the selected one (shown with a purple background) */
|
|
128
|
+
active: boolean;
|
|
129
|
+
/** Asks the user for the layer's new name (replaceable for tests) */
|
|
130
|
+
prompt: PromptFn;
|
|
119
131
|
/** Whether this row's layer is being dragged (set by the layers menu; the row floats with the pointer) */
|
|
120
132
|
dragging: boolean;
|
|
121
133
|
/** While this row's layer is dragged: what dropping it now would do (set by the layers menu; shown by the cursor) */
|
|
@@ -128,6 +140,8 @@ export declare class PcLayerItem extends PcElement {
|
|
|
128
140
|
/** Device pixels per CSS pixel (replaceable for tests) */
|
|
129
141
|
pixelRatio: () => number;
|
|
130
142
|
constructor();
|
|
143
|
+
/** Pressing anywhere on the row selects its layer, except in the dialogs it shows (e.g. after deleting it) */
|
|
144
|
+
private readonly onClick;
|
|
131
145
|
/**
|
|
132
146
|
* Run a context menu action. Merging down, clearing and deleting ask for confirmation first (see `confirmed`).
|
|
133
147
|
*/
|
|
@@ -180,13 +194,14 @@ export declare class PcLayerItem extends PcElement {
|
|
|
180
194
|
*/
|
|
181
195
|
private requestMask;
|
|
182
196
|
/**
|
|
183
|
-
*
|
|
197
|
+
* Cmd/Ctrl + click on the thumbnail or name makes a mask from the layer's alpha (the click also selects the layer).
|
|
184
198
|
*/
|
|
185
|
-
private
|
|
199
|
+
private onDetailsClick;
|
|
186
200
|
/**
|
|
187
|
-
*
|
|
201
|
+
* Ask for the layer's new name and use it. Cancelling or an empty name leaves the name as it was.
|
|
188
202
|
*/
|
|
189
|
-
private
|
|
203
|
+
private rename;
|
|
204
|
+
protected willUpdate(changed: Map<PropertyKey, unknown>): void;
|
|
190
205
|
updated(): void;
|
|
191
206
|
/**
|
|
192
207
|
* Draw the layer's image, scaled to fit, on a checkerboard that shows transparency.
|