using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text.RegularExpressions; using Gwen.Control.Layout; namespace Gwen.Control { /// /// ListBox control. /// public class ListBox : ScrollControl { private readonly Table m_Table; private readonly List m_SelectedRows; private bool m_MultiSelect; private bool m_IsToggle; private bool m_SizeToContents; private Pos m_OldDock; // used while autosizing /// /// Determines whether multiple rows can be selected at once. /// public bool AllowMultiSelect { get { return m_MultiSelect; } set { m_MultiSelect = value; if (value) IsToggle = true; } } /// /// Determines whether rows can be unselected by clicking on them again. /// public bool IsToggle { get { return m_IsToggle; } set { m_IsToggle = value; } } /// /// Number of rows in the list box. /// public int RowCount { get { return m_Table.RowCount; } } /// /// Returns specific row of the ListBox. /// /// Row index. /// Row at the specified index. public ListBoxRow this[int index] { get { return m_Table[index] as ListBoxRow; } } /// /// List of selected rows. /// public IEnumerable SelectedRows { get { return m_SelectedRows; } } /// /// First selected row (and only if list is not multiselectable). /// public TableRow SelectedRow { get { if (m_SelectedRows.Count == 0) return null; return m_SelectedRows[0]; } } /// /// Gets the selected row number. /// public int SelectedRowIndex { get { var selected = SelectedRow; if (selected == null) return -1; return m_Table.GetRowIndex(selected); } } /// /// Column count of table rows. /// public int ColumnCount { get { return m_Table.ColumnCount; } set { m_Table.ColumnCount = value; Invalidate(); } } /// /// Invoked when a row has been selected. /// public event GwenEventHandler RowSelected; /// /// Invoked whan a row has beed unselected. /// public event GwenEventHandler RowUnselected; /// /// Initializes a new instance of the class. /// /// Parent control. public ListBox(Base parent) : base(parent) { m_SelectedRows = new List(); EnableScroll(false, true); AutoHideBars = true; Margin = Margin.One; m_Table = new Table(this); m_Table.Dock = Pos.Fill; m_Table.ColumnCount = 1; m_Table.BoundsChanged += TableResized; m_MultiSelect = false; m_IsToggle = false; } /// /// Selects the specified row by index. /// /// Row to select. /// Determines whether to deselect previously selected rows. public void SelectRow(int index, bool clearOthers = false) { if (index < 0 || index >= m_Table.RowCount) return; SelectRow(m_Table.Children[index], clearOthers); } /// /// Selects the specified row(s) by text. /// /// Text to search for (exact match). /// Determines whether to deselect previously selected rows. public void SelectRows(String rowText, bool clearOthers = false) { var rows = m_Table.Children.OfType().Where(x => x.Text == rowText); foreach (ListBoxRow row in rows) { SelectRow(row, clearOthers); } } /// /// Selects the specified row(s) by regex text search. /// /// Regex pattern to search for. /// Regex options. /// Determines whether to deselect previously selected rows. public void SelectRowsByRegex(String pattern, RegexOptions regexOptions = RegexOptions.None, bool clearOthers = false) { var rows = m_Table.Children.OfType().Where(x => Regex.IsMatch(x.Text, pattern) ); foreach (ListBoxRow row in rows) { SelectRow(row, clearOthers); } } /// /// Slelects the specified row. /// /// Row to select. /// Determines whether to deselect previously selected rows. public void SelectRow(Base control, bool clearOthers = false) { if (!AllowMultiSelect || clearOthers) UnselectAll(); ListBoxRow row = control as ListBoxRow; if (row == null) return; // TODO: make sure this is one of our rows! row.IsSelected = true; m_SelectedRows.Add(row); if (RowSelected != null) RowSelected.Invoke(this); } /// /// Removes the specified row by index. /// /// Row index. public void RemoveRow(int idx) { m_Table.RemoveRow(idx); // this calls Dispose() } /// /// Adds a new row. /// /// Row text. /// Newly created control. public TableRow AddRow(String label) { return AddRow(label, String.Empty); } /// /// Adds a new row. /// /// Row text. /// Internal control name. /// Newly created control. public TableRow AddRow(String label, String name) { ListBoxRow row = new ListBoxRow(this); m_Table.AddRow(row); row.SetCellText(0, label); row.Name = name; row.Selected += OnRowSelected; m_Table.SizeToContents(Width); return row; } /// /// Sets the column width (in pixels). /// /// Column index. /// Column width. public void SetColumnWidth(int column, int width) { m_Table.SetColumnWidth(column, width); Invalidate(); } /// /// Renders the control using specified skin. /// /// Skin to use. protected override void Render(Skin.Base skin) { skin.DrawListBox(this); } /// /// Deselects all rows. /// public virtual void UnselectAll() { foreach (ListBoxRow row in m_SelectedRows) { row.IsSelected = false; if (RowUnselected != null) RowUnselected.Invoke(this); } m_SelectedRows.Clear(); } /// /// Unselects the specified row. /// /// Row to unselect. public void UnselectRow(ListBoxRow row) { row.IsSelected = false; m_SelectedRows.Remove(row); if (RowUnselected != null) RowUnselected.Invoke(this); } /// /// Handler for the row selection event. /// /// Event source. protected virtual void OnRowSelected(Base control) { // [omeg] changed default behavior bool clear = false;// !InputHandler.InputHandler.IsShiftDown; ListBoxRow row = control as ListBoxRow; if (row == null) return; if (row.IsSelected) { if (IsToggle) UnselectRow(row); } else { SelectRow(control, clear); } } /// /// Removes all rows. /// public virtual void Clear() { UnselectAll(); m_Table.RemoveAll(); } public void SizeToContents() { m_SizeToContents = true; // docking interferes with autosizing so we disable it until sizing is done m_OldDock = m_Table.Dock; m_Table.Dock = Pos.None; m_Table.SizeToContents(0); // autosize without constraints } private void TableResized(Base control) { if (m_SizeToContents) { SetSize(m_Table.Width, m_Table.Height); m_SizeToContents = false; m_Table.Dock = m_OldDock; Invalidate(); } } } }