refactor: migrate project and start refactor
This commit is contained in:
71
Legacy/BallanceTASEditor/Core/ClipboardUtil.cs
Normal file
71
Legacy/BallanceTASEditor/Core/ClipboardUtil.cs
Normal file
@ -0,0 +1,71 @@
|
||||
using BallanceTASEditor.Core.TASStruct;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
|
||||
namespace BallanceTASEditor.Core {
|
||||
public class ClipboardUtil {
|
||||
|
||||
// comes from https://stackoverflow.com/questions/22272822/copy-binary-data-to-clipboard
|
||||
|
||||
private static readonly string CLIPBOARD_DATA_FORMAT = "BallanceTASFrameData";
|
||||
public static bool SetFrameData(LinkedList<FrameData> ls) {
|
||||
try {
|
||||
DataObject data = new DataObject();
|
||||
using (var mem = new MemoryStream()) {
|
||||
mem.Write(BitConverter.GetBytes(ls.Count), 0, 4);
|
||||
|
||||
var node = ls.First;
|
||||
while (node != null) {
|
||||
mem.Write(BitConverter.GetBytes(node.Value.deltaTime), 0, 4);
|
||||
mem.Write(BitConverter.GetBytes(node.Value.keystates), 0, 4);
|
||||
node = node.Next;
|
||||
}
|
||||
|
||||
data.SetData(CLIPBOARD_DATA_FORMAT, mem, false);
|
||||
Clipboard.SetDataObject(data, true);
|
||||
}
|
||||
return true;
|
||||
#if DEBUG
|
||||
} catch (Exception e) {
|
||||
#else
|
||||
} catch {
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool GetFrameData(LinkedList<FrameData> ls) {
|
||||
try {
|
||||
// detect
|
||||
DataObject retrievedData = Clipboard.GetDataObject() as DataObject;
|
||||
if (retrievedData == null || !retrievedData.GetDataPresent(CLIPBOARD_DATA_FORMAT))
|
||||
return false;
|
||||
MemoryStream byteStream = retrievedData.GetData(CLIPBOARD_DATA_FORMAT) as MemoryStream;
|
||||
if (byteStream == null)
|
||||
return false;
|
||||
|
||||
// read
|
||||
byteStream.Seek(0, SeekOrigin.Begin);
|
||||
byte[] temp = new byte[8];
|
||||
byteStream.Read(temp, 0, 4);
|
||||
int count = BitConverter.ToInt32(temp, 0);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
ls.AddLast(new FrameData(byteStream));
|
||||
}
|
||||
|
||||
return true;
|
||||
#if DEBUG
|
||||
} catch (Exception e) {
|
||||
#else
|
||||
} catch {
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
65
Legacy/BallanceTASEditor/Core/ConfigManager.cs
Normal file
65
Legacy/BallanceTASEditor/Core/ConfigManager.cs
Normal file
@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BallanceTASEditor.Core {
|
||||
public class ConfigManager {
|
||||
|
||||
public ConfigManager(string fileName, Dictionary<string, string> defaultValue) {
|
||||
_fileName = fileName;
|
||||
_defaultValue = defaultValue;
|
||||
|
||||
Configuration = Read();
|
||||
}
|
||||
|
||||
string _fileName;
|
||||
Dictionary<string, string> _defaultValue;
|
||||
public Dictionary<string, string> Configuration;
|
||||
|
||||
public static readonly string CfgNode_Language = "Language";
|
||||
public static readonly string CfgNode_ItemCount = "ItemCount";
|
||||
public static readonly string CfgNode_IsHorizonLayout = "IsHorizonLayout";
|
||||
public static readonly string CfgNode_IsOverwrittenPaste = "IsOverwrittenPaste";
|
||||
|
||||
Dictionary<string, string> Read() {
|
||||
if (!File.Exists(Path.Combine(Environment.CurrentDirectory, _fileName)))
|
||||
Init();
|
||||
|
||||
Dictionary<string, string> data;
|
||||
using (StreamReader fs = new StreamReader(Path.Combine(Environment.CurrentDirectory, _fileName), Encoding.UTF8)) {
|
||||
data = JsonConvert.DeserializeObject<Dictionary<string, string>>(fs.ReadToEnd());
|
||||
fs.Close();
|
||||
}
|
||||
|
||||
// check field to make sure each field is existed
|
||||
// because version update it might be changed
|
||||
foreach(var pair in _defaultValue) {
|
||||
if (!data.ContainsKey(pair.Key)) {
|
||||
data.Add(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void Init() {
|
||||
using (StreamWriter fs = new StreamWriter(Path.Combine(Environment.CurrentDirectory, _fileName), false, Encoding.UTF8)) {
|
||||
fs.Write(JsonConvert.SerializeObject(_defaultValue));
|
||||
fs.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public void Save() {
|
||||
using (StreamWriter fs = new StreamWriter(Path.Combine(Environment.CurrentDirectory, _fileName), false, Encoding.UTF8)) {
|
||||
fs.Write(JsonConvert.SerializeObject(this.Configuration));
|
||||
fs.Close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
437
Legacy/BallanceTASEditor/Core/FileOperation.cs
Normal file
437
Legacy/BallanceTASEditor/Core/FileOperation.cs
Normal file
@ -0,0 +1,437 @@
|
||||
using BallanceTASEditor.Core.TASStruct;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace BallanceTASEditor.Core.FileOperation {
|
||||
public abstract class RevocableOperation {
|
||||
public RevocableOperation() {
|
||||
hasBeenDone = false;
|
||||
}
|
||||
|
||||
private bool hasBeenDone;
|
||||
public virtual void Do(ref LinkedList<FrameData> mMem, ref LinkedListNode<FrameData> mPointer, ref long mPointerIndex) {
|
||||
if (hasBeenDone) throw new Exception("Try to call operation.do when the operation has been done.");
|
||||
hasBeenDone = true;
|
||||
}
|
||||
|
||||
public virtual void Undo(ref LinkedList<FrameData> mMem, ref LinkedListNode<FrameData> mPointer, ref long mPointerIndex) {
|
||||
if (!hasBeenDone) throw new Exception("Try to call operation.undo when the operation has not been done.");
|
||||
hasBeenDone = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class SetOperation : RevocableOperation {
|
||||
private SelectionRange field;
|
||||
private SelectionRange absoluteRange;
|
||||
private bool? isSet;
|
||||
|
||||
private uint internalOffset;
|
||||
private List<uint> changedItems;
|
||||
|
||||
public SetOperation(SelectionRange _field, SelectionRange _absoluteRange, bool? _isSet) : base() {
|
||||
field = _field;
|
||||
absoluteRange = _absoluteRange;
|
||||
isSet = _isSet;
|
||||
|
||||
// calc offset first for following operation
|
||||
internalOffset = 0;
|
||||
for (int i = (int)field.start; i <= (int)field.end; i++) {
|
||||
internalOffset |= ConstValue.Mapping[(FrameDataField)i];
|
||||
}
|
||||
|
||||
changedItems = new List<uint>();
|
||||
}
|
||||
|
||||
public override void Do(ref LinkedList<FrameData> mMem, ref LinkedListNode<FrameData> mPointer, ref long mPointerIndex) {
|
||||
base.Do(ref mMem, ref mPointer, ref mPointerIndex);
|
||||
if (mPointer == null) return;
|
||||
|
||||
changedItems.Clear();
|
||||
foreach (var item in mMem.IterateWithSelectionRange(absoluteRange, mPointer, mPointerIndex)) {
|
||||
// backup item first
|
||||
changedItems.Add(item.Value.keystates);
|
||||
|
||||
if (isSet == null) item.Value.ReverseKeyStates(internalOffset);
|
||||
else if (isSet == true) item.Value.SetKeyStates(internalOffset);
|
||||
else if (isSet == false) item.Value.UnsetKeyStates(internalOffset);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Undo(ref LinkedList<FrameData> mMem, ref LinkedListNode<FrameData> mPointer, ref long mPointerIndex) {
|
||||
base.Undo(ref mMem, ref mPointer, ref mPointerIndex);
|
||||
if (mPointer == null) return;
|
||||
|
||||
int counter = 0;
|
||||
foreach (var item in mMem.IterateWithSelectionRange(absoluteRange, mPointer, mPointerIndex)) {
|
||||
// restore data
|
||||
item.Value.keystates = changedItems[counter];
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class RemoveOperation : RevocableOperation {
|
||||
private SelectionRange absoluteRange;
|
||||
|
||||
private LinkedList<FrameData> removedItems;
|
||||
private LinkedListNode<FrameData> oldPointer;
|
||||
private long oldPointerIndex;
|
||||
private LinkedListNode<FrameData> removeStartNode;
|
||||
|
||||
public RemoveOperation(SelectionRange _absoluteRange) : base() {
|
||||
absoluteRange = _absoluteRange;
|
||||
|
||||
removedItems = new LinkedList<FrameData>();
|
||||
}
|
||||
|
||||
public override void Do(ref LinkedList<FrameData> mMem, ref LinkedListNode<FrameData> mPointer, ref long mPointerIndex) {
|
||||
base.Do(ref mMem, ref mPointer, ref mPointerIndex);
|
||||
if (mPointer == null) return;
|
||||
|
||||
// init backups list and backups 2 data
|
||||
// and backups remove start node(ps: if it is null, mean removed from head)
|
||||
removedItems.Clear();
|
||||
oldPointer = mPointer;
|
||||
oldPointerIndex = mPointerIndex;
|
||||
removeStartNode = absoluteRange.start == 0 ? null : mMem.FastGetNode(mPointer, mPointerIndex, absoluteRange.start - 1);
|
||||
|
||||
// find proper pointer after remove first. but we do not apply it in there.
|
||||
// if state is true, it mean the deleted content is placed before pointer previously. we should consider pointer data and we should correct them.
|
||||
LinkedListNode<FrameData> newPointer;
|
||||
long newPointerIndex;
|
||||
if (mPointerIndex >= absoluteRange.start) {
|
||||
// if point within removed content, we need to shift it to the head of removed content,
|
||||
// otherwise we only need to minus index with the length of removed content.
|
||||
if (absoluteRange.Within(mPointerIndex)) {
|
||||
// this contains 3 situation
|
||||
// if full delete, mPointer is null and mPointerIndex is invalid(with wrong data: -1)
|
||||
// if delete from head, mPointer and mPointerIndex all are valid. but it is the tail of removed content
|
||||
// otherwise, just find the head of removed content and shift to it.
|
||||
if (absoluteRange.start == 0 && absoluteRange.end == mMem.Count - 1) {
|
||||
// fully remove
|
||||
newPointer = null;
|
||||
newPointerIndex = -1;
|
||||
} else if (absoluteRange.start == 0) {
|
||||
// remove from head
|
||||
newPointerIndex = 0;
|
||||
newPointer = mMem.FastGetNode(mPointer, mPointerIndex, absoluteRange.end + 1);
|
||||
} else {
|
||||
// simple remove
|
||||
newPointerIndex = absoluteRange.start - 1;
|
||||
newPointer = mMem.FastGetNode(mPointer, mPointerIndex, absoluteRange.start - 1);
|
||||
}
|
||||
} else {
|
||||
newPointer = mPointer;
|
||||
newPointerIndex = mPointerIndex - absoluteRange.GetCount();
|
||||
}
|
||||
} else {
|
||||
// not affected situation
|
||||
newPointer = mPointer;
|
||||
newPointerIndex = mPointerIndex;
|
||||
}
|
||||
|
||||
// the real remove operation
|
||||
foreach (var item in mMem.IterateWithSelectionRange(absoluteRange, mPointer, mPointerIndex)) {
|
||||
mMem.Remove(item);
|
||||
removedItems.AddLast(item); // backups node;
|
||||
}
|
||||
|
||||
// apply gotten new pointer
|
||||
mPointer = newPointer;
|
||||
mPointerIndex = newPointerIndex;
|
||||
|
||||
}
|
||||
|
||||
public override void Undo(ref LinkedList<FrameData> mMem, ref LinkedListNode<FrameData> mPointer, ref long mPointerIndex) {
|
||||
base.Undo(ref mMem, ref mPointer, ref mPointerIndex);
|
||||
// may recovered from empty list
|
||||
//if (mPointer == null) return;
|
||||
|
||||
// re-insert data
|
||||
foreach (var item in removedItems.IterateFullReversed()) {
|
||||
removedItems.Remove(item);
|
||||
if (removeStartNode == null) {
|
||||
// insert at first
|
||||
mMem.AddFirst(item);
|
||||
} else {
|
||||
// insert after this node
|
||||
mMem.AddAfter(removeStartNode, item);
|
||||
}
|
||||
}
|
||||
|
||||
// reset pointer
|
||||
mPointer = oldPointer;
|
||||
mPointerIndex = oldPointerIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public class AddOperation : RevocableOperation {
|
||||
private long absolutePos;
|
||||
private long count;
|
||||
private float deltaTime;
|
||||
private bool isAddBefore;
|
||||
|
||||
private LinkedListNode<FrameData> addStartNode;
|
||||
private LinkedListNode<FrameData> oldPointer;
|
||||
private long oldPointerIndex;
|
||||
|
||||
public AddOperation(long _absolutePos, long _count, float _deltaTime, bool _isAddBefore) : base() {
|
||||
absolutePos = _absolutePos;
|
||||
count = _count;
|
||||
deltaTime = _deltaTime;
|
||||
isAddBefore = _isAddBefore;
|
||||
}
|
||||
|
||||
public override void Do(ref LinkedList<FrameData> mMem, ref LinkedListNode<FrameData> mPointer, ref long mPointerIndex) {
|
||||
base.Do(ref mMem, ref mPointer, ref mPointerIndex);
|
||||
if (count <= 0) return;
|
||||
|
||||
// backups 2 data
|
||||
oldPointer = mPointer;
|
||||
oldPointerIndex = mPointerIndex;
|
||||
|
||||
// real add operation
|
||||
if (mPointer == null) {
|
||||
// backups start pointer
|
||||
addStartNode = null;
|
||||
|
||||
// add into blank list, absolutePos and isAddBefore parameters are invalid
|
||||
// specially process
|
||||
for (long i = 0; i < count; i++) {
|
||||
mMem.AddFirst(new FrameData(deltaTime, 0));
|
||||
}
|
||||
mPointer = mMem.First;
|
||||
mPointerIndex = 0;
|
||||
} else {
|
||||
// normal add
|
||||
LinkedListNode<FrameData> node = mMem.FastGetNode(mPointer, mPointerIndex, absolutePos);
|
||||
// backups start pointer
|
||||
addStartNode = node;
|
||||
if (isAddBefore) {
|
||||
for (long i = 0; i < count; i++) {
|
||||
mMem.AddBefore(node, new FrameData(deltaTime, 0));
|
||||
}
|
||||
} else {
|
||||
for (long i = 0; i < count; i++) {
|
||||
mMem.AddAfter(node, new FrameData(deltaTime, 0));
|
||||
}
|
||||
}
|
||||
|
||||
// if the items are added before pointer, the index should add with the count of added items
|
||||
// but pointer don't need to be shifted.
|
||||
if ((isAddBefore && mPointerIndex >= absolutePos) ||
|
||||
(!isAddBefore && mPointerIndex > absolutePos))
|
||||
mPointerIndex += count;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Undo(ref LinkedList<FrameData> mMem, ref LinkedListNode<FrameData> mPointer, ref long mPointerIndex) {
|
||||
base.Undo(ref mMem, ref mPointer, ref mPointerIndex);
|
||||
if (count <= 0) return;
|
||||
|
||||
if (addStartNode == null) {
|
||||
// original state is blank
|
||||
// just clear mmem is ok
|
||||
mMem.Clear();
|
||||
} else {
|
||||
if (isAddBefore) {
|
||||
for (long i = 0; i < count; i++) {
|
||||
mMem.Remove(addStartNode.Previous);
|
||||
}
|
||||
} else {
|
||||
for (long i = 0; i < count; i++) {
|
||||
mMem.Remove(addStartNode.Next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// re-set pointer
|
||||
mPointer = oldPointer;
|
||||
mPointerIndex = oldPointerIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public class InsertOperation : RevocableOperation {
|
||||
private long absolutePos;
|
||||
private LinkedList<FrameData> data;
|
||||
private bool isInsertBefore;
|
||||
private bool isOverwritten;
|
||||
|
||||
private LinkedListNode<FrameData> addStartNode;
|
||||
private bool isBlankList;
|
||||
private LinkedListNode<FrameData> oldPointer;
|
||||
private long oldPointerIndex;
|
||||
|
||||
// because insert including remove oeration(overwritten mode)
|
||||
// so we need include this for code re-use
|
||||
private RemoveOperation internalRemoveOper;
|
||||
|
||||
private const long LINKEDLIST_HEAD = -1;
|
||||
private const long LINKEDLIST_TAIL = -2;
|
||||
|
||||
public InsertOperation(long _absolutePos, LinkedList<FrameData> _data, bool _isInsertBefore, bool _isOverwritten) : base() {
|
||||
absolutePos = _absolutePos;
|
||||
data = _data;
|
||||
isInsertBefore = _isInsertBefore;
|
||||
isOverwritten = _isOverwritten;
|
||||
|
||||
}
|
||||
|
||||
public override void Do(ref LinkedList<FrameData> mMem, ref LinkedListNode<FrameData> mPointer, ref long mPointerIndex) {
|
||||
base.Do(ref mMem, ref mPointer, ref mPointerIndex);
|
||||
if (data.Count == 0) return;
|
||||
|
||||
// because this oper have internal oper, so we need backup data after potential remove oper
|
||||
// so in there, no object need to be backuped
|
||||
|
||||
// if the list is blank, overwritten is invalid, just normal add them.
|
||||
if (mPointer == null) {
|
||||
// backups
|
||||
oldPointer = mPointer;
|
||||
oldPointerIndex = mPointerIndex;
|
||||
addStartNode = null;
|
||||
isBlankList = true;
|
||||
|
||||
foreach (var item in data.IterateFull()) {
|
||||
mMem.AddFirst(item.Value);
|
||||
}
|
||||
mPointer = mMem.First;
|
||||
mPointerIndex = 0;
|
||||
} else {
|
||||
LinkedListNode<FrameData> node = mMem.FastGetNode(mPointer, mPointerIndex, absolutePos);
|
||||
|
||||
// absolutePos is class member and shouldn't be changed.
|
||||
// but in overwritten mode, this value need to be changed so we create a temp value in there
|
||||
// to instead the fucntion of original variable
|
||||
var modifiedAbsolutePos = absolutePos;
|
||||
|
||||
// if list is not a blank list, we should consider overwritten
|
||||
// if in overwritten mode, we need to overwrite data from selected item.
|
||||
// otherwise, not in overwritten mode, just normally add them just like add operation.
|
||||
if (isOverwritten) {
|
||||
// in overwritten mode, if follwoing item is not enough to fufill the count of overwritten data
|
||||
// normally add them
|
||||
// we use delete and add method to do this
|
||||
|
||||
// now, try init internal remove oper if in overwritten mode
|
||||
// first, we need compare the length of remained item located in mMem and the length of added item
|
||||
// then construct remove oper
|
||||
long remainLength;
|
||||
if (isInsertBefore) remainLength = absolutePos + 1;
|
||||
else remainLength = mMem.Count - absolutePos;
|
||||
|
||||
long dataLength = data.Count;
|
||||
long expectedLength = dataLength > remainLength ? remainLength : dataLength;
|
||||
long expectedPos;
|
||||
if (isInsertBefore) expectedPos = absolutePos - expectedLength + 1;
|
||||
else expectedPos = absolutePos + expectedLength - 1;
|
||||
|
||||
if (isInsertBefore)
|
||||
internalRemoveOper = new RemoveOperation(new SelectionRange(expectedPos, absolutePos));
|
||||
else
|
||||
internalRemoveOper = new RemoveOperation(new SelectionRange(absolutePos, expectedPos));
|
||||
|
||||
node = isInsertBefore ? node.Next : node.Previous;
|
||||
internalRemoveOper.Do(ref mMem, ref mPointer, ref mPointerIndex);
|
||||
// now, we can treat it as normal insert(without overwritten)
|
||||
// but with one exception: absolutePos
|
||||
// we need re calc absolutePos bucause we have called remove oper
|
||||
|
||||
if (isInsertBefore) {
|
||||
if (node == null)
|
||||
modifiedAbsolutePos = LINKEDLIST_TAIL;
|
||||
else
|
||||
modifiedAbsolutePos = absolutePos + 1 - expectedLength;
|
||||
} else {
|
||||
if (node == null)
|
||||
modifiedAbsolutePos = LINKEDLIST_HEAD;
|
||||
else
|
||||
modifiedAbsolutePos -= 1;
|
||||
}
|
||||
|
||||
}
|
||||
// backups
|
||||
oldPointer = mPointer;
|
||||
oldPointerIndex = mPointerIndex;
|
||||
addStartNode = node;
|
||||
isBlankList = false;
|
||||
|
||||
if (isInsertBefore) {
|
||||
foreach (var item in data.IterateFull()) {
|
||||
if (node == null)
|
||||
mMem.AddLast(item.Value);
|
||||
else
|
||||
mMem.AddBefore(node, item.Value);
|
||||
}
|
||||
} else {
|
||||
foreach (var item in data.IterateFullReversed()) {
|
||||
if (node == null)
|
||||
mMem.AddFirst(item.Value);
|
||||
else
|
||||
mMem.AddAfter(node, item.Value);
|
||||
}
|
||||
}
|
||||
|
||||
if (modifiedAbsolutePos != LINKEDLIST_TAIL && modifiedAbsolutePos != LINKEDLIST_HEAD) {
|
||||
if ((isInsertBefore && mPointerIndex >= modifiedAbsolutePos) ||
|
||||
(!isInsertBefore && mPointerIndex > modifiedAbsolutePos))
|
||||
mPointerIndex += data.Count;
|
||||
}
|
||||
else if (modifiedAbsolutePos == LINKEDLIST_HEAD)
|
||||
mPointerIndex += data.Count;
|
||||
|
||||
// remove have chance to remove entire list
|
||||
// so we need restore pointer in that situation
|
||||
if (mPointer == null) {
|
||||
mPointer = mMem.First;
|
||||
mPointerIndex = mPointer == null ? -1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Undo(ref LinkedList<FrameData> mMem, ref LinkedListNode<FrameData> mPointer, ref long mPointerIndex) {
|
||||
base.Undo(ref mMem, ref mPointer, ref mPointerIndex);
|
||||
if (data.Count == 0) return;
|
||||
|
||||
if (isBlankList) {
|
||||
// original state is blank
|
||||
// just clear mmem is ok
|
||||
mMem.Clear();
|
||||
|
||||
// re-set pointer
|
||||
mPointer = oldPointer;
|
||||
mPointerIndex = oldPointerIndex;
|
||||
} else {
|
||||
// in overwrite or not in overwrite mode, we all need to remove inserted data first
|
||||
if (isInsertBefore) {
|
||||
for (long i = 0; i < data.Count; i++) {
|
||||
if (addStartNode == null)
|
||||
mMem.RemoveLast();
|
||||
else
|
||||
mMem.Remove(addStartNode.Previous);
|
||||
}
|
||||
} else {
|
||||
for (long i = 0; i < data.Count; i++) {
|
||||
if (addStartNode == null)
|
||||
mMem.RemoveFirst();
|
||||
else
|
||||
mMem.Remove(addStartNode.Next);
|
||||
}
|
||||
}
|
||||
|
||||
// re-set pointer
|
||||
mPointer = oldPointer;
|
||||
mPointerIndex = oldPointerIndex;
|
||||
|
||||
// if we use overwrite mode, we need re-add lost data
|
||||
if (isOverwritten) {
|
||||
internalRemoveOper.Undo(ref mMem, ref mPointer, ref mPointerIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
40
Legacy/BallanceTASEditor/Core/I18NProcessor.cs
Normal file
40
Legacy/BallanceTASEditor/Core/I18NProcessor.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
|
||||
namespace BallanceTASEditor.Core {
|
||||
public static class I18NProcessor {
|
||||
|
||||
public static string GetI18N(string key, params string[] parameters) {
|
||||
try {
|
||||
var cache = (string)(App.Current.Resources[key]);
|
||||
return string.Format(cache, parameters);
|
||||
} catch (Exception) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static void ChangeLanguage(string target) {
|
||||
ResourceDictionary langRd = null;
|
||||
try {
|
||||
langRd =
|
||||
Application.LoadComponent(
|
||||
new Uri(@"Language/" + target + ".xaml", UriKind.Relative))
|
||||
as ResourceDictionary;
|
||||
} catch {
|
||||
;
|
||||
}
|
||||
|
||||
if (langRd != null) {
|
||||
if (App.Current.Resources.MergedDictionaries.Count > 0) {
|
||||
App.Current.Resources.MergedDictionaries.Clear();
|
||||
}
|
||||
App.Current.Resources.MergedDictionaries.Add(langRd);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
223
Legacy/BallanceTASEditor/Core/KeyboardState.cs
Normal file
223
Legacy/BallanceTASEditor/Core/KeyboardState.cs
Normal file
@ -0,0 +1,223 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace BallanceTASEditor.Core {
|
||||
public class KeyboardState {
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
static extern short GetKeyState(VirtualKeyStates nVirtKey);
|
||||
|
||||
public static bool IsKeyPressed(VirtualKeyStates testKey) {
|
||||
bool keyPressed = false;
|
||||
short result = GetKeyState(testKey);
|
||||
switch (result) {
|
||||
case 0:
|
||||
// Not pressed and not toggled on.
|
||||
keyPressed = false;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Not pressed, but toggled on
|
||||
keyPressed = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Pressed (and may be toggled on)
|
||||
keyPressed = true;
|
||||
break;
|
||||
}
|
||||
return keyPressed;
|
||||
}
|
||||
|
||||
public enum VirtualKeyStates : int {
|
||||
VK_LBUTTON = 0x01,
|
||||
VK_RBUTTON = 0x02,
|
||||
VK_CANCEL = 0x03,
|
||||
VK_MBUTTON = 0x04,
|
||||
//
|
||||
VK_XBUTTON1 = 0x05,
|
||||
VK_XBUTTON2 = 0x06,
|
||||
//
|
||||
VK_BACK = 0x08,
|
||||
VK_TAB = 0x09,
|
||||
//
|
||||
VK_CLEAR = 0x0C,
|
||||
VK_RETURN = 0x0D,
|
||||
//
|
||||
VK_SHIFT = 0x10,
|
||||
VK_CONTROL = 0x11,
|
||||
VK_MENU = 0x12,
|
||||
VK_PAUSE = 0x13,
|
||||
VK_CAPITAL = 0x14,
|
||||
//
|
||||
VK_KANA = 0x15,
|
||||
VK_HANGEUL = 0x15, /* old name - should be here for compatibility */
|
||||
VK_HANGUL = 0x15,
|
||||
VK_JUNJA = 0x17,
|
||||
VK_FINAL = 0x18,
|
||||
VK_HANJA = 0x19,
|
||||
VK_KANJI = 0x19,
|
||||
//
|
||||
VK_ESCAPE = 0x1B,
|
||||
//
|
||||
VK_CONVERT = 0x1C,
|
||||
VK_NONCONVERT = 0x1D,
|
||||
VK_ACCEPT = 0x1E,
|
||||
VK_MODECHANGE = 0x1F,
|
||||
//
|
||||
VK_SPACE = 0x20,
|
||||
VK_PRIOR = 0x21,
|
||||
VK_NEXT = 0x22,
|
||||
VK_END = 0x23,
|
||||
VK_HOME = 0x24,
|
||||
VK_LEFT = 0x25,
|
||||
VK_UP = 0x26,
|
||||
VK_RIGHT = 0x27,
|
||||
VK_DOWN = 0x28,
|
||||
VK_SELECT = 0x29,
|
||||
VK_PRINT = 0x2A,
|
||||
VK_EXECUTE = 0x2B,
|
||||
VK_SNAPSHOT = 0x2C,
|
||||
VK_INSERT = 0x2D,
|
||||
VK_DELETE = 0x2E,
|
||||
VK_HELP = 0x2F,
|
||||
//
|
||||
VK_LWIN = 0x5B,
|
||||
VK_RWIN = 0x5C,
|
||||
VK_APPS = 0x5D,
|
||||
//
|
||||
VK_SLEEP = 0x5F,
|
||||
//
|
||||
VK_NUMPAD0 = 0x60,
|
||||
VK_NUMPAD1 = 0x61,
|
||||
VK_NUMPAD2 = 0x62,
|
||||
VK_NUMPAD3 = 0x63,
|
||||
VK_NUMPAD4 = 0x64,
|
||||
VK_NUMPAD5 = 0x65,
|
||||
VK_NUMPAD6 = 0x66,
|
||||
VK_NUMPAD7 = 0x67,
|
||||
VK_NUMPAD8 = 0x68,
|
||||
VK_NUMPAD9 = 0x69,
|
||||
VK_MULTIPLY = 0x6A,
|
||||
VK_ADD = 0x6B,
|
||||
VK_SEPARATOR = 0x6C,
|
||||
VK_SUBTRACT = 0x6D,
|
||||
VK_DECIMAL = 0x6E,
|
||||
VK_DIVIDE = 0x6F,
|
||||
VK_F1 = 0x70,
|
||||
VK_F2 = 0x71,
|
||||
VK_F3 = 0x72,
|
||||
VK_F4 = 0x73,
|
||||
VK_F5 = 0x74,
|
||||
VK_F6 = 0x75,
|
||||
VK_F7 = 0x76,
|
||||
VK_F8 = 0x77,
|
||||
VK_F9 = 0x78,
|
||||
VK_F10 = 0x79,
|
||||
VK_F11 = 0x7A,
|
||||
VK_F12 = 0x7B,
|
||||
VK_F13 = 0x7C,
|
||||
VK_F14 = 0x7D,
|
||||
VK_F15 = 0x7E,
|
||||
VK_F16 = 0x7F,
|
||||
VK_F17 = 0x80,
|
||||
VK_F18 = 0x81,
|
||||
VK_F19 = 0x82,
|
||||
VK_F20 = 0x83,
|
||||
VK_F21 = 0x84,
|
||||
VK_F22 = 0x85,
|
||||
VK_F23 = 0x86,
|
||||
VK_F24 = 0x87,
|
||||
//
|
||||
VK_NUMLOCK = 0x90,
|
||||
VK_SCROLL = 0x91,
|
||||
//
|
||||
VK_OEM_NEC_EQUAL = 0x92, // '=' key on numpad
|
||||
//
|
||||
VK_OEM_FJ_JISHO = 0x92, // 'Dictionary' key
|
||||
VK_OEM_FJ_MASSHOU = 0x93, // 'Unregister word' key
|
||||
VK_OEM_FJ_TOUROKU = 0x94, // 'Register word' key
|
||||
VK_OEM_FJ_LOYA = 0x95, // 'Left OYAYUBI' key
|
||||
VK_OEM_FJ_ROYA = 0x96, // 'Right OYAYUBI' key
|
||||
//
|
||||
VK_LSHIFT = 0xA0,
|
||||
VK_RSHIFT = 0xA1,
|
||||
VK_LCONTROL = 0xA2,
|
||||
VK_RCONTROL = 0xA3,
|
||||
VK_LMENU = 0xA4,
|
||||
VK_RMENU = 0xA5,
|
||||
//
|
||||
VK_BROWSER_BACK = 0xA6,
|
||||
VK_BROWSER_FORWARD = 0xA7,
|
||||
VK_BROWSER_REFRESH = 0xA8,
|
||||
VK_BROWSER_STOP = 0xA9,
|
||||
VK_BROWSER_SEARCH = 0xAA,
|
||||
VK_BROWSER_FAVORITES = 0xAB,
|
||||
VK_BROWSER_HOME = 0xAC,
|
||||
//
|
||||
VK_VOLUME_MUTE = 0xAD,
|
||||
VK_VOLUME_DOWN = 0xAE,
|
||||
VK_VOLUME_UP = 0xAF,
|
||||
VK_MEDIA_NEXT_TRACK = 0xB0,
|
||||
VK_MEDIA_PREV_TRACK = 0xB1,
|
||||
VK_MEDIA_STOP = 0xB2,
|
||||
VK_MEDIA_PLAY_PAUSE = 0xB3,
|
||||
VK_LAUNCH_MAIL = 0xB4,
|
||||
VK_LAUNCH_MEDIA_SELECT = 0xB5,
|
||||
VK_LAUNCH_APP1 = 0xB6,
|
||||
VK_LAUNCH_APP2 = 0xB7,
|
||||
//
|
||||
VK_OEM_1 = 0xBA, // ';:' for US
|
||||
VK_OEM_PLUS = 0xBB, // '+' any country
|
||||
VK_OEM_COMMA = 0xBC, // ',' any country
|
||||
VK_OEM_MINUS = 0xBD, // '-' any country
|
||||
VK_OEM_PERIOD = 0xBE, // '.' any country
|
||||
VK_OEM_2 = 0xBF, // '/?' for US
|
||||
VK_OEM_3 = 0xC0, // '`~' for US
|
||||
//
|
||||
VK_OEM_4 = 0xDB, // '[{' for US
|
||||
VK_OEM_5 = 0xDC, // '\|' for US
|
||||
VK_OEM_6 = 0xDD, // ']}' for US
|
||||
VK_OEM_7 = 0xDE, // ''"' for US
|
||||
VK_OEM_8 = 0xDF,
|
||||
//
|
||||
VK_OEM_AX = 0xE1, // 'AX' key on Japanese AX kbd
|
||||
VK_OEM_102 = 0xE2, // "<>" or "\|" on RT 102-key kbd.
|
||||
VK_ICO_HELP = 0xE3, // Help key on ICO
|
||||
VK_ICO_00 = 0xE4, // 00 key on ICO
|
||||
//
|
||||
VK_PROCESSKEY = 0xE5,
|
||||
//
|
||||
VK_ICO_CLEAR = 0xE6,
|
||||
//
|
||||
VK_PACKET = 0xE7,
|
||||
//
|
||||
VK_OEM_RESET = 0xE9,
|
||||
VK_OEM_JUMP = 0xEA,
|
||||
VK_OEM_PA1 = 0xEB,
|
||||
VK_OEM_PA2 = 0xEC,
|
||||
VK_OEM_PA3 = 0xED,
|
||||
VK_OEM_WSCTRL = 0xEE,
|
||||
VK_OEM_CUSEL = 0xEF,
|
||||
VK_OEM_ATTN = 0xF0,
|
||||
VK_OEM_FINISH = 0xF1,
|
||||
VK_OEM_COPY = 0xF2,
|
||||
VK_OEM_AUTO = 0xF3,
|
||||
VK_OEM_ENLW = 0xF4,
|
||||
VK_OEM_BACKTAB = 0xF5,
|
||||
//
|
||||
VK_ATTN = 0xF6,
|
||||
VK_CRSEL = 0xF7,
|
||||
VK_EXSEL = 0xF8,
|
||||
VK_EREOF = 0xF9,
|
||||
VK_PLAY = 0xFA,
|
||||
VK_ZOOM = 0xFB,
|
||||
VK_NONAME = 0xFC,
|
||||
VK_PA1 = 0xFD,
|
||||
VK_OEM_CLEAR = 0xFE
|
||||
}
|
||||
}
|
||||
}
|
||||
39
Legacy/BallanceTASEditor/Core/LimitedStack.cs
Normal file
39
Legacy/BallanceTASEditor/Core/LimitedStack.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace BallanceTASEditor.Core {
|
||||
public class LimitedStack<T> {
|
||||
private static readonly int STACK_LENGTH = 20;
|
||||
|
||||
public LimitedStack() {
|
||||
_stack = new LinkedList<T>();
|
||||
}
|
||||
|
||||
private LinkedList<T> _stack;
|
||||
|
||||
public void Push(T data) {
|
||||
_stack.AddLast(data);
|
||||
if (_stack.Count > STACK_LENGTH) {
|
||||
_stack.RemoveFirst();
|
||||
}
|
||||
}
|
||||
|
||||
public T Pop() {
|
||||
if (_stack.Last == null) return default(T);
|
||||
var data = _stack.Last.Value;
|
||||
_stack.RemoveLast();
|
||||
return data;
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
_stack.Clear();
|
||||
}
|
||||
|
||||
public bool IsEmpty() {
|
||||
return _stack.Count == 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
256
Legacy/BallanceTASEditor/Core/TASFile.cs
Normal file
256
Legacy/BallanceTASEditor/Core/TASFile.cs
Normal file
@ -0,0 +1,256 @@
|
||||
using BallanceTASEditor.Core.FileOperation;
|
||||
using BallanceTASEditor.Core.TASStruct;
|
||||
using BallanceTASEditor.UI;
|
||||
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<FrameData>();
|
||||
var fs = new FileStream(mFilename, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
ZlibUtil.DecompressTAS(mMem, fs);
|
||||
fs.Close();
|
||||
fs.Dispose();
|
||||
mPointer = mMem.First;
|
||||
mPointerIndex = mPointer == null ? -1 : 0;
|
||||
|
||||
mRedoStack = new LimitedStack<RevocableOperation>();
|
||||
mUndoStack = new LimitedStack<RevocableOperation>();
|
||||
}
|
||||
|
||||
public string mFilename { get; private set; }
|
||||
public long mFrameCount { get { return mMem.Count; } }
|
||||
LinkedList<FrameData> mMem;
|
||||
LinkedListNode<FrameData> mPointer;
|
||||
long mPointerIndex;
|
||||
|
||||
LimitedStack<RevocableOperation> mRedoStack;
|
||||
LimitedStack<RevocableOperation> mUndoStack;
|
||||
|
||||
public bool IsEmpty() {
|
||||
return (mPointer == null);
|
||||
}
|
||||
|
||||
public long GetPointerIndex() {
|
||||
// return invalid data to prevent error
|
||||
if (mPointer == null) return -1;//throw new Exception("Data is not ready");
|
||||
return mPointerIndex;
|
||||
}
|
||||
|
||||
public void Shift(long absoluteIndex) {
|
||||
if (mPointer == null) return;
|
||||
|
||||
mPointer = mMem.FastGetNode(mPointer, mPointerIndex, absoluteIndex);
|
||||
mPointerIndex = absoluteIndex;
|
||||
}
|
||||
|
||||
public void Get(List<FrameDataDisplay> container, int count) {
|
||||
// no item. clean container
|
||||
if (mPointer == null) {
|
||||
for (int j = 0; j < count; j++) {
|
||||
container[j].isEnable = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// fill container
|
||||
var cachePointer = mPointer;
|
||||
var startIndex = mPointerIndex;
|
||||
int i;
|
||||
for (i = 0; i < count && cachePointer != null; i++, startIndex++) {
|
||||
container[i].Reload(startIndex, cachePointer.Value);
|
||||
container[i].isEnable = true;
|
||||
cachePointer = cachePointer.Next;
|
||||
}
|
||||
for (; i < count; i++) {
|
||||
container[i].isEnable = false;
|
||||
}
|
||||
}
|
||||
|
||||
// if isSet is null, mean flip state
|
||||
public void Set(SelectionRange field, SelectionRange absoluteRange, bool? isSet) {
|
||||
var oper = new SetOperation(field, absoluteRange, isSet);
|
||||
oper.Do(ref mMem, ref mPointer, ref mPointerIndex);
|
||||
mUndoStack.Push(oper);
|
||||
mRedoStack.Clear();
|
||||
/*
|
||||
if (mPointer == null) return;
|
||||
|
||||
uint offset = 0;
|
||||
for(int i = (int)field.start; i <= (int)field.end; i++) {
|
||||
offset |= ConstValue.Mapping[(FrameDataField)i];
|
||||
}
|
||||
foreach(var item in mMem.IterateWithSelectionRange(absoluteRange, mPointer, mPointerIndex)) {
|
||||
if (isSet == null) item.Value.ReverseKeyStates(offset);
|
||||
else if (isSet == true) item.Value.SetKeyStates(offset);
|
||||
else if (isSet == false) item.Value.UnsetKeyStates(offset);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public void Remove(SelectionRange absoluteRange) {
|
||||
var oper = new RemoveOperation(absoluteRange);
|
||||
oper.Do(ref mMem, ref mPointer, ref mPointerIndex);
|
||||
mUndoStack.Push(oper);
|
||||
mRedoStack.Clear();
|
||||
/*
|
||||
if (mPointer == null) return;
|
||||
|
||||
// remove
|
||||
foreach(var item in mMem.IterateWithSelectionRange(absoluteRange, mPointer, mPointerIndex)) {
|
||||
mMem.Remove(item);
|
||||
}
|
||||
|
||||
// correct index data
|
||||
// if state is true, it mean the deleted content is placed before pointer previously.
|
||||
// so we need shift the pointer to the head of selection range.
|
||||
// and we should consider 2 situations, the full delete of LinkedList and delete from head
|
||||
if (mPointerIndex >= absoluteRange.start) {
|
||||
var newIndex = absoluteRange.start - 1;
|
||||
if (newIndex < 0) {
|
||||
// this contains 2 situation
|
||||
// if full delete, mPointer is null and mPointerIndex is invalid(with wrong data: 0)
|
||||
// if delete from head, mPointer and mPointerIndex all are valid.
|
||||
mPointer = mMem.First;
|
||||
mPointerIndex = 0;
|
||||
} else {
|
||||
mPointer = mMem.FastGetNode(mPointer, mPointerIndex, newIndex);
|
||||
mPointerIndex = newIndex;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public void Add(long absolutePos, long count, float deltaTime, bool isAddBefore) {
|
||||
var oper = new AddOperation(absolutePos, count, deltaTime, isAddBefore);
|
||||
oper.Do(ref mMem, ref mPointer, ref mPointerIndex);
|
||||
mUndoStack.Push(oper);
|
||||
mRedoStack.Clear();
|
||||
/*
|
||||
if (count <= 0) return;
|
||||
|
||||
if (mPointer == null) {
|
||||
// add into blank list, absolutePos and isAddBefore parameters are invalid
|
||||
// specially process
|
||||
for(long i = 0; i < count; i++) {
|
||||
mMem.AddFirst(new FrameData(deltaTime, 0));
|
||||
}
|
||||
mPointer = mMem.First;
|
||||
mPointerIndex = 0;
|
||||
} else {
|
||||
// normal add
|
||||
// normal add doesn't affect pointer
|
||||
LinkedListNode<FrameData> node = mMem.FastGetNode(mPointer, mPointerIndex, absolutePos);
|
||||
if (isAddBefore) {
|
||||
for (long i = 0; i < count; i++) {
|
||||
mMem.AddBefore(node, new FrameData(deltaTime, 0));
|
||||
}
|
||||
} else {
|
||||
for (long i = 0; i < count; i++) {
|
||||
mMem.AddAfter(node, new FrameData(deltaTime, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public void Insert(long absolutePos, LinkedList<FrameData> data, bool isInsertBefore, bool isOverwritten) {
|
||||
var oper = new InsertOperation(absolutePos, data, isInsertBefore, isOverwritten);
|
||||
oper.Do(ref mMem, ref mPointer, ref mPointerIndex);
|
||||
mUndoStack.Push(oper);
|
||||
mRedoStack.Clear();
|
||||
/*
|
||||
if (data.Count == 0) return;
|
||||
|
||||
// the same process route with add function
|
||||
if (mPointer == null) {
|
||||
foreach (var item in data.IterateFull()) {
|
||||
mMem.AddFirst(item.Value);
|
||||
}
|
||||
mPointer = mMem.First;
|
||||
mPointerIndex = 0;
|
||||
} else {
|
||||
LinkedListNode<FrameData> node = mMem.FastGetNode(mPointer, mPointerIndex, absolutePos);
|
||||
if (isInsertBefore) {
|
||||
foreach (var item in data.IterateFull()) {
|
||||
mMem.AddBefore(node, item.Value);
|
||||
}
|
||||
} else {
|
||||
foreach (var item in data.IterateFullReversed()) {
|
||||
mMem.AddAfter(node, item.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public void Redo() {
|
||||
if (mRedoStack.IsEmpty()) return;
|
||||
var oper = mRedoStack.Pop();
|
||||
oper.Do(ref mMem, ref mPointer, ref mPointerIndex);
|
||||
mUndoStack.Push(oper);
|
||||
}
|
||||
|
||||
public void Undo() {
|
||||
if (mUndoStack.IsEmpty()) return;
|
||||
var oper = mUndoStack.Pop();
|
||||
oper.Undo(ref mMem, ref mPointer, ref mPointerIndex);
|
||||
mRedoStack.Push(oper);
|
||||
}
|
||||
|
||||
public void Copy(SelectionRange absoluteRange, LinkedList<FrameData> data) {
|
||||
if (mPointer == null) return;
|
||||
|
||||
foreach (var item in mMem.IterateWithSelectionRange(absoluteRange, mPointer, mPointerIndex)) {
|
||||
data.AddLast(item.Value);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
#if DEBUG
|
||||
// following code only should be used in debug mode and served for testbench
|
||||
public TASFile(LinkedList<FrameData> items) {
|
||||
mFilename = "";
|
||||
mMem = items;
|
||||
mPointer = mMem.First;
|
||||
mPointerIndex = mPointer == null ? -1 : 0;
|
||||
|
||||
mRedoStack = new LimitedStack<RevocableOperation>();
|
||||
mUndoStack = new LimitedStack<RevocableOperation>();
|
||||
}
|
||||
|
||||
public string Output2TestString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (mPointer == null) sb.Append("null;");
|
||||
else sb.Append($"{mPointer.Value.keystates.ToString()};");
|
||||
sb.Append($"{mPointerIndex};");
|
||||
|
||||
foreach (var item in mMem.IterateFull()) {
|
||||
sb.Append(item.Value.keystates.ToString());
|
||||
sb.Append(",");
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
131
Legacy/BallanceTASEditor/Core/TASStruct.cs
Normal file
131
Legacy/BallanceTASEditor/Core/TASStruct.cs
Normal file
@ -0,0 +1,131 @@
|
||||
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 {
|
||||
public FrameDataDisplay(long index, FrameData fd) {
|
||||
isEnable = true;
|
||||
Reload(index, fd);
|
||||
}
|
||||
|
||||
public void Reload(long index, FrameData fd) {
|
||||
this.index = index;
|
||||
this.deltaTime = fd.deltaTime;
|
||||
this.keystates = fd.keystates;
|
||||
}
|
||||
|
||||
public bool isEnable { get; set; }
|
||||
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();
|
||||
}
|
||||
}
|
||||
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 void ReverseKeyStates(UInt32 offset) {
|
||||
keystates ^= offset;
|
||||
}
|
||||
|
||||
public float deltaTime;
|
||||
public UInt32 keystates;
|
||||
}
|
||||
|
||||
public class ConstValue {
|
||||
public static readonly Dictionary<FrameDataField, UInt32> Mapping = new Dictionary<FrameDataField, UInt32>() {
|
||||
{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 : int {
|
||||
Key_Up = 0,
|
||||
Key_Down = 1,
|
||||
Key_Left = 2,
|
||||
Key_Right = 3,
|
||||
Key_Shift = 4,
|
||||
Key_Space = 5,
|
||||
Key_Q = 6,
|
||||
Key_Esc = 7,
|
||||
Key_Enter = 8
|
||||
}
|
||||
|
||||
}
|
||||
161
Legacy/BallanceTASEditor/Core/Util.cs
Normal file
161
Legacy/BallanceTASEditor/Core/Util.cs
Normal file
@ -0,0 +1,161 @@
|
||||
using BallanceTASEditor.Core.TASStruct;
|
||||
using BallanceTASEditor.UI;
|
||||
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 Int32 ToInt32(this double value) {
|
||||
return (Int32)Math.Floor(value);
|
||||
}
|
||||
public static Int64 ToInt64(this double value) {
|
||||
return (Int64)Math.Floor(value);
|
||||
}
|
||||
|
||||
public static int Clamp(int value, int min, int max) {
|
||||
if (value < min) return min;
|
||||
if (value > max) return max;
|
||||
return value;
|
||||
}
|
||||
|
||||
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<FrameData> 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);
|
||||
//}
|
||||
|
||||
// remove safety. because it store the next node.
|
||||
public static IEnumerable<LinkedListNode<FrameData>> IterateFullReversed(this LinkedList<FrameData> ls) {
|
||||
var pos = ls.Last;
|
||||
LinkedListNode<FrameData> cacheNextNode;
|
||||
|
||||
while (pos != null) {
|
||||
cacheNextNode = pos.Previous;
|
||||
yield return pos;
|
||||
pos = cacheNextNode;
|
||||
}
|
||||
}
|
||||
|
||||
// remove safety. because it store the next node.
|
||||
public static IEnumerable<LinkedListNode<FrameData>> IterateFull(this LinkedList<FrameData> ls) {
|
||||
var pos = ls.First;
|
||||
LinkedListNode<FrameData> cacheNextNode;
|
||||
|
||||
while(pos != null) {
|
||||
cacheNextNode = pos.Next;
|
||||
yield return pos;
|
||||
pos = cacheNextNode;
|
||||
}
|
||||
}
|
||||
|
||||
public static LinkedListNode<FrameData> FastGetNode(this LinkedList<FrameData> ls, LinkedListNode<FrameData> refNode, long refIndex, long targetIndex) {
|
||||
long count = ls.Count - 1;
|
||||
if (targetIndex > count || refIndex > count) throw new Exception("Index is invalid!");
|
||||
var span = new StupidSortStruct[3] {
|
||||
new StupidSortStruct() { type = 1, data = targetIndex },
|
||||
new StupidSortStruct() { type = 2, data = targetIndex - count },
|
||||
new StupidSortStruct() { type = 3, data = targetIndex - refIndex }
|
||||
};
|
||||
|
||||
// sort to get the min value
|
||||
StupidSortStruct tmp;
|
||||
if (Math.Abs(span[0].data) < Math.Abs(span[1].data)) {
|
||||
tmp = span[0];
|
||||
span[0] = span[1];
|
||||
span[1] = tmp;
|
||||
}
|
||||
if (Math.Abs(span[1].data) < Math.Abs(span[2].data)) {
|
||||
tmp = span[1];
|
||||
span[2] = span[1];
|
||||
span[2] = tmp;
|
||||
}
|
||||
|
||||
LinkedListNode<FrameData> iterateNode;
|
||||
if (span[2].type == 1) iterateNode = ls.First;
|
||||
else if (span[2].type == 2) iterateNode = ls.Last;
|
||||
else if (span[2].type == 3) iterateNode = refNode;
|
||||
else throw new Exception("Unknow node type");
|
||||
|
||||
return iterateNode.ShiftTo(span[2].data);
|
||||
}
|
||||
|
||||
// remove safety. because it store the next node.
|
||||
public static IEnumerable<LinkedListNode<FrameData>> IterateWithSelectionRange(this LinkedList<FrameData> ls, SelectionRange absoluteRange, LinkedListNode<FrameData> refNode, long refIndex) {
|
||||
// goto header first
|
||||
var cache = ls.FastGetNode(refNode, refIndex, absoluteRange.start);
|
||||
|
||||
var counter = absoluteRange.start;
|
||||
LinkedListNode<FrameData> cacheNextNode;
|
||||
while (counter <= absoluteRange.end) {
|
||||
if (cache == null) throw new Exception("Unexpected head or tail of linked list!");
|
||||
cacheNextNode = cache.Next;
|
||||
yield return cache;
|
||||
cache = cacheNextNode;
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
public static LinkedListNode<FrameData> ShiftTo(this LinkedListNode<FrameData> node, long offset) {
|
||||
var cache = node;
|
||||
|
||||
long realShifted = 0;
|
||||
if (offset < 0) {
|
||||
while (realShifted != offset) {
|
||||
if (cache.Previous == null) throw new Exception("Unexpected head or tail of linked list!");
|
||||
cache = cache.Previous;
|
||||
realShifted--;
|
||||
}
|
||||
} else if (offset > 0) {
|
||||
while (realShifted != offset) {
|
||||
if (cache.Next == null) throw new Exception("Unexpected head or tail of linked list!");
|
||||
cache = cache.Next;
|
||||
realShifted++;
|
||||
}
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct SelectionRange {
|
||||
public SelectionRange(long value1, long value2) {
|
||||
if (value1 > value2) {
|
||||
start = value2;
|
||||
end = value1;
|
||||
} else {
|
||||
start = value1;
|
||||
end = value2;
|
||||
}
|
||||
}
|
||||
public long start;
|
||||
public long end;
|
||||
public SelectionRange GetRelative(long refer) {
|
||||
var res = new SelectionRange();
|
||||
res.start = start - refer;
|
||||
res.end = end - refer;
|
||||
return res;
|
||||
}
|
||||
public bool Within(long num) {
|
||||
return (num >= start && num <= end);
|
||||
}
|
||||
public long GetCount() {
|
||||
return end - start + 1;
|
||||
}
|
||||
}
|
||||
|
||||
public struct StupidSortStruct {
|
||||
public int type;
|
||||
public long data;
|
||||
}
|
||||
|
||||
}
|
||||
84
Legacy/BallanceTASEditor/Core/ZlibUtil.cs
Normal file
84
Legacy/BallanceTASEditor/Core/ZlibUtil.cs
Normal file
@ -0,0 +1,84 @@
|
||||
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<FrameData> mem, FileStream file) {
|
||||
file.Write(BitConverter.GetBytes(mem.Count * ConstValue.FRAMEDATA_SIZE), 0, 4);
|
||||
|
||||
using (var zo = new Ionic.Zlib.ZlibStream(file, Ionic.Zlib.CompressionMode.Compress, Ionic.Zlib.CompressionLevel.Level9, true)) {
|
||||
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.Close();
|
||||
}
|
||||
|
||||
//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<FrameData> ls, FileStream file) {
|
||||
var lengthTemp = new byte[4];
|
||||
file.Read(lengthTemp, 0, 4);
|
||||
Int32 expectedLength = BitConverter.ToInt32(lengthTemp, 0);
|
||||
long expectedCount = expectedLength / ConstValue.FRAMEDATA_SIZE;
|
||||
|
||||
using (var mem = new MemoryStream()) {
|
||||
using (var zo = new Ionic.Zlib.ZlibStream(mem, Ionic.Zlib.CompressionMode.Decompress, true)) {
|
||||
CopyStream(file, zo);
|
||||
zo.Close();
|
||||
}
|
||||
|
||||
mem.Seek(0, SeekOrigin.Begin);
|
||||
for (long i = 0; i < expectedCount; i++) {
|
||||
ls.AddLast(new FrameData(mem));
|
||||
}
|
||||
mem.Close();
|
||||
}
|
||||
|
||||
//mem.Seek(0, SeekOrigin.Begin);
|
||||
//for (long i = 0; i < expectedCount; i++) {
|
||||
// ls.AddLast(new FrameData(mem));
|
||||
//}
|
||||
//mem.Close();
|
||||
//zo.Close();
|
||||
|
||||
//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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user