Added basic structure and comments for Tools

Fixed lpe palette loading, added custom events
This commit is contained in:
unsettledgames 2021-10-25 19:23:06 +02:00
parent a930fabcba
commit 0fcb309cc7
10 changed files with 131 additions and 13 deletions

View File

@ -4,6 +4,10 @@ This is a browser based software for creating pixel art
The tool can be viewed online here: https://lospec.com/pixel-editor The tool can be viewed online here: https://lospec.com/pixel-editor
## How to contribute
Please do not submit pull requests with new features or core changes. Instead, please file an issue first for discussion.
## What to Contribute ## What to Contribute
Any changes that fix bugs or add features are welcome. Any changes that fix bugs or add features are welcome.
@ -15,10 +19,9 @@ Suggestions / Planned features:
- Documentation - Documentation
- Possibility to hide and resize menus (layers, palette) - Possibility to hide and resize menus (layers, palette)
- Line tool
- Tiled mode - Tiled mode
- Load palette from LPE file - Load palette from LPE file
- Symmetry options - Symmetry options (currently being worked on)
- Mobile - Mobile
- Touch equivalent for mouse clicks - Touch equivalent for mouse clicks

View File

@ -69,6 +69,8 @@
} }
#brush-preview { #brush-preview {
background-color:black;
opacity:0.3;
position: absolute; position: absolute;
border: solid 1px #fff; border: solid 1px #fff;
z-index: 1200; z-index: 1200;

View File

@ -98,8 +98,7 @@ const ColorModule = (() => {
//left clicked color //left clicked color
if (e.which == 1) { if (e.which == 1) {
// remove current color selection // remove current color selection
var selectedColor = document.querySelector('#colors-menu li.selected'); document.querySelector('#colors-menu li.selected')?.classList.remove('selected');
if (selectedColor) selectedColor.classList.remove('selected');
//set current color //set current color
updateCurrentColor(e.target.style.backgroundColor); updateCurrentColor(e.target.style.backgroundColor);
@ -125,7 +124,7 @@ const ColorModule = (() => {
const newColor = new Color("hsv", Math.floor(Math.random()*360), Math.floor(Math.random()*100), Math.floor(Math.random()*100)).hex; const newColor = new Color("hsv", Math.floor(Math.random()*360), Math.floor(Math.random()*100), Math.floor(Math.random()*100)).hex;
//remove current color selection //remove current color selection
document.querySelector('#colors-menu li.selected').classList.remove('selected'); document.querySelector('#colors-menu li.selected')?.classList.remove('selected');
//add new color and make it selected //add new color and make it selected
let addedColor = addColor(newColor); let addedColor = addColor(newColor);
@ -369,8 +368,7 @@ const ColorModule = (() => {
if (newColRgb.r + newColRgb.g + newColRgb.b < darkestColorRgb.r + darkestColorRgb.g + darkestColorRgb.b) { if (newColRgb.r + newColRgb.g + newColRgb.b < darkestColorRgb.r + darkestColorRgb.g + darkestColorRgb.b) {
//remove current color selection //remove current color selection
var selectedColor = document.querySelector('#colors-menu li.selected'); document.querySelector('#colors-menu li.selected')?.classList.remove('selected');
if (selectedColor) selectedColor.classList.remove('selected');
//set as current color //set as current color
newColorElement.classList.add('selected'); newColorElement.classList.add('selected');

View File

@ -1,4 +1,6 @@
class Events { class Events {
customCallback = {};
/** Used to programmatically create an input event /** Used to programmatically create an input event
* *
* @param {*} keyCode KeyCode of the key to press * @param {*} keyCode KeyCode of the key to press
@ -89,6 +91,13 @@ class Events {
return element; return element;
} }
/** Register a callback for a certain window event
*
* @param {*} event The event to register to
* @param {*} elementId The id of the element that will listen to the event
* @param {*} functionCallback The function to callback when the event is shoot
* @param {...any} args Arguments for the callback
*/
static on(event, elementId, functionCallback, ...args) { static on(event, elementId, functionCallback, ...args) {
//if element provided is string, get the actual element //if element provided is string, get the actual element
const element = Util.getElement(elementId); const element = Util.getElement(elementId);
@ -99,6 +108,14 @@ class Events {
}); });
} }
/** Register a callback for a certain window event that is shot by the children of
* an element passed as an argument
*
* @param {*} event The event to register to
* @param {*} elementId The id of the element whose children will listen to the event
* @param {*} functionCallback The function to callback when the event is shoot
* @param {...any} args Arguments for the callback
*/
static onChildren(event, parentElement, functionCallback, ...args) { static onChildren(event, parentElement, functionCallback, ...args) {
parentElement = Util.getElement(parentElement); parentElement = Util.getElement(parentElement);
const children = parentElement.children; const children = parentElement.children;
@ -108,4 +125,27 @@ class Events {
on(event, children[i], functionCallback, ...args); on(event, children[i], functionCallback, ...args);
} }
} }
/** Registers a callback for a custom (non HTML) event
*
* @param {*} event The event to register to
* @param {*} functionCallback The function to call
*/
static onCustom(event, functionCallback) {
if (customCallback[event] === undefined)
customCallback[event] = [];
customCallback[event].push(functionCallback);
}
/** Emits a custom (non HTML) event
*
* @param {*} event The event to emit
* @param {...any} args The arguments for that event
*/
static emit(event, ...args) {
if (customCallback[event] != undefined)
for (let i=0; i<customCallback[event].length; i++)
customCallback[event][i](args);
}
} }

View File

@ -180,6 +180,9 @@ const FileManager = (() => {
reader.onload = function (e) { reader.onload = function (e) {
let dictionary = JSON.parse(e.target.result); let dictionary = JSON.parse(e.target.result);
Startup.newPixel(dictionary['canvasWidth'], dictionary['canvasHeight'], dictionary); Startup.newPixel(dictionary['canvasWidth'], dictionary['canvasHeight'], dictionary);
for (let i=0; i<dictionary['color' + i] != null; i++) {
ColorModule.addColor(dictionary['color'+i]);
}
} }
} }

View File

@ -23,7 +23,7 @@ class Layer {
this.canvasSize = [width, height]; this.canvasSize = [width, height];
// REFACTOR: the canvas should actually be a Canvas instance // REFACTOR: the canvas should actually be a Canvas instance
this.canvas = Util.getElement(canvas); this.canvas = Util.getElement(canvas);
// REFACOTR: the context could be an attribute of the canvas class, but it's a bit easier // REFACTOR: the context could be an attribute of the canvas class, but it's a bit easier
// to just type layer.context, we should discuss this // to just type layer.context, we should discuss this
this.context = this.canvas.getContext('2d'); this.context = this.canvas.getContext('2d');
this.isSelected = false; this.isSelected = false;

View File

@ -1,5 +1,3 @@
// REFACTOR: convert to IIFE
const Settings = (() => { const Settings = (() => {
let settings; let settings;
let settingsFromCookie; let settingsFromCookie;

14
js/ToolManager.js Normal file
View File

@ -0,0 +1,14 @@
const ToolManager = (() => {
/** What it should do
*
* - Listen to mouse events
* - Bind mouse events
* - Call tool functions
*
*
*/
return {
}
})

View File

@ -100,8 +100,7 @@ window.addEventListener("mouseup", function (mouseEvent) {
//if picked color matches this color //if picked color matches this color
if (newColor == colors[i].jscolor.toString()) { if (newColor == colors[i].jscolor.toString()) {
//remove current color selection //remove current color selection
let selectedColor = document.querySelector("#colors-menu li.selected") document.querySelector("#colors-menu li.selected")?.classList.remove("selected");
if (selectedColor) selectedColor.classList.remove("selected");
//set current color //set current color

View File

@ -4,6 +4,51 @@ var tool = {};
//class for tools //class for tools
class Tool { class Tool {
name = "AbstractTool";
cursorType = {};
cursorHTMLElement = undefined;
currBrushSize = 1;
prevBrushSize = 1;
startMousePos = {};
prevMousePos = {};
endMousePos = {};
onSelect() {
}
onHover(cursorPosition) {
let toSub = 1;
// Prevents the brush to be put in the middle of pixels
if (this.currentBrushSize % 2 == 0) {
toSub = 0.5;
}
brushPreview.style.left = (Math.floor(cursorLocation[0] / zoom) * zoom + currentLayer.canvas.offsetLeft - this.currentBrushSize * zoom / 2 - zoom / 2 + toSub * zoom) + 'px';
brushPreview.style.top = (Math.floor(cursorLocation[1] / zoom) * zoom + currentLayer.canvas.offsetTop - this.currentBrushSize * zoom / 2 - zoom / 2 + toSub * zoom) + 'px';
}
onDeselect() {
}
onStart() {
}
onDrag() {
}
onEnd() {
}
updateCursor2() {
}
constructor (name, options) { constructor (name, options) {
//stores the name in object, only needed for legacy functions from when currentTool was just a string //stores the name in object, only needed for legacy functions from when currentTool was just a string
@ -102,4 +147,20 @@ class Tool {
} }
/*global dragging currentTool, currentToolTemp, selectionCanceled, endSelection*/ /*global dragging currentTool, currentToolTemp, selectionCanceled, endSelection*/
/**
* Class selectionTool extends Tool {
* imageDataToMove
* startDataPos
* currDataPos
* finalDataPos
* canMove
*
* movePreview()
*
* // start and end selection just overwrite the onStart and onEnd methods
*
* }
*
*/