commit 7259c36da11b7977a4e1287f5aaaae51a4302aa2 Author: yyc12345 Date: Thu May 13 15:49:26 2021 +0800 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..72de34f --- /dev/null +++ b/.gitignore @@ -0,0 +1,388 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Nuget personal access tokens and Credentials +nuget.config + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +.idea/ +*.sln.iml \ No newline at end of file diff --git a/App.xaml b/App.xaml new file mode 100644 index 0000000..0a66cf4 --- /dev/null +++ b/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/App.xaml.cs b/App.xaml.cs new file mode 100644 index 0000000..1127de7 --- /dev/null +++ b/App.xaml.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Windows; + +namespace BallanceTASEditor { + /// + /// App.xaml 的交互逻辑 + /// + public partial class App : Application { + } +} diff --git a/BallanceTASEditor.csproj b/BallanceTASEditor.csproj new file mode 100644 index 0000000..0f7020e --- /dev/null +++ b/BallanceTASEditor.csproj @@ -0,0 +1,104 @@ + + + + + Debug + AnyCPU + {3127A635-B9E5-4C78-8414-0B9B196EC25E} + WinExe + BallanceTASEditor + BallanceTASEditor + v4.0 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + 4.0 + + + + + + packages\zlib.net.1.0.4.0\lib\zlib.net.dll + + + + + MSBuild:Compile + Designer + + + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + + + + + + MainWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + \ No newline at end of file diff --git a/BallanceTASEditor.sln b/BallanceTASEditor.sln new file mode 100644 index 0000000..ed2152a --- /dev/null +++ b/BallanceTASEditor.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29418.71 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BallanceTASEditor", "BallanceTASEditor.csproj", "{3127A635-B9E5-4C78-8414-0B9B196EC25E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3127A635-B9E5-4C78-8414-0B9B196EC25E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3127A635-B9E5-4C78-8414-0B9B196EC25E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3127A635-B9E5-4C78-8414-0B9B196EC25E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3127A635-B9E5-4C78-8414-0B9B196EC25E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {ABECA811-4FBB-4394-805E-EEBC799ECC89} + EndGlobalSection +EndGlobal diff --git a/Core/TASFile.cs b/Core/TASFile.cs new file mode 100644 index 0000000..da3d260 --- /dev/null +++ b/Core/TASFile.cs @@ -0,0 +1,81 @@ +using BallanceTASEditor.Core.TASStruct; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Text; + +namespace BallanceTASEditor.Core { + public class TASFile { + public TASFile(string filename) { + mFilename = filename; + mMem = new LinkedList(); + var fs = new FileStream(mFilename, FileMode.Open, FileAccess.Read, FileShare.Read); + ZlibUtil.DecompressTAS(mMem, fs); + fs.Close(); + fs.Dispose(); + mPointer = mMem.First; + } + + public string mFilename { get; private set; } + public long mFrameCount { get { return mMem.Count; } } + LinkedList mMem; + LinkedListNode mPointer; + + public void Shift(long shiftNum) { + if (mPointer == null) return; + if (shiftNum == 0) return; + var absNum = Math.Abs(shiftNum); + if (shiftNum > 0) { + for(long num = 0; num < absNum && mPointer.Next != null; num++) { + mPointer = mPointer.Next; + } + } else { + for (long num = 0; num < absNum && mPointer.Previous != null; num++) { + mPointer = mPointer.Previous; + } + } + } + + public int Get(ObservableCollection container, long startIndex, int count) { + if (mPointer == null) return 0; + var cachePointer = mPointer; + int i; + for(i = 0; i < count && cachePointer != null; i++, startIndex++) { + container[i].Reload(startIndex, cachePointer.Value); + cachePointer = cachePointer.Next; + } + return i; + } + + public void Set(FrameDataField field, long prevRange, long nextRange, bool isSet) { + if (mPointer == null) return; + + var cachePointer = mPointer; + var offset = ConstValue.Mapping[field]; + for (long i = 0; i < nextRange && cachePointer != null; i++) { + if (isSet) cachePointer.Value.SetKeyStates(offset); + else cachePointer.Value.UnsetKeyStates(offset); + cachePointer = cachePointer.Next; + } + for (long i = 0; i < prevRange && cachePointer != null; i++) { + if (isSet) cachePointer.Value.SetKeyStates(offset); + else cachePointer.Value.UnsetKeyStates(offset); + cachePointer = cachePointer.Previous; + } + } + + public void Save() { + var fs = new FileStream(mFilename, FileMode.Create, FileAccess.Write, FileShare.None); + ZlibUtil.CompressTAS(mMem, fs); + fs.Close(); + fs.Dispose(); + } + + public void SaveAs(string newfile) { + mFilename = newfile; + Save(); + } + } +} diff --git a/Core/TASStruct.cs b/Core/TASStruct.cs new file mode 100644 index 0000000..5e344a2 --- /dev/null +++ b/Core/TASStruct.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Text; + +namespace BallanceTASEditor.Core.TASStruct { + public class FrameDataDisplay : INotifyPropertyChanged { + public FrameDataDisplay(long index, FrameData fd) { + Reload(index, fd); + } + + public event PropertyChangedEventHandler PropertyChanged; + private void OnPropertyChanged(String propertyName) { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + public void Reload(long index, FrameData fd) { + this.index = index; + this.deltaTime = fd.deltaTime; + + OnPropertyChanged("index"); + OnPropertyChanged("deltaTime"); + + this.keystates = fd.keystates; + } + + public long index { get; set; } + public float deltaTime { get; set; } + public UInt32 keystates { + get { + UInt32 result = 0; + if (key_enter) result |= 1; result <<= 1; + if (key_esc) result |= 1; result <<= 1; + if (key_q) result |= 1; result <<= 1; + if (key_space) result |= 1; result <<= 1; + if (key_shift) result |= 1; result <<= 1; + if (key_right) result |= 1; result <<= 1; + if (key_left) result |= 1; result <<= 1; + if (key_down) result |= 1; result <<= 1; + if (key_up) result |= 1; result <<= 1; + + return result; + } + set { + key_up = (value & (1 << 0)).ToBool(); + key_down = (value & (1 << 1)).ToBool(); + key_left = (value & (1 << 2)).ToBool(); + key_right = (value & (1 << 3)).ToBool(); + key_shift = (value & (1 << 4)).ToBool(); + key_space = (value & (1 << 5)).ToBool(); + key_q = (value & (1 << 6)).ToBool(); + key_esc = (value & (1 << 7)).ToBool(); + key_enter = (value & (1 << 8)).ToBool(); + + OnPropertyChanged("key_up"); + OnPropertyChanged("key_down"); + OnPropertyChanged("key_left"); + OnPropertyChanged("key_right"); + OnPropertyChanged("key_shift"); + OnPropertyChanged("key_space"); + OnPropertyChanged("key_q"); + OnPropertyChanged("key_esc"); + OnPropertyChanged("key_enter"); + } + } + public bool key_up { get; set; } + public bool key_down { get; set; } + public bool key_left { get; set; } + public bool key_right { get; set; } + public bool key_shift { get; set; } + public bool key_space { get; set; } + public bool key_q { get; set; } + public bool key_esc { get; set; } + public bool key_enter { get; set; } + } + + public class FrameData { + + public FrameData(Stream st) { + var temp = new byte[ConstValue.FRAMEDATA_SIZE]; + st.Read(temp, 0, ConstValue.FRAMEDATA_SIZE); + + deltaTime = BitConverter.ToSingle(temp, ConstValue.FRAMEDATA_OFFSET_DELTATIME); + keystates = BitConverter.ToUInt32(temp, ConstValue.FRAMEDATA_OFFSET_KEY_STATES); + } + public FrameData(FrameDataDisplay fdd) { + this.deltaTime = fdd.deltaTime; + this.keystates = fdd.keystates; + } + + public FrameData() { + this.deltaTime = 0f; + this.keystates = 0; + } + + public FrameData(float d, UInt32 k) { + this.deltaTime = d; + this.keystates = k; + } + + public void SetKeyStates(UInt32 offset) { + keystates |= offset; + } + + public void UnsetKeyStates(UInt32 offset) { + keystates &= ~offset; + } + + public float deltaTime; + public UInt32 keystates; + } + + public class ConstValue { + public static readonly Dictionary Mapping = new Dictionary() { + {FrameDataField.Key_Up, (1 << 0)}, + {FrameDataField.Key_Down, (1 << 1)}, + {FrameDataField.Key_Left, (1 << 2)}, + {FrameDataField.Key_Right, (1 << 3)}, + {FrameDataField.Key_Shift, (1 << 4)}, + {FrameDataField.Key_Space, (1 << 5)}, + {FrameDataField.Key_Q, (1 << 6)}, + {FrameDataField.Key_Esc, (1 << 7)}, + {FrameDataField.Key_Enter, (1 << 8)} + }; + public const int FRAMEDATA_SIZE = 8; + public const int FRAMEDATA_OFFSET_DELTATIME = 0; + public const int FRAMEDATA_OFFSET_KEY_STATES = 4; + } + + public enum FrameDataField { + Key_Up, + Key_Down, + Key_Left, + Key_Right, + Key_Shift, + Key_Space, + Key_Q, + Key_Esc, + Key_Enter + } + +} diff --git a/Core/Util.cs b/Core/Util.cs new file mode 100644 index 0000000..3097d57 --- /dev/null +++ b/Core/Util.cs @@ -0,0 +1,22 @@ +using BallanceTASEditor.Core.TASStruct; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; + +namespace BallanceTASEditor.Core { + public static class Util { + public static bool ToBool(this UInt32 num) { + return (num != 0); + } + public static UInt32 ToUInt32(this bool b) { + return (UInt32)(b ? 1 : 0); + } + //public static void RemoveRange(this ModifiedObservableCollection list, int index, int count) { + // if (index >= list.Count) return; + // if (index + count > list.Count) count = list.Count - index; + // for (int i = 0; i < count; i++) list.RemoveAt(index); + //} + } +} diff --git a/Core/ZlibUtil.cs b/Core/ZlibUtil.cs new file mode 100644 index 0000000..2273eab --- /dev/null +++ b/Core/ZlibUtil.cs @@ -0,0 +1,55 @@ +using BallanceTASEditor.Core.TASStruct; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace BallanceTASEditor.Core { + public class ZlibUtil { + private const int COPY_STREAM_UNIT = 1024; + + public static void CompressTAS(LinkedList mem, FileStream file) { + file.Write(BitConverter.GetBytes(mem.Count * ConstValue.FRAMEDATA_SIZE), 0, 4); + + var zo = new zlib.ZOutputStream(file, 9); + var node = mem.First; + while (node != null) { + zo.Write(BitConverter.GetBytes(node.Value.deltaTime), 0, 4); + zo.Write(BitConverter.GetBytes(node.Value.keystates), 0, 4); + node = node.Next; + } + zo.finish(); + zo.Close(); + } + + public static void DecompressTAS(LinkedList ls, FileStream file) { + var lengthTemp = new byte[4]; + var mem = new MemoryStream(); + file.Read(lengthTemp, 0, 4); + Int32 expectedLength = BitConverter.ToInt32(lengthTemp, 0); + long expectedCount = expectedLength / ConstValue.FRAMEDATA_SIZE; + + var zo = new zlib.ZOutputStream(mem); + CopyStream(file, zo); + zo.finish(); + + mem.Seek(0, SeekOrigin.Begin); + for(long i = 0; i < expectedCount; i++) { + ls.AddLast(new FrameData(mem)); + } + mem.Close(); + zo.Close(); + } + + public static void CopyStream(Stream origin, Stream target) { + var buffer = new byte[COPY_STREAM_UNIT]; + int len; + while ((len = origin.Read(buffer, 0, COPY_STREAM_UNIT)) > 0) { + target.Write(buffer, 0, len); + } + //target.Flush(); + } + + } +} diff --git a/DialogUtil.cs b/DialogUtil.cs new file mode 100644 index 0000000..e24f97d --- /dev/null +++ b/DialogUtil.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; + +namespace BallanceTASEditor { + public class DialogUtil { + + public static string OpenFileDialog() { + Microsoft.Win32.OpenFileDialog op = new Microsoft.Win32.OpenFileDialog(); + op.RestoreDirectory = true; + op.Multiselect = false; + op.Filter = "TAS file(*.tas)|*.tas|All file(*.*)|*.*"; + if (!(bool)op.ShowDialog()) return ""; + return op.FileName; + } + + public static string SaveFileDialog() { + Microsoft.Win32.SaveFileDialog op = new Microsoft.Win32.SaveFileDialog(); + op.RestoreDirectory = true; + op.Filter = "TAS file(*.tas)|*.tas|All file(*.*)|*.*"; + if (!(bool)op.ShowDialog()) return ""; + return op.FileName; + } + + public static bool ConfirmDialog(string str) { + var result = MessageBox.Show(str, "Warning", MessageBoxButton.YesNo, MessageBoxImage.Warning); + return (result == MessageBoxResult.Yes); + } + + } +} diff --git a/MainWindow.xaml b/MainWindow.xaml new file mode 100644 index 0000000..8c689c4 --- /dev/null +++ b/MainWindow.xaml @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs new file mode 100644 index 0000000..b8a0368 --- /dev/null +++ b/MainWindow.xaml.cs @@ -0,0 +1,91 @@ +using BallanceTASEditor.Core; +using BallanceTASEditor.Core.TASStruct; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +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 { + /// + /// MainWindow.xaml 的交互逻辑 + /// + public partial class MainWindow : Window { + public MainWindow() { + InitializeComponent(); + RefreshUI(false); + } + + TASFile mFile; + TASViewer mViewer; + + #region ui func + + // menu + private void funcMenu_Help_ReportBugs(object sender, RoutedEventArgs e) { + System.Diagnostics.Process.Start("https://github.com/yyc12345/BallanceTASEditor/issues"); + } + + private void funcMenu_Help_About(object sender, RoutedEventArgs e) { + MessageBox.Show("Under MIT License\nVersion 0\nyyc12345.", "Ballance TAS Editor"); + } + + private void funcMenu_File_Open(object sender, RoutedEventArgs e) { + var file = DialogUtil.OpenFileDialog(); + if (file == "") return; + mFile = new TASFile(file); + mViewer = new TASViewer(mFile, uiTASSlider, uiTASData); + RefreshUI(true); + } + + private void funcMenu_File_Save(object sender, RoutedEventArgs e) { + mFile.Save(); + } + + private void funcMenu_File_SaveAs(object sender, RoutedEventArgs e) { + var file = DialogUtil.SaveFileDialog(); + if (file == "") return; + mFile.SaveAs(file); + } + + private void funcMenu_File_Close(object sender, RoutedEventArgs e) { + if (!DialogUtil.ConfirmDialog("Do you want to close this TAS file?")) return; + mViewer.Dispose(); + mFile = null; + mViewer = null; + RefreshUI(false); + } + + + #endregion + + private void RefreshUI(bool isFileOpened) { + if (isFileOpened) { + uiEditorPanel.Visibility = Visibility.Visible; + uiEditorNote.Visibility = Visibility.Collapsed; + + uiMenu_File_Open.IsEnabled = false; + uiMenu_File_Save.IsEnabled = true; + uiMenu_File_SaveAs.IsEnabled = true; + uiMenu_File_Close.IsEnabled = true; + } else { + uiEditorPanel.Visibility = Visibility.Collapsed; + uiEditorNote.Visibility = Visibility.Visible; + + uiMenu_File_Open.IsEnabled = true; + uiMenu_File_Save.IsEnabled = false; + uiMenu_File_SaveAs.IsEnabled = false; + uiMenu_File_Close.IsEnabled = false; + } + } + + } +} diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..be90d6d --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("BallanceTASEditor")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("BallanceTASEditor")] +[assembly: AssemblyCopyright("Copyright © 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +//若要开始生成可本地化的应用程序,请设置 +//.csproj 文件中的 CultureYouAreCodingWith +//例如,如果您在源文件中使用的是美国英语, +//使用的是美国英语,请将 设置为 en-US。 然后取消 +//对以下 NeutralResourceLanguage 特性的注释。 更新 +//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。 + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //主题特定资源词典所处位置 + //(未在页面中找到资源时使用, + //或应用程序资源字典中找到时使用) + ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置 + //(未在页面中找到资源时使用, + //、应用程序或任何主题专用资源字典中找到时使用) +)] + + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs new file mode 100644 index 0000000..8f442dc --- /dev/null +++ b/Properties/Resources.Designer.cs @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本: 4.0.30319.42000 +// +// 对此文件的更改可能导致不正确的行为,如果 +// 重新生成代码,则所做更改将丢失。 +// +//------------------------------------------------------------------------------ + +namespace BallanceTASEditor.Properties { + + + /// + /// 强类型资源类,用于查找本地化字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 返回此类使用的缓存 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if ((resourceMan == null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("BallanceTASEditor.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 覆盖当前线程的 CurrentUICulture 属性 + /// 使用此强类型的资源类的资源查找。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/Properties/Resources.resx b/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs new file mode 100644 index 0000000..756ca5a --- /dev/null +++ b/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace BallanceTASEditor.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/Properties/Settings.settings b/Properties/Settings.settings new file mode 100644 index 0000000..033d7a5 --- /dev/null +++ b/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/StyleConverter.cs b/StyleConverter.cs new file mode 100644 index 0000000..5471885 --- /dev/null +++ b/StyleConverter.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Windows.Data; +using System.Windows.Media; + +namespace BallanceTASEditor { + + [ValueConversion(typeof(bool), typeof(Color))] + public class BackgroundConverter : IValueConverter { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { + try { + bool bl = System.Convert.ToBoolean(value); + if (bl) return Color.FromRgb(30, 144, 255); + else return Color.FromArgb(0, 255, 255, 255); + } catch { + return Color.FromArgb(0, 255, 255, 255); + } + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { + return null; + } + } + + [ValueConversion(typeof(float), typeof(string))] + public class FloatConverter : IValueConverter { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { + try { + float bl = System.Convert.ToSingle(value); + if (bl < 0) return ""; + else return bl.ToString(); + } catch { + return ""; + } + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { + return null; + } + } + + [ValueConversion(typeof(long), typeof(string))] + public class LongConverter : IValueConverter { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { + try { + float bl = System.Convert.ToInt64(value); + if (bl < 0) return ""; + else return bl.ToString(); + } catch { + return ""; + } + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { + return null; + } + } +} diff --git a/TASViewer.cs b/TASViewer.cs new file mode 100644 index 0000000..950be85 --- /dev/null +++ b/TASViewer.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using BallanceTASEditor.Core; +using BallanceTASEditor.Core.TASStruct; +using System.Collections.ObjectModel; +using System.Windows.Controls; +using System.Windows; + +namespace BallanceTASEditor { + public class TASViewer : IDisposable { + public TASViewer(TASFile file, Slider slider, DataGrid datagrid) { + mFile = file; + mSlider = slider; + mDataGrid = datagrid; + + // restore slider + mSlider.Minimum = 0; + updateSliderRange(); + + // init data + mPosition = 0; + mDataSource = new ObservableCollection(); + INVALID_FRAME_DATA = new FrameData(-1f, 0); + for (int i = 0; i < DATA_LIST_LENGTH; i++) { + mDataSource.Add(new FrameDataDisplay(0, INVALID_FRAME_DATA)); + } + mFile.Get(mDataSource, 0, DATA_LIST_LENGTH); + + // bind event and source + mDataGrid.ItemsSource = mDataSource; + mSlider.ValueChanged += sliderValueChanged; + } + public void Dispose() { + mDataGrid.ItemsSource = null; + mSlider.ValueChanged -= sliderValueChanged; + } + + const int DATA_LIST_LENGTH = 30; + FrameData INVALID_FRAME_DATA; + TASFile mFile; + Slider mSlider; + DataGrid mDataGrid; + long mPosition; + ObservableCollection mDataSource; + + private void sliderValueChanged(object sender, RoutedPropertyChangedEventArgs e) { + long pos = Convert.ToInt64(Math.Floor(e.NewValue)); + long offset = pos - mPosition; + mFile.Shift(offset); + var gotten = mFile.Get(mDataSource, pos, DATA_LIST_LENGTH); + for(; gotten < DATA_LIST_LENGTH; gotten++) { + mDataSource[gotten].Reload(-1, INVALID_FRAME_DATA); + } + + mPosition = pos; + } + + private void updateSliderRange() { + long newSize = mFile.mFrameCount - 1; + if (mSlider.Value > newSize) + mSlider.Value = newSize; + mSlider.Maximum = newSize; + } + } +} diff --git a/packages.config b/packages.config new file mode 100644 index 0000000..ea2c82d --- /dev/null +++ b/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file