Implemented the markdown widget in agg

This commit is contained in:
Lars Brubaker 2022-10-10 17:10:25 -07:00
parent d416cef105
commit 4ac0b4da67
36 changed files with 22 additions and 2294 deletions

View file

@ -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" />

View file

@ -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;
@ -1137,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)
{

View file

@ -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; }
}
}

View file

@ -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
{

View file

@ -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; }
}
}
}

View file

@ -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" />

View file

@ -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
{

View file

@ -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();
}
}
}

View file

@ -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();
}
}
}

View file

@ -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();
}
}
}

View file

@ -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;
}
}
}
}

View file

@ -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();
}
}
}

View file

@ -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
{
}
}

View file

@ -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();
}
}
}

View file

@ -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();
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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());
}
}
}

View file

@ -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();
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -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(" ");
}
}
}
}

View file

@ -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();
}
}
}
}
}

View file

@ -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);
}
}
}

View file

@ -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; }
}
}

View file

@ -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();
}
}
}

View file

@ -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;
}
}
}

View file

@ -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; }
}
}

View file

@ -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;
}
}
}

View file

@ -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);
}
}
}

View file

@ -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; }
}
}

View file

@ -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;
}
}
}
}
}

View file

@ -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();
}
}
}

View file

@ -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 02de9c7a54a825dc2dde4335869ea1c8a5e39f67
Subproject commit 8d9c41fda05ae25a84ba5e3483255fb4b4f040b4