using FastReport.Utils; using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; namespace FastReport.Controls { internal class FRScrollablePanel : UserControl { #region Fields private VScrollBar _VScrollBar = null; private HScrollBar _HScrollBar = null; private Control _Thumb = null; private bool _VScrollBarVisible; private bool _HScrollBarVisible; private bool _ThumbVisible; private Point _AutoScrollPosition = Point.Empty; private bool _AutoScroll = false; private Size _AutoScrollMinSize = Size.Empty; #endregion #region Properties /// /// Gets the reference to internal vertical scroll-bar control if one is created or null if no scrollbar is visible. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public VScrollBar VScrollBar { get { return _VScrollBar; } } /// /// Gets the reference to internal horizontal scroll-bar control if one is created or null if no scrollbar is visible. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public HScrollBar HScrollBar { get { return _HScrollBar; } } /// /// Gets or sets a value indicating whether the control enables the user to scroll to items placed outside of its visible boundaries. /// [Browsable(true), DefaultValue(false)] public new bool AutoScroll { get { return _AutoScroll; } set { if (_AutoScroll != value) { _AutoScroll = value; UpdateScrollBars(); } } } /// /// Gets or sets the minimum size of the auto-scroll. Returns a Size that represents the minimum height and width of the scrolling area in pixels. /// This property is managed internally by control and should not be modified. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new Size AutoScrollMinSize { get { return _AutoScrollMinSize; } set { _AutoScrollMinSize = value; UpdateScrollBars(); } } public event EventHandler AutoScrollPositionChanged; /// /// Gets or sets the location of the auto-scroll position. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new Point AutoScrollPosition { get { return _AutoScrollPosition; } set { if (!HScrollBarVisible) value.X = 0; else value.X = -Math.Max(Math.Min(-value.X, _HScrollBar.Maximum - _HScrollBar.LargeChange), _HScrollBar.Minimum); if (!VScrollBarVisible) value.Y = 0; else value.Y = -Math.Max(Math.Min(-value.Y, _VScrollBar.Maximum - _VScrollBar.LargeChange), _VScrollBar.Minimum); if (_AutoScrollPosition != value) { _AutoScrollPosition = value; if (_AutoScroll) { if (VScrollBarVisible && _VScrollBar.Value != -_AutoScrollPosition.Y) { _VScrollBar.Value = -_AutoScrollPosition.Y; } if (HScrollBarVisible && _HScrollBar.Value != -_AutoScrollPosition.X) { _HScrollBar.Value = -_AutoScrollPosition.X; } Invalidate(); } OnAutoScrollPositionChanged(); } } } private bool HScrollBarVisible { get { return _HScrollBarVisible; } set { _HScrollBarVisible = value; _HScrollBar.Visible = value; } } private bool VScrollBarVisible { get { return _VScrollBarVisible; } set { _VScrollBarVisible = value; _VScrollBar.Visible = value; } } private bool ThumbVisible { get { return _ThumbVisible; } set { _ThumbVisible = value; _Thumb.Visible = value; } } #endregion #region Private Methods private void UpdateScrollBars() { if (!_AutoScroll) { VScrollBarVisible = false; HScrollBarVisible = false; ThumbVisible = false; return; } Rectangle innerBounds = this.ClientRectangle; // Check do we need vertical scrollbar Size scrollSize = _AutoScrollMinSize; if (scrollSize.Height > innerBounds.Height) { VScrollBarVisible = true; if (_VScrollBar.Minimum != 0) _VScrollBar.Minimum = 0; if (_VScrollBar.LargeChange != innerBounds.Height && innerBounds.Height > 0) _VScrollBar.LargeChange = innerBounds.Height; _VScrollBar.SmallChange = 100; if (_VScrollBar.Maximum != _AutoScrollMinSize.Height) _VScrollBar.Maximum = _AutoScrollMinSize.Height; if (_VScrollBar.Value != -_AutoScrollPosition.Y) _VScrollBar.Value = (Math.Min(_VScrollBar.Maximum, Math.Abs(_AutoScrollPosition.Y))); } else { VScrollBarVisible = false; } // Check horizontal scrollbar if (scrollSize.Width > innerBounds.Width) { HScrollBarVisible = true; if (_HScrollBar.Minimum != 0) _HScrollBar.Minimum = 0; if (_HScrollBar.LargeChange != innerBounds.Width && innerBounds.Width > 0) _HScrollBar.LargeChange = innerBounds.Width; if (_HScrollBar.Maximum != _AutoScrollMinSize.Width) _HScrollBar.Maximum = _AutoScrollMinSize.Width; if (_HScrollBar.Value != -_AutoScrollPosition.X) _HScrollBar.Value = (Math.Min(_HScrollBar.Maximum, Math.Abs(_AutoScrollPosition.X))); _HScrollBar.SmallChange = 100; } else { HScrollBarVisible = false; } RepositionScrollBars(); } private void VScrollBarScroll(object sender, ScrollEventArgs e) { if (_AutoScrollPosition.Y != -e.NewValue) { _AutoScrollPosition.Y = -e.NewValue; OnAutoScrollPositionChanged(); this.OnScroll(e); this.Invalidate(); } } private void HScrollBarScroll(object sender, ScrollEventArgs e) { if (_AutoScrollPosition.X != -e.NewValue) { _AutoScrollPosition.X = -e.NewValue; OnAutoScrollPositionChanged(); this.OnScroll(e); this.Invalidate(); } } private void RepositionScrollBars() { Rectangle innerBounds = this.ClientRectangle; _VScrollBar.Width = this.LogicalToDevice(SystemInformation.VerticalScrollBarWidth); _HScrollBar.Height = this.LogicalToDevice(SystemInformation.HorizontalScrollBarHeight); if (HScrollBarVisible) { int width = innerBounds.Width; if (VScrollBarVisible) width -= _VScrollBar.Width - 1; _HScrollBar.Bounds = new Rectangle(innerBounds.X, innerBounds.Bottom - _HScrollBar.Height + 1, width, _HScrollBar.Height); } if (VScrollBarVisible) { int height = innerBounds.Height; if (HScrollBarVisible) height -= _HScrollBar.Height - 1; _VScrollBar.Bounds = new Rectangle(innerBounds.Right - _VScrollBar.Width + 1, innerBounds.Y, _VScrollBar.Width, height); } if (VScrollBarVisible && HScrollBarVisible) { ThumbVisible = true; _Thumb.Bounds = new Rectangle(_HScrollBar.Bounds.Right, _VScrollBar.Bounds.Bottom, _VScrollBar.Width, _HScrollBar.Height); } else { ThumbVisible = false; } } #endregion #region Protected Methods protected virtual void OnAutoScrollPositionChanged() { if (AutoScrollPositionChanged != null) AutoScrollPositionChanged(this, EventArgs.Empty); } protected override void Dispose(bool disposing) { if (disposing) { if (_VScrollBar != null) _VScrollBar.Dispose(); _VScrollBar = null; if (_HScrollBar != null) _HScrollBar.Dispose(); _HScrollBar = null; if (_Thumb != null) _Thumb.Dispose(); _Thumb = null; } base.Dispose(disposing); } protected override void OnMouseWheel(MouseEventArgs e) { if (VScrollBarVisible) { int newValue = _VScrollBar.Value + _VScrollBar.SmallChange * (e.Delta < 0 ? 1 : -1); if (newValue < _VScrollBar.Minimum) newValue = _VScrollBar.Minimum; if (newValue > _VScrollBar.Maximum - _VScrollBar.LargeChange + 1) newValue = _VScrollBar.Maximum - _VScrollBar.LargeChange + 1; ScrollEventType scType = e.Delta < 0 ? ScrollEventType.SmallIncrement : ScrollEventType.SmallDecrement; VScrollBarScroll(this, new ScrollEventArgs(scType, _VScrollBar.Value, newValue)); _VScrollBar.Value = newValue; } base.OnMouseWheel(e); } protected override void OnResize(EventArgs e) { base.OnResize(e); UpdateScrollBars(); AutoScrollPosition = AutoScrollPosition; } #endregion public FRScrollablePanel() { _VScrollBar = new VScrollBar(); _VScrollBar.Width = this.LogicalToDevice(SystemInformation.VerticalScrollBarWidth); _VScrollBar.Cursor = Cursors.Default; this.Controls.Add(_VScrollBar); _VScrollBar.Scroll += new ScrollEventHandler(VScrollBarScroll); // CreateControl is needed to avoid error in mdi child mode _VScrollBar.CreateControl(); _HScrollBar = new HScrollBar(); _HScrollBar.Height = this.LogicalToDevice(SystemInformation.HorizontalScrollBarHeight); _HScrollBar.Cursor = Cursors.Default; this.Controls.Add(_HScrollBar); _HScrollBar.Scroll += new ScrollEventHandler(HScrollBarScroll); _HScrollBar.CreateControl(); _Thumb = new Control(); _Thumb.BackColor = SystemColors.Control; _Thumb.TabStop = false; this.Controls.Add(_Thumb); _Thumb.CreateControl(); SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true); } } }