5 changed files with 215 additions and 198 deletions
@ -1,144 +1,80 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
|
|||
#nullable enable |
|||
|
|||
namespace Avalonia.Controls |
|||
{ |
|||
internal class SelectionModelChangeSet |
|||
{ |
|||
private SelectionNode _owner; |
|||
private List<IndexRange>? _selected; |
|||
private List<IndexRange>? _deselected; |
|||
|
|||
public SelectionModelChangeSet(SelectionNode owner) => _owner = owner; |
|||
|
|||
public bool IsTracking { get; private set; } |
|||
public bool HasChanges => _selected?.Count > 0 || _deselected?.Count > 0; |
|||
public IEnumerable<IndexPath> SelectedIndices => EnumerateIndices(_selected); |
|||
public IEnumerable<IndexPath> DeselectedIndices => EnumerateIndices(_deselected); |
|||
public IEnumerable<object> SelectedItems => EnumerateItems(_selected); |
|||
public IEnumerable<object> DeselectedItems => EnumerateItems(_deselected); |
|||
private List<SelectionNodeOperation> _changes; |
|||
|
|||
public void BeginOperation() |
|||
public SelectionModelChangeSet(List<SelectionNodeOperation> changes) |
|||
{ |
|||
if (IsTracking) |
|||
{ |
|||
throw new AvaloniaInternalException("SelectionModel change operation already in progress."); |
|||
} |
|||
|
|||
IsTracking = true; |
|||
_selected?.Clear(); |
|||
_deselected?.Clear(); |
|||
_changes = changes; |
|||
} |
|||
|
|||
public void EndOperation() => IsTracking = false; |
|||
|
|||
public void Selected(IndexRange range) |
|||
public SelectionModelSelectionChangedEventArgs CreateEventArgs() |
|||
{ |
|||
if (!IsTracking) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
Add(range, ref _selected, _deselected); |
|||
return new SelectionModelSelectionChangedEventArgs( |
|||
CreateIndices(x => x.DeselectedRanges), |
|||
CreateIndices(x => x.SelectedRanges), |
|||
CreateItems(x => x.DeselectedRanges), |
|||
CreateItems(x => x.SelectedRanges)); |
|||
} |
|||
|
|||
public void Selected(IEnumerable<IndexRange> ranges) |
|||
private IReadOnlyList<IndexPath> CreateIndices(Func<SelectionNodeOperation, List<IndexRange>?> selector) |
|||
{ |
|||
if (!IsTracking) |
|||
if (_changes == null) |
|||
{ |
|||
return; |
|||
return Array.Empty<IndexPath>(); |
|||
} |
|||
|
|||
foreach (var range in ranges) |
|||
{ |
|||
Selected(range); |
|||
} |
|||
} |
|||
|
|||
public void Deselected(IndexRange range) |
|||
{ |
|||
if (!IsTracking) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
Add(range, ref _deselected, _selected); |
|||
} |
|||
var result = new List<IndexPath>(); |
|||
|
|||
public void Deselected(IEnumerable<IndexRange> ranges) |
|||
{ |
|||
if (!IsTracking) |
|||
foreach (var i in _changes) |
|||
{ |
|||
return; |
|||
} |
|||
var ranges = selector(i); |
|||
|
|||
foreach (var range in ranges) |
|||
{ |
|||
Deselected(range); |
|||
} |
|||
} |
|||
|
|||
private static void Add( |
|||
IndexRange range, |
|||
ref List<IndexRange>? add, |
|||
List<IndexRange>? remove) |
|||
{ |
|||
if (remove != null) |
|||
{ |
|||
var removed = new List<IndexRange>(); |
|||
IndexRange.Remove(remove, range, removed); |
|||
var selected = IndexRange.Subtract(range, removed); |
|||
|
|||
if (selected.Any()) |
|||
if (ranges != null) |
|||
{ |
|||
add ??= new List<IndexRange>(); |
|||
|
|||
foreach (var r in selected) |
|||
foreach (var j in ranges) |
|||
{ |
|||
IndexRange.Add(add, r); |
|||
for (var k = j.Begin; k <= j.End; ++k) |
|||
{ |
|||
result.Add(i.Path.CloneWithChildIndex(k)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
add ??= new List<IndexRange>(); |
|||
IndexRange.Add(add, range); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
private IEnumerable<IndexPath> EnumerateIndices(IEnumerable<IndexRange>? ranges) |
|||
private IReadOnlyList<object> CreateItems(Func<SelectionNodeOperation, List<IndexRange>?> selector) |
|||
{ |
|||
var path = _owner.IndexPath; |
|||
|
|||
if (ranges != null) |
|||
if (_changes == null) |
|||
{ |
|||
foreach (var range in ranges) |
|||
{ |
|||
for (var i = range.Begin; i <= range.End; ++i) |
|||
{ |
|||
yield return path.CloneWithChildIndex(i); |
|||
} |
|||
} |
|||
return Array.Empty<object>(); |
|||
} |
|||
} |
|||
|
|||
private IEnumerable<object> EnumerateItems(IEnumerable<IndexRange>? ranges) |
|||
{ |
|||
var items = _owner.ItemsSourceView; |
|||
var result = new List<object>(); |
|||
|
|||
if (ranges != null && items != null) |
|||
foreach (var i in _changes) |
|||
{ |
|||
foreach (var range in ranges) |
|||
var ranges = selector(i); |
|||
|
|||
if (ranges != null && i.Items != null) |
|||
{ |
|||
for (var i = range.Begin; i <= range.End; ++i) |
|||
foreach (var j in ranges) |
|||
{ |
|||
yield return items.GetAt(i); |
|||
for (var k = j.Begin; k <= j.End; ++k) |
|||
{ |
|||
result.Add(i.Items.GetAt(k)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,80 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
|
|||
#nullable enable |
|||
|
|||
namespace Avalonia.Controls |
|||
{ |
|||
internal class SelectionNodeOperation |
|||
{ |
|||
private readonly SelectionNode _owner; |
|||
private List<IndexRange>? _selected; |
|||
private List<IndexRange>? _deselected; |
|||
|
|||
public SelectionNodeOperation(SelectionNode owner) |
|||
{ |
|||
_owner = owner; |
|||
} |
|||
|
|||
public bool HasChanges => _selected?.Count > 0 || _deselected?.Count > 0; |
|||
public List<IndexRange>? SelectedRanges => _selected; |
|||
public List<IndexRange>? DeselectedRanges => _deselected; |
|||
public IndexPath Path => _owner.IndexPath; |
|||
public ItemsSourceView? Items => _owner.ItemsSourceView; |
|||
|
|||
public void Selected(IndexRange range) |
|||
{ |
|||
Add(range, ref _selected, _deselected); |
|||
} |
|||
|
|||
public void Selected(IEnumerable<IndexRange> ranges) |
|||
{ |
|||
foreach (var range in ranges) |
|||
{ |
|||
Selected(range); |
|||
} |
|||
} |
|||
|
|||
public void Deselected(IndexRange range) |
|||
{ |
|||
Add(range, ref _deselected, _selected); |
|||
} |
|||
|
|||
public void Deselected(IEnumerable<IndexRange> ranges) |
|||
{ |
|||
foreach (var range in ranges) |
|||
{ |
|||
Deselected(range); |
|||
} |
|||
} |
|||
|
|||
private static void Add( |
|||
IndexRange range, |
|||
ref List<IndexRange>? add, |
|||
List<IndexRange>? remove) |
|||
{ |
|||
if (remove != null) |
|||
{ |
|||
var removed = new List<IndexRange>(); |
|||
IndexRange.Remove(remove, range, removed); |
|||
var selected = IndexRange.Subtract(range, removed); |
|||
|
|||
if (selected.Any()) |
|||
{ |
|||
add ??= new List<IndexRange>(); |
|||
|
|||
foreach (var r in selected) |
|||
{ |
|||
IndexRange.Add(add, r); |
|||
} |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
add ??= new List<IndexRange>(); |
|||
IndexRange.Add(add, range); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue