/// <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 * } * * } */ } }
/// <summary> /// Assigns some style to the current selection. /// </summary> /// <param name="type">Determines how to assign the style.</param> 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 (GlobalUI.UI.ShowInputDialog("New style...", "Please enter a unique style name", out cStyle) != DialogResult.OK) { return; } cStyle = cStyle.Trim(); // check if style name is valid and unique if (ParseTree == null || cStyle == "") { return; } if (ParseTree.styles.ContainsKey(cStyle)) { GlobalUI.UI.ShowMessageBox("Error: Style name '" + cStyle + "' already exists.", "Style exists", MessageBoxButtons.OK, MessageBoxIcon.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(); } bool SomeStylesCouldNotBeSet = false; // loop through selected items and set styles foreach (OverlayShapeVM ols in selectionTool.SelItems) { // currently only node styles can be set Tikz_Node tn = null; if (ols.item is Tikz_XYItem) { tn = TikzParseTreeHelper.GetReferenceableNode(ols.item as Tikz_XYItem, ParseTree.GetTikzPicture()); } if (tn == null) { SomeStylesCouldNotBeSet = true; continue; } 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)! if (SomeStylesCouldNotBeSet) { GlobalUI.UI.ShowMessageBox("Sorry, TikzEdt could not assign the styles of one or more of the selected objects automatically. Please do it manually.", "Assign Style", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); } }
/// <summary> /// Performs some action on the currently selected items. /// /// If necessary, raises the ReplaceText event (via calling RaiseRelaceText) to request text changes. /// This is necessary since the Parsetree currently does not support deletions. /// Ideally, we would directly do the changes to the Parsetree instead of firing the ReplaceText event. /// </summary> public void PerformCodeBlockOperation(CodeBlockAction action) { // The operations are only valid when the select tool is active if (View.Tool != OverlayToolType.move) { return; } List <TikzParseItem> FullSelection = TikzParseTreeHelper.GetFullSelection(selectionTool.SelItems.Select(ols => ols.item)); if (!FullSelection.Any()) { return; } // get codeblock text string cbtext = "", cbtextE = ""; foreach (var tpi in FullSelection) { cbtext += tpi.ToString() + Environment.NewLine; } // if the selected items are within a path, enscope by adding { }. If they are within another scope or the tikzpicture, enscope by \begin{scope} \end{scope} TikzContainerParseItem tc = FullSelection.First().parent; if (tc is Tikz_Picture || tc is Tikz_Scope) { cbtextE = "\\begin{scope}[]" + Environment.NewLine + cbtext + Environment.NewLine + "\\end{scope}" + Environment.NewLine; } else { cbtextE = " { " + cbtext + " } "; } var ReplacementList = new List <ReplaceTextEventArgs.ReplaceData>(); if (action == CodeBlockAction.Copy) { Clipboard.SetText(cbtext); } else if (action == CodeBlockAction.CopyEnscoped) { Clipboard.SetText(cbtextE); } else if (action == CodeBlockAction.Delete || action == CodeBlockAction.Cut || action == CodeBlockAction.CutEnscoped) { foreach (var tpi in FullSelection) { ReplacementList.Insert(0, new ReplaceTextEventArgs.ReplaceData() { StartPosition = tpi.StartPosition(), Length = tpi.Length, ReplacementText = "" }); } if (action == CodeBlockAction.Cut) { Clipboard.SetText(cbtext); } else if (action == CodeBlockAction.CutEnscoped) { Clipboard.SetText(cbtextE); } View.RaiseReplaceText(new ReplaceTextEventArgs() { Replacements = ReplacementList }); } else if (action == CodeBlockAction.Collect || action == CodeBlockAction.CollectEnscoped) { // Text to delete ... mind the order foreach (var tpi in FullSelection) { ReplacementList.Insert(0, new ReplaceTextEventArgs.ReplaceData() { StartPosition = tpi.StartPosition(), Length = tpi.Length, ReplacementText = "" }); } // text to insert (text of selected nodes, gathered together, optionally enscoped if (action == CodeBlockAction.Collect) { ReplacementList.Add(new ReplaceTextEventArgs.ReplaceData() { StartPosition = FullSelection.First().StartPosition(), Length = 0, ReplacementText = cbtext }); } else { ReplacementList.Add(new ReplaceTextEventArgs.ReplaceData() { StartPosition = FullSelection.First().StartPosition(), Length = 0, ReplacementText = cbtextE }); } View.RaiseReplaceText(new ReplaceTextEventArgs() { Replacements = ReplacementList }); } }
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); }