#region Imports
|
|
using DPumpHydr.WinFrmUI.RLT.Manager;
|
using DPumpHydr.WinFrmUI.RLT.Util;
|
using System;
|
using System.ComponentModel;
|
using System.Data;
|
using System.Drawing;
|
using System.Drawing.Drawing2D;
|
using System.Linq;
|
using System.Windows.Forms;
|
using static DPumpHydr.WinFrmUI.RLT.Helper.MaterialDrawHelper;
|
using static DPumpHydr.WinFrmUI.RLT.Util.MaterialAnimations;
|
|
#endregion
|
|
namespace DPumpHydr.WinFrmUI.RLT.Controls
|
{
|
#region MaterialComboBox
|
|
public class MaterialComboBox : ComboBox, MaterialControlI
|
{
|
// For some reason, even when overriding the AutoSize property, it doesn't appear on the properties panel, so we have to create a new one.
|
[Browsable(true), EditorBrowsable(EditorBrowsableState.Always), Category("Layout")]
|
private bool _AutoResize;
|
|
public bool AutoResize
|
{
|
get => _AutoResize;
|
set
|
{
|
_AutoResize = value;
|
recalculateAutoSize();
|
}
|
}
|
|
//Properties for managing the material design properties
|
[Browsable(false)]
|
public int Depth { get; set; }
|
|
[Browsable(false)]
|
public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
|
|
[Browsable(false)]
|
public MaterialMouseState MouseState { get; set; }
|
|
private bool _UseTallSize;
|
|
[Category("Material"), DefaultValue(true), Description("Using a larger size enables the hint to always be visible")]
|
public bool UseTallSize
|
{
|
get => _UseTallSize;
|
set
|
{
|
_UseTallSize = value;
|
setHeightVars();
|
Invalidate();
|
}
|
}
|
|
[Category("Material"), DefaultValue(true)]
|
public bool UseAccent { get; set; }
|
|
private string _hint = string.Empty;
|
|
[Category("Material"), DefaultValue(""), Localizable(true)]
|
public string Hint
|
{
|
get => _hint;
|
set
|
{
|
_hint = value;
|
hasHint = !string.IsNullOrEmpty(Hint);
|
Invalidate();
|
}
|
}
|
|
private int _startIndex;
|
public int StartIndex
|
{
|
get => _startIndex;
|
set
|
{
|
_startIndex = value;
|
try
|
{
|
if (base.Items.Count > 0)
|
{
|
base.SelectedIndex = value;
|
}
|
}
|
catch
|
{
|
}
|
Invalidate();
|
}
|
}
|
|
private const int TEXT_SMALL_SIZE = 18;
|
private const int TEXT_SMALL_Y = 4;
|
private const int BOTTOM_PADDING = 3;
|
private int HEIGHT = 50;
|
private int LINE_Y;
|
|
private bool hasHint;
|
|
private readonly AnimationManager _animationManager;
|
|
public MaterialComboBox()
|
{
|
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
|
|
// Material Properties
|
Hint = "";
|
UseAccent = true;
|
UseTallSize = true;
|
MaxDropDownItems = 4;
|
|
Font = SkinManager.GetFontByType(MaterialSkinManager.FontType.Subtitle2);
|
BackColor = SkinManager.BackgroundColor;
|
ForeColor = SkinManager.TextHighEmphasisColor;
|
DrawMode = DrawMode.OwnerDrawVariable;
|
DropDownStyle = ComboBoxStyle.DropDownList;
|
DropDownWidth = Width;
|
|
// Animations
|
_animationManager = new AnimationManager(true)
|
{
|
Increment = 0.08,
|
AnimationType = AnimationType.EaseInOut
|
};
|
_animationManager.OnAnimationProgress += sender => Invalidate();
|
_animationManager.OnAnimationFinished += sender => _animationManager.SetProgress(0);
|
DropDownClosed += (sender, args) =>
|
{
|
MouseState = MaterialMouseState.OUT;
|
if (SelectedIndex < 0 && !Focused)
|
{
|
_animationManager.StartNewAnimation(AnimationDirection.Out);
|
}
|
};
|
LostFocus += (sender, args) =>
|
{
|
MouseState = MaterialMouseState.OUT;
|
if (SelectedIndex < 0)
|
{
|
_animationManager.StartNewAnimation(AnimationDirection.Out);
|
}
|
};
|
DropDown += (sender, args) =>
|
{
|
_animationManager.StartNewAnimation(AnimationDirection.In);
|
};
|
GotFocus += (sender, args) =>
|
{
|
_animationManager.StartNewAnimation(AnimationDirection.In);
|
Invalidate();
|
};
|
MouseEnter += (sender, args) =>
|
{
|
MouseState = MaterialMouseState.HOVER;
|
Invalidate();
|
};
|
MouseLeave += (sender, args) =>
|
{
|
MouseState = MaterialMouseState.OUT;
|
Invalidate();
|
};
|
SelectedIndexChanged += (sender, args) =>
|
{
|
Invalidate();
|
};
|
KeyUp += (sender, args) =>
|
{
|
if (Enabled && DropDownStyle == ComboBoxStyle.DropDownList && (args.KeyCode == Keys.Delete || args.KeyCode == Keys.Back))
|
{
|
SelectedIndex = -1;
|
Invalidate();
|
}
|
};
|
}
|
|
protected override void OnPaint(PaintEventArgs pevent)
|
{
|
Graphics g = pevent.Graphics;
|
|
g.Clear(Parent.BackColor == Color.Transparent ? ((Parent.Parent == null || (Parent.Parent != null && Parent.Parent.BackColor == Color.Transparent)) ? SkinManager.BackgroundColor : Parent.Parent.BackColor) : Parent.BackColor);
|
g.FillRectangle(Enabled ? Focused ?
|
SkinManager.BackgroundFocusBrush : // Focused
|
MouseState == MaterialMouseState.HOVER ?
|
SkinManager.BackgroundHoverBrush : // Hover
|
SkinManager.BackgroundAlternativeBrush : // normal
|
SkinManager.BackgroundDisabledBrush // Disabled
|
, ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width, LINE_Y);
|
|
//Set color and brush
|
Color SelectedColor = new();
|
if (UseAccent)
|
{
|
SelectedColor = SkinManager.ColorScheme.AccentColor;
|
}
|
else
|
{
|
SelectedColor = SkinManager.ColorScheme.PrimaryColor;
|
}
|
|
SolidBrush SelectedBrush = new(SelectedColor);
|
|
// Create and Draw the arrow
|
GraphicsPath pth = new();
|
PointF TopRight = new(this.Width - 0.5f - SkinManager.FORM_PADDING, (this.Height >> 1) - 2.5f);
|
PointF MidBottom = new(this.Width - 4.5f - SkinManager.FORM_PADDING, (this.Height >> 1) + 2.5f);
|
PointF TopLeft = new(this.Width - 8.5f - SkinManager.FORM_PADDING, (this.Height >> 1) - 2.5f);
|
pth.AddLine(TopLeft, TopRight);
|
pth.AddLine(TopRight, MidBottom);
|
|
g.SmoothingMode = SmoothingMode.AntiAlias;
|
g.FillPath((SolidBrush)(Enabled ? DroppedDown || Focused ?
|
SelectedBrush : //DroppedDown or Focused
|
SkinManager.TextHighEmphasisBrush : //Not DroppedDown and not Focused
|
new SolidBrush(BlendColor(SkinManager.TextHighEmphasisColor, SkinManager.SwitchOffDisabledThumbColor, 197)) //Disabled
|
), pth);
|
g.SmoothingMode = SmoothingMode.None;
|
|
// HintText
|
bool userTextPresent = SelectedIndex >= 0;
|
Rectangle hintRect = new(SkinManager.FORM_PADDING, ClientRectangle.Y, Width, LINE_Y);
|
int hintTextSize = 16;
|
|
// bottom line base
|
g.FillRectangle(SkinManager.DividersAlternativeBrush, 0, LINE_Y, Width, 1);
|
|
if (!_animationManager.IsAnimating())
|
{
|
// No animation
|
if (hasHint && UseTallSize && (DroppedDown || Focused || SelectedIndex >= 0))
|
{
|
// hint text
|
hintRect = new Rectangle(SkinManager.FORM_PADDING, TEXT_SMALL_Y, Width, TEXT_SMALL_SIZE);
|
hintTextSize = 12;
|
}
|
|
// bottom line
|
if (DroppedDown || Focused)
|
{
|
g.FillRectangle(SelectedBrush, 0, LINE_Y, Width, 2);
|
}
|
}
|
else
|
{
|
// Animate - Focus got/lost
|
double animationProgress = _animationManager.GetProgress();
|
|
// hint Animation
|
if (hasHint && UseTallSize)
|
{
|
hintRect = new Rectangle(
|
SkinManager.FORM_PADDING,
|
userTextPresent && !_animationManager.IsAnimating() ? TEXT_SMALL_Y : ClientRectangle.Y + (int)((TEXT_SMALL_Y - ClientRectangle.Y) * animationProgress),
|
Width,
|
userTextPresent && !_animationManager.IsAnimating() ? TEXT_SMALL_SIZE : (int)(LINE_Y + ((TEXT_SMALL_SIZE - LINE_Y) * animationProgress)));
|
hintTextSize = userTextPresent && !_animationManager.IsAnimating() ? 12 : (int)(16 + ((12 - 16) * animationProgress));
|
}
|
|
// Line Animation
|
int LineAnimationWidth = (int)(Width * animationProgress);
|
int LineAnimationX = (Width / 2) - (LineAnimationWidth / 2);
|
g.FillRectangle(SelectedBrush, LineAnimationX, LINE_Y, LineAnimationWidth, 2);
|
}
|
|
// Calc text Rect
|
Rectangle textRect = new(
|
SkinManager.FORM_PADDING,
|
hasHint && UseTallSize ? hintRect.Y + hintRect.Height - 2 : ClientRectangle.Y,
|
ClientRectangle.Width - (SkinManager.FORM_PADDING * 3) - 8,
|
hasHint && UseTallSize ? LINE_Y - (hintRect.Y + hintRect.Height) : LINE_Y);
|
|
g.Clip = new Region(textRect);
|
|
using (MaterialNativeTextRenderer NativeText = new(g))
|
{
|
// Draw user text
|
NativeText.DrawTransparentText(
|
Text,
|
SkinManager.GetLogFontByType(MaterialSkinManager.FontType.Subtitle1),
|
Enabled ? SkinManager.TextHighEmphasisColor : SkinManager.TextDisabledOrHintColor,
|
textRect.Location,
|
textRect.Size,
|
MaterialNativeTextRenderer.TextAlignFlags.Left | MaterialNativeTextRenderer.TextAlignFlags.Middle);
|
}
|
|
g.ResetClip();
|
|
// Draw hint text
|
if (hasHint && (UseTallSize || string.IsNullOrEmpty(Text)))
|
{
|
using MaterialNativeTextRenderer NativeText = new(g);
|
NativeText.DrawTransparentText(
|
Hint,
|
SkinManager.GetTextBoxFontBySize(hintTextSize),
|
Enabled ? DroppedDown || Focused ?
|
SelectedColor : // Focus
|
SkinManager.TextMediumEmphasisColor : // not focused
|
SkinManager.TextDisabledOrHintColor, // Disabled
|
hintRect.Location,
|
hintRect.Size,
|
MaterialNativeTextRenderer.TextAlignFlags.Left | MaterialNativeTextRenderer.TextAlignFlags.Middle);
|
}
|
}
|
|
private void CustomMeasureItem(object sender, MeasureItemEventArgs e)
|
{
|
e.ItemHeight = HEIGHT - 7;
|
}
|
|
private void CustomDrawItem(object sender, DrawItemEventArgs e)
|
{
|
if (e.Index < 0 || e.Index > Items.Count || !Focused)
|
{
|
return;
|
}
|
|
Graphics g = e.Graphics;
|
|
// Draw the background of the item.
|
g.FillRectangle(SkinManager.BackgroundBrush, e.Bounds);
|
|
// Hover
|
if (e.State.HasFlag(DrawItemState.Focus)) // Focus == hover
|
{
|
g.FillRectangle(SkinManager.BackgroundHoverBrush, e.Bounds);
|
}
|
|
string Text = "";
|
if (!string.IsNullOrWhiteSpace(DisplayMember))
|
{
|
if (!Items[e.Index].GetType().Equals(typeof(DataRowView)))
|
{
|
object item = Items[e.Index].GetType().GetProperty(DisplayMember).GetValue(Items[e.Index]);
|
Text = item.ToString();
|
}
|
else
|
{
|
DataTable table = ((DataRow)Items[e.Index].GetType().GetProperty("Row").GetValue(Items[e.Index])).Table;
|
Text = table.Rows[e.Index][DisplayMember].ToString();
|
}
|
}
|
else
|
{
|
Text = Items[e.Index].ToString();
|
}
|
|
using MaterialNativeTextRenderer NativeText = new(g);
|
NativeText.DrawTransparentText(
|
Text,
|
SkinManager.GetFontByType(MaterialSkinManager.FontType.Subtitle1),
|
SkinManager.TextHighEmphasisNoAlphaColor,
|
new Point(e.Bounds.Location.X + SkinManager.FORM_PADDING, e.Bounds.Location.Y),
|
new Size(e.Bounds.Size.Width - (SkinManager.FORM_PADDING * 2), e.Bounds.Size.Height),
|
MaterialNativeTextRenderer.TextAlignFlags.Left | MaterialNativeTextRenderer.TextAlignFlags.Middle); ;
|
}
|
|
protected override void OnCreateControl()
|
{
|
base.OnCreateControl();
|
MouseState = MaterialMouseState.OUT;
|
MeasureItem += CustomMeasureItem;
|
DrawItem += CustomDrawItem;
|
DropDownStyle = ComboBoxStyle.DropDownList;
|
DrawMode = DrawMode.OwnerDrawVariable;
|
recalculateAutoSize();
|
setHeightVars();
|
}
|
|
protected override void OnResize(EventArgs e)
|
{
|
base.OnResize(e);
|
recalculateAutoSize();
|
setHeightVars();
|
}
|
|
private void setHeightVars()
|
{
|
HEIGHT = UseTallSize ? 50 : 36;
|
Size = new Size(Size.Width, HEIGHT);
|
LINE_Y = HEIGHT - BOTTOM_PADDING;
|
ItemHeight = HEIGHT - 7;
|
DropDownHeight = (ItemHeight * MaxDropDownItems) + 2;
|
}
|
|
public void recalculateAutoSize()
|
{
|
if (!AutoResize)
|
{
|
return;
|
}
|
|
int w = DropDownWidth;
|
int padding = SkinManager.FORM_PADDING * 3;
|
int vertScrollBarWidth = (Items.Count > MaxDropDownItems) ? SystemInformation.VerticalScrollBarWidth : 0;
|
|
Graphics g = CreateGraphics();
|
using (MaterialNativeTextRenderer NativeText = new(g))
|
{
|
System.Collections.Generic.IEnumerable<string> itemsList = this.Items.Cast<object>().Select(item => item.ToString());
|
foreach (string s in itemsList)
|
{
|
int newWidth = NativeText.MeasureLogString(s, SkinManager.GetLogFontByType(MaterialSkinManager.FontType.Subtitle1)).Width + vertScrollBarWidth + padding;
|
if (w < newWidth)
|
{
|
w = newWidth;
|
}
|
}
|
}
|
|
if (Width != w)
|
{
|
DropDownWidth = w;
|
Width = w;
|
}
|
}
|
}
|
|
#endregion
|
}
|