// COPYRIGHT (C) Tom. ALL RIGHTS RESERVED. // THE AntdUI PROJECT IS AN WINFORM LIBRARY LICENSED UNDER THE Apache-2.0 License. // LICENSED UNDER THE Apache License, VERSION 2.0 (THE "License") // YOU MAY NOT USE THIS FILE EXCEPT IN COMPLIANCE WITH THE License. // YOU MAY OBTAIN A COPY OF THE LICENSE AT // // http://www.apache.org/licenses/LICENSE-2.0 // // UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, SOFTWARE // DISTRIBUTED UNDER THE LICENSE IS DISTRIBUTED ON AN "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // SEE THE LICENSE FOR THE SPECIFIC LANGUAGE GOVERNING PERMISSIONS AND // LIMITATIONS UNDER THE License. // GITEE: https://gitee.com/antdui/AntdUI // GITHUB: https://github.com/AntdUI/AntdUI // CSDN: https://blog.csdn.net/v_132 // QQ: 17379620 using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Design; using System.Windows.Forms; namespace AntdUI { /// /// SliderRange 滑动范围输入条 /// /// 滑动型输入器,展示当前值和可选范围。 [Description("SliderRange 滑动范围输入条")] [ToolboxItem(true)] [DefaultProperty("Value")] [DefaultEvent("ValueChanged")] public class SliderRange : Slider { #region 属性 int _value2 = 10; /// /// 当前值2 /// [Description("当前值2"), Category("数据"), DefaultValue(10)] public int Value2 { get => _value2; set { if (value < MinValue) value = MinValue; else if (value > MaxValue) value = MaxValue; if (_value2 == value) return; _value2 = value; Value2Changed?.Invoke(this, new IntEventArgs(_value2)); Invalidate(); } } /// /// Value 属性值更改时发生 /// [Description("Value 属性值更改时发生"), Category("行为")] public event IntEventHandler? Value2Changed; #endregion #region 渲染 internal override void IPaint(Graphics g, Rectangle rect, bool enabled, Color color, Color color_dot, Color color_hover, Color color_active) { float prog = ProgValue(Value), prog2 = ProgValue(_value2); #region 线条 using (var path = rect_read.RoundPath(rect_read.Height / 2)) { using (var brush = new SolidBrush(Style.Db.FillQuaternary)) { g.FillPath(brush, path); if (AnimationHover) { using (var brush_hover = new SolidBrush(Helper.ToColorN(AnimationHoverValue, brush.Color))) { g.FillPath(brush_hover, path); } } else if (ExtraMouseHover) g.FillPath(brush, path); } if (prog != prog2) { g.SetClip(RectLine(rect_read, prog, prog2)); if (AnimationHover) { using (var brush = new SolidBrush(color)) { g.FillPath(brush, path); } using (var brush = new SolidBrush(Helper.ToColor(255 * AnimationHoverValue, color_hover))) { g.FillPath(brush, path); } } else { using (var brush = new SolidBrush(ExtraMouseHover ? color_hover : color)) { g.FillPath(brush, path); } } g.ResetClip(); } } #endregion using (var brush = new SolidBrush(Style.Db.BgBase)) { PaintMarksEllipse(g, rect, rect_read, brush, color, LineSize); PaintEllipse(g, rect, rect_read, prog, brush, color_dot, color_hover, color_active, LineSize); if (prog != prog2) PaintEllipse2(g, rect, rect_read, prog2, brush, color_dot, color_hover, color_active, LineSize); } } RectangleF rectEllipse2; internal void PaintEllipse2(Graphics g, Rectangle rect, RectangleF rect_read, float prog, SolidBrush brush, Color color, Color color_hover, Color color_active, int LineSize) { int DotSize = (int)(dotSize * Config.Dpi), DotSizeActive = (int)(dotSizeActive * Config.Dpi); rectEllipse2 = RectDot(rect, rect_read, prog, DotSizeActive + LineSize); var rect_ellipse_rl = RectDot(rect, rect_read, prog, DotSize + LineSize); if (ShowValue && ExtraMouseDot2Hover) ShowTips(_value2, rect_ellipse_rl); if (AnimationDot2Hover) { float value = ((DotSizeActive - DotSize) * AnimationDot2HoverValue); using (var brush_shadow = new SolidBrush(color_active.rgba(.2F))) { g.FillEllipse(brush_shadow, RectDot(rect, rect_read, prog, DotSizeActive + LineSize + LineSize * 2 * AnimationDot2HoverValue)); } using (var brush_dot = new SolidBrush(color_active)) { g.FillEllipse(brush_dot, RectDot(rect, rect_read, prog, DotSize + LineSize + value)); } g.FillEllipse(brush, RectDot(rect, rect_read, prog, DotSize + value)); } else if (ExtraMouseDot2Hover) { using (var brush_shadow = new SolidBrush(color_active.rgba(.2F))) { g.FillEllipse(brush_shadow, RectDot(rect, rect_read, prog, DotSizeActive + LineSize * 3)); } using (var brush_dot = new SolidBrush(color_active)) { g.FillEllipse(brush_dot, RectDot(rect, rect_read, prog, DotSizeActive + LineSize)); } g.FillEllipse(brush, RectDot(rect, rect_read, prog, DotSizeActive)); } else { if (AnimationHover) { using (var brush_dot_old = new SolidBrush(color)) using (var brush_dot = new SolidBrush(Helper.ToColor(255 * AnimationHoverValue, color_hover))) { var rect_dot = RectDot(rect, rect_read, prog, DotSize + LineSize); g.FillEllipse(brush_dot_old, rect_dot); g.FillEllipse(brush_dot, rect_dot); } } else { using (var brush_dot = new SolidBrush(ExtraMouseHover ? color_hover : color)) { g.FillEllipse(brush_dot, RectDot(rect, rect_read, prog, DotSize + LineSize)); } } g.FillEllipse(brush, RectDot(rect, rect_read, prog, DotSize)); } } internal RectangleF RectLine(RectangleF rect, float prog, float prog2) { switch (Align) { case TAlignMini.Right: return new RectangleF(rect.X + rect.Width - prog2, rect.Y, prog2 - prog, rect.Height); case TAlignMini.Top: return new RectangleF(rect.X, rect.Y + prog, rect.Width, prog2 - prog); case TAlignMini.Bottom: return new RectangleF(rect.X, rect.Y + rect.Height - prog2, rect.Width, prog2 - prog); default: return new RectangleF(rect.X + prog, rect.Y, prog2 - prog, rect.Height); } } #endregion #region 鼠标 protected override void OnMouseDown(MouseEventArgs e) { if (e.Button == MouseButtons.Left) { if (rectEllipse.Contains(e.X, e.Y)) { base.OnMouseDown(e); return; } if (rectEllipse2.Contains(e.X, e.Y)) { Value2 = FindIndex(e.X, e.Y, true); mouseFlat = true; return; } var mark_list = new List(2); int i = 0; int max = MaxValue - MinValue; switch (Align) { case TAlignMini.Right: mark_list.Add(rect_read.Width - (Value >= MaxValue ? rect_read.Width : rect_read.Width * ((Value - MinValue) * 1F / max))); mark_list.Add(rect_read.Width - (_value2 >= MaxValue ? rect_read.Width : rect_read.Width * ((_value2 - MinValue) * 1F / max))); i = FindNumber(e.X, mark_list); break; case TAlignMini.Top: mark_list.Add(Value >= MaxValue ? rect_read.Height : rect_read.Height * ((Value - MinValue) * 1F / max)); mark_list.Add(_value2 >= MaxValue ? rect_read.Height : rect_read.Height * ((_value2 - MinValue) * 1F / max)); i = FindNumber(e.Y, mark_list); break; case TAlignMini.Bottom: mark_list.Add(rect_read.Height - (Value >= MaxValue ? rect_read.Height : rect_read.Height * ((Value - MinValue) * 1F / max))); mark_list.Add(rect_read.Height - (_value2 >= MaxValue ? rect_read.Height : rect_read.Height * ((_value2 - MinValue) * 1F / max))); i = FindNumber(e.Y, mark_list); break; default: mark_list.Add(Value >= MaxValue ? rect_read.Width : rect_read.Width * ((Value - MinValue) * 1F / max)); mark_list.Add(_value2 >= MaxValue ? rect_read.Width : rect_read.Width * ((_value2 - MinValue) * 1F / max)); i = FindNumber(e.X, mark_list); break; } if (i == 1) { Value2 = FindIndex(e.X, e.Y, true); mouseFlat = true; return; } } base.OnMouseDown(e); } protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if (mouseFlat) { ExtraMouseDot2Hover = true; Value2 = FindIndex(e.X, e.Y, false); } else ExtraMouseDot2Hover = rectEllipse2.Contains(e.X, e.Y); } bool mouseFlat = false; protected override void OnMouseUp(MouseEventArgs e) { base.OnMouseUp(e); mouseFlat = false; Invalidate(); } internal float AnimationDot2HoverValue = 0F; internal bool AnimationDot2Hover = false; bool _mouseDotHover = false; internal bool ExtraMouseDot2Hover { get => _mouseDotHover; set { if (_mouseDotHover == value) return; _mouseDotHover = value; if (!value) CloseTips(); if (Config.Animation) { ThreadHover?.Dispose(); ThreadHover = null; ThreadDot2Hover?.Dispose(); AnimationDot2Hover = true; if (value) { ThreadDot2Hover = new ITask(this, () => { AnimationDot2HoverValue = AnimationDot2HoverValue.Calculate(0.1F); if (AnimationDot2HoverValue > 1) { AnimationDot2HoverValue = 1; return false; } Invalidate(); return true; }, 10, () => { AnimationDot2Hover = false; Invalidate(); }); } else { ThreadDot2Hover = new ITask(this, () => { AnimationDot2HoverValue = AnimationDot2HoverValue.Calculate(-0.1F); if (AnimationDot2HoverValue <= 0) { AnimationDot2HoverValue = 0F; return false; } Invalidate(); return true; }, 10, () => { AnimationDot2Hover = false; Invalidate(); }); } } else Invalidate(); } } #region 动画 protected override void Dispose(bool disposing) { ThreadDot2Hover?.Dispose(); base.Dispose(disposing); } ITask? ThreadDot2Hover = null; #endregion #endregion } }