Beispiel #1
0
        /// <summary>
        /// Copy a block onto the local clipboard.
        /// </summary>
        /// <param name="block">Block to be copied.</param>
        private static void copy_(Block block)
        {
            var xmlBlock = Xml.blockToDom(block);

            if (Core.dragMode_ != Core.DRAG_FREE)
            {
                Xml.deleteNext(xmlBlock);
            }
            // Encode start position in XML.
            var xy = block.getRelativeToSurfaceXY();

            xmlBlock.SetAttribute("x", (block.RTL ? -xy.x : xy.x).ToString());
            xmlBlock.SetAttribute("y", xy.y.ToString());
            Core.clipboardXml_    = xmlBlock;
            Core.clipboardSource_ = (WorkspaceSvg)block.workspace;
        }
Beispiel #2
0
        /// <summary>
        /// Encode a block subtree as XML with XY coordinates.
        /// </summary>
        /// <param name="block">The root block to encode.</param>
        /// <param name="opt_noId">True if the encoder should skip the block id.</param>
        /// <returns>Tree of XML elements.</returns>
        public static Element blockToDomWithXY(Block block, bool opt_noId = false)
        {
            var width = 0.0;              // Not used in LTR.

            if (block.workspace.RTL)
            {
                width = block.workspace.getWidth();
            }
            var element = Xml.blockToDom(block, opt_noId);
            var xy      = block.getRelativeToSurfaceXY();

            element.SetAttribute("x",
                                 System.Math.Round(block.workspace.RTL ? width - xy.x : xy.x).ToString());
            element.SetAttribute("y", System.Math.Round(xy.y).ToString());
            return(element);
        }
Beispiel #3
0
        /// <summary>
        /// Encode a block subtree as XML.
        /// </summary>
        /// <param name="block">The root block to encode.</param>
        /// <returns>Tree of XML elements.</returns>
        public static Element blockToDom(Block block, bool opt_noId = false)
        {
            var element = goog.dom.createDom(block.isShadow() ? "shadow" : "block");

            element.SetAttribute("type", block.type);
            if (!opt_noId)
            {
                element.SetAttribute("id", block.id);
            }
            if (true /*block.mutationToDom*/)
            {
                // Custom data for an advanced block.
                var mutation = block.mutationToDom();
                if (mutation != null && (mutation.HasChildNodes() || mutation.Attributes.Length > 0))
                {
                    element.AppendChild(mutation);
                }
            }
            Element container  = null;
            var     fieldToDom = new Action <Field>((field) => {
                if (field.name != null && field.EDITABLE)
                {
                    container = goog.dom.createDom("field", null, field.getValue());
                    container.SetAttribute("name", field.name);
                    element.AppendChild(container);
                }
            });

            foreach (var input in block.inputList)
            {
                foreach (var field in input.fieldRow)
                {
                    fieldToDom(field);
                }
            }

            var commentText = block.getCommentText();

            if (!String.IsNullOrEmpty(commentText))
            {
                var commentElement = goog.dom.createDom("comment", null, commentText);
                if (((BlockSvg)block).comment != null)
                {
                    commentElement.SetAttribute("pinned", ((BlockSvg)block).comment.isVisible().ToString());
                    var hw = ((BlockSvg)block).comment.getBubbleSize();
                    commentElement.SetAttribute("h", hw.height.ToString());
                    commentElement.SetAttribute("w", hw.width.ToString());
                }
                element.AppendChild(commentElement);
            }

            if (block.data != null)
            {
                var dataElement = goog.dom.createDom("data", null, block.data);
                element.AppendChild(dataElement);
            }

            Element shadow;

            foreach (var input in block.inputList)
            {
                var empty = true;
                if (input.type == Core.DUMMY_INPUT)
                {
                    continue;
                }
                else
                {
                    var childBlock = input.connection.targetBlock();
                    if (input.type == Core.INPUT_VALUE)
                    {
                        container = goog.dom.createDom("value");
                    }
                    else if (input.type == Core.NEXT_STATEMENT)
                    {
                        container = goog.dom.createDom("statement");
                    }
                    shadow = input.connection.getShadowDom();
                    if (shadow != null && (childBlock == null || !childBlock.isShadow()))
                    {
                        container.AppendChild(Xml.cloneShadow_(shadow));
                    }
                    if (childBlock != null)
                    {
                        container.AppendChild(Xml.blockToDom(childBlock, opt_noId));
                        empty = false;
                    }
                }
                container.SetAttribute("name", input.name);
                if (!empty)
                {
                    element.AppendChild(container);
                }
            }
            if (block.inputsInlineDefault != block.inputsInline)
            {
                element.SetAttribute("inline", block.inputsInline.ToString());
            }
            if (block.isCollapsed())
            {
                element.SetAttribute("collapsed", true.ToString());
            }
            if (block.disabled)
            {
                element.SetAttribute("disabled", true.ToString());
            }
            if (!block.isDeletable() && !block.isShadow())
            {
                element.SetAttribute("deletable", false.ToString());
            }
            if (!block.isMovable() && !block.isShadow())
            {
                element.SetAttribute("movable", false.ToString());
            }
            if (!block.isEditable())
            {
                element.SetAttribute("editable", false.ToString());
            }

            var nextBlock = block.getNextBlock();

            if (nextBlock != null)
            {
                container = goog.dom.createDom("next", null,
                                               Xml.blockToDom(nextBlock, opt_noId));
                element.AppendChild(container);
            }
            shadow = block.nextConnection?.getShadowDom();
            if (shadow != null && (nextBlock == null || !nextBlock.isShadow()))
            {
                container.AppendChild(Xml.cloneShadow_(shadow));
            }

            return(element);
        }
Beispiel #4
0
        /// <summary>
        /// Connect two connections together.  This is the connection on the superior
        /// block.
        /// </summary>
        /// <param name="childConnection"></param>
        protected virtual void connect_(Connection childConnection)
        {
            var parentConnection = this;
            var parentBlock      = parentConnection.getSourceBlock();
            var childBlock       = childConnection.getSourceBlock();

            // Disconnect any existing parent on the child connection.
            if (childConnection.isConnected())
            {
                childConnection.disconnect();
            }
            if (parentConnection.isConnected())
            {
                // Other connection is already connected to something.
                // Disconnect it and reattach it or bump it as needed.
                var orphanBlock = parentConnection.targetBlock();
                var shadowDom   = parentConnection.getShadowDom();
                // Temporarily set the shadow DOM to null so it does not respawn.
                parentConnection.setShadowDom(null);
                // Displaced shadow blocks dissolve rather than reattaching or bumping.
                if (orphanBlock.isShadow())
                {
                    // Save the shadow block so that field values are preserved.
                    shadowDom = Xml.blockToDom(orphanBlock);
                    orphanBlock.dispose();
                    orphanBlock = null;
                }
                else if (parentConnection.type == Core.INPUT_VALUE)
                {
                    // Value connections.
                    // If female block is already connected, disconnect and bump the male.
                    if (orphanBlock.outputConnection == null)
                    {
                        throw new Exception("Orphan block does not have an output connection.");
                    }
                    // Attempt to reattach the orphan at the end of the newly inserted
                    // block.  Since this block may be a row, walk down to the end
                    // or to the first (and only) shadow block.
                    var connection = Connection.lastConnectionInRow_(
                        childBlock, orphanBlock);
                    if (connection != null)
                    {
                        orphanBlock.outputConnection.connect(connection);
                        orphanBlock = null;
                    }
                }
                else if (parentConnection.type == Core.NEXT_STATEMENT)
                {
                    // Statement connections.
                    // Statement blocks may be inserted into the middle of a stack.
                    // Split the stack.
                    if (orphanBlock.previousConnection == null)
                    {
                        throw new Exception("Orphan block does not have a previous connection.");
                    }
                    // Attempt to reattach the orphan at the bottom of the newly inserted
                    // block.  Since this block may be a stack, walk down to the end.
                    var newBlock = childBlock;
                    while (newBlock.nextConnection != null)
                    {
                        var nextBlock = newBlock.getNextBlock();
                        if (nextBlock != null && !nextBlock.isShadow())
                        {
                            newBlock = nextBlock;
                        }
                        else
                        {
                            if (orphanBlock.previousConnection.checkType_(
                                    newBlock.nextConnection))
                            {
                                newBlock.nextConnection.connect(orphanBlock.previousConnection);
                                orphanBlock = null;
                            }
                            break;
                        }
                    }
                }
                if (orphanBlock != null)
                {
                    // Unable to reattach orphan.
                    parentConnection.disconnect();
                    if (Events.recordUndo)
                    {
                        // Bump it off to the side after a moment.
                        var group = Events.getGroup();
                        Window.SetTimeout(() => {
                            // Verify orphan hasn't been deleted or reconnected (user on meth).
                            if (orphanBlock.workspace != null && orphanBlock.getParent() == null)
                            {
                                Events.setGroup(group);
                                if (orphanBlock.outputConnection != null)
                                {
                                    ((RenderedConnection)orphanBlock.outputConnection).bumpAwayFrom_(parentConnection);
                                }
                                else if (orphanBlock.previousConnection != null)
                                {
                                    ((RenderedConnection)orphanBlock.previousConnection).bumpAwayFrom_(parentConnection);
                                }
                                Events.setGroup(false);
                            }
                        }, Core.BUMP_DELAY);
                    }
                }
                // Restore the shadow DOM.
                parentConnection.setShadowDom(shadowDom);
            }

            Events.Move e = null;
            if (Events.isEnabled())
            {
                e = new Events.Move(childBlock);
            }
            // Establish the connections.
            Connection.connectReciprocally_(parentConnection, childConnection);
            // Demote the inferior block so that one is a child of the superior one.
            childBlock.setParent(parentBlock);
            if (e != null)
            {
                e.recordNew();
                Events.fire(e);
            }
        }