diff --git a/BallanceTasEditor/BallanceTasEditor/BallanceTasEditor.csproj b/BallanceTasEditor/BallanceTasEditor/BallanceTasEditor.csproj
index be52488..3f5051e 100644
--- a/BallanceTasEditor/BallanceTasEditor/BallanceTasEditor.csproj
+++ b/BallanceTasEditor/BallanceTasEditor/BallanceTasEditor.csproj
@@ -16,8 +16,8 @@
+
-
diff --git a/BallanceTasEditor/BallanceTasEditor/Frontend/Models/EditorSetting.cs b/BallanceTasEditor/BallanceTasEditor/Frontend/Models/EditorSetting.cs
new file mode 100644
index 0000000..1f7011d
--- /dev/null
+++ b/BallanceTasEditor/BallanceTasEditor/Frontend/Models/EditorSetting.cs
@@ -0,0 +1,67 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BallanceTasEditor.Frontend.Models {
+
+ public partial class EditorSetting : ObservableObject {
+
+ public EditorSetting() {
+ // YYC MARK:
+ // Due to the shitty conflict between CommunityToolkit.Mvvm and Nullable aware,
+ // I was forcely set this field to clear all warning.
+ GamePath = "";
+
+ // Initialize from singleton.
+ FromSingleton();
+ }
+
+ [ObservableProperty]
+ private Shared.TasSequenceKind sequenceKind;
+ [ObservableProperty]
+ private Shared.EditorLayoutKind editorLayout;
+ [ObservableProperty]
+ private Shared.EditorPasteMode pasteMode;
+ [ObservableProperty]
+ private int frameCount;
+ [ObservableProperty]
+ private string gamePath;
+
+ [MemberNotNull(nameof(SequenceKind))]
+ [MemberNotNull(nameof(EditorLayout))]
+ [MemberNotNull(nameof(PasteMode))]
+ [MemberNotNull(nameof(FrameCount))]
+ [MemberNotNull(nameof(GamePath))]
+ private void FromSingleton() {
+ var singleton = Shared.EditorConfiguration.Instance;
+
+ SequenceKind = singleton.SequenceKind;
+ EditorLayout = singleton.EditorLayout;
+ PasteMode = singleton.PasteMode;
+ FrameCount = singleton.FrameCount;
+ GamePath = singleton.GamePath;
+ }
+
+ private void ToSingleton() {
+ var singleton = Shared.EditorConfiguration.Instance;
+
+ singleton.SequenceKind = SequenceKind;
+ singleton.EditorLayout = EditorLayout;
+ singleton.PasteMode = PasteMode;
+ singleton.FrameCount = FrameCount;
+ singleton.GamePath = GamePath;
+ }
+
+ public void Save() {
+ ToSingleton();
+ Shared.EditorConfiguration.Instance.Save();
+ }
+ }
+
+}
diff --git a/BallanceTasEditor/BallanceTasEditor/Frontend/Models/TasFile.cs b/BallanceTasEditor/BallanceTasEditor/Frontend/Models/TasFile.cs
index 076528d..730e421 100644
--- a/BallanceTasEditor/BallanceTasEditor/Frontend/Models/TasFile.cs
+++ b/BallanceTasEditor/BallanceTasEditor/Frontend/Models/TasFile.cs
@@ -30,28 +30,28 @@ namespace BallanceTasEditor.Frontend.Models {
get => FileBody is null;
}
- public void NewFile(TasSequenceKind kind, int count, uint fps) {
+ public void NewFile(Shared.TasSequenceKind kind, int count, uint fps) {
// Check status
if (IsFileLoaded) {
throw new InvalidOperationException();
}
// Initialize sequence
- var seq = TasSequenceKindHelper.CreateSequenceByKind(kind);
+ var seq = Shared.TasSequenceKindHelper.CreateSequenceByKind(kind);
// Initialize items
Backend.TasStorage.Init(seq, count, fps);
// Set members
FileBody = seq;
}
- public void LoadFile(TasSequenceKind kind, string path) {
+ public void LoadFile(Shared.TasSequenceKind kind, string path) {
// Check status
if (IsFileLoaded) {
throw new InvalidOperationException();
}
// Initialize sequence
- var seq = TasSequenceKindHelper.CreateSequenceByKind(kind);
+ var seq = Shared.TasSequenceKindHelper.CreateSequenceByKind(kind);
// Load into sequence
Backend.TasStorage.Load(path, seq);
// Set members
diff --git a/BallanceTasEditor/BallanceTasEditor/Frontend/Models/TasSequenceKind.cs b/BallanceTasEditor/BallanceTasEditor/Frontend/Models/TasSequenceKind.cs
deleted file mode 100644
index 2618773..0000000
--- a/BallanceTasEditor/BallanceTasEditor/Frontend/Models/TasSequenceKind.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-
-namespace BallanceTasEditor.Frontend.Models {
- public enum TasSequenceKind {
- Array,
- DoubleLinkedList
- }
-
- public static class TasSequenceKindHelper {
- public static Backend.ITasSequence CreateSequenceByKind(TasSequenceKind kind) {
- return kind switch {
- TasSequenceKind.Array => new Backend.ListTasSequence(),
- TasSequenceKind.DoubleLinkedList => new Backend.LegacyTasSequence(),
- _ => throw new UnreachableException(),
- };
- }
- }
-
-}
diff --git a/BallanceTasEditor/BallanceTasEditor/Frontend/Shared/EditorConfiguration.cs b/BallanceTasEditor/BallanceTasEditor/Frontend/Shared/EditorConfiguration.cs
new file mode 100644
index 0000000..c304eb0
--- /dev/null
+++ b/BallanceTasEditor/BallanceTasEditor/Frontend/Shared/EditorConfiguration.cs
@@ -0,0 +1,185 @@
+using BallanceTasEditor.Frontend.Models;
+using CommunityToolkit.Mvvm.ComponentModel;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BallanceTasEditor.Frontend.Shared {
+ public class EditorConfiguration {
+
+ public static readonly EditorConfiguration Instance = new EditorConfiguration();
+
+ private EditorConfiguration() {
+ Init();
+ }
+
+ public TasSequenceKind SequenceKind { get; set; }
+ public EditorLayoutKind EditorLayout { get; set; }
+ public EditorPasteMode PasteMode { get; set; }
+ public int FrameCount { get; set; }
+ public string GamePath { get; set; }
+
+ [MemberNotNull(nameof(SequenceKind))]
+ [MemberNotNull(nameof(EditorLayout))]
+ [MemberNotNull(nameof(PasteMode))]
+ [MemberNotNull(nameof(FrameCount))]
+ [MemberNotNull(nameof(GamePath))]
+ private void FromRaw(RawEditorConfiguration raw) {
+ SequenceKind = raw.SequenceKind;
+ EditorLayout = raw.EditorLayout;
+ PasteMode = raw.PasteMode;
+ FrameCount = raw.FrameCount;
+ GamePath = raw.GamePath;
+ }
+
+ private RawEditorConfiguration ToRaw() {
+ return new RawEditorConfiguration {
+ SequenceKind = SequenceKind,
+ EditorLayout = EditorLayout,
+ PasteMode = PasteMode,
+ FrameCount = FrameCount,
+ GamePath = GamePath
+ };
+ }
+
+ private string GetSettingFilePath() {
+ string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
+ string selfAppDataPath = Path.Combine(appDataPath, "BallanceTasEditor");
+ return Path.Combine(selfAppDataPath, "BallanceTasEditor.cfg");
+ }
+
+ private bool Load() {
+ try {
+ using (var fs = new StreamReader(GetSettingFilePath(), Encoding.UTF8)) {
+ // Read semester object.
+ var raw = JsonConvert.DeserializeObject(fs.ReadToEnd()).Unwrap();
+ // Apply to self.
+ FromRaw(raw);
+ }
+ return true;
+ } catch (Exception) {
+ return false;
+ }
+ }
+
+ [MemberNotNull(nameof(SequenceKind))]
+ [MemberNotNull(nameof(EditorLayout))]
+ [MemberNotNull(nameof(PasteMode))]
+ [MemberNotNull(nameof(FrameCount))]
+ [MemberNotNull(nameof(GamePath))]
+ private void Init() {
+ var defaultRaw = new RawEditorConfiguration();
+ FromRaw(defaultRaw);
+ }
+
+ public void LoadOrInit() {
+ if (!Load()) {
+ Init();
+ }
+ }
+
+ public void Save() {
+ try {
+ // Check file path directory.
+ var settingFilePath = GetSettingFilePath();
+ var settingFileDirectory = Path.GetDirectoryName(settingFilePath).Unwrap();
+ if (!Directory.Exists(settingFileDirectory)) {
+ Directory.CreateDirectory(settingFileDirectory);
+ }
+ // Write it.
+ using (var fs = new StreamWriter(GetSettingFilePath(), false, Encoding.UTF8)) {
+ fs.Write(JsonConvert.SerializeObject(ToRaw()));
+ }
+ } catch (Exception) {
+ // Do nothing.
+ }
+ }
+
+ private class RawEditorConfiguration {
+ [JsonProperty("sequence_kind", Required = Required.Always)]
+ [JsonConverter(typeof(TasSequenceKindConverter))]
+ public TasSequenceKind SequenceKind { get; set; } = TasSequenceKind.Array;
+
+ [JsonProperty("editor_layout", Required = Required.Always)]
+ [JsonConverter(typeof(EditorLayoutKindConverter))]
+ public EditorLayoutKind EditorLayout { get; set; } = EditorLayoutKind.Vertical;
+
+ [JsonProperty("paste_mode", Required = Required.Always)]
+ [JsonConverter(typeof(EditorPasteModeConverter))]
+ public EditorPasteMode PasteMode { get; set; } = EditorPasteMode.Insert;
+
+ [JsonProperty("frame_count", Required = Required.Always)]
+ public int FrameCount { get; set; } = 20;
+
+ [JsonProperty("game_path", Required = Required.Always)]
+ public string GamePath { get; set; } = "";
+ }
+
+ #region Custom JSON Converter
+
+ private class TasSequenceKindConverter : JsonConverter {
+ public override TasSequenceKind ReadJson(JsonReader reader, Type objectType, TasSequenceKind existingValue, bool hasExistingValue, JsonSerializer serializer) {
+ if (reader.TokenType == JsonToken.String) {
+ var value = (reader.Value as string).Unwrap();
+ if (TasSequenceKindHelper.TryParse(value, out var kind)) {
+ return kind;
+ } else {
+ throw new JsonSerializationException($"given string can not be parsed as TasSequenceKind: {value}");
+ }
+ } else {
+ throw new JsonSerializationException($"expect a integer but got {reader.TokenType}");
+ }
+ }
+
+ public override void WriteJson(JsonWriter writer, TasSequenceKind value, JsonSerializer serializer) {
+ writer.WriteValue(TasSequenceKindHelper.ToString(value));
+ }
+ }
+
+ private class EditorLayoutKindConverter : JsonConverter {
+ public override EditorLayoutKind ReadJson(JsonReader reader, Type objectType, EditorLayoutKind existingValue, bool hasExistingValue, JsonSerializer serializer) {
+ if (reader.TokenType == JsonToken.String) {
+ var value = (reader.Value as string).Unwrap();
+ if (EditorLayoutKindHelper.TryParse(value, out var kind)) {
+ return kind;
+ } else {
+ throw new JsonSerializationException($"given string can not be parsed as EditorLayoutKind: {value}");
+ }
+ } else {
+ throw new JsonSerializationException($"expect a integer but got {reader.TokenType}");
+ }
+ }
+
+ public override void WriteJson(JsonWriter writer, EditorLayoutKind value, JsonSerializer serializer) {
+ writer.WriteValue(EditorLayoutKindHelper.ToString(value));
+ }
+ }
+
+ private class EditorPasteModeConverter : JsonConverter {
+ public override EditorPasteMode ReadJson(JsonReader reader, Type objectType, EditorPasteMode existingValue, bool hasExistingValue, JsonSerializer serializer) {
+ if (reader.TokenType == JsonToken.String) {
+ var value = (reader.Value as string).Unwrap();
+ if (EditorPasteModeHelper.TryParse(value, out var kind)) {
+ return kind;
+ } else {
+ throw new JsonSerializationException($"given string can not be parsed as EditorPasteMode: {value}");
+ }
+ } else {
+ throw new JsonSerializationException($"expect a integer but got {reader.TokenType}");
+ }
+ }
+
+ public override void WriteJson(JsonWriter writer, EditorPasteMode value, JsonSerializer serializer) {
+ writer.WriteValue(EditorPasteModeHelper.ToString(value));
+ }
+ }
+
+ #endregion
+
+ }
+}
diff --git a/BallanceTasEditor/BallanceTasEditor/Frontend/Shared/Enums.cs b/BallanceTasEditor/BallanceTasEditor/Frontend/Shared/Enums.cs
new file mode 100644
index 0000000..cd23e03
--- /dev/null
+++ b/BallanceTasEditor/BallanceTasEditor/Frontend/Shared/Enums.cs
@@ -0,0 +1,106 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BallanceTasEditor.Frontend.Shared {
+
+ public enum TasSequenceKind {
+ Array,
+ DoubleLinkedList
+ }
+
+ public static class TasSequenceKindHelper {
+ public static Backend.ITasSequence CreateSequenceByKind(TasSequenceKind kind) {
+ return kind switch {
+ TasSequenceKind.Array => new Backend.ListTasSequence(),
+ TasSequenceKind.DoubleLinkedList => new Backend.LegacyTasSequence(),
+ _ => throw new UnreachableException(),
+ };
+ }
+
+ public static bool TryParse(string s, out TasSequenceKind value) {
+ switch (s) {
+ case "array":
+ value = TasSequenceKind.Array;
+ return true;
+ case "double_linked_list":
+ value = TasSequenceKind.DoubleLinkedList;
+ return true;
+ default:
+ value = default;
+ return false;
+ }
+ }
+
+ public static string ToString(TasSequenceKind kind) {
+ return kind switch {
+ TasSequenceKind.Array => "array",
+ TasSequenceKind.DoubleLinkedList => "double_linked_list",
+ _ => throw new UnreachableException(),
+ };
+ }
+ }
+
+ public enum EditorLayoutKind {
+ Vertical,
+ Horizontal
+ }
+
+ public static class EditorLayoutKindHelper {
+ public static bool TryParse(string s, out EditorLayoutKind value) {
+ switch (s) {
+ case "vertical":
+ value = EditorLayoutKind.Vertical;
+ return true;
+ case "horizontal":
+ value = EditorLayoutKind.Horizontal;
+ return true;
+ default:
+ value = default;
+ return false;
+ }
+ }
+ public static string ToString(EditorLayoutKind kind) {
+ return kind switch {
+ EditorLayoutKind.Vertical => "vertical",
+ EditorLayoutKind.Horizontal => "horizontal",
+ _ => throw new UnreachableException(),
+ };
+ }
+ }
+
+ public enum EditorPasteMode {
+ Insert,
+ Override
+ }
+
+ public static class EditorPasteModeHelper {
+ public static bool TryParse(string s, out EditorPasteMode value) {
+ switch (s) {
+ case "insert":
+ value = EditorPasteMode.Insert;
+ return true;
+ case "override":
+ value = EditorPasteMode.Override;
+ return true;
+ default:
+ value = default;
+ return false;
+ }
+ }
+
+ public static string ToString(EditorPasteMode mode) {
+ return mode switch {
+ EditorPasteMode.Insert => "insert",
+ EditorPasteMode.Override => "override",
+ _ => throw new UnreachableException(),
+ };
+ }
+ }
+
+
+}
diff --git a/BallanceTasEditor/BallanceTasEditor/Frontend/ViewModels/MainWindow.cs b/BallanceTasEditor/BallanceTasEditor/Frontend/ViewModels/MainWindow.cs
index e9e5f54..d672f0d 100644
--- a/BallanceTasEditor/BallanceTasEditor/Frontend/ViewModels/MainWindow.cs
+++ b/BallanceTasEditor/BallanceTasEditor/Frontend/ViewModels/MainWindow.cs
@@ -57,7 +57,7 @@ namespace BallanceTasEditor.Frontend.ViewModels {
if (dialog is null) return;
// Create new file
- TasFile.NewFile(Models.TasSequenceKind.Array, dialog.Count, dialog.Fps);
+ TasFile.NewFile(Shared.TasSequenceKind.Array, dialog.Count, dialog.Fps);
// Set members
TasFilePath = null;
// Send notification
@@ -76,7 +76,7 @@ namespace BallanceTasEditor.Frontend.ViewModels {
// Load file
try {
- TasFile.LoadFile(Models.TasSequenceKind.Array, dialog.Path);
+ TasFile.LoadFile(Shared.TasSequenceKind.Array, dialog.Path);
} catch (Exception e) {
m_DialogService.ShowOpenFileFailedDialog(e);
return;