Add a popover with a list of diagnostics to the diagnostics toolbar buttons
This commit is contained in:
parent
92695b8361
commit
7610ffaf38
10 changed files with 769 additions and 42 deletions
96
Cauldron.Macos/SourceList/SourceListDataSource.cs
Normal file
96
Cauldron.Macos/SourceList/SourceListDataSource.cs
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using AppKit;
|
||||
using Foundation;
|
||||
|
||||
namespace Cauldron.Macos.SourceList
|
||||
{
|
||||
public class SourceListDataSource : NSOutlineViewDataSource
|
||||
{
|
||||
#region Private Variables
|
||||
|
||||
private SourceListView _controller;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Variables
|
||||
|
||||
public List<SourceListItem> Items = new();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public SourceListDataSource(SourceListView controller)
|
||||
{
|
||||
// Initialize
|
||||
this._controller = controller;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Override Properties
|
||||
|
||||
public override nint GetChildrenCount(NSOutlineView outlineView, Foundation.NSObject item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return Items.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ((SourceListItem)item).Count;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool ItemExpandable(NSOutlineView outlineView, Foundation.NSObject item)
|
||||
{
|
||||
return ((SourceListItem)item).HasChildren;
|
||||
}
|
||||
|
||||
public override NSObject GetChild(NSOutlineView outlineView, nint childIndex, Foundation.NSObject item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return Items[(int)childIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
return ((SourceListItem)item)[(int)childIndex];
|
||||
}
|
||||
}
|
||||
|
||||
public override NSObject GetObjectValue(NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item)
|
||||
{
|
||||
return new NSString(((SourceListItem)item).Title);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Methods
|
||||
|
||||
internal SourceListItem ItemForRow(int row)
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
// Look at each group
|
||||
foreach (SourceListItem item in Items)
|
||||
{
|
||||
// Is the row inside this group?
|
||||
if (row >= index && row <= (index + item.Count))
|
||||
{
|
||||
return item[row - index - 1];
|
||||
}
|
||||
|
||||
// Move index
|
||||
index += item.Count + 1;
|
||||
}
|
||||
|
||||
// Not found
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
112
Cauldron.Macos/SourceList/SourceListDelegate.cs
Normal file
112
Cauldron.Macos/SourceList/SourceListDelegate.cs
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
using AppKit;
|
||||
using CoreGraphics;
|
||||
using Foundation;
|
||||
|
||||
namespace Cauldron.Macos.SourceList
|
||||
{
|
||||
public class SourceListDelegate : NSOutlineViewDelegate
|
||||
{
|
||||
#region Private variables
|
||||
|
||||
private SourceListView _controller;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public SourceListDelegate(SourceListView controller)
|
||||
{
|
||||
this._controller = controller;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Override Methods
|
||||
|
||||
public override bool ShouldEditTableColumn(NSOutlineView outlineView,
|
||||
NSTableColumn tableColumn, NSObject item)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override NSCell GetCell(NSOutlineView outlineView, NSTableColumn tableColumn,
|
||||
NSObject item)
|
||||
{
|
||||
nint row = outlineView.RowForItem(item);
|
||||
return tableColumn.DataCellForRow(row);
|
||||
}
|
||||
|
||||
public override bool IsGroupItem(NSOutlineView outlineView, NSObject item)
|
||||
{
|
||||
return ((SourceListItem)item).HasChildren;
|
||||
}
|
||||
|
||||
public override NSView GetView(NSOutlineView outlineView, NSTableColumn tableColumn,
|
||||
NSObject item)
|
||||
{
|
||||
NSTableCellView view;
|
||||
|
||||
// Is this a group item?
|
||||
if (((SourceListItem)item).IsHeader)
|
||||
{
|
||||
view = (NSTableCellView)outlineView.MakeView("HeaderCell", this);
|
||||
}
|
||||
else
|
||||
{
|
||||
view = (NSTableCellView)outlineView.MakeView("DataCell", this);
|
||||
view.ImageView.Image = ((SourceListItem)item).Icon;
|
||||
view.TextField.LineBreakMode = NSLineBreakMode.CharWrapping;
|
||||
view.TextField.UsesSingleLineMode = false;
|
||||
view.TextField.MaximumNumberOfLines = 0;
|
||||
}
|
||||
|
||||
view.TextField.StringValue = ((SourceListItem)item).Title;
|
||||
view.TextField.SetBoundsSize(CalculateTextFieldHeight(view));
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
public override bool ShouldSelectItem(NSOutlineView outlineView, NSObject item)
|
||||
{
|
||||
return (outlineView.GetParent(item) != null);
|
||||
}
|
||||
|
||||
public override void SelectionDidChange(NSNotification notification)
|
||||
{
|
||||
NSIndexSet selectedIndexes = _controller.SelectedRows;
|
||||
|
||||
// More than one item selected?
|
||||
if (selectedIndexes.Count > 1)
|
||||
{
|
||||
// Not handling this case
|
||||
}
|
||||
else
|
||||
{
|
||||
// Grab the item
|
||||
var item = _controller.Data.ItemForRow((int)selectedIndexes.FirstIndex);
|
||||
|
||||
// Was an item found?
|
||||
if (item != null)
|
||||
{
|
||||
// Fire the clicked event for the item
|
||||
item.RaiseClickedEvent();
|
||||
|
||||
// Inform caller of selection
|
||||
_controller.RaiseItemSelected(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static CGSize CalculateTextFieldHeight(NSTableCellView cell)
|
||||
{
|
||||
CGRect rect = new(0, 0, cell.TextField.Bounds.Width, double.MaxValue);
|
||||
NSString str = new(cell.TextField.StringValue);
|
||||
CGRect bounds = str.BoundingRectWithSize(rect.Size, 0,
|
||||
new NSDictionary(NSStringAttributeKey.Font, cell.TextField.Font));
|
||||
|
||||
return new CGSize(cell.TextField.Bounds.Width, bounds.Size.Height);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
241
Cauldron.Macos/SourceList/SourceListItem.cs
Normal file
241
Cauldron.Macos/SourceList/SourceListItem.cs
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using AppKit;
|
||||
using Foundation;
|
||||
|
||||
namespace Cauldron.Macos.SourceList
|
||||
{
|
||||
public class SourceListItem : NSObject, IEnumerator, IEnumerable
|
||||
{
|
||||
#region Private Properties
|
||||
|
||||
private string _title;
|
||||
private NSImage _icon;
|
||||
private string _tag;
|
||||
private bool _isHeader = false;
|
||||
private List<SourceListItem> _items = new();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Computed Properties
|
||||
|
||||
public string Title
|
||||
{
|
||||
get { return _title; }
|
||||
set { _title = value; }
|
||||
}
|
||||
|
||||
public NSImage Icon
|
||||
{
|
||||
get { return _icon; }
|
||||
set { _icon = value; }
|
||||
}
|
||||
|
||||
public string Tag
|
||||
{
|
||||
get { return _tag; }
|
||||
set { _tag = value; }
|
||||
}
|
||||
|
||||
public bool IsHeader
|
||||
{
|
||||
get => this._isHeader;
|
||||
set => this._isHeader = value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Indexer
|
||||
|
||||
public SourceListItem this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return _items[index];
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_items[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return _items.Count; }
|
||||
}
|
||||
|
||||
public bool HasChildren
|
||||
{
|
||||
get { return (Count > 0); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Enumerable Routines
|
||||
|
||||
private int _position = -1;
|
||||
|
||||
public IEnumerator GetEnumerator()
|
||||
{
|
||||
_position = -1;
|
||||
return (IEnumerator)this;
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
_position++;
|
||||
return (_position < _items.Count);
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{ _position = -1; }
|
||||
|
||||
public object Current
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return _items[_position];
|
||||
}
|
||||
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public SourceListItem() { }
|
||||
|
||||
public SourceListItem(string title)
|
||||
{
|
||||
this._title = title;
|
||||
}
|
||||
|
||||
public SourceListItem(string title, string icon)
|
||||
{
|
||||
this._title = title;
|
||||
this._icon = NSImage.ImageNamed(icon);
|
||||
}
|
||||
|
||||
public SourceListItem(string title, string icon, ClickedDelegate clicked)
|
||||
{
|
||||
this._title = title;
|
||||
this._icon = NSImage.ImageNamed(icon);
|
||||
this.Clicked = clicked;
|
||||
}
|
||||
|
||||
public SourceListItem(string title, NSImage icon)
|
||||
{
|
||||
this._title = title;
|
||||
this._icon = icon;
|
||||
}
|
||||
|
||||
public SourceListItem(string title, NSImage icon, ClickedDelegate clicked)
|
||||
{
|
||||
this._title = title;
|
||||
this._icon = icon;
|
||||
this.Clicked = clicked;
|
||||
}
|
||||
|
||||
public SourceListItem(string title, NSImage icon, string tag)
|
||||
{
|
||||
this._title = title;
|
||||
this._icon = icon;
|
||||
this._tag = tag;
|
||||
}
|
||||
|
||||
public SourceListItem(string title, NSImage icon, string tag, ClickedDelegate clicked)
|
||||
{
|
||||
this._title = title;
|
||||
this._icon = icon;
|
||||
this._tag = tag;
|
||||
this.Clicked = clicked;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public void AddItem(SourceListItem item)
|
||||
{
|
||||
_items.Add(item);
|
||||
}
|
||||
|
||||
public void AddItem(string title)
|
||||
{
|
||||
_items.Add(new SourceListItem(title));
|
||||
}
|
||||
|
||||
public void AddItem(string title, string icon)
|
||||
{
|
||||
_items.Add(new SourceListItem(title, icon));
|
||||
}
|
||||
|
||||
public void AddItem(string title, string icon, ClickedDelegate clicked)
|
||||
{
|
||||
_items.Add(new SourceListItem(title, icon, clicked));
|
||||
}
|
||||
|
||||
public void AddItem(string title, NSImage icon)
|
||||
{
|
||||
_items.Add(new SourceListItem(title, icon));
|
||||
}
|
||||
|
||||
public void AddItem(string title, NSImage icon, ClickedDelegate clicked)
|
||||
{
|
||||
_items.Add(new SourceListItem(title, icon, clicked));
|
||||
}
|
||||
|
||||
public void AddItem(string title, NSImage icon, string tag)
|
||||
{
|
||||
_items.Add(new SourceListItem(title, icon, tag));
|
||||
}
|
||||
|
||||
public void AddItem(string title, NSImage icon, string tag, ClickedDelegate clicked)
|
||||
{
|
||||
_items.Add(new SourceListItem(title, icon, tag, clicked));
|
||||
}
|
||||
|
||||
public void Insert(int n, SourceListItem item)
|
||||
{
|
||||
_items.Insert(n, item);
|
||||
}
|
||||
|
||||
public void RemoveItem(SourceListItem item)
|
||||
{
|
||||
_items.Remove(item);
|
||||
}
|
||||
|
||||
public void RemoveItem(int n)
|
||||
{
|
||||
_items.RemoveAt(n);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_items.Clear();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
public delegate void ClickedDelegate();
|
||||
public event ClickedDelegate Clicked;
|
||||
|
||||
internal void RaiseClickedEvent()
|
||||
{
|
||||
this.Clicked?.Invoke();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
69
Cauldron.Macos/SourceList/SourceListView.cs
Normal file
69
Cauldron.Macos/SourceList/SourceListView.cs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
using System;
|
||||
using AppKit;
|
||||
using Foundation;
|
||||
|
||||
namespace Cauldron.Macos.SourceList
|
||||
{
|
||||
[Register("SourceListView")]
|
||||
public class SourceListView : NSOutlineView
|
||||
{
|
||||
#region Computed Properties
|
||||
|
||||
public SourceListDataSource Data
|
||||
{
|
||||
get { return (SourceListDataSource)this.DataSource; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public SourceListView() { }
|
||||
|
||||
public SourceListView(IntPtr handle) : base(handle) { }
|
||||
|
||||
public SourceListView(NSCoder coder) : base(coder) { }
|
||||
|
||||
public SourceListView(NSObjectFlag t) : base(t) { }
|
||||
|
||||
public SourceListView(ObjCRuntime.NativeHandle handle) : base(handle) { }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Override Methods
|
||||
|
||||
public override void AwakeFromNib()
|
||||
{
|
||||
base.AwakeFromNib();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
this.DataSource = new SourceListDataSource(this);
|
||||
this.Delegate = new SourceListDelegate(this);
|
||||
}
|
||||
|
||||
public void AddItem(SourceListItem item)
|
||||
{
|
||||
Data?.Items.Add(item);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
public delegate void ItemSelectedDelegate(SourceListItem item);
|
||||
public event ItemSelectedDelegate ItemSelected;
|
||||
|
||||
internal void RaiseItemSelected(SourceListItem item)
|
||||
{
|
||||
this.ItemSelected?.Invoke(item);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue