2014-08-06 01:32:27 +00:00
using System ;
2014-10-14 13:17:02 +00:00
using System.Collections ;
2014-08-06 01:32:27 +00:00
using System.Collections.Generic ;
2014-08-07 14:55:55 +00:00
using System.ComponentModel ;
using System.Drawing ;
2014-08-06 01:32:27 +00:00
using System.Linq ;
using System.Windows.Forms ;
2014-10-14 13:17:02 +00:00
using BizHawk.Client.Common ;
2014-08-07 18:32:09 +00:00
using BizHawk.Client.EmuHawk.CustomControls ;
2014-08-06 01:32:27 +00:00
namespace BizHawk.Client.EmuHawk
{
2014-08-30 18:42:14 +00:00
//Row width depends on font size and padding
//Column width is specified in column headers
//Row width is specified for horizontal orientation
2014-08-06 01:32:27 +00:00
public class InputRoll : Control
{
2014-08-09 13:13:24 +00:00
private readonly GDIRenderer Gdi ;
2014-10-14 13:17:02 +00:00
private RollColumns _columns = new RollColumns ( ) ;
2014-08-12 11:07:21 +00:00
private readonly List < Cell > SelectedItems = new List < Cell > ( ) ;
2014-08-09 13:13:24 +00:00
2014-08-18 21:38:02 +00:00
private readonly VScrollBar VBar ;
2014-08-15 00:42:03 +00:00
2014-08-18 21:38:02 +00:00
private readonly HScrollBar HBar ;
2014-08-15 00:42:03 +00:00
2014-08-30 18:42:14 +00:00
private bool _horizontalOrientation = false ;
2014-08-31 15:40:02 +00:00
private bool _programmaticallyUpdatingScrollBarValues = false ;
2014-09-01 15:35:48 +00:00
private int _maxCharactersInHorizontal = 1 ;
2014-08-30 18:42:14 +00:00
private int _rowCount = 0 ;
2014-08-09 16:11:25 +00:00
private Size _charSize ;
2014-08-09 13:13:24 +00:00
2014-08-06 01:32:27 +00:00
public InputRoll ( )
{
2014-08-18 21:38:02 +00:00
2014-08-24 14:31:25 +00:00
UseCustomBackground = true ;
2014-08-23 14:30:12 +00:00
GridLines = true ;
2014-09-24 21:10:57 +00:00
CellWidthPadding = 3 ;
CellHeightPadding = 1 ;
2014-08-10 22:23:14 +00:00
CurrentCell = null ;
Font = new Font ( "Courier New" , 8 ) ; // Only support fixed width
2014-08-06 01:32:27 +00:00
SetStyle ( ControlStyles . AllPaintingInWmPaint , true ) ;
2014-08-10 18:49:17 +00:00
SetStyle ( ControlStyles . UserPaint , true ) ;
2014-08-07 21:52:22 +00:00
SetStyle ( ControlStyles . SupportsTransparentBackColor , true ) ;
2014-08-08 13:36:37 +00:00
SetStyle ( ControlStyles . Opaque , true ) ;
2014-08-08 13:42:05 +00:00
2014-08-10 18:49:17 +00:00
Gdi = new GDIRenderer ( ) ;
using ( var g = CreateGraphics ( ) )
2014-08-10 22:23:14 +00:00
using ( var LCK = Gdi . LockGraphics ( g ) )
{
2014-10-13 18:28:29 +00:00
_charSize = Gdi . MeasureString ( "A" , this . Font ) ; // TODO make this a property so changing it updates other values.
2014-08-10 22:23:14 +00:00
}
2014-08-18 21:38:02 +00:00
2014-08-31 23:03:59 +00:00
UpdateCellSize ( ) ;
ColumnWidth = CellWidth ;
2014-09-22 15:33:04 +00:00
ColumnHeight = CellHeight + 2 ;
2014-08-31 23:03:59 +00:00
2014-10-14 00:20:34 +00:00
var width = new VScrollBar ( ) . Width ;
2014-08-31 17:11:47 +00:00
VBar = new VScrollBar
{
2014-10-14 00:20:34 +00:00
Location = new Point ( Width - width , 0 ) ,
2014-08-31 17:11:47 +00:00
Visible = false ,
Anchor = AnchorStyles . Top | AnchorStyles . Right | AnchorStyles . Bottom ,
SmallChange = CellHeight ,
LargeChange = CellHeight * 20
} ;
2014-10-14 00:20:34 +00:00
var height = new HScrollBar ( ) . Height ;
2014-08-31 17:11:47 +00:00
HBar = new HScrollBar
{
2014-10-14 00:20:34 +00:00
Location = new Point ( 0 , Height - height ) ,
2014-08-31 17:11:47 +00:00
Visible = false ,
Anchor = AnchorStyles . Bottom | AnchorStyles . Left | AnchorStyles . Right ,
SmallChange = 1 ,
LargeChange = 20
} ;
2014-08-18 21:38:02 +00:00
this . Controls . Add ( VBar ) ;
this . Controls . Add ( HBar ) ;
2014-08-19 00:37:38 +00:00
VBar . ValueChanged + = VerticalBar_ValueChanged ;
HBar . ValueChanged + = HorizontalBar_ValueChanged ;
2014-08-30 18:42:14 +00:00
HorizontalOrientation = false ;
2014-08-18 21:38:02 +00:00
RecalculateScrollBars ( ) ;
2014-08-23 13:14:25 +00:00
_columns . ChangedCallback = ColumnChangedCallback ;
2014-08-06 01:32:27 +00:00
}
2014-08-07 14:55:55 +00:00
2014-08-09 17:15:05 +00:00
protected override void Dispose ( bool disposing )
{
Gdi . Dispose ( ) ;
base . Dispose ( disposing ) ;
}
2014-08-07 14:55:55 +00:00
#region Properties
2014-08-07 18:32:09 +00:00
/// <summary>
2014-09-24 21:10:57 +00:00
/// Gets or sets the amount of left and right padding on the text inside a cell
2014-08-07 18:32:09 +00:00
/// </summary>
[DefaultValue(3)]
2014-08-10 22:23:14 +00:00
[Category("Behavior")]
2014-09-24 21:10:57 +00:00
public int CellWidthPadding { get ; set ; }
/// <summary>
/// Gets or sets the amount of top and bottom padding on the text inside a cell
/// </summary>
[DefaultValue(1)]
[Category("Behavior")]
public int CellHeightPadding { get ; set ; }
2014-08-07 18:32:09 +00:00
2014-08-23 14:30:12 +00:00
/// <summary>
/// Displays grid lines around cells
/// </summary>
[Category("Appearance")]
[DefaultValue(true)]
public bool GridLines { get ; set ; }
2014-08-07 14:55:55 +00:00
/// <summary>
/// Gets or sets whether the control is horizontal or vertical
/// </summary>
[Category("Behavior")]
2014-08-30 18:42:14 +00:00
public bool HorizontalOrientation {
get {
return _horizontalOrientation ;
}
set
{
if ( _horizontalOrientation ! = value )
{
_horizontalOrientation = value ;
OrientationChanged ( ) ;
}
}
}
2014-08-07 14:55:55 +00:00
/// <summary>
2014-08-31 17:11:47 +00:00
/// Gets or sets the sets the virtual number of rows to be displayed. Does not include the column header row.
2014-08-07 14:55:55 +00:00
/// </summary>
[Category("Behavior")]
2014-08-30 18:42:14 +00:00
public int RowCount
2014-08-18 21:38:02 +00:00
{
get
{
2014-08-30 18:42:14 +00:00
return _rowCount ;
2014-08-18 21:38:02 +00:00
}
set
{
2014-08-30 18:42:14 +00:00
_rowCount = value ;
2014-08-18 21:38:02 +00:00
RecalculateScrollBars ( ) ;
}
}
2014-08-07 14:55:55 +00:00
/// <summary>
/// Gets or sets the sets the columns can be resized
/// </summary>
[Category("Behavior")]
public bool AllowColumnResize { get ; set ; }
/// <summary>
/// Gets or sets the sets the columns can be reordered
/// </summary>
[Category("Behavior")]
public bool AllowColumnReorder { get ; set ; }
2014-08-11 11:11:51 +00:00
/// <summary>
/// Indicates whether the entire row will always be selected
/// </summary>
[Category("Appearance")]
2014-08-14 23:10:56 +00:00
[DefaultValue(false)]
2014-08-11 11:11:51 +00:00
public bool FullRowSelect { get ; set ; }
2014-08-14 23:10:56 +00:00
/// <summary>
/// Allows multiple items to be selected
/// </summary>
[Category("Behavior")]
[DefaultValue(true)]
public bool MultiSelect { get ; set ; }
2014-08-23 13:05:28 +00:00
/// <summary>
/// Gets or sets whether or not the control is in input painting mode
/// </summary>
[Category("Behavior")]
[DefaultValue(false)]
public bool InputPaintingMode { get ; set ; }
2014-08-23 13:19:48 +00:00
/// <summary>
2014-10-12 16:37:45 +00:00
/// All visible columns
2014-08-23 13:19:48 +00:00
/// </summary>
[Category("Behavior")]
2014-10-12 16:37:45 +00:00
public IEnumerable < RollColumn > VisibleColumns { get { return _columns . VisibleColumns ; } }
/// <summary>
/// Returns all columns including those that are not visible
/// </summary>
/// <returns></returns>
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
public RollColumns AllColumns { get { return _columns ; } }
2014-08-23 13:19:48 +00:00
2014-08-23 14:30:12 +00:00
public void SelectAll ( )
{
var oldFullRowVal = FullRowSelect ;
FullRowSelect = true ;
2014-08-30 18:42:14 +00:00
for ( int i = 0 ; i < RowCount ; i + + )
2014-08-23 14:30:12 +00:00
{
2014-08-31 15:40:02 +00:00
SelectRow ( i , true ) ;
2014-08-23 14:30:12 +00:00
}
FullRowSelect = oldFullRowVal ;
}
public void DeselectAll ( )
{
SelectedItems . Clear ( ) ;
}
2014-08-07 14:55:55 +00:00
#endregion
#region Event Handlers
/// <summary>
2014-09-03 03:16:16 +00:00
/// Fire the QueryItemText event which requests the text for the passed cell
2014-08-07 14:55:55 +00:00
/// </summary>
2014-08-10 22:23:14 +00:00
[Category("Virtual")]
public event QueryItemTextHandler QueryItemText ;
2014-08-07 14:55:55 +00:00
/// <summary>
2014-09-03 03:16:16 +00:00
/// Fire the QueryItemBkColor event which requests the background color for the passed cell
2014-08-07 14:55:55 +00:00
/// </summary>
2014-08-10 22:23:14 +00:00
[Category("Virtual")]
public event QueryItemBkColorHandler QueryItemBkColor ;
2014-08-07 14:55:55 +00:00
2014-09-03 03:16:16 +00:00
/// <summary>
/// Fire the QueryItemIconHandler event which requests an icon for a given cell
/// </summary>
[Category("Virtual")]
public event QueryItemIconHandler QueryItemIcon ;
2014-08-07 14:55:55 +00:00
/// <summary>
2014-08-10 22:23:14 +00:00
/// Fires when the mouse moves from one cell to another (including column header cells)
2014-08-07 14:55:55 +00:00
/// </summary>
2014-08-10 22:23:14 +00:00
[Category("Mouse")]
public event CellChangeEventHandler PointedCellChanged ;
2014-08-07 14:55:55 +00:00
2014-08-14 23:10:56 +00:00
/// <summary>
/// Occurs when a column header is clicked
/// </summary>
2014-08-11 01:49:45 +00:00
[Category("Action")]
2014-10-14 00:31:59 +00:00
public event ColumnClickEventHandler ColumnClick ;
2014-08-11 01:49:45 +00:00
2014-09-25 17:52:21 +00:00
/// <summary>
/// Occurs when a column header is right-clicked
/// </summary>
[Category("Action")]
2014-10-14 00:31:59 +00:00
public event ColumnClickEventHandler ColumnRightClick ;
2014-09-25 17:52:21 +00:00
2014-08-14 23:10:56 +00:00
/// <summary>
/// Occurs whenever the 'SelectedItems' property for this control changes
/// </summary>
[Category("Behavior")]
2014-08-23 14:36:55 +00:00
public event System . EventHandler SelectedIndexChanged ;
2014-08-14 23:10:56 +00:00
2014-08-23 13:05:28 +00:00
/// <summary>
/// Occurs whenever the mouse wheel is scrolled while the right mouse button is held
/// </summary>
[Category("Behavior")]
public event RightMouseScrollEventHandler RightMouseScrolled ;
2014-08-07 14:55:55 +00:00
/// <summary>
2014-08-10 22:23:14 +00:00
/// Retrieve the text for a cell
2014-08-07 14:55:55 +00:00
/// </summary>
2014-10-13 19:10:11 +00:00
public delegate void QueryItemTextHandler ( int index , RollColumn column , out string text ) ;
2014-08-10 22:23:14 +00:00
/// <summary>
/// Retrieve the background color for a cell
/// </summary>
2014-10-13 19:30:59 +00:00
public delegate void QueryItemBkColorHandler ( int index , RollColumn column , ref Color color ) ;
2014-08-10 22:23:14 +00:00
2014-09-03 03:16:16 +00:00
/// <summary>
/// Retrive the image for a given cell
/// </summary>
2014-10-13 19:30:59 +00:00
public delegate void QueryItemIconHandler ( int index , RollColumn column , ref Bitmap icon ) ;
2014-09-03 03:16:16 +00:00
2014-08-10 22:23:14 +00:00
public delegate void CellChangeEventHandler ( object sender , CellEventArgs e ) ;
2014-08-07 14:55:55 +00:00
2014-08-23 13:05:28 +00:00
public delegate void RightMouseScrollEventHandler ( object sender , MouseEventArgs e ) ;
2014-10-14 00:31:59 +00:00
public delegate void ColumnClickEventHandler ( object sender , ColumnClickEventArgs e ) ;
2014-08-10 15:57:59 +00:00
public class CellEventArgs
{
public CellEventArgs ( Cell oldCell , Cell newCell )
{
OldCell = oldCell ;
NewCell = newCell ;
}
public Cell OldCell { get ; private set ; }
public Cell NewCell { get ; private set ; }
}
2014-10-14 00:31:59 +00:00
public class ColumnClickEventArgs
{
public ColumnClickEventArgs ( RollColumn column )
{
Column = column ;
}
public RollColumn Column { get ; private set ; }
}
2014-08-07 14:55:55 +00:00
#endregion
2014-08-11 00:24:38 +00:00
#region Api
2014-08-07 14:55:55 +00:00
2014-08-31 15:40:02 +00:00
public void SelectRow ( int index , bool val )
2014-08-23 14:30:12 +00:00
{
2014-10-12 16:37:45 +00:00
if ( _columns . VisibleColumns . Any ( ) )
2014-08-23 14:30:12 +00:00
{
if ( val )
{
SelectCell ( new Cell
{
RowIndex = index ,
Column = _columns [ 0 ]
} ) ;
}
else
{
2014-08-30 18:42:14 +00:00
var items = SelectedItems . Where ( cell = > cell . RowIndex = = index ) ;
2014-08-23 14:30:12 +00:00
SelectedItems . RemoveAll ( x = > items . Contains ( x ) ) ;
}
}
}
2014-08-23 16:00:56 +00:00
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
public int? FirstSelectedIndex
{
get
{
2014-08-30 18:42:14 +00:00
if ( SelectedRows . Any ( ) )
2014-08-23 16:00:56 +00:00
{
2014-08-30 18:42:14 +00:00
return SelectedRows
2014-08-23 16:00:56 +00:00
. OrderBy ( x = > x )
. First ( ) ;
}
return null ;
}
}
2014-08-23 13:50:47 +00:00
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
public int? LastSelectedIndex
{
get
{
2014-08-30 18:42:14 +00:00
if ( SelectedRows . Any ( ) )
2014-08-23 13:50:47 +00:00
{
2014-08-30 18:42:14 +00:00
return SelectedRows
2014-08-23 13:50:47 +00:00
. OrderBy ( x = > x )
. Last ( ) ;
}
return null ;
}
}
2014-08-30 18:42:14 +00:00
/// <summary>
/// The current Cell that the mouse was in.
/// </summary>
2014-08-11 00:24:38 +00:00
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
2014-08-10 15:57:59 +00:00
public Cell CurrentCell { get ; set ; }
2014-08-30 18:42:14 +00:00
/// <summary>
/// The previous Cell that the mouse was in.
/// </summary>
2014-08-23 13:05:28 +00:00
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
public Cell LastCell { get ; set ; }
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
public bool IsPaintDown { get ; set ; }
2014-08-11 00:24:38 +00:00
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
public bool UseCustomBackground { get ; set ; }
2014-08-31 15:40:02 +00:00
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
public int DrawHeight { get ; private set ; }
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
public int DrawWidth { get ; private set ; }
2014-09-01 15:35:48 +00:00
/// <summary>
/// Sets the width of data cells when in Horizontal orientation.
/// </summary>
/// <param name="maxLength">The maximum number of characters the column will support in Horizontal orientation.</param>
2014-10-15 16:50:51 +00:00
public int MaxCharactersInHorizontal
{
2014-09-01 15:35:48 +00:00
get
{
return _maxCharactersInHorizontal ;
}
set
{
_maxCharactersInHorizontal = value ;
UpdateCellSize ( ) ;
}
}
2014-08-23 13:05:28 +00:00
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
public bool RightButtonHeld { get ; set ; }
2014-08-07 14:55:55 +00:00
public string UserSettingsSerialized ( )
{
2014-10-14 13:17:02 +00:00
// TODO: More than just columns
var settings = ConfigService . SaveWithType ( _columns ) ;
return settings ;
}
public void LoadSettingsSerialized ( string settingsJson )
{
//TODO: more than just columns
var settings = ConfigService . LoadWithType ( settingsJson ) ;
_columns = ( RollColumns ) settings ;
2014-08-07 14:55:55 +00:00
}
2014-08-23 13:50:47 +00:00
/// <summary>
2014-08-30 18:42:14 +00:00
/// Gets or sets the first visible row index, if scrolling is needed
2014-08-23 13:50:47 +00:00
/// </summary>
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
2014-08-30 18:42:14 +00:00
public int FirstVisibleRow
2014-08-23 13:50:47 +00:00
{
get
{
if ( HorizontalOrientation )
{
if ( NeedsHScrollbar )
{
2014-09-01 20:34:10 +00:00
return HBar . Value / CellWidth ;
2014-08-23 13:50:47 +00:00
}
}
if ( NeedsVScrollbar )
{
2014-08-31 17:11:47 +00:00
return VBar . Value / CellHeight ;
2014-08-23 13:50:47 +00:00
}
return 0 ;
}
set
{
if ( HorizontalOrientation )
{
if ( NeedsHScrollbar )
{
2014-08-27 22:33:27 +00:00
_programmaticallyUpdatingScrollBarValues = true ;
2014-09-01 20:34:10 +00:00
HBar . Value = value * CellWidth ;
2014-08-27 22:33:27 +00:00
_programmaticallyUpdatingScrollBarValues = false ;
2014-08-23 13:50:47 +00:00
}
}
2014-09-01 20:34:10 +00:00
else
2014-08-23 13:50:47 +00:00
{
2014-09-01 20:34:10 +00:00
if ( NeedsVScrollbar )
{
_programmaticallyUpdatingScrollBarValues = true ;
VBar . Value = value * CellHeight ;
_programmaticallyUpdatingScrollBarValues = false ;
}
2014-08-23 13:50:47 +00:00
}
}
}
2014-08-30 18:42:14 +00:00
public int LastVisibleRow
2014-08-23 14:49:01 +00:00
{
get
{
2014-08-30 18:42:14 +00:00
return FirstVisibleRow + VisibleRows ;
2014-08-23 14:49:01 +00:00
}
set
{
2014-09-01 20:34:10 +00:00
int i = Math . Max ( value - VisibleRows , 0 ) ;
2014-08-30 18:42:14 +00:00
FirstVisibleRow = i ;
2014-08-23 14:49:01 +00:00
}
}
2014-09-17 23:51:16 +00:00
public bool IsVisible ( int index )
{
return ( index > = FirstVisibleRow ) & & ( index < = LastVisibleRow ) ;
}
2014-08-23 13:50:47 +00:00
/// <summary>
2014-09-01 20:34:10 +00:00
/// Gets the number of rows currently visible including partially visible rows.
2014-08-23 13:50:47 +00:00
/// </summary>
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
public int VisibleRows
{
get
{
if ( HorizontalOrientation )
{
2014-09-17 23:31:59 +00:00
var width = DrawWidth - ( NeedsVScrollbar ? VBar . Width : 0 ) ;
2014-09-17 23:51:16 +00:00
return ( int ) ( ( width - ColumnWidth ) / CellWidth ) ;
2014-08-23 13:50:47 +00:00
}
2014-09-17 23:31:59 +00:00
2014-09-25 17:24:17 +00:00
var height = DrawHeight - ( NeedsHScrollbar ? HBar . Height : ( CellHeight - 1 ) ) ;
2014-09-17 23:31:59 +00:00
2014-09-25 13:01:57 +00:00
return ( ( int ) height / CellHeight ) - 1 ; // adelikat: -1 to compensate for what this math should be doing anyway, TODO: figure out why it doesn't work without it?
2014-08-23 13:50:47 +00:00
}
}
2014-08-12 11:07:21 +00:00
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
2014-10-13 18:28:29 +00:00
public IEnumerable < int > SelectedRows
2014-08-12 11:07:21 +00:00
{
get
{
return SelectedItems
. Where ( cell = > cell . RowIndex . HasValue )
2014-08-14 23:10:56 +00:00
. Select ( cell = > cell . RowIndex . Value )
2014-10-13 18:28:29 +00:00
. Distinct ( ) ;
2014-08-12 11:07:21 +00:00
}
}
2014-10-15 16:50:51 +00:00
public IEnumerable < ToolStripItem > GenerateContextMenuItems ( )
{
yield return new ToolStripSeparator ( ) ;
var rotate = new ToolStripMenuItem
{
Name = "RotateMenuItem" ,
Text = "Rotate" ,
2014-10-15 17:07:01 +00:00
ShortcutKeyDisplayString = RotateHotkeyStr ,
2014-10-15 16:50:51 +00:00
} ;
rotate . Click + = ( o , ev ) = >
{
this . HorizontalOrientation ^ = true ;
} ;
yield return rotate ;
}
2014-10-15 17:07:01 +00:00
public string RotateHotkeyStr
{
get { return "Ctrl+Shift+F" ; }
}
2014-08-07 14:55:55 +00:00
#endregion
#region Paint
2014-08-10 22:23:14 +00:00
protected override void OnPaint ( PaintEventArgs e )
2014-08-07 18:32:09 +00:00
{
2014-08-10 22:23:14 +00:00
using ( var LCK = Gdi . LockGraphics ( e . Graphics ) )
2014-08-07 18:32:09 +00:00
{
2014-08-18 00:23:09 +00:00
Gdi . StartOffScreenBitmap ( Width , Height ) ;
2014-08-31 15:40:02 +00:00
//White Background
2014-08-30 18:42:14 +00:00
Gdi . SetBrush ( Color . White ) ;
2014-08-31 15:40:02 +00:00
Gdi . SetSolidPen ( Color . White ) ;
Gdi . FillRectangle ( 0 , 0 , Width , Height ) ;
2014-10-12 16:37:45 +00:00
if ( _columns . VisibleColumns . Any ( ) )
2014-08-09 16:11:25 +00:00
{
2014-08-10 22:23:14 +00:00
DrawColumnBg ( e ) ;
DrawColumnText ( e ) ;
2014-08-09 16:11:25 +00:00
}
2014-08-07 18:32:09 +00:00
2014-09-01 20:34:10 +00:00
//Background
2014-08-10 22:23:14 +00:00
DrawBg ( e ) ;
2014-08-07 18:32:09 +00:00
2014-09-01 20:34:10 +00:00
//Foreground
2014-08-10 22:23:14 +00:00
DrawData ( e ) ;
2014-08-18 00:23:09 +00:00
Gdi . CopyToScreen ( ) ;
Gdi . EndOffScreenBitmap ( ) ;
2014-08-07 18:32:09 +00:00
}
}
2014-08-07 14:55:55 +00:00
protected override void OnPaintBackground ( PaintEventArgs pevent )
{
2014-08-08 13:42:05 +00:00
// Do nothing, and this should never be called
2014-08-07 14:55:55 +00:00
}
2014-08-10 22:23:14 +00:00
private void DrawColumnText ( PaintEventArgs e )
2014-08-08 02:09:59 +00:00
{
2014-10-12 16:37:45 +00:00
var columns = _columns . VisibleColumns . ToList ( ) ;
2014-08-08 02:09:59 +00:00
if ( HorizontalOrientation )
{
int start = 0 ;
2014-08-10 22:23:14 +00:00
Gdi . PrepDrawString ( this . Font , this . ForeColor ) ;
2014-10-12 16:37:45 +00:00
foreach ( var column in columns )
2014-08-08 02:09:59 +00:00
{
2014-09-24 21:10:57 +00:00
var point = new Point ( CellWidthPadding , start + CellHeightPadding ) ;
2014-08-11 01:23:53 +00:00
if ( IsHoveringOnColumnCell & & column = = CurrentCell . Column )
{
Gdi . PrepDrawString ( this . Font , SystemColors . HighlightText ) ;
Gdi . DrawString ( column . Text , point ) ;
Gdi . PrepDrawString ( this . Font , this . ForeColor ) ;
}
else
{
Gdi . DrawString ( column . Text , point ) ;
}
2014-08-08 02:09:59 +00:00
start + = CellHeight ;
}
}
else
{
2014-08-10 22:23:14 +00:00
Gdi . PrepDrawString ( this . Font , this . ForeColor ) ;
2014-10-12 16:37:45 +00:00
foreach ( var column in columns )
2014-08-08 02:09:59 +00:00
{
2014-09-24 21:10:57 +00:00
var point = new Point ( column . Left . Value + 2 * CellWidthPadding - HBar . Value , CellHeightPadding ) ; // TODO: fix this CellPadding issue (2 * CellPadding vs just CellPadding)
2014-08-11 01:23:53 +00:00
if ( IsHoveringOnColumnCell & & column = = CurrentCell . Column )
{
Gdi . PrepDrawString ( this . Font , SystemColors . HighlightText ) ;
Gdi . DrawString ( column . Text , point ) ;
Gdi . PrepDrawString ( this . Font , this . ForeColor ) ;
}
else
{
Gdi . DrawString ( column . Text , point ) ;
}
2014-08-08 02:09:59 +00:00
}
}
}
2014-08-10 22:23:14 +00:00
private void DrawData ( PaintEventArgs e )
2014-08-09 17:15:05 +00:00
{
2014-10-12 16:37:45 +00:00
var columns = _columns . VisibleColumns . ToList ( ) ;
2014-08-09 21:27:05 +00:00
if ( QueryItemText ! = null )
{
if ( HorizontalOrientation )
{
2014-10-16 20:50:07 +00:00
int startRow = FirstVisibleRow ;
int range = Math . Min ( LastVisibleRow , RowCount - 1 ) - startRow + 1 ;
2014-08-23 12:30:21 +00:00
2014-08-10 22:23:14 +00:00
Gdi . PrepDrawString ( this . Font , this . ForeColor ) ;
2014-08-23 12:30:21 +00:00
for ( int i = 0 ; i < range ; i + + )
2014-08-10 13:21:26 +00:00
{
2014-10-12 16:37:45 +00:00
for ( int j = 0 ; j < columns . Count ; j + + )
2014-08-10 13:21:26 +00:00
{
2014-10-16 20:50:07 +00:00
Bitmap image = null ;
int x = 0 ;
int y = 0 ;
2014-10-16 20:43:02 +00:00
2014-10-16 20:50:07 +00:00
if ( QueryItemIcon ! = null )
2014-10-16 20:43:02 +00:00
{
2014-10-16 20:50:07 +00:00
x = RowsToPixels ( i ) + CellWidthPadding ;
y = ( j * CellHeight ) + ( CellHeightPadding * 2 ) ;
2014-10-16 20:43:02 +00:00
2014-10-16 20:50:07 +00:00
QueryItemIcon ( i + startRow , columns [ j ] , ref image ) ;
}
2014-10-16 20:43:02 +00:00
2014-10-16 20:50:07 +00:00
if ( image ! = null )
2014-08-29 14:30:52 +00:00
{
2014-10-16 20:50:07 +00:00
Gdi . DrawBitmap ( image , new Point ( x , y ) , true ) ;
2014-08-31 23:03:59 +00:00
}
2014-10-16 20:50:07 +00:00
else
2014-10-16 20:43:02 +00:00
{
2014-10-16 20:50:07 +00:00
string text ;
QueryItemText ( i + startRow , columns [ j ] , out text ) ;
// Center Text
x = RowsToPixels ( i ) + ( CellWidth - text . Length * _charSize . Width ) / 2 ;
y = ( j * CellHeight ) + CellHeightPadding ;
var point = new Point ( x , y ) ;
bool rePrep = false ;
2014-10-16 22:28:48 +00:00
if ( SelectedItems . Contains ( new Cell { Column = columns [ j ] , RowIndex = i + startRow } ) )
2014-10-16 20:50:07 +00:00
{
Gdi . PrepDrawString ( this . Font , SystemColors . HighlightText ) ;
rePrep = true ;
}
if ( ! string . IsNullOrWhiteSpace ( text ) )
{
Gdi . DrawString ( text , point ) ;
}
if ( rePrep )
{
Gdi . PrepDrawString ( this . Font , this . ForeColor ) ;
}
2014-10-16 20:43:02 +00:00
}
2014-08-10 13:21:26 +00:00
}
}
2014-08-09 21:27:05 +00:00
}
else
{
2014-08-31 17:11:47 +00:00
int startRow = FirstVisibleRow ;
2014-09-01 20:34:10 +00:00
int range = Math . Min ( LastVisibleRow , RowCount - 1 ) - startRow + 1 ;
2014-08-22 00:39:56 +00:00
2014-08-10 22:23:14 +00:00
Gdi . PrepDrawString ( this . Font , this . ForeColor ) ;
2014-09-24 21:10:57 +00:00
int xPadding = CellWidthPadding + 1 - HBar . Value ;
2014-10-13 19:30:59 +00:00
for ( int i = 0 ; i < range ; i + + ) // Vertical
2014-08-09 21:27:05 +00:00
{
2014-10-13 19:30:59 +00:00
for ( int j = 0 ; j < columns . Count ; j + + ) // Horizontal
2014-08-09 21:27:05 +00:00
{
2014-10-12 16:37:45 +00:00
var col = columns [ j ] ;
2014-09-01 20:34:10 +00:00
if ( col . Left . Value < 0 | | col . Right . Value > DrawWidth )
{
continue ;
}
2014-08-09 21:27:05 +00:00
string text ;
2014-09-24 21:10:57 +00:00
var point = new Point ( col . Left . Value + xPadding , RowsToPixels ( i ) + CellHeightPadding ) ;
2014-09-03 03:16:16 +00:00
Bitmap image = null ;
if ( QueryItemIcon ! = null )
2014-08-29 14:30:52 +00:00
{
2014-10-13 19:30:59 +00:00
QueryItemIcon ( i + startRow , columns [ j ] , ref image ) ;
2014-09-03 03:16:16 +00:00
}
if ( image ! = null )
{
2014-09-24 21:10:57 +00:00
Gdi . DrawBitmap ( image , new Point ( col . Left . Value , point . Y + CellHeightPadding ) , true ) ;
2014-09-03 03:16:16 +00:00
}
else
{
2014-10-13 19:10:11 +00:00
QueryItemText ( i + startRow , columns [ j ] , out text ) ;
2014-10-16 20:43:02 +00:00
bool rePrep = false ;
2014-10-16 22:28:48 +00:00
if ( SelectedItems . Contains ( new Cell { Column = columns [ j ] , RowIndex = i + startRow } ) )
2014-10-16 20:43:02 +00:00
{
Gdi . PrepDrawString ( this . Font , SystemColors . HighlightText ) ;
rePrep = true ;
}
2014-09-03 03:16:16 +00:00
if ( ! string . IsNullOrWhiteSpace ( text ) )
{
Gdi . DrawString ( text , point ) ;
}
2014-10-16 20:43:02 +00:00
if ( rePrep )
{
Gdi . PrepDrawString ( this . Font , this . ForeColor ) ;
}
2014-08-29 14:30:52 +00:00
}
2014-08-09 21:27:05 +00:00
}
}
}
}
2014-08-09 17:15:05 +00:00
}
2014-08-08 13:42:05 +00:00
2014-08-10 22:23:14 +00:00
private void DrawColumnBg ( PaintEventArgs e )
2014-08-07 14:55:55 +00:00
{
2014-08-10 22:23:14 +00:00
Gdi . SetBrush ( SystemColors . ControlLight ) ;
Gdi . SetSolidPen ( Color . Black ) ;
2014-10-12 16:37:45 +00:00
var columns = _columns . VisibleColumns . ToList ( ) ;
2014-08-10 22:23:14 +00:00
if ( HorizontalOrientation )
2014-08-08 02:09:59 +00:00
{
2014-09-01 20:34:10 +00:00
Gdi . FillRectangle ( 0 , 0 , ColumnWidth + 1 , DrawHeight + 1 ) ;
2014-10-12 16:37:45 +00:00
Gdi . Line ( 0 , 0 , 0 , columns . Count * CellHeight + 1 ) ;
Gdi . Line ( ColumnWidth , 0 , ColumnWidth , columns . Count * CellHeight + 1 ) ;
2014-08-10 22:23:14 +00:00
int start = 0 ;
2014-10-12 16:37:45 +00:00
foreach ( var column in columns )
2014-08-10 22:23:14 +00:00
{
2014-09-01 20:34:10 +00:00
Gdi . Line ( 1 , start , ColumnWidth , start ) ;
2014-08-10 22:23:14 +00:00
start + = CellHeight ;
2014-09-01 20:34:10 +00:00
}
2014-10-12 16:37:45 +00:00
if ( columns . Any ( ) )
2014-09-01 20:34:10 +00:00
{
2014-08-31 23:03:59 +00:00
Gdi . Line ( 1 , start , ColumnWidth , start ) ;
2014-08-10 22:23:14 +00:00
}
}
else
{
2014-08-31 23:03:59 +00:00
int bottomEdge = RowsToPixels ( 0 ) ;
2014-08-31 15:40:02 +00:00
//Gray column box and black line underneath
2014-08-31 23:03:59 +00:00
Gdi . FillRectangle ( 0 , 0 , Width + 1 , bottomEdge + 1 ) ;
2014-08-31 15:40:02 +00:00
Gdi . Line ( 0 , 0 , TotalColWidth . Value + 1 , 0 ) ;
2014-08-31 23:03:59 +00:00
Gdi . Line ( 0 , bottomEdge , TotalColWidth . Value + 1 , bottomEdge ) ;
2014-08-10 22:23:14 +00:00
2014-08-31 15:40:02 +00:00
//Vertical black seperators
2014-10-12 16:37:45 +00:00
for ( int i = 0 ; i < columns . Count ; i + + )
2014-08-10 18:49:17 +00:00
{
2014-10-12 16:37:45 +00:00
int pos = columns [ i ] . Left . Value - HBar . Value ;
2014-08-31 23:03:59 +00:00
Gdi . Line ( pos , 0 , pos , bottomEdge ) ;
2014-08-30 18:42:14 +00:00
}
2014-08-31 23:03:59 +00:00
////Draw right most line
2014-10-12 16:37:45 +00:00
if ( columns . Any ( ) )
2014-08-30 18:42:14 +00:00
{
2014-08-31 15:40:02 +00:00
int right = TotalColWidth . Value - HBar . Value ;
2014-08-31 23:03:59 +00:00
Gdi . Line ( right , 0 , right , bottomEdge ) ;
2014-08-10 18:49:17 +00:00
}
2014-08-10 22:23:14 +00:00
}
2014-08-11 01:23:53 +00:00
2014-09-25 17:24:17 +00:00
// Emphasis
2014-10-12 16:37:45 +00:00
foreach ( var column in columns . Where ( c = > c . Emphasis ) )
2014-09-25 17:24:17 +00:00
{
2014-09-25 17:52:21 +00:00
Gdi . SetBrush ( SystemColors . ActiveBorder ) ;
2014-09-25 17:24:17 +00:00
if ( HorizontalOrientation )
{
2014-10-12 16:37:45 +00:00
Gdi . FillRectangle ( 1 , columns . IndexOf ( column ) * CellHeight + 1 , ColumnWidth - 1 , ColumnHeight - 1 ) ;
2014-09-25 17:24:17 +00:00
}
else
{
2014-09-25 17:52:21 +00:00
Gdi . FillRectangle ( column . Left . Value + 1 , 1 , column . Width . Value - 1 , ColumnHeight - 1 ) ;
2014-09-25 17:24:17 +00:00
}
}
2014-08-11 01:23:53 +00:00
// If the user is hovering over a column
if ( IsHoveringOnColumnCell )
{
if ( HorizontalOrientation )
{
2014-10-12 16:37:45 +00:00
for ( int i = 0 ; i < columns . Count ; i + + )
2014-08-11 01:23:53 +00:00
{
2014-10-12 16:37:45 +00:00
if ( columns [ i ] ! = CurrentCell . Column )
2014-08-11 01:23:53 +00:00
{
2014-08-30 18:42:14 +00:00
continue ;
}
2014-09-25 18:12:18 +00:00
if ( CurrentCell . Column . Emphasis )
{
Gdi . SetBrush ( Add ( SystemColors . Highlight , 0x00222222 ) ) ;
}
else
{
Gdi . SetBrush ( SystemColors . Highlight ) ;
}
2014-09-22 15:49:55 +00:00
Gdi . FillRectangle ( 1 , i * CellHeight + 1 , ColumnWidth - 1 , ColumnHeight - 1 ) ;
2014-08-11 01:23:53 +00:00
}
}
else
{
2014-09-01 20:34:10 +00:00
//TODO multiple selected columns
2014-10-12 16:37:45 +00:00
for ( int i = 0 ; i < columns . Count ; i + + )
2014-08-11 01:23:53 +00:00
{
2014-10-12 16:37:45 +00:00
if ( columns [ i ] = = CurrentCell . Column )
{
2014-08-30 18:42:14 +00:00
//Left of column is to the right of the viewable area or right of column is to the left of the viewable area
2014-10-12 16:37:45 +00:00
if ( columns [ i ] . Left . Value - HBar . Value > Width | | columns [ i ] . Right . Value - HBar . Value < 0 )
{
2014-08-30 18:42:14 +00:00
continue ;
}
2014-10-12 16:37:45 +00:00
int left = columns [ i ] . Left . Value - HBar . Value ;
int width = columns [ i ] . Right . Value - HBar . Value - left ;
2014-09-25 18:12:18 +00:00
if ( CurrentCell . Column . Emphasis )
{
Gdi . SetBrush ( Add ( SystemColors . Highlight , 0x00550000 ) ) ;
}
else
{
Gdi . SetBrush ( SystemColors . Highlight ) ;
}
2014-09-22 15:49:55 +00:00
Gdi . FillRectangle ( left + 1 , 1 , width - 1 , ColumnHeight - 1 ) ;
2014-08-11 01:23:53 +00:00
}
}
}
}
2014-08-10 22:23:14 +00:00
}
2014-09-25 17:52:21 +00:00
2014-09-25 18:12:18 +00:00
// TODO: Make into an extension method
private Color Add ( Color color , int val )
{
var col = color . ToArgb ( ) ;
col + = val ;
return Color . FromArgb ( col ) ;
}
2014-08-30 18:42:14 +00:00
//TODO refactor this and DoBackGroundCallback functions.
/// <summary>
/// Draw Gridlines and background colors using QueryItemBkColor.
/// </summary>
/// <param name="e"></param>
2014-08-10 22:23:14 +00:00
private void DrawBg ( PaintEventArgs e )
{
2014-08-29 14:49:36 +00:00
if ( QueryItemBkColor ! = null & & UseCustomBackground )
{
DoBackGroundCallback ( e ) ;
}
2014-10-12 16:37:45 +00:00
2014-08-23 23:03:19 +00:00
if ( GridLines )
2014-08-10 22:23:14 +00:00
{
2014-10-12 16:37:45 +00:00
var columns = _columns . VisibleColumns . ToList ( ) ;
2014-08-23 23:03:19 +00:00
Gdi . SetSolidPen ( SystemColors . ControlLight ) ;
if ( HorizontalOrientation )
2014-08-10 22:23:14 +00:00
{
2014-08-23 23:03:19 +00:00
// Columns
2014-09-01 20:34:10 +00:00
for ( int i = 1 ; i < VisibleRows + 1 ; i + + )
2014-08-19 00:37:38 +00:00
{
2014-09-01 20:34:10 +00:00
var x = RowsToPixels ( i ) ;
2014-10-12 16:37:45 +00:00
var y2 = ( columns . Count * CellHeight ) - 1 ;
2014-08-23 23:03:19 +00:00
if ( y2 > Height )
{
y2 = Height - 2 ;
}
2014-08-19 00:37:38 +00:00
2014-09-01 20:34:10 +00:00
Gdi . Line ( x , 1 , x , DrawHeight ) ;
2014-08-23 23:03:19 +00:00
}
2014-08-10 22:23:14 +00:00
2014-08-23 23:03:19 +00:00
// Rows
2014-10-12 16:37:45 +00:00
for ( int i = 0 ; i < columns . Count + 1 ; i + + )
2014-08-23 23:03:19 +00:00
{
2014-09-01 20:34:10 +00:00
Gdi . Line ( RowsToPixels ( 0 ) + 1 , i * CellHeight , DrawWidth , i * CellHeight ) ;
2014-08-23 23:03:19 +00:00
}
2014-08-10 22:23:14 +00:00
}
2014-08-23 23:03:19 +00:00
else
2014-08-10 22:23:14 +00:00
{
2014-08-23 23:03:19 +00:00
// Columns
2014-08-31 23:03:59 +00:00
int y = ColumnHeight + 1 ;
2014-10-12 16:37:45 +00:00
foreach ( var column in columns )
2014-08-23 23:03:19 +00:00
{
2014-08-30 18:42:14 +00:00
int x = column . Left . Value - HBar . Value ;
2014-08-23 23:03:19 +00:00
Gdi . Line ( x , y , x , Height - 1 ) ;
}
2014-10-12 16:37:45 +00:00
if ( columns . Any ( ) )
2014-08-31 15:40:02 +00:00
{
2014-08-31 23:03:59 +00:00
Gdi . Line ( TotalColWidth . Value - HBar . Value , y , TotalColWidth . Value - HBar . Value , Height - 1 ) ;
2014-08-31 15:40:02 +00:00
}
2014-08-10 22:23:14 +00:00
2014-08-23 23:03:19 +00:00
// Rows
2014-08-31 23:03:59 +00:00
for ( int i = 1 ; i < VisibleRows + 1 ; i + + )
2014-08-23 23:03:19 +00:00
{
2014-08-31 23:03:59 +00:00
Gdi . Line ( 0 , RowsToPixels ( i ) , Width + 1 , RowsToPixels ( i ) ) ;
2014-08-23 23:03:19 +00:00
}
2014-08-10 22:23:14 +00:00
}
2014-08-10 18:49:17 +00:00
}
2014-08-11 00:08:16 +00:00
2014-08-14 22:48:59 +00:00
if ( SelectedItems . Any ( ) )
{
DoSelectionBG ( e ) ;
}
}
private void DoSelectionBG ( PaintEventArgs e )
{
foreach ( var cell in SelectedItems )
{
2014-08-31 18:06:31 +00:00
var relativeCell = new Cell ( )
{
RowIndex = cell . RowIndex - FirstVisibleRow ,
Column = cell . Column ,
CurrentText = cell . CurrentText
} ;
DrawCellBG ( SystemColors . Highlight , relativeCell ) ;
2014-08-14 22:48:59 +00:00
}
}
2014-08-31 18:06:31 +00:00
/// <summary>
/// Given a cell with rowindex inbetween 0 and VisibleRows, it draws the background color specified. Do not call with absolute rowindices.
/// </summary>
/// <param name="color"></param>
/// <param name="cell"></param>
2014-08-14 22:48:59 +00:00
private void DrawCellBG ( Color color , Cell cell )
{
2014-10-12 16:37:45 +00:00
var columns = _columns . VisibleColumns . ToList ( ) ;
2014-08-14 22:48:59 +00:00
int x = 0 ,
y = 0 ,
w = 0 ,
h = 0 ;
if ( HorizontalOrientation )
{
2014-09-01 20:34:10 +00:00
x = RowsToPixels ( cell . RowIndex . Value ) + 1 ;
2014-08-14 22:48:59 +00:00
w = CellWidth - 1 ;
2014-10-12 16:37:45 +00:00
y = ( CellHeight * columns . IndexOf ( cell . Column ) ) + 1 ; // We can't draw without row and column, so assume they exist and fail catastrophically if they don't
2014-08-14 22:48:59 +00:00
h = CellHeight - 1 ;
2014-09-01 15:35:48 +00:00
if ( x < ColumnWidth ) { return ; }
2014-08-14 22:48:59 +00:00
}
else
{
2014-08-30 18:42:14 +00:00
w = cell . Column . Width . Value - 1 ;
x = cell . Column . Left . Value - HBar . Value + 1 ;
2014-08-31 23:03:59 +00:00
y = RowsToPixels ( cell . RowIndex . Value ) + 1 ; // We can't draw without row and column, so assume they exist and fail catastrophically if they don't
2014-08-14 22:48:59 +00:00
h = CellHeight - 1 ;
2014-09-01 15:35:48 +00:00
if ( y < ColumnHeight ) { return ; }
2014-08-14 22:48:59 +00:00
}
2014-08-31 23:03:59 +00:00
if ( x > DrawWidth | | y > DrawHeight ) { return ; } //Don't draw if off screen.
2014-08-31 18:06:31 +00:00
2014-08-14 22:48:59 +00:00
Gdi . SetBrush ( color ) ;
Gdi . FillRectangle ( x , y , w , h ) ;
}
2014-08-30 18:42:14 +00:00
/// <summary>
/// Calls QueryItemBkColor callback for all visible cells and fills in the background of those cells.
/// </summary>
/// <param name="e"></param>
2014-08-14 22:48:59 +00:00
private void DoBackGroundCallback ( PaintEventArgs e )
{
2014-10-12 16:37:45 +00:00
var columns = _columns . VisibleColumns . ToList ( ) ;
2014-08-14 22:48:59 +00:00
if ( HorizontalOrientation )
{
2014-09-01 20:34:10 +00:00
int startIndex = FirstVisibleRow ;
int range = Math . Min ( LastVisibleRow , RowCount - 1 ) - startIndex + 1 ;
2014-08-29 00:04:42 +00:00
for ( int i = 0 ; i < range ; i + + )
2014-08-14 22:48:59 +00:00
{
2014-10-13 19:30:59 +00:00
for ( int j = 0 ; j < columns . Count ; j + + ) // TODO: Don't query all columns
2014-08-14 22:48:59 +00:00
{
Color color = Color . White ;
2014-10-13 19:30:59 +00:00
QueryItemBkColor ( i + startIndex , columns [ j ] , ref color ) ;
2014-08-14 22:48:59 +00:00
if ( color ! = Color . White ) // An easy optimization, don't draw unless the user specified something other than the default
2014-08-11 00:08:16 +00:00
{
2014-08-30 18:42:14 +00:00
var cell = new Cell ( )
{
2014-10-12 16:37:45 +00:00
Column = columns [ j ] ,
2014-08-30 18:42:14 +00:00
RowIndex = i
} ;
DrawCellBG ( color , cell ) ;
2014-08-11 00:08:16 +00:00
}
}
}
2014-08-14 22:48:59 +00:00
}
else
{
2014-08-31 17:11:47 +00:00
int startRow = FirstVisibleRow ;
2014-09-01 20:34:10 +00:00
int range = Math . Min ( LastVisibleRow , RowCount - 1 ) - startRow + 1 ;
2014-08-29 00:04:42 +00:00
2014-10-13 19:30:59 +00:00
for ( int i = 0 ; i < range ; i + + ) // Vertical
2014-08-11 00:08:16 +00:00
{
2014-10-13 19:30:59 +00:00
for ( int j = 0 ; j < columns . Count ; j + + ) // Horizontal
2014-08-11 00:08:16 +00:00
{
2014-08-14 22:48:59 +00:00
Color color = Color . White ;
2014-10-13 19:30:59 +00:00
QueryItemBkColor ( i + startRow , columns [ j ] , ref color ) ;
2014-08-14 22:48:59 +00:00
if ( color ! = Color . White ) // An easy optimization, don't draw unless the user specified something other than the default
{
2014-10-12 16:37:45 +00:00
var cell = new Cell
2014-08-30 18:42:14 +00:00
{
2014-10-12 16:37:45 +00:00
Column = columns [ j ] ,
2014-08-30 18:42:14 +00:00
RowIndex = i
} ;
DrawCellBG ( color , cell ) ;
2014-08-11 00:08:16 +00:00
}
}
}
}
2014-08-07 14:55:55 +00:00
}
#endregion
#region Mouse and Key Events
2014-08-10 22:23:14 +00:00
protected override void OnMouseMove ( MouseEventArgs e )
{
2014-08-30 18:42:14 +00:00
var newCell = CalculatePointedCell ( e . X , e . Y ) ;
2014-09-01 15:35:48 +00:00
newCell . RowIndex + = FirstVisibleRow ;
2014-08-30 18:42:14 +00:00
if ( ! newCell . Equals ( CurrentCell ) )
{
CellChanged ( newCell ) ;
if ( IsHoveringOnColumnCell | |
( WasHoveringOnColumnCell & & ! IsHoveringOnColumnCell ) )
{
Refresh ( ) ;
}
}
2014-08-10 22:23:14 +00:00
base . OnMouseMove ( e ) ;
}
protected override void OnMouseEnter ( EventArgs e )
{
CurrentCell = new Cell
{
Column = null ,
RowIndex = null
} ;
base . OnMouseEnter ( e ) ;
}
protected override void OnMouseLeave ( EventArgs e )
{
CurrentCell = null ;
2014-08-23 13:05:28 +00:00
IsPaintDown = false ;
2014-08-11 01:23:53 +00:00
Refresh ( ) ;
2014-08-10 22:23:14 +00:00
base . OnMouseLeave ( e ) ;
}
2014-09-01 20:34:10 +00:00
//TODO add query callback of whether to select the cell or not
2014-08-29 17:42:07 +00:00
protected override void OnMouseDown ( MouseEventArgs e )
2014-08-11 01:49:45 +00:00
{
2014-08-29 17:42:07 +00:00
if ( e . Button = = MouseButtons . Left & & InputPaintingMode )
2014-08-11 01:49:45 +00:00
{
2014-08-29 17:42:07 +00:00
IsPaintDown = true ;
2014-08-11 01:49:45 +00:00
}
2014-08-29 17:42:07 +00:00
if ( e . Button = = MouseButtons . Right )
2014-08-12 11:07:21 +00:00
{
2014-09-25 17:52:21 +00:00
if ( IsHoveringOnColumnCell )
{
ColumnRightClickEvent ( ColumnAtX ( e . X ) ) ;
}
else
{
RightButtonHeld = true ;
}
2014-08-29 17:42:07 +00:00
}
if ( e . Button = = MouseButtons . Left )
{
2014-09-01 15:35:48 +00:00
if ( IsHoveringOnColumnCell )
2014-08-14 22:48:59 +00:00
{
2014-09-01 15:35:48 +00:00
ColumnClickEvent ( ColumnAtX ( e . X ) ) ;
2014-08-14 22:48:59 +00:00
}
2014-09-01 15:35:48 +00:00
else if ( IsHoveringOnDataCell )
2014-08-12 11:07:21 +00:00
{
2014-09-01 15:35:48 +00:00
if ( ModifierKeys = = Keys . Alt )
2014-08-14 22:48:59 +00:00
{
2014-09-01 15:35:48 +00:00
MessageBox . Show ( "Alt click logic is not yet implemented" ) ;
}
else if ( ModifierKeys = = Keys . Shift )
{
if ( SelectedItems . Any ( ) )
{
2014-09-21 16:21:10 +00:00
if ( FullRowSelect )
{
var selected = SelectedItems . Any ( c = > c . RowIndex . HasValue & & CurrentCell . RowIndex . HasValue & & c . RowIndex = = CurrentCell . RowIndex ) ;
if ( ! selected )
{
var rowIndices = SelectedItems
. Where ( c = > c . RowIndex . HasValue )
. Select ( c = > c . RowIndex ? ? - 1 )
. Where ( c = > c > = 0 ) // Hack to avoid possible Nullable exceptions
. Distinct ( ) ;
var firstIndex = rowIndices . Min ( ) ;
var lastIndex = rowIndices . Max ( ) ;
if ( CurrentCell . RowIndex . Value < firstIndex )
{
for ( int i = CurrentCell . RowIndex . Value ; i < firstIndex ; i + + )
{
SelectCell ( new Cell
{
RowIndex = i ,
Column = CurrentCell . Column
} ) ;
}
}
else if ( CurrentCell . RowIndex . Value > lastIndex )
{
for ( int i = lastIndex + 1 ; i < = CurrentCell . RowIndex . Value ; i + + )
{
SelectCell ( new Cell
{
RowIndex = i ,
Column = CurrentCell . Column
} ) ;
}
}
else // Somewhere in between, a scenario that can happen with ctrl-clicking, find the previous and highlight from there
{
var nearest = rowIndices
. Where ( x = > x < CurrentCell . RowIndex . Value )
. Max ( ) ;
for ( int i = nearest + 1 ; i < = CurrentCell . RowIndex . Value ; i + + )
{
SelectCell ( new Cell
{
RowIndex = i ,
Column = CurrentCell . Column
} ) ;
}
}
}
}
else
{
MessageBox . Show ( "Shift click logic for individual cells has not yet implemented" ) ;
}
2014-09-01 15:35:48 +00:00
}
else
{
SelectCell ( CurrentCell ) ;
}
}
else if ( ModifierKeys = = Keys . Control )
{
2014-09-21 16:00:42 +00:00
SelectCell ( CurrentCell , toggle : true ) ;
2014-08-14 22:48:59 +00:00
}
else
{
2014-09-01 15:35:48 +00:00
SelectedItems . Clear ( ) ;
2014-08-14 23:10:56 +00:00
SelectCell ( CurrentCell ) ;
2014-08-14 22:48:59 +00:00
}
2014-08-30 18:42:14 +00:00
2014-09-01 15:35:48 +00:00
Refresh ( ) ;
}
2014-08-23 13:05:28 +00:00
}
base . OnMouseDown ( e ) ;
}
protected override void OnMouseUp ( MouseEventArgs e )
{
IsPaintDown = false ;
RightButtonHeld = false ;
base . OnMouseUp ( e ) ;
2014-08-30 18:42:14 +00:00
}
2014-08-23 13:05:28 +00:00
2014-08-29 15:53:59 +00:00
private void IncrementScrollBar ( ScrollBar bar , bool increment )
2014-08-31 23:03:59 +00:00
{
2014-08-29 15:53:59 +00:00
int newVal ;
if ( increment )
{
newVal = bar . Value + bar . SmallChange ;
if ( newVal > bar . Maximum )
{
newVal = bar . Maximum ;
2014-08-31 23:03:59 +00:00
}
2014-08-29 15:53:59 +00:00
}
else
{
newVal = bar . Value - bar . SmallChange ;
if ( newVal < 0 )
2014-08-31 23:03:59 +00:00
{
2014-08-29 15:53:59 +00:00
newVal = 0 ;
}
}
_programmaticallyUpdatingScrollBarValues = true ;
bar . Value = newVal ;
_programmaticallyUpdatingScrollBarValues = false ;
}
2014-08-23 13:05:28 +00:00
protected override void OnMouseWheel ( MouseEventArgs e )
{
if ( RightButtonHeld )
{
DoRightMouseScroll ( this , e ) ;
}
else
{
2014-08-29 15:53:59 +00:00
if ( HorizontalOrientation )
{
IncrementScrollBar ( HBar , e . Delta < 0 ) ;
}
else
{
IncrementScrollBar ( VBar , e . Delta < 0 ) ;
}
Refresh ( ) ;
2014-08-23 13:05:28 +00:00
}
}
2014-08-30 18:42:14 +00:00
private void DoRightMouseScroll ( object sender , MouseEventArgs e )
{
if ( RightMouseScrolled ! = null )
{
RightMouseScrolled ( sender , e ) ;
}
}
private void ColumnClickEvent ( RollColumn column )
{
if ( ColumnClick ! = null )
{
2014-10-14 00:31:59 +00:00
ColumnClick ( this , new ColumnClickEventArgs ( column ) ) ;
2014-08-30 18:42:14 +00:00
}
}
2014-09-25 17:52:21 +00:00
private void ColumnRightClickEvent ( RollColumn column )
{
if ( ColumnRightClick ! = null )
{
2014-10-14 00:31:59 +00:00
ColumnRightClick ( this , new ColumnClickEventArgs ( column ) ) ;
2014-09-25 17:52:21 +00:00
}
}
2014-10-15 16:50:51 +00:00
protected override void OnKeyDown ( KeyEventArgs e )
{
if ( e . Control & & ! e . Alt & & e . Shift & & e . KeyCode = = Keys . F ) // Ctrl+Shift+F
{
HorizontalOrientation ^ = true ;
}
base . OnKeyDown ( e ) ;
}
2014-08-10 22:23:14 +00:00
#endregion
2014-08-18 21:38:02 +00:00
#region Change Events
protected override void OnResize ( EventArgs e )
{
RecalculateScrollBars ( ) ;
base . OnResize ( e ) ;
Refresh ( ) ;
}
2014-08-30 18:42:14 +00:00
private void OrientationChanged ( )
2014-08-23 13:05:28 +00:00
{
2014-09-01 20:34:10 +00:00
RecalculateScrollBars ( ) ;
//TODO scroll to correct positions
if ( HorizontalOrientation )
{
VBar . SmallChange = CellHeight ;
HBar . SmallChange = CellWidth ;
VBar . LargeChange = 10 ;
HBar . LargeChange = CellWidth * 20 ;
}
else
{
VBar . SmallChange = CellHeight ;
HBar . SmallChange = 1 ;
VBar . LargeChange = CellHeight * 20 ;
HBar . LargeChange = 20 ;
}
2014-10-15 22:14:44 +00:00
ColumnChangedCallback ( ) ;
2014-09-01 20:34:10 +00:00
RecalculateScrollBars ( ) ;
2014-09-01 15:35:48 +00:00
Refresh ( ) ;
2014-08-30 18:42:14 +00:00
}
2014-08-31 15:40:02 +00:00
2014-08-30 18:42:14 +00:00
/// <summary>
/// Call this function to change the CurrentCell to newCell
/// </summary>
/// <param name="oldCell"></param>
/// <param name="newCell"></param>
private void CellChanged ( Cell newCell )
2014-09-01 20:34:10 +00:00
{
2014-09-28 17:28:57 +00:00
LastCell = CurrentCell ;
CurrentCell = newCell ;
2014-10-11 17:38:03 +00:00
if ( PointedCellChanged ! = null & &
( LastCell . Column ! = CurrentCell . Column | | LastCell . RowIndex ! = CurrentCell . RowIndex ) )
2014-08-30 18:42:14 +00:00
{
PointedCellChanged ( this , new CellEventArgs ( LastCell , CurrentCell ) ) ;
2014-08-23 13:05:28 +00:00
}
}
2014-08-19 00:37:38 +00:00
private void VerticalBar_ValueChanged ( object sender , EventArgs e )
{
2014-08-27 22:33:27 +00:00
if ( ! _programmaticallyUpdatingScrollBarValues )
{
Refresh ( ) ;
}
2014-08-19 00:37:38 +00:00
}
private void HorizontalBar_ValueChanged ( object sender , EventArgs e )
{
2014-08-27 22:33:27 +00:00
if ( ! _programmaticallyUpdatingScrollBarValues )
{
Refresh ( ) ;
}
2014-08-19 00:37:38 +00:00
}
2014-08-18 23:50:50 +00:00
private void ColumnChangedCallback ( )
{
RecalculateScrollBars ( ) ;
2014-10-12 16:37:45 +00:00
if ( _columns . VisibleColumns . Any ( ) )
2014-08-31 23:03:59 +00:00
{
2014-10-12 16:37:45 +00:00
ColumnWidth = _columns . VisibleColumns . Max ( c = > c . Width . Value ) + CellWidthPadding * 4 ;
2014-08-31 23:03:59 +00:00
}
2014-08-18 23:50:50 +00:00
}
2014-08-30 18:42:14 +00:00
#endregion
#region Helpers
2014-08-31 15:40:02 +00:00
//ScrollBar.Maximum = DesiredValue + ScrollBar.LargeChange - 1
//See MSDN Page for more information on the dumb ScrollBar.Maximum Property
2014-08-18 21:38:02 +00:00
private void RecalculateScrollBars ( )
{
2014-08-31 15:40:02 +00:00
UpdateDrawSize ( ) ;
2014-10-12 16:37:45 +00:00
var columns = _columns . VisibleColumns . ToList ( ) ;
2014-08-31 15:40:02 +00:00
if ( HorizontalOrientation )
2014-08-18 21:38:02 +00:00
{
2014-10-12 16:37:45 +00:00
NeedsVScrollbar = columns . Count > DrawHeight / CellHeight ;
2014-08-31 23:03:59 +00:00
NeedsHScrollbar = RowCount > ( DrawWidth - ColumnWidth ) / CellWidth ;
2014-08-31 15:40:02 +00:00
}
else
{
NeedsVScrollbar = RowCount > DrawHeight / CellHeight ;
NeedsHScrollbar = TotalColWidth . HasValue & & TotalColWidth . Value - DrawWidth + 1 > 0 ;
}
UpdateDrawSize ( ) ;
2014-08-21 21:09:21 +00:00
2014-09-01 20:34:10 +00:00
//Update VBar
2014-08-31 15:40:02 +00:00
if ( NeedsVScrollbar )
{
2014-08-18 21:38:02 +00:00
if ( HorizontalOrientation )
{
2014-10-12 16:37:45 +00:00
VBar . Maximum = ( ( ( columns . Count ( ) * CellHeight ) - DrawHeight ) / CellHeight ) + VBar . LargeChange ;
2014-08-18 21:38:02 +00:00
}
else
{
2014-08-31 23:03:59 +00:00
VBar . Maximum = RowsToPixels ( RowCount + 1 ) - DrawHeight + VBar . LargeChange - 1 ;
2014-08-18 21:38:02 +00:00
}
2014-08-21 21:09:21 +00:00
2014-09-16 20:54:18 +00:00
VBar . Location = new Point ( Width - 17 , 0 ) ;
2014-08-21 21:09:21 +00:00
VBar . Size = new Size ( VBar . Width , Height ) ;
VBar . Visible = true ;
2014-08-18 21:38:02 +00:00
}
else
{
VBar . Visible = false ;
2014-08-31 15:40:02 +00:00
VBar . Value = 0 ;
2014-08-18 21:38:02 +00:00
}
2014-09-01 20:34:10 +00:00
//Update HBar
2014-08-18 21:38:02 +00:00
if ( NeedsHScrollbar )
{
HBar . Visible = true ;
if ( HorizontalOrientation )
{
2014-09-01 20:34:10 +00:00
HBar . Maximum = RowsToPixels ( RowCount + 1 ) - DrawWidth + HBar . LargeChange - 1 ;
2014-08-18 21:38:02 +00:00
}
else
{
2014-08-31 15:40:02 +00:00
HBar . Maximum = TotalColWidth . Value - DrawWidth + HBar . LargeChange ;
2014-08-30 18:42:14 +00:00
}
if ( NeedsVScrollbar )
{
2014-08-31 15:40:02 +00:00
HBar . Size = new Size ( Width - VBar . Width + 1 , HBar . Height ) ;
2014-08-30 18:42:14 +00:00
}
else
{
2014-09-22 15:19:04 +00:00
VBar . Location = new Point ( 0 , Height - 17 ) ;
2014-08-30 18:42:14 +00:00
HBar . Size = new Size ( Width , HBar . Height ) ;
2014-08-18 21:38:02 +00:00
}
}
else
{
HBar . Visible = false ;
2014-08-31 15:40:02 +00:00
HBar . Value = 0 ;
}
}
private void UpdateDrawSize ( )
{
if ( NeedsVScrollbar )
{
DrawWidth = Width - VBar . Width ;
}
else
{
DrawWidth = Width ;
}
if ( NeedsHScrollbar ) {
DrawHeight = Height - HBar . Height ;
}
else
{
DrawHeight = Height ;
2014-08-18 21:38:02 +00:00
}
}
2014-08-30 18:42:14 +00:00
/// <summary>
/// If FullRowSelect is enabled, selects all cells in the row that contains the given cell. Otherwise only given cell is added.
/// </summary>
/// <param name="cell">The cell to select.</param>
2014-09-21 16:00:42 +00:00
private void SelectCell ( Cell cell , bool toggle = false )
2014-08-14 23:10:56 +00:00
{
2014-09-21 16:27:49 +00:00
if ( cell . RowIndex . HasValue & & cell . RowIndex < RowCount )
2014-08-14 23:10:56 +00:00
{
2014-09-21 16:27:49 +00:00
if ( ! MultiSelect )
{
SelectedItems . Clear ( ) ;
}
2014-08-14 23:10:56 +00:00
2014-09-21 16:27:49 +00:00
if ( FullRowSelect )
2014-08-14 23:10:56 +00:00
{
2014-09-21 16:27:49 +00:00
if ( toggle & & SelectedItems . Any ( x = > x . RowIndex . HasValue & & x . RowIndex = = cell . RowIndex ) )
{
var items = SelectedItems
. Where ( x = > x . RowIndex . HasValue & & x . RowIndex = = cell . RowIndex )
. ToList ( ) ;
2014-09-21 16:00:42 +00:00
2014-09-21 16:27:49 +00:00
foreach ( var item in items )
{
SelectedItems . Remove ( item ) ;
}
}
else
2014-08-14 23:10:56 +00:00
{
2014-09-21 16:27:49 +00:00
foreach ( var column in _columns )
{
SelectedItems . Add ( new Cell
{
RowIndex = cell . RowIndex ,
Column = column
} ) ;
}
2014-09-21 16:00:42 +00:00
}
}
else
{
2014-09-21 16:27:49 +00:00
if ( toggle & & SelectedItems . Any ( x = > x . RowIndex . HasValue & & x . RowIndex = = cell . RowIndex ) )
2014-09-21 16:00:42 +00:00
{
2014-09-21 16:27:49 +00:00
var item = SelectedItems
. FirstOrDefault ( x = > x . Equals ( cell ) ) ;
if ( item ! = null )
2014-09-21 16:00:42 +00:00
{
2014-09-21 16:27:49 +00:00
SelectedItems . Remove ( item ) ;
}
2014-09-21 16:00:42 +00:00
}
2014-09-21 16:27:49 +00:00
else
2014-09-21 16:00:42 +00:00
{
2014-09-21 16:27:49 +00:00
SelectedItems . Add ( CurrentCell ) ;
2014-09-21 16:00:42 +00:00
}
}
2014-08-14 23:10:56 +00:00
2014-09-21 16:27:49 +00:00
SelectedIndexChanged ( this , new EventArgs ( ) ) ;
}
2014-08-14 23:10:56 +00:00
}
2014-08-30 18:42:14 +00:00
/// <summary>
/// Bool that indicates if CurrentCell is a Column Cell.
/// </summary>
2014-08-11 01:23:53 +00:00
private bool IsHoveringOnColumnCell
{
get
{
return CurrentCell ! = null & &
CurrentCell . Column ! = null & &
! CurrentCell . RowIndex . HasValue ;
}
}
2014-08-30 18:42:14 +00:00
/// <summary>
/// Bool that indicates if CurrentCell is a Data Cell.
/// </summary>
2014-08-12 11:07:21 +00:00
private bool IsHoveringOnDataCell
{
get
{
return CurrentCell ! = null & &
CurrentCell . Column ! = null & &
CurrentCell . RowIndex . HasValue ;
}
}
2014-08-30 18:42:14 +00:00
/// <summary>
/// Bool that indicates if CurrentCell is a Column Cell.
/// </summary>
private bool WasHoveringOnColumnCell
{
get
{
return LastCell ! = null & &
LastCell . Column ! = null & &
! LastCell . RowIndex . HasValue ;
}
}
/// <summary>
/// Bool that indicates if CurrentCell is a Data Cell.
/// </summary>
private bool WasHoveringOnDataCell
{
get
{
return LastCell ! = null & &
LastCell . Column ! = null & &
LastCell . RowIndex . HasValue ;
}
}
/// <summary>
/// Finds the specific cell that contains the (x, y) coordinate.
/// </summary>
2014-09-01 15:35:48 +00:00
/// <remarks>The row number that it returns will be between 0 and VisibleRows, NOT the absolute row number.</remarks>
2014-08-30 18:42:14 +00:00
/// <param name="x">X coordinate point.</param>
/// <param name="y">Y coordinate point.</param>
2014-09-01 15:35:48 +00:00
/// <returns>The cell with row number and RollColumn reference, both of which can be null. </returns>
2014-08-30 18:42:14 +00:00
private Cell CalculatePointedCell ( int x , int y )
2014-08-10 15:57:59 +00:00
{
var newCell = new Cell ( ) ;
2014-10-12 16:37:45 +00:00
var columns = _columns . VisibleColumns . ToList ( ) ;
2014-08-10 15:57:59 +00:00
// If pointing to a column header
2014-10-12 16:37:45 +00:00
if ( columns . Any ( ) )
2014-08-10 15:57:59 +00:00
{
if ( HorizontalOrientation )
{
2014-09-01 20:34:10 +00:00
if ( x > = ColumnWidth )
2014-08-10 15:57:59 +00:00
{
2014-08-31 23:03:59 +00:00
newCell . RowIndex = PixelsToRows ( x ) ;
2014-08-10 15:57:59 +00:00
}
int colIndex = ( y / CellHeight ) ;
2014-10-12 16:37:45 +00:00
if ( colIndex > = 0 & & colIndex < columns . Count )
2014-08-10 15:57:59 +00:00
{
2014-10-12 16:37:45 +00:00
newCell . Column = columns [ colIndex ] ;
2014-08-10 15:57:59 +00:00
}
}
else
{
2014-09-01 20:34:10 +00:00
if ( y > = CellHeight )
2014-08-10 15:57:59 +00:00
{
2014-09-01 00:45:58 +00:00
newCell . RowIndex = PixelsToRows ( y ) ;
2014-08-10 15:57:59 +00:00
}
2014-08-30 18:42:14 +00:00
newCell . Column = ColumnAtX ( x ) ;
2014-08-11 01:23:53 +00:00
}
2014-08-10 15:57:59 +00:00
}
2014-08-30 18:42:14 +00:00
return newCell ;
2014-08-10 15:57:59 +00:00
}
2014-08-10 22:23:14 +00:00
// TODO: Calculate this on Orientation change instead of call it every time
2014-08-31 15:40:02 +00:00
//TODO: find a different solution
2014-08-09 13:13:24 +00:00
private Point StartBg ( )
2014-08-07 18:32:09 +00:00
{
2014-10-12 16:37:45 +00:00
if ( _columns . VisibleColumns . Any ( ) )
2014-08-07 18:32:09 +00:00
{
2014-08-09 13:13:24 +00:00
if ( HorizontalOrientation )
2014-08-07 18:32:09 +00:00
{
2014-08-31 23:03:59 +00:00
var x = ColumnWidth ;
2014-08-09 13:13:24 +00:00
var y = 0 ;
return new Point ( x , y ) ;
}
else
{
2014-08-31 23:03:59 +00:00
var y = ColumnHeight ;
2014-08-10 22:23:14 +00:00
return new Point ( 0 , y ) ;
2014-08-07 18:32:09 +00:00
}
}
2014-08-09 13:13:24 +00:00
return new Point ( 0 , 0 ) ;
2014-08-07 23:10:41 +00:00
}
2014-08-31 15:40:02 +00:00
private void DrawRectangleNoFill ( GDIRenderer gdi , int x , int y , int width , int height )
{
gdi . Line ( x , y , x + width , y ) ;
gdi . Line ( x + width , y , x + width , y + height ) ;
gdi . Line ( x + width , y + height , x , y + height ) ;
gdi . Line ( x , y + height , x , y ) ;
}
2014-08-30 18:42:14 +00:00
/// <summary>
/// A boolean that indicates if the InputRoll is too large vertically and requires a vertical scrollbar.
/// </summary>
2014-08-31 15:40:02 +00:00
private bool NeedsVScrollbar { get ; set ; }
2014-08-15 00:42:03 +00:00
2014-08-30 18:42:14 +00:00
/// <summary>
/// A boolean that indicates if the InputRoll is too large horizontally and requires a horizontal scrollbar.
/// </summary>
2014-08-31 15:40:02 +00:00
private bool NeedsHScrollbar { get ; set ; }
2014-08-07 14:55:55 +00:00
2014-08-30 18:42:14 +00:00
/// <summary>
/// Updates the width of the supplied column.
/// <remarks>Call when changing the ColumnCell text, CellPadding, or text font.</remarks>
/// </summary>
/// <param name="col">The RollColumn object to update.</param>
/// <returns>The new width of the RollColumn object.</returns>
private int UpdateWidth ( RollColumn col )
2014-08-09 16:11:25 +00:00
{
2014-09-24 21:10:57 +00:00
col . Width = ( ( col . Text . Length * _charSize . Width ) + ( CellWidthPadding * 4 ) ) ;
2014-08-30 18:42:14 +00:00
return col . Width . Value ;
2014-08-08 18:30:57 +00:00
}
2014-08-31 15:40:02 +00:00
/// <summary>
/// Gets the total width of all the columns by using the last column's Right property.
/// </summary>
/// <returns>A nullable Int representing total width.</returns>
private int? TotalColWidth
{
get {
2014-10-12 16:37:45 +00:00
if ( _columns . VisibleColumns . Any ( ) )
2014-08-31 15:40:02 +00:00
{
2014-10-12 16:37:45 +00:00
return _columns . VisibleColumns . Last ( ) . Right ;
2014-08-31 15:40:02 +00:00
}
return null ;
}
}
2014-08-30 18:42:14 +00:00
/// <summary>
/// Returns the RollColumn object at the specified visible x coordinate. Coordinate should be between 0 and Width of the InputRoll Control.
/// </summary>
/// <param name="x">The x coordinate.</param>
/// <returns>RollColumn object that contains the x coordinate or null if none exists.</returns>
2014-08-11 01:49:45 +00:00
private RollColumn ColumnAtX ( int x )
{
2014-10-12 16:37:45 +00:00
foreach ( var column in _columns . VisibleColumns )
2014-08-11 01:49:45 +00:00
{
2014-08-30 18:42:14 +00:00
if ( column . Left . Value - HBar . Value < = x & & column . Right . Value - HBar . Value > = x )
2014-08-11 01:49:45 +00:00
{
return column ;
}
}
return null ;
}
2014-08-31 23:03:59 +00:00
/// <summary>
/// Converts a row number to a horizontal or vertical coordinate.
/// </summary>
/// <param name="pixels">A row number.</param>
/// <returns>A vertical coordinate if Vertical Oriented, otherwise a horizontal coordinate.</returns>
private int RowsToPixels ( int index )
{
if ( _horizontalOrientation )
{
2014-10-15 22:14:44 +00:00
return ( index * CellWidth ) + ColumnWidth ;
2014-08-31 23:03:59 +00:00
}
2014-10-15 22:14:44 +00:00
return ( index * CellHeight ) + ColumnHeight ;
2014-08-31 23:03:59 +00:00
}
/// <summary>
/// Converts a horizontal or vertical coordinate to a row number.
/// </summary>
/// <param name="pixels">A vertical coordinate if Vertical Oriented, otherwise a horizontal coordinate.</param>
/// <returns>A row number between 0 and VisibleRows if it is a Datarow, otherwise a negative number if above all Datarows.</returns>
private int PixelsToRows ( int pixels )
{
if ( _horizontalOrientation )
{
return ( pixels - ColumnWidth ) / CellWidth ;
}
return ( pixels - ColumnHeight ) / CellHeight ;
}
/// <summary>
/// The width of the largest column cell in Horizontal Orientation
/// </summary>
private int ColumnWidth { get ; set ; }
/// <summary>
/// The height of a column cell in Vertical Orientation.
/// </summary>
private int ColumnHeight { get ; set ; }
//Cell defaults
/// <summary>
/// The width of a cell in Horizontal Orientation. Only can be changed by changing the Font or CellPadding.
/// </summary>
private int CellWidth { get ; set ; }
/// <summary>
/// The height of a cell in Vertical Orientation. Only can be changed by changing the Font or CellPadding.
/// </summary>
private int CellHeight { get ; set ; }
/// <summary>
2014-09-01 15:35:48 +00:00
/// Call when _charSize, MaxCharactersInHorizontal, or CellPadding is changed.
2014-08-31 23:03:59 +00:00
/// </summary>
private void UpdateCellSize ( )
{
2014-10-15 22:14:44 +00:00
CellHeight = _charSize . Height + ( CellHeightPadding * 2 ) ;
CellWidth = ( _charSize . Width * MaxCharactersInHorizontal ) + ( CellWidthPadding * 4 ) ; // Double the padding for horizontal because it looks better
2014-08-31 23:03:59 +00:00
}
2014-08-31 17:11:47 +00:00
2014-08-07 14:55:55 +00:00
#endregion
2014-08-11 00:08:16 +00:00
#region Classes
public class RollColumns : List < RollColumn >
2014-08-07 14:55:55 +00:00
{
2014-08-23 13:19:48 +00:00
public RollColumn this [ string name ]
{
get
{
return this . SingleOrDefault ( column = > column . Name = = name ) ;
}
}
2014-10-12 16:37:45 +00:00
public IEnumerable < RollColumn > VisibleColumns
{
get
{
return this . Where ( c = > c . Visible ) ;
}
}
2014-08-18 23:50:50 +00:00
public Action ChangedCallback { get ; set ; }
private void DoChangeCallback ( )
2014-08-07 14:55:55 +00:00
{
2014-08-18 23:50:50 +00:00
if ( ChangedCallback ! = null )
2014-08-11 00:08:16 +00:00
{
2014-08-18 23:50:50 +00:00
ChangedCallback ( ) ;
}
}
2014-10-12 16:37:45 +00:00
// TODO: this shouldn't be exposed. But in order to not expose it, each RollColumn must have a chane callback, and all property changes must call it, it is quicker and easier to just call this when needed
public void ColumnsChanged ( )
2014-08-30 18:42:14 +00:00
{
int pos = 0 ;
2014-10-12 16:37:45 +00:00
var columns = VisibleColumns . ToList ( ) ;
for ( int i = 0 ; i < columns . Count ; i + + )
2014-08-30 18:42:14 +00:00
{
2014-10-12 16:37:45 +00:00
columns [ i ] . Left = pos ;
pos + = columns [ i ] . Width . Value ;
columns [ i ] . Right = pos ;
2014-08-30 18:42:14 +00:00
}
DoChangeCallback ( ) ;
}
2014-08-18 23:50:50 +00:00
public new void Add ( RollColumn column )
{
if ( this . Any ( c = > c . Name = = column . Name ) )
{
2014-08-23 15:19:48 +00:00
// The designer sucks, doing nothing for now
return ;
//throw new InvalidOperationException("A column with this name already exists.");
2014-08-18 23:50:50 +00:00
}
base . Add ( column ) ;
2014-08-30 18:42:14 +00:00
ColumnsChanged ( ) ;
2014-08-18 23:50:50 +00:00
}
public new void AddRange ( IEnumerable < RollColumn > collection )
{
foreach ( var column in collection )
{
if ( this . Any ( c = > c . Name = = column . Name ) )
{
2014-08-23 15:19:48 +00:00
// The designer sucks, doing nothing for now
return ;
2014-08-18 23:50:50 +00:00
throw new InvalidOperationException ( "A column with this name already exists." ) ;
}
}
base . AddRange ( collection ) ;
2014-08-30 18:42:14 +00:00
ColumnsChanged ( ) ;
2014-08-18 23:50:50 +00:00
}
public new void Insert ( int index , RollColumn column )
{
if ( this . Any ( c = > c . Name = = column . Name ) )
{
throw new InvalidOperationException ( "A column with this name already exists." ) ;
}
base . Insert ( index , column ) ;
2014-08-30 18:42:14 +00:00
ColumnsChanged ( ) ;
2014-08-18 23:50:50 +00:00
}
public new void InsertRange ( int index , IEnumerable < RollColumn > collection )
{
foreach ( var column in collection )
{
if ( this . Any ( c = > c . Name = = column . Name ) )
{
throw new InvalidOperationException ( "A column with this name already exists." ) ;
}
}
base . InsertRange ( index , collection ) ;
2014-08-30 18:42:14 +00:00
ColumnsChanged ( ) ;
2014-08-18 23:50:50 +00:00
}
public new bool Remove ( RollColumn column )
{
var result = base . Remove ( column ) ;
2014-08-30 18:42:14 +00:00
ColumnsChanged ( ) ;
2014-08-18 23:50:50 +00:00
return result ;
}
public new int RemoveAll ( Predicate < RollColumn > match )
{
var result = base . RemoveAll ( match ) ;
2014-08-30 18:42:14 +00:00
ColumnsChanged ( ) ;
2014-08-18 23:50:50 +00:00
return result ;
}
public new void RemoveAt ( int index )
{
base . RemoveAt ( index ) ;
2014-08-30 18:42:14 +00:00
ColumnsChanged ( ) ;
2014-08-18 23:50:50 +00:00
}
public new void RemoveRange ( int index , int count )
{
base . RemoveRange ( index , count ) ;
2014-08-30 18:42:14 +00:00
ColumnsChanged ( ) ;
2014-08-18 23:50:50 +00:00
}
public new void Clear ( )
{
base . Clear ( ) ;
2014-08-30 18:42:14 +00:00
ColumnsChanged ( ) ;
2014-08-11 00:08:16 +00:00
}
2014-08-09 16:11:25 +00:00
2014-08-11 00:08:16 +00:00
public IEnumerable < string > Groups
2014-08-09 16:11:25 +00:00
{
2014-08-11 00:08:16 +00:00
get
{
return this
. Select ( x = > x . Group )
. Distinct ( ) ;
}
2014-08-09 16:11:25 +00:00
}
}
2014-08-07 14:55:55 +00:00
2014-08-11 00:08:16 +00:00
public class RollColumn
{
public enum InputType { Boolean , Float , Text , Image }
2014-08-07 18:32:09 +00:00
2014-08-11 00:08:16 +00:00
public string Group { get ; set ; }
public int? Width { get ; set ; }
2014-08-30 18:42:14 +00:00
public int? Left { get ; set ; }
public int? Right { get ; set ; }
2014-08-11 00:08:16 +00:00
public string Name { get ; set ; }
public string Text { get ; set ; }
public InputType Type { get ; set ; }
2014-10-12 16:37:45 +00:00
public bool Visible { get ; set ; }
2014-09-25 17:24:17 +00:00
/// <summary>
/// Column will be drawn with an emphasized look, if true
/// </summary>
public bool Emphasis { get ; set ; }
2014-10-12 16:37:45 +00:00
public RollColumn ( )
{
Visible = true ;
}
2014-08-11 00:08:16 +00:00
}
2014-08-10 15:57:59 +00:00
2014-08-30 18:42:14 +00:00
/// <summary>
///
/// </summary>
2014-08-11 00:08:16 +00:00
public class Cell
{
2014-08-30 18:42:14 +00:00
public RollColumn Column { get ; internal set ; }
public int? RowIndex { get ; internal set ; }
public string CurrentText { get ; internal set ; }
2014-08-10 15:57:59 +00:00
2014-08-11 00:08:16 +00:00
public Cell ( ) { }
2014-08-10 15:57:59 +00:00
2014-08-11 00:08:16 +00:00
public Cell ( Cell cell )
{
Column = cell . Column ;
RowIndex = cell . RowIndex ;
}
2014-08-10 15:57:59 +00:00
2014-08-11 00:08:16 +00:00
public override bool Equals ( object obj )
2014-08-10 15:57:59 +00:00
{
2014-08-11 00:08:16 +00:00
if ( obj is Cell )
{
var cell = obj as Cell ;
return this . Column = = cell . Column & & this . RowIndex = = cell . RowIndex ;
}
return base . Equals ( obj ) ;
2014-08-10 15:57:59 +00:00
}
2014-08-11 00:08:16 +00:00
public override int GetHashCode ( )
{
return Column . GetHashCode ( ) + RowIndex . GetHashCode ( ) ;
}
2014-08-10 15:57:59 +00:00
}
2014-08-11 00:08:16 +00:00
#endregion
2014-08-10 15:57:59 +00:00
}
2014-08-06 01:32:27 +00:00
}