Exemple #1
0
        public TextWidget(string text, double x = 0, double y = 0, double pointSize = 12, Justification justification = Justification.Left, RGBA_Bytes textColor = new RGBA_Bytes(), bool ellipsisIfClipped = true, bool underline = false, RGBA_Bytes backgroundColor = new RGBA_Bytes())
        {
            pointSize             *= GlobalPointSizeScaleRatio;
            Selectable             = false;
            DoubleBuffer           = DoubleBufferDefault;
            AutoExpandBoundsToText = false;
            EllipsisIfClipped      = ellipsisIfClipped;
            OriginRelativeParent   = new Vector2(x, y);
            this.textColor         = textColor;
            if (this.textColor.Alpha0To255 == 0)
            {
                // we assume it is the default if alpha 0.  Also there is no reason to make a text color of this as it will draw nothing.
                this.textColor = RGBA_Bytes.Black;
            }
            if (backgroundColor.Alpha0To255 != 0)
            {
                BackgroundColor = backgroundColor;
            }

            base.Text = text;
            StyledTypeFace typeFaceStyle = new StyledTypeFace(LiberationSansFont.Instance, pointSize, underline);

            printer = new TypeFacePrinter(text, typeFaceStyle, justification: justification);

            LocalBounds = printer.LocalBounds;

            MinimumSize = new Vector2(LocalBounds.Width, LocalBounds.Height);
        }
        private void AddCharacterMeshes(string currentText, TypeFacePrinter printer)
        {
            int            newIndex = asynchMeshGroups.Count;
            StyledTypeFace typeFace = printer.TypeFaceStyle;

            for (int i = 0; i < currentText.Length; i++)
            {
                string          letter        = currentText[i].ToString();
                TypeFacePrinter letterPrinter = new TypeFacePrinter(letter, typeFace);

                if (CharacterHasMesh(letterPrinter, letter))
                {
                    Mesh textMesh = VertexSourceToMesh.Extrude(letterPrinter, unscaledLetterHeight / 2);

                    asynchMeshGroups.Add(new MeshGroup(textMesh));

                    PlatingMeshGroupData newMeshInfo = new PlatingMeshGroupData();

                    newMeshInfo.spacing = printer.GetOffsetLeftOfCharacterIndex(i);
                    asynchPlatingDatas.Add(newMeshInfo);
                    asynchMeshGroupTransforms.Add(ScaleRotateTranslate.Identity());

                    PlatingHelper.CreateITraceableForMeshGroup(asynchPlatingDatas, asynchMeshGroups, newIndex, null);
                    ScaleRotateTranslate moved = asynchMeshGroupTransforms[newIndex];
                    moved.translation *= Matrix4X4.CreateTranslation(new Vector3(0, 0, unscaledLetterHeight / 2));
                    asynchMeshGroupTransforms[newIndex] = moved;

                    newIndex++;
                }

                processingProgressControl.PercentComplete = ((i + 1) * 95 / currentText.Length);
            }
        }
        public override Task Rebuild()
        {
            this.DebugDepth("Rebuild");

            var rebuildLock = RebuildLock();

            return(Task.Run(() =>
            {
                using (new CenterAndHeightMaintainer(this))
                {
                    bool valuesChanged = false;
                    var height = Height.ClampIfNotCalculated(this, .01, 1000000, ref valuesChanged);
                    var nameToWrite = NameToWrite.Value(this);
                    if (string.IsNullOrWhiteSpace(nameToWrite))
                    {
                        Mesh = PlatonicSolids.CreateCube(20, 10, height);
                    }
                    else
                    {
                        Mesh = null;
                        this.Children.Modify(list =>
                        {
                            list.Clear();

                            var offest = 0.0;
                            double pointsToMm = 0.352778;

                            foreach (var letter in nameToWrite.ToCharArray())
                            {
                                var style = new StyledTypeFace(ApplicationController.GetTypeFace(this.Font), PointSize.Value(this));
                                var letterPrinter = new TypeFacePrinter(letter.ToString(), style)
                                {
                                    ResolutionScale = 10
                                };
                                var scaledLetterPrinter = new VertexSourceApplyTransform(letterPrinter, Affine.NewScaling(pointsToMm));

                                list.Add(new Object3D()
                                {
                                    Mesh = VertexSourceToMesh.Extrude(scaledLetterPrinter, this.Height.Value(this)),
                                    Matrix = Matrix4X4.CreateTranslation(offest, 0, 0),
                                    Name = letter.ToString()
                                });

                                offest += letterPrinter.GetSize(letter.ToString()).X *pointsToMm;
                            }
                        });
                    }
                }

                UiThread.RunOnIdle(() =>
                {
                    rebuildLock.Dispose();
                    Invalidate(InvalidateType.DisplayValues);
                    Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
                });
            }));
        }
Exemple #4
0
        public blur()
        {
            m_rbuf2                 = new ImageBuffer();
            m_shape_bounds          = new RectangleDouble();
            m_method                = new RadioButtonGroup(new Vector2(10.0, 10.0), new Vector2(130.0, 60.0));
            m_radius                = new Slider(new Vector2(130 + 10.0, 10.0 + 4.0), new Vector2(290, 8.0));
            m_shadow_ctrl           = new PolygonEditWidget(4);
            m_channel_r             = new CheckBox(10.0, 80.0, "Red");
            m_channel_g             = new CheckBox(10.0, 95.0, "Green");
            m_channel_b             = new CheckBox(10.0, 110.0, "Blue");
            m_FlattenCurves         = new CheckBox(10, 315, "Convert And Flatten Curves");
            m_FlattenCurves.Checked = true;

            AddChild(m_method);
            m_method.AddRadioButton("Stack Blur");
            m_method.AddRadioButton("Recursive Blur");
            m_method.AddRadioButton("Channels");
            m_method.SelectedIndex = 1;

            AddChild(m_radius);
            m_radius.SetRange(0.0, 40.0);
            m_radius.Value = 15.0;
            m_radius.Text  = "Blur Radius={0:F2}";

            AddChild(m_shadow_ctrl);

            AddChild(m_channel_r);
            AddChild(m_channel_g);
            AddChild(m_channel_b);
            AddChild(m_FlattenCurves);
            m_channel_g.Checked = true;

            m_sl = new ScanlineCachePacked8();

            StyledTypeFace typeFaceForLargeA = new StyledTypeFace(LiberationSansFont.Instance, 300, flatenCurves: false);

            m_path = typeFaceForLargeA.GetGlyphForCharacter('a');

            Affine shape_mtx = Affine.NewIdentity();

            shape_mtx *= Affine.NewTranslation(150, 100);
            m_path     = new VertexSourceApplyTransform(m_path, shape_mtx);
            m_shape    = new FlattenCurves(m_path);

            bounding_rect.bounding_rect_single(m_shape, 0, ref m_shape_bounds);

            m_shadow_ctrl.SetXN(0, m_shape_bounds.Left);
            m_shadow_ctrl.SetYN(0, m_shape_bounds.Bottom);
            m_shadow_ctrl.SetXN(1, m_shape_bounds.Right);
            m_shadow_ctrl.SetYN(1, m_shape_bounds.Bottom);
            m_shadow_ctrl.SetXN(2, m_shape_bounds.Right);
            m_shadow_ctrl.SetYN(2, m_shape_bounds.Top);
            m_shadow_ctrl.SetXN(3, m_shape_bounds.Left);
            m_shadow_ctrl.SetYN(3, m_shape_bounds.Top);
            m_shadow_ctrl.line_color(new ColorF(0, 0.3, 0.5, 0.3));
        }
Exemple #5
0
        public void CharacterBoundsTest()
        {
            // Validates character bounds computation from IVertexSource
            char[] sampleCharacters = "@ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz{}[]| !\"#$%&?'()*+,-./0123456789".ToCharArray();

            int fontSize = 12;

            var typeface = new StyledTypeFace(LiberationSansFont.Instance, fontSize);

            string filename = $"{nameof(LiberationSansFont)}-{fontSize}.json";

            string testDataPath = TestContext.CurrentContext.ResolveProjectPath(new string[] { "..", "..", "TestData", filename });

            // Project sample string characters to dictionary with character bounds
            var characterBounds = sampleCharacters.ToDictionary(c => c, c => GetCharacterBounds(c, typeface));

            var jsonSettings = new JsonSerializerSettings()
            {
                Converters = new List <JsonConverter>()
                {
                    new FlatRectangleDoubleConverter()
                }
            };

            // Update the control data
            if (false)
            {
                Directory.CreateDirectory(Path.GetDirectoryName(testDataPath));

                File.WriteAllText(
                    testDataPath,
                    JsonConvert.SerializeObject(characterBounds,
                                                jsonSettings));
            }

            // Load sample data
            string json        = File.ReadAllText(testDataPath);
            var    controlData = JsonConvert.DeserializeObject <Dictionary <char, RectangleDouble> >(json, jsonSettings);

            // Validate each character against previously computed control data
            foreach (var kvp in characterBounds)
            {
                Assert.IsTrue(controlData.ContainsKey(kvp.Key), "Expected key not found: " + kvp.Key);

                RectangleDouble actual   = kvp.Value;
                RectangleDouble expected = controlData[kvp.Key];

                Assert.AreEqual(expected.Left, actual.Left, 0.001, "Bounds Left differ");
                Assert.AreEqual(expected.Bottom, actual.Bottom, 0.001, "Bounds Bottom differ");
                Assert.AreEqual(expected.Right, actual.Right, 0.001, "Bounds Right differ");
                Assert.AreEqual(expected.Top, actual.Top, 0.001, "Bounds Top differ");

                Assert.AreEqual(expected, actual);
            }
        }
Exemple #6
0
        private void AddCharacterMeshes(string currentText, TypeFacePrinter printer)
        {
            int            newIndex = asyncMeshGroups.Count;
            StyledTypeFace typeFace = printer.TypeFaceStyle;

            for (int i = 0; i < currentText.Length; i++)
            {
                string          letter        = currentText[i].ToString();
                TypeFacePrinter letterPrinter = new TypeFacePrinter(letter, typeFace);

                if (CharacterHasMesh(letterPrinter, letter))
                {
#if true
                    Mesh textMesh = VertexSourceToMesh.Extrude(letterPrinter, unscaledLetterHeight / 2);
#else
                    Mesh textMesh = VertexSourceToMesh.Extrude(letterPrinter, unscaledLetterHeight / 2);
                    // this is the code to make rounded tops
                    // convert the letterPrinter to clipper polygons
                    List <List <IntPoint> > insetPoly = VertexSourceToPolygon.CreatePolygons(letterPrinter);
                    // inset them
                    ClipperOffset clipper = new ClipperOffset();
                    clipper.AddPaths(insetPoly, JoinType.jtMiter, EndType.etClosedPolygon);
                    List <List <IntPoint> > solution = new List <List <IntPoint> >();
                    clipper.Execute(solution, 5.0);
                    // convert them back into a vertex source
                    // merge both the inset and original vertex sources together
                    // convert the new vertex source into a mesh (trianglulate them)
                    // offset the inner loop in z
                    // create the polygons from the inner loop to a center point so that there is the rest of an approximation of the bubble
                    // make the mesh for the bottom
                    // add the top and bottom together
                    // done
#endif

                    asyncMeshGroups.Add(new MeshGroup(textMesh));

                    PlatingMeshGroupData newMeshInfo = new PlatingMeshGroupData();

                    newMeshInfo.spacing = printer.GetOffsetLeftOfCharacterIndex(i);
                    asyncPlatingDatas.Add(newMeshInfo);
                    asyncMeshGroupTransforms.Add(ScaleRotateTranslate.Identity());

                    PlatingHelper.CreateITraceableForMeshGroup(asyncPlatingDatas, asyncMeshGroups, newIndex, null);
                    ScaleRotateTranslate moved = asyncMeshGroupTransforms[newIndex];
                    moved.translation *= Matrix4X4.CreateTranslation(new Vector3(0, 0, unscaledLetterHeight / 2));
                    asyncMeshGroupTransforms[newIndex] = moved;

                    newIndex++;
                }

                processingProgressControl.PercentComplete = ((i + 1) * 95 / currentText.Length);
            }
        }
        public override void OnDraw(Graphics2D graphics2D)
        {
#if DEBUG
            ExecutionTimer.Instance.Reset();
            totalDrawTime.Restart();
#endif
            drawTimer.Start();
            base.OnDraw(graphics2D);
            drawTimer.Stop();

#if DEBUG // this is to debug memory allocation and freeing
            totalDrawTime.Stop();
            long memory = GC.GetTotalMemory(false);
            this.Title = string.Format("Allocated = {0:n0} : {1}ms, d{2} Size = {3}x{4}", memory, totalDrawTime.ElapsedMilliseconds, drawCount++, this.Width, this.Height);

#if false
            if (timingWindow == null)
            {
                string   staticDataPath = ApplicationDataStorage.Instance.ApplicationStaticDataPath;
                string   fontPath       = Path.Combine(staticDataPath, "Fonts", "LiberationMono.svg");
                TypeFace boldTypeFace   = TypeFace.LoadSVG(fontPath);
                typeFaceToUse = new StyledTypeFace(boldTypeFace, 12);

                timingWindow = new PerformanceFeedbackWindow();
            }
            {
                if (totalDrawTime.Elapsed.TotalSeconds > .05)
                {
                    timingWindow.ShowResults(totalDrawTime.Elapsed.TotalSeconds);
                }
            }
#endif
#endif

            if (firstDraw)
            {
                Parent.MinimumSize = new Vector2(590, 540);
                firstDraw          = false;
                foreach (string arg in commandLineArgs)
                {
                    if (Path.GetExtension(arg).ToUpper() == ".STL")
                    {
                        new PartPreviewMainWindow(new PrintItemWrapper(new DataStorage.PrintItem(Path.GetFileName(arg), Path.GetFullPath(arg))));
                    }
                }
            }
        }
        public override void OnDraw(Graphics2D graphics2D)
        {
            GammaLookUpTable    gamma         = new GammaLookUpTable(gammaSlider.Value);
            IRecieveBlenderByte NormalBlender = new BlenderBGR();
            IRecieveBlenderByte GammaBlender  = new BlenderGammaBGR(gamma);
            ImageBuffer         rasterNormal  = new ImageBuffer();

            rasterNormal.Attach(graphics2D.DestImage, NormalBlender);
            ImageBuffer rasterGamma = new ImageBuffer();

            rasterGamma.Attach(graphics2D.DestImage, GammaBlender);
            ImageClippingProxy clippingProxyNormal = new ImageClippingProxy(rasterNormal);
            ImageClippingProxy clippingProxyGamma  = new ImageClippingProxy(rasterGamma);

            clippingProxyNormal.clear(new RGBA_Floats(1, 1, 1));

            ScanlineRasterizer  ras = new ScanlineRasterizer();
            scanline_unpacked_8 sl  = new scanline_unpacked_8();

            int size_mul = (int)pixelSizeSlider.Value;

            renderer_enlarged ren_en = new renderer_enlarged(size_mul);

            StyledTypeFace type      = new StyledTypeFace(LiberationSansFont.Instance, 12);
            IVertexSource  character = type.GetGlyphForCharacter('E');

            character.rewind(0);
            ras.reset();
            ras.add_path(character);
            ren_en.RenderSolid(clippingProxyGamma, ras, sl, RGBA_Bytes.Black);

            ScanlineRenderer scanlineRenderer = new ScanlineRenderer();

            scanlineRenderer.RenderSolid(clippingProxyGamma, ras, sl, RGBA_Bytes.Black);

            ras.gamma(new gamma_none());

            PathStorage ps = new PathStorage();
            Stroke      pg = new Stroke(ps);

            pg.width(2);

            DrawBigA(graphics2D);

            base.OnDraw(graphics2D);
        }
        private void InsertTextDoWork(string currentText)
        {
            Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

            asynchMeshGroups.Clear();
            asynchMeshGroupTransforms.Clear();
            asynchPlatingDatas.Clear();

            TypeFacePrinter brailPrinter = new TypeFacePrinter(currentText, new StyledTypeFace(brailTypeFace, 12));

            int            firstNewCharacter = 0;
            StyledTypeFace boldStyled        = new StyledTypeFace(boldTypeFace, 12);

            if (includeText.Checked)
            {
                TypeFacePrinter normalPrinter = new TypeFacePrinter(currentText, boldStyled);
                Vector2         normalSize    = normalPrinter.GetSize();
                AddCharacterMeshes(currentText, normalPrinter);

                firstNewCharacter = asynchPlatingDatas.Count;
            }

            AddCharacterMeshes(currentText, brailPrinter);
            Vector2 brailSize = brailPrinter.GetSize();

            for (int i = firstNewCharacter; i < asynchPlatingDatas.Count; i++)
            {
                asynchPlatingDatas[i].spacing = asynchPlatingDatas[i - firstNewCharacter].spacing + new Vector2(0, -boldStyled.CapHeightInPixels * 1.5);
            }

            CreateBase(asynchMeshGroups, asynchMeshGroupTransforms, asynchPlatingDatas);

            SetWordPositions(asynchMeshGroups, asynchMeshGroupTransforms, asynchPlatingDatas);
            SetWordSize(asynchMeshGroups, asynchMeshGroupTransforms);
            SetWordHeight(asynchMeshGroups, asynchMeshGroupTransforms);

            CenterTextOnScreen(asynchMeshGroups, asynchMeshGroupTransforms);

            processingProgressControl.PercentComplete = 95;
        }
Exemple #10
0
        // Behavior which relies on classic IVertexSource.vertex iteration
        private static RectangleDouble GetCharacterBounds(char character, StyledTypeFace typeface)
        {
            IVertexSource glyphForCharacter = typeface.GetGlyphForCharacter(character, 1);

            glyphForCharacter.rewind(0);

            ShapePath.FlagsAndCommand curCommand;

            var bounds = RectangleDouble.ZeroIntersection;

            do
            {
                curCommand = glyphForCharacter.vertex(out double x, out double y);

                if (curCommand != ShapePath.FlagsAndCommand.Stop &&
                    !ShapePath.is_close(curCommand))
                {
                    bounds.ExpandToInclude(x, y);
                }
            } while (curCommand != ShapePath.FlagsAndCommand.Stop);

            return(bounds);
        }
Exemple #11
0
        private void AddContent(HtmlParser htmlParser, string htmlContent)
        {
            ElementState elementState = htmlParser.CurrentElementState;
            string       decodedHtml  = HtmlParser.UrlDecode(htmlContent);

            switch (elementState.TypeName)
            {
            case "p":
            {
                elementsUnderConstruction.Push(new FlowLayoutWidget());
                elementsUnderConstruction.Peek().Name    = "p";
                elementsUnderConstruction.Peek().HAnchor = HAnchor.ParentLeftRight;

                if (decodedHtml != null && decodedHtml != "")
                {
                    WrappingTextWidget content = new WrappingTextWidget(decodedHtml, pointSize: elementState.PointSize, textColor: ActiveTheme.Instance.PrimaryTextColor);
                    //content.VAnchor = VAnchor.ParentTop;
                    elementsUnderConstruction.Peek().AddChild(content);
                }
            }
            break;

            case "div":
            {
                elementsUnderConstruction.Push(new FlowLayoutWidget());
                elementsUnderConstruction.Peek().Name = "div";

                if (decodedHtml != null && decodedHtml != "")
                {
                    TextWidget content = new TextWidget(decodedHtml, pointSize: elementState.PointSize, textColor: ActiveTheme.Instance.PrimaryTextColor);
                    elementsUnderConstruction.Peek().AddChild(content);
                }
            }
            break;

            case "!DOCTYPE":
                break;

            case "body":
                break;

            case "img":
            {
                ImageBuffer image = new ImageBuffer(elementState.SizeFixed.x, elementState.SizeFixed.y, 32, new BlenderBGRA());
                ImageWidget_AsyncLoadOnDraw imageWidget = new ImageWidget_AsyncLoadOnDraw(image, elementState.src);
                // put the image into the widget when it is done downloading.

                if (elementsUnderConstruction.Peek().Name == "a")
                {
                    Button linkButton = new Button(0, 0, imageWidget);
                    linkButton.Cursor = Cursors.Hand;
                    linkButton.Click += (sender, mouseEvent) =>
                    {
                        MatterControlApplication.Instance.LaunchBrowser(elementState.Href);
                    };
                    elementsUnderConstruction.Peek().AddChild(linkButton);
                }
                else
                {
                    elementsUnderConstruction.Peek().AddChild(imageWidget);
                }
            }
            break;

            case "a":
            {
                elementsUnderConstruction.Push(new FlowLayoutWidget());
                elementsUnderConstruction.Peek().Name = "a";

                if (decodedHtml != null && decodedHtml != "")
                {
                    Button         linkButton      = linkButtonFactory.Generate(decodedHtml);
                    StyledTypeFace styled          = new StyledTypeFace(LiberationSansFont.Instance, elementState.PointSize);
                    double         descentInPixels = styled.DescentInPixels;
                    linkButton.OriginRelativeParent = new VectorMath.Vector2(linkButton.OriginRelativeParent.x, linkButton.OriginRelativeParent.y + descentInPixels);
                    linkButton.Click += (sender, mouseEvent) =>
                    {
                        MatterControlApplication.Instance.LaunchBrowser(elementState.Href);
                    };
                    elementsUnderConstruction.Peek().AddChild(linkButton);
                }
            }
            break;

            case "table":
                break;

            case "td":
            case "span":
                GuiWidget widgetToAdd;

                if (elementState.Classes.Contains("translate"))
                {
                    decodedHtml = decodedHtml.Localize();
                }
                if (elementState.Classes.Contains("toUpper"))
                {
                    decodedHtml = decodedHtml.ToUpper();
                }
                if (elementState.Classes.Contains("versionNumber"))
                {
                    decodedHtml = VersionInfo.Instance.ReleaseVersion;
                }
                if (elementState.Classes.Contains("buildNumber"))
                {
                    decodedHtml = VersionInfo.Instance.BuildVersion;
                }

                Button createdButton = null;
                if (elementState.Classes.Contains("centeredButton"))
                {
                    createdButton = textImageButtonFactory.Generate(decodedHtml);
                    widgetToAdd   = createdButton;
                }
                else if (elementState.Classes.Contains("linkButton"))
                {
                    double oldFontSize = linkButtonFactory.fontSize;
                    linkButtonFactory.fontSize = elementState.PointSize;
                    createdButton = linkButtonFactory.Generate(decodedHtml);
                    StyledTypeFace styled          = new StyledTypeFace(LiberationSansFont.Instance, elementState.PointSize);
                    double         descentInPixels = styled.DescentInPixels;
                    createdButton.OriginRelativeParent = new VectorMath.Vector2(createdButton.OriginRelativeParent.x, createdButton.OriginRelativeParent.y + descentInPixels);
                    widgetToAdd = createdButton;
                    linkButtonFactory.fontSize = oldFontSize;
                }
                else
                {
                    TextWidget content = new TextWidget(decodedHtml, pointSize: elementState.PointSize, textColor: ActiveTheme.Instance.PrimaryTextColor);
                    widgetToAdd = content;
                }

                if (createdButton != null)
                {
                    if (elementState.Id == "sendFeedback")
                    {
                        createdButton.Click += (sender, mouseEvent) => { ContactFormWindow.Open(); };
                    }
                    else if (elementState.Id == "clearCache")
                    {
                        createdButton.Click += (sender, mouseEvent) => { AboutWidget.DeleteCacheData(); };
                    }
                }

                if (elementState.VerticalAlignment == ElementState.VerticalAlignType.top)
                {
                    widgetToAdd.VAnchor = VAnchor.ParentTop;
                }

                elementsUnderConstruction.Peek().AddChild(widgetToAdd);
                break;

            case "tr":
                elementsUnderConstruction.Push(new FlowLayoutWidget());
                elementsUnderConstruction.Peek().Name = "tr";
                if (elementState.SizePercent.y == 100)
                {
                    elementsUnderConstruction.Peek().VAnchor = VAnchor.ParentBottomTop;
                }
                if (elementState.Alignment == ElementState.AlignType.center)
                {
                    elementsUnderConstruction.Peek().HAnchor |= HAnchor.ParentCenter;
                }
                break;

            default:
                throw new NotImplementedException("Don't know what to do with '{0}'".FormatWith(elementState.TypeName));
            }
        }
Exemple #12
0
        private void AddContent(HtmlParser htmlParser, string htmlContent)
        {
            ElementState elementState = htmlParser.CurrentElementState;
            string       decodedHtml  = HtmlParser.UrlDecode(htmlContent);

            switch (elementState.TypeName)
            {
            case "a":
            {
                Button         linkButton      = linkButtonFactory.Generate(decodedHtml);
                StyledTypeFace styled          = new StyledTypeFace(LiberationSansFont.Instance, elementState.PointSize);
                double         descentInPixels = styled.DescentInPixels;
                linkButton.OriginRelativeParent = new VectorMath.Vector2(linkButton.OriginRelativeParent.x, linkButton.OriginRelativeParent.y + descentInPixels);
                linkButton.Click += (sender, mouseEvent) =>
                {
                    MatterControlApplication.Instance.LaunchBrowser(elementState.Href);
                };
                currentRow.AddChild(linkButton);
            }
            break;

            case "table":
                break;

            case "td":
            case "span":
                GuiWidget widgetToAdd;

                if (elementState.Classes.Contains("translate"))
                {
                    decodedHtml = decodedHtml.Localize();
                }
                if (elementState.Classes.Contains("toUpper"))
                {
                    decodedHtml = decodedHtml.ToUpper();
                }
                if (elementState.Classes.Contains("versionNumber"))
                {
                    decodedHtml = VersionInfo.Instance.ReleaseVersion;
                }
                if (elementState.Classes.Contains("buildNumber"))
                {
                    decodedHtml = VersionInfo.Instance.BuildVersion;
                }

                Button createdButton = null;
                if (elementState.Classes.Contains("centeredButton"))
                {
                    createdButton = textImageButtonFactory.Generate(decodedHtml);
                    widgetToAdd   = createdButton;
                }
                else if (elementState.Classes.Contains("linkButton"))
                {
                    double oldFontSize = linkButtonFactory.fontSize;
                    linkButtonFactory.fontSize = elementState.PointSize;
                    createdButton = linkButtonFactory.Generate(decodedHtml);
                    StyledTypeFace styled          = new StyledTypeFace(LiberationSansFont.Instance, elementState.PointSize);
                    double         descentInPixels = styled.DescentInPixels;
                    createdButton.OriginRelativeParent = new VectorMath.Vector2(createdButton.OriginRelativeParent.x, createdButton.OriginRelativeParent.y + descentInPixels);
                    widgetToAdd = createdButton;
                    linkButtonFactory.fontSize = oldFontSize;
                }
                else
                {
                    TextWidget content = new TextWidget(decodedHtml, pointSize: elementState.PointSize, textColor: ActiveTheme.Instance.PrimaryTextColor);
                    widgetToAdd = content;
                }

                if (createdButton != null)
                {
                    if (elementState.Id == "sendFeedback")
                    {
                        createdButton.Click += (sender, mouseEvent) => { ContactFormWindow.Open(); };
                    }
                    else if (elementState.Id == "clearCache")
                    {
                        createdButton.Click += (sender, mouseEvent) => { DeleteCacheData(); };
                    }
                }

                if (elementState.VerticalAlignment == ElementState.VerticalAlignType.top)
                {
                    widgetToAdd.VAnchor = VAnchor.ParentTop;
                }

                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("Don't know what to do with {0}".FormatWith(elementState.TypeName));
            }
        }