------ #### ryControlsV4 V3.0.2107.0101 - *.[新增]新增Sheng.Winform.Controls部分控件。 #### RyWeb V3.0.2107.0101 - *.[新增]QuickWeb新增引用页设置。 #### MyDbV4 V3.0.2107.0101 - *.[新增]支持忽略大小写的替换功能。
455 lines
13 KiB
C#
455 lines
13 KiB
C#
/* GraphicsExtension - [Extended Graphics]
|
|
* Author name: Arun Reginald Zaheeruddin
|
|
* Current version: 1.0.0.4 (12b)
|
|
* Release documentation: http://www.codeproject.com
|
|
* License information: Microsoft Public License (Ms-PL) [http://www.opensource.org/licenses/ms-pl.html]
|
|
*
|
|
* Enhancements and history
|
|
* ------------------------
|
|
* 1.0.0.1 (20 Jul 2009): Initial release with modified code from previous CodeProject article.
|
|
* 1.0.0.2 (25 Jul 2009): Added functionality that allows selected corners on a rectangle to be rounded.
|
|
* Modified code to adapt to an anti-aliased output while drawing and filling rounded rectangles.
|
|
* 1.0.0.3 (26 Jul 2009): Added DrawRoundedRectangle and FillRoundedRectangle methods that take a Rectangle and RectangleF object.
|
|
* 1.0.0.4 (27 Jul 2009): Added font metrics and measuring utility that measures a font's height, leading, ascent, etc.
|
|
*
|
|
* Issues addressed
|
|
* ----------------
|
|
* 1. Rounded rectangles - rounding edges of a rectangle.
|
|
* 2. Font Metrics - Measuring a font's height, leading, ascent, etc.
|
|
*/
|
|
using System;
|
|
using System.Drawing;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace Sheng.Winform.Controls.Drawing
|
|
{
|
|
static class GraphicsExtension
|
|
{
|
|
private static GraphicsPath GenerateRoundedRectangle(
|
|
this Graphics graphics,
|
|
RectangleF rectangle,
|
|
float radius,
|
|
RectangleEdgeFilter filter)
|
|
{
|
|
float diameter;
|
|
GraphicsPath path = new GraphicsPath();
|
|
if (radius <= 0.0F || filter == RectangleEdgeFilter.None)
|
|
{
|
|
path.AddRectangle(rectangle);
|
|
path.CloseFigure();
|
|
return path;
|
|
}
|
|
else
|
|
{
|
|
if (radius >= (Math.Min(rectangle.Width, rectangle.Height)) / 2.0)
|
|
return graphics.GenerateCapsule(rectangle);
|
|
diameter = radius * 2.0F;
|
|
SizeF sizeF = new SizeF(diameter, diameter);
|
|
RectangleF arc = new RectangleF(rectangle.Location, sizeF);
|
|
if ((RectangleEdgeFilter.TopLeft & filter) == RectangleEdgeFilter.TopLeft)
|
|
path.AddArc(arc, 180, 90);
|
|
else
|
|
{
|
|
path.AddLine(arc.X, arc.Y + arc.Height, arc.X, arc.Y);
|
|
path.AddLine(arc.X, arc.Y, arc.X + arc.Width, arc.Y);
|
|
}
|
|
arc.X = rectangle.Right - diameter;
|
|
if ((RectangleEdgeFilter.TopRight & filter) == RectangleEdgeFilter.TopRight)
|
|
path.AddArc(arc, 270, 90);
|
|
else
|
|
{
|
|
path.AddLine(arc.X, arc.Y, arc.X + arc.Width, arc.Y);
|
|
path.AddLine(arc.X + arc.Width, arc.Y + arc.Height, arc.X + arc.Width, arc.Y);
|
|
}
|
|
arc.Y = rectangle.Bottom - diameter;
|
|
if ((RectangleEdgeFilter.BottomRight & filter) == RectangleEdgeFilter.BottomRight)
|
|
path.AddArc(arc, 0, 90);
|
|
else
|
|
{
|
|
path.AddLine(arc.X + arc.Width, arc.Y, arc.X + arc.Width, arc.Y + arc.Height);
|
|
path.AddLine(arc.X, arc.Y + arc.Height, arc.X + arc.Width, arc.Y + arc.Height);
|
|
}
|
|
arc.X = rectangle.Left;
|
|
if ((RectangleEdgeFilter.BottomLeft & filter) == RectangleEdgeFilter.BottomLeft)
|
|
path.AddArc(arc, 90, 90);
|
|
else
|
|
{
|
|
path.AddLine(arc.X + arc.Width, arc.Y + arc.Height, arc.X, arc.Y + arc.Height);
|
|
path.AddLine(arc.X, arc.Y + arc.Height, arc.X, arc.Y);
|
|
}
|
|
path.CloseFigure();
|
|
}
|
|
return path;
|
|
}
|
|
private static GraphicsPath GenerateCapsule(
|
|
this Graphics graphics,
|
|
RectangleF rectangle)
|
|
{
|
|
float diameter;
|
|
RectangleF arc;
|
|
GraphicsPath path = new GraphicsPath();
|
|
try
|
|
{
|
|
if (rectangle.Width > rectangle.Height)
|
|
{
|
|
diameter = rectangle.Height;
|
|
SizeF sizeF = new SizeF(diameter, diameter);
|
|
arc = new RectangleF(rectangle.Location, sizeF);
|
|
path.AddArc(arc, 90, 180);
|
|
arc.X = rectangle.Right - diameter;
|
|
path.AddArc(arc, 270, 180);
|
|
}
|
|
else if (rectangle.Width < rectangle.Height)
|
|
{
|
|
diameter = rectangle.Width;
|
|
SizeF sizeF = new SizeF(diameter, diameter);
|
|
arc = new RectangleF(rectangle.Location, sizeF);
|
|
path.AddArc(arc, 180, 180);
|
|
arc.Y = rectangle.Bottom - diameter;
|
|
path.AddArc(arc, 0, 180);
|
|
}
|
|
else path.AddEllipse(rectangle);
|
|
}
|
|
catch { path.AddEllipse(rectangle); }
|
|
finally { path.CloseFigure(); }
|
|
return path;
|
|
}
|
|
public static void DrawRoundedRectangle(
|
|
this Graphics graphics,
|
|
Pen pen,
|
|
float x,
|
|
float y,
|
|
float width,
|
|
float height,
|
|
float radius,
|
|
RectangleEdgeFilter filter)
|
|
{
|
|
RectangleF rectangle = new RectangleF(x, y, width, height);
|
|
GraphicsPath path = graphics.GenerateRoundedRectangle(rectangle, radius, filter);
|
|
SmoothingMode old = graphics.SmoothingMode;
|
|
graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
|
graphics.DrawPath(pen, path);
|
|
graphics.SmoothingMode = old;
|
|
}
|
|
public static void DrawRoundedRectangle(
|
|
this Graphics graphics,
|
|
Pen pen,
|
|
float x,
|
|
float y,
|
|
float width,
|
|
float height,
|
|
float radius)
|
|
{
|
|
graphics.DrawRoundedRectangle(
|
|
pen,
|
|
x,
|
|
y,
|
|
width,
|
|
height,
|
|
radius,
|
|
RectangleEdgeFilter.All);
|
|
}
|
|
public static void DrawRoundedRectangle(
|
|
this Graphics graphics,
|
|
Pen pen,
|
|
int x,
|
|
int y,
|
|
int width,
|
|
int height,
|
|
int radius)
|
|
{
|
|
graphics.DrawRoundedRectangle(
|
|
pen,
|
|
Convert.ToSingle(x),
|
|
Convert.ToSingle(y),
|
|
Convert.ToSingle(width),
|
|
Convert.ToSingle(height),
|
|
Convert.ToSingle(radius));
|
|
}
|
|
public static void DrawRoundedRectangle(
|
|
this Graphics graphics,
|
|
Pen pen,
|
|
Rectangle rectangle,
|
|
int radius,
|
|
RectangleEdgeFilter filter)
|
|
{
|
|
graphics.DrawRoundedRectangle(
|
|
pen,
|
|
rectangle.X,
|
|
rectangle.Y,
|
|
rectangle.Width,
|
|
rectangle.Height,
|
|
radius,
|
|
filter);
|
|
}
|
|
public static void DrawRoundedRectangle(
|
|
this Graphics graphics,
|
|
Pen pen,
|
|
Rectangle rectangle,
|
|
int radius)
|
|
{
|
|
graphics.DrawRoundedRectangle(
|
|
pen,
|
|
rectangle.X,
|
|
rectangle.Y,
|
|
rectangle.Width,
|
|
rectangle.Height,
|
|
radius,
|
|
RectangleEdgeFilter.All);
|
|
}
|
|
public static void DrawRoundedRectangle(
|
|
this Graphics graphics,
|
|
Pen pen,
|
|
RectangleF rectangle,
|
|
int radius,
|
|
RectangleEdgeFilter filter)
|
|
{
|
|
graphics.DrawRoundedRectangle(
|
|
pen,
|
|
rectangle.X,
|
|
rectangle.Y,
|
|
rectangle.Width,
|
|
rectangle.Height,
|
|
radius,
|
|
filter);
|
|
}
|
|
public static void DrawRoundedRectangle(
|
|
this Graphics graphics,
|
|
Pen pen,
|
|
RectangleF rectangle,
|
|
int radius)
|
|
{
|
|
graphics.DrawRoundedRectangle(
|
|
pen,
|
|
rectangle.X,
|
|
rectangle.Y,
|
|
rectangle.Width,
|
|
rectangle.Height,
|
|
radius,
|
|
RectangleEdgeFilter.All);
|
|
}
|
|
public static void FillRoundedRectangle(
|
|
this Graphics graphics,
|
|
Brush brush,
|
|
float x,
|
|
float y,
|
|
float width,
|
|
float height,
|
|
float radius,
|
|
RectangleEdgeFilter filter)
|
|
{
|
|
RectangleF rectangle = new RectangleF(x, y, width, height);
|
|
GraphicsPath path = graphics.GenerateRoundedRectangle(rectangle, radius, filter);
|
|
SmoothingMode old = graphics.SmoothingMode;
|
|
graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
|
graphics.FillPath(brush, path);
|
|
graphics.SmoothingMode = old;
|
|
}
|
|
public static void FillRoundedRectangle(
|
|
this Graphics graphics,
|
|
Brush brush,
|
|
float x,
|
|
float y,
|
|
float width,
|
|
float height,
|
|
float radius)
|
|
{
|
|
graphics.FillRoundedRectangle(
|
|
brush,
|
|
x,
|
|
y,
|
|
width,
|
|
height,
|
|
radius,
|
|
RectangleEdgeFilter.All);
|
|
}
|
|
public static void FillRoundedRectangle(
|
|
this Graphics graphics,
|
|
Brush brush,
|
|
int x,
|
|
int y,
|
|
int width,
|
|
int height,
|
|
int radius)
|
|
{
|
|
graphics.FillRoundedRectangle(
|
|
brush,
|
|
Convert.ToSingle(x),
|
|
Convert.ToSingle(y),
|
|
Convert.ToSingle(width),
|
|
Convert.ToSingle(height),
|
|
Convert.ToSingle(radius));
|
|
}
|
|
public static void FillRoundedRectangle(
|
|
this Graphics graphics,
|
|
Brush brush,
|
|
Rectangle rectangle,
|
|
int radius,
|
|
RectangleEdgeFilter filter)
|
|
{
|
|
graphics.FillRoundedRectangle(
|
|
brush,
|
|
rectangle.X,
|
|
rectangle.Y,
|
|
rectangle.Width,
|
|
rectangle.Height,
|
|
radius,
|
|
filter);
|
|
}
|
|
public static void FillRoundedRectangle(
|
|
this Graphics graphics,
|
|
Brush brush,
|
|
Rectangle rectangle,
|
|
int radius)
|
|
{
|
|
graphics.FillRoundedRectangle(
|
|
brush,
|
|
rectangle.X,
|
|
rectangle.Y,
|
|
rectangle.Width,
|
|
rectangle.Height,
|
|
radius,
|
|
RectangleEdgeFilter.All);
|
|
}
|
|
public static void FillRoundedRectangle(
|
|
this Graphics graphics,
|
|
Brush brush,
|
|
RectangleF rectangle,
|
|
int radius,
|
|
RectangleEdgeFilter filter)
|
|
{
|
|
graphics.FillRoundedRectangle(
|
|
brush,
|
|
rectangle.X,
|
|
rectangle.Y,
|
|
rectangle.Width,
|
|
rectangle.Height,
|
|
radius,
|
|
filter);
|
|
}
|
|
public static void FillRoundedRectangle(
|
|
this Graphics graphics,
|
|
Brush brush,
|
|
RectangleF rectangle,
|
|
int radius)
|
|
{
|
|
graphics.FillRoundedRectangle(
|
|
brush,
|
|
rectangle.X,
|
|
rectangle.Y,
|
|
rectangle.Width,
|
|
rectangle.Height,
|
|
radius,
|
|
RectangleEdgeFilter.All);
|
|
}
|
|
public static FontMetrics GetFontMetrics(
|
|
this Graphics graphics,
|
|
Font font)
|
|
{
|
|
return FontMetricsImpl.GetFontMetrics(graphics, font);
|
|
}
|
|
private class FontMetricsImpl : FontMetrics
|
|
{
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
public struct TEXTMETRIC
|
|
{
|
|
public int tmHeight;
|
|
public int tmAscent;
|
|
public int tmDescent;
|
|
public int tmInternalLeading;
|
|
public int tmExternalLeading;
|
|
public int tmAveCharWidth;
|
|
public int tmMaxCharWidth;
|
|
public int tmWeight;
|
|
public int tmOverhang;
|
|
public int tmDigitizedAspectX;
|
|
public int tmDigitizedAspectY;
|
|
public char tmFirstChar;
|
|
public char tmLastChar;
|
|
public char tmDefaultChar;
|
|
public char tmBreakChar;
|
|
public byte tmItalic;
|
|
public byte tmUnderlined;
|
|
public byte tmStruckOut;
|
|
public byte tmPitchAndFamily;
|
|
public byte tmCharSet;
|
|
}
|
|
[DllImport("gdi32.dll", CharSet = CharSet.Unicode)]
|
|
public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
|
|
[DllImport("gdi32.dll", CharSet = CharSet.Unicode)]
|
|
public static extern bool GetTextMetrics(IntPtr hdc, out TEXTMETRIC lptm);
|
|
[DllImport("gdi32.dll", CharSet = CharSet.Unicode)]
|
|
public static extern bool DeleteObject(IntPtr hdc);
|
|
private TEXTMETRIC GenerateTextMetrics(
|
|
Graphics graphics,
|
|
Font font)
|
|
{
|
|
IntPtr hDC = IntPtr.Zero;
|
|
TEXTMETRIC textMetric;
|
|
IntPtr hFont = IntPtr.Zero;
|
|
try
|
|
{
|
|
hDC = graphics.GetHdc();
|
|
hFont = font.ToHfont();
|
|
IntPtr hFontDefault = SelectObject(hDC, hFont);
|
|
bool result = GetTextMetrics(hDC, out textMetric);
|
|
SelectObject(hDC, hFontDefault);
|
|
}
|
|
finally
|
|
{
|
|
if (hFont != IntPtr.Zero) DeleteObject(hFont);
|
|
if (hDC != IntPtr.Zero) graphics.ReleaseHdc(hDC);
|
|
}
|
|
return textMetric;
|
|
}
|
|
private TEXTMETRIC metrics;
|
|
public override int Height { get { return this.metrics.tmHeight; } }
|
|
public override int Ascent { get { return this.metrics.tmAscent; } }
|
|
public override int Descent { get { return this.metrics.tmDescent; } }
|
|
public override int InternalLeading { get { return this.metrics.tmInternalLeading; } }
|
|
public override int ExternalLeading { get { return this.metrics.tmExternalLeading; } }
|
|
public override int AverageCharacterWidth { get { return this.metrics.tmAveCharWidth; } }
|
|
public override int MaximumCharacterWidth { get { return this.metrics.tmMaxCharWidth; } }
|
|
public override int Weight { get { return this.metrics.tmWeight; } }
|
|
public override int Overhang { get { return this.metrics.tmOverhang; } }
|
|
public override int DigitizedAspectX { get { return this.metrics.tmDigitizedAspectX; } }
|
|
public override int DigitizedAspectY { get { return this.metrics.tmDigitizedAspectY; } }
|
|
private FontMetricsImpl(Graphics graphics, Font font)
|
|
{
|
|
this.metrics = this.GenerateTextMetrics(graphics, font);
|
|
}
|
|
public static FontMetrics GetFontMetrics(
|
|
Graphics graphics,
|
|
Font font)
|
|
{
|
|
return new FontMetricsImpl(graphics, font);
|
|
}
|
|
}
|
|
|
|
public enum RectangleEdgeFilter
|
|
{
|
|
None = 0,
|
|
TopLeft = 1,
|
|
TopRight = 2,
|
|
BottomLeft = 4,
|
|
BottomRight = 8,
|
|
All = TopLeft | TopRight | BottomLeft | BottomRight
|
|
}
|
|
public abstract class FontMetrics
|
|
{
|
|
public virtual int Height { get { return 0; } }
|
|
public virtual int Ascent { get { return 0; } }
|
|
public virtual int Descent { get { return 0; } }
|
|
public virtual int InternalLeading { get { return 0; } }
|
|
public virtual int ExternalLeading { get { return 0; } }
|
|
public virtual int AverageCharacterWidth { get { return 0; } }
|
|
public virtual int MaximumCharacterWidth { get { return 0; } }
|
|
public virtual int Weight { get { return 0; } }
|
|
public virtual int Overhang { get { return 0; } }
|
|
public virtual int DigitizedAspectX { get { return 0; } }
|
|
public virtual int DigitizedAspectY { get { return 0; } }
|
|
}
|
|
}
|
|
}
|