From f52a92f7b58f8bcf7d33d4252ef8ce15f4e5d47f Mon Sep 17 00:00:00 2001 From: Tom <17379620@qq.com> Date: Mon, 3 Mar 2025 21:36:29 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=92=8E=20Splitter=20=E5=88=86=E9=9A=94?= =?UTF-8?q?=E9=9D=A2=E6=9D=BF=E5=A2=9E=E5=8A=A0=E6=8A=98=E5=8F=A0=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E3=80=81Select=20=E6=96=B0=E5=A2=9E=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=20CloseIcon=EF=BC=8C=E4=BA=8B=E4=BB=B6=20ClosedItem?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/AntdUI/AntdUI.csproj | 2 +- src/AntdUI/Controls/IControl.cs | 5 + src/AntdUI/Controls/Select.cs | 109 ++-- src/AntdUI/Controls/Splitter.cs | 561 +++++++++--------- .../LayeredWindow/LayeredFormSelectDown.cs | 118 +++- .../LayeredFormSelectMultiple.cs | 17 +- 6 files changed, 455 insertions(+), 357 deletions(-) diff --git a/src/AntdUI/AntdUI.csproj b/src/AntdUI/AntdUI.csproj index 76c9600f..63d11b1b 100644 --- a/src/AntdUI/AntdUI.csproj +++ b/src/AntdUI/AntdUI.csproj @@ -13,7 +13,7 @@ Winform UI library use Ant Design 5.0 $(Version) $(Version) - 1.9.0 + 1.9.1 👚 基于 Ant Design 设计语言的 Winform 界面库 false 9.0 diff --git a/src/AntdUI/Controls/IControl.cs b/src/AntdUI/Controls/IControl.cs index 247cfac4..8d52f468 100644 --- a/src/AntdUI/Controls/IControl.cs +++ b/src/AntdUI/Controls/IControl.cs @@ -313,6 +313,10 @@ namespace AntdUI flag = false; SetCursor(Cursors.VSplit); break; + case CursorType.HSplit: + flag = false; + SetCursor(Cursors.HSplit); + break; case CursorType.Default: default: SetCursor(DefaultCursor); @@ -632,6 +636,7 @@ namespace AntdUI No, SizeAll, VSplit, + HSplit, } public interface BadgeConfig diff --git a/src/AntdUI/Controls/Select.cs b/src/AntdUI/Controls/Select.cs index c5a76a4b..01a16d5d 100644 --- a/src/AntdUI/Controls/Select.cs +++ b/src/AntdUI/Controls/Select.cs @@ -104,6 +104,12 @@ namespace AntdUI [Description("点击切换下拉"), Category("行为"), DefaultValue(true)] public bool ClickSwitchDropdown { get; set; } = true; + /// + /// 是否显示关闭图标 + /// + [Description("是否显示关闭图标"), Category("行为"), DefaultValue(false)] + public bool CloseIcon { get; set; } + #region 数据 BaseCollection? items; @@ -283,6 +289,14 @@ namespace AntdUI subForm = null; } + internal bool DropDownClose(object value) + { + if (ClosedItem == null) return false; + if (value is SelectItem it) ClosedItem(this, new ObjectNEventArgs(it.Tag)); + else ClosedItem(this, new ObjectNEventArgs(value)); + return true; + } + #endregion /// @@ -303,6 +317,12 @@ namespace AntdUI [Description("SelectedValue 属性值更改时发生"), Category("行为")] public event ObjectNEventHandler? SelectedValueChanged = null; + /// + /// 关闭某项 时发生 + /// + [Description("关闭某项 时发生"), Category("行为")] + public event ObjectNEventHandler? ClosedItem = null; + public delegate IList? FilterEventHandler(object sender, string value); /// /// 控制筛选 Text更改时发生 @@ -722,13 +742,13 @@ namespace AntdUI internal class ObjectItem { - public ObjectItem(object _val, int _i, Rectangle rect, Rectangle rect_text) + public ObjectItem(object _val, int _i, Rectangle rect, Rectangle rect_text, bool closeIcon, int gap_x, int gap_x2, int gap_y, int gap_y2) { Show = true; Val = _val; Text = _val.ToString() ?? string.Empty; ID = _i; - SetRect(rect, rect_text); + SetRectBase(rect, rect_text, closeIcon, gap_x, gap_x2, gap_y, gap_y2); string pinyin = Text; PY = new string[] { pinyin.ToLower(), @@ -737,13 +757,13 @@ namespace AntdUI }; } - public ObjectItem(GroupSelectItem _val, int _i, Rectangle rect, Rectangle rect_text) + public ObjectItem(GroupSelectItem _val, int _i, Rectangle rect, Rectangle rect_text, bool closeIcon, int gap_x, int gap_x2, int gap_y, int gap_y2) { Show = Group = true; Val = _val; Text = _val.Title; ID = _i; - SetRect(rect, rect_text); + SetRectBase(rect, rect_text, closeIcon, gap_x, gap_x2, gap_y, gap_y2); string pinyin = Text; PY = new string[] { pinyin.ToLower(), @@ -752,7 +772,7 @@ namespace AntdUI }; } - public ObjectItem(SelectItem _val, int _i, Rectangle rect, Rectangle rect_text, int gap_x, int gap_x2, int gap_y, int gap_y2) + public ObjectItem(SelectItem _val, int _i, Rectangle rect, Rectangle rect_text, bool closeIcon, int gap_x, int gap_x2, int gap_y, int gap_y2) { Sub = _val.Sub; if (Sub != null && Sub.Count > 0) has_sub = true; @@ -766,7 +786,7 @@ namespace AntdUI SubText = _val.SubText; Enable = _val.Enable; ID = _i; - SetRect(rect, rect_text, gap_x, gap_x2, gap_y, gap_y2); + SetRect(rect, rect_text, closeIcon, gap_x, gap_x2, gap_y, gap_y2); string pinyin = _val.Text + _val.SubText; PY = new string[] { pinyin.ToLower(), @@ -857,43 +877,58 @@ namespace AntdUI internal bool ShowAndID => ID == -1 || !Show; internal Rectangle RectArrow { get; set; } - + internal Rectangle RectClose { get; set; } + internal Rectangle RectCloseIcon { get; set; } + internal bool HoverClose { get; set; } public Rectangle Rect { get; set; } - internal void SetRect(Rectangle rect, Rectangle rect_text, int gap_x, int gap_x2, int gap_y, int gap_y2) + internal void SetRectAuto(Rectangle rect, Rectangle rect_text, bool closeIcon, int gap_x, int gap_x2, int gap_y, int gap_y2) { - Rect = rect; - if (Val is SelectItem) - { - if (Online > -1 || HasIcon) - { - if (Online > -1 && HasIcon) - { - RectOnline = new Rectangle(rect_text.X - gap_y / 2, rect_text.Y + (rect_text.Height - gap_y) / 2, gap_y, gap_y); - RectIcon = new Rectangle(rect_text.X + gap_y2, rect_text.Y, rect_text.Height, rect_text.Height); - RectText = new Rectangle(rect_text.X + gap_y + gap_y2 + rect_text.Height, rect_text.Y, rect_text.Width - rect_text.Height - gap_y - gap_y2, rect_text.Height); - } - else if (Online > -1) - { - RectOnline = new Rectangle(rect_text.X - gap_y / 2, rect_text.Y + (rect_text.Height - gap_y) / 2, gap_y, gap_y); - RectText = new Rectangle(rect_text.X + gap_y2, rect_text.Y, rect_text.Width - gap_y2, rect_text.Height); - } - else - { - RectIcon = new Rectangle(rect.X + gap_x / 2, rect_text.Y, rect_text.Height, rect_text.Height); - RectText = new Rectangle(rect_text.X + rect_text.Height, rect_text.Y, rect_text.Width - rect_text.Height, rect_text.Height); - } - } - else RectText = rect_text; - RectArrow = new Rectangle(Rect.Right - Rect.Height - gap_y, Rect.Y, Rect.Height, Rect.Height); - } - else RectText = rect_text; + if (Val is SelectItem) SetRect(rect, rect_text, closeIcon, gap_x, gap_x2, gap_y, gap_y2); + else SetRectBase(rect, rect_text, closeIcon, gap_x, gap_x2, gap_y, gap_y2); } - internal void SetRect(Rectangle rect, Rectangle rect_text) + internal void SetRect(Rectangle rect, Rectangle rect_text, bool closeIcon, int gap_x, int gap_x2, int gap_y, int gap_y2) + { + Rect = rect; + if (Online > -1 || HasIcon) + { + if (Online > -1 && HasIcon) + { + RectOnline = new Rectangle(rect_text.X - gap_y / 2, rect_text.Y + (rect_text.Height - gap_y) / 2, gap_y, gap_y); + RectIcon = new Rectangle(rect_text.X + gap_y2, rect_text.Y, rect_text.Height, rect_text.Height); + RectText = new Rectangle(rect_text.X + gap_y + gap_y2 + rect_text.Height, rect_text.Y, rect_text.Width - rect_text.Height - gap_y - gap_y2, rect_text.Height); + } + else if (Online > -1) + { + RectOnline = new Rectangle(rect_text.X - gap_y / 2, rect_text.Y + (rect_text.Height - gap_y) / 2, gap_y, gap_y); + RectText = new Rectangle(rect_text.X + gap_y2, rect_text.Y, rect_text.Width - gap_y2, rect_text.Height); + } + else + { + RectIcon = new Rectangle(rect.X + gap_x / 2, rect_text.Y, rect_text.Height, rect_text.Height); + RectText = new Rectangle(rect_text.X + rect_text.Height, rect_text.Y, rect_text.Width - rect_text.Height, rect_text.Height); + } + } + else RectText = rect_text; + RectArrow = new Rectangle(Rect.Right - Rect.Height - gap_y, Rect.Y, Rect.Height, Rect.Height); + if (closeIcon) + { + RectClose = new Rectangle(RectArrow.X + gap_y, RectArrow.Y + gap_y, RectArrow.Width - gap_y2, RectArrow.Height - gap_y2); + RectCloseIcon = new Rectangle(RectClose.X + gap_y, RectClose.Y + gap_y, RectClose.Width - gap_y2, RectClose.Height - gap_y2); + } + } + + internal void SetRectBase(Rectangle rect, Rectangle rect_text, bool closeIcon, int gap_x, int gap_x2, int gap_y, int gap_y2) { Rect = rect; RectText = rect_text; + RectArrow = new Rectangle(Rect.Right - Rect.Height - gap_y, Rect.Y, Rect.Height, Rect.Height); + if (closeIcon) + { + RectClose = new Rectangle(RectArrow.X + gap_y, RectArrow.Y + gap_y, RectArrow.Width - gap_y2, RectArrow.Height - gap_y2); + RectCloseIcon = new Rectangle(RectClose.X + gap_y, RectClose.Y + gap_y, RectClose.Width - gap_y2, RectClose.Height - gap_y2); + } } internal bool SetHover(bool val) @@ -911,9 +946,9 @@ namespace AntdUI } return change; } - internal bool Contains(Point point, int x, int y, out bool change) + internal bool Contains(int x, int y, int sx, int sy, out bool change) { - if (ID > -1 && Rect.Contains(point.X + x, point.Y + y)) + if (ID > -1 && Rect.Contains(x + sx, y + sy)) { change = SetHover(true); return true; diff --git a/src/AntdUI/Controls/Splitter.cs b/src/AntdUI/Controls/Splitter.cs index 7a2d123a..c72d231e 100644 --- a/src/AntdUI/Controls/Splitter.cs +++ b/src/AntdUI/Controls/Splitter.cs @@ -17,7 +17,6 @@ // QQ: 17379620 using System; -using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Design; @@ -33,14 +32,28 @@ namespace AntdUI [ToolboxItem(true)] public class Splitter : SplitContainer { + public Splitter() + { + SetStyle( + ControlStyles.UserPaint | + ControlStyles.AllPaintingInWmPaint | + ControlStyles.OptimizedDoubleBuffer | + ControlStyles.ResizeRedraw, true); + + SplitterMoving += Splitter_SplitterMoving; + SplitterMoved += Splitter_SplitterMoved; + } + + #region 参数 + /// /// 记录折叠前的分隔距离 /// - private int _lastDistance; + int _lastDistance; //记录折叠控件最小大小 //折叠忽略最小,最小只在拖动分割栏时有效 - private int _minSize; + int _minSize; /// /// 当前鼠标状态 @@ -48,17 +61,12 @@ namespace AntdUI /// false = 移动 /// true = 箭头 /// - private bool? _MouseState; - - /// - /// 记录折叠控件的当前大小 - /// - private int _size; + bool? _MouseState; /// /// 箭头SVG /// - private string[] arrowSvg = new string[4] + string[] arrowSvg = new string[4] { "UpOutlined" , "DownOutlined", "LeftOutlined" , "RightOutlined" @@ -67,77 +75,42 @@ namespace AntdUI /// /// 鼠标是否在箭头区域 /// - private bool m_bIsArrowRegion; + bool m_bIsArrowRegion; - public Splitter() - { - SetStyle( - ControlStyles.UserPaint | - ControlStyles.AllPaintingInWmPaint | - ControlStyles.OptimizedDoubleBuffer | - ControlStyles.ResizeRedraw, true); - } - - #region 事件 - - /// - /// SplitPanelState 属性值更改时发生 - /// - [Description("SplitPanelState 属性值更改时发生"), Category("行为")] - public event BoolEventHandler? SplitPanelStateChanged = null; - - #endregion 事件 + #endregion #region 属性 - private Color? _arrawBackHoverColor; - - private Color? _arrowBackColor; - - private Color? _arrowColor; - - private int _arrowSize = 30; - - private ADCollapsePanel _collapsePanel = ADCollapsePanel.Panel1; - /// - /// 当前折叠状态 + /// 滑块大小 /// - private bool _splitPanelState = true; + [Description("滑块大小"), Category("行为"), DefaultValue(20)] + public int SplitterSize { get; set; } = 20; - private Color? back; - - public enum ADCollapsePanel - { - None = 0, - Panel1 = 1, - Panel2 = 2, - } - - [Description("箭头背景色"), DefaultValue(null), Category("外观")] + Color? splitterBack; + /// + /// 滑块背景 + /// + [Description("滑块背景"), DefaultValue(null), Category("外观")] [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] - public Color? ArrawBackColor + public Color? SplitterBack { - get => _arrowBackColor; + get => splitterBack; set { - _arrowBackColor = value; + if (splitterBack == value) return; + splitterBack = value; Invalidate(); } } - - [Description("鼠标悬浮箭头背景色"), DefaultValue(null), Category("外观")] + /// + /// 滑块移动背景 + /// + [Description("滑块移动背景"), DefaultValue(null), Category("外观")] [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] - public Color? ArrawBackHoverColor - { - get => _arrawBackHoverColor; - set - { - _arrawBackHoverColor = value; - Invalidate(); - } - } + public Color? SplitterBackMove { get; set; } + Color? _arrowColor; [Description("箭头颜色"), DefaultValue(null), Category("外观")] [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] public Color? ArrowColor @@ -145,57 +118,60 @@ namespace AntdUI get => _arrowColor; set { + if (_arrowColor == value) return; _arrowColor = value; Invalidate(); } } /// - /// 箭头大小 + /// 鼠标悬浮箭头颜色 /// - [Description("箭头大小"), Category("外观"), DefaultValue(30)] - public int ArrowSize + [Description("鼠标悬浮箭头颜色"), DefaultValue(null), Category("外观")] + [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] + public Color? ArrawColorHover { get; set; } + + Color? _arrowBackColor; + [Description("箭头背景色"), DefaultValue(null), Category("外观")] + [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] + public Color? ArrawBackColor { - get => _arrowSize; + get => _arrowBackColor; set { - if (_arrowSize == value) return; - _arrowSize = value; + if (_arrowBackColor == value) return; + _arrowBackColor = value; Invalidate(); } } /// - /// 背景颜色 + /// 鼠标悬浮箭头背景色 /// - [Description("背景颜色"), DefaultValue(null), Category("外观")] + [Description("鼠标悬浮箭头背景色"), DefaultValue(null), Category("外观")] [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] - public new Color? BackColor - { - get => back; - set - { - if (back == value) return; - back = value; - Invalidate(); - } - } + public Color? ArrawBackHover { get; set; } - [Description("点击后收起的Panel"), Category("行为"), DefaultValue(ADCollapsePanel.Panel1)] + ADCollapsePanel _collapsePanel = ADCollapsePanel.None; + [Description("点击后收起的Panel"), Category("行为"), DefaultValue(ADCollapsePanel.None)] public ADCollapsePanel CollapsePanel { get => _collapsePanel; set { - if (_collapsePanel != value) - { - Expand(); - _collapsePanel = value; - Invalidate(); - } + if (_collapsePanel == value) return; + _collapsePanel = value; + Expand(); } } + public enum ADCollapsePanel + { + None = 0, + Panel1 = 1, + Panel2 = 2, + } + [Description("拆分器是水平的还是垂直的"), Category("行为"), DefaultValue(Orientation.Vertical)] public new Orientation Orientation { @@ -204,6 +180,7 @@ namespace AntdUI { if (base.Orientation == value) return; base.Orientation = value; + if (_collapsePanel == ADCollapsePanel.None) return; if (!SplitPanelState) { SplitPanelState = true; @@ -213,44 +190,33 @@ namespace AntdUI } } - [Description("分隔栏宽度"), Category("外观"), DefaultValue(15)] - public new int SplitterWidth - { - get => base.SplitterWidth; - set - { - if (base.SplitterWidth == value) return; - base.SplitterWidth = value; - Invalidate(); - } - } - + /// + /// 当前折叠状态 + /// + bool _splitPanelState = true; [Description("是否进行展开"), Category("行为"), DefaultValue(true)] private bool SplitPanelState { get => _splitPanelState; set { - if (_splitPanelState == value) - return; - - if (value) - Expand(); - else - Collapse(); - + if (_splitPanelState == value) return; + if (value) Expand(); + else Collapse(); _splitPanelState = value; } } + #endregion + + #region 方法 + /// /// 折叠 /// public void Collapse() { - if (_collapsePanel == ADCollapsePanel.None) - return; - + if (_collapsePanel == ADCollapsePanel.None) return; _lastDistance = SplitterDistance; if (_collapsePanel == ADCollapsePanel.Panel1) { @@ -260,13 +226,11 @@ namespace AntdUI } else { - int width = Orientation == Orientation.Horizontal ? - Height : Width; + int width = Orientation == Orientation.Horizontal ? Height : Width; _minSize = Panel2MinSize; Panel2MinSize = 0; SplitterDistance = width - SplitterWidth - Padding.Vertical; } - _splitPanelState = false; Invalidate(); } @@ -276,268 +240,293 @@ namespace AntdUI /// public void Expand() { - if (_collapsePanel == ADCollapsePanel.None) - return; - + if (_collapsePanel == ADCollapsePanel.None) return; SplitterDistance = _lastDistance; - - if (_collapsePanel == ADCollapsePanel.Panel1) - Panel1MinSize = _minSize; - else - Panel2MinSize = _minSize; - + if (_collapsePanel == ADCollapsePanel.Panel1) Panel1MinSize = _minSize; + else Panel2MinSize = _minSize; _splitPanelState = true; Invalidate(); } - #endregion 属性 + #endregion - #region 渲染 + #region 事件 /// - /// 箭头背景区域 + /// SplitPanelState 属性值更改时发生 /// - private Rectangle ArrowRect - { - get - { - if (_collapsePanel == ADCollapsePanel.None) - return Rectangle.Empty; + [Description("SplitPanelState 属性值更改时发生"), Category("行为")] + public event BoolEventHandler? SplitPanelStateChanged; - int size = ArrowSize; - Rectangle rect = SplitterRectangle; - if (Orientation == Orientation.Horizontal) - { - rect.X = (int)((Width - size) / 2); - rect.Width = (int)(size); - } - else - { - rect.Y = (int)((Height - size) / 2); - rect.Height = (int)(size); - } + #endregion - return rect; - } - } + #region 渲染 protected override void OnPaint(PaintEventArgs e) { if (Panel1Collapsed || Panel2Collapsed) return; var g = e.Graphics.High(); var rect = SplitterRectangle; - - //绘制背景 - g.Fill(back ?? Colour.Split.Get("Splitter"), rect); - - //不进行折叠 if (_collapsePanel == ADCollapsePanel.None) - return; - - //画箭头背景 - Point[] points = GetHandlePoints(); - if (m_bIsArrowRegion) - g.FillPolygon(_arrawBackHoverColor ?? Colour.PrimaryBgHover.Get("Splitter"), points); + { + if (moving) g.Fill(SplitterBackMove ?? Style.Db.PrimaryBg, rect); + else g.Fill(splitterBack ?? Style.Db.FillTertiary, rect); + int size = (int)(SplitterSize * Config.Dpi); + if (Orientation == Orientation.Horizontal) g.Fill(Style.Db.Fill, new Rectangle(rect.X + (rect.Width - size) / 2, rect.Y, size, rect.Height)); + else g.Fill(Style.Db.Fill, new Rectangle(rect.X, rect.Y + (rect.Height - size) / 2, rect.Width, size)); + } else - g.FillPolygon(_arrowBackColor ?? Colour.PrimaryBg.Get("Splitter"), points); + { + if (moving) g.Fill(SplitterBackMove ?? Style.Db.PrimaryBg, rect); + else g.Fill(splitterBack ?? Style.Db.FillTertiary, rect); - //计算显示图标 - bool is_p1 = _collapsePanel == ADCollapsePanel.Panel1; - int index = 0; + //计算显示图标 + int index = 0; + if (Orientation == Orientation.Horizontal) index = 1; + else index = 3; + if ((_collapsePanel == ADCollapsePanel.Panel1) == SplitPanelState) index--; + + //画箭头背景 + var points = GetHandlePoints(out var rect_arrow); + + //绘制箭头 + if (m_bIsArrowRegion) + { + g.FillPolygon(ArrawBackHover ?? Colour.Primary.Get("Splitter"), points); + SvgExtend.GetImgExtend(g, arrowSvg[index], rect_arrow, ArrawColorHover ?? Colour.PrimaryColor.Get("Splitter")); + } + else + { + g.FillPolygon(_arrowBackColor ?? Colour.PrimaryBg.Get("Splitter"), points); + SvgExtend.GetImgExtend(g, arrowSvg[index], rect_arrow, _arrowColor ?? Colour.PrimaryBorder.Get("Splitter")); + } + + } + } + + // + /// 箭头背景区域 + /// + Rectangle ArrowRect(Rectangle rect) + { + if (_collapsePanel == ADCollapsePanel.None) return Rectangle.Empty; + int size = (int)(SplitterSize * Config.Dpi); if (Orientation == Orientation.Horizontal) - index = 1; + { + rect.X = (Width - size) / 2; + rect.Width = size; + } else - index = 3; - - if (is_p1 == SplitPanelState) - index--; - - //绘制箭头 - DrawArrow(g, arrowSvg[index]); + { + rect.Y = (Height - size) / 2; + rect.Height = size; + } + return rect; } - protected override void OnSizeChanged(EventArgs e) + Point[] GetHandlePoints(out Rectangle rect_arrow) { - base.OnSizeChanged(e); - Invalidate(); - } + bool isCollapsed = (CollapsePanel == ADCollapsePanel.Panel1) == SplitPanelState; - private void DrawArrow(Canvas g, string svg) - { - int size = Math.Min(ArrowSize, SplitterWidth); - Point point; - - //居中显示 - if (Orientation == Orientation.Horizontal) - point = new Point((SplitterRectangle.Width - size) / 2, SplitterRectangle.Top); - else - point = new Point(SplitterRectangle.Left, (SplitterRectangle.Height - size) / 2); - - Rectangle rectangle = new Rectangle(point.X, point.Y, size, size); - - SvgExtend.GetImgExtend(g, svg, rectangle, _arrowColor ?? Colour.PrimaryBorder.Get("Splitter")); - } - - private Point[] GetHandlePoints() - { - var points = new List(); - bool isPanel1 = CollapsePanel == ADCollapsePanel.Panel1; - bool isCollapsed = isPanel1 == SplitPanelState; - - int size = 5; + int size = (int)(4 * Config.Dpi); + rect_arrow = ArrowRect(SplitterRectangle); if (Orientation == Orientation.Horizontal) { int y1 = 0, y2 = 0; if (isCollapsed) { - y1 = ArrowRect.Bottom; - y2 = ArrowRect.Top; + y1 = rect_arrow.Bottom; + y2 = rect_arrow.Top; } else { - y1 = ArrowRect.Top; - y2 = ArrowRect.Bottom; + y1 = rect_arrow.Top; + y2 = rect_arrow.Bottom; } - points.Add(new Point(ArrowRect.Left, y1)); - points.Add(new Point(ArrowRect.Right, y1)); - points.Add(new Point(ArrowRect.Right - size, y2)); - points.Add(new Point(ArrowRect.Left + size, y2)); + return new Point[] { + new Point(rect_arrow.Left, y1), + new Point(rect_arrow.Right, y1), + new Point(rect_arrow.Right - size, y2), + new Point(rect_arrow.Left + size, y2) + }; } - else if (Orientation == Orientation.Vertical) + else { int x1 = 0, x2 = 0; if (isCollapsed) { - x1 = ArrowRect.Right; - x2 = ArrowRect.Left; + x1 = rect_arrow.Right; + x2 = rect_arrow.Left; } else { - x1 = ArrowRect.Left; - x2 = ArrowRect.Right; + x1 = rect_arrow.Left; + x2 = rect_arrow.Right; } - points.Add(new Point(x1, ArrowRect.Top)); - points.Add(new Point(x1, ArrowRect.Bottom)); - points.Add(new Point(x2, ArrowRect.Bottom - size)); - points.Add(new Point(x2, ArrowRect.Top + size)); + return new Point[] { + new Point(x1, rect_arrow.Top), + new Point(x1, rect_arrow.Bottom), + new Point(x2, rect_arrow.Bottom - size), + new Point(x2, rect_arrow.Top + size) + }; } - - return points.ToArray(); } - #endregion 渲染 + #endregion #region 鼠标 - /// - /// 重载鼠标按下事件 - /// - /// 鼠标参数 + bool moving = false; + private void Splitter_SplitterMoving(object? sender, SplitterCancelEventArgs e) + { + if (e.Cancel) return; + moving = true; + Invalidate(); + } + + private void Splitter_SplitterMoved(object? sender, SplitterEventArgs e) + { + moving = false; + Invalidate(); + } + protected override void OnMouseDown(MouseEventArgs e) { - if (DesignMode) - return; - - //点位在箭头矩形内 - if (ArrowRect.Contains(e.Location)) - _MouseState = true; - else if (!SplitPanelState) - _MouseState = null; - //点位在分割线内 - else if (SplitterRectangle.Contains(e.Location)) - _MouseState = false; - - if (_MouseState != true) + if (DesignMode || _collapsePanel == ADCollapsePanel.None) + { base.OnMouseDown(e); + return; + } + Rectangle rect = SplitterRectangle, rect_arrow = ArrowRect(rect); + if (rect_arrow.Contains(e.Location)) _MouseState = true;//点位在箭头矩形内 + else if (!SplitPanelState) _MouseState = null; + else if (rect.Contains(e.Location)) _MouseState = false;//点位在分割线内 + if (_MouseState != true) base.OnMouseDown(e); } - /// - /// 重载鼠标离开事件 - /// - /// 鼠标参数 protected override void OnMouseLeave(EventArgs e) { - if (DesignMode) - return; - base.Cursor = Cursors.Default; + base.OnMouseLeave(e); + if (DesignMode || _collapsePanel == ADCollapsePanel.None) return; + SetCursor(CursorType.Default); m_bIsArrowRegion = false; Invalidate(); - base.OnMouseLeave(e); } - /// - /// 重载鼠标移动事件 - /// - /// 鼠标参数 protected override void OnMouseMove(MouseEventArgs e) { - if (DesignMode) - return; + base.OnMouseMove(e); + if (DesignMode || _collapsePanel == ADCollapsePanel.None) return; //如果鼠标的左键没有按下,重置鼠标状态 - if (e.Button != MouseButtons.Left) - _MouseState = null; - + if (e.Button != MouseButtons.Left) _MouseState = null; //鼠标在Arrow矩形里,并且不是在拖动 - if (ArrowRect.Contains(e.Location) && _MouseState != false) + Rectangle rect = SplitterRectangle, rect_arrow = ArrowRect(rect); + if (rect_arrow.Contains(e.Location) && _MouseState != false) { - Cursor = Cursors.Hand; + SetCursor(CursorType.Hand); m_bIsArrowRegion = true; Invalidate(); return; } - if (_MouseState == true) - return; - + if (_MouseState == true) return; m_bIsArrowRegion = false; Invalidate(); - //鼠标在分隔栏矩形里 - if (SplitterRectangle.Contains(e.Location)) + if (rect.Contains(e.Location)) { //如果已经折叠,就不允许拖动了 - if (_collapsePanel != ADCollapsePanel.None && !SplitPanelState) - Cursor = Cursors.Default; - //鼠标没有按下,设置Split光标 - else if (_MouseState == null && !IsSplitterFixed) - Cursor = Orientation == Orientation.Horizontal ? Cursors.HSplit : Cursors.VSplit; + if (_collapsePanel != ADCollapsePanel.None && !SplitPanelState) SetCursor(CursorType.Default); + else if (_MouseState == null && !IsSplitterFixed) SetCursor(Orientation == Orientation.Horizontal ? CursorType.HSplit : CursorType.VSplit);//鼠标没有按下,设置Split光标 return; } - //正在拖动分隔栏 - if (_MouseState == false && !IsSplitterFixed) - { - Cursor = Orientation == Orientation.Horizontal ? Cursors.HSplit : Cursors.VSplit; - base.OnMouseMove(e); - return; - } - - base.Cursor = Cursors.Default; + if (_MouseState == false && !IsSplitterFixed) SetCursor(Orientation == Orientation.Horizontal ? CursorType.HSplit : CursorType.VSplit); + else SetCursor(CursorType.Default); } - /// - /// 重载鼠标抬起事件 - /// - /// 鼠标参数 protected override void OnMouseUp(MouseEventArgs e) { - if (DesignMode) - return; - base.OnMouseUp(e); + if (DesignMode || _collapsePanel == ADCollapsePanel.None) return; Invalidate(); - - if (_MouseState == true && e.Button == MouseButtons.Left && ArrowRect.Contains(e.Location)) + if (_MouseState == true && e.Button == MouseButtons.Left && ArrowRect(SplitterRectangle).Contains(e.Location)) { - SplitPanelState = !SplitPanelState; + SplitPanelState = !_splitPanelState; SplitPanelStateChanged?.Invoke(this, new BoolEventArgs(SplitPanelState)); } - _MouseState = null; } - #endregion 鼠标 + #region 鼠标 + + CursorType oldcursor = CursorType.Default; + public void SetCursor(bool val) => SetCursor(val ? CursorType.Hand : CursorType.Default); + public void SetCursor(CursorType cursor = CursorType.Default) + { + if (oldcursor == cursor) return; + oldcursor = cursor; + bool flag = true; + switch (cursor) + { + case CursorType.Hand: + SetCursor(Cursors.Hand); + break; + case CursorType.IBeam: + SetCursor(Cursors.IBeam); + break; + case CursorType.No: + SetCursor(Cursors.No); + break; + case CursorType.SizeAll: + flag = false; + SetCursor(Cursors.SizeAll); + break; + case CursorType.VSplit: + flag = false; + SetCursor(Cursors.VSplit); + break; + case CursorType.HSplit: + flag = false; + SetCursor(Cursors.HSplit); + break; + case CursorType.Default: + default: + SetCursor(DefaultCursor); + break; + } + SetWindow(flag); + } + void SetCursor(Cursor cursor) + { + if (InvokeRequired) + { + Invoke(new Action(() => SetCursor(cursor))); + return; + } + Cursor = cursor; + } + + bool setwindow = false; + void SetWindow(bool flag) + { + if (setwindow == flag) return; + setwindow = flag; + var form = Parent.FindPARENT(); + if (form is BaseForm baseForm) baseForm.EnableHitTest = setwindow; + } + + #endregion + + protected override void Dispose(bool disposing) + { + SplitterMoving -= Splitter_SplitterMoving; + SplitterMoved -= Splitter_SplitterMoved; + base.Dispose(disposing); + } + + #endregion } } \ No newline at end of file diff --git a/src/AntdUI/Forms/LayeredWindow/LayeredFormSelectDown.cs b/src/AntdUI/Forms/LayeredWindow/LayeredFormSelectDown.cs index fbcc8496..4bd2f897 100644 --- a/src/AntdUI/Forms/LayeredWindow/LayeredFormSelectDown.cs +++ b/src/AntdUI/Forms/LayeredWindow/LayeredFormSelectDown.cs @@ -29,7 +29,7 @@ namespace AntdUI int MaxCount = 0; Size DPadding; internal float Radius = 0; - bool ClickEnd = false; + bool ClickEnd = false, CloseIcon = false; object? selectedValue; int r_w = 0; List Items; @@ -41,6 +41,7 @@ namespace AntdUI control.Parent.SetTopMost(Handle); PARENT = control; ClickEnd = control.ClickEnd; + CloseIcon = control.CloseIcon; select_x = 0; scrollY = new ScrollY(this); MaxCount = control.MaxCount; @@ -192,6 +193,7 @@ namespace AntdUI else b_w += gap_y; } if (ui_arrow) b_w += gap_y2; + else if (CloseIcon) b_w += text_height; w = r_w = b_w + gap_x2 + gap2; } else stringFormatLeft.Trimming = StringTrimming.EllipsisCharacter; @@ -215,7 +217,6 @@ namespace AntdUI } else { - int ry = 10 + gap2 + vr; if (control is LayeredFormSelectDown) { @@ -260,19 +261,13 @@ namespace AntdUI rx = point.X - r_w + 10; ShowLeft = true; } - if (ry > screen.Bottom - TargetRect.Height) - { - ry = screen.Bottom - TargetRect.Height; - } + if (ry > screen.Bottom - TargetRect.Height) ry = screen.Bottom - TargetRect.Height; SetLocation(rx, ry); } else { int ry = point.Y + rect_read.Y; - if (ry > screen.Bottom - TargetRect.Height) - { - Placement = TAlignFrom.Top; - } + if (ry > screen.Bottom - TargetRect.Height) Placement = TAlignFrom.Top; MyPoint(point, Placement, ShowArrow, rect_read); } @@ -395,20 +390,20 @@ namespace AntdUI Rectangle rect = new Rectangle(10 + gap, y, width - gap2, item_height), rect_text = new Rectangle(rect.X + gap_x, rect.Y + gap_y, rect.Width - gap_x2, text_height); if (value is SelectItem it) { - Items.Add(new ObjectItem(it, i, rect, rect_text, gap_x, gap_x2, gap_y, gap_y2) { NoIndex = NoIndex }); + Items.Add(new ObjectItem(it, i, rect, rect_text, CloseIcon, gap_x, gap_x2, gap_y, gap_y2) { NoIndex = NoIndex }); if (selectedValue == it.Tag) select_y = y; y += item_height; } else if (value is GroupSelectItem group && group.Sub != null && group.Sub.Count > 0) { - Items.Add(new ObjectItem(group, i, rect, rect_text)); + Items.Add(new ObjectItem(group, i, rect, rect_text, CloseIcon, gap_x, gap_x2, gap_y, gap_y2)); if (selectedValue == value) select_y = y; y += item_height; foreach (var item in group.Sub) ReadList(item, i, width, item_height, text_height, gap, gap2, gap_x, gap_x2, gap_y, gap_y2, sp, ref item_count, ref divider_count, ref y, ref select_y, false); } else { - Items.Add(new ObjectItem(value, i, rect, rect_text) { NoIndex = NoIndex }); + Items.Add(new ObjectItem(value, i, rect, rect_text, CloseIcon, gap_x, gap_x2, gap_y, gap_y2) { NoIndex = NoIndex }); if (selectedValue == value) select_y = y; y += item_height; } @@ -541,7 +536,7 @@ namespace AntdUI list_count++; Rectangle rect_bg = new Rectangle(10 + gap, y, w - gap2, item_height), rect_text = new Rectangle(rect_bg.X + gap_x, rect_bg.Y + gap_y, rect_bg.Width - gap_x2, text_height); - it.SetRect(rect_bg, rect_text, gap_x, gap_x2, gap_y, gap_y2); + it.SetRectAuto(rect_bg, rect_text, CloseIcon, gap_x, gap_x2, gap_y, gap_y2); y += item_height; } }); @@ -661,7 +656,7 @@ namespace AntdUI list_count++; Rectangle rect_bg = new Rectangle(10 + gap, y, w - gap2, item_height), rect_text = new Rectangle(rect_bg.X + gap_x, rect_bg.Y + gap_y, rect_bg.Width - gap_x2, text_height); - it.SetRect(rect_bg, rect_text, gap_x, gap_x2, gap_y, gap_y2); + it.SetRectAuto(rect_bg, rect_text, CloseIcon, gap_x, gap_x2, gap_y, gap_y2); y += item_height; } }); @@ -748,7 +743,7 @@ namespace AntdUI list_count++; Rectangle rect_bg = new Rectangle(10 + gap, y, w - gap2, item_height), rect_text = new Rectangle(rect_bg.X + gap_x, rect_bg.Y + gap_y, rect_bg.Width - gap_x2, text_height); - it.SetRect(rect_bg, rect_text, gap_x, gap_x2, gap_y, gap_y2); + it.SetRectAuto(rect_bg, rect_text, CloseIcon, gap_x, gap_x2, gap_y, gap_y2); y += item_height; } }); @@ -816,11 +811,30 @@ namespace AntdUI if (scrollY.MouseUp(e.Location) && OnTouchUp() && down) { if (RunAnimation) return; - foreach (var it in Items) + int sy = (int)scrollY.Value; + if (CloseIcon) { - if (it.Show && it.Enable && it.ID > -1 && it.Contains(e.Location, 0, (int)scrollY.Value, out _)) + foreach (var it in Items) { - if (OnClick(it)) return; + if (it.Show && it.Enable && it.ID > -1 && it.Contains(e.X, e.Y, 0, sy, out _)) + { + if (it.RectClose.Contains(e.X, e.Y + sy) && PARENT is Select select && select.DropDownClose(it.Val)) + { + IClose(); + return; + } + else if (OnClick(it)) return; + } + } + } + else + { + foreach (var it in Items) + { + if (it.Show && it.Enable && it.ID > -1 && it.Contains(e.X, e.Y, 0, sy, out _)) + { + if (OnClick(it)) return; + } } } } @@ -887,14 +901,56 @@ namespace AntdUI hoveindex = -1; if (scrollY.MouseMove(e.Location) && OnTouchMove(e.X, e.Y)) { - int count = 0; - for (int i = 0; i < Items.Count; i++) + int count = 0, sy = (int)scrollY.Value; + if (CloseIcon) { - var it = Items[i]; - if (it.Enable) + for (int i = 0; i < Items.Count; i++) { - if (it.Contains(e.Location, 0, (int)scrollY.Value, out var change)) hoveindex = i; - if (change) count++; + var it = Items[i]; + if (it.Enable) + { + if (it.has_sub) + { + if (it.Contains(e.X, e.Y, 0, sy, out var change)) hoveindex = i; + if (change) count++; + } + else + { + if (it.Contains(e.X, e.Y, 0, sy, out var change)) + { + hoveindex = i; + bool hover = it.RectArrow.Contains(e.X, e.Y + sy); + if (it.HoverClose == hover) + { + if (change) count++; + } + else + { + it.HoverClose = hover; + count++; + } + + } + else if (it.HoverClose) + { + it.HoverClose = false; + count++; + } + else if (change) count++; + } + } + } + } + else + { + for (int i = 0; i < Items.Count; i++) + { + var it = Items[i]; + if (it.Enable) + { + if (it.Contains(e.X, e.Y, 0, sy, out var change)) hoveindex = i; + if (change) count++; + } } } if (count > 0) Print(); @@ -1005,6 +1061,18 @@ namespace AntdUI } } if (it.has_sub) DrawArrow(g, it, Colour.TextBase.Get(keyid)); + else if (CloseIcon) + { + if (it.HoverClose) + { + using (var path = it.RectClose.RoundPath((int)(4 * Config.Dpi))) + { + g.Fill(Colour.FillSecondary.Get(keyid), path); + } + g.PaintIconClose(it.RectCloseIcon, Colour.Text.Get(keyid)); + } + else g.PaintIconClose(it.RectCloseIcon, Colour.TextTertiary.Get(keyid)); + } } void DrawTextIconSelect(Canvas g, ObjectItem it) diff --git a/src/AntdUI/Forms/LayeredWindow/LayeredFormSelectMultiple.cs b/src/AntdUI/Forms/LayeredWindow/LayeredFormSelectMultiple.cs index 5aaacb2f..82b638b9 100644 --- a/src/AntdUI/Forms/LayeredWindow/LayeredFormSelectMultiple.cs +++ b/src/AntdUI/Forms/LayeredWindow/LayeredFormSelectMultiple.cs @@ -185,20 +185,20 @@ namespace AntdUI Rectangle rect = new Rectangle(10 + gap, y, width - gap2, item_height), rect_text = new Rectangle(rect.X + gap_x, rect.Y + gap_y, rect.Width - gap_x2, text_height); if (value is SelectItem it) { - Items.Add(new ObjectItem(it, i, rect, rect_text, gap_x, gap_x2, gap_y, gap_y2) { NoIndex = NoIndex }); + Items.Add(new ObjectItem(it, i, rect, rect_text, false, gap_x, gap_x2, gap_y, gap_y2) { NoIndex = NoIndex }); if (selectedValue == it.Tag) select_y = y; y += item_height; } else if (value is GroupSelectItem group && group.Sub != null && group.Sub.Count > 0) { - Items.Add(new ObjectItem(group, i, rect, rect_text)); + Items.Add(new ObjectItem(group, i, rect, rect_text, false, gap_x, gap_x2, gap_y, gap_y2)); if (selectedValue == value) select_y = y; y += item_height; foreach (var item in group.Sub) ReadList(item, i, width, item_height, text_height, gap, gap2, gap_x, gap_x2, gap_y, gap_y2, sp, ref item_count, ref divider_count, ref y, ref select_y, false); } else { - Items.Add(new ObjectItem(value, i, rect, rect_text) { NoIndex = NoIndex }); + Items.Add(new ObjectItem(value, i, rect, rect_text, false, gap_x, gap_x2, gap_y, gap_y2) { NoIndex = NoIndex }); if (selectedValue == value) select_y = y; y += item_height; } @@ -332,7 +332,7 @@ namespace AntdUI list_count++; Rectangle rect_bg = new Rectangle(10 + gap, y, w - gap2, item_height), rect_text = new Rectangle(rect_bg.X + gap_x, rect_bg.Y + gap_y, rect_bg.Width - gap_x2, text_height); - it.SetRect(rect_bg, rect_text, gap_x, gap_x2, gap_y, gap_y2); + it.SetRectAuto(rect_bg, rect_text, false, gap_x, gap_x2, gap_y, gap_y2); y += item_height; } }); @@ -419,7 +419,7 @@ namespace AntdUI list_count++; Rectangle rect_bg = new Rectangle(10 + gap, y, w - gap2, item_height), rect_text = new Rectangle(rect_bg.X + gap_x, rect_bg.Y + gap_y, rect_bg.Width - gap_x2, text_height); - it.SetRect(rect_bg, rect_text, gap_x, gap_x2, gap_y, gap_y2); + it.SetRectAuto(rect_bg, rect_text, false, gap_x, gap_x2, gap_y, gap_y2); y += item_height; } }); @@ -482,9 +482,10 @@ namespace AntdUI if (scrollY.MouseUp(e.Location) && OnTouchUp() && down) { if (RunAnimation) return; + int sy = (int)scrollY.Value; foreach (var it in Items) { - if (it.Show && it.Enable && it.ID > -1 && it.Contains(e.Location, 0, (int)scrollY.Value, out _)) + if (it.Show && it.Enable && it.ID > -1 && it.Contains(e.X, e.Y, 0, sy, out _)) { OnClick(it); return; @@ -548,13 +549,13 @@ namespace AntdUI hoveindex = -1; if (scrollY.MouseMove(e.Location) && OnTouchMove(e.X, e.Y)) { - int count = 0; + int count = 0, sy = (int)scrollY.Value; for (int i = 0; i < Items.Count; i++) { var it = Items[i]; if (it.Enable) { - if (it.Contains(e.Location, 0, (int)scrollY.Value, out var change)) hoveindex = i; + if (it.Contains(e.X, e.Y, 0, sy, out var change)) hoveindex = i; if (change) count++; } }