Add entity manager content

This commit is contained in:
John Gross
2017-05-15 12:33:00 -07:00
parent d4649ea8ef
commit 8ad9ecf2bb
22 changed files with 598 additions and 72 deletions

View File

@@ -1,4 +1,4 @@
using System.Reflection;
[assembly: AssemblyVersion("1.0.119.399")]
[assembly: AssemblyFileVersion("1.0.119.399")]
[assembly: AssemblyVersion("1.0.135.374")]
[assembly: AssemblyFileVersion("1.0.135.374")]

View File

@@ -1,4 +1,4 @@
using System.Reflection;
[assembly: AssemblyVersion("1.0.119.399")]
[assembly: AssemblyFileVersion("1.0.119.399")]
[assembly: AssemblyVersion("1.0.135.374")]
[assembly: AssemblyFileVersion("1.0.135.374")]

View File

@@ -175,19 +175,28 @@
<Compile Include="TorchServiceInstaller.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="ViewModels\CharacterViewModel.cs" />
<Compile Include="ViewModels\Blocks\BlockViewModel.cs" />
<Compile Include="ViewModels\Blocks\BlockViewModelGenerator.cs" />
<Compile Include="ViewModels\Blocks\PropertyViewModel.cs" />
<Compile Include="ViewModels\Entities\CharacterViewModel.cs" />
<Compile Include="ViewModels\ConfigDedicatedViewModel.cs" />
<Compile Include="ViewModels\EntityTreeViewModel.cs" />
<Compile Include="ViewModels\EntityViewModel.cs" />
<Compile Include="ViewModels\Entities\EntityViewModel.cs" />
<Compile Include="ViewModels\FloatingObjectViewModel.cs" />
<Compile Include="ViewModels\GridViewModel.cs" />
<Compile Include="ViewModels\Entities\GridViewModel.cs" />
<Compile Include="ViewModels\PluginManagerViewModel.cs" />
<Compile Include="ViewModels\PluginViewModel.cs" />
<Compile Include="ViewModels\SessionSettingsViewModel.cs" />
<Compile Include="ViewModels\VoxelMapViewModel.cs" />
<Compile Include="ViewModels\Entities\VoxelMapViewModel.cs" />
<Compile Include="Views\AddWorkshopItemsDialog.xaml.cs">
<DependentUpon>AddWorkshopItemsDialog.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Blocks\BlockView.xaml.cs">
<DependentUpon>BlockView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Blocks\PropertyView.xaml.cs">
<DependentUpon>PropertyView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ChatControl.xaml.cs">
<DependentUpon>ChatControl.xaml</DependentUpon>
</Compile>
@@ -251,6 +260,14 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Blocks\BlockView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Blocks\PropertyView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\ChatControl.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@@ -292,6 +309,7 @@
<LastGenOutput>AssemblyInfo.cs</LastGenOutput>
</Content>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>copy "$(SolutionDir)NLog.config" "$(TargetDir)"</PostBuildEvent>

View File

@@ -9,6 +9,7 @@ using System.Threading;
using System.Xml.Serialization;
using SteamSDK;
using Torch.API;
using Torch.Server.ViewModels.Blocks;
using VRage.Dedicated;
using VRage.FileSystem;
using VRage.Game;

View File

@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sandbox.ModAPI;
using Sandbox.ModAPI.Interfaces;
using Torch.Server.ViewModels.Entities;
namespace Torch.Server.ViewModels.Blocks
{
public class BlockViewModel : EntityViewModel
{
public IMyTerminalBlock Block { get; }
public MTObservableCollection<PropertyViewModel> Properties { get; } = new MTObservableCollection<PropertyViewModel>();
public string FullName => $"{Block.CubeGrid.CustomName} - {Block.CustomName}";
public override string Name
{
get => Block?.CustomName ?? "null";
set
{
TorchBase.Instance.InvokeBlocking(() => Block.CustomName = value);
OnPropertyChanged();
}
}
public override bool CanStop => false;
public BlockViewModel(IMyTerminalBlock block) : base(block)
{
Block = block;
var propList = new List<ITerminalProperty>();
block.GetProperties(propList);
foreach (var prop in propList)
{
Type propType = null;
foreach (var iface in prop.GetType().GetInterfaces())
{
if (iface.IsGenericType && iface.GetGenericTypeDefinition() == typeof(ITerminalProperty<>))
propType = iface.GenericTypeArguments[0];
}
var modelType = typeof(PropertyViewModel<>).MakeGenericType(propType);
Properties.Add((PropertyViewModel)Activator.CreateInstance(modelType, prop, this));
}
}
public BlockViewModel()
{
}
}
}

View File

@@ -0,0 +1,132 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Sandbox.Game.Entities.Cube;
using Sandbox.ModAPI;
using Sandbox.ModAPI.Interfaces;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using NLog;
using Sandbox.ModAPI.Interfaces.Terminal;
namespace Torch.Server.ViewModels.Blocks
{
public static class BlockViewModelGenerator
{
private static Dictionary<Type, Type> _cache = new Dictionary<Type, Type>();
private static AssemblyName _asmName;
private static ModuleBuilder _mb;
private static AssemblyBuilder _ab;
private static Logger _log = LogManager.GetLogger("Generator");
static BlockViewModelGenerator()
{
_asmName = new AssemblyName("Torch.Server.ViewModels.Generated");
_ab = AppDomain.CurrentDomain.DefineDynamicAssembly(_asmName, AssemblyBuilderAccess.RunAndSave);
_mb = _ab.DefineDynamicModule(_asmName.Name);
}
public static void GenerateModels()
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies().Where(a => !a.IsDynamic))
{
foreach (var type in assembly.ExportedTypes.Where(t => t.IsSubclassOf(typeof(MyTerminalBlock))))
{
GenerateModel(type);
}
}
_ab.Save("Generated.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
}
public static Type GenerateModel(Type blockType, bool force = false)
{
if (_cache.ContainsKey(blockType) && !force)
return _cache[blockType];
var propertyList = new List<ITerminalProperty>();
MyTerminalControlFactoryHelper.Static.GetProperties(blockType, propertyList);
var getPropertyMethod = blockType.GetMethod("GetProperty", new[] {typeof(string)});
var getValueMethod = typeof(ITerminalProperty<>).GetMethod("GetValue");
var setValueMethod = typeof(ITerminalProperty<>).GetMethod("SetValue");
var tb = _mb.DefineType($"{_asmName.Name}.{blockType.Name}ViewModel", TypeAttributes.Class | TypeAttributes.Public);
var blockField = tb.DefineField("_block", blockType, FieldAttributes.Private);
var ctor = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new[] {blockType});
var ctorIl = ctor.GetILGenerator();
ctorIl.Emit(OpCodes.Ldarg_0);
ctorIl.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
ctorIl.Emit(OpCodes.Ldarg_0);
ctorIl.Emit(OpCodes.Ldarg_1);
ctorIl.Emit(OpCodes.Stfld, blockField);
ctorIl.Emit(OpCodes.Ret);
for (var i = 0; i < propertyList.Count; i++)
{
var prop = propertyList[i];
var propType = prop.GetType();
Type propGenericArg = null;
foreach (var iface in propType.GetInterfaces())
{
if (iface.IsGenericType && iface.GetGenericTypeDefinition() == typeof(ITerminalProperty<>))
propGenericArg = iface.GenericTypeArguments[0];
}
if (propGenericArg == null)
{
_log.Error($"Property {prop.Id} does not implement {typeof(ITerminalProperty<>).Name}");
return null;
}
_log.Info($"GENERIC ARG: {propGenericArg.Name}");
var pb = tb.DefineProperty($"{prop.Id}", PropertyAttributes.HasDefault, propGenericArg, null);
var getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
var getter = tb.DefineMethod($"get_{prop.Id}", getSetAttr, propGenericArg, Type.EmptyTypes);
{
var getterIl = getter.GetILGenerator();
var propLoc = getterIl.DeclareLocal(propType);
getterIl.Emit(OpCodes.Ldarg_0);
getterIl.Emit(OpCodes.Ldfld, blockField);
getterIl.Emit(OpCodes.Ldstr, prop.Id);
getterIl.EmitCall(OpCodes.Callvirt, getPropertyMethod, null);
getterIl.Emit(OpCodes.Stloc, propLoc);
getterIl.Emit(OpCodes.Ldloc, propLoc);
getterIl.Emit(OpCodes.Ldarg_0);
getterIl.Emit(OpCodes.Ldfld, blockField);
getterIl.EmitCall(OpCodes.Callvirt, getValueMethod, null);
getterIl.Emit(OpCodes.Ret);
pb.SetGetMethod(getter);
}
var setter = tb.DefineMethod($"set_{prop.Id}", getSetAttr, null, Type.EmptyTypes);
{
var setterIl = setter.GetILGenerator();
var propLoc = setterIl.DeclareLocal(propType);
setterIl.Emit(OpCodes.Ldarg_0);
setterIl.Emit(OpCodes.Stfld, blockField);
setterIl.EmitCall(OpCodes.Callvirt, getPropertyMethod, null);
setterIl.Emit(OpCodes.Stloc, propLoc);
setterIl.Emit(OpCodes.Ldarg_1);
setterIl.Emit(OpCodes.Ldarg_0);
setterIl.Emit(OpCodes.Ldfld, blockField);
setterIl.EmitCall(OpCodes.Callvirt, setValueMethod, null);
setterIl.Emit(OpCodes.Ret);
pb.SetSetMethod(setter);
}
}
var vmType = tb.CreateType();
_cache.Add(blockType, vmType);
return vmType;
}
}
}

View File

@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sandbox.ModAPI;
using Sandbox.ModAPI.Interfaces;
namespace Torch.Server.ViewModels.Blocks
{
public class PropertyViewModel<T> : PropertyViewModel
{
private readonly ITerminalProperty<T> _prop;
public string Name { get; }
public Type PropertyType => typeof(T);
public T Value
{
get
{
var val = default(T);
TorchBase.Instance.InvokeBlocking(() => val = _prop.GetValue(Block.Block));
return val;
}
set
{
TorchBase.Instance.InvokeBlocking(() => _prop.SetValue(Block.Block, value));
OnPropertyChanged();
Block.RefreshModel();
}
}
public PropertyViewModel(ITerminalProperty<T> property, BlockViewModel blockViewModel) : base(blockViewModel)
{
Name = property.Id;
_prop = property;
}
}
public class PropertyViewModel : ViewModel
{
protected readonly BlockViewModel Block;
public PropertyViewModel(BlockViewModel blockViewModel)
{
Block = blockViewModel;
}
}
}

View File

@@ -1,18 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sandbox.Game.Entities.Character;
using VRage.Game.ModAPI;
namespace Torch.Server.ViewModels
{
public class CharacterViewModel : EntityViewModel
{
public CharacterViewModel(MyCharacter character) : base(character)
{
}
}
}

View File

@@ -0,0 +1,12 @@
using Sandbox.Game.Entities.Character;
namespace Torch.Server.ViewModels.Entities
{
public class CharacterViewModel : EntityViewModel
{
public CharacterViewModel(MyCharacter character) : base(character)
{
}
}
}

View File

@@ -1,13 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VRage.Game.ModAPI;
using VRage.Game.ModAPI;
using VRage.ModAPI;
using VRageMath;
namespace Torch.Server.ViewModels
namespace Torch.Server.ViewModels.Entities
{
public class EntityViewModel : ViewModel
{
@@ -45,5 +40,10 @@ namespace Torch.Server.ViewModels
{
Entity = entity;
}
public EntityViewModel()
{
}
}
}

View File

@@ -0,0 +1,49 @@
using System.Linq;
using Sandbox.Game.Entities;
using Sandbox.ModAPI;
using Torch.Server.ViewModels.Blocks;
namespace Torch.Server.ViewModels.Entities
{
public class GridViewModel : EntityViewModel
{
private MyCubeGrid Grid => (MyCubeGrid)Entity;
public MTObservableCollection<BlockViewModel> Blocks { get; } = new MTObservableCollection<BlockViewModel>();
/// <inheritdoc />
public override string Name => $"{base.Name} ({Grid.BlocksCount} blocks)";
public GridViewModel(MyCubeGrid grid) : base(grid)
{
TorchBase.Instance.InvokeBlocking(() =>
{
foreach (var block in grid.GetFatBlocks().Where(b => b is IMyTerminalBlock))
{
Blocks.Add(new BlockViewModel((IMyTerminalBlock)block));
}
});
Blocks.Sort(b => b.Block.GetType().AssemblyQualifiedName);
grid.OnBlockAdded += Grid_OnBlockAdded;
grid.OnBlockRemoved += Grid_OnBlockRemoved;
}
private void Grid_OnBlockRemoved(Sandbox.Game.Entities.Cube.MySlimBlock obj)
{
if (obj.FatBlock != null)
Blocks.RemoveWhere(b => b.Block.EntityId == obj.FatBlock?.EntityId);
Blocks.Sort(b => b.Block.GetType().AssemblyQualifiedName);
OnPropertyChanged(nameof(Name));
}
private void Grid_OnBlockAdded(Sandbox.Game.Entities.Cube.MySlimBlock obj)
{
if (obj.FatBlock != null)
Blocks.Add(new BlockViewModel((IMyTerminalBlock)obj.FatBlock));
Blocks.Sort(b => b.Block.GetType().AssemblyQualifiedName);
OnPropertyChanged(nameof(Name));
}
}
}

View File

@@ -1,13 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Medieval.ObjectBuilders.Definitions;
using Sandbox.Game.Entities;
using VRage.ModAPI;
using Sandbox.Game.Entities;
namespace Torch.Server.ViewModels
namespace Torch.Server.ViewModels.Entities
{
public class VoxelMapViewModel : EntityViewModel
{

View File

@@ -5,6 +5,7 @@ using System.Text;
using System.Threading.Tasks;
using Sandbox.Game.Entities;
using Sandbox.Game.Entities.Character;
using Torch.Server.ViewModels.Entities;
using VRage.Game.ModAPI;
using VRage.ModAPI;

View File

@@ -1,4 +1,5 @@
using Sandbox.Game.Entities;
using Torch.Server.ViewModels.Entities;
namespace Torch.Server.ViewModels
{

View File

@@ -1,23 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sandbox.Game.Entities;
using VRage.Game.ModAPI;
namespace Torch.Server.ViewModels
{
public class GridViewModel : EntityViewModel
{
private MyCubeGrid Grid => (MyCubeGrid)Entity;
/// <inheritdoc />
public override string Name => $"{base.Name} ({Grid.BlocksCount} blocks)";
public GridViewModel(MyCubeGrid grid) : base(grid)
{
}
}
}

View File

@@ -0,0 +1,32 @@
<UserControl x:Class="Torch.Server.Views.Blocks.BlockView"
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:Torch.Server.Views.Blocks"
xmlns:blocks="clr-namespace:Torch.Server.ViewModels.Blocks"
mc:Ignorable="d">
<UserControl.DataContext>
<blocks:BlockViewModel />
</UserControl.DataContext>
<DockPanel x:Name="Stack" Margin="3">
<Label Content="{Binding FullName}" FontSize="16" DockPanel.Dock="Top" />
<ListView ItemsSource="{Binding Properties}" Margin="3" IsEnabled="True" DockPanel.Dock="Bottom">
<ListView.ItemTemplate>
<DataTemplate>
<local:PropertyView />
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment"
Value="Stretch" />
<Setter Property="VerticalContentAlignment"
Value="Center" />
<Setter Property="Focusable"
Value="false" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
</DockPanel>
</UserControl>

View File

@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Sandbox.ModAPI;
using Sandbox.ModAPI.Interfaces;
using Torch.Server.ViewModels.Blocks;
using VRage.Game.ModAPI;
namespace Torch.Server.Views.Blocks
{
/// <summary>
/// Interaction logic for BlockView.xaml
/// </summary>
public partial class BlockView : UserControl
{
public BlockView()
{
InitializeComponent();
}
/*
public void SetTarget(BlockViewModel model)
{
DataContext = model;
Stack.Children.Clear();
var propList = new List<ITerminalProperty>();
model.Block.GetProperties(propList);
foreach (var prop in propList)
{
Type propType = null;
foreach (var iface in prop.GetType().GetInterfaces())
{
if (iface.IsGenericType && iface.GetGenericTypeDefinition() == typeof(ITerminalProperty<>))
propType = iface.GenericTypeArguments[0];
}
var modelType = typeof(PropertyViewModel<>).MakeGenericType(propType);
var vm = Activator.CreateInstance(modelType, prop, model.Block);
var label = new Label { Content = $"{prop.Id}: "};
var textBox = new TextBox { Margin = new Thickness(3) };
var binding = new Binding("Value") {Source = vm};
textBox.SetBinding(TextBox.TextProperty, binding);
var stack = new DockPanel {Children = {label, textBox}, LastChildFill = true};
Stack.Children.Add(stack);
}
/*
var properties = model.PropertyWrapper.GetType().GetProperties();
foreach (var property in properties)
{
var control = new TextBox {Margin = new Thickness(3), Text = property.GetValue(model.PropertyWrapper).ToString()};
var bindingPath = $"{nameof(model.PropertyWrapper)}.{property.Name}";
var binding = new Binding {Path = new PropertyPath(bindingPath), Source = model};
BindingOperations.SetBinding(control, TextBox.TextProperty, binding);
Stack.Children.Add(control);
}
}*/
}
}

View File

@@ -0,0 +1,21 @@
<UserControl x:Class="Torch.Server.Views.Blocks.PropertyView"
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:Torch.Server.Views.Blocks"
xmlns:blocks="clr-namespace:Torch.Server.ViewModels.Blocks"
mc:Ignorable="d">
<UserControl.Resources>
<local:StringIdConverter x:Key="StringIdConverter"/>
</UserControl.Resources>
<DockPanel x:Name="Dock">
<Label x:Name="Label" Width="150" VerticalAlignment="Center" DockPanel.Dock="Left">
<Label.Content>
<TextBlock Text="{Binding Name, StringFormat={}{0}: }" />
</Label.Content>
</Label>
<Frame x:Name="Frame" DockPanel.Dock="Right" NavigationUIVisibility="Hidden"/>
</DockPanel>
</UserControl>

View File

@@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Torch.Server.ViewModels.Blocks;
using VRage.Utils;
namespace Torch.Server.Views.Blocks
{
/// <summary>
/// Interaction logic for PropertyView.xaml
/// </summary>
public partial class PropertyView : UserControl
{
public PropertyView()
{
InitializeComponent();
DataContextChanged += OnDataContextChanged;
}
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs args)
{
switch (args.NewValue)
{
case PropertyViewModel<bool> vmBool:
InitBool();
break;
case PropertyViewModel<StringBuilder> vmSb:
InitStringBuilder();
break;
default:
InitDefault();
break;
}
}
private void InitStringBuilder()
{
var textBox = new TextBox { VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Stretch };
var binding = new Binding("Value") { Source = DataContext, Converter = new StringBuilderConverter()};
textBox.SetBinding(TextBox.TextProperty, binding);
Frame.Content = textBox;
}
private void InitBool()
{
var checkBox = new CheckBox {VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Left};
var binding = new Binding("Value") { Source = DataContext };
checkBox.SetBinding(CheckBox.IsCheckedProperty, binding);
Frame.Content = checkBox;
}
private void InitDefault()
{
var textBox = new TextBox { VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Stretch};
var binding = new Binding("Value") { Source = DataContext };
textBox.SetBinding(TextBox.TextProperty, binding);
Frame.Content = textBox;
}
}
public class StringBuilderConverter : IValueConverter
{
/// <inheritdoc />
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((StringBuilder)value).ToString();
}
/// <inheritdoc />
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return new StringBuilder((string)value);
}
}
public class StringIdConverter : IValueConverter
{
/// <inheritdoc />
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return MyStringId.GetOrCompute((string)value);
}
/// <inheritdoc />
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new InvalidOperationException();
}
}
}

View File

@@ -5,6 +5,9 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Torch.Server.Views"
xmlns:viewModels="clr-namespace:Torch.Server.ViewModels"
xmlns:blocks="clr-namespace:Torch.Server.Views.Blocks"
xmlns:entities="clr-namespace:Torch.Server.ViewModels.Entities"
xmlns:blocks1="clr-namespace:Torch.Server.ViewModels.Blocks"
mc:Ignorable="d">
<UserControl.DataContext>
<viewModels:EntityTreeViewModel />
@@ -17,15 +20,18 @@
<Button Content="Stop" Click="Stop_OnClick" IsEnabled="{Binding CurrentEntity.CanStop}" Margin="3" />
</StackPanel>
<TreeView Width="300" Margin="3" DockPanel.Dock="Top" SelectedItemChanged="TreeView_OnSelectedItemChanged">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type entities:GridViewModel}" ItemsSource="{Binding Blocks}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type blocks1:BlockViewModel}">
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</TreeView.Resources>
<TreeViewItem ItemsSource="{Binding Grids}" IsExpanded="true">
<TreeViewItem.Header>
<TextBlock Text="{Binding Grids.Count, StringFormat=Grids ({0})}" />
</TreeViewItem.Header>
<TreeViewItem.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</TreeViewItem.ItemTemplate>
</TreeViewItem>
<TreeViewItem ItemsSource="{Binding Characters}" IsExpanded="true">
<TreeViewItem.Header>
@@ -59,6 +65,6 @@
</TreeViewItem>
</TreeView>
</DockPanel>
<Frame Margin="3" />
<Frame x:Name="EditorFrame" Margin="3" NavigationUIVisibility="Hidden" />
</DockPanel>
</UserControl>

View File

@@ -13,6 +13,9 @@ using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Torch.Server.ViewModels;
using Torch.Server.ViewModels.Blocks;
using Torch.Server.ViewModels.Entities;
using Torch.Server.Views.Blocks;
using VRage.Game.ModAPI;
namespace Torch.Server.Views
@@ -33,7 +36,11 @@ namespace Torch.Server.Views
private void TreeView_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if (e.NewValue is EntityViewModel vm)
{
Entities.CurrentEntity = vm;
if (e.NewValue is BlockViewModel bvm)
EditorFrame.Content = new BlockView { DataContext = bvm };
}
else
Entities.CurrentEntity = null;
}

View File

@@ -33,12 +33,25 @@ namespace Torch
}
}
public void Sort<TKey>(Func<T, TKey> selector, IComparer<TKey> comparer = null)
{
List<T> sortedItems;
if (comparer != null)
sortedItems = Items.OrderBy(selector, comparer).ToList();
else
sortedItems = Items.OrderBy(selector).ToList();
Items.Clear();
foreach (var item in sortedItems)
Add(item);
}
public void RemoveWhere(Func<T, bool> condition)
{
for (var i = Items.Count - 1; i > 0; i--)
{
if (condition(Items[i]))
Items.RemoveAt(i);
RemoveAt(i);
}
}
}