|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.ComponentModel;
namespace System.Windows.Forms;
/// <summary>
/// Basic Properties for Scrollbars.
/// </summary>
public abstract class ScrollProperties
{
internal int _minimum;
internal int _maximum = 100;
internal int _smallChange = 1;
internal int _largeChange = 10;
internal int _value;
internal bool _maximumSetExternally;
internal bool _smallChangeSetExternally;
internal bool _largeChangeSetExternally;
private readonly ScrollableControl? _parent;
protected ScrollableControl? ParentControl => _parent;
internal bool _visible;
private bool _enabled = true;
protected ScrollProperties(ScrollableControl? container)
{
_parent = container;
}
/// <summary>
/// Gets or sets a bool value controlling whether the scrollbar is enabled.
/// </summary>
[SRCategory(nameof(SR.CatBehavior))]
[DefaultValue(true)]
[SRDescription(nameof(SR.ScrollBarEnableDescr))]
public bool Enabled
{
get => _enabled;
set
{
if (_parent is not null && _parent.AutoScroll)
{
return;
}
if (value != _enabled)
{
_enabled = value;
if (_parent is not null)
{
PInvoke.EnableScrollBar(
_parent,
Orientation,
value ? ENABLE_SCROLL_BAR_ARROWS.ESB_ENABLE_BOTH : ENABLE_SCROLL_BAR_ARROWS.ESB_DISABLE_BOTH);
}
}
}
}
/// <summary>
/// Gets or sets a value to be added or subtracted to the <see cref="LargeChange"/>
/// property when the scroll box is moved a large distance.
/// </summary>
[SRCategory(nameof(SR.CatBehavior))]
[DefaultValue(10)]
[SRDescription(nameof(SR.ScrollBarLargeChangeDescr))]
[RefreshProperties(RefreshProperties.Repaint)]
public int LargeChange
{
get
{
// We preserve the actual large change value that has been set, but when we come to
// get the value of this property, make sure it's within the maximum allowable value.
// This way we ensure that we don't depend on the order of property sets when
// code is generated at design-time.
return Math.Min(_largeChange, _maximum - _minimum + 1);
}
set
{
if (_largeChange != value)
{
ArgumentOutOfRangeException.ThrowIfNegative(value);
_largeChange = value;
_largeChangeSetExternally = true;
UpdateScrollInfo();
}
}
}
/// <summary>
/// Gets or sets the upper limit of values of the scrollable range.
/// </summary>
[SRCategory(nameof(SR.CatBehavior))]
[DefaultValue(100)]
[SRDescription(nameof(SR.ScrollBarMaximumDescr))]
[RefreshProperties(RefreshProperties.Repaint)]
public int Maximum
{
get => _maximum;
set
{
if (_parent is not null && _parent.AutoScroll)
{
return;
}
if (_maximum != value)
{
if (_minimum > value)
{
_minimum = value;
}
if (value < _value)
{
Value = value;
}
_maximum = value;
_maximumSetExternally = true;
UpdateScrollInfo();
}
}
}
/// <summary>
/// Gets or sets the lower limit of values of the scrollable range.
/// </summary>
[SRCategory(nameof(SR.CatBehavior))]
[DefaultValue(0)]
[SRDescription(nameof(SR.ScrollBarMinimumDescr))]
[RefreshProperties(RefreshProperties.Repaint)]
public int Minimum
{
get => _minimum;
set
{
if (_parent is not null && _parent.AutoScroll)
{
return;
}
if (_minimum != value)
{
ArgumentOutOfRangeException.ThrowIfNegative(value);
if (_maximum < value)
{
_maximum = value;
}
if (value > _value)
{
_value = value;
}
_minimum = value;
UpdateScrollInfo();
}
}
}
private protected abstract int GetPageSize(ScrollableControl parent);
private protected abstract SCROLLBAR_CONSTANTS Orientation { get; }
private protected abstract int GetHorizontalDisplayPosition(ScrollableControl parent);
private protected abstract int GetVerticalDisplayPosition(ScrollableControl parent);
/// <summary>
/// Gets or sets the value to be added or subtracted to the <see cref="ScrollBar.Value"/>
/// property when the scroll box is moved a small distance.
/// </summary>
[SRCategory(nameof(SR.CatBehavior))]
[DefaultValue(1)]
[SRDescription(nameof(SR.ScrollBarSmallChangeDescr))]
public int SmallChange
{
get
{
// We can't have SmallChange > LargeChange, but we shouldn't manipulate
// the set values for these properties, so we just return the smaller
// value here.
return Math.Min(_smallChange, LargeChange);
}
set
{
if (_smallChange != value)
{
ArgumentOutOfRangeException.ThrowIfNegative(value);
_smallChange = value;
_smallChangeSetExternally = true;
UpdateScrollInfo();
}
}
}
/// <summary>
/// Gets or sets a numeric value that represents the current position of the scroll box
/// on the scroll bar control.
/// </summary>
[SRCategory(nameof(SR.CatBehavior))]
[DefaultValue(0)]
[Bindable(true)]
[SRDescription(nameof(SR.ScrollBarValueDescr))]
public int Value
{
get => _value;
set
{
if (_value != value)
{
if (value < _minimum || value > _maximum)
{
throw new ArgumentOutOfRangeException(nameof(value), string.Format(SR.InvalidBoundArgument, nameof(Value), value, $"'{nameof(Minimum)}'", $"'{nameof(Maximum)}'"));
}
_value = value;
UpdateScrollInfo();
UpdateDisplayPosition();
}
}
}
/// <summary>
/// Gets or sets a bool value controlling whether the scrollbar is showing.
/// </summary>
[SRCategory(nameof(SR.CatBehavior))]
[DefaultValue(false)]
[SRDescription(nameof(SR.ScrollBarVisibleDescr))]
public bool Visible
{
get => _visible;
set
{
if (_parent is not null && _parent.AutoScroll)
{
return;
}
if (value != _visible)
{
_visible = value;
_parent?.UpdateStylesCore();
UpdateScrollInfo();
UpdateDisplayPosition();
}
}
}
internal unsafe void UpdateScrollInfo()
{
if (_parent is not null && _parent.IsHandleCreated && _visible)
{
SCROLLINFO si = new()
{
cbSize = (uint)sizeof(SCROLLINFO),
fMask = SCROLLINFO_MASK.SIF_ALL,
nMin = _minimum,
nMax = _maximum,
nPage = _parent.AutoScroll ? (uint)GetPageSize(_parent) : (uint)LargeChange,
nPos = _value,
nTrackPos = 0
};
PInvoke.SetScrollInfo(_parent, Orientation, ref si, true);
}
}
private void UpdateDisplayPosition()
{
if (_parent is null)
{
return;
}
int horizontal = GetHorizontalDisplayPosition(_parent);
int vertical = GetVerticalDisplayPosition(_parent);
_parent.SetDisplayFromScrollProps(horizontal, vertical);
}
}
|