SunnyUI/SunnyUI/Controls/UIButton.cs

797 lines
24 KiB
C#
Raw Normal View History

2020-05-11 21:11:29 +08:00
/******************************************************************************
* SunnyUI
2024-05-02 23:37:18 +08:00
* CopyRight (C) 2012-2024 ShenYongHua().
2021-02-20 15:45:47 +08:00
* QQ群56829229 QQ17612584 EMailSunnyUI@QQ.Com
2020-05-11 21:11:29 +08:00
*
* Blog: https://www.cnblogs.com/yhuse
* Gitee: https://gitee.com/yhuse/SunnyUI
* GitHub: https://github.com/yhuse/SunnyUI
*
* SunnyUI.dll can be used for free under the GPL-3.0 license.
* If you use this code, please keep this note.
* 使
******************************************************************************
* : UIButton.cs
* :
2022-01-05 21:57:47 +08:00
* : V3.1
2020-05-11 21:11:29 +08:00
* : 2020-01-01
*
* 2020-01-01: V2.2.0
* 2020-04-25: V2.2.4
2020-07-30 21:21:47 +08:00
* 2020-07-26: V2.2.6 Selected及选中颜色配置
2020-09-17 21:20:47 +08:00
* 2020-08-22: V2.2.7 press背景效果
* 2020-09-14: V2.2.7 Tips颜色可设置
* 2021-07-18: V3.0.5 ShowFocusColorFocus状态
* 2021-12-11: V3.0.9
2022-02-26 10:28:54 +08:00
* 2022-02-26: V3.1.1 AutoSize属性
* 2022-03-19: V3.1.1
* 2022-03-31: V3.1.2
* 2022-08-25: V3.2.3 GroupIndex的按钮控件的Selected单选
2023-06-06 21:59:43 +08:00
* 2023-05-12: V3.3.6 DrawString函数
* 2023-07-02: V3.3.9
* 2023-11-24: V3.6.2 LightStyle的文字颜色
* 2023-12-06: V3.6.2 LightStyle的背景颜色
* 2024-02-22: V3.6.3 &Alt快捷键功能
* 2024-02-23: V3.6.3 Text的属性编辑器
2020-05-11 21:11:29 +08:00
******************************************************************************/
using System;
using System.Collections.Generic;
2020-05-11 21:11:29 +08:00
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Text;
2020-05-11 21:11:29 +08:00
using System.Windows.Forms;
namespace Sunny.UI
{
2022-06-24 15:04:08 +08:00
/// <summary>
/// 按钮
/// </summary>
2020-05-11 21:11:29 +08:00
[DefaultEvent("Click")]
[DefaultProperty("Text")]
[ToolboxItem(true)]
public class UIButton : UIControl, IButtonControl
2020-05-11 21:11:29 +08:00
{
2022-06-24 15:04:08 +08:00
/// <summary>
/// 构造函数
/// </summary>
2020-05-11 21:11:29 +08:00
public UIButton()
{
SetStyleFlags();
2020-05-11 21:11:29 +08:00
TabStop = true;
Width = 100;
Height = 35;
base.Cursor = Cursors.Hand;
2020-05-11 21:11:29 +08:00
plainColor = UIStyles.Blue.PlainColor;
foreHoverColor = UIStyles.Blue.ButtonForeHoverColor;
forePressColor = UIStyles.Blue.ButtonForePressColor;
foreSelectedColor = UIStyles.Blue.ButtonForeSelectedColor;
2020-05-11 21:11:29 +08:00
rectHoverColor = UIStyles.Blue.ButtonRectHoverColor;
rectPressColor = UIStyles.Blue.ButtonRectPressColor;
rectSelectedColor = UIStyles.Blue.ButtonRectSelectedColor;
2020-05-11 21:11:29 +08:00
fillHoverColor = UIStyles.Blue.ButtonFillHoverColor;
fillPressColor = UIStyles.Blue.ButtonFillPressColor;
fillSelectedColor = UIStyles.Blue.ButtonFillSelectedColor;
SetStyle(ControlStyles.StandardDoubleClick, UseDoubleClick);
UseMnemonic = true;
}
2024-09-13 23:43:27 +08:00
[Browsable(false)]
public override string[] FormTranslatorProperties => ["Text"];
[DefaultValue(true)]
[Description("如果为true&符号后面的第一次字符将做按钮的助记键"), Category("SunnyUI")]
public bool UseMnemonic { get; set; }
protected override bool ProcessMnemonic(char charCode)
{
if (UseMnemonic && CanProcessMnemonic() && IsMnemonic(charCode, Text))
{
PerformClick();
return true;
}
return base.ProcessMnemonic(charCode);
}
private bool CanProcessMnemonic()
{
return UseMnemonic && CanSelect && Enabled && Visible && Parent != null;
}
public string TextWithoutMnemonics(string text)
{
if (text == null)
{
return null;
}
int index = text.IndexOf('&');
if (index == -1)
{
return text;
}
StringBuilder str = new StringBuilder(text.Substring(0, index));
for (; index < text.Length; ++index)
{
if (text[index] == '&')
{
index++; // Skip this & and copy the next character instead
}
if (index < text.Length)
{
str.Append(text[index]);
}
}
return str.ToString();
2020-05-11 21:11:29 +08:00
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 是否显示浅色背景
/// </summary>
[DefaultValue(false)]
[Description("是否显示浅色背景"), Category("SunnyUI")]
public bool LightStyle
{
get => lightStyle;
set
{
if (lightStyle != value)
{
lightStyle = value;
Invalidate();
}
}
}
[DefaultValue(typeof(Color), "243, 249, 255")]
[Description("浅色背景"), Category("SunnyUI")]
public Color LightColor
{
get => plainColor;
set => SetPlainColor(value);
}
2022-02-26 10:28:54 +08:00
private bool autoSize;
2022-06-24 15:04:08 +08:00
/// <summary>
/// 自动大小
/// </summary>
2022-02-26 10:28:54 +08:00
[Browsable(true), DefaultValue(false)]
[Description("自动大小"), Category("SunnyUI")]
public override bool AutoSize
{
get => autoSize;
set
{
autoSize = value;
Invalidate();
}
}
2020-06-01 22:52:50 +08:00
private bool isClick;
2022-06-24 15:04:08 +08:00
/// <summary>
/// 调用点击事件
/// </summary>
2020-06-01 22:52:50 +08:00
public void PerformClick()
{
if (isClick) return;
if (CanSelect && Enabled)
{
isClick = true;
OnClick(EventArgs.Empty);
isClick = false;
}
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 重载点击事件
/// </summary>
/// <param name="e">参数</param>
protected override void OnClick(EventArgs e)
{
Form form = FindFormInternal();
if (form != null) form.DialogResult = DialogResult;
Focus();
base.OnClick(e);
}
internal Form FindFormInternal()
{
Control cur = this;
while (cur != null && !(cur is Form))
{
cur = cur.Parent;
}
return (Form)cur;
}
2020-05-11 21:11:29 +08:00
private bool showTips = false;
2022-06-24 15:04:08 +08:00
/// <summary>
/// 是否显示角标
/// </summary>
[Description("是否显示角标"), Category("SunnyUI")]
2020-05-11 21:11:29 +08:00
[DefaultValue(false)]
public bool ShowTips
{
get
{
return showTips;
}
set
{
if (showTips != value)
{
showTips = value;
Invalidate();
}
}
}
private string tipsText = "";
2022-06-24 15:04:08 +08:00
/// <summary>
/// 角标文字
/// </summary>
[Description("角标文字"), Category("SunnyUI")]
2020-05-11 21:11:29 +08:00
[DefaultValue("")]
public string TipsText
{
get { return tipsText; }
set
{
if (tipsText != value)
{
tipsText = value;
if (ShowTips)
{
Invalidate();
}
}
}
}
2023-05-25 10:51:41 +08:00
private Font tipsFont = UIStyles.SubFont();
2020-05-11 21:11:29 +08:00
2022-06-24 15:04:08 +08:00
/// <summary>
/// 角标文字字体
/// </summary>
[Description("角标文字字体"), Category("SunnyUI")]
[DefaultValue(typeof(Font), "宋体, 9pt")]
2020-05-11 21:11:29 +08:00
public Font TipsFont
{
get { return tipsFont; }
set
{
if (!tipsFont.Equals(value))
{
tipsFont = value;
Invalidate();
}
}
}
2022-06-23 23:27:55 +08:00
/// <summary>
/// 绘制填充颜色
/// </summary>
/// <param name="g">绘图图面</param>
/// <param name="path">绘图路径</param>
protected override void OnPaintFill(Graphics g, GraphicsPath path)
{
if (FillColorGradient)
{
if (IsHover || IsPress || Selected || Disabled)
{
base.OnPaintFill(g, path);
}
else
{
LinearGradientBrush br;
switch (fillColorGradientDirection)
{
case FlowDirection.LeftToRight:
br = new LinearGradientBrush(new Point(0, 0), new Point(Width, y: 0), FillColor, FillColor2);
break;
case FlowDirection.TopDown:
br = new LinearGradientBrush(new Point(0, 0), new Point(0, Height), FillColor, FillColor2);
break;
case FlowDirection.RightToLeft:
br = new LinearGradientBrush(new Point(Width, 0), new Point(0, y: 0), FillColor, FillColor2);
break;
case FlowDirection.BottomUp:
br = new LinearGradientBrush(new Point(0, Height), new Point(0, 0), FillColor, FillColor2);
break;
default:
br = new LinearGradientBrush(new Point(0, 0), new Point(0, Height), FillColor, FillColor2);
break;
}
br.GammaCorrection = true;
g.FillPath(br, path);
2023-10-30 11:19:41 +08:00
br?.Dispose();
}
}
else
{
base.OnPaintFill(g, path);
}
}
2020-09-14 21:31:09 +08:00
private Color tipsColor = Color.Red;
2022-06-24 15:04:08 +08:00
/// <summary>
/// 角标背景颜色
/// </summary>
[Description("角标背景颜色"), Category("SunnyUI")]
2020-09-14 21:31:09 +08:00
[DefaultValue(typeof(Color), "Red")]
public Color TipsColor
{
get => tipsColor;
set
{
tipsColor = value;
Invalidate();
}
}
private Color tipsForeColor = Color.White;
2022-06-24 15:04:08 +08:00
/// <summary>
/// 角标文字颜色
/// </summary>
[DefaultValue(typeof(Color), "White"), Category("SunnyUI"), Description("角标文字颜色")]
public Color TipsForeColor
{
get => tipsForeColor;
set
{
tipsForeColor = value;
Invalidate();
}
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 重载绘图
/// </summary>
/// <param name="e">绘图参数</param>
2020-05-11 21:11:29 +08:00
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
2022-02-26 10:28:54 +08:00
if (autoSize && Dock == DockStyle.None)
{
2023-05-16 13:27:58 +08:00
Size sf = TextRenderer.MeasureText(Text, Font);
if (Width != sf.Width + 6) Width = sf.Width + 6;
if (Height != sf.Height + 6) Height = sf.Height + 6;
2022-02-26 10:28:54 +08:00
}
2020-05-11 21:11:29 +08:00
if (Enabled && ShowTips && !string.IsNullOrEmpty(TipsText))
{
e.Graphics.SetHighQuality();
using var TempFont = TipsFont.DPIScaleFont(TipsFont.Size);
2023-05-16 15:01:46 +08:00
Size sf = TextRenderer.MeasureText(TipsText, TempFont);
int sfMax = Math.Max(sf.Width, sf.Height);
2023-05-11 22:48:40 +08:00
int x = Width - 1 - 2 - sfMax;
int y = 1 + 1;
e.Graphics.FillEllipse(TipsColor, x - 1, y, sfMax, sfMax);
e.Graphics.DrawString(TipsText, TempFont, TipsForeColor, new Rectangle(x, y, sfMax, sfMax), ContentAlignment.MiddleCenter);
2020-05-11 21:11:29 +08:00
}
if (Focused && ShowFocusLine)
{
Rectangle rect = new Rectangle(2, 2, Width - 5, Height - 5);
2023-10-30 11:19:41 +08:00
using var path = rect.CreateRoundedRectanglePath(Radius);
using Pen pn = new Pen(ForeColor);
pn.DashStyle = DashStyle.Dot;
e.Graphics.DrawPath(pn, path);
}
2020-05-11 21:11:29 +08:00
}
2020-05-11 21:11:29 +08:00
/// <summary>
/// 是否选中
/// </summary>
[DefaultValue(false)]
[Description("是否选中"), Category("SunnyUI")]
2020-05-11 21:11:29 +08:00
public bool Selected
{
get => selected;
set
{
if (selected != value)
{
selected = value;
Invalidate();
if (value && Parent != null)
{
if (this is UISymbolButton)
{
List<UISymbolButton> buttons = Parent.GetControls<UISymbolButton>();
foreach (var box in buttons)
{
if (box == this) continue;
if (box.GroupIndex != GroupIndex) continue;
if (box.Selected) box.Selected = false;
}
return;
}
if (this is UIButton)
{
List<UIButton> buttons = Parent.GetControls<UIButton>();
foreach (var box in buttons)
{
if (box is UISymbolButton) continue;
if (box == this) continue;
if (box.GroupIndex != GroupIndex) continue;
if (box.Selected) box.Selected = false;
}
return;
}
}
2020-05-11 21:11:29 +08:00
}
}
}
2022-06-23 23:27:55 +08:00
/// <summary>
/// 设置主题样式
/// </summary>
/// <param name="uiColor">主题样式</param>
2020-05-11 21:11:29 +08:00
public override void SetStyleColor(UIBaseStyle uiColor)
{
base.SetStyleColor(uiColor);
plainColor = uiColor.PlainColor;
2020-05-11 21:11:29 +08:00
fillHoverColor = uiColor.ButtonFillHoverColor;
rectHoverColor = uiColor.ButtonRectHoverColor;
2020-05-11 21:11:29 +08:00
foreHoverColor = uiColor.ButtonForeHoverColor;
fillPressColor = uiColor.ButtonFillPressColor;
rectPressColor = uiColor.ButtonRectPressColor;
2020-05-11 21:11:29 +08:00
forePressColor = uiColor.ButtonForePressColor;
fillSelectedColor = uiColor.ButtonFillSelectedColor;
foreSelectedColor = uiColor.ButtonForeSelectedColor;
rectSelectedColor = uiColor.ButtonRectSelectedColor;
2020-05-11 21:11:29 +08:00
}
/// <summary>
/// 填充颜色,当值为背景色或透明色或空值则不填充
/// </summary>
[Description("填充颜色"), Category("SunnyUI")]
2020-05-11 21:11:29 +08:00
[DefaultValue(typeof(Color), "80, 160, 255")]
public Color FillColor
{
get => fillColor;
set => SetFillColor(value);
}
/// <summary>
/// 填充颜色,当值为背景色或透明色或空值则不填充
/// </summary>
[Description("填充颜色"), Category("SunnyUI")]
[DefaultValue(typeof(Color), "80, 160, 255")]
public Color FillColor2
{
get => fillColor2;
set => SetFillColor2(value);
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 填充颜色渐变
/// </summary>
[Description("填充颜色渐变"), Category("SunnyUI")]
[DefaultValue(false)]
public bool FillColorGradient
{
get => fillColorGradient;
set
{
if (fillColorGradient != value)
{
fillColorGradient = value;
Invalidate();
}
}
}
private FlowDirection fillColorGradientDirection = FlowDirection.TopDown;
[Description("填充颜色渐变方向"), Category("SunnyUI")]
[DefaultValue(FlowDirection.TopDown)]
public FlowDirection FillColorGradientDirection
{
get => fillColorGradientDirection;
set
{
if (fillColorGradientDirection != value)
{
fillColorGradientDirection = value;
Invalidate();
}
}
}
2020-05-11 21:11:29 +08:00
/// <summary>
/// 边框颜色
/// </summary>
[Description("边框颜色"), Category("SunnyUI")]
2020-05-11 21:11:29 +08:00
[DefaultValue(typeof(Color), "80, 160, 255")]
public Color RectColor
{
get => rectColor;
set => SetRectColor(value);
}
/// <summary>
/// 字体颜色
/// </summary>
[Description("字体颜色"), Category("SunnyUI")]
2020-05-11 21:11:29 +08:00
[DefaultValue(typeof(Color), "White")]
public override Color ForeColor
{
get => foreColor;
set => SetForeColor(value);
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 不可用时填充颜色
/// </summary>
[DefaultValue(typeof(Color), "244, 244, 244"), Category("SunnyUI")]
[Description("不可用时填充颜色")]
2020-05-11 21:11:29 +08:00
public Color FillDisableColor
{
get => fillDisableColor;
set => SetFillDisableColor(value);
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 不可用时边框颜色
/// </summary>
[DefaultValue(typeof(Color), "173, 178, 181"), Category("SunnyUI")]
[Description("不可用时边框颜色")]
2020-05-11 21:11:29 +08:00
public Color RectDisableColor
{
get => rectDisableColor;
set => SetRectDisableColor(value);
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 不可用时字体颜色
/// </summary>
[DefaultValue(typeof(Color), "109, 109, 103"), Category("SunnyUI")]
[Description("不可用时字体颜色")]
2020-05-11 21:11:29 +08:00
public Color ForeDisableColor
{
get => foreDisableColor;
set => SetForeDisableColor(value);
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 鼠标移上时填充颜色
/// </summary>
[DefaultValue(typeof(Color), "115, 179, 255"), Category("SunnyUI")]
[Description("鼠标移上时填充颜色")]
2020-05-11 21:11:29 +08:00
public Color FillHoverColor
{
get => fillHoverColor;
set => SetFillHoverColor(value);
2020-05-11 21:11:29 +08:00
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 鼠标按下时填充颜色
/// </summary>
[DefaultValue(typeof(Color), "64, 128, 204"), Category("SunnyUI")]
[Description("鼠标按下时填充颜色")]
2020-05-11 21:11:29 +08:00
public Color FillPressColor
{
get => fillPressColor;
set => SetFillPressColor(value);
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 鼠标移上时字体颜色
/// </summary>
[DefaultValue(typeof(Color), "White"), Category("SunnyUI")]
[Description("鼠标移上时字体颜色")]
2020-05-11 21:11:29 +08:00
public Color ForeHoverColor
{
get => foreHoverColor;
set => SetForeHoverColor(value);
2020-05-11 21:11:29 +08:00
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 鼠标按下时字体颜色
/// </summary>
[DefaultValue(typeof(Color), "White"), Category("SunnyUI")]
[Description("鼠标按下时字体颜色")]
2020-05-11 21:11:29 +08:00
public Color ForePressColor
{
get => forePressColor;
set => SetForePressColor(value);
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 鼠标移上时边框颜色
/// </summary>
[DefaultValue(typeof(Color), "115, 179, 255"), Category("SunnyUI")]
[Description("鼠标移上时边框颜色")]
2020-05-11 21:11:29 +08:00
public Color RectHoverColor
{
get => rectHoverColor;
set => SetRectHoverColor(value);
2020-05-11 21:11:29 +08:00
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 鼠标按下时边框颜色
/// </summary>
[DefaultValue(typeof(Color), "64, 128, 204"), Category("SunnyUI")]
[Description("鼠标按下时边框颜色")]
2020-05-11 21:11:29 +08:00
public Color RectPressColor
{
get => rectPressColor;
set => SetRectPressColor(value);
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 选中时填充颜色
/// </summary>
[DefaultValue(typeof(Color), "64, 128, 204"), Category("SunnyUI")]
[Description("选中时填充颜色")]
public Color FillSelectedColor
{
get => fillSelectedColor;
set => SetFillSelectedColor(value);
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 选中时字体颜色
/// </summary>
[DefaultValue(typeof(Color), "White"), Category("SunnyUI")]
[Description("选中时字体颜色")]
public Color ForeSelectedColor
{
get => foreSelectedColor;
set => SetForeSelectedColor(value);
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 选中时边框颜色
/// </summary>
[DefaultValue(typeof(Color), "64, 128, 204"), Category("SunnyUI")]
[Description("选中时边框颜色")]
public Color RectSelectedColor
2020-05-11 21:11:29 +08:00
{
get => rectSelectedColor;
set => SetRectSelectedColor(value);
2020-05-11 21:11:29 +08:00
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 重载鼠标按下事件
/// </summary>
/// <param name="e">鼠标参数</param>
2020-05-11 21:11:29 +08:00
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
IsPress = true;
Invalidate();
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 重载鼠标抬起事件
/// </summary>
/// <param name="e">鼠标参数</param>
2020-05-11 21:11:29 +08:00
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
IsPress = false;
Invalidate();
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 重载鼠标离开事件
/// </summary>
/// <param name="e">鼠标参数</param>
2020-05-11 21:11:29 +08:00
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
IsPress = false;
IsHover = false;
Invalidate();
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 重载鼠标进入事件
/// </summary>
/// <param name="e">鼠标参数</param>
2020-05-11 21:11:29 +08:00
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
IsHover = true;
Invalidate();
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 通知控件它是默认按钮
/// </summary>
/// <param name="value"></param>
public void NotifyDefault(bool value)
{
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 指定标识符以指示对话框的返回值
/// </summary>
[DefaultValue(DialogResult.None)]
[Description("指定标识符以指示对话框的返回值"), Category("SunnyUI")]
public DialogResult DialogResult { get; set; } = DialogResult.None;
2022-06-24 15:04:08 +08:00
/// <summary>
/// 键盘按下事件
/// </summary>
/// <param name="e">按键参数</param>
protected override void OnKeyDown(KeyEventArgs e)
{
if (Focused && e.KeyCode == Keys.Space)
{
IsPress = true;
Invalidate();
PerformClick();
}
base.OnKeyDown(e);
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 键盘抬起事件
/// </summary>
/// <param name="e">按键参数</param>
protected override void OnKeyUp(KeyEventArgs e)
{
IsPress = false;
Invalidate();
base.OnKeyUp(e);
}
2022-06-24 15:04:08 +08:00
/// <summary>
/// 显示激活时边框线
/// </summary>
[DefaultValue(false)]
[Description("显示激活时边框线"), Category("SunnyUI")]
public bool ShowFocusLine { get; set; }
[DefaultValue(0)]
[Description("分组编号"), Category("SunnyUI")]
public int GroupIndex { get; set; }
[Description("文本返回值"), Category("SunnyUI")]
[Browsable(true)]
[DefaultValue("")]
[Editor("System.ComponentModel.Design.MultilineStringEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
public override string Text
{
get => base.Text;
set => base.Text = value;
}
2020-05-11 21:11:29 +08:00
}
}