Fix noise from last merge.
This commit is contained in:
parent
e4e10646bf
commit
6eb44acd4f
|
@ -1,183 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A performant VirtualListView implementation that doesn't rely on native Win32 API calls
|
|
||||||
/// (and in fact does not inherit the ListView class at all)
|
|
||||||
/// It is an enhanced version of the work done with GDI+ rendering in InputRoll.cs
|
|
||||||
/// -------------------
|
|
||||||
/// *** API Related ***
|
|
||||||
/// -------------------
|
|
||||||
/// </summary>
|
|
||||||
public partial class PlatformAgnosticVirtualListView
|
|
||||||
{
|
|
||||||
private Cell _draggingCell;
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Parent form calls this to add columns
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="columnName"></param>
|
|
||||||
/// <param name="columnText"></param>
|
|
||||||
/// <param name="columnWidth"></param>
|
|
||||||
/// <param name="columnType"></param>
|
|
||||||
public void AddColumn(string columnName, string columnText, int columnWidth, ListColumn.InputType columnType = ListColumn.InputType.Boolean)
|
|
||||||
{
|
|
||||||
if (AllColumns[columnName] == null)
|
|
||||||
{
|
|
||||||
var column = new ListColumn
|
|
||||||
{
|
|
||||||
Name = columnName,
|
|
||||||
Text = columnText,
|
|
||||||
Width = columnWidth,
|
|
||||||
Type = columnType
|
|
||||||
};
|
|
||||||
|
|
||||||
AllColumns.Add(column);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the state of the passed row index
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="index"></param>
|
|
||||||
/// <param name="val"></param>
|
|
||||||
public void SelectItem(int index, bool val)
|
|
||||||
{
|
|
||||||
if (_columns.VisibleColumns.Any())
|
|
||||||
{
|
|
||||||
if (val)
|
|
||||||
{
|
|
||||||
SelectCell(new Cell
|
|
||||||
{
|
|
||||||
RowIndex = index,
|
|
||||||
Column = _columns[0]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
IEnumerable<Cell> items = _selectedItems.Where(cell => cell.RowIndex == index);
|
|
||||||
_selectedItems.RemoveWhere(items.Contains);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SelectAll()
|
|
||||||
{
|
|
||||||
var oldFullRowVal = FullRowSelect;
|
|
||||||
FullRowSelect = true;
|
|
||||||
for (int i = 0; i < ItemCount; i++)
|
|
||||||
{
|
|
||||||
SelectItem(i, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
FullRowSelect = oldFullRowVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DeselectAll()
|
|
||||||
{
|
|
||||||
_selectedItems.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void TruncateSelection(int index)
|
|
||||||
{
|
|
||||||
_selectedItems.RemoveWhere(cell => cell.RowIndex > index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsVisible(int index)
|
|
||||||
{
|
|
||||||
return (index >= FirstVisibleRow) && (index <= LastFullyVisibleRow);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsPartiallyVisible(int index)
|
|
||||||
{
|
|
||||||
return index >= FirstVisibleRow && index <= LastVisibleRow;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DragCurrentCell()
|
|
||||||
{
|
|
||||||
_draggingCell = CurrentCell;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ReleaseCurrentCell()
|
|
||||||
{
|
|
||||||
if (_draggingCell != null)
|
|
||||||
{
|
|
||||||
var draggedCell = _draggingCell;
|
|
||||||
_draggingCell = null;
|
|
||||||
|
|
||||||
if (CurrentCell != draggedCell)
|
|
||||||
{
|
|
||||||
CellDropped?.Invoke(this, new CellEventArgs(draggedCell, CurrentCell));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Scrolls to the given index, according to the scroll settings.
|
|
||||||
/// </summary>
|
|
||||||
public void ScrollToIndex(int index)
|
|
||||||
{
|
|
||||||
if (ScrollMethod == "near")
|
|
||||||
{
|
|
||||||
MakeIndexVisible(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsVisible(index) || AlwaysScroll)
|
|
||||||
{
|
|
||||||
if (ScrollMethod == "top")
|
|
||||||
{
|
|
||||||
FirstVisibleRow = index;
|
|
||||||
}
|
|
||||||
else if (ScrollMethod == "bottom")
|
|
||||||
{
|
|
||||||
LastVisibleRow = index;
|
|
||||||
}
|
|
||||||
else if (ScrollMethod == "center")
|
|
||||||
{
|
|
||||||
FirstVisibleRow = Math.Max(index - (VisibleRows / 2), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Scrolls so that the given index is visible, if it isn't already; doesn't use scroll settings.
|
|
||||||
/// </summary>
|
|
||||||
public void MakeIndexVisible(int index)
|
|
||||||
{
|
|
||||||
if (!IsVisible(index))
|
|
||||||
{
|
|
||||||
if (FirstVisibleRow > index)
|
|
||||||
{
|
|
||||||
FirstVisibleRow = index;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LastVisibleRow = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compatibility method from VirtualListView
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="index"></param>
|
|
||||||
public void ensureVisible()
|
|
||||||
{
|
|
||||||
if (_selectedItems.Count != 0)
|
|
||||||
MakeIndexVisible(_selectedItems.Last().RowIndex.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearSelectedRows()
|
|
||||||
{
|
|
||||||
_selectedItems.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,315 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A performant VirtualListView implementation that doesn't rely on native Win32 API calls
|
|
||||||
/// (and in fact does not inherit the ListView class at all)
|
|
||||||
/// It is an enhanced version of the work done with GDI+ rendering in InputRoll.cs
|
|
||||||
/// ---------------
|
|
||||||
/// *** Classes ***
|
|
||||||
/// ---------------
|
|
||||||
/// </summary>
|
|
||||||
public partial class PlatformAgnosticVirtualListView
|
|
||||||
{
|
|
||||||
#region Event Args
|
|
||||||
|
|
||||||
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; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ColumnClickEventArgs
|
|
||||||
{
|
|
||||||
public ColumnClickEventArgs(ListColumn column)
|
|
||||||
{
|
|
||||||
Column = column;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ListColumn Column { get; private set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ColumnReorderedEventArgs
|
|
||||||
{
|
|
||||||
public ColumnReorderedEventArgs(int oldDisplayIndex, int newDisplayIndex, ListColumn column)
|
|
||||||
{
|
|
||||||
Column = column;
|
|
||||||
OldDisplayIndex = oldDisplayIndex;
|
|
||||||
NewDisplayIndex = newDisplayIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ListColumn Column { get; private set; }
|
|
||||||
public int OldDisplayIndex { get; private set; }
|
|
||||||
public int NewDisplayIndex { get; private set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Columns
|
|
||||||
|
|
||||||
public class ListColumn
|
|
||||||
{
|
|
||||||
public enum InputType { Boolean, Float, Text, Image }
|
|
||||||
|
|
||||||
public int Index { get; set; }
|
|
||||||
public int OriginalIndex { get; set; } // for implementations that dont use ColumnReorderedEventArgs
|
|
||||||
public string Group { get; set; }
|
|
||||||
public int? Width { get; set; }
|
|
||||||
public int? Left { get; set; }
|
|
||||||
public int? Right { get; set; }
|
|
||||||
public string Name { get; set; }
|
|
||||||
public string Text { get; set; }
|
|
||||||
public InputType Type { get; set; }
|
|
||||||
public bool Visible { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Column will be drawn with an emphasized look, if true
|
|
||||||
/// </summary>
|
|
||||||
private bool _emphasis;
|
|
||||||
public bool Emphasis
|
|
||||||
{
|
|
||||||
get { return _emphasis; }
|
|
||||||
set { _emphasis = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public ListColumn()
|
|
||||||
{
|
|
||||||
Visible = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ListColumns : List<ListColumn>
|
|
||||||
{
|
|
||||||
public ListColumn this[string name]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return this.SingleOrDefault(column => column.Name == name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<ListColumn> VisibleColumns
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return this.Where(c => c.Visible);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Action ChangedCallback { get; set; }
|
|
||||||
|
|
||||||
private void DoChangeCallback()
|
|
||||||
{
|
|
||||||
// no check will make it crash for user too, not sure which way of alarm we prefer. no alarm at all will cause all sorts of subtle bugs
|
|
||||||
if (ChangedCallback == null)
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.Fail("ColumnChangedCallback has died!");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ChangedCallback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: this shouldn't be exposed. But in order to not expose it, each RollColumn must have a change callback, and all property changes must call it, it is quicker and easier to just call this when needed
|
|
||||||
public void ColumnsChanged()
|
|
||||||
{
|
|
||||||
int pos = 0;
|
|
||||||
|
|
||||||
var columns = VisibleColumns.ToList();
|
|
||||||
|
|
||||||
for (int i = 0; i < columns.Count; i++)
|
|
||||||
{
|
|
||||||
columns[i].Left = pos;
|
|
||||||
pos += columns[i].Width.Value;
|
|
||||||
columns[i].Right = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
DoChangeCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
public new void Add(ListColumn column)
|
|
||||||
{
|
|
||||||
if (this.Any(c => c.Name == column.Name))
|
|
||||||
{
|
|
||||||
// The designer sucks, doing nothing for now
|
|
||||||
return;
|
|
||||||
//throw new InvalidOperationException("A column with this name already exists.");
|
|
||||||
}
|
|
||||||
|
|
||||||
base.Add(column);
|
|
||||||
// save the original index for implementations that do not use ColumnReorderedEventArgs
|
|
||||||
column.OriginalIndex = this.IndexOf(column);
|
|
||||||
ColumnsChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public new void AddRange(IEnumerable<ListColumn> collection)
|
|
||||||
{
|
|
||||||
foreach (var column in collection)
|
|
||||||
{
|
|
||||||
if (this.Any(c => c.Name == column.Name))
|
|
||||||
{
|
|
||||||
// The designer sucks, doing nothing for now
|
|
||||||
return;
|
|
||||||
|
|
||||||
throw new InvalidOperationException("A column with this name already exists.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
base.AddRange(collection);
|
|
||||||
ColumnsChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public new void Insert(int index, ListColumn column)
|
|
||||||
{
|
|
||||||
if (this.Any(c => c.Name == column.Name))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("A column with this name already exists.");
|
|
||||||
}
|
|
||||||
|
|
||||||
base.Insert(index, column);
|
|
||||||
ColumnsChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public new void InsertRange(int index, IEnumerable<ListColumn> 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);
|
|
||||||
ColumnsChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public new bool Remove(ListColumn column)
|
|
||||||
{
|
|
||||||
var result = base.Remove(column);
|
|
||||||
ColumnsChanged();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public new int RemoveAll(Predicate<ListColumn> match)
|
|
||||||
{
|
|
||||||
var result = base.RemoveAll(match);
|
|
||||||
ColumnsChanged();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public new void RemoveAt(int index)
|
|
||||||
{
|
|
||||||
base.RemoveAt(index);
|
|
||||||
ColumnsChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public new void RemoveRange(int index, int count)
|
|
||||||
{
|
|
||||||
base.RemoveRange(index, count);
|
|
||||||
ColumnsChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public new void Clear()
|
|
||||||
{
|
|
||||||
base.Clear();
|
|
||||||
ColumnsChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<string> Groups
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return this
|
|
||||||
.Select(x => x.Group)
|
|
||||||
.Distinct();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Cells
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a single cell of the Roll
|
|
||||||
/// </summary>
|
|
||||||
public class Cell
|
|
||||||
{
|
|
||||||
public ListColumn Column { get; internal set; }
|
|
||||||
public int? RowIndex { get; internal set; }
|
|
||||||
public string CurrentText { get; internal set; }
|
|
||||||
|
|
||||||
public Cell() { }
|
|
||||||
|
|
||||||
public Cell(Cell cell)
|
|
||||||
{
|
|
||||||
Column = cell.Column;
|
|
||||||
RowIndex = cell.RowIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsDataCell => Column != null && RowIndex.HasValue;
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
if (obj is Cell)
|
|
||||||
{
|
|
||||||
var cell = obj as Cell;
|
|
||||||
return this.Column == cell.Column && this.RowIndex == cell.RowIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.Equals(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return Column.GetHashCode() + RowIndex.GetHashCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class SortCell : IComparer<Cell>
|
|
||||||
{
|
|
||||||
int IComparer<Cell>.Compare(Cell a, Cell b)
|
|
||||||
{
|
|
||||||
Cell c1 = a as Cell;
|
|
||||||
Cell c2 = b as Cell;
|
|
||||||
if (c1.RowIndex.HasValue)
|
|
||||||
{
|
|
||||||
if (c2.RowIndex.HasValue)
|
|
||||||
{
|
|
||||||
int row = c1.RowIndex.Value.CompareTo(c2.RowIndex.Value);
|
|
||||||
if (row == 0)
|
|
||||||
{
|
|
||||||
return c1.Column.Name.CompareTo(c2.Column.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c2.RowIndex.HasValue)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return c1.Column.Name.CompareTo(c2.Column.Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,531 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A performant VirtualListView implementation that doesn't rely on native Win32 API calls
|
|
||||||
/// (and in fact does not inherit the ListView class at all)
|
|
||||||
/// It is an enhanced version of the work done with GDI+ rendering in InputRoll.cs
|
|
||||||
/// ------------------------------
|
|
||||||
/// *** GDI+ Rendering Methods ***
|
|
||||||
/// ------------------------------
|
|
||||||
/// </summary>
|
|
||||||
public partial class PlatformAgnosticVirtualListView
|
|
||||||
{
|
|
||||||
// reusable Pen and Brush objects
|
|
||||||
private Pen sPen = null;
|
|
||||||
private Brush sBrush = null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when font sizes are changed
|
|
||||||
/// Recalculates cell sizes
|
|
||||||
/// </summary>
|
|
||||||
private void SetCharSize()
|
|
||||||
{
|
|
||||||
using (var g = CreateGraphics())
|
|
||||||
{
|
|
||||||
var sizeC = Size.Round(g.MeasureString("A", ColumnHeaderFont));
|
|
||||||
var sizeI = Size.Round(g.MeasureString("A", CellFont));
|
|
||||||
if (sizeC.Width > sizeI.Width)
|
|
||||||
_charSize = sizeC;
|
|
||||||
else
|
|
||||||
_charSize = sizeI;
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateCellSize();
|
|
||||||
ColumnWidth = CellWidth;
|
|
||||||
ColumnHeight = CellHeight + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// We draw everthing manually and never call base.OnPaint()
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="e"></param>
|
|
||||||
protected override void OnPaint(PaintEventArgs e)
|
|
||||||
{
|
|
||||||
// white background
|
|
||||||
sBrush = new SolidBrush(Color.White);
|
|
||||||
sPen = new Pen(Color.White);
|
|
||||||
|
|
||||||
Rectangle rect = e.ClipRectangle;
|
|
||||||
|
|
||||||
e.Graphics.FillRectangle(sBrush, rect);
|
|
||||||
e.Graphics.Flush();
|
|
||||||
|
|
||||||
var visibleColumns = _columns.VisibleColumns.ToList();
|
|
||||||
|
|
||||||
if (visibleColumns.Any())
|
|
||||||
{
|
|
||||||
DrawColumnBg(e, visibleColumns);
|
|
||||||
DrawColumnText(e, visibleColumns);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Background
|
|
||||||
DrawBg(e, visibleColumns);
|
|
||||||
|
|
||||||
// Foreground
|
|
||||||
DrawData(e, visibleColumns);
|
|
||||||
|
|
||||||
DrawColumnDrag(e);
|
|
||||||
DrawCellDrag(e);
|
|
||||||
|
|
||||||
if (BorderSize > 0)
|
|
||||||
{
|
|
||||||
// apparently mono can sometimes call OnPaint before attached to the parent??
|
|
||||||
if (this.Parent != null)
|
|
||||||
{
|
|
||||||
// paint parent border
|
|
||||||
using (var gParent = this.Parent.CreateGraphics())
|
|
||||||
{
|
|
||||||
Pen borderPen = new Pen(BorderColor);
|
|
||||||
for (int b = 1, c = 1; b <= BorderSize; b++, c += 2)
|
|
||||||
{
|
|
||||||
gParent.DrawRectangle(borderPen, this.Left - b, this.Top - b, this.Width + c, this.Height + c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawColumnDrag(PaintEventArgs e)
|
|
||||||
{
|
|
||||||
if (_draggingCell != null)
|
|
||||||
{
|
|
||||||
var text = "";
|
|
||||||
int offsetX = 0;
|
|
||||||
int offsetY = 0;
|
|
||||||
|
|
||||||
QueryItemText?.Invoke(_draggingCell.RowIndex.Value, _columns.IndexOf(_draggingCell.Column), out text);
|
|
||||||
QueryItemTextAdvanced?.Invoke(_draggingCell.RowIndex.Value, _draggingCell.Column, out text, ref offsetX, ref offsetY);
|
|
||||||
|
|
||||||
Color bgColor = ColumnHeaderBackgroundColor;
|
|
||||||
QueryItemBkColor?.Invoke(_draggingCell.RowIndex.Value, _columns.IndexOf(_draggingCell.Column), ref bgColor);
|
|
||||||
QueryItemBkColorAdvanced?.Invoke(_draggingCell.RowIndex.Value, _draggingCell.Column, ref bgColor);
|
|
||||||
|
|
||||||
int x1 = _currentX.Value - (_draggingCell.Column.Width.Value / 2);
|
|
||||||
int y1 = _currentY.Value - (CellHeight / 2);
|
|
||||||
int x2 = x1 + _draggingCell.Column.Width.Value;
|
|
||||||
int y2 = y1 + CellHeight;
|
|
||||||
|
|
||||||
sBrush = new SolidBrush(bgColor);
|
|
||||||
e.Graphics.FillRectangle(sBrush, x1, y1, x2 - x1, y2 - y1);
|
|
||||||
sBrush = new SolidBrush(ColumnHeaderFontColor);
|
|
||||||
e.Graphics.DrawString(text, ColumnHeaderFont, sBrush, (PointF)(new Point(x1 + CellWidthPadding + offsetX, y1 + CellHeightPadding + offsetY)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawCellDrag(PaintEventArgs e)
|
|
||||||
{
|
|
||||||
if (_draggingCell != null)
|
|
||||||
{
|
|
||||||
var text = "";
|
|
||||||
int offsetX = 0;
|
|
||||||
int offsetY = 0;
|
|
||||||
QueryItemText?.Invoke(_draggingCell.RowIndex.Value, _columns.IndexOf(_draggingCell.Column), out text);
|
|
||||||
QueryItemTextAdvanced?.Invoke(_draggingCell.RowIndex.Value, _draggingCell.Column, out text, ref offsetX, ref offsetY);
|
|
||||||
|
|
||||||
Color bgColor = CellBackgroundColor;
|
|
||||||
QueryItemBkColor?.Invoke(_draggingCell.RowIndex.Value, _columns.IndexOf(_draggingCell.Column), ref bgColor);
|
|
||||||
QueryItemBkColorAdvanced?.Invoke(_draggingCell.RowIndex.Value, _draggingCell.Column, ref bgColor);
|
|
||||||
|
|
||||||
int x1 = _currentX.Value - (_draggingCell.Column.Width.Value / 2);
|
|
||||||
int y1 = _currentY.Value - (CellHeight / 2);
|
|
||||||
int x2 = x1 + _draggingCell.Column.Width.Value;
|
|
||||||
int y2 = y1 + CellHeight;
|
|
||||||
|
|
||||||
sBrush = new SolidBrush(bgColor);
|
|
||||||
e.Graphics.FillRectangle(sBrush, x1, y1, x2 - x1, y2 - y1);
|
|
||||||
sBrush = new SolidBrush(CellFontColor);
|
|
||||||
e.Graphics.DrawString(text, CellFont, sBrush, (PointF)(new Point(x1 + CellWidthPadding + offsetX, y1 + CellHeightPadding + offsetY)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawColumnText(PaintEventArgs e, List<ListColumn> visibleColumns)
|
|
||||||
{
|
|
||||||
sBrush = new SolidBrush(ColumnHeaderFontColor);
|
|
||||||
|
|
||||||
foreach (var column in visibleColumns)
|
|
||||||
{
|
|
||||||
var point = new Point(column.Left.Value + CellWidthPadding - _hBar.Value, CellHeightPadding);
|
|
||||||
|
|
||||||
string t = column.Text;
|
|
||||||
ResizeTextToFit(ref t, column.Width.Value, ColumnHeaderFont);
|
|
||||||
|
|
||||||
if (IsHoveringOnColumnCell && column == CurrentCell.Column)
|
|
||||||
{
|
|
||||||
sBrush = new SolidBrush(InvertColor(ColumnHeaderBackgroundHighlightColor));
|
|
||||||
e.Graphics.DrawString(t, ColumnHeaderFont, sBrush, (PointF)(point));
|
|
||||||
sBrush = new SolidBrush(ColumnHeaderFontColor);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
e.Graphics.DrawString(t, ColumnHeaderFont, sBrush, (PointF)(point));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawData(PaintEventArgs e, List<ListColumn> visibleColumns)
|
|
||||||
{
|
|
||||||
// Prevent exceptions with small windows
|
|
||||||
if (visibleColumns.Count == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (QueryItemText != null || QueryItemTextAdvanced != null)
|
|
||||||
{
|
|
||||||
int startRow = FirstVisibleRow;
|
|
||||||
int range = Math.Min(LastVisibleRow, ItemCount - 1) - startRow + 1;
|
|
||||||
|
|
||||||
sBrush = new SolidBrush(CellFontColor);
|
|
||||||
|
|
||||||
int xPadding = CellWidthPadding + 1 - _hBar.Value;
|
|
||||||
for (int i = 0, f = 0; f < range; i++, f++) // Vertical
|
|
||||||
{
|
|
||||||
//f += _lagFrames[i];
|
|
||||||
int LastVisible = LastVisibleColumnIndex;
|
|
||||||
for (int j = FirstVisibleColumn; j <= LastVisible; j++) // Horizontal
|
|
||||||
{
|
|
||||||
ListColumn col = visibleColumns[j];
|
|
||||||
|
|
||||||
string text = "";
|
|
||||||
int strOffsetX = 0;
|
|
||||||
int strOffsetY = 0;
|
|
||||||
Point point = new Point(col.Left.Value + xPadding, RowsToPixels(i) + CellHeightPadding);
|
|
||||||
|
|
||||||
Bitmap image = null;
|
|
||||||
int bitmapOffsetX = 0;
|
|
||||||
int bitmapOffsetY = 0;
|
|
||||||
|
|
||||||
QueryItemIcon?.Invoke(f + startRow, visibleColumns[j], ref image, ref bitmapOffsetX, ref bitmapOffsetY);
|
|
||||||
|
|
||||||
if (image != null)
|
|
||||||
{
|
|
||||||
e.Graphics.DrawImage(image, new Point(point.X + bitmapOffsetX, point.Y + bitmapOffsetY + CellHeightPadding));
|
|
||||||
}
|
|
||||||
|
|
||||||
QueryItemText?.Invoke(f + startRow, _columns.IndexOf(visibleColumns[j]), out text);
|
|
||||||
QueryItemTextAdvanced?.Invoke(f + startRow, visibleColumns[j], out text, ref strOffsetX, ref strOffsetY);
|
|
||||||
|
|
||||||
bool rePrep = false;
|
|
||||||
if (_selectedItems.Contains(new Cell { Column = visibleColumns[j], RowIndex = f + startRow }))
|
|
||||||
{
|
|
||||||
sBrush = new SolidBrush(InvertColor(CellBackgroundHighlightColor));
|
|
||||||
rePrep = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(text))
|
|
||||||
{
|
|
||||||
ResizeTextToFit(ref text, col.Width.Value, CellFont);
|
|
||||||
e.Graphics.DrawString(text, CellFont, sBrush, (PointF)(new Point(point.X + strOffsetX, point.Y + strOffsetY)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rePrep)
|
|
||||||
{
|
|
||||||
sBrush = new SolidBrush(CellFontColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ResizeTextToFit(ref string text, int destinationSize, Font font)
|
|
||||||
{
|
|
||||||
Size strLen;
|
|
||||||
using (var g = CreateGraphics())
|
|
||||||
{
|
|
||||||
strLen = Size.Round(g.MeasureString(text, font));
|
|
||||||
}
|
|
||||||
if (strLen.Width > destinationSize - CellWidthPadding)
|
|
||||||
{
|
|
||||||
// text needs trimming
|
|
||||||
List<char> chars = new List<char>();
|
|
||||||
|
|
||||||
for (int s = 0; s < text.Length; s++)
|
|
||||||
{
|
|
||||||
chars.Add(text[s]);
|
|
||||||
Size tS;
|
|
||||||
Size dotS;
|
|
||||||
using (var g = CreateGraphics())
|
|
||||||
{
|
|
||||||
tS = Size.Round(g.MeasureString(new string(chars.ToArray()), CellFont));
|
|
||||||
dotS = Size.Round(g.MeasureString(".", CellFont));
|
|
||||||
}
|
|
||||||
int dotWidth = dotS.Width * 3;
|
|
||||||
if (tS.Width >= destinationSize - CellWidthPadding - dotWidth)
|
|
||||||
{
|
|
||||||
text = new string(chars.ToArray()) + "...";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://stackoverflow.com/a/34107015/6813055
|
|
||||||
private Color InvertColor(Color color)
|
|
||||||
{
|
|
||||||
var inverted = Color.FromArgb(color.ToArgb() ^ 0xffffff);
|
|
||||||
|
|
||||||
if (inverted.R > 110 && inverted.R < 150 &&
|
|
||||||
inverted.G > 110 && inverted.G < 150 &&
|
|
||||||
inverted.B > 110 && inverted.B < 150)
|
|
||||||
{
|
|
||||||
int avg = (inverted.R + inverted.G + inverted.B) / 3;
|
|
||||||
avg = avg > 128 ? 200 : 60;
|
|
||||||
inverted = Color.FromArgb(avg, avg, avg);
|
|
||||||
}
|
|
||||||
|
|
||||||
return inverted;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawColumnBg(PaintEventArgs e, List<ListColumn> visibleColumns)
|
|
||||||
{
|
|
||||||
sBrush = new SolidBrush(ColumnHeaderBackgroundColor);
|
|
||||||
sPen = new Pen(ColumnHeaderOutlineColor);
|
|
||||||
|
|
||||||
int bottomEdge = RowsToPixels(0);
|
|
||||||
|
|
||||||
// Gray column box and black line underneath
|
|
||||||
e.Graphics.FillRectangle(sBrush, 0, 0, Width + 1, bottomEdge + 1);
|
|
||||||
e.Graphics.DrawLine(sPen, 0, 0, TotalColWidth.Value + 1, 0);
|
|
||||||
e.Graphics.DrawLine(sPen, 0, bottomEdge, TotalColWidth.Value + 1, bottomEdge);
|
|
||||||
|
|
||||||
// Vertical black seperators
|
|
||||||
for (int i = 0; i < visibleColumns.Count; i++)
|
|
||||||
{
|
|
||||||
int pos = visibleColumns[i].Left.Value - _hBar.Value;
|
|
||||||
e.Graphics.DrawLine(sPen, pos, 0, pos, bottomEdge);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw right most line
|
|
||||||
if (visibleColumns.Any())
|
|
||||||
{
|
|
||||||
int right = TotalColWidth.Value - _hBar.Value;
|
|
||||||
e.Graphics.DrawLine(sPen, right, 0, right, bottomEdge);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emphasis
|
|
||||||
foreach (var column in visibleColumns.Where(c => c.Emphasis))
|
|
||||||
{
|
|
||||||
sBrush = new SolidBrush(SystemColors.ActiveBorder);
|
|
||||||
e.Graphics.FillRectangle(sBrush, column.Left.Value + 1 - _hBar.Value, 1, column.Width.Value - 1, ColumnHeight - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the user is hovering over a column
|
|
||||||
if (IsHoveringOnColumnCell)
|
|
||||||
{
|
|
||||||
// TODO multiple selected columns
|
|
||||||
for (int i = 0; i < visibleColumns.Count; i++)
|
|
||||||
{
|
|
||||||
if (visibleColumns[i] == CurrentCell.Column)
|
|
||||||
{
|
|
||||||
// Left of column is to the right of the viewable area or right of column is to the left of the viewable area
|
|
||||||
if (visibleColumns[i].Left.Value - _hBar.Value > Width || visibleColumns[i].Right.Value - _hBar.Value < 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int left = visibleColumns[i].Left.Value - _hBar.Value;
|
|
||||||
int width = visibleColumns[i].Right.Value - _hBar.Value - left;
|
|
||||||
|
|
||||||
if (CurrentCell.Column.Emphasis)
|
|
||||||
{
|
|
||||||
sBrush = new SolidBrush(Color.FromArgb(ColumnHeaderBackgroundHighlightColor.ToArgb() + 0x00550000));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sBrush = new SolidBrush(ColumnHeaderBackgroundHighlightColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
e.Graphics.FillRectangle(sBrush, left + 1, 1, width - 1, ColumnHeight - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO refactor this and DoBackGroundCallback functions.
|
|
||||||
/// <summary>
|
|
||||||
/// Draw Gridlines and background colors using QueryItemBkColor.
|
|
||||||
/// </summary>
|
|
||||||
private void DrawBg(PaintEventArgs e, List<ListColumn> visibleColumns)
|
|
||||||
{
|
|
||||||
if (UseCustomBackground && QueryItemBkColor != null)
|
|
||||||
{
|
|
||||||
DoBackGroundCallback(e, visibleColumns);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GridLines)
|
|
||||||
{
|
|
||||||
sPen = new Pen(GridLineColor);
|
|
||||||
|
|
||||||
// Columns
|
|
||||||
int y = ColumnHeight + 1;
|
|
||||||
int? totalColWidth = TotalColWidth;
|
|
||||||
foreach (var column in visibleColumns)
|
|
||||||
{
|
|
||||||
int x = column.Left.Value - _hBar.Value;
|
|
||||||
e.Graphics.DrawLine(sPen, x, y, x, Height - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (visibleColumns.Any())
|
|
||||||
{
|
|
||||||
e.Graphics.DrawLine(sPen, totalColWidth.Value - _hBar.Value, y, totalColWidth.Value - _hBar.Value, Height - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rows
|
|
||||||
for (int i = 1; i < VisibleRows + 1; i++)
|
|
||||||
{
|
|
||||||
e.Graphics.DrawLine(sPen, 0, RowsToPixels(i), Width + 1, RowsToPixels(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_selectedItems.Any() && !HideSelection)
|
|
||||||
{
|
|
||||||
DoSelectionBG(e, visibleColumns);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Given a cell with rowindex inbetween 0 and VisibleRows, it draws the background color specified. Do not call with absolute rowindices.
|
|
||||||
/// </summary>
|
|
||||||
private void DrawCellBG(PaintEventArgs e, Color color, Cell cell, List<ListColumn> visibleColumns)
|
|
||||||
{
|
|
||||||
int x, y, w, h;
|
|
||||||
|
|
||||||
w = cell.Column.Width.Value - 1;
|
|
||||||
x = cell.Column.Left.Value - _hBar.Value + 1;
|
|
||||||
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
|
|
||||||
h = CellHeight - 1;
|
|
||||||
if (y < ColumnHeight)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x > DrawWidth || y > DrawHeight)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
} // Don't draw if off screen.
|
|
||||||
|
|
||||||
var col = cell.Column.Name;
|
|
||||||
if (color.A == 0)
|
|
||||||
{
|
|
||||||
sBrush = new SolidBrush(Color.FromArgb(255, color));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sBrush = new SolidBrush(color);
|
|
||||||
}
|
|
||||||
|
|
||||||
e.Graphics.FillRectangle(sBrush, x, y, w, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnPaintBackground(PaintEventArgs pevent)
|
|
||||||
{
|
|
||||||
// Do nothing, and this should never be called
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DoSelectionBG(PaintEventArgs e, List<ListColumn> visibleColumns)
|
|
||||||
{
|
|
||||||
// SuuperW: This allows user to see other colors in selected frames.
|
|
||||||
Color rowColor = CellBackgroundColor; // Color.White;
|
|
||||||
int _lastVisibleRow = LastVisibleRow;
|
|
||||||
int lastRow = -1;
|
|
||||||
foreach (Cell cell in _selectedItems)
|
|
||||||
{
|
|
||||||
if (cell.RowIndex > _lastVisibleRow || cell.RowIndex < FirstVisibleRow || !VisibleColumns.Contains(cell.Column))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Cell relativeCell = new Cell
|
|
||||||
{
|
|
||||||
RowIndex = cell.RowIndex - FirstVisibleRow,
|
|
||||||
Column = cell.Column,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (QueryRowBkColor != null && lastRow != cell.RowIndex.Value)
|
|
||||||
{
|
|
||||||
QueryRowBkColor(cell.RowIndex.Value, ref rowColor);
|
|
||||||
lastRow = cell.RowIndex.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
Color cellColor = rowColor;
|
|
||||||
QueryItemBkColor?.Invoke(cell.RowIndex.Value, _columns.IndexOf(cell.Column), ref cellColor);
|
|
||||||
QueryItemBkColorAdvanced?.Invoke(cell.RowIndex.Value, cell.Column, ref cellColor);
|
|
||||||
|
|
||||||
// Alpha layering for cell before selection
|
|
||||||
float alpha = (float)cellColor.A / 255;
|
|
||||||
if (cellColor.A != 255 && cellColor.A != 0)
|
|
||||||
{
|
|
||||||
cellColor = Color.FromArgb(rowColor.R - (int)((rowColor.R - cellColor.R) * alpha),
|
|
||||||
rowColor.G - (int)((rowColor.G - cellColor.G) * alpha),
|
|
||||||
rowColor.B - (int)((rowColor.B - cellColor.B) * alpha));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alpha layering for selection
|
|
||||||
alpha = 0.85f;
|
|
||||||
cellColor = Color.FromArgb(cellColor.R - (int)((cellColor.R - CellBackgroundHighlightColor.R) * alpha),
|
|
||||||
cellColor.G - (int)((cellColor.G - CellBackgroundHighlightColor.G) * alpha),
|
|
||||||
cellColor.B - (int)((cellColor.B - CellBackgroundHighlightColor.B) * alpha));
|
|
||||||
|
|
||||||
DrawCellBG(e, cellColor, relativeCell, visibleColumns);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Calls QueryItemBkColor callback for all visible cells and fills in the background of those cells.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="e"></param>
|
|
||||||
private void DoBackGroundCallback(PaintEventArgs e, List<ListColumn> visibleColumns)
|
|
||||||
{
|
|
||||||
int startIndex = FirstVisibleRow;
|
|
||||||
int range = Math.Min(LastVisibleRow, ItemCount - 1) - startIndex + 1;
|
|
||||||
int lastVisible = LastVisibleColumnIndex;
|
|
||||||
int firstVisibleColumn = FirstVisibleColumn;
|
|
||||||
// Prevent exceptions with small windows
|
|
||||||
if (firstVisibleColumn < 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (int i = 0, f = 0; f < range; i++, f++) // Vertical
|
|
||||||
{
|
|
||||||
//f += _lagFrames[i];
|
|
||||||
|
|
||||||
Color rowColor = CellBackgroundColor;
|
|
||||||
QueryRowBkColor?.Invoke(f + startIndex, ref rowColor);
|
|
||||||
|
|
||||||
for (int j = FirstVisibleColumn; j <= lastVisible; j++) // Horizontal
|
|
||||||
{
|
|
||||||
Color itemColor = CellBackgroundColor;
|
|
||||||
QueryItemBkColor?.Invoke(f + startIndex, _columns.IndexOf(visibleColumns[j]), ref itemColor);
|
|
||||||
QueryItemBkColorAdvanced?.Invoke(f + startIndex, visibleColumns[j], ref itemColor);
|
|
||||||
if (itemColor == CellBackgroundColor)
|
|
||||||
{
|
|
||||||
itemColor = rowColor;
|
|
||||||
}
|
|
||||||
else if (itemColor.A != 255 && itemColor.A != 0)
|
|
||||||
{
|
|
||||||
float alpha = (float)itemColor.A / 255;
|
|
||||||
itemColor = Color.FromArgb(rowColor.R - (int)((rowColor.R - itemColor.R) * alpha),
|
|
||||||
rowColor.G - (int)((rowColor.G - itemColor.G) * alpha),
|
|
||||||
rowColor.B - (int)((rowColor.B - itemColor.B) * alpha));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (itemColor != Color.White) // An easy optimization, don't draw unless the user specified something other than the default
|
|
||||||
{
|
|
||||||
var cell = new Cell
|
|
||||||
{
|
|
||||||
Column = visibleColumns[j],
|
|
||||||
RowIndex = i
|
|
||||||
};
|
|
||||||
DrawCellBG(e, itemColor, cell, visibleColumns);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,703 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A performant VirtualListView implementation that doesn't rely on native Win32 API calls
|
|
||||||
/// (and in fact does not inherit the ListView class at all)
|
|
||||||
/// It is an enhanced version of the work done with GDI+ rendering in InputRoll.cs
|
|
||||||
/// -----------------------------------
|
|
||||||
/// *** Events ***
|
|
||||||
/// -----------------------------------
|
|
||||||
/// </summary>
|
|
||||||
public partial class PlatformAgnosticVirtualListView
|
|
||||||
{
|
|
||||||
#region Event Handlers
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Fire the <see cref="QueryItemText"/> event which requests the text for the passed cell
|
|
||||||
/// </summary>
|
|
||||||
[Category("Virtual")]
|
|
||||||
public event QueryItemTextHandler QueryItemText;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Fire the <see cref="QueryItemTextAdvanced"/> event which requests the text for the passed cell
|
|
||||||
/// </summary>
|
|
||||||
[Category("Virtual")]
|
|
||||||
public event QueryItemTextHandlerAdvanced QueryItemTextAdvanced;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Fire the <see cref="QueryItemBkColor"/> event which requests the background color for the passed cell
|
|
||||||
/// </summary>
|
|
||||||
[Category("Virtual")]
|
|
||||||
public event QueryItemBkColorHandler QueryItemBkColor;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Fire the <see cref="QueryItemBkColorAdvanced"/> event which requests the background color for the passed cell
|
|
||||||
/// </summary>
|
|
||||||
[Category("Virtual")]
|
|
||||||
public event QueryItemBkColorHandlerAdvanced QueryItemBkColorAdvanced;
|
|
||||||
|
|
||||||
[Category("Virtual")]
|
|
||||||
public event QueryRowBkColorHandler QueryRowBkColor;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Fire the <see cref="QueryItemIconHandler"/> event which requests an icon for a given cell
|
|
||||||
/// </summary>
|
|
||||||
[Category("Virtual")]
|
|
||||||
public event QueryItemIconHandler QueryItemIcon;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Fires when the mouse moves from one cell to another (including column header cells)
|
|
||||||
/// </summary>
|
|
||||||
[Category("Mouse")]
|
|
||||||
public event CellChangeEventHandler PointedCellChanged;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Fires when a cell is hovered on
|
|
||||||
/// </summary>
|
|
||||||
[Category("Mouse")]
|
|
||||||
public event HoverEventHandler CellHovered;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Occurs when a column header is clicked
|
|
||||||
/// </summary>
|
|
||||||
[Category("Action")]
|
|
||||||
public event ColumnClickEventHandler ColumnClick;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Occurs when a column header is right-clicked
|
|
||||||
/// </summary>
|
|
||||||
[Category("Action")]
|
|
||||||
public event ColumnClickEventHandler ColumnRightClick;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Occurs whenever the 'SelectedItems' property for this control changes
|
|
||||||
/// </summary>
|
|
||||||
[Category("Behavior")]
|
|
||||||
public event EventHandler SelectedIndexChanged;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Occurs whenever the mouse wheel is scrolled while the right mouse button is held
|
|
||||||
/// </summary>
|
|
||||||
[Category("Behavior")]
|
|
||||||
public event RightMouseScrollEventHandler RightMouseScrolled;
|
|
||||||
|
|
||||||
[Category("Property Changed")]
|
|
||||||
[Description("Occurs when the column header has been reordered")]
|
|
||||||
public event ColumnReorderedEventHandler ColumnReordered;
|
|
||||||
|
|
||||||
[Category("Action")]
|
|
||||||
[Description("Occurs when the scroll value of the visible rows change (in vertical orientation this is the vertical scroll bar change, and in horizontal it is the horizontal scroll bar)")]
|
|
||||||
public event RowScrollEvent RowScroll;
|
|
||||||
|
|
||||||
[Category("Action")]
|
|
||||||
[Description("Occurs when the scroll value of the columns (in vertical orientation this is the horizontal scroll bar change, and in horizontal it is the vertical scroll bar)")]
|
|
||||||
public event ColumnScrollEvent ColumnScroll;
|
|
||||||
|
|
||||||
[Category("Action")]
|
|
||||||
[Description("Occurs when a cell is dragged and then dropped into a new cell, old cell is the cell that was being dragged, new cell is its new destination")]
|
|
||||||
public event CellDroppedEvent CellDropped;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Delegates
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieve the text for a cell
|
|
||||||
/// </summary>
|
|
||||||
public delegate void QueryItemTextHandlerAdvanced(int index, ListColumn column, out string text, ref int offsetX, ref int offsetY);
|
|
||||||
public delegate void QueryItemTextHandler(int index, int column, out string text);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieve the background color for a cell
|
|
||||||
/// </summary>
|
|
||||||
public delegate void QueryItemBkColorHandlerAdvanced(int index, ListColumn column, ref Color color);
|
|
||||||
public delegate void QueryItemBkColorHandler(int index, int column, ref Color color);
|
|
||||||
public delegate void QueryRowBkColorHandler(int index, ref Color color);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieve the image for a given cell
|
|
||||||
/// </summary>
|
|
||||||
public delegate void QueryItemIconHandler(int index, ListColumn column, ref Bitmap icon, ref int offsetX, ref int offsetY);
|
|
||||||
|
|
||||||
public delegate void CellChangeEventHandler(object sender, CellEventArgs e);
|
|
||||||
|
|
||||||
public delegate void HoverEventHandler(object sender, CellEventArgs e);
|
|
||||||
|
|
||||||
public delegate void RightMouseScrollEventHandler(object sender, MouseEventArgs e);
|
|
||||||
|
|
||||||
public delegate void ColumnClickEventHandler(object sender, ColumnClickEventArgs e);
|
|
||||||
|
|
||||||
public delegate void ColumnReorderedEventHandler(object sender, ColumnReorderedEventArgs e);
|
|
||||||
|
|
||||||
public delegate void RowScrollEvent(object sender, EventArgs e);
|
|
||||||
|
|
||||||
public delegate void ColumnScrollEvent(object sender, EventArgs e);
|
|
||||||
|
|
||||||
public delegate void CellDroppedEvent(object sender, CellEventArgs e);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Mouse and Key Events
|
|
||||||
|
|
||||||
private bool _columnDownMoved;
|
|
||||||
|
|
||||||
protected override void OnMouseMove(MouseEventArgs e)
|
|
||||||
{
|
|
||||||
_currentX = e.X;
|
|
||||||
_currentY = e.Y;
|
|
||||||
|
|
||||||
if (_columnDown != null)
|
|
||||||
{
|
|
||||||
_columnDownMoved = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Cell newCell = CalculatePointedCell(_currentX.Value, _currentY.Value);
|
|
||||||
|
|
||||||
newCell.RowIndex += FirstVisibleRow;
|
|
||||||
if (newCell.RowIndex < 0)
|
|
||||||
{
|
|
||||||
newCell.RowIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!newCell.Equals(CurrentCell))
|
|
||||||
{
|
|
||||||
CellChanged(newCell);
|
|
||||||
|
|
||||||
if (IsHoveringOnColumnCell ||
|
|
||||||
(WasHoveringOnColumnCell && !IsHoveringOnColumnCell))
|
|
||||||
{
|
|
||||||
Refresh();
|
|
||||||
}
|
|
||||||
else if (_columnDown != null)
|
|
||||||
{
|
|
||||||
Refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (_columnDown != null) // Kind of silly feeling to have this check twice, but the only alternative I can think of has it refreshing twice when pointed column changes with column down, and speed matters
|
|
||||||
{
|
|
||||||
Refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_columnSeparatorDown != null)
|
|
||||||
{
|
|
||||||
// column is being resized
|
|
||||||
DoColumnResize();
|
|
||||||
Refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
// cursor changes
|
|
||||||
if (IsHoveringOnDraggableColumnDivide && AllowColumnResize)
|
|
||||||
Cursor.Current = Cursors.VSplit;
|
|
||||||
else if (IsHoveringOnColumnCell && AllowColumnReorder)
|
|
||||||
Cursor.Current = Cursors.Hand;
|
|
||||||
else
|
|
||||||
Cursor.Current = Cursors.Default;
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
_currentX = null;
|
|
||||||
_currentY = null;
|
|
||||||
CurrentCell = null;
|
|
||||||
IsPaintDown = false;
|
|
||||||
_hoverTimer.Stop();
|
|
||||||
Cursor.Current = Cursors.Default;
|
|
||||||
Refresh();
|
|
||||||
base.OnMouseLeave(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO add query callback of whether to select the cell or not
|
|
||||||
protected override void OnMouseDown(MouseEventArgs e)
|
|
||||||
{
|
|
||||||
if (!GlobalWin.MainForm.EmulatorPaused && _currentX.HasValue)
|
|
||||||
{
|
|
||||||
// copypaste from OnMouseMove()
|
|
||||||
Cell newCell = CalculatePointedCell(_currentX.Value, _currentY.Value);
|
|
||||||
|
|
||||||
newCell.RowIndex += FirstVisibleRow;
|
|
||||||
if (newCell.RowIndex < 0)
|
|
||||||
{
|
|
||||||
newCell.RowIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!newCell.Equals(CurrentCell))
|
|
||||||
{
|
|
||||||
CellChanged(newCell);
|
|
||||||
|
|
||||||
if (IsHoveringOnColumnCell ||
|
|
||||||
(WasHoveringOnColumnCell && !IsHoveringOnColumnCell))
|
|
||||||
{
|
|
||||||
Refresh();
|
|
||||||
}
|
|
||||||
else if (_columnDown != null)
|
|
||||||
{
|
|
||||||
Refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (_columnDown != null)
|
|
||||||
{
|
|
||||||
Refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.Button == MouseButtons.Left)
|
|
||||||
{
|
|
||||||
if (IsHoveringOnDraggableColumnDivide && AllowColumnResize)
|
|
||||||
{
|
|
||||||
_columnSeparatorDown = ColumnAtX(_currentX.Value);
|
|
||||||
}
|
|
||||||
else if (IsHoveringOnColumnCell && AllowColumnReorder)
|
|
||||||
{
|
|
||||||
_columnDown = CurrentCell.Column;
|
|
||||||
}
|
|
||||||
else if (InputPaintingMode)
|
|
||||||
{
|
|
||||||
IsPaintDown = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.Button == MouseButtons.Right)
|
|
||||||
{
|
|
||||||
if (!IsHoveringOnColumnCell)
|
|
||||||
{
|
|
||||||
RightButtonHeld = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.Button == MouseButtons.Left)
|
|
||||||
{
|
|
||||||
if (IsHoveringOnDataCell)
|
|
||||||
{
|
|
||||||
if (ModifierKeys == Keys.Alt)
|
|
||||||
{
|
|
||||||
// do marker drag here
|
|
||||||
}
|
|
||||||
else if (ModifierKeys == Keys.Shift && (CurrentCell.Column.Type == ListColumn.InputType.Text))
|
|
||||||
{
|
|
||||||
if (_selectedItems.Any())
|
|
||||||
{
|
|
||||||
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()
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SelectCell(CurrentCell);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (ModifierKeys == Keys.Control && (CurrentCell.Column.Type == ListColumn.InputType.Text))
|
|
||||||
{
|
|
||||||
SelectCell(CurrentCell, toggle: true);
|
|
||||||
}
|
|
||||||
else if (ModifierKeys != Keys.Shift)
|
|
||||||
{
|
|
||||||
var hadIndex = _selectedItems.Any();
|
|
||||||
_selectedItems.Clear();
|
|
||||||
SelectCell(CurrentCell);
|
|
||||||
}
|
|
||||||
|
|
||||||
Refresh();
|
|
||||||
|
|
||||||
SelectedIndexChanged?.Invoke(this, new EventArgs());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
base.OnMouseDown(e);
|
|
||||||
|
|
||||||
if (AllowRightClickSelecton && e.Button == MouseButtons.Right)
|
|
||||||
{
|
|
||||||
if (!IsHoveringOnColumnCell)
|
|
||||||
{
|
|
||||||
_currentX = e.X;
|
|
||||||
_currentY = e.Y;
|
|
||||||
Cell newCell = CalculatePointedCell(_currentX.Value, _currentY.Value);
|
|
||||||
newCell.RowIndex += FirstVisibleRow;
|
|
||||||
CellChanged(newCell);
|
|
||||||
SelectCell(CurrentCell);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnMouseUp(MouseEventArgs e)
|
|
||||||
{
|
|
||||||
if (_columnSeparatorDown != null && AllowColumnResize)
|
|
||||||
{
|
|
||||||
DoColumnResize();
|
|
||||||
Refresh();
|
|
||||||
}
|
|
||||||
else if (IsHoveringOnColumnCell && AllowColumnReorder)
|
|
||||||
{
|
|
||||||
if (_columnDown != null && _columnDownMoved)
|
|
||||||
{
|
|
||||||
DoColumnReorder();
|
|
||||||
_columnDown = null;
|
|
||||||
Refresh();
|
|
||||||
}
|
|
||||||
else if (e.Button == MouseButtons.Left)
|
|
||||||
{
|
|
||||||
ColumnClickEvent(ColumnAtX(e.X));
|
|
||||||
}
|
|
||||||
else if (e.Button == MouseButtons.Right)
|
|
||||||
{
|
|
||||||
ColumnRightClickEvent(ColumnAtX(e.X));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_columnDown = null;
|
|
||||||
_columnDownMoved = false;
|
|
||||||
_columnSeparatorDown = null;
|
|
||||||
RightButtonHeld = false;
|
|
||||||
IsPaintDown = false;
|
|
||||||
base.OnMouseUp(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void IncrementScrollBar(ScrollBar bar, bool increment)
|
|
||||||
{
|
|
||||||
int newVal;
|
|
||||||
if (increment)
|
|
||||||
{
|
|
||||||
newVal = bar.Value + (bar.SmallChange * ScrollSpeed);
|
|
||||||
if (newVal > bar.Maximum - bar.LargeChange)
|
|
||||||
{
|
|
||||||
newVal = bar.Maximum - bar.LargeChange;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
newVal = bar.Value - (bar.SmallChange * ScrollSpeed);
|
|
||||||
if (newVal < 0)
|
|
||||||
{
|
|
||||||
newVal = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_programmaticallyUpdatingScrollBarValues = true;
|
|
||||||
bar.Value = newVal;
|
|
||||||
_programmaticallyUpdatingScrollBarValues = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnMouseWheel(MouseEventArgs e)
|
|
||||||
{
|
|
||||||
IncrementScrollBar(_vBar, e.Delta < 0);
|
|
||||||
if (_currentX != null)
|
|
||||||
{
|
|
||||||
OnMouseMove(new MouseEventArgs(MouseButtons.None, 0, _currentX.Value, _currentY.Value, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
Refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DoRightMouseScroll(object sender, MouseEventArgs e)
|
|
||||||
{
|
|
||||||
RightMouseScrolled?.Invoke(sender, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ColumnClickEvent(ListColumn column)
|
|
||||||
{
|
|
||||||
ColumnClick?.Invoke(this, new ColumnClickEventArgs(column));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ColumnRightClickEvent(ListColumn column)
|
|
||||||
{
|
|
||||||
ColumnRightClick?.Invoke(this, new ColumnClickEventArgs(column));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnKeyDown(KeyEventArgs e)
|
|
||||||
{
|
|
||||||
if (!SuspendHotkeys)
|
|
||||||
{
|
|
||||||
if (e.Control && !e.Alt && e.Shift && e.KeyCode == Keys.F) // Ctrl+Shift+F
|
|
||||||
{
|
|
||||||
//HorizontalOrientation ^= true;
|
|
||||||
}
|
|
||||||
// Scroll
|
|
||||||
else if (!e.Control && !e.Alt && !e.Shift && e.KeyCode == Keys.PageUp) // Page Up
|
|
||||||
{
|
|
||||||
if (FirstVisibleRow > 0)
|
|
||||||
{
|
|
||||||
LastVisibleRow = FirstVisibleRow;
|
|
||||||
Refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!e.Control && !e.Alt && !e.Shift && e.KeyCode == Keys.PageDown) // Page Down
|
|
||||||
{
|
|
||||||
var totalRows = LastVisibleRow - FirstVisibleRow;
|
|
||||||
if (totalRows <= ItemCount)
|
|
||||||
{
|
|
||||||
var final = LastVisibleRow + totalRows;
|
|
||||||
if (final > ItemCount)
|
|
||||||
{
|
|
||||||
final = ItemCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
LastVisibleRow = final;
|
|
||||||
Refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!e.Control && !e.Alt && !e.Shift && e.KeyCode == Keys.Home) // Home
|
|
||||||
{
|
|
||||||
FirstVisibleRow = 0;
|
|
||||||
Refresh();
|
|
||||||
}
|
|
||||||
else if (!e.Control && !e.Alt && !e.Shift && e.KeyCode == Keys.End) // End
|
|
||||||
{
|
|
||||||
LastVisibleRow = ItemCount;
|
|
||||||
Refresh();
|
|
||||||
}
|
|
||||||
else if (!e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Up) // Up
|
|
||||||
{
|
|
||||||
if (FirstVisibleRow > 0)
|
|
||||||
{
|
|
||||||
FirstVisibleRow--;
|
|
||||||
Refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Down) // Down
|
|
||||||
{
|
|
||||||
if (FirstVisibleRow < ItemCount - 1)
|
|
||||||
{
|
|
||||||
FirstVisibleRow++;
|
|
||||||
Refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Selection courser
|
|
||||||
else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Up) // Ctrl + Up
|
|
||||||
{
|
|
||||||
if (SelectedRows.Any() && LetKeysModifySelection && SelectedRows.First() > 0)
|
|
||||||
{
|
|
||||||
foreach (var row in SelectedRows.ToList())
|
|
||||||
{
|
|
||||||
SelectItem(row - 1, true);
|
|
||||||
SelectItem(row, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Down) // Ctrl + Down
|
|
||||||
{
|
|
||||||
if (SelectedRows.Any() && LetKeysModifySelection)
|
|
||||||
{
|
|
||||||
foreach (var row in SelectedRows.Reverse().ToList())
|
|
||||||
{
|
|
||||||
SelectItem(row + 1, true);
|
|
||||||
SelectItem(row, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Left) // Ctrl + Left
|
|
||||||
{
|
|
||||||
if (SelectedRows.Any() && LetKeysModifySelection)
|
|
||||||
{
|
|
||||||
SelectItem(SelectedRows.Last(), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Right) // Ctrl + Right
|
|
||||||
{
|
|
||||||
if (SelectedRows.Any() && LetKeysModifySelection && SelectedRows.Last() < _itemCount - 1)
|
|
||||||
{
|
|
||||||
SelectItem(SelectedRows.Last() + 1, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (e.Control && e.Shift && !e.Alt && e.KeyCode == Keys.Left) // Ctrl + Shift + Left
|
|
||||||
{
|
|
||||||
if (SelectedRows.Any() && LetKeysModifySelection && SelectedRows.First() > 0)
|
|
||||||
{
|
|
||||||
SelectItem(SelectedRows.First() - 1, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (e.Control && e.Shift && !e.Alt && e.KeyCode == Keys.Right) // Ctrl + Shift + Right
|
|
||||||
{
|
|
||||||
if (SelectedRows.Any() && LetKeysModifySelection)
|
|
||||||
{
|
|
||||||
SelectItem(SelectedRows.First(), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.PageUp) // Ctrl + Page Up
|
|
||||||
{
|
|
||||||
//jump to above marker with selection courser
|
|
||||||
if (LetKeysModifySelection)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.PageDown) // Ctrl + Page Down
|
|
||||||
{
|
|
||||||
//jump to below marker with selection courser
|
|
||||||
if (LetKeysModifySelection)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Home) // Ctrl + Home
|
|
||||||
{
|
|
||||||
//move selection courser to frame 0
|
|
||||||
if (LetKeysModifySelection)
|
|
||||||
{
|
|
||||||
DeselectAll();
|
|
||||||
SelectItem(0, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.End) // Ctrl + End
|
|
||||||
{
|
|
||||||
//move selection courser to end of movie
|
|
||||||
if (LetKeysModifySelection)
|
|
||||||
{
|
|
||||||
DeselectAll();
|
|
||||||
SelectItem(ItemCount - 1, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
base.OnKeyDown(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Change Events
|
|
||||||
|
|
||||||
protected override void OnResize(EventArgs e)
|
|
||||||
{
|
|
||||||
RecalculateScrollBars();
|
|
||||||
if (BorderSize > 0 && this.Parent != null)
|
|
||||||
{
|
|
||||||
// refresh the parent control to regen the border
|
|
||||||
this.Parent.Refresh();
|
|
||||||
}
|
|
||||||
base.OnResize(e);
|
|
||||||
Refresh();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Call this function to change the CurrentCell to newCell
|
|
||||||
/// </summary>
|
|
||||||
private void CellChanged(Cell newCell)
|
|
||||||
{
|
|
||||||
LastCell = CurrentCell;
|
|
||||||
CurrentCell = newCell;
|
|
||||||
|
|
||||||
if (PointedCellChanged != null &&
|
|
||||||
(LastCell.Column != CurrentCell.Column || LastCell.RowIndex != CurrentCell.RowIndex))
|
|
||||||
{
|
|
||||||
PointedCellChanged(this, new CellEventArgs(LastCell, CurrentCell));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CurrentCell?.Column != null && CurrentCell.RowIndex.HasValue)
|
|
||||||
{
|
|
||||||
_hoverTimer.Start();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_hoverTimer.Stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void VerticalBar_ValueChanged(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (!_programmaticallyUpdatingScrollBarValues)
|
|
||||||
{
|
|
||||||
Refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
RowScroll?.Invoke(this, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HorizontalBar_ValueChanged(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (!_programmaticallyUpdatingScrollBarValues)
|
|
||||||
{
|
|
||||||
Refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnScroll?.Invoke(this, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ColumnChangedCallback()
|
|
||||||
{
|
|
||||||
RecalculateScrollBars();
|
|
||||||
if (_columns.VisibleColumns.Any())
|
|
||||||
{
|
|
||||||
ColumnWidth = _columns.VisibleColumns.Max(c => c.Width.Value) + CellWidthPadding * 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,359 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A performant VirtualListView implementation that doesn't rely on native Win32 API calls
|
|
||||||
/// (and in fact does not inherit the ListView class at all)
|
|
||||||
/// It is an enhanced version of the work done with GDI+ rendering in InputRoll.cs
|
|
||||||
/// ----------------------
|
|
||||||
/// *** Helper Methods ***
|
|
||||||
/// ----------------------
|
|
||||||
/// </summary>
|
|
||||||
public partial class PlatformAgnosticVirtualListView
|
|
||||||
{
|
|
||||||
// TODO: Make into an extension method
|
|
||||||
private static Color Add(Color color, int val)
|
|
||||||
{
|
|
||||||
var col = color.ToArgb();
|
|
||||||
col += val;
|
|
||||||
return Color.FromArgb(col);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DoColumnReorder()
|
|
||||||
{
|
|
||||||
if (_columnDown != CurrentCell.Column)
|
|
||||||
{
|
|
||||||
var oldIndex = _columns.IndexOf(_columnDown);
|
|
||||||
var newIndex = _columns.IndexOf(CurrentCell.Column);
|
|
||||||
|
|
||||||
ColumnReordered?.Invoke(this, new ColumnReorderedEventArgs(oldIndex, newIndex, _columnDown));
|
|
||||||
|
|
||||||
_columns.Remove(_columnDown);
|
|
||||||
_columns.Insert(newIndex, _columnDown);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Helper method for implementations that do not make use of ColumnReorderedEventArgs related callbacks
|
|
||||||
/// Basically, each column stores its initial index when added in .OriginalIndex
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="currIndex"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public int GetOriginalColumnIndex(int currIndex)
|
|
||||||
{
|
|
||||||
return AllColumns[currIndex].OriginalIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScrollBar.Maximum = DesiredValue + ScrollBar.LargeChange - 1
|
|
||||||
// See MSDN Page for more information on the dumb ScrollBar.Maximum Property
|
|
||||||
private void RecalculateScrollBars()
|
|
||||||
{
|
|
||||||
if (_vBar == null || _hBar == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
UpdateDrawSize();
|
|
||||||
|
|
||||||
var columns = _columns.VisibleColumns.ToList();
|
|
||||||
|
|
||||||
if (CellHeight == 0) CellHeight++;
|
|
||||||
NeedsVScrollbar = ItemCount > 1;
|
|
||||||
NeedsHScrollbar = TotalColWidth.HasValue && TotalColWidth.Value - DrawWidth + 1 > 0;
|
|
||||||
|
|
||||||
UpdateDrawSize();
|
|
||||||
if (VisibleRows > 0)
|
|
||||||
{
|
|
||||||
_vBar.Maximum = Math.Max((VisibleRows - 1) * CellHeight, _vBar.Maximum); // ScrollBar.Maximum is dumb
|
|
||||||
_vBar.LargeChange = (VisibleRows - 1) * CellHeight;
|
|
||||||
// DrawWidth can be negative if the TAStudio window is small enough
|
|
||||||
// Clamp LargeChange to 0 here to prevent exceptions
|
|
||||||
_hBar.LargeChange = Math.Max(0, DrawWidth / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update VBar
|
|
||||||
if (NeedsVScrollbar)
|
|
||||||
{
|
|
||||||
_vBar.Maximum = RowsToPixels(ItemCount + 1) - (CellHeight * 3) + _vBar.LargeChange - 1;
|
|
||||||
|
|
||||||
_vBar.Location = new Point(Width - _vBar.Width, 0);
|
|
||||||
_vBar.Height = Height;
|
|
||||||
_vBar.Visible = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_vBar.Visible = false;
|
|
||||||
_vBar.Value = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update HBar
|
|
||||||
if (NeedsHScrollbar)
|
|
||||||
{
|
|
||||||
_hBar.Maximum = TotalColWidth.Value - DrawWidth + _hBar.LargeChange;
|
|
||||||
|
|
||||||
_hBar.Location = new Point(0, Height - _hBar.Height);
|
|
||||||
_hBar.Width = Width - (NeedsVScrollbar ? (_vBar.Width + 1) : 0);
|
|
||||||
_hBar.Visible = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_hBar.Visible = false;
|
|
||||||
_hBar.Value = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateDrawSize()
|
|
||||||
{
|
|
||||||
if (NeedsVScrollbar)
|
|
||||||
{
|
|
||||||
DrawWidth = Width - _vBar.Width;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DrawWidth = Width;
|
|
||||||
}
|
|
||||||
if (NeedsHScrollbar)
|
|
||||||
{
|
|
||||||
DrawHeight = Height - _hBar.Height;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DrawHeight = Height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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>
|
|
||||||
private void SelectCell(Cell cell, bool toggle = false)
|
|
||||||
{
|
|
||||||
if (cell.RowIndex.HasValue && cell.RowIndex < ItemCount)
|
|
||||||
{
|
|
||||||
if (!MultiSelect)
|
|
||||||
{
|
|
||||||
_selectedItems.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FullRowSelect)
|
|
||||||
{
|
|
||||||
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();
|
|
||||||
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
_selectedItems.Remove(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var column in _columns)
|
|
||||||
{
|
|
||||||
_selectedItems.Add(new Cell
|
|
||||||
{
|
|
||||||
RowIndex = cell.RowIndex,
|
|
||||||
Column = column
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (toggle && _selectedItems.Any(x => x.RowIndex.HasValue && x.RowIndex == cell.RowIndex))
|
|
||||||
{
|
|
||||||
var item = _selectedItems
|
|
||||||
.FirstOrDefault(x => x.Equals(cell));
|
|
||||||
|
|
||||||
if (item != null)
|
|
||||||
{
|
|
||||||
_selectedItems.Remove(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_selectedItems.Add(CurrentCell);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsHoveringOnDraggableColumnDivide =>
|
|
||||||
IsHoveringOnColumnCell &&
|
|
||||||
((_currentX <= CurrentCell.Column.Left + 2 && CurrentCell.Column.Index != 0) ||
|
|
||||||
(_currentX >= CurrentCell.Column.Right - 2 && CurrentCell.Column.Index != _columns.Count - 1));
|
|
||||||
|
|
||||||
private bool IsHoveringOnColumnCell => CurrentCell?.Column != null && !CurrentCell.RowIndex.HasValue;
|
|
||||||
|
|
||||||
private bool IsHoveringOnDataCell => CurrentCell?.Column != null && CurrentCell.RowIndex.HasValue;
|
|
||||||
|
|
||||||
private bool WasHoveringOnColumnCell => LastCell?.Column != null && !LastCell.RowIndex.HasValue;
|
|
||||||
|
|
||||||
private bool WasHoveringOnDataCell => LastCell?.Column != null && LastCell.RowIndex.HasValue;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Finds the specific cell that contains the (x, y) coordinate.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>The row number that it returns will be between 0 and VisibleRows, NOT the absolute row number.</remarks>
|
|
||||||
/// <param name="x">X coordinate point.</param>
|
|
||||||
/// <param name="y">Y coordinate point.</param>
|
|
||||||
/// <returns>The cell with row number and RollColumn reference, both of which can be null. </returns>
|
|
||||||
private Cell CalculatePointedCell(int x, int y)
|
|
||||||
{
|
|
||||||
var newCell = new Cell();
|
|
||||||
var columns = _columns.VisibleColumns.ToList();
|
|
||||||
|
|
||||||
// If pointing to a column header
|
|
||||||
if (columns.Any())
|
|
||||||
{
|
|
||||||
newCell.RowIndex = PixelsToRows(y);
|
|
||||||
newCell.Column = ColumnAtX(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(IsPaintDown || RightButtonHeld) && newCell.RowIndex <= -1) // -2 if we're entering from the top
|
|
||||||
{
|
|
||||||
newCell.RowIndex = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return newCell;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void CalculateColumnToResize()
|
|
||||||
{
|
|
||||||
// if this is reached, we are already over a selectable column divide
|
|
||||||
_columnSeparatorDown = ColumnAtX(_currentX.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DoColumnResize()
|
|
||||||
{
|
|
||||||
var widthChange = _currentX - _columnSeparatorDown.Right;
|
|
||||||
_columnSeparatorDown.Width += widthChange;
|
|
||||||
if (_columnSeparatorDown.Width < MinimumColumnSize)
|
|
||||||
_columnSeparatorDown.Width = MinimumColumnSize;
|
|
||||||
AllColumns.ColumnsChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
// A boolean that indicates if the InputRoll is too large vertically and requires a vertical scrollbar.
|
|
||||||
private bool NeedsVScrollbar { get; set; }
|
|
||||||
|
|
||||||
// A boolean that indicates if the InputRoll is too large horizontally and requires a horizontal scrollbar.
|
|
||||||
private bool NeedsHScrollbar { get; set; }
|
|
||||||
|
|
||||||
/// <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(ListColumn col)
|
|
||||||
{
|
|
||||||
col.Width = (col.Text.Length * _charSize.Width) + (CellWidthPadding * 4);
|
|
||||||
return col.Width.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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
|
|
||||||
{
|
|
||||||
if (_columns.VisibleColumns.Any())
|
|
||||||
{
|
|
||||||
return _columns.VisibleColumns.Last().Right;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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>
|
|
||||||
private ListColumn ColumnAtX(int x)
|
|
||||||
{
|
|
||||||
foreach (ListColumn column in _columns.VisibleColumns)
|
|
||||||
{
|
|
||||||
if (column.Left.Value - _hBar.Value <= x && column.Right.Value - _hBar.Value >= x)
|
|
||||||
{
|
|
||||||
return column;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts a row number to a horizontal or vertical coordinate.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A vertical coordinate if Vertical Oriented, otherwise a horizontal coordinate.</returns>
|
|
||||||
private int RowsToPixels(int index)
|
|
||||||
{
|
|
||||||
return (index * CellHeight) + ColumnHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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)
|
|
||||||
{
|
|
||||||
// Using Math.Floor and float because integer division rounds towards 0 but we want to round down.
|
|
||||||
if (CellHeight == 0)
|
|
||||||
CellHeight++;
|
|
||||||
|
|
||||||
return (int)Math.Floor((float)(pixels - ColumnHeight) / CellHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The width of the largest column cell in Horizontal Orientation
|
|
||||||
private int ColumnWidth { get; set; }
|
|
||||||
|
|
||||||
// The height of a column cell in Vertical Orientation.
|
|
||||||
private int ColumnHeight { get; set; }
|
|
||||||
|
|
||||||
// The width of a cell in Horizontal Orientation. Only can be changed by changing the Font or CellPadding.
|
|
||||||
private int CellWidth { get; set; }
|
|
||||||
|
|
||||||
[Browsable(false)]
|
|
||||||
public int RowHeight => CellHeight;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating 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>
|
|
||||||
/// Call when _charSize, MaxCharactersInHorizontal, or CellPadding is changed.
|
|
||||||
/// </summary>
|
|
||||||
private void UpdateCellSize()
|
|
||||||
{
|
|
||||||
CellHeight = _charSize.Height + (CellHeightPadding * 2);
|
|
||||||
CellWidth = (_charSize.Width/* * MaxCharactersInHorizontal*/) + (CellWidthPadding * 4); // Double the padding for horizontal because it looks better
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
/// <summary>
|
|
||||||
/// Call when _charSize, MaxCharactersInHorizontal, or CellPadding is changed.
|
|
||||||
/// </summary>
|
|
||||||
private void UpdateColumnSize()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Number of displayed + hidden frames, if fps is as expected
|
|
||||||
private int ExpectedDisplayRange()
|
|
||||||
{
|
|
||||||
return (VisibleRows + 1); // * LagFramesToHide;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,780 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A performant VirtualListView implementation that doesn't rely on native Win32 API calls
|
|
||||||
/// (and in fact does not inherit the ListView class at all)
|
|
||||||
/// It is an enhanced version of the work done with GDI+ rendering in InputRoll.cs
|
|
||||||
/// -------------------------
|
|
||||||
/// *** Public Properties ***
|
|
||||||
/// -------------------------
|
|
||||||
/// </summary>
|
|
||||||
public partial class PlatformAgnosticVirtualListView
|
|
||||||
{
|
|
||||||
#region ListView Compatibility Properties
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This VirtualListView implementation doesn't really need this, but it is here for compatibility
|
|
||||||
/// </summary>
|
|
||||||
[Category("Behavior")]
|
|
||||||
public int VirtualListSize
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _itemCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_itemCount = value;
|
|
||||||
RecalculateScrollBars();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// ListView compatibility property
|
|
||||||
/// THIS DOES NOT WORK PROPERLY - AVOID!
|
|
||||||
/// </summary>
|
|
||||||
[System.ComponentModel.Browsable(false)]
|
|
||||||
public System.Windows.Forms.ListView.SelectedIndexCollection SelectedIndices
|
|
||||||
{
|
|
||||||
// !!! does not work properly, avoid using this in the calling implementation !!!
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var tmpListView = new System.Windows.Forms.ListView();
|
|
||||||
//tmpListView.VirtualMode = true;
|
|
||||||
//var selectedIndexCollection = new System.Windows.Forms.ListView.SelectedIndexCollection(tmpListView);
|
|
||||||
//tmpListView.VirtualListSize = ItemCount;
|
|
||||||
for (int i = 0; i < ItemCount; i++)
|
|
||||||
{
|
|
||||||
tmpListView.Items.Add(i.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
//tmpListView.Refresh();
|
|
||||||
|
|
||||||
if (AnyRowsSelected)
|
|
||||||
{
|
|
||||||
var indices = SelectedRows.ToList();
|
|
||||||
foreach (var i in indices)
|
|
||||||
{
|
|
||||||
tmpListView.SelectedIndices.Add(i);
|
|
||||||
//selectedIndexCollection.Add(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return tmpListView.SelectedIndices; // selectedIndexCollection;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compatibility property
|
|
||||||
/// With a standard ListView you can add columns in the Designer
|
|
||||||
/// We will ignore this (but leave it here for compatibility)
|
|
||||||
/// Columns must be added through the AddColumns() public method
|
|
||||||
/// </summary>
|
|
||||||
public System.Windows.Forms.ListView.ColumnHeaderCollection Columns = new System.Windows.Forms.ListView.ColumnHeaderCollection(new System.Windows.Forms.ListView());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compatibility with ListView class
|
|
||||||
/// This is not used in this implementation
|
|
||||||
/// </summary>
|
|
||||||
[Category("Behavior")]
|
|
||||||
public bool VirtualMode { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether the selected item in the control remains highlighted when the control loses focus
|
|
||||||
/// </summary>
|
|
||||||
[Category("Behavior")]
|
|
||||||
public bool HideSelection { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether the ListView uses state image behavior that is compatible with the .NET Framework 1.1 or the .NET Framework 2.0.
|
|
||||||
/// Here for ListView api compatibility (we dont care about this)
|
|
||||||
/// </summary>
|
|
||||||
[System.ComponentModel.Browsable(false)]
|
|
||||||
public bool UseCompatibleStateImageBehavior { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets how items are displayed in the control.
|
|
||||||
/// Here for ListView api compatibility (we dont care about this)
|
|
||||||
/// </summary>
|
|
||||||
public System.Windows.Forms.View View { get; set; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region VirtualListView Compatibility Properties
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Informs user that a select all event is in place, can be used in change events to wait until this is false
|
|
||||||
/// Not used in this implementation (yet)
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public bool SelectAllInProgress { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets/Sets the selected item
|
|
||||||
/// Here for compatibility with VirtualListView.cs
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public int selectedItem
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (SelectedRows.Count() == 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return SelectedRows.First();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
SelectItem(value, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Category("Behavior")]
|
|
||||||
public bool BlazingFast { get; set; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Behavior
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the amount of left and right padding on the text inside a cell
|
|
||||||
/// </summary>
|
|
||||||
[DefaultValue(3)]
|
|
||||||
[Category("Behavior")]
|
|
||||||
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; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the scrolling speed
|
|
||||||
/// </summary>
|
|
||||||
[Category("Behavior")]
|
|
||||||
public int ScrollSpeed
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (CellHeight == 0)
|
|
||||||
CellHeight++;
|
|
||||||
return _vBar.SmallChange / CellHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_vBar.SmallChange = value * CellHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether columns can be resized
|
|
||||||
/// </summary>
|
|
||||||
[Category("Behavior")]
|
|
||||||
[DefaultValue(true)]
|
|
||||||
public bool AllowColumnResize { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether columns can be reordered
|
|
||||||
/// </summary>
|
|
||||||
[Category("Behavior")]
|
|
||||||
[DefaultValue(true)]
|
|
||||||
public bool AllowColumnReorder { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether multiple items can to be selected
|
|
||||||
/// </summary>
|
|
||||||
[Category("Behavior")]
|
|
||||||
[DefaultValue(true)]
|
|
||||||
public bool MultiSelect { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether the control is in input painting mode
|
|
||||||
/// </summary>
|
|
||||||
[Category("Behavior")]
|
|
||||||
[DefaultValue(false)]
|
|
||||||
public bool InputPaintingMode { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets how the InputRoll scrolls when calling ScrollToIndex.
|
|
||||||
/// </summary>
|
|
||||||
[DefaultValue("near")]
|
|
||||||
[Category("Behavior")]
|
|
||||||
public string ScrollMethod { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating how the Intever for the hover event
|
|
||||||
/// </summary>
|
|
||||||
[DefaultValue(false)]
|
|
||||||
[Category("Behavior")]
|
|
||||||
public bool AlwaysScroll { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the lowest seek interval to activate the progress bar
|
|
||||||
/// </summary>
|
|
||||||
[Category("Behavior")]
|
|
||||||
public int SeekingCutoffInterval { get; set; }
|
|
||||||
|
|
||||||
[DefaultValue(750)]
|
|
||||||
[Category("Behavior")]
|
|
||||||
public int HoverInterval
|
|
||||||
{
|
|
||||||
get { return _hoverTimer.Interval; }
|
|
||||||
set { _hoverTimer.Interval = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets whether you can use right click to select things
|
|
||||||
/// </summary>
|
|
||||||
[Category("Behavior")]
|
|
||||||
public bool AllowRightClickSelecton { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets whether keys can modify selection
|
|
||||||
/// </summary>
|
|
||||||
[Category("Behavior")]
|
|
||||||
public bool LetKeysModifySelection { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets whether hot keys are suspended
|
|
||||||
/// </summary>
|
|
||||||
[Category("Behavior")]
|
|
||||||
public bool SuspendHotkeys { get; set; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Appearance
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether grid lines are displayed around cells
|
|
||||||
/// </summary>
|
|
||||||
[Category("Appearance")]
|
|
||||||
[DefaultValue(true)]
|
|
||||||
public bool GridLines { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether the entire row will always be selected
|
|
||||||
/// </summary>
|
|
||||||
[Category("Appearance")]
|
|
||||||
[DefaultValue(false)]
|
|
||||||
public bool FullRowSelect { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the font used for the column header text
|
|
||||||
/// Also forces a cell size re-evaluation
|
|
||||||
/// </summary>
|
|
||||||
[Category("Appearance")]
|
|
||||||
public Font ColumnHeaderFont
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_columnHeaderFont == null)
|
|
||||||
{
|
|
||||||
ColumnHeaderFont = new Font("Arial", 8, FontStyle.Bold);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _columnHeaderFont;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_columnHeaderFont = value;
|
|
||||||
SetCharSize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private Font _columnHeaderFont;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the color of the column header text
|
|
||||||
/// </summary>
|
|
||||||
[Category("Appearance")]
|
|
||||||
public Color ColumnHeaderFontColor
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_columnHeaderFontColor == null)
|
|
||||||
_columnHeaderFontColor = Color.Black;
|
|
||||||
return _columnHeaderFontColor;
|
|
||||||
}
|
|
||||||
set { _columnHeaderFontColor = value; }
|
|
||||||
}
|
|
||||||
private Color _columnHeaderFontColor;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the background color of the column header cells
|
|
||||||
/// </summary>
|
|
||||||
[Category("Appearance")]
|
|
||||||
public Color ColumnHeaderBackgroundColor
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_columnHeaderBackgroundColor == null)
|
|
||||||
_columnHeaderBackgroundColor = Color.LightGray;
|
|
||||||
return _columnHeaderBackgroundColor;
|
|
||||||
}
|
|
||||||
set { _columnHeaderBackgroundColor = value; }
|
|
||||||
}
|
|
||||||
private Color _columnHeaderBackgroundColor;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the background color of the column header cells when they are highlighted
|
|
||||||
/// </summary>
|
|
||||||
[Category("Appearance")]
|
|
||||||
public Color ColumnHeaderBackgroundHighlightColor
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_columnHeaderBackgroundHighlightColor == null)
|
|
||||||
_columnHeaderBackgroundHighlightColor = SystemColors.HighlightText;
|
|
||||||
return _columnHeaderBackgroundHighlightColor;
|
|
||||||
}
|
|
||||||
set { _columnHeaderBackgroundHighlightColor = value; }
|
|
||||||
}
|
|
||||||
private Color _columnHeaderBackgroundHighlightColor;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the color of the column header outline
|
|
||||||
/// </summary>
|
|
||||||
[Category("Appearance")]
|
|
||||||
public Color ColumnHeaderOutlineColor
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_columnHeaderOutlineColor == null)
|
|
||||||
_columnHeaderOutlineColor = Color.Black;
|
|
||||||
return _columnHeaderOutlineColor;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_columnHeaderOutlineColor = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private Color _columnHeaderOutlineColor;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the font used for every row cell
|
|
||||||
/// Also forces a cell size re-evaluation
|
|
||||||
/// </summary>
|
|
||||||
[Category("Appearance")]
|
|
||||||
public Font CellFont
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_cellFont == null)
|
|
||||||
{
|
|
||||||
CellFont = new Font("Arial", 8, FontStyle.Regular);
|
|
||||||
}
|
|
||||||
return _cellFont;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_cellFont = value;
|
|
||||||
SetCharSize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private Font _cellFont;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the color of the font used for every row cell
|
|
||||||
/// </summary>
|
|
||||||
[Category("Appearance")]
|
|
||||||
public Color CellFontColor
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_cellFontColor == null)
|
|
||||||
_cellFontColor = Color.Black;
|
|
||||||
return _cellFontColor;
|
|
||||||
}
|
|
||||||
set { _cellFontColor = value; }
|
|
||||||
}
|
|
||||||
private Color _cellFontColor;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the background color for every row cell
|
|
||||||
/// </summary>
|
|
||||||
[Category("Appearance")]
|
|
||||||
public Color CellBackgroundColor
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_cellBackgroundColor == null)
|
|
||||||
_cellBackgroundColor = Color.White;
|
|
||||||
return _cellBackgroundColor;
|
|
||||||
}
|
|
||||||
set { _cellBackgroundColor = value; }
|
|
||||||
}
|
|
||||||
private Color _cellBackgroundColor;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the background color for every row cell that is highlighted
|
|
||||||
/// </summary>
|
|
||||||
[Category("Appearance")]
|
|
||||||
public Color CellBackgroundHighlightColor
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_cellBackgroundHighlightColor == null)
|
|
||||||
_cellBackgroundHighlightColor = Color.Blue;
|
|
||||||
return _cellBackgroundHighlightColor;
|
|
||||||
}
|
|
||||||
set { _cellBackgroundHighlightColor = value; }
|
|
||||||
}
|
|
||||||
private Color _cellBackgroundHighlightColor;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the color used to draw the ListView gridlines
|
|
||||||
/// </summary>
|
|
||||||
[Category("Appearance")]
|
|
||||||
public Color GridLineColor
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_gridLineColor == null)
|
|
||||||
_gridLineColor = SystemColors.ControlLight;
|
|
||||||
return _gridLineColor;
|
|
||||||
}
|
|
||||||
set { _gridLineColor = value; }
|
|
||||||
}
|
|
||||||
private Color _gridLineColor;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the size of control's border
|
|
||||||
/// Note: this is drawn directly onto the parent control, so large values will probably look terrible
|
|
||||||
/// </summary>
|
|
||||||
[Category("Appearance")]
|
|
||||||
public int BorderSize { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines the absolute minimum column size (used when manually resizing columns)
|
|
||||||
/// </summary>
|
|
||||||
[DefaultValue(50)]
|
|
||||||
[Category("Appearance")]
|
|
||||||
public int MinimumColumnSize { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The padding property is disabled for this control (as this is handled internally)
|
|
||||||
/// </summary>
|
|
||||||
[Category("Appearance")]
|
|
||||||
public new System.Windows.Forms.Padding Padding
|
|
||||||
{
|
|
||||||
get { return new System.Windows.Forms.Padding(0); }
|
|
||||||
set { }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the color of the control's border
|
|
||||||
/// </summary>
|
|
||||||
[Category("Appearance")]
|
|
||||||
public Color BorderColor
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_borderColor == null)
|
|
||||||
_borderColor = SystemColors.InactiveBorder;
|
|
||||||
return _borderColor;
|
|
||||||
}
|
|
||||||
set { _borderColor = value; }
|
|
||||||
}
|
|
||||||
private Color _borderColor;
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region API
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// All visible columns
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public IEnumerable<ListColumn> VisibleColumns => _columns.VisibleColumns;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the sets the virtual number of rows to be displayed. Does not include the column header row.
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public int ItemCount
|
|
||||||
{
|
|
||||||
get { return _itemCount; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_itemCount = value;
|
|
||||||
RecalculateScrollBars();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns all columns including those that are not visible
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public ListColumns AllColumns => _columns;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets whether the mouse is currently over a column cell
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public bool IsPointingAtColumnHeader => IsHoveringOnColumnCell;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the index of the first selected row (null if no selection)
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public int? FirstSelectedIndex
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (AnyRowsSelected)
|
|
||||||
{
|
|
||||||
return SelectedRows.Min();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the index of the last selected row (null if no selection)
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public int? LastSelectedIndex
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (AnyRowsSelected)
|
|
||||||
{
|
|
||||||
return SelectedRows.Max();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the first visible row index, if scrolling is needed
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public int FirstVisibleRow
|
|
||||||
{
|
|
||||||
get // SuuperW: This was checking if the scroll bars were needed, which is useless because their Value is 0 if they aren't needed.
|
|
||||||
{
|
|
||||||
if (CellHeight == 0) CellHeight++;
|
|
||||||
return _vBar.Value / CellHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (NeedsVScrollbar)
|
|
||||||
{
|
|
||||||
_programmaticallyUpdatingScrollBarValues = true;
|
|
||||||
if (value * CellHeight <= _vBar.Maximum)
|
|
||||||
{
|
|
||||||
_vBar.Value = value * CellHeight;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_vBar.Value = _vBar.Maximum;
|
|
||||||
}
|
|
||||||
|
|
||||||
_programmaticallyUpdatingScrollBarValues = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the last row that is fully visible
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
private int LastFullyVisibleRow
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
int halfRow = 0;
|
|
||||||
if ((DrawHeight - ColumnHeight - 3) % CellHeight < CellHeight / 2)
|
|
||||||
{
|
|
||||||
halfRow = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FirstVisibleRow + VisibleRows - halfRow; // + CountLagFramesDisplay(VisibleRows - halfRow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the last visible row
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public int LastVisibleRow
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return FirstVisibleRow + VisibleRows; // + CountLagFramesDisplay(VisibleRows);
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
int halfRow = 0;
|
|
||||||
if ((DrawHeight - ColumnHeight - 3) % CellHeight < CellHeight / 2)
|
|
||||||
{
|
|
||||||
halfRow = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
FirstVisibleRow = Math.Max(value - (VisibleRows - halfRow), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the number of rows currently visible including partially visible rows.
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public int VisibleRows
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (CellHeight == 0) CellHeight++;
|
|
||||||
return (DrawHeight - ColumnHeight - 3) / CellHeight; // Minus three makes it work
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the first visible column index, if scrolling is needed
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public int FirstVisibleColumn
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (CellHeight == 0) CellHeight++;
|
|
||||||
var columnList = VisibleColumns.ToList();
|
|
||||||
return columnList.FindIndex(c => c.Right > _hBar.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the last visible column index, if scrolling is needed
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public int LastVisibleColumnIndex
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (CellHeight == 0) CellHeight++;
|
|
||||||
List<ListColumn> columnList = VisibleColumns.ToList();
|
|
||||||
int ret;
|
|
||||||
ret = columnList.FindLastIndex(c => c.Left <= DrawWidth + _hBar.Value);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the current Cell that the mouse was in.
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public Cell CurrentCell { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns whether the current cell is a data cell or not
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public bool CurrentCellIsDataCell => CurrentCell?.RowIndex != null && CurrentCell.Column != null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a list of selected row indexes
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public IEnumerable<int> SelectedRows
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _selectedItems
|
|
||||||
.Where(cell => cell.RowIndex.HasValue)
|
|
||||||
.Select(cell => cell.RowIndex.Value)
|
|
||||||
.Distinct();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns whether any rows are selected
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public bool AnyRowsSelected
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _selectedItems.Any(cell => cell.RowIndex.HasValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the previous Cell that the mouse was in.
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public Cell LastCell { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets whether paint down is happening
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public bool IsPaintDown { get; private set; }
|
|
||||||
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public bool UseCustomBackground { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the current draw height
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public int DrawHeight { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the current draw width
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public int DrawWidth { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets whether the right mouse button is held down
|
|
||||||
/// </summary>
|
|
||||||
[Browsable(false)]
|
|
||||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
||||||
public bool RightButtonHeld { get; private set; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,356 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A performant VirtualListView implementation that doesn't rely on native Win32 API calls
|
|
||||||
/// (and in fact does not inherit the ListView class at all)
|
|
||||||
/// It is an enhanced version of the work done with GDI+ rendering in InputRoll.cs
|
|
||||||
/// </summary>
|
|
||||||
public partial class PlatformAgnosticVirtualListView : Control
|
|
||||||
{
|
|
||||||
private readonly SortedSet<Cell> _selectedItems = new SortedSet<Cell>(new SortCell());
|
|
||||||
|
|
||||||
private readonly VScrollBar _vBar;
|
|
||||||
private readonly HScrollBar _hBar;
|
|
||||||
|
|
||||||
private readonly Timer _hoverTimer = new Timer();
|
|
||||||
|
|
||||||
private ListColumns _columns = new ListColumns();
|
|
||||||
|
|
||||||
private bool _programmaticallyUpdatingScrollBarValues;
|
|
||||||
|
|
||||||
private int _itemCount;
|
|
||||||
private Size _charSize;
|
|
||||||
|
|
||||||
private ListColumn _columnDown;
|
|
||||||
private ListColumn _columnSeparatorDown;
|
|
||||||
|
|
||||||
private int? _currentX;
|
|
||||||
private int? _currentY;
|
|
||||||
|
|
||||||
public PlatformAgnosticVirtualListView()
|
|
||||||
{
|
|
||||||
ColumnHeaderFont = new Font("Microsoft Sans Serif", 8.25F, FontStyle.Bold, GraphicsUnit.Point);
|
|
||||||
ColumnHeaderFontColor = Color.Black;
|
|
||||||
ColumnHeaderBackgroundColor = Color.LightGray;
|
|
||||||
ColumnHeaderBackgroundHighlightColor = SystemColors.HighlightText;
|
|
||||||
ColumnHeaderOutlineColor = Color.Black;
|
|
||||||
|
|
||||||
CellFont = new Font("Microsoft Sans Serif", 8.25F, FontStyle.Regular, GraphicsUnit.Point);
|
|
||||||
CellFontColor = Color.Black;
|
|
||||||
CellBackgroundColor = Color.White;
|
|
||||||
CellBackgroundHighlightColor = Color.Blue;
|
|
||||||
|
|
||||||
GridLines = true;
|
|
||||||
GridLineColor = SystemColors.ControlLight;
|
|
||||||
|
|
||||||
UseCustomBackground = true;
|
|
||||||
|
|
||||||
BorderColor = Color.DarkGray;
|
|
||||||
BorderSize = 1;
|
|
||||||
|
|
||||||
MinimumColumnSize = 50;
|
|
||||||
|
|
||||||
CellWidthPadding = 3;
|
|
||||||
CellHeightPadding = 0;
|
|
||||||
CurrentCell = null;
|
|
||||||
ScrollMethod = "near";
|
|
||||||
|
|
||||||
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
|
|
||||||
SetStyle(ControlStyles.UserPaint, true);
|
|
||||||
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
|
|
||||||
SetStyle(ControlStyles.Opaque, true);
|
|
||||||
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
|
|
||||||
|
|
||||||
_vBar = new VScrollBar
|
|
||||||
{
|
|
||||||
// Location gets calculated later (e.g. on resize)
|
|
||||||
Visible = false,
|
|
||||||
SmallChange = CellHeight,
|
|
||||||
LargeChange = CellHeight * 20
|
|
||||||
};
|
|
||||||
|
|
||||||
_hBar = new HScrollBar
|
|
||||||
{
|
|
||||||
// Location gets calculated later (e.g. on resize)
|
|
||||||
Visible = false,
|
|
||||||
SmallChange = CellWidth,
|
|
||||||
LargeChange = 20
|
|
||||||
};
|
|
||||||
|
|
||||||
Controls.Add(_vBar);
|
|
||||||
Controls.Add(_hBar);
|
|
||||||
|
|
||||||
_vBar.ValueChanged += VerticalBar_ValueChanged;
|
|
||||||
_hBar.ValueChanged += HorizontalBar_ValueChanged;
|
|
||||||
|
|
||||||
RecalculateScrollBars();
|
|
||||||
|
|
||||||
_columns.ChangedCallback = ColumnChangedCallback;
|
|
||||||
|
|
||||||
_hoverTimer.Interval = 750;
|
|
||||||
_hoverTimer.Tick += HoverTimerEventProcessor;
|
|
||||||
_hoverTimer.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HoverTimerEventProcessor(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
_hoverTimer.Stop();
|
|
||||||
|
|
||||||
CellHovered?.Invoke(this, new CellEventArgs(LastCell, CurrentCell));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Pending Removal
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
|
|
||||||
//private readonly byte[] _lagFrames = new byte[256]; // Large enough value that it shouldn't ever need resizing. // apparently not large enough for 4K
|
|
||||||
|
|
||||||
private int _maxCharactersInHorizontal = 1;
|
|
||||||
private bool _horizontalOrientation;
|
|
||||||
|
|
||||||
public string UserSettingsSerialized()
|
|
||||||
{
|
|
||||||
var settings = ConfigService.SaveWithType(Settings);
|
|
||||||
return settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void LoadSettingsSerialized(string settingsJson)
|
|
||||||
{
|
|
||||||
var settings = ConfigService.LoadWithType(settingsJson);
|
|
||||||
|
|
||||||
// TODO: don't silently fail, inform the user somehow
|
|
||||||
if (settings is InputRollSettings)
|
|
||||||
{
|
|
||||||
var rollSettings = settings as InputRollSettings;
|
|
||||||
_columns = rollSettings.Columns;
|
|
||||||
_columns.ChangedCallback = ColumnChangedCallback;
|
|
||||||
HorizontalOrientation = rollSettings.HorizontalOrientation;
|
|
||||||
//LagFramesToHide = rollSettings.LagFramesToHide;
|
|
||||||
//HideWasLagFrames = rollSettings.HideWasLagFrames;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private InputRollSettings Settings => new InputRollSettings
|
|
||||||
{
|
|
||||||
Columns = _columns,
|
|
||||||
HorizontalOrientation = HorizontalOrientation,
|
|
||||||
//LagFramesToHide = LagFramesToHide,
|
|
||||||
//HideWasLagFrames = HideWasLagFrames
|
|
||||||
};
|
|
||||||
|
|
||||||
public class InputRollSettings
|
|
||||||
{
|
|
||||||
public RollColumns Columns { get; set; }
|
|
||||||
public bool HorizontalOrientation { get; set; }
|
|
||||||
public int LagFramesToHide { get; set; }
|
|
||||||
public bool HideWasLagFrames { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the width of data cells when in Horizontal orientation.
|
|
||||||
/// </summary>
|
|
||||||
public int MaxCharactersInHorizontal
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _maxCharactersInHorizontal;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_maxCharactersInHorizontal = value;
|
|
||||||
UpdateCellSize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether the control is horizontal or vertical
|
|
||||||
/// </summary>
|
|
||||||
[Category("Behavior")]
|
|
||||||
public bool HorizontalOrientation
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _horizontalOrientation;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_horizontalOrientation != value)
|
|
||||||
{
|
|
||||||
int temp = ScrollSpeed;
|
|
||||||
_horizontalOrientation = value;
|
|
||||||
OrientationChanged();
|
|
||||||
_hBar.SmallChange = CellWidth;
|
|
||||||
_vBar.SmallChange = CellHeight;
|
|
||||||
ScrollSpeed = temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<ToolStripItem> GenerateContextMenuItems()
|
|
||||||
{
|
|
||||||
yield return new ToolStripSeparator();
|
|
||||||
|
|
||||||
var rotate = new ToolStripMenuItem
|
|
||||||
{
|
|
||||||
Name = "RotateMenuItem",
|
|
||||||
Text = "Rotate",
|
|
||||||
ShortcutKeyDisplayString = RotateHotkeyStr,
|
|
||||||
};
|
|
||||||
|
|
||||||
rotate.Click += (o, ev) =>
|
|
||||||
{
|
|
||||||
HorizontalOrientation ^= true;
|
|
||||||
};
|
|
||||||
|
|
||||||
yield return rotate;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SuuperW: Count lag frames between FirstDisplayed and given display position
|
|
||||||
private int CountLagFramesDisplay(int relativeIndex)
|
|
||||||
{
|
|
||||||
if (QueryFrameLag != null && LagFramesToHide != 0)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
for (int i = 0; i <= relativeIndex; i++)
|
|
||||||
{
|
|
||||||
count += _lagFrames[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count lag frames between FirstDisplayed and given relative frame index
|
|
||||||
private int CountLagFramesAbsolute(int relativeIndex)
|
|
||||||
{
|
|
||||||
if (QueryFrameLag != null) // && LagFramesToHide != 0)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
for (int i = 0; i + count <= relativeIndex; i++)
|
|
||||||
{
|
|
||||||
count += _lagFrames[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetLagFramesArray()
|
|
||||||
{
|
|
||||||
if (QueryFrameLag != null) // && LagFramesToHide != 0)
|
|
||||||
{
|
|
||||||
bool showNext = false;
|
|
||||||
|
|
||||||
// First one needs to check BACKWARDS for lag frame count.
|
|
||||||
SetLagFramesFirst();
|
|
||||||
int f = _lagFrames[0];
|
|
||||||
|
|
||||||
if (QueryFrameLag(FirstVisibleRow + f, HideWasLagFrames))
|
|
||||||
{
|
|
||||||
showNext = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 1; i <= VisibleRows; i++)
|
|
||||||
{
|
|
||||||
_lagFrames[i] = 0;
|
|
||||||
if (!showNext)
|
|
||||||
{
|
|
||||||
for (; _lagFrames[i] < LagFramesToHide; _lagFrames[i]++)
|
|
||||||
{
|
|
||||||
if (!QueryFrameLag(FirstVisibleRow + i + f, HideWasLagFrames))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
f++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!QueryFrameLag(FirstVisibleRow + i + f, HideWasLagFrames))
|
|
||||||
{
|
|
||||||
showNext = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_lagFrames[i] == LagFramesToHide && QueryFrameLag(FirstVisibleRow + i + f, HideWasLagFrames))
|
|
||||||
{
|
|
||||||
showNext = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i <= VisibleRows; i++)
|
|
||||||
{
|
|
||||||
_lagFrames[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetLagFramesFirst()
|
|
||||||
{
|
|
||||||
if (QueryFrameLag != null && LagFramesToHide != 0)
|
|
||||||
{
|
|
||||||
// Count how many lag frames are above displayed area.
|
|
||||||
int count = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
while (QueryFrameLag(FirstVisibleRow - count, HideWasLagFrames) && count <= LagFramesToHide);
|
|
||||||
count--;
|
|
||||||
|
|
||||||
// Count forward
|
|
||||||
int fCount = -1;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
fCount++;
|
|
||||||
}
|
|
||||||
while (QueryFrameLag(FirstVisibleRow + fCount, HideWasLagFrames) && count + fCount < LagFramesToHide);
|
|
||||||
_lagFrames[0] = (byte)fCount;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_lagFrames[0] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string RotateHotkeyStr => "Ctrl+Shift+F";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Check if a given frame is a lag frame
|
|
||||||
/// </summary>
|
|
||||||
public delegate bool QueryFrameLagHandler(int index, bool hideWasLag);
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Fire the QueryFrameLag event which checks if a given frame is a lag frame
|
|
||||||
/// </summary>
|
|
||||||
[Category("Virtual")]
|
|
||||||
public event QueryFrameLagHandler QueryFrameLag;
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1795,4 +1795,4 @@ namespace BizHawk.Client.EmuHawk
|
||||||
private System.Windows.Forms.ToolStripMenuItem SingleClickFloatEditMenuItem;
|
private System.Windows.Forms.ToolStripMenuItem SingleClickFloatEditMenuItem;
|
||||||
private System.Windows.Forms.ToolStripMenuItem LoadBranchOnDoubleclickMenuItem;
|
private System.Windows.Forms.ToolStripMenuItem LoadBranchOnDoubleclickMenuItem;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,7 +8,6 @@ using BizHawk.Client.Common;
|
||||||
using BizHawk.Client.Common.MovieConversionExtensions;
|
using BizHawk.Client.Common.MovieConversionExtensions;
|
||||||
using BizHawk.Client.EmuHawk.ToolExtensions;
|
using BizHawk.Client.EmuHawk.ToolExtensions;
|
||||||
using BizHawk.Client.EmuHawk.WinFormExtensions;
|
using BizHawk.Client.EmuHawk.WinFormExtensions;
|
||||||
using BizHawk.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
|
|
|
@ -123,19 +123,19 @@
|
||||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||||
<data name="RecentSubMenu.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="RecentSubMenu.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6
|
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||||
JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAAsBAAALAQE2cE9bAAACTUlE
|
YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAlwSFlzAAALAQAA
|
||||||
QVQ4T5WSS29SURSFWx+x0ehERw4cmvgL9E840ehfMHGg6UAnJs6UBm2R1JramJg2yOMWKJfypjwKFgv4
|
CwEBNnBPWwAAAk1JREFUOE+VkktvUlEUhVsfsdHoREcOHJr4C/RPONHoXzBxoOlAJybOlAZtkdSa2piY
|
||||||
QIHaUoHyurSTlsSaKJFu1z7pvYHoxMFH9llr73X2Pe0QEf1Fu50cPoTrf/aoDBy2t5PnwFVFWdaXy8Fs
|
NsjjFiiX8qY8ChYL+ECB2lKB8rq0k5bEmiiRbtc+6b2B6MTBR/ZZa+919j3tEBH9RbudHD6E63/2qAwc
|
||||||
sSDvA0L9A9oyvBvgZP+MVrTbibNAt7npz0bCMzuSVdeVzDqSzI9JsugoHJz+VSr5NtAzCs4MBEAYAXdL
|
treT58BVRVnWl8vBbLEg7wNC/QPaMrwb4GT/jFa024mzQLe56c9GwjM7klXXlcw6ksyPSbLoKByc/lUq
|
||||||
G17FIxt/y84JWn1nIr7965pb1M75J+Sw6WmtKO+i14CNTmsBipK4XK9HU9HwTC8YmKLytwChgVJv53iA
|
+TbQMwrODARAGAF3SxtexSMbf8vOCVp9ZyK+/euaW9TO+SfksOlprSjvoteAjU5rAYqSuFyvR1PR8Ewv
|
||||||
MCA0j/yMZMc4VSuhPfjXRAAe6TgCbhWL8o7PPYkbF8VwsxkjfArlPtmppcSFxhtZTY8okzYftFrxcTXg
|
GJii8rcAoYFSb+d4gDAgNI/8jGTHOFUroT3410QAHuk4Am4Vi/KOzz2JGxfFcLMZI3wK5T7ZqaXEhcYb
|
||||||
BA73V1OmTiT0kur1iBgeCGjFxZk9r9tIIf8LajSis9oGjUZsNB571UnEX7OhgU/C2kZaCk3T+4xFaBzK
|
WU2PKJM2H7Ra8XE14AQO91dTpk4k9JLq9YgYHghoxcWZPa/bSCH/C2o0orPaBo1GbDQee9VJxF+zoYFP
|
||||||
IbVaxKQGHEXAbQTsBXzPaWsrLG5i+AGzaQuvjPVdwuPhIDaAP6cGHEHynWzG0pm3jFH+i1MM12pLWhDD
|
wtpGWgpN0/uMRWgcyiG1WsSkBhxFwG0E7AV8z2lrKyxuYvgBs2kLr4z1XcLj4SA2gD+nBhxB8p1sxtKZ
|
||||||
t7PHb8B/FWiTWgCaH5ZK3u/8wosuA62ve0RAP6yx57I/JfR2od1UA4ar1dA9rNf8nLMf2K1j5JD0tJKc
|
t4xR/otTDNdqS1oQw7ezx2/AfxVok1oAmh+WSt7v/MKLLgOtr3tEQD+sseeyPyX0dqHdVAOGq9XQPazX
|
||||||
pXx+QcA1a+yhhz8lhpkREcA/OJwHD0ChkF/4GfBNkQ3/gbY3h6BmDV4PPTlwgee0AKZSCZ4C12FGy+XA
|
/JyzH9itY+SQ9LSSnKV8fkHANWvsoYc/JYaZERHAPzicBw9AoZBf+BnwTZEN/4G2N4egZg1eDz05cIHn
|
||||||
frHoOvj4QRKg7kHrwkuj55I6MxDAoOkYuAIm0OgHKyAFfNAM4GJ/PzNw+H9o6A/udhOJUDYlqgAAAABJ
|
tACmUgmeAtdhRsvlwH6x6Dr4+EESoO5B68JLo+eSOjMQwKDpGLgCJtDoBysgBXzQDOBifz8zcPh/aOgP
|
||||||
RU5ErkJggg==
|
7nYTiVA2JaoAAAAASUVORK5CYII=
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<metadata name="TasStatusStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
<metadata name="TasStatusStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
|
|
@ -709,6 +709,38 @@
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Consoles\Intellivision\PSG.cs" />
|
<Compile Include="Consoles\Intellivision\PSG.cs" />
|
||||||
<Compile Include="Consoles\Intellivision\STIC.cs" />
|
<Compile Include="Consoles\Intellivision\STIC.cs" />
|
||||||
|
<Compile Include="Consoles\Magnavox\Odyssey2\Audio.cs" />
|
||||||
|
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.cs" />
|
||||||
|
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.ICodeDataLog.cs" />
|
||||||
|
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.IDebuggable.cs">
|
||||||
|
<DependentUpon>O2Hawk.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.IEmulator.cs">
|
||||||
|
<DependentUpon>O2Hawk.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.IInputPollable.cs">
|
||||||
|
<DependentUpon>O2Hawk.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.IMemoryDomains.cs">
|
||||||
|
<DependentUpon>O2Hawk.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.ISaveRam.cs">
|
||||||
|
<DependentUpon>O2Hawk.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.ISettable.cs">
|
||||||
|
<DependentUpon>O2Hawk.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.IStatable.cs">
|
||||||
|
<DependentUpon>O2Hawk.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Consoles\Magnavox\Odyssey2\O2HawkControllerDeck.cs" />
|
||||||
|
<Compile Include="Consoles\Magnavox\Odyssey2\O2HawkControllers.cs" />
|
||||||
|
<Compile Include="Consoles\Magnavox\Odyssey2\HW_Registers.cs" />
|
||||||
|
<Compile Include="Consoles\Magnavox\Odyssey2\Mappers\MapperBase.cs" />
|
||||||
|
<Compile Include="Consoles\Magnavox\Odyssey2\Mappers\Mapper_Default.cs" />
|
||||||
|
<Compile Include="Consoles\Magnavox\Odyssey2\MemoryMap.cs" />
|
||||||
|
<Compile Include="Consoles\Magnavox\Odyssey2\PPU.cs" />
|
||||||
|
<Compile Include="Consoles\Magnavox\Odyssey2\SerialPort.cs" />
|
||||||
<Compile Include="Consoles\Magnavox\LibO2Em.cs" />
|
<Compile Include="Consoles\Magnavox\LibO2Em.cs" />
|
||||||
<Compile Include="Consoles\Magnavox\O2Em.cs" />
|
<Compile Include="Consoles\Magnavox\O2Em.cs" />
|
||||||
<Compile Include="Consoles\NEC\PCFX\LibTst.cs" />
|
<Compile Include="Consoles\NEC\PCFX\LibTst.cs" />
|
||||||
|
@ -1607,6 +1639,13 @@
|
||||||
<Compile Include="CPUs\MC6800\Operations.cs" />
|
<Compile Include="CPUs\MC6800\Operations.cs" />
|
||||||
<Compile Include="CPUs\MC6800\OP_Tables.cs" />
|
<Compile Include="CPUs\MC6800\OP_Tables.cs" />
|
||||||
<Compile Include="CPUs\MC6800\Registers.cs" />
|
<Compile Include="CPUs\MC6800\Registers.cs" />
|
||||||
|
<Compile Include="CPUs\Intel8048\Disassembler.cs" />
|
||||||
|
<Compile Include="CPUs\Intel8048\Execute.cs" />
|
||||||
|
<Compile Include="CPUs\Intel8048\Interrupts.cs" />
|
||||||
|
<Compile Include="CPUs\Intel8048\I8048.cs" />
|
||||||
|
<Compile Include="CPUs\Intel8048\Operations.cs" />
|
||||||
|
<Compile Include="CPUs\Intel8048\OP_Tables.cs" />
|
||||||
|
<Compile Include="CPUs\Intel8048\Registers.cs" />
|
||||||
<Compile Include="CPUs\MC6809\Execute.cs" />
|
<Compile Include="CPUs\MC6809\Execute.cs" />
|
||||||
<Compile Include="CPUs\MC6809\Interrupts.cs" />
|
<Compile Include="CPUs\MC6809\Interrupts.cs" />
|
||||||
<Compile Include="CPUs\MC6809\MC6809.cs" />
|
<Compile Include="CPUs\MC6809\MC6809.cs" />
|
||||||
|
|
Loading…
Reference in New Issue