private void ShowLegend(TextStyleInfo info)
        {
            View legendView = new ColorView(Color.AntiqueWhite);
            // round height
            int lineHeight = (int)(info.Height + 0.5);
            // height is enough for each line plus half a line padding plus line for total
            int   boxHeight    = lineHeight * (_legend.Count + 2);
            float longestLabel = 0;

            foreach (string label in _legend.Keys)
            {
                longestLabel = Math.Max(longestLabel, info.MeasureText(label).Width);
            }
            // width is long enough for the longest line + color palete + padding
            // using Height for width and height of color palete (shrunk a little for margin)
            int boxWidth = (int)(longestLabel + 0.5 + 2 * lineHeight);

            legendView.Bounds = new Rectangle(Bounds.Width - boxWidth, 0, boxWidth, boxHeight);
            Children.Add(legendView);

            // leave a half line space at the top (and bottom since the whole thing has an extra line height)
            int topText = lineHeight / 2;
            // small left margin for black border. actual color starts one more pixel in
            int leftColor = lineHeight / 4;
            // enough space for the color.  Subtract on since the black border gives too much margin
            int leftText = lineHeight / 2 + lineHeight - 1;
            // subtract three from color size to get 1 pixel margin between boxes plus a pixel for top and bottom black border
            int colorSize = lineHeight - 3;

            foreach (var legendEntry in _legend)
            {
                ColorView colorBorder = new ColorView(Color.Black);
                colorBorder.Bounds = new Rectangle(leftColor, topText, colorSize + 2, colorSize + 2);
                ColorView legendColor = new ColorView(legendEntry.Value);
                legendColor.Bounds = new Rectangle(1, 1, colorSize, colorSize);
                colorBorder.Children.Add(legendColor);
                legendView.Children.Add(colorBorder);
                TextView legendText = new TextView(legendEntry.Key, _legendStyle, Color.Black, TextLayout.HorizontalAlignLeft);
                legendText.Bounds = new Rectangle(leftText, topText, boxWidth - leftText, lineHeight);
                legendView.Children.Add(legendText);
                topText += lineHeight;
            }
            TextView diskSizeText = new TextView("Estimated Disk Size " + GetPrettySize(_estimatedDiskSize),
                                                 new TextStyle(_legendStyle.Name, _legendStyle.Style, _legendStyle.Weight * 3 / 4),
                                                 Color.Black, TextLayout.HorizontalAlignCenter);

            diskSizeText.Bounds = new Rectangle(0, topText + lineHeight / 4, boxWidth, lineHeight);
            legendView.Children.Add(diskSizeText);
            topText += lineHeight;
        }
        private static void EnsureStyleTable()
        {
            if (DefaultTypeRamp.Length != AdaptiveConstants.KNOWN_TEXT_STYLES_COUNT)
            {
                throw new Exception("DefaultTypeRamp size is incorrect");
            }

            _stylesMap = new TextStylesMap();

            DefaultStyleInfo = new TextStyleInfo("CaptionTextBlockStyle", 0);

            _stylesMap.Add(new TextStyleInfoPair("caption", DefaultStyleInfo));
            _stylesMap.Add(new TextStyleInfoPair("body", new TextStyleInfo("BodyTextBlockStyle", 1)));
            _stylesMap.Add(new TextStyleInfoPair("base", new TextStyleInfo("BaseTextBlockStyle", 1)));
            _stylesMap.Add(new TextStyleInfoPair("subtitle", new TextStyleInfo("SubtitleTextBlockStyle", 2)));
            _stylesMap.Add(new TextStyleInfoPair("title", new TextStyleInfo("TitleTextBlockStyle", 3)));
            _stylesMap.Add(new TextStyleInfoPair("subheader", new TextStyleInfo("SubheaderTextBlockStyle", 4)));
            _stylesMap.Add(new TextStyleInfoPair("header", new TextStyleInfo("HeaderTextBlockStyle", 5)));
            _stylesMap.Add(new TextStyleInfoPair("titlenumeral", new TextStyleInfo("TitleTextBlockStyle", 6, TextLineBounds.Tight)));
            _stylesMap.Add(new TextStyleInfoPair("subheadernumeral", new TextStyleInfo("SubheaderTextBlockStyle", 7, TextLineBounds.Tight)));
            _stylesMap.Add(new TextStyleInfoPair("headernumeral", new TextStyleInfo("HeaderTextBlockStyle", 8, TextLineBounds.Tight)));
        }
        /// <summary>
        /// Returns the offset for the top item
        /// </summary>
        /// <param name="subgroups"></param>
        /// <returns></returns>
        private static double GetSubgroupsTopMarginOffset(IList <AdaptiveSubgroup> subgroups)
        {
            bool   hasImage  = false;
            double maxOffset = 0.0;

            // Look through each subgroup that has children
            foreach (var subgroup in subgroups.Where(i => i.Children.Any()))
            {
                var    firstNode  = subgroup.Children.Where(i => IsChildInline(i)).First();
                double itemOffset = 0;

                if (firstNode is AdaptiveTextField)
                {
                    bool          ignore;
                    TextStyleInfo textStyleInfo  = AdaptiveGenerator_Text.GetStyleIndex((firstNode as AdaptiveTextField).HintStyle, out ignore);
                    int           lineStyleIndex = textStyleInfo.Index;
                    itemOffset = AdaptiveGenerator_Text.DefaultTypeRamp[lineStyleIndex].TopOffset;
                }

                else if (firstNode is AdaptiveImage)
                {
                    hasImage = true;
                }

                if (itemOffset > maxOffset)
                {
                    maxOffset = itemOffset;
                }
            }

            if (hasImage && maxOffset < AdaptiveConstants.DefaultImageMargin)
            {
                maxOffset = AdaptiveConstants.DefaultImageMargin;
            }

            return(maxOffset);
        }
        private static TextStyleInfo GetStyleIndex(string styleName, out bool subtle)
        {
            const string subtleSuffix = "subtle";

            styleName = styleName.ToLower();

            subtle = styleName.EndsWith(subtleSuffix);
            if (subtle)
            {
                styleName = styleName.Substring(0, styleName.Length - subtleSuffix.Length);
            }

            TextStyleInfo textStyleInfo = _stylesMap.Find(styleName);

            // If not found
            if (textStyleInfo == null)
            {
                // Clear subtle style
                subtle = false;
                return(DefaultStyleInfo);
            }

            return(textStyleInfo);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="textField"></param>
        /// <param name="isFirst">Whether this is the first top-level item on the surface.</param>
        /// <param name="isFirstGroup">Whether this is inside a group.</param>
        /// <param name="previousLineStyleIndex"></param>
        /// <param name="topMarginOffset"></param>
        /// <param name="needsImageMargin"></param>
        /// <param name="lineStyleIndex"></param>
        /// <returns></returns>
        public static TextBlock GenerateText(
            AdaptiveTextField textField,
            bool isFirst,
            bool isFirstGroup,
            int previousLineStyleIndex,
            double topMarginOffset,
            bool needsImageMargin,
            out int lineStyleIndex)
        {
            lineStyleIndex = -1;

            TextBlock spTextBlock = new TextBlock()
            {
                //Foreground = TextBlockBrush,
                Text         = textField.Text,
                TextWrapping = DefaultTextWrapping
            };

            // Get the text style info
            bool          isSubtle;
            TextStyleInfo textStyleInfo = GetStyleIndex(textField.HintStyle, out isSubtle);

            // Set the XAML text style
            SetStyle(spTextBlock, textStyleInfo.XamlName);

            // If it's subtle
            if (isSubtle)
            {
                // Apply subtle opacity
                spTextBlock.Opacity = SubtleOpacity;
            }

            // Get the style index
            lineStyleIndex = textStyleInfo.Index;

            // Default top margin values for textblocks
            double topMargin;

            if (isFirst)
            {
                if (isFirstGroup)
                {
                    topMargin = DefaultTypeRamp[lineStyleIndex].FirstGroupMargin - AdaptiveConstants.DefaultExternalMargin;
                }

                else
                {
                    topMargin = topMarginOffset - DefaultTypeRamp[lineStyleIndex].TopOffset;
                }
            }

            else if (previousLineStyleIndex != -1)
            {
                topMargin = DefaultTypeRamp[previousLineStyleIndex].TopMarginValues[lineStyleIndex];
            }

            else if (needsImageMargin)
            {
                topMargin = AdaptiveConstants.DefaultImageMargin;
            }

            else
            {
                topMargin = DefaultTypeRamp[0].TopMarginValues[lineStyleIndex];
            }

            // Override if needed line height
            if (DefaultTypeRamp[lineStyleIndex].LineHeightOverride > 0.0)
            {
                spTextBlock.LineHeight = DefaultTypeRamp[lineStyleIndex].LineHeightOverride;
            }

            // Text wrapping
            if (textField.HintWrap.GetValueOrDefault(false))
            {
                spTextBlock.TextWrapping = TextWrapping.Wrap;
            }

            // Max lines
            if (textField.HintMaxLines != null)
            {
                spTextBlock.MaxLines = textField.HintMaxLines.Value;
            }

            // Align
            switch (textField.HintAlign)
            {
            case Model.Enums.HintAlign.Center:
                spTextBlock.TextAlignment = TextAlignment.Center;
                break;

            case Model.Enums.HintAlign.Right:
                spTextBlock.TextAlignment = TextAlignment.Right;
                break;

            case Model.Enums.HintAlign.Left:
            default:
                spTextBlock.TextAlignment = TextAlignment.Left;
                break;
            }
            spTextBlock.OpticalMarginAlignment = DefaultOpticalMarginAlignment;
            spTextBlock.TextLineBounds         = textStyleInfo.TextLineBounds;
            spTextBlock.TextTrimming           = DefaultTextTrimming;

            // Min lines (default of HintMinLines is 1)
            spTextBlock.MinHeight = textField.HintMinLines.GetValueOrDefault(1) * DefaultTypeRamp[lineStyleIndex].MinLineHeight;

            // Margins
            Thickness margins = new Thickness(0, topMargin, 0, 0);

            spTextBlock.Margin = margins;

            return(spTextBlock);
        }