@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,48 @@
|
|
|
1
|
+
import { type default as PaintCanvas } from "../PaintCanvas";
|
|
2
|
+
import { type ShortcutAction } from "../../utils/shortcuts";
|
|
3
|
+
/** Event dispatched on the window for shortcut actions handled elsewhere (e.g. saving) */
|
|
4
|
+
export declare const SHORTCUT_EVENT = "pc-shortcut";
|
|
5
|
+
/**
|
|
6
|
+
* Listens for key presses and runs the matching shortcut on the app. Shortcuts are ignored while typing in text fields.
|
|
7
|
+
*
|
|
8
|
+
* Tool selection, brush/eraser size, interface visibility, select all/deselect, undo/redo, cut/copy/paste, deleting the
|
|
9
|
+
* masked image data (Delete or Backspace) and finishing or cancelling a
|
|
10
|
+
* lasso shape are handled here; other actions (and Escape/Enter for later features) dispatch an `pc-shortcut` event with the action as `detail`.
|
|
11
|
+
* Holding Space pans temporarily; releasing it returns to the selected tool.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* const shortcuts = new KeyboardShortcuts(app);
|
|
15
|
+
* shortcuts.attach(window);
|
|
16
|
+
*/
|
|
17
|
+
export default class KeyboardShortcuts {
|
|
18
|
+
private readonly app;
|
|
19
|
+
private target;
|
|
20
|
+
private readonly onKeyDown;
|
|
21
|
+
private readonly onKeyUp;
|
|
22
|
+
private readonly onBlur;
|
|
23
|
+
constructor(app: PaintCanvas);
|
|
24
|
+
/**
|
|
25
|
+
* Start listening for key presses on a target (usually `window`).
|
|
26
|
+
*/
|
|
27
|
+
attach(target: EventTarget): void;
|
|
28
|
+
/**
|
|
29
|
+
* Stop listening for key presses.
|
|
30
|
+
*/
|
|
31
|
+
detach(): void;
|
|
32
|
+
/**
|
|
33
|
+
* Run the shortcut for a key press, if any. Returns the action run.
|
|
34
|
+
*/
|
|
35
|
+
handle(event: KeyboardEvent): ShortcutAction | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Return to the selected tool when the hold-to-pan key is released.
|
|
38
|
+
*/
|
|
39
|
+
handleKeyUp(event: KeyboardEvent): void;
|
|
40
|
+
/**
|
|
41
|
+
* Run a shortcut action.
|
|
42
|
+
*/
|
|
43
|
+
run(action: ShortcutAction): void;
|
|
44
|
+
/**
|
|
45
|
+
* Dispatch an action as an `pc-shortcut` event for features handled elsewhere.
|
|
46
|
+
*/
|
|
47
|
+
private dispatch;
|
|
48
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { Tool } from "../PaintCanvas/index.js";
|
|
2
|
+
import { isTypingTarget, matchShortcut } from "../../utils/shortcuts/index.js";
|
|
3
|
+
// src/lib/classes/KeyboardShortcuts/index.ts
|
|
4
|
+
/** Event dispatched on the window for shortcut actions handled elsewhere (e.g. saving) */
|
|
5
|
+
var SHORTCUT_EVENT = "pc-shortcut";
|
|
6
|
+
/**
|
|
7
|
+
* Listens for key presses and runs the matching shortcut on the app. Shortcuts are ignored while typing in text fields.
|
|
8
|
+
*
|
|
9
|
+
* Tool selection, brush/eraser size, interface visibility, select all/deselect, undo/redo, cut/copy/paste, deleting the
|
|
10
|
+
* masked image data (Delete or Backspace) and finishing or cancelling a
|
|
11
|
+
* lasso shape are handled here; other actions (and Escape/Enter for later features) dispatch an `pc-shortcut` event with the action as `detail`.
|
|
12
|
+
* Holding Space pans temporarily; releasing it returns to the selected tool.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* const shortcuts = new KeyboardShortcuts(app);
|
|
16
|
+
* shortcuts.attach(window);
|
|
17
|
+
*/
|
|
18
|
+
var KeyboardShortcuts = class {
|
|
19
|
+
app;
|
|
20
|
+
target = null;
|
|
21
|
+
onKeyDown = (event) => this.handle(event);
|
|
22
|
+
onKeyUp = (event) => this.handleKeyUp(event);
|
|
23
|
+
onBlur = () => this.app.releaseHeldTool();
|
|
24
|
+
constructor(app) {
|
|
25
|
+
this.app = app;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Start listening for key presses on a target (usually `window`).
|
|
29
|
+
*/
|
|
30
|
+
attach(target) {
|
|
31
|
+
this.detach();
|
|
32
|
+
this.target = target;
|
|
33
|
+
target.addEventListener("keydown", this.onKeyDown);
|
|
34
|
+
target.addEventListener("keyup", this.onKeyUp);
|
|
35
|
+
target.addEventListener("blur", this.onBlur);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Stop listening for key presses.
|
|
39
|
+
*/
|
|
40
|
+
detach() {
|
|
41
|
+
this.target?.removeEventListener("keydown", this.onKeyDown);
|
|
42
|
+
this.target?.removeEventListener("keyup", this.onKeyUp);
|
|
43
|
+
this.target?.removeEventListener("blur", this.onBlur);
|
|
44
|
+
this.target = null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Run the shortcut for a key press, if any. Returns the action run.
|
|
48
|
+
*/
|
|
49
|
+
handle(event) {
|
|
50
|
+
if (isTypingTarget(event.composedPath()[0] ?? event.target)) return void 0;
|
|
51
|
+
if (event.key === " " && !event.metaKey && !event.ctrlKey && !event.altKey) {
|
|
52
|
+
event.preventDefault();
|
|
53
|
+
this.app.holdTool(Tool.Pan);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const action = matchShortcut(event);
|
|
57
|
+
if (!action) return void 0;
|
|
58
|
+
event.preventDefault();
|
|
59
|
+
this.run(action);
|
|
60
|
+
return action;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Return to the selected tool when the hold-to-pan key is released.
|
|
64
|
+
*/
|
|
65
|
+
handleKeyUp(event) {
|
|
66
|
+
if (event.key === " ") this.app.releaseHeldTool();
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Run a shortcut action.
|
|
70
|
+
*/
|
|
71
|
+
run(action) {
|
|
72
|
+
const app = this.app;
|
|
73
|
+
switch (action.type) {
|
|
74
|
+
case "tool":
|
|
75
|
+
app.selectTool(action.tool);
|
|
76
|
+
break;
|
|
77
|
+
case "brush-smaller":
|
|
78
|
+
case "brush-bigger": {
|
|
79
|
+
const settings = app.tool === Tool.Eraser ? app.eraser : app.tool === Tool.Brush ? app.brush : void 0;
|
|
80
|
+
if (action.type === "brush-bigger") settings?.grow();
|
|
81
|
+
else settings?.shrink();
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
case "toggle-interface":
|
|
85
|
+
app.toggleInterface();
|
|
86
|
+
break;
|
|
87
|
+
case "select-all":
|
|
88
|
+
app.selection.selectAll();
|
|
89
|
+
break;
|
|
90
|
+
case "deselect":
|
|
91
|
+
app.selection.clear();
|
|
92
|
+
break;
|
|
93
|
+
case "undo":
|
|
94
|
+
app.undo();
|
|
95
|
+
break;
|
|
96
|
+
case "redo":
|
|
97
|
+
app.redo();
|
|
98
|
+
break;
|
|
99
|
+
case "cut":
|
|
100
|
+
app.cut();
|
|
101
|
+
break;
|
|
102
|
+
case "delete":
|
|
103
|
+
app.deleteMasked();
|
|
104
|
+
break;
|
|
105
|
+
case "copy":
|
|
106
|
+
app.copy();
|
|
107
|
+
break;
|
|
108
|
+
case "paste":
|
|
109
|
+
app.paste();
|
|
110
|
+
break;
|
|
111
|
+
case "commit":
|
|
112
|
+
if (app.transform.pending) {
|
|
113
|
+
app.commitTransform();
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
if (app.lasso.active) {
|
|
117
|
+
app.applyLasso(app.lasso.close());
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
this.dispatch(action);
|
|
121
|
+
break;
|
|
122
|
+
case "cancel":
|
|
123
|
+
app.lasso.cancel();
|
|
124
|
+
app.cancelTransform();
|
|
125
|
+
this.dispatch(action);
|
|
126
|
+
break;
|
|
127
|
+
default: this.dispatch(action);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Dispatch an action as an `pc-shortcut` event for features handled elsewhere.
|
|
132
|
+
*/
|
|
133
|
+
dispatch(action) {
|
|
134
|
+
(this.target ?? this.app).dispatchEvent(new CustomEvent(SHORTCUT_EVENT, { detail: action }));
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
export { SHORTCUT_EVENT, KeyboardShortcuts as default };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/** Layer blending modes, mapped to canvas `globalCompositeOperation` values */
|
|
2
|
+
export declare enum BlendMode {
|
|
3
|
+
Normal = "source-over",
|
|
4
|
+
Screen = "screen",
|
|
5
|
+
Lighten = "lighten",
|
|
6
|
+
Multiply = "multiply",
|
|
7
|
+
Darken = "darken",
|
|
8
|
+
Overlay = "overlay"
|
|
9
|
+
}
|
|
10
|
+
/** Maximum length of a layer name */
|
|
11
|
+
export declare const MAX_LAYER_NAME_LENGTH = 64;
|
|
12
|
+
export interface LayerConfig {
|
|
13
|
+
/** Unique ID (generated if not given) */
|
|
14
|
+
id?: string;
|
|
15
|
+
/** Layer name */
|
|
16
|
+
name: string;
|
|
17
|
+
/** Affects how the layer blends with layers below */
|
|
18
|
+
blendMode?: BlendMode;
|
|
19
|
+
/** Opacity (0–1) */
|
|
20
|
+
opacity?: number;
|
|
21
|
+
/** Visibility */
|
|
22
|
+
visible?: boolean;
|
|
23
|
+
/** When enabled, drawing cannot add or remove alpha data on the layer */
|
|
24
|
+
alphaLock?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/** Creates the canvas that stores a layer's image data. Replaceable so tests can run without a real canvas. */
|
|
27
|
+
export type CanvasFactory = (width: number, height: number) => OffscreenCanvas;
|
|
28
|
+
/**
|
|
29
|
+
* Create an `OffscreenCanvas` of the given size.
|
|
30
|
+
*/
|
|
31
|
+
export declare const createOffscreenCanvas: CanvasFactory;
|
|
32
|
+
/**
|
|
33
|
+
* Clamp an opacity value to 0–1.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* clampOpacity(1.5); // 1
|
|
37
|
+
*/
|
|
38
|
+
export declare const clampOpacity: (value: number) => number;
|
|
39
|
+
/**
|
|
40
|
+
* A single drawing layer. Layers are local to each user and never sent to other users; only the flattened result of all a user's layers is sent.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* const layer = new Layer({ name: "Layer 1" }, 2000, 2000);
|
|
44
|
+
* layer.opacity = 0.5;
|
|
45
|
+
*/
|
|
46
|
+
export default class Layer {
|
|
47
|
+
/** Unique ID */
|
|
48
|
+
readonly id: string;
|
|
49
|
+
/** Width in pixels */
|
|
50
|
+
readonly width: number;
|
|
51
|
+
/** Height in pixels */
|
|
52
|
+
readonly height: number;
|
|
53
|
+
/** Image data */
|
|
54
|
+
readonly canvas: OffscreenCanvas;
|
|
55
|
+
/** Blending mode */
|
|
56
|
+
blendMode: BlendMode;
|
|
57
|
+
/** Visibility */
|
|
58
|
+
visible: boolean;
|
|
59
|
+
/** Alpha lock */
|
|
60
|
+
alphaLock: boolean;
|
|
61
|
+
private layerName;
|
|
62
|
+
private layerOpacity;
|
|
63
|
+
constructor(config: LayerConfig, width: number, height: number, createCanvas?: CanvasFactory);
|
|
64
|
+
/** Layer name (trimmed, 1–64 characters) */
|
|
65
|
+
get name(): string;
|
|
66
|
+
set name(value: string);
|
|
67
|
+
/** Opacity (clamped to 0–1) */
|
|
68
|
+
get opacity(): number;
|
|
69
|
+
set opacity(value: number);
|
|
70
|
+
/**
|
|
71
|
+
* Get the 2D drawing context of the layer's canvas.
|
|
72
|
+
*/
|
|
73
|
+
get context(): OffscreenCanvasRenderingContext2D;
|
|
74
|
+
/**
|
|
75
|
+
* Remove all image data from the layer.
|
|
76
|
+
*/
|
|
77
|
+
clear(): void;
|
|
78
|
+
/**
|
|
79
|
+
* Replace this layer's image data with a copy of another layer's image data.
|
|
80
|
+
*/
|
|
81
|
+
copyImageFrom(source: Layer): void;
|
|
82
|
+
/**
|
|
83
|
+
* Get the layer's settings (without image data).
|
|
84
|
+
*/
|
|
85
|
+
toConfig(): Required<LayerConfig>;
|
|
86
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// src/lib/classes/Layer/index.ts
|
|
2
|
+
/** Layer blending modes, mapped to canvas `globalCompositeOperation` values */
|
|
3
|
+
var BlendMode = /* @__PURE__ */ function(BlendMode) {
|
|
4
|
+
BlendMode["Normal"] = "source-over";
|
|
5
|
+
BlendMode["Screen"] = "screen";
|
|
6
|
+
BlendMode["Lighten"] = "lighten";
|
|
7
|
+
BlendMode["Multiply"] = "multiply";
|
|
8
|
+
BlendMode["Darken"] = "darken";
|
|
9
|
+
BlendMode["Overlay"] = "overlay";
|
|
10
|
+
return BlendMode;
|
|
11
|
+
}({});
|
|
12
|
+
/** Maximum length of a layer name */
|
|
13
|
+
var MAX_LAYER_NAME_LENGTH = 64;
|
|
14
|
+
/**
|
|
15
|
+
* Create an `OffscreenCanvas` of the given size.
|
|
16
|
+
*/
|
|
17
|
+
var createOffscreenCanvas = (width, height) => new OffscreenCanvas(width, height);
|
|
18
|
+
/**
|
|
19
|
+
* Clamp an opacity value to 0–1.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* clampOpacity(1.5); // 1
|
|
23
|
+
*/
|
|
24
|
+
var clampOpacity = (value) => Number.isNaN(value) ? 1 : Math.max(0, Math.min(1, value));
|
|
25
|
+
/**
|
|
26
|
+
* A single drawing layer. Layers are local to each user and never sent to other users; only the flattened result of all a user's layers is sent.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* const layer = new Layer({ name: "Layer 1" }, 2000, 2000);
|
|
30
|
+
* layer.opacity = 0.5;
|
|
31
|
+
*/
|
|
32
|
+
var Layer = class {
|
|
33
|
+
/** Unique ID */
|
|
34
|
+
id;
|
|
35
|
+
/** Width in pixels */
|
|
36
|
+
width;
|
|
37
|
+
/** Height in pixels */
|
|
38
|
+
height;
|
|
39
|
+
/** Image data */
|
|
40
|
+
canvas;
|
|
41
|
+
/** Blending mode */
|
|
42
|
+
blendMode;
|
|
43
|
+
/** Visibility */
|
|
44
|
+
visible;
|
|
45
|
+
/** Alpha lock */
|
|
46
|
+
alphaLock;
|
|
47
|
+
layerName = "";
|
|
48
|
+
layerOpacity = 1;
|
|
49
|
+
constructor(config, width, height, createCanvas = createOffscreenCanvas) {
|
|
50
|
+
this.id = config.id ?? crypto.randomUUID();
|
|
51
|
+
this.name = config.name;
|
|
52
|
+
this.width = width;
|
|
53
|
+
this.height = height;
|
|
54
|
+
this.canvas = createCanvas(width, height);
|
|
55
|
+
this.blendMode = config.blendMode ?? "source-over";
|
|
56
|
+
this.opacity = config.opacity ?? 1;
|
|
57
|
+
this.visible = config.visible ?? true;
|
|
58
|
+
this.alphaLock = config.alphaLock ?? false;
|
|
59
|
+
}
|
|
60
|
+
/** Layer name (trimmed, 1–64 characters) */
|
|
61
|
+
get name() {
|
|
62
|
+
return this.layerName;
|
|
63
|
+
}
|
|
64
|
+
set name(value) {
|
|
65
|
+
const name = value.trim().slice(0, 64);
|
|
66
|
+
if (name.length === 0) throw new Error("Layer name cannot be empty");
|
|
67
|
+
this.layerName = name;
|
|
68
|
+
}
|
|
69
|
+
/** Opacity (clamped to 0–1) */
|
|
70
|
+
get opacity() {
|
|
71
|
+
return this.layerOpacity;
|
|
72
|
+
}
|
|
73
|
+
set opacity(value) {
|
|
74
|
+
this.layerOpacity = clampOpacity(value);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get the 2D drawing context of the layer's canvas.
|
|
78
|
+
*/
|
|
79
|
+
get context() {
|
|
80
|
+
const context = this.canvas.getContext("2d");
|
|
81
|
+
if (!context) throw new Error("Layer canvas has no 2D context");
|
|
82
|
+
return context;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Remove all image data from the layer.
|
|
86
|
+
*/
|
|
87
|
+
clear() {
|
|
88
|
+
this.context.clearRect(0, 0, this.width, this.height);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Replace this layer's image data with a copy of another layer's image data.
|
|
92
|
+
*/
|
|
93
|
+
copyImageFrom(source) {
|
|
94
|
+
this.clear();
|
|
95
|
+
this.context.drawImage(source.canvas, 0, 0);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get the layer's settings (without image data).
|
|
99
|
+
*/
|
|
100
|
+
toConfig() {
|
|
101
|
+
return {
|
|
102
|
+
id: this.id,
|
|
103
|
+
name: this.name,
|
|
104
|
+
blendMode: this.blendMode,
|
|
105
|
+
opacity: this.opacity,
|
|
106
|
+
visible: this.visible,
|
|
107
|
+
alphaLock: this.alphaLock
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
export { BlendMode, MAX_LAYER_NAME_LENGTH, clampOpacity, createOffscreenCanvas, Layer as default };
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import type LayerStack from "../LayerStack";
|
|
2
|
+
import type BackgroundWork from "../BackgroundWork";
|
|
3
|
+
import { type LayerStoreLike, type SavedLayer } from "../../storage";
|
|
4
|
+
/** How long to wait after the layers change before saving, so quick changes are saved together (milliseconds) */
|
|
5
|
+
export declare const SAVE_DELAY_MS = 500;
|
|
6
|
+
/** Name of the save in the canvas's background work */
|
|
7
|
+
export declare const SAVE_WORK = "save";
|
|
8
|
+
/** Event dispatched when loading or saving fails (detail: the error) */
|
|
9
|
+
export declare const AUTOSAVE_ERROR_EVENT = "error";
|
|
10
|
+
/** Where autosaving is up to */
|
|
11
|
+
export declare const AutosaveState: {
|
|
12
|
+
/** Waiting to draw (another window may have the drawing) or loading the saved drawing */
|
|
13
|
+
readonly Starting: "starting";
|
|
14
|
+
/** Another window has the drawing; this one doesn't save (see `takeOver`) */
|
|
15
|
+
readonly Elsewhere: "elsewhere";
|
|
16
|
+
/** The saved drawing is shown, and changes are saved */
|
|
17
|
+
readonly Ready: "ready";
|
|
18
|
+
/** Not saving any more (see `stop`) */
|
|
19
|
+
readonly Stopped: "stopped";
|
|
20
|
+
};
|
|
21
|
+
export type AutosaveState = (typeof AutosaveState)[keyof typeof AutosaveState];
|
|
22
|
+
/** The canvas whose layers are saved (`PaintCanvas`) */
|
|
23
|
+
export interface AutosaveCanvas extends EventTarget {
|
|
24
|
+
/** The user's layers (replaced when the canvas size changes, followed by a `change` event) */
|
|
25
|
+
readonly layers: LayerStack;
|
|
26
|
+
/** Slow work that waits for pauses in drawing */
|
|
27
|
+
readonly background: BackgroundWork;
|
|
28
|
+
/** Replace the canvas size and layers with saved ones, drawing each layer's image, and select one */
|
|
29
|
+
restoreLayers(width: number, height: number, layers: readonly SavedLayer[], images: readonly CanvasImageSource[], activeLayer: string): void;
|
|
30
|
+
}
|
|
31
|
+
/** Options for `LayerAutosave` */
|
|
32
|
+
export interface AutosaveOptions {
|
|
33
|
+
/** Makes sure only one window draws on a drawing (the browser's Web Locks by default; none to skip) */
|
|
34
|
+
locks?: LockManager | null;
|
|
35
|
+
/** Tells when the page is hidden or shown again (the page's document by default) */
|
|
36
|
+
document?: Pick<Document, "visibilityState" | "addEventListener" | "removeEventListener"> | null;
|
|
37
|
+
/** Turns a layer's canvas into a PNG (replaceable for tests) */
|
|
38
|
+
encode?: (canvas: OffscreenCanvas) => Promise<Blob>;
|
|
39
|
+
/** Turns a saved PNG into an image to draw (replaceable for tests) */
|
|
40
|
+
decode?: (image: Blob) => Promise<CanvasImageSource>;
|
|
41
|
+
/** How long to wait after the layers change before saving (default `SAVE_DELAY_MS`) */
|
|
42
|
+
delayMs?: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Keeps a canvas's layers in a store, so the drawing survives reloading the page: restores the saved drawing when it
|
|
46
|
+
* starts, then saves soon after the layers change (once drawing pauses), and straight away when the page is hidden.
|
|
47
|
+
* Only layers whose pixels changed are encoded and saved again; a quick fingerprint of each layer's pixels tells
|
|
48
|
+
* which.
|
|
49
|
+
*
|
|
50
|
+
* Only one window draws on a drawing at a time: the first to start has it, and others wait in the `elsewhere` state
|
|
51
|
+
* (the UI blocks drawing there). When the page is shown again it tries again, and `takeOver` takes the drawing from
|
|
52
|
+
* the other window, which then waits instead. Without Web Locks, every window draws.
|
|
53
|
+
*
|
|
54
|
+
* If the saved drawing can't be loaded or restored, autosaving stops (`stopped`) so the drawing isn't saved over; clear
|
|
55
|
+
* the store to start again. Dispatches `change` when its state or `storedBytes` changes, and `error` (detail: the
|
|
56
|
+
* error) when loading or saving fails. Undo history isn't saved.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* const autosave = new LayerAutosave(canvas, new IndexedDbLayerStore("my-drawing"));
|
|
60
|
+
* autosave.start();
|
|
61
|
+
* autosave.addEventListener("change", () => (blocked.hidden = autosave.state !== AutosaveState.Elsewhere));
|
|
62
|
+
*/
|
|
63
|
+
export default class LayerAutosave extends EventTarget {
|
|
64
|
+
/** Where the layers are kept */
|
|
65
|
+
readonly store: LayerStoreLike;
|
|
66
|
+
/** The last loading or saving error, until a save succeeds */
|
|
67
|
+
error?: unknown;
|
|
68
|
+
private currentState;
|
|
69
|
+
private readonly canvas;
|
|
70
|
+
private readonly locks;
|
|
71
|
+
private readonly document;
|
|
72
|
+
private readonly encode;
|
|
73
|
+
private readonly decode;
|
|
74
|
+
private readonly delayMs;
|
|
75
|
+
/** The layers being watched for changes */
|
|
76
|
+
private watched?;
|
|
77
|
+
/** Fingerprints of each layer's pixels as last saved, by layer ID */
|
|
78
|
+
private prints;
|
|
79
|
+
/** Size in bytes of each layer's image as last saved or restored, by layer ID */
|
|
80
|
+
private sizes;
|
|
81
|
+
/** Layers whose pixels changed since the last save */
|
|
82
|
+
private changed;
|
|
83
|
+
/** Whether any layer may have changed since the last save (not only those in `changed`) */
|
|
84
|
+
private checkAll;
|
|
85
|
+
private timer?;
|
|
86
|
+
/** The save being written, if any */
|
|
87
|
+
private saving?;
|
|
88
|
+
/** Whether to save again once the current save finishes */
|
|
89
|
+
private again;
|
|
90
|
+
/** Lets go of the drawing's lock, while held */
|
|
91
|
+
private release?;
|
|
92
|
+
private readonly onLayersChange;
|
|
93
|
+
private readonly onCanvasChange;
|
|
94
|
+
private readonly onVisibilityChange;
|
|
95
|
+
constructor(canvas: AutosaveCanvas, store: LayerStoreLike, options?: AutosaveOptions);
|
|
96
|
+
/** Where autosaving is up to (see `AutosaveState`) */
|
|
97
|
+
get state(): AutosaveState;
|
|
98
|
+
/** Total size in bytes of the layer images kept in the store (as last saved or restored) */
|
|
99
|
+
get storedBytes(): number;
|
|
100
|
+
/** Name of the Web Lock that only one window holds per drawing */
|
|
101
|
+
get lockName(): string;
|
|
102
|
+
/**
|
|
103
|
+
* Start: wait for the drawing (unless another window has it), restore it, then save changes.
|
|
104
|
+
*/
|
|
105
|
+
start(): void;
|
|
106
|
+
/**
|
|
107
|
+
* Take the drawing from the window that has it: that window stops saving, and this one restores the drawing as last
|
|
108
|
+
* saved and saves its changes. Does nothing unless another window has it.
|
|
109
|
+
*/
|
|
110
|
+
takeOver(): void;
|
|
111
|
+
/**
|
|
112
|
+
* Stop saving and let other windows have the drawing, after saving any changes not saved yet.
|
|
113
|
+
*/
|
|
114
|
+
stop(): Promise<void>;
|
|
115
|
+
/**
|
|
116
|
+
* Save the changes not saved yet now, without waiting. While a save is being written, another follows it.
|
|
117
|
+
*/
|
|
118
|
+
save(): Promise<void>;
|
|
119
|
+
/**
|
|
120
|
+
* Ask for the drawing's lock, if there are locks: only if no other window has it, or taking it from the one that
|
|
121
|
+
* does. Without locks, start straight away.
|
|
122
|
+
*/
|
|
123
|
+
private claim;
|
|
124
|
+
/**
|
|
125
|
+
* Restore the saved drawing (if any), then watch for changes; with nothing saved, the current drawing is saved. If
|
|
126
|
+
* the saved drawing can't be loaded or restored (e.g. it's from another version, or an image can't be decoded),
|
|
127
|
+
* autosaving stops instead, so it isn't saved over.
|
|
128
|
+
*/
|
|
129
|
+
private begin;
|
|
130
|
+
/**
|
|
131
|
+
* Draw a saved drawing onto the canvas. Returns false if autosaving stopped or another window took the drawing
|
|
132
|
+
* meanwhile. Throws if the drawing is incomplete or from another version, or the canvas can't take it.
|
|
133
|
+
*/
|
|
134
|
+
private restore;
|
|
135
|
+
/**
|
|
136
|
+
* Remember each layer's pixels as saved (just restored).
|
|
137
|
+
*/
|
|
138
|
+
private remember;
|
|
139
|
+
/**
|
|
140
|
+
* Save the drawing, encoding only the layers whose pixels changed since they were last saved.
|
|
141
|
+
*/
|
|
142
|
+
private write;
|
|
143
|
+
/**
|
|
144
|
+
* Remember the sizes of the layer images just saved, forgetting layers that are gone, and tell listeners if the total
|
|
145
|
+
* changed.
|
|
146
|
+
*/
|
|
147
|
+
private rememberSizes;
|
|
148
|
+
/**
|
|
149
|
+
* A fingerprint of a layer's pixels.
|
|
150
|
+
*/
|
|
151
|
+
private fingerprint;
|
|
152
|
+
/**
|
|
153
|
+
* Save once the layers have stopped changing for a moment and drawing pauses.
|
|
154
|
+
*/
|
|
155
|
+
private schedule;
|
|
156
|
+
/**
|
|
157
|
+
* Watch the canvas and its current layers for changes.
|
|
158
|
+
*/
|
|
159
|
+
private watch;
|
|
160
|
+
/**
|
|
161
|
+
* Stop watching for changes, forgetting a save that hasn't started.
|
|
162
|
+
*/
|
|
163
|
+
private unwatch;
|
|
164
|
+
/**
|
|
165
|
+
* Another window took the drawing: stop saving and wait.
|
|
166
|
+
*/
|
|
167
|
+
private lostLock;
|
|
168
|
+
/**
|
|
169
|
+
* Let other windows have the drawing.
|
|
170
|
+
*/
|
|
171
|
+
private letGo;
|
|
172
|
+
/**
|
|
173
|
+
* Remember an error and tell listeners.
|
|
174
|
+
*/
|
|
175
|
+
private fail;
|
|
176
|
+
/**
|
|
177
|
+
* Change state and tell listeners.
|
|
178
|
+
*/
|
|
179
|
+
private setState;
|
|
180
|
+
}
|