mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-01-01 10:13:30 +00:00
Debugger - Added datamodel debugger
Shared UI - Added data model VMs
This commit is contained in:
parent
e05de0d780
commit
e4c1c99e27
2
src/.idea/.idea.Artemis/.idea/avalonia.xml
generated
2
src/.idea/.idea.Artemis/.idea/avalonia.xml
generated
@ -14,6 +14,8 @@
|
|||||||
<entry key="Artemis.UI.Avalonia/Screens/Sidebar/Views/SidebarProfileConfigurationView.axaml" value="Artemis.UI.Avalonia/Artemis.UI.Avalonia.csproj" />
|
<entry key="Artemis.UI.Avalonia/Screens/Sidebar/Views/SidebarProfileConfigurationView.axaml" value="Artemis.UI.Avalonia/Artemis.UI.Avalonia.csproj" />
|
||||||
<entry key="Artemis.UI.Avalonia/Screens/SidebarView.axaml" value="Artemis.UI.Avalonia/Artemis.UI.Avalonia.csproj" />
|
<entry key="Artemis.UI.Avalonia/Screens/SidebarView.axaml" value="Artemis.UI.Avalonia/Artemis.UI.Avalonia.csproj" />
|
||||||
<entry key="Artemis.UI.Avalonia/Views/MainWindow.axaml" value="Artemis.UI.Avalonia/Artemis.UI.Avalonia.csproj" />
|
<entry key="Artemis.UI.Avalonia/Views/MainWindow.axaml" value="Artemis.UI.Avalonia/Artemis.UI.Avalonia.csproj" />
|
||||||
|
<entry key="Avalonia/Artemis.UI/Screens/Debugger/Tabs/Render/RenderDebugView.axaml" value="Avalonia/Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
|
<entry key="Avalonia/Artemis.UI/Styles/Artemis.axaml" value="Avalonia/Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
</map>
|
</map>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
@ -3,8 +3,6 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Artemis.Core.Ninject;
|
using Artemis.Core.Ninject;
|
||||||
using Artemis.Core.ScriptingProviders;
|
using Artemis.Core.ScriptingProviders;
|
||||||
using Artemis.Storage;
|
using Artemis.Storage;
|
||||||
@ -23,17 +21,19 @@ namespace Artemis.Core.Services
|
|||||||
internal class CoreService : ICoreService
|
internal class CoreService : ICoreService
|
||||||
{
|
{
|
||||||
internal static IKernel? Kernel;
|
internal static IKernel? Kernel;
|
||||||
|
|
||||||
private readonly Stopwatch _frameStopWatch;
|
private readonly Stopwatch _frameStopWatch;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly PluginSetting<LogEventLevel> _loggingLevel;
|
private readonly PluginSetting<LogEventLevel> _loggingLevel;
|
||||||
|
private readonly IModuleService _moduleService;
|
||||||
private readonly IPluginManagementService _pluginManagementService;
|
private readonly IPluginManagementService _pluginManagementService;
|
||||||
private readonly IProfileService _profileService;
|
private readonly IProfileService _profileService;
|
||||||
private readonly IModuleService _moduleService;
|
|
||||||
private readonly IScriptingService _scriptingService;
|
|
||||||
private readonly IRgbService _rgbService;
|
private readonly IRgbService _rgbService;
|
||||||
|
private readonly IScriptingService _scriptingService;
|
||||||
private readonly List<Exception> _updateExceptions = new();
|
private readonly List<Exception> _updateExceptions = new();
|
||||||
|
|
||||||
|
private int _frames;
|
||||||
private DateTime _lastExceptionLog;
|
private DateTime _lastExceptionLog;
|
||||||
|
private DateTime _lastFrameRateSample;
|
||||||
|
|
||||||
// ReSharper disable UnusedParameter.Local
|
// ReSharper disable UnusedParameter.Local
|
||||||
public CoreService(IKernel kernel,
|
public CoreService(IKernel kernel,
|
||||||
@ -151,6 +151,15 @@ namespace Artemis.Core.Services
|
|||||||
{
|
{
|
||||||
_rgbService.CloseRender();
|
_rgbService.CloseRender();
|
||||||
_frameStopWatch.Stop();
|
_frameStopWatch.Stop();
|
||||||
|
_frames++;
|
||||||
|
|
||||||
|
if ((DateTime.Now - _lastFrameRateSample).TotalSeconds >= 1)
|
||||||
|
{
|
||||||
|
FrameRate = _frames;
|
||||||
|
_frames = 0;
|
||||||
|
_lastFrameRateSample = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
FrameTime = _frameStopWatch.Elapsed;
|
FrameTime = _frameStopWatch.Elapsed;
|
||||||
|
|
||||||
LogUpdateExceptions();
|
LogUpdateExceptions();
|
||||||
@ -181,6 +190,7 @@ namespace Artemis.Core.Services
|
|||||||
Initialized?.Invoke(this, EventArgs.Empty);
|
Initialized?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int FrameRate { get; private set; }
|
||||||
public TimeSpan FrameTime { get; private set; }
|
public TimeSpan FrameTime { get; private set; }
|
||||||
public bool ProfileRenderingDisabled { get; set; }
|
public bool ProfileRenderingDisabled { get; set; }
|
||||||
public List<string> StartupArguments { get; set; }
|
public List<string> StartupArguments { get; set; }
|
||||||
|
|||||||
@ -18,6 +18,11 @@ namespace Artemis.Core.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
TimeSpan FrameTime { get; }
|
TimeSpan FrameTime { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The amount of frames rendered each second
|
||||||
|
/// </summary>
|
||||||
|
public int FrameRate { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets whether profiles are rendered each frame by calling their Render method
|
/// Gets or sets whether profiles are rendered each frame by calling their Render method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -602,7 +602,10 @@ namespace Artemis.Core.Services
|
|||||||
if (!saveState)
|
if (!saveState)
|
||||||
{
|
{
|
||||||
OnPluginFeatureEnableFailed(new PluginFeatureEventArgs(pluginFeature));
|
OnPluginFeatureEnableFailed(new PluginFeatureEventArgs(pluginFeature));
|
||||||
throw new ArtemisCoreException("Cannot enable a feature that requires elevation without saving it's state.");
|
if (isAutoEnable)
|
||||||
|
_logger.Warning("Skipped auto-enabling plugin feature {feature} - {plugin} because it requires elevation but state isn't being saved", pluginFeature, pluginFeature.Plugin);
|
||||||
|
else
|
||||||
|
throw new ArtemisCoreException("Cannot enable a feature that requires elevation without saving it's state.");
|
||||||
}
|
}
|
||||||
|
|
||||||
pluginFeature.Entity.IsEnabled = true;
|
pluginFeature.Entity.IsEnabled = true;
|
||||||
|
|||||||
@ -32,5 +32,15 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
return Enum.GetValues(t).Cast<Enum>().Select(e => (e, e.Humanize())).ToList();
|
return Enum.GetValues(t).Cast<Enum>().Select(e => (e, e.Humanize())).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Humanizes the given enum value using the Humanizer library
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The enum value to humanize</param>
|
||||||
|
/// <returns>A humanized string describing the given value</returns>
|
||||||
|
public static string HumanizeValue(Enum value)
|
||||||
|
{
|
||||||
|
return value.Humanize();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,6 +174,468 @@
|
|||||||
<member name="M:Artemis.UI.Shared.Converters.SKColorToColorConverter.ConvertBack(System.Object,System.Type,System.Object,System.Globalization.CultureInfo)">
|
<member name="M:Artemis.UI.Shared.Converters.SKColorToColorConverter.ConvertBack(System.Object,System.Type,System.Object,System.Globalization.CultureInfo)">
|
||||||
<inheritdoc />
|
<inheritdoc />
|
||||||
</member>
|
</member>
|
||||||
|
<member name="T:Artemis.UI.Shared.Converters.TypeToStringConverter">
|
||||||
|
<summary>
|
||||||
|
Converts <see cref="T:System.Type" /> into <see cref="T:System.String" />.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.Converters.TypeToStringConverter.Convert(System.Object,System.Type,System.Object,System.Globalization.CultureInfo)">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.Converters.TypeToStringConverter.ConvertBack(System.Object,System.Type,System.Object,System.Globalization.CultureInfo)">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="T:Artemis.UI.Shared.DataModelVisualization.DataModelDisplayViewModel`1">
|
||||||
|
<summary>
|
||||||
|
Represents a <see cref="T:Artemis.Core.Modules.DataModel" /> display view model
|
||||||
|
</summary>
|
||||||
|
<typeparam name="T">The type of the data model</typeparam>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.DataModelDisplayViewModel`1.DisplayValue">
|
||||||
|
<summary>
|
||||||
|
Gets or sets value that the view model must display
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.DataModelDisplayViewModel`1.UpdateValue(System.Object)">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.DataModelDisplayViewModel`1.OnDisplayValueUpdated">
|
||||||
|
<summary>
|
||||||
|
Occurs when the display value is updated
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="T:Artemis.UI.Shared.DataModelVisualization.DataModelDisplayViewModel">
|
||||||
|
<summary>
|
||||||
|
For internal use only, implement <see cref="T:Artemis.UI.Shared.DataModelVisualization.DataModelDisplayViewModel`1" /> instead.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.DataModelDisplayViewModel.PropertyDescription">
|
||||||
|
<summary>
|
||||||
|
Gets the property description of this value
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.DataModelDisplayViewModel.InternalGuard">
|
||||||
|
<summary>
|
||||||
|
Prevents this type being implemented directly, implement <see cref="T:Artemis.UI.Shared.DataModelVisualization.DataModelDisplayViewModel`1" /> instead.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.DataModelDisplayViewModel.UpdateValue(System.Object)">
|
||||||
|
<summary>
|
||||||
|
Updates the display value
|
||||||
|
</summary>
|
||||||
|
<param name="model">The value to set</param>
|
||||||
|
</member>
|
||||||
|
<member name="T:Artemis.UI.Shared.DataModelVisualization.DataModelInputViewModel`1">
|
||||||
|
<summary>
|
||||||
|
Represents a <see cref="T:Artemis.Core.Modules.DataModel" /> input view model
|
||||||
|
</summary>
|
||||||
|
<typeparam name="T">The type of the data model</typeparam>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.DataModelInputViewModel`1.#ctor(Artemis.Core.Modules.DataModelPropertyAttribute,`0)">
|
||||||
|
<summary>
|
||||||
|
Creates a new instance of the <see cref="T:Artemis.UI.Shared.DataModelVisualization.DataModelInputViewModel`1" /> class
|
||||||
|
</summary>
|
||||||
|
<param name="targetDescription">The description of the property this input VM is representing</param>
|
||||||
|
<param name="initialValue">The initial value to set the input value to</param>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.DataModelInputViewModel`1.InputValue">
|
||||||
|
<summary>
|
||||||
|
Gets or sets the value shown in the input
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.DataModelInputViewModel`1.TargetDescription">
|
||||||
|
<summary>
|
||||||
|
Gets the description of the property this input VM is representing
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.DataModelInputViewModel`1.Submit">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.DataModelInputViewModel`1.Cancel">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="T:Artemis.UI.Shared.DataModelVisualization.DataModelInputViewModel">
|
||||||
|
<summary>
|
||||||
|
For internal use only, implement <see cref="T:Artemis.UI.Shared.DataModelVisualization.DataModelInputViewModel`1" /> instead.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.DataModelInputViewModel.InternalGuard">
|
||||||
|
<summary>
|
||||||
|
Prevents this type being implemented directly, implement <see cref="T:Artemis.UI.Shared.DataModelVisualization.DataModelInputViewModel`1" /> instead.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.DataModelInputViewModel.CompatibleConversionTypes">
|
||||||
|
<summary>
|
||||||
|
Gets the types this input view model can support through type conversion. This list is defined when registering the
|
||||||
|
view model.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.DataModelInputViewModel.Submit">
|
||||||
|
<summary>
|
||||||
|
Submits the input value and removes this view model.
|
||||||
|
<para>This is called automatically when the user presses enter or clicks outside the view</para>
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.DataModelInputViewModel.Cancel">
|
||||||
|
<summary>
|
||||||
|
Discards changes to the input value and removes this view model.
|
||||||
|
<para>This is called automatically when the user presses escape</para>
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.DataModelInputViewModel.OnSubmit">
|
||||||
|
<summary>
|
||||||
|
Called before the current value is submitted
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.DataModelInputViewModel.OnCancel">
|
||||||
|
<summary>
|
||||||
|
Called before the current value is discarded
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="T:Artemis.UI.Shared.DataModelVisualization.DataModelVisualizationRegistration">
|
||||||
|
<summary>
|
||||||
|
Represents a layer brush registered through
|
||||||
|
<see cref="M:Artemis.UI.Shared.Services.IDataModelUIService.RegisterDataModelInput``1(Artemis.Core.Plugin,System.Collections.Generic.IReadOnlyCollection{System.Type})" /> or
|
||||||
|
<see cref="M:Artemis.UI.Shared.Services.IDataModelUIService.RegisterDataModelDisplay``1(Artemis.Core.Plugin)" />
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.DataModelVisualizationRegistration.RegistrationType">
|
||||||
|
<summary>
|
||||||
|
Gets the type of registration, either a display or an input
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.DataModelVisualizationRegistration.Plugin">
|
||||||
|
<summary>
|
||||||
|
Gets the plugin that registered the visualization
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.DataModelVisualizationRegistration.SupportedType">
|
||||||
|
<summary>
|
||||||
|
Gets the type supported by the visualization
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.DataModelVisualizationRegistration.ViewModelType">
|
||||||
|
<summary>
|
||||||
|
Gets the view model type of the visualization
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.DataModelVisualizationRegistration.CompatibleConversionTypes">
|
||||||
|
<summary>
|
||||||
|
Gets a read only collection of types this visualization can convert to and from
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="T:Artemis.UI.Shared.DataModelVisualization.RegistrationType">
|
||||||
|
<summary>
|
||||||
|
Represents a type of data model visualization registration
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:Artemis.UI.Shared.DataModelVisualization.RegistrationType.Display">
|
||||||
|
<summary>
|
||||||
|
A visualization used for displaying values
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:Artemis.UI.Shared.DataModelVisualization.RegistrationType.Input">
|
||||||
|
<summary>
|
||||||
|
A visualization used for inputting values
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="T:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelEventViewModel">
|
||||||
|
<summary>
|
||||||
|
Represents a view model that visualizes an event data model property
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelEventViewModel.DisplayValueType">
|
||||||
|
<summary>
|
||||||
|
Gets the type of event arguments this event triggers and that must be displayed as children
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelEventViewModel.Update(Artemis.UI.Shared.Services.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelEventViewModel.GetCurrentValue">
|
||||||
|
<summary>
|
||||||
|
Always returns <see langword="null"/> for data model events
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelEventViewModel.ToString">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="T:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertiesViewModel">
|
||||||
|
<summary>
|
||||||
|
Represents a view model that wraps a regular <see cref="T:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertiesViewModel" /> but contained in
|
||||||
|
a <see cref="T:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListViewModel" />
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertiesViewModel.Index">
|
||||||
|
<summary>
|
||||||
|
Gets the index of the element within the list
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertiesViewModel.ListType">
|
||||||
|
<summary>
|
||||||
|
Gets the type of elements contained in the list
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertiesViewModel.DisplayValue">
|
||||||
|
<summary>
|
||||||
|
Gets the value of the property that is being visualized
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertiesViewModel.DisplayViewModel">
|
||||||
|
<summary>
|
||||||
|
Gets the view model that handles displaying the property
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertiesViewModel.DisplayPath">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertiesViewModel.Update(Artemis.UI.Shared.Services.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertiesViewModel.GetCurrentValue">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertiesViewModel.ToString">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="T:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertyViewModel">
|
||||||
|
<summary>
|
||||||
|
Represents a view model that visualizes a single data model property contained in a
|
||||||
|
<see cref="T:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListViewModel" />
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertyViewModel.Index">
|
||||||
|
<summary>
|
||||||
|
Gets the index of the element within the list
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertyViewModel.ListType">
|
||||||
|
<summary>
|
||||||
|
Gets the type of elements contained in the list
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertyViewModel.GetCurrentValue">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertyViewModel.Update(Artemis.UI.Shared.Services.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertyViewModel.ToString">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="T:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListViewModel">
|
||||||
|
<summary>
|
||||||
|
Represents a view model that visualizes a list data model property
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListViewModel.List">
|
||||||
|
<summary>
|
||||||
|
Gets the instance of the list that is being visualized
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListViewModel.ListCount">
|
||||||
|
<summary>
|
||||||
|
Gets amount of elements in the list that is being visualized
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListViewModel.DisplayValueType">
|
||||||
|
<summary>
|
||||||
|
Gets the type of elements this list contains and that must be displayed as children
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListViewModel.CountDisplay">
|
||||||
|
<summary>
|
||||||
|
Gets a human readable display count
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListViewModel.ListChildren">
|
||||||
|
<summary>
|
||||||
|
Gets a list of child view models that visualize the elements in the list
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListViewModel.Update(Artemis.UI.Shared.Services.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListViewModel.ToString">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="T:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertiesViewModel">
|
||||||
|
<summary>
|
||||||
|
Represents a view model that visualizes a class (POCO) data model property containing child properties
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertiesViewModel.DisplayValueType">
|
||||||
|
<summary>
|
||||||
|
Gets the type of the property that is being visualized
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertiesViewModel.DisplayValue">
|
||||||
|
<summary>
|
||||||
|
Gets the value of the property that is being visualized
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertiesViewModel.Update(Artemis.UI.Shared.Services.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertiesViewModel.GetCurrentValue">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertiesViewModel.ToString">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="T:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertyViewModel">
|
||||||
|
<summary>
|
||||||
|
Represents a view model that visualizes a single data model property contained in a
|
||||||
|
<see cref="T:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertiesViewModel" />
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertyViewModel.DisplayValue">
|
||||||
|
<summary>
|
||||||
|
Gets the value of the property that is being visualized
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertyViewModel.DisplayValueType">
|
||||||
|
<summary>
|
||||||
|
Gets the type of the property that is being visualized
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertyViewModel.DisplayViewModel">
|
||||||
|
<summary>
|
||||||
|
Gets the view model used to display the display value
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertyViewModel.Update(Artemis.UI.Shared.Services.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertyViewModel.ToString">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="T:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration">
|
||||||
|
<summary>
|
||||||
|
Represents a configuration to use while updating a <see cref="T:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel" />
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration.#ctor(System.Boolean)">
|
||||||
|
<summary>
|
||||||
|
Creates a new instance of the <see cref="T:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration" /> class
|
||||||
|
</summary>
|
||||||
|
<param name="createEventChildren">A boolean indicating whether or not event children should be created</param>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration.CreateEventChildren">
|
||||||
|
<summary>
|
||||||
|
Gets a boolean indicating whether or not event children should be created
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="T:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel">
|
||||||
|
<summary>
|
||||||
|
Represents a base class for a view model that visualizes a part of the data model
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.IsRootViewModel">
|
||||||
|
<summary>
|
||||||
|
Gets a boolean indicating whether this view model is at the root of the data model
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.DataModelPath">
|
||||||
|
<summary>
|
||||||
|
Gets the data model path to the property this view model is visualizing
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.Path">
|
||||||
|
<summary>
|
||||||
|
Gets a string representation of the path backing this model
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.Depth">
|
||||||
|
<summary>
|
||||||
|
Gets the property depth of the view model
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.DataModel">
|
||||||
|
<summary>
|
||||||
|
Gets the data model backing this view model
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.PropertyDescription">
|
||||||
|
<summary>
|
||||||
|
Gets the property description of the property this view model is visualizing
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.Parent">
|
||||||
|
<summary>
|
||||||
|
Gets the parent of this view model
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.Children">
|
||||||
|
<summary>
|
||||||
|
Gets or sets an observable collection containing the children of this view model
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.IsMatchingFilteredTypes">
|
||||||
|
<summary>
|
||||||
|
Gets a boolean indicating whether the property being visualized matches the types last provided to
|
||||||
|
<see cref="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.ApplyTypeFilter(System.Boolean,System.Type[])" />
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.IsVisualizationExpanded">
|
||||||
|
<summary>
|
||||||
|
Gets or sets a boolean indicating whether the visualization is expanded, exposing the <see cref="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.Children" />
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.DisplayPath">
|
||||||
|
<summary>
|
||||||
|
Gets a user-friendly representation of the <see cref="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.DataModelPath" />
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.Update(Artemis.UI.Shared.Services.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)">
|
||||||
|
<summary>
|
||||||
|
Updates the datamodel and if in an parent, any children
|
||||||
|
</summary>
|
||||||
|
<param name="dataModelUIService">The data model UI service used during update</param>
|
||||||
|
<param name="configuration">The configuration to apply while updating</param>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.GetCurrentValue">
|
||||||
|
<summary>
|
||||||
|
Gets the current value of the property being visualized
|
||||||
|
</summary>
|
||||||
|
<returns>The current value of the property being visualized</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.ApplyTypeFilter(System.Boolean,System.Type[])">
|
||||||
|
<summary>
|
||||||
|
Determines whether the provided types match the type of the property being visualized and sets the result in
|
||||||
|
<see cref="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.IsMatchingFilteredTypes" />
|
||||||
|
</summary>
|
||||||
|
<param name="looseMatch">Whether the type may be a loose match, meaning it can be cast or converted</param>
|
||||||
|
<param name="filteredTypes">The types to filter</param>
|
||||||
|
</member>
|
||||||
|
<member name="E:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.UpdateRequested">
|
||||||
|
<summary>
|
||||||
|
Occurs when an update to the property this view model visualizes is requested
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.OnUpdateRequested">
|
||||||
|
<summary>
|
||||||
|
Invokes the <see cref="E:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.UpdateRequested" /> event
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.Dispose(System.Boolean)">
|
||||||
|
<summary>
|
||||||
|
Releases the unmanaged resources used by the object and optionally releases the managed resources.
|
||||||
|
</summary>
|
||||||
|
<param name="disposing">
|
||||||
|
<see langword="true" /> to release both managed and unmanaged resources;
|
||||||
|
<see langword="false" /> to release only unmanaged resources.
|
||||||
|
</param>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.Dispose">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="T:Artemis.UI.Shared.DefaultTypes.DataModel.Display.DefaultDataModelDisplayViewModel">
|
||||||
|
<summary>
|
||||||
|
Represents the default data model display view model that is used when no display viewmodel specific for the type
|
||||||
|
is registered
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
<member name="T:Artemis.UI.Shared.Events.DataModelInputDynamicEventArgs">
|
<member name="T:Artemis.UI.Shared.Events.DataModelInputDynamicEventArgs">
|
||||||
<summary>
|
<summary>
|
||||||
Provides data about selection events raised by <see cref="!:DataModelDynamicViewModel" />
|
Provides data about selection events raised by <see cref="!:DataModelDynamicViewModel" />
|
||||||
@ -239,7 +701,7 @@
|
|||||||
If applicable, the previous active profile element before the event was raised
|
If applicable, the previous active profile element before the event was raised
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="T:Artemis.UI.Shared.Exceptions.ArtemisSharedUIException">
|
<member name="T:Artemis.UI.Shared.ArtemisSharedUIException">
|
||||||
<summary>
|
<summary>
|
||||||
Represents errors that occur within the Artemis Shared UI library
|
Represents errors that occur within the Artemis Shared UI library
|
||||||
</summary>
|
</summary>
|
||||||
@ -453,6 +915,104 @@
|
|||||||
</summary>
|
</summary>
|
||||||
<returns>The builder that can be used to configure the dialog</returns>
|
<returns>The builder that can be used to configure the dialog</returns>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="T:Artemis.UI.Shared.Services.IDataModelUIService">
|
||||||
|
<summary>
|
||||||
|
A service for UI related data model tasks
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.Services.IDataModelUIService.RegisteredDataModelEditors">
|
||||||
|
<summary>
|
||||||
|
Gets a read-only list of all registered data model editors
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:Artemis.UI.Shared.Services.IDataModelUIService.RegisteredDataModelDisplays">
|
||||||
|
<summary>
|
||||||
|
Gets a read-only list of all registered data model displays
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.Services.IDataModelUIService.GetMainDataModelVisualization">
|
||||||
|
<summary>
|
||||||
|
Creates a data model visualization view model for the main data model
|
||||||
|
</summary>
|
||||||
|
<returns>
|
||||||
|
A data model visualization view model containing all data model expansions and modules that expand the main
|
||||||
|
data model
|
||||||
|
</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.Services.IDataModelUIService.GetPluginDataModelVisualization(System.Collections.Generic.List{Artemis.Core.Modules.Module},System.Boolean)">
|
||||||
|
<summary>
|
||||||
|
Creates a data model visualization view model for the data model of the provided plugin feature
|
||||||
|
</summary>
|
||||||
|
<param name="modules">The modules to create the data model visualization view model for</param>
|
||||||
|
<param name="includeMainDataModel">
|
||||||
|
Whether or not also to include the main data model (and therefore any modules marked
|
||||||
|
as <see cref="P:Artemis.Core.Modules.Module.IsAlwaysAvailable" />)
|
||||||
|
</param>
|
||||||
|
<returns>A data model visualization view model containing the data model of the provided feature</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.Services.IDataModelUIService.UpdateModules(Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertiesViewModel)">
|
||||||
|
<summary>
|
||||||
|
Updates the children of the provided main data model visualization, removing disabled children and adding newly
|
||||||
|
enabled children
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.Services.IDataModelUIService.RegisterDataModelInput``1(Artemis.Core.Plugin,System.Collections.Generic.IReadOnlyCollection{System.Type})">
|
||||||
|
<summary>
|
||||||
|
Registers a new data model editor
|
||||||
|
</summary>
|
||||||
|
<typeparam name="T">The type of the editor</typeparam>
|
||||||
|
<param name="plugin">The plugin this editor belongs to</param>
|
||||||
|
<param name="compatibleConversionTypes">A collection of extra types this editor supports</param>
|
||||||
|
<returns>A registration that can be used to remove the editor</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.Services.IDataModelUIService.RegisterDataModelDisplay``1(Artemis.Core.Plugin)">
|
||||||
|
<summary>
|
||||||
|
Registers a new data model display
|
||||||
|
</summary>
|
||||||
|
<typeparam name="T">The type of the display</typeparam>
|
||||||
|
<param name="plugin">The plugin this display belongs to</param>
|
||||||
|
<returns>A registration that can be used to remove the display</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.Services.IDataModelUIService.RemoveDataModelInput(Artemis.UI.Shared.DataModelVisualization.DataModelVisualizationRegistration)">
|
||||||
|
<summary>
|
||||||
|
Removes a data model editor
|
||||||
|
</summary>
|
||||||
|
<param name="registration">
|
||||||
|
The registration of the editor as returned by <see cref="M:Artemis.UI.Shared.Services.IDataModelUIService.RegisterDataModelInput``1(Artemis.Core.Plugin,System.Collections.Generic.IReadOnlyCollection{System.Type})" />
|
||||||
|
</param>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.Services.IDataModelUIService.RemoveDataModelDisplay(Artemis.UI.Shared.DataModelVisualization.DataModelVisualizationRegistration)">
|
||||||
|
<summary>
|
||||||
|
Removes a data model display
|
||||||
|
</summary>
|
||||||
|
<param name="registration">
|
||||||
|
The registration of the display as returned by <see cref="M:Artemis.UI.Shared.Services.IDataModelUIService.RegisterDataModelDisplay``1(Artemis.Core.Plugin)" />
|
||||||
|
</param>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.Services.IDataModelUIService.GetDataModelDisplayViewModel(System.Type,Artemis.Core.Modules.DataModelPropertyAttribute,System.Boolean)">
|
||||||
|
<summary>
|
||||||
|
Creates the most appropriate display view model for the provided <paramref name="propertyType" /> that can display
|
||||||
|
a value
|
||||||
|
</summary>
|
||||||
|
<param name="propertyType">The type of data model property to find a display view model for</param>
|
||||||
|
<param name="description">The description of the data model property</param>
|
||||||
|
<param name="fallBackToDefault">
|
||||||
|
If <see langword="true"></see>, a simple .ToString() display view model will be
|
||||||
|
returned if nothing else is found
|
||||||
|
</param>
|
||||||
|
<returns>The most appropriate display view model for the provided <paramref name="propertyType"></paramref></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.Services.IDataModelUIService.GetDataModelInputViewModel(System.Type,Artemis.Core.Modules.DataModelPropertyAttribute,System.Object,System.Action{System.Object,System.Boolean})">
|
||||||
|
<summary>
|
||||||
|
Creates the most appropriate input view model for the provided <paramref name="propertyType" /> that allows
|
||||||
|
inputting a value
|
||||||
|
</summary>
|
||||||
|
<param name="propertyType">The type of data model property to find a display view model for</param>
|
||||||
|
<param name="description">The description of the data model property</param>
|
||||||
|
<param name="initialValue">The initial value to show in the input</param>
|
||||||
|
<param name="updateCallback">A function to call whenever the input was updated (submitted or not)</param>
|
||||||
|
<returns>The most appropriate input view model for the provided <paramref name="propertyType" /></returns>
|
||||||
|
</member>
|
||||||
<member name="T:Artemis.UI.Shared.ViewModelBase">
|
<member name="T:Artemis.UI.Shared.ViewModelBase">
|
||||||
<summary>
|
<summary>
|
||||||
Represents the base class for Artemis view models
|
Represents the base class for Artemis view models
|
||||||
|
|||||||
@ -10,6 +10,11 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
<DocumentationFile>C:\Repos\Artemis\src\Artemis.UI.Avalonia.Shared\Artemis.UI.Avalonia.Shared.xml</DocumentationFile>
|
<DocumentationFile>C:\Repos\Artemis\src\Artemis.UI.Avalonia.Shared\Artemis.UI.Avalonia.Shared.xml</DocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="Artemis.UI.Avalonia.Shared.csproj.DotSettings" />
|
||||||
|
<None Remove="Artemis.UI.Shared.csproj.DotSettings" />
|
||||||
|
<None Remove="DefaultTypes\DataModel\Display\DefaultDataModelDisplayView.xaml" />
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Avalonia" Version="0.10.10" />
|
<PackageReference Include="Avalonia" Version="0.10.10" />
|
||||||
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.10" />
|
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.10" />
|
||||||
@ -20,6 +25,12 @@
|
|||||||
<PackageReference Include="FluentAvaloniaUI" Version="1.1.5" />
|
<PackageReference Include="FluentAvaloniaUI" Version="1.1.5" />
|
||||||
<PackageReference Include="Material.Icons.Avalonia" Version="1.0.2" />
|
<PackageReference Include="Material.Icons.Avalonia" Version="1.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Page Include="DefaultTypes\DataModel\Display\DefaultDataModelDisplayView.xaml">
|
||||||
|
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\Artemis.Core\Artemis.Core.csproj" />
|
<ProjectReference Include="..\..\Artemis.Core\Artemis.Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=exceptions/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=plugins/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=plugins/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cwindowservice/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cwindowservice/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Avalonia.Data.Converters;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared.Converters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts <see cref="T:System.Type" /> into <see cref="T:System.String" />.
|
||||||
|
/// </summary>
|
||||||
|
public class TypeToStringConverter : IValueConverter
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
bool humanizeProvided = bool.TryParse(parameter?.ToString(), out bool humanize);
|
||||||
|
if (value is Type type)
|
||||||
|
return type.GetDisplayName(humanizeProvided && humanize);
|
||||||
|
|
||||||
|
return value?.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,73 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Artemis.Core.Modules;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared.DataModelVisualization
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a <see cref="DataModel" /> display view model
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the data model</typeparam>
|
||||||
|
public abstract class DataModelDisplayViewModel<T> : DataModelDisplayViewModel
|
||||||
|
{
|
||||||
|
[AllowNull] private T _displayValue = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets value that the view model must display
|
||||||
|
/// </summary>
|
||||||
|
[AllowNull]
|
||||||
|
public T DisplayValue
|
||||||
|
{
|
||||||
|
get => _displayValue;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (Equals(value, _displayValue)) return;
|
||||||
|
this.RaiseAndSetIfChanged(ref _displayValue, value);
|
||||||
|
OnDisplayValueUpdated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override object InternalGuard => new();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void UpdateValue(object? model)
|
||||||
|
{
|
||||||
|
DisplayValue = model is T value ? value : default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when the display value is updated
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnDisplayValueUpdated()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For internal use only, implement <see cref="DataModelDisplayViewModel{T}" /> instead.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class DataModelDisplayViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
private DataModelPropertyAttribute? _propertyDescription;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the property description of this value
|
||||||
|
/// </summary>
|
||||||
|
public DataModelPropertyAttribute? PropertyDescription
|
||||||
|
{
|
||||||
|
get => _propertyDescription;
|
||||||
|
internal set => this.RaiseAndSetIfChanged(ref _propertyDescription, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prevents this type being implemented directly, implement <see cref="DataModelDisplayViewModel{T}" /> instead.
|
||||||
|
/// </summary>
|
||||||
|
internal abstract object InternalGuard { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the display value
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The value to set</param>
|
||||||
|
public abstract void UpdateValue(object? model);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,114 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Artemis.Core.Modules;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared.DataModelVisualization
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a <see cref="DataModel" /> input view model
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the data model</typeparam>
|
||||||
|
public abstract class DataModelInputViewModel<T> : DataModelInputViewModel
|
||||||
|
{
|
||||||
|
private bool _closed;
|
||||||
|
[AllowNull] private T _inputValue = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="DataModelInputViewModel{T}" /> class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetDescription">The description of the property this input VM is representing</param>
|
||||||
|
/// <param name="initialValue">The initial value to set the input value to</param>
|
||||||
|
protected DataModelInputViewModel(DataModelPropertyAttribute targetDescription, T initialValue)
|
||||||
|
{
|
||||||
|
TargetDescription = targetDescription;
|
||||||
|
InputValue = initialValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the value shown in the input
|
||||||
|
/// </summary>
|
||||||
|
[AllowNull]
|
||||||
|
public T InputValue
|
||||||
|
{
|
||||||
|
get => _inputValue;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _inputValue, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the description of the property this input VM is representing
|
||||||
|
/// </summary>
|
||||||
|
public DataModelPropertyAttribute TargetDescription { get; }
|
||||||
|
|
||||||
|
internal override object InternalGuard { get; } = new();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public sealed override void Submit()
|
||||||
|
{
|
||||||
|
if (_closed)
|
||||||
|
return;
|
||||||
|
_closed = true;
|
||||||
|
|
||||||
|
OnSubmit();
|
||||||
|
UpdateCallback(InputValue, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public sealed override void Cancel()
|
||||||
|
{
|
||||||
|
if (_closed)
|
||||||
|
return;
|
||||||
|
_closed = true;
|
||||||
|
|
||||||
|
OnCancel();
|
||||||
|
UpdateCallback(InputValue, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For internal use only, implement <see cref="DataModelInputViewModel{T}" /> instead.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class DataModelInputViewModel : ReactiveObject
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Prevents this type being implemented directly, implement <see cref="DataModelInputViewModel{T}" /> instead.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once UnusedMember.Global
|
||||||
|
internal abstract object InternalGuard { get; }
|
||||||
|
|
||||||
|
internal Action<object?, bool> UpdateCallback { get; set; } = null!; // Set right after construction
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the types this input view model can support through type conversion. This list is defined when registering the
|
||||||
|
/// view model.
|
||||||
|
/// </summary>
|
||||||
|
internal IReadOnlyCollection<Type>? CompatibleConversionTypes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Submits the input value and removes this view model.
|
||||||
|
/// <para>This is called automatically when the user presses enter or clicks outside the view</para>
|
||||||
|
/// </summary>
|
||||||
|
public abstract void Submit();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Discards changes to the input value and removes this view model.
|
||||||
|
/// <para>This is called automatically when the user presses escape</para>
|
||||||
|
/// </summary>
|
||||||
|
public abstract void Cancel();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called before the current value is submitted
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnSubmit()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called before the current value is discarded
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnCancel()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,88 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.UI.Shared.Services;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared.DataModelVisualization
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a layer brush registered through
|
||||||
|
/// <see cref="IDataModelUIService.RegisterDataModelInput{T}" /> or
|
||||||
|
/// <see cref="IDataModelUIService.RegisterDataModelDisplay{T}" />
|
||||||
|
/// </summary>
|
||||||
|
public class DataModelVisualizationRegistration
|
||||||
|
{
|
||||||
|
private readonly IDataModelUIService _dataModelUIService;
|
||||||
|
|
||||||
|
internal DataModelVisualizationRegistration(IDataModelUIService dataModelUIService,
|
||||||
|
RegistrationType registrationType,
|
||||||
|
Plugin plugin,
|
||||||
|
Type supportedType,
|
||||||
|
Type viewModelType)
|
||||||
|
{
|
||||||
|
_dataModelUIService = dataModelUIService;
|
||||||
|
RegistrationType = registrationType;
|
||||||
|
Plugin = plugin;
|
||||||
|
SupportedType = supportedType;
|
||||||
|
ViewModelType = viewModelType;
|
||||||
|
|
||||||
|
if (Plugin != Constants.CorePlugin)
|
||||||
|
Plugin.Disabled += InstanceOnDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type of registration, either a display or an input
|
||||||
|
/// </summary>
|
||||||
|
public RegistrationType RegistrationType { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the plugin that registered the visualization
|
||||||
|
/// </summary>
|
||||||
|
public Plugin Plugin { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type supported by the visualization
|
||||||
|
/// </summary>
|
||||||
|
public Type SupportedType { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the view model type of the visualization
|
||||||
|
/// </summary>
|
||||||
|
public Type ViewModelType { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a read only collection of types this visualization can convert to and from
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyCollection<Type>? CompatibleConversionTypes { get; internal set; }
|
||||||
|
|
||||||
|
internal void Unsubscribe()
|
||||||
|
{
|
||||||
|
if (Plugin != Constants.CorePlugin)
|
||||||
|
Plugin.Disabled -= InstanceOnDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InstanceOnDisabled(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (RegistrationType == RegistrationType.Input)
|
||||||
|
_dataModelUIService.RemoveDataModelInput(this);
|
||||||
|
else if (RegistrationType == RegistrationType.Display)
|
||||||
|
_dataModelUIService.RemoveDataModelDisplay(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a type of data model visualization registration
|
||||||
|
/// </summary>
|
||||||
|
public enum RegistrationType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A visualization used for displaying values
|
||||||
|
/// </summary>
|
||||||
|
Display,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A visualization used for inputting values
|
||||||
|
/// </summary>
|
||||||
|
Input
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Modules;
|
||||||
|
using Artemis.UI.Shared.Services;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a view model that visualizes an event data model property
|
||||||
|
/// </summary>
|
||||||
|
public class DataModelEventViewModel : DataModelVisualizationViewModel
|
||||||
|
{
|
||||||
|
private Type? _displayValueType;
|
||||||
|
|
||||||
|
internal DataModelEventViewModel(DataModel dataModel, DataModelVisualizationViewModel parent, DataModelPath dataModelPath) : base(dataModel, parent, dataModelPath)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type of event arguments this event triggers and that must be displayed as children
|
||||||
|
/// </summary>
|
||||||
|
public Type? DisplayValueType
|
||||||
|
{
|
||||||
|
get => _displayValueType;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _displayValueType, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration? configuration)
|
||||||
|
{
|
||||||
|
DisplayValueType = DataModelPath?.GetPropertyType();
|
||||||
|
|
||||||
|
if (configuration != null)
|
||||||
|
{
|
||||||
|
if (configuration.CreateEventChildren)
|
||||||
|
PopulateProperties(dataModelUIService, configuration);
|
||||||
|
else if (Children.Any())
|
||||||
|
Children.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only update children if the parent is expanded
|
||||||
|
if (Parent != null && !Parent.IsRootViewModel && !Parent.IsVisualizationExpanded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (DataModelVisualizationViewModel dataModelVisualizationViewModel in Children)
|
||||||
|
dataModelVisualizationViewModel.Update(dataModelUIService, configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Always returns <see langword="null"/> for data model events
|
||||||
|
/// </summary>
|
||||||
|
public override object? GetCurrentValue()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string? ToString()
|
||||||
|
{
|
||||||
|
return DisplayPath ?? Path;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override int GetChildDepth()
|
||||||
|
{
|
||||||
|
return PropertyDescription != null && !PropertyDescription.ResetsDepth ? Depth + 1 : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using Artemis.UI.Shared.Services;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a view model that wraps a regular <see cref="DataModelPropertiesViewModel" /> but contained in
|
||||||
|
/// a <see cref="DataModelListViewModel" />
|
||||||
|
/// </summary>
|
||||||
|
public class DataModelListPropertiesViewModel : DataModelPropertiesViewModel
|
||||||
|
{
|
||||||
|
private object? _displayValue;
|
||||||
|
private int _index;
|
||||||
|
private Type? _listType;
|
||||||
|
|
||||||
|
internal DataModelListPropertiesViewModel(Type listType, string? name) : base(null, null, null)
|
||||||
|
{
|
||||||
|
ListType = listType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the index of the element within the list
|
||||||
|
/// </summary>
|
||||||
|
public int Index
|
||||||
|
{
|
||||||
|
get => _index;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type of elements contained in the list
|
||||||
|
/// </summary>
|
||||||
|
public Type? ListType
|
||||||
|
{
|
||||||
|
get => _listType;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _listType, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value of the property that is being visualized
|
||||||
|
/// </summary>
|
||||||
|
public new object? DisplayValue
|
||||||
|
{
|
||||||
|
get => _displayValue;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _displayValue, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the view model that handles displaying the property
|
||||||
|
/// </summary>
|
||||||
|
public DataModelVisualizationViewModel? DisplayViewModel => Children.FirstOrDefault();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string? DisplayPath => null;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration? configuration)
|
||||||
|
{
|
||||||
|
PopulateProperties(dataModelUIService, configuration);
|
||||||
|
if (DisplayViewModel == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (IsVisualizationExpanded && !DisplayViewModel.IsVisualizationExpanded)
|
||||||
|
DisplayViewModel.IsVisualizationExpanded = IsVisualizationExpanded;
|
||||||
|
DisplayViewModel.Update(dataModelUIService, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override object? GetCurrentValue()
|
||||||
|
{
|
||||||
|
return DisplayValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"[List item {Index}] {DisplayPath ?? Path}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
using System;
|
||||||
|
using Artemis.UI.Shared.Services;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a view model that visualizes a single data model property contained in a
|
||||||
|
/// <see cref="DataModelListViewModel" />
|
||||||
|
/// </summary>
|
||||||
|
public class DataModelListPropertyViewModel : DataModelPropertyViewModel
|
||||||
|
{
|
||||||
|
private int _index;
|
||||||
|
private Type? _listType;
|
||||||
|
|
||||||
|
internal DataModelListPropertyViewModel(Type listType, DataModelDisplayViewModel displayViewModel, string? name) : base(null, null, null)
|
||||||
|
{
|
||||||
|
ListType = listType;
|
||||||
|
DisplayViewModel = displayViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DataModelListPropertyViewModel(Type listType, string? name) : base(null, null, null)
|
||||||
|
{
|
||||||
|
ListType = listType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the index of the element within the list
|
||||||
|
/// </summary>
|
||||||
|
public int Index
|
||||||
|
{
|
||||||
|
get => _index;
|
||||||
|
internal set => this.RaiseAndSetIfChanged(ref _index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type of elements contained in the list
|
||||||
|
/// </summary>
|
||||||
|
public Type? ListType
|
||||||
|
{
|
||||||
|
get => _listType;
|
||||||
|
private set => this.RaiseAndSetIfChanged(ref _listType, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override object? GetCurrentValue()
|
||||||
|
{
|
||||||
|
return DisplayValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration? configuration)
|
||||||
|
{
|
||||||
|
// Display value gets updated by parent, don't do anything if it is null
|
||||||
|
if (DisplayValue == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (DisplayViewModel == null)
|
||||||
|
DisplayViewModel = dataModelUIService.GetDataModelDisplayViewModel(DisplayValue.GetType(), PropertyDescription, true);
|
||||||
|
|
||||||
|
ListType = DisplayValue.GetType();
|
||||||
|
DisplayViewModel?.UpdateValue(DisplayValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"[List item {Index}] {DisplayPath ?? Path} - {DisplayValue}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,149 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Modules;
|
||||||
|
using Artemis.UI.Shared.Services;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a view model that visualizes a list data model property
|
||||||
|
/// </summary>
|
||||||
|
public class DataModelListViewModel : DataModelVisualizationViewModel
|
||||||
|
{
|
||||||
|
private string _countDisplay;
|
||||||
|
private Type? _displayValueType;
|
||||||
|
private IEnumerable? _list;
|
||||||
|
private ObservableCollection<DataModelVisualizationViewModel> _listChildren;
|
||||||
|
private int _listCount;
|
||||||
|
|
||||||
|
internal DataModelListViewModel(DataModel dataModel, DataModelVisualizationViewModel parent, DataModelPath dataModelPath)
|
||||||
|
: base(dataModel, parent, dataModelPath)
|
||||||
|
{
|
||||||
|
_countDisplay = "0 items";
|
||||||
|
_listChildren = new ObservableCollection<DataModelVisualizationViewModel>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the instance of the list that is being visualized
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable? List
|
||||||
|
{
|
||||||
|
get => _list;
|
||||||
|
private set => this.RaiseAndSetIfChanged(ref _list, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets amount of elements in the list that is being visualized
|
||||||
|
/// </summary>
|
||||||
|
public int ListCount
|
||||||
|
{
|
||||||
|
get => _listCount;
|
||||||
|
private set => this.RaiseAndSetIfChanged(ref _listCount, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type of elements this list contains and that must be displayed as children
|
||||||
|
/// </summary>
|
||||||
|
public Type? DisplayValueType
|
||||||
|
{
|
||||||
|
get => _displayValueType;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _displayValueType, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a human readable display count
|
||||||
|
/// </summary>
|
||||||
|
public string CountDisplay
|
||||||
|
{
|
||||||
|
get => _countDisplay;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _countDisplay, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of child view models that visualize the elements in the list
|
||||||
|
/// </summary>
|
||||||
|
public ObservableCollection<DataModelVisualizationViewModel> ListChildren
|
||||||
|
{
|
||||||
|
get => _listChildren;
|
||||||
|
private set => this.RaiseAndSetIfChanged(ref _listChildren, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration? configuration)
|
||||||
|
{
|
||||||
|
if (Parent != null && !Parent.IsVisualizationExpanded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
List = GetCurrentValue() as IEnumerable;
|
||||||
|
DisplayValueType = List?.GetType();
|
||||||
|
if (List == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
foreach (object item in List)
|
||||||
|
{
|
||||||
|
if (item == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
DataModelVisualizationViewModel? child;
|
||||||
|
if (ListChildren.Count <= index)
|
||||||
|
{
|
||||||
|
child = CreateListChild(dataModelUIService, item.GetType(), DataModelPath?.GetPropertyDescription()?.ListItemName);
|
||||||
|
if (child == null)
|
||||||
|
continue;
|
||||||
|
ListChildren.Add(child);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
child = ListChildren[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child is DataModelListPropertiesViewModel dataModelListClassViewModel)
|
||||||
|
{
|
||||||
|
dataModelListClassViewModel.DisplayValue = item;
|
||||||
|
dataModelListClassViewModel.Index = index;
|
||||||
|
}
|
||||||
|
else if (child is DataModelListPropertyViewModel dataModelListPropertyViewModel)
|
||||||
|
{
|
||||||
|
dataModelListPropertyViewModel.DisplayValue = item;
|
||||||
|
dataModelListPropertyViewModel.Index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
child.Update(dataModelUIService, configuration);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListCount = index;
|
||||||
|
|
||||||
|
while (ListChildren.Count > ListCount)
|
||||||
|
ListChildren.RemoveAt(ListChildren.Count - 1);
|
||||||
|
|
||||||
|
CountDisplay = $"{ListChildren.Count} {(ListChildren.Count == 1 ? "item" : "items")}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"[List] {DisplayPath ?? Path} - {ListCount} item(s)";
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataModelVisualizationViewModel? CreateListChild(IDataModelUIService dataModelUIService, Type listType, string? name)
|
||||||
|
{
|
||||||
|
// If a display VM was found, prefer to use that in any case
|
||||||
|
DataModelDisplayViewModel? typeViewModel = dataModelUIService.GetDataModelDisplayViewModel(listType, PropertyDescription);
|
||||||
|
if (typeViewModel != null)
|
||||||
|
return new DataModelListPropertyViewModel(listType, typeViewModel, name);
|
||||||
|
// For primitives, create a property view model, it may be null that is fine
|
||||||
|
if (listType.IsPrimitive || listType.IsEnum || listType == typeof(string))
|
||||||
|
return new DataModelListPropertyViewModel(listType, name);
|
||||||
|
// For other value types create a child view model
|
||||||
|
if (listType.IsClass || listType.IsStruct())
|
||||||
|
return new DataModelListPropertiesViewModel(listType, name);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
using System;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Modules;
|
||||||
|
using Artemis.UI.Shared.Services;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a view model that visualizes a class (POCO) data model property containing child properties
|
||||||
|
/// </summary>
|
||||||
|
public class DataModelPropertiesViewModel : DataModelVisualizationViewModel
|
||||||
|
{
|
||||||
|
private object? _displayValue;
|
||||||
|
private Type? _displayValueType;
|
||||||
|
|
||||||
|
internal DataModelPropertiesViewModel(DataModel? dataModel, DataModelVisualizationViewModel? parent, DataModelPath? dataModelPath)
|
||||||
|
: base(dataModel, parent, dataModelPath)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type of the property that is being visualized
|
||||||
|
/// </summary>
|
||||||
|
public Type? DisplayValueType
|
||||||
|
{
|
||||||
|
get => _displayValueType;
|
||||||
|
private set => this.RaiseAndSetIfChanged(ref _displayValueType, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value of the property that is being visualized
|
||||||
|
/// </summary>
|
||||||
|
public object? DisplayValue
|
||||||
|
{
|
||||||
|
get => _displayValue;
|
||||||
|
private set => this.RaiseAndSetIfChanged(ref _displayValue, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration? configuration)
|
||||||
|
{
|
||||||
|
DisplayValueType = DataModelPath?.GetPropertyType();
|
||||||
|
|
||||||
|
// Only set a display value if ToString returns useful information and not just the type name
|
||||||
|
object? currentValue = GetCurrentValue();
|
||||||
|
if (currentValue != null && currentValue.ToString() != currentValue.GetType().ToString())
|
||||||
|
DisplayValue = currentValue.ToString();
|
||||||
|
else
|
||||||
|
DisplayValue = null;
|
||||||
|
|
||||||
|
// Always populate properties
|
||||||
|
PopulateProperties(dataModelUIService, configuration);
|
||||||
|
|
||||||
|
// Only update children if the parent is expanded
|
||||||
|
if (Parent != null && !Parent.IsRootViewModel && !Parent.IsVisualizationExpanded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (DataModelVisualizationViewModel dataModelVisualizationViewModel in Children)
|
||||||
|
dataModelVisualizationViewModel.Update(dataModelUIService, configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override object? GetCurrentValue()
|
||||||
|
{
|
||||||
|
if (Parent == null || Parent.IsRootViewModel || IsRootViewModel)
|
||||||
|
return DataModel;
|
||||||
|
return base.GetCurrentValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string? ToString()
|
||||||
|
{
|
||||||
|
return DisplayPath ?? Path;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override int GetChildDepth()
|
||||||
|
{
|
||||||
|
return PropertyDescription != null && !PropertyDescription.ResetsDepth ? Depth + 1 : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
using System;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Modules;
|
||||||
|
using Artemis.UI.Shared.Services;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a view model that visualizes a single data model property contained in a
|
||||||
|
/// <see cref="DataModelPropertiesViewModel" />
|
||||||
|
/// </summary>
|
||||||
|
public class DataModelPropertyViewModel : DataModelVisualizationViewModel
|
||||||
|
{
|
||||||
|
private object? _displayValue;
|
||||||
|
private Type? _displayValueType;
|
||||||
|
private DataModelDisplayViewModel? _displayViewModel;
|
||||||
|
|
||||||
|
internal DataModelPropertyViewModel(DataModel? dataModel, DataModelVisualizationViewModel? parent, DataModelPath? dataModelPath)
|
||||||
|
: base(dataModel, parent, dataModelPath)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value of the property that is being visualized
|
||||||
|
/// </summary>
|
||||||
|
public object? DisplayValue
|
||||||
|
{
|
||||||
|
get => _displayValue;
|
||||||
|
internal set => this.RaiseAndSetIfChanged(ref _displayValue, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type of the property that is being visualized
|
||||||
|
/// </summary>
|
||||||
|
public Type? DisplayValueType
|
||||||
|
{
|
||||||
|
get => _displayValueType;
|
||||||
|
protected set => this.RaiseAndSetIfChanged(ref _displayValueType, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the view model used to display the display value
|
||||||
|
/// </summary>
|
||||||
|
public DataModelDisplayViewModel? DisplayViewModel
|
||||||
|
{
|
||||||
|
get => _displayViewModel;
|
||||||
|
internal set => this.RaiseAndSetIfChanged(ref _displayViewModel, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration? configuration)
|
||||||
|
{
|
||||||
|
if (Parent != null && !Parent.IsVisualizationExpanded && !Parent.IsRootViewModel)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (DisplayViewModel == null)
|
||||||
|
{
|
||||||
|
Type? propertyType = DataModelPath?.GetPropertyType();
|
||||||
|
if (propertyType != null)
|
||||||
|
{
|
||||||
|
DisplayViewModel = dataModelUIService.GetDataModelDisplayViewModel(propertyType, PropertyDescription, true);
|
||||||
|
if (DisplayViewModel != null)
|
||||||
|
DisplayViewModel.PropertyDescription = DataModelPath?.GetPropertyDescription();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayValue = GetCurrentValue();
|
||||||
|
DisplayValueType = DisplayValue != null ? DisplayValue.GetType() : DataModelPath?.GetPropertyType();
|
||||||
|
|
||||||
|
DisplayViewModel?.UpdateValue(DisplayValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
if (DisplayValueType != null)
|
||||||
|
return $"[{DisplayValueType.Name}] {DisplayPath ?? Path} - {DisplayValue}";
|
||||||
|
return $"{DisplayPath ?? Path} - {DisplayValue}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a configuration to use while updating a <see cref="DataModelVisualizationViewModel" />
|
||||||
|
/// </summary>
|
||||||
|
public class DataModelUpdateConfiguration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="DataModelUpdateConfiguration" /> class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="createEventChildren">A boolean indicating whether or not event children should be created</param>
|
||||||
|
public DataModelUpdateConfiguration(bool createEventChildren)
|
||||||
|
{
|
||||||
|
CreateEventChildren = createEventChildren;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean indicating whether or not event children should be created
|
||||||
|
/// </summary>
|
||||||
|
public bool CreateEventChildren { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,373 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Modules;
|
||||||
|
using Artemis.UI.Shared.Services;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a base class for a view model that visualizes a part of the data model
|
||||||
|
/// </summary>
|
||||||
|
public abstract class DataModelVisualizationViewModel : ReactiveObject, IDisposable
|
||||||
|
{
|
||||||
|
private const int MaxDepth = 4;
|
||||||
|
private ObservableCollection<DataModelVisualizationViewModel> _children;
|
||||||
|
private DataModel? _dataModel;
|
||||||
|
private bool _isMatchingFilteredTypes;
|
||||||
|
private bool _isVisualizationExpanded;
|
||||||
|
private DataModelVisualizationViewModel? _parent;
|
||||||
|
private DataModelPropertyAttribute? _propertyDescription;
|
||||||
|
private bool _populatedStaticChildren;
|
||||||
|
|
||||||
|
internal DataModelVisualizationViewModel(DataModel? dataModel, DataModelVisualizationViewModel? parent, DataModelPath? dataModelPath)
|
||||||
|
{
|
||||||
|
_dataModel = dataModel;
|
||||||
|
_children = new ObservableCollection<DataModelVisualizationViewModel>();
|
||||||
|
_parent = parent;
|
||||||
|
DataModelPath = dataModelPath;
|
||||||
|
IsMatchingFilteredTypes = true;
|
||||||
|
|
||||||
|
if (parent == null)
|
||||||
|
IsRootViewModel = true;
|
||||||
|
else
|
||||||
|
PropertyDescription = DataModelPath?.GetPropertyDescription() ?? DataModel?.DataModelDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean indicating whether this view model is at the root of the data model
|
||||||
|
/// </summary>
|
||||||
|
public bool IsRootViewModel { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the data model path to the property this view model is visualizing
|
||||||
|
/// </summary>
|
||||||
|
public DataModelPath? DataModelPath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a string representation of the path backing this model
|
||||||
|
/// </summary>
|
||||||
|
public string? Path => DataModelPath?.Path;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the property depth of the view model
|
||||||
|
/// </summary>
|
||||||
|
public int Depth { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the data model backing this view model
|
||||||
|
/// </summary>
|
||||||
|
public DataModel? DataModel
|
||||||
|
{
|
||||||
|
get => _dataModel;
|
||||||
|
protected set => this.RaiseAndSetIfChanged(ref _dataModel, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the property description of the property this view model is visualizing
|
||||||
|
/// </summary>
|
||||||
|
public DataModelPropertyAttribute? PropertyDescription
|
||||||
|
{
|
||||||
|
get => _propertyDescription;
|
||||||
|
protected set => this.RaiseAndSetIfChanged(ref _propertyDescription, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the parent of this view model
|
||||||
|
/// </summary>
|
||||||
|
public DataModelVisualizationViewModel? Parent
|
||||||
|
{
|
||||||
|
get => _parent;
|
||||||
|
protected set => this.RaiseAndSetIfChanged(ref _parent, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets an observable collection containing the children of this view model
|
||||||
|
/// </summary>
|
||||||
|
public ObservableCollection<DataModelVisualizationViewModel> Children
|
||||||
|
{
|
||||||
|
get => _children;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _children, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean indicating whether the property being visualized matches the types last provided to
|
||||||
|
/// <see cref="ApplyTypeFilter" />
|
||||||
|
/// </summary>
|
||||||
|
public bool IsMatchingFilteredTypes
|
||||||
|
{
|
||||||
|
get => _isMatchingFilteredTypes;
|
||||||
|
private set => this.RaiseAndSetIfChanged(ref _isMatchingFilteredTypes, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a boolean indicating whether the visualization is expanded, exposing the <see cref="Children" />
|
||||||
|
/// </summary>
|
||||||
|
public bool IsVisualizationExpanded
|
||||||
|
{
|
||||||
|
get => _isVisualizationExpanded;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!this.RaiseAndSetIfChanged(ref _isVisualizationExpanded, value)) return;
|
||||||
|
RequestUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a user-friendly representation of the <see cref="DataModelPath" />
|
||||||
|
/// </summary>
|
||||||
|
public virtual string? DisplayPath => DataModelPath != null
|
||||||
|
? string.Join(" › ", DataModelPath.Segments.Select(s => s.GetPropertyDescription()?.Name ?? s.Identifier))
|
||||||
|
: null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the datamodel and if in an parent, any children
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dataModelUIService">The data model UI service used during update</param>
|
||||||
|
/// <param name="configuration">The configuration to apply while updating</param>
|
||||||
|
public abstract void Update(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration? configuration);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current value of the property being visualized
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The current value of the property being visualized</returns>
|
||||||
|
public virtual object? GetCurrentValue()
|
||||||
|
{
|
||||||
|
if (IsRootViewModel)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return DataModelPath?.GetValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the provided types match the type of the property being visualized and sets the result in
|
||||||
|
/// <see cref="IsMatchingFilteredTypes" />
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="looseMatch">Whether the type may be a loose match, meaning it can be cast or converted</param>
|
||||||
|
/// <param name="filteredTypes">The types to filter</param>
|
||||||
|
public void ApplyTypeFilter(bool looseMatch, params Type[]? filteredTypes)
|
||||||
|
{
|
||||||
|
if (filteredTypes != null)
|
||||||
|
{
|
||||||
|
if (filteredTypes.All(t => t == null))
|
||||||
|
filteredTypes = null;
|
||||||
|
else
|
||||||
|
filteredTypes = filteredTypes.Where(t => t != null).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the VM has children, its own type is not relevant
|
||||||
|
if (Children.Any())
|
||||||
|
{
|
||||||
|
foreach (DataModelVisualizationViewModel child in Children)
|
||||||
|
child?.ApplyTypeFilter(looseMatch, filteredTypes);
|
||||||
|
|
||||||
|
IsMatchingFilteredTypes = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If null is passed, clear the type filter
|
||||||
|
if (filteredTypes == null || filteredTypes.Length == 0)
|
||||||
|
{
|
||||||
|
IsMatchingFilteredTypes = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the type couldn't be retrieved either way, assume false
|
||||||
|
Type? type = DataModelPath?.GetPropertyType();
|
||||||
|
if (type == null)
|
||||||
|
{
|
||||||
|
IsMatchingFilteredTypes = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (looseMatch)
|
||||||
|
IsMatchingFilteredTypes = filteredTypes.Any(t => t.IsCastableFrom(type) ||
|
||||||
|
t == typeof(Enum) && type.IsEnum ||
|
||||||
|
t == typeof(IEnumerable<>) && type.IsGenericEnumerable() ||
|
||||||
|
type.IsGenericType && t == type.GetGenericTypeDefinition());
|
||||||
|
else
|
||||||
|
IsMatchingFilteredTypes = filteredTypes.Any(t => t == type || t == typeof(Enum) && type.IsEnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal virtual int GetChildDepth()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void PopulateProperties(IDataModelUIService dataModelUIService, DataModelUpdateConfiguration? dataModelUpdateConfiguration)
|
||||||
|
{
|
||||||
|
if (IsRootViewModel && DataModel == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Type? modelType = IsRootViewModel ? DataModel?.GetType() : DataModelPath?.GetPropertyType();
|
||||||
|
if (modelType == null)
|
||||||
|
throw new ArtemisSharedUIException("Failed to populate data model visualization properties, couldn't get a property type");
|
||||||
|
|
||||||
|
// Add missing static children only once, they're static after all
|
||||||
|
if (!_populatedStaticChildren)
|
||||||
|
{
|
||||||
|
foreach (PropertyInfo propertyInfo in modelType.GetProperties(BindingFlags.Public | BindingFlags.Instance).OrderBy(t => t.MetadataToken))
|
||||||
|
{
|
||||||
|
string childPath = AppendToPath(propertyInfo.Name);
|
||||||
|
if (Children.Any(c => c.Path != null && c.Path.Equals(childPath)))
|
||||||
|
continue;
|
||||||
|
if (propertyInfo.GetCustomAttribute<DataModelIgnoreAttribute>() != null)
|
||||||
|
continue;
|
||||||
|
MethodInfo? getMethod = propertyInfo.GetGetMethod();
|
||||||
|
if (getMethod == null || getMethod.GetParameters().Any())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
DataModelVisualizationViewModel? child = CreateChild(dataModelUIService, childPath, GetChildDepth());
|
||||||
|
if (child != null)
|
||||||
|
Children.Add(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
_populatedStaticChildren = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove static children that should be hidden
|
||||||
|
if (DataModel != null)
|
||||||
|
{
|
||||||
|
ReadOnlyCollection<PropertyInfo> hiddenProperties = DataModel.GetHiddenProperties();
|
||||||
|
foreach (PropertyInfo hiddenProperty in hiddenProperties)
|
||||||
|
{
|
||||||
|
string childPath = AppendToPath(hiddenProperty.Name);
|
||||||
|
DataModelVisualizationViewModel? toRemove = Children.FirstOrDefault(c => c.Path != null && c.Path == childPath);
|
||||||
|
if (toRemove != null)
|
||||||
|
Children.Remove(toRemove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add missing dynamic children
|
||||||
|
object? value = Parent == null || Parent.IsRootViewModel ? DataModel : DataModelPath?.GetValue();
|
||||||
|
if (value is DataModel dataModel)
|
||||||
|
{
|
||||||
|
foreach (string key in dataModel.DynamicChildren.Keys.ToList())
|
||||||
|
{
|
||||||
|
string childPath = AppendToPath(key);
|
||||||
|
if (Children.Any(c => c.Path != null && c.Path.Equals(childPath)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
DataModelVisualizationViewModel? child = CreateChild(dataModelUIService, childPath, GetChildDepth());
|
||||||
|
if (child != null)
|
||||||
|
Children.Add(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove dynamic children that have been removed from the data model
|
||||||
|
List<DataModelVisualizationViewModel> toRemoveDynamic = Children.Where(c => c.DataModelPath != null && !c.DataModelPath.IsValid).ToList();
|
||||||
|
foreach (DataModelVisualizationViewModel dataModelVisualizationViewModel in toRemoveDynamic)
|
||||||
|
Children.Remove(dataModelVisualizationViewModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataModelVisualizationViewModel? CreateChild(IDataModelUIService dataModelUIService, string path, int depth)
|
||||||
|
{
|
||||||
|
if (DataModel == null)
|
||||||
|
throw new ArtemisSharedUIException("Cannot create a data model visualization child VM for a parent without a data model");
|
||||||
|
if (depth > MaxDepth)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
DataModelPath dataModelPath = new(DataModel, path);
|
||||||
|
if (!dataModelPath.IsValid)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
PropertyInfo? propertyInfo = dataModelPath.GetPropertyInfo();
|
||||||
|
Type? propertyType = dataModelPath.GetPropertyType();
|
||||||
|
|
||||||
|
// Skip properties decorated with DataModelIgnore
|
||||||
|
if (propertyInfo != null && Attribute.IsDefined(propertyInfo, typeof(DataModelIgnoreAttribute)))
|
||||||
|
return null;
|
||||||
|
// Skip properties that are in the ignored properties list of the respective profile module/data model expansion
|
||||||
|
if (DataModel.GetHiddenProperties().Any(p => p.Equals(propertyInfo)))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (propertyType == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// If a display VM was found, prefer to use that in any case
|
||||||
|
DataModelDisplayViewModel? typeViewModel = dataModelUIService.GetDataModelDisplayViewModel(propertyType, PropertyDescription);
|
||||||
|
if (typeViewModel != null)
|
||||||
|
return new DataModelPropertyViewModel(DataModel, this, dataModelPath) {DisplayViewModel = typeViewModel, Depth = depth};
|
||||||
|
// For primitives, create a property view model, it may be null that is fine
|
||||||
|
if (propertyType.IsPrimitive || propertyType.IsEnum || propertyType == typeof(string) || propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||||
|
return new DataModelPropertyViewModel(DataModel, this, dataModelPath) {Depth = depth};
|
||||||
|
if (propertyType.IsGenericEnumerable())
|
||||||
|
return new DataModelListViewModel(DataModel, this, dataModelPath) {Depth = depth};
|
||||||
|
if (propertyType == typeof(DataModelEvent) || propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(DataModelEvent<>))
|
||||||
|
return new DataModelEventViewModel(DataModel, this, dataModelPath) {Depth = depth};
|
||||||
|
// For other value types create a child view model
|
||||||
|
if (propertyType.IsClass || propertyType.IsStruct())
|
||||||
|
return new DataModelPropertiesViewModel(DataModel, this, dataModelPath) {Depth = depth};
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string AppendToPath(string toAppend)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(Path))
|
||||||
|
return toAppend;
|
||||||
|
|
||||||
|
StringBuilder builder = new();
|
||||||
|
builder.Append(Path);
|
||||||
|
builder.Append(".");
|
||||||
|
builder.Append(toAppend);
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RequestUpdate()
|
||||||
|
{
|
||||||
|
Parent?.RequestUpdate();
|
||||||
|
OnUpdateRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when an update to the property this view model visualizes is requested
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler? UpdateRequested;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the <see cref="UpdateRequested" /> event
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnUpdateRequested()
|
||||||
|
{
|
||||||
|
UpdateRequested?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IDisposable
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">
|
||||||
|
/// <see langword="true" /> to release both managed and unmanaged resources;
|
||||||
|
/// <see langword="false" /> to release only unmanaged resources.
|
||||||
|
/// </param>
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
DataModelPath?.Dispose();
|
||||||
|
foreach (DataModelVisualizationViewModel dataModelVisualizationViewModel in Children)
|
||||||
|
dataModelVisualizationViewModel.Dispose(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Artemis.UI.Shared.DefaultTypes.DataModel.Display.DefaultDataModelDisplayView">
|
||||||
|
<Grid ColumnDefinitions="*,Auto,Auto">
|
||||||
|
<!-- Prefix -->
|
||||||
|
<TextBlock Grid.Column="0"
|
||||||
|
Text="{Binding PropertyDescription.Prefix}"
|
||||||
|
IsVisible="{Binding PropertyDescription.Prefix, Converter={x:Static ObjectConverters.IsNotNull}}"
|
||||||
|
TextAlignment="Right"
|
||||||
|
Margin="0 0 5 0" />
|
||||||
|
|
||||||
|
<!-- Value -->
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Text="{Binding DisplayValue, Mode=OneWay}"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
IsVisible="{Binding ShowToString}"/>
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Text="null"
|
||||||
|
FontFamily="Consolas"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Foreground="{DynamicResource MaterialDesignCheckBoxDisabled}"
|
||||||
|
IsVisible="{Binding ShowNull}"/>
|
||||||
|
|
||||||
|
<!-- Affix -->
|
||||||
|
<TextBlock Grid.Column="2"
|
||||||
|
Text="{Binding PropertyDescription.Affix}"
|
||||||
|
IsVisible="{Binding PropertyDescription.Affix, Converter={x:Static ObjectConverters.IsNotNull}}"
|
||||||
|
Margin="5 0 0 0" />
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared.DefaultTypes.DataModel.Display
|
||||||
|
{
|
||||||
|
public partial class DefaultDataModelDisplayView : UserControl
|
||||||
|
{
|
||||||
|
public DefaultDataModelDisplayView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
<UserControl x:Class="Artemis.UI.Shared.DefaultTypes.DataModel.Display.DefaultDataModelDisplayView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:Artemis.UI.Shared.DefaultTypes.DataModel.Display"
|
||||||
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
|
xmlns:shared="clr-namespace:Artemis.UI.Shared"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
|
d:DataContext="{d:DesignInstance local:DefaultDataModelDisplayViewModel}">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<!-- Prefix -->
|
||||||
|
<TextBlock Grid.Column="0"
|
||||||
|
Text="{Binding PropertyDescription.Prefix}"
|
||||||
|
Visibility="{Binding PropertyDescription.Prefix, Converter={StaticResource NullToVisibilityConverter}}"
|
||||||
|
TextAlignment="Right"
|
||||||
|
Margin="0 0 5 0" />
|
||||||
|
|
||||||
|
<!-- Value -->
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Text="{Binding DisplayValue, Mode=OneWay}"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Visibility="{Binding ShowToString, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Text="null"
|
||||||
|
FontFamily="Consolas"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Foreground="{DynamicResource MaterialDesignCheckBoxDisabled}"
|
||||||
|
Visibility="{Binding ShowNull, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
|
||||||
|
|
||||||
|
<!-- Affix -->
|
||||||
|
<TextBlock Grid.Column="2"
|
||||||
|
Text="{Binding PropertyDescription.Affix}"
|
||||||
|
Visibility="{Binding PropertyDescription.Affix, Converter={StaticResource NullToVisibilityConverter}}"
|
||||||
|
Margin="5 0 0 0" />
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
using System;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.UI.Shared.DataModelVisualization;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared.DefaultTypes.DataModel.Display
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the default data model display view model that is used when no display viewmodel specific for the type
|
||||||
|
/// is registered
|
||||||
|
/// </summary>
|
||||||
|
internal class DefaultDataModelDisplayViewModel : DataModelDisplayViewModel<object>
|
||||||
|
{
|
||||||
|
private bool _showNull;
|
||||||
|
private bool _showToString;
|
||||||
|
|
||||||
|
internal DefaultDataModelDisplayViewModel()
|
||||||
|
{
|
||||||
|
ShowNull = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShowToString
|
||||||
|
{
|
||||||
|
get => _showToString;
|
||||||
|
private set => this.RaiseAndSetIfChanged(ref _showToString, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShowNull
|
||||||
|
{
|
||||||
|
get => _showNull;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _showNull, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDisplayValueUpdated()
|
||||||
|
{
|
||||||
|
if (DisplayValue is Enum enumDisplayValue)
|
||||||
|
DisplayValue = EnumUtilities.HumanizeValue(enumDisplayValue);
|
||||||
|
|
||||||
|
ShowToString = DisplayValue != null;
|
||||||
|
ShowNull = DisplayValue == null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Artemis.UI.Shared.Exceptions
|
namespace Artemis.UI.Shared
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents errors that occur within the Artemis Shared UI library
|
/// Represents errors that occur within the Artemis Shared UI library
|
||||||
|
|||||||
251
src/Avalonia/Artemis.UI.Shared/Services/DataModelUIService.cs
Normal file
251
src/Avalonia/Artemis.UI.Shared/Services/DataModelUIService.cs
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Modules;
|
||||||
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.UI.Shared.DataModelVisualization;
|
||||||
|
using Artemis.UI.Shared.DataModelVisualization.Shared;
|
||||||
|
using Artemis.UI.Shared.DefaultTypes.DataModel.Display;
|
||||||
|
using Ninject;
|
||||||
|
using Ninject.Parameters;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared.Services
|
||||||
|
{
|
||||||
|
internal class DataModelUIService : IDataModelUIService
|
||||||
|
{
|
||||||
|
private readonly IDataModelService _dataModelService;
|
||||||
|
private readonly IKernel _kernel;
|
||||||
|
private readonly List<DataModelVisualizationRegistration> _registeredDataModelDisplays;
|
||||||
|
private readonly List<DataModelVisualizationRegistration> _registeredDataModelEditors;
|
||||||
|
|
||||||
|
public DataModelUIService(IDataModelService dataModelService, IKernel kernel)
|
||||||
|
{
|
||||||
|
_dataModelService = dataModelService;
|
||||||
|
_kernel = kernel;
|
||||||
|
_registeredDataModelEditors = new List<DataModelVisualizationRegistration>();
|
||||||
|
_registeredDataModelDisplays = new List<DataModelVisualizationRegistration>();
|
||||||
|
|
||||||
|
RegisteredDataModelEditors = new ReadOnlyCollection<DataModelVisualizationRegistration>(_registeredDataModelEditors);
|
||||||
|
RegisteredDataModelDisplays = new ReadOnlyCollection<DataModelVisualizationRegistration>(_registeredDataModelDisplays);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyCollection<DataModelVisualizationRegistration> RegisteredDataModelEditors { get; }
|
||||||
|
public IReadOnlyCollection<DataModelVisualizationRegistration> RegisteredDataModelDisplays { get; }
|
||||||
|
|
||||||
|
public DataModelPropertiesViewModel GetMainDataModelVisualization()
|
||||||
|
{
|
||||||
|
DataModelPropertiesViewModel viewModel = new(null, null, null);
|
||||||
|
foreach (DataModel dataModelExpansion in _dataModelService.GetDataModels().Where(d => d.IsExpansion).OrderBy(d => d.DataModelDescription.Name))
|
||||||
|
viewModel.Children.Add(new DataModelPropertiesViewModel(dataModelExpansion, viewModel, new DataModelPath(dataModelExpansion)));
|
||||||
|
|
||||||
|
// Update to populate children
|
||||||
|
viewModel.Update(this, null);
|
||||||
|
viewModel.UpdateRequested += (sender, args) => viewModel.Update(this, null);
|
||||||
|
return viewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateModules(DataModelPropertiesViewModel mainDataModelVisualization)
|
||||||
|
{
|
||||||
|
List<DataModelVisualizationViewModel> disabledChildren = mainDataModelVisualization.Children
|
||||||
|
.Where(d => d.DataModel != null && !d.DataModel.Module.IsEnabled)
|
||||||
|
.ToList();
|
||||||
|
foreach (DataModelVisualizationViewModel child in disabledChildren)
|
||||||
|
mainDataModelVisualization.Children.Remove(child);
|
||||||
|
|
||||||
|
foreach (DataModel dataModelExpansion in _dataModelService.GetDataModels().OrderBy(d => d.DataModelDescription.Name))
|
||||||
|
{
|
||||||
|
if (mainDataModelVisualization.Children.All(c => c.DataModel != dataModelExpansion))
|
||||||
|
{
|
||||||
|
mainDataModelVisualization.Children.Add(
|
||||||
|
new DataModelPropertiesViewModel(dataModelExpansion, mainDataModelVisualization, new DataModelPath(dataModelExpansion))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mainDataModelVisualization.Update(this, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataModelPropertiesViewModel? GetPluginDataModelVisualization(List<Module> modules, bool includeMainDataModel)
|
||||||
|
{
|
||||||
|
DataModelPropertiesViewModel root;
|
||||||
|
// This will contain any modules that are always available
|
||||||
|
if (includeMainDataModel)
|
||||||
|
root = GetMainDataModelVisualization();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
root = new DataModelPropertiesViewModel(null, null, null);
|
||||||
|
root.UpdateRequested += (sender, args) => root.Update(this, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Module module in modules)
|
||||||
|
{
|
||||||
|
DataModel? dataModel = _dataModelService.GetPluginDataModel(module);
|
||||||
|
if (dataModel == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
root.Children.Add(new DataModelPropertiesViewModel(dataModel, root, new DataModelPath(dataModel)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!root.Children.Any())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Update to populate children
|
||||||
|
root.Update(this, null);
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataModelVisualizationRegistration RegisterDataModelInput<T>(Plugin plugin, IReadOnlyCollection<Type>? compatibleConversionTypes = null) where T : DataModelInputViewModel
|
||||||
|
{
|
||||||
|
compatibleConversionTypes ??= new List<Type>();
|
||||||
|
Type viewModelType = typeof(T);
|
||||||
|
lock (_registeredDataModelEditors)
|
||||||
|
{
|
||||||
|
Type supportedType = viewModelType.BaseType!.GetGenericArguments()[0];
|
||||||
|
DataModelVisualizationRegistration? existing = _registeredDataModelEditors.FirstOrDefault(r => r.SupportedType == supportedType);
|
||||||
|
if (existing != null)
|
||||||
|
{
|
||||||
|
if (existing.Plugin != plugin)
|
||||||
|
throw new ArtemisSharedUIException($"Cannot register data model input for type {supportedType.Name} because an editor was already" +
|
||||||
|
$" registered by {existing.Plugin}");
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
_kernel.Bind(viewModelType).ToSelf();
|
||||||
|
|
||||||
|
// Create the registration
|
||||||
|
DataModelVisualizationRegistration registration = new(this, RegistrationType.Input, plugin, supportedType, viewModelType)
|
||||||
|
{
|
||||||
|
// Apply the compatible conversion types to the registration
|
||||||
|
CompatibleConversionTypes = compatibleConversionTypes
|
||||||
|
};
|
||||||
|
|
||||||
|
_registeredDataModelEditors.Add(registration);
|
||||||
|
return registration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataModelVisualizationRegistration RegisterDataModelDisplay<T>(Plugin plugin) where T : DataModelDisplayViewModel
|
||||||
|
{
|
||||||
|
Type viewModelType = typeof(T);
|
||||||
|
lock (_registeredDataModelDisplays)
|
||||||
|
{
|
||||||
|
Type supportedType = viewModelType.BaseType!.GetGenericArguments()[0];
|
||||||
|
DataModelVisualizationRegistration? existing = _registeredDataModelDisplays.FirstOrDefault(r => r.SupportedType == supportedType);
|
||||||
|
if (existing != null)
|
||||||
|
{
|
||||||
|
if (existing.Plugin != plugin)
|
||||||
|
throw new ArtemisSharedUIException($"Cannot register data model display for type {supportedType.Name} because an editor was already" +
|
||||||
|
$" registered by {existing.Plugin}");
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
_kernel.Bind(viewModelType).ToSelf();
|
||||||
|
DataModelVisualizationRegistration registration = new(this, RegistrationType.Display, plugin, supportedType, viewModelType);
|
||||||
|
_registeredDataModelDisplays.Add(registration);
|
||||||
|
return registration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveDataModelInput(DataModelVisualizationRegistration registration)
|
||||||
|
{
|
||||||
|
lock (_registeredDataModelEditors)
|
||||||
|
{
|
||||||
|
if (_registeredDataModelEditors.Contains(registration))
|
||||||
|
{
|
||||||
|
registration.Unsubscribe();
|
||||||
|
_registeredDataModelEditors.Remove(registration);
|
||||||
|
|
||||||
|
_kernel.Unbind(registration.ViewModelType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveDataModelDisplay(DataModelVisualizationRegistration registration)
|
||||||
|
{
|
||||||
|
lock (_registeredDataModelDisplays)
|
||||||
|
{
|
||||||
|
if (_registeredDataModelDisplays.Contains(registration))
|
||||||
|
{
|
||||||
|
registration.Unsubscribe();
|
||||||
|
_registeredDataModelDisplays.Remove(registration);
|
||||||
|
|
||||||
|
_kernel.Unbind(registration.ViewModelType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataModelDisplayViewModel? GetDataModelDisplayViewModel(Type propertyType, DataModelPropertyAttribute? description, bool fallBackToDefault)
|
||||||
|
{
|
||||||
|
lock (_registeredDataModelDisplays)
|
||||||
|
{
|
||||||
|
DataModelDisplayViewModel? result;
|
||||||
|
|
||||||
|
DataModelVisualizationRegistration? match = _registeredDataModelDisplays.FirstOrDefault(d => d.SupportedType == propertyType);
|
||||||
|
if (match != null)
|
||||||
|
{
|
||||||
|
// If this ever happens something is likely wrong with the plugin unload detection
|
||||||
|
if (match.Plugin.Kernel == null)
|
||||||
|
throw new ArtemisSharedUIException("Cannot GetDataModelDisplayViewModel for a registration by an uninitialized plugin");
|
||||||
|
|
||||||
|
result = (DataModelDisplayViewModel) match.Plugin.Kernel.Get(match.ViewModelType);
|
||||||
|
}
|
||||||
|
else if (!fallBackToDefault)
|
||||||
|
result = null;
|
||||||
|
else
|
||||||
|
result = _kernel.Get<DefaultDataModelDisplayViewModel>();
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
result.PropertyDescription = description;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataModelInputViewModel? GetDataModelInputViewModel(Type propertyType, DataModelPropertyAttribute? description, object? initialValue, Action<object?, bool> updateCallback)
|
||||||
|
{
|
||||||
|
lock (_registeredDataModelEditors)
|
||||||
|
{
|
||||||
|
// Prefer a VM that natively supports the type
|
||||||
|
DataModelVisualizationRegistration? match = _registeredDataModelEditors.FirstOrDefault(d => d.SupportedType == propertyType);
|
||||||
|
// Fall back on a VM that supports the type through conversion
|
||||||
|
if (match == null)
|
||||||
|
match = _registeredDataModelEditors.FirstOrDefault(d => d.CompatibleConversionTypes != null && d.CompatibleConversionTypes.Contains(propertyType));
|
||||||
|
// Lastly try getting an enum VM if the provided type is an enum
|
||||||
|
if (match == null && propertyType.IsEnum)
|
||||||
|
match = _registeredDataModelEditors.FirstOrDefault(d => d.SupportedType == typeof(Enum));
|
||||||
|
|
||||||
|
if (match != null)
|
||||||
|
{
|
||||||
|
DataModelInputViewModel viewModel = InstantiateDataModelInputViewModel(match, description, initialValue);
|
||||||
|
viewModel.UpdateCallback = updateCallback;
|
||||||
|
return viewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataModelInputViewModel InstantiateDataModelInputViewModel(DataModelVisualizationRegistration registration, DataModelPropertyAttribute? description, object? initialValue)
|
||||||
|
{
|
||||||
|
// This assumes the type can be converted, that has been checked when the VM was created
|
||||||
|
if (initialValue != null && initialValue.GetType() != registration.SupportedType)
|
||||||
|
initialValue = Convert.ChangeType(initialValue, registration.SupportedType);
|
||||||
|
|
||||||
|
IParameter[] parameters =
|
||||||
|
{
|
||||||
|
new ConstructorArgument("targetDescription", description),
|
||||||
|
new ConstructorArgument("initialValue", initialValue)
|
||||||
|
};
|
||||||
|
|
||||||
|
// If this ever happens something is likely wrong with the plugin unload detection
|
||||||
|
if (registration.Plugin.Kernel == null)
|
||||||
|
throw new ArtemisSharedUIException("Cannot InstantiateDataModelInputViewModel for a registration by an uninitialized plugin");
|
||||||
|
|
||||||
|
DataModelInputViewModel viewModel = (DataModelInputViewModel) registration.Plugin.Kernel.Get(registration.ViewModelType, parameters);
|
||||||
|
viewModel.CompatibleConversionTypes = registration.CompatibleConversionTypes;
|
||||||
|
return viewModel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,109 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Modules;
|
||||||
|
using Artemis.UI.Shared.DataModelVisualization;
|
||||||
|
using Artemis.UI.Shared.DataModelVisualization.Shared;
|
||||||
|
using Artemis.UI.Shared.Services.Interfaces;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared.Services
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A service for UI related data model tasks
|
||||||
|
/// </summary>
|
||||||
|
public interface IDataModelUIService : IArtemisSharedUIService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a read-only list of all registered data model editors
|
||||||
|
/// </summary>
|
||||||
|
IReadOnlyCollection<DataModelVisualizationRegistration> RegisteredDataModelEditors { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a read-only list of all registered data model displays
|
||||||
|
/// </summary>
|
||||||
|
IReadOnlyCollection<DataModelVisualizationRegistration> RegisteredDataModelDisplays { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a data model visualization view model for the main data model
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// A data model visualization view model containing all data model expansions and modules that expand the main
|
||||||
|
/// data model
|
||||||
|
/// </returns>
|
||||||
|
DataModelPropertiesViewModel GetMainDataModelVisualization();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a data model visualization view model for the data model of the provided plugin feature
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="modules">The modules to create the data model visualization view model for</param>
|
||||||
|
/// <param name="includeMainDataModel">
|
||||||
|
/// Whether or not also to include the main data model (and therefore any modules marked
|
||||||
|
/// as <see cref="Module.IsAlwaysAvailable" />)
|
||||||
|
/// </param>
|
||||||
|
/// <returns>A data model visualization view model containing the data model of the provided feature</returns>
|
||||||
|
DataModelPropertiesViewModel? GetPluginDataModelVisualization(List<Module> modules, bool includeMainDataModel);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the children of the provided main data model visualization, removing disabled children and adding newly
|
||||||
|
/// enabled children
|
||||||
|
/// </summary>
|
||||||
|
void UpdateModules(DataModelPropertiesViewModel mainDataModelVisualization);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers a new data model editor
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the editor</typeparam>
|
||||||
|
/// <param name="plugin">The plugin this editor belongs to</param>
|
||||||
|
/// <param name="compatibleConversionTypes">A collection of extra types this editor supports</param>
|
||||||
|
/// <returns>A registration that can be used to remove the editor</returns>
|
||||||
|
DataModelVisualizationRegistration RegisterDataModelInput<T>(Plugin plugin, IReadOnlyCollection<Type> compatibleConversionTypes) where T : DataModelInputViewModel;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers a new data model display
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the display</typeparam>
|
||||||
|
/// <param name="plugin">The plugin this display belongs to</param>
|
||||||
|
/// <returns>A registration that can be used to remove the display</returns>
|
||||||
|
DataModelVisualizationRegistration RegisterDataModelDisplay<T>(Plugin plugin) where T : DataModelDisplayViewModel;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a data model editor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="registration">
|
||||||
|
/// The registration of the editor as returned by <see cref="RegisterDataModelInput{T}" />
|
||||||
|
/// </param>
|
||||||
|
void RemoveDataModelInput(DataModelVisualizationRegistration registration);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a data model display
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="registration">
|
||||||
|
/// The registration of the display as returned by <see cref="RegisterDataModelDisplay{T}" />
|
||||||
|
/// </param>
|
||||||
|
void RemoveDataModelDisplay(DataModelVisualizationRegistration registration);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the most appropriate display view model for the provided <paramref name="propertyType" /> that can display
|
||||||
|
/// a value
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="propertyType">The type of data model property to find a display view model for</param>
|
||||||
|
/// <param name="description">The description of the data model property</param>
|
||||||
|
/// <param name="fallBackToDefault">
|
||||||
|
/// If <see langword="true"></see>, a simple .ToString() display view model will be
|
||||||
|
/// returned if nothing else is found
|
||||||
|
/// </param>
|
||||||
|
/// <returns>The most appropriate display view model for the provided <paramref name="propertyType"></paramref></returns>
|
||||||
|
DataModelDisplayViewModel? GetDataModelDisplayViewModel(Type propertyType, DataModelPropertyAttribute? description, bool fallBackToDefault = false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the most appropriate input view model for the provided <paramref name="propertyType" /> that allows
|
||||||
|
/// inputting a value
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="propertyType">The type of data model property to find a display view model for</param>
|
||||||
|
/// <param name="description">The description of the data model property</param>
|
||||||
|
/// <param name="initialValue">The initial value to show in the input</param>
|
||||||
|
/// <param name="updateCallback">A function to call whenever the input was updated (submitted or not)</param>
|
||||||
|
/// <returns>The most appropriate input view model for the provided <paramref name="propertyType" /></returns>
|
||||||
|
DataModelInputViewModel? GetDataModelInputViewModel(Type propertyType, DataModelPropertyAttribute? description, object? initialValue, Action<object?, bool> updateCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.UI.Shared.Exceptions;
|
|
||||||
using Artemis.UI.Shared.Services.Builders;
|
using Artemis.UI.Shared.Services.Builders;
|
||||||
using Artemis.UI.Shared.Services.Interfaces;
|
using Artemis.UI.Shared.Services.Interfaces;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
|
|||||||
@ -46,4 +46,9 @@
|
|||||||
<Resource Include="Assets\Images\Logo\bow.ico" />
|
<Resource Include="Assets\Images\Logo\bow.ico" />
|
||||||
<Resource Include="Assets\Images\Logo\bow.svg" />
|
<Resource Include="Assets\Images\Logo\bow.svg" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Update="Screens\Debugger\Tabs\Settings\DebugSettingsView.axaml.cs">
|
||||||
|
<DependentUpon>DebugSettingsView.axaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@ -3,6 +3,8 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
|
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
|
xmlns:reactiveUi="http://reactiveui.net"
|
||||||
mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="800"
|
mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="800"
|
||||||
x:Class="Artemis.UI.Screens.Debugger.DebugView"
|
x:Class="Artemis.UI.Screens.Debugger.DebugView"
|
||||||
Title="Artemis | Debugger"
|
Title="Artemis | Debugger"
|
||||||
@ -10,9 +12,59 @@
|
|||||||
Height="800"
|
Height="800"
|
||||||
ExtendClientAreaToDecorationsHint="True">
|
ExtendClientAreaToDecorationsHint="True">
|
||||||
|
|
||||||
<controls:NavigationView x:Name="Navigation">
|
<Window.Styles>
|
||||||
|
<Style Selector="StackPanel.sidebar-stackpanel avalonia|MaterialIcon">
|
||||||
|
<Setter Property="Margin" Value="-7 0 0 0" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="StackPanel.sidebar-stackpanel TextBlock">
|
||||||
|
<Setter Property="Margin" Value="15 0 0 0" />
|
||||||
|
</Style>
|
||||||
|
</Window.Styles>
|
||||||
|
<controls:NavigationView x:Name="Navigation"
|
||||||
|
SelectedItem="{Binding SelectedItem}"
|
||||||
|
IsPaneToggleButtonVisible="False"
|
||||||
|
PaneDisplayMode="Left"
|
||||||
|
Margin="0 30 0 0">
|
||||||
|
<controls:NavigationView.MenuItems>
|
||||||
|
<controls:NavigationViewItem Tag="Rendering">
|
||||||
|
<controls:NavigationViewItem.Content>
|
||||||
|
<StackPanel Orientation="Horizontal" Classes="sidebar-stackpanel">
|
||||||
|
<avalonia:MaterialIcon Kind="Paint" />
|
||||||
|
<TextBlock>Rendering</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</controls:NavigationViewItem.Content>
|
||||||
|
</controls:NavigationViewItem>
|
||||||
|
<controls:NavigationViewItem Tag="DataModel">
|
||||||
|
<controls:NavigationViewItem.Content>
|
||||||
|
<StackPanel Orientation="Horizontal" Classes="sidebar-stackpanel">
|
||||||
|
<avalonia:MaterialIcon Kind="FormatListBulletedType" />
|
||||||
|
<TextBlock>Data Model</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</controls:NavigationViewItem.Content>
|
||||||
|
</controls:NavigationViewItem>
|
||||||
|
<controls:NavigationViewItem Tag="Performance">
|
||||||
|
<controls:NavigationViewItem.Content>
|
||||||
|
<StackPanel Orientation="Horizontal" Classes="sidebar-stackpanel">
|
||||||
|
<avalonia:MaterialIcon Kind="Gauge" />
|
||||||
|
<TextBlock>Performance</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</controls:NavigationViewItem.Content>
|
||||||
|
</controls:NavigationViewItem>
|
||||||
|
<controls:NavigationViewItem Tag="Logging">
|
||||||
|
<controls:NavigationViewItem.Content>
|
||||||
|
<StackPanel Orientation="Horizontal" Classes="sidebar-stackpanel">
|
||||||
|
<avalonia:MaterialIcon Kind="Text" />
|
||||||
|
<TextBlock>Logging</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</controls:NavigationViewItem.Content>
|
||||||
|
</controls:NavigationViewItem>
|
||||||
|
</controls:NavigationView.MenuItems>
|
||||||
|
|
||||||
|
<reactiveUi:RoutedViewHost Router="{Binding Router}" Padding="12">
|
||||||
|
<reactiveUi:RoutedViewHost.PageTransition>
|
||||||
|
<CrossFade Duration="0.1" />
|
||||||
|
</reactiveUi:RoutedViewHost.PageTransition>
|
||||||
|
</reactiveUi:RoutedViewHost>
|
||||||
|
|
||||||
</controls:NavigationView>
|
</controls:NavigationView>
|
||||||
|
|
||||||
|
|
||||||
</Window>
|
</Window>
|
||||||
@ -4,6 +4,7 @@ using Artemis.UI.Screens.Debugger.Tabs.DataModel;
|
|||||||
using Artemis.UI.Screens.Debugger.Tabs.Logs;
|
using Artemis.UI.Screens.Debugger.Tabs.Logs;
|
||||||
using Artemis.UI.Screens.Debugger.Tabs.Performance;
|
using Artemis.UI.Screens.Debugger.Tabs.Performance;
|
||||||
using Artemis.UI.Screens.Debugger.Tabs.Render;
|
using Artemis.UI.Screens.Debugger.Tabs.Render;
|
||||||
|
using Artemis.UI.Screens.Debugger.Tabs.Settings;
|
||||||
using Artemis.UI.Services.Interfaces;
|
using Artemis.UI.Services.Interfaces;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
@ -50,20 +51,23 @@ namespace Artemis.UI.Screens.Debugger
|
|||||||
{
|
{
|
||||||
// Kind of a lame way to do this but it's so static idc
|
// Kind of a lame way to do this but it's so static idc
|
||||||
ConstructorArgument hostScreen = new("hostScreen", this);
|
ConstructorArgument hostScreen = new("hostScreen", this);
|
||||||
switch ((string) item.Content)
|
switch (item.Tag as string)
|
||||||
{
|
{
|
||||||
case "Rendering":
|
case "Rendering":
|
||||||
Router.Navigate.Execute(_kernel.Get<RenderDebugViewModel>(hostScreen));
|
Router.Navigate.Execute(_kernel.Get<RenderDebugViewModel>(hostScreen));
|
||||||
break;
|
break;
|
||||||
case "Logs":
|
case "DataModel":
|
||||||
Router.Navigate.Execute(_kernel.Get<LogsDebugViewModel>(hostScreen));
|
|
||||||
break;
|
|
||||||
case "Data Model":
|
|
||||||
Router.Navigate.Execute(_kernel.Get<DataModelDebugViewModel>(hostScreen));
|
Router.Navigate.Execute(_kernel.Get<DataModelDebugViewModel>(hostScreen));
|
||||||
break;
|
break;
|
||||||
case "Performance":
|
case "Performance":
|
||||||
Router.Navigate.Execute(_kernel.Get<PerformanceDebugViewModel>(hostScreen));
|
Router.Navigate.Execute(_kernel.Get<PerformanceDebugViewModel>(hostScreen));
|
||||||
break;
|
break;
|
||||||
|
case "Logging":
|
||||||
|
Router.Navigate.Execute(_kernel.Get<LogsDebugViewModel>(hostScreen));
|
||||||
|
break;
|
||||||
|
case "Settings":
|
||||||
|
Router.Navigate.Execute(_kernel.Get<DebugSettingsViewModel>(hostScreen));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,109 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:dataModel="clr-namespace:Artemis.UI.Shared.DataModelVisualization.Shared;assembly=Artemis.UI.Shared"
|
||||||
|
xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.Debugger.Tabs.DataModel.DataModelDebugView">
|
x:Class="Artemis.UI.Screens.Debugger.Tabs.DataModel.DataModelDebugView">
|
||||||
<TextBlock>Data Model</TextBlock>
|
<UserControl.Resources>
|
||||||
|
<converters:TypeToStringConverter x:Key="TypeToStringConverter" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
<StackPanel>
|
||||||
|
<TreeView Items="{Binding MainDataModel.Children}">
|
||||||
|
<TreeView.Styles>
|
||||||
|
<Style Selector="TreeViewItem">
|
||||||
|
<Setter Property="IsExpanded" Value="{Binding IsVisualizationExpanded, Mode=TwoWay}" />
|
||||||
|
</Style>
|
||||||
|
</TreeView.Styles>
|
||||||
|
<TreeView.DataTemplates>
|
||||||
|
<TreeDataTemplate DataType="{x:Type dataModel:DataModelPropertiesViewModel}" ItemsSource="{Binding Children}">
|
||||||
|
<Grid ColumnDefinitions="Auto,Auto,*">
|
||||||
|
<StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0 0 5 0">
|
||||||
|
<TextBlock FontWeight="Bold">[</TextBlock>
|
||||||
|
<TextBlock FontWeight="Bold" Text="{Binding DisplayValueType, Converter={StaticResource TypeToStringConverter}, Mode=OneWay}" />
|
||||||
|
<TextBlock FontWeight="Bold">]</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="1" Text="{Binding PropertyDescription.Name}" ToolTip.Tip="{Binding PropertyDescription.Description}" />
|
||||||
|
<TextBlock Grid.Column="2"
|
||||||
|
Text="{Binding DisplayValue}"
|
||||||
|
FontFamily="Consolas"
|
||||||
|
HorizontalAlignment="Right" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</TreeDataTemplate>
|
||||||
|
<TreeDataTemplate DataType="{x:Type dataModel:DataModelListViewModel}" ItemsSource="{Binding ListChildren}">
|
||||||
|
<Grid ColumnDefinitions="Auto,Auto,*">
|
||||||
|
<StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0 0 5 0">
|
||||||
|
<TextBlock FontWeight="Bold">[</TextBlock>
|
||||||
|
<TextBlock FontWeight="Bold" Text="{Binding DisplayValueType, Converter={StaticResource TypeToStringConverter}, Mode=OneWay}" />
|
||||||
|
<TextBlock FontWeight="Bold">]</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
<TextBlock Grid.Column="1" Text="{Binding PropertyDescription.Name}" ToolTip.Tip="{Binding PropertyDescription.Description}" />
|
||||||
|
<TextBlock Grid.Column="2"
|
||||||
|
Text="{Binding CountDisplay, Mode=OneWay}"
|
||||||
|
FontFamily="Consolas"
|
||||||
|
HorizontalAlignment="Right" />
|
||||||
|
</Grid>
|
||||||
|
</TreeDataTemplate>
|
||||||
|
<TreeDataTemplate DataType="{x:Type dataModel:DataModelPropertyViewModel}">
|
||||||
|
<Grid ColumnDefinitions="Auto,Auto,*">
|
||||||
|
|
||||||
|
<!-- Value description -->
|
||||||
|
<StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0 0 5 0">
|
||||||
|
<TextBlock FontWeight="Bold">[</TextBlock>
|
||||||
|
<TextBlock FontWeight="Bold" Text="{Binding DisplayValueType, Converter={StaticResource TypeToStringConverter}, Mode=OneWay}" />
|
||||||
|
<TextBlock FontWeight="Bold">]</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
<TextBlock Grid.Column="1" Text="{Binding PropertyDescription.Name}" ToolTip.Tip="{Binding PropertyDescription.Description}" />
|
||||||
|
|
||||||
|
<!-- Value display -->
|
||||||
|
<ContentControl Grid.Column="2" Content="{Binding DisplayViewModel}" FontFamily="Consolas" />
|
||||||
|
</Grid>
|
||||||
|
</TreeDataTemplate>
|
||||||
|
<TreeDataTemplate DataType="{x:Type dataModel:DataModelListPropertyViewModel}">
|
||||||
|
<Grid ColumnDefinitions="Auto,Auto,*">
|
||||||
|
|
||||||
|
<!-- Value description -->
|
||||||
|
<StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0 0 5 0">
|
||||||
|
<TextBlock FontWeight="Bold">[</TextBlock>
|
||||||
|
<TextBlock FontWeight="Bold" Text="{Binding ListType, Converter={StaticResource TypeToStringConverter}, Mode=OneWay}" />
|
||||||
|
<TextBlock FontWeight="Bold">]</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Grid.Column="1" Orientation="Horizontal" Margin="0 0 5 0">
|
||||||
|
<TextBlock>List item [</TextBlock>
|
||||||
|
<TextBlock Text="{Binding Index, Mode=OneWay}" />
|
||||||
|
<TextBlock>]</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Value display -->
|
||||||
|
<ContentControl Grid.Column="2" Content="{Binding DisplayViewModel}" FontFamily="Consolas" />
|
||||||
|
</Grid>
|
||||||
|
</TreeDataTemplate>
|
||||||
|
|
||||||
|
<TreeDataTemplate DataType="{x:Type dataModel:DataModelEventViewModel}" ItemsSource="{Binding Children}">
|
||||||
|
<Grid ColumnDefinitions="Auto,Auto,*">
|
||||||
|
<StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0 0 5 0">
|
||||||
|
<TextBlock FontWeight="Bold">[</TextBlock>
|
||||||
|
<TextBlock FontWeight="Bold" Text="{Binding DisplayValueType, Converter={StaticResource TypeToStringConverter}, Mode=OneWay}" />
|
||||||
|
<TextBlock FontWeight="Bold">]</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
<TextBlock Grid.Column="1" Text="{Binding PropertyDescription.Name}" ToolTip.Tip="{Binding PropertyDescription.Description}" />
|
||||||
|
<TextBlock Grid.Column="2"
|
||||||
|
Text="{Binding CountDisplay, Mode=OneWay}"
|
||||||
|
FontFamily="Consolas"
|
||||||
|
HorizontalAlignment="Right" />
|
||||||
|
</Grid>
|
||||||
|
</TreeDataTemplate>
|
||||||
|
|
||||||
|
<TreeDataTemplate DataType="{x:Type dataModel:DataModelListPropertiesViewModel}" ItemsSource="{Binding DisplayViewModel.Children}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock>List item [</TextBlock>
|
||||||
|
<TextBlock Text="{Binding Index, Mode=OneWay}" />
|
||||||
|
<TextBlock>]</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</TreeDataTemplate>
|
||||||
|
</TreeView.DataTemplates>
|
||||||
|
</TreeView>
|
||||||
|
</StackPanel>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -1,16 +1,147 @@
|
|||||||
using Artemis.UI.Shared;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
using System.Timers;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Modules;
|
||||||
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.UI.Shared;
|
||||||
|
using Artemis.UI.Shared.DataModelVisualization.Shared;
|
||||||
|
using Artemis.UI.Shared.Services;
|
||||||
|
using DynamicData;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Debugger.Tabs.DataModel
|
namespace Artemis.UI.Screens.Debugger.Tabs.DataModel
|
||||||
{
|
{
|
||||||
public class DataModelDebugViewModel : ActivatableViewModelBase, IRoutableViewModel
|
public class DataModelDebugViewModel : ActivatableViewModelBase, IRoutableViewModel
|
||||||
{
|
{
|
||||||
public DataModelDebugViewModel(IScreen hostScreen)
|
private readonly IDataModelUIService _dataModelUIService;
|
||||||
|
private readonly IPluginManagementService _pluginManagementService;
|
||||||
|
private readonly Timer _updateTimer;
|
||||||
|
|
||||||
|
private bool _isModuleFilterEnabled;
|
||||||
|
private DataModelPropertiesViewModel? _mainDataModel;
|
||||||
|
private string? _propertySearch;
|
||||||
|
private Module? _selectedModule;
|
||||||
|
private bool _slowUpdates;
|
||||||
|
|
||||||
|
public DataModelDebugViewModel(IScreen hostScreen, IDataModelUIService dataModelUIService, IPluginManagementService pluginManagementService)
|
||||||
{
|
{
|
||||||
|
_dataModelUIService = dataModelUIService;
|
||||||
|
_pluginManagementService = pluginManagementService;
|
||||||
|
_updateTimer = new Timer(25);
|
||||||
|
_updateTimer.Elapsed += UpdateTimerOnElapsed;
|
||||||
|
|
||||||
HostScreen = hostScreen;
|
HostScreen = hostScreen;
|
||||||
|
Modules = new ObservableCollection<Module>();
|
||||||
|
|
||||||
|
this.WhenActivated(disposables =>
|
||||||
|
{
|
||||||
|
Observable.FromEventPattern<PluginFeatureEventArgs>(x => pluginManagementService.PluginFeatureEnabled += x, x => pluginManagementService.PluginFeatureEnabled -= x)
|
||||||
|
.Subscribe(d => PluginFeatureToggled(d.EventArgs.PluginFeature))
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
Observable.FromEventPattern<PluginFeatureEventArgs>(x => pluginManagementService.PluginFeatureDisabled += x, x => pluginManagementService.PluginFeatureDisabled -= x)
|
||||||
|
.Subscribe(d => PluginFeatureToggled(d.EventArgs.PluginFeature))
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
|
GetDataModel();
|
||||||
|
_updateTimer.Start();
|
||||||
|
Disposable.Create(() => _updateTimer.Stop()).DisposeWith(disposables);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public string UrlPathSegment => "data-model";
|
public string UrlPathSegment => "data-model";
|
||||||
public IScreen HostScreen { get; }
|
public IScreen HostScreen { get; }
|
||||||
|
|
||||||
|
public DataModelPropertiesViewModel? MainDataModel
|
||||||
|
{
|
||||||
|
get => _mainDataModel;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _mainDataModel, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? PropertySearch
|
||||||
|
{
|
||||||
|
get => _propertySearch;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _propertySearch, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SlowUpdates
|
||||||
|
{
|
||||||
|
get => _slowUpdates;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.RaiseAndSetIfChanged(ref _slowUpdates, value);
|
||||||
|
_updateTimer.Interval = _slowUpdates ? 500 : 25;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableCollection<Module> Modules { get; }
|
||||||
|
|
||||||
|
public Module? SelectedModule
|
||||||
|
{
|
||||||
|
get => _selectedModule;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.RaiseAndSetIfChanged(ref _selectedModule, value);
|
||||||
|
GetDataModel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsModuleFilterEnabled
|
||||||
|
{
|
||||||
|
get => _isModuleFilterEnabled;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.RaiseAndSetIfChanged(ref _isModuleFilterEnabled, value);
|
||||||
|
|
||||||
|
if (!IsModuleFilterEnabled)
|
||||||
|
SelectedModule = null;
|
||||||
|
else
|
||||||
|
GetDataModel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void UpdateTimerOnElapsed(object sender, ElapsedEventArgs e)
|
||||||
|
{
|
||||||
|
if (MainDataModel == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lock (MainDataModel)
|
||||||
|
{
|
||||||
|
MainDataModel.Update(_dataModelUIService, new DataModelUpdateConfiguration(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PluginFeatureToggled(PluginFeature pluginFeature)
|
||||||
|
{
|
||||||
|
if (pluginFeature is Module)
|
||||||
|
PopulateModules();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetDataModel()
|
||||||
|
{
|
||||||
|
MainDataModel = SelectedModule != null
|
||||||
|
? _dataModelUIService.GetPluginDataModelVisualization(new List<Module>() { SelectedModule }, false)
|
||||||
|
: _dataModelUIService.GetMainDataModelVisualization();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PopulateModules()
|
||||||
|
{
|
||||||
|
Modules.Clear();
|
||||||
|
Modules.AddRange(_pluginManagementService.GetFeaturesOfType<Module>().Where(p => p.IsEnabled).OrderBy(m => m.Info.Name));
|
||||||
|
|
||||||
|
if (MainDataModel == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (SelectedModule == null)
|
||||||
|
{
|
||||||
|
if (MainDataModel != null)
|
||||||
|
_dataModelUIService.UpdateModules(MainDataModel);
|
||||||
|
}
|
||||||
|
else if (!SelectedModule.IsEnabled)
|
||||||
|
SelectedModule = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4,13 +4,26 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.Debugger.Tabs.Render.RenderDebugView">
|
x:Class="Artemis.UI.Screens.Debugger.Tabs.Render.RenderDebugView">
|
||||||
<Grid Margin="12">
|
<StackPanel>
|
||||||
<Grid.RowDefinitions>
|
<TextBlock Classes="h3">Render</TextBlock>
|
||||||
<RowDefinition Height="Auto"/>
|
<TextBlock TextWrapping="Wrap">
|
||||||
<RowDefinition Height="*"/>
|
On this page you can view what Artemis renders to devices in real time. Artemis will overlay this image on your devices, taking the average of each pixel covering a LED, resulting the image appearing on your devices.
|
||||||
</Grid.RowDefinitions>
|
</TextBlock>
|
||||||
<TextBlock>Render</TextBlock>
|
<TextBlock TextWrapping="Wrap" Classes="subtitle" Margin="0 10">
|
||||||
|
Please note that having this window open can have a performance impact on your system.
|
||||||
|
</TextBlock>
|
||||||
|
|
||||||
<Image Source="{Binding CurrentFrame}" Grid.Row="1"></Image>
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
|
||||||
</Grid>
|
<TextBlock Text="FPS: " />
|
||||||
|
<TextBlock FontWeight="Bold" Text="{Binding CurrentFps}" />
|
||||||
|
<TextBlock Text=" at " />
|
||||||
|
<TextBlock Text="{Binding RenderWidth}" />
|
||||||
|
<TextBlock Text="x" />
|
||||||
|
<TextBlock Text="{Binding RenderHeight}" />
|
||||||
|
<TextBlock Text=" - Renderer: "></TextBlock>
|
||||||
|
<TextBlock Text="{Binding Renderer}"></TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<Image Source="{Binding CurrentFrame}" />
|
||||||
|
</StackPanel>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -1,9 +1,15 @@
|
|||||||
using System.IO;
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
|
using System.Reflection.Metadata.Ecma335;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Media.Imaging;
|
||||||
|
using Avalonia.Platform;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
@ -12,11 +18,9 @@ namespace Artemis.UI.Screens.Debugger.Tabs.Render
|
|||||||
public class RenderDebugViewModel : ActivatableViewModelBase, IRoutableViewModel
|
public class RenderDebugViewModel : ActivatableViewModelBase, IRoutableViewModel
|
||||||
{
|
{
|
||||||
private readonly ICoreService _coreService;
|
private readonly ICoreService _coreService;
|
||||||
private readonly Timer _fpsTimer;
|
|
||||||
private double _currentFps;
|
private double _currentFps;
|
||||||
|
|
||||||
private SKImage? _currentFrame;
|
private Bitmap? _currentFrame;
|
||||||
private int _frames;
|
|
||||||
private string? _frameTargetPath;
|
private string? _frameTargetPath;
|
||||||
private string _renderer;
|
private string _renderer;
|
||||||
private int _renderHeight;
|
private int _renderHeight;
|
||||||
@ -25,10 +29,7 @@ namespace Artemis.UI.Screens.Debugger.Tabs.Render
|
|||||||
public RenderDebugViewModel(DebugViewModel hostScreen, ICoreService coreService)
|
public RenderDebugViewModel(DebugViewModel hostScreen, ICoreService coreService)
|
||||||
{
|
{
|
||||||
HostScreen = hostScreen;
|
HostScreen = hostScreen;
|
||||||
|
|
||||||
_coreService = coreService;
|
_coreService = coreService;
|
||||||
_fpsTimer = new Timer(1000);
|
|
||||||
_fpsTimer.Start();
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
@ -37,7 +38,7 @@ namespace Artemis.UI.Screens.Debugger.Tabs.Render
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public SKImage? CurrentFrame
|
public Bitmap? CurrentFrame
|
||||||
{
|
{
|
||||||
get => _currentFrame;
|
get => _currentFrame;
|
||||||
set => this.RaiseAndSetIfChanged(ref _currentFrame, value);
|
set => this.RaiseAndSetIfChanged(ref _currentFrame, value);
|
||||||
@ -69,21 +70,18 @@ namespace Artemis.UI.Screens.Debugger.Tabs.Render
|
|||||||
|
|
||||||
private void HandleActivation()
|
private void HandleActivation()
|
||||||
{
|
{
|
||||||
|
Renderer = Constants.ManagedGraphicsContext != null ? Constants.ManagedGraphicsContext.GetType().Name : "Software";
|
||||||
_coreService.FrameRendered += CoreServiceOnFrameRendered;
|
_coreService.FrameRendered += CoreServiceOnFrameRendered;
|
||||||
_fpsTimer.Elapsed += FpsTimerOnElapsed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleDeactivation()
|
private void HandleDeactivation()
|
||||||
{
|
{
|
||||||
_coreService.FrameRendered -= CoreServiceOnFrameRendered;
|
_coreService.FrameRendered -= CoreServiceOnFrameRendered;
|
||||||
_fpsTimer.Elapsed -= FpsTimerOnElapsed;
|
|
||||||
_fpsTimer.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CoreServiceOnFrameRendered(object? sender, FrameRenderedEventArgs e)
|
private void CoreServiceOnFrameRendered(object? sender, FrameRenderedEventArgs e)
|
||||||
{
|
{
|
||||||
_frames++;
|
CurrentFps = _coreService.FrameRate;
|
||||||
|
|
||||||
using SKImage skImage = e.Texture.Surface.Snapshot();
|
using SKImage skImage = e.Texture.Surface.Snapshot();
|
||||||
SKImageInfo bitmapInfo = e.Texture.ImageInfo;
|
SKImageInfo bitmapInfo = e.Texture.ImageInfo;
|
||||||
|
|
||||||
@ -103,15 +101,13 @@ namespace Artemis.UI.Screens.Debugger.Tabs.Render
|
|||||||
RenderHeight = bitmapInfo.Height;
|
RenderHeight = bitmapInfo.Height;
|
||||||
RenderWidth = bitmapInfo.Width;
|
RenderWidth = bitmapInfo.Width;
|
||||||
|
|
||||||
CurrentFrame = e.Texture.Surface.Snapshot();
|
// TODO: This performs well enough but look into something else
|
||||||
|
using (SKData data = skImage.Encode(SKEncodedImageFormat.Png, 100))
|
||||||
|
{
|
||||||
|
CurrentFrame = new Bitmap(data.AsStream());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FpsTimerOnElapsed(object sender, ElapsedEventArgs e)
|
|
||||||
{
|
|
||||||
CurrentFps = _frames;
|
|
||||||
Renderer = Constants.ManagedGraphicsContext != null ? Constants.ManagedGraphicsContext.GetType().Name : "Software";
|
|
||||||
_frames = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string UrlPathSegment => "render";
|
public string UrlPathSegment => "render";
|
||||||
public IScreen HostScreen { get; }
|
public IScreen HostScreen { get; }
|
||||||
|
|||||||
@ -0,0 +1,8 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Artemis.UI.Screens.Debugger.Tabs.Settings.DebugSettingsView">
|
||||||
|
<TextBlock>Settings</TextBlock>
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Debugger.Tabs.Settings
|
||||||
|
{
|
||||||
|
public class DebugSettingsView : ReactiveUserControl<DebugSettingsViewModel>
|
||||||
|
{
|
||||||
|
public DebugSettingsView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
using Artemis.UI.Shared;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Debugger.Tabs.Settings
|
||||||
|
{
|
||||||
|
public class DebugSettingsViewModel : ActivatableViewModelBase, IRoutableViewModel
|
||||||
|
{
|
||||||
|
public DebugSettingsViewModel(IScreen hostScreen)
|
||||||
|
{
|
||||||
|
HostScreen = hostScreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string UrlPathSegment => "logs";
|
||||||
|
public IScreen HostScreen { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user