1
0

feat: write shit

This commit is contained in:
2026-04-02 20:35:30 +08:00
parent 08734c6ef7
commit a55a8c7456
13 changed files with 481 additions and 65 deletions

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BallanceTasEditor.Backend {
public enum EditorLayoutKind {
Horizontal, Vertical
}
public class AppSettings {
public EditorLayoutKind EditorLayout { get; set; }
}
}

View File

@@ -156,6 +156,14 @@ namespace BallanceTasEditor.Backend {
raw.KeyFlags = m_KeyFlags; raw.KeyFlags = m_KeyFlags;
} }
/// <summary>
/// 返回自身的克隆(深拷贝)。
/// </summary>
/// <returns>自身的克隆。</returns>
public TasFrame Clone() {
return new TasFrame(m_TimeDelta, m_KeyFlags);
}
/// <summary> /// <summary>
/// 该帧的持续时间(以秒为单位)。 /// 该帧的持续时间(以秒为单位)。
/// </summary> /// </summary>

View File

@@ -10,11 +10,31 @@ using System.Threading.Tasks;
namespace BallanceTasEditor.Backend { namespace BallanceTasEditor.Backend {
public static class TasStorage { public static class TasStorage {
/// <summary>
/// Initialize given TAS sequence with given count frame which has given FPS.
/// </summary>
/// <param name="seq">The TAS sequence to initialize.</param>
/// <param name="count">The count of frame.</param>
/// <param name="fps">The FPS of frame.</param>
public static void Init(ITasSequence seq, int count, uint fps) {
var frame = TasFrame.FromFps(fps);
var iter = Enumerable.Range(0, count).Select((_) => frame.Clone());
var exactSizeIter = new ExactSizeEnumerableAdapter<TasFrame>(iter, count);
seq.Insert(seq.GetCount(), exactSizeIter);
}
internal const int SIZEOF_I32 = sizeof(int); internal const int SIZEOF_I32 = sizeof(int);
internal const int SIZEOF_F32 = sizeof(float); internal const int SIZEOF_F32 = sizeof(float);
internal const int SIZEOF_U32 = sizeof(uint); internal const int SIZEOF_U32 = sizeof(uint);
internal const int SIZEOF_RAW_TAS_FRAME = SIZEOF_F32 + SIZEOF_U32; internal const int SIZEOF_RAW_TAS_FRAME = SIZEOF_F32 + SIZEOF_U32;
/// <summary>
/// Save given TAS sequence into given file path.
/// </summary>
/// <param name="filepath">The path to file for saving.</param>
/// <param name="seq">The TAS sequence to save.</param>
/// <exception cref="Exception">Any exception occurs when saving.</exception>
public static void Save(string filepath, ITasSequence seq) { public static void Save(string filepath, ITasSequence seq) {
using (var fs = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None)) { using (var fs = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None)) {
Save(fs, seq); Save(fs, seq);
@@ -22,6 +42,12 @@ namespace BallanceTasEditor.Backend {
} }
} }
/// <summary>
/// Save given TAS sequence into given file stream.
/// </summary>
/// <param name="fs">The file stream for saving.</param>
/// <param name="seq">The TAS sequence to save.</param>
/// <exception cref="Exception">Any exception occurs when saving.</exception>
public static void Save(Stream fs, ITasSequence seq) { public static void Save(Stream fs, ITasSequence seq) {
var totalByte = seq.GetCount() * SIZEOF_RAW_TAS_FRAME; var totalByte = seq.GetCount() * SIZEOF_RAW_TAS_FRAME;
fs.Write(BitConverter.GetBytes(totalByte), 0, SIZEOF_I32); fs.Write(BitConverter.GetBytes(totalByte), 0, SIZEOF_I32);
@@ -46,6 +72,12 @@ namespace BallanceTasEditor.Backend {
//zo.Close(); //zo.Close();
} }
/// <summary>
/// Load TAS sequence from given file path into given sequence.
/// </summary>
/// <param name="filepath">The path to file for loading.</param>
/// <param name="seq">The TAS sequence to load.</param>
/// <exception cref="Exception">Any exception occurs when loading.</exception>
public static void Load(string filepath, ITasSequence seq) { public static void Load(string filepath, ITasSequence seq) {
using (var fs = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read)) { using (var fs = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read)) {
Load(fs, seq); Load(fs, seq);
@@ -53,6 +85,12 @@ namespace BallanceTasEditor.Backend {
} }
} }
/// <summary>
/// Load TAS sequence from given file stream into given sequence.
/// </summary>
/// <param name="fs">The file stream for loading.</param>
/// <param name="seq">The TAS sequence to load.</param>
/// <exception cref="Exception">Any exception occurs when loading.</exception>
public static void Load(Stream fs, ITasSequence seq) { public static void Load(Stream fs, ITasSequence seq) {
// Read total bytes // Read total bytes
var lenCache = new byte[SIZEOF_I32]; var lenCache = new byte[SIZEOF_I32];

View File

@@ -17,9 +17,12 @@
<PackageReference Include="CommunityToolkit.HighPerformance" Version="8.4.0" /> <PackageReference Include="CommunityToolkit.HighPerformance" Version="8.4.0" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1" /> <PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1" />
<PackageReference Include="DotNetZip" Version="1.9.1.8" /> <PackageReference Include="DotNetZip" Version="1.9.1.8" />
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.142" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="10.0.5" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Frontend\Models\" />
<Folder Include="Frontend\Utils\" /> <Folder Include="Frontend\Utils\" />
</ItemGroup> </ItemGroup>

View File

@@ -0,0 +1,49 @@
using Microsoft.Xaml.Behaviors;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
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;
namespace BallanceTasEditor.Frontend.Behaviors {
public class ConfirmCloseBehavior : Behavior<Window> {
public ICommand ConfirmCommand {
get { return (ICommand)GetValue(ConfirmCommandProperty); }
set { SetValue(ConfirmCommandProperty, value); }
}
// Using a DependencyProperty as the backing store for ConfirmCommand. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ConfirmCommandProperty =
DependencyProperty.Register("ConfirmCommand", typeof(ICommand), typeof(ConfirmCloseBehavior));
protected override void OnAttached() {
base.OnAttached();
AssociatedObject.Closing += OnClosing;
}
protected override void OnDetaching() {
AssociatedObject.Closing -= OnClosing;
base.OnDetaching();
}
private void OnClosing(object? sender, CancelEventArgs e) {
if (ConfirmCommand?.CanExecute(null) == true) {
// 假设Command返回 bool 或通过回调/事件通知结果
bool allowClose = (Func<object?, bool>)ConfirmCommand.Execute(null);
e.Cancel = !allowClose;
}
}
}
}

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BallanceTasEditor.Frontend.ViewModels {
public interface IDialogService {
NewFileDialogResult? ShowNewFileDialog();
OpenFileDialogResult? ShowOpenFileDialog();
void ShowOpenFileFailedDialog(Exception e);
SaveFileDialogResult? ShowSaveFileDialog();
void ShowSaveFileFailedDialog(Exception e);
bool ShowConfirmCloseFileDialog(string message);
bool ShowConfirmExitWhenOpeningFileDialog();
bool ShowFileChangedDialog();
GotoDialogResult? ShowGotoDialog();
EditFpsDialogResult? ShowEditFpsDialog();
AddFrameDialogResult? ShowAddFrameDialog();
PreferenceDialogResult? ShowPreferenceDialog();
void ShowAboutDialog();
}
public record NewFileDialogResult {
public required uint Fps { get; init; }
public required int Count { get; init; }
}
public record OpenFileDialogResult {
public required string Path { get; init; }
}
public record SaveFileDialogResult {
public required string Path { get; init; }
}
public record GotoDialogResult { }
public record EditFpsDialogResult { }
public record AddFrameDialogResult { }
public record PreferenceDialogResult { }
}

View File

@@ -0,0 +1,156 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BallanceTasEditor.Frontend.ViewModels {
public partial class MainWindow : ObservableObject {
public MainWindow(IDialogService dialogService) {
m_DialogService = dialogService;
this.TasFile = null;
this.TasFilePath = null;
}
private IDialogService m_DialogService;
#region File Operation
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(WindowTitle))]
[NotifyCanExecuteChangedFor(nameof(NewFileCommand))]
[NotifyCanExecuteChangedFor(nameof(OpenFileCommand))]
[NotifyCanExecuteChangedFor(nameof(SaveFileCommand))]
[NotifyCanExecuteChangedFor(nameof(SaveFileAsCommand))]
[NotifyCanExecuteChangedFor(nameof(CloseFileCommand))]
private Backend.ITasSequence? tasFile;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(WindowTitle))]
private string? tasFilePath;
[RelayCommand(CanExecute = nameof(CanNewFile))]
private void NewFile() {
// Request new file properties
var dialog = m_DialogService.ShowNewFileDialog();
if (dialog is null) return;
// Initialize sequence
var seq = new Backend.ListTasSequence();
// Initialize items
Backend.TasStorage.Init(seq, dialog.Count, dialog.Fps);
// Set members
this.TasFile = seq;
this.TasFilePath = null;
}
private bool CanNewFile() {
return this.TasFile is null;
}
[RelayCommand(CanExecute = nameof(CanOpenFile))]
private void OpenFile() {
// Request file path
var dialog = m_DialogService.ShowOpenFileDialog();
if (dialog is null) return;
// Initialize sequence
var seq = new Backend.ListTasSequence();
// Load into sequence
try {
Backend.TasStorage.Load(dialog.Path, seq);
} catch (Exception e) {
m_DialogService.ShowOpenFileFailedDialog(e);
return;
}
// Set members
this.TasFile = seq;
this.TasFilePath = dialog.Path;
}
private bool CanOpenFile() {
return this.TasFile is null;
}
[RelayCommand(CanExecute = nameof(CanSaveFile))]
private void SaveFile() {
// If there is no associated file path,
// it means that this file is not stored on disk,
// We must make a request to user for fetching it.
string? filePath = this.TasFilePath;
if (filePath is null) {
var dialog = m_DialogService.ShowSaveFileDialog();
if (dialog is null) return;
filePath = dialog.Path;
}
// Save file
try {
Backend.TasStorage.Save(filePath, this.TasFile.Unwrap());
} catch (Exception e) {
m_DialogService.ShowSaveFileFailedDialog(e);
return;
}
// Update member
this.TasFilePath = filePath;
}
private bool CanSaveFile() {
return this.TasFile is not null;
}
[RelayCommand(CanExecute = nameof(CanSaveFileAs))]
private void SaveFileAs() {
// We always request a new path when saving as
var dialog = m_DialogService.ShowSaveFileDialog();
if (dialog is null) return;
// Save file
try {
Backend.TasStorage.Save(dialog.Path, this.TasFile.Unwrap());
} catch (Exception e) {
m_DialogService.ShowSaveFileFailedDialog(e);
return;
}
// Set file path
TasFilePath = dialog.Path;
}
private bool CanSaveFileAs() {
return this.TasFile is not null;
}
[RelayCommand(CanExecute = nameof(CanCloseFile))]
private void CloseFile() {
this.TasFile = null;
this.TasFilePath = null;
}
private bool CanCloseFile() {
return this.TasFile is not null;
}
#endregion
#region UI Only
public string WindowTitle {
get {
if (TasFile is null) {
return "Ballance TAS Editor";
} else {
if (TasFilePath is null) {
return "Ballance TAS Editor - [Untitled]";
} else {
return $"Ballance TAS Editor - [{TasFilePath}]";
}
}
}
}
#endregion
}
}

View File

@@ -9,11 +9,6 @@ using System.Threading.Tasks;
namespace BallanceTasEditor.Frontend.ViewModels { namespace BallanceTasEditor.Frontend.ViewModels {
public struct NewFileDialogResult {
public int Count { get; set; }
public float DeltaTime { get; set; }
}
public partial class NewFileDialog : ObservableValidator { public partial class NewFileDialog : ObservableValidator {
public NewFileDialog() { public NewFileDialog() {
Count = 10000.ToString(); Count = 10000.ToString();

View File

@@ -0,0 +1,139 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace BallanceTasEditor.Frontend.Views {
public class DialogService : ViewModels.IDialogService {
public DialogService(Window parent) {
m_Parent = parent;
}
private readonly Window m_Parent;
public ViewModels.NewFileDialogResult? ShowNewFileDialog() {
var dialog = new NewFileDialog();
dialog.Owner = m_Parent;
if (dialog.ShowDialog() is true) {
// TODO: Finish result extraction
return new ViewModels.NewFileDialogResult() { Count = 0, Fps = 60 };
} else {
return null;
}
}
public ViewModels.OpenFileDialogResult? ShowOpenFileDialog() {
Microsoft.Win32.OpenFileDialog op = new Microsoft.Win32.OpenFileDialog();
op.RestoreDirectory = true;
op.Multiselect = false;
op.Filter = "TAS file(*.tas)|*.tas|All file(*.*)|*.*";
if (op.ShowDialog() is true) {
return new ViewModels.OpenFileDialogResult() { Path = op.FileName };
} else {
return null;
}
}
public void ShowOpenFileFailedDialog(Exception e) {
MessageBox.Show("Fail to open file. This file might not a legal TAS file." + e.Message,
"Error",
MessageBoxButton.OK, MessageBoxImage.Error);
}
public ViewModels.SaveFileDialogResult? ShowSaveFileDialog() {
Microsoft.Win32.SaveFileDialog op = new Microsoft.Win32.SaveFileDialog();
op.RestoreDirectory = true;
op.Filter = "TAS file(*.tas)|*.tas|All file(*.*)|*.*";
if (op.ShowDialog() is true) {
return new ViewModels.SaveFileDialogResult() { Path = op.FileName };
} else {
return null;
}
}
public void ShowSaveFileFailedDialog(Exception e) {
MessageBox.Show(
"Fail to save file." + e.Message,
"Error",
MessageBoxButton.OK, MessageBoxImage.Error);
}
public bool ShowConfirmCloseFileDialog(string message) {
var rv = MessageBox.Show(
"Do you want to close this TAS file? All changes will not be saved.",
"File Is Not Saved",
MessageBoxButton.YesNo, MessageBoxImage.Warning);
return rv == MessageBoxResult.Yes;
}
public bool ShowConfirmExitWhenOpeningFileDialog() {
var rv = MessageBox.Show(
"File is not closed. Do you want to just quit? All changes will not be saved.",
"File Is Not Saved",
MessageBoxButton.YesNo, MessageBoxImage.Warning);
return rv == MessageBoxResult.Yes;
}
public bool ShowFileChangedDialog() {
var rv = MessageBox.Show(
"File is changed. Do you want to reload it?",
"File Is Changed",
MessageBoxButton.YesNo, MessageBoxImage.Question);
return rv == MessageBoxResult.Yes;
}
public ViewModels.GotoDialogResult? ShowGotoDialog() {
var dialog = new GotoDialog();
dialog.Owner = m_Parent;
if (dialog.ShowDialog() is true) {
// TODO: Finish result extraction
return new ViewModels.GotoDialogResult();
} else {
return null;
}
}
public ViewModels.EditFpsDialogResult? ShowEditFpsDialog() {
var dialog = new EditFpsDialog();
dialog.Owner = m_Parent;
if (dialog.ShowDialog() is true) {
// TODO: Finish result extraction
return new ViewModels.EditFpsDialogResult();
} else {
return null;
}
}
public ViewModels.AddFrameDialogResult? ShowAddFrameDialog() {
var dialog = new AddFrameDialog();
dialog.Owner = m_Parent;
if (dialog.ShowDialog() is true) {
// TODO: Finish result extraction
return new ViewModels.AddFrameDialogResult();
} else {
return null;
}
}
public ViewModels.PreferenceDialogResult? ShowPreferenceDialog() {
var dialog = new PreferenceDialog();
dialog.Owner = m_Parent;
if (dialog.ShowDialog() is true) {
// TODO: Finish result extraction
return new ViewModels.PreferenceDialogResult();
} else {
return null;
}
}
public void ShowAboutDialog() {
var dialog = new AboutDialog();
dialog.Owner = m_Parent;
dialog.ShowDialog();
}
}
}

View File

@@ -5,8 +5,11 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:BallanceTasEditor.Frontend.Views" xmlns:local="clr-namespace:BallanceTasEditor.Frontend.Views"
xmlns:styles="clr-namespace:BallanceTasEditor.Frontend.Styles" xmlns:styles="clr-namespace:BallanceTasEditor.Frontend.Styles"
mc:Ignorable="d" WindowStartupLocation="CenterScreen" xmlns:vm="clr-namespace:BallanceTasEditor.Frontend.ViewModels"
Title="Ballance TAS Editor" Height="600" Width="800" Icon="/Frontend/Assets/App.ico"> mc:Ignorable="d"
d:DataContext="{d:DesignInstance vm:MainWindow}"
WindowStartupLocation="CenterScreen"
Title="{Binding WindowTitle, Mode=OneWay}" Height="600" Width="800" Icon="/Frontend/Assets/App.ico">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
@@ -44,14 +47,14 @@
</Menu.Resources> </Menu.Resources>
<MenuItem Header="_File" Padding="5"> <MenuItem Header="_File" Padding="5">
<MenuItem Header="_New File" Icon="{StaticResource IconNewFile}" InputGestureText="Ctrl+N" Click="MenuItem_Click_3"/> <MenuItem Header="_New File" Icon="{StaticResource IconNewFile}" InputGestureText="Ctrl+N" Command="{Binding NewFileCommand}"/>
<MenuItem Header="_Open File" Icon="{StaticResource IconOpenFile}" InputGestureText="Ctrl+O"/> <MenuItem Header="_Open File" Icon="{StaticResource IconOpenFile}" InputGestureText="Ctrl+O" Command="{Binding OpenFileCommand}"/>
<Separator/> <Separator/>
<MenuItem Header="_Save File" Icon="{StaticResource IconSaveFile}" InputGestureText="Ctrl+S"/> <MenuItem Header="_Save File" Icon="{StaticResource IconSaveFile}" InputGestureText="Ctrl+S" Command="{Binding SaveFileCommand}"/>
<MenuItem Header="Save File as ..." Icon="{StaticResource IconSaveFileAs}"/> <MenuItem Header="Save File as ..." Icon="{StaticResource IconSaveFileAs}" Command="{Binding SaveFileAsCommand}"/>
<MenuItem Header="Save File then _Run Game" Icon="{StaticResource IconSaveFileThenRunGame}" InputGestureText="B"/> <MenuItem Header="Save File then _Run Game" Icon="{StaticResource IconSaveFileThenRunGame}" InputGestureText="B"/>
<Separator/> <Separator/>
<MenuItem Header="Close File" Icon="{StaticResource IconCloseFile}"/> <MenuItem Header="Close File" Icon="{StaticResource IconCloseFile}" Command="{Binding CloseFileCommand}"/>
<MenuItem Header="Exit" Icon="{StaticResource IconExit}"/> <MenuItem Header="Exit" Icon="{StaticResource IconExit}"/>
</MenuItem> </MenuItem>
<MenuItem Header="_Edit" Padding="5"> <MenuItem Header="_Edit" Padding="5">
@@ -62,20 +65,20 @@
<MenuItem Header="Previous Item" Icon="{StaticResource IconPreviousItem}" InputGestureText="S"/> <MenuItem Header="Previous Item" Icon="{StaticResource IconPreviousItem}" InputGestureText="S"/>
<MenuItem Header="Next Page" Icon="{StaticResource IconNextPage}" InputGestureText="D"/> <MenuItem Header="Next Page" Icon="{StaticResource IconNextPage}" InputGestureText="D"/>
<MenuItem Header="Next Item" Icon="{StaticResource IconNextItem}" InputGestureText="F"/> <MenuItem Header="Next Item" Icon="{StaticResource IconNextItem}" InputGestureText="F"/>
<MenuItem Header="Goto Item" Icon="{StaticResource IconGoto}" InputGestureText="G" Click="MenuItem_Click_4"/> <MenuItem Header="Goto Item" Icon="{StaticResource IconGoto}" InputGestureText="G"/>
<Separator/> <Separator/>
<MenuItem Header="Select Mode" Icon="{StaticResource IconSelectMode}"/> <MenuItem Header="Select Mode" Icon="{StaticResource IconSelectMode}"/>
<MenuItem Header="Fill Mode" Icon="{StaticResource IconFillMode}"/> <MenuItem Header="Fill Mode" Icon="{StaticResource IconFillMode}"/>
<MenuItem Header="Draw Mode" Icon="{StaticResource IconDrawMode}"/> <MenuItem Header="Draw Mode" Icon="{StaticResource IconDrawMode}"/>
<Separator/> <Separator/>
<MenuItem Header="Clear Keys" Icon="{StaticResource IconClearKeys}"/> <MenuItem Header="Clear Keys" Icon="{StaticResource IconClearKeys}"/>
<MenuItem Header="Uniform FPS" Icon="{StaticResource IconUniformFps}" Click="MenuItem_Click_5"/> <MenuItem Header="Uniform FPS" Icon="{StaticResource IconUniformFps}"/>
<Separator/> <Separator/>
<MenuItem Header="Preference" Icon="{StaticResource IconPreference}" InputGestureText="Ctrl+P" Click="MenuItem_Click"/> <MenuItem Header="Preference" Icon="{StaticResource IconPreference}" InputGestureText="Ctrl+P"/>
</MenuItem> </MenuItem>
<MenuItem Header="_Help" Padding="5"> <MenuItem Header="_Help" Padding="5">
<MenuItem Header="Report Bug" Icon="{StaticResource IconReportBug}"/> <MenuItem Header="Report Bug" Icon="{StaticResource IconReportBug}"/>
<MenuItem Header="About" Icon="{StaticResource IconAbout}" Click="MenuItem_Click_1"/> <MenuItem Header="About" Icon="{StaticResource IconAbout}"/>
</MenuItem> </MenuItem>
</Menu> </Menu>
@@ -133,14 +136,14 @@
<MenuItem Header="Paste after This" Icon="{StaticResource IconPaste}" InputGestureText="Ctrl+V"/> <MenuItem Header="Paste after This" Icon="{StaticResource IconPaste}" InputGestureText="Ctrl+V"/>
<MenuItem Header="Paste before This"/> <MenuItem Header="Paste before This"/>
<Separator/> <Separator/>
<MenuItem Header="Delete This" Icon="{StaticResource IconDelete}"/> <MenuItem Header="Delete" Icon="{StaticResource IconDelete}"/>
<MenuItem Header="Delete after This" InputGestureText="Del"/> <MenuItem Header="Delete after This" InputGestureText="Del"/>
<MenuItem Header="Delete before This" InputGestureText="Backspace"/> <MenuItem Header="Delete before This" InputGestureText="Backspace"/>
<Separator/> <Separator/>
<MenuItem Header="Add after This" Icon="{StaticResource IconAdd}" Click="MenuItem_Click_2"/> <MenuItem Header="Add after This" Icon="{StaticResource IconAdd}"/>
<MenuItem Header="Add before This"/> <MenuItem Header="Add before This"/>
<Separator/> <Separator/>
<MenuItem Header="Set FPS" Icon="{StaticResource IconFps}" Click="MenuItem_Click_6"/> <MenuItem Header="Set FPS" Icon="{StaticResource IconFps}"/>
</ContextMenu> </ContextMenu>
</local:TasViewer.ContextMenu> </local:TasViewer.ContextMenu>
</local:TasViewer> </local:TasViewer>
@@ -150,8 +153,6 @@
<!-- 这玩意要逆序排列才能达到我想要的需求也是奇葩 --> <!-- 这玩意要逆序排列才能达到我想要的需求也是奇葩 -->
<StatusBarItem Content="v2.0 stable" DockPanel.Dock="Right" Foreground="Gray" FontStyle="Italic"/> <StatusBarItem Content="v2.0 stable" DockPanel.Dock="Right" Foreground="Gray" FontStyle="Italic"/>
<Separator DockPanel.Dock="Right"/> <Separator DockPanel.Dock="Right"/>
<StatusBarItem Content="$PasteMode" DockPanel.Dock="Right"/>
<Separator DockPanel.Dock="Right"/>
<StatusBarItem Content="$Selection" DockPanel.Dock="Right"/> <StatusBarItem Content="$Selection" DockPanel.Dock="Right"/>
<Separator DockPanel.Dock="Right"/> <Separator DockPanel.Dock="Right"/>
<StatusBarItem Content="$ToolMode" DockPanel.Dock="Right"/> <StatusBarItem Content="$ToolMode" DockPanel.Dock="Right"/>

View File

@@ -20,48 +20,8 @@ namespace BallanceTasEditor.Frontend.Views {
public partial class MainWindow : Window { public partial class MainWindow : Window {
public MainWindow() { public MainWindow() {
InitializeComponent(); InitializeComponent();
} var dialogService = new DialogService(this);
this.DataContext = new ViewModels.MainWindow(dialogService);
private void MenuItem_Click_3(object sender, RoutedEventArgs e) {
var dialog = new NewFileDialog();
dialog.Owner = this;
dialog.ShowDialog();
}
private void MenuItem_Click(object sender, RoutedEventArgs e) {
var dialog = new PreferenceDialog();
dialog.Owner = this;
dialog.ShowDialog();
}
private void MenuItem_Click_1(object sender, RoutedEventArgs e) {
var dialog = new AboutDialog();
dialog.Owner = this;
dialog.ShowDialog();
}
private void MenuItem_Click_4(object sender, RoutedEventArgs e) {
var dialog =new GotoDialog();
dialog.Owner = this;
dialog.ShowDialog();
}
private void MenuItem_Click_5(object sender, RoutedEventArgs e) {
var dialog = new EditFpsDialog();
dialog.Owner = this;
dialog.ShowDialog();
}
private void MenuItem_Click_6(object sender, RoutedEventArgs e) {
var dialog = new EditFpsDialog();
dialog.Owner = this;
dialog.ShowDialog();
}
private void MenuItem_Click_2(object sender, RoutedEventArgs e) {
var dialog = new AddFrameDialog();
dialog.Owner = this;
dialog.ShowDialog();
} }
} }

View File

@@ -5,7 +5,7 @@ using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace BallanceTasEditor.Backend { namespace BallanceTasEditor {
public static class NullableExtensions { public static class NullableExtensions {
public static T Unwrap<T>(this T? value, [CallerArgumentExpression(nameof(value))] string? paramName = null) where T : class { public static T Unwrap<T>(this T? value, [CallerArgumentExpression(nameof(value))] string? paramName = null) where T : class {
ArgumentNullException.ThrowIfNull(value, paramName); ArgumentNullException.ThrowIfNull(value, paramName);

View File

@@ -40,7 +40,7 @@
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />--> <!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->
<!-- Windows 10 --> <!-- Windows 10 -->
<!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />--> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application> </application>
</compatibility> </compatibility>