Skip to content
Open
Show file tree
Hide file tree
Changes from 11 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: 2 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
<PackageVersion Include="Debounce.Core" Version="1.0.0" />
<PackageVersion Include="DockPanelSuite" Version="3.1.1" />
<PackageVersion Include="DockPanelSuite.ThemeVS2015" Version="3.1.1" />
<PackageVersion Include="Extended.Wpf.Toolkit" Version="5.0.0" />
<PackageVersion Include="Fody" Version="6.6.4" />
<PackageVersion Include="FTD2XX.Net" Version="1.2.1" />
<PackageVersion Include="gong-wpf-dragdrop" Version="4.0.0" />
<PackageVersion Include="HtmlRenderer.WPF" Version="1.5.2" />
<PackageVersion Include="LiteDB" Version="4.1.4" />
<PackageVersion Include="LoadAssembliesOnStartup.Fody" Version="4.6.0" />
<PackageVersion Include="MessagePack" Version="2.5.192" />
Expand Down
224 changes: 181 additions & 43 deletions src/Vixen.Application/SetupDisplay/ViewModels/PropNodeTreeViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
using Orc.Wizard;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Controls;
using Vixen.Extensions;
using Vixen.Sys;
using Vixen.Sys.Managers;
using Vixen.Sys.Props;
Expand All @@ -22,11 +24,20 @@

namespace VixenApplication.SetupDisplay.ViewModels
{
public class PropTypeMenuItem
{
public PropType Id { get; set; }
public required string DisplayName { get; set; }
}

public class PropNodeTreeViewModel : ViewModelBase, IDropTarget, IDragSource
{
private static NLog.Logger Logging = NLog.LogManager.GetCurrentClassLogger();
public event EventHandler ModelsChanged;

public ObservableCollection<PropTypeMenuItem> AvailableProps { get; }
= new ObservableCollection<PropTypeMenuItem>();

public PropNodeTreeViewModel()
{
PropManager = VixenSystem.Props;
Expand All @@ -37,17 +48,22 @@ public PropNodeTreeViewModel()
PropComponentNodeViewModels = [pcvm];

PropNodes = new();
PropNodes.AddRange(RootNodeViewModel.SelectMany(x => x.GetPropEnumerator()));
Catel.Collections.CollectionExtensions.AddRange(PropNodes, RootNodeViewModel.SelectMany(x => x.GetPropEnumerator()));

PropManager.PropCollectionChanged += PropManager_PropCollectionChanged;
SelectedItems = new();
SelectedItems.CollectionChanged += SelectedItemsCollectionChanged;

foreach (PropType menuItem in Enum.GetValues(typeof(PropType)))
{
AvailableProps.Add(new PropTypeMenuItem { Id = menuItem, DisplayName = menuItem.GetEnumDescription() });
}
}

private void PropManager_PropCollectionChanged(object? sender, EventArgs e)
{
PropNodes.Clear();
PropNodes.AddRange(RootNodeViewModel.SelectMany(x => x.GetPropEnumerator()));
Catel.Collections.CollectionExtensions.AddRange(PropNodes, RootNodeViewModel.SelectMany(x => x.GetPropEnumerator()));
}

#region PropManager model property
Expand Down Expand Up @@ -126,6 +142,29 @@ public ObservableCollection<PropNodeViewModel> PropNodes

#endregion

public bool IsTopNode
{
get => GetValue<bool>(IsTopNodeProperty);
set => SetValue(IsTopNodeProperty, value);
}

public static readonly IPropertyData IsTopNodeProperty =
RegisterProperty<bool>(nameof(IsTopNode), true);

public bool IsSubNode
Copy link
Contributor

Choose a reason for hiding this comment

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

If IsTopNode and IsSubNode are inverses of each other used for visibility there are several methods of handling that in the XAML with InverseBooleanToVisibilityConverter. Only change if this appeals to you.

{
get => GetValue<bool>(IsSubNodeProperty);
set => SetValue(IsSubNodeProperty, value);
}

public static readonly IPropertyData IsSubNodeProperty =
RegisterProperty<bool>(nameof(IsSubNode), false);


private void OnIsTopNodeChanged()
Copy link
Contributor

Choose a reason for hiding this comment

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

This method appears not be used.

{
RaisePropertyChanged(nameof(IsSubNode));
}
#region SelectedItems property

/// <summary>
Expand Down Expand Up @@ -162,6 +201,7 @@ private void SelectedItemsCollectionChanged(object? sender, System.Collections.S
MoveToGroupCommand.RaiseCanExecuteChanged();
CreateNodeCommand.RaiseCanExecuteChanged();
CreatePropCommand.RaiseCanExecuteChanged();
ChangePropCommand.RaiseCanExecuteChanged();
}

#endregion
Expand Down Expand Up @@ -540,65 +580,62 @@ private bool CanCreateNode()

#region CreateProp command

private TaskCommand<string> _createPropCommand;
private TaskCommand<PropType> _createPropCommand;

/// <summary>
/// Gets the CreateProp command.
/// </summary>
public TaskCommand<string> CreatePropCommand
public TaskCommand<PropType> CreatePropCommand
{
get { return _createPropCommand ??= new(CreateProp, CanCreateProp); }
}

/// <summary>
/// Method to invoke when the CreatePropNode command is executed.
/// </summary>
private async Task CreateProp(string? propType)
private async Task CreateProp(PropType result)
{
if(Enum.TryParse(propType, out PropType result))
{
IPropGroup propGroup = await GeneratePropNodes(result);
IPropGroup propGroup = await GeneratePropNodes(result);

if (propGroup != null)
if (propGroup != null)
{
// Determine the parent of the group or props
PropNode pNodeParent;
if (SelectedItem != null)
{
// Determine the parent of the group or props
PropNode pNodeParent;
if (SelectedItem != null)
{
pNodeParent = SelectedItem.PropNode;
}
else
{
pNodeParent = PropManager.RootNode;
}
pNodeParent = SelectedItem.PropNode;
}
else
{
pNodeParent = PropManager.RootNode;
}

// If the props are to be grouped then...
PropNode groupNode;
if (propGroup.CreateGroup)
{
// Create the group prop node
groupNode = new(propGroup.GroupName);
// If the props are to be grouped then...
PropNode groupNode;
if (propGroup.CreateGroup)
{
// Create the group prop node
groupNode = new(propGroup.GroupName);

// Add the group node to the tree
PropManager.AddPropNode(groupNode, pNodeParent);
// Add the group node to the tree
PropManager.AddPropNode(groupNode, pNodeParent);

// Make the group node the parent
pNodeParent = groupNode;
}
// Make the group node the parent
pNodeParent = groupNode;
}

// Loop over the props
foreach (IProp prop in propGroup.Props)
// Loop over the props
foreach (IProp prop in propGroup.Props)
{
if (prop != null)
{
if (prop != null)
// Add the prop to the tree
PropManager.AddProp(prop, pNodeParent);

//Ensure parent is expanded
if (SelectedItem != null)
{
// Add the prop to the tree
PropManager.AddProp(prop, pNodeParent);

//Ensure parent is expanded
if (SelectedItem != null)
{
SelectedItem.IsExpanded = true;
}
SelectedItem.IsExpanded = true;
}
}
}
Expand All @@ -609,7 +646,7 @@ private async Task CreateProp(string? propType)
/// Method to check whether the CreatePropNode command can be executed.
/// </summary>
/// <returns><c>true</c> if the command can be executed; otherwise <c>false</c></returns>
private bool CanCreateProp(string? propType)
private bool CanCreateProp(PropType propType)
{
if (SelectedItems.Count == 1 && SelectedItem is { IsGroupNode: true })
{
Expand All @@ -621,6 +658,43 @@ private bool CanCreateProp(string? propType)

#endregion





#region ChangeProp command

private TaskCommand<PropType> _changePropCommand;

public TaskCommand<PropType> ChangePropCommand
{
get { return _changePropCommand ??= new(ChangeProp, CanChangeProp); }
}

private async Task ChangeProp(PropType result)
{
IPropGroup propGroup = await EditPropNodes(SelectedItems[0].PropNode.Prop);
RaisePropertyChanged(nameof(SelectedItem));
}

private bool CanChangeProp(PropType propType)
{
if (SelectedItems.Count == 1 && SelectedItem is { IsGroupNode: true })
{
return false;
}

return true;
}

#endregion







#region Cut command

private Command _cutCommand;
Expand Down Expand Up @@ -991,6 +1065,9 @@ private async Task<IPropGroup> GeneratePropNodes(PropType propType)
// Get the Catel type factory
ITypeFactory typeFactory = this.GetTypeFactory();

IPropFactory newPropFactory = PropFactory.CreateInstance(propType);
(IProp newProp, IPropGroup propGroup) = newPropFactory.CreateBaseProp();
Copy link
Contributor

Choose a reason for hiding this comment

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

This is where I noticed that supporting groups got broken. The previous design was that the prop(s) were not created until the user had gone through Wizard to know how many props to create. Seems like to me we may need to hide the Group page when editing the prop after initial creation. We also probably need to look into allowing the user to just hit finish rather than forcing them to go through all the pages. I think Nick was asking for this feature as well.


// Retrieve the color scheme service
IBaseColorSchemeService baseColorService = (IBaseColorSchemeService)dependencyResolver.Resolve(typeof(IBaseColorSchemeService));

Expand All @@ -1000,6 +1077,7 @@ private async Task<IPropGroup> GeneratePropNodes(PropType propType)
// Use the type factory to create the prop wizard
(IPropWizard Wizard, IPropFactory Factory) propWizard = PropWizardFactory.CreateInstance(propType, typeFactory);


// Configure the wizard window to show up in the Windows task bar
propWizard.Wizard.ShowInTaskbarWrapper = true;

Expand All @@ -1018,6 +1096,8 @@ private async Task<IPropGroup> GeneratePropNodes(PropType propType)
// Configure the wizard with a navigation controller
propWizard.Wizard.NavigationControllerWrapper = typeFactory.CreateInstanceWithParametersAndAutoCompletion<PropWizardNavigationController>(propWizard.Wizard);

newPropFactory.LoadWizard(newProp, propWizard.Wizard);

var ws = dependencyResolver.Resolve<IWizardService>();
if (ws != null && propWizard.Wizard != null)
{
Expand All @@ -1026,7 +1106,7 @@ private async Task<IPropGroup> GeneratePropNodes(PropType propType)
if (result.HasValue && result.Value)
{
// Have the prop factory create the props from the wizard data
IPropGroup propGroup = propWizard.Factory.GetProps(propWizard.Wizard);
newPropFactory.UpdateProp(newProp, propWizard.Wizard);

// User did not cancel
return propGroup;
Expand All @@ -1036,6 +1116,64 @@ private async Task<IPropGroup> GeneratePropNodes(PropType propType)
return null;
}

private async Task<IPropGroup> EditPropNodes(IProp newProp)
{
var dependencyResolver = this.GetDependencyResolver();

// Get the Catel type factory
ITypeFactory typeFactory = this.GetTypeFactory();

var propType = newProp.PropType;
IPropFactory newPropFactory = PropFactory.CreateInstance(propType);
IPropGroup propGroup = newPropFactory.EditExistingProp(newProp);

// Retrieve the color scheme service
IBaseColorSchemeService baseColorService = (IBaseColorSchemeService)dependencyResolver.Resolve(typeof(IBaseColorSchemeService));

// Select the dark color scheme
baseColorService.SetBaseColorScheme("Dark");

// Use the type factory to create the prop wizard
(IPropWizard Wizard, IPropFactory Factory) propWizard = PropWizardFactory.CreateInstance(propType, typeFactory);


// Configure the wizard window to show up in the Windows task bar
propWizard.Wizard.ShowInTaskbarWrapper = true;

// Enable the help button
propWizard.Wizard.ShowHelpWrapper = true;

// Configure the wizard to allow the user to jump between already visited pages
propWizard.Wizard.AllowQuickNavigationWrapper = true;

// Allow Catel to help determine when it is safe to transition to the next wizard page
propWizard.Wizard.HandleNavigationStatesWrapper = true;

// Configure the wizard to NOT cache views
propWizard.Wizard.CacheViewsWrapper = false;

// Configure the wizard with a navigation controller
propWizard.Wizard.NavigationControllerWrapper = typeFactory.CreateInstanceWithParametersAndAutoCompletion<PropWizardNavigationController>(propWizard.Wizard);

newPropFactory.LoadWizard(newProp, propWizard.Wizard);

var ws = dependencyResolver.Resolve<IWizardService>();
if (ws != null && propWizard.Wizard != null)
{
bool? result = (await ws.ShowWizardAsync(propWizard.Wizard)).DialogResult;
// Determine if the wizard was cancelled
if (result.HasValue && result.Value)
{
// Have the prop factory create the props from the wizard data
newPropFactory.UpdateProp(newProp, propWizard.Wizard);

// User did not cancel
return propGroup;
}
}

return null;
}
#endregion

#region Event Handling
Expand Down
Loading