Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Remove Entity Component from Entity #286

Merged
merged 3 commits into from
Dec 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions FinalEngine.Editor.Desktop/App.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<ResourceDictionary Source="Styles/Controls/ToggleButtonStyle.xaml" />
<ResourceDictionary Source="Styles/Controls/TransparentListBoxStyle.xaml" />
<ResourceDictionary Source="Styles/Controls/TransparentListBoxItemStyle.xaml" />
<ResourceDictionary Source="Styles/Controls/IconButtonStyle.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Expand Down
7 changes: 7 additions & 0 deletions FinalEngine.Editor.Desktop/Controls/Common/IconButton.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Button x:Class="FinalEngine.Editor.Desktop.Controls.Common.IconButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Image x:Name="image" Width="16" Height="16" />
</Grid>
</Button>
34 changes: 34 additions & 0 deletions FinalEngine.Editor.Desktop/Controls/Common/IconButton.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// <copyright file="IconButton.xaml.cs" company="Software Antics">
// Copyright (c) Software Antics. All rights reserved.
// </copyright>

namespace FinalEngine.Editor.Desktop.Controls.Common;

using System.Windows.Controls;
using System.Windows.Media;

/// <summary>
/// Interaction logic for IconButton.xaml.
/// </summary>
public partial class IconButton : Button
{
/// <summary>
/// Initializes a new instance of the <see cref="IconButton"/> class.
/// </summary>
public IconButton()
{
this.InitializeComponent();
}

/// <summary>
/// Gets or sets the URI source for the icon.
/// </summary>
/// <value>
/// The URI source for the icon.
/// </value>
public ImageSource UriSource
{
get { return this.image.Source; }
set { this.image.Source = value; }
}
}
7 changes: 7 additions & 0 deletions FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
</PropertyGroup>

<ItemGroup>
<None Remove="Resources\Images\Icons\Settings.png" />
<None Remove="Resources\Images\Splashes\splash.png" />
</ItemGroup>

Expand Down Expand Up @@ -48,6 +49,12 @@
<ProjectReference Include="..\FinalEngine.Rendering.OpenGL\FinalEngine.Rendering.OpenGL.csproj" />
</ItemGroup>

<ItemGroup>
<Resource Include="Resources\Images\Icons\Settings.png">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</Resource>
</ItemGroup>

<ItemGroup>
<SplashScreen Include="Resources\Images\Splashes\splash.png" />
</ItemGroup>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions FinalEngine.Editor.Desktop/Styles/Controls/IconButtonStyle.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:c="clr-namespace:FinalEngine.Editor.Desktop.Controls.Common"
mc:Ignorable="d">
<Style TargetType="{x:Type c:IconButton}" BasedOn="{StaticResource MahApps.Styles.Button.VisualStudio}">
<Style.Setters>
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="MinWidth" Value="24" />
<Setter Property="MinHeight" Value="24" />
<Setter Property="Margin" Value="0" />
<Setter Property="Padding" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
</Style.Setters>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource MahApps.Brushes.Button.Square.Background.MouseOver}" />
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Background" Value="Transparent" />
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
Original file line number Diff line number Diff line change
Expand Up @@ -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">

<UserControl.Resources>
<BitmapImage x:Key="Icon_Settings" UriSource="/Resources/Images/Icons/Settings.png" />
</UserControl.Resources>

<Grid Margin="5">
<StackPanel>
<ToggleButton Content="{Binding Name}" Command="{Binding ToggleCommand}" />
<DockPanel>
<ToggleButton DockPanel.Dock="Left" HorizontalAlignment="Left" Content="{Binding Name}" Command="{Binding ToggleCommand}" />
<c:IconButton DockPanel.Dock="Right" HorizontalAlignment="Right" UriSource="{StaticResource Icon_Settings}">
<c:IconButton.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove Component" Command="{Binding RemoveCommand}" />
</ContextMenu>
</c:IconButton.ContextMenu>
</c:IconButton>
</DockPanel>

<ListBox ItemsSource="{Binding PropertyViewModels, UpdateSourceTrigger=PropertyChanged}"
Visibility="{Binding IsVisible, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BooleanToVisibilityConverter}}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Platforms>x64</Platforms>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// <copyright file="EntityComponentViewModel.cs" company="Software Antics">
// Copyright (c) Software Antics. All rights reserved.
// Copyright (c) Software Antics. All rights reserved.
// </copyright>

namespace FinalEngine.Editor.ViewModels.Inspectors;
Expand All @@ -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;

/// <summary>
/// Provides a standard implementation of an <see cref="IEntityComponentViewModel"/>.
/// Provides a standard implementation of an <see cref="IEntityComponentViewModel"/>.
/// </summary>
/// <seealso cref="ObservableObject" />
/// <seealso cref="IEntityComponentViewModel" />
/// <seealso cref="ObservableObject"/>
/// <seealso cref="IEntityComponentViewModel"/>
public sealed class EntityComponentViewModel : ObservableObject, IEntityComponentViewModel
{
/// <summary>
/// The property view models associated with this component model.
/// The component to model.
/// </summary>
private readonly IEntityComponent component;

/// <summary>
/// The entity that contains the component to be modeled.
/// </summary>
private readonly Entity entity;

/// <summary>
/// The messenger, used to notify other views when the entity has been modified.
/// </summary>
private readonly IMessenger messenger;

/// <summary>
/// The property view models associated with this component model.
/// </summary>
private readonly ObservableCollection<ObservableObject> propertyViewModels;

/// <summary>
/// Indicates whether the components properties are visible.
/// Indicates whether the components properties are visible.
/// </summary>
private bool isVisible;

/// <summary>
/// The toggle command.
/// The remove command, used to remove the component from the entity.
/// </summary>
private ICommand? removeCommand;

/// <summary>
/// The toggle command.
/// </summary>
private ICommand? toggleCommand;

/// <summary>
/// Initializes a new instance of the <see cref="EntityComponentViewModel"/> class.
/// Initializes a new instance of the <see cref="EntityComponentViewModel"/> class.
/// </summary>
/// <param name="messenger">
/// The messenger.
/// </param>
/// <param name="component">
/// The component to be modelled.
/// The component to be modeled.
/// </param>
/// <param name="entity">
/// The entity that contains the specified <paramref name="component"/>.
/// </param>
/// <exception cref="ArgumentNullException">
/// The specified <paramref name="component"/> parameter cannot be null.
/// The specified <paramref name="messenger"/>, <paramref name="entity"/> or <paramref name="component"/> parameter cannot be null.
/// </exception>
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<ObservableObject>();

Expand Down Expand Up @@ -138,14 +166,48 @@ public ICollection<ObservableObject> PropertyViewModels
get { return this.propertyViewModels; }
}

/// <inheritdoc/>
public ICommand RemoveCommand
{
get { return this.removeCommand ??= new RelayCommand(this.Remove, this.CanRemove); }
}

/// <inheritdoc/>
public ICommand ToggleCommand
{
get { return this.toggleCommand ??= new RelayCommand(this.Toggle); }
}

/// <summary>
/// Toggles the visibility of the components properties.
/// Determines whether the component can be removed from the entity.
/// </summary>
/// <returns>
/// <c>true</c> if the component can be removed from the entity; otherwise, <c>false</c>.
/// </returns>
private bool CanRemove()
{
return this.component.GetType() != typeof(TagComponent);
}

/// <summary>
/// Removes the component from the entity and notifies other views that the entity has been modified.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The <see cref="Entity"/> provided to this instance does not contain an <see cref="IEntityComponent"/> of the required type.
/// </exception>
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));
}

/// <summary>
/// Toggles the visibility of the components properties.
/// </summary>
private void Toggle()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// <copyright file="EntityInspectorViewModel.cs" company="Software Antics">
// Copyright (c) Software Antics. All rights reserved.
// Copyright (c) Software Antics. All rights reserved.
// </copyright>

namespace FinalEngine.Editor.ViewModels.Inspectors;
Expand All @@ -8,48 +8,90 @@ 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;

/// <summary>
/// Provides a standard implementation of an <see cref="IEntityInspectorViewModel"/>.
/// Provides a standard implementation of an <see cref="IEntityInspectorViewModel"/>.
/// </summary>
/// <seealso cref="ObservableObject" />
/// <seealso cref="IEntityInspectorViewModel" />
/// <seealso cref="ObservableObject"/>
/// <seealso cref="IEntityInspectorViewModel"/>
public sealed class EntityInspectorViewModel : ObservableObject, IEntityInspectorViewModel
{
/// <summary>
/// The component view models.
/// The component view models.
/// </summary>
private readonly ObservableCollection<IEntityComponentViewModel> componentViewModels;

/// <summary>
/// The entity being inspected.
/// The entity being inspected.
/// </summary>
private readonly Entity entity;

/// <summary>
/// Initializes a new instance of the <see cref="EntityInspectorViewModel"/> class.
/// The messenger.
/// </summary>
private readonly IMessenger messenger;

/// <summary>
/// Initializes a new instance of the <see cref="EntityInspectorViewModel"/> class.
/// </summary>
/// <param name="messenger">
/// The messenger.
/// </param>
/// <param name="entity">
/// The entity to be inspected.
/// The entity to be inspected.
/// </param>
/// <exception cref="ArgumentNullException">
/// The specified <paramref name="entity"/> parameter cannot be null.
/// The specified <paramref name="entity"/> parameter cannot be null.
/// </exception>
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<IEntityComponentViewModel>();

foreach (var component in this.entity.Components)
{
this.componentViewModels.Add(new EntityComponentViewModel(component));
}
this.messenger.Register<EntityModifiedMessage>(this, this.HandleEntityModified);

this.InitializeEntityComponents();
}

/// <inheritdoc/>
public ICollection<IEntityComponentViewModel> ComponentViewModels
{
get { return this.componentViewModels; }
}

/// <summary>
/// Handles the <see cref="EntityModifiedMessage"/> and initializes the entity component view models.
/// </summary>
/// <param name="recipient">
/// The recipient.
/// </param>
/// <param name="message">
/// The message.
/// </param>
private void HandleEntityModified(object recipient, EntityModifiedMessage message)
{
if (!ReferenceEquals(this.entity, message.Entity))
{
return;
}

this.InitializeEntityComponents();
}

/// <summary>
/// Initializes the entity component view models for the <see cref="Entity"/>.
/// </summary>
private void InitializeEntityComponents()
{
this.componentViewModels.Clear();

foreach (var component in this.entity.Components)
{
this.componentViewModels.Add(new EntityComponentViewModel(this.messenger, this.entity, component));
}
}
}
Loading
Loading