#region Imports using DPumpHydr.WinFrmUI.RLT.Extension; using DPumpHydr.WinFrmUI.RLT.Helper; using DPumpHydr.WinFrmUI.RLT.Manager; using DPumpHydr.WinFrmUI.RLT.Util; using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Text; using System.Windows.Forms; using static DPumpHydr.WinFrmUI.RLT.Helper.MaterialDrawHelper; #endregion namespace DPumpHydr.WinFrmUI.RLT.Controls { #region MaterialSlider public class MaterialSlider : Control, MaterialControlI { #region "Private members" private bool _mousePressed; private int _mouseX; //private int _indicatorSize; private bool _hovered = false; private Rectangle _indicatorRectangle; private Rectangle _indicatorRectangleNormal; private Rectangle _indicatorRectanglePressed; private Rectangle _textRectangle; private Rectangle _valueRectangle; private Rectangle _sliderRectangle; private const int _activeTrack = 6; private const int _inactiveTrack = 4; private const int _thumbRadius = 20; private const int _thumbRadiusHoverPressed = 40; #endregion #region "Public Properties" [Browsable(false)] public int Depth { get; set; } [Browsable(false)] public MaterialSkinManager SkinManager => MaterialSkinManager.Instance; [Browsable(false)] public MaterialMouseState MouseState { get; set; } [Category("Material")] [DefaultValue(Directions.Normal)] [Description("Define control direction change value with mouse wheel")] public Directions ScrollDirection { get; set; } protected int _stepChange = 2; [Category("Material")] [Description("Define control step change value")] public int StepChange { get => _stepChange; set => _stepChange = value.Clamp(1, RangeMax); } private int _value; [DefaultValue(50)] [Category("Material")] [Description("Define control value")] public int Value { get => _value; set { if (value < _rangeMin) { _value = _rangeMin; } else if (value > _rangeMax) { _value = _rangeMax; } else { _value = value; } //_mouseX = _sliderRectangle.X + ((int)((double)_value / (double)(RangeMax - RangeMin) * (double)(_sliderRectangle.Width) - _thumbRadius / 2)); _mouseX = _sliderRectangle.X + ((int)((double)_value / (double)(RangeMax - RangeMin) * (double)(_sliderRectangle.Width - _thumbRadius))); RecalcutlateIndicator(); } } private int _valueMax; [DefaultValue(0)] [Category("Material")] [Description("Define position indicator maximum value. Ignored when set to 0.")] public int ValueMax { get => _valueMax; set { if (value > _rangeMax) { _valueMax = _rangeMax; } else if (value < _rangeMin) { _valueMax = _rangeMin; } else { _valueMax = value; } } } private int _rangeMax; [DefaultValue(100)] [Category("Material")] [Description("Define control range maximum value")] public int RangeMax { get => _rangeMax; set { _rangeMax = value; //_mouseX = _sliderRectangle.X + ((int)((double)_value / (double)(RangeMax - RangeMin) * (double)(_sliderRectangle.Width) - _thumbRadius / 2)); _mouseX = _sliderRectangle.X + ((int)((double)_value / (double)(RangeMax - RangeMin) * (double)(_sliderRectangle.Width - _thumbRadius))); RecalcutlateIndicator(); } } private int _rangeMin; [DefaultValue(0)] [Category("Material")] [Description("Define control range minimum value")] public int RangeMin { get => _rangeMin; set { _rangeMin = value; //_mouseX = _sliderRectangle.X + ((int)((double)_value / (double)(RangeMax - RangeMin) * (double)(_sliderRectangle.Width) - _thumbRadius / 2)); _mouseX = _sliderRectangle.X + ((int)((double)_value / (double)(RangeMax - RangeMin) * (double)(_sliderRectangle.Width - _thumbRadius))); RecalcutlateIndicator(); } } private string _text; [DefaultValue("MyData")] [Category("Material")] [Description("Set control text")] public override string Text { get => _text; set { _text = value; UpdateRects(); Invalidate(); } } private string _valueSuffix; [DefaultValue("")] [Category("Material")] [Description("Set control value suffix text")] public string ValueSuffix { get => _valueSuffix; set { _valueSuffix = value; UpdateRects(); } } private string _valuePrefix; [DefaultValue("")] [Category("Material")] [Description("Set control value prefix text")] public string ValuePrefix { get => _valuePrefix; set { _valuePrefix = value; UpdateRects(); } } private bool _showText; [DefaultValue(true)] [Category("Material"), DisplayName("Show Text")] [Description("Show text")] public bool ShowText { get => _showText; set { _showText = value; UpdateRects(); Invalidate(); } } private bool _showValue; [DefaultValue(true)] [Category("Material"), DisplayName("Show Value")] [Description("Show value")] public bool ShowValue { get => _showValue; set { _showValue = value; UpdateRects(); Invalidate(); } } private bool _useAccentColor; [Category("Material"), DefaultValue(false), DisplayName("Use Accent Color")] public bool UseAccentColor { get => _useAccentColor; set { _useAccentColor = value; Invalidate(); } } private MaterialSkinManager.FontType _fontType = MaterialSkinManager.FontType.Body1; [Category("Material"), DefaultValue(typeof(MaterialSkinManager.FontType), "Body1")] public MaterialSkinManager.FontType FontType { get => _fontType; set { _fontType = value; Font = SkinManager.GetFontByType(_fontType); Refresh(); } } #endregion #region "Events" [Category("Behavior")] [Description("Occurs when value change.")] public delegate void ValueChanged(object sender, int newValue); public event ValueChanged onValueChanged; #endregion #region "Enums" public enum Directions { Normal, Reverse } #endregion public MaterialSlider() { SetStyle(ControlStyles.Selectable, true); ForeColor = SkinManager.TextHighEmphasisColor; // Color.Black; RangeMax = 100; RangeMin = 0; Size = new Size(250, _thumbRadiusHoverPressed); Text = "My Data"; Value = 50; ValueSuffix = ""; ValuePrefix = ""; ShowText = true; ShowValue = true; UseAccentColor = false; UpdateRects(); //EnabledChanged += MaterialSlider_EnabledChanged; DoubleBuffered = true; } //protected override void OnCreateControl() //{ // base.OnCreateControl(); //} protected override void OnSizeChanged(EventArgs e) { base.OnSizeChanged(e); Height = _thumbRadiusHoverPressed; UpdateRects(); } protected override void OnGotFocus(EventArgs e) { base.OnGotFocus(e); _hovered = true; Invalidate(); } protected override void OnLostFocus(EventArgs e) { base.OnLostFocus(e); _hovered = false; Invalidate(); } protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); if (e.Button == MouseButtons.Left && e.Y > _indicatorRectanglePressed.Top && e.Y < _indicatorRectanglePressed.Bottom) { _mousePressed = true; UpdateValue(e); } } protected override void OnMouseWheel(MouseEventArgs e) { base.OnMouseWheel(e); int scrollLines = SystemInformation.MouseWheelScrollLines; Value += e.Delta / 40 / scrollLines * StepChange * (ScrollDirection == Directions.Normal ? 1 : -1); Value = Value.Clamp(RangeMin, RangeMax); onValueChanged?.Invoke(this, _value); } protected override void OnMouseEnter(EventArgs e) { base.OnMouseEnter(e); _hovered = true; if (!this.Focused) { this.Focus(); } Invalidate(); } protected override void OnMouseLeave(EventArgs e) { base.OnMouseLeave(e); _hovered = false; if (this.Focused) { this.Parent.Focus(); } Invalidate(); } protected override void OnMouseUp(MouseEventArgs e) { base.OnMouseUp(e); _mousePressed = false; Invalidate(); } protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if (_mousePressed) { UpdateValue(e); } } private void UpdateValue(MouseEventArgs e) { int v = 0; if (e.X >= _sliderRectangle.X + (_thumbRadius / 2) && e.X <= _sliderRectangle.Right - (_thumbRadius / 2)) { _mouseX = e.X - (_thumbRadius / 2); double ValuePerPx = ((double)(RangeMax - RangeMin)) / (_sliderRectangle.Width - _thumbRadius); v = (int)(ValuePerPx * (_mouseX - _sliderRectangle.X)); //if (_valueMax!=0 && v > _valueMax) v = _valueMax; } else if (e.X < _sliderRectangle.X)// + (_thumbRadius / 2)) { _mouseX = _sliderRectangle.X; v = _rangeMin; } else if (e.X > _sliderRectangle.Right - _thumbRadius)// / 2) { _mouseX = _sliderRectangle.Right - _thumbRadius; v = _rangeMax; } if (_valueMax != 0 && v > _valueMax) { Value = _valueMax; } else { if (v != _value) { _value = v; onValueChanged?.Invoke(this, _value); } RecalcutlateIndicator(); } } private void UpdateRects() { Size textSize; Size valueSize; using (MaterialNativeTextRenderer NativeText = new(CreateGraphics())) { textSize = NativeText.MeasureLogString(_showText ? Text : "", SkinManager.GetLogFontByType(_fontType)); valueSize = NativeText.MeasureLogString(_showValue ? _valuePrefix + RangeMax.ToString() + _valueSuffix : "", SkinManager.GetLogFontByType(_fontType)); } _valueRectangle = new Rectangle(Width - valueSize.Width - (_thumbRadiusHoverPressed / 4), 0, valueSize.Width + (_thumbRadiusHoverPressed / 4), Height); _textRectangle = new Rectangle(0, 0, textSize.Width + (_thumbRadiusHoverPressed / 4), Height); _sliderRectangle = new Rectangle(_textRectangle.Right, 0, _valueRectangle.Left - _textRectangle.Right, _thumbRadius); _mouseX = _sliderRectangle.X + ((int)(((double)_value / (double)(_rangeMax - _rangeMin) * (double)_sliderRectangle.Width) - (_thumbRadius / 2))); RecalcutlateIndicator(); } private void RecalcutlateIndicator() { _indicatorRectangle = new Rectangle(_mouseX, (Height - _thumbRadius) / 2, _thumbRadius, _thumbRadius); _indicatorRectangleNormal = new Rectangle(_indicatorRectangle.X, (Height / 2) - (_thumbRadius / 2), _thumbRadius, _thumbRadius); _indicatorRectanglePressed = new Rectangle(_indicatorRectangle.X + (_thumbRadius / 2) - (_thumbRadiusHoverPressed / 2), (Height / 2) - (_thumbRadiusHoverPressed / 2), _thumbRadiusHoverPressed, _thumbRadiusHoverPressed); Invalidate(); } protected override void OnPaint(PaintEventArgs e) { Graphics g = e.Graphics; g.SmoothingMode = SmoothingMode.AntiAlias; g.TextRenderingHint = TextRenderingHint.AntiAlias; g.Clear(Parent.BackColor == Color.Transparent ? ((Parent.Parent == null || (Parent.Parent != null && Parent.Parent.BackColor == Color.Transparent)) ? SkinManager.BackgroundColor : Parent.Parent.BackColor) : Parent.BackColor); Color _inactiveTrackColor; Color _accentColor; Brush _accentBrush; Brush _disabledBrush; Color _disabledColor; Color _thumbHoverColor; Color _thumbPressedColor; if (_useAccentColor) { _accentColor = SkinManager.ColorScheme.AccentColor; } else { _accentColor = SkinManager.ColorScheme.PrimaryColor; } _accentBrush = new SolidBrush(_accentColor); _disabledBrush = new SolidBrush(Color.FromArgb(255, 158, 158, 158)); if (SkinManager.Theme == MaterialSkinManager.Themes.DARK) { _disabledColor = Color.FromArgb((int)(2.55 * 30), 255, 255, 255); _inactiveTrackColor = _accentColor.Darken(0.25f); } else { _disabledColor = Color.FromArgb((int)(2.55 * (_hovered ? 38 : 26)), 0, 0, 0); _inactiveTrackColor = _accentColor.Lighten(0.6f); } //_disabledBrush = new SolidBrush(_disabledColor); //_thumbHoverColor = Color.FromArgb((int)(2.55 * 15), (Value == 0 ? Color.Gray : _accentColor)); //_thumbPressedColor = Color.FromArgb((int)(2.55 * 30), (Value == 0 ? Color.Gray : _accentColor)); _thumbHoverColor = Color.FromArgb((int)(2.55 * 15), (Value == 0 ? Color.Gray : _accentColor)); _thumbHoverColor = Color.FromArgb((int)(2.55 * 15), _accentColor); _thumbPressedColor = Color.FromArgb((int)(2.55 * 30), _accentColor); //Pen LinePen = new Pen(_disabledColor, _inactiveTrack); //Draw track //g.DrawLine(LinePen, _indicatorSize / 2, Height / 2 + (Height - _indicatorSize) / 2, Width - _indicatorSize / 2, Height / 2 + (Height - _indicatorSize) / 2); //g.DrawLine(LinePen, _sliderRectangle.X + (_indicatorSize / 2), Height / 2 , _sliderRectangle.Right - (_indicatorSize / 2), Height / 2 ); GraphicsPath _inactiveTrackPath = CreateRoundRect(_sliderRectangle.X + (_thumbRadius / 2), _sliderRectangle.Y + (Height / 2) - (_inactiveTrack / 2), _sliderRectangle.Width - _thumbRadius, _inactiveTrack, 2); //g.FillPath(_disabledBrush, _inactiveTrackPath); GraphicsPath _activeTrackPath = CreateRoundRect(_sliderRectangle.X + (_thumbRadius / 2), _sliderRectangle.Y + (Height / 2) - (_activeTrack / 2), _indicatorRectangleNormal.X - _sliderRectangle.X, _activeTrack, 2); if (Enabled) { //Draw inactive track g.FillPath(new SolidBrush(_inactiveTrackColor), _inactiveTrackPath); //Draw active track //g.DrawLine(SkinManager.ColorScheme.AccentPen, _indicatorSize / 2, Height / 2 + (Height - _indicatorSize) / 2, _indicatorRectangleNormal.X, Height / 2 + (Height - _indicatorSize) / 2); //g.DrawLine(AccentPen, _sliderRectangle.X + (_indicatorSize / 2), Height / 2 , _indicatorRectangleNormal.X + (_indicatorSize / 2), Height / 2 ) ; g.FillPath(_accentBrush, _activeTrackPath); if (_mousePressed) { //g.FillEllipse(_accentBrush, _indicatorRectanglePressed); g.FillEllipse(_accentBrush, _indicatorRectangleNormal); g.FillEllipse(new SolidBrush(_thumbPressedColor), _indicatorRectanglePressed); } else { g.FillEllipse(_accentBrush, _indicatorRectangleNormal); if (_hovered) { g.FillEllipse(new SolidBrush(_thumbHoverColor), _indicatorRectanglePressed); } } } else { //Draw inactive track g.FillPath(new SolidBrush(_disabledColor.Lighten(0.25f)), _inactiveTrackPath); //Draw active track g.FillPath(_disabledBrush, _activeTrackPath); g.FillEllipse(_disabledBrush, _indicatorRectangleNormal); } using MaterialNativeTextRenderer NativeText = new(g); if (_showText == true) { // Draw text NativeText.DrawTransparentText( Text, SkinManager.GetLogFontByType(_fontType), Enabled ? SkinManager.TextHighEmphasisColor : SkinManager.TextDisabledOrHintColor, _textRectangle.Location, _textRectangle.Size, MaterialNativeTextRenderer.TextAlignFlags.Left | MaterialNativeTextRenderer.TextAlignFlags.Middle); } if (_showValue == true) { // Draw value NativeText.DrawTransparentText( ValuePrefix + Value.ToString() + ValueSuffix, SkinManager.GetLogFontByType(_fontType), Enabled ? SkinManager.TextHighEmphasisColor : SkinManager.TextDisabledOrHintColor, _valueRectangle.Location, _valueRectangle.Size, MaterialNativeTextRenderer.TextAlignFlags.Right | MaterialNativeTextRenderer.TextAlignFlags.Middle); } } } #endregion }