Skip to content
This repository was archived by the owner on Sep 4, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Xwt.XamMac/Xwt.Mac.CellViews/CellViewBackend.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public void QueueDraw ()
public void QueueResize ()
{
CurrentCellView.NeedsDisplay = true;
((ICellRenderer)CurrentCellView).CellContainer.InvalidateRowHeight ();
((ICellRenderer)CurrentCellView).CellContainer.QueueResize ();
}

public Rectangle CellBounds {
Expand Down
6 changes: 3 additions & 3 deletions Xwt.XamMac/Xwt.Mac.CellViews/CompositeCell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,11 @@ public void SetCurrentEventRow ()
}

bool recalculatingHeight = false;
public void InvalidateRowHeight ()
public void QueueResize ()
{
if (tablePosition != null && !recalculatingHeight) {
recalculatingHeight = true;
source.InvalidateRowHeight (tablePosition.Position);
source.QueueResizeRow (tablePosition.Position);
recalculatingHeight = false;
}
}
Expand Down Expand Up @@ -193,7 +193,7 @@ public override CGRect Frame {
height = Math.Max (height, c.Frame.Height);
}
if (Math.Abs(value.Height - height) > double.Epsilon)
InvalidateRowHeight ();
QueueResize ();

}
}
Expand Down
2 changes: 1 addition & 1 deletion Xwt.XamMac/Xwt.Mac.CellViews/ICellSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ interface ICellSource
object GetValue (object pos, int nField);
void SetValue (object pos, int nField, object value);
void SetCurrentEventRow (object pos);
void InvalidateRowHeight (object pos);
void QueueResizeRow (object pos);
List<NSTableColumn> Columns { get; }
NSTableView TableView { get; }
}
Expand Down
67 changes: 57 additions & 10 deletions Xwt.XamMac/Xwt.Mac/ListViewBackend.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,25 @@ public override nfloat GetSizeToFitColumnWidth (NSTableView tableView, nint colu
{
var tableColumn = Backend.Columns[(int)column] as TableColumn;
var width = tableColumn.HeaderCell.CellSize.Width;
var rowWidths = Backend.ColumnRowWidths[(int)column];

CompositeCell templateCell = null;
for (int i = 0; i < tableView.RowCount; i++) {
if (rowWidths[i] > -1)
width = (nfloat)Math.Max (width, rowWidths[i]);
else {
var cellView = tableView.GetView (column, i, false) as CompositeCell;
if (cellView == null) { // use template for invisible rows
cellView = templateCell ?? (templateCell = (tableColumn as TableColumn)?.DataView?.Copy () as CompositeCell);
if (cellView != null)
cellView.ObjectValue = NSNumber.FromInt32 (i);
if (cellView == null) { // use template for invisible rows
cellView = templateCell ?? (templateCell = (tableColumn as TableColumn)?.DataView as CompositeCell);
if (cellView != null)
cellView.ObjectValue = NSNumber.FromInt32 (i);
}
if (cellView != null) {
var size = cellView.FittingSize;
rowWidths[i] = size.Width;
width = (nfloat)Math.Max (width, size.Width);
}
}
width = (nfloat)Math.Max (width, cellView.FittingSize.Width);
}
return width;
}
Expand All @@ -95,6 +104,9 @@ public override NSIndexSet GetSelectionIndexes(NSTableView tableView, NSIndexSet
IListDataSource source;
ListSource tsource;

List<List<nfloat>> ColumnRowWidths = new List<List<nfloat>> ();
List<nfloat> RowHeights = new List<nfloat> ();

protected override NSTableView CreateView ()
{
var listView = new NSTableViewBackend (this);
Expand Down Expand Up @@ -140,14 +152,36 @@ void HandleDoubleClick (object sender, EventArgs e)
});
}
}


public override NSTableColumn AddColumn (ListViewColumn col)
{
NSTableColumn tcol = base.AddColumn (col);
var widths = new List<nfloat> ();
if (Table.RowCount > 0)
widths.InsertRange (0, Enumerable.Repeat<nfloat> (-1f, (int)Table.RowCount));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will do Insert N times instead of doing a block insert. Avoid direct IEnumerables here. Please pass something ICollection derived. (the IEnumerable<T> overload handles checking for ICollection<T>)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I think pre-allocating list capacity (new List<nfloat> (table.RowCount) then doing
for (int i = 0; i < Table.RowCount; ++i) widths.Add (-1f) is better

ColumnRowWidths.Add (widths);
return tcol;
}

public override void RemoveColumn (ListViewColumn col, object handle)
{
var tcol = (NSTableColumn)handle;
var index = Columns.IndexOf (tcol);
ColumnRowWidths.RemoveAt (index);
base.RemoveColumn (col, handle);
}

public virtual void SetSource (IListDataSource source, IBackend sourceBackend)
{
this.source = source;

RowHeights = new List<nfloat> ();
for (int i = 0; i < source.RowCount; i++)
RowHeights.Add (-1);
foreach (var colWidths in ColumnRowWidths) {
colWidths.Clear ();
colWidths.AddRange (Enumerable.Repeat<nfloat> (-1, source.RowCount));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, AddRange on IEnumerable<T> but not ICollection<T> does not do block copy.

}

tsource = new ListSource (source);
Table.DataSource = tsource;
Expand All @@ -157,30 +191,43 @@ public virtual void SetSource (IListDataSource source, IBackend sourceBackend)
// only the visible rows are reloaded.
source.RowInserted += (sender, e) => {
RowHeights.Insert (e.Row, -1);
foreach (var colWidths in ColumnRowWidths)
colWidths.Insert (e.Row, -1);
Table.ReloadData ();
};
source.RowDeleted += (sender, e) => {
RowHeights.RemoveAt (e.Row);
foreach (var colWidths in ColumnRowWidths)
colWidths.RemoveAt (e.Row);
Table.ReloadData ();
};
source.RowChanged += (sender, e) => {
UpdateRowHeight (e.Row);
Table.ReloadData (NSIndexSet.FromIndex (e.Row), NSIndexSet.FromNSRange (new NSRange (0, Table.ColumnCount)));
};
source.RowsReordered += (sender, e) => { RowHeights.Clear (); Table.ReloadData (); };
source.RowsReordered += (sender, e) => {
RowHeights.Clear ();
foreach (var colWidths in ColumnRowWidths)
colWidths.Clear ();
Table.ReloadData ();
};
}

public override void InvalidateRowHeight (object pos)
public override void QueueResizeRow (object pos)
{
UpdateRowHeight((int)pos);
}

List<nfloat> RowHeights = new List<nfloat> ();

bool updatingRowHeight;
public void UpdateRowHeight (nint row)
{
if (updatingRowHeight)
return;

// FIXME: this won't resize the columns, which might be needed for custom cells
// In order to resize horizontally we'll need trigger column autosizing.
foreach (var colWidths in ColumnRowWidths) // invalidate widths for full recalculation
colWidths[(int)row] = -1;
RowHeights[(int)row] = CalcRowHeight (row);
Table.NoteHeightOfRowsWithIndexesChanged (NSIndexSet.FromIndex (row));
}
Expand Down
4 changes: 2 additions & 2 deletions Xwt.XamMac/Xwt.Mac/TableViewBackend.cs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ object IColumnContainerBackend.AddColumn (ListViewColumn col)
return AddColumn (col);
}

public void RemoveColumn (ListViewColumn col, object handle)
public virtual void RemoveColumn (ListViewColumn col, object handle)
{
var tcol = (NSTableColumn)handle;
cols.Remove (tcol);
Expand Down Expand Up @@ -271,7 +271,7 @@ public void StartEditingCell (int row, CellView cell)

public abstract void SetCurrentEventRow (object pos);

public abstract void InvalidateRowHeight (object pos);
public abstract void QueueResizeRow (object pos);

public bool BorderVisible {
get { return scroll.BorderType == NSBorderType.BezelBorder;}
Expand Down
70 changes: 54 additions & 16 deletions Xwt.XamMac/Xwt.Mac/TreeViewBackend.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ public class TreeViewBackend: TableViewBackend<NSOutlineView,ITreeViewEventSink>
ITreeDataSource source;
TreeSource tsource;

List<Dictionary<TreePosition, nfloat>> ColumnRowWidths = new List<Dictionary<TreePosition, nfloat>> ();
Dictionary<TreeItem, nfloat> RowHeights = new Dictionary<TreeItem, nfloat> ();

class TreeDelegate: NSOutlineViewDelegate
{
public TreeViewBackend Backend;
Expand Down Expand Up @@ -95,17 +98,23 @@ public override nfloat GetSizeToFitColumnWidth (NSOutlineView outlineView, nint

CompositeCell templateCell = null;
for (int i = 0; i < outlineView.RowCount; i++) {
var cellView = outlineView.GetView (column, i, false) as CompositeCell;
if (cellView == null) { // use template for invisible rows
cellView = templateCell ?? (templateCell = (tableColumn as TableColumn)?.DataView?.Copy () as CompositeCell);
if (cellView != null)
cellView.ObjectValue = outlineView.ItemAtRow (i);
}
if (cellView != null) {
if (column == 0) // first column contains expanders
width = (nfloat)Math.Max (width, cellView.Frame.X + cellView.FittingSize.Width);
else
width = (nfloat)Math.Max (width, cellView.FittingSize.Width);
nfloat cellWidth;
var item = (TreeItem)outlineView.ItemAtRow (i);
if (Backend.ColumnRowWidths[(int)column].TryGetValue (item.Position, out cellWidth) && cellWidth > -1)
width = (nfloat)Math.Max (width, cellWidth);
else {
var cellView = outlineView.GetView (column, i, false) as CompositeCell;
if (cellView == null) { // use template for invisible rows
cellView = templateCell ?? (templateCell = (tableColumn as TableColumn)?.DataView as CompositeCell);
if (cellView != null)
cellView.ObjectValue = item;
}
if (cellView != null) {
// first column contains expanders
cellWidth = column == 0 ? cellView.Frame.X + cellView.FittingSize.Width : cellView.FittingSize.Width;
Backend.ColumnRowWidths[(int)column][item.Position] = cellWidth;
width = (nfloat)Math.Max (width, cellWidth);
}
}
}
return width;
Expand Down Expand Up @@ -148,8 +157,17 @@ public override NSTableColumn AddColumn (ListViewColumn col)
NSTableColumn tcol = base.AddColumn (col);
if (Tree.OutlineTableColumn == null)
Tree.OutlineTableColumn = tcol;
ColumnRowWidths.Add (new Dictionary<TreePosition, nfloat> ());
return tcol;
}

public override void RemoveColumn (ListViewColumn col, object handle)
{
var tcol = (NSTableColumn)handle;
var index = Columns.IndexOf (tcol);
ColumnRowWidths.RemoveAt (index);
base.RemoveColumn (col, handle);
}

public void SetSource (ITreeDataSource source, IBackend sourceBackend)
{
Expand All @@ -163,6 +181,8 @@ public void SetSource (ITreeDataSource source, IBackend sourceBackend)
Tree.ReloadItem (parent, parent == null || Tree.IsItemExpanded (parent));
};
source.NodeDeleted += (sender, e) => {
foreach (var colWidths in ColumnRowWidths)
colWidths.Remove (e.Child);
var parent = tsource.GetItem (e.Node);
var item = tsource.GetItem(e.Child);
if (item != null)
Expand All @@ -173,17 +193,24 @@ public void SetSource (ITreeDataSource source, IBackend sourceBackend)
var item = tsource.GetItem (e.Node);
if (item != null) {
Tree.ReloadItem (item, false);
foreach (var colWidths in ColumnRowWidths)
colWidths [e.Node] = -1;
UpdateRowHeight (item);
}
};
source.NodesReordered += (sender, e) => {
var parent = tsource.GetItem (e.Node);
foreach (var colWidths in ColumnRowWidths)
for (int i = 0; i < source.GetChildrenCount (e.Node); i++)
colWidths [source.GetChild (e.Node, i)] = -1;
Tree.ReloadItem (parent, parent == null || Tree.IsItemExpanded (parent));
};
source.Cleared += (sender, e) =>
{
Tree.ReloadData ();
RowHeights.Clear ();
foreach (var colWidths in ColumnRowWidths)
colWidths.Clear ();
};
}

Expand All @@ -197,12 +224,11 @@ public override void SetValue (object pos, int nField, object value)
source.SetValue ((TreePosition)pos, nField, value);
}

public override void InvalidateRowHeight (object pos)
public override void QueueResizeRow (object pos)
{
UpdateRowHeight (tsource.GetItem((TreePosition)pos));
}

Dictionary<TreeItem, nfloat> RowHeights = new Dictionary<TreeItem, nfloat> ();
bool updatingRowHeight;

void UpdateRowHeight (TreeItem pos)
Expand All @@ -211,8 +237,12 @@ void UpdateRowHeight (TreeItem pos)
return;
var row = Tree.RowForItem (pos);
if (row >= 0) {
// calculate new height now by reusing the visible cell to avoid using the template cell with unnecessary data reloads
// calculate new size now by reusing the visible cell to avoid using the template cell with unnecessary data reloads
// NOTE: cell reusing is not supported in Delegate.GetRowHeight and would require an other data reload to the template cell
// FIXME: this won't resize the columns, which might be needed for custom cells
// In order to resize horizontally we'll need trigger column autosizing.
foreach (var colWidths in ColumnRowWidths) // invalidate widths for full recalculation
colWidths [pos.Position] = -1;
RowHeights[pos] = CalcRowHeight (pos);
Table.NoteHeightOfRowsWithIndexesChanged (NSIndexSet.FromIndex (row));
} else // Invalidate the height, to force recalculation in Delegate.GetRowHeight
Expand All @@ -226,13 +256,21 @@ nfloat CalcRowHeight (TreeItem pos, bool tryReuse = true)
var row = Tree.RowForItem (pos);

for (int i = 0; i < Columns.Count; i++) {
var col = (TableColumn)Columns [i];
CompositeCell cell = tryReuse && row >= 0 ? Tree.GetView (i, row, false) as CompositeCell : null;
if (cell == null) {
cell = (Columns [i] as TableColumn)?.DataView as CompositeCell;
cell = col.DataView;
cell.ObjectValue = pos;
height = (nfloat)Math.Max (height, cell.FittingSize.Height);
} else {
height = (nfloat)Math.Max (height, cell.GetRequiredHeightForWidth (cell.Frame.Width));
nfloat cellWidth = -1;
ColumnRowWidths [i].TryGetValue (pos.Position, out cellWidth);
if (cellWidth <= 0)
cellWidth = cell.Frame.Width;
if (cellWidth <= 0)
height = (nfloat)Math.Max (height, cell.FittingSize.Height);
else
height = (nfloat)Math.Max (height, cell.GetRequiredHeightForWidth (cellWidth));
}
}
updatingRowHeight = false;
Expand Down