123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631 |
- using BsWidget.BeatSaberHttpStatus;
- using BsWidget.BsYurHttpStatus;
- using BsWidgetShareCodes;
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Drawing;
- using System.Drawing.Drawing2D;
- using System.Drawing.Text;
- using System.IO;
- using System.Linq;
- using System.Windows.Forms;
- namespace BsWidget
- {
- internal class MainForm : BaseForm
- {
- private Timer _updateTimer;
- private BlockingCollection<UpdateFlags> _queue;
- private BeatSaberHttpStatusClient _client;
- private BsYurHttpStatusClient _yurClient;
- private Font _smallFont = new Font("", 12, FontStyle.Regular, GraphicsUnit.Pixel);
- private Font _mediumFont = new Font("", 20, FontStyle.Regular, GraphicsUnit.Pixel);
- [Flags]
- private enum UpdateFlags
- {
- BeatMap = 1 << 0,
- Performance = 1 << 1,
- NoteFullyCut = 1 << 2,
- ClearAll = 1 << 3,
- RefreshAll = 1 << 4,
- }
- public Image SongIcon { get; set; } = Properties.Resources.sample_cover;
- public string SongName { get; set; } = "Song Name";
- public string SongSubName { get; set; } = "Song Sub Name";
- public string SongArtist { get; set; } = "Song Artist";
- public string BeatMapper { get; set; } = "Mapper";
- public string Difficulty { get; set; } = "Difficulty";
- public double SongBpm { get; set; } = 123;
- public double SongNjs { get; set; } = 23;
- public int CurrentScore { get; set; } = 12345;
- public int CurrentCombo { get; set; } = 120;
- public string CurrentRank { get; set; } = "XX";
- public int CurrentMaxScore { get; set; }
- public YurStatus YurStatus { get; set; } = new YurStatus { HeartRate = 0, KcalPerMin = 0 };
- /// <summary> FinalScore,CurrentCombo </summary>
- public List<HistoryModel> CutHistory { get; set; }
- public class HistoryModel
- {
- public int CutScore { get; set; }
- public int CurrentCombo { get; set; }
- public float Percent { get; set; }
- public float HeartRate { get; set; }
- public float KcalPerMin { get; set; }
- }
- public MainForm()
- {
- KeyPreview = true;
- FormBorderStyle = FormBorderStyle.None;
- _client = new BeatSaberHttpStatusClient();
- _client.Event += BeatSaber_Event;
- _yurClient = new BsYurHttpStatusClient();
- _yurClient.Event += Yur_Event;
- Text = "Beat Saber Status Widget";
- _queue = new BlockingCollection<UpdateFlags>();
- CutHistory = new List<HistoryModel>();
- _updateTimer = new Timer { Interval = 25 };
- _updateTimer.Tick += UpdateTimer_Tick;
- }
- protected override void OnLoad(EventArgs e)
- {
- base.OnLoad(e);
- Font = new Font("", 30, FontStyle.Bold, GraphicsUnit.Pixel);
- TopMost = false;
- WindowState = FormWindowState.Normal;
- _updateTimer.Start();
- _client.Start();
- _yurClient.Start();
- }
- protected override void OnShown(EventArgs e)
- {
- WindowState = FormWindowState.Normal;
- Location = Screen.PrimaryScreen.Bounds.Location;
- ClientSize = Screen.PrimaryScreen.Bounds.Size;
- TopMost = true;
- base.OnShown(e);
- if (_queue.Count == 0)
- {
- _queue.Add(UpdateFlags.RefreshAll);
- }
- }
- protected override void OnClosing(CancelEventArgs e)
- {
- _client.Stop();
- _updateTimer.Stop();
- base.OnClosing(e);
- }
- protected override void OnKeyDown(KeyEventArgs e)
- {
- base.OnKeyDown(e);
- if (e.KeyCode == Keys.Escape) Application.Exit();
- }
- private void BeatSaber_Event(object sender, BeatSaberStatusEventArgs e)
- {
- if (e.Event == "noteMissed")
- {
- var bp = 0;
- }
- var flags = (UpdateFlags)0;
- if (e.Event == "menu" && CutHistory.Count > 0)
- {
- lock (CutHistory)
- {
- CutHistory.Clear();
- }
- flags |= UpdateFlags.ClearAll;
- }
- if (null != e.Status.Beatmap)
- {
- var bytes = Convert.FromBase64String(e.Status.Beatmap.SongCover);
- using var stream = new MemoryStream(bytes);
- var newImg = Image.FromStream(stream);
- var old = SongIcon;
- SongIcon = newImg;
- old?.Dispose();
- SongName = e.Status.Beatmap.SongName;
- SongSubName = e.Status.Beatmap.SongSubName;
- SongArtist = e.Status.Beatmap.SongAuthorName;
- BeatMapper = e.Status.Beatmap.LevelAuthorName;
- if (string.IsNullOrEmpty(BeatMapper)) BeatMapper = "Unknown Mapper";
- Difficulty = e.Status.Beatmap.Difficulty.ToUpper();
- if (Difficulty == "EXPERTPLUS") Difficulty = "EXPERT+";
- SongBpm = e.Status.Beatmap.SongBPM;
- SongNjs = e.Status.Beatmap.NoteJumpSpeed;
- flags |= UpdateFlags.BeatMap;
- }
- if (null != e.Status.Performance)
- {
- CurrentScore = e.Status.Performance.Score;
- CurrentCombo = e.Status.Performance.Combo;
- CurrentRank = e.Status.Performance.Rank;
- CurrentMaxScore = e.Status.Performance.CurrentMaxScore;
- flags |= UpdateFlags.Performance;
- }
- if (e.Event == "noteFullyCut" && null != e.NoteCut?.FinalScore)
- {
- lock (CutHistory)
- {
- CutHistory.Add(new HistoryModel
- {
- CutScore = e.NoteCut.FinalScore.Value,
- CurrentCombo = CurrentCombo,
- Percent = (float)CurrentScore / CurrentMaxScore,
- HeartRate = YurStatus.HeartRate,
- KcalPerMin = YurStatus.KcalPerMin,
- });
- }
- flags |= UpdateFlags.NoteFullyCut;
- }
- if (flags == 0)
- {
- var bp = 0;
- }
- else
- {
- _queue.Add(flags);
- }
- }
- private void Yur_Event(object sender, YurStatus e) => YurStatus = e;
- private void UpdateTimer_Tick(object sender, EventArgs e)
- {
- if (_queue.Count == 0) return;
- UpdateGraphic();
- }
- protected override void RenderGraphic(Graphics g)
- {
- const int margin = 10;
- var ChWidth = ViewSize.Width - margin * 2;
- var ChHeight = 64;
- if (_queue.Count == 0) return;
- var flags = _queue.Take();
- if (flags.HasFlag(UpdateFlags.ClearAll)) g.Clear(Color.Transparent);
- g.SetHighQuality();
- float nextY = 0;
- if (flags.HasFlag(UpdateFlags.NoteFullyCut) || flags.HasFlag(UpdateFlags.RefreshAll))
- {
- var ChLeft = margin;
- var ChTop = margin;
- var ChBottom = ChTop + ChHeight;
- float RecordPixel = 5;
- var LineWidth = 2f;
- var DisplayCount = (int)(ChWidth / RecordPixel);
- using var scorePen = new Pen(Color.FromArgb(200, 255, 0, 0), LineWidth) { LineJoin = LineJoin.Round };
- using var comboPen = new Pen(Color.FromArgb(200, 0, 0, 255), LineWidth) { LineJoin = LineJoin.Round };
- using var percentPen = new Pen(Color.FromArgb(200, Color.Green), LineWidth) { LineJoin = LineJoin.Round };
- using var heartPen = new Pen(Color.FromArgb(200, Color.White), LineWidth) { LineJoin = LineJoin.Round };
- using var calPen = new Pen(Color.FromArgb(200, Color.Lime), LineWidth) { LineJoin = LineJoin.Round };
- //clear region 0,210 Wx200
- g.ClearRect(Color.Transparent, 0, ChTop - 3, ViewSize.Width, ChHeight + 6 + 20);
- //draw chart
- using var bgBrush = new SolidBrush(Color.FromArgb(90, 255, 255, 255));
- g.FillRectangle(bgBrush, ChLeft, ChTop, ChWidth, ChHeight);
- g.DrawRectangle(Pens.White, ChLeft - 1, ChTop - 1, ChWidth + 2, ChHeight + 2);
- if (CutHistory.Count > 1)
- {
- HistoryModel[] items;
- lock (CutHistory)
- {
- var skip = CutHistory.Count > DisplayCount ? CutHistory.Count - DisplayCount : 0;
- items = CutHistory.Skip(skip).ToArray();
- }
- if (items.Length > 1)
- {
- var minScore = items.Select(p => p.CutScore).Min();
- var maxScore = items.Select(p => p.CutScore).Max();
- var rngScore = maxScore - minScore;
- if (rngScore < 1) rngScore = 1;
- var minCombo = items.Select(p => p.CurrentCombo).Min();
- var maxCombo = items.Select(p => p.CurrentCombo).Max();
- var rngCombo = maxCombo - minCombo;
- if (rngCombo < 1) rngCombo = 1;
- var minHea = items.Select(p => p.HeartRate).Min();
- var maxHea = items.Select(p => p.HeartRate).Max();
- var rngHea = maxHea - minHea;
- if (rngHea < 1) rngHea = 1;
- var minCal = items.Select(p => p.KcalPerMin).Min();
- var maxCal = items.Select(p => p.KcalPerMin).Max();
- var rngCal = maxCal - minCal;
- if (rngCal < 1) rngCal = 1;
- var x = ChWidth - items.Length * RecordPixel + ChLeft + 1;
- var scorePts = new List<PointF>();
- var comboPts = new List<PointF>();
- var percentPts = new List<PointF>();
- var heaPts = new List<PointF>();
- var calPts = new List<PointF>();
- for (var i = 0; i < items.Length; i++)
- {
- var item = items[i];
- scorePts.Add(new PointF(x + RecordPixel * i, (ChBottom - 1) - (ChHeight - 2) * ((float)(item.CutScore - minScore) / rngScore)));
- comboPts.Add(new PointF(x + RecordPixel * i, (ChBottom - 1) - (ChHeight - 2) * ((float)(item.CurrentCombo - minCombo) / rngCombo)));
- percentPts.Add(new PointF(x + RecordPixel * i, (ChBottom - 1) - (ChHeight - 2) * item.Percent));
- heaPts.Add(new PointF(x + RecordPixel * i, (ChBottom - 1) - (ChHeight - 2) * ((item.HeartRate - minHea) / rngHea)));
- calPts.Add(new PointF(x + RecordPixel * i, (ChBottom - 1) - (ChHeight - 2) * ((item.KcalPerMin - minCal) / rngCal)));
- }
- g.DrawLines(scorePen, scorePts.ToArray());
- g.DrawLines(comboPen, comboPts.ToArray());
- g.DrawLines(percentPen, percentPts.ToArray());
- g.DrawLines(heartPen, heaPts.ToArray());
- g.DrawLines(calPen, calPts.ToArray());
- }
- }
- nextY = ChHeight + margin * 2;
- }
- if (flags.HasFlag(UpdateFlags.Performance) || flags.HasFlag(UpdateFlags.RefreshAll))
- {
- float x = margin;
- float y = ChHeight + margin * 2;
- //clear region 0,180 Wx180
- g.ClearRect(Color.Transparent, 0, y, ViewSize.Width, 50);
- //draw text
- var sz = g.DrawStringWithOutline($"{CurrentScore:N0}", Font, x, y, Color.Black, Color.White);
- x += sz.Width + margin * 2;
- sz = g.DrawStringWithRoundedRect("POINT", _smallFont, x, y + margin * 1.5f, Brushes.White, Brushes.Red,
- 2.5f);
- x += sz.Width + margin * 2;
- sz = g.DrawStringWithOutline($"{CurrentCombo}", Font, x, y, Color.Black, Color.White);
- x += sz.Width + margin * 2;
- sz = g.DrawStringWithRoundedRect("COMBO", _smallFont, x, y + margin * 1.5f, Brushes.White, Brushes.Blue,
- 2.5f);
- x += sz.Width + margin * 2;
- sz = g.DrawStringWithOutline($"{CurrentRank}", Font, x, y, Color.Black, Color.White);
- x += sz.Width + margin * 2;
- sz = g.DrawStringWithRoundedRect("RANK", _smallFont, x, y + margin * 1.5f, Brushes.White,
- Brushes.Green, 2.5f);
- x += sz.Width + margin * 2;
- sz = g.DrawStringWithOutline($"{YurStatus.HeartRate:N1}", Font, x, y, Color.Black, Color.White);
- x += sz.Width + margin * 2;
- sz = g.DrawStringWithRoundedRect("HEART", _smallFont, x, y + margin * 1.5f, Brushes.Black,
- Brushes.White, 2.5f);
- x += sz.Width + margin * 2;
- sz = g.DrawStringWithOutline($"{YurStatus.KcalPerMin:N1}", Font, x, y, Color.Black, Color.White);
- x += sz.Width + margin * 2;
- sz = g.DrawStringWithRoundedRect("KCAL / MIN", _smallFont, x, y + margin * 1.5f, Brushes.Black,
- Brushes.Lime, 2.5f);
- }
- if (flags.HasFlag(UpdateFlags.BeatMap) || flags.HasFlag(UpdateFlags.RefreshAll))
- {
- const int coverSize = 130;
- g.ClearRect(Color.Transparent, 0, ViewSize.Height - (coverSize + 100), ViewSize.Width, coverSize + 100);
- var coverLeft = ViewSize.Width - coverSize - margin * 2;
- var coverTop = ViewSize.Height - coverSize - margin * 2;
- g.DrawImage(SongIcon, coverLeft, coverTop, coverSize, coverSize);
- g.DrawRectangle(Pens.White, coverLeft, coverTop, coverSize, coverSize);
- g.DrawStringWithRoundedRect(Difficulty, Font, coverLeft - 20, coverTop - 100, Brushes.Black, Brushes.White);
- {
- float x = coverLeft - 80;
- var y = coverTop - 50;
- var sz = g.DrawStringWithOutline($"{SongBpm}", Font, x, y, Color.Black, Color.White);
- x += sz.Width + margin * 2;
- sz = g.DrawStringWithRoundedRect("BPM", _smallFont, x, y + margin * 1.5f, Brushes.Black, Brushes.White, 2.5f);
- x += sz.Width + margin * 2;
- sz = g.DrawStringWithOutline($"{SongNjs}", Font, x, y, Color.Black, Color.White);
- x += sz.Width + margin * 2;
- sz = g.DrawStringWithRoundedRect("NJS", _smallFont, x, y + margin * 1.5f, Brushes.Black, Brushes.White, 2.5f);
- }
- {
- var bootom = ViewSize.Height - margin * 1.5f;
- var right = coverLeft - margin;
- var fontDeltaW = 1.3f;
- var fontDeltaH = 1.4f;
- var sz = g.MeasureString(SongName, _mediumFont);
- g.DrawStringWithOutline(SongName, _mediumFont, right - sz.Width * fontDeltaW, bootom - sz.Height * fontDeltaH, Color.Black, Color.White);
- sz = g.MeasureString(SongSubName, _mediumFont);
- g.DrawStringWithOutline(SongSubName, _mediumFont, right - sz.Width * fontDeltaW, bootom - (sz.Height * fontDeltaH) * 2, Color.Black, Color.White);
- sz = g.MeasureString(SongArtist, _mediumFont);
- g.DrawStringWithOutline(SongArtist, _mediumFont, right - sz.Width * fontDeltaW, bootom - (sz.Height * fontDeltaH) * 3, Color.Black, Color.White);
- sz = g.MeasureString(BeatMapper, _mediumFont);
- g.DrawStringWithOutline(BeatMapper, _mediumFont, right - sz.Width * fontDeltaW, bootom - (sz.Height * fontDeltaH) * 4, Color.Black, Color.White);
- }
- }
- if (flags.HasFlag(UpdateFlags.Performance) || flags.HasFlag(UpdateFlags.RefreshAll))
- {
- // //clear region 0,180 Wx180
- // g.ClearRect(Color.Transparent, 0, nextY + margin, ViewSize.Width, fontHeight);
- // //draw text
- // float x = margin;
- // float y = nextY + margin;
- // var sz = g.DrawStringWithOutline($"{CurrentScore:N0}", Font, x, y, Color.Black, Color.White);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithRoundedRect("POINT", _smallFont, x, y + margin * 1.5f, Brushes.Black,
- // Brushes.White, 2.5f);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithOutline($"{CurrentCombo}", Font, x, y, Color.Black, Color.White);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithRoundedRect("COMBO", _smallFont, x, y + margin * 1.5f, Brushes.Black,
- // Brushes.White, 2.5f);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithOutline($"{CurrentRank}", Font, x, y, Color.Black, Color.White);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithRoundedRect("RANK", _smallFont, x, y + margin * 1.5f, Brushes.Black, Brushes.White,
- // 2.5f);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithOutline($"{YurStatus.HeartRate:N1}", Font, x, y, Color.Black, Color.White);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithRoundedRect("HEART", _smallFont, x, y + margin * 1.5f, Brushes.Black,
- // Brushes.White, 2.5f);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithOutline($"{YurStatus.KcalPerMin:N1}", Font, x, y, Color.Black, Color.White);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithRoundedRect("KCAL/MIN", _smallFont, x, y + margin * 1.5f, Brushes.Black,
- // Brushes.White, 2.5f);
- }
- if (flags.HasFlag(UpdateFlags.BeatMap) || flags.HasFlag(UpdateFlags.RefreshAll))
- {
- // //clear region
- // g.ClearRect(Color.Transparent, 0, 0, ViewSize.Width, margin + coverSize + margin);
- // //draw cover and text
- // g.DrawImage(SongIcon, margin, margin, coverSize, coverSize);
- // g.DrawRectangle(Pens.White, 10, 10, coverSize, coverSize);
- // float x = coverSize + margin;
- // var y = margin;
- // var sz = g.DrawStringWithOutline(SongName, Font, x, y, Color.Black, Color.White);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithRoundedRect(Difficulty, Font, x, y + 5, Brushes.Black, Brushes.White);
- // g.DrawRoundedRectangle(Pens.Black, new RectangleF(x + 2, y + 7, sz.Width - 4, sz.Height - 4), 8);
- // x += sz.Width + margin;
- // sz = g.DrawStringWithOutline($"{SongBpm}", Font, x, y, Color.Black, Color.White);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithRoundedRect("BPM", _smallFont, x, y + margin * 1.5f, Brushes.Black, Brushes.White,
- // 2.5f);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithOutline($"{SongNjs}", Font, x, y, Color.Black, Color.White);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithRoundedRect("NJS", _smallFont, x, y + margin * 1.5f, Brushes.Black, Brushes.White,
- // 2.5f);
- // x += sz.Width + margin;
- // x = coverSize + margin;
- // y = margin;
- // g.DrawStringWithOutline(SongSubName, Font, x, y + fontHeight, Color.Black, Color.White);
- // g.DrawStringWithOutline(SongArtist, Font, x, y + fontHeight * 2, Color.Black, Color.White);
- // g.DrawStringWithOutline(BeatMapper, Font, x, y + fontHeight * 3, Color.Black, Color.White);
- }
- if (flags.HasFlag(UpdateFlags.Performance) || flags.HasFlag(UpdateFlags.RefreshAll))
- {
- // float x = margin;
- // float y = ChHeight + margin * 2;
- // //clear region 0,180 Wx180
- // g.ClearRect(Color.Transparent, 0, y, ViewSize.Width, fontHeight);
- // //draw text
- // var sz = g.DrawStringWithOutline($"{CurrentScore:N0}", Font, x, y, Color.Black, Color.White);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithRoundedRect("POINT", _smallFont, x, y + margin * 1.5f, Brushes.White, Brushes.Red,
- // 2.5f);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithOutline($"{CurrentCombo}", Font, x, y, Color.Black, Color.White);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithRoundedRect("COMBO", _smallFont, x, y + margin * 1.5f, Brushes.White, Brushes.Blue,
- // 2.5f);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithOutline($"{CurrentRank}", Font, x, y, Color.Black, Color.White);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithRoundedRect("PERCENT", _smallFont, x, y + margin * 1.5f, Brushes.White,
- // Brushes.Green, 2.5f);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithOutline($"{YurStatus.HeartRate:N1}", Font, x, y, Color.Black, Color.White);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithRoundedRect("HEART", _smallFont, x, y + margin * 1.5f, Brushes.Black,
- // Brushes.White, 2.5f);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithOutline($"{YurStatus.KcalPerMin:N1}", Font, x, y, Color.Black, Color.White);
- // x += sz.Width + margin * 2;
- // sz = g.DrawStringWithRoundedRect("KCAL/MIN", _smallFont, x, y + margin * 1.5f, Brushes.Black,
- // Brushes.Lime, 2.5f);
- }
- }
- }
- internal static class GdiPlusExt
- {
- public static void ClearRect(this Graphics g, Color color, float x, float y, float w, float h)
- {
- g.SetClip(new RectangleF(x, y, w, h));
- g.Clear(color);
- g.ResetClip();
- }
- public static void SetHighQuality(this Graphics g)
- {
- g.CompositingMode = CompositingMode.SourceOver;
- g.InterpolationMode = InterpolationMode.HighQualityBicubic;
- g.PixelOffsetMode = PixelOffsetMode.HighQuality;
- g.SmoothingMode = SmoothingMode.HighQuality;
- g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
- }
- public static SizeF DrawStringWithOutline(this Graphics g, string text, Font font, float x, float y, Color outlineColor, Color fillColor, float outlineWidth = 1)
- {
- // assuming g is the Graphics object on which you want to draw the text
- using var p = new GraphicsPath();
- p.AddString(
- text, // text to draw
- font.FontFamily, // or any other font family
- (int)FontStyle.Regular, // font style (bold, italic, etc.)
- g.DpiY * font.Size / 72, // em size
- new PointF(x, y), // location where to draw text
- new StringFormat()); // set options here (e.g. center alignment)
- using var outlinePen = new Pen(outlineColor, outlineWidth);
- using var fillBrush = new SolidBrush(fillColor);
- g.FillPath(fillBrush, p);
- g.DrawPath(outlinePen, p);
- return p.GetBounds().Size;
- }
- public static void DrawRoundedRectangle(this Graphics graphics, Pen pen, RectangleF bounds, int cornerRadius)
- {
- if (graphics == null)
- throw new ArgumentNullException("graphics");
- if (pen == null)
- throw new ArgumentNullException("pen");
- using var path = RoundedRect(bounds, cornerRadius);
- graphics.DrawPath(pen, path);
- }
- public static void FillRoundedRectangle(this Graphics graphics, Brush brush, RectangleF bounds, float cornerRadius)
- {
- if (graphics == null)
- throw new ArgumentNullException("graphics");
- if (brush == null)
- throw new ArgumentNullException("brush");
- using var path = RoundedRect(bounds, cornerRadius);
- graphics.FillPath(brush, path);
- }
- public static SizeF DrawStringWithRoundedRect(this Graphics g, string text, Font font, float x, float y, Brush textbBrushe, Brush bgBrush, float radus = 10)
- {
- var sz = g.MeasureString(text, font);
- g.FillRoundedRectangle(bgBrush, new RectangleF(x, y, sz.Width, sz.Height), radus);
- g.DrawString(text, font, textbBrushe, x, y);
- return sz;
- }
- private static GraphicsPath RoundedRect(RectangleF bounds, float radius)
- {
- var diameter = radius * 2;
- var size = new SizeF(diameter, diameter);
- var arc = new RectangleF(bounds.Location, size);
- var path = new GraphicsPath();
- if (radius == 0)
- {
- path.AddRectangle(bounds);
- return path;
- }
- // top left arc
- path.AddArc(arc, 180, 90);
- // top right arc
- arc.X = bounds.Right - diameter;
- path.AddArc(arc, 270, 90);
- // bottom right arc
- arc.Y = bounds.Bottom - diameter;
- path.AddArc(arc, 0, 90);
- // bottom left arc
- arc.X = bounds.Left;
- path.AddArc(arc, 90, 90);
- path.CloseFigure();
- return path;
- }
- }
- }
|