/// <summary> /// Recursively add colours to this toolbox. /// </summary> /// <param name="opt_tree">Starting point of tree. /// Defaults to the root node.</param> internal void addColour_(goog.ui.tree.BaseNode opt_tree = null) { var tree = opt_tree != null ? opt_tree : (goog.ui.tree.BaseNode) this.tree_; var children = tree.getChildren(); foreach (ITreeNode child in children) { var element = child.getRowElement(); if (element != null) { string border; if (this.hasColours_) { border = "8px solid " + (child.hexColour ?? "#ddd"); } else { border = "none"; } if (this.workspace_.RTL) { element.Style.BorderRight = border; } else { element.Style.BorderLeft = border; } } this.addColour_((BaseNode)child); } }
/// <summary> /// Dispose of this toolbox. /// </summary> public void dispose() { this.flyout_.dispose(); this.tree_.dispose(); goog.dom.removeNode(this.HtmlDiv); this.workspace_ = null; this.lastCategory_ = null; }
/// <summary> /// Display/hide the flyout when an item is selected. /// </summary> /// <param name="node">The item to select.</param> public override void setSelectedItem(goog.ui.tree.BaseNode node) { var toolbox = this.toolbox_; if (node == this.selectedItem_ || node == toolbox.tree_) { return; } if (toolbox.lastCategory_ != null) { toolbox.lastCategory_.getRowElement().Style.BackgroundColor = ""; } if (node is TreeNode) { var treeNode = (TreeNode)node; var hexColour = treeNode.hexColour ?? "#57e"; treeNode.getRowElement().Style.BackgroundColor = hexColour; // Add colours to child nodes which may have been collapsed and thus // not rendered. toolbox.addColour_(treeNode); } else if (node is TreeControl) { var treeControl = (TreeControl)node; var hexColour = treeControl.hexColour ?? "#57e"; treeControl.getRowElement().Style.BackgroundColor = hexColour; // Add colours to child nodes which may have been collapsed and thus // not rendered. toolbox.addColour_(treeControl); } var oldNode = this.getSelectedItem(); base.setSelectedItem(node); if (node != null && node is ITreeNode itreeNode && itreeNode.blocks.As <JsArray <Node> >()?.Length != 0) { toolbox.flyout_.show(itreeNode.blocks); // Scroll the flyout to the top if the category has changed. if (toolbox.lastCategory_ != node) { toolbox.flyout_.scrollToStart(); } }
/// <summary> /// Sync trees of the toolbox. /// </summary> /// <param name="treeIn">DOM tree of blocks.</param> /// <param name="treeOut"></param> /// <param name="pathToMedia"></param> /// <returns>Tree node to open at startup (or null).</returns> private goog.ui.tree.BaseNode syncTrees_(Element treeIn, ITreeNode treeOut, string pathToMedia) { goog.ui.tree.BaseNode openNode = null; Element lastElement = null; foreach (var childIn_ in treeIn.ChildNodes) { if (!(childIn_ is Element)) { // Skip over text. continue; } Element childIn = (Element)childIn_; switch (childIn.TagName.ToUpperCase()) { case "CATEGORY": var childOut = (ITreeNode)this.tree_.createNode(childIn.GetAttribute("name")); childOut.blocks = new JsArray <Node>(); treeOut.add((BaseNode)childOut); var custom = childIn.GetAttribute("custom"); if (custom != null) { // Variables and procedures are special dynamic categories. childOut.blocks = custom; } else { var newOpenNode = this.syncTrees_(childIn, childOut, pathToMedia); if (newOpenNode != null) { openNode = newOpenNode; } } var colour = childIn.GetAttribute("colour"); if (colour is string) { if (colour.Match(new Regex(@"^#[0-9a-fA-F]{6}$")) != null) { childOut.hexColour = colour; } else { childOut.hexColour = Core.hueToRgb(Script.ParseFloat(colour)); } this.hasColours_ = true; } else { childOut.hexColour = ""; } if (childIn.GetAttribute("expanded") == "true") { if (childOut.blocks.Is <JsArray <Node> >() && childOut.blocks.As <JsArray <Node> >().Length != 0) { // This is a category that directly contians blocks. // After the tree is rendered, open this category and show flyout. openNode = (BaseNode)childOut; } childOut.setExpanded(true); } else { childOut.setExpanded(false); } lastElement = childIn; break; case "SEP": if (lastElement != null) { if (lastElement.TagName.ToUpperCase() == "CATEGORY") { // Separator between two categories. // <sep></sep> treeOut.add(new Toolbox.TreeSeparator( this.treeSeparatorConfig_)); } else { // Change the gap between two blocks. // <sep gap="36"></sep> // The default gap is 24, can be set larger or smaller. // Note that a deprecated method is to add a gap to a block. // <block type="math_arithmetic" gap="8"></block> var newGap = Script.ParseFloat(childIn.GetAttribute("gap")); if (!Double.IsNaN(newGap) && lastElement != null) { lastElement.SetAttribute("gap", newGap.ToString()); } } } break; case "BLOCK": case "SHADOW": treeOut.blocks.As <JsArray <Node> >().Push(childIn); lastElement = childIn; break; } } return(openNode); }