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.

1047 lines
32 KiB

  1. // Copyright (c) 2014-16 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. //The ProtoBlock class is defined in this file. Protoblocks are the prototypes
  12. //from which Blocks are created.
  13. // Protoblock contain generic information about blocks and some
  14. // methods common to all blocks.
  15. function ProtoBlock(name) {
  16. // Name is used run-dictionary index, and palette label.
  17. this.name = name;
  18. // The palette to which this block is assigned.
  19. this.palette = null;
  20. // The graphic style used by the block.
  21. this.style = null;
  22. // The generator function used to create the artwork
  23. this.generator = null;
  24. // Does the block expand (or collapse) when other blocks are
  25. // attached? e.g., start, repeat...
  26. this.expandable = false;
  27. // Is this block a parameter? Parameters have their labels
  28. // overwritten with their current value.
  29. this.parameter = false;
  30. // How many "non-flow" arguments does a block have? (flow is
  31. // vertical down a stack; args are horizontal. The pendown block
  32. // has 0 args; the forward block has 1 arg; the setxy block has 2
  33. // args.
  34. this.args = 0;
  35. // Default values for block parameters, e.g., forward 100 or right 90.
  36. this.defaults = [];
  37. // What is the size of the block prior to any expansion?
  38. this.size = 1.0;
  39. // Dock types are a list of the types associated with the docking points.
  40. this.dockTypes = [];
  41. // Static labels are generated as part of the inline SVG.
  42. this.staticLabels = [];
  43. // Default fontsize used for static labels.
  44. this.fontsize = null;
  45. // Extra block width for long labels
  46. this.extraWidth = 0;
  47. // Block scale
  48. this.scale = DEFAULTBLOCKSCALE;
  49. // The filepath of the image.
  50. this.image = null;
  51. // Hidden: don't show on any palette
  52. this.hidden = false;
  53. // Disabled: use inactive colors
  54. this.disabled = false;
  55. //Stores the width of the text component
  56. this.textWidth = 0;
  57. this.adjustWidthToLabel = function () {
  58. if (this.staticLabels.length === 0) {
  59. return;
  60. }
  61. var c = new createjs.Container();
  62. var text = new createjs.Text(this.staticLabels[0], this.fontSize + 'px Sans', '#000000');
  63. c.addChild(text);
  64. var b = c.getBounds();
  65. this.textWidth = b.width;
  66. this.extraWidth += Math.max(b.width - 30, 0);
  67. };
  68. // What follows are the initializations for different block
  69. // styles.
  70. // E.g., penup, pendown
  71. this.zeroArgBlock = function () {
  72. this.args = 0;
  73. this.dockTypes.push('out');
  74. this.dockTypes.push('in');
  75. this.generator = this.zeroArgBlockGenerator;
  76. };
  77. this.zeroArgBlockGenerator = function () {
  78. var svg = new SVG();
  79. svg.init();
  80. svg.setScale(this.scale);
  81. svg.setTab(true);
  82. svg.setSlot(true);
  83. if (this.fontsize) {
  84. svg.setFontSize(this.fontsize);
  85. }
  86. svg.setExpand(30 + this.extraWidth, 0, 0, 0);
  87. var artwork = svg.basicBlock();
  88. return [artwork, svg.docks];
  89. };
  90. // E.g., hidden (used at end of clamp)
  91. this.hiddenBlockFlow = function () {
  92. this.args = 0;
  93. this.size = 0;
  94. this.dockTypes.push('out');
  95. this.dockTypes.push('in');
  96. this.generator = this.hiddenBlockFlowGenerator;
  97. };
  98. // E.g., hidden (used at end of no flow clamp)
  99. this.hiddenBlockNoFlow = function () {
  100. this.args = 0;
  101. this.size = 0;
  102. this.dockTypes.push('out');
  103. this.dockTypes.push('unavailable');
  104. this.generator = this.hiddenBlockFlowGenerator;
  105. };
  106. this.hiddenBlockFlowGenerator = function () {
  107. var svg = new SVG();
  108. svg.init();
  109. svg.setScale(this.scale);
  110. svg.setSlot(true);
  111. svg.setTab(true);
  112. if (this.fontsize) {
  113. svg.setFontSize(this.fontsize);
  114. }
  115. // We need to generate the artwork in order to generate the dock.
  116. var artwork = svg.basicBlock();
  117. // Then we replace the artwork with a single pixel.
  118. var artwork = '<svg xmlns="http://www.w3.org/2000/svg" width="1" height="1"><text style="font-size:10px;fill:#000000;font-family:sans-serif;text-anchor:end"><tspan x="46.333333333333336" y="13.5">block_label</tspan></text></svg>';
  119. // And bring the last dock position to the top.
  120. svg.docks[1][1] = svg.docks[0][1];
  121. return [artwork, svg.docks];
  122. };
  123. // E.g., break
  124. this.basicBlockNoFlow = function () {
  125. this.args = 0;
  126. this.dockTypes.push('out');
  127. this.dockTypes.push('unavailable');
  128. this.generator = this.basicBlockNoFlowGenerator;
  129. };
  130. this.basicBlockNoFlowGenerator = function () {
  131. var svg = new SVG();
  132. svg.init();
  133. svg.setScale(this.scale);
  134. svg.setSlot(true);
  135. svg.setTail(true);
  136. if (this.fontsize) {
  137. svg.setFontSize(this.fontsize);
  138. }
  139. svg.setExpand(30 + this.extraWidth, 0, 0, 0);
  140. var artwork = svg.basicBlock();
  141. return [artwork, svg.docks];
  142. };
  143. // E.g., collapsed
  144. this.basicBlockCollapsed = function () {
  145. this.args = 0;
  146. this.dockTypes.push('unavailable');
  147. this.dockTypes.push('unavailable');
  148. this.generator = this.basicBlockCollapsedGenerator;
  149. };
  150. this.basicBlockCollapsedGenerator = function () {
  151. var svg = new SVG();
  152. svg.init();
  153. svg.setScale(this.scale);
  154. svg.setCap(true);
  155. svg.setTail(true);
  156. if (this.fontsize) {
  157. svg.setFontSize(this.fontsize);
  158. }
  159. svg.setExpand(30 + this.extraWidth, 0, 0, 0);
  160. var artwork = svg.basicBlock();
  161. return [artwork, svg.docks];
  162. };
  163. // E.g., forward, right
  164. this.oneArgBlock = function () {
  165. this.args = 1;
  166. this.dockTypes.push('out');
  167. this.dockTypes.push('numberin');
  168. this.dockTypes.push('in');
  169. this.generator = this.oneArgBlockGenerator;
  170. };
  171. this.oneArgBlockGenerator = function () {
  172. var svg = new SVG();
  173. svg.init();
  174. svg.setScale(this.scale);
  175. svg.setTab(true);
  176. svg.setInnies([true]);
  177. svg.setSlot(true);
  178. if (this.fontsize) {
  179. svg.setFontSize(this.fontsize);
  180. }
  181. svg.setExpand(30 + this.extraWidth, 0, 0, 0);
  182. var artwork = svg.basicBlock();
  183. return [artwork, svg.docks];
  184. };
  185. // E.g., wait for
  186. this.oneBooleanArgBlock = function () {
  187. this.args = 1;
  188. this.size = 2.6;
  189. this.dockTypes.push('out');
  190. this.dockTypes.push('booleanin');
  191. this.dockTypes.push('in');
  192. this.generator = this.oneBooleanArgBlockGenerator;
  193. };
  194. this.oneBooleanArgBlockGenerator = function () {
  195. var svg = new SVG();
  196. svg.init();
  197. svg.setScale(this.scale);
  198. svg.setTab(true);
  199. svg.setSlot(true);
  200. svg.setBoolean(true);
  201. svg.setClampCount(0);
  202. if (this.fontsize) {
  203. svg.setFontSize(this.fontsize);
  204. }
  205. svg.setExpand(30 + this.extraWidth, 0, 0, 0);
  206. var artwork = svg.basicClamp();
  207. return [artwork, svg.docks];
  208. };
  209. // E.g., setxy. These are expandable.
  210. this.twoArgBlock = function () {
  211. this.expandable = true;
  212. this.style = 'twoarg';
  213. this.size = 2;
  214. this.args = 2;
  215. this.dockTypes.push('out');
  216. this.dockTypes.push('numberin');
  217. this.dockTypes.push('numberin');
  218. this.dockTypes.push('in');
  219. this.generator = this.twoArgBlockGenerator;
  220. };
  221. this.twoArgBlockGenerator = function (expandY) {
  222. var svg = new SVG();
  223. svg.init();
  224. svg.setScale(this.scale);
  225. svg.setTab(true);
  226. svg.setInnies([true, true]);
  227. svg.setSlot(true);
  228. if (expandY) {
  229. svg.setExpand(30 + this.extraWidth, (expandY - 1) * STANDARDBLOCKHEIGHT / 2, 0, 0);
  230. } else {
  231. svg.setExpand(30 + this.extraWidth, 0, 0, 0);
  232. }
  233. if (this.fontsize) {
  234. svg.setFontSize(this.fontsize);
  235. }
  236. var artwork = svg.basicBlock();
  237. return [artwork, svg.docks];
  238. };
  239. // E.g., ??? These are expandable.
  240. this.threeArgBlock = function () {
  241. this.expandable = true;
  242. this.style = 'twoarg';
  243. this.size = 3;
  244. this.args = 3;
  245. this.dockTypes.push('out');
  246. this.dockTypes.push('numberin');
  247. this.dockTypes.push('numberin');
  248. this.dockTypes.push('numberin');
  249. this.dockTypes.push('in');
  250. this.generator = this.threeArgBlockGenerator;
  251. };
  252. this.threeArgBlockGenerator = function (expandY) {
  253. var svg = new SVG();
  254. svg.init();
  255. svg.setScale(this.scale);
  256. svg.setTab(true);
  257. svg.setInnies([true, true, true]);
  258. svg.setSlot(true);
  259. if (expandY) {
  260. svg.setExpand(30 + this.extraWidth, (expandY - 1) * STANDARDBLOCKHEIGHT / 2, 0, 0);
  261. } else {
  262. svg.setExpand(30 + this.extraWidth, 0, 0, 0);
  263. }
  264. if (this.fontsize) {
  265. svg.setFontSize(this.fontsize);
  266. }
  267. var artwork = svg.basicBlock();
  268. return [artwork, svg.docks];
  269. };
  270. // E.g., sqrt, box
  271. this.oneArgMathBlock = function () {
  272. this.style = 'arg';
  273. this.size = 1;
  274. this.args = 1;
  275. this.parameter = true;
  276. this.dockTypes.push('numberout');
  277. this.dockTypes.push('numberin');
  278. this.generator = this.oneArgMathBlockGenerator;
  279. };
  280. this.oneArgMathBlockGenerator = function () {
  281. var svg = new SVG();
  282. svg.init();
  283. svg.setScale(this.scale);
  284. svg.setSlot(false);
  285. svg.setInnies([true]);
  286. svg.setOutie(true);
  287. svg.setTab(false);
  288. if (this.fontsize) {
  289. svg.setFontSize(this.fontsize);
  290. }
  291. svg.setExpand(30 + this.extraWidth, 0, 0, 0);
  292. var artwork = svg.basicBlock();
  293. return [artwork, svg.docks];
  294. };
  295. // E.g., plus, minus, multiply, divide, power. These are also expandable.
  296. this.twoArgMathBlock = function () {
  297. this.expandable = true;
  298. this.style = 'arg';
  299. this.size = 2;
  300. this.args = 2;
  301. this.parameter = true;
  302. this.dockTypes.push('numberout');
  303. this.dockTypes.push('numberin');
  304. this.dockTypes.push('numberin');
  305. this.generator = this.twoArgMathBlockGenerator;
  306. };
  307. this.twoArgMathBlockGenerator = function (expandY) {
  308. var svg = new SVG();
  309. svg.init();
  310. svg.setScale(this.scale);
  311. svg.setSlot(false);
  312. svg.setInnies([true, true]);
  313. svg.setOutie(true);
  314. svg.setTab(false);
  315. if (expandY) {
  316. svg.setExpand(30 + this.extraWidth, (expandY - 1) * STANDARDBLOCKHEIGHT / 2, 0, 0);
  317. } else {
  318. svg.setExpand(30 + this.extraWidth, 0, 0, 0);
  319. }
  320. if (this.fontsize) {
  321. svg.setFontSize(this.fontsize);
  322. }
  323. var artwork = svg.basicBlock();
  324. return [artwork, svg.docks];
  325. };
  326. //
  327. this.threeArgMathBlock = function () {
  328. this.expandable = true;
  329. this.style = 'arg';
  330. this.size = 3;
  331. this.args = 3;
  332. this.parameter = true;
  333. this.dockTypes.push('numberout');
  334. this.dockTypes.push('numberin');
  335. this.dockTypes.push('numberin');
  336. this.dockTypes.push('numberin');
  337. this.generator = this.threeArgMathBlockGenerator;
  338. };
  339. this.threeArgMathBlockGenerator = function (expandY) {
  340. var svg = new SVG();
  341. svg.init();
  342. svg.setScale(this.scale);
  343. svg.setSlot(false);
  344. svg.setInnies([true, true, true]);
  345. svg.setOutie(true);
  346. svg.setTab(false);
  347. if (expandY) {
  348. svg.setExpand(30 + this.extraWidth, (expandY - 1) * STANDARDBLOCKHEIGHT / 2, 0, 0);
  349. } else {
  350. svg.setExpand(30 + this.extraWidth, 0, 0, 0);
  351. }
  352. if (this.fontsize) {
  353. svg.setFontSize(this.fontsize);
  354. }
  355. var artwork = svg.basicBlock();
  356. return [artwork, svg.docks];
  357. };
  358. // E.g., number, string. Value blocks get DOM textareas associated
  359. // with them so their values can be edited by the user.
  360. this.valueBlock = function () {
  361. this.style = 'value';
  362. this.size = 1;
  363. this.args = 0;
  364. this.dockTypes.push('numberout');
  365. this.generator = this.valueBlockGenerator;
  366. };
  367. this.valueBlockGenerator = function () {
  368. var svg = new SVG();
  369. svg.init();
  370. svg.setScale(this.scale);
  371. // Extra room for parameter label
  372. svg.setExpand(60 + this.extraWidth, 0, 0, 0);
  373. svg.setOutie(true);
  374. if (this.fontsize) {
  375. svg.setFontSize(this.fontsize);
  376. }
  377. var artwork = svg.basicBox();
  378. return [artwork, svg.docks];
  379. };
  380. // E.g., media. Media blocks invoke a chooser and a thumbnail
  381. // image is overlayed to represent the data associated with the
  382. // block.
  383. this.mediaBlock = function () {
  384. this.style = 'value';
  385. this.size = 2;
  386. this.args = 0;
  387. this.dockTypes.push('mediaout');
  388. this.generator = this.mediaBlockGenerator;
  389. };
  390. this.mediaBlockGenerator = function () {
  391. var svg = new SVG();
  392. svg.init();
  393. svg.setScale(this.scale);
  394. // Extra room for graphics
  395. svg.setExpand(60 + this.extraWidth, 23, 0, 0);
  396. svg.setOutie(true);
  397. if (this.fontsize) {
  398. svg.setFontSize(this.fontsize);
  399. }
  400. var artwork = svg.basicBox();
  401. return [artwork, svg.docks];
  402. };
  403. // E.g., start. A "child" flow is docked in an expandable clamp.
  404. // There are no additional arguments and no flow above or below.
  405. this.stackClampZeroArgBlock = function () {
  406. this.style = 'clamp';
  407. this.expandable = true;
  408. this.size = 3;
  409. this.args = 1;
  410. this.dockTypes.push('unavailable');
  411. this.dockTypes.push('in');
  412. this.dockTypes.push('unavailable');
  413. this.generator = this.stackClampZeroArgBlockGenerator;
  414. };
  415. this.stackClampZeroArgBlockGenerator = function (slots) {
  416. var svg = new SVG();
  417. svg.init();
  418. svg.setScale(this.scale);
  419. svg.setCap(true);
  420. svg.setTail(true);
  421. svg.setExpand(20 + this.extraWidth, 0, 0, 0);
  422. if (slots) {
  423. svg.setClampSlots(0, slots);
  424. } else {
  425. svg.setClampSlots(0, 1);
  426. }
  427. if (this.fontsize) {
  428. svg.setFontSize(this.fontsize);
  429. }
  430. var artwork = svg.basicClamp();
  431. return [artwork, svg.docks];
  432. };
  433. // E.g., emptyclamp. Unlike start, there is a flow above and below.
  434. this.flowClampBlock = function () {
  435. this.style = 'clamp';
  436. this.expandable = true;
  437. this.size = 2;
  438. this.args = 1;
  439. this.dockTypes.push('out');
  440. this.dockTypes.push('in');
  441. this.dockTypes.push('in');
  442. this.generator = this.flowClampBlockGenerator;
  443. };
  444. this.flowClampBlockGenerator = function (slots) {
  445. var svg = new SVG();
  446. svg.init();
  447. svg.setScale(this.scale);
  448. svg.setTab(true);
  449. svg.setSlot(true);
  450. svg.setExpand(20 + this.extraWidth, 0, 0, 0);
  451. if (slots) {
  452. svg.setClampSlots(0, slots);
  453. } else {
  454. svg.setClampSlots(0, 1);
  455. }
  456. if (this.fontsize) {
  457. svg.setFontSize(this.fontsize);
  458. }
  459. var artwork = svg.basicClamp();
  460. return [artwork, svg.docks];
  461. };
  462. // E.g., repeat. Unlike action, there is a flow above and below.
  463. this.flowClampOneArgBlock = function () {
  464. this.style = 'clamp';
  465. this.expandable = true;
  466. this.size = 2;
  467. this.args = 2;
  468. this.dockTypes.push('out');
  469. this.dockTypes.push('numberin');
  470. this.dockTypes.push('in');
  471. this.dockTypes.push('in');
  472. this.generator = this.flowClampOneArgBlockGenerator;
  473. };
  474. this.flowClampOneArgBlockGenerator = function (slots) {
  475. var svg = new SVG();
  476. svg.init();
  477. svg.setScale(this.scale);
  478. svg.setTab(true);
  479. svg.setSlot(true);
  480. svg.setInnies([true]);
  481. svg.setExpand(20 + this.extraWidth, 0, 0, 0);
  482. if (slots) {
  483. svg.setClampSlots(0, slots);
  484. } else {
  485. svg.setClampSlots(0, 1);
  486. }
  487. if (this.fontsize) {
  488. svg.setFontSize(this.fontsize);
  489. }
  490. var artwork = svg.basicClamp();
  491. return [artwork, svg.docks];
  492. };
  493. // E.g., tuplet, which takes two args plus an interior flow. There is a flow above and below.
  494. this.flowClampTwoArgBlock = function () {
  495. this.style = 'clamp';
  496. this.expandable = true;
  497. this.size = 3;
  498. this.args = 3;
  499. this.dockTypes.push('out');
  500. this.dockTypes.push('numberin');
  501. this.dockTypes.push('numberin');
  502. this.dockTypes.push('in');
  503. this.dockTypes.push('in');
  504. this.generator = this.flowClampTwoArgBlockGenerator;
  505. };
  506. this.flowClampTwoArgBlockGenerator = function (slots) {
  507. var svg = new SVG();
  508. svg.init();
  509. svg.setScale(this.scale);
  510. svg.setTab(true);
  511. svg.setSlot(true);
  512. svg.setInnies([true, true]);
  513. svg.setExpand(20 + this.extraWidth, 0, 0, 0);
  514. if (slots) {
  515. svg.setClampSlots(0, slots);
  516. } else {
  517. svg.setClampSlots(0, 1);
  518. }
  519. if (this.fontsize) {
  520. svg.setFontSize(this.fontsize);
  521. }
  522. var artwork = svg.basicClamp();
  523. return [artwork, svg.docks];
  524. };
  525. this.flowClampThreeArgBlock = function (){
  526. this.style = 'clamp';
  527. this.expandable = true;
  528. this.size = 4;
  529. this.args = 4;
  530. this.dockTypes.push('out');
  531. this.dockTypes.push('numberin');
  532. this.dockTypes.push('numberin');
  533. this.dockTypes.push('textin');
  534. this.dockTypes.push('in');
  535. this.dockTypes.push('in');
  536. this.generator = this.flowClampThreeArgBlockGenerator;
  537. };
  538. this.flowClampThreeArgBlockGenerator = function (slots) {
  539. var svg = new SVG();
  540. svg.init();
  541. svg.setScale(this.scale);
  542. svg.setTab(true);
  543. svg.setSlot(true);
  544. svg.setInnies([true, true,true]);
  545. svg.setExpand(20 + this.extraWidth, 0, 0, 0);
  546. if (slots) {
  547. svg.setClampSlots(0, slots);
  548. } else {
  549. svg.setClampSlots(0, 1);
  550. }
  551. if (this.fontsize) {
  552. svg.setFontSize(this.fontsize);
  553. }
  554. var artwork = svg.basicClamp();
  555. return [artwork, svg.docks];
  556. };
  557. // E.g., do with args: innies instead of interior slots.
  558. this.argClampOneArgBlock = function () {
  559. this.style = 'argclamp';
  560. this.expandable = true;
  561. this.size = 3;
  562. this.args = 2;
  563. this.dockTypes.push('out');
  564. this.dockTypes.push('textin');
  565. this.dockTypes.push('anyin');
  566. this.dockTypes.push('in');
  567. this.generator = this.argClampOneArgBlockGenerator;
  568. };
  569. this.argClampOneArgBlockGenerator = function (slots) {
  570. var svg = new SVG();
  571. svg.init();
  572. svg.setScale(this.scale);
  573. svg.setTab(true);
  574. svg.setSlot(true);
  575. svg.setInnies([true]);
  576. svg.setExpand(20 + this.extraWidth, 0, 0, 0);
  577. if (slots) {
  578. svg.setClampSlots(0, slots);
  579. } else {
  580. svg.setClampSlots(0, [1]);
  581. }
  582. if (this.fontsize) {
  583. svg.setFontSize(this.fontsize);
  584. }
  585. var artwork = svg.argClamp();
  586. return [artwork, svg.docks];
  587. };
  588. // E.g., calculate with args: innies instead of interior slots.
  589. this.argClampOneArgMathBlock = function () {
  590. this.style = 'argclamparg';
  591. this.expandable = true;
  592. this.size = 3;
  593. this.args = 2;
  594. this.dockTypes.push('anyout');
  595. this.dockTypes.push('textin');
  596. this.dockTypes.push('anyin');
  597. this.generator = this.argClampOneArgMathBlockGenerator;
  598. };
  599. this.argClampOneArgMathBlockGenerator = function (slots) {
  600. var svg = new SVG();
  601. svg.init();
  602. svg.setScale(this.scale);
  603. svg.setInnies([true]);
  604. svg.setOutie(true);
  605. svg.setTab(false);
  606. svg.setSlot(false);
  607. svg.setExpand(20 + this.extraWidth, 0, 0, 0);
  608. if (slots) {
  609. svg.setClampSlots(0, slots);
  610. } else {
  611. svg.setClampSlots(0, [1]);
  612. }
  613. if (this.fontsize) {
  614. svg.setFontSize(this.fontsize);
  615. }
  616. var artwork = svg.argClamp();
  617. return [artwork, svg.docks];
  618. };
  619. // E.g., named do with args: innies instead of interior slots.
  620. this.argClampBlock = function () {
  621. this.style = 'argclamp';
  622. this.expandable = true;
  623. this.size = 3;
  624. this.args = 1;
  625. this.dockTypes.push('out');
  626. this.dockTypes.push('anyin');
  627. this.dockTypes.push('in');
  628. this.generator = this.argClampBlockGenerator;
  629. };
  630. this.argClampBlockGenerator = function (slots) {
  631. var svg = new SVG();
  632. svg.init();
  633. svg.setScale(this.scale);
  634. svg.setTab(true);
  635. svg.setSlot(true);
  636. svg.setExpand(20 + this.extraWidth, 0, 0, 0);
  637. if (slots) {
  638. svg.setClampSlots(0, slots);
  639. } else {
  640. svg.setClampSlots(0, [1]);
  641. }
  642. if (this.fontsize) {
  643. svg.setFontSize(this.fontsize);
  644. }
  645. var artwork = svg.argClamp();
  646. return [artwork, svg.docks];
  647. };
  648. // E.g., named calculate with args: innies instead of interior slots.
  649. this.argClampMathBlock = function () {
  650. this.style = 'argclamparg';
  651. this.expandable = true;
  652. this.size = 3;
  653. this.args = 1;
  654. this.dockTypes.push('anyout');
  655. this.dockTypes.push('anyin');
  656. this.generator = this.argClampMathBlockGenerator;
  657. };
  658. this.argClampMathBlockGenerator = function (slots) {
  659. var svg = new SVG();
  660. svg.init();
  661. svg.setScale(this.scale);
  662. svg.setOutie(true);
  663. svg.setTab(false);
  664. svg.setSlot(false);
  665. svg.setExpand(20 + this.extraWidth, 0, 0, 0);
  666. if (slots) {
  667. svg.setClampSlots(0, slots);
  668. } else {
  669. svg.setClampSlots(0, [1]);
  670. }
  671. if (this.fontsize) {
  672. svg.setFontSize(this.fontsize);
  673. }
  674. var artwork = svg.argClamp();
  675. return [artwork, svg.docks];
  676. };
  677. // E.g., if. A "child" flow is docked in an expandable clamp. The
  678. // additional argument is a boolean. There is flow above and below.
  679. this.flowClampBooleanArgBlock = function () {
  680. this.style = 'clamp';
  681. this.expandable = true;
  682. this.size = 3;
  683. this.args = 2;
  684. this.dockTypes.push('out');
  685. this.dockTypes.push('booleanin');
  686. this.dockTypes.push('in');
  687. this.dockTypes.push('in');
  688. this.generator = this.flowClampBooleanArgBlockGenerator;
  689. };
  690. this.flowClampBooleanArgBlockGenerator = function (slots) {
  691. var svg = new SVG();
  692. svg.init();
  693. svg.setScale(this.scale);
  694. svg.setTab(true);
  695. svg.setBoolean(true);
  696. svg.setSlot(true);
  697. svg.setExpand(this.extraWidth, 0, 0, 0);
  698. if (slots) {
  699. svg.setClampSlots(0, slots);
  700. } else {
  701. svg.setClampSlots(0, 1);
  702. }
  703. if (this.fontsize) {
  704. svg.setFontSize(this.fontsize);
  705. }
  706. var artwork = svg.basicClamp();
  707. return [artwork, svg.docks];
  708. };
  709. // E.g., if then else. Two "child" flows are docked in expandable
  710. // clamps. The additional argument is a boolean. There is flow
  711. // above and below.
  712. this.doubleFlowClampBooleanArgBlock = function () {
  713. this.style = 'doubleclamp';
  714. this.expandable = true;
  715. this.size = 4;
  716. this.args = 3;
  717. this.dockTypes.push('out');
  718. this.dockTypes.push('booleanin');
  719. this.dockTypes.push('in');
  720. this.dockTypes.push('in');
  721. this.dockTypes.push('in');
  722. this.generator = this.doubleFlowClampBooleanArgBlockGenerator;
  723. };
  724. this.doubleFlowClampBooleanArgBlockGenerator = function (bottomSlots, topSlots) {
  725. var svg = new SVG();
  726. svg.init();
  727. svg.setScale(this.scale);
  728. svg.setTab(true);
  729. svg.setSlot(true);
  730. svg.setBoolean(true);
  731. svg.setClampCount(2);
  732. if (topSlots) {
  733. svg.setClampSlots(0, topSlots);
  734. } else {
  735. svg.setClampSlots(0, 1);
  736. }
  737. if (bottomSlots) {
  738. svg.setClampSlots(1, bottomSlots);
  739. } else {
  740. svg.setClampSlots(1, 1);
  741. }
  742. svg.setExpand(this.extraWidth, 0, 0, 0);
  743. if (this.fontsize) {
  744. svg.setFontSize(this.fontsize);
  745. }
  746. var artwork = svg.basicClamp();
  747. return [artwork, svg.docks];
  748. };
  749. // E.g., forever. Unlike start, there is flow above and below.
  750. this.flowClampZeroArgBlock = function () {
  751. this.style = 'clamp';
  752. this.expandable = true;
  753. this.size = 2;
  754. this.args = 1;
  755. this.dockTypes.push('out');
  756. this.dockTypes.push('in');
  757. this.dockTypes.push('in');
  758. this.generator = this.flowClampZeroArgBlockGenerator;
  759. };
  760. this.flowClampZeroArgBlockGenerator = function (slots) {
  761. var svg = new SVG();
  762. svg.init();
  763. svg.setScale(this.scale);
  764. svg.setTab(true);
  765. svg.setSlot(true);
  766. svg.setExpand(10 + this.extraWidth, 0, 0, 0);
  767. if (slots) {
  768. svg.setClampSlots(0, slots);
  769. } else {
  770. svg.setClampSlots(0, 1);
  771. }
  772. if (this.fontsize) {
  773. svg.setFontSize(this.fontsize);
  774. }
  775. var artwork = svg.basicClamp();
  776. return [artwork, svg.docks];
  777. };
  778. // E.g., count clamp: math block with interior slots
  779. this.argFlowClampBlock = function () {
  780. this.style = 'argflowclamp';
  781. this.expandable = true;
  782. this.size = 3;
  783. this.args = 2;
  784. this.dockTypes.push('anyout');
  785. this.dockTypes.push('in');
  786. this.generator = this.argFlowClampGenerator;
  787. };
  788. this.argFlowClampGenerator = function (slots) {
  789. var svg = new SVG();
  790. svg.init();
  791. svg.setScale(this.scale);
  792. svg.setSlot(false);
  793. svg.setOutie(true);
  794. svg.setExpand(20 + this.extraWidth, 0, 0, 0);
  795. if (slots) {
  796. svg.setClampSlots(0, slots);
  797. } else {
  798. svg.setClampSlots(0, [1]);
  799. }
  800. if (this.fontsize) {
  801. svg.setFontSize(this.fontsize);
  802. }
  803. var artwork = svg.basicClamp();
  804. return [artwork, svg.docks];
  805. };
  806. // E.g., action. A "child" flow is docked in an expandable clamp.
  807. // The additional argument is a name. Again, no flow above or below.
  808. this.stackClampOneArgBlock = function () {
  809. this.style = 'clamp';
  810. this.expandable = true;
  811. this.size = 3;
  812. this.args = 2;
  813. this.dockTypes.push('unavailable');
  814. this.dockTypes.push('anyin');
  815. this.dockTypes.push('in');
  816. this.dockTypes.push('unavailable');
  817. this.generator = this.stackClampOneArgBlockGenerator;
  818. };
  819. this.stackClampOneArgBlockGenerator = function (slots) {
  820. var svg = new SVG();
  821. svg.init();
  822. svg.setScale(this.scale);
  823. svg.setCap(true);
  824. svg.setTail(true);
  825. svg.setInnies([true]);
  826. svg.setExpand(10 + this.extraWidth, 0, 0, 0);
  827. if (slots) {
  828. svg.setClampSlots(0, slots);
  829. } else {
  830. svg.setClampSlots(0, 1);
  831. }
  832. if (this.fontsize) {
  833. svg.setFontSize(this.fontsize);
  834. }
  835. var artwork = svg.basicClamp();
  836. return [artwork, svg.docks];
  837. };
  838. // E.g., mouse button.
  839. this.booleanZeroArgBlock = function () {
  840. this.style = 'arg';
  841. this.size = 1;
  842. this.args = 0;
  843. this.dockTypes.push('booleanout');
  844. this.generator = this.booleanZeroArgBlockGenerator;
  845. };
  846. this.booleanZeroArgBlockGenerator = function () {
  847. var svg = new SVG();
  848. svg.init();
  849. svg.setScale(this.scale);
  850. svg.setExpand(60 + this.extraWidth, 0, 0, 4);
  851. if (this.fontsize) {
  852. svg.setFontSize(this.fontsize);
  853. }
  854. var artwork = svg.booleanNot(true);
  855. return [artwork, svg.docks];
  856. };
  857. // E.g., named sensor blocks
  858. this.booleanOneArgBlock = function () {
  859. this.style = 'arg';
  860. this.size = 2;
  861. this.args = 1;
  862. this.parameter = true;
  863. this.dockTypes.push('booleanout');
  864. this.dockTypes.push('textin');
  865. this.generator = this.booleanOneArgBlockGenerator;
  866. };
  867. this.booleanOneArgBlockGenerator = function () {
  868. var svg = new SVG();
  869. svg.init();
  870. svg.setScale(this.scale);
  871. svg.setExpand(20 + this.extraWidth, 0, 0, 0);
  872. if (this.fontsize) {
  873. svg.setFontSize(this.fontsize);
  874. }
  875. svg.setInnies([true]);
  876. var artwork = svg.booleanNot(true); // OneArg
  877. return [artwork, svg.docks];
  878. };
  879. // E.g., not
  880. this.booleanOneBooleanArgBlock = function () {
  881. this.style = 'arg';
  882. this.size = 2;
  883. this.args = 1;
  884. this.parameter = true;
  885. this.dockTypes.push('booleanout');
  886. this.dockTypes.push('booleanin');
  887. this.generator = this.booleanOneBooleanArgBlockGenerator;
  888. };
  889. this.booleanOneBooleanArgBlockGenerator = function () {
  890. var svg = new SVG();
  891. svg.init();
  892. svg.setScale(this.scale);
  893. svg.setExpand(20 + this.extraWidth, 0, 0, 0);
  894. if (this.fontsize) {
  895. svg.setFontSize(this.fontsize);
  896. }
  897. var artwork = svg.booleanNot(false);
  898. return [artwork, svg.docks];
  899. };
  900. // E.g., and, or
  901. this.booleanTwoBooleanArgBlock = function () {
  902. this.style = 'arg';
  903. this.size = 3;
  904. this.args = 2;
  905. this.parameter = true;
  906. this.dockTypes.push('booleanout');
  907. this.dockTypes.push('booleanin');
  908. this.dockTypes.push('booleanin');
  909. this.generator = this.booleanTwoBooleanArgBlockGenerator;
  910. };
  911. this.booleanTwoBooleanArgBlockGenerator = function () {
  912. var svg = new SVG();
  913. svg.init();
  914. svg.setScale(this.scale);
  915. svg.setExpand(20 + this.extraWidth, 0, 0, 0);
  916. if (this.fontsize) {
  917. svg.setFontSize(this.fontsize);
  918. }
  919. var artwork = svg.booleanAndOr();
  920. return [artwork, svg.docks];
  921. };
  922. // E.g., greater, less, equal
  923. this.booleanTwoArgBlock = function () {
  924. this.style = 'arg';
  925. this.size = 2;
  926. this.args = 2;
  927. this.parameter = true;
  928. this.expandable = true;
  929. this.dockTypes.push('booleanout');
  930. this.dockTypes.push('numberin');
  931. this.dockTypes.push('numberin');
  932. this.generator = this.booleanTwoArgBlockGenerator;
  933. };
  934. this.booleanTwoArgBlockGenerator = function (expandY) {
  935. var svg = new SVG();
  936. svg.init();
  937. svg.setScale(this.scale);
  938. if (expandY) {
  939. svg.setExpand(10 + this.extraWidth, (expandY - 1) * STANDARDBLOCKHEIGHT / 2, 0, 0);
  940. } else {
  941. svg.setExpand(10 + this.extraWidth, 0, 0, 0);
  942. }
  943. if (this.fontsize) {
  944. svg.setFontSize(this.fontsize);
  945. }
  946. var artwork = svg.booleanCompare();
  947. return [artwork, svg.docks];
  948. };
  949. // E.g., color, shade, pensize, ...
  950. this.parameterBlock = function () {
  951. this.style = 'arg';
  952. this.parameter = true;
  953. this.size = 1;
  954. this.args = 0;
  955. this.dockTypes.push('numberout');
  956. this.generator = this.parameterBlockGenerator;
  957. };
  958. this.parameterBlockGenerator = function () {
  959. var svg = new SVG();
  960. svg.init();
  961. svg.setScale(this.scale);
  962. // Extra room for parameter label
  963. svg.setExpand(70 + this.extraWidth, 0, 0, 0);
  964. svg.setOutie(true);
  965. if (this.fontsize) {
  966. svg.setFontSize(this.fontsize);
  967. }
  968. var artwork = svg.basicBox();
  969. return [artwork, svg.docks];
  970. };
  971. };