feat: write shit
This commit is contained in:
20
BallanceTasEditor/BallanceTasEditor/Backend/AppSettings.cs
Normal file
20
BallanceTasEditor/BallanceTasEditor/Backend/AppSettings.cs
Normal 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; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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];
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 { }
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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"/>
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user