mirror of https://github.com/dahall/Vanara.git
566 lines
20 KiB
C#
566 lines
20 KiB
C#
using System;
|
|
using System.ComponentModel;
|
|
using System.ComponentModel.Design;
|
|
using System.ComponentModel.Design.Serialization;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.Drawing.Design;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Windows.Forms;
|
|
using Vanara.Extensions;
|
|
using Vanara.PInvoke;
|
|
using static Vanara.PInvoke.ComCtl32;
|
|
using static Vanara.PInvoke.Macros;
|
|
using static Vanara.PInvoke.User32;
|
|
|
|
namespace Vanara.Windows.Forms
|
|
{
|
|
/// <summary>
|
|
/// Extends the <see cref="TrackBar"/> class to provide full native-control functionality, including tick marks and value, and custom drawing.
|
|
/// </summary>
|
|
/// <seealso cref="System.Windows.Forms.TrackBar"/>
|
|
public class TrackBarEx : TrackBar
|
|
{
|
|
private bool autoTicks = true;
|
|
private int cumulativeWheelData;
|
|
private int lastValue;
|
|
private bool limitThumbToSel, showSel;
|
|
private int requestedDim;
|
|
private int selMin, selMax, thumbLength = -1;
|
|
private int[] ticks;
|
|
|
|
/// <summary>Initializes a new instance of the <see cref="TrackBarEx"/> class.</summary>
|
|
public TrackBarEx()
|
|
{
|
|
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
|
|
BackColorChanged += (o, a) => { if (IsHandleCreated) RecreateHandle(); };
|
|
requestedDim = PreferredDimension;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Occurs when the channel for a <see cref="TrackBarEx"/> needs to be drawn and the <see cref="OwnerDraw"/> property is set to <c>true</c>.
|
|
/// </summary>
|
|
[Category("Drawing")]
|
|
public event PaintEventHandler DrawChannel;
|
|
|
|
/// <summary>
|
|
/// Occurs when the thumb for a <see cref="TrackBarEx"/> needs to be drawn and the <see cref="OwnerDraw"/> property is set to <c>true</c>.
|
|
/// </summary>
|
|
[Category("Drawing")]
|
|
public event PaintEventHandler DrawThumb;
|
|
|
|
/// <summary>
|
|
/// Occurs when the ticks for a <see cref="TrackBarEx"/> need to be drawn and the <see cref="OwnerDraw"/> property is set to <c>true</c>.
|
|
/// </summary>
|
|
[Category("Drawing")]
|
|
public event PaintEventHandler DrawTics;
|
|
|
|
/// <summary>Gets or sets a value indicating whether to draw ticks based on the <see cref="TrackBar.TickFrequency"/> interval.</summary>
|
|
/// <value><c>true</c> if automatic ticks should be shown; otherwise, <c>false</c>.</value>
|
|
[DefaultValue(true), Category("Appearance"), Description("Specifies whether to automatically draw tick marks at the frequency defined by TickFreqency.")]
|
|
public bool AutoTicks
|
|
{
|
|
get => autoTicks;
|
|
set
|
|
{
|
|
if (autoTicks == value) return;
|
|
autoTicks = value;
|
|
if (IsHandleCreated) RecreateHandle();
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets the bounds of the channel (slider track).</summary>
|
|
/// <value>The channel bounds.</value>
|
|
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public Rectangle ChannelBounds
|
|
{
|
|
get
|
|
{
|
|
var r = new RECT();
|
|
if (IsHandleCreated)
|
|
SendMsg(TrackBarMessage.TBM_GETCHANNELRECT, ref r);
|
|
return r;
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets or sets a value indicating whether to limit thumb movement to the selection.</summary>
|
|
/// <value><c>true</c> if movement is limited to selection; otherwise, <c>false</c>.</value>
|
|
[DefaultValue(false), Category("Appearance"), Description("Indicates if thumb movement is limited to the selection range.")]
|
|
public bool LimitThumbToSelection
|
|
{
|
|
get => limitThumbToSel;
|
|
set
|
|
{
|
|
if (limitThumbToSel == value) return;
|
|
limitThumbToSel = value;
|
|
if (!showSel) return;
|
|
if (Value < SelectionStart)
|
|
Value = SelectionStart;
|
|
else if (Value > SelectionEnd)
|
|
Value = SelectionEnd;
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets or sets a value indicating the horizontal or vertical orientation of the track bar.</summary>
|
|
[DefaultValue(Orientation.Horizontal), Category("Appearance"), Description("Indicates orientation of the trackbar.")]
|
|
public new Orientation Orientation
|
|
{
|
|
get => base.Orientation;
|
|
set
|
|
{
|
|
//valid values are 0x0 to 0x1
|
|
if (value != Orientation.Horizontal && value != Orientation.Vertical)
|
|
throw new InvalidEnumArgumentException(nameof(Orientation), (int)value, typeof(Orientation));
|
|
|
|
if (base.Orientation != value)
|
|
{
|
|
if (value == Orientation.Horizontal)
|
|
Width = requestedDim;
|
|
else
|
|
Height = requestedDim;
|
|
|
|
base.Orientation = value;
|
|
|
|
if (IsHandleCreated)
|
|
AdjustSize();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets or sets a value indicating whether the control is drawn by the operating system or by code that you provide.</summary>
|
|
/// <value>
|
|
/// <c>true</c> if the control is drawn by code that you provide; <c>false</c> if the control is drawn by the operating system. The
|
|
/// default is <c>false</c>.
|
|
/// </value>
|
|
[DefaultValue(false), Category("Behavior"), Description("Specifies whether to custom draw the trackbar.")]
|
|
public bool OwnerDraw { get; set; }
|
|
|
|
/// <summary>Gets or sets the upper limit of the selection range this TrackBar is working with.</summary>
|
|
/// <value>
|
|
/// The logical position at which the selection ends. This value must be less than or equal to the value of the <see
|
|
/// cref="TrackBar.Maximum"/> property.
|
|
/// </value>
|
|
[DefaultValue(0), Category("Behavior"), Description("The ending logical position of the current selection range in a trackbar.")]
|
|
public int SelectionEnd
|
|
{
|
|
get => selMax;
|
|
set => SetSelectionRange(selMin, value);
|
|
}
|
|
|
|
/// <summary>Gets or sets the lower limit of the selection range this TrackBar is working with.</summary>
|
|
/// <value>
|
|
/// The logical position at which the selection starts. This value must be greater than or equal to the value of the <see
|
|
/// cref="TrackBar.Minimum"/> property.
|
|
/// </value>
|
|
[DefaultValue(0), Category("Behavior"), Description("The starting logical position of the current selection range in a trackbar.")]
|
|
public int SelectionStart
|
|
{
|
|
get => selMin;
|
|
set => SetSelectionRange(value, selMax);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether to show the selection area defined by <see cref="SelectionStart"/> and <see cref="SelectionEnd"/>.
|
|
/// </summary>
|
|
/// <value><c>true</c> if showing selection area; otherwise, <c>false</c>.</value>
|
|
[DefaultValue(false), Category("Appearance"), Description("Indicates if the TaskBar shows a selection range.")]
|
|
public bool ShowSelection
|
|
{
|
|
get => showSel;
|
|
set
|
|
{
|
|
if (showSel == value) return;
|
|
showSel = value;
|
|
if (IsHandleCreated) RecreateHandle();
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets the bounds of the thumb slider in its current position.</summary>
|
|
/// <value>The thumb bounds.</value>
|
|
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public Rectangle ThumbBounds
|
|
{
|
|
get
|
|
{
|
|
var r = new RECT();
|
|
if (IsHandleCreated)
|
|
SendMsg(TrackBarMessage.TBM_GETTHUMBRECT, ref r);
|
|
return r;
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets or sets the length of the thumb, overriding the default.</summary>
|
|
/// <value>
|
|
/// The length of the thumb. This is the vertical length if the orientation is horizontal and the horizontal length if the
|
|
/// orientation is vertical.
|
|
/// </value>
|
|
[Category("Appearance"), Description("The length of the slider in a trackbar.")]
|
|
public int ThumbLength
|
|
{
|
|
get => IsHandleCreated ? SendMsg(TrackBarMessage.TBM_GETTHUMBLENGTH).ToInt32() : (thumbLength == -1 ? (TickStyle == TickStyle.Both ? 21 : 19) : thumbLength);
|
|
set
|
|
{
|
|
if (thumbLength == value) return;
|
|
thumbLength = value;
|
|
if (IsHandleCreated) RecreateHandle();
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets or sets an array that contains the positions of the tick marks for a trackbar.</summary>
|
|
/// <value>
|
|
/// The elements of the array specify the logical positions of the trackbar's tick marks, not including the first and last tick
|
|
/// marks created by the trackbar. The logical positions can be any of the integer values in the trackbar's range of minimum to
|
|
/// maximum slider positions.
|
|
/// </value>
|
|
[Category("Appearance"), Description("Indicates the logical values of the trackbar where ticks are drawn.")]
|
|
[Browsable(false)]
|
|
//[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
|
//[Editor(typeof(ArrayEditor), typeof(UITypeEditor))]
|
|
//[TypeConverter(typeof(ArrayConverter))]
|
|
public int[] TickPositions
|
|
{
|
|
get
|
|
{
|
|
var tickCnt = 0;
|
|
if (!IsHandleCreated || TickStyle == TickStyle.None || 0 == (tickCnt = SendMsg(TrackBarMessage.TBM_GETNUMTICS).ToInt32()))
|
|
return new int[0];
|
|
var ptr = SendMsg(TrackBarMessage.TBM_GETPTICS);
|
|
return ptr.ToIEnum<int>(tickCnt - 2).OrderBy(i => i).Distinct().ToArray();
|
|
}
|
|
set
|
|
{
|
|
if (value != null && value.Length > 0)
|
|
{
|
|
if (TickStyle == TickStyle.None) throw new ArgumentException("Tick positions cannot be set when TickStyle is None.");
|
|
if (value.Min() < Minimum || value.Max() > Maximum) throw new ArgumentOutOfRangeException(nameof(TickPositions), "All values must be between Minimum and Maximum range values.");
|
|
}
|
|
ticks = value ?? new int[0];
|
|
if (IsHandleCreated)
|
|
RecreateHandle();
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override CreateParams CreateParams
|
|
{
|
|
get
|
|
{
|
|
var cp = base.CreateParams;
|
|
cp.Style |= (int)TrackBarStyle.TBS_NOTIFYBEFOREMOVE;
|
|
cp.Style = showSel ? cp.Style | (int)TrackBarStyle.TBS_ENABLESELRANGE : cp.Style & ~(int)TrackBarStyle.TBS_ENABLESELRANGE;
|
|
cp.Style = BackColor == Color.Transparent ? cp.Style | (int)TrackBarStyle.TBS_TRANSPARENTBKGND : cp.Style & ~(int)TrackBarStyle.TBS_TRANSPARENTBKGND;
|
|
cp.Style = thumbLength >= 0 ? cp.Style | (int)TrackBarStyle.TBS_FIXEDLENGTH : cp.Style & ~(int)TrackBarStyle.TBS_FIXEDLENGTH;
|
|
cp.Style = autoTicks && TickStyle != TickStyle.None ? cp.Style | (int)TrackBarStyle.TBS_AUTOTICKS : cp.Style & ~(int)TrackBarStyle.TBS_AUTOTICKS;
|
|
return cp;
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override Size DefaultSize => new Size(104, PreferredDimension);
|
|
|
|
private int PreferredDimension
|
|
{
|
|
get
|
|
{
|
|
var track = TickStyle == TickStyle.None ? 6 : (TickStyle == TickStyle.Both ? 22 : 14);
|
|
return ThumbLength + track;
|
|
}
|
|
}
|
|
|
|
/// <summary>Sets the starting and ending positions for the available selection range in a trackbar.</summary>
|
|
/// <param name="rangeMin">The starting logical position for the selection range.</param>
|
|
/// <param name="rangeMax">The ending logical position for the selection range.</param>
|
|
/// <param name="redrawAll">
|
|
/// If this parameter is TRUE, the trackbar is redrawn after the selection range is set. If this parameter is FALSE, the message
|
|
/// sets the selection range but does not redraw the trackbar.
|
|
/// </param>
|
|
public void SetSelectionRange(int rangeMin, int rangeMax, bool redrawAll = true)
|
|
{
|
|
if (rangeMin == selMin && rangeMax == selMax) return;
|
|
if (rangeMin < 0) throw new ArgumentOutOfRangeException(nameof(rangeMin));
|
|
if (rangeMax < 0 || rangeMax < rangeMin) throw new ArgumentOutOfRangeException(nameof(rangeMax));
|
|
if (rangeMin == rangeMax)
|
|
{
|
|
ShowSelection = false;
|
|
}
|
|
else
|
|
{
|
|
ShowSelection = true;
|
|
if (rangeMin < Minimum) rangeMin = Minimum;
|
|
if (rangeMin > Maximum) rangeMax = Maximum;
|
|
}
|
|
selMin = rangeMin;
|
|
selMax = rangeMax;
|
|
SendMsg(TrackBarMessage.TBM_SETSELEND, 0, rangeMax);
|
|
SendMsg(TrackBarMessage.TBM_SETSELSTART, redrawAll ? 1 : 0, rangeMin);
|
|
}
|
|
|
|
/// <summary>Adjusts the size of the control.</summary>
|
|
protected virtual void AdjustSize()
|
|
{
|
|
if (IsHandleCreated)
|
|
{
|
|
var saveDim = requestedDim;
|
|
try
|
|
{
|
|
if (Orientation == Orientation.Horizontal)
|
|
Height = AutoSize ? PreferredDimension : saveDim;
|
|
else
|
|
Width = AutoSize ? PreferredDimension : saveDim;
|
|
}
|
|
finally
|
|
{
|
|
requestedDim = saveDim;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void OnAutoSizeChanged(EventArgs e)
|
|
{
|
|
base.OnAutoSizeChanged(e);
|
|
AdjustSize();
|
|
}
|
|
|
|
/// <summary>Raises the <see cref="E:DrawChannel"/> event.</summary>
|
|
/// <param name="pe">The <see cref="PaintEventArgs"/> instance containing the event data.</param>
|
|
/// <returns>
|
|
/// If overwritten, the method should return <c>true</c> to indicate that all drawing has been done by the method and the system
|
|
/// should not draw this item. If this method returns <c>false</c>, the system will draw the item.
|
|
/// </returns>
|
|
protected virtual bool OnDrawChannel(PaintEventArgs pe)
|
|
{
|
|
DrawChannel?.Invoke(this, pe);
|
|
return DrawChannel != null;
|
|
}
|
|
|
|
/// <summary>Raises the <see cref="E:DrawThumb"/> event.</summary>
|
|
/// <param name="pe">The <see cref="PaintEventArgs"/> instance containing the event data.</param>
|
|
/// <returns>
|
|
/// If overwritten, the method should return <c>true</c> to indicate that all drawing has been done by the method and the system
|
|
/// should not draw this item. If this method returns <c>false</c>, the system will draw the item.
|
|
/// </returns>
|
|
protected virtual bool OnDrawThumb(PaintEventArgs pe)
|
|
{
|
|
DrawThumb?.Invoke(this, pe);
|
|
return DrawThumb != null;
|
|
}
|
|
|
|
/// <summary>Raises the <see cref="E:DrawTics"/> event.</summary>
|
|
/// <param name="pe">The <see cref="PaintEventArgs"/> instance containing the event data.</param>
|
|
/// <returns>
|
|
/// If overwritten, the method should return <c>true</c> to indicate that all drawing has been done by the method and the system
|
|
/// should not draw this item. If this method returns <c>false</c>, the system will draw the item.
|
|
/// </returns>
|
|
protected virtual bool OnDrawTics(PaintEventArgs pe)
|
|
{
|
|
DrawTics?.Invoke(this, pe);
|
|
return DrawTics != null;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void OnHandleCreated(EventArgs e)
|
|
{
|
|
base.OnHandleCreated(e);
|
|
if (showSel)
|
|
{
|
|
SendMsg(TrackBarMessage.TBM_SETSELEND, 0, selMax);
|
|
SendMsg(TrackBarMessage.TBM_SETSELSTART, 1, selMin);
|
|
}
|
|
if (thumbLength >= 0)
|
|
SendMsg(TrackBarMessage.TBM_SETTHUMBLENGTH, thumbLength);
|
|
SendMsg(TrackBarMessage.TBM_CLEARTICS);
|
|
if (ticks != null && TickStyle != TickStyle.None)
|
|
foreach (var t in ticks)
|
|
SendMsg(TrackBarMessage.TBM_SETTIC, 0, t);
|
|
AdjustSize();
|
|
}
|
|
|
|
/// <summary>Raises the <see cref="Control.MouseWheel"/> event.</summary>
|
|
/// <param name="e">A <see cref="MouseEventArgs"/> that contains the event data.</param>
|
|
protected override void OnMouseWheel(MouseEventArgs e)
|
|
{
|
|
const int WHEEL_DELTA = 120;
|
|
var hme = e as HandledMouseEventArgs;
|
|
if (hme != null)
|
|
{
|
|
if (hme.Handled) return;
|
|
hme.Handled = true;
|
|
}
|
|
|
|
if ((ModifierKeys & (Keys.Shift | Keys.Alt)) != 0 || MouseButtons != MouseButtons.None)
|
|
return; // Do not scroll when Shift or Alt key is down, or when a mouse button is down.
|
|
|
|
var wheelScrollLines = SystemInformation.MouseWheelScrollLines;
|
|
if (wheelScrollLines == 0) return; // Do not scroll when the user system setting is 0 lines per notch
|
|
|
|
Debug.Assert(cumulativeWheelData > -WHEEL_DELTA, "cumulativeWheelData is too small");
|
|
Debug.Assert(cumulativeWheelData < WHEEL_DELTA, "cumulativeWheelData is too big");
|
|
cumulativeWheelData += e.Delta;
|
|
|
|
var partialNotches = cumulativeWheelData / (float)WHEEL_DELTA;
|
|
|
|
if (wheelScrollLines == -1)
|
|
wheelScrollLines = TickFrequency;
|
|
|
|
// Evaluate number of bands to scroll
|
|
var scrollBands = (int)(wheelScrollLines * partialNotches);
|
|
|
|
if (scrollBands != 0)
|
|
{
|
|
int absScrollBands;
|
|
if (scrollBands > 0)
|
|
{
|
|
absScrollBands = scrollBands;
|
|
Value = Math.Min(absScrollBands + Value, showSel && limitThumbToSel ? selMax : Maximum);
|
|
cumulativeWheelData -= (int)(scrollBands * (WHEEL_DELTA / (float)wheelScrollLines));
|
|
}
|
|
else
|
|
{
|
|
absScrollBands = -scrollBands;
|
|
Value = Math.Max(Value - absScrollBands, showSel && limitThumbToSel ? selMin : Minimum);
|
|
cumulativeWheelData -= (int)(scrollBands * (WHEEL_DELTA / (float)wheelScrollLines));
|
|
}
|
|
}
|
|
|
|
if (e.Delta != Value)
|
|
{
|
|
OnScroll(EventArgs.Empty);
|
|
OnValueChanged(EventArgs.Empty);
|
|
}
|
|
}
|
|
|
|
/// <summary>Raises the <see cref="E:System.Windows.Forms.TrackBar.ValueChanged"/> event.</summary>
|
|
/// <param name="e">The <see cref="T:System.EventArgs"/> that contains the event data.</param>
|
|
protected override void OnValueChanged(EventArgs e)
|
|
{
|
|
base.OnValueChanged(e);
|
|
Debug.WriteLine($">> TB ValueChg={Value} from {lastValue}");
|
|
lastValue = Value;
|
|
}
|
|
|
|
/// <summary>Sends the supplied message and parameters to the underlying TRACKBAR system control.</summary>
|
|
/// <param name="msg">The Windows message identifier.</param>
|
|
/// <param name="wParam">The wParam.</param>
|
|
/// <param name="lParam">The lParam.</param>
|
|
/// <returns>The result value defined for the message.</returns>
|
|
protected IntPtr SendMsg(TrackBarMessage msg, int wParam = 0, int lParam = 0) => IsHandleCreated ? SendMessage(Handle, (uint)msg, (IntPtr)wParam, (IntPtr)lParam) : IntPtr.Zero;
|
|
|
|
/// <inheritdoc/>
|
|
protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
|
|
{
|
|
requestedDim = Orientation == Orientation.Horizontal ? height : width;
|
|
|
|
if (AutoSize)
|
|
{
|
|
if (Orientation == Orientation.Horizontal)
|
|
{
|
|
if ((specified & BoundsSpecified.Height) != BoundsSpecified.None)
|
|
height = PreferredDimension;
|
|
}
|
|
else
|
|
{
|
|
if ((specified & BoundsSpecified.Width) != BoundsSpecified.None)
|
|
width = PreferredDimension;
|
|
}
|
|
}
|
|
// Call base method on Control and not TrackBar
|
|
typeof(Control).GetMethod("SetBoundsCore", BindingFlags.Instance | BindingFlags.NonPublic).InvokeNotOverride(this, x, y, width, height, specified);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void WndProc(ref Message m)
|
|
{
|
|
var msg = (WindowMessage)m.Msg;
|
|
//Debug.WriteLine($"TB WndProc: Msg={msg}");
|
|
if (msg == (WindowMessage.WM_NOTIFY | WindowMessage.WM_REFLECT))
|
|
{
|
|
if (OwnerDraw)
|
|
{
|
|
var hdr = (NMHDR)m.GetLParam(typeof(NMHDR));
|
|
if (hdr.code == (int)CommonControlNotification.NM_CUSTOMDRAW)
|
|
{
|
|
var cd = (NMCUSTOMDRAW)m.GetLParam(typeof(NMCUSTOMDRAW));
|
|
Debug.WriteLine($"{new TimeSpan(Environment.TickCount)} TBCustDraw: {cd.dwDrawStage}, {cd.dwItemSpec.ToInt32()}, {cd.uItemState}, {(Rectangle)cd.rc}");
|
|
m.Result = new IntPtr((int)CustomDraw(ref cd));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else if (msg == (WindowMessage.WM_HSCROLL | WindowMessage.WM_REFLECT) || msg == (WindowMessage.WM_VSCROLL | WindowMessage.WM_REFLECT))
|
|
{
|
|
var pos = Value;
|
|
var code = (TrackBarScrollNotification)LOWORD(m.WParam);
|
|
Debug.WriteLine($"TB_SCROLL: pos={pos}, lastPos={lastValue}, code={code}, sel={showSel}, limit={limitThumbToSel}, selMin={selMin}, selMax={selMax}");
|
|
if (showSel && limitThumbToSel)
|
|
{
|
|
if (pos > selMax) SendMsg(TrackBarMessage.TBM_SETPOS, 1, selMax);
|
|
else if (pos < selMin) SendMsg(TrackBarMessage.TBM_SETPOS, 1, selMin);
|
|
}
|
|
if (code != TrackBarScrollNotification.TB_THUMBPOSITION && code != TrackBarScrollNotification.TB_ENDTRACK && lastValue != Value)
|
|
{
|
|
var e = new ScrollEventArgs((ScrollEventType)code, lastValue, pos, m.Msg == (int)WindowMessage.WM_HSCROLL ? ScrollOrientation.HorizontalScroll : ScrollOrientation.VerticalScroll);
|
|
OnScroll(e);
|
|
OnValueChanged(EventArgs.Empty);
|
|
}
|
|
return;
|
|
}
|
|
base.WndProc(ref m);
|
|
}
|
|
|
|
private CustomDrawResponse CustomDraw(ref NMCUSTOMDRAW cd)
|
|
{
|
|
switch (cd.dwDrawStage)
|
|
{
|
|
case CustomDrawStage.CDDS_PREPAINT:
|
|
return CustomDrawResponse.CDRF_NOTIFYITEMDRAW; // | CustomDrawResponse.CDRF_NOTIFYPOSTPAINT;
|
|
|
|
case CustomDrawStage.CDDS_ITEMPREPAINT:
|
|
switch ((TrackBarCustomDraw)cd.dwItemSpec.ToInt32())
|
|
{
|
|
case TrackBarCustomDraw.TBCD_CHANNEL:
|
|
using (var g = Graphics.FromHdc((IntPtr)cd.hdc))
|
|
{
|
|
if (OnDrawChannel(new PaintEventArgs(g, cd.rc)))
|
|
return CustomDrawResponse.CDRF_SKIPDEFAULT;
|
|
}
|
|
break;
|
|
|
|
case TrackBarCustomDraw.TBCD_THUMB:
|
|
using (var g = Graphics.FromHdc((IntPtr)cd.hdc))
|
|
{
|
|
if (OnDrawThumb(new PaintEventArgs(g, cd.rc)))
|
|
return CustomDrawResponse.CDRF_SKIPDEFAULT;
|
|
}
|
|
break;
|
|
|
|
case TrackBarCustomDraw.TBCD_TICS:
|
|
using (var g = Graphics.FromHdc((IntPtr)cd.hdc))
|
|
{
|
|
if (OnDrawTics(new PaintEventArgs(g, cd.rc)))
|
|
return CustomDrawResponse.CDRF_SKIPDEFAULT;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
return CustomDrawResponse.CDRF_DODEFAULT;
|
|
}
|
|
|
|
private void ResetThumbLength()
|
|
{
|
|
thumbLength = -1;
|
|
if (IsHandleCreated) RecreateHandle();
|
|
}
|
|
|
|
private void ResetTickPositions() => TickPositions = new int[0];
|
|
|
|
private IntPtr SendMsg(TrackBarMessage msg, ref RECT rect) => SendMessage(Handle, (uint)msg, IntPtr.Zero, ref rect);
|
|
|
|
private bool ShouldSerializeThumbLength() => thumbLength >= 0;
|
|
|
|
private bool ShouldSerializeTickPositions() => ticks != null && ticks.Length > 0;
|
|
}
|
|
} |