Files
archived-g-helper/app/UI/RComboBox.cs
2024-03-10 20:54:48 +01:00

258 lines
9.1 KiB
C#

using System.ComponentModel;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
namespace GHelper.UI
{
public class RComboBox : ComboBox
{
private Color borderColor = Color.Gray;
[DefaultValue(typeof(Color), "Gray")]
public Color BorderColor
{
get { return borderColor; }
set
{
if (borderColor != value)
{
borderColor = value;
Invalidate();
}
}
}
private Color buttonColor = Color.FromArgb(255, 255, 255, 255);
[DefaultValue(typeof(Color), "255, 255, 255")]
public Color ButtonColor
{
get { return buttonColor; }
set
{
if (buttonColor != value)
{
buttonColor = value;
Invalidate();
}
}
}
private Color arrowColor = Color.Black;
[DefaultValue(typeof(Color), "Black")]
public Color ArrowColor
{
get { return arrowColor; }
set
{
if (arrowColor != value)
{
arrowColor = value;
Invalidate();
}
}
}
public static GraphicsPath RoundedRect(Rectangle bounds, int radiusL, int radiusR)
{
int diameterL = radiusL * 2;
int diameterR = radiusR * 2;
Size sizeL = new Size(diameterL, diameterL);
Size sizeR = new Size(diameterR, diameterR);
Rectangle arcL = new Rectangle(bounds.Location, sizeL);
Rectangle arcR = new Rectangle(bounds.Location, sizeR);
GraphicsPath path = new GraphicsPath();
// top left arc
path.AddArc(arcL, 180, 90);
// top right arc
arcR.X = bounds.Right - diameterR;
arcR.Y = bounds.Top;
path.AddArc(arcR, 270, 90);
// bottom right arc
arcR.Y = bounds.Bottom - diameterR;
arcR.X = bounds.Right - diameterR;
path.AddArc(arcR, 0, 90);
// bottom left arc
arcL.X = bounds.Left;
arcL.Y = bounds.Bottom - diameterL;
path.AddArc(arcL, 90, 90);
path.CloseFigure();
return path;
}
public static void DrawRoundedRectangle(Graphics graphics, Pen pen, Rectangle bounds, int cornerRadiusL = 5, int cornerRadiusR = 5)
{
if (graphics == null)
throw new ArgumentNullException(nameof(graphics));
if (pen == null)
throw new ArgumentNullException(nameof(pen));
using (GraphicsPath path = RoundedRect(bounds, cornerRadiusL, cornerRadiusR))
{
graphics.DrawPath(pen, path);
}
}
public static void FillRoundedRectangle(Graphics graphics, Brush brush, Rectangle bounds, int cornerRadiusL = 5, int cornerRadiusR = 5)
{
if (graphics == null)
throw new ArgumentNullException(nameof(graphics));
if (brush == null)
throw new ArgumentNullException(nameof(brush));
using (GraphicsPath path = RoundedRect(bounds, cornerRadiusL, cornerRadiusR))
{
graphics.FillPath(brush, path);
}
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_PAINT && DropDownStyle != ComboBoxStyle.Simple)
{
var clientRect = ClientRectangle;
var dropDownButtonWidth = SystemInformation.HorizontalScrollBarArrowWidth;
var outerBorder = new Rectangle(clientRect.Location,
new Size(clientRect.Width - 1, clientRect.Height - 1));
var innerBorder = new Rectangle(outerBorder.X + 1, outerBorder.Y + 1,
outerBorder.Width - dropDownButtonWidth - 2, outerBorder.Height - 2);
var innerInnerBorder = new Rectangle(innerBorder.X + 1, innerBorder.Y + 1,
innerBorder.Width - 2, innerBorder.Height - 2);
var dropDownRect = new Rectangle(innerBorder.Right + 1, innerBorder.Y,
dropDownButtonWidth, innerBorder.Height + 1);
if (RightToLeft == RightToLeft.Yes)
{
innerBorder.X = clientRect.Width - innerBorder.Right;
innerInnerBorder.X = clientRect.Width - innerInnerBorder.Right;
dropDownRect.X = clientRect.Width - dropDownRect.Right;
dropDownRect.Width += 1;
}
var innerBorderColor = Enabled ? BackColor : SystemColors.Control;
var outerBorderColor = Enabled ? BorderColor : SystemColors.ControlDark;
var buttonColor = Enabled ? ButtonColor : SystemColors.Control;
var middle = new Point(dropDownRect.Left + dropDownRect.Width / 2,
dropDownRect.Top + dropDownRect.Height / 2);
var arrow = new Point[]
{
new Point(middle.X - 3, middle.Y - 2),
new Point(middle.X + 4, middle.Y - 2),
new Point(middle.X, middle.Y + 2)
};
var ps = new PAINTSTRUCT();
bool shoulEndPaint = false;
nint dc;
if (m.WParam == nint.Zero)
{
dc = BeginPaint(Handle, ref ps);
m.WParam = dc;
shoulEndPaint = true;
}
else
{
dc = m.WParam;
}
var rgn = CreateRectRgn(innerInnerBorder.Left, innerInnerBorder.Top,
innerInnerBorder.Right, innerInnerBorder.Bottom);
SelectClipRgn(dc, rgn);
DefWndProc(ref m);
DeleteObject(rgn);
rgn = CreateRectRgn(clientRect.Left, clientRect.Top,
clientRect.Right, clientRect.Bottom);
SelectClipRgn(dc, rgn);
using (var g = Graphics.FromHdc(dc))
{
using (var b = new SolidBrush(buttonColor))
{
//FillRoundedRectangle(g, b, dropDownRect, 1, 3);
g.FillRectangle(b, dropDownRect);
}
using (var b = new SolidBrush(arrowColor))
{
g.FillPolygon(b, arrow);
}
using (var p = new Pen(innerBorderColor, 2))
{
DrawRoundedRectangle(g, p, innerBorder, 3, 1);
//DrawRoundedRectangle(g, p, innerInnerBorder, 3, 1);
//g.DrawRectangle(p, innerBorder);
//g.DrawRectangle(p, innerInnerBorder);
}
using (var p = new Pen(outerBorderColor))
{
DrawRoundedRectangle(g, p, outerBorder, 4, 4);
//g.DrawRectangle(p, outerBorder);
}
}
if (shoulEndPaint)
EndPaint(Handle, ref ps);
DeleteObject(rgn);
}
else
base.WndProc(ref m);
}
private const int WM_PAINT = 0xF;
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int L, T, R, B;
}
[StructLayout(LayoutKind.Sequential)]
public struct PAINTSTRUCT
{
public nint hdc;
public bool fErase;
public int rcPaint_left;
public int rcPaint_top;
public int rcPaint_right;
public int rcPaint_bottom;
public bool fRestore;
public bool fIncUpdate;
public int reserved1;
public int reserved2;
public int reserved3;
public int reserved4;
public int reserved5;
public int reserved6;
public int reserved7;
public int reserved8;
}
[DllImport("user32.dll")]
private static extern nint BeginPaint(nint hWnd,
[In, Out] ref PAINTSTRUCT lpPaint);
[DllImport("user32.dll")]
private static extern bool EndPaint(nint hWnd, ref PAINTSTRUCT lpPaint);
[DllImport("gdi32.dll")]
public static extern int SelectClipRgn(nint hDC, nint hRgn);
[DllImport("user32.dll")]
public static extern int GetUpdateRgn(nint hwnd, nint hrgn, bool fErase);
public enum RegionFlags
{
ERROR = 0,
NULLREGION = 1,
SIMPLEREGION = 2,
COMPLEXREGION = 3,
}
[DllImport("gdi32.dll")]
internal static extern bool DeleteObject(nint hObject);
[DllImport("gdi32.dll")]
private static extern nint CreateRectRgn(int x1, int y1, int x2, int y2);
}
}