From 72c2dfa0d70a56f3da2a94afadfd778091a58d1a Mon Sep 17 00:00:00 2001
From: Software Antics <50978201+softwareantics@users.noreply.github.com>
Date: Sun, 3 Dec 2023 00:48:08 +1100
Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Remove=20Entity=20Component=20from?=
=?UTF-8?q?=20Entity=20(#286)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Initial
* Added unit tests and fixed up issues.
* Added documentation
---
FinalEngine.Editor.Desktop/App.xaml | 1 +
.../Controls/Common/IconButton.xaml | 7 +
.../Controls/Common/IconButton.xaml.cs | 34 ++++
.../FinalEngine.Editor.Desktop.csproj | 7 +
.../Resources/Images/Icons/Settings.png | Bin 0 -> 778 bytes
.../Styles/Controls/IconButtonStyle.xaml | 27 ++++
.../Views/Inspectors/EntityComponentView.xaml | 17 +-
.../FinalEngine.Editor.ViewModels.csproj | 1 -
.../Inspectors/EntityComponentViewModel.cs | 94 +++++++++--
.../Inspectors/EntityInspectorViewModel.cs | 70 ++++++--
.../Inspectors/IEntityComponentViewModel.cs | 31 ++--
.../Inspectors/PropertiesToolViewModel.cs | 2 +-
.../Entities/EntityModifiedMessage.cs | 36 +++++
.../Core/Input/Mouse/MouseTests.cs | 15 --
.../Services/Rendering/SceneRendererTests.cs | 43 ++++-
.../EntityComponentViewModelTests.cs | 152 +++++++++++++++---
.../EntityInspectorViewModelTests.cs | 57 ++++++-
.../Mocks/EntityComponentBoolean.cs | 2 +-
.../PropertiesToolViewModelTests.cs | 8 +-
FinalEngine.Tests/FinalEngine.Tests.csproj | 1 -
.../OpenGL/OpenGLRenderContextTests.cs | 29 ----
FinalEngine.sln | 1 -
test.txt | 1 -
23 files changed, 513 insertions(+), 123 deletions(-)
create mode 100644 FinalEngine.Editor.Desktop/Controls/Common/IconButton.xaml
create mode 100644 FinalEngine.Editor.Desktop/Controls/Common/IconButton.xaml.cs
create mode 100644 FinalEngine.Editor.Desktop/Resources/Images/Icons/Settings.png
create mode 100644 FinalEngine.Editor.Desktop/Styles/Controls/IconButtonStyle.xaml
create mode 100644 FinalEngine.Editor.ViewModels/Messages/Entities/EntityModifiedMessage.cs
delete mode 100644 test.txt
diff --git a/FinalEngine.Editor.Desktop/App.xaml b/FinalEngine.Editor.Desktop/App.xaml
index 9ae18f29..3c353475 100644
--- a/FinalEngine.Editor.Desktop/App.xaml
+++ b/FinalEngine.Editor.Desktop/App.xaml
@@ -19,6 +19,7 @@
+
diff --git a/FinalEngine.Editor.Desktop/Controls/Common/IconButton.xaml b/FinalEngine.Editor.Desktop/Controls/Common/IconButton.xaml
new file mode 100644
index 00000000..f850d18c
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Controls/Common/IconButton.xaml
@@ -0,0 +1,7 @@
+
diff --git a/FinalEngine.Editor.Desktop/Controls/Common/IconButton.xaml.cs b/FinalEngine.Editor.Desktop/Controls/Common/IconButton.xaml.cs
new file mode 100644
index 00000000..70008906
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Controls/Common/IconButton.xaml.cs
@@ -0,0 +1,34 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Controls.Common;
+
+using System.Windows.Controls;
+using System.Windows.Media;
+
+///
+/// Interaction logic for IconButton.xaml.
+///
+public partial class IconButton : Button
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public IconButton()
+ {
+ this.InitializeComponent();
+ }
+
+ ///
+ /// Gets or sets the URI source for the icon.
+ ///
+ ///
+ /// The URI source for the icon.
+ ///
+ public ImageSource UriSource
+ {
+ get { return this.image.Source; }
+ set { this.image.Source = value; }
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj b/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj
index 68d17cee..a739a538 100644
--- a/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj
+++ b/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj
@@ -14,6 +14,7 @@
+
@@ -48,6 +49,12 @@
+
+
+ Never
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Resources/Images/Icons/Settings.png b/FinalEngine.Editor.Desktop/Resources/Images/Icons/Settings.png
new file mode 100644
index 0000000000000000000000000000000000000000..2f263a293a47c3b1b961a3906c039c72a6483173
GIT binary patch
literal 778
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl
z_H+M9WCij$3p^r=85sBugD~Uq{1quc4c9zf978PpmrnBaW(pK(n;W<>)jPU{OGwv9
zvuA-q(}w*I7Ww9hG&gM%b!^R5R{Eu|!FBd8#
A3uIj?%WHhL68ieOJ*-%XKK^iDJqBTJ@Jtj@4Y`?xl>Dh{n&_5kbvS-y#oL
zc)Z@V&%u#t$pPcZ^QX*LP-niB;KOxf4O`5N#zP)bd1kZ2H*h|8`6~Yj_6gsWEWMegZ(nFK
z-SsuYn(nm5PwXe3AJhyoU+VVev-F%sPBoRxZQP6g*u-v#uG!$6H`h8*DlJNM#?^-V
z#qv?ivU=0C8Ri?Wl;;bYlls@LM*XN~|MAV;_su5RFAC9G%M_gWbh$OtYr+3%X1A>y
z{#xCeDX~-r80`$6u6{1-oD!OnICtnMi3;vy?5TPmKjUVd;7s9(o`Rap!fD@9($kmU
z3tezCXPsF0(f0=uR$txqVve+*W-artkgewDKYw0Tb@0r*y!?FoU$fI^y{%YgT`lzQ
zY8{j1ju)D9zXWdq+M-(G8c~vxSdwa$T$Bo=7>o>z40H|5b&V`T42-Od4Xg|dv<*Py
Zw&(?~P&DM`r(~v8;?{7SO(G20BLIx3Jz4+&
literal 0
HcmV?d00001
diff --git a/FinalEngine.Editor.Desktop/Styles/Controls/IconButtonStyle.xaml b/FinalEngine.Editor.Desktop/Styles/Controls/IconButtonStyle.xaml
new file mode 100644
index 00000000..a4439bda
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Styles/Controls/IconButtonStyle.xaml
@@ -0,0 +1,27 @@
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Inspectors/EntityComponentView.xaml b/FinalEngine.Editor.Desktop/Views/Inspectors/EntityComponentView.xaml
index 8f9c76e7..f1946f6e 100644
--- a/FinalEngine.Editor.Desktop/Views/Inspectors/EntityComponentView.xaml
+++ b/FinalEngine.Editor.Desktop/Views/Inspectors/EntityComponentView.xaml
@@ -7,11 +7,26 @@
xmlns:dtv="clr-namespace:FinalEngine.Editor.Desktop.Views.Editing.DataTypes"
xmlns:dt="clr-namespace:FinalEngine.Editor.ViewModels.Editing.DataTypes;assembly=FinalEngine.Editor.ViewModels"
xmlns:vm="clr-namespace:FinalEngine.Editor.ViewModels.Inspectors;assembly=FinalEngine.Editor.ViewModels"
+ xmlns:c="clr-namespace:FinalEngine.Editor.Desktop.Controls.Common"
d:DataContext="{d:DesignInstance Type=vm:EntityComponentViewModel}"
mc:Ignorable="d">
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
false
true
x64
- true
diff --git a/FinalEngine.Editor.ViewModels/Inspectors/EntityComponentViewModel.cs b/FinalEngine.Editor.ViewModels/Inspectors/EntityComponentViewModel.cs
index d25d080e..be5bf8b0 100644
--- a/FinalEngine.Editor.ViewModels/Inspectors/EntityComponentViewModel.cs
+++ b/FinalEngine.Editor.ViewModels/Inspectors/EntityComponentViewModel.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) Software Antics. All rights reserved.
+// Copyright (c) Software Antics. All rights reserved.
//
namespace FinalEngine.Editor.ViewModels.Inspectors;
@@ -13,47 +13,75 @@ namespace FinalEngine.Editor.ViewModels.Inspectors;
using System.Windows.Input;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
+using CommunityToolkit.Mvvm.Messaging;
using FinalEngine.ECS;
+using FinalEngine.ECS.Components.Core;
using FinalEngine.Editor.ViewModels.Editing.DataTypes;
using FinalEngine.Editor.ViewModels.Exceptions.Inspectors;
+using FinalEngine.Editor.ViewModels.Messages.Entities;
///
-/// Provides a standard implementation of an .
+/// Provides a standard implementation of an .
///
-///
-///
+///
+///
public sealed class EntityComponentViewModel : ObservableObject, IEntityComponentViewModel
{
///
- /// The property view models associated with this component model.
+ /// The component to model.
+ ///
+ private readonly IEntityComponent component;
+
+ ///
+ /// The entity that contains the component to be modeled.
+ ///
+ private readonly Entity entity;
+
+ ///
+ /// The messenger, used to notify other views when the entity has been modified.
+ ///
+ private readonly IMessenger messenger;
+
+ ///
+ /// The property view models associated with this component model.
///
private readonly ObservableCollection propertyViewModels;
///
- /// Indicates whether the components properties are visible.
+ /// Indicates whether the components properties are visible.
///
private bool isVisible;
///
- /// The toggle command.
+ /// The remove command, used to remove the component from the entity.
+ ///
+ private ICommand? removeCommand;
+
+ ///
+ /// The toggle command.
///
private ICommand? toggleCommand;
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
+ ///
+ /// The messenger.
+ ///
///
- /// The component to be modelled.
+ /// The component to be modeled.
+ ///
+ ///
+ /// The entity that contains the specified .
///
///
- /// The specified parameter cannot be null.
+ /// The specified , or parameter cannot be null.
///
- public EntityComponentViewModel(IEntityComponent component)
+ public EntityComponentViewModel(IMessenger messenger, Entity entity, IEntityComponent component)
{
- if (component == null)
- {
- throw new ArgumentNullException(nameof(component));
- }
+ this.messenger = messenger ?? throw new ArgumentNullException(nameof(messenger));
+ this.entity = entity ?? throw new ArgumentNullException(nameof(entity));
+ this.component = component ?? throw new ArgumentNullException(nameof(component));
this.propertyViewModels = new ObservableCollection();
@@ -138,6 +166,12 @@ public ICollection PropertyViewModels
get { return this.propertyViewModels; }
}
+ ///
+ public ICommand RemoveCommand
+ {
+ get { return this.removeCommand ??= new RelayCommand(this.Remove, this.CanRemove); }
+ }
+
///
public ICommand ToggleCommand
{
@@ -145,7 +179,35 @@ public ICommand ToggleCommand
}
///
- /// Toggles the visibility of the components properties.
+ /// Determines whether the component can be removed from the entity.
+ ///
+ ///
+ /// true if the component can be removed from the entity; otherwise, false.
+ ///
+ private bool CanRemove()
+ {
+ return this.component.GetType() != typeof(TagComponent);
+ }
+
+ ///
+ /// Removes the component from the entity and notifies other views that the entity has been modified.
+ ///
+ ///
+ /// The provided to this instance does not contain an of the required type.
+ ///
+ private void Remove()
+ {
+ if (!this.entity.ContainsComponent(this.component))
+ {
+ throw new InvalidOperationException($"The {nameof(Entity)} provided to this instance does not contain an {nameof(IEntityComponent)} of type: '{this.component.GetType()}'");
+ }
+
+ this.entity.RemoveComponent(this.component);
+ this.messenger.Send(new EntityModifiedMessage(this.entity));
+ }
+
+ ///
+ /// Toggles the visibility of the components properties.
///
private void Toggle()
{
diff --git a/FinalEngine.Editor.ViewModels/Inspectors/EntityInspectorViewModel.cs b/FinalEngine.Editor.ViewModels/Inspectors/EntityInspectorViewModel.cs
index 85adc5f9..65b88fb9 100644
--- a/FinalEngine.Editor.ViewModels/Inspectors/EntityInspectorViewModel.cs
+++ b/FinalEngine.Editor.ViewModels/Inspectors/EntityInspectorViewModel.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) Software Antics. All rights reserved.
+// Copyright (c) Software Antics. All rights reserved.
//
namespace FinalEngine.Editor.ViewModels.Inspectors;
@@ -8,43 +8,53 @@ namespace FinalEngine.Editor.ViewModels.Inspectors;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Messaging;
using FinalEngine.ECS;
+using FinalEngine.Editor.ViewModels.Messages.Entities;
///
-/// Provides a standard implementation of an .
+/// Provides a standard implementation of an .
///
-///
-///
+///
+///
public sealed class EntityInspectorViewModel : ObservableObject, IEntityInspectorViewModel
{
///
- /// The component view models.
+ /// The component view models.
///
private readonly ObservableCollection componentViewModels;
///
- /// The entity being inspected.
+ /// The entity being inspected.
///
private readonly Entity entity;
///
- /// Initializes a new instance of the class.
+ /// The messenger.
///
+ private readonly IMessenger messenger;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The messenger.
+ ///
///
- /// The entity to be inspected.
+ /// The entity to be inspected.
///
///
- /// The specified parameter cannot be null.
+ /// The specified parameter cannot be null.
///
- public EntityInspectorViewModel(Entity entity)
+ public EntityInspectorViewModel(IMessenger messenger, Entity entity)
{
+ this.messenger = messenger ?? throw new ArgumentNullException(nameof(messenger));
this.entity = entity ?? throw new ArgumentNullException(nameof(entity));
this.componentViewModels = new ObservableCollection();
- foreach (var component in this.entity.Components)
- {
- this.componentViewModels.Add(new EntityComponentViewModel(component));
- }
+ this.messenger.Register(this, this.HandleEntityModified);
+
+ this.InitializeEntityComponents();
}
///
@@ -52,4 +62,36 @@ public ICollection ComponentViewModels
{
get { return this.componentViewModels; }
}
+
+ ///
+ /// Handles the and initializes the entity component view models.
+ ///
+ ///
+ /// The recipient.
+ ///
+ ///
+ /// The message.
+ ///
+ private void HandleEntityModified(object recipient, EntityModifiedMessage message)
+ {
+ if (!ReferenceEquals(this.entity, message.Entity))
+ {
+ return;
+ }
+
+ this.InitializeEntityComponents();
+ }
+
+ ///
+ /// Initializes the entity component view models for the .
+ ///
+ private void InitializeEntityComponents()
+ {
+ this.componentViewModels.Clear();
+
+ foreach (var component in this.entity.Components)
+ {
+ this.componentViewModels.Add(new EntityComponentViewModel(this.messenger, this.entity, component));
+ }
+ }
}
diff --git a/FinalEngine.Editor.ViewModels/Inspectors/IEntityComponentViewModel.cs b/FinalEngine.Editor.ViewModels/Inspectors/IEntityComponentViewModel.cs
index e3b9d0c7..361566d2 100644
--- a/FinalEngine.Editor.ViewModels/Inspectors/IEntityComponentViewModel.cs
+++ b/FinalEngine.Editor.ViewModels/Inspectors/IEntityComponentViewModel.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) Software Antics. All rights reserved.
+// Copyright (c) Software Antics. All rights reserved.
//
namespace FinalEngine.Editor.ViewModels.Inspectors;
@@ -10,12 +10,12 @@ namespace FinalEngine.Editor.ViewModels.Inspectors;
using FinalEngine.ECS;
///
-/// Defines an interface that represents a model of an entity component view.
+/// Defines an interface that represents a model of an entity component view.
///
public interface IEntityComponentViewModel
{
///
- /// Gets a value indicating whether the components properties are visible.
+ /// Gets a value indicating whether the components properties are visible.
///
///
/// true if the components properties are visible; otherwise, false.
@@ -23,29 +23,40 @@ public interface IEntityComponentViewModel
bool IsVisible { get; }
///
- /// Gets the name of the .
+ /// Gets the name of the .
///
///
- /// The name of the .
+ /// The name of the .
///
string Name { get; }
///
- /// Gets the property view models.
+ /// Gets the property view models.
///
///
- /// The property view models.
+ /// The property view models.
///
ICollection PropertyViewModels { get; }
///
- /// Gets the toggle command.
+ /// Gets the remove command.
///
///
- /// The toggle command.
+ /// The remove command.
///
///
- /// The is used to toggle the visibility of the components properties.
+ /// The is used to remove an from an .
+ ///
+ ICommand RemoveCommand { get; }
+
+ ///
+ /// Gets the toggle command.
+ ///
+ ///
+ /// The toggle command.
+ ///
+ ///
+ /// The is used to toggle the visibility of the components properties.
///
ICommand ToggleCommand { get; }
}
diff --git a/FinalEngine.Editor.ViewModels/Inspectors/PropertiesToolViewModel.cs b/FinalEngine.Editor.ViewModels/Inspectors/PropertiesToolViewModel.cs
index 68d243d3..f81e5839 100644
--- a/FinalEngine.Editor.ViewModels/Inspectors/PropertiesToolViewModel.cs
+++ b/FinalEngine.Editor.ViewModels/Inspectors/PropertiesToolViewModel.cs
@@ -96,7 +96,7 @@ private void HandleEntitySelected(object recipient, EntitySelectedMessage messag
this.logger.LogInformation($"Changing properties view to: '{nameof(EntityInspectorViewModel)}'.");
this.Title = "Entity Inspector";
- this.CurrentViewModel = new EntityInspectorViewModel(message.Entity);
+ this.CurrentViewModel = new EntityInspectorViewModel(this.messenger, message.Entity);
}
///
diff --git a/FinalEngine.Editor.ViewModels/Messages/Entities/EntityModifiedMessage.cs b/FinalEngine.Editor.ViewModels/Messages/Entities/EntityModifiedMessage.cs
new file mode 100644
index 00000000..21aa4cfe
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Messages/Entities/EntityModifiedMessage.cs
@@ -0,0 +1,36 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Messages.Entities;
+
+using System;
+using FinalEngine.ECS;
+
+///
+/// Provides a message that should be published when an has been modified.
+///
+public sealed class EntityModifiedMessage
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The entity that has been modified.
+ ///
+ ///
+ /// The specified parameter cannot be null.
+ ///
+ public EntityModifiedMessage(Entity entity)
+ {
+ this.Entity = entity ?? throw new ArgumentNullException(nameof(entity));
+ }
+
+ ///
+ /// Gets the entity that has been modified.
+ ///
+ ///
+ /// The entity that has been modified.
+ ///
+ public Entity Entity { get; }
+}
diff --git a/FinalEngine.Tests/Core/Input/Mouse/MouseTests.cs b/FinalEngine.Tests/Core/Input/Mouse/MouseTests.cs
index da87de49..4eac2124 100644
--- a/FinalEngine.Tests/Core/Input/Mouse/MouseTests.cs
+++ b/FinalEngine.Tests/Core/Input/Mouse/MouseTests.cs
@@ -70,21 +70,6 @@ public void DeltaShouldReturnDeviceLocationDeltaWhenDeviceIsNotNull()
this.mouseDevice.VerifyGet(x => x.LocationDelta, Times.Once);
}
- [Test]
- public void DeltaShouldReturnPointEmptyWhenDeviceIsNull()
- {
- // Arrange
- var mouse = new Mouse(null);
- PointF expected = Point.Empty;
-
- // Act
- var actual = mouse.Delta;
- mouse.Dispose();
-
- // Assert
- Assert.AreEqual(expected, actual);
- }
-
[Test]
public void DeviceButtonDownShouldThrowArgumentNullExceptionWhenEventDataIsNull()
{
diff --git a/FinalEngine.Tests/Editor/Common/Services/Rendering/SceneRendererTests.cs b/FinalEngine.Tests/Editor/Common/Services/Rendering/SceneRendererTests.cs
index 14352237..4d489957 100644
--- a/FinalEngine.Tests/Editor/Common/Services/Rendering/SceneRendererTests.cs
+++ b/FinalEngine.Tests/Editor/Common/Services/Rendering/SceneRendererTests.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) Software Antics. All rights reserved.
+// Copyright (c) Software Antics. All rights reserved.
//
namespace FinalEngine.Tests.Editor.Common.Services.Rendering;
@@ -15,6 +15,8 @@ namespace FinalEngine.Tests.Editor.Common.Services.Rendering;
[TestFixture]
public sealed class SceneRendererTests
{
+ private Mock pipeline;
+
private Mock renderDevice;
private Mock scene;
@@ -23,13 +25,23 @@ public sealed class SceneRendererTests
private SceneRenderer sceneRenderer;
+ [Test]
+ public void ConstructorShouldThrowArgumentNullExceptionWhenPipelineIsNull()
+ {
+ // Act and assert
+ Assert.Throws(() =>
+ {
+ new SceneRenderer(null, this.renderDevice.Object, this.sceneManager.Object);
+ });
+ }
+
[Test]
public void ConstructorShouldThrowArgumentNullExceptionWhenRenderDeviceIsNull()
{
// Act and assert
Assert.Throws(() =>
{
- new SceneRenderer(null, this.sceneManager.Object);
+ new SceneRenderer(this.pipeline.Object, null, this.sceneManager.Object);
});
}
@@ -39,7 +51,7 @@ public void ConstructorShouldThrowArgumentNullExceptionWhenSceneManagerIsNull()
// Act and assert
Assert.Throws(() =>
{
- new SceneRenderer(this.renderDevice.Object, null);
+ new SceneRenderer(this.pipeline.Object, this.renderDevice.Object, null);
});
}
@@ -53,6 +65,27 @@ public void RenderShouldInvokeActiveSceneRenderWhenInvoked()
this.scene.Verify(x => x.Render(), Times.Once);
}
+ [Test]
+ public void RenderShouldInvokePipelineInitializedOnceWhenInvokedMoreThanOnce()
+ {
+ // Act
+ this.sceneRenderer.Render();
+ this.sceneRenderer.Render();
+
+ // Assert
+ this.pipeline.Verify(x => x.Initialize(), Times.Once);
+ }
+
+ [Test]
+ public void RenderShouldInvokePipelineInitializedWhenInvoked()
+ {
+ // Act
+ this.sceneRenderer.Render();
+
+ // Assert
+ this.pipeline.Verify(x => x.Initialize(), Times.Once);
+ }
+
[Test]
public void RenderShouldInvokeRenderDeviceClearWhenInvoked()
{
@@ -68,10 +101,12 @@ public void Setup()
{
this.sceneManager = new Mock();
this.renderDevice = new Mock();
+ this.pipeline = new Mock();
+
this.scene = new Mock();
this.sceneManager.SetupGet(x => x.ActiveScene).Returns(this.scene.Object);
- this.sceneRenderer = new SceneRenderer(this.renderDevice.Object, this.sceneManager.Object);
+ this.sceneRenderer = new SceneRenderer(this.pipeline.Object, this.renderDevice.Object, this.sceneManager.Object);
}
}
diff --git a/FinalEngine.Tests/Editor/ViewModels/Inspectors/EntityComponentViewModelTests.cs b/FinalEngine.Tests/Editor/ViewModels/Inspectors/EntityComponentViewModelTests.cs
index 7d53497a..67d6e7b9 100644
--- a/FinalEngine.Tests/Editor/ViewModels/Inspectors/EntityComponentViewModelTests.cs
+++ b/FinalEngine.Tests/Editor/ViewModels/Inspectors/EntityComponentViewModelTests.cs
@@ -1,29 +1,38 @@
//
-// Copyright (c) Software Antics. All rights reserved.
+// Copyright (c) Software Antics. All rights reserved.
//
namespace FinalEngine.Tests.Editor.ViewModels.Inspectors;
using System;
using System.Linq;
+using CommunityToolkit.Mvvm.Messaging;
+using FinalEngine.ECS;
using FinalEngine.ECS.Components.Core;
using FinalEngine.Editor.ViewModels.Editing.DataTypes;
using FinalEngine.Editor.ViewModels.Exceptions.Inspectors;
using FinalEngine.Editor.ViewModels.Inspectors;
+using FinalEngine.Editor.ViewModels.Messages.Entities;
using FinalEngine.Tests.Editor.ViewModels.Inspectors.Mocks;
+using FinalEngine.Tests.Editor.ViewModels.Messages;
+using Moq;
using NUnit.Framework;
[TestFixture]
public sealed class EntityComponentViewModelTests
{
+ private Entity entity;
+
+ private Mock messenger;
+
[Test]
public void ConstructorShouldAddBooleanPropertyViewModelWhenComponentHasBoolean()
{
// Arrange
- var component = new EntityComponenBoolean();
+ var component = new EntityComponentBoolean();
// Act
- var viewModel = new EntityComponentViewModel(component);
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
// Assert
Assert.That(viewModel.PropertyViewModels.FirstOrDefault(), Is.TypeOf());
@@ -36,7 +45,7 @@ public void ConstructorShouldAddDoublePropertyViewModelWhenComponentHasDouble()
var component = new EntityComponentDouble();
// Act
- var viewModel = new EntityComponentViewModel(component);
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
// Assert
Assert.That(viewModel.PropertyViewModels.FirstOrDefault(), Is.TypeOf());
@@ -49,7 +58,7 @@ public void ConstructorShouldAddFloatPropertyViewModelWhenComponentHasFloat()
var component = new EntityComponentFloat();
// Act
- var viewModel = new EntityComponentViewModel(component);
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
// Assert
Assert.That(viewModel.PropertyViewModels.FirstOrDefault(), Is.TypeOf());
@@ -62,7 +71,7 @@ public void ConstructorShouldAddIntPropertyViewModelWhenComponentHasInteger()
var component = new EntityComponentInteger();
// Act
- var viewModel = new EntityComponentViewModel(component);
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
// Assert
Assert.That(viewModel.PropertyViewModels.FirstOrDefault(), Is.TypeOf());
@@ -75,7 +84,7 @@ public void ConstructorShouldAddPropertyViewModelWhenComponentDoesNotHaveBrowsab
var component = new TagComponent();
// Act
- var viewModel = new EntityComponentViewModel(component);
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
// Assert
Assert.That(viewModel.PropertyViewModels, Has.Count.EqualTo(1));
@@ -88,7 +97,7 @@ public void ConstructorShouldAddPropertyViewModelWhenComponentIsBrowseable()
var component = new EntityComponentBrowsable();
// Act
- var viewModel = new EntityComponentViewModel(component);
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
// Assert
Assert.That(viewModel.PropertyViewModels, Has.Count.EqualTo(1));
@@ -101,7 +110,7 @@ public void ConstructorShouldAddStringPropertyViewModelWhenComponentHasString()
var component = new EntityComponentString();
// Act
- var viewModel = new EntityComponentViewModel(component);
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
// Assert
Assert.That(viewModel.PropertyViewModels.FirstOrDefault(), Is.TypeOf());
@@ -114,7 +123,7 @@ public void ConstructorShouldAddVector2PropertyViewModelWhenComponentHasVector2(
var component = new EntityComponentVector2();
// Act
- var viewModel = new EntityComponentViewModel(component);
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
// Assert
Assert.That(viewModel.PropertyViewModels.FirstOrDefault(), Is.TypeOf());
@@ -127,7 +136,7 @@ public void ConstructorShouldAddVector3PropertyViewModelWhenComponentHasVector3(
var component = new EntityComponentVector3();
// Act
- var viewModel = new EntityComponentViewModel(component);
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
// Assert
Assert.That(viewModel.PropertyViewModels.FirstOrDefault(), Is.TypeOf());
@@ -140,7 +149,7 @@ public void ConstructorShouldAddVector4PropertyViewModelWhenComponentHasVector4(
var component = new EntityComponentVector4();
// Act
- var viewModel = new EntityComponentViewModel(component);
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
// Assert
Assert.That(viewModel.PropertyViewModels.FirstOrDefault(), Is.TypeOf());
@@ -153,7 +162,7 @@ public void ConstructorShouldNotAddPropertyViewModelWhenComponentNotBrowseable()
var component = new EntityComponentNotBrowsable();
// Act
- var viewModel = new EntityComponentViewModel(component);
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
// Assert
Assert.That(viewModel.PropertyViewModels, Is.Empty);
@@ -166,7 +175,7 @@ public void ConstructorShouldNotAddPropertyViewModelWhenPropertyHasNonPublicGett
var component = new EntityComponentPrivateGetter();
// Act
- var viewModel = new EntityComponentViewModel(component);
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
// Assert
Assert.That(viewModel.PropertyViewModels.Count, Is.Zero);
@@ -179,7 +188,7 @@ public void ConstructorShouldNotAddPropertyViewModelWhenPropertyHasNonPublicSett
var component = new EntityComponentPrivateSetter();
// Act
- var viewModel = new EntityComponentViewModel(component);
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
// Assert
Assert.That(viewModel.PropertyViewModels.Count, Is.Zero);
@@ -192,7 +201,7 @@ public void ConstructorShouldSetIsVisibleToTrueWhenInvoked()
var component = new TagComponent();
// Act
- var viewModel = new EntityComponentViewModel(component);
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
// Assert
Assert.That(viewModel.IsVisible, Is.True);
@@ -204,7 +213,27 @@ public void ConstructorShouldThrowArgumentNullExceptionWhenComponentIsNull()
// Act and assert
Assert.Throws(() =>
{
- new EntityComponentViewModel(null);
+ new EntityComponentViewModel(this.messenger.Object, this.entity, null);
+ });
+ }
+
+ [Test]
+ public void ConstructorShouldThrowArgumentNullExceptionWhenEntityIsNull()
+ {
+ // Act and assert
+ Assert.Throws(() =>
+ {
+ new EntityComponentViewModel(this.messenger.Object, null, new TagComponent());
+ });
+ }
+
+ [Test]
+ public void ConstructorShouldThrowArgumentNullExceptionWhenMessengerIsNull()
+ {
+ // Act and assert
+ Assert.Throws(() =>
+ {
+ new EntityComponentViewModel(null, this.entity, new TagComponent());
});
}
@@ -214,7 +243,7 @@ public void ConstructorShouldThrowPropertyTypeNotFoundExceptionWhenPropertyTypeI
// Act and assert
Assert.Throws(() =>
{
- new EntityComponentViewModel(new EntityComponentUnsupportedPropertyType());
+ new EntityComponentViewModel(this.messenger.Object, this.entity, new EntityComponentUnsupportedPropertyType());
});
}
@@ -228,7 +257,7 @@ public void NameShouldReturnTagComponentWhenInvoked()
};
string expected = component.GetType().Name;
- var viewModel = new EntityComponentViewModel(component);
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
// Act
string actual = viewModel.Name;
@@ -237,12 +266,93 @@ public void NameShouldReturnTagComponentWhenInvoked()
Assert.That(actual, Is.EqualTo(expected));
}
+ [Test]
+ public void RemoveCommandCanExecuteShouldReturnFalseWhenComponentIsTagComponent()
+ {
+ // Arrange
+ var component = new TagComponent();
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
+
+ // Act
+ bool actual = viewModel.RemoveCommand.CanExecute(null);
+
+ // Assert
+ Assert.That(actual, Is.False);
+ }
+
+ [Test]
+ public void RemoveCommandCanExecuteShouldReturnTrueWhenComponentIsNotTagComponent()
+ {
+ // Arrange
+ var component = new EntityComponentVector3();
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
+
+ // Act
+ bool actual = viewModel.RemoveCommand.CanExecute(null);
+
+ // Assert
+ Assert.That(actual, Is.True);
+ }
+
+ [Test]
+ public void RemoveCommandExecuteShouldRemoveComponentWhenComponentIsAddedToEntity()
+ {
+ // Arrange
+ var component = new EntityComponentBoolean();
+ this.entity.AddComponent(component);
+
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
+
+ // Act
+ viewModel.RemoveCommand.Execute(null);
+
+ // Assert
+ Assert.That(this.entity.ContainsComponent(component), Is.False);
+ }
+
+ [Test]
+ public void RemoveCommandExecuteShouldSendEntityModifiedMessageWhenComponentIsAddedToEntity()
+ {
+ // Arrange
+ var component = new EntityComponentBoolean();
+ this.entity.AddComponent(component);
+
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
+
+ // Act
+ viewModel.RemoveCommand.Execute(null);
+
+ // Assert
+ this.messenger.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Once);
+ }
+
+ [Test]
+ public void RemoveCommandExecuteShouldThrowInvalidOperationExceptionWhenComponentIsNotAddedToEntity()
+ {
+ // Arrange
+ var component = new EntityComponentBoolean();
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
+
+ // Act and assert
+ Assert.Throws(() =>
+ {
+ viewModel.RemoveCommand.Execute(null);
+ });
+ }
+
+ [SetUp]
+ public void Setup()
+ {
+ this.entity = new Entity();
+ this.messenger = new Mock();
+ }
+
[Test]
public void ToggleCommandShouldSetIsVisibleToFalseWhenIsVisibleIsTrue()
{
// Arrange
var component = new TagComponent();
- var viewModel = new EntityComponentViewModel(component);
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
// Act
viewModel.ToggleCommand.Execute(null);
@@ -256,7 +366,7 @@ public void ToggleCommandShouldSetIsVisibleToTrueWhenIsVisibleIsFalse()
{
// Arrange
var component = new TagComponent();
- var viewModel = new EntityComponentViewModel(component);
+ var viewModel = new EntityComponentViewModel(this.messenger.Object, this.entity, component);
viewModel.ToggleCommand.Execute(null);
diff --git a/FinalEngine.Tests/Editor/ViewModels/Inspectors/EntityInspectorViewModelTests.cs b/FinalEngine.Tests/Editor/ViewModels/Inspectors/EntityInspectorViewModelTests.cs
index 58b93549..c2a297c7 100644
--- a/FinalEngine.Tests/Editor/ViewModels/Inspectors/EntityInspectorViewModelTests.cs
+++ b/FinalEngine.Tests/Editor/ViewModels/Inspectors/EntityInspectorViewModelTests.cs
@@ -1,14 +1,17 @@
//
-// Copyright (c) Software Antics. All rights reserved.
+// Copyright (c) Software Antics. All rights reserved.
//
namespace FinalEngine.Tests.Editor.ViewModels.Inspectors;
using System;
using System.Linq;
+using CommunityToolkit.Mvvm.Messaging;
using FinalEngine.ECS;
using FinalEngine.ECS.Components.Core;
using FinalEngine.Editor.ViewModels.Inspectors;
+using FinalEngine.Editor.ViewModels.Messages.Entities;
+using FinalEngine.Tests.Editor.ViewModels.Inspectors.Mocks;
using NUnit.Framework;
[TestFixture]
@@ -16,6 +19,8 @@ public sealed class EntityInspectorViewModelTests
{
private Entity entity;
+ private IMessenger messenger;
+
private EntityInspectorViewModel viewModel;
[Test]
@@ -38,16 +43,60 @@ public void ComponentViewModelsShouldReturnEntityComponentViewModels()
Assert.That(actual, Is.AssignableFrom());
}
+ [Test]
+ public void ConstructorShouldRegisterEntityModifiedMessageWhenInvoked()
+ {
+ // Assert
+ this.messenger.IsRegistered(this.viewModel);
+ }
+
[Test]
public void ConstructorShouldThrowArgumentNullExceptionWhenEntityIsNull()
{
// Act and assert
Assert.Throws(() =>
{
- new EntityInspectorViewModel(null);
+ new EntityInspectorViewModel(this.messenger, null);
+ });
+ }
+
+ [Test]
+ public void ConstructorShouldThrowArgumentNullExceptionWhenMessengerIsNull()
+ {
+ // Act and assert
+ Assert.Throws(() =>
+ {
+ new EntityInspectorViewModel(null, this.entity);
});
}
+ [Test]
+ public void HandleEntityModifiedShouldNotRefreshComponentsWhenEntityIsNotSameEntity()
+ {
+ // Arrange
+ var entity = new Entity();
+ entity.AddComponent(new EntityComponentBoolean());
+
+ // Act
+ this.messenger.Send(new EntityModifiedMessage(entity));
+
+ // Assert
+ Assert.That(this.viewModel.ComponentViewModels.Count, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void HandleEntityModifiedShouldRefreshComponentsWhenEntityIsNotSameEntity()
+ {
+ // Arrange
+ this.entity.AddComponent(new EntityComponentBoolean());
+
+ // Act
+ this.messenger.Send(new EntityModifiedMessage(this.entity));
+
+ // Assert
+ Assert.That(this.viewModel.ComponentViewModels.Count, Is.EqualTo(2));
+ }
+
[SetUp]
public void Setup()
{
@@ -58,6 +107,8 @@ public void Setup()
Tag = "Tag",
});
- this.viewModel = new EntityInspectorViewModel(this.entity);
+ this.messenger = WeakReferenceMessenger.Default;
+
+ this.viewModel = new EntityInspectorViewModel(this.messenger, this.entity);
}
}
diff --git a/FinalEngine.Tests/Editor/ViewModels/Inspectors/Mocks/EntityComponentBoolean.cs b/FinalEngine.Tests/Editor/ViewModels/Inspectors/Mocks/EntityComponentBoolean.cs
index db9707df..f1ec56a6 100644
--- a/FinalEngine.Tests/Editor/ViewModels/Inspectors/Mocks/EntityComponentBoolean.cs
+++ b/FinalEngine.Tests/Editor/ViewModels/Inspectors/Mocks/EntityComponentBoolean.cs
@@ -6,7 +6,7 @@ namespace FinalEngine.Tests.Editor.ViewModels.Inspectors.Mocks;
using FinalEngine.ECS;
-public sealed class EntityComponenBoolean : IEntityComponent
+public sealed class EntityComponentBoolean : IEntityComponent
{
public bool Test { get; set; }
}
diff --git a/FinalEngine.Tests/Editor/ViewModels/Inspectors/PropertiesToolViewModelTests.cs b/FinalEngine.Tests/Editor/ViewModels/Inspectors/PropertiesToolViewModelTests.cs
index 840dbbdc..739f54f0 100644
--- a/FinalEngine.Tests/Editor/ViewModels/Inspectors/PropertiesToolViewModelTests.cs
+++ b/FinalEngine.Tests/Editor/ViewModels/Inspectors/PropertiesToolViewModelTests.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) Software Antics. All rights reserved.
+// Copyright (c) Software Antics. All rights reserved.
//
namespace FinalEngine.Tests.Editor.ViewModels.Inspectors;
@@ -22,7 +22,7 @@ public sealed class PropertiesToolViewModelTests
private PropertiesToolViewModel viewModel;
[Test]
- public void COnstructorShouldRegisterEntityDeletedMessageWhenInvoked()
+ public void ConstructorShouldRegisterEntityDeletedMessageWhenInvoked()
{
// Assert
Assert.That(WeakReferenceMessenger.Default.IsRegistered(this.viewModel), Is.True);
@@ -82,7 +82,7 @@ public void ConstructorShouldThrowArgumentNullExceptionWhenMessengerIsNull()
}
[Test]
- public void MessengerPubilshShouldSetCurrentViewToEntityInspectorViewModelWhenInvoked()
+ public void MessengerPublishShouldSetCurrentViewToEntityInspectorViewModelWhenInvoked()
{
// Arrange
var entity = new Entity();
@@ -96,7 +96,7 @@ public void MessengerPubilshShouldSetCurrentViewToEntityInspectorViewModelWhenIn
}
[Test]
- public void MessengerPubilshShouldSetTitleToEntityInspectorWhenInvoked()
+ public void MessengerPublishShouldSetTitleToEntityInspectorWhenInvoked()
{
// Arrange
var entity = new Entity();
diff --git a/FinalEngine.Tests/FinalEngine.Tests.csproj b/FinalEngine.Tests/FinalEngine.Tests.csproj
index 58a75698..46633ca7 100644
--- a/FinalEngine.Tests/FinalEngine.Tests.csproj
+++ b/FinalEngine.Tests/FinalEngine.Tests.csproj
@@ -7,7 +7,6 @@
All
false
x64
- true
diff --git a/FinalEngine.Tests/Rendering/OpenGL/OpenGLRenderContextTests.cs b/FinalEngine.Tests/Rendering/OpenGL/OpenGLRenderContextTests.cs
index 495c8d62..e057a52d 100644
--- a/FinalEngine.Tests/Rendering/OpenGL/OpenGLRenderContextTests.cs
+++ b/FinalEngine.Tests/Rendering/OpenGL/OpenGLRenderContextTests.cs
@@ -69,19 +69,6 @@ public void ConstructorShouldThrowArgumentNullExceptionWhenInvokerIsNull()
});
}
- [Test]
- public void DisposeShouldNotExecuteWhenAlreadyDisposed()
- {
- // Arrange
- this.renderContext.Dispose();
-
- // Act
- this.renderContext.Dispose();
-
- // Assert
- this.invoker.Verify(x => x.DeleteVertexArray(VertexArrayID), Times.Once);
- }
-
[SetUp]
public void Setup()
{
@@ -109,16 +96,6 @@ public void SwapBuffersShouldInvokeSwapBuffersWhenContextIsCurrent()
this.graphicsContext.Verify(x => x.SwapBuffers(), Times.Once);
}
- [Test]
- public void SwapBuffersShouldThrowObjectDisposedExceptionWhenDisposed()
- {
- // Arrange
- this.renderContext.Dispose();
-
- // Act and assert
- Assert.Throws(this.renderContext.SwapBuffers);
- }
-
[Test]
public void SwapBuffersShouldThrowRenderContextExceptionWhenContextIsNotCurrent()
{
@@ -128,10 +105,4 @@ public void SwapBuffersShouldThrowRenderContextExceptionWhenContextIsNotCurrent(
// Act and assert
Assert.Throws(this.renderContext.SwapBuffers);
}
-
- [TearDown]
- public void TearDown()
- {
- this.renderContext.Dispose();
- }
}
diff --git a/FinalEngine.sln b/FinalEngine.sln
index 9619029a..d9a112ee 100644
--- a/FinalEngine.sln
+++ b/FinalEngine.sln
@@ -6,7 +6,6 @@ MinimumVisualStudioVersion = 15.0.26124.0
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{14909D16-2584-4EB6-8656-7DA0C1DD540F}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
- CodeReview.md = CodeReview.md
SharedAssemblyInfo.cs = SharedAssemblyInfo.cs
EndProjectSection
EndProject
diff --git a/test.txt b/test.txt
deleted file mode 100644
index 8b137891..00000000
--- a/test.txt
+++ /dev/null
@@ -1 +0,0 @@
-