basic block editor in main brush, better brush preview

This commit is contained in:
Hugh Bord 2021-08-07 15:36:32 +10:00
parent a5ccdbca23
commit 4439b3b0bb
9 changed files with 639 additions and 259 deletions

View File

@ -19,17 +19,13 @@
* If you resize an ascii, and then undo and try fill in blocks it will error cuz the blocks don't exist
* Redo (ctrl y) is a buggy
* Circle brush (works okay for odd width and height numbers)
* Select only works from dragging top left to bottom right, not the other way around
# FOCUSING ON NOW
* Cut / copy then paste with ctrl v
* drawBrush preview flip / rotate
* Type letter when choosing char, leave char panel open after
* close tabs
* Edit brush
* SELECT TOOL DEV
* Reverse select bug fix needed
* Enhance how the select tool looks and and make selected blocks more obvious
* Modals
* Edit current ascii
@ -38,10 +34,8 @@
* OPTIONS MODAL (SORRY SKG LOL)
* Encodings - UTF8 vs NOT that
* Context Menus (right click menu) - we started this
* Keyboard shortcuts
* LAYERS
# Keyboard Shortcuts

View File

@ -138,7 +138,7 @@ export default {
NewAscii,
EditAscii,
PasteAscii,
BrushLibrary
BrushLibrary,
},
name: "Dashboard",
data: () => ({

View File

@ -16,63 +16,73 @@
<t-button
type="button"
:class="`block w-full ${
tab === 1
panel.tab === 1
? 'border-gray-900 bg-blue-500'
: 'border-gray-200 bg-gray-500'
}`"
@click="tab = 1"
@click="changeTab(1)"
>Library</t-button
>
<t-button
type="button"
:class="`block w-full ${
tab === 0
panel.tab === 0
? 'border-gray-900 bg-blue-500'
: 'border-gray-200 bg-gray-500'
}`"
@click="tab = 0"
@click="changeTab(0)"
>History</t-button
>
<div class="flex">
<div v-if="tab === 0">
<div v-if="panel.tab === 0">
<div v-for="(brush, key) in brushHistory" :key="key">
<t-card
:class="`hover:border-blue-900 border-gray-300 bg-gray-200`"
>
<t-card class="hover:border-blue-900 border-gray-300 bg-gray-200">
<BrushCanvas :blocks="decompressBlock(brush.blocks)" />
<t-button
type="button"
@click="saveToLibrary(decompressBlock(brush.blocks))"
><font-awesome-icon :icon="['fas', 'save']" size="lg"
><font-awesome-icon
:icon="['fas', 'save']"
size="lg"
class="p-1 mx-1"
/></t-button>
<t-button
type="button"
@click="reuseBlocks(decompressBlock(brush.blocks))"
><font-awesome-icon :icon="['fas', 'paint-brush']" size="lg"
><font-awesome-icon
:icon="['fas', 'paint-brush']"
size="lg"
class="p-1 mx-1"
/></t-button>
</t-card>
</div>
</div>
<div v-if="tab === 1">
<div v-if="panel.tab === 1">
<div v-for="(brush, key) in brushLibrary" :key="key">
<t-card
:class="`hover:border-blue-900 border-gray-300 bg-gray-200`"
>
<BrushCanvas :blocks="decompressBlock(brush.blocks)" />
<t-button
type="button"
@click="removeFromLibrary(decompressBlock(brush.blocks))"
><font-awesome-icon :icon="['fas', 'trash']" size="lg"
><font-awesome-icon
:icon="['fas', 'trash']"
size="lg"
class="p-1 mx-1"
/></t-button>
<t-button
type="button"
@click="reuseBlocks(decompressBlock(brush.blocks))"
><font-awesome-icon :icon="['fas', 'paint-brush']" size="lg"
><font-awesome-icon
:icon="['fas', 'paint-brush']"
size="lg"
class="p-1 mx-1"
/></t-button>
</t-card>
</div>
@ -95,15 +105,16 @@ export default {
this.panel.y = this.brushLibraryState.y;
this.panel.w = this.brushLibraryState.w;
this.panel.h = this.brushLibraryState.h;
this.panel.tab = this.brushLibraryState.tab;
},
data: () => ({
tab: 1,
panel: {
w: 0,
h: 0,
x: 100,
y: 100,
visible: true,
tab: 1,
},
}),
components: {
@ -171,13 +182,15 @@ export default {
watch: {},
methods: {
changeTab(tab) {
this.tab = tab;
this.panel.tab = tab;
this.$store.commit("changeBrushLibraryState", this.panel);
},
decompressBlock(item) {
return JSON.parse(LZString.decompressFromUTF16(item));
},
reuseBlocks(value) {
this.$store.commit("brushBlocks", value);
this.$store.commit("changeTool", 4);
},
saveToLibrary(value) {
this.$store.commit("pushBrushLibrary", value);
@ -190,14 +203,13 @@ export default {
this.panel.y = y;
this.panel.w = w;
this.panel.h = h;
this.$store.commit('changeBrushLibraryState', this.panel);
this.$store.commit("changeBrushLibraryState", this.panel);
},
onDragStop(x, y) {
this.panel.x = x;
this.panel.y = y;
this.$store.commit('changeBrushLibraryState', this.panel);
this.$store.commit("changeBrushLibraryState", this.panel);
},
},
};

View File

@ -12,6 +12,7 @@
:h="toolbarState.h"
:x="toolbarState.x"
:y="toolbarState.y"
:draggable="draggable"
>
<t-card class="h-full">
<Colours />
@ -158,6 +159,9 @@ export default {
currentChar() {
return this.$store.getters.currentChar;
},
draggable() {
return this.toolbarState.draggable;
},
},
watch: {},
methods: {

View File

@ -7,7 +7,6 @@
:width="blocksWidthHeight.w"
:height="blocksWidthHeight.h"
/>
</t-card>
</div>

View File

@ -34,43 +34,34 @@
</label>
<label class="block">
<t-radio
name="options"
value="circle"
v-model="brushSizeTypeInput"
/>
<t-radio name="options" value="circle" v-model="brushSizeTypeInput" />
<span class="text-sm">Circle</span>
</label>
<label class="block">
<t-radio
name="options"
value="cross"
v-model="brushSizeTypeInput"
/>
<t-radio name="options" value="cross" v-model="brushSizeTypeInput" />
<span class="text-sm">Cross</span>
</label>
</div>
<BrushCanvas />
<MainBrushCanvas />
</div>
</template>
<script>
import { emptyBlock } from "../../ascii";
import BrushCanvas from "./BrushCanvas.vue"
import MainBrushCanvas from "./MainBrushCanvas.vue";
export default {
name: "BrushPreview",
components: {
BrushCanvas,
MainBrushCanvas,
},
mounted() {
this.brushSizeWidthInput = this.brushSizeWidth;
this.brushSizeHeightInput = this.brushSizeHeight;
this.brushSizeTypeInput = this.brushSizeType;
this.createBlocks()
this.createBlocks();
},
data: () => ({
blocks: [],
@ -98,11 +89,11 @@ export default {
return this.$store.getters.brushSizeType;
},
currentAsciiBlocks() {
return this.$store.getters.currentAsciiBlocks
return this.$store.getters.currentAsciiBlocks;
},
brushBlocks() {
return this.$store.getters.brushBlocks
}
return this.$store.getters.brushBlocks;
},
},
watch: {
brushSizeWidth() {
@ -116,38 +107,37 @@ export default {
},
brushSizeHeightInput(val, old) {
if (val !== old) {
this.createBlocks()
}
this.createBlocks();
}
},
brushSizeWidthInput(val, old) {
if (val !== old) {
this.createBlocks()
}
this.createBlocks();
}
},
brushSizeTypeInput(val, old) {
if (val !== old) {
this.createBlocks()
}
this.createBlocks();
}
},
currentChar(val, old) {
if (val !== old) {
this.createBlocks()
}
this.createBlocks();
}
},
currentBg(val, old) {
if (val !== old) {
this.createBlocks()
}
this.createBlocks();
}
},
currentFg(val, old) {
if (val !== old) {
this.createBlocks()
}
this.createBlocks();
}
},
brushBlocks() {
this.$store.commit("pushBrushHistory", this.brushBlocks)
}
this.$store.commit("pushBrushHistory", this.brushBlocks);
},
},
methods: {
updateBrushSize() {
@ -158,7 +148,7 @@ export default {
});
},
createBlocks() {
this.updateBrushSize()
this.updateBrushSize();
const brushHeight = this.brushSizeHeight;
const brushWidth = this.brushSizeWidth;
@ -178,7 +168,7 @@ export default {
const middleX = Math.floor(brushWidth / 2);
let yModifier = 0;
//
//
// Recreate 2d array for preview
for (y = 0; y < brushHeight; y++) {
@ -239,13 +229,13 @@ export default {
this.blocks[y][x] = { ...emptyBlock };
}
}
break;
}
}
}
this.$store.commit("brushBlocks", this.blocks)
this.$store.commit("brushBlocks", this.blocks);
},
},
};

View File

@ -0,0 +1,289 @@
<template>
<div>
<t-card>
<canvas
ref="brushcanvas"
id="brushcanvas"
class="brushcanvas"
@mousemove="canvasMouseMove"
@mouseup="disable"
@mousedown.left="addBlock"
@mousedown.right="eraseBlock"
@contextmenu.prevent
:width="blocksWidthHeight.w"
:height="blocksWidthHeight.h"
@mouseenter="disableToolbarMoving"
@mouseleave="enableToolbarMoving"
/>
</t-card>
</div>
</template>
<style>
body {
background: #eee;
}
.brushcanvastools {
position: absolute;
z-index: 100;
opacity: 0.5;
cursor: crosshair;
}
.brushcanvas {
position: absolute;
background: rgba(0, 0, 0, 0.8);
border: lightgrey 1px solid;
z-index: 0;
}
</style>
<script>
import {
mircColours99,
blockWidth,
blockHeight,
getBlocksWidth,
filterNullBlocks,
} from "../../ascii";
export default {
name: "MainBrushCanvas",
mounted() {
this.ctx = this.$refs.brushcanvas.getContext("2d");
this.delayRedrawCanvas();
},
data: () => ({
ctx: null,
redraw: true,
erasing: false,
drawing: false,
x: 0,
y: 0,
}),
computed: {
currentAscii() {
return this.$store.getters.currentAscii;
},
toolbarState() {
return this.$store.getters.toolbarState;
},
isTargettingBg() {
return this.$store.getters.isTargettingBg;
},
isTargettingFg() {
return this.$store.getters.isTargettingFg;
},
isTargettingChar() {
return this.$store.getters.isTargettingChar;
},
canFg() {
return this.$store.getters.isTargettingFg;
},
canBg() {
return this.$store.getters.isTargettingBg;
},
canText() {
return this.$store.getters.isTargettingChar;
},
currentFg() {
return this.$store.getters.currentFg;
},
currentBg() {
return this.$store.getters.currentBg;
},
currentChar() {
return this.$store.getters.currentChar;
},
brushSizeHeight() {
return this.$store.getters.brushSizeHeight;
},
brushSizeWidth() {
return this.$store.getters.brushSizeWidth;
},
brushSizeType() {
return this.$store.getters.brushSizeType;
},
options() {
return this.$store.getters.options;
},
brushBlocks() {
return this.$store.getters.brushBlocks;
},
blocksWidthHeight() {
return {
w: this.getBlocksWidth(this.brushBlocks) * blockWidth,
h: this.brushBlocks.length * blockHeight,
};
},
mircColours() {
return mircColours99;
},
},
watch: {
brushBlocks() {
this.delayRedrawCanvas();
},
currentAscii() {
this.delayRedrawCanvas();
},
brushSizeHeight() {
this.delayRedrawCanvas();
},
brushSizeWidth() {
this.delayRedrawCanvas();
},
isTargettingBg() {
this.delayRedrawCanvas();
},
isTargettingFg() {
this.delayRedrawCanvas();
},
isTargettingChar() {
this.delayRedrawCanvas();
},
currentFg() {
this.delayRedrawCanvas();
},
currentBg() {
this.delayRedrawCanvas();
},
currentChar() {
this.delayRedrawCanvas();
},
},
methods: {
getBlocksWidth(blocks) {
return getBlocksWidth(blocks);
},
filterNullBlocks(blocks) {
return filterNullBlocks(blocks);
},
drawPreview() {
this.ctx.clearRect(0, 0, 10000, 10000);
this.ctx.fillStyle = this.mircColours[1];
const BLOCK_WIDTH = this.currentAscii.blockWidth;
const BLOCK_HEIGHT = this.currentAscii.blockHeight;
// hack font for ascii shout outs 2 beenz
this.ctx.font = "13px Hack";
let y = 0;
let x = 0;
// Get middle block
if (this.brushBlocks) {
let blocksWidth = this.getBlocksWidth(this.brushBlocks);
for (y = 0; y < this.brushBlocks.length; y++) {
for (x = 0; x < blocksWidth; x++) {
if (this.brushBlocks[y] && this.brushBlocks[y][x]) {
const curBlock = this.brushBlocks[y][x];
if (curBlock.bg !== null && this.isTargettingBg) {
this.ctx.fillStyle = this.mircColours[curBlock.bg];
this.ctx.fillRect(
x * BLOCK_WIDTH,
y * BLOCK_HEIGHT,
BLOCK_WIDTH,
BLOCK_HEIGHT
);
}
if (curBlock.fg !== null && this.isTargettingFg) {
this.ctx.fillStyle = this.mircColours[curBlock.fg];
}
if (curBlock.char !== null && this.isTargettingChar) {
this.ctx.fillStyle = this.mircColours[curBlock.fg];
this.ctx.fillText(
curBlock.char,
x * BLOCK_WIDTH - 1,
y * BLOCK_HEIGHT + BLOCK_HEIGHT - 3
);
}
}
}
}
this.ctx.stroke();
}
},
delayRedrawCanvas() {
if (this.redraw) {
this.redraw = false;
setTimeout(() => {
this.redraw = true;
this.drawPreview();
}, this.options.canvasRedrawSpeed);
}
},
// Basic block editing
canvasMouseMove(e) {
if (e.offsetX >= 0) {
this.x = e.offsetX;
}
if (e.offsetY >= 0) {
this.y = e.offsetY;
}
this.x = Math.floor(this.x / blockWidth);
this.y = Math.floor(this.y / blockHeight);
if (this.erasing) {
this.brushBlocks[this.y][this.x] = {
bg: this.canBg ? null : this.currentFg,
fg: this.canFg ? null : this.currentBg,
char: this.canText ? null : this.currentChar,
};
}
if (this.drawing) {
this.brushBlocks[this.y][this.x] = {
bg: this.canBg ? this.currentBg : null,
fg: this.canFg ? this.currentFg : null,
char: this.canText ? this.currentChar : null,
};
}
this.delayRedrawCanvas();
},
disable() {
this.erasing = false;
this.drawing = false;
},
addBlock() {
this.drawing = true;
this.brushBlocks[this.y][this.x] = {
bg: this.canBg ? this.currentBg : null,
fg: this.canFg ? this.currentFg : null,
char: this.canText ? this.currentChar : null,
};
},
eraseBlock(e) {
this.erasing = true;
this.brushBlocks[this.y][this.x] = {
bg: this.canBg ? null : this.currentFg,
fg: this.canFg ? null : this.currentBg,
char: this.canText ? null : this.currentChar,
};
},
disableToolbarMoving() {
this.$store.commit("changeToolBarDraggable", false);
},
enableToolbarMoving() {
// Save the blocks when the mouse leaves the canvas area
// To avoid one block history changes
this.disable()
this.$store.commit("brushBlocks", this.brushBlocks);
this.$store.commit("changeToolBarDraggable", true);
},
},
};
</script>

View File

@ -56,6 +56,7 @@ export default new Vuex.Store({
y: blockHeight * 2,
h: blockHeight * 39,
w: blockWidth * 25,
draggable: true,
},
debugPanelState: {
x: 936,
@ -75,6 +76,7 @@ export default new Vuex.Store({
h: blockHeight * 50,
w: blockWidth * 25,
visible: true,
tab: 0,
},
},
mutations: {
@ -102,6 +104,9 @@ export default new Vuex.Store({
state.toolbarState.w = payload.w;
state.toolbarState.h = payload.h;
},
changeToolBarDraggable(state, payload) {
state.toolbarState.draggable = payload;
},
changeAsciiWidthHeight(state, payload) {
state.asciibirdMeta[state.tab].width = payload.width;
state.asciibirdMeta[state.tab].height = payload.height;

File diff suppressed because it is too large Load Diff