not really known
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

313 lines
10 KiB

  1. // Copyright (c) 2015 Walter Bender
  2. //
  3. // This program is free software; you can redistribute it and/or
  4. // modify it under the terms of the The GNU Affero General Public
  5. // License as published by the Free Software Foundation; either
  6. // version 3 of the License, or (at your option) any later version.
  7. //
  8. // You should have received a copy of the GNU Affero General Public
  9. // License along with this library; if not, write to the Free Software
  10. // Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA
  11. //
  12. // FIXME: Use busy cursor
  13. // A viewer for Turtle Blocks plugins
  14. function PluginsViewer(canvas, stage, refreshCanvas, close, load) {
  15. this.canvas = canvas;
  16. this.stage = stage;
  17. this.refreshCanvas = refreshCanvas;
  18. this.closeViewer = close;
  19. this.loadPlugin = load;
  20. this.dict = {};
  21. this.pluginFiles = [];
  22. this.container = null;
  23. this.prev = null;
  24. this.next = null;
  25. this.page = 0; // 4x4 image matrix per page
  26. this.server = true;
  27. this.setServer = function(server) {
  28. this.server = server;
  29. }
  30. this.hide = function() {
  31. if (this.container !== null) {
  32. this.container.visible = false;
  33. this.refreshCanvas();
  34. }
  35. }
  36. this.show = function(scale) {
  37. this.scale = scale;
  38. this.page = 0;
  39. if (this.server) {
  40. try {
  41. var rawData = httpGet();
  42. var obj = JSON.parse(rawData);
  43. // console.log('json parse: ' + obj);
  44. // Look for svg
  45. for (var file in obj) {
  46. if (fileExt(obj[file]) === 'svg') {
  47. var name = fileBasename(obj[file]);
  48. if (this.pluginFiles.indexOf(name) === -1) {
  49. this.pluginFiles.push(name);
  50. }
  51. }
  52. }
  53. // and corresponding .json files
  54. for (var file in this.pluginFiles) {
  55. var tbfile = this.pluginFiles[file] + '.json';
  56. if (!tbfile in obj) {
  57. this.pluginFiles.remove(this.pluginFiles[file]);
  58. }
  59. }
  60. } catch (e) {
  61. console.log(e);
  62. return false;
  63. }
  64. } else {
  65. // FIXME: grab files from a local server?
  66. this.pluginFiles = SAMPLEPLUGINS;
  67. }
  68. console.log('found these projects: ' + this.pluginFiles.sort());
  69. if (this.container === null) {
  70. this.container = new createjs.Container();
  71. this.stage.addChild(this.container);
  72. this.container.x = Math.floor(((this.canvas.width / scale) - 650) / 2);
  73. this.container.y = 27;
  74. function processBackground(viewer, name, bitmap, extras) {
  75. viewer.container.addChild(bitmap);
  76. function processPrev(viewer, name, bitmap, extras) {
  77. viewer.prev = bitmap;
  78. viewer.container.addChild(viewer.prev);
  79. viewer.prev.x = 270;
  80. viewer.prev.y = 535;
  81. function processNext(viewer, name, bitmap, scale) {
  82. viewer.next = bitmap;
  83. viewer.container.addChild(viewer.next);
  84. viewer.next.x = 325;
  85. viewer.next.y = 535;
  86. viewer.container.visible = true;
  87. viewer.refreshCanvas();
  88. viewer.completeInit();
  89. loadThumbnailContainerHandler(viewer);
  90. return true;
  91. }
  92. makeViewerBitmap(viewer, NEXTBUTTON, 'viewer', processNext, null);
  93. }
  94. makeViewerBitmap(viewer, PREVBUTTON, 'viewer', processPrev, null);
  95. }
  96. makeViewerBitmap(this, BACKGROUND, 'viewer', processBackground, null);
  97. } else {
  98. this.container.visible = true;
  99. this.refreshCanvas();
  100. this.completeInit();
  101. return true;
  102. }
  103. }
  104. this.downloadImage = function(p, prepareNextImage) {
  105. var header = 'data:image/svg+xml;utf8,';
  106. var name = this.pluginFiles[p] + '.svg';
  107. // console.log('getting ' + name + ' from samples');
  108. if (this.server) {
  109. var data = header + httpGet(name);
  110. } else {
  111. var data = header + SAMPLESSVG[name];
  112. }
  113. var image = new Image();
  114. var viewer = this;
  115. image.onload = function() {
  116. bitmap = new createjs.Bitmap(data);
  117. bitmap.scaleX = 0.5;
  118. bitmap.scaleY = 0.5;
  119. viewer.container.addChild(bitmap);
  120. lastChild = last(viewer.container.children);
  121. viewer.container.swapChildren(bitmap, lastChild);
  122. viewer.dict[viewer.pluginFiles[p]] = bitmap;
  123. x = 5 + (p % 4) * 160;
  124. y = 55 + Math.floor((p % 16) / 4) * 120;
  125. viewer.dict[viewer.pluginFiles[p]].x = x;
  126. viewer.dict[viewer.pluginFiles[p]].y = y;
  127. viewer.dict[viewer.pluginFiles[p]].visible = true;
  128. viewer.refreshCanvas();
  129. if (prepareNextImage !== null) {
  130. prepareNextImage(viewer, p + 1);
  131. }
  132. }
  133. image.src = data;
  134. }
  135. this.completeInit = function() {
  136. var p = 0;
  137. this.prepareNextImage(this, p);
  138. }
  139. this.prepareNextImage = function(viewer, p) {
  140. // TODO: this.pluginFiles.sort()
  141. // Only download the images on the first page.
  142. if (p < viewer.pluginFiles.length && p < (viewer.page * 16 + 16)) {
  143. if (viewer.pluginFiles[p] in viewer.dict) {
  144. x = 5 + (p % 4) * 160;
  145. y = 55 + Math.floor((p % 16) / 4) * 120;
  146. viewer.dict[viewer.pluginFiles[p]].x = x;
  147. viewer.dict[viewer.pluginFiles[p]].y = y;
  148. viewer.dict[viewer.pluginFiles[p]].visible = true;
  149. viewer.prepareNextImage(viewer, p + 1)
  150. } else {
  151. viewer.downloadImage(p, viewer.prepareNextImage);
  152. }
  153. } else {
  154. if (viewer.page === 0) {
  155. viewer.prev.visible = false;
  156. }
  157. if ((viewer.page + 1) * 16 < viewer.pluginFiles.length) {
  158. viewer.next.visible = true;
  159. }
  160. viewer.refreshCanvas();
  161. }
  162. }
  163. }
  164. function hideCurrentPage(viewer) {
  165. var min = viewer.page * 16;
  166. var max = Math.min(viewer.pluginFiles.length, (viewer.page + 1) * 16);
  167. // Hide the current page.
  168. for (var p = min; p < max; p++) {
  169. viewer.dict[viewer.pluginFiles[p]].visible = false;
  170. }
  171. // Go back to previous page.
  172. viewer.page -= 1;
  173. if (viewer.page === 0) {
  174. viewer.prev.visible = false;
  175. }
  176. if ((viewer.page + 1) * 16 < viewer.pluginFiles.length) {
  177. viewer.next.visible = true;
  178. }
  179. // Show the current page.
  180. var min = viewer.page * 16;
  181. var max = Math.min(viewer.pluginFiles.length, (viewer.page + 1) * 16);
  182. for (var p = min; p < max; p++) {
  183. viewer.dict[viewer.pluginFiles[p]].visible = true;
  184. }
  185. viewer.refreshCanvas();
  186. }
  187. function showNextPage(viewer) {
  188. var min = viewer.page * 16;
  189. var max = Math.min(viewer.pluginFiles.length, (viewer.page + 1) * 16);
  190. // Hide the current page.
  191. for (var p = min; p < max; p++) {
  192. viewer.dict[viewer.pluginFiles[p]].visible = false;
  193. }
  194. // Advance to next page.
  195. viewer.page += 1;
  196. viewer.prev.visible = true;
  197. if ((viewer.page + 1) * 16 + 1 > viewer.pluginFiles.length) {
  198. viewer.next.visible = false;
  199. }
  200. viewer.prepareNextImage(viewer, max);
  201. viewer.refreshCanvas();
  202. }
  203. function viewerClicked(viewer, event) {
  204. var x = (event.stageX / viewer.scale) - viewer.container.x;
  205. var y = (event.stageY / viewer.scale) - viewer.container.y;
  206. if (x > 600 && y < 55) {
  207. viewer.hide();
  208. viewer.closeViewer();
  209. } else if (y > 535) {
  210. if (viewer.prev.visible && x < 325) {
  211. hideCurrentPage(viewer);
  212. } else if (viewer.next.visible && x > 325) {
  213. showNextPage(viewer)
  214. }
  215. } else {
  216. // Select a plugin.
  217. var col = Math.floor((x - 5) / 160);
  218. var row = Math.floor((y - 55) / 120);
  219. var p = row * 4 + col + 16 * viewer.page;
  220. if (p < viewer.pluginFiles.length) {
  221. viewer.hide();
  222. viewer.closeViewer();
  223. viewer.loadPlugin(viewer.pluginFiles[p] + '.json');
  224. }
  225. }
  226. }
  227. function loadThumbnailContainerHandler(viewer) {
  228. var hitArea = new createjs.Shape();
  229. var w = 650;
  230. var h = 590;
  231. var startX, startY, endX, endY;
  232. hitArea.graphics.beginFill('#FFF').drawRect(0, 0, w, h);
  233. hitArea.x = 0;
  234. hitArea.y = 0;
  235. viewer.container.hitArea = hitArea;
  236. var locked = false;
  237. viewer.container.on('click', function(event) {
  238. // We need a lock to "debouce" the click.
  239. if (locked) {
  240. console.log('debouncing click');
  241. return;
  242. }
  243. locked = true;
  244. setTimeout(function() {
  245. locked = false;
  246. }, 500);
  247. viewerClicked(viewer, event)
  248. });
  249. viewer.container.on('mousedown', function(event) {
  250. startX = event.stageX;
  251. startY = event.stageY;
  252. locked = true;
  253. });
  254. viewer.container.on('pressup', function(event) {
  255. endX = event.stageX;
  256. endY = event.stageY;
  257. if (endY > startY + 30 || endX > startX + 30) {
  258. // Down or right
  259. if (viewer.next.visible) {
  260. showNextPage(viewer);
  261. }
  262. }
  263. else if(endY < startY - 30 || endX < startX - 30) {
  264. // Up or left
  265. if (viewer.prev.visible) {
  266. hideCurrentPage(viewer);
  267. }
  268. }
  269. else {
  270. locked = false;
  271. viewerClicked(viewer, event)
  272. }
  273. });
  274. }
  275. function makeViewerBitmap(viewer, data, name, callback, extras) {
  276. // Async creation of bitmap from SVG data
  277. // Works with Chrome, Safari, Firefox (untested on IE)
  278. var img = new Image();
  279. img.onload = function() {
  280. bitmap = new createjs.Bitmap(img);
  281. callback(viewer, name, bitmap, extras);
  282. }
  283. img.src = 'data:image/svg+xml;base64,' + window.btoa(
  284. unescape(encodeURIComponent(data)));
  285. }