Browse Source
git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@640 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
17 changed files with 1638 additions and 38 deletions
@ -0,0 +1,141 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt">2002-2005 AlphaSierraPapa</copyright>
|
||||||
|
// <license see="prj:///doc/license.txt">GNU General Public License</license>
|
||||||
|
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||||
|
// <version>$Revision$</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Diagnostics; |
||||||
|
|
||||||
|
namespace ICSharpCode.SharpDevelop.Gui.TreeGrid |
||||||
|
{ |
||||||
|
public class CollectionItemEventArgs<T> : EventArgs |
||||||
|
{ |
||||||
|
T item; |
||||||
|
|
||||||
|
public T Item { |
||||||
|
get { |
||||||
|
return item; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public CollectionItemEventArgs(T item) |
||||||
|
{ |
||||||
|
this.item = item; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A collection that fires events when items are added or removed.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class CollectionWithEvents<T> : IList<T> |
||||||
|
{ |
||||||
|
List<T> list = new List<T>(); |
||||||
|
public event EventHandler<CollectionItemEventArgs<T>> Added; |
||||||
|
public event EventHandler<CollectionItemEventArgs<T>> Removed; |
||||||
|
|
||||||
|
void OnAdded(T item) |
||||||
|
{ |
||||||
|
if (Added != null) |
||||||
|
Added(this, new CollectionItemEventArgs<T>(item)); |
||||||
|
} |
||||||
|
void OnRemoved(T item) |
||||||
|
{ |
||||||
|
if (Removed != null) |
||||||
|
Removed(this, new CollectionItemEventArgs<T>(item)); |
||||||
|
} |
||||||
|
|
||||||
|
public T this[int index] { |
||||||
|
get { |
||||||
|
return list[index]; |
||||||
|
} |
||||||
|
set { |
||||||
|
T oldValue = list[index]; |
||||||
|
if (!object.Equals(oldValue, value)) { |
||||||
|
list[index] = value; |
||||||
|
OnRemoved(oldValue); |
||||||
|
OnAdded(value); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public int Count { |
||||||
|
[DebuggerStepThrough] |
||||||
|
get { |
||||||
|
return list.Count; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public bool IsReadOnly { |
||||||
|
get { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public int IndexOf(T item) |
||||||
|
{ |
||||||
|
return list.IndexOf(item); |
||||||
|
} |
||||||
|
|
||||||
|
public void Insert(int index, T item) |
||||||
|
{ |
||||||
|
list.Insert(index, item); |
||||||
|
OnAdded(item); |
||||||
|
} |
||||||
|
|
||||||
|
public void RemoveAt(int index) |
||||||
|
{ |
||||||
|
T item = list[index]; |
||||||
|
list.RemoveAt(index); |
||||||
|
OnRemoved(item); |
||||||
|
} |
||||||
|
|
||||||
|
public void Add(T item) |
||||||
|
{ |
||||||
|
list.Add(item); |
||||||
|
OnAdded(item); |
||||||
|
} |
||||||
|
|
||||||
|
public void Clear() |
||||||
|
{ |
||||||
|
List<T> oldList = list; |
||||||
|
list = new List<T>(); |
||||||
|
foreach (T item in oldList) { |
||||||
|
OnRemoved(item); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public bool Contains(T item) |
||||||
|
{ |
||||||
|
return list.Contains(item); |
||||||
|
} |
||||||
|
|
||||||
|
public void CopyTo(T[] array, int arrayIndex) |
||||||
|
{ |
||||||
|
list.CopyTo(array, arrayIndex); |
||||||
|
} |
||||||
|
|
||||||
|
public bool Remove(T item) |
||||||
|
{ |
||||||
|
if (list.Remove(item)) { |
||||||
|
OnRemoved(item); |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
[DebuggerStepThrough] |
||||||
|
public IEnumerator<T> GetEnumerator() |
||||||
|
{ |
||||||
|
return list.GetEnumerator(); |
||||||
|
} |
||||||
|
|
||||||
|
[DebuggerStepThrough] |
||||||
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() |
||||||
|
{ |
||||||
|
return list.GetEnumerator(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,432 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt">2002-2005 AlphaSierraPapa</copyright>
|
||||||
|
// <license see="prj:///doc/license.txt">GNU General Public License</license>
|
||||||
|
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||||
|
// <version>$Revision$</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.ComponentModel; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Diagnostics; |
||||||
|
using System.Drawing; |
||||||
|
using System.Windows.Forms; |
||||||
|
|
||||||
|
namespace ICSharpCode.SharpDevelop.Gui.TreeGrid |
||||||
|
{ |
||||||
|
public class DynamicList : UserControl, VerticalScrollContainer.IScrollable |
||||||
|
{ |
||||||
|
public const int MaxColumnCount = 1000; |
||||||
|
|
||||||
|
public DynamicList() |
||||||
|
: this(new CollectionWithEvents<DynamicListColumn>(), new CollectionWithEvents<DynamicListRow>()) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public DynamicList(CollectionWithEvents<DynamicListColumn> columns, CollectionWithEvents<DynamicListRow> rows) |
||||||
|
{ |
||||||
|
inUpdate = true; |
||||||
|
if (columns == null) |
||||||
|
throw new ArgumentNullException("columns"); |
||||||
|
if (rows == null) |
||||||
|
throw new ArgumentNullException("rows"); |
||||||
|
this.columns = columns; |
||||||
|
this.rows = rows; |
||||||
|
// we have to register our events on the existing items
|
||||||
|
foreach (DynamicListColumn column in columns) { |
||||||
|
OnColumnAdded(null, new CollectionItemEventArgs<DynamicListColumn>(column)); |
||||||
|
} |
||||||
|
foreach (DynamicListRow row in rows) { |
||||||
|
OnRowAdded(null, new CollectionItemEventArgs<DynamicListRow>(row)); |
||||||
|
} |
||||||
|
columns.Added += OnColumnAdded; |
||||||
|
columns.Removed += OnColumnRemoved; |
||||||
|
rows.Added += OnRowAdded; |
||||||
|
rows.Removed += OnRowRemoved; |
||||||
|
this.BackColor = DefaultBackColor; |
||||||
|
this.SetStyle(ControlStyles.UserPaint, true); |
||||||
|
this.SetStyle(ControlStyles.Selectable, true); |
||||||
|
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); |
||||||
|
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true); |
||||||
|
inUpdate = false; |
||||||
|
RecalculateColumnWidths(); |
||||||
|
} |
||||||
|
|
||||||
|
public new static readonly Color DefaultBackColor = SystemColors.ControlLightLight; |
||||||
|
|
||||||
|
protected override void Dispose(bool disposing) |
||||||
|
{ |
||||||
|
base.Dispose(disposing); |
||||||
|
if (disposing) { |
||||||
|
columns.Added -= OnColumnAdded; |
||||||
|
columns.Removed -= OnColumnRemoved; |
||||||
|
rows.Added -= OnRowAdded; |
||||||
|
rows.Removed -= OnRowRemoved; |
||||||
|
foreach (DynamicListColumn column in columns) { |
||||||
|
OnColumnRemoved(null, new CollectionItemEventArgs<DynamicListColumn>(column)); |
||||||
|
} |
||||||
|
foreach (DynamicListRow row in rows) { |
||||||
|
OnRowRemoved(null, new CollectionItemEventArgs<DynamicListRow>(row)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void OnColumnAdded(object sender, CollectionItemEventArgs<DynamicListColumn> e) |
||||||
|
{ |
||||||
|
e.Item.MinimumWidthChanged += ColumnMinimumWidthChanged; |
||||||
|
e.Item.WidthChanged += ColumnWidthChanged; |
||||||
|
RecalculateColumnWidths(); |
||||||
|
} |
||||||
|
|
||||||
|
void OnColumnRemoved(object sender, CollectionItemEventArgs<DynamicListColumn> e) |
||||||
|
{ |
||||||
|
e.Item.MinimumWidthChanged -= ColumnMinimumWidthChanged; |
||||||
|
e.Item.WidthChanged -= ColumnWidthChanged; |
||||||
|
RecalculateColumnWidths(); |
||||||
|
} |
||||||
|
|
||||||
|
void OnRowAdded(object sender, CollectionItemEventArgs<DynamicListRow> e) |
||||||
|
{ |
||||||
|
e.Item.HeightChanged += RowHeightChanged; |
||||||
|
e.Item.ItemChanged += RowItemChanged; |
||||||
|
} |
||||||
|
|
||||||
|
void OnRowRemoved(object sender, CollectionItemEventArgs<DynamicListRow> e) |
||||||
|
{ |
||||||
|
e.Item.HeightChanged -= RowHeightChanged; |
||||||
|
e.Item.ItemChanged -= RowItemChanged; |
||||||
|
} |
||||||
|
|
||||||
|
void ColumnMinimumWidthChanged(object sender, EventArgs e) |
||||||
|
{ |
||||||
|
RecalculateColumnWidths(); |
||||||
|
} |
||||||
|
|
||||||
|
void RowHeightChanged(object sender, EventArgs e) |
||||||
|
{ |
||||||
|
Redraw(); |
||||||
|
} |
||||||
|
|
||||||
|
void RowItemChanged(object sender, EventArgs e) |
||||||
|
{ |
||||||
|
Redraw(); |
||||||
|
} |
||||||
|
|
||||||
|
bool inRecalculateColumnWidths; |
||||||
|
bool inRecalculateNeedsRedraw; |
||||||
|
|
||||||
|
void RecalculateColumnWidths() |
||||||
|
{ |
||||||
|
if (inUpdate) return; |
||||||
|
if (inRecalculateColumnWidths) return; |
||||||
|
inRecalculateColumnWidths = true; |
||||||
|
inRecalculateNeedsRedraw = false; |
||||||
|
try { |
||||||
|
int availableWidth = ClientSize.Width; |
||||||
|
int minRequiredWidth = 0; |
||||||
|
foreach (DynamicListColumn c in columns) { |
||||||
|
if (c.AllowGrow) |
||||||
|
minRequiredWidth += c.MinimumWidth; |
||||||
|
else |
||||||
|
availableWidth -= c.Width; |
||||||
|
availableWidth -= 1; |
||||||
|
} |
||||||
|
// everyone gets c.MinimumWidth * availableWidth / minRequiredWidth
|
||||||
|
foreach (DynamicListColumn c in columns) { |
||||||
|
if (c.AllowGrow) |
||||||
|
c.Width = Math.Max(2, c.MinimumWidth * availableWidth / minRequiredWidth); |
||||||
|
} |
||||||
|
} finally { |
||||||
|
inRecalculateColumnWidths = false; |
||||||
|
} |
||||||
|
if (inRecalculateNeedsRedraw) { |
||||||
|
Redraw(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void ColumnWidthChanged(object sender, EventArgs e) |
||||||
|
{ |
||||||
|
if (inRecalculateColumnWidths) { |
||||||
|
inRecalculateNeedsRedraw = true; |
||||||
|
return; |
||||||
|
} |
||||||
|
Redraw(); |
||||||
|
} |
||||||
|
|
||||||
|
bool inUpdate; |
||||||
|
|
||||||
|
public void BeginUpdate() |
||||||
|
{ |
||||||
|
inUpdate = true; |
||||||
|
} |
||||||
|
|
||||||
|
public void EndUpdate() |
||||||
|
{ |
||||||
|
inUpdate = false; |
||||||
|
RecalculateColumnWidths(); |
||||||
|
} |
||||||
|
|
||||||
|
void Redraw() |
||||||
|
{ |
||||||
|
if (inUpdate) return; |
||||||
|
Invalidate(); |
||||||
|
} |
||||||
|
|
||||||
|
List<Control> allowedControls = new List<Control>(); |
||||||
|
List<Control> removedControls = new List<Control>(); |
||||||
|
int scrollOffset = 0; |
||||||
|
|
||||||
|
public int ScrollOffset { |
||||||
|
get { |
||||||
|
return scrollOffset; |
||||||
|
} |
||||||
|
set { |
||||||
|
if (scrollOffset != value) { |
||||||
|
scrollOffset = value; |
||||||
|
Redraw(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int VerticalScrollContainer.IScrollable.ScrollOffsetY { |
||||||
|
get { |
||||||
|
return this.ScrollOffset; |
||||||
|
} |
||||||
|
set { |
||||||
|
this.ScrollOffset = value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int VerticalScrollContainer.IScrollable.ScrollHeightY { |
||||||
|
get { |
||||||
|
return this.TotalRowHeight; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnPaint(PaintEventArgs e) |
||||||
|
{ |
||||||
|
//Debug.WriteLine("OnPaint");
|
||||||
|
Graphics g = e.Graphics; |
||||||
|
allowedControls.Clear(); |
||||||
|
|
||||||
|
int columnIndex = -1; |
||||||
|
foreach (DynamicListColumn col in Columns) { |
||||||
|
columnIndex += 1; |
||||||
|
if (!col.AutoSize) |
||||||
|
continue; |
||||||
|
int minimumWidth = DynamicListColumn.DefaultWidth; |
||||||
|
foreach (DynamicListRow row in Rows) { |
||||||
|
DynamicListItem item = row[columnIndex]; |
||||||
|
item.MeasureMinimumWidth(e.Graphics, ref minimumWidth); |
||||||
|
} |
||||||
|
col.MinimumWidth = minimumWidth; |
||||||
|
} |
||||||
|
|
||||||
|
int controlIndex = 0; |
||||||
|
int yPos = -scrollOffset; |
||||||
|
int clientHeight = ClientSize.Height; |
||||||
|
foreach (DynamicListRow row in Rows) { |
||||||
|
if (yPos + row.Height > 0 && yPos < clientHeight) { |
||||||
|
columnIndex = 0; |
||||||
|
int xPos = 0; |
||||||
|
foreach (DynamicListColumn col in Columns) { |
||||||
|
Rectangle rect = new Rectangle(xPos, yPos, col.Width, row.Height); |
||||||
|
DynamicListItem item = row[columnIndex]; |
||||||
|
Control ctl = item.Control; |
||||||
|
if (ctl != null) { |
||||||
|
allowedControls.Add(ctl); |
||||||
|
if (rect != ctl.Bounds) |
||||||
|
ctl.Bounds = rect; |
||||||
|
if (!this.Controls.Contains(ctl)) { |
||||||
|
this.Controls.Add(ctl); |
||||||
|
this.Controls.SetChildIndex(ctl, controlIndex); |
||||||
|
} |
||||||
|
controlIndex += 1; |
||||||
|
} else { |
||||||
|
item.PaintTo(e.Graphics, rect, col, item == itemAtMousePosition); |
||||||
|
} |
||||||
|
xPos += col.Width + 1; |
||||||
|
columnIndex += 1; |
||||||
|
} |
||||||
|
} |
||||||
|
yPos += row.Height + 1; |
||||||
|
} |
||||||
|
removedControls.Clear(); |
||||||
|
foreach (Control ctl in Controls) { |
||||||
|
if (!allowedControls.Contains(ctl)) |
||||||
|
removedControls.Add(ctl); |
||||||
|
} |
||||||
|
foreach (Control ctl in removedControls) { |
||||||
|
Debug.WriteLine("Removing control"); |
||||||
|
Controls.Remove(ctl); |
||||||
|
Debug.WriteLine("Control removed"); |
||||||
|
} |
||||||
|
allowedControls.Clear(); |
||||||
|
removedControls.Clear(); |
||||||
|
base.OnPaint(e); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnSizeChanged(EventArgs e) |
||||||
|
{ |
||||||
|
base.OnSizeChanged(e); |
||||||
|
RecalculateColumnWidths(); |
||||||
|
} |
||||||
|
|
||||||
|
public DynamicListRow GetRowFromPoint(int yPos) |
||||||
|
{ |
||||||
|
int y = -scrollOffset; |
||||||
|
foreach (DynamicListRow row in Rows) { |
||||||
|
if (yPos < y) |
||||||
|
break; |
||||||
|
if (yPos <= y + row.Height) |
||||||
|
return row; |
||||||
|
y += row.Height + 1; |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the upper left corner of the specified row.
|
||||||
|
/// </summary>
|
||||||
|
public Point GetPositionFromRow(DynamicListRow row) |
||||||
|
{ |
||||||
|
int y = -scrollOffset; |
||||||
|
foreach (DynamicListRow r in Rows) { |
||||||
|
if (r == row) |
||||||
|
return new Point(0, y); |
||||||
|
y += r.Height + 1; |
||||||
|
} |
||||||
|
throw new ArgumentException("The row in not in this list!"); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the height of all rows.
|
||||||
|
/// </summary>
|
||||||
|
public int TotalRowHeight { |
||||||
|
get { |
||||||
|
int y = 0; |
||||||
|
foreach (DynamicListRow r in Rows) { |
||||||
|
y += r.Height + 1; |
||||||
|
} |
||||||
|
return y; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public int GetColumnIndexFromPoint(int xPos) |
||||||
|
{ |
||||||
|
int columnIndex = 0; |
||||||
|
int x = 0; |
||||||
|
foreach (DynamicListColumn col in Columns) { |
||||||
|
if (xPos < x) |
||||||
|
break; |
||||||
|
if (xPos <= x + col.Width) |
||||||
|
return columnIndex; |
||||||
|
x += col.Width + 1; |
||||||
|
columnIndex += 1; |
||||||
|
} |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
public DynamicListItem GetItemFromPoint(Point position) |
||||||
|
{ |
||||||
|
DynamicListRow row = GetRowFromPoint(position.Y); |
||||||
|
if (row == null) |
||||||
|
return null; |
||||||
|
int columnIndex = GetColumnIndexFromPoint(position.X); |
||||||
|
if (columnIndex < 0) |
||||||
|
return null; |
||||||
|
return row[columnIndex]; |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnClick(EventArgs e) |
||||||
|
{ |
||||||
|
base.OnClick(e); |
||||||
|
DynamicListItem item = GetItemFromPoint(PointToClient(Control.MousePosition)); |
||||||
|
if (item != null) item.PerformClick(this); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnDoubleClick(EventArgs e) |
||||||
|
{ |
||||||
|
base.OnDoubleClick(e); |
||||||
|
DynamicListItem item = GetItemFromPoint(PointToClient(Control.MousePosition)); |
||||||
|
if (item != null) item.PerformDoubleClick(this); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnMouseHover(EventArgs e) |
||||||
|
{ |
||||||
|
base.OnMouseHover(e); |
||||||
|
DynamicListItem item = GetItemFromPoint(PointToClient(Control.MousePosition)); |
||||||
|
if (item != null) item.OnMouseHover(this); |
||||||
|
} |
||||||
|
|
||||||
|
DynamicListItem itemAtMousePosition; |
||||||
|
|
||||||
|
protected override void OnMouseMove(MouseEventArgs e) |
||||||
|
{ |
||||||
|
base.OnMouseMove(e); |
||||||
|
DynamicListItem item = GetItemFromPoint(e.Location); |
||||||
|
if (itemAtMousePosition != item) { |
||||||
|
if (itemAtMousePosition != null) { |
||||||
|
OnLeaveItem(itemAtMousePosition); |
||||||
|
} |
||||||
|
ResetMouseEventArgs(); // raise hover again
|
||||||
|
itemAtMousePosition = item; |
||||||
|
if (item != null) { |
||||||
|
if (item.Cursor != null) |
||||||
|
this.Cursor = item.Cursor; |
||||||
|
item.OnMouseEnter(this); |
||||||
|
} |
||||||
|
} |
||||||
|
if (item != null) { |
||||||
|
item.OnMouseMove(new DynamicListMouseEventArgs(this, e)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnMouseDown(MouseEventArgs e) |
||||||
|
{ |
||||||
|
base.OnMouseDown(e); |
||||||
|
DynamicListItem item = GetItemFromPoint(e.Location); |
||||||
|
if (item != null) item.OnMouseDown(new DynamicListMouseEventArgs(this, e)); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnMouseUp(MouseEventArgs e) |
||||||
|
{ |
||||||
|
base.OnMouseUp(e); |
||||||
|
DynamicListItem item = GetItemFromPoint(e.Location); |
||||||
|
if (item != null) item.OnMouseUp(new DynamicListMouseEventArgs(this, e)); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnMouseLeave(EventArgs e) |
||||||
|
{ |
||||||
|
if (itemAtMousePosition != null) { |
||||||
|
OnLeaveItem(itemAtMousePosition); |
||||||
|
itemAtMousePosition = null; |
||||||
|
} |
||||||
|
base.OnMouseLeave(e); |
||||||
|
} |
||||||
|
|
||||||
|
protected virtual void OnLeaveItem(DynamicListItem item) |
||||||
|
{ |
||||||
|
itemAtMousePosition.OnMouseLeave(this); |
||||||
|
this.Cursor = Cursors.Default; |
||||||
|
} |
||||||
|
|
||||||
|
readonly CollectionWithEvents<DynamicListColumn> columns; |
||||||
|
readonly CollectionWithEvents<DynamicListRow> rows; |
||||||
|
|
||||||
|
public CollectionWithEvents<DynamicListColumn> Columns { |
||||||
|
[DebuggerStepThrough] |
||||||
|
get { |
||||||
|
return columns; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
[Browsable(false)] |
||||||
|
public CollectionWithEvents<DynamicListRow> Rows { |
||||||
|
[DebuggerStepThrough] |
||||||
|
get { |
||||||
|
return rows; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,116 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt">2002-2005 AlphaSierraPapa</copyright>
|
||||||
|
// <license see="prj:///doc/license.txt">GNU General Public License</license>
|
||||||
|
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||||
|
// <version>$Revision$</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Drawing; |
||||||
|
|
||||||
|
namespace ICSharpCode.SharpDevelop.Gui.TreeGrid |
||||||
|
{ |
||||||
|
public class DynamicListColumn : ICloneable |
||||||
|
{ |
||||||
|
public const int DefaultWidth = 16; |
||||||
|
|
||||||
|
int width = DefaultWidth; |
||||||
|
int minimumWidth = DefaultWidth; |
||||||
|
bool allowGrow = true; |
||||||
|
bool autoSize = false; |
||||||
|
|
||||||
|
Brush backgroundBrush = SystemBrushes.ControlLight; |
||||||
|
public static readonly Color DefaultBackColor = SystemColors.ControlLight; |
||||||
|
|
||||||
|
public DynamicListColumn() |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>Copy constructor</summary>
|
||||||
|
protected DynamicListColumn(DynamicListColumn col) |
||||||
|
{ |
||||||
|
width = col.width; |
||||||
|
minimumWidth = col.minimumWidth; |
||||||
|
allowGrow = col.allowGrow; |
||||||
|
autoSize = col.autoSize; |
||||||
|
backgroundBrush = col.backgroundBrush; |
||||||
|
} |
||||||
|
|
||||||
|
public virtual DynamicListColumn Clone() |
||||||
|
{ |
||||||
|
return new DynamicListColumn(this); |
||||||
|
} |
||||||
|
|
||||||
|
object ICloneable.Clone() |
||||||
|
{ |
||||||
|
return this.Clone(); |
||||||
|
} |
||||||
|
|
||||||
|
#region Properties
|
||||||
|
public int MinimumWidth { |
||||||
|
get { |
||||||
|
return minimumWidth; |
||||||
|
} |
||||||
|
set { |
||||||
|
if (value < 2) |
||||||
|
throw new ArgumentOutOfRangeException("value", value, "MinimumWidth must be at least 2"); |
||||||
|
if (minimumWidth != value) { |
||||||
|
minimumWidth = value; |
||||||
|
if (MinimumWidthChanged != null) { |
||||||
|
MinimumWidthChanged(this, EventArgs.Empty); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public event EventHandler MinimumWidthChanged; |
||||||
|
|
||||||
|
public int Width { |
||||||
|
get { |
||||||
|
return width; |
||||||
|
} |
||||||
|
set { |
||||||
|
if (value < 2) |
||||||
|
throw new ArgumentOutOfRangeException("value", value, "Width must be at least 2"); |
||||||
|
if (width != value) { |
||||||
|
width = value; |
||||||
|
if (WidthChanged != null) { |
||||||
|
WidthChanged(this, EventArgs.Empty); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public event EventHandler WidthChanged; |
||||||
|
|
||||||
|
public bool AllowGrow { |
||||||
|
get { |
||||||
|
return allowGrow; |
||||||
|
} |
||||||
|
set { |
||||||
|
allowGrow = value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public bool AutoSize { |
||||||
|
get { |
||||||
|
return autoSize; |
||||||
|
} |
||||||
|
set { |
||||||
|
autoSize = value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public Brush BackgroundBrush { |
||||||
|
get { |
||||||
|
return backgroundBrush; |
||||||
|
} |
||||||
|
set { |
||||||
|
if (value == null) |
||||||
|
throw new ArgumentNullException("value"); |
||||||
|
backgroundBrush = value; |
||||||
|
} |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,345 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt">2002-2005 AlphaSierraPapa</copyright>
|
||||||
|
// <license see="prj:///doc/license.txt">GNU General Public License</license>
|
||||||
|
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||||
|
// <version>$Revision$</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Drawing; |
||||||
|
using System.Diagnostics; |
||||||
|
using System.Windows.Forms; |
||||||
|
|
||||||
|
namespace ICSharpCode.SharpDevelop.Gui.TreeGrid |
||||||
|
{ |
||||||
|
public sealed class DynamicListItem |
||||||
|
{ |
||||||
|
DynamicListRow row; |
||||||
|
|
||||||
|
internal DynamicListItem(DynamicListRow row) |
||||||
|
{ |
||||||
|
this.row = row; |
||||||
|
} |
||||||
|
|
||||||
|
void OnItemChanged() |
||||||
|
{ |
||||||
|
row.RaiseItemChanged(this); |
||||||
|
} |
||||||
|
|
||||||
|
Cursor cursor; |
||||||
|
|
||||||
|
public Cursor Cursor { |
||||||
|
get { |
||||||
|
return cursor; |
||||||
|
} |
||||||
|
set { |
||||||
|
cursor = value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#region BackgroundBrush / Control
|
||||||
|
Brush backgroundBrush; |
||||||
|
|
||||||
|
public Brush BackgroundBrush { |
||||||
|
get { |
||||||
|
return backgroundBrush; |
||||||
|
} |
||||||
|
set { |
||||||
|
if (backgroundBrush != value) { |
||||||
|
backgroundBrush = value; |
||||||
|
OnItemChanged(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Brush highlightBrush; |
||||||
|
|
||||||
|
public Brush HighlightBrush { |
||||||
|
get { |
||||||
|
return highlightBrush; |
||||||
|
} |
||||||
|
set { |
||||||
|
if (highlightBrush != value) { |
||||||
|
highlightBrush = value; |
||||||
|
OnItemChanged(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Control control; |
||||||
|
|
||||||
|
public Control Control { |
||||||
|
get { |
||||||
|
return control; |
||||||
|
} |
||||||
|
set { |
||||||
|
if (control != value) { |
||||||
|
control = value; |
||||||
|
OnItemChanged(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region MeasureWidth / Paint
|
||||||
|
public event EventHandler<MeasureWidthEventArgs> MeasureWidth; |
||||||
|
|
||||||
|
internal void MeasureMinimumWidth(Graphics graphics, ref int minimumWidth) |
||||||
|
{ |
||||||
|
if (MeasureWidth != null) { |
||||||
|
MeasureWidthEventArgs e = new MeasureWidthEventArgs(graphics); |
||||||
|
MeasureWidth(this, e); |
||||||
|
minimumWidth = Math.Max(minimumWidth, e.ItemWidth); |
||||||
|
} |
||||||
|
if (text.Length > 0) { |
||||||
|
int width = (int)graphics.MeasureString(text, font, new PointF(0, 0), textFormat).Width; |
||||||
|
minimumWidth = Math.Max(minimumWidth, width); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public event PaintEventHandler Paint; |
||||||
|
|
||||||
|
internal void PaintTo(Graphics g, Rectangle rectangle, DynamicListColumn column, bool isMouseEntered) |
||||||
|
{ |
||||||
|
if (highlightBrush != null && isMouseEntered) |
||||||
|
g.FillRectangle(highlightBrush, rectangle); |
||||||
|
else |
||||||
|
g.FillRectangle(backgroundBrush ?? column.BackgroundBrush, rectangle); |
||||||
|
if (Paint != null) { |
||||||
|
Paint(this, new PaintEventArgs(g, rectangle)); |
||||||
|
} |
||||||
|
if (text.Length > 0) { |
||||||
|
g.DrawString(text, font, textBrush, rectangle, textFormat); |
||||||
|
} |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Text drawing
|
||||||
|
string text = string.Empty; |
||||||
|
|
||||||
|
public string Text { |
||||||
|
get { |
||||||
|
return text; |
||||||
|
} |
||||||
|
set { |
||||||
|
if (value == null) |
||||||
|
throw new ArgumentNullException("value", "Use string.Empty instead of null!"); |
||||||
|
if (text != value) { |
||||||
|
text = value; |
||||||
|
OnItemChanged(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Font font = Control.DefaultFont; |
||||||
|
|
||||||
|
public Font Font { |
||||||
|
get { |
||||||
|
return font; |
||||||
|
} |
||||||
|
set { |
||||||
|
if (value == null) |
||||||
|
throw new ArgumentNullException("value"); |
||||||
|
if (font != value) { |
||||||
|
font = value; |
||||||
|
OnItemChanged(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Brush textBrush = SystemBrushes.ControlText; |
||||||
|
|
||||||
|
public Brush TextBrush { |
||||||
|
get { |
||||||
|
return textBrush; |
||||||
|
} |
||||||
|
set { |
||||||
|
if (value == null) |
||||||
|
throw new ArgumentNullException("value"); |
||||||
|
if (textBrush != value) { |
||||||
|
textBrush = value; |
||||||
|
OnItemChanged(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
StringFormat textFormat = StringFormat.GenericDefault; |
||||||
|
|
||||||
|
public StringFormat TextFormat { |
||||||
|
get { |
||||||
|
return textFormat; |
||||||
|
} |
||||||
|
set { |
||||||
|
if (value == null) |
||||||
|
throw new ArgumentNullException("value"); |
||||||
|
if (textFormat != value) { |
||||||
|
textFormat = value; |
||||||
|
OnItemChanged(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Mouse Events
|
||||||
|
public event EventHandler<DynamicListEventArgs> Click; |
||||||
|
|
||||||
|
public void PerformClick(DynamicList list) |
||||||
|
{ |
||||||
|
if (Click != null) |
||||||
|
Click(this, new DynamicListEventArgs(list)); |
||||||
|
} |
||||||
|
|
||||||
|
public event EventHandler<DynamicListEventArgs> DoubleClick; |
||||||
|
|
||||||
|
public void PerformDoubleClick(DynamicList list) |
||||||
|
{ |
||||||
|
if (DoubleClick != null) |
||||||
|
DoubleClick(this, new DynamicListEventArgs(list)); |
||||||
|
} |
||||||
|
|
||||||
|
public event EventHandler<DynamicListEventArgs> MouseHover; |
||||||
|
|
||||||
|
internal void OnMouseHover(DynamicList list) |
||||||
|
{ |
||||||
|
if (MouseHover != null) { |
||||||
|
MouseHover(this, new DynamicListEventArgs(list)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public event EventHandler<DynamicListEventArgs> MouseLeave; |
||||||
|
|
||||||
|
internal void OnMouseLeave(DynamicList list) |
||||||
|
{ |
||||||
|
if (MouseLeave != null) { |
||||||
|
MouseLeave(this, new DynamicListEventArgs(list)); |
||||||
|
} |
||||||
|
if (highlightBrush != null) OnItemChanged(); |
||||||
|
} |
||||||
|
|
||||||
|
public event EventHandler<DynamicListEventArgs> MouseEnter; |
||||||
|
|
||||||
|
internal void OnMouseEnter(DynamicList list) |
||||||
|
{ |
||||||
|
if (MouseEnter != null) { |
||||||
|
MouseEnter(this, new DynamicListEventArgs(list)); |
||||||
|
} |
||||||
|
if (highlightBrush != null) OnItemChanged(); |
||||||
|
} |
||||||
|
|
||||||
|
public event EventHandler<DynamicListMouseEventArgs> MouseMove; |
||||||
|
|
||||||
|
internal void OnMouseMove(DynamicListMouseEventArgs e) |
||||||
|
{ |
||||||
|
if (MouseMove != null) { |
||||||
|
MouseMove(this, e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public event EventHandler<DynamicListMouseEventArgs> MouseDown; |
||||||
|
|
||||||
|
internal void OnMouseDown(DynamicListMouseEventArgs e) |
||||||
|
{ |
||||||
|
if (MouseDown != null) { |
||||||
|
MouseDown(this, e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public event EventHandler<DynamicListMouseEventArgs> MouseUp; |
||||||
|
|
||||||
|
internal void OnMouseUp(DynamicListMouseEventArgs e) |
||||||
|
{ |
||||||
|
if (MouseUp != null) { |
||||||
|
MouseUp(this, e); |
||||||
|
} |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Display the control for this item. Automatically assign focus to the control
|
||||||
|
/// and removes+disposes the control when it looses focus.
|
||||||
|
/// </summary>
|
||||||
|
public void AssignControlUntilFocusChange(Control control) |
||||||
|
{ |
||||||
|
MethodInvoker method = delegate { |
||||||
|
if (!control.Focus()) { |
||||||
|
control.Focus(); |
||||||
|
} |
||||||
|
control.LostFocus += delegate { |
||||||
|
this.Control = null; |
||||||
|
control.Dispose(); |
||||||
|
}; |
||||||
|
}; |
||||||
|
|
||||||
|
control.HandleCreated += delegate { |
||||||
|
control.BeginInvoke(method); |
||||||
|
}; |
||||||
|
this.Control = control; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public class DynamicListEventArgs : EventArgs |
||||||
|
{ |
||||||
|
DynamicList list; |
||||||
|
|
||||||
|
public DynamicList List { |
||||||
|
[DebuggerStepThrough] |
||||||
|
get { |
||||||
|
return list; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public DynamicListEventArgs(DynamicList list) |
||||||
|
{ |
||||||
|
if (list == null) throw new ArgumentNullException("list"); |
||||||
|
this.list = list; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public class DynamicListMouseEventArgs : MouseEventArgs |
||||||
|
{ |
||||||
|
DynamicList list; |
||||||
|
|
||||||
|
public DynamicList List { |
||||||
|
[DebuggerStepThrough] |
||||||
|
get { |
||||||
|
return list; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public DynamicListMouseEventArgs(DynamicList list, MouseEventArgs me) |
||||||
|
: base(me.Button, me.Clicks, me.X, me.Y, me.Delta) |
||||||
|
{ |
||||||
|
if (list == null) throw new ArgumentNullException("list"); |
||||||
|
this.list = list; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public class MeasureWidthEventArgs : EventArgs |
||||||
|
{ |
||||||
|
Graphics graphics; |
||||||
|
|
||||||
|
public Graphics Graphics { |
||||||
|
get { |
||||||
|
return graphics; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int itemWidth; |
||||||
|
|
||||||
|
public int ItemWidth { |
||||||
|
get { |
||||||
|
return itemWidth; |
||||||
|
} |
||||||
|
set { |
||||||
|
itemWidth = value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public MeasureWidthEventArgs(Graphics graphics) |
||||||
|
{ |
||||||
|
if (graphics == null) |
||||||
|
throw new ArgumentNullException("graphics"); |
||||||
|
this.graphics = graphics; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,78 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt">2002-2005 AlphaSierraPapa</copyright>
|
||||||
|
// <license see="prj:///doc/license.txt">GNU General Public License</license>
|
||||||
|
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||||
|
// <version>$Revision$</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Diagnostics; |
||||||
|
using System.Windows.Forms; |
||||||
|
|
||||||
|
namespace ICSharpCode.SharpDevelop.Gui.TreeGrid |
||||||
|
{ |
||||||
|
public class DynamicListRow |
||||||
|
{ |
||||||
|
int height = 16; |
||||||
|
|
||||||
|
public int Height { |
||||||
|
get { |
||||||
|
return height; |
||||||
|
} |
||||||
|
set { |
||||||
|
if (value < 2) |
||||||
|
throw new ArgumentOutOfRangeException("value", value, "value must be at least 2"); |
||||||
|
if (height != value) { |
||||||
|
height = value; |
||||||
|
OnHeightChanged(EventArgs.Empty); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public event EventHandler HeightChanged; |
||||||
|
|
||||||
|
protected virtual void OnHeightChanged(EventArgs e) |
||||||
|
{ |
||||||
|
if (HeightChanged != null) { |
||||||
|
HeightChanged(this, e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fired when any item has changed.
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler ItemChanged; |
||||||
|
|
||||||
|
protected virtual void OnItemChanged(EventArgs e) |
||||||
|
{ |
||||||
|
if (ItemChanged != null) { |
||||||
|
ItemChanged(this, e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal void RaiseItemChanged(DynamicListItem item) |
||||||
|
{ |
||||||
|
OnItemChanged(EventArgs.Empty); |
||||||
|
} |
||||||
|
|
||||||
|
DynamicListItem[] items = new DynamicListItem[10]; |
||||||
|
|
||||||
|
public DynamicListItem this[int columnIndex] { |
||||||
|
[DebuggerStepThrough] |
||||||
|
get { |
||||||
|
if (columnIndex < 0) |
||||||
|
throw new ArgumentOutOfRangeException("columnIndex", columnIndex, "columnIndex must be >= 0"); |
||||||
|
if (columnIndex > DynamicList.MaxColumnCount) |
||||||
|
throw new ArgumentOutOfRangeException("columnIndex", columnIndex, "columnIndex must be <= " + DynamicList.MaxColumnCount); |
||||||
|
if (columnIndex >= items.Length) { |
||||||
|
Array.Resize(ref items, columnIndex * 2 + 1); |
||||||
|
} |
||||||
|
DynamicListItem item = items[columnIndex]; |
||||||
|
if (item == null) { |
||||||
|
items[columnIndex] = item = new DynamicListItem(this); |
||||||
|
} |
||||||
|
return item; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,188 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt">2002-2005 AlphaSierraPapa</copyright>
|
||||||
|
// <license see="prj:///doc/license.txt">GNU General Public License</license>
|
||||||
|
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||||
|
// <version>$Revision$</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Drawing; |
||||||
|
using System.Windows.Forms; |
||||||
|
|
||||||
|
namespace ICSharpCode.SharpDevelop.Gui.TreeGrid |
||||||
|
{ |
||||||
|
public class DynamicTreeRow : DynamicListRow |
||||||
|
{ |
||||||
|
CollectionWithEvents<DynamicListColumn> childColumns = new CollectionWithEvents<DynamicListColumn>(); |
||||||
|
CollectionWithEvents<DynamicListRow> childRows = new CollectionWithEvents<DynamicListRow>(); |
||||||
|
|
||||||
|
DynamicListItem plus; |
||||||
|
|
||||||
|
public DynamicTreeRow() |
||||||
|
{ |
||||||
|
plus = this[0]; |
||||||
|
plus.HighlightBrush = Brushes.AliceBlue; |
||||||
|
plus.Cursor = Cursors.Hand; |
||||||
|
plus.Click += OnPlusClick; |
||||||
|
plus.Paint += OnPlusPaint; |
||||||
|
plus.Text = "+"; |
||||||
|
plus.TextFormat = new StringFormat(plus.TextFormat); |
||||||
|
plus.TextFormat.Alignment = StringAlignment.Center; |
||||||
|
plus.TextFormat.LineAlignment = StringAlignment.Center; |
||||||
|
} |
||||||
|
|
||||||
|
protected virtual void OnPlusPaint(object sender, PaintEventArgs e) |
||||||
|
{ |
||||||
|
Rectangle r = e.ClipRectangle; |
||||||
|
r.Inflate(-4, -4); |
||||||
|
e.Graphics.DrawRectangle(SystemPens.ControlDarkDark, r); |
||||||
|
} |
||||||
|
|
||||||
|
class ChildForm : Form |
||||||
|
{ |
||||||
|
bool isActive = true; |
||||||
|
|
||||||
|
protected override void OnActivated(EventArgs e) |
||||||
|
{ |
||||||
|
base.OnActivated(e); |
||||||
|
isActive = true; |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnDeactivate(EventArgs e) |
||||||
|
{ |
||||||
|
base.OnDeactivate(e); |
||||||
|
isActive = false; |
||||||
|
if (isOpeningChild) |
||||||
|
return; |
||||||
|
BeginInvoke(new MethodInvoker(CloseOnDeactivate)); |
||||||
|
} |
||||||
|
|
||||||
|
void CloseOnDeactivate() |
||||||
|
{ |
||||||
|
ChildForm owner = Owner as ChildForm; |
||||||
|
if (owner != null) { |
||||||
|
if (owner.isActive) |
||||||
|
Close(); |
||||||
|
else |
||||||
|
owner.CloseOnDeactivate(); |
||||||
|
} else { |
||||||
|
Close(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ChildForm frm; |
||||||
|
static bool isOpeningChild; |
||||||
|
|
||||||
|
protected virtual void OnPlusClick(object sender, DynamicListEventArgs e) |
||||||
|
{ |
||||||
|
if (frm != null) { |
||||||
|
frm.Close(); |
||||||
|
} |
||||||
|
frm = new ChildForm(); |
||||||
|
frm.Closed += delegate { |
||||||
|
frm = null; |
||||||
|
OnCollapsed(EventArgs.Empty); |
||||||
|
}; |
||||||
|
frm.FormBorderStyle = FormBorderStyle.SizableToolWindow; |
||||||
|
Point p = e.List.PointToScreen(e.List.GetPositionFromRow(this)); |
||||||
|
p.Offset(e.List.Columns[0].Width, Height); |
||||||
|
frm.StartPosition = FormStartPosition.Manual; |
||||||
|
frm.Location = p; |
||||||
|
frm.ShowInTaskbar = false; |
||||||
|
frm.Text = childWindowCaption; |
||||||
|
frm.Owner = e.List.FindForm(); |
||||||
|
OnExpanding(e); |
||||||
|
|
||||||
|
VerticalScrollContainer scrollContainer = new VerticalScrollContainer(); |
||||||
|
scrollContainer.Dock = DockStyle.Fill; |
||||||
|
|
||||||
|
DynamicList childList = new DynamicList(childColumns, childRows); |
||||||
|
childList.Dock = DockStyle.Fill; |
||||||
|
childList.KeyDown += delegate(object sender2, KeyEventArgs e2) { |
||||||
|
if (e2.KeyData == Keys.Escape) { |
||||||
|
frm.Close(); |
||||||
|
// workaround focus problem: sometimes the mainform gets focus after this
|
||||||
|
e.List.FindForm().Focus(); |
||||||
|
} |
||||||
|
}; |
||||||
|
scrollContainer.Controls.Add(childList); |
||||||
|
|
||||||
|
frm.DockPadding.All = 2; |
||||||
|
frm.Controls.Add(scrollContainer); |
||||||
|
|
||||||
|
int screenHeight = Screen.FromPoint(p).WorkingArea.Bottom - p.Y; |
||||||
|
screenHeight -= frm.Size.Height - frm.ClientSize.Height; |
||||||
|
int formHeight = Math.Min(childList.TotalRowHeight + 4, screenHeight); |
||||||
|
if (formHeight < 100) { |
||||||
|
formHeight += 100; |
||||||
|
frm.Top -= 100; |
||||||
|
} |
||||||
|
frm.ClientSize = new Size(e.List.Width, formHeight); |
||||||
|
isOpeningChild = true; |
||||||
|
frm.Show(); |
||||||
|
isOpeningChild = false; |
||||||
|
childList.Focus(); |
||||||
|
OnExpanded(e); |
||||||
|
} |
||||||
|
|
||||||
|
public event EventHandler Expanding; |
||||||
|
public event EventHandler Expanded; |
||||||
|
public event EventHandler Collapsed; |
||||||
|
|
||||||
|
protected virtual void OnExpanding(EventArgs e) |
||||||
|
{ |
||||||
|
if (Expanding != null) { |
||||||
|
Expanding(this, e); |
||||||
|
} |
||||||
|
} |
||||||
|
protected virtual void OnExpanded(EventArgs e) |
||||||
|
{ |
||||||
|
if (Expanded != null) { |
||||||
|
Expanded(this, e); |
||||||
|
} |
||||||
|
} |
||||||
|
protected virtual void OnCollapsed(EventArgs e) |
||||||
|
{ |
||||||
|
if (Collapsed != null) { |
||||||
|
Collapsed(this, e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
string childWindowCaption = "Child window"; |
||||||
|
|
||||||
|
public string ChildWindowCaption { |
||||||
|
get { |
||||||
|
return childWindowCaption; |
||||||
|
} |
||||||
|
set { |
||||||
|
if (value == null) |
||||||
|
throw new ArgumentNullException(); |
||||||
|
childWindowCaption = value; |
||||||
|
if (frm != null) frm.Text = value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public CollectionWithEvents<DynamicListColumn> ChildColumns { |
||||||
|
get { |
||||||
|
return childColumns; |
||||||
|
} |
||||||
|
set { |
||||||
|
if (value == null) |
||||||
|
throw new ArgumentNullException("value"); |
||||||
|
childColumns = value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public CollectionWithEvents<DynamicListRow> ChildRows { |
||||||
|
get { |
||||||
|
return childRows; |
||||||
|
} |
||||||
|
set { |
||||||
|
if (value == null) |
||||||
|
throw new ArgumentNullException("value"); |
||||||
|
childRows = value; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,120 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt">2002-2005 AlphaSierraPapa</copyright>
|
||||||
|
// <license see="prj:///doc/license.txt">GNU General Public License</license>
|
||||||
|
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||||
|
// <version>$Revision$</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.ComponentModel; |
||||||
|
using System.Drawing; |
||||||
|
using System.Windows.Forms; |
||||||
|
|
||||||
|
namespace ICSharpCode.SharpDevelop.Gui.TreeGrid |
||||||
|
{ |
||||||
|
public class ScrollButtonControl : Control |
||||||
|
{ |
||||||
|
public ScrollButtonControl() |
||||||
|
{ |
||||||
|
this.BackColor = DynamicListColumn.DefaultBackColor; |
||||||
|
this.TabStop = false; |
||||||
|
this.SetStyle(ControlStyles.Selectable, false); |
||||||
|
} |
||||||
|
|
||||||
|
protected override Size DefaultSize { |
||||||
|
get { |
||||||
|
return new Size(14, 14); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ScrollButton arrow = ScrollButton.Down; |
||||||
|
|
||||||
|
public ScrollButton Arrow { |
||||||
|
get { |
||||||
|
return arrow; |
||||||
|
} |
||||||
|
set { |
||||||
|
arrow = value; |
||||||
|
Invalidate(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bool drawSeparatorLine = true; |
||||||
|
|
||||||
|
public bool DrawSeparatorLine { |
||||||
|
get { |
||||||
|
return drawSeparatorLine; |
||||||
|
} |
||||||
|
set { |
||||||
|
drawSeparatorLine = value; |
||||||
|
Invalidate(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Color highlightColor = SystemColors.Highlight; |
||||||
|
|
||||||
|
public Color HighlightColor { |
||||||
|
get { |
||||||
|
return highlightColor; |
||||||
|
} |
||||||
|
set { |
||||||
|
highlightColor = value; |
||||||
|
Invalidate(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnPaint(PaintEventArgs e) |
||||||
|
{ |
||||||
|
base.OnPaint(e); |
||||||
|
const int margin = 2; |
||||||
|
int height = this.ClientSize.Height; |
||||||
|
int size = height - 2 * margin; |
||||||
|
int width = this.ClientSize.Width; |
||||||
|
int left = (width - size) / 2; |
||||||
|
int right = (width + size) / 2; |
||||||
|
Point[] triangle; |
||||||
|
switch (arrow) { |
||||||
|
case ScrollButton.Down: |
||||||
|
triangle = new Point[] { |
||||||
|
new Point(left, margin), new Point(right, margin), new Point(width / 2, margin + size) |
||||||
|
}; |
||||||
|
if (drawSeparatorLine) |
||||||
|
e.Graphics.DrawLine(SystemPens.GrayText, 0, 0, width, 0); |
||||||
|
break; |
||||||
|
case ScrollButton.Up: |
||||||
|
triangle = new Point[] { |
||||||
|
new Point(left, margin + size), new Point(right, margin + size), new Point(width / 2, margin) |
||||||
|
}; |
||||||
|
if (drawSeparatorLine) |
||||||
|
e.Graphics.DrawLine(SystemPens.GrayText, 0, height - 1, width, height - 1); |
||||||
|
break; |
||||||
|
default: |
||||||
|
return; |
||||||
|
} |
||||||
|
Color color; |
||||||
|
if (Enabled) |
||||||
|
color = cursorEntered ? HighlightColor : ForeColor; |
||||||
|
else |
||||||
|
color = SystemColors.GrayText; |
||||||
|
using (Brush b = new SolidBrush(color)) { |
||||||
|
e.Graphics.FillPolygon(b, triangle); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bool cursorEntered = false; |
||||||
|
|
||||||
|
protected override void OnMouseEnter(EventArgs e) |
||||||
|
{ |
||||||
|
base.OnMouseEnter(e); |
||||||
|
cursorEntered = true; |
||||||
|
Invalidate(); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnMouseLeave(EventArgs e) |
||||||
|
{ |
||||||
|
base.OnMouseLeave(e); |
||||||
|
cursorEntered = false; |
||||||
|
Invalidate(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,172 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt">2002-2005 AlphaSierraPapa</copyright>
|
||||||
|
// <license see="prj:///doc/license.txt">GNU General Public License</license>
|
||||||
|
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||||
|
// <version>$Revision$</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.ComponentModel; |
||||||
|
using System.Drawing; |
||||||
|
using System.Windows.Forms; |
||||||
|
|
||||||
|
namespace ICSharpCode.SharpDevelop.Gui.TreeGrid |
||||||
|
{ |
||||||
|
public class VerticalScrollContainer : Control |
||||||
|
{ |
||||||
|
public interface IScrollable |
||||||
|
{ |
||||||
|
int ScrollOffsetY { get; set; } |
||||||
|
int ScrollHeightY { get; } |
||||||
|
int Height { get; } |
||||||
|
event MouseEventHandler MouseWheel; |
||||||
|
} |
||||||
|
|
||||||
|
IScrollable scrollable; |
||||||
|
bool showButtonsOnlyIfRequired = true; |
||||||
|
ScrollButtonControl down = new ScrollButtonControl(); |
||||||
|
ScrollButtonControl up = new ScrollButtonControl(); |
||||||
|
Timer timer = new Timer(); |
||||||
|
|
||||||
|
int scrollSpeed = 5; |
||||||
|
|
||||||
|
public int ScrollSpeed { |
||||||
|
get { |
||||||
|
return scrollSpeed; |
||||||
|
} |
||||||
|
set { |
||||||
|
scrollSpeed = value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public VerticalScrollContainer() |
||||||
|
{ |
||||||
|
up.Arrow = ScrollButton.Up; |
||||||
|
down.Arrow = ScrollButton.Down; |
||||||
|
up.Dock = DockStyle.Top; |
||||||
|
down.Dock = DockStyle.Bottom; |
||||||
|
this.TabStop = false; |
||||||
|
this.SetStyle(ControlStyles.Selectable, false); |
||||||
|
Controls.Add(up); |
||||||
|
Controls.Add(down); |
||||||
|
UpdateEnabled(); |
||||||
|
|
||||||
|
timer.Interval = 50; |
||||||
|
timer.Tick += delegate { |
||||||
|
ScrollBy((int)timer.Tag); |
||||||
|
}; |
||||||
|
up.MouseDown += delegate { |
||||||
|
timer.Tag = -scrollSpeed; |
||||||
|
ScrollBy(-scrollSpeed); |
||||||
|
timer.Start(); |
||||||
|
}; |
||||||
|
down.MouseDown += delegate { |
||||||
|
timer.Tag = scrollSpeed; |
||||||
|
ScrollBy(scrollSpeed); |
||||||
|
timer.Start(); |
||||||
|
}; |
||||||
|
up.MouseUp += StopTimer; |
||||||
|
down.MouseUp += StopTimer; |
||||||
|
} |
||||||
|
|
||||||
|
void StopTimer(object sender, MouseEventArgs e) |
||||||
|
{ |
||||||
|
timer.Stop(); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void Dispose(bool disposing) |
||||||
|
{ |
||||||
|
base.Dispose(disposing); |
||||||
|
if (disposing) { |
||||||
|
timer.Dispose(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void UpdateEnabled() |
||||||
|
{ |
||||||
|
if (scrollable == null) { |
||||||
|
up.Visible = down.Visible = true; |
||||||
|
up.Enabled = down.Enabled = false; |
||||||
|
} else { |
||||||
|
int scrollHeightY = scrollable.ScrollHeightY; |
||||||
|
if (showButtonsOnlyIfRequired) { |
||||||
|
if (scrollHeightY <= this.Height) { |
||||||
|
scrollable.ScrollOffsetY = 0; |
||||||
|
up.Visible = down.Visible = false; |
||||||
|
return; |
||||||
|
} |
||||||
|
up.Visible = down.Visible = true; |
||||||
|
} else { |
||||||
|
up.Visible = down.Visible = true; |
||||||
|
if (scrollable.ScrollHeightY <= scrollable.Height) { |
||||||
|
scrollable.ScrollOffsetY = 0; |
||||||
|
up.Enabled = down.Enabled = false; |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
// set enabled
|
||||||
|
up.Enabled = scrollable.ScrollOffsetY > 0; |
||||||
|
down.Enabled = scrollable.ScrollOffsetY < scrollHeightY - scrollable.Height; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void ScrollBy(int amount) |
||||||
|
{ |
||||||
|
scrollable.ScrollOffsetY = Math.Max(0, Math.Min(scrollable.ScrollOffsetY + amount, scrollable.ScrollHeightY - scrollable.Height)); |
||||||
|
UpdateEnabled(); |
||||||
|
} |
||||||
|
|
||||||
|
public bool ShowButtonsOnlyIfRequired { |
||||||
|
get { |
||||||
|
return showButtonsOnlyIfRequired; |
||||||
|
} |
||||||
|
set { |
||||||
|
if (showButtonsOnlyIfRequired != value) { |
||||||
|
showButtonsOnlyIfRequired = value; |
||||||
|
UpdateEnabled(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void ScrollableWheel(object sender, MouseEventArgs e) |
||||||
|
{ |
||||||
|
ScrollBy(-e.Delta / 3); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnSizeChanged(EventArgs e) |
||||||
|
{ |
||||||
|
base.OnSizeChanged(e); |
||||||
|
UpdateEnabled(); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnControlAdded(ControlEventArgs e) |
||||||
|
{ |
||||||
|
base.OnControlAdded(e); |
||||||
|
if (scrollable == null && !DesignMode) { |
||||||
|
scrollable = e.Control as IScrollable; |
||||||
|
if (scrollable != null) { |
||||||
|
scrollable.MouseWheel += ScrollableWheel; |
||||||
|
Controls.SetChildIndex(e.Control, 0); |
||||||
|
UpdateEnabled(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnControlRemoved(ControlEventArgs e) |
||||||
|
{ |
||||||
|
base.OnControlRemoved(e); |
||||||
|
if (scrollable == e.Control) { |
||||||
|
scrollable.MouseWheel -= ScrollableWheel; |
||||||
|
scrollable = null; |
||||||
|
UpdateEnabled(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnHandleCreated(EventArgs e) |
||||||
|
{ |
||||||
|
base.OnHandleCreated(e); |
||||||
|
// HACK: Windows.Forms bug workaround
|
||||||
|
BeginInvoke(new MethodInvoker(PerformLayout)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue