Archived
forked from RDTKEditor/RDTKEditor
添加项目文件。
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
<Application x:Class="RDTKEditor.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:RDTKEditor"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
using System.Configuration;
|
||||
using System.Data;
|
||||
using System.Windows;
|
||||
|
||||
namespace RDTKEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.Windows;
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
||||
@@ -0,0 +1,68 @@
|
||||
<Window x:Class="RDTKEditor.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
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"
|
||||
xmlns:skia="clr-namespace:SkiaSharp.Views.WPF;assembly=SkiaSharp.Views.WPF"
|
||||
xmlns:local="clr-namespace:RDTKEditor"
|
||||
mc:Ignorable="d"
|
||||
Title="RDTK Editor" Height="450" Width="800">
|
||||
<Window.DataContext>
|
||||
<local:MainViewModel/>
|
||||
</Window.DataContext>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Menu Grid.Row="0" VerticalAlignment="Top">
|
||||
<MenuItem Header="文件(_F)">
|
||||
<MenuItem Header="打开文件(_O)" Click="OpenFile" InputGestureText="Ctrl+O"/>
|
||||
<MenuItem Header="保存文件(_S)" Click="SaveFile" InputGestureText="Ctrl+S"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="退出(_E)" Click="Exit"/>
|
||||
</MenuItem>
|
||||
<MenuItem Header="帮助(_H)">
|
||||
<MenuItem Header="关于(_A)" Click="About"/>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="200" MinWidth="100" MaxWidth="300" />
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="200" MinWidth="100" MaxWidth="300" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="5" />
|
||||
<RowDefinition Height="100" MinHeight="90" MaxHeight="270"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Border Grid.Column="0" Background="LightBlue">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||
<ItemsControl x:Name="ItemProperties" Background="LightGray">
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
<GridSplitter Grid.Column="1" Width="5" Background="Gray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
|
||||
<Viewbox Grid.Row="0" Grid.Column="2" Stretch="Uniform">
|
||||
<Border Background="LightGray" Width="1600" Height="900">
|
||||
<skia:SKElement x:Name="mainUI" PaintSurface="mainUI_PaintSurface" />
|
||||
</Border>
|
||||
</Viewbox>
|
||||
<GridSplitter Grid.Column="3" Width="5" Background="Gray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
|
||||
<Border Grid.Column="4" Background="LightBlue" >
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||
<Grid x:Name="timelineCanvas3" Background="LightGray" />
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
<GridSplitter Grid.Row="1" Grid.ColumnSpan="5" Height="5" Background="Gray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
|
||||
<Border Grid.ColumnSpan="5" Grid.Row="2" Background="LightSalmon">
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<Canvas x:Name="timelineCanvas" Background="LightGray" />
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -0,0 +1,257 @@
|
||||
using Microsoft.Win32;
|
||||
using RDTKEditor.Models;
|
||||
using RhythmBase.Events;
|
||||
using SkiaSharp;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace RDTKEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
private readonly RDTKView viewModel = new();
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
private void OpenFile(object sender, RoutedEventArgs e)
|
||||
{
|
||||
OpenFileDialog openFileDialog = new()
|
||||
{
|
||||
Filter = "关卡文件|*.rdlevel|关卡压缩包 (*.rdzip)|*.rdzip"
|
||||
};
|
||||
if (openFileDialog.ShowDialog() == true)
|
||||
{
|
||||
string filename = openFileDialog.FileName;
|
||||
viewModel.UpdateLevelByPath(filename);
|
||||
}
|
||||
}
|
||||
private void SaveFile(object sender, RoutedEventArgs e)
|
||||
{
|
||||
OpenFileDialog openFileDialog = new()
|
||||
{
|
||||
Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*"
|
||||
};
|
||||
if (openFileDialog.ShowDialog() == true)
|
||||
{
|
||||
string filename = openFileDialog.FileName;
|
||||
viewModel.SaveLevelByPath(filename);
|
||||
}
|
||||
}
|
||||
private void Exit(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
private void About(object sender, RoutedEventArgs e)
|
||||
{
|
||||
OnUpdateEventProperties(GetProperties(new MoveRow()));
|
||||
|
||||
//OnUpdateEventProperties([
|
||||
// new(){
|
||||
// Verifier = new RDTKPropertyVerifierDefault(),
|
||||
// Name = "Name",
|
||||
// Value = "RDTK Editor",
|
||||
// Type = RDPropertyType.String,
|
||||
// },
|
||||
// new(){
|
||||
// Verifier = new RDTKPropertyVerifierDefault(),
|
||||
// Name = "Version",
|
||||
// Value = "1.0.0",
|
||||
// Type = RDPropertyType.String,
|
||||
// },
|
||||
// new(){
|
||||
// Verifier = new RDTKPropertyVerifierEnum(typeof(EventType)),
|
||||
// Name = "Description",
|
||||
// Value = "RDTK Editor 是一个简单的节奏医生关卡编辑器。",
|
||||
// Type = RDPropertyType.Enum,
|
||||
// },
|
||||
// new(){
|
||||
// Verifier = new RDTKPropertyVerifierBool(),
|
||||
// Name = "测试值",
|
||||
// Value = "true",
|
||||
// Type = RDPropertyType.Bool,
|
||||
// }
|
||||
// ]);
|
||||
//MessageBox.Show("RDTK Editor 是一个简单的节奏医生关卡编辑器。", "关于 RDTK Editor");
|
||||
}
|
||||
private RDTKProperty[] GetProperties(BaseEvent e)
|
||||
{
|
||||
return [
|
||||
new RDTKProperty()
|
||||
{
|
||||
Verifier = new RDTKPropertyVerifierDefault(),
|
||||
Name = "类型",
|
||||
Value = e.Type.ToString(),
|
||||
Type = RDPropertyType.String,
|
||||
},
|
||||
..e.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Select(p => GetProperty(p,e)).ToArray()
|
||||
];
|
||||
}
|
||||
private RDTKProperty GetProperty(PropertyInfo property, object obj)
|
||||
{
|
||||
switch (property.PropertyType.Name)
|
||||
{
|
||||
case "Boolean":
|
||||
return new()
|
||||
{
|
||||
Verifier = new RDTKPropertyVerifierBool(),
|
||||
Name = property.Name,
|
||||
Value = property.GetValue(obj)?.ToString() ?? "false",
|
||||
Type = RDPropertyType.Bool,
|
||||
};
|
||||
case "Enum":
|
||||
return new()
|
||||
{
|
||||
Verifier = new RDTKPropertyVerifierEnum(property.PropertyType),
|
||||
Name = property.Name,
|
||||
Value = property.GetValue(obj)?.ToString() ?? "null",
|
||||
Type = RDPropertyType.Enum,
|
||||
};
|
||||
case "String":
|
||||
return new()
|
||||
{
|
||||
Verifier = new RDTKPropertyVerifierDefault(),
|
||||
Name = property.Name,
|
||||
Value = property.GetValue(obj)?.ToString() ?? "null",
|
||||
Type = RDPropertyType.String,
|
||||
};
|
||||
}
|
||||
return new()
|
||||
{
|
||||
Verifier = new RDTKPropertyVerifierDefault(),
|
||||
Name = property.Name,
|
||||
Value = property.GetValue(obj)?.ToString() ?? "null",
|
||||
Type = RDPropertyType.String,
|
||||
};
|
||||
}
|
||||
internal void OnUpdateEventProperties(RDTKProperty[] properties)
|
||||
{
|
||||
ItemProperties.Items.Clear();
|
||||
foreach (var property in properties)
|
||||
{
|
||||
StackPanel stackPanel;
|
||||
switch (property.Type)
|
||||
{
|
||||
case RDPropertyType.Bool:
|
||||
stackPanel = new()
|
||||
{
|
||||
Orientation = Orientation.Horizontal,
|
||||
FlowDirection = FlowDirection.LeftToRight,
|
||||
Children =
|
||||
{
|
||||
new Label(){Content = property.Name},
|
||||
new CheckBox() { IsChecked = bool.Parse( property.Value), }
|
||||
},
|
||||
};
|
||||
break;
|
||||
case RDPropertyType.Enum:
|
||||
stackPanel = new()
|
||||
{
|
||||
AllowDrop = true,
|
||||
Orientation = Orientation.Horizontal,
|
||||
FlowDirection = FlowDirection.LeftToRight,
|
||||
Children =
|
||||
{
|
||||
new Label(){Content = property.Name},
|
||||
new ComboBox()
|
||||
{
|
||||
ItemsSource = Enum.GetValues(((RDTKPropertyVerifierEnum)property.Verifier).EnumType),
|
||||
SelectedValue = property.Value,
|
||||
}
|
||||
},
|
||||
};
|
||||
break;
|
||||
case RDPropertyType.String:
|
||||
stackPanel = new()
|
||||
{
|
||||
AllowDrop = true,
|
||||
Orientation = Orientation.Horizontal,
|
||||
FlowDirection = FlowDirection.LeftToRight,
|
||||
Children =
|
||||
{
|
||||
new Label(){Content = property.Name},
|
||||
new TextBox() { Text = property.Value, }
|
||||
},
|
||||
};
|
||||
break;
|
||||
default:
|
||||
stackPanel = new()
|
||||
{
|
||||
Orientation = Orientation.Horizontal,
|
||||
Children =
|
||||
{
|
||||
new Label(){Content = property.Name},
|
||||
new Label(){Content = property.Value}
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
foreach (var child in stackPanel.Children)
|
||||
{
|
||||
switch (child)
|
||||
{
|
||||
case CheckBox checkBox:
|
||||
checkBox.Checked += (sender, e) =>
|
||||
{
|
||||
property.OnChanged("true");
|
||||
};
|
||||
checkBox.Unchecked += (sender, e) =>
|
||||
{
|
||||
property.OnChanged("false");
|
||||
};
|
||||
break;
|
||||
case TextBox textBox:
|
||||
textBox.TextChanged += (sender, e) =>
|
||||
{
|
||||
property.OnChanged(textBox.Text);
|
||||
};
|
||||
break;
|
||||
case ComboBox comboBox:
|
||||
comboBox.SelectionChanged += (sender, e) =>
|
||||
{
|
||||
property.OnChanged(comboBox.SelectedValue);
|
||||
};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
ItemProperties.Items.Add(stackPanel);
|
||||
property.PropertyChanged += (e, s) => UpdateEvent();
|
||||
}
|
||||
}
|
||||
private void UpdateEvent()
|
||||
{
|
||||
MessageBox.Show("Update Event");
|
||||
}
|
||||
private void UpdateTimeLine()
|
||||
{
|
||||
Rectangle rectangle = new()
|
||||
{
|
||||
Width = 100,
|
||||
Height = 100,
|
||||
};
|
||||
timelineCanvas.Children.Add(rectangle);
|
||||
}
|
||||
private void mainUI_PaintSurface(object sender, SkiaSharp.Views.Desktop.SKPaintSurfaceEventArgs e)
|
||||
{
|
||||
var sfc = e.Surface;
|
||||
var cvs = sfc.Canvas;
|
||||
cvs.Clear(SKColors.Black);
|
||||
cvs.DrawLine(0, 0, 1600, 900, new()
|
||||
{
|
||||
Color = SKColors.Red,
|
||||
});
|
||||
}
|
||||
}
|
||||
public class MainViewModel : INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
using RhythmBase.Components;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace RDTKEditor.Models
|
||||
{
|
||||
internal enum RDPropertyType
|
||||
{
|
||||
Bool,
|
||||
Integer,
|
||||
Float,
|
||||
Expression,
|
||||
IntegerPair,
|
||||
FloatPair,
|
||||
ExpressionPair,
|
||||
String,
|
||||
Color,
|
||||
Enum,
|
||||
}
|
||||
internal interface IRDTKPropertyVerifier
|
||||
{
|
||||
RDPropertyType Type { get; }
|
||||
bool TryParse(string value, out object result);
|
||||
string ToString(object value);
|
||||
}
|
||||
internal class RDTKPropertyVerifierEnum(Type enumType) : IRDTKPropertyVerifier
|
||||
{
|
||||
public RDPropertyType Type => RDPropertyType.Enum;
|
||||
public Type EnumType { get; set; } = enumType;
|
||||
public bool TryParse(string value, out object result)
|
||||
{
|
||||
if (Enum.TryParse(EnumType, value, out object v))
|
||||
{
|
||||
result = v;
|
||||
return true;
|
||||
}
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
public string ToString(object value) => value?.ToString() ?? "null";
|
||||
}
|
||||
internal class RDTKPropertyVerifierBool : IRDTKPropertyVerifier
|
||||
{
|
||||
public RDPropertyType Type => RDPropertyType.Bool;
|
||||
public bool TryParse(string value, out object result)
|
||||
{
|
||||
var t = bool.TryParse(value, out bool v);
|
||||
result = v;
|
||||
return t;
|
||||
}
|
||||
public string ToString(object value) => (bool)value ? "true" : "false";
|
||||
}
|
||||
internal class RDTKPropertyVerifierDefault : IRDTKPropertyVerifier
|
||||
{
|
||||
public RDPropertyType Type { get; set; }
|
||||
public bool TryParse(string value, out object result)
|
||||
{
|
||||
result = value;
|
||||
return true;
|
||||
}
|
||||
public string ToString(object value) => value?.ToString() ?? "null";
|
||||
}
|
||||
internal struct RDTKProperty(object value)
|
||||
{
|
||||
public event EventHandler<object?>? PropertyChanged = null;
|
||||
private object _value = value;
|
||||
public string Name { get; set; } = "";
|
||||
public string Description { get; set; } = "";
|
||||
public RDPropertyType Type { get; set; }
|
||||
public IRDTKPropertyVerifier Verifier { get; set; } = new RDTKPropertyVerifierDefault();
|
||||
public string Value
|
||||
{
|
||||
readonly get => Verifier.ToString(_value);
|
||||
set
|
||||
{
|
||||
if (Verifier.TryParse(value, out object result))
|
||||
{
|
||||
_value = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
public void OnChanged(object value)
|
||||
{
|
||||
if (_value == value) return;
|
||||
if (Verifier.TryParse(value?.ToString()??"", out object result))
|
||||
{
|
||||
_value = result;
|
||||
PropertyChanged?.Invoke(this, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
internal class RDTKView
|
||||
{
|
||||
|
||||
private RDLevel? Level { get; set; }
|
||||
public RDTKView()
|
||||
{
|
||||
}
|
||||
public RDTKViewMessage UpdateLevelByPath(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
Level = RDLevel.Read(path);
|
||||
return new()
|
||||
{
|
||||
Message = "关卡已加载。",
|
||||
Level = RDTKViewMessageLevel.Info,
|
||||
Details = $"关卡路径:{path}",
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Message = ex.Message,
|
||||
Level = RDTKViewMessageLevel.Error,
|
||||
Details = ex.StackTrace ?? "",
|
||||
};
|
||||
}
|
||||
}
|
||||
public RDTKViewMessage SaveLevelByPath(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
Level?.Write(path);
|
||||
|
||||
return new()
|
||||
{
|
||||
Message = "关卡已加载。",
|
||||
Level = RDTKViewMessageLevel.Info,
|
||||
Details = $"关卡路径:{path}",
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Message = ex.Message,
|
||||
Level = RDTKViewMessageLevel.Error,
|
||||
Details = ex.StackTrace ?? "",
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace RDTKEditor.Models
|
||||
{
|
||||
internal struct RDTKViewMessage()
|
||||
{
|
||||
public string Message { get; set; } = "";
|
||||
public RDTKViewMessageLevel Level { get; set; }
|
||||
public string Details { get; set; } = "";
|
||||
public DateTime TimeStamp { get; } = DateTime.Now;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace RDTKEditor.Models
|
||||
{
|
||||
internal enum RDTKViewMessageLevel
|
||||
{
|
||||
None = 0,
|
||||
Info = 1,
|
||||
Warning = 2,
|
||||
Error = 3,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UseWPF>true</UseWPF>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="RhythmBase" Version="1.1.0-beta" />
|
||||
<PackageReference Include="SkiaSharp.Views.WPF" Version="3.118.0-preview.2.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.12.35506.116 d17.12
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RDTKEditor", "RDTKEditor.csproj", "{6372AB7C-8E8F-4803-8930-B74A51CE334D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{6372AB7C-8E8F-4803-8930-B74A51CE334D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6372AB7C-8E8F-4803-8930-B74A51CE334D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6372AB7C-8E8F-4803-8930-B74A51CE334D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6372AB7C-8E8F-4803-8930-B74A51CE334D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Reference in New Issue
Block a user