asciibird/src/components/parts/KeyboardShortcuts.vue

673 lines
19 KiB
Vue

<template>
<div />
</template>
<script>
import {
toolbarIcons,
maxBrushSize,
filterNullBlocks,
getBlocksWidth,
emptyBlock,
exportMirc,
downloadFile,
} from "../../ascii";
export default {
name: "KeyboardShortcuts",
created() {
const thisIs = this;
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 (this.isModalOpen || e.key === "\0") {
return;
}
e.preventDefault();
// When press escape go back to default took
if (e.key === "Escape" && !this.isDefault && this.haveOpenTabs) {
this.$emit("updatecanvas");
this.$store.commit("changeTool", 0);
return;
}
// Change char when car picker is open
if (this.toolbarState.isChoosingChar && e.key.length === 1 && this.haveOpenTabs) {
this.$store.commit("changeChar", e.key);
return;
}
// Keys without any ctrl, shift or alt are also integrated
// and are available only in their toolbar context
// for example pressing E in default mode will toggle edit ascii
// E in text mode will type the character E
// E in brush mode will flip the brush
// Copy and paste,
const ctrlKey = e.ctrlKey || e.metaKey;
// Files / system related
const shiftKey = e.shiftKey;
// Alt key functions are toolbar related
const altKey = e.altKey;
// Used for text typing
if (this.isTextEditing && this.haveOpenTabs) {
thisIs.canvasKeyDown(e.key);
return;
}
// Show / hide grid view
if (e.key === "g" && altKey) {
this.$store.commit("toggleGridView", !this.gridView && this.haveOpenTabs);
return;
}
// Ctrl Z here
// skg - thanks for mac key suggestion, bro
if (e.key === "z" && ctrlKey && this.haveOpenTabs) {
this.undo();
return;
}
// Ctrl Y here
if (e.key === "y" && ctrlKey && this.haveOpenTabs) {
this.redo();
return;
}
// Change toolbar icon
if (
Number.parseInt(e.key) >= 1 &&
Number.parseInt(e.key) <= 8 &&
!this.toolbarState.isChoosingFg &&
!this.toolbarState.isChoosingBg &&
altKey && this.haveOpenTabs
) {
this.$store.commit("changeTool", Number.parseInt(e.key - 1));
this.$emit("updatecanvas");
return;
}
// Swap colours
if (e.key === "r" && altKey && this.haveOpenTabs) {
let bg = this.currentBg;
let fg = this.currentFg;
this.$store.commit("changeColourFg", bg);
this.$store.commit("changeColourBg", fg);
return;
}
// Show FG
if (e.key === "f" && altKey && !ctrlKey && this.haveOpenTabs) {
this.$store.commit(
"changeIsUpdatingFg",
!this.toolbarState.isChoosingFg
);
return;
}
// Show BG
if (e.key === "b" && altKey && !ctrlKey && this.haveOpenTabs) {
this.$store.commit(
"changeIsUpdatingBg",
!this.toolbarState.isChoosingBg
);
return;
}
// Show Character select
if (e.key === "c" && altKey && !ctrlKey && this.haveOpenTabs) {
this.$store.commit(
"changeIsUpdatingChar",
!this.toolbarState.isChoosingChar
);
return;
}
// Choose FG or BG with Keyboard
if (
Number.parseInt(e.key) >= 0 &&
Number.parseInt(e.key) <= 9 &&
(this.toolbarState.isChoosingFg || this.toolbarState.isChoosingBg) && this.haveOpenTabs
) {
if (this.toolbarState.isChoosingFg) {
this.$store.commit("changeColourFg", Number.parseInt(e.key));
return;
}
if (this.toolbarState.isChoosingBg) {
this.$store.commit("changeColourBg", Number.parseInt(e.key));
return;
}
}
// Ctrl C - copy blocks
if (e.key === "c" && ctrlKey && !shiftKey && this.haveOpenTabs) {
if (this.selectedBlocks.length) {
this.$store.commit(
"selectBlocks",
filterNullBlocks(this.selectedBlocks)
);
this.$toasted.show("Copied blocks!", {
type: "success",
icon: "fa-check-circle",
});
}
return;
}
// Delte blocks but do not save them when pressing Delete when selected
if (e.key === "Delete" && this.haveOpenTabs) {
console.log(getBlocksWidth(this.selectedBlocks));
if (this.selectedBlocks.length) {
for (let y = 0; y < this.selectedBlocks.length + 1; y++) {
for (let x = 0; x < getBlocksWidth(this.selectedBlocks) + 1; x++) {
if (this.selectedBlocks[y] && this.selectedBlocks[y][x]) {
this.currentAsciiLayerBlocks[y][x] = { ...emptyBlock };
}
}
}
// Reset and hide the select after successful copy
this.$store.commit("updateAsciiBlocks", this.currentAsciiLayerBlocks);
this.$emit("updatecanvas");
this.$toasted.show("Deleted blocks!", {
type: "success",
icon: "fa-check-circle",
});
}
return;
}
// Ctrl X - cut blocks
if (e.key === "x" && ctrlKey && !shiftKey && this.haveOpenTabs) {
if (this.selectedBlocks.length) {
for (let y = 0; y < this.selectedBlocks.length + 1; y++) {
for (let x = 0; x < getBlocksWidth(this.selectedBlocks) + 1; x++) {
if (this.selectedBlocks[y] && this.selectedBlocks[y][x]) {
this.currentAsciiLayerBlocks[y][x] = { ...emptyBlock };
}
}
}
this.$store.commit(
"selectBlocks",
filterNullBlocks(this.selectedBlocks)
);
this.selectedBlocks = [];
// Reset and hide the select after successful copy
this.$store.commit("updateAsciiBlocks", this.currentAsciiLayerBlocks);
this.$emit("updatecanvas");
this.$toasted.show("Cut blocks!", {
type: "success",
icon: "fa-check-circle",
});
}
return;
}
// Ctrl V - paste blocks
if (e.key === "v" && ctrlKey && this.haveOpenTabs) {
if (this.haveSelectBlocks) {
this.$store.commit("pushBrushHistory", this.brushBlocks);
this.$store.commit("brushBlocks", this.selectBlocks);
this.$store.commit("changeTool", 4);
}
return;
}
// Show / hide debug panel
if (e.key === "d" && this.isDefault && this.haveOpenTabs) {
this.$store.commit("toggleDebugPanel", !this.debugPanelState.visible);
return;
}
// Show / hide brush library
if (e.key === "l" && this.isDefault && this.haveOpenTabs) {
this.$store.commit(
"toggleBrushLibrary",
!this.brushLibraryState.visible
);
return;
}
// New ASCII
// Ctrl N doesn't seem to work in chrome? https://github.com/liftoff/GateOne/issues/290
if (e.key === "n" && this.isDefault && !this.isTextEditing) {
this.$store.commit("openModal", "new-ascii");
return;
}
// Edit ASCII
if (e.key === "e" && this.isDefault && !this.isTextEditing && this.haveOpenTabs) {
this.$store.commit("openModal", "edit-ascii");
return;
}
// Paste ASCII
if (e.key === "p" && this.isDefault && !this.isTextEditing) {
this.$store.commit("openModal", "paste-ascii");
return;
}
// Export to clipboard
if (e.key === "C" && ctrlKey && shiftKey && this.haveOpenTabs) {
let ascii = exportMirc();
this.$copyText(ascii.output.join("")).then(
(e) => {
this.$toasted.show("Copied mIRC to clipboard!", {
type: "success",
});
},
(e) => {
this.$toasted.show("Error when copying mIRC to clipboard!", {
type: "error",
});
}
);
return;
}
// Export to txt
if (e.key === "F" && ctrlKey && shiftKey && this.haveOpenTabs) {
let ascii = exportMirc();
downloadFile(ascii.output.join(""), ascii.filename, "text/plain");
return;
}
if (
e.key === "]" &&
ctrlKey &&
this.brushSizeHeight < maxBrushSize &&
this.brushSizeHeight >= 1 &&
this.brushSizeWidth < maxBrushSize &&
this.brushSizeWidth >= 1 && this.haveOpenTabs
) {
this.$store.commit("updateBrushSize", {
brushSizeHeight: parseInt(this.brushSizeHeight) + 1,
brushSizeWidth: parseInt(this.brushSizeWidth) + 1,
brushSizeType: this.brushSizeType,
});
return;
}
if (
e.key === "[" &&
ctrlKey &&
this.brushSizeHeight <= maxBrushSize &&
this.brushSizeHeight > 1 &&
this.brushSizeWidth <= maxBrushSize &&
this.brushSizeWidth > 1 && this.haveOpenTabs
) {
this.$store.commit("updateBrushSize", {
brushSizeHeight: parseInt(this.brushSizeHeight) - 1,
brushSizeWidth: parseInt(this.brushSizeWidth) - 1,
brushSizeType: this.brushSizeType,
});
return;
}
// Hopefully we can still pick up the previous inputs
// while in brush mode
if (this.isBrushing && this.haveOpenTabs) {
if (e.key === "e") {
this.$store.commit("flipRotateBlocks", {
type: "flip",
});
}
if (e.key === "q") {
this.$store.commit("flipRotateBlocks", {
type: "rotate",
});
}
return;
}
};
document.addEventListener("keydown", this.keyListener.bind(this));
},
props: ["selectedBlocks", "textEditing"],
computed: {
isModalOpen() {
return this.$store.getters.isModalOpen;
},
brushSizeHeight() {
return this.$store.getters.brushSizeHeight;
},
brushSizeWidth() {
return this.$store.getters.brushSizeWidth;
},
brushSizeType() {
return this.$store.getters.brushSizeType;
},
currentAscii() {
return this.$store.getters.currentAscii;
},
currentAsciiBlocks() {
return this.$store.getters.currentAsciiBlocks;
},
currentTool() {
return toolbarIcons[this.$store.getters.currentTool];
},
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;
},
isTextEditing() {
return this.currentTool.name === "text";
},
isSelecting() {
return this.currentTool.name === "select";
},
isDefault() {
return this.currentTool.name === "default";
},
isBrushing() {
return this.currentTool.name === "brush";
},
isSelected() {
return (
this.selecting.startX &&
this.selecting.startY &&
this.selecting.endX &&
this.selecting.endY
);
},
brushBlocks() {
return this.$store.getters.brushBlocks;
},
toolbarState() {
return this.$store.getters.toolbarState;
},
mirrorX() {
return this.toolbarState.mirrorX;
},
mirrorY() {
return this.toolbarState.mirrorY;
},
debugPanelState() {
return this.$store.getters.debugPanel;
},
selectBlocks() {
return this.$store.getters.selectBlocks;
},
haveSelectBlocks() {
return !!this.selectBlocks.length;
},
brushLibraryState() {
return this.$store.getters.brushLibraryState;
},
currentAsciiLayers() {
return this.$store.getters.currentAsciiLayers;
},
currentSelectedLayer() {
return this.currentAsciiLayers[this.currentAscii.selectedLayer];
},
currentAsciiLayerBlocks() {
return this.currentSelectedLayer.data;
},
currentAsciiWidth() {
return this.currentSelectedLayer.width;
},
currentAsciiHeight() {
return this.currentSelectedLayer.height;
},
haveOpenTabs() {
return this.$store.getters.currentAscii !== false
}
},
methods: {
filterNullBlocks(val) {
return filterNullBlocks(val);
},
undo() {
this.$store.commit("undoBlocks");
},
redo() {
this.$store.commit("redoBlocks");
},
canvasKeyDown(char) {
if (this.isTextEditing) {
if (
this.currentAsciiLayerBlocks[this.textEditing.startY] &&
this.currentAsciiLayerBlocks[this.textEditing.startY][
this.textEditing.startX
]
) {
let targetBlock =
this.currentAsciiLayerBlocks[this.textEditing.startY][
this.textEditing.startX
];
switch (char) {
// Remove a character
case "Backspace":
if (
this.currentAsciiLayerBlocks[this.textEditing.startY][
this.textEditing.startX - 1
]
) {
targetBlock =
this.currentAsciiLayerBlocks[this.textEditing.startY][
this.textEditing.startX - 1
];
this.currentAsciiLayerBlocks[this.textEditing.startY][
this.textEditing.startX - 1
].char = null;
this.textEditing.startX -= 1;
}
// Remove char as current position, but don't change position after
case "Delete":
if (
this.currentAsciiLayerBlocks[this.textEditing.startY][
this.textEditing.startX
]
) {
targetBlock =
this.currentAsciiLayerBlocks[this.textEditing.startY][
this.textEditing.startX
];
this.currentAsciiLayerBlocks[this.textEditing.startY][
this.textEditing.startX
].char = null;
}
// Also remove in mirror mode the other chars
if (this.mirrorX) {
targetBlock =
this.currentAsciiLayerBlocks[this.textEditing.startY][
this.currentAsciiWidth - this.textEditing.startX
];
targetBlock.char = null;
}
if (this.mirrorY) {
targetBlock =
this.currentAsciiLayerBlocks[
this.currentAsciiHeight - this.textEditing.startY
][this.textEditing.startX];
targetBlock.char = null;
}
if (this.mirrorY && this.mirrorX) {
targetBlock =
this.currentAsciiLayerBlocks[
this.currentAsciiHeight - this.textEditing.startY
][this.currentAsciiWidth - this.textEditing.startX];
targetBlock.char = null;
}
break;
// Jump to next line at the 0 X position
case "Enter":
if (
this.currentAsciiLayerBlocks[this.textEditing.startY + 1][0]
) {
this.textEditing.startX = 0;
this.textEditing.startY += 1;
}
break;
// Move the text indicator around with the arrow keys
case "ArrowUp":
if (
this.currentAsciiLayerBlocks[this.textEditing.startY - 1][
this.textEditing.startX
]
) {
this.textEditing.startY -= 1;
}
break;
case "ArrowDown":
if (
this.currentAsciiLayerBlocks[this.textEditing.startY + 1][
this.textEditing.startX
]
) {
this.textEditing.startY += 1;
}
break;
case "ArrowLeft":
if (
this.currentAsciiLayerBlocks[this.textEditing.startY][
this.textEditing.startX - 1
]
) {
this.textEditing.startX -= 1;
}
break;
case "ArrowRight":
if (
this.currentAsciiLayerBlocks[this.textEditing.startY][
this.textEditing.startX + 1
]
) {
this.textEditing.startX += 1;
}
break;
// Normal typing
default:
if (char.length === 1) {
if (this.canFg) {
targetBlock.fg = this.currentFg;
}
targetBlock.char = char;
if (this.mirrorX) {
targetBlock =
this.currentAsciiLayerBlocks[this.textEditing.startY][
this.currentAsciiWidth - this.textEditing.startX
];
if (this.canFg) {
targetBlock.fg = this.currentFg;
}
targetBlock.char = char;
}
if (this.mirrorY) {
targetBlock =
this.currentAsciiLayerBlocks[
this.currentAsciiHeight - this.textEditing.startY
][this.textEditing.startX];
if (this.canFg) {
targetBlock.fg = this.currentFg;
}
targetBlock.char = char;
}
if (this.mirrorY && this.mirrorX) {
targetBlock =
this.currentAsciiLayerBlocks[
this.currentAsciiHeight - this.textEditing.startY
][this.currentAsciiWidth - this.textEditing.startX];
if (this.canFg) {
targetBlock.fg = this.currentFg;
}
targetBlock.char = char;
}
if (
this.currentAsciiLayerBlocks[this.textEditing.startY][
this.textEditing.startX + 1
]
) {
this.textEditing.startX++;
} else {
this.textEditing.startX = 0;
if (this.textEditing.startY < this.currentAsciiHeight) {
this.textEditing.startY++;
}
}
}
break;
}
}
// Emit back to dashboard then to editor that we need to redraw the canvas
this.$emit("updatecanvas");
}
},
},
};
</script>