LAYERS (wip) - brushing preview broken
This commit is contained in:
parent
a168d1cf8d
commit
4c38f83503
10
README.md
10
README.md
|
@ -64,17 +64,17 @@ ASCIIBIRD is mostly usable. There are some bugs however to note at the moment.
|
|||
* Redo (ctrl y) is a buggy
|
||||
* Circle brush (works okay for odd width and height numbers)
|
||||
* Importer could be re-written with regex
|
||||
|
||||
* Exporter will default transparent bg to black by default, which wont for some asciis
|
||||
## Focusing on Now
|
||||
|
||||
* Modals to add
|
||||
* Asciibird options / Options modal from skgs PR
|
||||
|
||||
* Review encodings check on file import - UTF8 vs Latin something
|
||||
* Context Menus (right click menu) - add to other areas of asciibird
|
||||
* LAYERS, drag and drop to arrange layers
|
||||
* Image overlay for trace mode
|
||||
|
||||
* Experimental code to only render blocks visible on screen
|
||||
* Review encodings check on file import - UTF8 vs Latin something
|
||||
# Keyboard Shortcuts
|
||||
|
||||
## ASCII Editing
|
||||
|
@ -92,7 +92,7 @@ Until the keyboard shortcuts are moved out of `Editor.vue` they will only work w
|
|||
* When the colour picker is open, the first 0 to 9 colours can be chosen with the keyboards number.
|
||||
* When the character picker is open, you can also press any key on your keyboard to set the character.
|
||||
|
||||
## Toolbar Keyboard Shortcusts
|
||||
## Toolbar Keyboard Shortcuts
|
||||
The toolbar keyboard shorts are used with the ALT key.
|
||||
|
||||
* Alt 1 to 8 - Will toggle the corresponding toolbar icon
|
||||
|
@ -118,7 +118,7 @@ The toolbar keyboard shorts are used with the ALT key.
|
|||
|
||||
* Ctrl + c - Copy blocks to clipboard
|
||||
* Ctrl + x - Cut blocks to clipboard
|
||||
* Ctrl + v - Paste blocks
|
||||
* Ctrl + v - Paste blocks as brush
|
||||
* Delete - Delete selected blocks
|
||||
|
||||
### Brush Mode Only
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
"vue-draggable-resizable": "^2.3.0",
|
||||
"vue-tailwind": "^2.0.0",
|
||||
"vue-toasted": "^1.1.28",
|
||||
"vuedraggable": "^2.24.3",
|
||||
"vuex": "^3.4.0",
|
||||
"vuex-persist": "^3.1.3"
|
||||
},
|
||||
|
|
|
@ -92,6 +92,8 @@
|
|||
/>
|
||||
|
||||
<BrushLibrary v-if="brushLibraryState.visible" />
|
||||
<BrushPreview />
|
||||
|
||||
</template>
|
||||
<template v-else>
|
||||
<div
|
||||
|
@ -131,8 +133,11 @@ import EditAscii from "./components/modals/EditAscii.vue";
|
|||
import PasteAscii from "./components/modals/PasteAscii.vue";
|
||||
|
||||
import BrushCanvas from "./components/parts/BrushCanvas.vue";
|
||||
import BrushPreview from "./components/parts/BrushPreview.vue";
|
||||
// import KeyboardShortcuts from "./components/parts/KeyboardShortcuts.vue";
|
||||
|
||||
import draggable from "vuedraggable";
|
||||
|
||||
import {
|
||||
parseMircAscii,
|
||||
toolbarIcons,
|
||||
|
@ -159,6 +164,8 @@ export default {
|
|||
PasteAscii,
|
||||
BrushLibrary,
|
||||
BrushCanvas,
|
||||
BrushPreview,
|
||||
draggable,
|
||||
// KeyboardShortcuts
|
||||
},
|
||||
name: "Dashboard",
|
||||
|
|
91
src/ascii.js
91
src/ascii.js
File diff suppressed because one or more lines are too long
|
@ -3,8 +3,8 @@
|
|||
<vue-draggable-resizable
|
||||
@dragstop="onDragStop"
|
||||
@resizestop="onResize"
|
||||
:grid="[currentAscii.blockWidth, currentAscii.blockHeight]"
|
||||
:min-width="blockWidth * 25"
|
||||
:grid="[blockWidth, blockHeight]"
|
||||
:min-width="blockWidth * 35"
|
||||
:max-width="blockWidth * 50"
|
||||
:min-height="blockHeight * 50"
|
||||
:max-height="blockHeight * 100"
|
||||
|
@ -36,10 +36,23 @@
|
|||
>History</t-button
|
||||
>
|
||||
|
||||
<t-button
|
||||
type="button"
|
||||
:class="`block w-full ${
|
||||
panel.tab === 1
|
||||
? 'border-gray-900 bg-blue-500'
|
||||
: 'border-gray-200 bg-gray-500'
|
||||
}`"
|
||||
@click="changeTab(2)"
|
||||
>Layers</t-button
|
||||
>
|
||||
|
||||
<div class="flex">
|
||||
<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 mt-2">
|
||||
<t-card
|
||||
class="hover:border-blue-900 border-gray-300 bg-gray-200 mt-2"
|
||||
>
|
||||
<BrushCanvas :blocks="decompressBlock(brush.blocks)" />
|
||||
|
||||
<t-button
|
||||
|
@ -97,17 +110,38 @@
|
|||
</t-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="panel.tab === 2"
|
||||
class="w-full bg-white rounded-lg shadow-lg"
|
||||
>
|
||||
|
||||
<Layers />
|
||||
</div>
|
||||
</div>
|
||||
</t-card>
|
||||
</vue-draggable-resizable>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.buttons {
|
||||
margin-top: 35px;
|
||||
}
|
||||
.ghost {
|
||||
opacity: 0.5;
|
||||
background: #c8ebfb;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { mircColours99, blockWidth, blockHeight } from "../ascii";
|
||||
import BrushCanvas from "./parts/BrushCanvas.vue";
|
||||
import BrushPreview from "./parts/BrushPreview.vue";
|
||||
import Layers from "./parts/Layers.vue";
|
||||
import LZString from "lz-string";
|
||||
|
||||
|
||||
export default {
|
||||
name: "BrushLibrary",
|
||||
created() {
|
||||
|
@ -125,17 +159,23 @@ export default {
|
|||
y: 100,
|
||||
visible: true,
|
||||
tab: 1,
|
||||
dragging: false,
|
||||
},
|
||||
}),
|
||||
components: {
|
||||
BrushCanvas,
|
||||
BrushPreview,
|
||||
Layers
|
||||
},
|
||||
computed: {
|
||||
blockWidth() {
|
||||
return blockWidth;
|
||||
return blockWidth * this.blockSizeMultiplier;
|
||||
},
|
||||
blockHeight() {
|
||||
return blockHeight;
|
||||
return blockHeight * this.blockSizeMultiplier;
|
||||
},
|
||||
blockSizeMultiplier() {
|
||||
return this.$store.getters.blockSizeMultiplier;
|
||||
},
|
||||
currentAscii() {
|
||||
return this.$store.getters.currentAscii;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div>
|
||||
<vue-draggable-resizable
|
||||
@dragstop="onDragStop"
|
||||
:grid="[currentAscii.blockWidth, currentAscii.blockHeight]"
|
||||
:grid="[blockWidth, blockHeight]"
|
||||
:min-width="blockWidth * 40"
|
||||
:max-width="blockWidth * 40"
|
||||
:min-height="blockHeight * 20"
|
||||
|
@ -80,10 +80,13 @@ export default {
|
|||
}),
|
||||
computed: {
|
||||
blockWidth() {
|
||||
return blockWidth;
|
||||
return blockWidth * this.blockSizeMultiplier;
|
||||
},
|
||||
blockHeight() {
|
||||
return blockHeight;
|
||||
return blockHeight * this.blockSizeMultiplier;
|
||||
},
|
||||
blockSizeMultiplier() {
|
||||
return this.$store.getters.blockSizeMultiplier
|
||||
},
|
||||
getToolName() {
|
||||
return toolbarIcons[this.$store.getters.currentTool] ? toolbarIcons[this.$store.getters.currentTool].name : 'none';
|
||||
|
@ -153,10 +156,10 @@ export default {
|
|||
return this.$store.getters.brushBlocks;
|
||||
},
|
||||
// canvasX() {
|
||||
// return this.x * this.currentAscii.blockWidth;
|
||||
// return this.x * this.blockWidth;
|
||||
// },
|
||||
// canvasY() {
|
||||
// return this.y * this.currentAscii.blockHeight;
|
||||
// return this.y * this.blockHeight;
|
||||
// },
|
||||
toolbarState() {
|
||||
return this.$store.getters.toolbarState;
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
<div>
|
||||
<vue-draggable-resizable
|
||||
@dragstop="onDragStop"
|
||||
:grid="[currentAscii.blockWidth, currentAscii.blockHeight]"
|
||||
:grid="[blockWidth, blockHeight]"
|
||||
style="z-index: 5"
|
||||
:min-width="blockWidth * 25"
|
||||
:max-width="blockWidth * 30"
|
||||
:max-height="blockHeight * 39"
|
||||
:min-height="blockHeight * 38"
|
||||
:max-width="blockWidth * 40"
|
||||
:max-height="blockHeight * 20"
|
||||
:min-height="blockHeight * 19"
|
||||
:w="toolbarState.w"
|
||||
:h="toolbarState.h"
|
||||
:x="toolbarState.x"
|
||||
|
@ -50,7 +50,7 @@
|
|||
<div class="flex">
|
||||
<label class="ml-1 w-1/2">
|
||||
<t-checkbox
|
||||
name="targetingFg"
|
||||
name="mirror-x"
|
||||
v-model="mirror.x"
|
||||
@change="updateMirror()"
|
||||
/>
|
||||
|
@ -58,7 +58,7 @@
|
|||
</label>
|
||||
<label class="ml-1 w-1/2">
|
||||
<t-checkbox
|
||||
name="targetingBg"
|
||||
name="mirror-y"
|
||||
v-model="mirror.y"
|
||||
@change="updateMirror()"
|
||||
/>
|
||||
|
@ -66,6 +66,25 @@
|
|||
</label>
|
||||
</div>
|
||||
|
||||
<div class="flex">
|
||||
<label class="ml-1 w-1/2">
|
||||
<t-checkbox
|
||||
name="update-brush"
|
||||
v-model="toolbarState.updateBrush"
|
||||
@change="$store.commit('toggleUpdateBrush', updateBrush)"
|
||||
/>
|
||||
<span class="text-sm">Update Brush</span>
|
||||
</label>
|
||||
<label class="ml-1 w-1/2">
|
||||
<t-checkbox
|
||||
name="grid"
|
||||
v-model="toolbarState.gridView"
|
||||
@change="$store.commit('toggleGridView', gridView)"
|
||||
/>
|
||||
<span class="text-sm">Grid</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<hr class="m-3" />
|
||||
|
||||
<t-button
|
||||
|
@ -82,9 +101,6 @@
|
|||
<font-awesome-icon :icon="[value.fa, value.icon]" size="lg" />
|
||||
</t-button>
|
||||
|
||||
<hr class="m-3" />
|
||||
<small>Brush</small>
|
||||
<BrushPreview />
|
||||
</t-card>
|
||||
</vue-draggable-resizable>
|
||||
</div>
|
||||
|
@ -92,7 +108,6 @@
|
|||
|
||||
<script>
|
||||
import Colours from "./Colours.vue";
|
||||
import BrushPreview from "./parts/BrushPreview.vue";
|
||||
import { toolbarIcons, blockWidth, blockHeight } from "../ascii";
|
||||
|
||||
export default {
|
||||
|
@ -106,7 +121,7 @@ export default {
|
|||
this.mirror.y = this.toolbarState.mirrorY;
|
||||
},
|
||||
name: "Toolbar",
|
||||
components: { Colours, BrushPreview },
|
||||
components: { Colours },
|
||||
|
||||
data: () => ({
|
||||
toolbar: {
|
||||
|
@ -125,10 +140,13 @@ export default {
|
|||
return toolbarIcons;
|
||||
},
|
||||
blockWidth() {
|
||||
return blockWidth;
|
||||
return blockWidth * this.blockSizeMultiplier;
|
||||
},
|
||||
blockHeight() {
|
||||
return blockHeight;
|
||||
return blockHeight * this.blockSizeMultiplier;
|
||||
},
|
||||
blockSizeMultiplier() {
|
||||
return this.$store.getters.blockSizeMultiplier
|
||||
},
|
||||
toolbarState() {
|
||||
return this.$store.getters.toolbarState;
|
||||
|
@ -160,6 +178,12 @@ export default {
|
|||
draggable() {
|
||||
return this.toolbarState.draggable;
|
||||
},
|
||||
gridView() {
|
||||
return this.toolbarState.gridView;
|
||||
},
|
||||
updateBrush() {
|
||||
return this.toolbarState.updateBrush;
|
||||
},
|
||||
},
|
||||
watch: {},
|
||||
methods: {
|
||||
|
|
|
@ -23,12 +23,18 @@
|
|||
</style>
|
||||
|
||||
<script>
|
||||
import { mircColours99, blockWidth, blockHeight, cyrb53, getBlocksWidth, filterNullBlocks } from "../../ascii";
|
||||
import { mircColours99, blockWidth, blockHeight, cyrb53, getBlocksWidth, filterNullBlocks, checkVisible } from "../../ascii";
|
||||
|
||||
export default {
|
||||
name: "BrushCanvas",
|
||||
created() {
|
||||
window.addEventListener('load', () => {
|
||||
// Fixes the font on load issue
|
||||
this.delayRedrawCanvas();
|
||||
})
|
||||
},
|
||||
mounted() {
|
||||
this.ctx = this.canvasRef.getContext("2d");
|
||||
this.ctx = this.$refs[this.canvasName].getContext("2d");
|
||||
this.delayRedrawCanvas();
|
||||
},
|
||||
props: {
|
||||
|
@ -43,6 +49,15 @@ export default {
|
|||
redraw: true,
|
||||
}),
|
||||
computed: {
|
||||
blockWidth() {
|
||||
return blockWidth * this.blockSizeMultiplier;
|
||||
},
|
||||
blockHeight() {
|
||||
return blockHeight * this.blockSizeMultiplier;
|
||||
},
|
||||
blockSizeMultiplier() {
|
||||
return this.$store.getters.blockSizeMultiplier
|
||||
},
|
||||
currentAscii() {
|
||||
return this.$store.getters.currentAscii;
|
||||
},
|
||||
|
@ -93,8 +108,8 @@ export default {
|
|||
},
|
||||
blocksWidthHeight() {
|
||||
return {
|
||||
w: getBlocksWidth(this.getBlocks) * blockWidth,
|
||||
h: this.getBlocks.length * blockHeight
|
||||
w: getBlocksWidth(this.getBlocks) * this.blockWidth,
|
||||
h: this.getBlocks.length * this.blockHeight
|
||||
}
|
||||
},
|
||||
mircColours() {
|
||||
|
@ -105,6 +120,9 @@ export default {
|
|||
}
|
||||
},
|
||||
watch: {
|
||||
blockSizeMultiplier() {
|
||||
this.delayRedrawCanvas();
|
||||
},
|
||||
getBlocks() {
|
||||
this.delayRedrawCanvas();
|
||||
},
|
||||
|
@ -168,10 +186,10 @@ export default {
|
|||
this.ctx.fillStyle = this.mircColours[curBlock.bg];
|
||||
|
||||
this.ctx.fillRect(
|
||||
x * blockWidth,
|
||||
y * blockHeight,
|
||||
blockWidth,
|
||||
blockHeight
|
||||
x * this.blockWidth,
|
||||
y * this.blockHeight,
|
||||
this.blockWidth,
|
||||
this.blockHeight
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -183,8 +201,8 @@ export default {
|
|||
this.ctx.fillStyle = this.mircColours[curBlock.fg];
|
||||
this.ctx.fillText(
|
||||
curBlock.char,
|
||||
x * blockWidth,
|
||||
y * blockHeight + blockHeight - 3
|
||||
x * this.blockWidth,
|
||||
y * this.blockHeight + this.blockHeight - 3
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,55 +1,82 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="flex">
|
||||
<div class="w-1/2">
|
||||
<t-input
|
||||
type="number"
|
||||
name="width"
|
||||
v-model="brushSizeWidthInput"
|
||||
min="1"
|
||||
:max="maxBrushSize"
|
||||
/>
|
||||
</div>
|
||||
<vue-draggable-resizable
|
||||
@dragstop="onDragStop"
|
||||
@resizestop="onResize"
|
||||
:grid="[blockWidth, blockHeight]"
|
||||
:min-width="blockWidth * 20"
|
||||
:max-width="blockWidth * 80"
|
||||
:min-height="blockHeight * 20"
|
||||
:max-height="blockHeight * 80"
|
||||
:w="brushPreviewState.w"
|
||||
:h="brushPreviewState.h"
|
||||
:x="brushPreviewState.x"
|
||||
:y="brushPreviewState.y"
|
||||
:draggable="canDrag"
|
||||
>
|
||||
<t-card class="h-full">
|
||||
<div class="flex w-full">
|
||||
<div class="w-1/2">
|
||||
<t-input
|
||||
type="number"
|
||||
name="width"
|
||||
v-model="brushSizeWidthInput"
|
||||
min="1"
|
||||
:max="maxBrushSize"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="w-1/2">
|
||||
<t-input
|
||||
type="number"
|
||||
name="height"
|
||||
v-model="brushSizeHeightInput"
|
||||
min="1"
|
||||
:max="maxBrushSize"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
<t-input
|
||||
type="number"
|
||||
name="height"
|
||||
v-model="brushSizeHeightInput"
|
||||
min="1"
|
||||
:max="maxBrushSize"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex">
|
||||
<label class="block">
|
||||
<t-radio
|
||||
name="options"
|
||||
value="square"
|
||||
checked
|
||||
v-model="brushSizeTypeInput"
|
||||
/>
|
||||
<span class="text-sm">Square</span>
|
||||
</label>
|
||||
<div class="flex w-full">
|
||||
<label class="block">
|
||||
<t-radio
|
||||
name="options"
|
||||
value="square"
|
||||
checked
|
||||
v-model="brushSizeTypeInput"
|
||||
/>
|
||||
<span class="text-sm">Square</span>
|
||||
</label>
|
||||
|
||||
<label class="block">
|
||||
<t-radio name="options" value="circle" v-model="brushSizeTypeInput" />
|
||||
<span class="text-sm">Circle</span>
|
||||
</label>
|
||||
<label class="block">
|
||||
<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" />
|
||||
<span class="text-sm">Cross</span>
|
||||
</label>
|
||||
</div>
|
||||
<label class="block">
|
||||
<t-radio
|
||||
name="options"
|
||||
value="cross"
|
||||
v-model="brushSizeTypeInput"
|
||||
/>
|
||||
<span class="text-sm">Cross</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<MainBrushCanvas />
|
||||
<div @mouseenter="canDrag = false" @mouseleave="canDrag = true">
|
||||
<MainBrushCanvas />
|
||||
</div>
|
||||
</t-card>
|
||||
</vue-draggable-resizable>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { emptyBlock, maxBrushSize } from "../../ascii";
|
||||
import { emptyBlock, maxBrushSize, blockWidth, blockHeight } from "../../ascii";
|
||||
import MainBrushCanvas from "./MainBrushCanvas.vue";
|
||||
|
||||
export default {
|
||||
|
@ -57,21 +84,52 @@ export default {
|
|||
components: {
|
||||
MainBrushCanvas,
|
||||
},
|
||||
mounted() {
|
||||
created() {
|
||||
if (this.brushBlocksEmpty) {
|
||||
this.createBlocks();
|
||||
this.brushSizeWidthInput = this.brushSizeWidth;
|
||||
this.brushSizeHeightInput = this.brushSizeHeight;
|
||||
this.brushSizeTypeInput = this.brushSizeType;
|
||||
this.createBlocks();
|
||||
}
|
||||
|
||||
this.panel.x = this.brushPreviewState.x;
|
||||
this.panel.y = this.brushPreviewState.y;
|
||||
this.panel.w = this.brushPreviewState.w;
|
||||
this.panel.h = this.brushPreviewState.h;
|
||||
},
|
||||
data: () => ({
|
||||
canDrag: true,
|
||||
blocks: [],
|
||||
brushSizeHeightInput: 1,
|
||||
brushSizeWidthInput: 1,
|
||||
brushSizeTypeInput: "square",
|
||||
panel: {
|
||||
w: 0,
|
||||
h: 0,
|
||||
x: 100,
|
||||
y: 100,
|
||||
visible: true,
|
||||
},
|
||||
}),
|
||||
computed: {
|
||||
blockWidth() {
|
||||
return blockWidth * this.blockSizeMultiplier;
|
||||
},
|
||||
blockHeight() {
|
||||
return blockHeight * this.blockSizeMultiplier;
|
||||
},
|
||||
blockSizeMultiplier() {
|
||||
return this.$store.getters.blockSizeMultiplier;
|
||||
},
|
||||
canFg() {
|
||||
return this.$store.getters.isTargettingFg;
|
||||
},
|
||||
canBg() {
|
||||
return this.$store.getters.isTargettingBg;
|
||||
},
|
||||
canText() {
|
||||
return this.$store.getters.isTargettingChar;
|
||||
},
|
||||
currentFg() {
|
||||
return this.$store.getters.currentFg;
|
||||
},
|
||||
|
@ -81,6 +139,9 @@ export default {
|
|||
currentChar() {
|
||||
return this.$store.getters.currentChar;
|
||||
},
|
||||
toolbarState() {
|
||||
return this.$store.getters.toolbarState;
|
||||
},
|
||||
brushSizeHeight() {
|
||||
return this.$store.getters.brushSizeHeight;
|
||||
},
|
||||
|
@ -100,8 +161,14 @@ export default {
|
|||
return this.brushBlocks.length === 0;
|
||||
},
|
||||
maxBrushSize() {
|
||||
return maxBrushSize
|
||||
}
|
||||
return maxBrushSize;
|
||||
},
|
||||
brushPreviewState() {
|
||||
return this.$store.getters.brushPreviewState;
|
||||
},
|
||||
updateBrush() {
|
||||
return this.toolbarState.updateBrush;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
brushSizeWidth() {
|
||||
|
@ -128,9 +195,40 @@ export default {
|
|||
this.createBlocks();
|
||||
}
|
||||
},
|
||||
canFg(val, old) {
|
||||
if (val !== old && this.updateBrush) {
|
||||
this.createBlocks();
|
||||
}
|
||||
},
|
||||
canBg(val, old) {
|
||||
if (val !== old && this.updateBrush) {
|
||||
this.createBlocks();
|
||||
}
|
||||
},
|
||||
canText(val, old) {
|
||||
if (val !== old && this.updateBrush) {
|
||||
this.createBlocks();
|
||||
}
|
||||
},
|
||||
currentFg(val, old) {
|
||||
if (val !== old && this.updateBrush) {
|
||||
this.createBlocks();
|
||||
}
|
||||
},
|
||||
currentBg(val, old) {
|
||||
if (val !== old && this.updateBrush) {
|
||||
this.createBlocks();
|
||||
}
|
||||
},
|
||||
currentChar(val, old) {
|
||||
if (val !== old && this.updateBrush) {
|
||||
this.createBlocks();
|
||||
}
|
||||
},
|
||||
brushBlocks() {
|
||||
this.$store.commit("pushBrushHistory", this.brushBlocks);
|
||||
},
|
||||
|
||||
},
|
||||
methods: {
|
||||
updateBrushSize() {
|
||||
|
@ -160,7 +258,7 @@ export default {
|
|||
const middleY = Math.floor(brushHeight / 2);
|
||||
const middleX = Math.floor(brushWidth / 2);
|
||||
let yModifier = 0;
|
||||
|
||||
|
||||
// Recreate 2d array for preview
|
||||
for (y = 0; y < brushHeight; y++) {
|
||||
this.blocks[y] = [];
|
||||
|
@ -228,6 +326,20 @@ export default {
|
|||
|
||||
this.$store.commit("brushBlocks", this.blocks);
|
||||
},
|
||||
onResize(x, y, w, h) {
|
||||
this.panel.x = x;
|
||||
this.panel.y = y;
|
||||
this.panel.w = w;
|
||||
this.panel.h = h;
|
||||
|
||||
this.$store.commit("changeBrushPreviewState", this.panel);
|
||||
},
|
||||
onDragStop(x, y) {
|
||||
this.panel.x = x;
|
||||
this.panel.y = y;
|
||||
|
||||
this.$store.commit("changeBrushPreviewState", this.panel);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -7,7 +7,7 @@ import { mircColours99, toolbarIcons, maxBrushSize } from '../../ascii';
|
|||
|
||||
export default {
|
||||
name: 'KeyboardShortcuts',
|
||||
mounted() {
|
||||
created() {
|
||||
const thisIs = this;
|
||||
this.keyListener = function (e) {
|
||||
// Stop blocking input when modals are open
|
||||
|
@ -69,7 +69,7 @@ export default {
|
|||
|
||||
// Show / hide grid view
|
||||
if (e.key === "g" && ctrlKey) {
|
||||
this.$store.commit("toggleGridView", !this.gridView);
|
||||
this.$store.commit("toggleGridView", !this.toolbarState.gridView);
|
||||
}
|
||||
|
||||
// Show / hide brush library
|
||||
|
@ -261,9 +261,6 @@ export default {
|
|||
brushLibraryState() {
|
||||
return this.$store.getters.brushLibraryState;
|
||||
},
|
||||
gridView() {
|
||||
return this.$store.getters.gridView;
|
||||
},
|
||||
maxBrushSize() {
|
||||
return maxBrushSize;
|
||||
},
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
<template>
|
||||
<div>
|
||||
<t-card class="h-full">
|
||||
<t-button
|
||||
type="button"
|
||||
class="block w-full border-gray-200 bg-gray-500 p-2 m-2"
|
||||
@click="addLayer()"
|
||||
>Add Layer</t-button
|
||||
>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="w-full bg-white rounded-lg shadow">
|
||||
<ul class="divide-y-2 divide-gray-100">
|
||||
<li
|
||||
:class="`p-1 ${selectedLayerClass(key)}`"
|
||||
v-for="(layer, key) in currentAsciiLayers"
|
||||
:key="key"
|
||||
>
|
||||
<div class="flex">
|
||||
<div class="w-12">
|
||||
<t-button
|
||||
type="button"
|
||||
class="rounded-xl"
|
||||
@click="toggleLayer(key)"
|
||||
:disabled="!canToggleLayer && lastVisible"
|
||||
><font-awesome-icon
|
||||
:icon="[
|
||||
'fas',
|
||||
layer.visible ? 'eye' : 'eye-slash',
|
||||
]" /></t-button
|
||||
><br />
|
||||
|
||||
<t-button
|
||||
type="button"
|
||||
class="rounded-xl"
|
||||
@click="removeLayer(key)"
|
||||
:disabled="!canToggleLayer"
|
||||
><font-awesome-icon :icon="['fas', 'trash']"
|
||||
/></t-button>
|
||||
</div>
|
||||
|
||||
<div class="w-full" @click="changeLayer(key)">
|
||||
<div class="flex text-right">
|
||||
<div class="w-full">
|
||||
<t-card class="w-full">
|
||||
{{ layer.label }}
|
||||
</t-card>
|
||||
</div>
|
||||
|
||||
<div class="w-5">
|
||||
<t-button
|
||||
type="button"
|
||||
class="rounded-xl"
|
||||
@click="upLayer(key)"
|
||||
:disabled="!canToggleLayer"
|
||||
><font-awesome-icon
|
||||
:icon="['fas', 'chevron-circle-up']" /></t-button
|
||||
><br />
|
||||
|
||||
<t-button
|
||||
type="button"
|
||||
class="rounded-xl"
|
||||
@click="downLayer(key)"
|
||||
:disabled="!canToggleLayer"
|
||||
><font-awesome-icon
|
||||
:icon="['fas', 'chevron-circle-down']"
|
||||
/></t-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</t-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "Layers",
|
||||
created() {},
|
||||
data: () => ({
|
||||
dragging: false,
|
||||
}),
|
||||
computed: {
|
||||
toolbarState() {
|
||||
return this.$store.getters.toolbarState;
|
||||
},
|
||||
currentAsciiLayers() {
|
||||
return this.$store.getters.currentAsciiLayers;
|
||||
},
|
||||
selectedLayer() {
|
||||
return this.$store.getters.selectedLayer;
|
||||
},
|
||||
canToggleLayer() {
|
||||
return this.currentAsciiLayers.length !== 1;
|
||||
// We want to avoid hiding all the layers, so if there's only one
|
||||
// visible left, we have to disable the buttons
|
||||
},
|
||||
lastVisible() {
|
||||
let visibleCount = 0;
|
||||
|
||||
for (let i = 0; i < this.currentAsciiLayers.length; i++) {
|
||||
if (this.currentAsciiLayers[i].visible) {
|
||||
visibleCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return visibleCount === 1;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
selectedLayerClass(key) {
|
||||
// Invisble layers are red
|
||||
if (
|
||||
this.currentAsciiLayers[key].visible === false &&
|
||||
key === this.selectedLayer
|
||||
) {
|
||||
if (this.currentAsciiLayers[key + 1]) {
|
||||
this.changeLayer(key + 1);
|
||||
} else if (this.currentAsciiLayers[key - 1]) {
|
||||
this.changeLayer(key - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.currentAsciiLayers[key].visible) {
|
||||
return "bg-red-200";
|
||||
}
|
||||
|
||||
// Selected layers blue
|
||||
if (key === this.selectedLayer) {
|
||||
return "bg-blue-200";
|
||||
}
|
||||
|
||||
// Otherwise gray
|
||||
return "bg-gray-200";
|
||||
},
|
||||
addLayer() {
|
||||
this.$store.commit("addLayer");
|
||||
},
|
||||
changeLayer(key) {
|
||||
this.$store.commit("changeLayer", key);
|
||||
},
|
||||
toggleLayer(key) {
|
||||
if (!this.lastVisible || key !== this.selectedLayer) {
|
||||
this.$store.commit("toggleLayer", key);
|
||||
}
|
||||
},
|
||||
upLayer(key) {
|
||||
this.$store.commit("upLayer", key);
|
||||
},
|
||||
downLayer(key) {
|
||||
this.$store.commit("downLayer", key);
|
||||
},
|
||||
removeLayer(key) {
|
||||
this.$store.commit("removeLayer", key);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -43,9 +43,14 @@ import {
|
|||
|
||||
export default {
|
||||
name: "MainBrushCanvas",
|
||||
created() {
|
||||
window.addEventListener('load', () => {
|
||||
// Fixes the font on load issue
|
||||
this.delayRedrawCanvas();
|
||||
})
|
||||
},
|
||||
mounted() {
|
||||
this.ctx = this.canvasRef.getContext("2d");
|
||||
this.delayRedrawCanvas();
|
||||
},
|
||||
data: () => ({
|
||||
ctx: null,
|
||||
|
@ -56,6 +61,15 @@ export default {
|
|||
y: 0,
|
||||
}),
|
||||
computed: {
|
||||
blockWidth() {
|
||||
return blockWidth * this.blockSizeMultiplier;
|
||||
},
|
||||
blockHeight() {
|
||||
return blockHeight * this.blockSizeMultiplier;
|
||||
},
|
||||
blockSizeMultiplier() {
|
||||
return this.$store.getters.blockSizeMultiplier
|
||||
},
|
||||
currentAscii() {
|
||||
return this.$store.getters.currentAscii;
|
||||
},
|
||||
|
@ -148,6 +162,9 @@ export default {
|
|||
currentChar() {
|
||||
this.delayRedrawCanvas();
|
||||
},
|
||||
blockSizeMultiplier() {
|
||||
this.delayRedrawCanvas();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getBlocksWidth(blocks) {
|
||||
|
@ -156,6 +173,7 @@ export default {
|
|||
filterNullBlocks(blocks) {
|
||||
return filterNullBlocks(blocks);
|
||||
},
|
||||
|
||||
drawPreview() {
|
||||
this.ctx.clearRect(0, 0, this.canvasRef.width, this.canvasRef.height);
|
||||
this.ctx.fillStyle = this.mircColours[1];
|
||||
|
|
|
@ -11,7 +11,11 @@ import {
|
|||
faSync,
|
||||
faSave,
|
||||
faTrash,
|
||||
faFill
|
||||
faFill,
|
||||
faChevronCircleUp,
|
||||
faChevronCircleDown,
|
||||
faEye,
|
||||
faEyeSlash
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
import {
|
||||
|
@ -19,4 +23,4 @@ import {
|
|||
} from '@fortawesome/free-regular-svg-icons';
|
||||
|
||||
library.add(faMousePointer, faSquare, faFont, faFillDrip, faPaintBrush, faEyeDropper, faEraser,
|
||||
faSync, faSave, faTrash, faFill);
|
||||
faSync, faSave, faTrash, faFill, faChevronCircleUp, faChevronCircleDown, faEye, faEyeSlash);
|
||||
|
|
|
@ -9,6 +9,7 @@ import store from './store';
|
|||
import Dashboard from './Dashboard.vue';
|
||||
import Toasted from 'vue-toasted';
|
||||
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
import {
|
||||
|
|
|
@ -6,7 +6,9 @@ import {
|
|||
blockWidth,
|
||||
blockHeight,
|
||||
cyrb53,
|
||||
getBlocksWidth
|
||||
getBlocksWidth,
|
||||
create2DArray,
|
||||
emptyBlock
|
||||
} from "../ascii";
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
@ -25,13 +27,11 @@ export default new Vuex.Store({
|
|||
// The various options of ASCIIBIRD will eventually
|
||||
// end up in its own modal I guess
|
||||
options: {
|
||||
canvasRedrawSpeed: 50,
|
||||
defaultBg: 1,
|
||||
defaultFg: 0,
|
||||
},
|
||||
// Current tab user is viewing
|
||||
tab: 0,
|
||||
gridView: false,
|
||||
// asciibirdMeta holds all of the ASCII information for all the tabs
|
||||
asciibirdMeta: [],
|
||||
toolbarState: {
|
||||
|
@ -56,15 +56,17 @@ export default new Vuex.Store({
|
|||
mirrorY: false,
|
||||
x: blockWidth * 2,
|
||||
y: blockHeight * 2,
|
||||
h: blockHeight * 39,
|
||||
h: blockHeight * 19,
|
||||
w: blockWidth * 25,
|
||||
draggable: true,
|
||||
updateBrush: true,
|
||||
gridView: false,
|
||||
},
|
||||
debugPanelState: {
|
||||
x: 936,
|
||||
y: 39,
|
||||
h: 260,
|
||||
w: 320,
|
||||
x: blockWidth * 130,
|
||||
y: blockHeight * 2,
|
||||
h: blockHeight * 50,
|
||||
w: blockWidth * 25,
|
||||
visible: false,
|
||||
},
|
||||
blockSizeMultiplier: 1,
|
||||
|
@ -76,10 +78,17 @@ export default new Vuex.Store({
|
|||
x: blockWidth * 130,
|
||||
y: blockHeight * 2,
|
||||
h: blockHeight * 50,
|
||||
w: blockWidth * 25,
|
||||
w: blockWidth * 35,
|
||||
visible: true,
|
||||
tab: 0,
|
||||
},
|
||||
brushPreviewState: {
|
||||
x: blockWidth * 2,
|
||||
y: blockHeight * 22,
|
||||
h: blockHeight * 19,
|
||||
w: blockWidth * 25,
|
||||
visible: true,
|
||||
},
|
||||
},
|
||||
mutations: {
|
||||
changeState(state, payload) {
|
||||
|
@ -98,6 +107,9 @@ export default new Vuex.Store({
|
|||
changeBrushLibraryState(state, payload) {
|
||||
state.brushLibraryState = payload;
|
||||
},
|
||||
changeBrushPreviewState(state, payload) {
|
||||
state.brushPreviewState = payload;
|
||||
},
|
||||
toggleBrushLibrary(state, payload) {
|
||||
state.brushLibraryState.visible = payload;
|
||||
},
|
||||
|
@ -171,12 +183,104 @@ export default new Vuex.Store({
|
|||
state.asciibirdMeta[state.tab].history.push(state.asciibirdMeta[state.tab].blocks);
|
||||
}
|
||||
|
||||
state.asciibirdMeta[state.tab].blocks = LZString.compressToUTF16(JSON.stringify(payload));
|
||||
let tempLayers = JSON.parse(LZString.decompressFromUTF16(state.asciibirdMeta[state.tab]
|
||||
.blocks))
|
||||
tempLayers[state.asciibirdMeta[state.tab].selectedLayer].data = payload
|
||||
|
||||
state.asciibirdMeta[state.tab].blocks = LZString.compressToUTF16(JSON.stringify(
|
||||
tempLayers));
|
||||
state.asciibirdMeta[state.tab].redo = [];
|
||||
},
|
||||
|
||||
//
|
||||
// LAYERS
|
||||
//
|
||||
addLayer(state) {
|
||||
let tempLayers = JSON.parse(LZString.decompressFromUTF16(state.asciibirdMeta[state.tab]
|
||||
.blocks))
|
||||
|
||||
let newBlocksArray = create2DArray(state.asciibirdMeta[state.tab].height);
|
||||
|
||||
// Push all the default ASCII blocks
|
||||
for (let x = 0; x < state.asciibirdMeta[state.tab].width; x++) {
|
||||
for (let y = 0; y < state.asciibirdMeta[state.tab].height; y++) {
|
||||
newBlocksArray[y].push({
|
||||
...emptyBlock,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
tempLayers.unshift({
|
||||
label: 'Layer ' + Number.parseInt(tempLayers.length),
|
||||
visible: true,
|
||||
data: newBlocksArray,
|
||||
})
|
||||
|
||||
state.asciibirdMeta[state.tab].blocks = LZString.compressToUTF16(JSON.stringify(
|
||||
tempLayers));
|
||||
},
|
||||
changeLayer(state, payload) {
|
||||
state.asciibirdMeta[state.tab].selectedLayer = payload
|
||||
},
|
||||
toggleLayer(state, payload) {
|
||||
let tempLayers = JSON.parse(LZString.decompressFromUTF16(state.asciibirdMeta[state.tab]
|
||||
.blocks))
|
||||
|
||||
tempLayers[payload].visible = !tempLayers[payload].visible
|
||||
|
||||
state.asciibirdMeta[state.tab].blocks = LZString.compressToUTF16(JSON.stringify(
|
||||
tempLayers));
|
||||
},
|
||||
removeLayer(state, payload) {
|
||||
let tempLayers = JSON.parse(LZString.decompressFromUTF16(state.asciibirdMeta[state.tab]
|
||||
.blocks))
|
||||
|
||||
if (tempLayers.length > 1) {
|
||||
tempLayers.splice(payload, 1)
|
||||
state.asciibirdMeta[state.tab].blocks = LZString.compressToUTF16(JSON.stringify(
|
||||
tempLayers));
|
||||
}
|
||||
|
||||
},
|
||||
downLayer(state, payload) {
|
||||
let tempLayers = JSON.parse(LZString.decompressFromUTF16(state.asciibirdMeta[state.tab]
|
||||
.blocks))
|
||||
|
||||
if (tempLayers[payload + 1]) {
|
||||
let swap1 = tempLayers[payload + 1];
|
||||
let swap = tempLayers[payload];
|
||||
|
||||
tempLayers[payload + 1] = swap
|
||||
tempLayers[payload] = swap1
|
||||
|
||||
state.asciibirdMeta[state.tab].blocks = LZString.compressToUTF16(JSON.stringify(
|
||||
tempLayers));
|
||||
}
|
||||
|
||||
},
|
||||
upLayer(state, payload) {
|
||||
let tempLayers = JSON.parse(LZString.decompressFromUTF16(state.asciibirdMeta[state.tab]
|
||||
.blocks))
|
||||
|
||||
if (tempLayers[payload - 1]) {
|
||||
let swap1 = tempLayers[payload - 1];
|
||||
let swap = tempLayers[payload];
|
||||
|
||||
tempLayers[payload - 1] = swap
|
||||
tempLayers[payload] = swap1
|
||||
|
||||
state.asciibirdMeta[state.tab].blocks = LZString.compressToUTF16(JSON.stringify(
|
||||
tempLayers));
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// ASCII
|
||||
updateAscii(state, payload) {
|
||||
state.asciibirdMeta[state.tab] = payload;
|
||||
},
|
||||
|
||||
// BLOCKS
|
||||
undoBlocks(state) {
|
||||
if (state.asciibirdMeta[state.tab].history.length > 1) {
|
||||
state.asciibirdMeta[state.tab].redo.push(state.asciibirdMeta[state.tab].blocks);
|
||||
|
@ -190,6 +294,10 @@ export default new Vuex.Store({
|
|||
state.asciibirdMeta[state.tab].history.push(next);
|
||||
}
|
||||
},
|
||||
|
||||
//
|
||||
// Toolbar
|
||||
//
|
||||
updateBrushSize(state, payload) {
|
||||
state.toolbarState.brushSizeHeight = payload.brushSizeHeight;
|
||||
state.toolbarState.brushSizeWidth = payload.brushSizeWidth;
|
||||
|
@ -202,11 +310,12 @@ export default new Vuex.Store({
|
|||
state.selectBlocks = LZString.compressToUTF16(JSON.stringify(payload));
|
||||
},
|
||||
toggleGridView(state, payload) {
|
||||
state.gridView = payload;
|
||||
state.toolbarState.gridView = payload;
|
||||
},
|
||||
//
|
||||
// Brush stuff
|
||||
//
|
||||
toggleUpdateBrush(state, payload) {
|
||||
state.toolbarState.updateBrush = payload;
|
||||
},
|
||||
|
||||
flipRotateBlocks(state, payload) {
|
||||
let tempBlocks = JSON.parse(LZString.decompressFromUTF16(state.brushBlocks))
|
||||
let parsedBlocks = [];
|
||||
|
@ -339,8 +448,19 @@ export default new Vuex.Store({
|
|||
currentChar: (state) => state.toolbarState.selectedChar,
|
||||
currentTab: (state) => state.tab,
|
||||
currentAscii: (state) => state.asciibirdMeta[state.tab] ?? false,
|
||||
currentAsciiBlocks: (state) => JSON.parse(LZString.decompressFromUTF16(state.asciibirdMeta[
|
||||
state.tab].blocks)) || [],
|
||||
currentAsciiBlocks: (state) => {
|
||||
let blocks = JSON.parse(LZString.decompressFromUTF16(state.asciibirdMeta[
|
||||
state.tab].blocks));
|
||||
|
||||
return blocks[state.asciibirdMeta[state.tab].selectedLayer].data
|
||||
},
|
||||
currentAsciiLayers: (state) => {
|
||||
let blocks = JSON.parse(LZString.decompressFromUTF16(state.asciibirdMeta[
|
||||
state.tab].blocks));
|
||||
|
||||
return blocks
|
||||
},
|
||||
selectedLayer: (state) => state.asciibirdMeta[state.tab].selectedLayer,
|
||||
asciibirdMeta: (state) => state.asciibirdMeta,
|
||||
nextTabValue: (state) => state.asciibirdMeta.length,
|
||||
brushSizeHeight: (state) => state.toolbarState.brushSizeHeight,
|
||||
|
@ -349,8 +469,8 @@ export default new Vuex.Store({
|
|||
blockSizeMultiplier: (state) => state.blockSizeMultiplier,
|
||||
brushHistory: (state) => state.brushHistory,
|
||||
brushLibrary: (state) => state.brushLibrary,
|
||||
gridView: (state) => state.gridView,
|
||||
brushLibraryState: (state) => state.brushLibraryState,
|
||||
brushPreviewState: (state) => state.brushPreviewState,
|
||||
brushBlocks: (state) => JSON.parse(LZString.decompressFromUTF16(state.brushBlocks)) || [],
|
||||
selectBlocks: (state) => JSON.parse(LZString.decompressFromUTF16(state.selectBlocks)) || [],
|
||||
isModalOpen: (state) => {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
>
|
||||
<vue-draggable-resizable
|
||||
style="z-index: 5"
|
||||
:grid="[currentAscii.blockWidth, currentAscii.blockHeight]"
|
||||
:grid="[blockWidth, blockHeight]"
|
||||
:w="canvas.width"
|
||||
:h="canvas.height"
|
||||
:draggable="isDefault"
|
||||
|
@ -16,23 +16,20 @@
|
|||
:x="currentAscii.x"
|
||||
:y="currentAscii.y"
|
||||
>
|
||||
<canvas
|
||||
ref="canvastools"
|
||||
id="canvastools"
|
||||
class="canvastools"
|
||||
:width="canvas.width"
|
||||
:height="canvas.height"
|
||||
@mousemove="canvasMouseMove"
|
||||
@mousedown="canvasMouseDown"
|
||||
@mouseup="canvasMouseUp"
|
||||
/>
|
||||
|
||||
<canvas
|
||||
ref="canvas"
|
||||
id="canvas"
|
||||
class="canvas"
|
||||
:width="canvas.width"
|
||||
:height="canvas.height"
|
||||
/>
|
||||
|
||||
<canvas
|
||||
ref="canvastools"
|
||||
id="canvastools"
|
||||
class="canvastools"
|
||||
:width="canvas.width"
|
||||
:height="canvas.height"
|
||||
@mousemove="canvasMouseMove"
|
||||
@mousedown="canvasMouseDown"
|
||||
@mouseup="canvasMouseUp"
|
||||
|
@ -73,15 +70,23 @@ import {
|
|||
fillNullBlocks,
|
||||
emptyBlock,
|
||||
getBlocksWidth,
|
||||
checkVisible,
|
||||
} from "../ascii";
|
||||
|
||||
export default {
|
||||
name: "Editor",
|
||||
mounted() {
|
||||
if (this.currentAsciiBlocks) {
|
||||
this.ctx = this.$refs.canvas.getContext("2d");
|
||||
this.toolCtx = this.$refs.canvastools.getContext("2d");
|
||||
this.ctx = this.canvasRef.getContext("2d");
|
||||
this.toolCtx = this.$refs.canvastools.getContext("2d");
|
||||
this.delayRedrawCanvas();
|
||||
},
|
||||
created() {
|
||||
window.addEventListener("load", () => {
|
||||
// Fixes the font on load issue
|
||||
this.delayRedrawCanvas();
|
||||
});
|
||||
|
||||
if (this.currentAsciiBlocks) {
|
||||
this.canvas.width = this.currentAscii.width * blockWidth;
|
||||
this.canvas.height = this.currentAscii.height * blockHeight;
|
||||
|
||||
|
@ -204,8 +209,6 @@ export default {
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Choose FG or BG with Keyboard
|
||||
if (
|
||||
Number.parseInt(e.key) >= 0 &&
|
||||
|
@ -439,6 +442,7 @@ export default {
|
|||
}
|
||||
};
|
||||
|
||||
document.removeEventListener("keydown", this.keyListener.bind(this));
|
||||
document.addEventListener("keydown", this.keyListener.bind(this));
|
||||
}
|
||||
},
|
||||
|
@ -451,6 +455,7 @@ export default {
|
|||
},
|
||||
x: 0, // Ascii X and Y
|
||||
y: 0, // Ascii X and Y
|
||||
top: false,
|
||||
redraw: true, // Used to limit canvas redraw
|
||||
canTool: false,
|
||||
textEditing: {
|
||||
|
@ -468,6 +473,18 @@ export default {
|
|||
selectedBlocks: [],
|
||||
}),
|
||||
computed: {
|
||||
canvasRef() {
|
||||
return this.$refs.canvas;
|
||||
},
|
||||
blockWidth() {
|
||||
return blockWidth * this.blockSizeMultiplier;
|
||||
},
|
||||
blockHeight() {
|
||||
return blockHeight * this.blockSizeMultiplier;
|
||||
},
|
||||
blockSizeMultiplier() {
|
||||
return this.$store.getters.blockSizeMultiplier;
|
||||
},
|
||||
isModalOpen() {
|
||||
return this.$store.getters.isModalOpen;
|
||||
},
|
||||
|
@ -486,6 +503,12 @@ export default {
|
|||
currentAsciiBlocks() {
|
||||
return this.$store.getters.currentAsciiBlocks;
|
||||
},
|
||||
currentAsciiLayers() {
|
||||
return this.$store.getters.currentAsciiLayers;
|
||||
},
|
||||
currentAsciiLayerBlocks() {
|
||||
return this.currentAsciiLayers[this.currentAscii.selectedLayer].data;
|
||||
},
|
||||
currentTool() {
|
||||
return toolbarIcons[this.$store.getters.currentTool];
|
||||
},
|
||||
|
@ -569,7 +592,7 @@ export default {
|
|||
return this.$store.getters.brushLibraryState;
|
||||
},
|
||||
gridView() {
|
||||
return this.$store.getters.gridView;
|
||||
return this.toolbarState.gridView;
|
||||
},
|
||||
asciiBlockAtXy() {
|
||||
return this.currentAsciiBlocks[this.y] &&
|
||||
|
@ -599,6 +622,13 @@ export default {
|
|||
document.title = `asciibird - ${this.currentAscii.title}`;
|
||||
}
|
||||
},
|
||||
currentAsciiLayers() {
|
||||
this.delayRedrawCanvas();
|
||||
},
|
||||
|
||||
// currentAsciiBlocks() {
|
||||
// this.delayRedrawCanvas();
|
||||
// },
|
||||
currentTool() {
|
||||
switch (this.currentTool.name) {
|
||||
case "default":
|
||||
|
@ -631,8 +661,14 @@ export default {
|
|||
this.drawBrush();
|
||||
}
|
||||
},
|
||||
blockSizeMultiplier() {
|
||||
this.delayRedrawCanvas();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
checkVisible(top) {
|
||||
return checkVisible(top, top - this.blockHeight);
|
||||
},
|
||||
undo() {
|
||||
this.$store.commit("undoBlocks");
|
||||
this.delayRedrawCanvas();
|
||||
|
@ -672,13 +708,15 @@ export default {
|
|||
}
|
||||
},
|
||||
redrawCanvas() {
|
||||
if (this.currentAsciiBlocks.length) {
|
||||
if (this.currentAsciiLayers.length) {
|
||||
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
|
||||
// Position of the meta array
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
|
||||
let i = 0;
|
||||
|
||||
// Draws the actual rectangle
|
||||
let canvasX = 0;
|
||||
let canvasY = 0;
|
||||
|
@ -690,10 +728,41 @@ export default {
|
|||
for (y = 0; y < this.currentAscii.height + 1; y++) {
|
||||
canvasY = blockHeight * y;
|
||||
|
||||
for (x = 0; x < this.currentAscii.width + 1; x++) {
|
||||
if (this.currentAsciiBlocks[y] && this.currentAsciiBlocks[y][x]) {
|
||||
curBlock = { ...this.currentAsciiBlocks[y][x] };
|
||||
// Experimental code to not rows blocks off screen
|
||||
// if (this.top !== false && !this.checkVisible(this.top + canvasY)) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
for (x = 0; x < this.currentAscii.width + 1; x++) {
|
||||
// Loop layers
|
||||
for (i = this.currentAsciiLayers.length - 1; i >= 0; i--) {
|
||||
// If this layer is invisble, skip it
|
||||
if (!this.currentAsciiLayers[i].visible) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this block on this layer has no data, skip to next row
|
||||
if (
|
||||
this.currentAsciiLayers[i] &&
|
||||
this.currentAsciiLayers[i].data &&
|
||||
this.currentAsciiLayers[i].data[y] &&
|
||||
this.currentAsciiLayers[i].data[y][x] &&
|
||||
i > 0 &&
|
||||
JSON.stringify(this.currentAsciiLayers[i].data[y][x]) ===
|
||||
JSON.stringify(emptyBlock)
|
||||
) {
|
||||
continue;
|
||||
} else if (
|
||||
// Otherwise if we are on the very first layer we need to render it
|
||||
this.currentAsciiLayers[i] &&
|
||||
this.currentAsciiLayers[i].data &&
|
||||
this.currentAsciiLayers[i].data[y] &&
|
||||
this.currentAsciiLayers[i].data[y][x]
|
||||
) {
|
||||
curBlock = { ...this.currentAsciiLayers[i].data[y][x] };
|
||||
}
|
||||
|
||||
// this.currentAsciiBlocks[y][x] = { ... curBlock}
|
||||
canvasX = blockWidth * x;
|
||||
|
||||
if (this.gridView) {
|
||||
|
@ -717,10 +786,12 @@ export default {
|
|||
|
||||
this.ctx.fillText(
|
||||
curBlock.char,
|
||||
canvasX ,
|
||||
canvasX,
|
||||
canvasY + blockHeight - 3
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -735,6 +806,7 @@ export default {
|
|||
canvasBlockWidth
|
||||
);
|
||||
|
||||
this.top = top;
|
||||
this.canvas.width = width;
|
||||
this.canvas.height = height;
|
||||
|
||||
|
@ -749,7 +821,13 @@ export default {
|
|||
},
|
||||
onCavasDragStop(x, y) {
|
||||
// Update left and top in panel
|
||||
this.top = y;
|
||||
this.$store.commit("changeAsciiCanvasState", { x, y });
|
||||
this.delayRedrawCanvas();
|
||||
},
|
||||
onCanvasDrag(x, y) {
|
||||
this.top = y;
|
||||
this.delayRedrawCanvas();
|
||||
},
|
||||
canvasKeyDown(char) {
|
||||
if (this.isTextEditing) {
|
||||
|
@ -1302,7 +1380,7 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
this.toolCtx.font = "Hack 13px"
|
||||
this.toolCtx.font = "Hack 13px";
|
||||
// We always have a Y array
|
||||
const brushDiffY = Math.floor(this.brushBlocks.length / 2) * blockHeight;
|
||||
|
||||
|
@ -1488,7 +1566,7 @@ export default {
|
|||
if (this.mirrorX) {
|
||||
this.toolCtx.fillText(
|
||||
brushBlock.char,
|
||||
(asciiWidth - arrayX) * blockWidth + 3,
|
||||
(asciiWidth - arrayX) * blockWidth + 3,
|
||||
brushY + blockHeight - 4
|
||||
);
|
||||
}
|
||||
|
@ -1496,14 +1574,14 @@ export default {
|
|||
if (this.mirrorY) {
|
||||
this.toolCtx.fillText(
|
||||
brushBlock.char,
|
||||
brushX + 3,
|
||||
brushX + 3,
|
||||
(asciiHeight - arrayY) * blockHeight + 10
|
||||
);
|
||||
}
|
||||
if (this.mirrorY && this.mirrorX) {
|
||||
this.toolCtx.fillText(
|
||||
brushBlock.char,
|
||||
(asciiWidth - arrayX) * blockWidth + 3,
|
||||
(asciiWidth - arrayX) * blockWidth + 3,
|
||||
(asciiHeight - arrayY) * blockHeight + 10
|
||||
);
|
||||
}
|
||||
|
@ -1707,7 +1785,7 @@ export default {
|
|||
// If the newColor is same as the existing
|
||||
// Then return the original image.
|
||||
if (current === newColor && !eraser) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
this.fillTool(this.currentAsciiBlocks, this.y, this.x, current, eraser);
|
||||
|
|
12
yarn.lock
12
yarn.lock
|
@ -8480,6 +8480,11 @@ sort-keys@^1.0.0:
|
|||
dependencies:
|
||||
is-plain-obj "^1.0.0"
|
||||
|
||||
sortablejs@1.10.2:
|
||||
version "1.10.2"
|
||||
resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.10.2.tgz#6e40364d913f98b85a14f6678f92b5c1221f5290"
|
||||
integrity sha512-YkPGufevysvfwn5rfdlGyrGjt7/CRHwvRPogD/lC+TnvcN29jDpCifKP+rBqf+LRldfXSTh+0CGLcSg0VIxq3A==
|
||||
|
||||
source-list-map@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
|
||||
|
@ -9502,6 +9507,13 @@ vue@^2.6.11:
|
|||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.14.tgz#e51aa5250250d569a3fbad3a8a5a687d6036e235"
|
||||
integrity sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==
|
||||
|
||||
vuedraggable@^2.24.3:
|
||||
version "2.24.3"
|
||||
resolved "https://registry.yarnpkg.com/vuedraggable/-/vuedraggable-2.24.3.tgz#43c93849b746a24ce503e123d5b259c701ba0d19"
|
||||
integrity sha512-6/HDXi92GzB+Hcs9fC6PAAozK1RLt1ewPTLjK0anTYguXLAeySDmcnqE8IC0xa7shvSzRjQXq3/+dsZ7ETGF3g==
|
||||
dependencies:
|
||||
sortablejs "1.10.2"
|
||||
|
||||
vuex-persist@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/vuex-persist/-/vuex-persist-3.1.3.tgz#518c722a2ca3026bcee5732f99d24f75cee0f3b6"
|
||||
|
|
Loading…
Reference in New Issue