/// <summary> /// Tries to find the referencable node (with a name) corresponding to a given coordinate. /// If no such node exists, null is returned. /// </summary> /// <param name="item"></param> /// <returns></returns> public static Tikz_Node GetReferenceableNode(Tikz_XYItem item, Tikz_Picture tpict) { if (item == null || tpict == null) { return(null); } if (item is Tikz_Node) { Tikz_Node n = item as Tikz_Node; if (n.name == null || n.name.Trim() == "") { return(null); } else { return(n); } } else if (item is Tikz_Coord || item is Tikz_Arc) { // find the next node for (int i = item.parent.Children.IndexOf(item) + 1; i < item.parent.Children.Count; i++) { if (item.parent.Children[i] is Tikz_Node) { Tikz_Node n = item.parent.Children[i] as Tikz_Node; // check if the node is really at the same position as the coordinate item if (n.coord == null) { if (n.name != null && n.name.Trim() != "") { return(n); } continue; } else { return(null); } } if (!(item.parent.Children[i] is Tikz_Something)) { break; } } // if we get here, nothing was found return(null); } else { return(null); //throw new NotImplementedException("MakeReferenceableNode not implemented for this type"); } }
/// <summary> /// Takes an XYItem (like (2,2) or a node) and tries to make it into a referenceable node /// (i.e, one with a name) /// /// Concretely, the routine does the following: /// - if item is a named node, return item. /// - if item is an unnamed node, give it a unique name and return item. /// - if item is a coordinate, see if there is a node at this coordinate /// (algorithm: see if next non-tikz_something item is a node) /// - if yes, start anew with item=this node /// - if no, add a named node at the specified coordinate /// </summary> /// <param name="item"></param> /// <returns></returns> protected Tikz_Node MakeReferenceableNode(Tikz_XYItem item) { Tikz_Picture tpict = overlay.ParseTree.GetTikzPicture(); if (item is Tikz_Node) { Tikz_Node n = item as Tikz_Node; if (n.name == "") { n.SetName(tpict.GetUniqueName()); n.UpdateText(); } return(n); } else if (item is Tikz_Coord) { // find the next node for (int i = item.parent.Children.IndexOf(item) + 1; i < item.parent.Children.Count; i++) { if (item.parent.Children[i] is Tikz_Node) { // check if the node is really at the same position as the coordinate item if ((item.parent.Children[i] as Tikz_Node).coord == null) { return(MakeReferenceableNode(item.parent.Children[i] as Tikz_Node)); } else { break; } } if (!(item.parent.Children[i] is Tikz_Something)) { break; } } // if we get here, nothing was found => add a new node Tikz_Something ws = new Tikz_Something(" "); Tikz_Node n = new Tikz_Node(); n.coord = null; item.parent.InsertChildAt(ws, item.parent.Children.IndexOf(item) + 1); item.parent.InsertChildAt(n, item.parent.Children.IndexOf(item) + 2); n.SetName(tpict.GetUniqueName()); n.UpdateText(); return(n); } else { throw new NotImplementedException("MakeReferenceableNode not implemented for this type"); } }
/// <summary> /// Recursive function to scan the parsetree in a depth first manner. /// nodelist contains the current map from _old_ nodenames to nodes. it is used to update node references /// </summary> private static void ScanTree(TikzContainerParseItem tc, Dictionary <string, Tikz_Node> nodelist, Tikz_Picture tp) { foreach (var tpi in tc.Children) { if (tpi is Tikz_Node) { Tikz_Node tn = tpi as Tikz_Node; if (tn.name != null && tn.name.Trim() != "") { string name = CleanName(tn.name.Trim()); // remember the node with its old name (all coordinates referring to this name henceforth will be changed to the new name nodelist[name] = tn; if (tp.nodelist.ContainsKey(name)) { // we have to change the name tn.name = UniquefyName(name, tp); tn.UpdateText(); } tn.RegisterNodeAndStyleRefs(); } } else if (tpi is Tikz_Coord) { Tikz_Coord tco = tpi as Tikz_Coord; if (tco.type == Tikz_CoordType.Named) { string nameref = CleanName(tco.nameref); if (nodelist.ContainsKey(nameref)) { if (CleanName(nodelist[nameref].name) != nameref) { tco.nameref = CleanName(nodelist[nameref].name); tco.UpdateText(); } } } } else if (tpi is TikzContainerParseItem) { ScanTree(tpi as TikzContainerParseItem, nodelist, tp); } } }
public void ParseTest4() { string code = @"%some text \begin{tikzpicture}[scale=2] \draw (1,2) node (v) {bla} -- (3,3); \end{tikzpicture} "; Tikz_ParseTree actual = TikzParser.Parse(code); Tikz_Picture tp = actual.GetTikzPicture(); Tikz_Node n = tp.GetNodeByName("v"); System.Windows.Point p; bool ret = n.GetAbsPos(out p); Assert.IsTrue(ret); Assert.AreEqual(2, p.X); Assert.AreEqual(4, p.Y); Assert.AreEqual("bla", n.label); }
public override void OnLeftMouseButtonUp(Point p, TEMouseArgs e) { // add the rectangle if (PreviewRect.Visible) { if (!EnsureParseTreeExists()) { return; } Point firstpoint = overlay.ScreenToTikz(origin, true); Point secondpoint = overlay.Rasterizer.RasterizePixelToTikz(p); double angle = -Helper.RotationFromMatrix(overlay.Rasterizer.View.CoordinateTransform); TikzMatrix R = TikzMatrix.RotationMatrix(angle); TikzMatrix RI = R.Inverse(); Point firstpointR = R.Transform(firstpoint), secondpointR = R.Transform(secondpoint); if (ForcePointsBLTR) { // ensure first pt is bottom left, second top right Rect r = new Rect(firstpointR, secondpointR); firstpointR = r.TopLeft; // note that we use upside down coordinates, so the c# notations are different secondpointR = r.BottomRight; firstpoint = RI.Transform(firstpointR); secondpoint = RI.Transform(secondpointR); } if (overlay.KeyboardModifiers.HasFlag(TEModifierKeys.Control)) { // both sides the same double sidelength = Math.Max(Math.Abs(firstpointR.X - secondpointR.X), Math.Abs(firstpointR.Y - secondpointR.Y)); secondpointR = new Point( firstpointR.X + Math.Sign(secondpointR.X - firstpointR.X) * sidelength, firstpointR.Y + Math.Sign(secondpointR.Y - firstpointR.Y) * sidelength); secondpoint = RI.Transform(secondpointR); } overlay.BeginUpdate(); if (AddNewCurAddTo()) { Parser.Tikz_Coord tc1 = new Parser.Tikz_Coord(); tc1.type = overlay.UsePolarCoordinates? Parser.Tikz_CoordType.Polar : Parser.Tikz_CoordType.Cartesian; Parser.Tikz_Coord tc2 = new Parser.Tikz_Coord(); tc2.type = overlay.UsePolarCoordinates ? Parser.Tikz_CoordType.Polar : Parser.Tikz_CoordType.Cartesian; curAddTo.AddChild(new Parser.Tikz_Something(" ")); curAddTo.AddChild(tc1); curAddTo.AddChild(new Parser.Tikz_Something(codeToInsert)); curAddTo.AddChild(tc2); if (originRef == null) { tc1.SetAbsPos(firstpoint); } else { Tikz_Node tn = MakeReferenceableNode((originRef as OverlayNode).tikzitem); tc1.type = Tikz_CoordType.Named; tc1.nameref = tn.name; } OverlayShapeVM hit = overlay.ObjectAtCursor; if ((hit is OverlayNode) && IsReferenceable(hit as OverlayNode)) { Tikz_Node tn = MakeReferenceableNode((hit as OverlayNode).tikzitem); tc2.type = Tikz_CoordType.Named; tc2.nameref = tn.name; } else { tc2.SetAbsPos(secondpoint); } // overlay.AddToDisplayTree(tc1); // overlay.AddToDisplayTree(tc2); curAddTo.UpdateText(); } overlay.EndUpdate(); PreviewRect.Visible = false; } }
public override void OnLeftMouseButtonUp(Point p, TEMouseArgs e) { // add the rectangle if (PreviewEllipse.Visible) { if (!EnsureParseTreeExists()) { return; } Point center = overlay.ScreenToTikz(origin, true); Point secondpoint = overlay.Rasterizer.RasterizePixelToTikz(p); // in axis aligned (untranformed) tikz coordinates // compute rotated diagonal double angle = -Helper.RotationFromMatrix(overlay.Rasterizer.View.CoordinateTransform); TikzMatrix R = TikzMatrix.RotationMatrix(angle); Vector newdiag = R.Transform(secondpoint - center); double width = Math.Abs(newdiag.X), // actually half the width/height! height = Math.Abs(newdiag.Y); if (overlay.KeyboardModifiers.HasFlag(TEModifierKeys.Control)) { width = height = Math.Max(width, height); } overlay.BeginUpdate(); if (AddNewCurAddTo()) { Parser.Tikz_Coord tc1 = new Parser.Tikz_Coord(); tc1.type = overlay.UsePolarCoordinates ? Parser.Tikz_CoordType.Polar : Parser.Tikz_CoordType.Cartesian; curAddTo.AddChild(new Parser.Tikz_Something(" ")); curAddTo.AddChild(tc1); // since there might be a coordinate tranform, the width/height have to be transformed // (note: rotates are not very well supported here) TikzMatrix M; if (curAddTo.GetCurrentTransformAt(tc1, out M)) { R = R.Inverse(); Point size_trans = M.Inverse().Transform(R.Transform(new Point(width, height)), true); width = size_trans.X; height = size_trans.Y; } else { GlobalUI.UI.AddStatusLine(this, "Warning: Couldn't compute tranform at insertion position. Coordinates might be wrong.", true); } width = Math.Round(width, (int)CompilerSettings.Instance.RoundToDecimals); height = Math.Round(height, (int)CompilerSettings.Instance.RoundToDecimals); if (overlay.KeyboardModifiers.HasFlag(TEModifierKeys.Control) && width == height) { curAddTo.AddChild(new Parser.Tikz_Something(" circle (" + width + ")")); } else { curAddTo.AddChild(new Parser.Tikz_Something(" ellipse (" + width + " and " + height + ")")); } if (originRef == null) { tc1.SetAbsPos(center); } else { Tikz_Node tn = MakeReferenceableNode((originRef as OverlayNode).tikzitem); tc1.type = Tikz_CoordType.Named; tc1.nameref = tn.name; } // overlay.AddToDisplayTree(tc1); curAddTo.UpdateText(); } overlay.EndUpdate(); PreviewEllipse.Visible = false; } }
/// <summary> /// Draws the TikzParseItem tpi, if it is drawn, or its children, if they can be drawn, /// or grandchildren etc..., and adds the drawn items to bag. /// </summary> /// <param name="tpi"></param> /// <param name="bag"></param> public void DrawObject(TikzParseItem tpi, List <OverlayShape> bag) { //BBGatherer bbg = new BBGatherer(); if (bag == null) { bag = new List <OverlayShape>(); // dummy, it is not used } if (tpi is Tikz_Scope) { OverlayScope os = new OverlayScope(ShapeFactory.NewScopeView()); os.pol = this; os.tikzitem = tpi as Tikz_Scope; foreach (TikzParseItem t in (tpi as TikzContainerParseItem).Children) { DrawObject(t, os.children); } // don't draw scopes with no drawable children // (we don't know where to render them) if (os.children.Count > 0) { bag.Add(os); os.AdjustPosition(Resolution); ////canvas1.Children.Add(os); } } else if (tpi is TikzContainerParseItem) { foreach (TikzParseItem t in (tpi as TikzContainerParseItem).Children) { DrawObject(t, bag); } } if (tpi is Tikz_XYItem) { if ((tpi as Tikz_XYItem).HasEditableCoordinate()) { OverlayNode el; if (tpi.parent is Tikz_Controls) { el = new OverlayControlPoint(ShapeFactory.NewCPView()); // control points for Bezier curves } else { el = new OverlayNode(ShapeFactory.NewNodeView()); } el.pol = this; el.tikzitem = tpi as Tikz_XYItem; //Ellipse el = new Ellipse(); //el.Stroke = Brushes.Red; el.AdjustPosition(Resolution); // add tooltip Tikz_Node nref = TikzParseTreeHelper.GetReferenceableNode(tpi as Tikz_XYItem, ParseTree.GetTikzPicture()); if (nref != null && nref.name != "") { el.View.SetToolTip(nref.name); } ////canvas1.Children.Add(el); bag.Add(el); //bbg.Add(new Rect(Canvas.GetLeft(el), Canvas.GetTop(el), el.Width, el.Height)); } } else if (tpi is Tikz_Path) { //could this be a possibility to show edges and provide backward search? //there are many possibility for draw commands. here we /* string simpleEdge_RegexString = @"[ \t\s]*\\draw.*\((?<start>.*)\).*\((?<end>.*)\).*"; * Regex BB_Regex = new Regex(simpleEdge_RegexString); * Match m = BB_Regex.Match(tpi.ToString()); * if (m.Success == true) * { * //we just found a LaTex draw cmd, e.g.: \draw[default_edge] (v91) to (v99); * * //get both nodes * Tikz_Node StartNode = tpi.parent.GetNodeByName(m.Groups[1].Value); * Tikz_Node EndNode = tpi.parent.GetNodeByName(m.Groups[2].Value); * * if (StartNode != null && EndNode != null) * { * //and determine the position in between both nodes * Point start, end; * if (StartNode.GetAbsPos() * double x = (StartNode.GetAbsPos().X + EndNode.GetAbsPos().X) / 2; * double y = (StartNode.GetAbsPos().Y + EndNode.GetAbsPos().Y) / 2; * * //draw an arrow at this pos. * //(new Point(x, y)); * //and when clicked, jump to AvalonEdit at position tpi.StartPosition * } * * } */ } }
public void AssignStyle(AssignStyleType type) { string cStyle = NodeStyle; Tikz_Picture tp = ParseTree.GetTikzPicture(); if (tp == null) { return; } if (View.Tool != OverlayToolType.move) { return; // context menu should actually only open with move tool,... but to be safe against later changes... } if (type == AssignStyleType.AssignNewStyle || type == AssignStyleType.ChangeToNewStyle) { if (Overlay.InputMessageBox.ShowInputDialog("New style...", "Please enter a unique style name", out cStyle) != MessageBoxResult.OK) { return; } cStyle = cStyle.Trim(); // check if style name is valid and unique if (ParseTree == null || cStyle == "") { return; } if (ParseTree.styles.ContainsKey(cStyle)) { GlobalUI.ShowMessageBox("Error: Style name '" + cStyle + "' already exists.", "Style exists", MessageBoxButton.OK, MessageBoxImage.Warning); return; } // add new style, immediately before \begin{tikzpicture}[...] BeginUpdate(); Tikz_Option to = new Tikz_Option(); to.type = Tikz_OptionType.style; to.key = cStyle; to.val = ""; to.text = "\\tikzstyle{" + cStyle + "}=[];"; int index = ParseTree.Children.IndexOf(tp); if (index >= 0) { ParseTree.InsertChildAt(to, index); to.RegisterNodeAndStyleRefs(); ParseTree.InsertChildAt(new Tikz_Something(Environment.NewLine), index + 1); } } else { if (cStyle.Trim() == "") { return; } BeginUpdate(); } // loop through selected items and set styles foreach (OverlayShape ols in selectionTool.SelItems) { // currently only node styles can be set if (ols.item is Tikz_Node) { Tikz_Node tn = ols.item as Tikz_Node; if (tn.options == "" || type == AssignStyleType.ChangeToCurrentNodeStyle || type == AssignStyleType.ChangeToNewStyle) { tn.options = "[" + cStyle + "]"; } else // just add option { string o = tn.options.Trim(); if (o.EndsWith("]")) { o = o.Substring(0, o.Length - 1); o = o + ", " + cStyle + "]"; } // otherwise, do nothing (error) tn.options = o; } tn.UpdateText(); } } EndUpdate(); // Make sure EndUpdate() is always called (..if Beginupdate() was)! }
Tikz_Option smoothOption; // this has to be changed to smooth cycle for closed curve public override void OnLeftMouseButtonDown(OverlayShape item, Point p, TEMouseArgs e) { if (!EnsureParseTreeExists()) { return; } p = overlay.Rasterizer.RasterizePixelToTikz(p); if (ContinueWithBigImage(p) == false) { return; } overlay.BeginUpdate(); overlay.SetCorrectRaster(overlay.CurEditing, true); //Point p = new Point(e.GetPosition(canvas1).X, Height - e.GetPosition(canvas1).Y); // find tikzpicture and add bool lcreated; if (EnsureCurAddToExists(out lcreated)) { // on double click -> close path if (e.ClickCount == 2) { if (!lcreated) { smoothOption.key = "smooth cycle"; smoothOption.UpdateText(); } } else { if (!lcreated) { // for prettier formatting curAddTo.AddChild(new Parser.Tikz_Something(" ")); } // create new coordinate Parser.Tikz_Coord tc = new Parser.Tikz_Coord(); tc.type = overlay.UsePolarCoordinates ? Parser.Tikz_CoordType.Polar : Parser.Tikz_CoordType.Cartesian; curAddTo.AddChild(tc); if (item is OverlayNode && IsReferenceable(item)) { Tikz_Node tn = MakeReferenceableNode((item as OverlayNode).tikzitem); tc.type = Tikz_CoordType.Named; tc.nameref = tn.name; } else { // do it here since the coordinate calculation needs the parents' coord. transform tc.SetAbsPos(new Point(p.X, p.Y)); } //tn.UpdateText(); curAddTo.UpdateText(); //tpict.UpdateText(); // draw the added object in the overlay overlay.AddToDisplayTree(tc); } } overlay.EndUpdate(); // doubleclick also stops path drawing if (e.ClickCount == 2) { overlay.ActivateDefaultTool(); } }
static bool FillItem(TikzContainerParseItem item, CommonTree t, CommonTokenStream tokens) { int curToken = t.TokenStartIndex; if (item is Tikz_ParseTree) { curToken = 0; // for root, start at the beginning } if (t.Children == null) { return(false); } foreach (CommonTree childt in t.Children) { addSomething(item, tokens, curToken, childt.TokenStartIndex - 1); switch (childt.Type) { case simpletikzParser.IM_PICTURE: Tikz_Picture tp = new Tikz_Picture(); FillItem(tp, childt, tokens); item.AddChild(tp); break; case simpletikzParser.IM_STARTTAG: item.starttag = getTokensString(tokens, childt.TokenStartIndex, childt.TokenStopIndex); break; case simpletikzParser.IM_ENDTAG: item.endtag = getTokensString(tokens, childt.TokenStartIndex, childt.TokenStopIndex); break; case simpletikzParser.IM_PATH: Tikz_Path tpath = new Tikz_Path(); FillItem(tpath, childt, tokens); item.AddChild(tpath); break; case simpletikzParser.IM_SCOPE: Tikz_Scope tscope = new Tikz_Scope(); FillItem(tscope, childt, tokens); item.AddChild(tscope); break; case simpletikzParser.IM_COORD: Tikz_Coord tc = Tikz_Coord.FromCommonTree(childt, tokens); tc.text = getTokensString(tokens, childt); item.AddChild(tc); break; case simpletikzParser.IM_ARC: Tikz_Arc ta = Tikz_Arc.FromCommonTree(childt, tokens); ta.text = getTokensString(tokens, childt); item.AddChild(ta); break; case simpletikzParser.IM_NODE: Tikz_Node tn = Tikz_Node.FromCommonTree(childt, tokens); tn.text = getTokensString(tokens, childt); item.AddChild(tn); break; case simpletikzParser.IM_OPTION_KV: case simpletikzParser.IM_OPTION_STYLE: Tikz_Option topt = Tikz_Option.FromCommonTree(childt, tokens); if (topt == null) { break; } //topt.text = getTokensString(tokens, childt); String s = getTokensString(tokens, childt); topt.text = s; item.AddChild(topt); break; case simpletikzParser.IM_OPTIONS: //Tikz_Options to = Tikz_Options.FromCommonTree(childt); Tikz_Options to = new Tikz_Options(); FillItem(to, childt, tokens); item.AddChild(to); //to.text = getTokensString(tokens, childt); //item.AddChild(tn); if (item.options == null) { // determine whether option belongs to the item (e.g. \draw [this belongs to draw] blabla [thisnot]) // i.e., the scope of the options is the whole item's body // this is hacky if (item.Children.Count == 1 || (item.Children.Count == 2 && (item.Children[0] is Tikz_Something) && item.Children[0].ToString().Trim() == "")) { item.options = to; } } break; case simpletikzParser.IM_TIKZSET: Tikz_Options to2 = new Tikz_Options(); FillItem(to2, childt, tokens); item.AddChild(to2); break; case simpletikzParser.IM_STYLE: Tikz_Option topt2 = Tikz_Option.FromCommonTree(childt, tokens); //FillItem(to2, childt, tokens); topt2.text = getTokensString(tokens, childt); item.AddChild(topt2); break; case simpletikzParser.IM_CONTROLS: Tikz_Controls tcontrols = new Tikz_Controls(); FillItem(tcontrols, childt, tokens); item.AddChild(tcontrols); break; case simpletikzParser.IM_SIZE: Tikz_Size tsize = Tikz_Size.FromCommonTree(childt, tokens); tsize.text = getTokensString(tokens, childt); item.AddChild(tsize); //Tikz_Size tsize = new Tikz_Size(); //item.AddChild(tsize); break; //case simpletikzParser.ID: //case simpletikzParser.IM_STRING: //case simpletikzParser.COMMAND: //case simpletikzParser.T__57: // break; case simpletikzParser.IM_TIKZEDT_CMD: Tikz_EdtCommand cmd = new Tikz_EdtCommand(getTokensString(tokens, childt)); item.AddChild(cmd); break; case simpletikzParser.IM_DONTCARE: Tikz_Something st = new Tikz_Something(getTokensString(tokens, childt)); item.AddChild(st); break; default: // getting here is an error throw new Exception(" childt.Type not handled! " + childt.Type.ToString() + " (\"" + getTokensString(tokens, childt) + "\")"); //break; } curToken = childt.TokenStopIndex + 1; } if (t.TokenStartIndex >= 0) // rule out empty code { addSomething(item, tokens, curToken, t.TokenStopIndex); } return(true); }
public override void OnLeftMouseButtonDown(OverlayShape item, Point p, TEMouseArgs e) { if (!EnsureParseTreeExists()) { return; } p = overlay.Rasterizer.RasterizePixelToTikz(p); if (ContinueWithBigImage(p) == false) { return; } overlay.BeginUpdate(); //overlay.SetCorrectRaster(overlay.CurEditing, true); UpdateRaster(); //Point p = new Point(e.GetPosition(canvas1).X, Height - e.GetPosition(canvas1).Y); // find next tikzpicture and add bool lcreated; if (EnsureCurAddToExists(out lcreated)) { // on double click -> close path if (e.ClickCount == 2) { if (!lcreated) { //if (!Keyboard.Modifiers.HasFlag(ModifierKeys.Control)) curAddTo.AddChild(new Parser.Tikz_Something(" -- cycle")); //else // curAddTo.AddChild(new Parser.Tikz_Something(" cycle")); } } else { if (!lcreated) { if (!overlay.KeyboardModifiers.HasFlag(TEModifierKeys.Control)) { // add an edge curAddTo.AddChild(new Parser.Tikz_Something(" -- ")); } else { curAddTo.AddChild(new Parser.Tikz_Something(" ")); } } // create new coordinate. If some node was clicked, set a reference to that node. Otherwise, just make new coordinates Tikz_Coord tc = new Tikz_Coord(); curAddTo.AddChild(tc); if (item is OverlayNode && IsReferenceable(item)) { Tikz_Node tn = MakeReferenceableNode((item as OverlayNode).tikzitem); tc.type = Tikz_CoordType.Named; tc.nameref = tn.name; } else { // do it here since the coordinate calculation needs the parents' coord. transform tc.type = overlay.UsePolarCoordinates ? Tikz_CoordType.Polar : Tikz_CoordType.Cartesian; if (!lcreated) { tc.deco = overlay.NewNodeModifier; // first node should always be in absolute coordinates } tc.SetAbsPos(new Point(p.X, p.Y)); //hack // if a nonempty node style is selected, also add a node with that style if (overlay.NodeStyle.Trim() != "") { Tikz_Node tn = new Tikz_Node() { options = "[" + overlay.NodeStyle + "]", coord = null, text = "" }; curAddTo.AddChild(new Tikz_Something(" ")); curAddTo.AddChild(tn); } } //tn.UpdateText(); curAddTo.UpdateText(); //tpict.UpdateText(); // draw the added object in the overlay overlay.AddToDisplayTree(tc); } } overlay.EndUpdate(); UpdateRaster(); // doubleclick also stops path drawing if (e.ClickCount == 2) { overlay.ActivateDefaultTool(); } }
IEnumerable <OverlayShapeVM> CreateOverlayShapesFromItem(TikzParseItem tpi) { var ret = new List <OverlayShapeVM>(); if (tpi is Tikz_Scope) { OverlayScope os = new OverlayScope(); //os.pol = this; os.tikzitem = tpi as Tikz_Scope; // add child shapes os.children.AddRange((tpi as TikzContainerParseItem).Children.SelectMany(child => CreateOverlayShapesFromItem(child))); //foreach (TikzParseItem t in (tpi as TikzContainerParseItem).Children) // DrawObject(t, os.children); // don't draw scopes with no drawable children // (we don't know where to render them) if (os.children.Count > 0) { ret.Add(os); os.AdjustPosition(TikzToScreen); } } else if (tpi is TikzContainerParseItem) { ret.AddRange((tpi as TikzContainerParseItem).Children.SelectMany(child => CreateOverlayShapesFromItem(child))); } else if (tpi is Tikz_XYItem) { if ((tpi as Tikz_XYItem).HasEditableCoordinate()) { OverlayNode el; if (tpi.parent is Tikz_Controls) { el = new OverlayControlPoint(); // control points for Bezier curves } else { el = new OverlayNode(); } //el.pol = this; el.tikzitem = tpi as Tikz_XYItem; el.AdjustPosition(TikzToScreen); // add tooltip if (ParseTree != null) { Tikz_Node nref = TikzParseTreeHelper.GetReferenceableNode(tpi as Tikz_XYItem, ParseTree.GetTikzPicture()); if (nref != null && !String.IsNullOrWhiteSpace(nref.name)) { el.ToolTip = nref.name; } } ////canvas1.Children.Add(el); ret.Add(el); //bbg.Add(new Rect(Canvas.GetLeft(el), Canvas.GetTop(el), el.Width, el.Height)); } } else if (tpi is Tikz_Path) { } return(ret); }