public/js/freehand_tools.js
function createPanelCursor(divElement) {
"use strict";
var cursor = createCanvas(0, 0);
cursor.classList.add("cursor");
divElement.appendChild(cursor);
function show() {
cursor.style.display = "block";
}
function hide() {
cursor.style.display = "none";
}
function resize(width, height) {
cursor.style.width = width + "px";
cursor.style.height = height + "px";
}
function setPos(x, y) {
cursor.style.left = x - 1 + "px";
cursor.style.top = y - 1 + "px";
}
return {
"show": show,
"hide": hide,
"resize": resize,
"setPos": setPos
};
}
function createFloatingPanelPalette(width, height) {
"use strict";
var canvasContainer = document.createElement("DIV");
var cursor = createPanelCursor(canvasContainer);
var canvas = createCanvas(width, height);
canvasContainer.appendChild(canvas);
var ctx = canvas.getContext("2d");
var imageData = new Array(16);
function generateSwatch(colour) {
imageData[colour] = ctx.createImageData(width / 8, height / 2);
var rgba = palette.getRGBAColour(colour);
for (var y = 0, i = 0; y < imageData[colour].height; y++) {
for (var x = 0; x < imageData[colour].width; x++, i += 4) {
imageData[colour].data.set(rgba, i);
}
}
}
function generateSwatches() {
for (var colour = 0; colour < 16; colour++) {
generateSwatch(colour);
}
}
function redrawSwatch(colour) {
ctx.putImageData(imageData[colour], (colour % 8) * (width / 8), (colour > 7) ? 0 : (height / 2));
}
function redrawSwatches() {
for (var colour = 0; colour < 16; colour++) {
redrawSwatch(colour);
}
}
function mouseDown(evt) {
var rect = canvas.getBoundingClientRect();
var mouseX = evt.clientX - rect.left;
var mouseY = evt.clientY - rect.top;
var colour = Math.floor(mouseX / (width / 8)) + ((mouseY < (height / 2)) ? 8 : 0);
if (evt.ctrlKey === false && evt.altKey === false) {
palette.setForegroundColour(colour);
} else {
palette.setBackgroundColour(colour);
}
}
function updateColour(colour) {
generateSwatch(colour);
redrawSwatch(colour);
}
function updatePalette() {
for (var colour = 0; colour < 16; colour++) {
updateColour(colour);
}
}
function getElement() {
return canvasContainer;
}
function updateCursor(colour) {
cursor.resize(width / 8, height / 2);
cursor.setPos((colour % 8) * (width / 8), (colour > 7) ? 0 : (height / 2));
}
function onForegroundChange(evt) {
updateCursor(evt.detail);
}
function resize(newWidth, newHeight) {
width = newWidth;
height = newHeight;
canvas.width = width;
canvas.height = height;
generateSwatches();
redrawSwatches();
updateCursor(palette.getForegroundColour());
}
generateSwatches();
redrawSwatches();
updateCursor(palette.getForegroundColour());
canvas.addEventListener("mousedown", mouseDown);
canvas.addEventListener("contextmenu", (evt) => {
evt.preventDefault();
});
document.addEventListener("onForegroundChange", onForegroundChange);
return {
"updateColour": updateColour,
"updatePalette": updatePalette,
"getElement": getElement,
"showCursor": cursor.show,
"hideCursor": cursor.hide,
"resize": resize
};
}
function createFloatingPanel(x, y) {
"use strict";
var panel = document.createElement("DIV");
panel.classList.add("floating-panel");
$("body-container").appendChild(panel);
var enabled = false;
var prev;
function setPos(newX, newY) {
panel.style.left = newX + "px";
x = newX;
panel.style.top = newY + "px";
y = newY;
}
function mousedown(evt) {
prev = [evt.clientX, evt.clientY];
}
function touchMove(evt) {
if (evt.which === 1 && prev !== undefined) {
evt.preventDefault();
evt.stopPropagation();
var rect = panel.getBoundingClientRect();
setPos(rect.left + (evt.touches[0].pageX - prev[0]), rect.top + (evt.touches[0].pageY - prev[1]));
prev = [evt.touches[0].pageX, evt.touches[0].pageY];
}
}
function mouseMove(evt) {
if (evt.which === 1 && prev !== undefined) {
evt.preventDefault();
evt.stopPropagation();
var rect = panel.getBoundingClientRect();
setPos(rect.left + (evt.clientX - prev[0]), rect.top + (evt.clientY - prev[1]));
prev = [evt.clientX, evt.clientY];
}
}
function mouseUp() {
prev = undefined;
}
function enable() {
panel.classList.add("enabled");
enabled = true;
document.addEventListener("touchmove", touchMove);
document.addEventListener("mousemove", mouseMove);
document.addEventListener("mouseup", mouseUp);
}
function disable() {
panel.classList.remove("enabled");
enabled = false;
document.removeEventListener("touchmove", touchMove);
document.removeEventListener("mousemove", mouseMove);
document.removeEventListener("mouseup", mouseUp);
}
function append(element) {
panel.appendChild(element);
}
setPos(x, y);
panel.addEventListener("mousedown", mousedown);
return {
"setPos": setPos,
"enable": enable,
"disable": disable,
"append": append
};
}
function createFreehandController(panel) {
"use strict";
var prev = {};
var drawMode;
function line(x0, y0, x1, y1, callback) {
var dx = Math.abs(x1 - x0);
var sx = (x0 < x1) ? 1 : -1;
var dy = Math.abs(y1 - y0);
var sy = (y0 < y1) ? 1 : -1;
var err = ((dx > dy) ? dx : -dy) / 2;
var e2;
while (true) {
callback(x0, y0);
if (x0 === x1 && y0 === y1) {
break;
}
e2 = err;
if (e2 > -dx) {
err -= dy;
x0 += sx;
}
if (e2 < dy) {
err += dx;
y0 += sy;
}
}
}
function draw(coords) {
if (prev.x !== coords.x || prev.y !== coords.y || prev.halfBlockY !== coords.halfBlockY) {
if (drawMode.halfBlockMode === true) {
var colour = (coords.leftMouseButton === true) ? palette.getForegroundColour() : palette.getBackgroundColour();
if (Math.abs(prev.x - coords.x) > 1 || Math.abs(prev.halfBlockY - coords.halfBlockY) > 1) {
textArtCanvas.drawHalfBlock((callback) => {
line(prev.x, prev.halfBlockY, coords.x, coords.halfBlockY, (x, y) => {
callback(colour, x, y);
});
});
} else {
textArtCanvas.drawHalfBlock((callback) => {
callback(colour, coords.x, coords.halfBlockY);
});
}
} else {
if (Math.abs(prev.x - coords.x) > 1 || Math.abs(prev.y - coords.y) > 1) {
textArtCanvas.draw((callback) => {
line(prev.x, prev.y, coords.x, coords.y, (x, y) => {
callback(drawMode.charCode, drawMode.foreground, drawMode.background, x, y);
});
}, false);
} else {
textArtCanvas.draw((callback) => {
callback(drawMode.charCode, drawMode.foreground, drawMode.background, coords.x, coords.y);
}, false);
}
}
positionInfo.update(coords.x, coords.y);
prev = coords;
}
}
function canvasUp() {
prev = {};
}
function canvasDown(evt) {
drawMode = panel.getMode();
textArtCanvas.startUndo();
draw(evt.detail);
}
function canvasDrag(evt) {
draw(evt.detail);
}
function enable() {
document.addEventListener("onTextCanvasDown", canvasDown);
document.addEventListener("onTextCanvasUp", canvasUp);
document.addEventListener("onTextCanvasDrag", canvasDrag);
panel.enable();
}
function disable() {
document.removeEventListener("onTextCanvasDown", canvasDown);
document.removeEventListener("onTextCanvasUp", canvasUp);
document.removeEventListener("onTextCanvasDrag", canvasDrag);
panel.disable();
}
return {
"enable": enable,
"disable": disable,
"select": panel.select,
"ignore": panel.ignore,
"unignore": panel.unignore
};
}
function createShadingPanel() {
"use strict";
var panelWidth = font.getWidth() * 20;
var panel = createFloatingPanel(50, 30);
var palettePanel = createFloatingPanelPalette(panelWidth, 40);
var canvasContainer = document.createElement("div");
var cursor = createPanelCursor(canvasContainer);
var canvases = new Array(16);
var halfBlockMode = true;
var x = 0;
var y = 0;
var ignored = false;
function updateCursor() {
var width = canvases[0].width / 5;
var height = canvases[0].height / 15;
cursor.resize(width, height);
cursor.setPos(x * width, y * height);
}
function mouseDownGenerator(colour) {
return function(evt) {
var rect = canvases[colour].getBoundingClientRect();
var mouseX = evt.clientX - rect.left;
var mouseY = evt.clientY - rect.top;
halfBlockMode = false;
x = Math.floor(mouseX / (canvases[colour].width / 5));
y = Math.floor(mouseY / (canvases[colour].height / 15));
palettePanel.hideCursor();
updateCursor();
cursor.show();
};
}
function generateCanvases() {
var fontHeight = font.getHeight();
for (var foreground = 0; foreground < 16; foreground++) {
var canvas = createCanvas(panelWidth, fontHeight * 15);
var ctx = canvas.getContext("2d");
var y = 0;
for (var background = 0; background < 8; background++) {
if (foreground !== background) {
for (var i = 0; i < 4; i++) {
font.draw(219, foreground, background, ctx, i, y);
}
for (var i = 4; i < 8; i++) {
font.draw(178, foreground, background, ctx, i, y);
}
for (var i = 8; i < 12; i++) {
font.draw(177, foreground, background, ctx, i, y);
}
for (var i = 12; i < 16; i++) {
font.draw(176, foreground, background, ctx, i, y);
}
for (var i = 16; i < 20; i++) {
font.draw(0, foreground, background, ctx, i, y);
}
y += 1;
}
}
for (var background = 8; background < 16; background++) {
if (foreground !== background) {
for (var i = 0; i < 4; i++) {
font.draw(219, foreground, background, ctx, i, y);
}
for (var i = 4; i < 8; i++) {
font.draw(178, foreground, background, ctx, i, y);
}
for (var i = 8; i < 12; i++) {
font.draw(177, foreground, background, ctx, i, y);
}
for (var i = 12; i < 16; i++) {
font.draw(176, foreground, background, ctx, i, y);
}
for (var i = 16; i < 20; i++) {
font.draw(0, foreground, background, ctx, i, y);
}
y += 1;
}
}
canvas.addEventListener("mousedown", mouseDownGenerator(foreground));
canvases[foreground] = canvas;
}
}
function keyDown(evt) {
if (ignored === false) {
var keyCode = (evt.keyCode || evt.which);
if (halfBlockMode === false) {
switch (keyCode) {
case 37:
evt.preventDefault();
x = Math.max(x - 1, 0);
updateCursor();
break;
case 38:
evt.preventDefault();
y = Math.max(y - 1, 0);
updateCursor();
break;
case 39:
evt.preventDefault();
x = Math.min(x + 1, 4);
updateCursor();
break;
case 40:
evt.preventDefault();
y = Math.min(y + 1, 14);
updateCursor();
break;
default:
break;
}
} else if (keyCode >= 37 && keyCode <= 40) {
evt.preventDefault();
halfBlockMode = false;
palettePanel.hideCursor();
cursor.show();
}
}
}
function enable() {
document.addEventListener("keydown", keyDown);
panel.enable();
}
function disable() {
document.removeEventListener("keydown", keyDown);
panel.disable();
}
function ignore() {
ignored = true;
}
function unignore() {
ignored = false;
}
function getMode() {
var charCode = 0;
switch (x) {
case 0: charCode = 219; break;
case 1: charCode = 178; break;
case 2: charCode = 177; break;
case 3: charCode = 176; break;
case 4: charCode = 0; break;
default: break;
}
var foreground = palette.getForegroundColour();
var background = y;
if (y >= foreground) {
background += 1;
}
return {
"halfBlockMode": halfBlockMode,
"foreground": foreground,
"background": background,
"charCode": charCode
};
}
function foregroundChange(evt) {
canvasContainer.removeChild(canvasContainer.firstChild);
canvasContainer.insertBefore(canvases[evt.detail], canvasContainer.firstChild);
palettePanel.showCursor();
cursor.hide();
halfBlockMode = true;
}
function fontChange() {
panelWidth = font.getWidth() * 20;
palettePanel.resize(panelWidth, 40);
generateCanvases();
updateCursor();
canvasContainer.removeChild(canvasContainer.firstChild);
canvasContainer.insertBefore(canvases[palette.getForegroundColour()], canvasContainer.firstChild);
}
function select(charCode) {
halfBlockMode = false;
x = 3 - (charCode - 176);
y = palette.getBackgroundColour();
if (y > palette.getForegroundColour()) {
y -= 1;
}
palettePanel.hideCursor();
updateCursor();
cursor.show();
}
document.addEventListener("onForegroundChange", foregroundChange);
document.addEventListener("onLetterSpacingChange", fontChange);
document.addEventListener("onFontChange", fontChange);
palettePanel.showCursor();
panel.append(palettePanel.getElement());
generateCanvases();
updateCursor();
canvasContainer.insertBefore(canvases[palette.getForegroundColour()], canvasContainer.firstChild);
panel.append(canvasContainer);
cursor.hide();
return {
"enable": enable,
"disable": disable,
"getMode": getMode,
"select": select,
"ignore": ignore,
"unignore": unignore
};
}
function createCharacterBrushPanel() {
"use strict";
var panelWidth = font.getWidth() * 16;
var panel = createFloatingPanel(50, 30);
var palettePanel = createFloatingPanelPalette(panelWidth, 40);
var canvasContainer = document.createElement("div");
var cursor = createPanelCursor(canvasContainer);
var canvas = createCanvas(panelWidth, font.getHeight() * 16);
var ctx = canvas.getContext("2d");
var x = 0;
var y = 0;
var ignored = false;
function updateCursor() {
var width = canvas.width / 16;
var height = canvas.height / 16;
cursor.resize(width, height);
cursor.setPos(x * width, y * height);
}
function redrawCanvas() {
var foreground = palette.getForegroundColour();
var background = palette.getBackgroundColour();
for (var y = 0, charCode = 0; y < 16; y++) {
for (var x = 0; x < 16; x++, charCode++) {
font.draw(charCode, foreground, background, ctx, x, y);
}
}
}
function keyDown(evt) {
if (ignored === false) {
var keyCode = (evt.keyCode || evt.which);
switch (keyCode) {
case 37:
evt.preventDefault();
x = Math.max(x - 1, 0);
updateCursor();
break;
case 38:
evt.preventDefault();
y = Math.max(y - 1, 0);
updateCursor();
break;
case 39:
evt.preventDefault();
x = Math.min(x + 1, 15);
updateCursor();
break;
case 40:
evt.preventDefault();
y = Math.min(y + 1, 15);
updateCursor();
break;
default:
break;
}
}
}
function enable() {
document.addEventListener("keydown", keyDown);
panel.enable();
}
function disable() {
document.removeEventListener("keydown", keyDown);
panel.disable();
}
function getMode() {
var charCode = y * 16 + x;
return {
"halfBlockMode": false,
"foreground": palette.getForegroundColour(),
"background": palette.getBackgroundColour(),
"charCode": charCode
};
}
function resizeCanvas() {
panelWidth = font.getWidth() * 16;
palettePanel.resize(panelWidth, 40);
canvas.width = panelWidth;
canvas.height = font.getHeight() * 16;
redrawCanvas();
updateCursor();
}
function mouseUp(evt) {
var rect = canvas.getBoundingClientRect();
var mouseX = evt.clientX - rect.left;
var mouseY = evt.clientY - rect.top;
x = Math.floor(mouseX / (canvas.width / 16));
y = Math.floor(mouseY / (canvas.height / 16));
updateCursor();
}
function select(charCode) {
x = charCode % 16;
y = Math.floor(charCode / 16);
updateCursor();
}
function ignore() {
ignored = true;
}
function unignore() {
ignored = false;
}
document.addEventListener("onForegroundChange", redrawCanvas);
document.addEventListener("onBackgroundChange", redrawCanvas);
document.addEventListener("onLetterSpacingChange", resizeCanvas);
document.addEventListener("onFontChange", resizeCanvas);
canvas.addEventListener("mouseup", mouseUp);
panel.append(palettePanel.getElement());
updateCursor();
cursor.show();
canvasContainer.appendChild(canvas);
panel.append(canvasContainer);
redrawCanvas();
return {
"enable": enable,
"disable": disable,
"getMode": getMode,
"select": select,
"ignore": ignore,
"unignore": unignore
};
}
function createFillController() {
"use strict";
function fillPoint(evt) {
var block = textArtCanvas.getHalfBlock(evt.detail.x, evt.detail.halfBlockY);
if (block.isBlocky) {
var targetColour = (block.halfBlockY === 0) ? block.upperBlockColour : block.lowerBlockColour;
var fillColour = palette.getForegroundColour();
if (targetColour !== fillColour) {
var columns = textArtCanvas.getColumns();
var rows = textArtCanvas.getRows();
var coord = [evt.detail.x, evt.detail.halfBlockY];
var queue = [coord];
textArtCanvas.startUndo();
textArtCanvas.drawHalfBlock((callback) => {
while (queue.length !== 0) {
coord = queue.pop();
block = textArtCanvas.getHalfBlock(coord[0], coord[1]);
if (block.isBlocky && (((block.halfBlockY === 0) && (block.upperBlockColour === targetColour)) || ((block.halfBlockY === 1) && (block.lowerBlockColour === targetColour)))) {
callback(fillColour, coord[0], coord[1]);
if (coord[0] > 0) {
queue.push([coord[0] - 1, coord[1], 0]);
}
if (coord[0] < columns - 1) {
queue.push([coord[0] + 1, coord[1], 1]);
}
if (coord[1] > 0) {
queue.push([coord[0], coord[1] - 1, 2]);
}
if (coord[1] < rows * 2 - 1) {
queue.push([coord[0], coord[1] + 1, 3]);
}
} else if (block.isVerticalBlocky) {
if (coord[2] !== 0 && block.leftBlockColour === targetColour) {
textArtCanvas.draw(function(callback) {
callback(221, fillColour, block.rightBlockColour, coord[0], block.textY);
}, true);
if (coord[0] > 0) {
queue.push([coord[0] - 1, coord[1], 0]);
}
if (coord[1] > 2) {
if (block.halfBlockY === 1) {
queue.push([coord[0], coord[1] - 2, 2]);
} else {
queue.push([coord[0], coord[1] - 1, 2]);
}
}
if (coord[1] < rows * 2 - 2) {
if (block.halfBlockY === 1) {
queue.push([coord[0], coord[1] + 1, 3]);
} else {
queue.push([coord[0], coord[1] + 2, 3]);
}
}
}
if (coord[2] !== 1 && block.rightBlockColour === targetColour) {
textArtCanvas.draw(function(callback) {
callback(222, fillColour, block.leftBlockColour, coord[0], block.textY);
}, true);
if (coord[0] > 0) {
queue.push([coord[0] - 1, coord[1], 0]);
}
if (coord[1] > 2) {
if (block.halfBlockY === 1) {
queue.push([coord[0], coord[1] - 2, 2]);
} else {
queue.push([coord[0], coord[1] - 1, 2]);
}
}
if (coord[1] < rows * 2 - 2) {
if (block.halfBlockY === 1) {
queue.push([coord[0], coord[1] + 1, 3]);
} else {
queue.push([coord[0], coord[1] + 2, 3]);
}
}
}
}
}
});
}
}
}
function enable() {
document.addEventListener("onTextCanvasDown", fillPoint);
}
function disable() {
document.removeEventListener("onTextCanvasDown", fillPoint);
}
return {
"enable": enable,
"disable": disable
};
}
function createLineController() {
"use strict";
var startXY;
var endXY;
function canvasDown(evt) {
startXY = evt.detail;
}
function line(x0, y0, x1, y1, callback) {
var dx = Math.abs(x1 - x0);
var sx = (x0 < x1) ? 1 : -1;
var dy = Math.abs(y1 - y0);
var sy = (y0 < y1) ? 1 : -1;
var err = ((dx > dy) ? dx : -dy) / 2;
var e2;
while (true) {
callback(x0, y0);
if (x0 === x1 && y0 === y1) {
break;
}
e2 = err;
if (e2 > -dx) {
err -= dy;
x0 += sx;
}
if (e2 < dy) {
err += dx;
y0 += sy;
}
}
}
function canvasUp() {
toolPreview.clear();
var foreground = palette.getForegroundColour();
textArtCanvas.startUndo();
textArtCanvas.drawHalfBlock((draw) => {
line(startXY.x, startXY.halfBlockY, endXY.x, endXY.halfBlockY, function(lineX, lineY) {
draw(foreground, lineX, lineY);
});
});
startXY = undefined;
endXY = undefined;
}
function canvasDrag(evt) {
if (startXY !== undefined) {
if (endXY === undefined || (evt.detail.x !== endXY.x || evt.detail.y !== endXY.y || evt.detail.halfBlockY !== endXY.halfBlockY)) {
if (endXY !== undefined) {
toolPreview.clear();
}
endXY = evt.detail;
var foreground = palette.getForegroundColour();
line(startXY.x, startXY.halfBlockY, endXY.x, endXY.halfBlockY, function(lineX, lineY) {
toolPreview.drawHalfBlock(foreground, lineX, lineY);
});
}
}
}
function enable() {
document.addEventListener("onTextCanvasDown", canvasDown);
document.addEventListener("onTextCanvasUp", canvasUp);
document.addEventListener("onTextCanvasDrag", canvasDrag);
}
function disable() {
document.removeEventListener("onTextCanvasDown", canvasDown);
document.removeEventListener("onTextCanvasUp", canvasUp);
document.removeEventListener("onTextCanvasDrag", canvasDrag);
}
return {
"enable": enable,
"disable": disable
};
}
function createSquareController() {
"use strict";
var panel = createFloatingPanel(50, 30);
var palettePanel = createFloatingPanelPalette(160, 40);
var startXY;
var endXY;
var outlineMode = true;
var outlineToggle = createToggleButton("Outline", "Filled", () => {
outlineMode = true;
}, () => {
outlineMode = false;
});
function canvasDown(evt) {
startXY = evt.detail;
}
function processCoords() {
var x0, y0, x1, y1;
if (startXY.x < endXY.x) {
x0 = startXY.x;
x1 = endXY.x;
} else {
x0 = endXY.x;
x1 = startXY.x;
}
if (startXY.halfBlockY < endXY.halfBlockY) {
y0 = startXY.halfBlockY;
y1 = endXY.halfBlockY;
} else {
y0 = endXY.halfBlockY;
y1 = startXY.halfBlockY;
}
return { "x0": x0, "y0": y0, "x1": x1, "y1": y1 };
}
function canvasUp() {
toolPreview.clear();
var coords = processCoords();
var foreground = palette.getForegroundColour();
textArtCanvas.startUndo();
textArtCanvas.drawHalfBlock((draw) => {
if (outlineMode === true) {
for (var px = coords.x0; px <= coords.x1; px++) {
draw(foreground, px, coords.y0);
draw(foreground, px, coords.y1);
}
for (var py = coords.y0 + 1; py < coords.y1; py++) {
draw(foreground, coords.x0, py);
draw(foreground, coords.x1, py);
}
} else {
for (var py = coords.y0; py <= coords.y1; py++) {
for (var px = coords.x0; px <= coords.x1; px++) {
draw(foreground, px, py);
}
}
}
});
startXY = undefined;
endXY = undefined;
}
function canvasDrag(evt) {
if (startXY !== undefined) {
if (evt.detail.x !== startXY.x || evt.detail.y !== startXY.y || evt.detail.halfBlockY !== startXY.halfBlockY) {
if (endXY !== undefined) {
toolPreview.clear();
}
endXY = evt.detail;
var coords = processCoords();
var foreground = palette.getForegroundColour();
if (outlineMode === true) {
for (var px = coords.x0; px <= coords.x1; px++) {
toolPreview.drawHalfBlock(foreground, px, coords.y0);
toolPreview.drawHalfBlock(foreground, px, coords.y1);
}
for (var py = coords.y0 + 1; py < coords.y1; py++) {
toolPreview.drawHalfBlock(foreground, coords.x0, py);
toolPreview.drawHalfBlock(foreground, coords.x1, py);
}
} else {
for (var py = coords.y0; py <= coords.y1; py++) {
for (var px = coords.x0; px <= coords.x1; px++) {
toolPreview.drawHalfBlock(foreground, px, py);
}
}
}
}
}
}
function enable() {
panel.enable();
document.addEventListener("onTextCanvasDown", canvasDown);
document.addEventListener("onTextCanvasUp", canvasUp);
document.addEventListener("onTextCanvasDrag", canvasDrag);
}
function disable() {
panel.disable();
document.removeEventListener("onTextCanvasDown", canvasDown);
document.removeEventListener("onTextCanvasUp", canvasUp);
document.removeEventListener("onTextCanvasDrag", canvasDrag);
}
panel.append(palettePanel.getElement());
palettePanel.showCursor();
panel.append(outlineToggle.getElement());
if (outlineMode === true) {
outlineToggle.setStateOne();
} else {
outlineToggle.setStateTwo();
}
return {
"enable": enable,
"disable": disable
};
}
function createCircleController() {
"use strict";
var panel = createFloatingPanel(50, 30);
var palettePanel = createFloatingPanelPalette(160, 40);
var startXY;
var endXY;
var outlineMode = true;
var outlineToggle = createToggleButton("Outline", "Filled", () => {
outlineMode = true;
}, () => {
outlineMode = false;
});
function canvasDown(evt) {
startXY = evt.detail;
}
function processCoords() {
var sx, sy, width, height;
sx = startXY.x;
sy = startXY.halfBlockY;
width = Math.abs(endXY.x - startXY.x);
height = Math.abs(endXY.halfBlockY - startXY.halfBlockY);
return {
"sx": sx,
"sy": sy,
"width": width,
"height": height
};
}
function ellipseOutline(sx, sy, width, height, callback) {
var a2 = width * width;
var b2 = height * height;
var fa2 = 4 * a2;
var fb2 = 4 * b2;
for (var px = 0, py = height, sigma = 2 * b2 + a2 * (1 - 2 * height); b2 * px <= a2 * py; px += 1) {
callback(sx + px, sy + py);
callback(sx - px, sy + py);
callback(sx + px, sy - py);
callback(sx - px, sy - py);
if (sigma >= 0) {
sigma += fa2 * (1 - py);
py -= 1;
}
sigma += b2 * ((4 * px) + 6);
}
for (var px = width, py = 0, sigma = 2 * a2 + b2 * (1 - 2 * width); a2 * py <= b2 * px; py += 1) {
callback(sx + px, sy + py);
callback(sx - px, sy + py);
callback(sx + px, sy - py);
callback(sx - px, sy - py);
if (sigma >= 0) {
sigma += fb2 * (1 - px);
px -= 1;
}
sigma += a2 * ((4 * py) + 6);
}
}
function ellipseFilled(sx, sy, width, height, callback) {
var a2 = width * width;
var b2 = height * height;
var fa2 = 4 * a2;
var fb2 = 4 * b2;
for (var px = 0, py = height, sigma = 2 * b2 + a2 * (1 - 2 * height); b2 * px <= a2 * py; px += 1) {
var amount = px * 2;
var start = sx - px;
var y0 = sy + py;
var y1 = sy - py;
for (var i = 0; i < amount; i++) {
callback(start + i, y0);
callback(start + i, y1);
}
if (sigma >= 0) {
sigma += fa2 * (1 - py);
py -= 1;
}
sigma += b2 * ((4 * px) + 6);
}
for (var px = width, py = 0, sigma = 2 * a2 + b2 * (1 - 2 * width); a2 * py <= b2 * px; py += 1) {
var amount = px * 2;
var start = sx - px;
var y0 = sy + py;
var y1 = sy - py;
for (var i = 0; i < amount; i++) {
callback(start + i, y0);
callback(start + i, y1);
}
if (sigma >= 0) {
sigma += fb2 * (1 - px);
px -= 1;
}
sigma += a2 * ((4 * py) + 6);
}
}
function canvasUp() {
toolPreview.clear();
var coords = processCoords();
var foreground = palette.getForegroundColour();
textArtCanvas.startUndo();
var columns = textArtCanvas.getColumns();
var rows = textArtCanvas.getRows();
var doubleRows = rows * 2;
textArtCanvas.drawHalfBlock((draw) => {
if (outlineMode === true) {
ellipseOutline(coords.sx, coords.sy, coords.width, coords.height, (px, py) => {
if (px >= 0 && px < columns && py >= 0 && py < doubleRows) {
draw(foreground, px, py);
}
});
} else {
ellipseFilled(coords.sx, coords.sy, coords.width, coords.height, (px, py) => {
if (px >= 0 && px < columns && py >= 0 && py < doubleRows) {
draw(foreground, px, py);
}
});
}
});
startXY = undefined;
endXY = undefined;
}
function canvasDrag(evt) {
if (startXY !== undefined) {
if (evt.detail.x !== startXY.x || evt.detail.y !== startXY.y || evt.detail.halfBlockY !== startXY.halfBlockY) {
if (endXY !== undefined) {
toolPreview.clear();
}
endXY = evt.detail;
var coords = processCoords();
var foreground = palette.getForegroundColour();
var columns = textArtCanvas.getColumns();
var rows = textArtCanvas.getRows();
var doubleRows = rows * 2;
if (outlineMode === true) {
ellipseOutline(coords.sx, coords.sy, coords.width, coords.height, (px, py) => {
if (px >= 0 && px < columns && py >= 0 && py < doubleRows) {
toolPreview.drawHalfBlock(foreground, px, py);
}
});
} else {
ellipseFilled(coords.sx, coords.sy, coords.width, coords.height, (px, py) => {
if (px >= 0 && px < columns && py >= 0 && py < doubleRows) {
toolPreview.drawHalfBlock(foreground, px, py);
}
});
}
}
}
}
function enable() {
panel.enable();
document.addEventListener("onTextCanvasDown", canvasDown);
document.addEventListener("onTextCanvasUp", canvasUp);
document.addEventListener("onTextCanvasDrag", canvasDrag);
}
function disable() {
panel.disable();
document.removeEventListener("onTextCanvasDown", canvasDown);
document.removeEventListener("onTextCanvasUp", canvasUp);
document.removeEventListener("onTextCanvasDrag", canvasDrag);
}
panel.append(palettePanel.getElement());
palettePanel.showCursor();
panel.append(outlineToggle.getElement());
if (outlineMode === true) {
outlineToggle.setStateOne();
} else {
outlineToggle.setStateTwo();
}
return {
"enable": enable,
"disable": disable
};
}
function createSampleTool(divElement, freestyle, divFreestyle, characterBrush, divCharacterBrush) {
"use strict";
function sample(x, halfBlockY) {
var block = textArtCanvas.getHalfBlock(x, halfBlockY);
if (block.isBlocky) {
if (block.halfBlockY === 0) {
palette.setForegroundColour(block.upperBlockColour);
} else {
palette.setForegroundColour(block.lowerBlockColour);
}
} else {
block = textArtCanvas.getBlock(block.x, Math.floor(block.y / 2));
palette.setForegroundColour(block.foregroundColour);
palette.setBackgroundColour(block.backgroundColour);
if (block.charCode >= 176 && block.charCode <= 178) {
freestyle.select(block.charCode);
divFreestyle.click();
} else {
characterBrush.select(block.charCode);
divCharacterBrush.click();
}
}
}
function canvasDown(evt) {
sample(evt.detail.x, evt.detail.halfBlockY);
}
function enable() {
document.addEventListener("onTextCanvasDown", canvasDown);
}
function disable() {
document.removeEventListener("onTextCanvasDown", canvasDown);
}
return {
"enable": enable,
"disable": disable,
"sample": sample
};
}
function createSelectionTool(divElement) {
"use strict";
function canvasDown(evt) {
selectionCursor.setStart(evt.detail.x, evt.detail.y);
selectionCursor.setEnd(evt.detail.x, evt.detail.y);
}
function canvasDrag(evt) {
selectionCursor.setEnd(evt.detail.x, evt.detail.y);
}
function enable() {
document.addEventListener("onTextCanvasDown", canvasDown);
document.addEventListener("onTextCanvasDrag", canvasDrag);
}
function disable() {
selectionCursor.hide();
document.removeEventListener("onTextCanvasDown", canvasDown);
document.removeEventListener("onTextCanvasDrag", canvasDrag);
pasteTool.disable();
}
return {
"enable": enable,
"disable": disable
};
}