Compare commits
6 Commits
afcc848e5b
...
ng
| Author | SHA1 | Date | |
|---|---|---|---|
| 6bcc12bf71 | |||
| 394768d862 | |||
| 6cb984fa92 | |||
| b938fe6acc | |||
| 5b230e40fc | |||
| c7578cc5a7 |
@@ -3,7 +3,7 @@
|
||||
viewBox="0 0 24 24"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="Cancel.svg"
|
||||
sodipodi:docname="FieldError.svg"
|
||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
@@ -31,11 +31,15 @@
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<path
|
||||
d="M 12,2 C 17.5,2 22,6.5 22,12 22,17.5 17.5,22 12,22 6.5,22 2,17.5 2,12 2,6.5 6.5,2 12,2 m 0,2 C 10.1,4 8.4,4.6 7.1,5.7 L 18.3,16.9 C 19.3,15.5 20,13.8 20,12 20,7.6 16.4,4 12,4 M 16.9,18.3 5.7,7.1 C 4.6,8.4 4,10.1 4,12 c 0,4.4 3.6,8 8,8 1.9,0 3.6,-0.6 4.9,-1.7 z"
|
||||
d="M 12,20 C 7.59,20 4,16.41 4,12 4,7.59 7.59,4 12,4 c 4.41,0 8,3.59 8,8 0,4.41 -3.59,8 -8,8 M 12,2 C 6.47,2 2,6.47 2,12 2,17.53 6.47,22 12,22 17.53,22 22,17.53 22,12 22,6.47 17.53,2 12,2 M 14.59,8 12,10.59 9.41,8 8,9.41 10.59,12 8,14.59 9.41,16 12,13.41 14.59,16 16,14.59 13.41,12 16,9.41 Z"
|
||||
id="path1"
|
||||
style="display:none" />
|
||||
<path
|
||||
style="fill:#f44336;fill-opacity:1;stroke-width:0.000911392"
|
||||
d="M 11.529114,21.976736 C 10.22238,21.889141 9.0970988,21.622033 8.0114321,21.141743 5.0411839,19.827731 2.8549818,17.127924 2.2192797,13.988839 2.0648176,13.226108 2.0373265,12.925617 2.0373265,12 c 0,-0.925617 0.027491,-1.226108 0.1819532,-1.988839 C 2.9672398,6.3177478 5.8643146,3.2688861 9.5104706,2.3379617 10.411349,2.1079524 11.074436,2.0255288 12.01519,2.026618 c 1.996985,0.00231 3.807406,0.5499071 5.467923,1.6538737 2.455605,1.6325675 4.010624,4.1204917 4.426934,7.0827903 0.07357,0.523513 0.07357,1.949923 0,2.473436 -0.326722,2.324832 -1.359557,4.372036 -2.997659,5.94173 -1.596575,1.5299 -3.611736,2.485613 -5.773541,2.738166 -0.389906,0.04555 -1.312862,0.08002 -1.609733,0.06012 z m 1.563357,-2.032544 c 0.925767,-0.122293 1.765668,-0.379382 2.5417,-0.778003 0.341195,-0.175259 0.942023,-0.568381 1.150639,-0.752863 l 0.136709,-0.120893 -5.605032,-5.606976 C 8.2337189,9.6016202 5.704605,7.0785217 5.6962335,7.0785715 5.6878621,7.0786214 5.5669726,7.2324188 5.4275903,7.4203437 4.7111807,8.3862562 4.2640759,9.494702 4.0680851,10.790778 c -0.065181,0.431036 -0.090079,1.53472 -0.044835,1.987446 0.2406062,2.407596 1.546148,4.562332 3.5868762,5.919974 0.4303689,0.286313 1.2614491,0.698786 1.7409864,0.864068 0.6315864,0.217689 1.3326383,0.369549 1.9653433,0.425729 0.425722,0.0378 1.326427,0.01559 1.776015,-0.0438 z m 5.537897,-3.505461 c 0.686116,-1.101759 1.081879,-2.107709 1.286142,-3.269111 0.0819,-0.465656 0.111841,-1.431584 0.06035,-1.946773 C 19.735881,8.811741 18.433266,6.6619006 16.388891,5.3012482 15.724197,4.8588544 14.767203,4.4347242 13.990518,4.2383123 12.090514,3.75783 10.037364,3.9752015 8.3658289,4.8338107 8.0246342,5.0090703 7.4238064,5.4021922 7.2151899,5.5866738 L 7.078481,5.707567 l 5.605063,5.608114 5.605064,5.608114 0.07595,-0.09009 c 0.04177,-0.04955 0.161387,-0.227288 0.265811,-0.394971 z"
|
||||
style="fill:#f44336;stroke-width:0.000911392;fill-opacity:1"
|
||||
d="M 11.498734,21.97371 C 10.538494,21.927417 9.4258037,21.695256 8.4759494,21.34301 8.0845522,21.197863 7.2207324,20.778082 6.8506329,20.553172 6.0186267,20.047561 5.2728592,19.437005 4.6411761,18.744304 2.5685315,16.471448 1.6637184,13.447187 2.1463612,10.405597 2.5810326,7.6663212 4.1740918,5.2042016 6.5063119,3.6671662 7.8220107,2.8000629 9.2792591,2.2701711 10.875949,2.0782573 c 0.574874,-0.069097 1.673228,-0.069097 2.248102,0 3.266567,0.3926243 6.042908,2.2588082 7.635954,5.13269 C 21.54949,8.63519 21.979539,10.323974 21.979539,12 c 0,3.054298 -1.366007,5.885584 -3.773974,7.822213 -0.621166,0.499579 -1.583784,1.066107 -2.374062,1.397204 -1.3282,0.556467 -2.869699,0.824827 -4.332769,0.754293 z m 1.112044,-1.98475 c 3.561075,-0.284458 6.493751,-2.850098 7.226887,-6.322415 C 20.26315,11.651338 19.880556,9.4662 18.803847,7.7620253 17.492724,5.6868267 15.384677,4.3473261 12.941772,4.0371303 12.549756,3.9873527 11.449156,3.9874453 11.058228,4.0372887 9.198254,4.2744355 7.5140166,5.1092443 6.254174,6.4184649 4.9923609,7.7297335 4.2458673,9.3098233 4.0364135,11.112759 c -0.059996,0.516438 -0.042475,1.588281 0.033872,2.072051 0.2243066,1.421314 0.78997,2.713286 1.6759437,3.827848 0.2493782,0.31372 0.8842563,0.953423 1.195543,1.204629 1.6091067,1.298537 3.6413238,1.933644 5.6690058,1.771673 z"
|
||||
id="path2" />
|
||||
<path
|
||||
style="fill:#f44336;fill-opacity:1;stroke-width:0.000911392"
|
||||
d="M 8.7189889,15.281014 8.0206349,14.582165 9.3114492,13.291082 10.602264,12 9.3114492,10.708918 8.0206349,9.4178352 8.7189889,8.7189858 9.4173428,8.0201364 10.708804,9.3113356 12.000265,10.602535 13.291164,9.3113678 14.582063,8.0202008 15.280797,8.718935 15.979531,9.4176691 14.688634,10.708835 13.397736,12 l 1.290898,1.291165 1.290897,1.291166 -0.698734,0.698734 -0.698734,0.698734 -1.290899,-1.291167 -1.290899,-1.291167 -1.291461,1.291199 -1.2914612,1.291199 z"
|
||||
id="path3" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.3 KiB |
49
BallanceTasEditor/Assets/AppIcons/SequenceKind.svg
Normal file
49
BallanceTasEditor/Assets/AppIcons/SequenceKind.svg
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="SequenceLayout.svg"
|
||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="32.916667"
|
||||
inkscape:cx="12"
|
||||
inkscape:cy="12"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<path
|
||||
d="m 15,7 v 9 H 10 V 7 h 5 m 6,-2 h -3 v 13 h 3 V 5 M 17,5 H 8 v 13 h 9 V 5 M 7,5 H 4 v 13 h 3 z"
|
||||
id="path1"
|
||||
style="display:none" />
|
||||
<path
|
||||
style="fill:#607d8b;fill-opacity:1;stroke-width:0.000911392"
|
||||
d="M 4.0253165,11.498734 V 5.0126582 H 5.4987342 6.9721519 V 11.498734 17.98481 H 5.4987342 4.0253165 Z"
|
||||
id="path2" />
|
||||
<path
|
||||
style="fill:#607d8b;fill-opacity:1;stroke-width:0.000911392"
|
||||
d="M 8.0050633,11.498734 V 5.0126582 h 4.4962027 4.496202 V 11.498734 17.98481 H 12.501266 8.0050633 Z m 7.0177217,0 V 6.9873418 H 12.501266 9.9797468 v 4.5113922 4.511393 h 2.5215192 2.521519 z"
|
||||
id="path3" />
|
||||
<path
|
||||
style="fill:#607d8b;fill-opacity:1;stroke-width:0.000911392"
|
||||
d="M 18,11.498734 V 5.0126582 h 1.488608 1.488607 V 11.498734 17.98481 H 19.488608 18 Z"
|
||||
id="path4" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -16,8 +16,8 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.HighPerformance" Version="8.4.0" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
<PackageReference Include="OneOf" Version="3.0.271" />
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="10.0.5" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 115 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 99 KiB |
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace BallanceTasEditor.Frontend.Converters {
|
||||
|
||||
internal class GenericEnumRadioButtonConverter<T> where T: struct {
|
||||
public object Convert(object value, object parameter) {
|
||||
var susValue = value as T?;
|
||||
var susParam = parameter as T?;
|
||||
|
||||
if (susValue is null || susParam is null) {
|
||||
return Binding.DoNothing;
|
||||
} else {
|
||||
return susValue.Value.Equals(susParam.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, object parameter) {
|
||||
var susValue = value as bool?;
|
||||
var susParam = parameter as T?;
|
||||
|
||||
if (susValue is null || susParam is null) {
|
||||
return Binding.DoNothing;
|
||||
} else {
|
||||
return susValue.Value ? susParam.Value : Binding.DoNothing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ValueConversion(typeof(Shared.SequenceKind), typeof(bool))]
|
||||
public class SequenceKindRadioButtonConverter : IValueConverter {
|
||||
public static readonly SequenceKindRadioButtonConverter Instance = new();
|
||||
|
||||
private readonly GenericEnumRadioButtonConverter<Shared.SequenceKind> m_Inner = new();
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
return m_Inner.Convert(value, parameter);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
return m_Inner.ConvertBack(value, parameter);
|
||||
}
|
||||
}
|
||||
|
||||
[ValueConversion(typeof(Shared.EditorLayoutKind), typeof(bool))]
|
||||
public class EditorLayoutKindRadioButtonConverter : IValueConverter {
|
||||
public static readonly EditorLayoutKindRadioButtonConverter Instance = new();
|
||||
|
||||
private readonly GenericEnumRadioButtonConverter<Shared.EditorLayoutKind> m_Inner = new();
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
return m_Inner.Convert(value, parameter);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
return m_Inner.ConvertBack(value, parameter);
|
||||
}
|
||||
}
|
||||
|
||||
[ValueConversion(typeof(Shared.EditorPasteBehavior), typeof(bool))]
|
||||
public class EditorPasteBehaviorRadioButtonConverter : IValueConverter {
|
||||
public static readonly EditorPasteBehaviorRadioButtonConverter Instance = new();
|
||||
|
||||
private readonly GenericEnumRadioButtonConverter<Shared.EditorPasteBehavior> m_Inner = new();
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
return m_Inner.Convert(value, parameter);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
return m_Inner.ConvertBack(value, parameter);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace BallanceTasEditor.Frontend.Converters {
|
||||
|
||||
[ValueConversion(typeof(bool), typeof(Visibility))]
|
||||
public class IsVisibleToVisibilityConverter : IValueConverter {
|
||||
public static readonly IsVisibleToVisibilityConverter Instance = new IsVisibleToVisibilityConverter();
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
var susBool = value as bool?;
|
||||
if (susBool is null) {
|
||||
return Binding.DoNothing;
|
||||
} else {
|
||||
return susBool.Value ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
return Binding.DoNothing;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.SequenceKind sequenceKind;
|
||||
[ObservableProperty]
|
||||
private Shared.EditorLayoutKind editorLayout;
|
||||
[ObservableProperty]
|
||||
private Shared.EditorPasteBehavior pasteBehavior;
|
||||
[ObservableProperty]
|
||||
private int frameCount;
|
||||
[ObservableProperty]
|
||||
private string gamePath;
|
||||
|
||||
[MemberNotNull(nameof(SequenceKind))]
|
||||
[MemberNotNull(nameof(EditorLayout))]
|
||||
[MemberNotNull(nameof(PasteBehavior))]
|
||||
[MemberNotNull(nameof(FrameCount))]
|
||||
[MemberNotNull(nameof(GamePath))]
|
||||
private void FromSingleton() {
|
||||
var singleton = Shared.EditorConfiguration.Instance;
|
||||
|
||||
SequenceKind = singleton.SequenceKind;
|
||||
EditorLayout = singleton.EditorLayout;
|
||||
PasteBehavior = singleton.PasteBehavior;
|
||||
FrameCount = singleton.FrameCount;
|
||||
GamePath = singleton.GamePath;
|
||||
}
|
||||
|
||||
private void ToSingleton() {
|
||||
var singleton = Shared.EditorConfiguration.Instance;
|
||||
|
||||
singleton.SequenceKind = SequenceKind;
|
||||
singleton.EditorLayout = EditorLayout;
|
||||
singleton.PasteBehavior = PasteBehavior;
|
||||
singleton.FrameCount = FrameCount;
|
||||
singleton.GamePath = GamePath;
|
||||
}
|
||||
|
||||
public void Save() {
|
||||
ToSingleton();
|
||||
Shared.EditorConfiguration.Instance.Save();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.SequenceKind kind, int count, uint fps) {
|
||||
// Check status
|
||||
if (IsFileLoaded) {
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
// Initialize sequence
|
||||
var seq = TasSequenceKindHelper.CreateSequenceByKind(kind);
|
||||
var seq = Shared.SequenceKindHelper.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.SequenceKind kind, string path) {
|
||||
// Check status
|
||||
if (IsFileLoaded) {
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
// Initialize sequence
|
||||
var seq = TasSequenceKindHelper.CreateSequenceByKind(kind);
|
||||
var seq = Shared.SequenceKindHelper.CreateSequenceByKind(kind);
|
||||
// Load into sequence
|
||||
Backend.TasStorage.Load(path, seq);
|
||||
// Set members
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,7 +17,9 @@ namespace BallanceTasEditor.Frontend.Shared {
|
||||
bool ShowConfirmExitWhenOpeningFileDialog();
|
||||
bool ShowFileChangedDialog();
|
||||
GotoDialogResult? ShowGotoDialog();
|
||||
bool ShowConfirmClearKeysDialog();
|
||||
EditFpsDialogResult? ShowEditFpsDialog();
|
||||
bool ShowConfirmUniformFpsDialog();
|
||||
AddFrameDialogResult? ShowAddFrameDialog();
|
||||
PreferenceDialogResult? ShowPreferenceDialog();
|
||||
void ShowManuallyReportBugDialog();
|
||||
@@ -133,6 +135,14 @@ namespace BallanceTasEditor.Frontend.Shared {
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowConfirmClearKeysDialog() {
|
||||
var rv = MessageBox.Show(
|
||||
"Do you really want to clear keys for all frames?\nThis operation can not be revoked.",
|
||||
"Clear Keys",
|
||||
MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||
return rv == MessageBoxResult.Yes;
|
||||
}
|
||||
|
||||
public EditFpsDialogResult? ShowEditFpsDialog() {
|
||||
var dialog = new Views.EditFpsDialog();
|
||||
dialog.Owner = m_Parent;
|
||||
@@ -144,6 +154,14 @@ namespace BallanceTasEditor.Frontend.Shared {
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowConfirmUniformFpsDialog() {
|
||||
var rv = MessageBox.Show(
|
||||
"Do you really want to set an uniform FPS value for all frames?\nThis operation can not be revoked.",
|
||||
"Uniform FPS",
|
||||
MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||
return rv == MessageBoxResult.Yes;
|
||||
}
|
||||
|
||||
public AddFrameDialogResult? ShowAddFrameDialog() {
|
||||
var dialog = new Views.AddFrameDialog();
|
||||
dialog.Owner = m_Parent;
|
||||
|
||||
@@ -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 SequenceKind SequenceKind { get; set; }
|
||||
public EditorLayoutKind EditorLayout { get; set; }
|
||||
public EditorPasteBehavior PasteBehavior { get; set; }
|
||||
public int FrameCount { get; set; }
|
||||
public string GamePath { get; set; }
|
||||
|
||||
[MemberNotNull(nameof(SequenceKind))]
|
||||
[MemberNotNull(nameof(EditorLayout))]
|
||||
[MemberNotNull(nameof(PasteBehavior))]
|
||||
[MemberNotNull(nameof(FrameCount))]
|
||||
[MemberNotNull(nameof(GamePath))]
|
||||
private void FromRaw(RawEditorConfiguration raw) {
|
||||
SequenceKind = raw.SequenceKind;
|
||||
EditorLayout = raw.EditorLayout;
|
||||
PasteBehavior = raw.PasteBehavior;
|
||||
FrameCount = raw.FrameCount;
|
||||
GamePath = raw.GamePath;
|
||||
}
|
||||
|
||||
private RawEditorConfiguration ToRaw() {
|
||||
return new RawEditorConfiguration {
|
||||
SequenceKind = SequenceKind,
|
||||
EditorLayout = EditorLayout,
|
||||
PasteBehavior = PasteBehavior,
|
||||
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<RawEditorConfiguration>(fs.ReadToEnd()).Unwrap();
|
||||
// Apply to self.
|
||||
FromRaw(raw);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[MemberNotNull(nameof(SequenceKind))]
|
||||
[MemberNotNull(nameof(EditorLayout))]
|
||||
[MemberNotNull(nameof(PasteBehavior))]
|
||||
[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 SequenceKind SequenceKind { get; set; } = SequenceKind.Array;
|
||||
|
||||
[JsonProperty("editor_layout", Required = Required.Always)]
|
||||
[JsonConverter(typeof(EditorLayoutKindConverter))]
|
||||
public EditorLayoutKind EditorLayout { get; set; } = EditorLayoutKind.Vertical;
|
||||
|
||||
[JsonProperty("paste_behavior", Required = Required.Always)]
|
||||
[JsonConverter(typeof(EditorPasteBehaviorConverter))]
|
||||
public EditorPasteBehavior PasteBehavior { get; set; } = EditorPasteBehavior.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<SequenceKind> {
|
||||
public override SequenceKind ReadJson(JsonReader reader, Type objectType, SequenceKind existingValue, bool hasExistingValue, JsonSerializer serializer) {
|
||||
if (reader.TokenType == JsonToken.String) {
|
||||
var value = (reader.Value as string).Unwrap();
|
||||
if (SequenceKindHelper.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, SequenceKind value, JsonSerializer serializer) {
|
||||
writer.WriteValue(SequenceKindHelper.ToString(value));
|
||||
}
|
||||
}
|
||||
|
||||
private class EditorLayoutKindConverter : JsonConverter<EditorLayoutKind> {
|
||||
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 EditorPasteBehaviorConverter : JsonConverter<EditorPasteBehavior> {
|
||||
public override EditorPasteBehavior ReadJson(JsonReader reader, Type objectType, EditorPasteBehavior existingValue, bool hasExistingValue, JsonSerializer serializer) {
|
||||
if (reader.TokenType == JsonToken.String) {
|
||||
var value = (reader.Value as string).Unwrap();
|
||||
if (EditorPasteBehaviorHelper.TryParse(value, out var kind)) {
|
||||
return kind;
|
||||
} else {
|
||||
throw new JsonSerializationException($"given string can not be parsed as EditorPasteBehavior: {value}");
|
||||
}
|
||||
} else {
|
||||
throw new JsonSerializationException($"expect a integer but got {reader.TokenType}");
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, EditorPasteBehavior value, JsonSerializer serializer) {
|
||||
writer.WriteValue(EditorPasteBehaviorHelper.ToString(value));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
106
BallanceTasEditor/BallanceTasEditor/Frontend/Shared/Enums.cs
Normal file
106
BallanceTasEditor/BallanceTasEditor/Frontend/Shared/Enums.cs
Normal file
@@ -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 SequenceKind {
|
||||
Array,
|
||||
DoubleLinkedList
|
||||
}
|
||||
|
||||
public static class SequenceKindHelper {
|
||||
public static Backend.ITasSequence CreateSequenceByKind(SequenceKind kind) {
|
||||
return kind switch {
|
||||
SequenceKind.Array => new Backend.ListTasSequence(),
|
||||
SequenceKind.DoubleLinkedList => new Backend.LegacyTasSequence(),
|
||||
_ => throw new UnreachableException(),
|
||||
};
|
||||
}
|
||||
|
||||
public static bool TryParse(string s, out SequenceKind value) {
|
||||
switch (s) {
|
||||
case "array":
|
||||
value = SequenceKind.Array;
|
||||
return true;
|
||||
case "double_linked_list":
|
||||
value = SequenceKind.DoubleLinkedList;
|
||||
return true;
|
||||
default:
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ToString(SequenceKind kind) {
|
||||
return kind switch {
|
||||
SequenceKind.Array => "array",
|
||||
SequenceKind.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 EditorPasteBehavior {
|
||||
Insert,
|
||||
Override
|
||||
}
|
||||
|
||||
public static class EditorPasteBehaviorHelper {
|
||||
public static bool TryParse(string s, out EditorPasteBehavior value) {
|
||||
switch (s) {
|
||||
case "insert":
|
||||
value = EditorPasteBehavior.Insert;
|
||||
return true;
|
||||
case "override":
|
||||
value = EditorPasteBehavior.Override;
|
||||
return true;
|
||||
default:
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ToString(EditorPasteBehavior mode) {
|
||||
return mode switch {
|
||||
EditorPasteBehavior.Insert => "insert",
|
||||
EditorPasteBehavior.Override => "override",
|
||||
_ => throw new UnreachableException(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<ControlTemplate x:Key="TextBoxErrorTemplate">
|
||||
<Grid>
|
||||
<Image Source="/Frontend/Assets/Cancel.ico" RenderOptions.BitmapScalingMode="HighQuality"
|
||||
<Image Source="/Frontend/Assets/FieldError.ico" RenderOptions.BitmapScalingMode="HighQuality"
|
||||
Width="16" Height="16" Margin="0, 0, 4, 0" VerticalAlignment="Center" HorizontalAlignment="Right">
|
||||
<Image.ToolTip>
|
||||
<ToolTip>
|
||||
|
||||
@@ -33,7 +33,6 @@ namespace BallanceTasEditor.Frontend.ViewModels {
|
||||
#region File Operation
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(WindowTitle))]
|
||||
private Models.TasFile tasFile;
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(WindowTitle))]
|
||||
@@ -42,11 +41,16 @@ namespace BallanceTasEditor.Frontend.ViewModels {
|
||||
private void TasFile_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e) {
|
||||
// YYC MARK:
|
||||
// Due to the shitty limit of MVVM Toolkit,
|
||||
// I was forced trigger these command manually.
|
||||
// I was forced trigger these manually.
|
||||
OnPropertyChanged(nameof(IsVisibleForLoadedFile));
|
||||
OnPropertyChanged(nameof(WindowTitle));
|
||||
OnPropertyChanged(nameof(IsVisibleForNotLoadedFile));
|
||||
|
||||
NewFileCommand.NotifyCanExecuteChanged();
|
||||
OpenFileCommand.NotifyCanExecuteChanged();
|
||||
SaveFileCommand.NotifyCanExecuteChanged();
|
||||
SaveFileAsCommand.NotifyCanExecuteChanged();
|
||||
SaveFileThenRunGameCommand.NotifyCanExecuteChanged();
|
||||
CloseFileCommand.NotifyCanExecuteChanged();
|
||||
}
|
||||
|
||||
@@ -57,7 +61,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.SequenceKind.Array, dialog.Count, dialog.Fps);
|
||||
// Set members
|
||||
TasFilePath = null;
|
||||
// Send notification
|
||||
@@ -76,7 +80,7 @@ namespace BallanceTasEditor.Frontend.ViewModels {
|
||||
|
||||
// Load file
|
||||
try {
|
||||
TasFile.LoadFile(Models.TasSequenceKind.Array, dialog.Path);
|
||||
TasFile.LoadFile(Shared.SequenceKind.Array, dialog.Path);
|
||||
} catch (Exception e) {
|
||||
m_DialogService.ShowOpenFileFailedDialog(e);
|
||||
return;
|
||||
@@ -159,6 +163,19 @@ namespace BallanceTasEditor.Frontend.ViewModels {
|
||||
|
||||
#endregion
|
||||
|
||||
#region Special Save with Running Game
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanSaveFileThenRunGame))]
|
||||
private void SaveFileThenRunGame() {
|
||||
SaveFile();
|
||||
}
|
||||
|
||||
private bool CanSaveFileThenRunGame() {
|
||||
return CanSaveFile() && true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Exit Stuff
|
||||
|
||||
[RelayCommand]
|
||||
@@ -179,6 +196,133 @@ namespace BallanceTasEditor.Frontend.ViewModels {
|
||||
|
||||
#region Edit Menu
|
||||
|
||||
#region Undo and Redo
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanUndo))]
|
||||
private void Undo() {
|
||||
|
||||
}
|
||||
|
||||
private bool CanUndo() {
|
||||
return true;
|
||||
}
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanRedo))]
|
||||
private void Redo() {
|
||||
|
||||
}
|
||||
|
||||
private bool CanRedo() {
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Viewer Operation
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanPreviousPage))]
|
||||
private void PreviousPage() {
|
||||
|
||||
}
|
||||
|
||||
private bool CanPreviousPage() {
|
||||
return true;
|
||||
}
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanPreviousItem))]
|
||||
private void PreviousItem() {
|
||||
|
||||
}
|
||||
|
||||
private bool CanPreviousItem() {
|
||||
return true;
|
||||
}
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanNextPage))]
|
||||
private void NextPage() {
|
||||
|
||||
}
|
||||
|
||||
private bool CanNextPage() {
|
||||
return true;
|
||||
}
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanNextItem))]
|
||||
private void NextItem() {
|
||||
|
||||
}
|
||||
|
||||
private bool CanNextItem() {
|
||||
return true;
|
||||
}
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanGoto))]
|
||||
private void Goto() {
|
||||
|
||||
}
|
||||
|
||||
private bool CanGoto() {
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tool Mode
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanSelectMode))]
|
||||
private void SelectMode() {
|
||||
|
||||
}
|
||||
|
||||
private bool CanSelectMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanFillMode))]
|
||||
private void FillMode() {
|
||||
|
||||
}
|
||||
|
||||
private bool CanFillMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanDrawMode))]
|
||||
private void DrawMode() {
|
||||
|
||||
}
|
||||
|
||||
private bool CanDrawMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Misc Edit Operations
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanUniformFps))]
|
||||
private void ClearKeys() {
|
||||
m_DialogService.ShowConfirmClearKeysDialog();
|
||||
}
|
||||
|
||||
private bool CanClearKeys() {
|
||||
return true;
|
||||
}
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanUniformFps))]
|
||||
private void UniformFps() {
|
||||
var rv = m_DialogService.ShowEditFpsDialog();
|
||||
if (rv is not null) {
|
||||
m_DialogService.ShowConfirmUniformFpsDialog();
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanUniformFps() {
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Preference
|
||||
|
||||
@@ -216,6 +360,9 @@ namespace BallanceTasEditor.Frontend.ViewModels {
|
||||
[ObservableProperty]
|
||||
private string statusMessage;
|
||||
|
||||
/// <summary>
|
||||
/// The UI thread timer for dimming status message after specific duration.
|
||||
/// </summary>
|
||||
private DispatcherTimer m_StatusMessageDimmer;
|
||||
|
||||
private void UpdateStatusMessage(string msg) {
|
||||
@@ -248,6 +395,14 @@ namespace BallanceTasEditor.Frontend.ViewModels {
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsVisibleForLoadedFile {
|
||||
get => TasFile.IsFileLoaded;
|
||||
}
|
||||
|
||||
public bool IsVisibleForNotLoadedFile {
|
||||
get => TasFile.IsFileNotLoaded;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
@@ -2,17 +2,47 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BallanceTasEditor.Frontend.ViewModels {
|
||||
public partial class PreferenceDialog : ObservableObject {
|
||||
public partial class PreferenceDialog : ObservableValidator {
|
||||
public PreferenceDialog() {
|
||||
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private Shared.SequenceKind sequenceKind;
|
||||
[ObservableProperty]
|
||||
private Shared.EditorLayoutKind layoutKind;
|
||||
[ObservableProperty]
|
||||
private Shared.EditorPasteBehavior pasteBehavior;
|
||||
[ObservableProperty]
|
||||
[NotifyDataErrorInfo]
|
||||
[CustomValidation(typeof(PreferenceDialog), nameof(ValidateCount))]
|
||||
[NotifyCanExecuteChangedFor(nameof(OkCommand))]
|
||||
private string frameCount;
|
||||
[ObservableProperty]
|
||||
private string gamePath;
|
||||
|
||||
#region Validators
|
||||
|
||||
private static readonly Validators.ValidatorAdapter<string, int, Validators.CountValidator> g_CountValidator =
|
||||
new Validators.ValidatorAdapter<string, int, Validators.CountValidator>(new Validators.CountValidator());
|
||||
|
||||
public static ValidationResult? ValidateCount(string value, ValidationContext context) {
|
||||
return g_CountValidator.Validate(value, context);
|
||||
}
|
||||
|
||||
//public Shared.NewFileDialogResult GetUserInput() {
|
||||
// return
|
||||
//}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Commands
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanOk))]
|
||||
private void Ok() {
|
||||
@@ -20,8 +50,7 @@ namespace BallanceTasEditor.Frontend.ViewModels {
|
||||
}
|
||||
|
||||
private bool CanOk() {
|
||||
// TODO
|
||||
return true;
|
||||
return !HasErrors;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
@@ -29,12 +58,13 @@ namespace BallanceTasEditor.Frontend.ViewModels {
|
||||
OnRequestCloseDialog(false);
|
||||
}
|
||||
|
||||
|
||||
public event Shared.RequestCloseDialogEventHandler? RequestCloseDialog;
|
||||
|
||||
private void OnRequestCloseDialog(bool result) {
|
||||
RequestCloseDialog?.Invoke(new Shared.RequestCloseDialogEventArgs { Result = result });
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:BallanceTasEditor.Frontend.Views"
|
||||
xmlns:vm="clr-namespace:BallanceTasEditor.Frontend.ViewModels"
|
||||
xmlns:conveter="clr-namespace:BallanceTasEditor.Frontend.Converters"
|
||||
xmlns:widget="clr-namespace:BallanceTasEditor.Frontend.Widgets"
|
||||
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">
|
||||
Title="{Binding WindowTitle, Mode=OneWay}" Height="800" Width="600" Icon="/Frontend/Assets/App.ico">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
@@ -52,27 +52,27 @@
|
||||
<Separator/>
|
||||
<MenuItem Header="_Save File" Icon="{StaticResource IconSaveFile}" InputGestureText="Ctrl+S" Command="{Binding SaveFileCommand}"/>
|
||||
<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" Command="{Binding SaveFileThenRunGameCommand}"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="Close File" Icon="{StaticResource IconCloseFile}" Command="{Binding CloseFileCommand}"/>
|
||||
<MenuItem Header="Exit" Icon="{StaticResource IconExit}" Command="{Binding ExitCommand}"/>
|
||||
</MenuItem>
|
||||
<MenuItem Header="_Edit" Padding="5">
|
||||
<MenuItem Header="_Undo" Icon="{StaticResource IconUndo}" InputGestureText="Ctrl+Z"/>
|
||||
<MenuItem Header="_Redo" Icon="{StaticResource IconRedo}" InputGestureText="Ctrl+Y"/>
|
||||
<MenuItem Header="_Undo" Icon="{StaticResource IconUndo}" InputGestureText="Ctrl+Z" Command="{Binding UndoCommand}"/>
|
||||
<MenuItem Header="_Redo" Icon="{StaticResource IconRedo}" InputGestureText="Ctrl+Y" Command="{Binding RedoCommand}"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="Previous Page" Icon="{StaticResource IconPreviousPage}" InputGestureText="A"/>
|
||||
<MenuItem Header="Previous Item" Icon="{StaticResource IconPreviousItem}" InputGestureText="S"/>
|
||||
<MenuItem Header="Next Page" Icon="{StaticResource IconNextPage}" InputGestureText="D"/>
|
||||
<MenuItem Header="Next Item" Icon="{StaticResource IconNextItem}" InputGestureText="F"/>
|
||||
<MenuItem Header="Goto Item" Icon="{StaticResource IconGoto}" InputGestureText="G"/>
|
||||
<MenuItem Header="Previous Page" Icon="{StaticResource IconPreviousPage}" InputGestureText="A" Command="{Binding PreviousPageCommand}"/>
|
||||
<MenuItem Header="Previous Item" Icon="{StaticResource IconPreviousItem}" InputGestureText="S" Command="{Binding PreviousItemCommand}"/>
|
||||
<MenuItem Header="Next Page" Icon="{StaticResource IconNextPage}" InputGestureText="D" Command="{Binding NextPageCommand}"/>
|
||||
<MenuItem Header="Next Item" Icon="{StaticResource IconNextItem}" InputGestureText="F" Command="{Binding NextItemCommand}"/>
|
||||
<MenuItem Header="Goto Item" Icon="{StaticResource IconGoto}" InputGestureText="G" Command="{Binding GotoCommand}"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="Select Mode" Icon="{StaticResource IconSelectMode}" InputGestureText="Q"/>
|
||||
<MenuItem Header="Fill Mode" Icon="{StaticResource IconFillMode}" InputGestureText="W"/>
|
||||
<MenuItem Header="Draw Mode" Icon="{StaticResource IconDrawMode}" InputGestureText="E"/>
|
||||
<MenuItem Header="Select Mode" Icon="{StaticResource IconSelectMode}" InputGestureText="Q" Command="{Binding SelectModeCommand}"/>
|
||||
<MenuItem Header="Fill Mode" Icon="{StaticResource IconFillMode}" InputGestureText="W" Command="{Binding FillModeCommand}"/>
|
||||
<MenuItem Header="Draw Mode" Icon="{StaticResource IconDrawMode}" InputGestureText="E" Command="{Binding DrawModeCommand}"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="Clear Keys" Icon="{StaticResource IconClearKeys}"/>
|
||||
<MenuItem Header="Uniform FPS" Icon="{StaticResource IconUniformFps}"/>
|
||||
<MenuItem Header="Clear Keys" Icon="{StaticResource IconClearKeys}" Command="{Binding ClearKeysCommand}"/>
|
||||
<MenuItem Header="Uniform FPS" Icon="{StaticResource IconUniformFps}" Command="{Binding UniformFpsCommand}"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="Preference" Icon="{StaticResource IconPreference}" InputGestureText="Ctrl+P" Command="{Binding PreferenceCommand}"/>
|
||||
</MenuItem>
|
||||
@@ -82,7 +82,23 @@
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
|
||||
<Grid Grid.Row="1">
|
||||
<Grid Grid.Row="1" Visibility="{Binding IsVisibleForNotLoadedFile, Mode=OneWay, Converter={x:Static conveter:IsVisibleToVisibilityConverter.Instance}}">
|
||||
<Grid VerticalAlignment="Center" HorizontalAlignment="Center" AllowDrop="True">
|
||||
<Rectangle StrokeThickness="4" Stroke="Gray" StrokeDashArray="4 4" Fill="Transparent"/>
|
||||
<StackPanel Orientation="Horizontal" Margin="20">
|
||||
<Image Source="/Frontend/Assets/OpenFile.ico" Width="24" Height="24" Margin="5" VerticalAlignment="Center"/>
|
||||
<TextBlock Margin="5" Text="Create, Open or Drop a TAS File in There for Editing" Foreground="Gray" FontSize="16" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" Visibility="{Binding IsVisibleForLoadedFile, Mode=OneWay, Converter={x:Static conveter:IsVisibleToVisibilityConverter.Instance}}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
@@ -91,30 +107,26 @@
|
||||
<StackPanel Orientation="Horizontal" Grid.Column="0">
|
||||
<widget:IconButton ButtonText="Select Mode"
|
||||
ButtonIcon="/Frontend/Assets/SelectMode.ico"
|
||||
Margin="5" Padding="5"/>
|
||||
Margin="5" Padding="5"
|
||||
Command="{Binding SelectModeCommand}"/>
|
||||
<widget:IconButton ButtonText="Fill Mode"
|
||||
ButtonIcon="/Frontend/Assets/FillMode.ico"
|
||||
Margin="5" Padding="5"/>
|
||||
Margin="5" Padding="5"
|
||||
Command="{Binding FillModeCommand}"/>
|
||||
<widget:IconButton ButtonText="Draw Mode"
|
||||
ButtonIcon="/Frontend/Assets/DrawMode.ico"
|
||||
Margin="5" Padding="5"/>
|
||||
Margin="5" Padding="5"
|
||||
Command="{Binding DrawModeCommand}"/>
|
||||
</StackPanel>
|
||||
|
||||
<widget:IconButton ButtonText="Save File then Run Game"
|
||||
ButtonIcon="/Frontend/Assets/SaveFileThenRunGame.ico"
|
||||
Grid.Column="1" Margin="5" Padding="5"/>
|
||||
Grid.Column="1" Margin="5" Padding="5"
|
||||
Command="{Binding SaveFileThenRunGameCommand}"/>
|
||||
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="2">
|
||||
<Grid VerticalAlignment="Center" HorizontalAlignment="Center" AllowDrop="True">
|
||||
<Rectangle StrokeThickness="4" Stroke="Gray" StrokeDashArray="4 4" Fill="Transparent"/>
|
||||
<StackPanel Orientation="Horizontal" Margin="20">
|
||||
<Image Source="/Frontend/Assets/OpenFile.ico" Width="24" Height="24" Margin="5" VerticalAlignment="Center"/>
|
||||
<TextBlock Margin="5" Text="Create, Open or Drop a TAS File in There for Editing" Foreground="Gray" FontSize="16" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1">
|
||||
<local:TasViewer>
|
||||
<local:TasViewer.ContextMenu>
|
||||
<ContextMenu>
|
||||
@@ -152,8 +164,9 @@
|
||||
</local:TasViewer.ContextMenu>
|
||||
</local:TasViewer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<StatusBar Grid.Row="3">
|
||||
<StatusBar Grid.Row="2">
|
||||
<!-- 这玩意要逆序排列才能达到我想要的需求也是奇葩 -->
|
||||
<StatusBarItem Content="v2.0 stable" DockPanel.Dock="Right" Foreground="Gray" FontStyle="Italic"/>
|
||||
<Separator DockPanel.Dock="Right"/>
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:BallanceTasEditor.Frontend.Views"
|
||||
xmlns:vm="clr-namespace:BallanceTasEditor.Frontend.ViewModels"
|
||||
xmlns:conveter="clr-namespace:BallanceTasEditor.Frontend.Converters"
|
||||
xmlns:shared="clr-namespace:BallanceTasEditor.Frontend.Shared"
|
||||
xmlns:widget="clr-namespace:BallanceTasEditor.Frontend.Widgets"
|
||||
d:DataContext="{d:DesignInstance vm:PreferenceDialog}"
|
||||
mc:Ignorable="d" WindowStartupLocation="CenterOwner" ResizeMode="NoResize" ShowInTaskbar="False"
|
||||
Title="Editor Preference" Height="450" Width="400" Icon="/Frontend/Assets/Preference.ico">
|
||||
Title="Editor Preference" Height="500" Width="400" Icon="/Frontend/Assets/Preference.ico">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
@@ -17,34 +19,64 @@
|
||||
|
||||
<ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Visible">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<widget:IconGroupBox GroupBoxText="Editor Layout"
|
||||
GroupBoxIcon="/Frontend/Assets/EditorLayout.ico"
|
||||
<widget:IconGroupBox GroupBoxText="Sequence Kind"
|
||||
GroupBoxIcon="/Frontend/Assets/SequenceKind.ico"
|
||||
Margin="10" Padding="10">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<RadioButton Content="Horizontal Layout" GroupName="EditorLayout" Grid.Column="0"/>
|
||||
<RadioButton Content="Vertical Layout" GroupName="EditorLayout" Grid.Column="1"/>
|
||||
<RadioButton Content="Array" GroupName="SequenceKind"
|
||||
ToolTip="Good for browsing. Bad for frequently inserting and removing frames."
|
||||
IsChecked="{Binding SequenceKind, Mode=TwoWay, Converter={x:Static conveter:SequenceKindRadioButtonConverter.Instance}, ConverterParameter={x:Static shared:SequenceKind.Array}}"
|
||||
Grid.Column="0"/>
|
||||
<RadioButton Content="Double Linked List" GroupName="SequenceKind"
|
||||
ToolTip="Good for frequently inserting and removing frames. Bad for browsing."
|
||||
IsChecked="{Binding SequenceKind, Mode=TwoWay, Converter={x:Static conveter:SequenceKindRadioButtonConverter.Instance}, ConverterParameter={x:Static shared:SequenceKind.DoubleLinkedList}}"
|
||||
Grid.Column="1"/>
|
||||
</Grid>
|
||||
</widget:IconGroupBox>
|
||||
<widget:IconGroupBox GroupBoxText="Editor Layout"
|
||||
GroupBoxIcon="/Frontend/Assets/EditorLayout.ico"
|
||||
Margin="10" Padding="10"
|
||||
IsEnabled="False">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<RadioButton Content="Horizontal Layout" GroupName="EditorLayout"
|
||||
IsChecked="{Binding LayoutKind, Mode=TwoWay, Converter={x:Static conveter:EditorLayoutKindRadioButtonConverter.Instance}, ConverterParameter={x:Static shared:EditorLayoutKind.Horizontal}}"
|
||||
Grid.Column="0"/>
|
||||
<RadioButton Content="Vertical Layout" GroupName="EditorLayout"
|
||||
IsChecked="{Binding LayoutKind, Mode=TwoWay, Converter={x:Static conveter:EditorLayoutKindRadioButtonConverter.Instance}, ConverterParameter={x:Static shared:EditorLayoutKind.Vertical}}"
|
||||
Grid.Column="1"/>
|
||||
</Grid>
|
||||
</widget:IconGroupBox>
|
||||
<widget:IconGroupBox GroupBoxText="Paste Behavior"
|
||||
GroupBoxIcon="/Frontend/Assets/PasteFrame.ico"
|
||||
Margin="10" Padding="10">
|
||||
Margin="10" Padding="10"
|
||||
IsEnabled="False">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<RadioButton Content="Insert Paste" GroupName="PasteBehavior" Grid.Column="0"/>
|
||||
<RadioButton Content="Overwritten Paste" GroupName="PasteBehavior" Grid.Column="1"/>
|
||||
<RadioButton Content="Insert Paste" GroupName="PasteBehavior"
|
||||
IsChecked="{Binding PasteBehavior, Mode=TwoWay, Converter={x:Static conveter:EditorPasteBehaviorRadioButtonConverter.Instance}, ConverterParameter={x:Static shared:EditorPasteBehavior.Insert}}"
|
||||
Grid.Column="0"/>
|
||||
<RadioButton Content="Overwritten Paste" GroupName="PasteBehavior"
|
||||
IsChecked="{Binding PasteBehavior, Mode=TwoWay, Converter={x:Static conveter:EditorPasteBehaviorRadioButtonConverter.Instance}, ConverterParameter={x:Static shared:EditorPasteBehavior.Override}}"
|
||||
Grid.Column="1"/>
|
||||
</Grid>
|
||||
</widget:IconGroupBox>
|
||||
<widget:IconGroupBox GroupBoxText="Frame Count"
|
||||
GroupBoxIcon="/Frontend/Assets/Count.ico"
|
||||
Margin="10" Padding="10">
|
||||
<TextBox Padding="3"/>
|
||||
<TextBox Padding="3"
|
||||
Text="{Binding FrameCount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnNotifyDataErrors=True}"
|
||||
Style="{StaticResource TextBoxWithErrorNotifyStyle}"/>
|
||||
</widget:IconGroupBox>
|
||||
<widget:IconGroupBox GroupBoxText="Game Path"
|
||||
GroupBoxIcon="/Frontend/Assets/SaveFileThenRunGame.ico"
|
||||
|
||||
Reference in New Issue
Block a user