diff --git a/QuestPDF.ReportSample/Layouts/ImageTemplate.cs b/QuestPDF.ReportSample/Layouts/ImageTemplate.cs index 673d470..0e3eca8 100644 --- a/QuestPDF.ReportSample/Layouts/ImageTemplate.cs +++ b/QuestPDF.ReportSample/Layouts/ImageTemplate.cs @@ -1,5 +1,6 @@ using System; using QuestPDF.Fluent; +using QuestPDF.Helpers; using QuestPDF.Infrastructure; namespace QuestPDF.ReportSample.Layouts @@ -24,7 +25,7 @@ namespace QuestPDF.ReportSample.Layouts { container .AspectRatio(AspectRatio) - .Background("#EEEEEE") + .Background(Colors.Grey.Lighten3) .Image(Source(Size.Zero)); } } diff --git a/QuestPDF.ReportSample/Layouts/PhotoTemplate.cs b/QuestPDF.ReportSample/Layouts/PhotoTemplate.cs index 8384147..f2a4c7d 100644 --- a/QuestPDF.ReportSample/Layouts/PhotoTemplate.cs +++ b/QuestPDF.ReportSample/Layouts/PhotoTemplate.cs @@ -48,13 +48,13 @@ namespace QuestPDF.ReportSample.Layouts { grid.Columns(6); - grid.Item().LabelCell().Text("Date", Typography.Normal); - grid.Item(2).ValueCell().Text(Model.Date?.ToString("g") ?? string.Empty, Typography.Normal); - grid.Item().LabelCell().Text("Location", Typography.Normal); - grid.Item(2).ValueCell().Text(Model.Location.Format(), Typography.Normal); + grid.Item().LabelCell().Text("Date"); + grid.Item(2).ValueCell().Text(Model.Date?.ToString("g") ?? string.Empty); + grid.Item().LabelCell().Text("Location"); + grid.Item(2).ValueCell().Text(Model.Location.Format()); - grid.Item().LabelCell().Text("Comments", Typography.Normal); - grid.Item(5).ValueCell().Text(Model.Comments, Typography.Normal); + grid.Item().LabelCell().Text("Comments"); + grid.Item(5).ValueCell().Text(Model.Comments); }); } } diff --git a/QuestPDF.ReportSample/Layouts/SectionTemplate.cs b/QuestPDF.ReportSample/Layouts/SectionTemplate.cs index f8da682..8142da9 100644 --- a/QuestPDF.ReportSample/Layouts/SectionTemplate.cs +++ b/QuestPDF.ReportSample/Layouts/SectionTemplate.cs @@ -30,11 +30,11 @@ namespace QuestPDF.ReportSample.Layouts { stack.Item().EnsureSpace(25).Row(row => { - row.ConstantColumn(150).LabelCell().Text(part.Label, Typography.Normal); + row.ConstantColumn(150).LabelCell().Text(part.Label); var frame = row.RelativeColumn().ValueCell(); if (part is ReportSectionText text) - frame.ShowEntire().Text(text.Text, Typography.Normal); + frame.ShowEntire().Text(text.Text); if (part is ReportSectionMap map) frame.Element(x => MapElement(x, map)); @@ -51,7 +51,7 @@ namespace QuestPDF.ReportSample.Layouts { if (model.ImageSource == null || model.Location == null) { - container.Text("No location provided", Typography.Normal); + container.Text("No location provided"); return; } @@ -60,7 +60,7 @@ namespace QuestPDF.ReportSample.Layouts stack.Spacing(5); stack.Item().MaxWidth(250).AspectRatio(4 / 3f).Image(Placeholders.Image); - stack.Item().Text(model.Location.Format(), Typography.Normal); + stack.Item().Text(model.Location.Format()); }); } @@ -68,7 +68,7 @@ namespace QuestPDF.ReportSample.Layouts { if (model.Photos.Count == 0) { - container.Text("No photos", Typography.Normal); + container.Text("No photos"); return; } diff --git a/QuestPDF.ReportSample/Layouts/StandardReport.cs b/QuestPDF.ReportSample/Layouts/StandardReport.cs index c130b82..61a9150 100644 --- a/QuestPDF.ReportSample/Layouts/StandardReport.cs +++ b/QuestPDF.ReportSample/Layouts/StandardReport.cs @@ -25,6 +25,7 @@ namespace QuestPDF.ReportSample.Layouts public void Compose(IDocumentContainer container) { container + .DefaultTextStyle(Typography.Normal) .Page(page => { page.MarginVertical(40); @@ -37,8 +38,6 @@ namespace QuestPDF.ReportSample.Layouts page.Footer().AlignCenter().Text(text => { - text.DefaultTextStyle(Typography.Normal); - text.CurrentPageNumber(); text.Span(" / "); text.TotalPages(); @@ -69,8 +68,8 @@ namespace QuestPDF.ReportSample.Layouts { grid.Item().Text(text => { - text.Span($"{field.Label}: ", Typography.Normal.SemiBold()); - text.Span(field.Value, Typography.Normal); + text.Span($"{field.Label}: ", TextStyle.Default.SemiBold()); + text.Span(field.Value); }); } }); diff --git a/QuestPDF.ReportSample/Layouts/TableOfContentsTemplate.cs b/QuestPDF.ReportSample/Layouts/TableOfContentsTemplate.cs index 087cfff..64ff8f2 100644 --- a/QuestPDF.ReportSample/Layouts/TableOfContentsTemplate.cs +++ b/QuestPDF.ReportSample/Layouts/TableOfContentsTemplate.cs @@ -41,9 +41,9 @@ namespace QuestPDF.ReportSample.Layouts .InternalLink(locationName) .Row(row => { - row.ConstantColumn(25).Text($"{number}.", Typography.Normal); - row.RelativeColumn().Text(locationName, Typography.Normal); - row.ConstantColumn(150).AlignRight().Text(text => text.PageNumberOfLocation(locationName, Typography.Normal)); + row.ConstantColumn(25).Text($"{number}."); + row.RelativeColumn().Text(locationName); + row.ConstantColumn(150).AlignRight().Text(text => text.PageNumberOfLocation(locationName)); }); } } diff --git a/QuestPDF.ReportSample/Typography.cs b/QuestPDF.ReportSample/Typography.cs index 1d8992c..434bf37 100644 --- a/QuestPDF.ReportSample/Typography.cs +++ b/QuestPDF.ReportSample/Typography.cs @@ -8,6 +8,6 @@ namespace QuestPDF.ReportSample { public static TextStyle Title => TextStyle.Default.FontType(Fonts.Calibri).Color(Colors.Blue.Darken3).Size(26).Black(); public static TextStyle Headline => TextStyle.Default.FontType(Fonts.Calibri).Color(Colors.Blue.Medium).Size(16).SemiBold(); - public static TextStyle Normal => TextStyle.Default.FontType(Fonts.Calibri).Color(Colors.Black).Size(11).LineHeight(1.1f); + public static TextStyle Normal => TextStyle.Default.FontType(Fonts.Verdana).Color(Colors.Black).Size(10).LineHeight(1.2f); } } \ No newline at end of file diff --git a/QuestPDF/Drawing/DocumentContainer.cs b/QuestPDF/Drawing/DocumentContainer.cs index e813839..9f593e2 100644 --- a/QuestPDF/Drawing/DocumentContainer.cs +++ b/QuestPDF/Drawing/DocumentContainer.cs @@ -9,6 +9,7 @@ namespace QuestPDF.Drawing { internal class DocumentContainer : IDocumentContainer { + internal TextStyle DefaultTextStyle { get; set; } = TextStyle.Default; internal List Pages { get; set; } = new List(); internal Container Compose() diff --git a/QuestPDF/Drawing/DocumentGenerator.cs b/QuestPDF/Drawing/DocumentGenerator.cs index f7fbb59..364c98c 100644 --- a/QuestPDF/Drawing/DocumentGenerator.cs +++ b/QuestPDF/Drawing/DocumentGenerator.cs @@ -1,9 +1,12 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using QuestPDF.Drawing.Exceptions; using QuestPDF.Drawing.SpacePlan; using QuestPDF.Elements; +using QuestPDF.Elements.Text; +using QuestPDF.Elements.Text.Items; using QuestPDF.Infrastructure; namespace QuestPDF.Drawing @@ -36,6 +39,7 @@ namespace QuestPDF.Drawing var metadata = document.GetMetadata(); var pageContext = new PageContext(); + ApplyDefaultTextStyle(content, container.DefaultTextStyle); RenderPass(pageContext, new FreeCanvas(), content, metadata); RenderPass(pageContext, canvas, content, metadata); } @@ -93,5 +97,27 @@ namespace QuestPDF.Drawing throw new DocumentLayoutException("Composed layout generates infinite document."); } } + + private static void ApplyDefaultTextStyle(Element content, TextStyle documentDefaultTextStyle) + { + documentDefaultTextStyle.ApplyGlobalStyle(TextStyle.LibraryDefault); + + content.HandleVisitor(element => + { + var text = element as TextBlock; + + if (text == null) + return; + + foreach (var child in text.Children) + { + if (child is TextBlockSpan textSpan) + textSpan.Style.ApplyGlobalStyle(documentDefaultTextStyle); + + if (child is TextBlockElement textElement) + ApplyDefaultTextStyle(textElement.Element, documentDefaultTextStyle); + } + }); + } } } \ No newline at end of file diff --git a/QuestPDF/Drawing/FontManager.cs b/QuestPDF/Drawing/FontManager.cs index 319eec7..19d8f5d 100644 --- a/QuestPDF/Drawing/FontManager.cs +++ b/QuestPDF/Drawing/FontManager.cs @@ -34,7 +34,7 @@ namespace QuestPDF.Drawing internal static SKPaint ToPaint(this TextStyle style) { - return Paints.GetOrAdd(style.ToString(), key => Convert(style)); + return Paints.GetOrAdd(style.Key, key => Convert(style)); static SKPaint Convert(TextStyle style) { @@ -42,7 +42,7 @@ namespace QuestPDF.Drawing { Color = SKColor.Parse(style.Color), Typeface = GetTypeface(style), - TextSize = style.Size, + TextSize = (style.Size ?? 12), TextEncoding = SKTextEncoding.Utf32 }; } @@ -52,16 +52,16 @@ namespace QuestPDF.Drawing if (Typefaces.TryGetValue(style.FontType, out var result)) return result; - var slant = style.IsItalic ? SKFontStyleSlant.Italic : SKFontStyleSlant.Upright; + var slant = (style.IsItalic ?? false) ? SKFontStyleSlant.Italic : SKFontStyleSlant.Upright; - return SKTypeface.FromFamilyName(style.FontType, (int)style.FontWeight, (int)SKFontStyleWidth.Normal, slant) + return SKTypeface.FromFamilyName(style.FontType, (int)(style.FontWeight ?? FontWeight.Normal), (int)SKFontStyleWidth.Normal, slant) ?? throw new ArgumentException($"The typeface {style.FontType} could not be found."); } } internal static SKFontMetrics ToFontMetrics(this TextStyle style) { - return FontMetrics.GetOrAdd(style.ToString(), key => style.ToPaint().FontMetrics); + return FontMetrics.GetOrAdd(style.Key, key => style.ToPaint().FontMetrics); } } } \ No newline at end of file diff --git a/QuestPDF/Elements/Text/Items/ITextBlockItem.cs b/QuestPDF/Elements/Text/Items/ITextBlockItem.cs index 581dcc9..570087b 100644 --- a/QuestPDF/Elements/Text/Items/ITextBlockItem.cs +++ b/QuestPDF/Elements/Text/Items/ITextBlockItem.cs @@ -1,4 +1,5 @@ using QuestPDF.Elements.Text.Calculation; +using QuestPDF.Infrastructure; namespace QuestPDF.Elements.Text.Items { diff --git a/QuestPDF/Elements/Text/Items/TextBlockExternalLink.cs b/QuestPDF/Elements/Text/Items/TextBlockExternalLink.cs index 9eac125..5337fca 100644 --- a/QuestPDF/Elements/Text/Items/TextBlockExternalLink.cs +++ b/QuestPDF/Elements/Text/Items/TextBlockExternalLink.cs @@ -3,33 +3,22 @@ using QuestPDF.Infrastructure; namespace QuestPDF.Elements.Text.Items { - internal class TextBlockExternalLink : ITextBlockItem + internal class TextBlockExternalLink : TextBlockSpan { - public TextStyle Style { get; set; } = new TextStyle(); - public string Text { get; set; } public string Url { get; set; } - public TextMeasurementResult? Measure(TextMeasurementRequest request) + public override TextMeasurementResult? Measure(TextMeasurementRequest request) { - return GetItem().MeasureWithoutCache(request); + return MeasureWithoutCache(request); } - public void Draw(TextDrawingRequest request) + public override void Draw(TextDrawingRequest request) { request.Canvas.Translate(new Position(0, request.TotalAscent)); request.Canvas.DrawExternalLink(Url, new Size(request.TextSize.Width, request.TextSize.Height)); request.Canvas.Translate(new Position(0, -request.TotalAscent)); - GetItem().Draw(request); - } - - private TextBlockSpan GetItem() - { - return new TextBlockSpan - { - Style = Style, - Text = Text - }; + base.Draw(request); } } } \ No newline at end of file diff --git a/QuestPDF/Elements/Text/Items/TextBlockInternalLink.cs b/QuestPDF/Elements/Text/Items/TextBlockInternalLink.cs index 914cd61..6b28113 100644 --- a/QuestPDF/Elements/Text/Items/TextBlockInternalLink.cs +++ b/QuestPDF/Elements/Text/Items/TextBlockInternalLink.cs @@ -3,33 +3,22 @@ using QuestPDF.Infrastructure; namespace QuestPDF.Elements.Text.Items { - internal class TextBlockInternalLink : ITextBlockItem + internal class TextBlockInternalLink : TextBlockSpan { - public TextStyle Style { get; set; } = new TextStyle(); - public string Text { get; set; } public string LocationName { get; set; } - public TextMeasurementResult? Measure(TextMeasurementRequest request) + public override TextMeasurementResult? Measure(TextMeasurementRequest request) { - return GetItem().MeasureWithoutCache(request); + return MeasureWithoutCache(request); } - public void Draw(TextDrawingRequest request) + public override void Draw(TextDrawingRequest request) { request.Canvas.Translate(new Position(0, request.TotalAscent)); request.Canvas.DrawLocationLink(LocationName, new Size(request.TextSize.Width, request.TextSize.Height)); request.Canvas.Translate(new Position(0, -request.TotalAscent)); - GetItem().Draw(request); - } - - private TextBlockSpan GetItem() - { - return new TextBlockSpan - { - Style = Style, - Text = Text - }; + base.Draw(request); } } } \ No newline at end of file diff --git a/QuestPDF/Elements/Text/Items/TextBlockPageNumber.cs b/QuestPDF/Elements/Text/Items/TextBlockPageNumber.cs index fda65ac..85a829d 100644 --- a/QuestPDF/Elements/Text/Items/TextBlockPageNumber.cs +++ b/QuestPDF/Elements/Text/Items/TextBlockPageNumber.cs @@ -3,34 +3,31 @@ using QuestPDF.Infrastructure; namespace QuestPDF.Elements.Text.Items { - internal class TextBlockPageNumber : ITextBlockItem + internal class TextBlockPageNumber : TextBlockSpan { - public TextStyle Style { get; set; } = new TextStyle(); public string SlotName { get; set; } - public TextMeasurementResult? Measure(TextMeasurementRequest request) + public override TextMeasurementResult? Measure(TextMeasurementRequest request) { - return GetItem(request.PageContext).MeasureWithoutCache(request); + SetPageNumber(request.PageContext); + return MeasureWithoutCache(request); } - public void Draw(TextDrawingRequest request) + public override void Draw(TextDrawingRequest request) { - GetItem(request.PageContext).Draw(request); + SetPageNumber(request.PageContext); + base.Draw(request); } - private TextBlockSpan GetItem(IPageContext context) + private void SetPageNumber(IPageContext context) { var pageNumberPlaceholder = 123; var pageNumber = context.GetRegisteredLocations().Contains(SlotName) ? context.GetLocationPage(SlotName) : pageNumberPlaceholder; - - return new TextBlockSpan - { - Style = Style, - Text = pageNumber.ToString() - }; + + Text = pageNumber.ToString(); } } } \ No newline at end of file diff --git a/QuestPDF/Elements/Text/Items/TextBlockSpan.cs b/QuestPDF/Elements/Text/Items/TextBlockSpan.cs index 2c0e4b2..a8d0436 100644 --- a/QuestPDF/Elements/Text/Items/TextBlockSpan.cs +++ b/QuestPDF/Elements/Text/Items/TextBlockSpan.cs @@ -14,7 +14,7 @@ namespace QuestPDF.Elements.Text.Items private Dictionary<(int startIndex, float availableWidth), TextMeasurementResult?> MeasureCache = new Dictionary<(int startIndex, float availableWidth), TextMeasurementResult?>(); - public TextMeasurementResult? Measure(TextMeasurementRequest request) + public virtual TextMeasurementResult? Measure(TextMeasurementRequest request) { var cacheKey = (request.StartIndex, request.AvailableWidth); @@ -45,7 +45,7 @@ namespace QuestPDF.Elements.Text.Items { Width = 0, - LineHeight = Style.LineHeight, + LineHeight = Style.LineHeight ?? 1, Ascent = fontMetrics.Ascent, Descent = fontMetrics.Descent }; @@ -96,7 +96,7 @@ namespace QuestPDF.Elements.Text.Items Ascent = fontMetrics.Ascent, Descent = fontMetrics.Descent, - LineHeight = Style.LineHeight, + LineHeight = Style.LineHeight ?? 1, StartIndex = startIndex, EndIndex = endIndex, @@ -105,7 +105,7 @@ namespace QuestPDF.Elements.Text.Items }; } - public void Draw(TextDrawingRequest request) + public virtual void Draw(TextDrawingRequest request) { var fontMetrics = Style.ToFontMetrics(); @@ -115,12 +115,12 @@ namespace QuestPDF.Elements.Text.Items request.Canvas.DrawText(text, Position.Zero, Style); // draw underline - if (Style.HasUnderline && fontMetrics.UnderlinePosition.HasValue) - DrawLine(fontMetrics.UnderlinePosition.Value, fontMetrics.UnderlineThickness.Value); + if ((Style.HasUnderline ?? false) && fontMetrics.UnderlinePosition.HasValue) + DrawLine(fontMetrics.UnderlinePosition.Value, fontMetrics.UnderlineThickness ?? 1); // draw stroke - if (Style.HasStrikethrough && fontMetrics.StrikeoutPosition.HasValue) - DrawLine(fontMetrics.StrikeoutPosition.Value, fontMetrics.StrikeoutThickness.Value); + if ((Style.HasStrikethrough ?? false) && fontMetrics.StrikeoutPosition.HasValue) + DrawLine(fontMetrics.StrikeoutPosition.Value, fontMetrics.StrikeoutThickness ?? 1); void DrawLine(float offset, float thickness) { diff --git a/QuestPDF/Fluent/PageExtensions.cs b/QuestPDF/Fluent/PageExtensions.cs index 24a35a8..f2c530c 100644 --- a/QuestPDF/Fluent/PageExtensions.cs +++ b/QuestPDF/Fluent/PageExtensions.cs @@ -94,6 +94,12 @@ namespace QuestPDF.Fluent public static class PageExtensions { + public static IDocumentContainer DefaultTextStyle(this IDocumentContainer document, TextStyle textStyle) + { + (document as DocumentContainer).DefaultTextStyle = textStyle; + return document; + } + public static IDocumentContainer Page(this IDocumentContainer document, Action handler) { var descriptor = new PageDescriptor(); diff --git a/QuestPDF/Fluent/TextExtensions.cs b/QuestPDF/Fluent/TextExtensions.cs index dd8eb3c..71036ab 100644 --- a/QuestPDF/Fluent/TextExtensions.cs +++ b/QuestPDF/Fluent/TextExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using QuestPDF.Drawing; using QuestPDF.Elements; using QuestPDF.Elements.Text; using QuestPDF.Elements.Text.Items; @@ -13,7 +14,7 @@ namespace QuestPDF.Fluent { private ICollection TextBlocks { get; } = new List(); private TextStyle DefaultStyle { get; set; } = TextStyle.Default; - private HorizontalAlignment Alignment { get; set; } = HorizontalAlignment.Left; + internal HorizontalAlignment Alignment { get; set; } = HorizontalAlignment.Left; private float Spacing { get; set; } = 0f; public void DefaultTextStyle(TextStyle style) @@ -51,7 +52,7 @@ namespace QuestPDF.Fluent public void Span(string text, TextStyle? style = null) { - style ??= DefaultStyle; + style ??= TextStyle.Default; var items = text .Replace("\r", string.Empty) @@ -92,7 +93,7 @@ namespace QuestPDF.Fluent private void PageNumber(string slotName, TextStyle? style = null) { - style ??= DefaultStyle; + style ??= TextStyle.Default; AddItemToLastTextBlock(new TextBlockPageNumber() { @@ -118,7 +119,7 @@ namespace QuestPDF.Fluent public void InternalLocation(string text, string locationName, TextStyle? style = null) { - style ??= DefaultStyle; + style ??= TextStyle.Default; AddItemToLastTextBlock(new TextBlockInternalLink { @@ -130,7 +131,7 @@ namespace QuestPDF.Fluent public void ExternalLocation(string text, string url, TextStyle? style = null) { - style ??= DefaultStyle; + style ??= TextStyle.Default; AddItemToLastTextBlock(new TextBlockExternalLink { @@ -156,6 +157,9 @@ namespace QuestPDF.Fluent { TextBlocks.ToList().ForEach(x => x.Alignment = Alignment); + foreach (var textBlockSpan in TextBlocks.SelectMany(x => x.Children).Where(x => x is TextBlockSpan).Cast()) + textBlockSpan.Style.ApplyParentStyle(DefaultStyle); + container.Stack(stack => { stack.Spacing(Spacing); @@ -170,12 +174,11 @@ namespace QuestPDF.Fluent { public static void Text(this IContainer element, Action content) { - var textBlock = new TextBlock(); - - if (element is Alignment alignment) - textBlock.Alignment = alignment.Horizontal; - var descriptor = new TextDescriptor(); + + if (element is Alignment alignment) + descriptor.Alignment = alignment.Horizontal; + content?.Invoke(descriptor); descriptor.Compose(element); } diff --git a/QuestPDF/Infrastructure/TextStyle.cs b/QuestPDF/Infrastructure/TextStyle.cs index 76bbd99..545d7db 100644 --- a/QuestPDF/Infrastructure/TextStyle.cs +++ b/QuestPDF/Infrastructure/TextStyle.cs @@ -1,29 +1,70 @@ -using QuestPDF.Helpers; +using System; +using QuestPDF.Helpers; namespace QuestPDF.Infrastructure { public class TextStyle { - internal string Color { get; set; } = Colors.Black; - internal string BackgroundColor { get; set; } = Colors.Transparent; - internal string FontType { get; set; } = "Calibri"; - internal float Size { get; set; } = 12; - internal float LineHeight { get; set; } = 1.2f; - internal FontWeight FontWeight { get; set; } = FontWeight.Normal; - internal bool IsItalic { get; set; } = false; - internal bool HasStrikethrough { get; set; } = false; - internal bool HasUnderline { get; set; } = false; - - public static TextStyle Default => new TextStyle(); - - private string? KeyCache { get; set; } + internal bool HasGlobalStyleApplied { get; private set; } - public override string ToString() + internal string? Color { get; set; } + internal string? BackgroundColor { get; set; } + internal string? FontType { get; set; } + internal float? Size { get; set; } + internal float? LineHeight { get; set; } + internal FontWeight? FontWeight { get; set; } + internal bool? IsItalic { get; set; } + internal bool? HasStrikethrough { get; set; } + internal bool? HasUnderline { get; set; } + + internal string? Key { get; private set; } + + internal static TextStyle LibraryDefault => new TextStyle { - KeyCache ??= $"{Color}|{BackgroundColor}|{FontType}|{Size}|{LineHeight}|{FontWeight}|{IsItalic}|{HasStrikethrough}|{HasUnderline}"; - return KeyCache; + Color = Colors.Black, + BackgroundColor = Colors.Transparent, + FontType = Fonts.Calibri, + Size = 12, + LineHeight = 1.2f, + FontWeight = Infrastructure.FontWeight.Normal, + IsItalic = false, + HasStrikethrough = false, + HasUnderline = false + }; + + private static TextStyle DefaultTextStyleCache = new TextStyle(); + public static TextStyle Default => DefaultTextStyleCache; + + internal void ApplyGlobalStyle(TextStyle globalStyle) + { + if (HasGlobalStyleApplied) + return; + + HasGlobalStyleApplied = true; + + ApplyParentStyle(globalStyle); + + Key ??= $"{Color}|{BackgroundColor}|{FontType}|{Size}|{LineHeight}|{FontWeight}|{IsItalic}|{HasStrikethrough}|{HasUnderline}"; + } + + internal void ApplyParentStyle(TextStyle parentStyle) + { + Color ??= parentStyle.Color; + BackgroundColor ??= parentStyle.BackgroundColor; + FontType ??= parentStyle.FontType; + Size ??= parentStyle.Size; + LineHeight ??= parentStyle.LineHeight; + FontWeight ??= parentStyle.FontWeight; + IsItalic ??= parentStyle.IsItalic; + HasStrikethrough ??= parentStyle.HasStrikethrough; + HasUnderline ??= parentStyle.HasUnderline; } - internal TextStyle Clone() => (TextStyle)MemberwiseClone(); + internal TextStyle Clone() + { + var clone = (TextStyle)MemberwiseClone(); + clone.HasGlobalStyleApplied = false; + return clone; + } } } \ No newline at end of file