commit
db7722d4aa
41 changed files with 56 additions and 3384 deletions
|
|
@ -40,15 +40,17 @@ using MatterHackers.VectorMath;
|
|||
|
||||
namespace MatterHackers.MatterControl
|
||||
{
|
||||
public partial class InspectForm : WinformsSystemWindow.FormInspector
|
||||
using WinTreeNode = System.Windows.Forms.TreeNode;
|
||||
|
||||
public partial class InspectForm : WinformsSystemWindow.FormInspector
|
||||
{
|
||||
private TreeNode activeTreeNode;
|
||||
private WinTreeNode activeTreeNode;
|
||||
private GuiWidget inspectedSystemWindow;
|
||||
|
||||
private Vector2 mousePosition;
|
||||
|
||||
private Dictionary<GuiWidget, TreeNode> aggTreeNodes = new Dictionary<GuiWidget, TreeNode>();
|
||||
private Dictionary<IObject3D, TreeNode> sceneTreeNodes = new Dictionary<IObject3D, TreeNode>();
|
||||
private Dictionary<GuiWidget, WinTreeNode> aggTreeNodes = new Dictionary<GuiWidget, WinTreeNode>();
|
||||
private Dictionary<IObject3D, WinTreeNode> sceneTreeNodes = new Dictionary<IObject3D, WinTreeNode>();
|
||||
|
||||
private InteractiveScene scene;
|
||||
private View3DWidget view3DWidget;
|
||||
|
|
@ -145,7 +147,7 @@ namespace MatterHackers.MatterControl
|
|||
activeTreeNode.Checked = false;
|
||||
}
|
||||
|
||||
if (aggTreeNodes.TryGetValue(_inspectedWidget, out TreeNode treeNode))
|
||||
if (aggTreeNodes.TryGetValue(_inspectedWidget, out WinTreeNode treeNode))
|
||||
{
|
||||
aggTreeView.SelectedNode = treeNode;
|
||||
|
||||
|
|
@ -182,14 +184,14 @@ namespace MatterHackers.MatterControl
|
|||
}
|
||||
}
|
||||
|
||||
private void AddItemEnsureAncestors(GuiWidget widget, string text = null, TreeNode childNode = null, bool showAllParents = true)
|
||||
private void AddItemEnsureAncestors(GuiWidget widget, string text = null, WinTreeNode childNode = null, bool showAllParents = true)
|
||||
{
|
||||
if (text == null)
|
||||
{
|
||||
text = BuildDefaultName(widget);
|
||||
}
|
||||
|
||||
if (aggTreeNodes.TryGetValue(widget, out TreeNode existingNode))
|
||||
if (aggTreeNodes.TryGetValue(widget, out WinTreeNode existingNode))
|
||||
{
|
||||
if (childNode != null)
|
||||
{
|
||||
|
|
@ -199,7 +201,7 @@ namespace MatterHackers.MatterControl
|
|||
}
|
||||
else
|
||||
{
|
||||
var node = new TreeNode(text)
|
||||
var node = new WinTreeNode(text)
|
||||
{
|
||||
Tag = widget
|
||||
};
|
||||
|
|
@ -230,9 +232,9 @@ namespace MatterHackers.MatterControl
|
|||
}
|
||||
}
|
||||
|
||||
private TreeNode AddItem(GuiWidget widget, TreeNode parentNode)
|
||||
private WinTreeNode AddItem(GuiWidget widget, WinTreeNode parentNode)
|
||||
{
|
||||
var node = new TreeNode(BuildDefaultName(widget))
|
||||
var node = new WinTreeNode(BuildDefaultName(widget))
|
||||
{
|
||||
Tag = widget
|
||||
};
|
||||
|
|
@ -252,9 +254,9 @@ namespace MatterHackers.MatterControl
|
|||
return node;
|
||||
}
|
||||
|
||||
private TreeNode AddItem(IObject3D item, TreeNode parentNode)
|
||||
private WinTreeNode AddItem(IObject3D item, WinTreeNode parentNode)
|
||||
{
|
||||
var node = new TreeNode(BuildDefaultName(item))
|
||||
var node = new WinTreeNode(BuildDefaultName(item))
|
||||
{
|
||||
Tag = item
|
||||
};
|
||||
|
|
@ -275,7 +277,7 @@ namespace MatterHackers.MatterControl
|
|||
return node;
|
||||
}
|
||||
|
||||
private void AddTree(GuiWidget widget, TreeNode parent)
|
||||
private void AddTree(GuiWidget widget, WinTreeNode parent)
|
||||
{
|
||||
var node = AddItem(widget, parent);
|
||||
|
||||
|
|
@ -285,7 +287,7 @@ namespace MatterHackers.MatterControl
|
|||
}
|
||||
}
|
||||
|
||||
private void AddTree(IObject3D item, TreeNode parent)
|
||||
private void AddTree(IObject3D item, WinTreeNode parent)
|
||||
{
|
||||
var node = AddItem(item, parent);
|
||||
|
||||
|
|
@ -348,7 +350,7 @@ namespace MatterHackers.MatterControl
|
|||
|
||||
public void MoveUpTree()
|
||||
{
|
||||
if (activeTreeNode?.Parent is TreeNode parent)
|
||||
if (activeTreeNode?.Parent is WinTreeNode parent)
|
||||
{
|
||||
this.InspectedWidget = parent.Tag as GuiWidget;
|
||||
}
|
||||
|
|
@ -356,7 +358,7 @@ namespace MatterHackers.MatterControl
|
|||
|
||||
public void MoveDownTree()
|
||||
{
|
||||
if (activeTreeNode?.Nodes.Cast<TreeNode>().FirstOrDefault() is TreeNode firstChild)
|
||||
if (activeTreeNode?.Nodes.Cast<WinTreeNode>().FirstOrDefault() is WinTreeNode firstChild)
|
||||
{
|
||||
this.InspectedWidget = firstChild.Tag as GuiWidget;
|
||||
}
|
||||
|
|
@ -502,11 +504,11 @@ namespace MatterHackers.MatterControl
|
|||
|
||||
private void InspectForm_Load(object sender, EventArgs e1)
|
||||
{
|
||||
var rootNode = new TreeNode("Theme");
|
||||
var rootNode = new WinTreeNode("Theme");
|
||||
|
||||
var themeNode = new TreeNode("Theme");
|
||||
var themeNode = new WinTreeNode("Theme");
|
||||
|
||||
var menuThemeNode = new TreeNode("MenuTheme");
|
||||
var menuThemeNode = new WinTreeNode("MenuTheme");
|
||||
|
||||
rootNode.Nodes.Add(themeNode);
|
||||
rootNode.Nodes.Add(menuThemeNode);
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CsvHelper">
|
||||
<Version>28.0.1</Version>
|
||||
<Version>29.0.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.9" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ using System.Text.RegularExpressions;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using global::MatterControl.Printing;
|
||||
using Markdig.Agg;
|
||||
using Markdig.Syntax.Inlines;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Font;
|
||||
using MatterHackers.Agg.Image;
|
||||
|
|
@ -588,9 +590,14 @@ namespace MatterHackers.MatterControl
|
|||
{
|
||||
try
|
||||
{
|
||||
Process.Start(input);
|
||||
}
|
||||
catch
|
||||
var p = new Process();
|
||||
p.StartInfo = new ProcessStartInfo(input)
|
||||
{
|
||||
UseShellExecute = true
|
||||
};
|
||||
p.Start();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// hack because of this: https://github.com/dotnet/corefx/issues/10361
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
|
|
@ -1132,7 +1139,12 @@ namespace MatterHackers.MatterControl
|
|||
{
|
||||
Workspaces = new ObservableCollection<PartWorkspace>();
|
||||
|
||||
Workspaces.CollectionChanged += (s, e) =>
|
||||
// get markdown working correctly
|
||||
MarkdownWidget.LaunchBrowser = ApplicationController.LaunchBrowser;
|
||||
MarkdownWidget.RetrieveText = WebCache.RetrieveText;
|
||||
MarkdownWidget.RetrieveImageSquenceAsync = WebCache.RetrieveImageSquenceAsync;
|
||||
|
||||
Workspaces.CollectionChanged += (s, e) =>
|
||||
{
|
||||
if (!restoringWorkspaces)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -27,56 +27,8 @@ of the authors and should not be interpreted as representing official policies,
|
|||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using global::MatterControl.Printing;
|
||||
using Markdig.Agg;
|
||||
using Markdig.Renderers.Agg;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Font;
|
||||
using MatterHackers.Agg.Image;
|
||||
using MatterHackers.Agg.Platform;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.Agg.VertexSource;
|
||||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.DataConverters3D.UndoCommands;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.CustomWidgets;
|
||||
using MatterHackers.MatterControl.DataStorage;
|
||||
using MatterHackers.MatterControl.DesignTools;
|
||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.MatterControl.Extensibility;
|
||||
using MatterHackers.MatterControl.Library;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow.View3D;
|
||||
using MatterHackers.MatterControl.Plugins;
|
||||
using MatterHackers.MatterControl.PrinterCommunication;
|
||||
using MatterHackers.MatterControl.PrinterControls.PrinterConnections;
|
||||
using MatterHackers.MatterControl.PrintQueue;
|
||||
using MatterHackers.MatterControl.SettingsManagement;
|
||||
using MatterHackers.MatterControl.SlicerConfiguration;
|
||||
using MatterHackers.MatterControl.Tour;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
using MatterHackers.VectorMath.TrackBall;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("MatterControl.Tests")]
|
||||
[assembly: InternalsVisibleTo("MatterControl.AutomationTests")]
|
||||
|
|
@ -84,11 +36,9 @@ using Newtonsoft.Json.Linq;
|
|||
|
||||
namespace MatterHackers.MatterControl
|
||||
{
|
||||
|
||||
public class DragDropData
|
||||
{
|
||||
public View3DWidget View3DWidget { get; set; }
|
||||
|
||||
public ISceneContext SceneContext { get; set; }
|
||||
}
|
||||
}
|
||||
public class DragDropData
|
||||
{
|
||||
public ISceneContext SceneContext { get; set; }
|
||||
public View3DWidget View3DWidget { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -27,8 +27,8 @@ of the authors and should not be interpreted as representing official policies,
|
|||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using MatterHackers.MatterControl;
|
||||
using System;
|
||||
|
||||
namespace Markdig.Agg
|
||||
{
|
||||
|
|
@ -1,181 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2017, Lars Brubaker, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Xml.Linq;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Image;
|
||||
using MatterHackers.Agg.Transform;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.Agg.VertexSource;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl
|
||||
{
|
||||
public class SvgWidget : GuiWidget
|
||||
{
|
||||
List<ColoredVertexSource> items = new List<ColoredVertexSource>();
|
||||
|
||||
private static XNamespace svg = "http://www.w3.org/2000/svg";
|
||||
|
||||
private ImageBuffer imageBuffer;
|
||||
|
||||
public double Scale { get; set; } = 0.7;
|
||||
|
||||
public SvgWidget(string filePath, double scale, int width = -1, int height = -1)
|
||||
: this (File.OpenRead(filePath), scale, width, height)
|
||||
{
|
||||
}
|
||||
|
||||
public SvgWidget(Stream stream, double scale, int width = -1, int height = -1)
|
||||
{
|
||||
var root = XElement.Load(stream);
|
||||
|
||||
this.Scale = scale;
|
||||
|
||||
string viewBox = (string)root.Attribute("viewBox");
|
||||
if (!string.IsNullOrEmpty(viewBox))
|
||||
{
|
||||
var segments = viewBox.Split(' ');
|
||||
|
||||
if (width == -1)
|
||||
{
|
||||
int.TryParse(segments[2], out width);
|
||||
}
|
||||
|
||||
if (height == -1)
|
||||
{
|
||||
int.TryParse(segments[3], out height);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var elem in root.Elements(svg + "g"))
|
||||
{
|
||||
ProcTree(elem);
|
||||
}
|
||||
|
||||
width = (int)(width * this.Scale);
|
||||
height = (int)(height * this.Scale);
|
||||
|
||||
imageBuffer = new ImageBuffer(width, height);
|
||||
|
||||
this.MinimumSize = new Vector2(width, height);
|
||||
|
||||
var graphics2D = imageBuffer.NewGraphics2D();
|
||||
|
||||
graphics2D.SetTransform(Affine.NewScaling(this.Scale));
|
||||
foreach (var item in items)
|
||||
{
|
||||
graphics2D.Render(item.VertexSource, item.Color);
|
||||
}
|
||||
|
||||
imageBuffer.FlipY();
|
||||
|
||||
stream.Dispose();
|
||||
//this.source = new PathStorage(svgDString);
|
||||
}
|
||||
|
||||
private void ProcTree(XElement g)
|
||||
{
|
||||
foreach (var elem in g.Elements())
|
||||
{
|
||||
switch (elem.Name.LocalName)
|
||||
{
|
||||
case "path":
|
||||
case "polygon":
|
||||
|
||||
string htmlColor = ((string)elem.Attribute("style"))?.Replace("fill:", "").Replace(";", "") ?? "#999";
|
||||
|
||||
if (elem.Name.LocalName == "polygon")
|
||||
{
|
||||
var path = new VertexStorage();
|
||||
|
||||
string pointsLine = ((string)elem.Attribute("points"))?.Trim();
|
||||
|
||||
var segments = pointsLine.Split(' ');
|
||||
|
||||
bool firstMove = true;
|
||||
foreach(var segment in segments)
|
||||
{
|
||||
var point = segment.Split(',');
|
||||
|
||||
if (firstMove)
|
||||
{
|
||||
path.MoveTo(new Vector2(double.Parse(point[0]), double.Parse(point[1])));
|
||||
firstMove = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
path.LineTo(new Vector2(double.Parse(point[0]), double.Parse(point[1])));
|
||||
}
|
||||
}
|
||||
|
||||
path.ClosePolygon();
|
||||
|
||||
items.Add(new ColoredVertexSource()
|
||||
{
|
||||
VertexSource = path,
|
||||
Color = new Color(htmlColor)
|
||||
});
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
string dString = (string)elem.Attribute("d");
|
||||
items.Add(new ColoredVertexSource()
|
||||
{
|
||||
VertexSource = new VertexStorage(dString),
|
||||
Color = new Color(htmlColor)
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "g":
|
||||
ProcTree(elem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDraw(Graphics2D graphics2D)
|
||||
{
|
||||
graphics2D.Render(imageBuffer, Point2D.Zero);
|
||||
|
||||
base.OnDraw(graphics2D);
|
||||
}
|
||||
|
||||
public class ColoredVertexSource
|
||||
{
|
||||
public IVertexSource VertexSource { get; set; }
|
||||
public Color Color { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,612 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2018, Lars Brubaker, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Font;
|
||||
using MatterHackers.Agg.Image;
|
||||
using MatterHackers.Agg.Platform;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.ImageProcessing;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.CustomWidgets
|
||||
{
|
||||
public class TreeNode : FlowLayoutWidget, ICheckbox
|
||||
{
|
||||
private readonly GuiWidget content;
|
||||
private TreeView _treeView;
|
||||
private ImageBuffer _image = null;
|
||||
private readonly TextWidget textWidget;
|
||||
private readonly TreeExpandWidget expandWidget;
|
||||
private readonly ImageWidget imageWidget;
|
||||
private bool isDirty;
|
||||
|
||||
public TreeNode(ThemeConfig theme, bool useIcon = true, TreeNode nodeParent = null)
|
||||
: base(FlowDirection.TopToBottom)
|
||||
{
|
||||
this.HAnchor = HAnchor.Fit | HAnchor.Left;
|
||||
this.VAnchor = VAnchor.Fit;
|
||||
|
||||
this.NodeParent = nodeParent;
|
||||
|
||||
this.TitleBar = new FlowLayoutWidget();
|
||||
this.TitleBar.Click += (s, e) =>
|
||||
{
|
||||
if (TreeView != null)
|
||||
{
|
||||
TreeView.SelectedNode = this;
|
||||
TreeView.NotifyItemClicked(TitleBar, e);
|
||||
}
|
||||
};
|
||||
|
||||
TreeNode hitNode = null;
|
||||
this.TitleBar.MouseDown += (s, e) =>
|
||||
{
|
||||
if (TreeView != null && e.Button == MouseButtons.Left)
|
||||
{
|
||||
if (e.Clicks == 1)
|
||||
{
|
||||
hitNode = this;
|
||||
}
|
||||
else if (e.Clicks == 2)
|
||||
{
|
||||
// Nodes can move around in the tree between clicks.
|
||||
// Make sure we're hitting the same node twice.
|
||||
if (this != hitNode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TreeView.SelectedNode = this;
|
||||
|
||||
if (this.Nodes.Count > 0)
|
||||
{
|
||||
this.Expanded = !this.Expanded;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.TreeView.NotifyItemDoubleClicked(TitleBar, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.AddChild(this.TitleBar);
|
||||
|
||||
// add a check box
|
||||
expandWidget = new TreeExpandWidget(theme)
|
||||
{
|
||||
Expandable = GetNodeCount(false) != 0,
|
||||
VAnchor = VAnchor.Fit | VAnchor.Center,
|
||||
Height = 16,
|
||||
Width = 16
|
||||
};
|
||||
|
||||
expandWidget.Click += (s, e) =>
|
||||
{
|
||||
this.Expanded = !this.Expanded;
|
||||
expandWidget.Expanded = this.Expanded;
|
||||
};
|
||||
|
||||
this.TitleBar.AddChild(expandWidget);
|
||||
|
||||
this.HighlightRegion = new FlowLayoutWidget()
|
||||
{
|
||||
VAnchor = VAnchor.Fit,
|
||||
HAnchor = HAnchor.Fit,
|
||||
Padding = useIcon ? new BorderDouble(2) : new BorderDouble(4, 2),
|
||||
Selectable = false
|
||||
};
|
||||
this.TitleBar.AddChild(this.HighlightRegion);
|
||||
|
||||
// add a check box
|
||||
if (useIcon)
|
||||
{
|
||||
_image = new ImageBuffer(16, 16);
|
||||
|
||||
this.HighlightRegion.AddChild(imageWidget = new ImageWidget(this.Image, listenForImageChanged: false)
|
||||
{
|
||||
VAnchor = VAnchor.Center,
|
||||
Margin = new BorderDouble(right: 4),
|
||||
Selectable = false
|
||||
});
|
||||
}
|
||||
|
||||
this.HighlightRegion.AddChild(textWidget = new TextWidget(this.Text, pointSize: theme.DefaultFontSize, textColor: theme.TextColor)
|
||||
{
|
||||
Selectable = false,
|
||||
AutoExpandBoundsToText = true,
|
||||
VAnchor = VAnchor.Center
|
||||
});
|
||||
|
||||
content = new FlowLayoutWidget(FlowDirection.TopToBottom)
|
||||
{
|
||||
HAnchor = HAnchor.Fit | HAnchor.Left,
|
||||
Visible = false, // content starts out not visible
|
||||
Name = "content",
|
||||
Margin = new BorderDouble(12, 3),
|
||||
};
|
||||
this.AddChild(content);
|
||||
|
||||
// Register listeners
|
||||
this.Nodes.CollectionChanged += this.Nodes_CollectionChanged;
|
||||
}
|
||||
|
||||
public override void OnKeyDown(KeyEventArgs keyEvent)
|
||||
{
|
||||
base.OnKeyDown(keyEvent);
|
||||
|
||||
var restoreFocus = Focused;
|
||||
|
||||
if (!keyEvent.Handled)
|
||||
{
|
||||
switch (keyEvent.KeyCode)
|
||||
{
|
||||
case Keys.Right:
|
||||
this.Expanded = true;
|
||||
keyEvent.Handled = true;
|
||||
break;
|
||||
|
||||
case Keys.Left:
|
||||
if (!this.Expanded)
|
||||
{
|
||||
if (this.NodeParent != null)
|
||||
{
|
||||
// navigate back up to the parent of this node
|
||||
TreeView.SelectedNode = this.NodeParent;
|
||||
TreeView.NotifyItemClicked(TreeView, new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0));
|
||||
}
|
||||
|
||||
restoreFocus = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Expanded = false;
|
||||
}
|
||||
|
||||
keyEvent.Handled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (restoreFocus && !Focused)
|
||||
{
|
||||
Focus();
|
||||
}
|
||||
}
|
||||
|
||||
private void Nodes_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
|
||||
{
|
||||
// Assign NodeParent when items are added
|
||||
foreach (var item in e.NewItems)
|
||||
{
|
||||
if (item is TreeNode treeNode)
|
||||
{
|
||||
treeNode.NodeParent = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isDirty = true;
|
||||
}
|
||||
|
||||
public FlowLayoutWidget TitleBar { get; }
|
||||
|
||||
public FlowLayoutWidget HighlightRegion { get; }
|
||||
|
||||
// **** Not implemented ****
|
||||
public void BeginEdit() => throw new NotImplementedException();
|
||||
|
||||
public void Collapse(bool collapseChildren) => throw new NotImplementedException();
|
||||
|
||||
public void Collapse() => throw new NotImplementedException();
|
||||
|
||||
public void EndEdit(bool cancel) => throw new NotImplementedException();
|
||||
|
||||
public void EnsureVisible() => throw new NotImplementedException();
|
||||
|
||||
public void ExpandAll() => throw new NotImplementedException();
|
||||
|
||||
public void Remove() => throw new NotImplementedException();
|
||||
|
||||
public int GetNodeCount(bool includeSubTrees)
|
||||
{
|
||||
if (includeSubTrees)
|
||||
{
|
||||
return this.Descendants<TreeNode>().Count();
|
||||
}
|
||||
|
||||
return content?.Children.Where((c) => c is TreeNode).Count() ?? 0;
|
||||
}
|
||||
|
||||
public bool AlwaysExpandable
|
||||
{
|
||||
get => expandWidget.AlwaysExpandable;
|
||||
set => expandWidget.AlwaysExpandable = value;
|
||||
}
|
||||
|
||||
public override void OnDraw(Graphics2D graphics2D)
|
||||
{
|
||||
if (isDirty)
|
||||
{
|
||||
// doing this during draw will often result in a enumeration changed
|
||||
RebuildContentSection();
|
||||
}
|
||||
|
||||
base.OnDraw(graphics2D);
|
||||
}
|
||||
|
||||
public override void OnTextChanged(EventArgs e)
|
||||
{
|
||||
if (textWidget != null)
|
||||
{
|
||||
textWidget.Text = this.Text;
|
||||
}
|
||||
|
||||
base.OnTextChanged(e);
|
||||
}
|
||||
|
||||
public override void OnClosed(EventArgs e)
|
||||
{
|
||||
// Unregister listeners
|
||||
this.Nodes.CollectionChanged -= this.Nodes_CollectionChanged;
|
||||
|
||||
base.OnClosed(e);
|
||||
}
|
||||
|
||||
public void Toggle()
|
||||
{
|
||||
content.Visible = !content.Visible;
|
||||
}
|
||||
|
||||
public IEnumerable<TreeNode> Ancestors()
|
||||
{
|
||||
var context = this.NodeParent;
|
||||
while (context != null)
|
||||
{
|
||||
yield return context;
|
||||
|
||||
context = context.NodeParent;
|
||||
}
|
||||
}
|
||||
|
||||
private void RebuildContentSection()
|
||||
{
|
||||
// Remove but don't close all the current nodes
|
||||
content.RemoveChildren();
|
||||
|
||||
using (content.LayoutLock())
|
||||
{
|
||||
// Then add them back in (after the change)
|
||||
foreach (var node in Nodes)
|
||||
{
|
||||
node.NodeParent = this;
|
||||
node.ClearRemovedFlag();
|
||||
content.AddChild(node);
|
||||
}
|
||||
}
|
||||
|
||||
content.PerformLayout();
|
||||
|
||||
// If the node count is ending at 0 we removed content and need to rebuild the title bar so it will net have a + in it
|
||||
expandWidget.Expandable = GetNodeCount(false) != 0;
|
||||
|
||||
isDirty = false;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return textWidget?.Text ?? "";
|
||||
}
|
||||
|
||||
public bool Checked { get; set; }
|
||||
|
||||
public bool Editing { get; }
|
||||
|
||||
public bool Expandable
|
||||
{
|
||||
get => expandWidget.Expandable;
|
||||
set => expandWidget.Expandable = value;
|
||||
}
|
||||
|
||||
public bool ReserveIconSpace
|
||||
{
|
||||
get => expandWidget.ReserveIconSpace;
|
||||
set => expandWidget.ReserveIconSpace = value;
|
||||
}
|
||||
|
||||
private bool _expanded;
|
||||
|
||||
public bool Expanded
|
||||
{
|
||||
get => _expanded;
|
||||
set
|
||||
{
|
||||
if (_expanded != value || content.Visible != value)
|
||||
{
|
||||
_expanded = value;
|
||||
expandWidget.Expanded = _expanded;
|
||||
|
||||
content.Visible = _expanded && this.Nodes.Count > 0;
|
||||
ExpandedChanged?.Invoke(this, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TreeNode FirstNode { get; }
|
||||
|
||||
public ImageBuffer Image
|
||||
{
|
||||
get
|
||||
{
|
||||
return _image;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_image != value)
|
||||
{
|
||||
_image = value;
|
||||
|
||||
if (imageWidget != null)
|
||||
{
|
||||
imageWidget.Image = _image;
|
||||
}
|
||||
|
||||
OnImageChanged(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TreeNode LastNode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the zero-based depth of the tree node in the TreeView control.
|
||||
/// </summary>
|
||||
public int Level { get; }
|
||||
|
||||
// Summary:
|
||||
// Gets the next sibling tree node.
|
||||
//
|
||||
// Returns:
|
||||
// A TreeNode that represents the next sibling tree node.
|
||||
public TreeNode NextNode { get; }
|
||||
|
||||
// Summary:
|
||||
// Gets the next visible tree node.
|
||||
//
|
||||
// Returns:
|
||||
// A TreeNode that represents the next visible tree node.
|
||||
public TreeNode NextVisibleNode { get; }
|
||||
|
||||
// Summary:
|
||||
// Gets or sets the font that is used to display the text on the tree node label.
|
||||
//
|
||||
// Returns:
|
||||
// The StyledTypeFace that is used to display the text on the tree node label.
|
||||
public StyledTypeFace NodeFont { get; set; }
|
||||
|
||||
// Summary:
|
||||
// Gets the parent tree node of the current tree node.
|
||||
//
|
||||
// Returns:
|
||||
// A TreeNode that represents the parent of the current tree
|
||||
// node.
|
||||
public TreeNode NodeParent { get; protected set; }
|
||||
|
||||
public ObservableCollection<TreeNode> Nodes { get; } = new ObservableCollection<TreeNode>();
|
||||
|
||||
public int PointSize { get; set; }
|
||||
|
||||
// Summary:
|
||||
// Gets the previous sibling tree node.
|
||||
//
|
||||
// Returns:
|
||||
// A TreeNode that represents the previous sibling tree node.
|
||||
public TreeNode PrevNode { get; }
|
||||
|
||||
// Summary:
|
||||
// Gets the previous visible tree node.
|
||||
//
|
||||
// Returns:
|
||||
// A TreeNode that represents the previous visible tree node.
|
||||
public TreeNode PrevVisibleNode { get; }
|
||||
|
||||
// Summary:
|
||||
// Gets a value indicating whether the tree node is in the selected state.
|
||||
//
|
||||
// Returns:
|
||||
// true if the tree node is in the selected state; otherwise, false.
|
||||
public bool Selected
|
||||
{
|
||||
get
|
||||
{
|
||||
if (TreeView != null)
|
||||
{
|
||||
return TreeView.SelectedNode == this;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Summary:
|
||||
// Gets or sets the image list index value of the image that is displayed when the
|
||||
// tree node is in the selected state.
|
||||
//
|
||||
// Returns:
|
||||
// A zero-based index value that represents the image position in an ImageList.
|
||||
public ImageBuffer SelectedImage { get; set; }
|
||||
|
||||
// Summary:
|
||||
// Gets or sets the index of the image that is used to indicate the state of the
|
||||
// TreeNode when the parent TreeView has
|
||||
// its TreeView.CheckBoxes property set to false.
|
||||
//
|
||||
// Returns:
|
||||
// The index of the image that is used to indicate the state of the TreeNode.
|
||||
//
|
||||
// Exceptions:
|
||||
// T:System.ArgumentOutOfRangeException:
|
||||
// The specified index is less than -1 or greater than 14.
|
||||
public ImageBuffer StateImage { get; set; }
|
||||
|
||||
// Summary:
|
||||
// Gets or sets the object that contains data about the tree node.
|
||||
//
|
||||
// Returns:
|
||||
// An System.Object that contains data about the tree node. The default is null.
|
||||
public object Tag { get; set; }
|
||||
|
||||
public Color TextColor { get; set; }
|
||||
|
||||
// Summary:
|
||||
// Gets the parent tree view that the tree node is assigned to.
|
||||
//
|
||||
// Returns:
|
||||
// A TreeView that represents the parent tree view that the
|
||||
// tree node is assigned to, or null if the node has not been assigned to a tree
|
||||
// view.
|
||||
|
||||
public virtual TreeView TreeView
|
||||
{
|
||||
get => _treeView ?? NodeParent.TreeView;
|
||||
set => _treeView = value;
|
||||
}
|
||||
|
||||
private void OnImageChanged(EventArgs args)
|
||||
{
|
||||
ImageChanged?.Invoke(this, null);
|
||||
}
|
||||
|
||||
public event EventHandler CheckedStateChanged;
|
||||
|
||||
public event EventHandler ExpandedChanged;
|
||||
|
||||
public event EventHandler ImageChanged;
|
||||
|
||||
private class TreeExpandWidget : FlowLayoutWidget
|
||||
{
|
||||
private readonly ImageBuffer arrowRight;
|
||||
private readonly ImageBuffer arrowDown;
|
||||
private readonly ImageBuffer placeholder;
|
||||
private readonly ThemedIconButton imageButton = null;
|
||||
|
||||
public TreeExpandWidget(ThemeConfig theme)
|
||||
{
|
||||
arrowRight = StaticData.Instance.LoadIcon("fa-angle-right_12.png", 12, 12).SetToColor(theme.TextColor);
|
||||
arrowDown = StaticData.Instance.LoadIcon("fa-angle-down_12.png", 12, 12).SetToColor(theme.TextColor);
|
||||
placeholder = new ImageBuffer(16, 16);
|
||||
|
||||
this.Margin = new BorderDouble(right: 4);
|
||||
|
||||
imageButton = new ThemedIconButton(placeholder, theme)
|
||||
{
|
||||
MinimumSize = new Vector2(16 * DeviceScale, 16 * DeviceScale),
|
||||
VAnchor = VAnchor.Center,
|
||||
Selectable = false,
|
||||
Width = 16 * DeviceScale,
|
||||
Height = 16 * DeviceScale
|
||||
};
|
||||
|
||||
this.AddChild(imageButton);
|
||||
}
|
||||
|
||||
private bool _alwaysExpandable;
|
||||
|
||||
public bool AlwaysExpandable
|
||||
{
|
||||
get => _alwaysExpandable;
|
||||
set
|
||||
{
|
||||
imageButton.SetIcon(_expanded ? arrowDown : arrowRight);
|
||||
_alwaysExpandable = value;
|
||||
}
|
||||
}
|
||||
|
||||
private bool? _expandable = null;
|
||||
|
||||
public bool Expandable
|
||||
{
|
||||
get => _expandable == true || this.AlwaysExpandable;
|
||||
set
|
||||
{
|
||||
if (_expandable != value)
|
||||
{
|
||||
_expandable = value;
|
||||
}
|
||||
|
||||
this.EnsureExpansionState();
|
||||
}
|
||||
}
|
||||
|
||||
private bool _expanded;
|
||||
|
||||
public bool Expanded
|
||||
{
|
||||
get => _expanded;
|
||||
set
|
||||
{
|
||||
if (_expanded != value)
|
||||
{
|
||||
_expanded = value;
|
||||
|
||||
this.EnsureExpansionState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureExpansionState()
|
||||
{
|
||||
if (!this.Expandable)
|
||||
{
|
||||
if (this.ReserveIconSpace)
|
||||
{
|
||||
imageButton.SetIcon(placeholder);
|
||||
}
|
||||
|
||||
imageButton.Visible = this.ReserveIconSpace;
|
||||
}
|
||||
else
|
||||
{
|
||||
imageButton.Visible = true;
|
||||
imageButton.SetIcon(_expanded ? arrowDown : arrowRight);
|
||||
}
|
||||
}
|
||||
|
||||
public bool ReserveIconSpace { get; set; } = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,455 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2018, Lars Brubaker, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.CustomWidgets
|
||||
{
|
||||
public class TreeView : ScrollableWidget
|
||||
{
|
||||
protected ThemeConfig theme;
|
||||
|
||||
public TreeView(ThemeConfig theme)
|
||||
: this(0, 0, theme)
|
||||
{
|
||||
}
|
||||
|
||||
public TreeView(int width, int height, ThemeConfig theme)
|
||||
: base(width, height)
|
||||
{
|
||||
this.theme = theme;
|
||||
this.AutoScroll = true;
|
||||
this.HAnchor = HAnchor.Stretch;
|
||||
this.VAnchor = VAnchor.Stretch;
|
||||
}
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler AfterCheck;
|
||||
|
||||
public event EventHandler AfterCollapse;
|
||||
|
||||
public event EventHandler AfterExpand;
|
||||
|
||||
public event EventHandler AfterLabelEdit;
|
||||
|
||||
public event EventHandler<TreeNode> AfterSelect;
|
||||
|
||||
public event EventHandler BeforeCheck;
|
||||
|
||||
internal void NotifyItemClicked(GuiWidget sourceWidget, MouseEventArgs e)
|
||||
{
|
||||
this.NodeMouseClick?.Invoke(sourceWidget, e);
|
||||
}
|
||||
|
||||
internal void NotifyItemDoubleClicked(GuiWidget sourceWidget, MouseEventArgs e)
|
||||
{
|
||||
this.NodeMouseDoubleClick?.Invoke(sourceWidget, e);
|
||||
}
|
||||
|
||||
public event EventHandler BeforeCollapse;
|
||||
|
||||
public event EventHandler BeforeExpand;
|
||||
|
||||
public event EventHandler BeforeLabelEdit;
|
||||
|
||||
public event EventHandler<TreeNode> BeforeSelect;
|
||||
|
||||
public event EventHandler NodeMouseClick;
|
||||
|
||||
public event EventHandler NodeMouseDoubleClick;
|
||||
|
||||
public event EventHandler NodeMouseHover;
|
||||
|
||||
#endregion Events
|
||||
|
||||
#region Properties
|
||||
|
||||
// Summary:
|
||||
// Gets or sets a value indicating whether check boxes are displayed next to the
|
||||
// tree nodes in the tree view control.
|
||||
//
|
||||
// Returns:
|
||||
// true if a check box is displayed next to each tree node in the tree view control;
|
||||
// otherwise, false. The default is false.
|
||||
public bool CheckBoxes { get; set; }
|
||||
|
||||
// Summary:
|
||||
// Gets or sets a value indicating whether the selection highlight spans the width
|
||||
// of the tree view control.
|
||||
//
|
||||
// Returns:
|
||||
// true if the selection highlight spans the width of the tree view control; otherwise,
|
||||
// false. The default is false.
|
||||
public bool FullRowSelect { get; set; }
|
||||
|
||||
// Summary:
|
||||
// Gets or sets a value indicating whether the selected tree node remains highlighted
|
||||
// even when the tree view has lost the focus.
|
||||
//
|
||||
// Returns:
|
||||
// true if the selected tree node is not highlighted when the tree view has lost
|
||||
// the focus; otherwise, false. The default is true.
|
||||
public bool HideSelection { get; set; }
|
||||
|
||||
// Summary:
|
||||
// Gets or sets the distance to indent each child tree node level.
|
||||
//
|
||||
// Returns:
|
||||
// The distance, in pixels, to indent each child tree node level. The default value
|
||||
// is 19.
|
||||
//
|
||||
// Exceptions:
|
||||
// T:System.ArgumentOutOfRangeException:
|
||||
// The assigned value is less than 0 (see Remarks).-or- The assigned value is greater
|
||||
// than 32,000.
|
||||
public int Indent { get; set; }
|
||||
|
||||
// Summary:
|
||||
// Gets or sets the height of each tree node in the tree view control.
|
||||
//
|
||||
// Returns:
|
||||
// The height, in pixels, of each tree node in the tree view.
|
||||
//
|
||||
// Exceptions:
|
||||
// T:System.ArgumentOutOfRangeException:
|
||||
// The assigned value is less than one.-or- The assigned value is greater than the
|
||||
// System.Int16.MaxValue value.
|
||||
public int ItemHeight { get; set; }
|
||||
|
||||
// Summary:
|
||||
// Gets or sets a value indicating whether the label text of the tree nodes can
|
||||
// be edited.
|
||||
//
|
||||
// Returns:
|
||||
// true if the label text of the tree nodes can be edited; otherwise, false. The
|
||||
// default is false.
|
||||
public bool LabelEdit { get; set; }
|
||||
|
||||
// Summary:
|
||||
// Gets or sets the color of the lines connecting the nodes of the TreeView
|
||||
// control.
|
||||
//
|
||||
// Returns:
|
||||
// The System.Drawing.Color of the lines connecting the tree nodes.
|
||||
public Color LineColor { get; set; }
|
||||
|
||||
// Summary:
|
||||
// Gets or sets the delimiter string that the tree node path uses.
|
||||
//
|
||||
// Returns:
|
||||
// The delimiter string that the tree node TreeNode.FullPath
|
||||
// property uses. The default is the backslash character (\).
|
||||
public string PathSeparator { get; set; }
|
||||
|
||||
public Color TextColor { get; set; } = Color.Black;
|
||||
|
||||
public double PointSize { get; set; } = 12;
|
||||
|
||||
// Summary:
|
||||
// Gets or sets a value indicating whether the tree view control displays scroll
|
||||
// bars when they are needed.
|
||||
//
|
||||
// Returns:
|
||||
// true if the tree view control displays scroll bars when they are needed; otherwise,
|
||||
// false. The default is true.
|
||||
public bool Scrollable { get; set; }
|
||||
|
||||
// Summary:
|
||||
// Gets or sets the tree node that is currently selected in the tree view control.
|
||||
//
|
||||
// Returns:
|
||||
// The TreeNode that is currently selected in the tree view
|
||||
// control.
|
||||
private TreeNode _selectedNode;
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
this.ScrollArea.CloseChildren();
|
||||
|
||||
// Release held reference
|
||||
_selectedNode = null;
|
||||
}
|
||||
|
||||
public override void OnKeyDown(KeyEventArgs keyEvent)
|
||||
{
|
||||
if (!keyEvent.Handled)
|
||||
{
|
||||
switch (keyEvent.KeyCode)
|
||||
{
|
||||
case Keys.Up:
|
||||
var prev = PreviousVisibleTreeNode(SelectedNode);
|
||||
if (prev != null)
|
||||
{
|
||||
SelectedNode = prev;
|
||||
keyEvent.Handled = true;
|
||||
prev.TreeView.NotifyItemClicked(prev.TreeView, new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Keys.Down:
|
||||
var next = NextVisibleTreeNode(SelectedNode);
|
||||
if (next != null)
|
||||
{
|
||||
SelectedNode = next;
|
||||
keyEvent.Handled = true;
|
||||
next.TreeView.NotifyItemClicked(next.TreeView, new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
base.OnKeyDown(keyEvent);
|
||||
}
|
||||
|
||||
private TreeNode NextVisibleTreeNode(TreeNode treeNode)
|
||||
{
|
||||
var nodes = this.Descendants<TreeNode>((child) => child.Visible).ToList();
|
||||
|
||||
var selectedIndex = nodes.IndexOf(SelectedNode);
|
||||
|
||||
if (selectedIndex < nodes.Count - 1)
|
||||
{
|
||||
return nodes[selectedIndex + 1];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private TreeNode PreviousVisibleTreeNode(TreeNode treeNode)
|
||||
{
|
||||
var nodes = this.Descendants<TreeNode>((child) => child.Visible).ToList();
|
||||
|
||||
var selectedIndex = nodes.IndexOf(SelectedNode);
|
||||
|
||||
if (selectedIndex > 0)
|
||||
{
|
||||
return nodes[selectedIndex - 1];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public TreeNode SelectedNode
|
||||
{
|
||||
get => _selectedNode;
|
||||
set
|
||||
{
|
||||
if (value != _selectedNode)
|
||||
{
|
||||
OnBeforeSelect(null);
|
||||
|
||||
var hadFocus = false;
|
||||
|
||||
// if the current selection (before change) is !null than clear its background color
|
||||
if (_selectedNode != null)
|
||||
{
|
||||
hadFocus = _selectedNode.ContainsFocus;
|
||||
_selectedNode.HighlightRegion.BackgroundColor = Color.Transparent;
|
||||
}
|
||||
|
||||
// change the selection
|
||||
_selectedNode = value;
|
||||
|
||||
if (_selectedNode != null)
|
||||
{
|
||||
// Ensure tree is expanded, walk backwards to the root, reverse, expand back to this node
|
||||
foreach (var ancestor in _selectedNode.Ancestors().Reverse())
|
||||
{
|
||||
ancestor.Expanded = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (_selectedNode != null)
|
||||
{
|
||||
_selectedNode.HighlightRegion.BackgroundColor = theme.AccentMimimalOverlay;
|
||||
}
|
||||
|
||||
this.ScrollIntoView(_selectedNode);
|
||||
if (hadFocus)
|
||||
{
|
||||
_selectedNode?.Focus();
|
||||
}
|
||||
|
||||
OnAfterSelect(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowLines { get; set; }
|
||||
|
||||
public bool ShowNodeToolTips { get; set; }
|
||||
|
||||
public bool ShowPlusMinus { get; set; }
|
||||
|
||||
public bool ShowRootLines { get; set; }
|
||||
|
||||
public bool Sorted { get; set; }
|
||||
|
||||
public IComparer TreeViewNodeSorter { get; set; }
|
||||
|
||||
// Summary:
|
||||
// Gets the number of tree nodes that can be fully visible in the tree view control.
|
||||
//
|
||||
// Returns:
|
||||
// The number of TreeNode items that can be fully visible in
|
||||
// the TreeView control.
|
||||
public int VisibleCount { get; }
|
||||
|
||||
#endregion Properties
|
||||
|
||||
// Summary:
|
||||
// Disables any redrawing of the tree view.
|
||||
public void BeginUpdate()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
// Summary:
|
||||
// Collapses all the tree nodes.
|
||||
public void CollapseAll()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
// Summary:
|
||||
// Enables the redrawing of the tree view.
|
||||
public void EndUpdate()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
// Summary:
|
||||
// Expands all the tree nodes.
|
||||
public void ExpandAll()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
// Summary:
|
||||
// Retrieves the tree node that is at the specified point.
|
||||
//
|
||||
// Parameters:
|
||||
// pt:
|
||||
// The System.Drawing.Point to evaluate and retrieve the node from.
|
||||
//
|
||||
// Returns:
|
||||
// The TreeNode at the specified point, in tree view (client)
|
||||
// coordinates, or null if there is no node at that location.
|
||||
public TreeNode GetNodeAt(Vector2 pt)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the number of tree nodes, optionally including those in all subtrees,
|
||||
/// assigned to the tree view control.
|
||||
/// </summary>
|
||||
/// <param name="includeSubTrees">true to count the TreeNode items that the subtrees contain;
|
||||
/// otherwise, false.</param>
|
||||
/// <returns>The number of tree nodes, optionally including those in all subtrees, assigned
|
||||
/// to the tree view control.</returns>
|
||||
public int GetNodeCount(bool includeSubTrees)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Sort()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected internal virtual void OnAfterCollapse(EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected internal virtual void OnBeforeCollapse(EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected virtual void OnAfterCheck(EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected virtual void OnAfterExpand(EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected virtual void OnAfterLabelEdit(EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected virtual void OnAfterSelect(TreeNode e)
|
||||
{
|
||||
AfterSelect?.Invoke(this, e);
|
||||
}
|
||||
|
||||
protected virtual void OnBeforeCheck(EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected virtual void OnBeforeExpand(EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected virtual void OnBeforeLabelEdit(EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected virtual void OnBeforeSelect(TreeNode e)
|
||||
{
|
||||
BeforeSelect?.Invoke(this, e);
|
||||
}
|
||||
|
||||
protected virtual void OnNodeMouseClick(EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected virtual void OnNodeMouseDoubleClick(EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -79,6 +79,7 @@
|
|||
<ProjectReference Include="..\Submodules\agg-sharp\Gui\Gui.csproj" />
|
||||
<ProjectReference Include="..\Submodules\agg-sharp\ImageProcessing\ImageProcessing.csproj" />
|
||||
<ProjectReference Include="..\Submodules\agg-sharp\MarchingSquares\MarchingSquares.csproj" />
|
||||
<ProjectReference Include="..\Submodules\agg-sharp\MarkdigAgg\MarkdigAgg.csproj" />
|
||||
<ProjectReference Include="..\Submodules\agg-sharp\MeshThumbnails\MeshThumbnails\MeshThumbnails.csproj" />
|
||||
<ProjectReference Include="..\Submodules\agg-sharp\VectorMath\VectorMath.csproj" />
|
||||
<ProjectReference Include="..\Submodules\agg-sharp\Tesselate\Tesselate.csproj" />
|
||||
|
|
@ -92,11 +93,11 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AngleSharp" Version="0.17.1" />
|
||||
<PackageReference Include="CsvHelper" Version="28.0.1" />
|
||||
<PackageReference Include="CsvHelper" Version="29.0.0" />
|
||||
<PackageReference Include="Lucene.Net" Version="4.8.0-beta00005" />
|
||||
<PackageReference Include="Lucene.Net.Analysis.Common" Version="4.8.0-beta00005" />
|
||||
<PackageReference Include="Lucene.Net.QueryParser" Version="4.8.0-beta00005" />
|
||||
<PackageReference Include="Markdig" Version="0.30.3" />
|
||||
<PackageReference Include="Markdig" Version="0.30.4" />
|
||||
<PackageReference Include="MathParser.org-mXparser" Version="5.0.7" />
|
||||
<PackageReference Include="MIConvexHull" Version="1.1.19.1019" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
|
||||
|
|
|
|||
|
|
@ -47,7 +47,10 @@ namespace MatterHackers.MatterControl
|
|||
private TypeFacePrinter typeFacePrinter = null;
|
||||
private PrinterConfig printer = null;
|
||||
|
||||
private int forceStartLine = -1;
|
||||
/// <summary>
|
||||
/// The first line to show from the existing visible lines. If -1 then show to the bottom of the list.
|
||||
/// </summary>
|
||||
private int forceStartLine = -1;
|
||||
|
||||
private Func<TerminalLine, string> _lineFilterFunction;
|
||||
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ namespace MatterHackers.MatterControl
|
|||
|
||||
if (!string.IsNullOrWhiteSpace(article.Path))
|
||||
{
|
||||
markdownWidget.LoadUri(new Uri(ApplicationController.Instance.HelpArticleSource, article.Path), sourceArticle: article);
|
||||
markdownWidget.LoadUri(new Uri(ApplicationController.Instance.HelpArticleSource, article.Path));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ either expressed or implied, of the FreeBSD Project.
|
|||
*/
|
||||
|
||||
using System;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.MatterControl.CustomWidgets;
|
||||
using MatterHackers.MatterControl.Library.Widgets;
|
||||
using MatterHackers.MatterControl.SlicerConfiguration;
|
||||
|
|
|
|||
|
|
@ -1,45 +0,0 @@
|
|||
// Copyright (c) 2016-2017 Nicolas Musset. All rights reserved.
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using Markdig.Syntax;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.MatterControl;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
public class CodeBlockX : FlowLeftRightWithWrapping
|
||||
{
|
||||
private ThemeConfig theme;
|
||||
|
||||
public CodeBlockX(ThemeConfig theme)
|
||||
{
|
||||
this.theme = theme;
|
||||
this.HAnchor = HAnchor.Stretch;
|
||||
this.VAnchor = VAnchor.Fit;
|
||||
this.Margin = 12;
|
||||
this.Padding = 6;
|
||||
this.BackgroundColor = theme.MinimalShade;
|
||||
}
|
||||
}
|
||||
|
||||
public class AggCodeBlockRenderer : AggObjectRenderer<CodeBlock>
|
||||
{
|
||||
private ThemeConfig theme;
|
||||
|
||||
public AggCodeBlockRenderer(ThemeConfig theme)
|
||||
{
|
||||
this.theme = theme;
|
||||
}
|
||||
|
||||
protected override void Write(AggRenderer renderer, CodeBlock obj)
|
||||
{
|
||||
//var paragraph = new Paragraph();
|
||||
//paragraph.SetResourceReference(FrameworkContentElement.StyleProperty, Styles.CodeBlockStyleKey);
|
||||
|
||||
renderer.Push(new CodeBlockX(theme));
|
||||
renderer.WriteLeafRawLines(obj);
|
||||
renderer.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
// Copyright (c) 2016-2017 Nicolas Musset. All rights reserved.
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using Markdig.Syntax;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
public class AggHeadingRenderer : AggObjectRenderer<HeadingBlock>
|
||||
{
|
||||
protected override void Write(AggRenderer renderer, HeadingBlock obj)
|
||||
{
|
||||
// var paragraph = new Paragraph();
|
||||
// ComponentResourceKey styleKey = null;
|
||||
|
||||
// switch (obj.Level)
|
||||
// {
|
||||
// case 1: styleKey = Styles.Heading1StyleKey; break;
|
||||
// case 2: styleKey = Styles.Heading2StyleKey; break;
|
||||
// case 3: styleKey = Styles.Heading3StyleKey; break;
|
||||
// case 4: styleKey = Styles.Heading4StyleKey; break;
|
||||
// case 5: styleKey = Styles.Heading5StyleKey; break;
|
||||
// case 6: styleKey = Styles.Heading6StyleKey; break;
|
||||
// }
|
||||
|
||||
// if (styleKey != null)
|
||||
// {
|
||||
// paragraph.SetResourceReference(FrameworkContentElement.StyleProperty, styleKey);
|
||||
// }
|
||||
|
||||
renderer.Push(new HeadingRowX()); // paragraph);
|
||||
renderer.WriteLeafInline(obj);
|
||||
renderer.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
// Copyright (c) 2016-2017 Nicolas Musset. All rights reserved.
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using Markdig.Syntax;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Platform;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.ImageProcessing;
|
||||
using MatterHackers.MatterControl;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
public class ListX : FlowLayoutWidget
|
||||
{
|
||||
public ListX()
|
||||
: base(FlowDirection.TopToBottom)
|
||||
{
|
||||
this.VAnchor = VAnchor.Fit;
|
||||
this.HAnchor = HAnchor.Stretch;
|
||||
}
|
||||
|
||||
public override GuiWidget AddChild(GuiWidget childToAdd, int indexInChildrenList = -1)
|
||||
{
|
||||
if (childToAdd is TextWidget textWidget)
|
||||
{
|
||||
textWidget.TextColor = new Color("#036ac3");
|
||||
textWidget.PointSize = 11;
|
||||
}
|
||||
|
||||
return base.AddChild(childToAdd, indexInChildrenList);
|
||||
}
|
||||
}
|
||||
|
||||
public class ListItemX : FlowLayoutWidget
|
||||
{
|
||||
private FlowLayoutWidget content;
|
||||
public ListItemX(ThemeConfig theme)
|
||||
{
|
||||
this.VAnchor = VAnchor.Fit;
|
||||
this.HAnchor = HAnchor.Stretch;
|
||||
|
||||
base.AddChild(new ImageWidget(StaticData.Instance.LoadIcon("bullet.png", 16, 16).SetToColor(theme.TextColor))
|
||||
{
|
||||
Margin = new BorderDouble(top: 1, left: 10),
|
||||
VAnchor = VAnchor.Top,
|
||||
});
|
||||
|
||||
base.AddChild(content = new FlowLayoutWidget(FlowDirection.TopToBottom)
|
||||
{
|
||||
HAnchor = HAnchor.Stretch
|
||||
});
|
||||
}
|
||||
|
||||
public override GuiWidget AddChild(GuiWidget childToAdd, int indexInChildrenList = -1)
|
||||
{
|
||||
// TODOD: Anything else required for list children?
|
||||
return content.AddChild(childToAdd, indexInChildrenList);
|
||||
}
|
||||
}
|
||||
|
||||
public class AggListRenderer : AggObjectRenderer<ListBlock>
|
||||
{
|
||||
private ThemeConfig theme;
|
||||
|
||||
public AggListRenderer(ThemeConfig theme)
|
||||
{
|
||||
this.theme = theme;
|
||||
}
|
||||
|
||||
protected override void Write(AggRenderer renderer, ListBlock listBlock)
|
||||
{
|
||||
//var list = new List();
|
||||
|
||||
//if (listBlock.IsOrdered)
|
||||
//{
|
||||
// list.MarkerStyle = TextMarkerStyle.Decimal;
|
||||
|
||||
// if (listBlock.OrderedStart != null && (listBlock.DefaultOrderedStart != listBlock.OrderedStart))
|
||||
// {
|
||||
// list.StartIndex = int.Parse(listBlock.OrderedStart);
|
||||
// }
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// list.MarkerStyle = TextMarkerStyle.Disc;
|
||||
//}
|
||||
|
||||
renderer.Push(new ListX()); // list);
|
||||
|
||||
foreach (var item in listBlock)
|
||||
{
|
||||
renderer.Push(new ListItemX(theme));
|
||||
renderer.WriteChildren(item as ListItemBlock);
|
||||
renderer.Pop();
|
||||
}
|
||||
|
||||
renderer.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,138 +0,0 @@
|
|||
/*
|
||||
Copyright(c) 2018, Lars Brubaker, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using Markdig.Renderers;
|
||||
using Markdig.Renderers.Agg;
|
||||
using MatterHackers.Agg.UI;
|
||||
|
||||
namespace Markdig.Agg
|
||||
{
|
||||
public class AggMarkdownDocument
|
||||
{
|
||||
private string _markDownText = null;
|
||||
private MarkdownPipeline _pipeLine = null;
|
||||
private static readonly MarkdownPipeline DefaultPipeline = new MarkdownPipelineBuilder().UseSupportedExtensions().Build();
|
||||
|
||||
public AggMarkdownDocument()
|
||||
{
|
||||
}
|
||||
|
||||
public AggMarkdownDocument(Uri baseUri)
|
||||
{
|
||||
this.BaseUri = baseUri;
|
||||
}
|
||||
|
||||
public string MatchingText { get; set; }
|
||||
|
||||
public Uri BaseUri { get; set; } = new Uri("https://www.matterhackers.com/");
|
||||
|
||||
public List<MarkdownDocumentLink> Children { get; private set; } = new List<MarkdownDocumentLink>();
|
||||
|
||||
public static AggMarkdownDocument Load(Uri uri)
|
||||
{
|
||||
var webClient = new WebClient();
|
||||
|
||||
string rawText = webClient.DownloadString(uri);
|
||||
|
||||
return new AggMarkdownDocument(uri)
|
||||
{
|
||||
Markdown = rawText,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Markdown to display.
|
||||
/// </summary>
|
||||
public string Markdown
|
||||
{
|
||||
get => _markDownText;
|
||||
set
|
||||
{
|
||||
if (_markDownText != value)
|
||||
{
|
||||
_markDownText = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Markdown pipeline to use.
|
||||
/// </summary>
|
||||
public MarkdownPipeline Pipeline
|
||||
{
|
||||
get => _pipeLine ?? DefaultPipeline;
|
||||
set
|
||||
{
|
||||
if (_pipeLine != value)
|
||||
{
|
||||
_pipeLine = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Parse(GuiWidget guiWidget = null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(this.Markdown))
|
||||
{
|
||||
MarkdownPipeline pipeline;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(MatchingText))
|
||||
{
|
||||
var builder = new MarkdownPipelineBuilder().UseSupportedExtensions();
|
||||
builder.InlineParsers.Add(new MatchingTextParser(MatchingText));
|
||||
|
||||
pipeline = builder.Build();
|
||||
}
|
||||
else
|
||||
{
|
||||
pipeline = Pipeline;
|
||||
}
|
||||
|
||||
var rootWidget = guiWidget ?? new GuiWidget();
|
||||
|
||||
var renderer = new AggRenderer(rootWidget)
|
||||
{
|
||||
BaseUri = this.BaseUri,
|
||||
ChildLinks = new List<MarkdownDocumentLink>()
|
||||
};
|
||||
|
||||
pipeline.Setup(renderer);
|
||||
|
||||
var document = Markdig.Markdown.Parse(this.Markdown, pipeline);
|
||||
|
||||
renderer.Render(document);
|
||||
|
||||
this.Children = renderer.ChildLinks;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
Copyright(c) 2019, Lars Brubaker, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using Markdig.Renderers.Agg.Inlines;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.MatterControl;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
public class AggMatchingTextRenderer : AggObjectRenderer<MatchingTextInline>
|
||||
{
|
||||
private ThemeConfig theme;
|
||||
|
||||
public AggMatchingTextRenderer(ThemeConfig theme)
|
||||
{
|
||||
this.theme = theme;
|
||||
}
|
||||
|
||||
protected override void Write(AggRenderer renderer, MatchingTextInline obj)
|
||||
{
|
||||
renderer.Push(new CodeInlineX(theme)
|
||||
{
|
||||
BackgroundColor = theme.AccentMimimalOverlay
|
||||
});
|
||||
renderer.WriteText(obj.MatchingText);
|
||||
renderer.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
// Copyright (c) 2016-2017 Nicolas Musset. All rights reserved.
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using Markdig.Syntax;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class for Agg rendering <see cref="Block"/> and <see cref="Markdig.Syntax.Inlines.Inline"/> Markdown objects.
|
||||
/// </summary>
|
||||
/// <typeparam name="TObject">The type of the object.</typeparam>
|
||||
/// <seealso cref="Markdig.Renderers.IMarkdownObjectRenderer" />
|
||||
public abstract class AggObjectRenderer<TObject> : MarkdownObjectRenderer<AggRenderer, TObject>
|
||||
where TObject : MarkdownObject
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
// Copyright (c) 2016-2017 Nicolas Musset. All rights reserved.
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using Markdig.Syntax;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.UI;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
public class AutoFit : GuiWidget
|
||||
{
|
||||
public AutoFit()
|
||||
{
|
||||
this.HAnchor = HAnchor.Fit | HAnchor.Left;
|
||||
this.VAnchor = VAnchor.Fit;
|
||||
}
|
||||
}
|
||||
|
||||
public class ParagraphX : FlowLeftRightWithWrapping, IHardBreak
|
||||
{
|
||||
public ParagraphX(bool bottomMargin)
|
||||
{
|
||||
// Adding HAnchor and initial fixed width properties to resolve excess vertical whitespace added during collapse to width 0
|
||||
//
|
||||
// TODO: Revise impact to FlowLeftRightWithWrapping
|
||||
this.HAnchor = HAnchor.Stretch;
|
||||
this.Width = 5000;
|
||||
if (bottomMargin)
|
||||
{
|
||||
Margin = new BorderDouble(0, 0, 0, 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//public class ParagraphRenderer :
|
||||
public class AggParagraphRenderer : AggObjectRenderer<ParagraphBlock>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
protected override void Write(AggRenderer renderer, ParagraphBlock obj)
|
||||
{
|
||||
var bottomMargin = false;
|
||||
if (obj.Parent is MarkdownDocument document
|
||||
&& obj.Parent.Count > 1
|
||||
&& obj.Line != 0)
|
||||
{
|
||||
bottomMargin = true;
|
||||
}
|
||||
|
||||
var paragraph = new ParagraphX(bottomMargin)
|
||||
{
|
||||
RowMargin = 0,
|
||||
RowPadding = 3
|
||||
};
|
||||
|
||||
renderer.Push(paragraph);
|
||||
renderer.WriteLeafInline(obj);
|
||||
renderer.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
// Copyright (c) 2016-2017 Nicolas Musset. All rights reserved.
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using Markdig.Syntax;
|
||||
using MatterHackers.Agg.UI;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
public class QuoteBlockX : AutoFit{ }
|
||||
|
||||
public class AggQuoteBlockRenderer : AggObjectRenderer<QuoteBlock>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
protected override void Write(AggRenderer renderer, QuoteBlock obj)
|
||||
{
|
||||
// var section = new Section();
|
||||
|
||||
renderer.Push(new QuoteBlockX()); // section);
|
||||
renderer.WriteChildren(obj);
|
||||
//section.SetResourceReference(FrameworkContentElement.StyleProperty, Styles.QuoteBlockStyleKey);
|
||||
renderer.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,253 +0,0 @@
|
|||
// Copyright (c) 2016-2017 Nicolas Musset. All rights reserved.
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Markdig.Agg;
|
||||
using Markdig.Helpers;
|
||||
using Markdig.Renderers.Agg;
|
||||
using Markdig.Renderers.Agg.Inlines;
|
||||
using Markdig.Syntax;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.MatterControl;
|
||||
|
||||
namespace Markdig.Renderers
|
||||
{
|
||||
public class TextWordX : TextWidget
|
||||
{
|
||||
public TextWordX(ThemeConfig theme)
|
||||
: base("", pointSize: 10, textColor: theme.TextColor)
|
||||
{
|
||||
this.AutoExpandBoundsToText = true;
|
||||
}
|
||||
}
|
||||
|
||||
public class TextSpaceX : TextWidget, ISkipIfFirst
|
||||
{
|
||||
public TextSpaceX(ThemeConfig theme)
|
||||
: base("", pointSize: 10, textColor: theme.TextColor)
|
||||
{
|
||||
this.AutoExpandBoundsToText = true;
|
||||
}
|
||||
}
|
||||
|
||||
public class LineBreakX : GuiWidget, IHardBreak
|
||||
{
|
||||
public LineBreakX()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Agg renderer for a Markdown <see cref="AggMarkdownDocument"/> object.
|
||||
/// </summary>
|
||||
/// <seealso cref="RendererBase" />
|
||||
public class AggRenderer : RendererBase
|
||||
{
|
||||
private readonly Stack<GuiWidget> stack = new Stack<GuiWidget>();
|
||||
private char[] buffer;
|
||||
private ThemeConfig theme;
|
||||
|
||||
public GuiWidget RootWidget { get; }
|
||||
|
||||
public Uri BaseUri { get; set; } = new Uri("https://www.matterhackers.com/");
|
||||
|
||||
public List<MarkdownDocumentLink> ChildLinks { get; internal set; }
|
||||
|
||||
public AggRenderer(ThemeConfig theme)
|
||||
{
|
||||
this.theme = theme;
|
||||
}
|
||||
|
||||
public AggRenderer(GuiWidget rootWidget)
|
||||
{
|
||||
this.theme = ApplicationController.Instance.Theme;
|
||||
|
||||
buffer = new char[1024];
|
||||
RootWidget = rootWidget;
|
||||
|
||||
stack.Push(rootWidget);
|
||||
|
||||
// Default block renderers
|
||||
ObjectRenderers.Add(new AggCodeBlockRenderer(theme));
|
||||
ObjectRenderers.Add(new AggListRenderer(theme));
|
||||
ObjectRenderers.Add(new AggHeadingRenderer());
|
||||
ObjectRenderers.Add(new AggParagraphRenderer());
|
||||
ObjectRenderers.Add(new AggQuoteBlockRenderer());
|
||||
ObjectRenderers.Add(new AggThematicBreakRenderer());
|
||||
|
||||
// Default inline renderers
|
||||
ObjectRenderers.Add(new AggAutolinkInlineRenderer());
|
||||
ObjectRenderers.Add(new AggCodeInlineRenderer(theme));
|
||||
ObjectRenderers.Add(new AggDelimiterInlineRenderer());
|
||||
ObjectRenderers.Add(new AggEmphasisInlineRenderer());
|
||||
ObjectRenderers.Add(new AggLineBreakInlineRenderer());
|
||||
ObjectRenderers.Add(new AggLinkInlineRenderer());
|
||||
ObjectRenderers.Add(new AggLiteralInlineRenderer());
|
||||
|
||||
ObjectRenderers.Add(new AggMatchingTextRenderer(theme));
|
||||
|
||||
// Extension renderers
|
||||
ObjectRenderers.Add(new AggTableRenderer());
|
||||
//ObjectRenderers.Add(new AggTaskListRenderer());
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override object Render(MarkdownObject markdownObject)
|
||||
{
|
||||
Write(markdownObject);
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
// TODO: investigate why this is required, layout should have already done this
|
||||
// but it didn't. markdown that looks like the following will not layout correctly without this
|
||||
// string badLayoutMarkdown = "I [s]()\n\nT";
|
||||
if (RootWidget?.Parent?.Parent != null)
|
||||
{
|
||||
RootWidget.Parent.Parent.Width = RootWidget.Parent.Parent.Width - 1;
|
||||
}
|
||||
});
|
||||
return RootWidget;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the inlines of a leaf inline.
|
||||
/// </summary>
|
||||
/// <param name="leafBlock">The leaf block.</param>
|
||||
/// <returns>This instance</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteLeafInline(LeafBlock leafBlock)
|
||||
{
|
||||
if (leafBlock == null) throw new ArgumentNullException(nameof(leafBlock));
|
||||
var inline = (Syntax.Inlines.Inline)leafBlock.Inline;
|
||||
while (inline != null)
|
||||
{
|
||||
Write(inline);
|
||||
inline = inline.NextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the lines of a <see cref="LeafBlock"/>
|
||||
/// </summary>
|
||||
/// <param name="leafBlock">The leaf block.</param>
|
||||
public void WriteLeafRawLines(LeafBlock leafBlock)
|
||||
{
|
||||
if (leafBlock == null) throw new ArgumentNullException(nameof(leafBlock));
|
||||
if (leafBlock.Lines.Lines != null)
|
||||
{
|
||||
var lines = leafBlock.Lines;
|
||||
var slices = lines.Lines;
|
||||
for (var i = 0; i < lines.Count; i++)
|
||||
{
|
||||
if (i != 0)
|
||||
//if (stack.Peek() is FlowLayoutWidget)
|
||||
//{
|
||||
// this.Pop();
|
||||
// this.Push(new ParagraphX());
|
||||
//}
|
||||
WriteInline(new LineBreakX()); // new LineBreak());
|
||||
|
||||
WriteText(ref slices[i].Slice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void Push(GuiWidget o)
|
||||
{
|
||||
stack.Push(o);
|
||||
}
|
||||
|
||||
internal void Pop()
|
||||
{
|
||||
var popped = stack.Pop();
|
||||
|
||||
if (stack.Count > 0)
|
||||
{
|
||||
var top = stack.Peek();
|
||||
top.AddChild(popped);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteBlock(GuiWidget block)
|
||||
{
|
||||
stack.Peek().AddChild(block);
|
||||
}
|
||||
|
||||
internal void WriteInline(GuiWidget inline)
|
||||
{
|
||||
AddInline(stack.Peek(), inline);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal void WriteText(ref StringSlice slice)
|
||||
{
|
||||
if (slice.Start > slice.End)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WriteText(slice.Text, slice.Start, slice.Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal void WriteText(string text)
|
||||
{
|
||||
var words = text.Split(' ');
|
||||
bool first = true;
|
||||
|
||||
foreach (var word in words)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
WriteInline(new TextSpaceX(theme)
|
||||
{
|
||||
Text = " "
|
||||
});
|
||||
}
|
||||
|
||||
if (word.Length > 0)
|
||||
{
|
||||
WriteInline(new TextWordX(theme)
|
||||
{
|
||||
Text = word
|
||||
});
|
||||
}
|
||||
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteText(string text, int offset, int length)
|
||||
{
|
||||
if (text == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (offset == 0 && text.Length == length)
|
||||
{
|
||||
WriteText(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (length > buffer.Length)
|
||||
{
|
||||
buffer = text.ToCharArray();
|
||||
WriteText(new string(buffer, offset, length));
|
||||
}
|
||||
else
|
||||
{
|
||||
text.CopyTo(offset, buffer, 0, length);
|
||||
WriteText(new string(buffer, 0, length));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddInline(GuiWidget parent, GuiWidget inline)
|
||||
{
|
||||
parent.AddChild(inline);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
// Copyright (c) 2016-2017 Nicolas Musset. All rights reserved.
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using Markdig.Syntax;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
public class ThematicBreakX : AutoFit{ }
|
||||
|
||||
public class AggThematicBreakRenderer : AggObjectRenderer<ThematicBreakBlock>
|
||||
{
|
||||
protected override void Write(AggRenderer renderer, ThematicBreakBlock obj)
|
||||
{
|
||||
//var line = new System.Windows.Shapes.Line { X2 = 1 };
|
||||
//line.SetResourceReference(FrameworkContentElement.StyleProperty, Styles.ThematicBreakStyleKey);
|
||||
|
||||
//var paragraph = new Paragraph
|
||||
//{
|
||||
// Inlines = { new InlineUIContainer(line) }
|
||||
//};
|
||||
|
||||
renderer.WriteBlock(new ThematicBreakX()); // paragraph);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
// Copyright (c) 2016-2017 Nicolas Musset. All rights reserved.
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using Markdig.Renderers.Agg.Inlines;
|
||||
using Markdig.Syntax;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.UI;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
public class HeadingRowX : FlowLeftRightWithWrapping
|
||||
{
|
||||
public HeadingRowX()
|
||||
{
|
||||
this.VAnchor = VAnchor.Fit;
|
||||
this.HAnchor = HAnchor.Stretch;
|
||||
this.Margin = new BorderDouble(3, 4, 0, 12);
|
||||
this.RowPadding = new BorderDouble(0, 3);
|
||||
}
|
||||
|
||||
public override GuiWidget AddChild(GuiWidget childToAdd, int indexInChildrenList = -1)
|
||||
{
|
||||
if (childToAdd is TextWidget textWidget)
|
||||
{
|
||||
// textWidget.TextColor = new Color("#036ac3");
|
||||
textWidget.PointSize = 14;
|
||||
}
|
||||
else if (childToAdd is TextLinkX textLink)
|
||||
{
|
||||
foreach (var child in childToAdd.Children)
|
||||
{
|
||||
if (child is TextWidget childTextWidget)
|
||||
{
|
||||
childTextWidget.PointSize = 14;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return base.AddChild(childToAdd, indexInChildrenList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
// Copyright (c) 2016-2017 Nicolas Musset. All rights reserved.
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using Markdig.Syntax.Inlines;
|
||||
|
||||
namespace Markdig.Renderers.Agg.Inlines
|
||||
{
|
||||
public class AutoLinkInlineX : AutoFit{ }
|
||||
|
||||
/// <summary>
|
||||
/// A Agg renderer for a <see cref="AutolinkInline"/>.
|
||||
/// </summary>
|
||||
/// <seealso cref="Markdig.Renderers.Agg.AggObjectRenderer{Markdig.Syntax.Inlines.AutolinkInline}" />
|
||||
public class AggAutolinkInlineRenderer : AggObjectRenderer<AutolinkInline>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
protected override void Write(AggRenderer renderer, AutolinkInline link)
|
||||
{
|
||||
var url = link.Url;
|
||||
|
||||
if (!Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute))
|
||||
{
|
||||
url = "#";
|
||||
}
|
||||
|
||||
//var hyperlink = new Hyperlink
|
||||
//{
|
||||
// Command = Commands.Hyperlink,
|
||||
// CommandParameter = url,
|
||||
// NavigateUri = new Uri(url, UriKind.RelativeOrAbsolute),
|
||||
// ToolTip = url,
|
||||
//};
|
||||
|
||||
renderer.WriteInline(new AutoLinkInlineX());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
// Copyright (c) 2016-2017 Nicolas Musset. All rights reserved.
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using Markdig.Syntax.Inlines;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.MatterControl;
|
||||
|
||||
namespace Markdig.Renderers.Agg.Inlines
|
||||
{
|
||||
public class CodeInlineX : FlowLayoutWidget
|
||||
{
|
||||
private ThemeConfig theme;
|
||||
|
||||
public CodeInlineX(ThemeConfig theme)
|
||||
{
|
||||
this.theme = theme;
|
||||
this.HAnchor = HAnchor.Fit;
|
||||
this.VAnchor = VAnchor.Fit;
|
||||
this.Padding = 4;
|
||||
this.BackgroundColor = theme.MinimalShade;
|
||||
}
|
||||
|
||||
public override GuiWidget AddChild(GuiWidget childToAdd, int indexInChildrenList = -1)
|
||||
{
|
||||
return base.AddChild(childToAdd, indexInChildrenList);
|
||||
}
|
||||
}
|
||||
|
||||
public class AggCodeInlineRenderer : AggObjectRenderer<CodeInline>
|
||||
{
|
||||
private ThemeConfig theme;
|
||||
|
||||
public AggCodeInlineRenderer(ThemeConfig theme)
|
||||
{
|
||||
this.theme = theme;
|
||||
}
|
||||
|
||||
protected override void Write(AggRenderer renderer, CodeInline obj)
|
||||
{
|
||||
//var run = new Run(obj.Content);
|
||||
//run.SetResourceReference(FrameworkContentElement.StyleProperty, Styles.CodeStyleKey);
|
||||
|
||||
//renderer.WriteInline(new CodeInlineX());
|
||||
renderer.Push(new CodeInlineX(theme));
|
||||
renderer.WriteText(obj.Content);
|
||||
renderer.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright (c) 2016-2017 Nicolas Musset. All rights reserved.
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using Markdig.Syntax.Inlines;
|
||||
|
||||
namespace Markdig.Renderers.Agg.Inlines
|
||||
{
|
||||
public class DelimiterInlineX : AutoFit{ }
|
||||
|
||||
/// <summary>
|
||||
/// A Agg renderer for a <see cref="DelimiterInline"/>.
|
||||
/// </summary>
|
||||
/// <seealso cref="Markdig.Renderers.Agg.AggObjectRenderer{Markdig.Syntax.Inlines.DelimiterInline}" />
|
||||
public class AggDelimiterInlineRenderer : AggObjectRenderer<DelimiterInline>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
protected override void Write(AggRenderer renderer, DelimiterInline obj)
|
||||
{
|
||||
renderer.WriteText(obj.ToLiteral());
|
||||
renderer.WriteChildren(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
// Copyright (c) 2016-2017 Nicolas Musset. All rights reserved.
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using Markdig.Syntax.Inlines;
|
||||
using MatterHackers.Agg.UI;
|
||||
|
||||
namespace Markdig.Renderers.Agg.Inlines
|
||||
{
|
||||
public class EmphasisInlineX : FlowLayoutWidget, IWrapChildrenSeparatly
|
||||
{
|
||||
private char delimiter;
|
||||
|
||||
public EmphasisInlineX(char delimiter)
|
||||
{
|
||||
this.HAnchor = HAnchor.Fit;
|
||||
this.VAnchor = VAnchor.Fit;
|
||||
|
||||
this.delimiter = delimiter;
|
||||
}
|
||||
|
||||
public override GuiWidget AddChild(GuiWidget childToAdd, int indexInChildrenList = -1)
|
||||
{
|
||||
if (childToAdd is TextWidget textWidget)
|
||||
{
|
||||
|
||||
switch (delimiter)
|
||||
{
|
||||
case '~':
|
||||
textWidget.StrikeThrough = true;
|
||||
break;
|
||||
case '*':
|
||||
default:
|
||||
textWidget.Bold = true;
|
||||
break;
|
||||
|
||||
// case '_': Italic();
|
||||
// case '^': Styles.SuperscriptStyleKey
|
||||
// case '+': Styles.InsertedStyleKey
|
||||
// case '=': Styles.MarkedStyleKey
|
||||
}
|
||||
}
|
||||
|
||||
return base.AddChild(childToAdd, indexInChildrenList);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A Agg renderer for an <see cref="EmphasisInline"/>.
|
||||
/// </summary>
|
||||
/// <seealso cref="EmphasisInline" />
|
||||
public class AggEmphasisInlineRenderer : AggObjectRenderer<EmphasisInline>
|
||||
{
|
||||
protected override void Write(AggRenderer renderer, EmphasisInline obj)
|
||||
{
|
||||
//Span span = null;
|
||||
|
||||
//switch (obj.DelimiterChar)
|
||||
//{
|
||||
// case '*':
|
||||
// case '_':
|
||||
// span = obj.IsDouble ? (Span)new Bold() : new Italic();
|
||||
// break;
|
||||
// case '~':
|
||||
// span = new Span();
|
||||
// span.SetResourceReference(FrameworkContentElement.StyleProperty, obj.IsDouble ? Styles.StrikeThroughStyleKey : Styles.SubscriptStyleKey);
|
||||
// break;
|
||||
// case '^':
|
||||
// span = new Span();
|
||||
// span.SetResourceReference(FrameworkContentElement.StyleProperty, Styles.SuperscriptStyleKey);
|
||||
// break;
|
||||
// case '+':
|
||||
// span = new Span();
|
||||
// span.SetResourceReference(FrameworkContentElement.StyleProperty, Styles.InsertedStyleKey);
|
||||
// break;
|
||||
// case '=':
|
||||
// span = new Span();
|
||||
// span.SetResourceReference(FrameworkContentElement.StyleProperty, Styles.MarkedStyleKey);
|
||||
// break;
|
||||
//}
|
||||
|
||||
if (true) //span != null)
|
||||
{
|
||||
renderer.Push(new EmphasisInlineX(obj.DelimiterChar));
|
||||
renderer.WriteChildren(obj);
|
||||
renderer.Pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
renderer.WriteChildren(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
// Copyright (c) 2016-2017 Nicolas Musset. All rights reserved.
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using Markdig.Syntax.Inlines;
|
||||
using MatterHackers.Agg.UI;
|
||||
|
||||
namespace Markdig.Renderers.Agg.Inlines
|
||||
{
|
||||
public class LineBreakX : AutoFit, IHardBreak { }
|
||||
public class LineBreakSoftX : AutoFit{ }
|
||||
|
||||
/// <summary>
|
||||
/// A Agg renderer for a <see cref="LineBreakInline"/>.
|
||||
/// </summary>
|
||||
/// <seealso cref="Markdig.Renderers.Agg.AggObjectRenderer{Markdig.Syntax.Inlines.LineBreakInline}" />
|
||||
public class AggLineBreakInlineRenderer : AggObjectRenderer<LineBreakInline>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
protected override void Write(AggRenderer renderer, LineBreakInline obj)
|
||||
{
|
||||
if (obj.IsHard)
|
||||
{
|
||||
renderer.WriteInline(new LineBreakX()); // new LineBreak());
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Remove soft - use WriteText
|
||||
renderer.WriteInline(new LineBreakSoftX()); // new LineBreak());
|
||||
|
||||
// Soft line break.
|
||||
renderer.WriteText(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,297 +0,0 @@
|
|||
// Copyright (c) 2016-2017 Nicolas Musset. All rights reserved.
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using Markdig.Agg;
|
||||
using Markdig.Syntax.Inlines;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Image;
|
||||
using MatterHackers.Agg.Platform;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.MatterControl;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace Markdig.Renderers.Agg.Inlines
|
||||
{
|
||||
public class TextLinkX : FlowLayoutWidget
|
||||
{
|
||||
private LinkInline linkInline;
|
||||
private string url;
|
||||
private AggRenderer aggRenderer;
|
||||
|
||||
public TextLinkX(AggRenderer renderer, string url, LinkInline linkInline)
|
||||
{
|
||||
this.HAnchor = HAnchor.Fit;
|
||||
this.VAnchor = VAnchor.Fit;
|
||||
this.Cursor = Cursors.Hand;
|
||||
this.linkInline = linkInline;
|
||||
this.url = url;
|
||||
this.aggRenderer = renderer;
|
||||
}
|
||||
|
||||
protected override void OnClick(MouseEventArgs mouseEvent)
|
||||
{
|
||||
if (linkInline.Url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ApplicationController.LaunchBrowser(linkInline.Url);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (aggRenderer.RootWidget.Parents<MarkdownWidget>().FirstOrDefault() is MarkdownWidget markdownWidget)
|
||||
{
|
||||
markdownWidget.LoadUri(new Uri(url));
|
||||
}
|
||||
}
|
||||
|
||||
base.OnClick(mouseEvent);
|
||||
}
|
||||
|
||||
public override GuiWidget AddChild(GuiWidget childToAdd, int indexInChildrenList = -1)
|
||||
{
|
||||
if (childToAdd is TextWidget textWidget)
|
||||
{
|
||||
// Underline TextWidget children of TextLink nodes
|
||||
textWidget.Underline = true;
|
||||
}
|
||||
|
||||
// Allow link parent to own mouse events
|
||||
childToAdd.Selectable = false;
|
||||
|
||||
return base.AddChild(childToAdd, indexInChildrenList);
|
||||
}
|
||||
}
|
||||
|
||||
public class ImageLinkSimpleX : FlowLayoutWidget
|
||||
{
|
||||
private static ImageBuffer icon = StaticData.Instance.LoadIcon("internet.png", 16, 16);
|
||||
|
||||
public ImageLinkSimpleX(AggRenderer renderer, string imageUrl, string linkUrl = null)
|
||||
{
|
||||
this.HAnchor = HAnchor.Stretch;
|
||||
this.VAnchor = VAnchor.Fit;
|
||||
this.Selectable = false;
|
||||
|
||||
this.ImageUrl = imageUrl;
|
||||
this.LinkUrl = linkUrl;
|
||||
|
||||
this.aggRenderer = renderer;
|
||||
|
||||
if (linkUrl != null)
|
||||
{
|
||||
this.Selectable = true;
|
||||
}
|
||||
|
||||
sequenceWidget = new ResponsiveImageSequenceWidget(new ImageSequence(icon))
|
||||
{
|
||||
Cursor = Cursors.Hand,
|
||||
};
|
||||
|
||||
sequenceWidget.MaximumSizeChanged += (s, e) =>
|
||||
{
|
||||
this.MinStretchOrFitHorizontal(20 * GuiWidget.DeviceScale, sequenceWidget.MaximumSize.X);
|
||||
if (aggRenderer.RootWidget.Parents<MarkdownWidget>().FirstOrDefault() is MarkdownWidget markdownWidget)
|
||||
{
|
||||
markdownWidget.Width += 1;
|
||||
}
|
||||
};
|
||||
|
||||
sequenceWidget.Click += SequenceWidget_Click;
|
||||
|
||||
this.AddChild(sequenceWidget);
|
||||
}
|
||||
|
||||
private void SequenceWidget_Click(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (this.LinkUrl != null)
|
||||
{
|
||||
if (LinkUrl.StartsWith("http", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ApplicationController.LaunchBrowser(LinkUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
if (aggRenderer.RootWidget.Parents<MarkdownWidget>().FirstOrDefault() is MarkdownWidget markdownWidget)
|
||||
{
|
||||
markdownWidget.LoadUri(new Uri(LinkUrl));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDraw(Graphics2D graphics2D)
|
||||
{
|
||||
if (!hasBeenLoaded)
|
||||
{
|
||||
if (ImageUrl.StartsWith("http"))
|
||||
{
|
||||
WebCache.RetrieveImageSquenceAsync(sequenceWidget.ImageSequence, ImageUrl);
|
||||
}
|
||||
|
||||
hasBeenLoaded = true;
|
||||
}
|
||||
|
||||
base.OnDraw(graphics2D);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets this control to Stretch and all direct parent FlowLayoutWidgets to Stretch, it then ensures
|
||||
/// this and all direct parent FlowLayouts have a max width of the contents of this.
|
||||
/// </summary>
|
||||
/// <param name="absoluteMinWidth">The minimum size will be set to the larger of the existing minimum size or this value.</param>
|
||||
/// <param name="absoluteMaxWidth">The maximum size will be set to this value.</param>
|
||||
private void MinStretchOrFitHorizontal(double absoluteMinWidth, double absoluteMaxWidth)
|
||||
{
|
||||
this.HAnchor = HAnchor.Stretch;
|
||||
|
||||
MinimumSize = new Vector2(Math.Max(absoluteMinWidth, MinimumSize.X), MinimumSize.Y);
|
||||
MaximumSize = new Vector2(absoluteMaxWidth, MaximumSize.Y);
|
||||
}
|
||||
|
||||
public string ImageUrl { get; }
|
||||
|
||||
private string LinkUrl { get; }
|
||||
|
||||
private AggRenderer aggRenderer;
|
||||
private bool hasBeenLoaded;
|
||||
private ResponsiveImageSequenceWidget sequenceWidget;
|
||||
}
|
||||
|
||||
public class ImageLinkAdvancedX : FlowLayoutWidget
|
||||
{
|
||||
private static HttpClient client = new HttpClient();
|
||||
|
||||
private static ImageBuffer icon = StaticData.Instance.LoadIcon("internet.png", 16, 16);
|
||||
|
||||
public string Url { get; }
|
||||
|
||||
public ImageLinkAdvancedX(string url)
|
||||
{
|
||||
HAnchor = HAnchor.Fit;
|
||||
VAnchor = VAnchor.Fit;
|
||||
this.Url = url;
|
||||
|
||||
var imageBuffer = new ImageBuffer(icon);
|
||||
var imageWidget = new ImageWidget(imageBuffer);
|
||||
|
||||
this.AddChild(imageWidget);
|
||||
|
||||
try
|
||||
{
|
||||
if (url.StartsWith("http"))
|
||||
{
|
||||
client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead).ContinueWith(task =>
|
||||
{
|
||||
var response = task.Result;
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
response.Content.ReadAsStreamAsync().ContinueWith(streamTask =>
|
||||
{
|
||||
// response.Headers.TryGetValues("", s[""] == "" ||
|
||||
if (string.Equals(Path.GetExtension(url), ".svg", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Load svg into SvgWidget, swap for ImageWidget
|
||||
try
|
||||
{
|
||||
var svgWidget = new SvgWidget(streamTask.Result, 1)
|
||||
{
|
||||
Border = 1,
|
||||
BorderColor = Color.YellowGreen
|
||||
};
|
||||
|
||||
this.ReplaceChild(imageWidget, svgWidget);
|
||||
}
|
||||
catch (Exception svgEx)
|
||||
{
|
||||
Debug.WriteLine("Error loading svg: {0} :: {1}", url, svgEx.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Load img
|
||||
if (!ImageIO.LoadImageData(streamTask.Result, imageBuffer))
|
||||
{
|
||||
Debug.WriteLine("Error loading image: " + url);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A Agg renderer for a <see cref="LinkInline"/>.
|
||||
/// </summary>
|
||||
/// <seealso cref="Markdig.Renderers.Agg.AggObjectRenderer{Markdig.Syntax.Inlines.LinkInline}" />
|
||||
public class AggLinkInlineRenderer : AggObjectRenderer<LinkInline>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
protected override void Write(AggRenderer renderer, LinkInline link)
|
||||
{
|
||||
var url = link.GetDynamicUrl != null ? link.GetDynamicUrl() ?? link.Url : link.Url;
|
||||
|
||||
if (!Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute))
|
||||
{
|
||||
url = "#";
|
||||
}
|
||||
|
||||
if (!url.StartsWith("http"))
|
||||
{
|
||||
var pageID = url;
|
||||
|
||||
url = new Uri(renderer.BaseUri, url).AbsoluteUri;
|
||||
|
||||
renderer.ChildLinks.Add(new MarkdownDocumentLink()
|
||||
{
|
||||
Uri = new Uri(url),
|
||||
LinkInline = link,
|
||||
PageID = pageID
|
||||
});
|
||||
}
|
||||
|
||||
if (link.IsImage)
|
||||
{
|
||||
if (link.Parent is LinkInline linkInLine)
|
||||
{
|
||||
renderer.WriteInline(new ImageLinkSimpleX(renderer, url, linkInLine.Url));
|
||||
}
|
||||
else
|
||||
{
|
||||
renderer.WriteInline(new ImageLinkSimpleX(renderer, url));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (link.FirstChild is LinkInline linkInLine
|
||||
&& linkInLine.IsImage)
|
||||
{
|
||||
renderer.WriteChildren(link);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderer.Push(new TextLinkX(renderer, url, link));
|
||||
renderer.WriteChildren(link);
|
||||
renderer.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright (c) 2016-2017 Nicolas Musset. All rights reserved.
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using Markdig.Syntax.Inlines;
|
||||
|
||||
namespace Markdig.Renderers.Agg.Inlines
|
||||
{
|
||||
/// <summary>
|
||||
/// A Agg renderer for a <see cref="LiteralInline"/>.
|
||||
/// </summary>
|
||||
/// <seealso cref="Markdig.Renderers.Agg.AggObjectRenderer{Markdig.Syntax.Inlines.LiteralInline}" />
|
||||
public class AggLiteralInlineRenderer : AggObjectRenderer<LiteralInline>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
protected override void Write(AggRenderer renderer, LiteralInline obj)
|
||||
{
|
||||
if (obj.Content.IsEmpty)
|
||||
return;
|
||||
|
||||
renderer.WriteText(ref obj.Content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
Copyright(c) 2018, Lars Brubaker, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Markdig.Syntax.Inlines;
|
||||
|
||||
namespace Markdig.Agg
|
||||
{
|
||||
public class MarkdownDocumentLink
|
||||
{
|
||||
public Uri Uri { get; internal set; }
|
||||
|
||||
public LinkInline LinkInline { get; internal set; }
|
||||
|
||||
public string PageID { get; internal set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
// Copyright (c) 2016-2017 Nicolas Musset. All rights reserved.
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using System;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Markdig.Agg
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extension methods for <see cref="MarkdownPipeline"/> to enable several Markdown extensions.
|
||||
/// </summary>
|
||||
public static class MarkdownExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Uses all extensions supported by <c>Markdig.Agg</c>.
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The pipeline.</param>
|
||||
/// <returns>The modified pipeline</returns>
|
||||
public static MarkdownPipelineBuilder UseSupportedExtensions(this MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
if (pipeline == null) throw new ArgumentNullException(nameof(pipeline));
|
||||
return pipeline
|
||||
.UseEmphasisExtras()
|
||||
.UseGridTables()
|
||||
.UsePipeTables()
|
||||
.UseTaskLists()
|
||||
.UseAutoLinks();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,181 +0,0 @@
|
|||
/*
|
||||
Copyright(c) 2018, Lars Brubaker, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl;
|
||||
using MatterHackers.MatterControl.CustomWidgets;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace Markdig.Agg
|
||||
{
|
||||
public class MarkdownWidget : ScrollableWidget
|
||||
{
|
||||
private string _markDownText = null;
|
||||
private FlowLayoutWidget contentPanel;
|
||||
|
||||
private AggMarkdownDocument markdownDocument;
|
||||
private ThemeConfig theme;
|
||||
|
||||
public MarkdownWidget(ThemeConfig theme, Uri contentUri, bool scrollContent = true)
|
||||
: this(theme, scrollContent)
|
||||
{
|
||||
markdownDocument.BaseUri = contentUri;
|
||||
|
||||
this.LoadUri(contentUri);
|
||||
}
|
||||
|
||||
public MarkdownWidget(ThemeConfig theme, bool scrollContent = true)
|
||||
: base(scrollContent)
|
||||
{
|
||||
markdownDocument = new AggMarkdownDocument();
|
||||
|
||||
this.theme = theme;
|
||||
this.HAnchor = HAnchor.Stretch;
|
||||
this.ScrollArea.HAnchor = HAnchor.Stretch;
|
||||
this.ScrollArea.VAnchor = VAnchor.Fit;
|
||||
if (scrollContent)
|
||||
{
|
||||
this.VAnchor = VAnchor.Stretch;
|
||||
this.ScrollArea.Margin = new BorderDouble(0, 0, 15, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.VAnchor = VAnchor.Fit;
|
||||
}
|
||||
|
||||
var lastScroll = this.TopLeftOffset;
|
||||
this.ScrollPositionChanged += (s, e) =>
|
||||
{
|
||||
lastScroll = TopLeftOffset;
|
||||
};
|
||||
|
||||
// make sure as the scrolling area changes height we maintain our current scroll position
|
||||
this.ScrollArea.BoundsChanged += (s, e) =>
|
||||
{
|
||||
TopLeftOffset = lastScroll;
|
||||
};
|
||||
|
||||
contentPanel = new FlowLayoutWidget(FlowDirection.TopToBottom)
|
||||
{
|
||||
HAnchor = HAnchor.Stretch,
|
||||
VAnchor = VAnchor.Fit
|
||||
};
|
||||
|
||||
this.AddChild(contentPanel);
|
||||
}
|
||||
|
||||
public override void OnSizeChanged(EventArgs e)
|
||||
{
|
||||
contentPanel.Height = contentPanel.Height - 1;
|
||||
|
||||
base.OnSizeChanged(e);
|
||||
}
|
||||
|
||||
public void LoadUri(Uri uri, HelpArticle sourceArticle = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var webClient = new WebClient();
|
||||
markdownDocument.BaseUri = uri;
|
||||
|
||||
this.sourceArticle = sourceArticle;
|
||||
|
||||
try
|
||||
{
|
||||
// put in controls from the feed that show relevant printer information
|
||||
WebCache.RetrieveText(uri.ToString(),
|
||||
(markDown) =>
|
||||
{
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
this.Markdown = markDown;
|
||||
});
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// On error, revert to empty content
|
||||
this.Markdown = "";
|
||||
}
|
||||
}
|
||||
|
||||
private HelpArticle sourceArticle;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the markdown to display.
|
||||
/// </summary>
|
||||
public string Markdown
|
||||
{
|
||||
get => _markDownText;
|
||||
set
|
||||
{
|
||||
if (_markDownText != value)
|
||||
{
|
||||
_markDownText = value;
|
||||
|
||||
// Empty self
|
||||
contentPanel.CloseChildren();
|
||||
|
||||
this.Width = 10;
|
||||
this.ScrollPositionFromTop = Vector2.Zero;
|
||||
|
||||
// Add header/edit button for HelpArticle pages
|
||||
if (sourceArticle != null)
|
||||
{
|
||||
var helpArticleHeader = new HelpArticleHeader(sourceArticle, theme, boldFont: true, pointSize: theme.FontSize14, editToolTipText: "Edit Page".Localize());
|
||||
helpArticleHeader.EditClicked += (s, e) =>
|
||||
{
|
||||
ApplicationController.LaunchBrowser($"https://github.com/MatterHackers/MatterControl-Help/blob/master/input/{sourceArticle.Path}");
|
||||
// ApplicationController.LaunchBrowser($"https://github.com/MatterHackers/MatterControl-Docs/tree/master/docs/Help/{sourceArticle.Path}");
|
||||
};
|
||||
contentPanel.AddChild(helpArticleHeader);
|
||||
}
|
||||
|
||||
// Parse and reconstruct
|
||||
markdownDocument.Markdown = value;
|
||||
markdownDocument.Parse(contentPanel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string MatchingText
|
||||
{
|
||||
get => markdownDocument.MatchingText;
|
||||
set => markdownDocument.MatchingText = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
Copyright(c) 2019, Lars Brubaker, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using Markdig.Syntax.Inlines;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
public class MatchingTextInline : LeafInline
|
||||
{
|
||||
public string MatchingText { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
Copyright(c) 2019, Lars Brubaker, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using Markdig.Helpers;
|
||||
using Markdig.Parsers;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
public class MatchingTextParser : InlineParser
|
||||
{
|
||||
private string matchingText;
|
||||
|
||||
public MatchingTextParser(string matchingText)
|
||||
{
|
||||
this.OpeningCharacters = new[] { matchingText[0] };
|
||||
this.matchingText = matchingText.ToLower();
|
||||
}
|
||||
|
||||
public override bool Match(InlineProcessor processor, ref StringSlice slice)
|
||||
{
|
||||
bool matchFound = slice.MatchLowercase(matchingText);
|
||||
|
||||
if (matchFound)
|
||||
{
|
||||
int inlineStart = processor.GetSourcePosition(slice.Start, out int line, out int column);
|
||||
|
||||
processor.Inline = new MatchingTextInline
|
||||
{
|
||||
Span =
|
||||
{
|
||||
Start = inlineStart,
|
||||
End = inlineStart + matchingText.Length
|
||||
},
|
||||
Line = line,
|
||||
Column = column,
|
||||
MatchingText = matchingText
|
||||
};
|
||||
|
||||
slice.Start = inlineStart + matchingText.Length;
|
||||
}
|
||||
|
||||
return matchFound;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
// Copyright (c) Nicolas Musset. All rights reserved.
|
||||
// Copyright (c) 2022, John Lewin
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Markdig.Extensions.Tables;
|
||||
using MatterHackers.Agg.UI;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
public class AggTable : FlowLayoutWidget
|
||||
{
|
||||
|
||||
public List<AggTableColumn> Columns { get; }
|
||||
|
||||
public List<AggTableRow> Rows { get; }
|
||||
|
||||
public AggTable(Table table) : base(FlowDirection.TopToBottom)
|
||||
{
|
||||
this.Columns = table.ColumnDefinitions.Select(c => new AggTableColumn(c)).ToList();
|
||||
}
|
||||
|
||||
public override void OnLayout(LayoutEventArgs layoutEventArgs)
|
||||
{
|
||||
if (this.Columns?.Count > 0)
|
||||
{
|
||||
foreach (var column in this.Columns)
|
||||
{
|
||||
column.SetCellWidths();
|
||||
}
|
||||
}
|
||||
|
||||
base.OnLayout(layoutEventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
// Copyright (c) 2016-2017 Nicolas Musset. All rights reserved.
|
||||
// Copyright (c) 2022, John Lewin
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using MatterHackers.Agg.UI;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
// Parent container to restrict bounds
|
||||
public class AggTableCell : GuiWidget
|
||||
{
|
||||
public AggTableCell()
|
||||
{
|
||||
// TODO: drive from column once width calculation is performed
|
||||
Width = 300;
|
||||
|
||||
Height = 25;
|
||||
|
||||
// Use event rather than OnLayout as it only seems to produce the desired effect
|
||||
this.Layout += AggTableCell_Layout;
|
||||
}
|
||||
|
||||
// TODO: Investigate. Without this solution, child content is wrapped and clipped, leaving only the last text block visible
|
||||
private void AggTableCell_Layout(object sender, EventArgs e)
|
||||
{
|
||||
Console.WriteLine(Parent?.Name);
|
||||
if (this.Children.Count > 0 && this.Children.First() is FlowLeftRightWithWrapping wrappedChild
|
||||
&& wrappedChild.Height != this.Height)
|
||||
{
|
||||
//using (this.LayoutLock())
|
||||
{
|
||||
//// Set height to ensure bounds grow to content after reflow
|
||||
//this.Height = wrappedChild.Height;
|
||||
|
||||
if (this.Parent is AggTableRow parentRow)
|
||||
{
|
||||
parentRow.CellHeightChanged(wrappedChild.Height);
|
||||
}
|
||||
}
|
||||
|
||||
this.ContentWidth = wrappedChild.ContentWidth;
|
||||
}
|
||||
}
|
||||
|
||||
public double ContentWidth { get; private set; }
|
||||
|
||||
// TODO: Use to align child content when bounds are less than current
|
||||
public HAnchor FlowHAnchor { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
// Copyright (c) Nicolas Musset. All rights reserved.
|
||||
// Copyright (c) 2022, John Lewin
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Markdig.Extensions.Tables;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
public class AggTableColumn
|
||||
{
|
||||
private TableColumnDefinition ColumnDefinition;
|
||||
|
||||
public AggTableColumn(TableColumnDefinition definition)
|
||||
{
|
||||
this.ColumnDefinition = definition;
|
||||
}
|
||||
|
||||
public List<AggTableCell> Cells { get; } = new List<AggTableCell>();
|
||||
|
||||
public void SetCellWidths()
|
||||
{
|
||||
double cellPadding = 10;
|
||||
|
||||
if (this.Cells.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Column/cell width theortically is:
|
||||
//
|
||||
// Case A. Expanding to the maximum content width of cells in column to grow each
|
||||
// cell to a minimum value.
|
||||
//
|
||||
// Case B. Contracting when the aggregate column widths exceed the bounds
|
||||
// of the parent container.
|
||||
//
|
||||
// Case C. Distributing percentages across fixed bounds of the parent container
|
||||
//
|
||||
// Other cases...
|
||||
|
||||
// This block attempts to implement Case A by finding the max content width per cells in each column
|
||||
//
|
||||
// Collect max content widths from each cell in this column
|
||||
double maxCellWidth = this.Cells.Select(c => c.ContentWidth).Max() + cellPadding * 2;
|
||||
|
||||
// Apply max width to cells in this column
|
||||
foreach (var cell in this.Cells)
|
||||
{
|
||||
if (cell.Width != maxCellWidth)
|
||||
{
|
||||
cell.Width = maxCellWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
// Copyright (c) Nicolas Musset. All rights reserved.
|
||||
// Copyright (c) 2022, John Lewin
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using Markdig.Extensions.Tables;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.UI;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
public class AggTableRenderer : AggObjectRenderer<Table>
|
||||
{
|
||||
protected override void Write(AggRenderer renderer, Table mdTable)
|
||||
{
|
||||
if (renderer == null) throw new ArgumentNullException(nameof(renderer));
|
||||
if (mdTable == null) throw new ArgumentNullException(nameof(mdTable));
|
||||
|
||||
var aggTable = new AggTable(mdTable)
|
||||
{
|
||||
Margin = new BorderDouble(top: 12),
|
||||
};
|
||||
|
||||
renderer.Push(aggTable);
|
||||
|
||||
foreach (var rowObj in mdTable)
|
||||
{
|
||||
var mdRow = (TableRow)rowObj;
|
||||
|
||||
var aggRow = new AggTableRow()
|
||||
{
|
||||
IsHeadingRow = mdRow.IsHeader,
|
||||
};
|
||||
|
||||
renderer.Push(aggRow);
|
||||
|
||||
if (mdRow.IsHeader)
|
||||
{
|
||||
// Update to desired header row styling and/or move into AggTableRow for consistency
|
||||
aggRow.BackgroundColor = MatterHackers.MatterControl.AppContext.Theme.TabBarBackground;
|
||||
}
|
||||
|
||||
for (var i = 0; i < mdRow.Count; i++)
|
||||
{
|
||||
var mdCell = (TableCell)mdRow[i];
|
||||
|
||||
var aggCell = new AggTableCell();
|
||||
aggRow.Cells.Add(aggCell);
|
||||
|
||||
if (mdTable.ColumnDefinitions.Count > 0)
|
||||
{
|
||||
// Grab the column definition, or fall back to a default
|
||||
var columnIndex = mdCell.ColumnIndex < 0 || mdCell.ColumnIndex >= mdTable.ColumnDefinitions.Count
|
||||
? i
|
||||
: mdCell.ColumnIndex;
|
||||
columnIndex = columnIndex >= mdTable.ColumnDefinitions.Count ? mdTable.ColumnDefinitions.Count - 1 : columnIndex;
|
||||
|
||||
aggTable.Columns[columnIndex].Cells.Add(aggCell);
|
||||
|
||||
if (mdTable.ColumnDefinitions[columnIndex].Alignment.HasValue)
|
||||
{
|
||||
switch (mdTable.ColumnDefinitions[columnIndex].Alignment)
|
||||
{
|
||||
case TableColumnAlign.Center:
|
||||
aggCell.FlowHAnchor |= HAnchor.Center;
|
||||
break;
|
||||
case TableColumnAlign.Right:
|
||||
aggCell.FlowHAnchor |= HAnchor.Right;
|
||||
break;
|
||||
case TableColumnAlign.Left:
|
||||
aggCell.FlowHAnchor |= HAnchor.Left;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renderer.Push(aggCell);
|
||||
renderer.Write(mdCell);
|
||||
renderer.Pop();
|
||||
}
|
||||
|
||||
// Pop row
|
||||
renderer.Pop();
|
||||
}
|
||||
|
||||
// Pop table
|
||||
renderer.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
// Copyright (c) 2016-2017 Nicolas Musset. All rights reserved.
|
||||
// Copyright (c) 2022, John Lewin
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Markdig.Renderers.Agg.Inlines;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.UI;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
public class AggTableRow : FlowLayoutWidget
|
||||
{
|
||||
public AggTableRow()
|
||||
{
|
||||
this.Margin = new BorderDouble(10, 4);
|
||||
this.VAnchor = VAnchor.Absolute;
|
||||
this.Height = 25;
|
||||
}
|
||||
|
||||
public bool IsHeadingRow { get; set; }
|
||||
|
||||
public List<AggTableCell> Cells { get; } = new List<AggTableCell>();
|
||||
public double RowHeight { get; private set; }
|
||||
|
||||
// Override AddChild to push styles to child elements when table rows are resolved to the tree
|
||||
public override GuiWidget AddChild(GuiWidget childToAdd, int indexInChildrenList = -1)
|
||||
{
|
||||
if (childToAdd is TextWidget textWidget)
|
||||
{
|
||||
// textWidget.TextColor = new Color("#036ac3");
|
||||
if (this.IsHeadingRow)
|
||||
{
|
||||
textWidget.Bold = true;
|
||||
}
|
||||
}
|
||||
else if (childToAdd is TextLinkX textLink)
|
||||
{
|
||||
foreach (var childTextWidget in childToAdd.Children.OfType<TextWidget>())
|
||||
{
|
||||
if (this.IsHeadingRow)
|
||||
{
|
||||
childTextWidget.Bold = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return base.AddChild(childToAdd, indexInChildrenList);
|
||||
}
|
||||
|
||||
internal void CellHeightChanged(double newHeight)
|
||||
{
|
||||
double cellPadding = 2;
|
||||
double height = newHeight + 2 * cellPadding;
|
||||
|
||||
//double maxChildHeight = this.Cells.Select(c => c.Height).Max();
|
||||
|
||||
if (this.RowHeight != height)
|
||||
{
|
||||
foreach (var cell in this.Cells)
|
||||
{
|
||||
using (cell.LayoutLock())
|
||||
{
|
||||
cell.Height = height;
|
||||
}
|
||||
}
|
||||
|
||||
using (this.LayoutLock())
|
||||
{
|
||||
this.Height = this.RowHeight = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 39d47369081d0434eb7ae0610bc76b71c4e0c210
|
||||
Subproject commit 8d9c41fda05ae25a84ba5e3483255fb4b4f040b4
|
||||
Loading…
Add table
Add a link
Reference in a new issue