Example #1
0
        /// <summary>
        /// Return the coordinates of the top-left corner of this element relative to
        /// its parent.  Only for SVG elements and children (e.g. rect, g, path).
        /// </summary>
        /// <param name="element">SVG element to find the coordinates of.</param>
        /// <returns>Object with .x and .y properties.</returns>
        internal static goog.math.Coordinate getRelativeXY_(Element element)
        {
            var xy = new goog.math.Coordinate(0, 0);
            // First, check for x and y attributes.
            var x = element.GetAttribute("x");

            if (!String.IsNullOrEmpty(x))
            {
                xy.x = Script.ParseFloat(x);
            }
            var y = element.GetAttribute("y");

            if (!String.IsNullOrEmpty(y))
            {
                xy.y = Script.ParseFloat(y);
            }
            // Second, check for transform="translate(...)" attribute.
            var transform = element.GetAttribute("transform");
            var r         = transform?.Match(Core.getRelativeXY__XY_REGEXP_);

            if (r?.Length > 0)
            {
                xy.x += Script.ParseFloat(r[1]);
                if (r[3] != null)
                {
                    xy.y += Script.ParseFloat(r[3]);
                }
            }
            return(xy);
        }
Example #2
0
 /// <summary>
 /// Position the widget at a given location.  Prevent the widget from going
 /// offscreen top or left (right in RTL).
 /// </summary>
 /// <param name="anchorX">Horizontal location (window coorditates, not body).</param>
 /// <param name="anchorY">Vertical location (window coorditates, not body).</param>
 /// <param name="windowSize">Height/width of window.</param>
 /// <param name="scrollOffset">X/y of window scrollbars.</param>
 /// <param name="rtl">True if RTL, false if LTR.</param>
 public static void position(double anchorX, double anchorY, goog.math.Size windowSize,
                             goog.math.Coordinate scrollOffset, bool rtl)
 {
     // Don't let the widget go above the top edge of the window.
     if (anchorY < scrollOffset.y)
     {
         anchorY = scrollOffset.y;
     }
     if (rtl)
     {
         // Don't let the widget go right of the right edge of the window.
         if (anchorX > windowSize.width + scrollOffset.x)
         {
             anchorX = windowSize.width + scrollOffset.x;
         }
     }
     else
     {
         // Don't let the widget go left of the left edge of the window.
         if (anchorX < scrollOffset.x)
         {
             anchorX = scrollOffset.x;
         }
     }
     WidgetDiv.DIV.Style.Left   = anchorX + "px";
     WidgetDiv.DIV.Style.Top    = anchorY + "px";
     WidgetDiv.DIV.Style.Height = windowSize.height + "px";
 }
Example #3
0
            /**
             * Record the block's new location.  Called after the move.
             */
            public void recordNew()
            {
                var location = this.currentLocation_();

                this.newParentId   = location.parentId;
                this.newInputName  = location.inputName;
                this.newCoordinate = location.coordinate;
            }
Example #4
0
 /// <summary>
 /// Notification that the anchor has moved.
 /// Update the arrow and bubble accordingly.
 /// </summary>
 /// <param name="xy">Absolute location.</param>
 public void setAnchorLocation(goog.math.Coordinate xy)
 {
     this.anchorXY_ = xy;
     if (this.rendered_)
     {
         this.positionBubble_();
     }
 }
Example #5
0
 /// <summary>
 /// Notification that the icon has moved.  Update the arrow accordingly.
 /// </summary>
 /// <param name="xy">Absolute location.</param>
 internal void setIconLocation(goog.math.Coordinate xy)
 {
     this.iconXY_ = xy;
     if (this.isVisible())
     {
         this.bubble_.setAnchorLocation(xy);
     }
 }
Example #6
0
 /// <summary>
 /// Class for a button in the flyout.
 /// </summary>
 /// <param name="workspace">The workspace in which to place this
 /// button.</param>
 /// <param name="targetWorkspace">The flyout's target workspace.</param>
 /// <param name="text">The text to display on the button.</param>
 public FlyoutButton(WorkspaceSvg workspace, WorkspaceSvg targetWorkspace, string text,
                     string d = null, bool label = false)
 {
     this.workspace_       = workspace;
     this.targetWorkspace_ = targetWorkspace;
     this.text_            = text;
     position_             = new goog.math.Coordinate(0.0, 0.0);
     this.callback_        = Core.flyoutButtonCallbacks_[d];
     this.isLabel_         = label;
 }
Example #7
0
 /// <summary>
 /// Decode the JSON event.
 /// </summary>
 /// <param name="json">JSON representation.</param>
 public override void fromJson(EventJsonData json)
 {
     base.fromJson(json);
     this.newParentId  = json.newParentId.ToString();
     this.newInputName = json.newInputName.ToString();
     if (json.newCoordinate != null)
     {
         var xy = (json.newCoordinate.ToString()).Split(",");
         this.newCoordinate =
             new goog.math.Coordinate(Script.ParseFloat(xy[0]), Script.ParseFloat(xy[1]));
     }
 }
Example #8
0
            /// <summary>
            /// Class for a block move ev.  Created before the move.
            /// </summary>
            /// <param name="block">The moved block.  Null for a blank ev.</param>
            public Move(Block block)
                : base(block, Events.MOVE)
            {
                if (block == null)
                {
                    return;                      // Blank ev to be populated by fromJson.
                }
                var location = this.currentLocation_();

                this.oldParentId   = location.parentId;
                this.oldInputName  = location.inputName;
                this.oldCoordinate = location.coordinate;
            }
Example #9
0
        /// <summary>
        /// Notification that the icon has moved, but we don't really know where.
        /// Recompute the icon's location from scratch.
        /// </summary>
        internal void computeIconLocation()
        {
            // Find coordinates for the centre of the icon and update the arrow.
            var blockXY = this.block_.getRelativeToSurfaceXY();
            var iconXY  = Core.getRelativeXY_(this.iconGroup_);
            var newXY   = new goog.math.Coordinate(
                blockXY.x + iconXY.x + this.SIZE / 2,
                blockXY.y + iconXY.y + this.SIZE / 2);

            if (!goog.math.Coordinate.equals(this.getIconLocation(), newXY))
            {
                this.setIconLocation(newXY);
            }
        }
Example #10
0
        /// <summary>
        /// Class for UI bubble.
        /// </summary>
        /// <param name="workspace">The workspace on which to draw the
        /// bubble.</param>
        /// <param name="content">SVG content for the bubble.</param>
        /// <param name="shape">SVG element to avoid eclipsing.</param>
        /// <param name="anchorXY">Absolute position of bubble's anchor
        /// point.</param>
        /// <param name="bubbleWidth">Width of bubble, or null if not resizable.</param>
        /// <param name="bubbleHeight">Height of bubble, or null if not resizable.</param>
        public Bubble(WorkspaceSvg workspace, SVGElement content, SVGElement shape,
                      goog.math.Coordinate anchorXY, double bubbleWidth, double bubbleHeight)
        {
            this.workspace_ = workspace;
            this.content_   = content;
            this.shape_     = shape;

            var angle = Bubble.ARROW_ANGLE;

            if (this.workspace_.RTL)
            {
                angle = -angle;
            }
            this.arrow_radians_ = goog.math.toRadians(angle);

            var canvas = workspace.getBubbleCanvas();

            canvas.AppendChild(this.createDom_(content, !(bubbleWidth != 0.0 && bubbleHeight != 0.0)));

            this.setAnchorLocation(anchorXY);
            if (bubbleWidth == 0.0 || bubbleHeight == 0.0)
            {
                var bBox = /** @type {SVGLocatable} */ (this.content_).getBBox();
                bubbleWidth  = bBox.width + 2 * Bubble.BORDER_WIDTH;
                bubbleHeight = bBox.height + 2 * Bubble.BORDER_WIDTH;
            }
            this.setBubbleSize(bubbleWidth, bubbleHeight);

            // Render the bubble.
            this.positionBubble_();
            this.renderArrow_();
            this.rendered_ = true;

            if (!workspace.options.readOnly)
            {
                Core.bindEventWithChecks_(this.bubbleBack_, "mousedown", this,
                                          new Action <MouseEvent>(this.bubbleMouseDown_));
                if (this.resizeGroup_ != null)
                {
                    Core.bindEventWithChecks_(this.resizeGroup_, "mousedown", this,
                                              new Action <MouseEvent>(this.resizeMouseDown_));
                }
            }
        }
Example #11
0
        public Scrollbar(WorkspaceSvg workspace, bool horizontal, bool opt_pair = false)
        {
            this.workspace_      = workspace;
            this.pair_           = opt_pair;
            this.horizontal_     = horizontal;
            this.oldHostMetrics_ = null;

            this.createDom_();

            this.position_ = new goog.math.Coordinate(0, 0);

            if (horizontal)
            {
                this.svgBackground_.SetAttribute("height",
                                                 Scrollbar.scrollbarThickness.ToString());
                this.svgHandle_.SetAttribute("height",
                                             (Scrollbar.scrollbarThickness - 5).ToString());
                this.svgHandle_.SetAttribute("y", 2.5.ToString());

                this.lengthAttribute_   = "width";
                this.positionAttribute_ = "x";
            }
            else
            {
                this.svgBackground_.SetAttribute("width",
                                                 Scrollbar.scrollbarThickness.ToString());
                this.svgHandle_.SetAttribute("width",
                                             (Scrollbar.scrollbarThickness - 5).ToString());
                this.svgHandle_.SetAttribute("x", 2.5.ToString());

                this.lengthAttribute_   = "height";
                this.positionAttribute_ = "y";
            }
            var scrollbar = this;

            this.onMouseDownBarWrapper_ = Core.bindEventWithChecks_(
                this.svgBackground_, "mousedown", scrollbar, new Action <MouseEvent>(scrollbar.onMouseDownBar_));
            this.onMouseDownHandleWrapper_ = Core.bindEventWithChecks_(this.svgHandle_,
                                                                       "mousedown", scrollbar, new Action <MouseEvent>(scrollbar.onMouseDownHandle_));
        }
Example #12
0
        public override void handleMouseUp(events.BrowserEvent e)
        {
            var parentMenu = (Menu)this.getParent();

            if (parentMenu != null) {
                var oldCoords = parentMenu.openingCoords;
                // Clear out the saved opening coords immediately so they"re not used twice.
                parentMenu.openingCoords = null;

                if (oldCoords != null /*&& goog.isNumber(e.clientX)*/) {
                    var newCoords = new goog.math.Coordinate(e.clientX, e.clientY);
                    if (goog.math.Coordinate.equals(oldCoords, newCoords)) {
                        // This menu was opened by a mousedown and we"re handling the consequent
                        // mouseup. The coords haven't changed, meaning this was a simple click,
                        // not a click and drag. Don't do the usual behavior because the menu
                        // just popped up under the mouse and the user didn't mean to activate
                        // this item.
                        return;
                    }
                }
            }

            base.handleMouseUp(e);
        }
Example #13
0
        /// <summary>
        /// Returns whether the provided element is to be considered inside the menu for
        /// purposes such as dismissing the menu on an event.  This is so submenus can
        /// make use of elements outside their own DOM.
        /// </summary>
        /// <param name="element">The element to test for.</param>
        /// <returns>Whether the provided element is to be considered inside
        ///     the menu.</returns>
        public bool containsElement(HTMLElement element)
        {
            if (((MenuRenderer)this.getRenderer()).containsElement(this, element))
            {
                return(true);
            }

            for (int i = 0, count = this.getChildCount(); i < count; i++)
            {
                var child = this.getChildAt(i);
                if (                /*typeof child.containsElement == "function"*/
                    child is Menu menu
                    /**/ &&
                    /*child*/ menu /**/.containsElement(element))
                {
                    return(true);
                }
            }

            return(false);
        }

        /// <summary>
        /// Adds a new menu item at the end of the menu.
        /// </summary>
        /// <param name="item"> Menu</param>
        ///    item to add to the menu.
        public void addItem(Union <MenuHeader, MenuItem, MenuSeparator> item)
        {
            this.addChild((Component)item.Value, true);
        }

        /// <summary>
        /// Adds a new menu item at a specific index in the menu.
        /// </summary>
        /// <param name="item">Menu
        ///    item to add to the menu.</param>
        /// <param name="n"> Index at which to insert the menu item.</param>
        public void addItemAt(Union <MenuHeader, MenuItem, MenuSeparator> item, int n)
        {
            this.addChildAt((Component)item.Value, n, true);
        }

        /// <summary>
        /// Removes an item from the menu and disposes of it.
        /// </summary>
        /// <param name="item"> The
        ///    menu item to remove.</param>
        public void removeItem(Union <MenuHeader, MenuItem, MenuSeparator> item)
        {
            var removedChild = this.removeChild((Component)item.Value, true);

            if (removedChild != null)
            {
                removedChild.dispose();
            }
        }

        /// <summary>
        /// Removes a menu item at a given index in the menu and disposes of it.
        /// </summary>
        /// <param name="n">Index of item.</param>
        public void removeItemAt(int n)
        {
            var removedChild = this.removeChildAt(n, true);

            if (removedChild != null)
            {
                removedChild.dispose();
            }
        }

        /// <summary>
        /// Returns a reference to the menu item at a given index.
        /// </summary>
        /// <param name="n"> Index of menu item.</param>
        /// <returns>Reference to the menu item.</returns>
        public Union <MenuHeader, MenuItem, MenuSeparator> getItemAt(int n)
        {
            return(new Union <MenuHeader, MenuItem, MenuSeparator>(this.getChildAt(n)));
        }

        /// <summary>
        /// Returns the number of items in the menu (including separators).
        /// </summary>
        /// <returns>The number of items in the menu.</returns>
        public int getItemCount()
        {
            return(this.getChildCount());
        }

        /// <summary>
        /// Returns an array containing the menu items contained in the menu.
        /// </summary>
        /// <returns>An array of menu items.</returns>
        public JsArray <MenuItem> getItems()
        {
            // TODO(user): Remove reference to getItems and instead use getChildAt,
            // forEachChild, and getChildCount
            var children = new JsArray <MenuItem>();

            this.forEachChild((child) => { children.Push((MenuItem)child); });
            return(children);
        }

        /// <summary>
        /// Sets the position of the menu relative to the view port.
        /// </summary>
        /// <param name="x">Left position or coordinate obj.</param>
        /// <param name="opt_y"> Top position.</param>
        public void setPosition(Union <double, goog.math.Coordinate> x, double opt_y = 0.0)
        {
            // NOTE(user): It is necessary to temporarily set the display from none, so
            // that the position gets set correctly.
            var visible = this.isVisible();

            if (!visible)
            {
                goog.style.setElementShown(this.getElement(), true);
            }
            goog.style.setPageOffset(this.getElement(), x, opt_y);
            if (!visible)
            {
                goog.style.setElementShown(this.getElement(), false);
            }
        }

        /// <summary>
        /// Gets the page offset of the menu, or null if the menu isn't visible
        /// </summary>
        /// <returns>Object holding the x-y coordinates of the
        ///     menu or null if the menu is not visible.</returns>
        public goog.math.Coordinate getPosition()
        {
            return(this.isVisible() ? goog.style.getPageOffset(this.getElement()) : null);
        }

        /// <summary>
        /// Sets whether the menu can automatically move focus to its key event target
        /// when it is set to visible.
        /// </summary>
        /// <param name="allow">Whether the menu can automatically move focus to its</param>
        public void setAllowAutoFocus(bool allow)
        {
            this.allowAutoFocus_ = allow;
            if (allow)
            {
                this.setFocusable(true);
            }
        }

        /// <summary>
        /// </summary>
        /// <returns>Whether the menu can automatically move focus to its key
        ///     event target when it is set to visible.</returns>
        public bool getAllowAutoFocus()
        {
            return(this.allowAutoFocus_);
        }

        /// <summary>
        /// Sets whether the menu will highlight disabled menu items or skip to the next
        /// active item.
        /// </summary>
        /// <param name="allow">Whether the menu will highlight disabled menu items or
        /// skip to the next active item.</param>
        public void setAllowHighlightDisabled(bool allow)
        {
            this.allowHighlightDisabled_ = allow;
        }

        /// <summary>
        /// </summary>
        /// <returns>Whether the menu will highlight disabled menu items or skip
        ///     to the next active item.</returns>
        public bool getAllowHighlightDisabled()
        {
            return(this.allowHighlightDisabled_);
        }

        public override bool setVisible(bool visible, bool opt_force = false)
        {
            return(setVisible(visible, opt_force));
        }

        /// <summary>
        /// </summary>
        /// <param name="show">Whether to show or hide the menu.</param>
        /// <param name="opt_force">If true, doesn't check whether the menu
        /// already has the requested visibility, and doesn't dispatch any events.</param>
        /// <param name="opt_e">Mousedown event that caused this menu to
        /// be made visible (ignored if show is false).</param>
        /// <returns></returns>
        public bool setVisible(bool show, bool opt_force = false, goog.events.BrowserEvent opt_e = null)
        {
            var visibilityChanged =
                base.setVisible(show, opt_force);

            if (visibilityChanged && show && this.isInDocument() &&
                this.allowAutoFocus_)
            {
                this.getKeyEventTarget().Focus();
            }
            if (show && opt_e != null /*&& goog.isNumber(opt_e.clientX)*/)
            {
                this.openingCoords = new goog.math.Coordinate(opt_e.clientX, opt_e.clientY);
            }
Example #14
0
        /// <summary>
        /// Find the closest compatible connection to this connection.
        /// </summary>
        /// <param name="conn">The connection searching for a compatible
        /// mate.</param>
        /// <param name="maxRadius">The maximum radius to another connection.</param>
        /// <param name="dxy">Offset between this connection's location
        /// in the database and the current location (as a result of dragging).</param>
        /// <returns>Contains two properties:' connection' which is either another connection or null,
        /// and 'radius' which is the distance.</returns>
        public RenderedConnection.Closest searchForClosest(RenderedConnection conn, double maxRadius,
                                                           goog.math.Coordinate dxy)
        {
            // Don't bother.
            if (this.array_.Length == 0)
            {
                return(new RenderedConnection.Closest {
                    connection = null, radius = maxRadius
                });
            }

            // Stash the values of x and y from before the drag.
            var baseY = conn.y_;
            var baseX = conn.x_;

            conn.x_ = baseX + dxy.x;
            conn.y_ = baseY + dxy.y;

            // findPositionForConnection finds an index for insertion, which is always
            // after any block with the same y index.  We want to search both forward
            // and back, so search on both sides of the index.
            var closestIndex = this.findPositionForConnection_(conn);

            Connection         bestConnection = null;
            var                bestRadius     = maxRadius;
            RenderedConnection temp;

            // Walk forward and back on the y axis looking for the closest x,y point.
            var pointerMin = closestIndex - 1;

            while (pointerMin >= 0 && this.isInYRange_(pointerMin, conn.y_, maxRadius))
            {
                temp = this.array_[pointerMin];
                if (conn.isConnectionAllowed(temp, bestRadius))
                {
                    bestConnection = temp;
                    bestRadius     = temp.distanceFrom(conn);
                }
                pointerMin--;
            }

            var pointerMax = closestIndex;

            while (pointerMax < this.array_.Length && this.isInYRange_(pointerMax, conn.y_,
                                                                       maxRadius))
            {
                temp = this.array_[pointerMax];
                if (conn.isConnectionAllowed(temp, bestRadius))
                {
                    bestConnection = temp;
                    bestRadius     = temp.distanceFrom(conn);
                }
                pointerMax++;
            }

            // Reset the values of x and y.
            conn.x_ = baseX;
            conn.y_ = baseY;

            // If there were no valid connections, bestConnection will be null.
            return(new RenderedConnection.Closest {
                connection = bestConnection, radius = bestRadius
            });
        }
Example #15
0
 /// <summary>
 /// Class for a connection between blocks that may be rendered on screen.
 /// </summary>
 /// <param name="source">The block establishing this connection.</param>
 /// <param name="type">The type of the connection.</param>
 public RenderedConnection(Block source, int type)
     : base(source, type)
 {
     this.offsetInBlock_ = new goog.math.Coordinate(0, 0);
 }
Example #16
0
 /// <summary>
 /// Move this connection to the location given by its offset within the block and
 /// the coordinate of the block's top left corner.
 /// </summary>
 /// <param name="blockTL">The coordinate of the top left corner
 /// of the block.</param>
 public void moveToOffset(goog.math.Coordinate blockTL)
 {
     this.moveTo(blockTL.x + this.offsetInBlock_.x,
                 blockTL.y + this.offsetInBlock_.y);
 }
Example #17
0
 public Location(string parentId, string inputName, goog.math.Coordinate coordinate)
 {
     this.parentId   = parentId;
     this.inputName  = inputName;
     this.coordinate = coordinate;
 }