updates, better options modal
This commit is contained in:
parent
e9307b48bd
commit
4fc0c99977
29
README.md
29
README.md
|
@ -64,8 +64,8 @@ A most latest production build to use is available at https://asciibird.jewbird.
|
|||
|
||||
ASCIIBIRD is mostly usable. There are some bugs however to note at the moment. Refreshing the page seems to fix most strange things.
|
||||
|
||||
* Redo ctrl Y is COOKED (not working)
|
||||
* Keyboard shortcuts can be pressed at the same time which makes bugs for undo and redo if you aren't careful!
|
||||
* Some BS on the layers rename stops shit working sometimes ?!!?!?!?!
|
||||
* Circle brush (works okay for odd width and height numbers)
|
||||
* Importer could be re-written with regex
|
||||
* Drag ascii canvas then right click and it gets stuck
|
||||
|
@ -73,38 +73,17 @@ ASCIIBIRD is mostly usable. There are some bugs however to note at the moment. R
|
|||
|
||||
* Having more than a few layers depending on ascii size will slow things down, until the `fillNullBlocks` is refactored.
|
||||
* CHUNKED DIFF ENGINE
|
||||
|
||||
|
||||
## Focusing on Now / Roadmap
|
||||
|
||||
* Modals to add
|
||||
* Asciibird options / Options modal from skgs PR
|
||||
* Arrow keys and space to use brush, eraser,
|
||||
* More Context Menus (right click menu)
|
||||
* Brushes Canvas right click
|
||||
* ASCII right click
|
||||
* Improve the char window to have a close button and border/bg
|
||||
* Review encodings check on file import - UTF8 vs Latin something
|
||||
* Revise the blocks system to only store what's changed
|
||||
|
||||
## User Feedback Requests
|
||||
|
||||
* Move brush with keys and space to paint
|
||||
* Improve the character panel, group chars
|
||||
|
||||
# Fixed / Finished
|
||||
|
||||
* Image overlay for trace mode
|
||||
* Cannot manually input brush sizes because keyboard shortcuts is stealing focus
|
||||
* If you open a modal and refresh the page it's stuck as opened inside the state, and you cannot open it again
|
||||
* Toolbars and panels follow when scrolling down
|
||||
* Experimental code to only render blocks visible on screen
|
||||
* Rename Layers
|
||||
* Some work around layers and transparent blocks, skip drawing transparent bg block on top layers. Or get bg from lowest layer if bg is null on higher layers.
|
||||
* The code that hides blocks off screen wont work if you scroll down, however it will work if you drag the canvas upward
|
||||
* Exporter will default transparent bg to black by default, which wont for some asciis
|
||||
* Review escape and enter keys on dialogs and modals
|
||||
* Select cannot select entire ASCII, is off by one at the end
|
||||
* Fill tool use fg or char as bounds
|
||||
* z indexing for toolbars and stuff is ANNOYING
|
||||
* Make grid faster (gonna do that later, maybe never)
|
||||
# Keyboard Shortcuts
|
||||
|
||||
## ASCII Editing
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
"vue": "^2.6.11",
|
||||
"vue-clipboard2": "^0.3.1",
|
||||
"vue-draggable-resizable": "^2.3.0",
|
||||
"vue-slider-component": "^2.8.16",
|
||||
"vue-tailwind": "^2.0.0",
|
||||
"vue-toasted": "^1.1.28",
|
||||
"vuex": "^3.4.0",
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
:is-showing-dialog="isShowingDialog"
|
||||
@updatecanvas="updatecanvas"
|
||||
:is-inputting-brush-size="this.isInputtingBrushSize"
|
||||
:canvas-x="canvasX"
|
||||
:canvas-y="canvasY"
|
||||
@triggerbrush="triggerbrush"
|
||||
/>
|
||||
|
||||
<t-dialog
|
||||
|
@ -142,6 +145,7 @@
|
|||
:update-canvas="updateCanvas"
|
||||
@selecting="updateSelecting"
|
||||
:y-offset="scrollOffset"
|
||||
:brush="drawBrush"
|
||||
/>
|
||||
|
||||
|
||||
|
@ -165,7 +169,6 @@
|
|||
|
||||
<LayersLibrary :y-offset="scrollOffset" />
|
||||
|
||||
|
||||
<CharPicker
|
||||
v-if="toolbarState.isChoosingChar"
|
||||
class="z-50"
|
||||
|
@ -279,6 +282,7 @@ export default {
|
|||
toolbarString: "top: 0px;",
|
||||
lastPostURL: "",
|
||||
isShowingDialog: false,
|
||||
drawBrush: false,
|
||||
}),
|
||||
computed: {
|
||||
splashAscii() {
|
||||
|
@ -340,6 +344,9 @@ export default {
|
|||
// },
|
||||
},
|
||||
methods: {
|
||||
triggerbrush() {
|
||||
this.drawBrush = ! this.drawBrush
|
||||
},
|
||||
inputtingbrush(val) {
|
||||
this.isInputtingBrushSize = val;
|
||||
},
|
||||
|
|
|
@ -212,8 +212,9 @@ export const blockWidth = 8;
|
|||
export const blockHeight = 15;
|
||||
|
||||
// Limits for undo and brush histories
|
||||
export const maxBrushHistory = 50;
|
||||
export const maxUndoHistory = 50;
|
||||
export const maxBrushHistory = 200;
|
||||
export const maxUndoHistory = 200;
|
||||
export const tabLimit = 20;
|
||||
|
||||
export const parseMircAscii = async (content, title) => {
|
||||
const MIRC_MAX_COLOURS = mircColours99.length;
|
||||
|
|
|
@ -10,17 +10,55 @@
|
|||
|
||||
<template v-slot:default>
|
||||
|
||||
<div>
|
||||
<div class="mt-6 lg:mt-0 rounded shadow bg-white">
|
||||
|
||||
<ul>
|
||||
<li> Redraw canvas speed? </li>
|
||||
<li>Render blocks off screen</li>
|
||||
<div class="mb-4">
|
||||
<label class="ml-1">
|
||||
<span class="text-sm">FPS</span>
|
||||
<vue-slider v-model="options.fps" @dragend="updateOptions" :min="1" :max="200"></vue-slider>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<li>Undo history?</li>
|
||||
<div class="mb-4">
|
||||
<label class="ml-1">
|
||||
<span class="text-lg">Render Offscreen Blocks</span><br />
|
||||
<t-checkbox
|
||||
class="form-checkbox m-1"
|
||||
name="renderOffScreen"
|
||||
v-model="options.renderOffScreen"
|
||||
@change="updateOptions"
|
||||
/>
|
||||
<small>ASCIIBIRD will avoid rendering blocks off screen to speed things up. </small>
|
||||
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mt-3 p-2 bg-red-300 rounded-md cursor-pointer" @click="clearCache()">Clear and Reset ASCIIBIRD</div>
|
||||
</ul>
|
||||
<div class="mb-4">
|
||||
<label class="ml-1">
|
||||
<span class="text-sm">Brush Histroy Limit</span>
|
||||
<vue-slider v-model="options.brushLimit" @dragend="updateOptions" :min="1" :max="maxBrushHistory"></vue-slider>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="ml-1">
|
||||
<span class="text-sm">Undo/Redo Histroy Limit</span>
|
||||
<vue-slider v-model="options.undoLimit" @dragend="updateOptions" :min="1" :max="maxUndoHistory"></vue-slider>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-4 border-t-2">
|
||||
<label class="ml-1">
|
||||
<span class="text-lg">Reset ASCIIBIRD state</span><br />
|
||||
<small>This will clear all data and start asciibird from a fresh state.</small><br />
|
||||
<div class="mt-1 p-2 bg-red-300 rounded-md cursor-pointer" @click="clearCache()">Clear and Reset ASCIIBIRD</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
@ -41,7 +79,6 @@
|
|||
<t-button
|
||||
type="button"
|
||||
class="p-2"
|
||||
@click="initiateNewAscii()"
|
||||
>
|
||||
Ok
|
||||
</t-button>
|
||||
|
@ -51,9 +88,16 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import vueSlider from 'vue-slider-component'
|
||||
import { maxBrushHistory,
|
||||
maxUndoHistory,
|
||||
tabLimit } from './../../ascii.js'
|
||||
|
||||
export default {
|
||||
name: "Options",
|
||||
components: {
|
||||
vueSlider,
|
||||
},
|
||||
created() {},
|
||||
mounted() {
|
||||
if (this.showOptionsModal) {
|
||||
|
@ -63,18 +107,39 @@ export default {
|
|||
}
|
||||
},
|
||||
data: () => ({
|
||||
forms: {
|
||||
createAscii: {
|
||||
width: 80,
|
||||
height: 30,
|
||||
title: "ascii",
|
||||
},
|
||||
},
|
||||
|
||||
// options: {
|
||||
// defaultBg: 1,
|
||||
// defaultFg: 0,
|
||||
// renderOffScreen: true,
|
||||
// undoLimit: 50,
|
||||
// tabLimit: 12,
|
||||
// fps: 50,
|
||||
// },
|
||||
|
||||
// forms: {
|
||||
// fps: this.options.fps,
|
||||
// renderOffScreen: true,
|
||||
// undoLimit: this.options.undoLimit,
|
||||
// tabLimit: this.options.tabLimit
|
||||
// },
|
||||
}),
|
||||
computed: {
|
||||
showOptionsModal() {
|
||||
return this.$store.getters.modalState.options;
|
||||
},
|
||||
options() {
|
||||
return this.$store.getters.options;
|
||||
},
|
||||
maxBrushHistory() {
|
||||
return maxBrushHistory;
|
||||
},
|
||||
maxUndoHistory() {
|
||||
return maxUndoHistory;
|
||||
},
|
||||
tabLimit() {
|
||||
return tabLimit;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
showOptionsModal(val) {
|
||||
|
@ -86,24 +151,27 @@ export default {
|
|||
this.close();
|
||||
}
|
||||
},
|
||||
// options:{
|
||||
// handler: function(val, old) {
|
||||
// this.$store.commit(updateOptions, val)
|
||||
// },
|
||||
// deep: true
|
||||
// }
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
this.$modal.show("options-modal");
|
||||
this.forms.createAscii.title = `New ASCII ${
|
||||
this.$store.getters.asciibirdMeta.length + 1
|
||||
}`;
|
||||
},
|
||||
close() {
|
||||
this.$modal.hide("options-modal");
|
||||
this.forms.createAscii.width = 80;
|
||||
this.forms.createAscii.height = 30;
|
||||
this.forms.createAscii.title = "New ASCII";
|
||||
},
|
||||
clearCache() {
|
||||
localStorage.clear();
|
||||
window.location.reload()
|
||||
},
|
||||
updateOptions() {
|
||||
this.$store.commit("updateOptions", { ...this.options})
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -19,14 +19,20 @@ export default {
|
|||
window.removeEventListener("keydown", this.keyListener.bind(this));
|
||||
},
|
||||
created() {
|
||||
console.log(this.canvasX);
|
||||
this.keyListener = function (e) {
|
||||
// Stop blocking input when modals are open
|
||||
// Whatever this char "'\0'" is it'd occur even without pressing any keys
|
||||
// This fixes it
|
||||
if (e.key === "\0" || this.isInputtingBrushSize || this.isKeyboardDisabled || this.isShowingDialog || this.isModalOpen) {
|
||||
|
||||
if (
|
||||
e.key === "\0" ||
|
||||
this.isInputtingBrushSize ||
|
||||
this.isKeyboardDisabled ||
|
||||
this.isShowingDialog ||
|
||||
this.isModalOpen
|
||||
) {
|
||||
if (e.key === "Enter" && this.isShowingDialog) {
|
||||
this.$dialog.hide('dialog-posthttp');
|
||||
this.$dialog.hide("dialog-posthttp");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -68,7 +74,10 @@ export default {
|
|||
const altKey = e.altKey;
|
||||
|
||||
// Used for text typing
|
||||
if (this.isTextEditing && this.haveOpenTabs) {
|
||||
if (
|
||||
(this.isTextEditing) &&
|
||||
this.haveOpenTabs
|
||||
) {
|
||||
this.canvasKeyDown(e.key);
|
||||
return;
|
||||
}
|
||||
|
@ -399,8 +408,20 @@ export default {
|
|||
data: () => ({
|
||||
isPressed: false,
|
||||
}),
|
||||
props: ["selectedBlocks", "textEditing", "selecting", "isInputtingBrushSize", "showingPostUrl", "isShowingDialog"],
|
||||
props: [
|
||||
"selectedBlocks",
|
||||
"textEditing",
|
||||
"selecting",
|
||||
"isInputtingBrushSize",
|
||||
"showingPostUrl",
|
||||
"isShowingDialog",
|
||||
"canvasX",
|
||||
"canvasY",
|
||||
],
|
||||
computed: {
|
||||
canvasXy() {
|
||||
return {x: this.canvasX, y: this.canvasY};
|
||||
},
|
||||
isModalOpen() {
|
||||
return this.$store.getters.isModalOpen;
|
||||
},
|
||||
|
@ -449,6 +470,9 @@ export default {
|
|||
isBrushing() {
|
||||
return this.currentTool.name === "brush";
|
||||
},
|
||||
isEraser() {
|
||||
return this.currentTool.name === "eraser";
|
||||
},
|
||||
isSelected() {
|
||||
return (
|
||||
this.selecting.startX >= 0 &&
|
||||
|
@ -504,7 +528,7 @@ export default {
|
|||
},
|
||||
isKeyboardDisabled() {
|
||||
return this.$store.getters.isKeyboardDisabled;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
undo() {
|
||||
|
@ -514,6 +538,43 @@ export default {
|
|||
this.$store.commit("redoBlocks");
|
||||
},
|
||||
canvasKeyDown(char) {
|
||||
// if (this.isBrushing || this.isEraser) {
|
||||
// switch (char) {
|
||||
// // Move the text indicator around with the arrow keys
|
||||
// case "ArrowUp":
|
||||
// if (this.currentAsciiLayerBlocks[this.canvasXy.y - 1][this.canvasXy.x]) {
|
||||
// this.canvasXy.y -= 1;
|
||||
// }
|
||||
// break;
|
||||
|
||||
// case "ArrowDown":
|
||||
// if (this.currentAsciiLayerBlocks[this.canvasXy.y + 1][this.canvasXy.x]) {
|
||||
// this.canvasXy.y += 1;
|
||||
// }
|
||||
// break;
|
||||
|
||||
// case "ArrowLeft":
|
||||
// if (this.currentAsciiLayerBlocks[this.canvasXy.y][this.canvasXy.x - 1]) {
|
||||
// this.canvasXy.x -= 1;
|
||||
// }
|
||||
// break;
|
||||
|
||||
// case "ArrowRight":
|
||||
// if (this.currentAsciiLayerBlocks[this.canvasXy.y][this.canvasXy.x + 1]) {
|
||||
// this.canvasXy.x += 1;
|
||||
// }
|
||||
// break;
|
||||
|
||||
// case " ":
|
||||
// this.$emit("triggerbrush");
|
||||
// return;
|
||||
// break;
|
||||
// }
|
||||
|
||||
// this.$emit("arrowkeys", this.canvasXy);
|
||||
|
||||
// }
|
||||
|
||||
if (this.isTextEditing) {
|
||||
if (
|
||||
this.currentAsciiLayerBlocks[this.textEditing.startY] &&
|
||||
|
|
|
@ -9,7 +9,6 @@ import store from './store';
|
|||
import Dashboard from './Dashboard.vue';
|
||||
import Toasted from 'vue-toasted';
|
||||
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
import {
|
||||
|
|
|
@ -9,8 +9,6 @@ import {
|
|||
getBlocksWidth,
|
||||
create2DArray,
|
||||
emptyBlock,
|
||||
maxBrushHistory,
|
||||
maxUndoHistory,
|
||||
mergeLayers
|
||||
} from "../ascii";
|
||||
|
||||
|
@ -37,6 +35,7 @@ export default new Vuex.Store({
|
|||
defaultFg: 0,
|
||||
renderOffScreen: true,
|
||||
undoLimit: 50,
|
||||
brushLimit: 50,
|
||||
tabLimit: 12,
|
||||
fps: 50,
|
||||
},
|
||||
|
@ -111,6 +110,9 @@ export default new Vuex.Store({
|
|||
changeState(state, payload) {
|
||||
Object.assign(state, payload);
|
||||
},
|
||||
updateOptions(state, payload) {
|
||||
state.options = { ... payload};
|
||||
},
|
||||
changeTab(state, payload) {
|
||||
state.tab = payload;
|
||||
document.title = `asciibird - ${state.asciibirdMeta[payload].title}`;
|
||||
|
@ -202,7 +204,7 @@ export default new Vuex.Store({
|
|||
state.toolbarState.mirrorY = payload.y;
|
||||
},
|
||||
updateAsciiBlocks(state, payload, skipUndo = false) {
|
||||
if (state.asciibirdMeta[state.tab].history.length >= maxUndoHistory) {
|
||||
if (state.asciibirdMeta[state.tab].history.length >= state.options.undoLimit) {
|
||||
state.asciibirdMeta[state.tab].history.shift()
|
||||
}
|
||||
|
||||
|
@ -428,8 +430,7 @@ export default new Vuex.Store({
|
|||
// Brush Library
|
||||
pushBrushHistory(state, payload) {
|
||||
// Check and remove duplicate brushes based on hash value
|
||||
console.log(state.brushHistory.length, maxBrushHistory)
|
||||
if (state.brushHistory.length >= maxBrushHistory) {
|
||||
if (state.brushHistory.length >= state.options.brushLimit) {
|
||||
state.brushHistory.pop();
|
||||
}
|
||||
|
||||
|
|
|
@ -113,8 +113,10 @@ export default {
|
|||
new: [],
|
||||
old: [],
|
||||
},
|
||||
|
||||
isUsingKeyboard: false,
|
||||
}),
|
||||
props: ["updateCanvas", "yOffset"],
|
||||
props: ["updateCanvas", "yOffset", "canvasxy", "brush"],
|
||||
computed: {
|
||||
canvasRef() {
|
||||
return this.$refs.canvas;
|
||||
|
@ -181,6 +183,9 @@ export default {
|
|||
isBrushing() {
|
||||
return this.currentTool.name === "brush";
|
||||
},
|
||||
isErasing() {
|
||||
return this.currentTool.name === "eraser";
|
||||
},
|
||||
isSelected() {
|
||||
return (
|
||||
this.selecting.startX !== null &&
|
||||
|
@ -377,6 +382,22 @@ export default {
|
|||
// }
|
||||
|
||||
// },
|
||||
// canvasxy(val,old) {
|
||||
// if ((this.isBrushing || this.isErasing) && isUsingKeyboard) {
|
||||
// this.x = val.x;
|
||||
// this.y = val.y;
|
||||
|
||||
// let e = {offsetX: (this.x), offsetY: (this.y)}
|
||||
// this.canvasMouseMove(e)
|
||||
// }
|
||||
// },
|
||||
// brush(val, old) {
|
||||
// console.log({triggerbrush: val})
|
||||
// if (val !== old) {
|
||||
// this.canvasMouseDown()
|
||||
// this.canvasMouseUp()
|
||||
// }
|
||||
// }
|
||||
},
|
||||
methods: {
|
||||
warnInvisibleLayer() {
|
||||
|
@ -1350,6 +1371,14 @@ export default {
|
|||
);
|
||||
},
|
||||
fillTool(fillBlocks, y, x, current, eraser) {
|
||||
if (y >= Math.floor(this.canvas.height / blockHeight)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (x >= Math.floor(this.canvas.width / blockWidth)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fillBlocks[y] === undefined || fillBlocks[y][x] === undefined) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -9466,6 +9466,11 @@ vue-loader@^15.9.2:
|
|||
vue-hot-reload-api "^2.3.0"
|
||||
vue-style-loader "^4.1.0"
|
||||
|
||||
vue-slider-component@^2.8.16:
|
||||
version "2.8.16"
|
||||
resolved "https://registry.yarnpkg.com/vue-slider-component/-/vue-slider-component-2.8.16.tgz#b2036f816ed64fa4fcd6741219b80c5063b4fd60"
|
||||
integrity sha512-06gDoheKMU8TdqjoofIJaYfXw3uuWOXF2I14d/F5yW/8iOxnoI4Ks9WSXy8RWY+gs62GBE6tQXHDSX/H6IOaAw==
|
||||
|
||||
vue-style-loader@^4.1.0, vue-style-loader@^4.1.2:
|
||||
version "4.1.3"
|
||||
resolved "https://registry.yarnpkg.com/vue-style-loader/-/vue-style-loader-4.1.3.tgz#6d55863a51fa757ab24e89d9371465072aa7bc35"
|
||||
|
|
Loading…
Reference in New Issue