#region Imports using DPumpHydr.WinFrmUI.RLT.Child.Metro; using DPumpHydr.WinFrmUI.RLT.Design.Metro; using DPumpHydr.WinFrmUI.RLT.Enum.Metro; using DPumpHydr.WinFrmUI.RLT.Extension.Metro; using DPumpHydr.WinFrmUI.RLT.Interface.Metro; using DPumpHydr.WinFrmUI.RLT.Manager; using DPumpHydr.WinFrmUI.RLT.Native; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Text; using System.Runtime.InteropServices; using System.Windows.Forms; #endregion namespace DPumpHydr.WinFrmUI.RLT.Controls { #region MetroListBox [ToolboxItem(true)] [ToolboxBitmap(typeof(MetroListBox), "Bitmaps.ListBox.bmp")] [Designer(typeof(MetroListBoxDesigner))] [DefaultProperty("Items")] [DefaultEvent("SelectedIndexChanged")] [ComVisible(true)] public class MetroListBox : Control, IMetroControl { #region Interfaces [Category("Metro"), Description("Gets or sets the style associated with the control.")] public Style Style { get => StyleManager?.Style ?? _style; set { _style = value; switch (value) { case Style.Light: ApplyTheme(); break; case Style.Dark: ApplyTheme(Style.Dark); break; case Style.Custom: ApplyTheme(Style.Custom); break; default: ApplyTheme(); break; } _svs.Style = value; Invalidate(); } } [Category("Metro"), Description("Gets or sets the Style Manager associated with the control.")] public MetroStyleManager StyleManager { get => _styleManager; set { _styleManager = value; Invalidate(); } } [Category("Metro"), Description("Gets or sets the The Author name associated with the theme.")] public string ThemeAuthor { get; set; } [Category("Metro"), Description("Gets or sets the The Theme name associated with the theme.")] public string ThemeName { get; set; } #endregion Interfaces #region Global Vars private readonly Utilites _utl; #endregion Global Vars #region Internal Vars private Style _style; private MetroStyleManager _styleManager; private List _indicates; private bool _multiSelect; private int _selectedIndex; private object _selectedItem; private string _selectedText; private bool _showScrollBar; private bool _multiKeyDown; private int _hoveredItem; private MetroScrollBar _svs; private object _selectedValue; private bool _isDerivedStyle = true; private int _itemHeight; private bool _showBorder; private Color _selectedItemColor; private Color _selectedItemBackColor; private Color _hoveredItemColor; private Color _hoveredItemBackColor; private Color _disabledForeColor; private Color _disabledBackColor; private Color _borderColor; #endregion Internal Vars #region Constructors public MetroListBox() { SetStyle ( ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.Selectable | ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer | ControlStyles.SupportsTransparentBackColor, true ); UpdateStyles(); base.BackColor = Color.Transparent; base.Font = MetroFonts.Light(10); _utl = new Utilites(); ApplyTheme(); SetDefaults(); } private void SetDefaults() { SelectedIndex = -1; _hoveredItem = -1; _showScrollBar = false; Items = new MetroItemCollection(); Items.ItemUpdated += InvalidateScroll; SelectedItems = new List(); _indicates = new List(); ItemHeight = 30; _multiKeyDown = false; _svs = new MetroScrollBar() { Orientation = ScrollOrientate.Vertical, Size = new(12, Height), Maximum = Items.Count * ItemHeight, SmallChange = 1, LargeChange = 5 }; _svs.Scroll += HandleScroll; _svs.MouseDown += VS_MouseDown; _svs.BackColor = Color.Transparent; if (!Controls.Contains(_svs)) { Controls.Add(_svs); } } #endregion Constructors #region ApplyTheme private void ApplyTheme(Style style = Style.Light) { if (!IsDerivedStyle) { return; } switch (style) { case Style.Light: ForeColor = Color.Black; BackColor = Color.White; SelectedItemBackColor = Color.FromArgb(65, 177, 225); SelectedItemColor = Color.White; HoveredItemColor = Color.DimGray; HoveredItemBackColor = Color.LightGray; DisabledBackColor = Color.FromArgb(204, 204, 204); DisabledForeColor = Color.FromArgb(136, 136, 136); BorderColor = Color.LightGray; ThemeAuthor = "Taiizor"; ThemeName = "MetroLight"; UpdateProperties(); break; case Style.Dark: ForeColor = Color.FromArgb(170, 170, 170); BackColor = Color.FromArgb(30, 30, 30); SelectedItemBackColor = Color.FromArgb(65, 177, 225); SelectedItemColor = Color.White; HoveredItemColor = Color.DimGray; HoveredItemBackColor = Color.LightGray; DisabledBackColor = Color.FromArgb(80, 80, 80); DisabledForeColor = Color.FromArgb(109, 109, 109); BorderColor = Color.FromArgb(64, 64, 64); ThemeAuthor = "Taiizor"; ThemeName = "MetroDark"; UpdateProperties(); break; case Style.Custom: if (StyleManager != null) { foreach (KeyValuePair varkey in StyleManager.ListBoxDictionary) { switch (varkey.Key) { case "ForeColor": ForeColor = _utl.HexColor((string)varkey.Value); break; case "BackColor": BackColor = _utl.HexColor((string)varkey.Value); break; case "DisabledBackColor": DisabledBackColor = _utl.HexColor((string)varkey.Value); break; case "DisabledForeColor": DisabledForeColor = _utl.HexColor((string)varkey.Value); break; case "HoveredItemBackColor": HoveredItemBackColor = _utl.HexColor((string)varkey.Value); break; case "HoveredItemColor": HoveredItemColor = _utl.HexColor((string)varkey.Value); break; case "SelectedItemBackColor": SelectedItemBackColor = _utl.HexColor((string)varkey.Value); break; case "SelectedItemColor": SelectedItemColor = _utl.HexColor((string)varkey.Value); break; case "BorderColor": BorderColor = _utl.HexColor((string)varkey.Value); break; default: return; } } } UpdateProperties(); break; default: throw new ArgumentOutOfRangeException(nameof(style), style, null); } } private void UpdateProperties() { Invalidate(); } #endregion ApplyTheme #region Draw Control protected override void OnPaint(PaintEventArgs e) { Graphics g = e.Graphics; g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; Rectangle mainRect = new(0, 0, Width - (ShowBorder ? 1 : 0), Height - (ShowBorder ? 1 : 0)); using SolidBrush bg = new(Enabled ? BackColor : DisabledBackColor); using SolidBrush usic = new(Enabled ? ForeColor : DisabledForeColor); using SolidBrush sic = new(SelectedItemColor); using SolidBrush sibc = new(SelectedItemBackColor); using SolidBrush hic = new(HoveredItemColor); using SolidBrush hibc = new(HoveredItemBackColor); using StringFormat sf = new() { Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Center }; int firstItem = _svs.Value / ItemHeight < 0 ? 0 : _svs.Value / ItemHeight; int lastItem = (_svs.Value / ItemHeight) + (Height / ItemHeight) + 1 > Items.Count ? Items.Count : (_svs.Value / ItemHeight) + (Height / ItemHeight) + 1; g.FillRectangle(bg, mainRect); for (int i = firstItem; i < lastItem; i++) { string itemText = (string)Items[i]; Rectangle rect = new(5, (i - firstItem) * ItemHeight, Width - 1, ItemHeight); g.DrawString(itemText, Font, usic, rect, sf); if (MultiSelect && _indicates.Count != 0) { if (i == _hoveredItem && !_indicates.Contains(i)) { g.FillRectangle(hibc, rect); g.DrawString(itemText, Font, hic, rect, sf); } else if (_indicates.Contains(i)) { g.FillRectangle(sibc, rect); g.DrawString(itemText, Font, sic, rect, sf); } } else { if (i == _hoveredItem && i != SelectedIndex) { g.FillRectangle(hibc, rect); g.DrawString(itemText, Font, hic, rect, sf); } else if (i == SelectedIndex) { g.FillRectangle(sibc, rect); g.DrawString(itemText, Font, sic, rect, sf); } } } if (ShowBorder) { g.DrawRectangle(Pens.LightGray, mainRect); } } #endregion Draw Control #region Properties [TypeConverter(typeof(CollectionConverter))] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] [Editor("System.Windows.Forms.Design.StringCollectionEditor, System.Design", "System.Drawing.Design.UITypeEditor, System.Drawing")] [Category("Metro"), Description("Gets the items of the ListBox.")] public MetroItemCollection Items { get; private set; } [Browsable(false)] [Category("Metro"), Description("Gets a collection containing the currently selected items in the ListBox.")] public List SelectedItems { get; private set; } [Category("Metro"), Description("Gets or sets the height of an item in the ListBox.")] public int ItemHeight { get => _itemHeight; set { _itemHeight = value; Refresh(); } } [Browsable(false), Category("Metro"), Description("Gets or sets the currently selected item in the ListBox.")] public object SelectedItem { get => _selectedItem; set { _selectedItem = value; Invalidate(); } } [Browsable(false), Category("Metro"), Description("Gets or sets the currently selected Text in the ListBox.")] public string SelectedText { get => _selectedText; set { _selectedText = value; Invalidate(); } } [Browsable(false), Category("Metro"), Description("Gets or sets the zero-based index of the currently selected item in a ListBox.")] public int SelectedIndex { get => _selectedIndex; set { _selectedIndex = value; Invalidate(); } } [Browsable(true), Category("Metro"), Description("Gets or sets the value of the member property specified by the ValueMember property.")] public object SelectedValue { get => _selectedValue; set { _selectedValue = value; Invalidate(); } } [Category("Metro"), Description("Gets or sets a value indicating whether the ListBox supports multiple rows.")] public bool MultiSelect { get => _multiSelect; set { _multiSelect = value; if (SelectedItems.Count > 1) { SelectedItems.RemoveRange(1, SelectedItems.Count - 1); } Invalidate(); } } [Browsable(false)] public int Count => Items.Count; [Category("Metro"), Description("Gets or sets a value indicating whether the vertical scroll bar be shown or not.")] public bool ShowScrollBar { get => _showScrollBar; set { _showScrollBar = value; _svs.Visible = value; Invalidate(); } } [Category("Metro"), Description("Gets or sets a value indicating whether the border shown or not.")] public bool ShowBorder { get => _showBorder; set { _showBorder = value; Refresh(); } } [Category("Metro"), Description("Gets or sets backcolor used by the control.")] public override Color BackColor { get; set; } [Category("Metro"), Description("Gets or sets forecolor used by the control.")] public override Color ForeColor { get; set; } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] public override string Text { get => base.Text; set => base.Text = value; } [Category("Metro"), Description("Gets or sets selected item used by the control.")] public Color SelectedItemColor { get => _selectedItemColor; set { _selectedItemColor = value; Refresh(); } } [Category("Metro"), Description("Gets or sets selected item backcolor used by the control.")] public Color SelectedItemBackColor { get => _selectedItemBackColor; set { _selectedItemBackColor = value; Refresh(); } } [Category("Metro"), Description("Gets or sets hovered item used by the control.")] public Color HoveredItemColor { get => _hoveredItemColor; set { _hoveredItemColor = value; Refresh(); } } [Category("Metro"), Description("Gets or sets hovered item backcolor used by the control.")] public Color HoveredItemBackColor { get => _hoveredItemBackColor; set { _hoveredItemBackColor = value; Refresh(); } } [Category("Metro"), Description("Gets or sets disabled forecolor used by the control.")] public Color DisabledForeColor { get => _disabledForeColor; set { _disabledForeColor = value; Refresh(); } } [Category("Metro"), Description("Gets or sets disabled backcolor used by the control.")] public Color DisabledBackColor { get => _disabledBackColor; set { _disabledBackColor = value; Refresh(); } } [Category("Metro"), Description("Gets or sets border color used by the control.")] public Color BorderColor { get => _borderColor; set { _borderColor = value; Refresh(); } } [Category("Metro")] [Description("Gets or sets the whether this control reflect to parent(s) style. \n " + "Set it to false if you want the style of this control be independent. ")] public bool IsDerivedStyle { get => _isDerivedStyle; set { _isDerivedStyle = value; Refresh(); } } #endregion Properties #region Methods public void AddItem(string newItem) { Items.Add(newItem); InvalidateScroll(this, null); } public void AddItems(string[] newItems) { foreach (string str in newItems) { AddItem(str); } InvalidateScroll(this, null); } public void RemoveItemAt(int index) { Items.RemoveAt(index); InvalidateScroll(this, null); } public void RemoveItem(string item) { Items.Remove(item); InvalidateScroll(this, null); } public int IndexOf(string value) { return Items.IndexOf(value); } public bool Contains(object item) { return Items.Contains(item.ToString()); } public void RemoveItems(string[] itemsToRemove) { foreach (string item in itemsToRemove) { Items.Remove(item); } InvalidateScroll(this, null); } public void Clear() { for (int i = Items.Count - 1; i >= 0; i += -1) { Items.RemoveAt(i); } InvalidateScroll(this, null); } #endregion Methods #region Events public event SelectedIndexChangedEventHandler SelectedIndexChanged; public delegate void SelectedIndexChangedEventHandler(object sender); public event SelectedValueEventHandler SelectedValueChanged; public delegate void SelectedValueEventHandler(object sender); protected override void OnSizeChanged(EventArgs e) { InvalidateScroll(this, e); InvalidateLayout(); base.OnSizeChanged(e); } protected override void OnMouseDown(MouseEventArgs e) { Focus(); if (e.Button == MouseButtons.Left) { int index = (_svs.Value / ItemHeight) + (e.Location.Y / ItemHeight); if (index >= 0 && index < Items.Count) { if (MultiSelect && _multiKeyDown) { _indicates.Add(index); SelectedItems.Add(Items[index]); } else { _indicates.Clear(); SelectedItems.Clear(); _selectedItem = Items[index]; _selectedIndex = index; _selectedValue = Items[index]; _selectedText = Items[index].ToString(); SelectedIndexChanged?.Invoke(this); SelectedValueChanged?.Invoke(this); } } Invalidate(); } base.OnMouseDown(e); } private void HandleScroll(object sender) { Invalidate(); } private void InvalidateScroll(object sender, EventArgs e) { _svs.Maximum = Items.Count * ItemHeight; Invalidate(); } private void VS_MouseDown(object sender, MouseEventArgs e) { Focus(); } private void InvalidateLayout() { _svs.Size = new(12, Height - (ShowBorder ? 2 : 0)); _svs.Location = new(Width - (_svs.Width + (ShowBorder ? 2 : 0)), ShowBorder ? 1 : 0); Invalidate(); } protected override void OnMouseWheel(MouseEventArgs e) { _svs.Value -= e.Delta / 4; base.OnMouseWheel(e); } protected override bool IsInputKey(Keys keyData) { switch (keyData) { case Keys.Down: try { SelectedItems.Remove(Items[SelectedIndex]); SelectedIndex += 1; SelectedItems.Add(Items[SelectedIndex]); } catch { // } break; case Keys.Up: try { SelectedItems.Remove(Items[SelectedIndex]); SelectedIndex -= 1; SelectedItems.Add(Items[SelectedIndex]); } catch { // } break; } Invalidate(); return base.IsInputKey(keyData); } protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); Cursor = Cursors.Hand; int index = (_svs.Value / ItemHeight) + (e.Location.Y / ItemHeight); if (index >= Items.Count) { index = -1; } if (index >= 0 && index < Items.Count) { _hoveredItem = index; } Invalidate(); } protected override void OnMouseLeave(EventArgs e) { _hoveredItem = -1; Cursor = Cursors.Default; Invalidate(); base.OnMouseLeave(e); } protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); _svs.Location = new(Width - (_svs.Width + (ShowBorder ? 2 : 0)), ShowBorder ? 1 : 0); InvalidateScroll(this, e); } protected override void WndProc(ref Message m) { if (m.Msg == User32.WM_SETCURSOR) { User32.SetCursor(User32.LoadCursor(IntPtr.Zero, User32.IDC_HAND)); m.Result = IntPtr.Zero; return; } base.WndProc(ref m); } #endregion Events } #endregion }