using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Windows.Forms.VisualStyles; namespace ScoutBase.Core { public class ListViewExtender : IDisposable { private readonly Dictionary _columns = new Dictionary(); public ListViewExtender(ListView listView) { if (listView == null) throw new ArgumentNullException("listView"); if (listView.View != View.Details) throw new ArgumentException(null, "listView"); ListView = listView; ListView.OwnerDraw = true; ListView.DrawItem += OnDrawItem; ListView.DrawSubItem += OnDrawSubItem; ListView.DrawColumnHeader += OnDrawColumnHeader; ListView.MouseMove += OnMouseMove; ListView.MouseClick += OnMouseClick; Font = new Font(ListView.Font.FontFamily, ListView.Font.Size - 2); } public virtual Font Font { get; private set; } public ListView ListView { get; private set; } protected virtual void OnMouseClick(object sender, MouseEventArgs e) { ListViewItem item; ListViewItem.ListViewSubItem sub; ListViewColumn column = GetColumnAt(e.X, e.Y, out item, out sub); if (column != null) { column.MouseClick(e, item, sub); } } public ListViewColumn GetColumnAt(int x, int y, out ListViewItem item, out ListViewItem.ListViewSubItem subItem) { subItem = null; item = ListView.GetItemAt(x, y); if (item == null) return null; subItem = item.GetSubItemAt(x, y); if (subItem == null) return null; for (int i = 0; i < item.SubItems.Count; i++) { if (item.SubItems[i] == subItem) return GetColumn(i); } return null; } protected virtual void OnMouseMove(object sender, MouseEventArgs e) { ListViewItem item; ListViewItem.ListViewSubItem sub; ListViewColumn column = GetColumnAt(e.X, e.Y, out item, out sub); if (column != null) { column.Invalidate(item, sub); return; } if (item != null) { ListView.Invalidate(item.Bounds); } } protected virtual void OnDrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e) { e.DrawDefault = true; } protected virtual void OnDrawSubItem(object sender, DrawListViewSubItemEventArgs e) { ListViewColumn column = GetColumn(e.ColumnIndex); if (column == null) { e.DrawDefault = true; return; } column.Draw(e); } protected virtual void OnDrawItem(object sender, DrawListViewItemEventArgs e) { // do nothing } public void AddColumn(ListViewColumn column) { if (column == null) throw new ArgumentNullException("column"); column.Extender = this; _columns[column.ColumnIndex] = column; } public ListViewColumn GetColumn(int index) { ListViewColumn column; return _columns.TryGetValue(index, out column) ? column : null; } public IEnumerable Columns { get { return _columns.Values; } } public virtual void Dispose() { if (Font != null) { Font.Dispose(); Font = null; } } } public abstract class ListViewColumn { public event EventHandler Click; protected ListViewColumn(int columnIndex) { if (columnIndex < 0) throw new ArgumentException(null, "columnIndex"); ColumnIndex = columnIndex; } public virtual ListViewExtender Extender { get; protected internal set; } public int ColumnIndex { get; private set; } public virtual Font Font { get { return Extender == null ? null : Extender.Font; } } public ListView ListView { get { return Extender == null ? null : Extender.ListView; } } public abstract void Draw(DrawListViewSubItemEventArgs e); public virtual void MouseClick(MouseEventArgs e, ListViewItem item, ListViewItem.ListViewSubItem subItem) { if (Click != null) { Click(this, new ListViewColumnMouseEventArgs(e, item, subItem)); } } public virtual void Invalidate(ListViewItem item, ListViewItem.ListViewSubItem subItem) { if (Extender != null) { Extender.ListView.Invalidate(subItem.Bounds); } } } public class ListViewColumnMouseEventArgs : MouseEventArgs { public ListViewColumnMouseEventArgs(MouseEventArgs e, ListViewItem item, ListViewItem.ListViewSubItem subItem) : base(e.Button, e.Clicks, e.X, e.Y, e.Delta) { Item = item; SubItem = subItem; } public ListViewItem Item { get; private set; } public ListViewItem.ListViewSubItem SubItem { get; private set; } } public class ListViewButtonColumn : ListViewColumn { private Rectangle _hot = Rectangle.Empty; public ListViewButtonColumn(int columnIndex) : base(columnIndex) { } public bool FixedWidth { get; set; } public bool DrawIfEmpty { get; set; } public override ListViewExtender Extender { get { return base.Extender; } protected internal set { base.Extender = value; if (FixedWidth) { base.Extender.ListView.ColumnWidthChanging += OnColumnWidthChanging; } } } protected virtual void OnColumnWidthChanging(object sender, ColumnWidthChangingEventArgs e) { if (e.ColumnIndex == ColumnIndex) { e.Cancel = true; e.NewWidth = ListView.Columns[e.ColumnIndex].Width; } } public override void Draw(DrawListViewSubItemEventArgs e) { if (_hot != Rectangle.Empty) { if (_hot != e.Bounds) { ListView.Invalidate(_hot); _hot = Rectangle.Empty; } } if ((!DrawIfEmpty) && (string.IsNullOrEmpty(e.SubItem.Text))) return; Point mouse = e.Item.ListView.PointToClient(Control.MousePosition); if ((ListView.GetItemAt(mouse.X, mouse.Y) == e.Item) && (e.Item.GetSubItemAt(mouse.X, mouse.Y) == e.SubItem)) { ButtonRenderer.DrawButton(e.Graphics, e.Bounds, e.SubItem.Text, Font, true, PushButtonState.Hot); _hot = e.Bounds; } else { ButtonRenderer.DrawButton(e.Graphics, e.Bounds, e.SubItem.Text, Font, false, PushButtonState.Default); } } } }