SunnyUI/SunnyUI/Controls/UIScrollBar.cs

512 lines
15 KiB
C#
Raw Normal View History

2020-05-11 21:11:29 +08:00
/******************************************************************************
* SunnyUI
2022-01-02 12:32:50 +08:00
* CopyRight (C) 2012-2022 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.
* 使
******************************************************************************
* : UIScrollBar.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
* 2022-03-19: V3.1.1
2020-05-11 21:11:29 +08:00
******************************************************************************/
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace Sunny.UI
{
[DefaultEvent("ValueChanged")]
[DefaultProperty("Value")]
[ToolboxItem(true)]
public sealed class UIScrollBar : UIControl
{
public UIScrollBar()
{
SetStyleFlags(true, false);
2020-05-11 21:11:29 +08:00
Maximum = 100;
up_state = value_state = down_state = DrawItemState.None;
timer = new Timer();
2020-05-11 21:11:29 +08:00
timer.Interval = 150;
timer.Tick += TimerTick;
Width = SystemInformation.VerticalScrollBarWidth + 2;
Height = 300;
ShowText = false;
fillColor = UIStyles.Blue.ScrollBarFillColor;
foreColor = UIStyles.Blue.ScrollBarForeColor;
fillHoverColor = UIStyles.Blue.ScrollBarFillHoverColor;
fillPressColor = UIStyles.Blue.ScrollBarFillPressColor;
2020-05-11 21:11:29 +08:00
}
private int scrollValue;
private int SmallChange = 1;
private int LargeChange = 10;
private int maximum = 100;
2020-05-11 21:11:29 +08:00
private DrawItemState up_state, value_state, down_state;
private DrawItemState up_state1, value_state1, down_state1;
private bool dragMove;
private int dragOffset;
private int barHeight;
private double percentValue;
private readonly Timer timer;
2020-05-11 21:11:29 +08:00
private bool isScrollUp = true;
private bool largeChange = true;
public event EventHandler ValueChanged;
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
timer?.Stop();
timer?.Dispose();
}
2020-05-11 21:11:29 +08:00
[DefaultValue(0)]
[Description("当前值"), Category("SunnyUI")]
2020-05-11 21:11:29 +08:00
public int Value
{
get => scrollValue;
set
{
scrollValue = Math.Min(maximum, value);
scrollValue = Math.Max(scrollValue, 0);
Invalidate();
}
}
[DefaultValue(100)]
[Description("最大值"), Category("SunnyUI")]
2020-05-11 21:11:29 +08:00
public int Maximum
{
get => maximum;
set
{
maximum = Math.Max(value, 1);
SmallChange = value / 50;
SmallChange = Math.Max(1, SmallChange);
LargeChange = value / 10;
LargeChange = Math.Max(1, LargeChange);
CalcValueArea();
Invalidate();
}
}
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
CalcValueArea();
}
private void TimerTick(object sender, EventArgs e)
{
if (isScrollUp)
ScrollUp(largeChange);
else
ScrollDown(largeChange);
}
private Rectangle GetUpRect()
{
var rect = new Rectangle(1, 1, Width - 2, 16);
return rect;
}
private void CalcValueArea()
{
var centerHeight = GetValueClipRect().Height;
barHeight = centerHeight / (maximum + 1);
barHeight = Math.Max(30, barHeight);
if (maximum == 0) maximum = 1;
2020-05-11 21:11:29 +08:00
percentValue = ((double)centerHeight - barHeight) / maximum;
}
private Rectangle GetValueRect()
{
return new Rectangle(Width / 2 - 3, ValueToPos(scrollValue), 6, barHeight);
}
private int ValueToPos(int value)
{
return (int)(value * percentValue) + 17;
}
private int PosToValue(int pos)
{
var value = (int)((pos - 17) / percentValue);
if (value < 0)
value = 0;
if (value > maximum)
value = maximum;
return value;
}
private Rectangle GetDownRect()
{
var rect = new Rectangle(1, Height - 17, Width - 2, 16);
return rect;
}
private Rectangle GetValueClipRect()
{
var clip = new Rectangle(1, 17, Width - 2, Height - 17 * 2);
return clip;
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.Clear(fillColor);
DrawUpDownArrow(e.Graphics, up_state, GetUpRect(), true);
DrawUpDownArrow(e.Graphics, down_state, GetDownRect(), false);
DrawValueBar(e.Graphics, value_state);
2022-03-21 23:25:57 +08:00
if (ShowLeftLine)
{
e.Graphics.DrawLine(RectColor, 0, 0, 0, Height);
}
}
private bool showLeftLine;
[DefaultValue(false)]
public bool ShowLeftLine
{
get => showLeftLine; set
{
showLeftLine = value;
Invalidate();
}
2020-05-11 21:11:29 +08:00
}
private void DrawValueBar(Graphics g, DrawItemState state)
{
var rect = GetValueRect();
Color clr = foreColor;
if ((state & DrawItemState.HotLight) == DrawItemState.HotLight)
{
clr = fillHoverColor;
}
if ((state & DrawItemState.Selected) == DrawItemState.Selected)
{
clr = fillPressColor;
}
if (dragMove)
{
rect = new Rectangle(rect.Left, MousePos - barHeight / 2, rect.Width, barHeight);
if (rect.Top < 17)
{
rect = new Rectangle(rect.Left, 17, rect.Width, barHeight);
}
if (rect.Bottom > Height - 17)
{
rect = new Rectangle(rect.Left, Height - 17 - barHeight, rect.Width, barHeight);
}
}
g.SetHighQuality();
g.FillRoundRectangle(clr, rect, 5);
g.SetDefaultQuality();
}
private void DrawUpDownArrow(Graphics g, DrawItemState state, Rectangle rect, bool isUp)
{
Color clr_arrow = foreColor;
if ((state & DrawItemState.HotLight) == DrawItemState.HotLight)
{
clr_arrow = fillHoverColor;
}
if ((state & DrawItemState.Selected) == DrawItemState.Selected)
{
clr_arrow = fillPressColor;
}
g.FillRectangle(fillColor, rect);
g.SetHighQuality();
using (var pen = new Pen(clr_arrow, 2))
{
Point pt1, pt2, pt3;
if (!isUp)
{
pt1 = new Point(Width / 2 - 4, Height - 16 / 2 - 4);
pt2 = new Point(Width / 2, Height - 16 / 2);
pt3 = new Point(Width / 2 + 4, Height - 16 / 2 - 4);
}
else
{
pt1 = new Point(Width / 2 - 4, 16 / 2 + 4 - 1);
pt2 = new Point(Width / 2, 16 / 2 - 1);
pt3 = new Point(Width / 2 + 4, 16 / 2 + 4 - 1);
}
g.DrawLines(pen, new[] { pt1, pt2, pt3 });
}
g.SetDefaultQuality();
}
public void SetValue(int value)
{
if (value < 0)
{
value = 0;
}
if (value > maximum)
{
value = maximum;
}
scrollValue = value;
2021-10-16 22:33:10 +08:00
ValueChanged?.Invoke(this, EventArgs.Empty);
2020-05-11 21:11:29 +08:00
Invalidate();
}
public void ScrollUp(bool large)
{
SetValue(scrollValue - (large ? LargeChange : SmallChange));
}
public void ScrollDown(bool large)
{
SetValue(scrollValue + (large ? LargeChange : SmallChange));
}
private void StartScroll(bool up, bool large)
{
isScrollUp = up;
largeChange = large;
timer.Start();
}
private void StopScroll()
{
timer.Stop();
}
protected override void OnMouseDown(MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
{
return;
}
up_state = value_state = down_state = DrawItemState.None;
IsPress = true;
var hit = HitState(e.X, e.Y);
switch (hit)
{
case 1:
if (Value > 0)
{
up_state = DrawItemState.Selected;
ScrollUp(false);
StartScroll(true, false);
}
break;
case 2:
value_state = DrawItemState.Selected;
dragMove = true;
dragOffset = GetValueRect().Y - e.Y;
break;
case 3:
if (Value < Maximum)
{
down_state = DrawItemState.Selected;
ScrollDown(false);
StartScroll(false, false);
}
break;
case 4:
if (Value > 0)
{
ScrollUp(true);
if (IsPress)
{
StartScroll(true, true);
}
}
break;
case 5:
if (Value < Maximum)
{
ScrollDown(false);
if (IsPress)
{
StartScroll(false, true);
}
}
break;
}
if (StateChange())
{
Invalidate();
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
IsPress = false;
dragMove = false;
StopScroll();
Invalidate();
}
private int MousePos;
protected override void OnMouseMove(MouseEventArgs e)
{
MousePos = e.Y;
var hit = HitState(e.X, e.Y);
up_state = value_state = down_state = DrawItemState.None;
switch (hit)
{
case 1:
up_state = IsPress ? DrawItemState.Selected : DrawItemState.HotLight;
break;
case 2:
value_state = IsPress ? DrawItemState.Selected : DrawItemState.HotLight;
break;
case 3:
down_state = IsPress ? DrawItemState.Selected : DrawItemState.HotLight;
break;
}
if (dragMove)
{
var value = PosToValue(e.Y + dragOffset);
SetValue(value);
return;
}
if (StateChange())
{
Invalidate();
}
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
up_state = down_state = value_state = DrawItemState.None;
Invalidate();
}
private bool StateChange()
{
var change = up_state != up_state1 || down_state != down_state1 || value_state != value_state1;
up_state1 = up_state;
value_state1 = value_state;
down_state1 = down_state;
return change;
}
private int HitState(int x, int y)
{
var rect_up = GetUpRect();
var rect_down = GetDownRect();
var rect_value = GetValueRect();
var rect_value_up = new Rectangle(0, rect_up.Bottom, Width, rect_value.Top - rect_up.Bottom);
var rect_value_down = new Rectangle(0, rect_value.Bottom, Width, rect_down.Top - rect_value.Bottom);
2020-05-11 21:11:29 +08:00
if (rect_up.Contains(x, y))
return 1;
else if (rect_down.Contains(x, y))
return 3;
2020-07-06 21:42:22 +08:00
else if (rect_value.Contains(x, y) || value_state == DrawItemState.Selected)
2020-05-11 21:11:29 +08:00
return 2;
else if (rect_value_up.Contains(x, y))
return 4;
else if (rect_value_down.Contains(x, y))
return 5;
else
return -1;
}
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);
fillColor = uiColor.ScrollBarFillColor;
2020-05-11 21:11:29 +08:00
foreColor = uiColor.ScrollBarForeColor;
fillHoverColor = uiColor.ScrollBarFillHoverColor;
fillPressColor = uiColor.ScrollBarFillPressColor;
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 override Color ForeColor
{
get => foreColor;
set => SetForeColor(value);
}
2022-03-21 23:25:57 +08:00
/// <summary>
/// 字体颜色
/// </summary>
[Description("字体颜色"), Category("SunnyUI")]
[DefaultValue(typeof(Color), "80, 160, 255")]
public Color RectColor
{
get => rectColor;
set => SetRectColor(value);
}
2020-05-11 21:11:29 +08:00
/// <summary>
/// 填充颜色,当值为背景色或透明色或空值则不填充
/// </summary>
[Description("填充颜色"), Category("SunnyUI")]
[DefaultValue(typeof(Color), "243, 249, 255")]
2020-05-11 21:11:29 +08:00
public Color FillColor
{
get => fillColor;
set => SetFillColor(value);
}
[DefaultValue(typeof(Color), "115, 179, 255")]
[Description("鼠标移上颜色"), Category("SunnyUI")]
2020-05-11 21:11:29 +08:00
public Color HoverColor
{
get => fillHoverColor;
set => SetFillHoverColor(value);
2020-05-11 21:11:29 +08:00
}
[DefaultValue(typeof(Color), "64, 128, 204")]
[Description("鼠标按下颜色"), Category("SunnyUI")]
2020-05-11 21:11:29 +08:00
public Color PressColor
{
get => fillPressColor;
set => SetFillPressColor(value);
}
}
}