basic block editor in main brush, better brush preview
This commit is contained in:
parent
a5ccdbca23
commit
4439b3b0bb
|
@ -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
|
||||
|
|
|
@ -138,7 +138,7 @@ export default {
|
|||
NewAscii,
|
||||
EditAscii,
|
||||
PasteAscii,
|
||||
BrushLibrary
|
||||
BrushLibrary,
|
||||
},
|
||||
name: "Dashboard",
|
||||
data: () => ({
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
:width="blocksWidthHeight.w"
|
||||
:height="blocksWidthHeight.h"
|
||||
|
||||
/>
|
||||
</t-card>
|
||||
</div>
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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>
|
|
@ -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
Loading…
Reference in New Issue