예제 #1
0
        /// <summary>
        /// Return the generator code of each block type in an array in a given language.
        /// </summary>
        /// <param name="blockXmlMap"></param> Map of block type to XML.
        /// <param name="generatorLanguage"> E.g. "JavaScript", "Python", "PHP", "Lua",
        /// "Dart"</param>
        /// <returns>The concatenation of each block's generator code in the
        /// desired format.</returns>
        public string getGeneratorCode(Dictionary <string, Element> blockXmlMap, string generatorLanguage)
        {
            var multiblockCode = new JsArray <string>();

            // Define the custom blocks in order to be able to create instances of
            // them in the exporter workspace.
            this.addBlockDefinitions(blockXmlMap);

            foreach (var blockType in blockXmlMap.Keys)
            {
                string blockGenCode;
                var    xml = blockXmlMap[blockType];
                if (xml != null)
                {
                    // Render the preview block in the hidden workspace.
                    var tempBlock =
                        FactoryUtils.getDefinedBlock(blockType, this.hiddenWorkspace);
                    // Get generator stub for the given block and add to  generator code.
                    blockGenCode =
                        FactoryUtils.getGeneratorStub(tempBlock, generatorLanguage);
                }
                else
                {
                    // Append warning comment and write to console.
                    blockGenCode = "// No generator stub generated for " + blockType +
                                   ". Block was not found in Block Library Storage.";
                    Console.WriteLine("No block generator stub generated for " + blockType +
                                      ". Block was not found in Block Library Storage.");
                }
                multiblockCode.Push(blockGenCode);
            }
            return(multiblockCode.Join("\n\n"));
        }
예제 #2
0
        /// <summary>
        /// Return the given language code of each block type in an array.
        /// </summary>
        /// <param name="blockXmlMap"> Map of block type to XML.</param>
        /// <param name="definitionFormat"> "JSON" or "JavaScript"</param>
        /// <returns>The concatenation of each block's language code in the
        ///    desired format.</returns>
        public string getBlockDefinitions(Dictionary <string, Element> blockXmlMap, string definitionFormat)
        {
            var blockCode = new JsArray <string>();

            foreach (var blockType in blockXmlMap.Keys)
            {
                string code;
                var    xml = blockXmlMap[blockType];
                if (xml != null)
                {
                    // Render and get block from hidden workspace.
                    var rootBlock = this.getRootBlockFromXml_(xml);
                    if (rootBlock != null)
                    {
                        // Generate the block's definition.
                        code = FactoryUtils.getBlockDefinition(blockType, rootBlock,
                                                               definitionFormat, this.hiddenWorkspace);
                        // Add block's definition to the definitions to return.
                    }
                    else
                    {
                        // Append warning comment and write to console.
                        code = "// No block definition generated for " + blockType +
                               ". Could not find root block in XML stored for this block.";
                        Console.WriteLine("No block definition generated for " + blockType +
                                          ". Could not find root block in XML stored for this block.");
                    }
                }
                else
                {
                    // Append warning comment and write to console.
                    code = "// No block definition generated for " + blockType +
                           ". Block was not found in Block Library Storage.";
                    Console.WriteLine("No block definition generated for " + blockType +
                                      ". Block was not found in Block Library Storage.");
                }
                blockCode.Push(code);
            }

            // Surround json with [] and comma separate items.
            if (definitionFormat == "JSON")
            {
                return("[" + blockCode.Join(",\n") + "]");
            }
            return(blockCode.Join("\n\n"));
        }
예제 #3
0
        /// <summary>
        /// Get this warning's texts.
        /// </summary>
        /// <returns>All texts concatenated into one string.</returns>
        public override string getText()
        {
            var allWarnings = new JsArray <string>();

            foreach (var id in this.text_.Keys)
            {
                allWarnings.Push(this.text_[id]);
            }
            return(allWarnings.Join("\n"));
        }
예제 #4
0
        private string join_(int[] ints, string dem)
        {
            var sb = new JsArray <string>();

            foreach (int i in ints)
            {
                sb.Push(i.ToString());
            }
            return(sb.Join(dem));
        }
예제 #5
0
        /// <summary>
        /// Generate a unique ID.  This should be globally unique.
        /// 87 characters ^ 20 length > 128 bits (better than a UUID).
        /// </summary>
        /// <returns>A globally unique ID string.</returns>
        public static string genUid()
        {
            var length     = 20;
            var soupLength = Core.genUid_soup_.Length;
            var id         = new JsArray <string>();

            for (var i = 0; i < length; i++)
            {
                int r = (int)(Script.Random() * soupLength);
                id.Push(Core.genUid_soup_.CharAt(r));
            }
            return(id.Join(""));
        }
예제 #6
0
            /// <summary>
            /// Reassemble the array of words into text, with the specified line breaks.
            /// </summary>
            /// <param name="words">Array of each word.</param>
            /// <param name="wordBreaks">Array of line breaks.</param>
            /// <returns>Plain text.</returns>
            private static string wrapToText_(string[] words, bool?[] wordBreaks)
            {
                var text = new JsArray <string>();

                for (var i = 0; i < words.Length; i++)
                {
                    text.Push(words[i]);
                    if (wordBreaks[i].HasValue)
                    {
                        text.Push(wordBreaks[i].Value ? "\n" : " ");
                    }
                }
                return(text.Join(""));
            }
        /// <summary>
        /// Tied to the "All Used" button in the Block Exporter's "Select" button.
        /// Selects all blocks stored in block library and used in workspace factory.
        /// </summary>
        public void selectUsedBlocks()
        {
            // Deselect all blocks.
            this.view.deselectAllBlocks();

            // Get list of block types that are in block library and used in workspace
            // factory.
            var storedBlockTypes = this.blockLibStorage.getBlockTypes();
            var sharedBlockTypes = new JsArray <string>();
            // Keep list of custom block types used but not in library.
            var unstoredCustomBlockTypes = new JsArray <string>();

            for (var i = 0; i < this.usedBlockTypes.Length; i++)
            {
                var blockType = this.usedBlockTypes[i];
                if (storedBlockTypes.IndexOf(blockType) != -1)
                {
                    sharedBlockTypes.Push(blockType);
                }
                else if (Array.IndexOf(StandardCategories.coreBlockTypes, blockType) == -1)
                {
                    unstoredCustomBlockTypes.Push(blockType);
                }
            }

            // Select each shared block type.
            for (var i = 0; i < sharedBlockTypes.Length; i++)
            {
                var blockType = sharedBlockTypes[i];
                this.view.select(blockType);
            }
            this.view.listSelectedBlocks();

            if (unstoredCustomBlockTypes.Length > 0)
            {
                // Warn user to import block defifnitions and generator code for blocks
                // not in their Block Library nor Blockly's standard library.
                var blockTypesText = unstoredCustomBlockTypes.Join(", ");
                var customWarning  = "Custom blocks used in workspace factory but not " +
                                     "stored in block library:\n " + blockTypesText +
                                     "\n\nDon\'t forget to include block definitions and generator code " +
                                     "for these blocks.";
                Window.Alert(customWarning);
            }
        }
        /// <summary>
        /// Support function for button creation.
        /// </summary>
        /// <param name="parentNode">Container the button should be added to.</param>
        /// <param name="label">Button label.</param>
        /// <param name="opt_className">Class name for button, which will be used
        /// in addition to "goog-date-picker-btn".</param>
        private HTMLElement createButton_(HTMLTableDataCellElement parentNode, string label,
                                          string opt_className = null)
        {
            var classes = new JsArray <string>()
            {
                le.getCssName(this.getBaseCssClass(), "btn")
            };

            if (opt_className != null)
            {
                classes.Push(opt_className);
            }
            var el = this.getDomHelper().createElement(goog.dom.TagName.BUTTON);

            el.ClassName = classes.Join(" ");
            el.AppendChild(this.getDomHelper().createTextNode(label));
            parentNode.AppendChild(el);
            return(el);
        }
예제 #9
0
        /// <summary>
        /// Redraw the graph with the current angle.
        /// </summary>
        public void updateGraph_()
        {
            if (this.gauge_ == null)
            {
                return;
            }
            var angleDegrees = Script.ParseFloat(this.getText()) + FieldAngle.OFFSET;
            var angleRadians = goog.math.toRadians(angleDegrees);
            var path         = new JsArray <string> {
                "M " + FieldAngle.HALF + "," + FieldAngle.HALF
            };
            double x2 = FieldAngle.HALF;
            double y2 = FieldAngle.HALF;

            if (!Double.IsNaN(angleRadians))
            {
                var angle1 = goog.math.toRadians(FieldAngle.OFFSET);
                var x1     = System.Math.Cos(angle1) * FieldAngle.RADIUS;
                var y1     = System.Math.Sin(angle1) * -FieldAngle.RADIUS;
                if (FieldAngle.CLOCKWISE)
                {
                    angleRadians = 2 * angle1 - angleRadians;
                }
                x2 += System.Math.Cos(angleRadians) * FieldAngle.RADIUS;
                y2 -= System.Math.Sin(angleRadians) * FieldAngle.RADIUS;
                // Don't ask how the flag calculations work.  They just do.
                var largeFlag = System.Math.Abs(System.Math.Floor((angleRadians - angle1) / System.Math.PI) % 2);
                if (FieldAngle.CLOCKWISE)
                {
                    largeFlag = 1 - largeFlag;
                }
                var sweepFlag = FieldAngle.CLOCKWISE ? 1 : 0;
                path.Push(" l " + x1 + "," + y1 +
                          " A " + FieldAngle.RADIUS + "," + FieldAngle.RADIUS +
                          " 0 " + largeFlag + " " + sweepFlag + " " + x2 + "," + y2 + " z");
            }
            this.gauge_.SetAttribute("d", path.Join(""));
            this.line_.SetAttribute("x2", x2.ToString());
            this.line_.SetAttribute("y2", y2.ToString());
        }
예제 #10
0
        /// <summary>
        /// Draw the path of the block.
        /// Move the fields to the correct locations.
        /// </summary>
        /// <param name="iconWidth">Offset of first row due to icons.</param>
        /// <param name="inputRows">2D array of objects, each
        /// containing position information.</param>
        private void renderDraw_(double iconWidth, InputRow inputRows)
        {
            this.startHat_ = false;
            // Reset the height to zero and let the rendering process add in
            // portions of the block height as it goes. (e.g. hats, inputs, etc.)
            this.height = 0;
            // Should the top and bottom left corners be rounded or square?
            if (this.outputConnection != null)
            {
                this.squareTopLeftCorner_    = true;
                this.squareBottomLeftCorner_ = true;
            }
            else
            {
                this.squareTopLeftCorner_    = false;
                this.squareBottomLeftCorner_ = false;
                // If this block is in the middle of a stack, square the corners.
                if (this.previousConnection != null)
                {
                    var prevBlock = this.previousConnection.targetBlock();
                    if (prevBlock != null && prevBlock.getNextBlock() == this)
                    {
                        this.squareTopLeftCorner_ = true;
                    }
                }
                else if (BlockSvg.START_HAT)
                {
                    // No output or previous connection.
                    this.squareTopLeftCorner_ = true;
                    this.startHat_            = true;
                    this.height        += BlockSvg.START_HAT_HEIGHT;
                    inputRows.rightEdge = System.Math.Max(inputRows.rightEdge, 100);
                }
                var nextBlock = this.getNextBlock();
                if (nextBlock != null)
                {
                    this.squareBottomLeftCorner_ = true;
                }
            }

            // Assemble the block's path.
            var steps       = new JsArray <string>();
            var inlineSteps = new JsArray <string>();
            // The highlighting applies to edges facing the upper-left corner.
            // Since highlighting is a two-pixel wide border, it would normally overhang
            // the edge of the block by a pixel. So undersize all measurements by a pixel.
            var highlightSteps       = new JsArray <string>();
            var highlightInlineSteps = new JsArray <string>();

            this.renderDrawTop_(steps, highlightSteps, inputRows.rightEdge);
            var cursorY = this.renderDrawRight_(steps, highlightSteps, inlineSteps,
                                                highlightInlineSteps, inputRows, iconWidth);

            this.renderDrawBottom_(steps, highlightSteps, cursorY);
            this.renderDrawLeft_(steps, highlightSteps);

            var pathString = steps.Join(" ") + "\n" + inlineSteps.Join(" ");

            this.svgPath_.SetAttribute("d", pathString);
            this.svgPathDark_.SetAttribute("d", pathString);
            pathString = highlightSteps.Join(" ") + "\n" + highlightInlineSteps.Join(" ");
            this.svgPathLight_.SetAttribute("d", pathString);
            if (this.RTL)
            {
                // Mirror the block's path.
                this.svgPath_.SetAttribute("transform", "scale(-1 1)");
                this.svgPathLight_.SetAttribute("transform", "scale(-1 1)");
                this.svgPathDark_.SetAttribute("transform", "translate(1,1) scale(-1 1)");
            }
        }
예제 #11
0
        /// <summary>
        /// Get the generator code for a given block.
        /// </summary>
        /// <param name="block"> Rendered block in preview workspace.</param>
        /// <param name="generatorLanguage">"JavaScript", "Python", "PHP", "Lua",
        /// "Dart".</param>
        /// <returns>Generator code for multiple blocks.</returns>
        public static string getGeneratorStub(Blockly.Block block, string generatorLanguage)
        {
            var makeVar = new Func <string, string, string>((root, name) => {
                name = name.ToLowerCase().Replace(new Regex(@"\W", RegexOptions.Multiline), "_");
                return("  var " + root + "_" + name);
            });
            // The makevar function lives in the original update generator.
            var language = generatorLanguage;
            var code     = new JsArray <string>();

            code.Push("Blockly." + language + "[\"" + block.type +
                      "\"] = (block) => {");

            // Generate getters for any fields or inputs.
            for (var i = 0; i < block.inputList.Length; i++)
            {
                string name;
                var    input = block.inputList[i];
                for (var j = 0; j < input.fieldRow.Length; j++)
                {
                    var field = input.fieldRow[j];
                    name = field.name;
                    if (String.IsNullOrEmpty(name))
                    {
                        continue;
                    }
                    if (typeof(Blockly.FieldVariable).IsInstanceOfType(field))
                    {
                        // Subclass of Blockly.FieldDropdown, must test first.
                        code.Push(makeVar("variable", name) +
                                  " = Blockly." + language +
                                  ".variableDB_.getName(block.getFieldValue(\"" + name +
                                  "\"), Blockly.Variables.NAME_TYPE);");
                    }
                    else if (typeof(Blockly.FieldAngle).IsInstanceOfType(field))
                    {
                        // Subclass of Blockly.FieldTextInput, must test first.
                        code.Push(makeVar("angle", name) +
                                  " = block.getFieldValue(\"" + name + "\");");
                    }
                    else if (typeof(Blockly.FieldDate).IsInstanceOfType(field))
                    {
                        // Blockly.FieldDate may not be compiled into Blockly.
                        code.Push(makeVar("date", name) +
                                  " = block.getFieldValue(\"" + name + "\");");
                    }
                    else if (typeof(Blockly.FieldColour).IsInstanceOfType(field))
                    {
                        code.Push(makeVar("colour", name) +
                                  " = block.getFieldValue(\"" + name + "\");");
                    }
                    else if (typeof(Blockly.FieldCheckbox).IsInstanceOfType(field))
                    {
                        code.Push(makeVar("checkbox", name) +
                                  " = block.getFieldValue(\"" + name + "\") == \"TRUE\";");
                    }
                    else if (typeof(Blockly.FieldDropdown).IsInstanceOfType(field))
                    {
                        code.Push(makeVar("dropdown", name) +
                                  " = block.getFieldValue(\"" + name + "\");");
                    }
                    else if (typeof(Blockly.FieldNumber).IsInstanceOfType(field))
                    {
                        code.Push(makeVar("number", name) +
                                  " = block.getFieldValue(\"" + name + "\");");
                    }
                    else if (typeof(Blockly.FieldTextInput).IsInstanceOfType(field))
                    {
                        code.Push(makeVar("text", name) +
                                  " = block.getFieldValue(\"" + name + "\");");
                    }
                }
                name = input.name;
                if (!String.IsNullOrEmpty(name))
                {
                    if (input.type == Blockly.Core.INPUT_VALUE)
                    {
                        code.Push(makeVar("value", name) +
                                  " = Blockly." + language + ".valueToCode(block, \"" + name +
                                  "\", Blockly." + language + ".ORDER_ATOMIC);");
                    }
                    else if (input.type == Blockly.Core.NEXT_STATEMENT)
                    {
                        code.Push(makeVar("statements", name) +
                                  " = Blockly." + language + ".statementToCode(block, \"" +
                                  name + "\");");
                    }
                }
            }
            // Most languages end lines with a semicolon.  Python does not.
            var lineEnd = new Dictionary <string, string> {
                { "JavaScript", ";" },
                { "Python", "" },
                { "PHP", ";" },
                { "Dart", ";" }
            };

            code.Push("  // TODO: Assemble " + language + " into code variable.");
            if (block.outputConnection != null)
            {
                code.Push("  var code = \"...\";");
                code.Push("  // TODO: Change ORDER_NONE to the correct strength.");
                code.Push("  return [code, Blockly." + language + ".ORDER_NONE];");
            }
            else
            {
                code.Push("  var code = \"...\" + (lineEnd[language] || \"\") + \"\\n\";");
                code.Push("  return code;");
            }
            code.Push("};");

            return(code.Join("\n"));
        }
예제 #12
0
        /// <summary>
        /// Returns field strings and any config.
        /// </summary>
        /// <param  name="block">Input block.</param>
        /// <returns>Field strings.</returns>
        private static JsArray <string> getFieldsJs_(Blockly.Block block)
        {
            var fields = new JsArray <string>();

            while (block != null)
            {
                if (!block.disabled && !block.getInheritedDisabled())
                {
                    switch (block.type)
                    {
                    case "field_static":
                        // Result: "hello"
                        fields.Push(FactoryUtils.escapeString(block.getFieldValue("TEXT")));
                        break;

                    case "field_input":
                        // Result: new Blockly.FieldTextInput("Hello"), "GREET"
                        fields.Push("new Blockly.FieldTextInput(" +
                                    FactoryUtils.escapeString(block.getFieldValue("TEXT")) + "), " +
                                    FactoryUtils.escapeString(block.getFieldValue("FIELDNAME")));
                        break;

                    case "field_number":
                        // Result: new Blockly.FieldNumber(10, 0, 100, 1), "NUMBER"
                        var args = new JsArray <double> {
                            Script.ParseFloat(block.getFieldValue("VALUE")),
                            Script.ParseFloat(block.getFieldValue("MIN")),
                            Script.ParseFloat(block.getFieldValue("MAX")),
                            Script.ParseFloat(block.getFieldValue("PRECISION"))
                        };
                        // Remove any trailing arguments that aren't needed.
                        if (args[3] == 0)
                        {
                            args.Pop();
                            if (args[2] == Double.PositiveInfinity)
                            {
                                args.Pop();
                                if (args[1] == Double.NegativeInfinity)
                                {
                                    args.Pop();
                                }
                            }
                        }
                        fields.Push("new Blockly.FieldNumber(" + args.Join(", ") + "), " +
                                    FactoryUtils.escapeString(block.getFieldValue("FIELDNAME")));
                        break;

                    case "field_angle":
                        // Result: new Blockly.FieldAngle(90), "ANGLE"
                        fields.Push("new Blockly.FieldAngle(" +
                                    Script.ParseFloat(block.getFieldValue("ANGLE")) + "), " +
                                    FactoryUtils.escapeString(block.getFieldValue("FIELDNAME")));
                        break;

                    case "field_checkbox":
                        // Result: new Blockly.FieldCheckbox("TRUE"), "CHECK"
                        fields.Push("new Blockly.FieldCheckbox(" +
                                    FactoryUtils.escapeString(block.getFieldValue("CHECKED")) +
                                    "), " +
                                    FactoryUtils.escapeString(block.getFieldValue("FIELDNAME")));
                        break;

                    case "field_colour":
                        // Result: new Blockly.FieldColour("#ff0000"), "COLOUR"
                        fields.Push("new Blockly.FieldColour(" +
                                    FactoryUtils.escapeString(block.getFieldValue("COLOUR")) +
                                    "), " +
                                    FactoryUtils.escapeString(block.getFieldValue("FIELDNAME")));
                        break;

                    case "field_date":
                        // Result: new Blockly.FieldDate("2015-02-04"), "DATE"
                        fields.Push("new Blockly.FieldDate(" +
                                    FactoryUtils.escapeString(block.getFieldValue("DATE")) + "), " +
                                    FactoryUtils.escapeString(block.getFieldValue("FIELDNAME")));
                        break;

                    case "field_variable":
                        // Result: new Blockly.FieldVariable("item"), "VAR"
                        var varname
                            = FactoryUtils.escapeString(block.getFieldValue("TEXT") ?? null);
                        fields.Push("new Blockly.FieldVariable(" + varname + "), " +
                                    FactoryUtils.escapeString(block.getFieldValue("FIELDNAME")));
                        break;

                    case "field_dropdown":
                        // Result:
                        // new Blockly.FieldDropdown([["yes", "1"], ["no", "0"]]), "TOGGLE"
                        var options = new JsArray <string>();
                        for (var i = 0; i < ((FieldDropdown)block).optionCount_; i++)
                        {
                            options[i] = "[" +
                                         FactoryUtils.escapeString(block.getFieldValue("USER" + i)) +
                                         ", " +
                                         FactoryUtils.escapeString(block.getFieldValue("CPU" + i)) + "]";
                        }
                        if (options.Length > 0)
                        {
                            fields.Push("new Blockly.FieldDropdown([" +
                                        options.Join(", ") + "]), " +
                                        FactoryUtils.escapeString(block.getFieldValue("FIELDNAME")));
                        }
                        break;

                    case "field_image":
                        // Result: new Blockly.FieldImage("http://...", 80, 60)
                        var src    = FactoryUtils.escapeString(block.getFieldValue("SRC"));
                        var width  = Convert.ToDouble(block.getFieldValue("WIDTH"));
                        var height = Convert.ToDouble(block.getFieldValue("HEIGHT"));
                        var alt    = FactoryUtils.escapeString(block.getFieldValue("ALT"));
                        fields.Push("new Blockly.FieldImage(" +
                                    src + ", " + width + ", " + height + ", " + alt + ")");
                        break;
                    }
                }
                block = block.nextConnection == null ? null : block.nextConnection.targetBlock();
            }
            return(fields);
        }
예제 #13
0
        /// <summary>
        /// Update the language code as JavaScript.
        /// </summary>
        /// <param name="blockType"> Name of block.</param>
        /// <param name="rootBlock"> Factory_base block.</param>
        /// <param name="workspace"></param> Where the root block lives.
        /// <returns>Generated language code.</returns>
        private static string formatJavaScript_(string blockType, Blockly.Block rootBlock, Blockly.Workspace workspace)
        {
            var code = new JsArray <string>();

            code.Push("Blockly.Core.Blocks[\"" + blockType + "\"] = {");
            code.Push("  init: () => {");
            // Generate inputs.
            var TYPES = new Dictionary <string, string>()
            {
                { "input_value", "appendValueInput" },
                { "input_statement", "appendStatementInput" },
                { "input_dummy", "appendDummyInput" }
            };
            var contentsBlock = rootBlock.getInputTargetBlock("INPUTS");

            while (contentsBlock != null)
            {
                if (!contentsBlock.disabled && !contentsBlock.getInheritedDisabled())
                {
                    var name = "";
                    // Dummy inputs don't have names.  Other inputs do.
                    if (contentsBlock.type != "input_dummy")
                    {
                        name =
                            FactoryUtils.escapeString(contentsBlock.getFieldValue("INPUTNAME"));
                    }
                    code.Push("    this." + TYPES[contentsBlock.type] + "(" + name + ")");
                    var check = FactoryUtils.getOptTypesFrom(contentsBlock, "TYPE");
                    if (!String.IsNullOrEmpty(check))
                    {
                        code.Push("        .setCheck(" + check + ")");
                    }
                    var align = contentsBlock.getFieldValue("ALIGN");
                    if (align != "LEFT")
                    {
                        code.Push("        .setAlign(Blockly.ALIGN_" + align + ")");
                    }
                    var fields = FactoryUtils.getFieldsJs_(
                        contentsBlock.getInputTargetBlock("FIELDS"));
                    for (var i = 0; i < fields.Length; i++)
                    {
                        code.Push("        .appendField(" + fields[i] + ")");
                    }
                    // Add semicolon to last line to finish the statement.
                    code[code.Length - 1] += ";";
                }
                contentsBlock = contentsBlock.nextConnection == null ? null :
                                contentsBlock.nextConnection.targetBlock();
            }
            // Generate inline/external switch.
            if (rootBlock.getFieldValue("INLINE") == "EXT")
            {
                code.Push("    this.setInputsInline(false);");
            }
            else if (rootBlock.getFieldValue("INLINE") == "INT")
            {
                code.Push("    this.setInputsInline(true);");
            }
            // Generate output, or next/previous connections.
            switch (rootBlock.getFieldValue("CONNECTIONS"))
            {
            case "LEFT":
                code.Push(FactoryUtils.connectionLineJs_("setOutput", "OUTPUTTYPE", workspace));
                break;

            case "BOTH":
                code.Push(
                    FactoryUtils.connectionLineJs_("setPreviousStatement", "TOPTYPE", workspace));
                code.Push(
                    FactoryUtils.connectionLineJs_("setNextStatement", "BOTTOMTYPE", workspace));
                break;

            case "TOP":
                code.Push(
                    FactoryUtils.connectionLineJs_("setPreviousStatement", "TOPTYPE", workspace));
                break;

            case "BOTTOM":
                code.Push(
                    FactoryUtils.connectionLineJs_("setNextStatement", "BOTTOMTYPE", workspace));
                break;
            }
            // Generate colour.
            var colourBlock = rootBlock.getInputTargetBlock("COLOUR");

            if (colourBlock != null && !colourBlock.disabled)
            {
                var hue = Script.ParseFloat(colourBlock.getFieldValue("HUE"));
                if (!Double.IsNaN(hue))
                {
                    code.Push("    this.setColour(" + hue + ");");
                }
            }
            code.Push("    this.setTooltip(\"\");");
            code.Push("    this.setHelpUrl(\"http://www.example.com/\");");
            code.Push("  }");
            code.Push("};");
            return(code.Join("\n"));
        }
예제 #14
0
        /// <summary>
        /// Update the language code as JSON.
        /// </summary>
        /// <param name="blockType"> Name of block.</param>
        /// <param  name="rootBlock">Factory_base block.</param>
        /// <returns>Generanted language code.</returns>
        private static string formatJson_(string blockType, Blockly.Block rootBlock)
        {
            var JS = new Dictionary <string, object>();

            // Type is not used by Blockly, but may be used by a loader.
            JS["type"] = blockType;
            // Generate inputs.
            var message       = new JsArray <string>();
            var args          = new JsArray <object>();
            var contentsBlock = rootBlock.getInputTargetBlock("INPUTS");

            Blockly.Block lastInput = null;
            while (contentsBlock != null)
            {
                if (!contentsBlock.disabled && !contentsBlock.getInheritedDisabled())
                {
                    var fields = FactoryUtils.getFieldsJson_(
                        contentsBlock.getInputTargetBlock("FIELDS"));
                    for (var i = 0; i < fields.Length; i++)
                    {
                        if (fields[i] is string str)
                        {
                            message.Push(str.Replace(new Regex("%", RegexOptions.Multiline), "%%"));
                        }
                        else
                        {
                            args.Push(fields[i]);
                            message.Push("%" + args.Length);
                        }
                    }

                    var input = new Dictionary <string, object>();
                    input.Add("type", contentsBlock.type);
                    // Dummy inputs don't have names.  Other inputs do.
                    if (contentsBlock.type != "input_dummy")
                    {
                        input["name"] = contentsBlock.getFieldValue("INPUTNAME");
                    }
                    var check = JSON.Parse(
                        FactoryUtils.getOptTypesFrom(contentsBlock, "TYPE") ?? "null");
                    if (check != null)
                    {
                        input["check"] = check;
                    }
                    var align = contentsBlock.getFieldValue("ALIGN");
                    if (align != "LEFT")
                    {
                        input["align"] = align;
                    }
                    args.Push(input);
                    message.Push("%" + args.Length);
                    lastInput = contentsBlock;
                }
                contentsBlock = contentsBlock.nextConnection == null ? null :
                                contentsBlock.nextConnection.targetBlock();
            }
            // Remove last input if dummy and not empty.
            if (lastInput != null && lastInput.type == "input_dummy")
            {
                var fields = lastInput.getInputTargetBlock("FIELDS");
                if (fields != null && FactoryUtils.getFieldsJson_(fields).Join("").Trim() != "")
                {
                    var align = lastInput.getFieldValue("ALIGN");
                    if (align != "LEFT")
                    {
                        JS["lastDummyAlign0"] = align;
                    }
                    args.Pop();
                    message.Pop();
                }
            }
            JS["message0"] = message.Join(" ");
            if (args.Length > 0)
            {
                JS["args0"] = args;
            }
            // Generate inline/external switch.
            if (rootBlock.getFieldValue("INLINE") == "EXT")
            {
                JS["inputsInline"] = false;
            }
            else if (rootBlock.getFieldValue("INLINE") == "INT")
            {
                JS["inputsInline"] = true;
            }
            // Generate output, or next/previous connections.
            switch (rootBlock.getFieldValue("CONNECTIONS"))
            {
            case "LEFT":
                JS["output"] =
                    JSON.Parse(
                        FactoryUtils.getOptTypesFrom(rootBlock, "OUTPUTTYPE") ?? "null");
                break;

            case "BOTH":
                JS["previousStatement"] =
                    JSON.Parse(
                        FactoryUtils.getOptTypesFrom(rootBlock, "TOPTYPE") ?? "null");
                JS["nextStatement"] =
                    JSON.Parse(
                        FactoryUtils.getOptTypesFrom(rootBlock, "BOTTOMTYPE") ?? "null");
                break;

            case "TOP":
                JS["previousStatement"] =
                    JSON.Parse(
                        FactoryUtils.getOptTypesFrom(rootBlock, "TOPTYPE") ?? "null");
                break;

            case "BOTTOM":
                JS["nextStatement"] =
                    JSON.Parse(
                        FactoryUtils.getOptTypesFrom(rootBlock, "BOTTOMTYPE") ?? "null");
                break;
            }
            // Generate colour.
            var colourBlock = rootBlock.getInputTargetBlock("COLOUR");

            if (colourBlock != null && !colourBlock.disabled)
            {
                var hue = Script.ParseFloat(colourBlock.getFieldValue("HUE"));
                JS["colour"] = hue;
            }
            JS["tooltip"] = "";
            JS["helpUrl"] = "http://www.example.com/";
            return(JSON.Stringify(JS, null, "  "));
        }
예제 #15
0
        /// <summary>
        /// Draw the arrow between the bubble and the origin.
        /// </summary>
        private void renderArrow_()
        {
            var steps = new JsArray <string>();
            // Find the relative coordinates of the center of the bubble.
            var relBubbleX = this.width_ / 2;
            var relBubbleY = this.height_ / 2;
            // Find the relative coordinates of the center of the anchor.
            var relAnchorX = -this.relativeLeft_;
            var relAnchorY = -this.relativeTop_;

            if (relBubbleX == relAnchorX && relBubbleY == relAnchorY)
            {
                // Null case.  Bubble is directly on top of the anchor.
                // Short circuit this rather than wade through divide by zeros.
                steps.Push("M " + relBubbleX + "," + relBubbleY);
            }
            else
            {
                // Compute the angle of the arrow's line.
                var rise = relAnchorY - relBubbleY;
                var run  = relAnchorX - relBubbleX;
                if (this.workspace_.RTL)
                {
                    run *= -1;
                }
                var hypotenuse = System.Math.Sqrt(rise * rise + run * run);
                var angle      = System.Math.Acos(run / hypotenuse);
                if (rise < 0)
                {
                    angle = 2 * System.Math.PI - angle;
                }
                // Compute a line perpendicular to the arrow.
                var rightAngle = angle + System.Math.PI / 2;
                if (rightAngle > System.Math.PI * 2)
                {
                    rightAngle -= System.Math.PI * 2;
                }
                var rightRise = System.Math.Sin(rightAngle);
                var rightRun  = System.Math.Cos(rightAngle);

                // Calculate the thickness of the base of the arrow.
                var bubbleSize = this.getBubbleSize();
                var thickness  = (bubbleSize.width + bubbleSize.height) /
                                 Bubble.ARROW_THICKNESS;
                thickness = System.Math.Min(thickness, System.Math.Min(bubbleSize.width, bubbleSize.height)) / 4;

                // Back the tip of the arrow off of the anchor.
                var backoffRatio = 1 - Bubble.ANCHOR_RADIUS / hypotenuse;
                relAnchorX = relBubbleX + backoffRatio * run;
                relAnchorY = relBubbleY + backoffRatio * rise;

                // Coordinates for the base of the arrow.
                var baseX1 = relBubbleX + thickness * rightRun;
                var baseY1 = relBubbleY + thickness * rightRise;
                var baseX2 = relBubbleX - thickness * rightRun;
                var baseY2 = relBubbleY - thickness * rightRise;

                // Distortion to curve the arrow.
                var swirlAngle = angle + this.arrow_radians_;
                if (swirlAngle > System.Math.PI * 2)
                {
                    swirlAngle -= System.Math.PI * 2;
                }
                var swirlRise = System.Math.Sin(swirlAngle) *
                                hypotenuse / Bubble.ARROW_BEND;
                var swirlRun = System.Math.Cos(swirlAngle) *
                               hypotenuse / Bubble.ARROW_BEND;

                steps.Push("M" + baseX1 + "," + baseY1);
                steps.Push("C" + (baseX1 + swirlRun) + "," + (baseY1 + swirlRise) +
                           " " + relAnchorX + "," + relAnchorY +
                           " " + relAnchorX + "," + relAnchorY);
                steps.Push("C" + relAnchorX + "," + relAnchorY +
                           " " + (baseX2 + swirlRun) + "," + (baseY2 + swirlRise) +
                           " " + baseX2 + "," + baseY2);
            }
            steps.Push("z");
            this.bubbleArrow_.SetAttribute("d", steps.Join(" "));
        }