diff --git a/AboutPage/AboutPage.cs b/AboutPage/AboutPage.cs index a26034eea..c1c8969bd 100644 --- a/AboutPage/AboutPage.cs +++ b/AboutPage/AboutPage.cs @@ -36,11 +36,15 @@ using MatterHackers.Localizations; using MatterHackers.MatterControl.ContactForm; using MatterHackers.MatterControl.CustomWidgets; using MatterHackers.MatterControl.DataStorage; +using MatterHackers.MatterControl.HtmlParsing; namespace MatterHackers.MatterControl { public class AboutPage : GuiWidget { + static string htmlContent = null; + + GuiWidget htmlWidget; LinkButtonFactory linkButtonFactory = new LinkButtonFactory(); TextImageButtonFactory textImageButtonFactory = new TextImageButtonFactory(); RGBA_Bytes aboutTextColor = ActiveTheme.Instance.PrimaryTextColor; @@ -68,24 +72,91 @@ namespace MatterHackers.MatterControl customInfoTopToBottom.AddChild(new UpdateControl()); //AddMatterHackersInfo(customInfoTopToBottom); - WidgetFromHtml creator = new WidgetFromHtml(); + HtmlParser htmlParser = new HtmlParser(); - creator.AddMapping("translate", DoTranslate); - creator.AddMapping("toUpper", DoToUpper); - creator.AddMapping("versionNumber", GetVersionString); - creator.AddMapping("buildNumber", GetBuildString); - creator.AddMapping("linkButton", CreateLinkButton); - creator.AddMapping("centeredButton", CreateCenteredButton); + if (htmlContent == null) + { + string aboutHtmlFile = Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, "OEMSettings", "AboutPage.html"); + htmlContent = File.ReadAllText(aboutHtmlFile); + } + + htmlWidget = new FlowLayoutWidget(FlowDirection.TopToBottom); + htmlWidget.VAnchor = VAnchor.Max_FitToChildren_ParentHeight; + htmlWidget.HAnchor |= HAnchor.ParentCenter; - string aboutHtmlFile = Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, "OEMSettings", "AboutPage.html"); - string htmlContent = File.ReadAllText(aboutHtmlFile); - GuiWidget htmlWidget = creator.CreateWidget(htmlContent); + htmlParser.ParseHtml(htmlContent, AddContent, CloseContent); customInfoTopToBottom.AddChild(htmlWidget); this.AddChild(customInfoTopToBottom); } + FlowLayoutWidget currentRow; + private void AddContent(HtmlParser htmlParser, string htmlContent) + { + ElementState elementState = htmlParser.CurrentElementState; + switch (elementState.TypeName) + { + case "a": + break; + + case "table": + break; + + case "td": + case "span": + GuiWidget widgetToAdd; + + TextWidget content = new TextWidget(htmlContent, pointSize: elementState.PointSize, textColor: ActiveTheme.Instance.PrimaryTextColor); + widgetToAdd = content; + + currentRow.AddChild(widgetToAdd); + break; + + case "tr": + currentRow = new FlowLayoutWidget(); + if (elementState.HeightPercent == 100) + { + currentRow.VAnchor = VAnchor.ParentBottomTop; + } + if (elementState.Alignment == ElementState.AlignType.center) + { + currentRow.HAnchor |= HAnchor.ParentCenter; + } + break; + + default: + throw new NotImplementedException(); + } + } + + private void CloseContent(HtmlParser htmlParser, string htmlContent) + { + ElementState elementState = htmlParser.CurrentElementState; + switch (elementState.TypeName) + { + case "a": + break; + + case "table": + break; + + case "span": + break; + + case "tr": + htmlWidget.AddChild(currentRow); + currentRow = null; + break; + + case "td": + break; + + default: + throw new NotImplementedException(); + } + } + public string DoTranslate(string content) { throw new NotImplementedException(); diff --git a/AboutPage/HtmlParser.cs b/AboutPage/HtmlParser.cs new file mode 100644 index 000000000..522c40fea --- /dev/null +++ b/AboutPage/HtmlParser.cs @@ -0,0 +1,213 @@ +/* +Copyright (c) 2014, Lars Brubaker +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.Linq; +using System.Text; +using System.IO; +using System.Text.RegularExpressions; + +using MatterHackers.Agg; +using MatterHackers.Agg.UI; + +namespace MatterHackers.MatterControl.HtmlParsing +{ + public class ElementState + { + public enum AlignType { none, center }; + public enum VerticalAlignType { none, top }; + + internal List classes = new List(); + public List Classes { get { return classes; } } + internal string typeName; + public string TypeName { get { return typeName; } } + + internal string href; + public string Href { get { return href; } } + + internal string id; + public string Id { get { return id; } } + + internal AlignType alignment; + public AlignType Alignment { get { return alignment; } } + internal VerticalAlignType verticalAlignment; + public VerticalAlignType VerticalAlignment { get { return verticalAlignment; } } + + internal double pointSize = 12; + public double PointSize { get { return pointSize; } } + internal int heightPercent = 0; + public int HeightPercent { get { return heightPercent; } } + + internal ElementState() + { + } + + internal ElementState(ElementState copy) + { + alignment = copy.alignment; + verticalAlignment = copy.verticalAlignment; + pointSize = copy.pointSize; + // not part of the ongoing state + //heightPercent = copy.heightPercent; + } + } + + public class HtmlParser + { + Stack elementQueue = new Stack(); + public ElementState CurrentElementState { get { return elementQueue.Peek(); } } + + public delegate void ProcessContent(HtmlParser htmlParser, string content); + + const string typeNameEnd = @"[ >]"; + private static readonly Regex typeNameEndRegex = new Regex(typeNameEnd, RegexOptions.Compiled); + public void ParseHtml(string htmlContent, ProcessContent addContentFunction, ProcessContent closeContentFunction) + { + elementQueue.Push(new ElementState()); + + int currentPosition = 0; + while (currentPosition < htmlContent.Length) + { + int openPosition = htmlContent.IndexOf('<', currentPosition); + if (openPosition == -1) + { + break; + } + int closePosition = htmlContent.IndexOf('>', openPosition); + if (htmlContent[openPosition + 1] == '/') + { + closeContentFunction(this, null); + elementQueue.Pop(); + + // get any content that is after this close but before the next open or close + int nextOpenPosition = htmlContent.IndexOf('<', closePosition); + if (nextOpenPosition > closePosition + 1) + { + string contentBetweenInsideAndEnd = htmlContent.Substring(closePosition + 1, nextOpenPosition - (closePosition + 1)); + addContentFunction(this, contentBetweenInsideAndEnd); + } + } + else + { + ParesTypeContent(openPosition, closePosition, htmlContent); + + int endOfName = typeNameEndRegex.Match(htmlContent, openPosition + 1).Index; + elementQueue.Peek().typeName = htmlContent.Substring(openPosition + 1, endOfName - (openPosition + 1)); + + int nextOpenPosition = htmlContent.IndexOf('<', closePosition); + string content = htmlContent.Substring(closePosition + 1, nextOpenPosition - closePosition - 1); + addContentFunction(this, content); + } + currentPosition = closePosition + 1; + } + } + + private void ParesTypeContent(int openPosition, int closePosition, string htmlContent) + { + string text = htmlContent.Substring(openPosition, closePosition - openPosition); + ElementState style = new ElementState(elementQueue.Peek()); + int afterTypeName = typeNameEndRegex.Match(htmlContent, openPosition).Index; + if (afterTypeName < closePosition) + { + string content = htmlContent.Substring(afterTypeName, closePosition - afterTypeName).Trim(); + string[] splitOnSpace = new Regex("' ").Split(content); + for (int i = 0; i < splitOnSpace.Length; i++) + { + string[] splitOnEquals = new Regex("='").Split(splitOnSpace[i]); + switch (splitOnEquals[0]) + { + case "style": + ParseStyleContent(splitOnEquals[1].Substring(0, splitOnEquals[1].Length - 1), style); + break; + + case "align": + break; + + case "class": + { + string[] classes = splitOnEquals[1].Split(' '); + foreach (string className in classes) + { + style.classes.Add(className); + } + } + break; + + case "href": + style.href = splitOnEquals[1].Substring(0, splitOnEquals[1].Length - 1); + break; + + case "id": + style.id = splitOnEquals[1].Substring(0, splitOnEquals[1].Length - 1); + break; + + default: + throw new NotImplementedException(); + } + } + } + + elementQueue.Push(style); + } + + private void ParseStyleContent(string styleContent, ElementState style) + { + string[] splitOnSemi = styleContent.Split(';'); + for (int i = 0; i < splitOnSemi.Length; i++) + { + if (splitOnSemi[i].Length > 0) + { + string[] splitOnColon = splitOnSemi[i].Split(':'); + switch (splitOnColon[0]) + { + case "height": + style.heightPercent = int.Parse(splitOnColon[1].Substring(0, splitOnColon[1].Length - 1)); + break; + + case "text-align": + style.alignment = (ElementState.AlignType)Enum.Parse(typeof(ElementState.AlignType), splitOnColon[1]); + break; + + case "font-size": + style.pointSize = int.Parse(splitOnColon[1].Substring(0, splitOnColon[1].Length - 2)); + break; + + case "vertical-align": + style.verticalAlignment = (ElementState.VerticalAlignType)Enum.Parse(typeof(ElementState.VerticalAlignType), splitOnColon[1]); + break; + + default: + throw new NotImplementedException(); + } + } + } + } + } +} diff --git a/AboutPage/WidgetFromHtml.cs b/AboutPage/WidgetFromHtml.cs deleted file mode 100644 index 2effce286..000000000 --- a/AboutPage/WidgetFromHtml.cs +++ /dev/null @@ -1,183 +0,0 @@ -/* -Copyright (c) 2014, Lars Brubaker -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.Linq; -using System.Text; -using System.IO; - -using MatterHackers.Agg; -using MatterHackers.Agg.UI; - -namespace MatterHackers.MatterControl -{ - public class WidgetFromHtml - { - internal class StyleState - { - internal enum AlignType { none, center }; - internal enum VerticalAlignType { none, top }; - - internal AlignType alignment; - internal VerticalAlignType vertiaclAlignment; - - internal double pointSize = 12; - internal int heightPercent = 0; - - internal StyleState() - { - } - - internal StyleState(StyleState copy) - { - alignment = copy.alignment; - vertiaclAlignment = copy.vertiaclAlignment; - pointSize = copy.pointSize; - heightPercent = copy.heightPercent; - } - } - - Stack styleQueue = new Stack(); - - public delegate string ProcessContent(string content); - - class ClassToFunctionMapping - { - string className; - ProcessContent function; - - public ClassToFunctionMapping(string className, ProcessContent function) - { - this.className = className; - this.function = function; - } - } - - List classFunctionMapping = new List(); - - public void AddMapping(string className, ProcessContent function) - { - classFunctionMapping.Add(new ClassToFunctionMapping(className, function)); - } - - GuiWidget widgetBeingCreated; - public GuiWidget CreateWidget(string htmlContent) - { - styleQueue.Push(new StyleState()); - widgetBeingCreated = new FlowLayoutWidget(FlowDirection.TopToBottom); - - int currentPosition = 0; - while (currentPosition < htmlContent.Length) - { - int openPosition = htmlContent.IndexOf('<', currentPosition); - if (openPosition == -1) - { - break; - } - int closePosition = htmlContent.IndexOf('>', openPosition); - if (htmlContent[openPosition + 1] == '/') - { - styleQueue.Pop(); - } - else - { - ParesTypeContent(openPosition, closePosition, htmlContent); - - if(htmlContent.Substring(openPosition+1).StartsWith("span")) - { - int nextOpenPosition = htmlContent.IndexOf('<', closePosition); - AddContent(htmlContent.Substring(closePosition, nextOpenPosition - closePosition)); - } - } - currentPosition = closePosition + 1; - } - - return widgetBeingCreated; - } - - private void AddContent(string htmlContent) - { - widgetBeingCreated.AddChild(new TextWidget(htmlContent)); - } - - private void ParesTypeContent(int openPosition, int closePosition, string htmlContent) - { - string text = htmlContent.Substring(openPosition, closePosition - openPosition); - StyleState style = new StyleState(styleQueue.Peek()); - int afterType = htmlContent.IndexOf(' ', openPosition); - if (afterType < closePosition) - { - string content = htmlContent.Substring(afterType, closePosition - afterType).Trim(); - string[] splitOnEquals = content.Split('='); - switch (splitOnEquals[0]) - { - case "style": - ParseStyleContent(splitOnEquals[1].Substring(1, splitOnEquals[1].Length - 2), style); - break; - } - } - - styleQueue.Push(style); - } - - private void ParseStyleContent(string styleContent, StyleState style) - { - string[] splitOnSemi = styleContent.Split(';'); - for (int i = 0; i < splitOnSemi.Length; i++) - { - if (splitOnSemi[i].Length > 0) - { - string[] splitOnColon = splitOnSemi[i].Split(':'); - switch (splitOnColon[0]) - { - case "height": - style.heightPercent = int.Parse(splitOnColon[1].Substring(0, splitOnColon[1].Length - 1)); - break; - - case "text-align": - style.alignment = (StyleState.AlignType)Enum.Parse(typeof(StyleState.AlignType), splitOnColon[1]); - break; - - case "font-size": - style.pointSize = int.Parse(splitOnColon[1].Substring(0, splitOnColon[1].Length - 2)); - break; - - case "vertical-align": - style.vertiaclAlignment = (StyleState.VerticalAlignType)Enum.Parse(typeof(StyleState.VerticalAlignType), splitOnColon[1]); - break; - - default: - throw new NotImplementedException(); - } - } - } - } - } -} diff --git a/MatterControl.csproj b/MatterControl.csproj index a3b5610c1..074cafda2 100644 --- a/MatterControl.csproj +++ b/MatterControl.csproj @@ -82,7 +82,7 @@ - + diff --git a/StaticData/OEMSettings/AboutPage.html b/StaticData/OEMSettings/AboutPage.html index 575687d58..18d812ddc 100644 --- a/StaticData/OEMSettings/AboutPage.html +++ b/StaticData/OEMSettings/AboutPage.html @@ -1,4 +1,4 @@ - +
@@ -6,8 +6,8 @@ - - + +
MatterControl
Version 0.0.0
Developed by: MatterHackers
Please consider donating to help support MatterControl.
 
Special thanks to:
Alessandro Ranellucci for Slic3r
David Braam and Ultimaker BV for CuraEngine
Alessandro Ranellucci for Slic3r
David Braam and Ultimaker BV for CuraEngine
 
Send FeedBack
www.matterhackers.com