添加项目文件。

This commit is contained in:
OLDREDSTONE
2025-02-26 10:55:02 +08:00
parent 28e70f8234
commit 0672aeb5d5
11 changed files with 563 additions and 0 deletions
+9
View File
@@ -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
View File
@@ -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
{
}
}
+10
View File
@@ -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)
)]
+68
View File
@@ -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>
+257
View File
@@ -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;
}
}
+147
View File
@@ -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 ?? "",
};
}
}
}
}
+10
View File
@@ -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;
}
}
+10
View File
@@ -0,0 +1,10 @@
namespace RDTKEditor.Models
{
internal enum RDTKViewMessageLevel
{
None = 0,
Info = 1,
Warning = 2,
Error = 3,
}
}
+16
View File
@@ -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>
+22
View File
@@ -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
View File