mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
166 lines
6.5 KiB
C#
166 lines
6.5 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.ComponentModel;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Data;
|
|
using System.Windows.Input;
|
|
using Artemis.Core;
|
|
using Artemis.VisualScripting.Editor.Controls.Wrapper;
|
|
|
|
namespace Artemis.VisualScripting.Editor.Controls
|
|
{
|
|
[TemplatePart(Name = PART_SEARCHBOX, Type = typeof(TextBox))]
|
|
[TemplatePart(Name = PART_CONTENT, Type = typeof(ListBox))]
|
|
public class VisualScriptNodeCreationBox : Control
|
|
{
|
|
#region Constants
|
|
|
|
private const string PART_SEARCHBOX = "PART_SearchBox";
|
|
private const string PART_CONTENT = "PART_Content";
|
|
|
|
#endregion
|
|
|
|
#region Properties & Fields
|
|
|
|
private TextBox _searchBox;
|
|
private ListBox _contentList;
|
|
|
|
private CollectionViewSource _collectionViewSource;
|
|
private ICollectionView _contentView;
|
|
|
|
#endregion
|
|
|
|
#region DependencyProperties
|
|
|
|
public static readonly DependencyProperty AvailableNodesProperty = DependencyProperty.Register(
|
|
"AvailableNodes", typeof(IEnumerable), typeof(VisualScriptNodeCreationBox), new PropertyMetadata(default(IEnumerable), OnItemsSourceChanged));
|
|
|
|
public IEnumerable AvailableNodes
|
|
{
|
|
get => (IEnumerable) GetValue(AvailableNodesProperty);
|
|
set => SetValue(AvailableNodesProperty, value);
|
|
}
|
|
|
|
public static readonly DependencyProperty SourcePinProperty = DependencyProperty.Register(
|
|
"SourcePin", typeof(VisualScriptPin), typeof(VisualScriptNodeCreationBox), new PropertyMetadata(default(VisualScriptPin), OnSourcePinChanged));
|
|
|
|
public VisualScriptPin SourcePin
|
|
{
|
|
get => (VisualScriptPin) GetValue(SourcePinProperty);
|
|
set => SetValue(SourcePinProperty, value);
|
|
}
|
|
|
|
public static readonly DependencyProperty CreateNodeCommandProperty = DependencyProperty.Register(
|
|
"CreateNodeCommand", typeof(ICommand), typeof(VisualScriptNodeCreationBox), new PropertyMetadata(default(ICommand)));
|
|
|
|
public ICommand CreateNodeCommand
|
|
{
|
|
get => (ICommand) GetValue(CreateNodeCommandProperty);
|
|
set => SetValue(CreateNodeCommandProperty, value);
|
|
}
|
|
|
|
public static readonly DependencyProperty SearchInputProperty = DependencyProperty.Register(
|
|
"SearchInput", typeof(string), typeof(VisualScriptNodeCreationBox), new PropertyMetadata(default(string), OnSearchInputChanged));
|
|
|
|
public string SearchInput
|
|
{
|
|
get => (string) GetValue(SearchInputProperty);
|
|
set => SetValue(SearchInputProperty, value);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
public override void OnApplyTemplate()
|
|
{
|
|
_searchBox = GetTemplateChild(PART_SEARCHBOX) as TextBox ?? throw new NullReferenceException($"The Element '{PART_SEARCHBOX}' is missing.");
|
|
_contentList = GetTemplateChild(PART_CONTENT) as ListBox ?? throw new NullReferenceException($"The Element '{PART_CONTENT}' is missing.");
|
|
|
|
_contentList.IsSynchronizedWithCurrentItem = false;
|
|
_contentList.SelectionChanged += OnContentListSelectionChanged;
|
|
_contentList.SelectionMode = SelectionMode.Single;
|
|
IsVisibleChanged += OnIsVisibleChanged;
|
|
|
|
_searchBox.Focus();
|
|
_contentView?.Refresh();
|
|
ItemsSourceChanged();
|
|
}
|
|
|
|
private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
if (e.NewValue is not true)
|
|
return;
|
|
|
|
_searchBox.Focus();
|
|
_searchBox.SelectionStart = 0;
|
|
_searchBox.SelectionLength = _searchBox.Text.Length;
|
|
}
|
|
|
|
private void OnContentListSelectionChanged(object sender, SelectionChangedEventArgs args)
|
|
{
|
|
if ((args == null) || (_contentList?.SelectedItem == null)) return;
|
|
|
|
CreateNodeCommand?.Execute(_contentList.SelectedItem);
|
|
_contentList.SelectedItem = null;
|
|
}
|
|
|
|
private bool Filter(object o)
|
|
{
|
|
if (o is not NodeData nodeData) return false;
|
|
|
|
bool searchContains;
|
|
if (string.IsNullOrWhiteSpace(SearchInput))
|
|
searchContains = true;
|
|
else
|
|
{
|
|
searchContains = nodeData.Name.Contains(SearchInput, StringComparison.OrdinalIgnoreCase) ||
|
|
nodeData.Description.Contains(SearchInput, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
if (SourcePin == null || SourcePin.Pin.Type == typeof(object))
|
|
return searchContains;
|
|
|
|
if (SourcePin.Pin.Direction == PinDirection.Input)
|
|
return nodeData.OutputType != null && searchContains && (nodeData.OutputType == typeof(object) || nodeData.OutputType.IsAssignableTo(SourcePin.Pin.Type));
|
|
return nodeData.InputType != null && searchContains && (nodeData.InputType == typeof(object) || nodeData.InputType.IsAssignableFrom(SourcePin.Pin.Type));
|
|
}
|
|
|
|
private void ItemsSourceChanged()
|
|
{
|
|
if (_contentList == null) return;
|
|
|
|
if (AvailableNodes == null)
|
|
{
|
|
_contentView = null;
|
|
_collectionViewSource = null;
|
|
}
|
|
else
|
|
{
|
|
_collectionViewSource = new CollectionViewSource
|
|
{
|
|
Source = AvailableNodes,
|
|
SortDescriptions =
|
|
{
|
|
new SortDescription(nameof(NodeData.Category), ListSortDirection.Ascending),
|
|
new SortDescription(nameof(NodeData.Name), ListSortDirection.Ascending)
|
|
},
|
|
GroupDescriptions = {new PropertyGroupDescription(nameof(NodeData.Category))}
|
|
};
|
|
_contentView = _collectionViewSource.View;
|
|
_contentView.Filter += Filter;
|
|
}
|
|
|
|
_contentList.ItemsSource = _contentView;
|
|
}
|
|
|
|
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs args) => (d as VisualScriptNodeCreationBox)?.ItemsSourceChanged();
|
|
|
|
private static void OnSourcePinChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => (d as VisualScriptNodeCreationBox)?._contentView.Refresh();
|
|
|
|
private static void OnSearchInputChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => (d as VisualScriptNodeCreationBox)?._contentView.Refresh();
|
|
|
|
#endregion
|
|
}
|
|
} |