public Form1() { InitializeComponent(); ResizeRedraw = true; this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true); /* * _richString = new RichString() * .FontSize(18).FontFamily("Open Sans") * .Alignment(TextAlignment.Center).MarginBottom(20) * .Add("CHARACTER SPACING!!", letterSpacing: 10, fontSize: 28) * .Paragraph() * .Alignment(TextAlignment.Left) * .Add("Para2a\nParam2b") * ; * var rs = new RichString() * .Alignment(TextAlignment.Center) * .FontFamily("Segoe UI") * .MarginBottom(20) * .Add("Welcome To RichTextKit", fontSize:24, fontWeight: 700, fontItalic: true) * .Paragraph().Alignment(TextAlignment.Left) * .FontSize(18) * .Add("This is a test string"); */ var rs = new RichString() .Add("Big text", fontSize: 40, letterSpacing: 0, backgroundColor: new SKColor(0xFFFF0000)) .Add("Little text", fontSize: 12, letterSpacing: 0); _richString = rs; }
public static string FromStyle(this string text, RichString rs) { string output = ""; if (rs.bold) { output += "<b>"; } if (rs.italic) { output += "<i>"; } if (rs.colored) { output += "<color=" + rs.Color + ">"; } output += text; if (rs.colored) { output += "</color>"; } if (rs.italic) { output += "</i>"; } if (rs.bold) { output += "</b>"; } return(output); }
public static SKImage SensorTitle(List <SensorReading> readings, SKColor readingColor) { var latestReading = readings.OrderByDescending(x => x.ReadingDateTime).First(); var fitSize = TextHelpers.AutoFitRichStringWidth( $"{latestReading.ReadingValue:0.0} - {latestReading.ReadingDateTime:M/dd HH}", "Arial", 360, 40); var titleRichString = new RichString() .FontFamily("Arial") .TextColor(SKColors.White) .FontSize(fitSize) .TextColor(readingColor) .Add($"{latestReading.ReadingValue:0.0}") .TextColor(SKColors.Gray) .Add(" - ") .TextColor(SKColors.White) .Add($"{latestReading.ReadingTag}"); var titleChartImage = new SKImageInfo(400, 50); var titleChartSurface = SKSurface.Create(titleChartImage); var titleChartCanvas = titleChartSurface.Canvas; var titleLeftStart = (400 - titleRichString.MeasuredWidth) / 2; titleRichString.Paint(titleChartCanvas, new SKPoint(titleLeftStart, 10)); titleChartCanvas.Save(); return(titleChartSurface.Snapshot()); }
public RichTextKitPage() { InitializeComponent(); richString = new RichString() .MarginLeft(12) .MarginTop(12) .MarginRight(12) .MarginBottom(12) .FontSize(18) .FontFamily("Segoe UI") .Add("Welcome to RichTextKit!\n", fontSize: 24, fontWeight: 700) .Add("\nRichTextKit is a rich text layout, rendering and measurement library for SkiaSharp.\n\nIt supports normal, ") .Add("bold", fontWeight: 700) .Add(", ") .Add("italic", fontItalic: true) .Add(", ") .Add("underline", underline: UnderlineStyle.Gapped) .Add(" (including ") .Add("gaps over descenders", underline: UnderlineStyle.Gapped) .Add("), ") .Add("strikethrough", strikeThrough: StrikeThroughStyle.Solid) .Add(", superscript (E=mc") .Add("2", fontVariant: FontVariant.SuperScript) .Add("), subscript (H") .Add("2", fontVariant: FontVariant.SubScript) .Add("O), ") .Add("colored ", textColor: SKColors.Red) .Add("text", textColor: SKColors.Blue) .Add(" and ") .Add("mixed ") .Add("sizes, ", fontSize: 12) .Add("widths", fontFamily: "Consolas") .Add(" and ") .Add("fonts", fontFamily: "Segoe Script") .Add(".\n\n") .Add("Font fallback means emojis work: 🌐 🍪 🍕 🚀 and ") .Add("text shaping and bi-directional text support means complex scripts and languages like Arabic: مرحبا بالعالم, Japanese: ハローワールド, Chinese: 世界您好 and Hindi: हैलो वर्ल्ड are rendered correctly!\n\n") .Add("RichTextKit also supports left/center/right text alignment, word wrapping, truncation with ellipsis place-holder, text measurement, hit testing, painting a selection range, caret position & shape helpers.") .Paragraph() .Add(LipsumGenerator.Generate(1)); }
public static float AutoFitRichStringWidth(string stringContents, string fontFamily, int maxWidth, int maxHeight) { var fontSize = 1; var testString = new RichString() .FontFamily(fontFamily) .FontSize(fontSize) .Add(stringContents); while (testString.MeasuredWidth < maxWidth && testString.MeasuredHeight < maxHeight) { testString = new RichString() .FontFamily(fontFamily) .FontSize(++fontSize) .Add(stringContents); } return(fontSize); }
public static void DrawItem(SKCanvas canvas, Item item, Lang lang, SKRect rect) { Console.Out.WriteLine($"[{lang}] {item.name.GetText(lang)}".AsSpan()); DrawItemBackground(canvas, rect); SKRect padded = new(rect.Left + itemPadding, rect.Top + itemPadding, rect.Right - itemPadding, rect.Bottom); float imageHeight = padded.Height * 0.4f; float nameHeight = padded.Height * 0.2f; float descHeight = padded.Height * 0.4f; SKRect imageRect = crect(padded.Left, padded.Top, padded.Width, imageHeight); SKRect nameRect = crect(padded.Left + 3, padded.Top + imageHeight, padded.Width - 5, nameHeight); SKRect descRect = crect(padded.Left + 3, padded.Top + imageHeight + nameHeight, padded.Width - 5, descHeight); var scaled = item.GetScaledBitmap(imageRect); if (scaled != null) { var imageDestRect = CalculateDisplayRect(imageRect, scaled, BitmapAlignment.Start, BitmapAlignment.Center); canvas.DrawBitmap(scaled, imageDestRect.Left + 5, imageDestRect.Top); } #region Draw Name RichString name = new RichString() { MaxWidth = nameRect.Width, DefaultStyle = nameStyle, }.Add(item.name.GetText(lang)); name.MaxLines = 1; name.Paint(canvas, new SKPoint(nameRect.Left, nameRect.Top + 4), paintOptions); #endregion Draw Name RichString desc = new RichString() { MaxWidth = nameRect.Width, MaxHeight = null, DefaultStyle = descStyle, }.Add(item.description.GetText(lang)); desc.MaxLines = 20; desc.Paint(canvas, new SKPoint(descRect.Left, descRect.Top + 1), paintOptions); }
public static void DrawLabel(SKCanvas canvas, MetaType metaType, Lang lang, SKRect rect) { var lineR = rect; lineR.Inflate(-(canvasMaxWidth * 0.8f), -(itemMargin * 2.4f)); //top //canvas.DrawLine(new SKPoint(lineR.Left, lineR.Top), new SKPoint(lineR.Right, lineR.Top), labelLine); //bottom canvas.DrawLine(new SKPoint(lineR.Left, lineR.Bottom), new SKPoint(lineR.Right, lineR.Bottom), labelLine); string labelName = "- " + GetMetaTypeLabel(lang, metaType) + " -"; RichString desc = new RichString() { DefaultStyle = labelStyle, MaxLines = 1, }.Add(labelName); const int offsetY = 3; int ori = canvas.SaveLayer(labelPaint); desc.Paint(canvas, new SKPoint(rect.MidX - desc.MeasuredWidth / 2, rect.MidY - desc.MeasuredHeight / 2 - offsetY), paintOptions); canvas.RestoreToCount(ori); }
public static void DrawCaptionLabels(this SKCanvas canvas, string label, SKColor labelColor, TextDirection textDirection, float labelTextSpacing, string value, SKColor valueColor, float textSize, SKPoint point, SKTextAlign horizontalAlignment, SKTypeface typeface, out SKRect totalBounds) { var hasLabel = !string.IsNullOrEmpty(label); var hasValueLabel = !string.IsNullOrEmpty(value); totalBounds = new SKRect(); if (hasLabel || hasValueLabel) { var hasOffset = hasLabel && hasValueLabel; var captionMargin = textSize * 0.60f; var space = hasOffset ? captionMargin : 0; if (hasLabel) { using (var paint = new SKPaint { TextSize = textSize, IsAntialias = true, Color = labelColor, IsStroke = false, TextAlign = horizontalAlignment, Typeface = typeface }) { var bounds = new SKRect(); var text = label; paint.MeasureText(text, ref bounds); var y = point.Y - ((bounds.Top + bounds.Bottom) / 2) - space; RichString rs; if (typeface != null) { rs = new RichString() .FontFamily(typeface.FamilyName) .FontSize(textSize) .LetterSpacing(labelTextSpacing) .TextColor(labelColor) .TextDirection(textDirection) .Add(text); } else { rs = new RichString() .FontSize(textSize) .LetterSpacing(labelTextSpacing) .TextColor(labelColor) .TextDirection(textDirection) .Add(text); } rs.Paint(canvas, new SKPoint(point.X, y), new TextPaintOptions { IsAntialias = true, LcdRenderText = true }); var labelBounds = GetAbsolutePositionRect(point.X, y, bounds, horizontalAlignment); totalBounds = labelBounds.Standardized; } } if (hasValueLabel) { using (var paint = new SKPaint() { TextSize = textSize, IsAntialias = true, FakeBoldText = true, Color = valueColor, IsStroke = false, TextAlign = horizontalAlignment, Typeface = typeface }) { var bounds = new SKRect(); var text = value; paint.MeasureText(text, ref bounds); var y = point.Y - ((bounds.Top + bounds.Bottom) / 2) + space; canvas.DrawText(text, point.X, y, paint); var valueBounds = GetAbsolutePositionRect(point.X, y, bounds, horizontalAlignment); if (totalBounds.IsEmpty) { totalBounds = valueBounds; } else { totalBounds.Union(valueBounds); } } } } }
public void DrawString(RichString richString, Point position) { this.DrawString(position, richString.Font, richString.Text, richString.TextSize, richString.Color, richString.Bold, richString.Italic, richString.Underline); }
public Size MeasureTextSize(RichString richString) { return this.MeasureTextSize(richString.Text, richString.TextSize, richString.Bold); }
public RichString CreateRichString(string fragment) { RichString richString = new RichString(fragment); richString.Font = activeFont; richString.TextSize = activeTextSize; richString.Color = activeColor; richString.Bold = activeBold; richString.Italic = activeItalic; richString.Underline = activeUnderline; richString.NewLine = activeNewLine; richString.Modified = false; activeNewLine = false; return richString; }
public void Append(RichString richString) { if(richString.NewLine) { nextStringPoint.X = 0; nextStringPoint.Y += lineSize; lineSize = 0; } lineSize = Math.Max(lineSize, richString.Size.Height); RichLabelString richLabelString = new RichLabelString(richString); if(nextStringPoint.X + richLabelString.RichString.Size.Width > Bounds.Width) { // if the text will not fit on this line string str = richLabelString.RichString.Text; if(str.Contains(" ")) { // if there are multiple words List<string> fragments = new List<string>(); List<Point> points = new List<Point>(); while(nextStringPoint.X + richLabelString.RichString.Font.MeasureTextSize(str, richLabelString.RichString.TextSize, richLabelString.RichString.Bold).Width > Bounds.Width) { // while there's remaining text that can't fit int bestMatch = 0; while(true) { // it matches for the best point of splitting int nextMatch = str.IndexOf(' ', bestMatch + 1); if(nextMatch != -1) { // if there is another space after the best match if(nextStringPoint.X + richLabelString.RichString.Font.MeasureTextSize( str.Substring(0, nextMatch), richLabelString.RichString.TextSize, richLabelString.RichString.Bold ).Width > Bounds.Width) break; // if it doesn't fit, abort else bestMatch = nextMatch; // otherwise the line can hold this much } else break; } if(bestMatch == 0) bestMatch = str.IndexOf(" "); if(bestMatch == -1) bestMatch = str.Length - 1; fragments.Add(str.Substring(0, bestMatch)); points.Add(nextStringPoint); nextStringPoint.X = 0; nextStringPoint.Y += lineSize; str = str.Substring(bestMatch + 1); } if(str.Length > 0) { // put the remnants fragments.Add(str); points.Add(nextStringPoint); nextStringPoint.X += richLabelString.RichString.Font.MeasureTextSize(str, richLabelString.RichString.TextSize, richLabelString.RichString.Bold).Width; } richLabelString.StringPoints = points.ToArray(); richLabelString.StringFragments = fragments.ToArray(); } else { // there is only one word, put it on the next line nextStringPoint.X = 0; nextStringPoint.Y += lineSize; richLabelString.StringPoints = new Point[]{ nextStringPoint }; nextStringPoint.X += richLabelString.RichString.Size.Width; lineSize = richLabelString.RichString.Size.Height; } } else { richLabelString.StringPoints = new Point[]{ nextStringPoint }; nextStringPoint.X += richLabelString.RichString.Size.Width; } this.MaxSize = new Size(this.Bounds.Width, richLabelString.StringPoints.Last().Y + richLabelString.RichString.Size.Height); text.Add(richLabelString); }
internal RichLabelString(RichString richString) : this() { RichString = richString; }