Skip to content

Commit 436d8c3

Browse files
author
Mikahil Ilin
committed
Draw UX improvements, ignored layer color, pen-draw refactoring, layer ids, setBitmapMode for transparency
1 parent 6ddcbdf commit 436d8c3

File tree

9 files changed

+622
-588
lines changed

9 files changed

+622
-588
lines changed

app.js

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Vue.createApp({
88
screenElements: [],
99
currentLayer: null,
1010

11-
activeTool: "pen",
11+
activeTool: "draw",
1212
activeTab: "code",
1313

1414
isInverted: false,
@@ -37,6 +37,9 @@ Vue.createApp({
3737
// this.screenElements = JSON.parse(localStorage.getItem("lopaka_layers")) ?? [];
3838
},
3939
mounted() {
40+
if (this.isFlipper) {
41+
this.activeTool = "frame";
42+
}
4043
if (this.screenElements.length) {
4144
this.updateCode();
4245
this.layerIndex = this.screenElements.length;
@@ -45,7 +48,6 @@ Vue.createApp({
4548
methods: {
4649
setactiveTab(tab) {
4750
this.activeTab = tab;
48-
this.updateCode();
4951
},
5052
prepareImages(e) {
5153
this.fuiImages = e;
@@ -146,23 +148,25 @@ Vue.createApp({
146148
selectLibrary(library) {
147149
this.library = library;
148150
if (library === "flipper") {
151+
if (this.activeTool === "draw") {
152+
this.activeTool = "frame";
153+
};
149154
this.display = "128×64";
150155
localStorage.setItem("lopaka_display", this.display);
151156
}
152157
this.updateCode();
153158
localStorage.setItem("lopaka_library", library);
154159
},
155160
updateCode() {
156-
if (this.activeTab === "code") {
157-
const context = this.$refs.fuiCanvas.$refs.screen.getContext("2d", {
158-
willReadFrequently: true,
159-
});
160-
this.codePreview = generateCode(
161-
this.screenElements,
162-
this.library,
163-
context
164-
);
165-
}
161+
const context = this.$refs.fuiCanvas.$refs.screen.getContext("2d", {
162+
willReadFrequently: true,
163+
});
164+
this.codePreview = generateCode(
165+
this.screenElements,
166+
this.library,
167+
context,
168+
this.imageDataCache,
169+
);
166170
},
167171
saveLayers() {
168172
// localStorage.setItem(

index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
<div id="lopaka_app"></div>
2424
<script src="https://unpkg.com/vue@3.2.37/dist/vue.global.prod.js" type="text/javascript"></script>
2525
<script src="js/utils.js?v=0.3" type="text/javascript"></script>
26+
<script src="js/graphics.js?v=0.3" type="text/javascript"></script>
2627
<script src="js/const.js?v=0.3" type="text/javascript"></script>
2728
<script src="js/templates.js?v=0.3" type="text/javascript"></script>
2829
<script src="js/fui-canvas.js?v=0.3" type="text/javascript"></script>

js/components.js

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ const fuiLayersComponent = {
44
screenElements: Array,
55
currentLayer: Object,
66
},
7+
computed: {
8+
classNames() {
9+
return (item) => ({
10+
layer_selected: this.currentLayer && this.currentLayer.index === item.index,
11+
layer_ignored: item.isOverlay,
12+
});
13+
}
14+
},
715
methods: {
816
updateCurrentLayer(item) {
917
this.$emit("updateCurrentLayer", item);
@@ -148,11 +156,12 @@ const fuiToolsComponent = {
148156
props: {
149157
callback: Function,
150158
activeTool: String,
159+
library: String,
151160
},
152-
data() {
153-
return {
154-
toolsList: ["pen", "frame", "box", "line", "dot", "circle", "disc"],
155-
};
161+
computed: {
162+
toolsList() {
163+
return [...(this.library !== "flipper" ? ["draw"] : []), "frame", "box", "line", "dot", "circle", "disc"];
164+
},
156165
},
157166
};
158167

@@ -165,22 +174,29 @@ const fuiInspectorComponent = {
165174
data() {
166175
return {};
167176
},
177+
computed: {
178+
isHWVisible() {
179+
// return true;
180+
return ["frame", "box", "draw", "icon"].includes(
181+
this.elem.type
182+
);
183+
},
184+
isHWDisabled() {
185+
return ["draw", "icon"].includes(
186+
this.elem.type
187+
);
188+
},
189+
isRadiusVisible() {
190+
return ["circle", "disc"].includes(this.elem.type);
191+
},
192+
},
168193
methods: {
169194
update(element) {
170195
this.$emit("updateCurrentLayer", element);
171196
this.$emit("redrawCanvas");
172197
this.$emit("saveLayers");
173198
this.$emit("updateCode");
174199
},
175-
isHWVisible(elem) {
176-
// return true;
177-
return !["line", "str", "dot", "icon", "circle", "disc"].includes(
178-
elem.type
179-
);
180-
},
181-
isRadiusVisible(elem) {
182-
return ["circle", "disc"].includes(elem.type);
183-
},
184200
},
185201
};
186202

@@ -191,14 +207,15 @@ const fuiInspectorInputComponent = {
191207
<option v-for="(font, idx) in fontsList[library]" :key="idx" :value="font">{{ font }}</option>
192208
</select>
193209
<input v-else-if="type === 'checkbox'" class="inspector__input" @input="onInput" :type="type" :id="id" :checked="element[field]"></input>
194-
<input v-else class="inspector__input" @input="onInput" :value="element[field]" :type="type" :id="id" max="1024" min="-1024" step="1"></input>
210+
<input v-else class="inspector__input" @input="onInput" :value="element[field]" :type="type" :id="id" max="1024" min="-1024" step="1" :disabled="disabled"></input>
195211
`,
196212
props: {
197213
element: Object,
198214
type: String,
199215
field: String,
200216
library: String,
201217
id: String,
218+
disabled: Boolean,
202219
},
203220
computed: {
204221
hasNoWidth() {

js/const.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,4 +306,5 @@ const KEYS = {
306306
DOWN: 40,
307307
LEFT: 37,
308308
RIGHT: 39,
309+
ESC: 27,
309310
}

js/fui-canvas.js

Lines changed: 36 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const fuiCanvasComponent = {
2424
currentLayer: Object,
2525
fuiImages: Array,
2626
imageDataCache: Object,
27+
library: String,
2728
},
2829
data() {
2930
return {
@@ -48,7 +49,7 @@ const fuiCanvasComponent = {
4849
return {
4950
"fui-canvas_select": this.activeTool === "select",
5051
"fui-canvas_moving": this.isMoving,
51-
"fui-canvas_draw": this.activeTool === "pen",
52+
"fui-canvas_draw": this.activeTool === "draw",
5253
};
5354
},
5455
canvasWidth() {
@@ -77,7 +78,7 @@ const fuiCanvasComponent = {
7778

7879
document.addEventListener("mouseup", this.canvasMouseUp);
7980
this.$refs.screen.addEventListener("contextmenu", (event) => {
80-
if (this.isDrawing || this.isMoving || this.activeTool === "pen") {
81+
if (this.isDrawing || this.isMoving || this.activeTool === "draw") {
8182
event.preventDefault();
8283
}
8384
});
@@ -118,11 +119,10 @@ const fuiCanvasComponent = {
118119
},
119120
canvasMouseDown(e) {
120121
e.preventDefault();
121-
const isRightClickDrawing = this.activeTool === "pen" && e.button === 2;
122+
const isRightClickDrawing = this.activeTool === "draw" && e.button === 2;
122123
if (e.button !== 0 && !isRightClickDrawing || this.isDrawing || this.isMoving) {
123124
return;
124125
}
125-
let layerProps = {};
126126
const [x, y] = [e.offsetX, e.offsetY];
127127
this.oX = scaleDown(x);
128128
this.oY = scaleDown(y);
@@ -131,54 +131,28 @@ const fuiCanvasComponent = {
131131
this.isDrawing = true;
132132
this.isEraser = e.button === 2;
133133

134-
if (this.currentLayer && this.currentLayer.type !== "pen" || this.activeTool === "select") {
134+
if (this.currentLayer && this.currentLayer.type !== "draw" || this.activeTool === "select") {
135135
this.$emit("updateCurrentLayer", undefined);
136136
}
137-
layerProps = {
138-
name: "",
137+
const uid = generateUID();
138+
let layerProps = {
139+
name: `${this.activeTool}_${uid}`,
139140
type: this.activeTool,
140141
index: this.layerIndex,
141142
x: scaleDown(x),
142143
y: scaleDown(y),
144+
id: uid,
143145
};
144146

145-
if (["pen"].includes(this.activeTool)) {
146-
if (this.currentLayer && this.currentLayer.type === "pen") {
147-
layerProps = {
148-
...this.currentLayer,
149-
imageData: addImageDataPadding(this.currentLayer.imageData, this.currentLayer.x, this.currentLayer.y, this.canvasWidth, this.canvasHeight),
150-
x: this.currentLayer.x > 0 ? 0 : this.currentLayer.x,
151-
y: this.currentLayer.y > 0 ? 0 : this.currentLayer.y,
152-
width: this.currentLayer.imageData.width,
153-
height: this.currentLayer.imageData.height,
154-
}
155-
this.$emit("updateCurrentLayer", layerProps);
156-
} else {
157-
layerProps.x = 0;
158-
layerProps.y = 0;
159-
const imageDataArraylength = 4 * this.canvasWidth * this.canvasHeight;
160-
layerProps.imageData = new ImageData(
161-
new Uint8ClampedArray(imageDataArraylength),
162-
this.canvasWidth,
163-
this.canvasHeight,
164-
);
165-
this.$emit("updateCurrentLayer", {
166-
...layerProps,
167-
width: layerProps.imageData.width,
168-
height: layerProps.imageData.height,
169-
});
170-
this.$emit("addScreenLayer");
147+
if (["draw"].includes(this.activeTool)) {
148+
const isDrawingCurrent = this.currentLayer && this.currentLayer.type === "draw";
149+
150+
layerProps = startDrawing(isDrawingCurrent, layerProps, this.currentLayer, this.canvasWidth, this.canvasHeight, this.oX, this.oY, this.isEraser);
151+
152+
this.$emit("updateCurrentLayer", layerProps);
153+
if (!isDrawingCurrent) {
154+
this.$emit("addScreenLayer", layerProps);
171155
}
172-
drawingLayer = this.currentLayer ? this.currentLayer : layerProps;
173-
drawLine(drawingLayer.imageData,
174-
this.oX - drawingLayer.x,
175-
this.oY - drawingLayer.y,
176-
this.oX - drawingLayer.x,
177-
this.oY - drawingLayer.y,
178-
drawingLayer.imageData.width,
179-
drawingLayer.imageData.height,
180-
this.isEraser,
181-
);
182156
} else if (["frame", "box", "dot", "circle", "disc"].includes(this.activeTool)) {
183157
this.$emit("updateCurrentLayer", {
184158
...layerProps,
@@ -281,7 +255,7 @@ const fuiCanvasComponent = {
281255
layerProps.x = scaleDown(x);
282256
layerProps.y = scaleDown(y);
283257
}
284-
} else if (this.activeTool === "pen") {
258+
} else if (this.activeTool === "draw") {
285259
drawLine(this.currentLayer.imageData,
286260
this.oX - this.currentLayer.x,
287261
this.oY - this.currentLayer.y,
@@ -334,7 +308,7 @@ const fuiCanvasComponent = {
334308
canvasMouseLeave(e) {
335309
e.preventDefault();
336310
// this.$refs.cursor.style.transform = `translate3d(-1000px, -1000px, 0)`;
337-
if (["select", "pen"].includes(this.activeTool) && this.isMoving) {
311+
if (["select", "draw"].includes(this.activeTool) && this.isMoving) {
338312
this.isDrawing = false;
339313
this.stopDrawing(e);
340314
}
@@ -350,7 +324,9 @@ const fuiCanvasComponent = {
350324
this.stopDrawing(e);
351325
this.isDrawing = false;
352326
}
353-
this.redrawCanvas(this.screenElements);
327+
if (this.isDrawing || this.isMoving) {
328+
this.redrawCanvas(this.screenElements);
329+
}
354330
},
355331
stopDrawing() {
356332
this.isEraser = false;
@@ -377,15 +353,7 @@ const fuiCanvasComponent = {
377353
}
378354
const { isCustom, width, height } = this.fuiImages[name];
379355
const layer = {
380-
type: "icon",
381-
name: name,
382-
index: this.layerIndex,
383-
x: x,
384-
y: y,
385-
width: width,
386-
height: height,
387-
isOverlay: false,
388-
isCustom: isCustom,
356+
type: "icon", name: name, index: this.layerIndex, x: x, y: y, width: width, height: height, isOverlay: false, isCustom: isCustom,
389357
};
390358
this.$emit("updateCurrentLayer", layer);
391359
this.$emit("addScreenLayer", layer);
@@ -419,46 +387,23 @@ const fuiCanvasComponent = {
419387
}
420388
break;
421389
case "line":
422-
drawLine(
423-
imgData,
424-
x,
425-
y,
426-
x2,
427-
y2,
428-
this.canvasWidth,
429-
this.canvasHeight,
430-
this.scale
431-
);
390+
drawLine(imgData, x, y, x2, y2, this.canvasWidth, this.canvasHeight, false);
432391
this.CTX.putImageData(imgData, 0, 0);
433392
break;
434393
case "circle":
435-
drawCircle(
436-
imgData,
437-
x + radius,
438-
y + radius,
439-
radius,
440-
this.canvasWidth,
441-
this.canvasHeight
442-
);
394+
drawCircle(imgData, x + radius, y + radius, radius, this.canvasWidth, this.canvasHeight);
443395
this.CTX.putImageData(imgData, 0, 0);
444396
break;
445397
case "disc":
446-
drawDisc(
447-
imgData,
448-
x + radius,
449-
y + radius,
450-
radius,
451-
this.canvasWidth,
452-
this.canvasHeight
453-
);
398+
drawDisc(imgData, x + radius, y + radius, radius, this.canvasWidth, this.canvasHeight);
454399
this.CTX.putImageData(imgData, 0, 0);
455400
break;
456401
case "str":
457402
const fontSize = fontSizes[font];
458403
this.CTX.font = `${fontSize}px ${font}`;
459404
this.CTX.fillText(text, x, y);
460405
break;
461-
case "pen":
406+
case "draw":
462407
const newImageData = maskAndMixImageData(imgData, screenElement.imageData, x, y);
463408
this.CTX.putImageData(newImageData, 0, 0);
464409
break;
@@ -469,10 +414,17 @@ const fuiCanvasComponent = {
469414
this.CTX.restore();
470415
},
471416
keyDownHandler(event) {
472-
if (event.isComposing || event.target !== document.body) {
417+
if (event.isComposing || !Object.values(KEYS).includes(event.keyCode)) {
418+
return;
419+
}
420+
if (event.keyCode === KEYS.ESC) {
421+
this.$emit("updateCurrentLayer");
422+
return;
423+
}
424+
if (event.target !== document.body) {
473425
return;
474426
}
475-
if (this.currentLayer && Object.values(KEYS).includes(event.keyCode)) {
427+
if (this.currentLayer) {
476428
event.preventDefault();
477429
const shift = event.shiftKey ? 10 : 1;
478430
switch (event.keyCode) {

0 commit comments

Comments
 (0)