using System;
using System.Data;
using System.Linq;
using System.Text;
namespace Terminal.Gui {
///
/// for a which adds a
/// checkbox column as an additional column in the table.
///
/// This class wraps another and dynamically
/// serves its rows/cols plus an extra column. Data in the wrapped source can be
/// dynamic (change over time).
public abstract class CheckBoxTableSourceWrapperBase : ITableSource {
private readonly TableView tableView;
///
/// Creates a new instance of the class presenting the data in
/// plus an additional checkbox column.
///
/// The this source will be used with.
/// This is required for event registration.
/// The original data source of the that you
/// want to add checkboxes to.
public CheckBoxTableSourceWrapperBase (TableView tableView, ITableSource toWrap)
{
this.Wrapping = toWrap;
this.tableView = tableView;
tableView.AddKeyBinding (Key.Space, Command.ToggleChecked);
tableView.MouseClick += TableView_MouseClick;
tableView.CellToggled += TableView_CellToggled;
}
///
/// Gets or sets the character to use for checked entries. Defaults to
///
public Rune CheckedRune { get; set; } = CM.Glyphs.Checked;
///
/// Gets or sets the character to use for UnChecked entries. Defaults to
///
public Rune UnCheckedRune { get; set; } = CM.Glyphs.UnChecked;
///
/// Gets or sets whether to only allow a single row to be toggled at once (Radio button).
///
public bool UseRadioButtons { get; set; }
///
/// Gets or sets the character to use for checked entry when is true.
/// Defaults to
///
public Rune RadioCheckedRune { get; set; } = CM.Glyphs.Selected;
///
/// Gets or sets the character to use for unchecked entries when is true.
/// Defaults to
///
public Rune RadioUnCheckedRune { get; set; } = CM.Glyphs.UnSelected;
///
/// Gets the that this instance is wrapping.
///
public ITableSource Wrapping { get; }
///
public object this [int row, int col] {
get {
if (col == 0) {
if(UseRadioButtons) {
return IsChecked (row) ? RadioCheckedRune : RadioUnCheckedRune;
}
return IsChecked(row) ? CheckedRune : UnCheckedRune;
}
return Wrapping [row, col - 1];
}
}
///
public int Rows => Wrapping.Rows;
///
public int Columns => Wrapping.Columns + 1;
///
public string [] ColumnNames {
get {
var toReturn = Wrapping.ColumnNames.ToList ();
toReturn.Insert (0, " ");
return toReturn.ToArray ();
}
}
private void TableView_MouseClick (object sender, MouseEventEventArgs e)
{
// we only care about clicks (not movements)
if(!e.MouseEvent.Flags.HasFlag(MouseFlags.Button1Clicked)) {
return;
}
var hit = tableView.ScreenToCell (e.MouseEvent.X,e.MouseEvent.Y, out int? headerIfAny);
if(headerIfAny.HasValue && headerIfAny.Value == 0) {
// clicking in header with radio buttons does nothing
if(UseRadioButtons) {
return;
}
// otherwise it ticks all rows
ToggleAllRows ();
e.Handled = true;
tableView.SetNeedsDisplay ();
}
else
if(hit.HasValue && hit.Value.X == 0) {
if(UseRadioButtons) {
ClearAllToggles ();
ToggleRow (hit.Value.Y);
} else {
ToggleRow (hit.Value.Y);
}
e.Handled = true;
tableView.SetNeedsDisplay ();
}
}
private void TableView_CellToggled (object sender, CellToggledEventArgs e)
{
// Suppress default toggle behavior when using checkboxes
// and instead handle ourselves
var range = tableView.GetAllSelectedCells ().Select (c => c.Y).Distinct ().ToArray();
if(UseRadioButtons) {
// multi selection makes it unclear what to toggle in this situation
if(range.Length != 1) {
e.Cancel = true;
return;
}
ClearAllToggles ();
ToggleRow (range.Single ());
}
else {
ToggleRows (range);
}
e.Cancel = true;
tableView.SetNeedsDisplay ();
}
///
/// Returns true if is checked.
///
///
///
protected abstract bool IsChecked (int row);
///
/// Flips the checked state for a collection of rows. If
/// some (but not all) are selected they should flip to all
/// selected.
///
///
protected abstract void ToggleRows (int [] range);
///
/// Flips the checked state of the given /
///
///
protected abstract void ToggleRow (int row);
///
/// Called when the 'toggled all' action is performed.
/// This should change state from 'some selected' to
/// 'all selected' or clear selection if all area already
/// selected.
///
protected abstract void ToggleAllRows ();
///
/// Clears the toggled state of all rows.
///
protected abstract void ClearAllToggles ();
}
}