source: EcnlProtoTool/trunk/webapp/webmrbc/Blocks/Math.cs@ 270

Last change on this file since 270 was 270, checked in by coas-nagasima, 7 years ago

mruby版ECNLプロトタイピング・ツールを追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csharp
File size: 16.5 KB
Line 
1/**
2 * @license
3 * Visual Blocks Editor
4 *
5 * Copyright 2012 Google Inc.
6 * https://developers.google.com/blockly/
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21/**
22 * @fileoverview Math blocks for Blockly.
23 * @author q.neutron@gmail.com (Quynh Neutron)
24 */
25using System;
26using System.Linq;
27using System.Text;
28using Bridge;
29using Bridge.Html5;
30using Bridge.jQuery2;
31
32namespace WebMrbc
33{
34 public class Math
35 {
36 /**
37 * Common HSV hue for all blocks in this category.
38 */
39 public static int HUE = 230;
40 }
41
42 public class MathNumberBlock : Block
43 {
44 public const string type_name = "math_number";
45
46 public MathNumberBlock()
47 : base(type_name)
48 {
49 }
50
51 /**
52 * Block for numeric value.
53 * @this Blockly.Block
54 */
55 public void init()
56 {
57 this.setHelpUrl(Msg.MATH_NUMBER_HELPURL);
58 this.setColour(Math.HUE);
59 this.appendDummyInput()
60 .appendField(new FieldNumber("0", "-Infinity", "Infinity", 0), "NUM");
61 this.setOutput(true, "Number");
62 // Assign "this" to a variable for use in the tooltip closure below.
63 var thisBlock = this;
64 // Number block is trivial. Use tooltip of parent block if it exists.
65 this.setTooltip(new Func<string>(() => {
66 var parent = thisBlock.getParent();
67 return (parent != null && parent.getInputsInline() && !String.IsNullOrEmpty(parent.tooltip)) ? parent.tooltip :
68 Msg.MATH_NUMBER_TOOLTIP;
69 }));
70 }
71 }
72
73 public class MathArithmeticBlock : Block
74 {
75 public const string type_name = "math_arithmetic";
76
77 public MathArithmeticBlock()
78 : base(type_name)
79 {
80 }
81
82 /**
83 * Block for basic arithmetic operator.
84 * @this Blockly.Block
85 */
86 public void init()
87 {
88 this.jsonInit(new {
89 message0 = "%1 %2 %3",
90 args0 = new object[] {
91 new {
92 type = "input_value",
93 name = "A",
94 check = "Number"
95 },
96 new {
97 type = "field_dropdown",
98 name = "OP",
99 options = new [] {
100 new [] {Msg.MATH_ADDITION_SYMBOL, "ADD"},
101 new [] {Msg.MATH_SUBTRACTION_SYMBOL, "MINUS"},
102 new [] {Msg.MATH_MULTIPLICATION_SYMBOL, "MULTIPLY"},
103 new [] {Msg.MATH_DIVISION_SYMBOL, "DIVIDE"},
104 new [] {Msg.MATH_POWER_SYMBOL, "POWER"}
105 }
106 },
107 new {
108 type = "input_value",
109 name = "B",
110 check = "Number"
111 }
112 },
113 inputsInline = true,
114 output = "Number",
115 colour = Math.HUE,
116 helpUrl = Msg.MATH_ARITHMETIC_HELPURL
117 });
118 // Assign "this" to a variable for use in the tooltip closure below.
119 var thisBlock = this;
120 this.setTooltip(new Func<string>(() => {
121 switch (thisBlock.getFieldValue("OP")) {
122 case "ADD": return Msg.MATH_ARITHMETIC_TOOLTIP_ADD;
123 case "MINUS": return Msg.MATH_ARITHMETIC_TOOLTIP_MINUS;
124 case "MULTIPLY": return Msg.MATH_ARITHMETIC_TOOLTIP_MULTIPLY;
125 case "DIVIDE": return Msg.MATH_ARITHMETIC_TOOLTIP_DIVIDE;
126 case "POWER": return Msg.MATH_ARITHMETIC_TOOLTIP_POWER;
127 };
128 return "";
129 }));
130 }
131 }
132
133 public class MathSingleBlock : Block
134 {
135 public const string type_name = "math_single";
136
137 public MathSingleBlock()
138 : base(type_name)
139 {
140 }
141
142 /**
143 * Block for advanced math operators with single operand.
144 * @this Blockly.Block
145 */
146 public void init()
147 {
148 this.jsonInit(new {
149 message0 = "%1 %2",
150 args0 = new object[] {
151 new {
152 type = "field_dropdown",
153 name = "OP",
154 options = new [] {
155 new [] {Msg.MATH_SINGLE_OP_ROOT, "ROOT"},
156 new [] {Msg.MATH_SINGLE_OP_ABSOLUTE, "ABS"},
157 new [] {"-", "NEG"},
158 new [] {"ln", "LN"},
159 new [] {"log10", "LOG10"},
160 new [] {"e^", "EXP"},
161 new [] {"10^", "POW10"}
162 }
163 },
164 new {
165 type = "input_value",
166 name = "NUM",
167 check = "Number"
168 }
169 },
170 output = "Number",
171 colour = Math.HUE,
172 helpUrl = Msg.MATH_SINGLE_HELPURL
173 });
174 // Assign "this" to a variable for use in the tooltip closure below.
175 var thisBlock = this;
176 this.setTooltip(new Func<string>(() => {
177 switch (thisBlock.getFieldValue("OP")) {
178 case "ROOT": return Msg.MATH_SINGLE_TOOLTIP_ROOT;
179 case "ABS": return Msg.MATH_SINGLE_TOOLTIP_ABS;
180 case "NEG": return Msg.MATH_SINGLE_TOOLTIP_NEG;
181 case "LN": return Msg.MATH_SINGLE_TOOLTIP_LN;
182 case "LOG10": return Msg.MATH_SINGLE_TOOLTIP_LOG10;
183 case "EXP": return Msg.MATH_SINGLE_TOOLTIP_EXP;
184 case "POW10": return Msg.MATH_SINGLE_TOOLTIP_POW10;
185 }
186 return "";
187 }));
188 }
189 }
190
191 public class MathTrigBlock : Block
192 {
193 public const string type_name = "math_trig";
194
195 public MathTrigBlock()
196 : base(type_name)
197 {
198 }
199
200 /**
201 * Block for trigonometry operators.
202 * @this Blockly.Block
203 */
204 public void init()
205 {
206 this.jsonInit(new {
207 message0 = "%1 %2",
208 args0 = new object[] {
209 new {
210 type = "field_dropdown",
211 name = "OP",
212 options = new [] {
213 new [] { Msg.MATH_TRIG_SIN, "SIN" },
214 new [] { Msg.MATH_TRIG_COS, "COS" },
215 new [] { Msg.MATH_TRIG_TAN, "TAN" },
216 new [] { Msg.MATH_TRIG_ASIN, "ASIN" },
217 new [] { Msg.MATH_TRIG_ACOS, "ACOS" },
218 new [] { Msg.MATH_TRIG_ATAN, "ATAN" }
219 }
220 },
221 new {
222 type = "input_value",
223 name = "NUM",
224 check = "Number"
225 }
226 },
227 output = "Number",
228 colour = Math.HUE,
229 helpUrl = Msg.MATH_TRIG_HELPURL
230 });
231 // Assign "this" to a variable for use in the tooltip closure below.
232 var thisBlock = this;
233 this.setTooltip(new Func<string>(() => {
234 switch (thisBlock.getFieldValue("OP")) {
235 case "SIN": return Msg.MATH_TRIG_TOOLTIP_SIN;
236 case "COS": return Msg.MATH_TRIG_TOOLTIP_COS;
237 case "TAN": return Msg.MATH_TRIG_TOOLTIP_TAN;
238 case "ASIN": return Msg.MATH_TRIG_TOOLTIP_ASIN;
239 case "ACOS": return Msg.MATH_TRIG_TOOLTIP_ACOS;
240 case "ATAN": return Msg.MATH_TRIG_TOOLTIP_ATAN;
241 }
242 return "";
243 }));
244 }
245 }
246
247 public class MathConstantBlock : Block
248 {
249 public const string type_name = "math_constant";
250
251 public MathConstantBlock()
252 : base(type_name)
253 {
254 }
255
256 /**
257 * Block for constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY.
258 * @this Blockly.Block
259 */
260 public void init()
261 {
262 this.jsonInit(new {
263 message0 = "%1",
264 args0 = new object[] {
265 new {
266 type = "field_dropdown",
267 name = "CONSTANT",
268 options = new [] {
269 new [] {"\u03c0", "PI"},
270 new [] {"e", "E"},
271 new [] {"\u03c6", "GOLDEN_RATIO"},
272 new [] {"sqrt(2)", "SQRT2"},
273 new [] {"sqrt(\u00bd)", "SQRT1_2"},
274 new [] {"\u221e", "INFINITY"}
275 }
276 }
277 },
278 output = "Number",
279 colour = Math.HUE,
280 tooltip = Msg.MATH_CONSTANT_TOOLTIP,
281 helpUrl = Msg.MATH_CONSTANT_HELPURL
282 });
283 }
284 }
285
286 public class MathNumberPropertyBlock : Block
287 {
288 public const string type_name = "math_number_property";
289
290 public MathNumberPropertyBlock()
291 : base(type_name)
292 {
293 }
294
295 /**
296 * Block for checking if a number is even, odd, prime, whole, positive,
297 * negative or if it is divisible by certain number.
298 * @this Blockly.Block
299 */
300 public void init()
301 {
302 var PROPERTIES = new[] {
303 new [] {Msg.MATH_IS_EVEN, "EVEN"},
304 new [] {Msg.MATH_IS_ODD, "ODD"},
305 new [] {Msg.MATH_IS_PRIME, "PRIME"},
306 new [] {Msg.MATH_IS_WHOLE, "WHOLE"},
307 new [] {Msg.MATH_IS_POSITIVE, "POSITIVE"},
308 new [] {Msg.MATH_IS_NEGATIVE, "NEGATIVE"},
309 new [] {Msg.MATH_IS_DIVISIBLE_BY, "DIVISIBLE_BY"}
310 };
311 this.setColour(Math.HUE);
312 this.appendValueInput("NUMBER_TO_CHECK")
313 .setCheck("Number");
314 var dropdown = new FieldDropdown(PROPERTIES, (option) => {
315 var divisorInput = (option == "DIVISIBLE_BY");
316 this.updateShape_(divisorInput);
317 return Script.Undefined;
318 });
319 this.appendDummyInput()
320 .appendField(dropdown, "PROPERTY");
321 this.setInputsInline(true);
322 this.setOutput(true, "Boolean");
323 this.setTooltip(Msg.MATH_IS_TOOLTIP);
324 }
325
326 /**
327 * Create XML to represent whether the "divisorInput" should be present.
328 * @return {Element} XML storage element.
329 * @this Blockly.Block
330 */
331 public Element mutationToDom()
332 {
333 var container = Document.CreateElement("mutation");
334 var divisorInput = (this.getFieldValue("PROPERTY") == "DIVISIBLE_BY");
335 container.SetAttribute("divisor_input", divisorInput.ToString());
336 return container;
337 }
338
339 /**
340 * Parse XML to restore the "divisorInput".
341 * @param {!Element} xmlElement XML storage element.
342 * @this Blockly.Block
343 */
344 public void domToMutation(Element xmlElement)
345 {
346 var divisorInput = (xmlElement.GetAttribute("divisor_input") == "true");
347 this.updateShape_(divisorInput);
348 }
349
350 /**
351 * Modify this block to have (or not have) an input for "is divisible by".
352 * @param {boolean} divisorInput True if this block has a divisor input.
353 * @private
354 * @this Blockly.Block
355 */
356 public void updateShape_(bool divisorInput)
357 {
358 // Add or remove a Value Input.
359 var inputExists = this.getInput("DIVISOR");
360 if (divisorInput) {
361 if (inputExists == null) {
362 this.appendValueInput("DIVISOR")
363 .setCheck("Number");
364 }
365 }
366 else if (inputExists != null) {
367 this.removeInput("DIVISOR");
368 }
369 }
370 }
371
372 public class MathChangeBlock : Block
373 {
374 public const string type_name = "math_change";
375
376 public MathChangeBlock()
377 : base(type_name)
378 {
379 }
380
381 /**
382 * Block for adding to a variable in place.
383 * @this Blockly.Block
384 */
385 public void init()
386 {
387 this.jsonInit(new {
388 message0 = Msg.MATH_CHANGE_TITLE,
389 args0 = new object[] {
390 new {
391 type = "field_variable",
392 name = "VAR",
393 variable = Msg.MATH_CHANGE_TITLE_ITEM
394 },
395 new {
396 type = "input_value",
397 name = "DELTA",
398 check = "Number"
399 }
400 },
401 previousStatement = (Union<string, string[]>)null,
402 nextStatement = (Union<string, string[]>)null,
403 colour = Blockly.Variables.HUE,
404 helpUrl = Msg.MATH_CHANGE_HELPURL
405 });
406 // Assign "this" to a variable for use in the tooltip closure below.
407 var thisBlock = this;
408 this.setTooltip(new Func<string>(() => {
409 return Msg.MATH_CHANGE_TOOLTIP.Replace("%1", thisBlock.getFieldValue("VAR"));
410 }));
411 }
412 }
413
414 public class MathRoundBlock : Block
415 {
416 public const string type_name = "math_round";
417
418 public MathRoundBlock()
419 : base(type_name)
420 {
421 }
422
423 /**
424 * Block for rounding functions.
425 * @this Blockly.Block
426 */
427 public void init()
428 {
429 this.jsonInit(new {
430 message0 = "%1 %2",
431 args0 = new object[] {
432 new {
433 type = "field_dropdown",
434 name = "OP",
435 options = new [] {
436 new [] {Msg.MATH_ROUND_OPERATOR_ROUND, "ROUND"},
437 new [] {Msg.MATH_ROUND_OPERATOR_ROUNDUP, "ROUNDUP"},
438 new [] {Msg.MATH_ROUND_OPERATOR_ROUNDDOWN, "ROUNDDOWN"}
439 }
440 },
441 new {
442 type = "input_value",
443 name = "NUM",
444 check = "Number"
445 }
446 },
447 output = "Number",
448 colour = Math.HUE,
449 tooltip = Msg.MATH_ROUND_TOOLTIP,
450 helpUrl = Msg.MATH_ROUND_HELPURL
451 });
452 }
453 }
454
455 public class MathOnListBlock : Block
456 {
457 public const string type_name = "math_on_list";
458
459 public MathOnListBlock()
460 : base(type_name)
461 {
462 }
463
464 /**
465 * Block for evaluating a list of numbers to return sum, average, min, max,
466 * etc. Some functions also work on text (min, max, mode, median).
467 * @this Blockly.Block
468 */
469 public void init()
470 {
471 var OPERATORS = new[] {
472 new [] {Msg.MATH_ONLIST_OPERATOR_SUM, "SUM"},
473 new [] {Msg.MATH_ONLIST_OPERATOR_MIN, "MIN"},
474 new [] {Msg.MATH_ONLIST_OPERATOR_MAX, "MAX"},
475 new [] {Msg.MATH_ONLIST_OPERATOR_AVERAGE, "AVERAGE"},
476 new [] {Msg.MATH_ONLIST_OPERATOR_MEDIAN, "MEDIAN"},
477 new [] {Msg.MATH_ONLIST_OPERATOR_MODE, "MODE"},
478 new [] {Msg.MATH_ONLIST_OPERATOR_STD_DEV, "STD_DEV"},
479 new [] {Msg.MATH_ONLIST_OPERATOR_RANDOM, "RANDOM"}
480 };
481 // Assign "this" to a variable for use in the closures below.
482 var thisBlock = this;
483 this.setHelpUrl(Msg.MATH_ONLIST_HELPURL);
484 this.setColour(Math.HUE);
485 this.setOutput(true, "Number");
486 var dropdown = new FieldDropdown(OPERATORS, (newOp) => {
487 thisBlock.updateType_(newOp);
488 return Script.Undefined;
489 });
490 this.appendValueInput("LIST")
491 .setCheck("Array")
492 .appendField(dropdown, "OP");
493 this.setTooltip(new Func<string>(() => {
494 switch (thisBlock.getFieldValue("OP")) {
495 case "SUM": return Msg.MATH_ONLIST_TOOLTIP_SUM;
496 case "MIN": return Msg.MATH_ONLIST_TOOLTIP_MIN;
497 case "MAX": return Msg.MATH_ONLIST_TOOLTIP_MAX;
498 case "AVERAGE": return Msg.MATH_ONLIST_TOOLTIP_AVERAGE;
499 case "MEDIAN": return Msg.MATH_ONLIST_TOOLTIP_MEDIAN;
500 case "MODE": return Msg.MATH_ONLIST_TOOLTIP_MODE;
501 case "STD_DEV": return Msg.MATH_ONLIST_TOOLTIP_STD_DEV;
502 case "RANDOM": return Msg.MATH_ONLIST_TOOLTIP_RANDOM;
503 }
504 return "";
505 }));
506 }
507
508 /**
509 * Modify this block to have the correct output type.
510 * @param {string} newOp Either "MODE" or some op than returns a number.
511 * @private
512 * @this Blockly.Block
513 */
514 public void updateType_(string newOp)
515 {
516 if (newOp == "MODE") {
517 this.outputConnection.setCheck("Array");
518 }
519 else {
520 this.outputConnection.setCheck("Number");
521 }
522 }
523
524 /**
525 * Create XML to represent the output type.
526 * @return {Element} XML storage element.
527 * @this Blockly.Block
528 */
529 public Element mutationToDom()
530 {
531 var container = Document.CreateElement("mutation");
532 container.SetAttribute("op", this.getFieldValue("OP"));
533 return container;
534 }
535
536 /**
537 * Parse XML to restore the output type.
538 * @param {!Element} xmlElement XML storage element.
539 * @this Blockly.Block
540 */
541 public void domToMutation(Element xmlElement)
542 {
543 this.updateType_(xmlElement.GetAttribute("op"));
544 }
545 }
546
547 public class MathModuloBlock : Block
548 {
549 public const string type_name = "math_modulo";
550
551 public MathModuloBlock()
552 : base(type_name)
553 {
554 }
555
556 /**
557 * Block for remainder of a division.
558 * @this Blockly.Block
559 */
560 public void init()
561 {
562 this.jsonInit(new {
563 message0 = Msg.MATH_MODULO_TITLE,
564 args0 = new object[] {
565 new {
566 type = "input_value",
567 name = "DIVIDEND",
568 check = "Number"
569 },
570 new {
571 type = "input_value",
572 name = "DIVISOR",
573 check = "Number"
574 }
575 },
576 inputsInline = true,
577 output = "Number",
578 colour = Math.HUE,
579 tooltip = Msg.MATH_MODULO_TOOLTIP,
580 helpUrl = Msg.MATH_MODULO_HELPURL
581 });
582 }
583 }
584
585 public class MathConstrainBlock : Block
586 {
587 public const string type_name = "math_constrain";
588
589 public MathConstrainBlock()
590 : base(type_name)
591 {
592 }
593
594 /**
595 * Block for constraining a number between two limits.
596 * @this Blockly.Block
597 */
598 public void init()
599 {
600 this.jsonInit(new {
601 message0 = Msg.MATH_CONSTRAIN_TITLE,
602 args0 = new object[] {
603 new {
604 type = "input_value",
605 name = "VALUE",
606 check = "Number"
607 },
608 new {
609 type = "input_value",
610 name = "LOW",
611 check = "Number"
612 },
613 new {
614 type = "input_value",
615 name = "HIGH",
616 check = "Number"
617 }
618 },
619 inputsInline = true,
620 output = "Number",
621 colour = Math.HUE,
622 tooltip = Msg.MATH_CONSTRAIN_TOOLTIP,
623 helpUrl = Msg.MATH_CONSTRAIN_HELPURL
624 });
625 }
626 }
627
628 public class MathRandomIntBlock : Block
629 {
630 public const string type_name = "math_random_int";
631
632 public MathRandomIntBlock()
633 : base(type_name)
634 {
635 }
636
637 /**
638 * Block for random integer between [X] and [Y].
639 * @this Blockly.Block
640 */
641 public void init()
642 {
643 this.jsonInit(new {
644 message0 = Msg.MATH_RANDOM_INT_TITLE,
645 args0 = new object[] {
646 new {
647 type = "input_value",
648 name = "FROM",
649 check = "Number"
650 },
651 new {
652 type = "input_value",
653 name = "TO",
654 check = "Number"
655 }
656 },
657 inputsInline = true,
658 output = "Number",
659 colour = Math.HUE,
660 tooltip = Msg.MATH_RANDOM_INT_TOOLTIP,
661 helpUrl = Msg.MATH_RANDOM_INT_HELPURL
662 });
663 }
664 }
665
666 public class MathRandomFloatBlock : Block
667 {
668 public const string type_name = "math_random_float";
669
670 public MathRandomFloatBlock()
671 : base(type_name)
672 {
673 }
674
675 /**
676 * Block for random fraction between 0 and 1.
677 * @this Blockly.Block
678 */
679 public void init()
680 {
681 this.jsonInit(new {
682 message0 = Msg.MATH_RANDOM_FLOAT_TITLE_RANDOM,
683 output = "Number",
684 colour = Math.HUE,
685 tooltip = Msg.MATH_RANDOM_FLOAT_TOOLTIP,
686 helpUrl = Msg.MATH_RANDOM_FLOAT_HELPURL
687 });
688 }
689 }
690}
Note: See TracBrowser for help on using the repository browser.