// Copyright (c) 2015 Walter Bender
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the The GNU Affero General Public
|
|
// License as published by the Free Software Foundation; either
|
|
// version 3 of the License, or (at your option) any later version.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public
|
|
// License along with this library; if not, write to the Free Software
|
|
// Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA
|
|
//
|
|
|
|
// FIXME: Use busy cursor
|
|
|
|
// A viewer for Turtle Blocks plugins
|
|
function PluginsViewer(canvas, stage, refreshCanvas, close, load) {
|
|
this.canvas = canvas;
|
|
this.stage = stage;
|
|
this.refreshCanvas = refreshCanvas;
|
|
this.closeViewer = close;
|
|
this.loadPlugin = load;
|
|
this.dict = {};
|
|
this.pluginFiles = [];
|
|
this.container = null;
|
|
this.prev = null;
|
|
this.next = null;
|
|
this.page = 0; // 4x4 image matrix per page
|
|
this.server = true;
|
|
|
|
this.setServer = function(server) {
|
|
this.server = server;
|
|
}
|
|
|
|
this.hide = function() {
|
|
if (this.container !== null) {
|
|
this.container.visible = false;
|
|
this.refreshCanvas();
|
|
}
|
|
}
|
|
|
|
this.show = function(scale) {
|
|
this.scale = scale;
|
|
this.page = 0;
|
|
if (this.server) {
|
|
try {
|
|
var rawData = httpGet();
|
|
var obj = JSON.parse(rawData);
|
|
// console.log('json parse: ' + obj);
|
|
// Look for svg
|
|
for (var file in obj) {
|
|
if (fileExt(obj[file]) === 'svg') {
|
|
var name = fileBasename(obj[file]);
|
|
if (this.pluginFiles.indexOf(name) === -1) {
|
|
this.pluginFiles.push(name);
|
|
}
|
|
}
|
|
}
|
|
// and corresponding .json files
|
|
for (var file in this.pluginFiles) {
|
|
var tbfile = this.pluginFiles[file] + '.json';
|
|
if (!tbfile in obj) {
|
|
this.pluginFiles.remove(this.pluginFiles[file]);
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.log(e);
|
|
return false;
|
|
}
|
|
} else {
|
|
// FIXME: grab files from a local server?
|
|
this.pluginFiles = SAMPLEPLUGINS;
|
|
}
|
|
console.log('found these projects: ' + this.pluginFiles.sort());
|
|
|
|
if (this.container === null) {
|
|
this.container = new createjs.Container();
|
|
this.stage.addChild(this.container);
|
|
this.container.x = Math.floor(((this.canvas.width / scale) - 650) / 2);
|
|
this.container.y = 27;
|
|
|
|
function processBackground(viewer, name, bitmap, extras) {
|
|
viewer.container.addChild(bitmap);
|
|
|
|
function processPrev(viewer, name, bitmap, extras) {
|
|
viewer.prev = bitmap;
|
|
viewer.container.addChild(viewer.prev);
|
|
viewer.prev.x = 270;
|
|
viewer.prev.y = 535;
|
|
|
|
function processNext(viewer, name, bitmap, scale) {
|
|
viewer.next = bitmap;
|
|
viewer.container.addChild(viewer.next);
|
|
viewer.next.x = 325;
|
|
viewer.next.y = 535;
|
|
viewer.container.visible = true;
|
|
viewer.refreshCanvas();
|
|
viewer.completeInit();
|
|
loadThumbnailContainerHandler(viewer);
|
|
return true;
|
|
}
|
|
makeViewerBitmap(viewer, NEXTBUTTON, 'viewer', processNext, null);
|
|
}
|
|
makeViewerBitmap(viewer, PREVBUTTON, 'viewer', processPrev, null);
|
|
}
|
|
makeViewerBitmap(this, BACKGROUND, 'viewer', processBackground, null);
|
|
} else {
|
|
this.container.visible = true;
|
|
this.refreshCanvas();
|
|
this.completeInit();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
this.downloadImage = function(p, prepareNextImage) {
|
|
var header = 'data:image/svg+xml;utf8,';
|
|
var name = this.pluginFiles[p] + '.svg';
|
|
// console.log('getting ' + name + ' from samples');
|
|
if (this.server) {
|
|
var data = header + httpGet(name);
|
|
} else {
|
|
var data = header + SAMPLESSVG[name];
|
|
}
|
|
var image = new Image();
|
|
var viewer = this;
|
|
|
|
image.onload = function() {
|
|
bitmap = new createjs.Bitmap(data);
|
|
bitmap.scaleX = 0.5;
|
|
bitmap.scaleY = 0.5;
|
|
viewer.container.addChild(bitmap);
|
|
lastChild = last(viewer.container.children);
|
|
viewer.container.swapChildren(bitmap, lastChild);
|
|
|
|
viewer.dict[viewer.pluginFiles[p]] = bitmap;
|
|
x = 5 + (p % 4) * 160;
|
|
y = 55 + Math.floor((p % 16) / 4) * 120;
|
|
viewer.dict[viewer.pluginFiles[p]].x = x;
|
|
viewer.dict[viewer.pluginFiles[p]].y = y;
|
|
viewer.dict[viewer.pluginFiles[p]].visible = true;
|
|
viewer.refreshCanvas();
|
|
if (prepareNextImage !== null) {
|
|
prepareNextImage(viewer, p + 1);
|
|
}
|
|
}
|
|
image.src = data;
|
|
}
|
|
|
|
this.completeInit = function() {
|
|
var p = 0;
|
|
this.prepareNextImage(this, p);
|
|
}
|
|
|
|
this.prepareNextImage = function(viewer, p) {
|
|
// TODO: this.pluginFiles.sort()
|
|
// Only download the images on the first page.
|
|
if (p < viewer.pluginFiles.length && p < (viewer.page * 16 + 16)) {
|
|
if (viewer.pluginFiles[p] in viewer.dict) {
|
|
x = 5 + (p % 4) * 160;
|
|
y = 55 + Math.floor((p % 16) / 4) * 120;
|
|
viewer.dict[viewer.pluginFiles[p]].x = x;
|
|
viewer.dict[viewer.pluginFiles[p]].y = y;
|
|
viewer.dict[viewer.pluginFiles[p]].visible = true;
|
|
viewer.prepareNextImage(viewer, p + 1)
|
|
} else {
|
|
viewer.downloadImage(p, viewer.prepareNextImage);
|
|
}
|
|
} else {
|
|
if (viewer.page === 0) {
|
|
viewer.prev.visible = false;
|
|
}
|
|
if ((viewer.page + 1) * 16 < viewer.pluginFiles.length) {
|
|
viewer.next.visible = true;
|
|
}
|
|
viewer.refreshCanvas();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function hideCurrentPage(viewer) {
|
|
var min = viewer.page * 16;
|
|
var max = Math.min(viewer.pluginFiles.length, (viewer.page + 1) * 16);
|
|
// Hide the current page.
|
|
for (var p = min; p < max; p++) {
|
|
viewer.dict[viewer.pluginFiles[p]].visible = false;
|
|
}
|
|
// Go back to previous page.
|
|
viewer.page -= 1;
|
|
if (viewer.page === 0) {
|
|
viewer.prev.visible = false;
|
|
}
|
|
if ((viewer.page + 1) * 16 < viewer.pluginFiles.length) {
|
|
viewer.next.visible = true;
|
|
}
|
|
// Show the current page.
|
|
var min = viewer.page * 16;
|
|
var max = Math.min(viewer.pluginFiles.length, (viewer.page + 1) * 16);
|
|
for (var p = min; p < max; p++) {
|
|
viewer.dict[viewer.pluginFiles[p]].visible = true;
|
|
}
|
|
viewer.refreshCanvas();
|
|
}
|
|
|
|
|
|
function showNextPage(viewer) {
|
|
var min = viewer.page * 16;
|
|
var max = Math.min(viewer.pluginFiles.length, (viewer.page + 1) * 16);
|
|
// Hide the current page.
|
|
for (var p = min; p < max; p++) {
|
|
viewer.dict[viewer.pluginFiles[p]].visible = false;
|
|
}
|
|
// Advance to next page.
|
|
viewer.page += 1;
|
|
viewer.prev.visible = true;
|
|
if ((viewer.page + 1) * 16 + 1 > viewer.pluginFiles.length) {
|
|
viewer.next.visible = false;
|
|
}
|
|
viewer.prepareNextImage(viewer, max);
|
|
viewer.refreshCanvas();
|
|
}
|
|
|
|
|
|
function viewerClicked(viewer, event) {
|
|
var x = (event.stageX / viewer.scale) - viewer.container.x;
|
|
var y = (event.stageY / viewer.scale) - viewer.container.y;
|
|
if (x > 600 && y < 55) {
|
|
viewer.hide();
|
|
viewer.closeViewer();
|
|
} else if (y > 535) {
|
|
if (viewer.prev.visible && x < 325) {
|
|
hideCurrentPage(viewer);
|
|
} else if (viewer.next.visible && x > 325) {
|
|
showNextPage(viewer)
|
|
}
|
|
} else {
|
|
// Select a plugin.
|
|
var col = Math.floor((x - 5) / 160);
|
|
var row = Math.floor((y - 55) / 120);
|
|
var p = row * 4 + col + 16 * viewer.page;
|
|
if (p < viewer.pluginFiles.length) {
|
|
viewer.hide();
|
|
viewer.closeViewer();
|
|
viewer.loadPlugin(viewer.pluginFiles[p] + '.json');
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function loadThumbnailContainerHandler(viewer) {
|
|
var hitArea = new createjs.Shape();
|
|
var w = 650;
|
|
var h = 590;
|
|
var startX, startY, endX, endY;
|
|
hitArea.graphics.beginFill('#FFF').drawRect(0, 0, w, h);
|
|
hitArea.x = 0;
|
|
hitArea.y = 0;
|
|
viewer.container.hitArea = hitArea;
|
|
|
|
var locked = false;
|
|
|
|
viewer.container.on('click', function(event) {
|
|
// We need a lock to "debouce" the click.
|
|
if (locked) {
|
|
console.log('debouncing click');
|
|
return;
|
|
}
|
|
locked = true;
|
|
setTimeout(function() {
|
|
locked = false;
|
|
}, 500);
|
|
viewerClicked(viewer, event)
|
|
});
|
|
|
|
viewer.container.on('mousedown', function(event) {
|
|
startX = event.stageX;
|
|
startY = event.stageY;
|
|
locked = true;
|
|
});
|
|
|
|
viewer.container.on('pressup', function(event) {
|
|
endX = event.stageX;
|
|
endY = event.stageY;
|
|
if (endY > startY + 30 || endX > startX + 30) {
|
|
// Down or right
|
|
if (viewer.next.visible) {
|
|
showNextPage(viewer);
|
|
}
|
|
}
|
|
else if(endY < startY - 30 || endX < startX - 30) {
|
|
// Up or left
|
|
if (viewer.prev.visible) {
|
|
hideCurrentPage(viewer);
|
|
}
|
|
}
|
|
else {
|
|
locked = false;
|
|
viewerClicked(viewer, event)
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
function makeViewerBitmap(viewer, data, name, callback, extras) {
|
|
// Async creation of bitmap from SVG data
|
|
// Works with Chrome, Safari, Firefox (untested on IE)
|
|
var img = new Image();
|
|
img.onload = function() {
|
|
bitmap = new createjs.Bitmap(img);
|
|
callback(viewer, name, bitmap, extras);
|
|
}
|
|
img.src = 'data:image/svg+xml;base64,' + window.btoa(
|
|
unescape(encodeURIComponent(data)));
|
|
}
|