Files
BallanceTasEditor/BallanceTASEditor/UI/TASViewer.cs

254 lines
9.8 KiB
C#
Raw Normal View History

2021-05-13 15:49:26 +08:00
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;
2021-05-13 22:18:51 +08:00
namespace BallanceTASEditor.UI {
2021-05-13 15:49:26 +08:00
public class TASViewer : IDisposable {
public TASViewer(TASFile file, TASSlider slider, TASFlow datagrid) {
2021-05-13 15:49:26 +08:00
mFile = file;
mSlider = slider;
mDataGrid = datagrid;
// restore slider
mSlider.UpdateRange(mFile);
2021-05-13 15:49:26 +08:00
2021-05-15 16:23:16 +08:00
// init selection
mSelectionHelp = new SelectionHelp();
mSelectionHelp.SelectionChanged += funcSelectionHelp_SelectionChanged;
2021-05-13 15:49:26 +08:00
// init data
INVALID_FRAME_DATA = new FrameData(-1f, 0);
2021-05-15 16:23:16 +08:00
mDataSource = new List<FrameDataDisplay>();
mListLength = 0;
mOverwrittenPaste = false;
2021-05-13 15:49:26 +08:00
// bind event and source
2021-05-13 22:18:51 +08:00
mDataGrid.DataSources = mDataSource;
2021-05-15 16:23:16 +08:00
mDataGrid.SelectionHelp = mSelectionHelp;
2021-05-16 14:15:35 +08:00
mDataGrid.Click += funcDataMenu_Click;
mSlider.ValueChanged += funcSlider_ValueChanged;
2021-05-13 15:49:26 +08:00
}
2021-05-15 16:23:16 +08:00
2021-05-13 15:49:26 +08:00
public void Dispose() {
2021-05-13 22:18:51 +08:00
mDataGrid.DataSources = null;
2021-05-16 14:15:35 +08:00
mDataGrid.Click -= funcDataMenu_Click;
mSlider.ValueChanged -= funcSlider_ValueChanged;
2021-05-13 15:49:26 +08:00
}
//const int DATA_LIST_LENGTH = 15;
2021-05-13 15:49:26 +08:00
FrameData INVALID_FRAME_DATA;
TASFile mFile;
TASSlider mSlider;
2021-05-13 22:18:51 +08:00
TASFlow mDataGrid;
2021-05-15 16:23:16 +08:00
SelectionHelp mSelectionHelp;
int mListLength;
2021-05-13 22:18:51 +08:00
List<FrameDataDisplay> mDataSource;
bool mOverwrittenPaste;
2021-05-13 15:49:26 +08:00
#region self event
public event Action<bool, bool, bool> UpdateDataUI;
public event Action<ToolMode> UpdateToolMode;
public event Action<SelectionHelp> UpdateSelection;
2021-05-13 15:49:26 +08:00
private void OnUpdateDataUI() {
ToolMode mode = mSelectionHelp.GetToolMode();
bool showCursorPasteAddDeleteOne = mode == ToolMode.Cursor && mSelectionHelp.IsDataPartialReady();
bool showFill = mode == ToolMode.Fill && mSelectionHelp.IsDataReady();
bool showCursorCopyDelete = mode == ToolMode.Cursor && mSelectionHelp.IsDataReady();
UpdateDataUI?.Invoke(showCursorPasteAddDeleteOne, showFill, showCursorCopyDelete);
2021-05-13 15:49:26 +08:00
}
private void OnUpdateToolMode() {
UpdateToolMode?.Invoke(mSelectionHelp.GetToolMode());
}
private void OnUpdateSelection() {
UpdateSelection?.Invoke(mSelectionHelp);
}
#endregion
#region process event
private void funcSlider_ValueChanged(long pos) {
mFile.Shift(pos);
RefreshDisplay();
2021-05-13 15:49:26 +08:00
}
2021-05-15 16:23:16 +08:00
private void funcSelectionHelp_SelectionChanged() {
mDataGrid.RefreshSelectionHighlight();
OnUpdateDataUI();
OnUpdateSelection();
2021-05-15 16:23:16 +08:00
}
private void funcDataMenu_Click() {
var data = mSelectionHelp.GetPoint();
var field = (int)mSelectionHelp.GetPointField();
mFile.Set(new SelectionRange(field, field), new SelectionRange(data, data), null);
RefreshDisplay();
2021-05-15 16:23:16 +08:00
}
#endregion
public void ChangeOverwrittenMode(bool isOverwritten) {
mOverwrittenPaste = isOverwritten;
}
2021-05-15 16:23:16 +08:00
public void ChangeListLength(int newLen) {
if (newLen < 5 || newLen > 200) return;
2021-05-15 16:23:16 +08:00
int offset = newLen - mListLength;
int abs = Math.Abs(offset);
if (offset == 0) return;
// change mDataSource first
if (offset > 0) {
for (int i = 0; i < abs; i++) {
mDataSource.Add(new FrameDataDisplay(0, INVALID_FRAME_DATA));
}
} else {
mDataSource.RemoveRange(newLen, abs);
}
// then change viewer control
mDataGrid.SetItemCount(newLen);
// apply new value
mListLength = newLen;
// then refresh
2021-05-21 22:37:25 +08:00
RefreshDisplay();
2021-05-15 16:23:16 +08:00
}
2021-05-21 22:37:25 +08:00
public void RefreshDisplay() {
mFile.Get(mDataSource, mListLength);
2021-05-15 16:23:16 +08:00
mDataGrid.RefreshDataSources();
mDataGrid.RefreshSelectionHighlight();
}
2021-05-15 16:23:16 +08:00
public void ChangeToolMode(ToolMode mode) {
mSelectionHelp.SetMode(mode);
OnUpdateToolMode();
2021-05-15 16:23:16 +08:00
}
2021-05-22 13:25:37 +08:00
public int GetItemCountInPage() {
return mListLength;
}
2021-05-16 14:15:35 +08:00
public void ProcessOperation(OperationEnum oper) {
switch (oper) {
case OperationEnum.Set:
case OperationEnum.Unset: {
mFile.Set(mSelectionHelp.GetFieldRange(), mSelectionHelp.GetRange(), oper == OperationEnum.Set);
RefreshDisplay();
}
break;
2021-08-08 12:04:17 +08:00
case OperationEnum.Cut: {
// cut is a hybrid operation, first, do copy
// then delete selected item
// due to copy is not affect TASFile and only delete oper affect it
// so this is a revocable oper
var data = new LinkedList<FrameData>();
mFile.Copy(mSelectionHelp.GetRange(), data);
if (!ClipboardUtil.SetFrameData(data)) {
MessageBox.Show("Fail to cut due to unknow reason!");
break; // if fail to cut, do not delete selected items.
}
// do delete
mFile.Remove(mSelectionHelp.GetRange());
mSelectionHelp.Reset();
mSlider.UpdateRange(mFile);
2021-08-08 12:04:17 +08:00
RefreshDisplay();
}
break;
case OperationEnum.Copy: {
var data = new LinkedList<FrameData>();
mFile.Copy(mSelectionHelp.GetRange(), data);
if (!ClipboardUtil.SetFrameData(data))
MessageBox.Show("Fail to copy due to unknow reason!");
}
break;
case OperationEnum.PasteAfter:
case OperationEnum.PasteBefore: {
var data = new LinkedList<FrameData>();
if (ClipboardUtil.GetFrameData(data)) {
mFile.Insert(mSelectionHelp.GetPoint(), data, oper == OperationEnum.PasteBefore, mOverwrittenPaste);
mSelectionHelp.Reset();
mSlider.UpdateRange(mFile);
RefreshDisplay();
} else MessageBox.Show("Fail to paste due to unknow reason or blank clipboard!");
}
break;
case OperationEnum.Delete: {
mFile.Remove(mSelectionHelp.GetRange());
mSelectionHelp.Reset();
mSlider.UpdateRange(mFile);
RefreshDisplay();
}
break;
case OperationEnum.DeleteAfter:
case OperationEnum.DeleteBefore: {
var pos = mSelectionHelp.GetPoint();
2021-07-27 17:17:34 +08:00
if (oper == OperationEnum.DeleteBefore) pos -= 1; // delete after mean delete current selected item
if (pos < 0 || pos >= mFile.mFrameCount) return;
// delete before need shift selection
2021-07-27 17:17:34 +08:00
// delete before couldn't cause empty list, so we just need to directly shift
if (oper == OperationEnum.DeleteBefore)
mSelectionHelp.ShiftTo(false);
2021-07-27 17:17:34 +08:00
// also, if we use delete after and delete the tail of item list, we also need to shift pos(use `else if` to prevent double shift)
else if (oper == OperationEnum.DeleteAfter && pos == mFile.mFrameCount - 1) {
2021-07-27 17:17:34 +08:00
// but delete after may cause empty list error(delete the item within only 1 item list)
// so we need prevent this situation
if (mFile.mFrameCount == 1) mSelectionHelp.Reset(); //yes, reset selection to prevent error
else mSelectionHelp.ShiftTo(false); //no, shift selection.
}
// do real operation
mFile.Remove(new SelectionRange(pos, pos));
mSlider.UpdateRange(mFile);
RefreshDisplay();
}
break;
case OperationEnum.AddAfter:
case OperationEnum.AddBefore: {
if (!DialogUtil.AddItemDialog(out int count, out float deltaTime)) return;
var pos = mSelectionHelp.GetPoint();
mFile.Add(pos, count, deltaTime, oper == OperationEnum.AddBefore);
mSelectionHelp.Reset();
mSlider.UpdateRange(mFile);
RefreshDisplay();
}
break;
case OperationEnum.Undo: {
mFile.Undo();
mSelectionHelp.Reset();
mSlider.UpdateRange(mFile);
RefreshDisplay();
}
break;
case OperationEnum.Redo: {
mFile.Redo();
mSelectionHelp.Reset();
mSlider.UpdateRange(mFile);
RefreshDisplay();
}
break;
}
2021-05-16 14:15:35 +08:00
}
2021-05-13 15:49:26 +08:00
}
}