#region Imports
|
|
using DPumpHydr.WinFrmUI.RLT.Controls;
|
using System;
|
using System.ComponentModel;
|
using System.Drawing;
|
using System.Windows.Forms;
|
using static DPumpHydr.WinFrmUI.RLT.Helper.CrownHelper;
|
|
#endregion
|
|
namespace DPumpHydr.WinFrmUI.RLT.Child.Crown
|
{
|
#region CrownScrollBaseChild
|
|
public abstract class CrownScrollBase : Control
|
{
|
#region Event Region
|
|
public event EventHandler ViewportChanged;
|
public event EventHandler ContentSizeChanged;
|
|
#endregion
|
|
#region Field Region
|
|
protected readonly CrownScrollBar _vScrollBar;
|
protected readonly CrownScrollBar _hScrollBar;
|
|
private Size _visibleSize;
|
private Size _contentSize;
|
|
private Rectangle _viewport;
|
|
private Point _offsetMousePosition;
|
|
private int _maxDragChange = 0;
|
private readonly Timer _dragTimer;
|
|
private bool _hideScrollBars = true;
|
|
#endregion
|
|
#region Property Region
|
|
[Browsable(false)]
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
public Rectangle Viewport
|
{
|
get => _viewport;
|
private set
|
{
|
_viewport = value;
|
|
ViewportChanged?.Invoke(this, null);
|
}
|
}
|
|
[Browsable(false)]
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
public Size ContentSize
|
{
|
get => _contentSize;
|
set
|
{
|
_contentSize = value;
|
UpdateScrollBars();
|
|
ContentSizeChanged?.Invoke(this, null);
|
}
|
}
|
|
[Browsable(false)]
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
public Point OffsetMousePosition => _offsetMousePosition;
|
|
[Category("Behavior")]
|
[Description("Determines the maximum scroll change when dragging.")]
|
[DefaultValue(0)]
|
public int MaxDragChange
|
{
|
get => _maxDragChange;
|
set
|
{
|
_maxDragChange = value;
|
Invalidate();
|
}
|
}
|
|
[Browsable(false)]
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
public bool IsDragging { get; private set; }
|
|
[Category("Behavior")]
|
[Description("Determines whether scrollbars will remain visible when disabled.")]
|
[DefaultValue(true)]
|
public bool HideScrollBars
|
{
|
get => _hideScrollBars;
|
set
|
{
|
_hideScrollBars = value;
|
UpdateScrollBars();
|
}
|
}
|
|
#endregion
|
|
#region Constructor Region
|
|
protected CrownScrollBase()
|
{
|
SetStyle
|
(
|
ControlStyles.Selectable |
|
ControlStyles.UserMouse,
|
true
|
);
|
|
_vScrollBar = new CrownScrollBar { ScrollOrientation = Enum.Crown.ScrollOrientation.Vertical };
|
_hScrollBar = new CrownScrollBar { ScrollOrientation = Enum.Crown.ScrollOrientation.Horizontal };
|
|
Controls.Add(_vScrollBar);
|
Controls.Add(_hScrollBar);
|
|
_vScrollBar.ValueChanged += delegate { UpdateViewport(); };
|
_hScrollBar.ValueChanged += delegate { UpdateViewport(); };
|
|
_vScrollBar.MouseDown += delegate { Select(); };
|
_hScrollBar.MouseDown += delegate { Select(); };
|
|
_dragTimer = new Timer
|
{
|
Interval = 1
|
};
|
_dragTimer.Tick += DragTimer_Tick;
|
}
|
|
#endregion
|
|
#region Method Region
|
|
private void UpdateScrollBars()
|
{
|
if (_vScrollBar.Maximum != ContentSize.Height)
|
{
|
_vScrollBar.Maximum = ContentSize.Height;
|
}
|
|
if (_hScrollBar.Maximum != ContentSize.Width)
|
{
|
_hScrollBar.Maximum = ContentSize.Width;
|
}
|
|
int scrollSize = ThemeProvider.Theme.Sizes.ScrollBarSize;
|
|
_vScrollBar.Location = new(ClientSize.Width - scrollSize, 0);
|
_vScrollBar.Size = new(scrollSize, ClientSize.Height);
|
|
_hScrollBar.Location = new(0, ClientSize.Height - scrollSize);
|
_hScrollBar.Size = new(ClientSize.Width, scrollSize);
|
|
if (DesignMode)
|
{
|
return;
|
}
|
|
// Do this twice in case changing the visibility of the scrollbars
|
// causes the VisibleSize to change in such a way as to require a second scrollbar.
|
// Probably a better way to detect that scenario...
|
SetVisibleSize();
|
SetScrollBarVisibility();
|
SetVisibleSize();
|
SetScrollBarVisibility();
|
|
if (_vScrollBar.Visible)
|
{
|
_hScrollBar.Width -= scrollSize;
|
}
|
|
if (_hScrollBar.Visible)
|
{
|
_vScrollBar.Height -= scrollSize;
|
}
|
|
_vScrollBar.ViewSize = _visibleSize.Height;
|
_hScrollBar.ViewSize = _visibleSize.Width;
|
|
UpdateViewport();
|
}
|
|
private void SetScrollBarVisibility()
|
{
|
_vScrollBar.Enabled = _visibleSize.Height < ContentSize.Height;
|
_hScrollBar.Enabled = _visibleSize.Width < ContentSize.Width;
|
|
if (_hideScrollBars)
|
{
|
_vScrollBar.Visible = _vScrollBar.Enabled;
|
_hScrollBar.Visible = _hScrollBar.Enabled;
|
}
|
}
|
|
private void SetVisibleSize()
|
{
|
int scrollSize = ThemeProvider.Theme.Sizes.ScrollBarSize;
|
|
_visibleSize = new(ClientSize.Width, ClientSize.Height);
|
|
if (_vScrollBar.Visible)
|
{
|
_visibleSize.Width -= scrollSize;
|
}
|
|
if (_hScrollBar.Visible)
|
{
|
_visibleSize.Height -= scrollSize;
|
}
|
}
|
|
private void UpdateViewport()
|
{
|
int left = 0;
|
int top = 0;
|
int width = ClientSize.Width;
|
int height = ClientSize.Height;
|
|
if (_hScrollBar.Visible)
|
{
|
left = _hScrollBar.Value;
|
height -= _hScrollBar.Height;
|
}
|
|
if (_vScrollBar.Visible)
|
{
|
top = _vScrollBar.Value;
|
width -= _vScrollBar.Width;
|
}
|
|
Viewport = new(left, top, width, height);
|
|
Point pos = PointToClient(MousePosition);
|
_offsetMousePosition = new(pos.X + Viewport.Left, pos.Y + Viewport.Top);
|
|
Invalidate();
|
}
|
|
public void ScrollTo(Point point)
|
{
|
HScrollTo(point.X);
|
VScrollTo(point.Y);
|
}
|
|
public void VScrollTo(int value)
|
{
|
if (_vScrollBar.Visible)
|
{
|
_vScrollBar.Value = value;
|
}
|
}
|
|
public void HScrollTo(int value)
|
{
|
if (_hScrollBar.Visible)
|
{
|
_hScrollBar.Value = value;
|
}
|
}
|
|
protected virtual void StartDrag()
|
{
|
IsDragging = true;
|
_dragTimer.Start();
|
}
|
|
protected virtual void StopDrag()
|
{
|
IsDragging = false;
|
_dragTimer.Stop();
|
}
|
|
public Point PointToView(Point point)
|
{
|
return new Point(point.X - Viewport.Left, point.Y - Viewport.Top);
|
}
|
|
public Rectangle RectangleToView(Rectangle rect)
|
{
|
return new Rectangle(new Point(rect.Left - Viewport.Left, rect.Top - Viewport.Top), rect.Size);
|
}
|
|
#endregion
|
|
#region Event Handler Region
|
|
protected override void OnCreateControl()
|
{
|
base.OnCreateControl();
|
|
UpdateScrollBars();
|
}
|
|
protected override void OnGotFocus(EventArgs e)
|
{
|
base.OnGotFocus(e);
|
|
Invalidate();
|
}
|
|
protected override void OnLostFocus(EventArgs e)
|
{
|
base.OnLostFocus(e);
|
|
Invalidate();
|
}
|
|
protected override void OnResize(EventArgs e)
|
{
|
base.OnResize(e);
|
|
UpdateScrollBars();
|
}
|
|
protected override void OnMouseMove(MouseEventArgs e)
|
{
|
base.OnMouseMove(e);
|
|
_offsetMousePosition = new(e.X + Viewport.Left, e.Y + Viewport.Top);
|
}
|
|
protected override void OnMouseDown(MouseEventArgs e)
|
{
|
base.OnMouseDown(e);
|
|
if (e.Button == MouseButtons.Right)
|
{
|
Select();
|
}
|
}
|
|
protected override void OnMouseWheel(MouseEventArgs e)
|
{
|
base.OnMouseWheel(e);
|
|
bool horizontal = false;
|
|
if (_hScrollBar.Visible && ModifierKeys == Keys.Control)
|
{
|
horizontal = true;
|
}
|
|
if (_hScrollBar.Visible && !_vScrollBar.Visible)
|
{
|
horizontal = true;
|
}
|
|
if (!horizontal)
|
{
|
if (e.Delta > 0)
|
{
|
_vScrollBar.ScrollByPhysical(3);
|
}
|
else if (e.Delta < 0)
|
{
|
_vScrollBar.ScrollByPhysical(-3);
|
}
|
}
|
else
|
{
|
if (e.Delta > 0)
|
{
|
_hScrollBar.ScrollByPhysical(3);
|
}
|
else if (e.Delta < 0)
|
{
|
_hScrollBar.ScrollByPhysical(-3);
|
}
|
}
|
}
|
|
protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
|
{
|
base.OnPreviewKeyDown(e);
|
|
// Allows arrow keys to trigger OnKeyPress
|
switch (e.KeyCode)
|
{
|
case Keys.Up:
|
case Keys.Down:
|
case Keys.Left:
|
case Keys.Right:
|
e.IsInputKey = true;
|
break;
|
}
|
}
|
|
private void DragTimer_Tick(object sender, EventArgs e)
|
{
|
Point pos = PointToClient(MousePosition);
|
|
int right = ClientRectangle.Right;
|
int bottom = ClientRectangle.Bottom;
|
|
if (_vScrollBar.Visible)
|
{
|
right = _vScrollBar.Left;
|
}
|
|
if (_hScrollBar.Visible)
|
{
|
bottom = _hScrollBar.Top;
|
}
|
|
if (_vScrollBar.Visible)
|
{
|
// Scroll up
|
if (pos.Y < ClientRectangle.Top)
|
{
|
int difference = (pos.Y - ClientRectangle.Top) * -1;
|
|
if (MaxDragChange > 0 && difference > MaxDragChange)
|
{
|
difference = MaxDragChange;
|
}
|
|
_vScrollBar.Value -= difference;
|
}
|
|
// Scroll down
|
if (pos.Y > bottom)
|
{
|
int difference = pos.Y - bottom;
|
|
if (MaxDragChange > 0 && difference > MaxDragChange)
|
{
|
difference = MaxDragChange;
|
}
|
|
_vScrollBar.Value += difference;
|
}
|
}
|
|
if (_hScrollBar.Visible)
|
{
|
// Scroll left
|
if (pos.X < ClientRectangle.Left)
|
{
|
int difference = (pos.X - ClientRectangle.Left) * -1;
|
|
if (MaxDragChange > 0 && difference > MaxDragChange)
|
{
|
difference = MaxDragChange;
|
}
|
|
_hScrollBar.Value -= difference;
|
}
|
|
// Scroll right
|
if (pos.X > right)
|
{
|
int difference = pos.X - right;
|
|
if (MaxDragChange > 0 && difference > MaxDragChange)
|
{
|
difference = MaxDragChange;
|
}
|
|
_hScrollBar.Value += difference;
|
}
|
}
|
}
|
|
#endregion
|
}
|
|
#endregion
|
}
|