Skip to content
This repository has been archived by the owner on Dec 21, 2023. It is now read-only.

Implement drawn Label control #136

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/GraphicsControls.Sample/MainPage.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using Microsoft.Maui;
using Microsoft.Maui.ApplicationModel;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Graphics;
using System;

namespace GraphicsControls.Sample
Expand Down Expand Up @@ -202,7 +201,7 @@ IView CreateFooter()
var footer = new Label
{
FontSize = 10,
Text = "Microsoft Corporation 2021",
Text = "Microsoft Corporation 2023",
HorizontalOptions = LayoutOptions.Center,
TextColor = SampleColors.LightTextColor
};
Expand Down
8 changes: 8 additions & 0 deletions src/GraphicsControls/Handlers/Label/ILabelDrawable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Microsoft.Maui.Graphics.Controls
{
public interface ILabelDrawable : IViewDrawable<ILabel>
{
void DrawBackground(ICanvas canvas, RectF dirtyRect, ILabel view);
void DrawText(ICanvas canvas, RectF dirtyRect, ILabel view);
}
}
74 changes: 74 additions & 0 deletions src/GraphicsControls/Handlers/Label/LabelDrawable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
namespace Microsoft.Maui.Graphics.Controls
{
public class LabelDrawable : ViewDrawable<ILabel>, ILabelDrawable
{
public void DrawBackground(ICanvas canvas, RectF dirtyRect, ILabel label)
{
if (label.Background is null)
return;

canvas.SaveState();

canvas.SetFillPaint(label.Background, dirtyRect);

var x = dirtyRect.X;
var y = dirtyRect.Y;

var height = dirtyRect.Height;
var width = dirtyRect.Width;

canvas.FillRectangle(x, y, width, height);

canvas.RestoreState();
}

public void DrawText(ICanvas canvas, RectF dirtyRect, ILabel label)
{
canvas.SaveState();

UpdateTextColor(canvas, dirtyRect, label);
UpdateFont(canvas, dirtyRect, label);
UpdateText(canvas, dirtyRect, label);

canvas.RestoreState();
}

void UpdateTextColor(ICanvas canvas, RectF dirtyRect, ILabel label)
{
var textColor = label.TextColor;
canvas.FontColor = textColor;
}

void UpdateFont(ICanvas canvas, RectF dirtyRect, ILabel label)
{
if (label.Font.Weight is FontWeight.Bold)
canvas.Font = Font.DefaultBold;

var fontSize = (float)label.Font.Size;
canvas.FontSize = fontSize;
}

void UpdateText(ICanvas canvas, RectF dirtyRect, ILabel label)
{
var margin = label.Margin;
var x = (float)(dirtyRect.X + margin.Left);
var y = (float)(dirtyRect.Y + margin.Top);

var height = dirtyRect.Height;
var width = dirtyRect.Width;

string text = label.Text;

// Update CharacterSpacing
double characterSpacing = label.CharacterSpacing;
text = text.WithCharacterSpacing(characterSpacing);

canvas.DrawString(
text,
x, y, width, height,
label.HorizontalTextAlignment.ToHorizontalAlignment(),
label.VerticalTextAlignment.ToVerticalAlignment(),
TextFlow.ClipBounds);
}
}
}
49 changes: 49 additions & 0 deletions src/GraphicsControls/Handlers/Label/LabelHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System.Linq;

namespace Microsoft.Maui.Graphics.Controls
{
public class LabelHandler : GraphicsControlHandler<ILabelDrawable, ILabel>
{
public LabelHandler() : base(DrawMapper, PropertyMapper)
{

}

public static PropertyMapper<ILabel> PropertyMapper = new PropertyMapper<ILabel>(ViewHandler.Mapper)
{
[nameof(ILabel.Text)] = ViewHandler.MapInvalidate,
[nameof(ILabel.TextColor)] = ViewHandler.MapInvalidate,
[nameof(ILabel.Font)] = ViewHandler.MapInvalidate,
[nameof(ILabel.CharacterSpacing)] = ViewHandler.MapInvalidate,
[nameof(ILabel.HorizontalTextAlignment)] = ViewHandler.MapInvalidate,
[nameof(ILabel.VerticalTextAlignment)] = ViewHandler.MapInvalidate,
};

public static DrawMapper<ILabelDrawable, ILabel> DrawMapper = new DrawMapper<ILabelDrawable, ILabel>(ViewHandler.DrawMapper)
{
["Background"] = MapDrawBackground,
["Text"] = MapDrawText
};

public static string[] DefaultLabelLayerDrawingOrder =
ViewHandler.DefaultLayerDrawingOrder.ToList().InsertAfter(new string[]
{
"Background",
"Text",
}, "Text").ToArray();

public override string[] LayerDrawingOrder() =>
DefaultLabelLayerDrawingOrder;

protected override ILabelDrawable CreateDrawable()
{
return new LabelDrawable();
}

public static void MapDrawBackground(ICanvas canvas, RectF dirtyRect, ILabelDrawable drawable, ILabel view)
=> drawable.DrawBackground(canvas, dirtyRect, view);

public static void MapDrawText(ICanvas canvas, RectF dirtyRect, ILabelDrawable drawable, ILabel view)
=> drawable.DrawText(canvas, dirtyRect, view);
}
}
56 changes: 56 additions & 0 deletions src/GraphicsControls/Platform/TextExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System.Text;

namespace Microsoft.Maui.Graphics.Controls
{
public static class TextExtensions
{
public static string WithCharacterSpacing(this string input, double characterSpacing)
{
int spaces = (int)characterSpacing;

if (input.Length <= 1)
return input;

StringBuilder sb = new StringBuilder();

for (int i = 0; i < input.Length; i++)
{
sb.Append(input[i]);
if (i != input.Length - 1)
sb.Append(' ', spaces);
}

return sb.ToString();
}

public static HorizontalAlignment ToHorizontalAlignment(this TextAlignment textAlignment)
{
switch (textAlignment)
{
case TextAlignment.Start:
return HorizontalAlignment.Left;
case TextAlignment.Center:
return HorizontalAlignment.Center;
case TextAlignment.End:
return HorizontalAlignment.Right;
default:
return HorizontalAlignment.Left;
}
}

public static VerticalAlignment ToVerticalAlignment(this TextAlignment textAlignment)
{
switch (textAlignment)
{
case TextAlignment.Start:
return VerticalAlignment.Top;
case TextAlignment.Center:
return VerticalAlignment.Center;
case TextAlignment.End:
return VerticalAlignment.Bottom;
default:
return VerticalAlignment.Top;
}
}
}
}