port from perforce

This commit is contained in:
2026-04-18 22:31:51 +02:00
commit 8d0ab5b7cc
8409 changed files with 3972376 additions and 0 deletions

View File

@@ -0,0 +1,126 @@
using DynamicData;
using ReactiveUI;
using System;
using System.Linq;
using System.Reactive.Linq;
using System.Windows.Input;
namespace NodeNetwork.Toolkit.ContextMenu
{
/// <summary>
/// A data type containing a command, parameter and display properties.
/// </summary>
public class LabeledCommand : ReactiveObject
{
#region Label
/// <summary>
/// The label that is displayed in the menu
/// </summary>
public string Label
{
get => _label;
set => this.RaiseAndSetIfChanged(ref _label, value);
}
private string _label = "";
#endregion
#region Visible
/// <summary>
/// Should the command be displayed in the menu?
/// </summary>
public bool Visible
{
get => _visible;
set => this.RaiseAndSetIfChanged(ref _visible, value);
}
private bool _visible = true;
#endregion
#region Command
/// <summary>
/// The command to be executed.
/// </summary>
public ICommand Command
{
get => _command;
set => this.RaiseAndSetIfChanged(ref _command, value);
}
private ICommand _command = null;
#endregion
#region CommandParameter
/// <summary>
/// The parameter to be passed to the command on execution.
/// </summary>
public object CommandParameter
{
get => _commandParameter;
set => this.RaiseAndSetIfChanged(ref _commandParameter, value);
}
private object _commandParameter = null;
#endregion
}
/// <summary>
/// A viewmodel for a context menu in which the entries can be filtered by the user based on a searchquery.
/// </summary>
public class SearchableContextMenuViewModel : ReactiveObject
{
static SearchableContextMenuViewModel()
{
NNViewRegistrar.AddRegistration(() => new SearchableContextMenuView(), typeof(IViewFor<SearchableContextMenuViewModel>));
}
/// <summary>
/// List of all the available commands in the menu.
/// </summary>
public ISourceList<LabeledCommand> Commands { get; } = new SourceList<LabeledCommand>();
/// <summary>
/// List of commands that are actually visible in the menu.
/// This list is based on Commands and SearchQuery.
/// </summary>
public IObservableList<LabeledCommand> VisibleCommands { get; }
#region SearchQuery
/// <summary>
/// The current search string that is used to filter Nodes into VisibleNodes.
/// </summary>
public string SearchQuery
{
get => _searchQuery;
set => this.RaiseAndSetIfChanged(ref _searchQuery, value);
}
private string _searchQuery = "";
#endregion
#region MaxItemsDisplayed
/// <summary>
/// Only the first MaxItemsDisplayed items from Commands that match the query are displayed.
/// </summary>
public int MaxItemsDisplayed
{
get => _maxItemsDisplayed;
set => this.RaiseAndSetIfChanged(ref _maxItemsDisplayed, value);
}
private int _maxItemsDisplayed = int.MaxValue;
#endregion
public SearchableContextMenuViewModel()
{
var onQueryChanged =
this.WhenAnyValue(vm => vm.SearchQuery, vm => vm.MaxItemsDisplayed)
.Throttle(TimeSpan.FromMilliseconds(70), RxApp.MainThreadScheduler)
.Publish();
onQueryChanged.Connect();
VisibleCommands = Commands.Connect()
.AutoRefreshOnObservable(_ => onQueryChanged)
.AutoRefresh(cmd => cmd.Label)
.AutoRefresh(cmd => cmd.Visible)
.Filter(cmd => cmd.Visible && (cmd.Label ?? "").ToUpper().Contains(SearchQuery?.ToUpper() ?? ""))
.Top(MaxItemsDisplayed)
.AsObservableList();
}
}
}