mirror of
https://github.com/RHeavenStudioPlus/HeavenStudioPlus.git
synced 2024-11-25 19:15:16 +00:00
0cdfb2bc63
* wip * move fix * wip * Insert / Delete Space
561 lines
No EOL
19 KiB
C#
561 lines
No EOL
19 KiB
C#
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
|
|
using Jukebox;
|
|
using TMPro;
|
|
using System.Linq;
|
|
using System.Collections.Generic;
|
|
|
|
namespace HeavenStudio.Editor.Track
|
|
{
|
|
public class TimelineEventObj : MonoBehaviour
|
|
{
|
|
public bool interacting;
|
|
|
|
private Vector3 lastPos;
|
|
public Vector2 moveStartPos;
|
|
private RectTransform rectTransform;
|
|
|
|
[Header("Components")]
|
|
[SerializeField] private RectTransform PosPreview;
|
|
[SerializeField] private RectTransform PosPreviewRef;
|
|
[SerializeField] public Image Icon;
|
|
[SerializeField] private Image selectedImage;
|
|
[SerializeField] public TMP_Text eventLabel;
|
|
|
|
[SerializeField] private Image resizeGraphic;
|
|
|
|
[SerializeField] private RectTransform leftDrag;
|
|
[SerializeField] private RectTransform rightDrag;
|
|
|
|
[SerializeField] private Image outline;
|
|
[SerializeField] private Image hasPropertiesIcon;
|
|
|
|
[SerializeField] private RectTransform visibleRegion;
|
|
|
|
// private GameObject moveTemp;
|
|
|
|
[Header("Properties")]
|
|
public RiqEntity entity;
|
|
public float length;
|
|
private bool lastVisible;
|
|
public bool selected;
|
|
public bool mouseHovering;
|
|
public bool resizable;
|
|
public bool moving;
|
|
public bool wasDuplicated;
|
|
|
|
public bool resizing => resizingLeft || resizingRight;
|
|
private bool resizingLeft;
|
|
private bool resizingRight;
|
|
private bool inResizeRegion;
|
|
private float resizingLeftBL;
|
|
|
|
private double lastResizeBeat = 0;
|
|
private float lastResizeLength = 0;
|
|
|
|
public bool isCreating;
|
|
|
|
private bool altWhenClicked = false;
|
|
private bool dragging = false;
|
|
|
|
private double initMoveX = 0;
|
|
private float initMoveY = 0;
|
|
private double selectedMinInitMoveX, selectedMaxInitMoveX;
|
|
private float selectedMinInitMoveY, selectedMaxInitMoveY;
|
|
|
|
private bool movedEntity = false;
|
|
private double lastBeat = 0;
|
|
private int lastLayer = 0;
|
|
|
|
private int lastSiblingIndex;
|
|
private bool changedSiblingIndex;
|
|
|
|
public float zPriority { get; private set; }
|
|
|
|
// Difference between mouseHovering is this is regardless if the user can see it.
|
|
private bool mouseOver;
|
|
|
|
private float clickTimer = 0.0f;
|
|
|
|
[Header("Colors")]
|
|
public Color NormalCol;
|
|
|
|
public void SetMarkerInfo()
|
|
{
|
|
moveStartPos = transform.localPosition;
|
|
rectTransform = GetComponent<RectTransform>();
|
|
|
|
var eventName = entity.datamodel;
|
|
|
|
string[] split = eventName.Split('/');
|
|
var action = EventCaller.instance.GetGameAction(split[0], split[1]);
|
|
|
|
if (split[1] == "switchGame")
|
|
Icon.sprite = Editor.GameIcon(split[2]);
|
|
else
|
|
Icon.sprite = Editor.GameIcon(split[0]);
|
|
|
|
if (action != null)
|
|
{
|
|
this.resizable = action.resizable;
|
|
if (action.resizable == false)
|
|
{
|
|
rectTransform.sizeDelta = new Vector2(action.defaultLength * Timeline.instance.PixelsPerBeat, Timeline.instance.LayerHeight());
|
|
this.length = action.defaultLength;
|
|
}
|
|
else
|
|
{
|
|
if (entity != null && action.defaultLength != entity.length)
|
|
{
|
|
rectTransform.sizeDelta = new Vector2(entity.length * Timeline.instance.PixelsPerBeat, Timeline.instance.LayerHeight());
|
|
}
|
|
else
|
|
{
|
|
rectTransform.sizeDelta = new Vector2(action.defaultLength * Timeline.instance.PixelsPerBeat, Timeline.instance.LayerHeight());
|
|
}
|
|
}
|
|
}
|
|
|
|
rectTransform.anchoredPosition = new Vector2((float)entity.beat * Timeline.instance.PixelsPerBeat, (int)-entity["track"] * Timeline.instance.LayerHeight());
|
|
resizeGraphic.gameObject.SetActive(resizable);
|
|
eventLabel.text = action.displayName;
|
|
|
|
hasPropertiesIcon.enabled = action.actionName != "switchGame" && action.parameters != null && action.parameters.Count > 0;
|
|
|
|
SetColor((int)entity["track"]);
|
|
SetWidthHeight();
|
|
selectedImage.gameObject.SetActive(false);
|
|
|
|
lastBeat = entity.beat;
|
|
initMoveX = 0.0f;
|
|
initMoveY = 0.0f;
|
|
lastResizeBeat = 0;
|
|
lastResizeLength = 0;
|
|
}
|
|
|
|
public void SetEntity(RiqEntity entity)
|
|
{
|
|
this.entity = entity;
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
clickTimer += Time.deltaTime;
|
|
}
|
|
|
|
public void UpdateMarker()
|
|
{
|
|
mouseOver = Timeline.instance.timelineState.selected && Timeline.instance.MouseInTimeline &&
|
|
HeavenStudio.Util.MathUtils.IsBetween(Timeline.instance.MousePos2Beat, (float)entity.beat, (float)entity.beat + entity.length) &&
|
|
Timeline.instance.MousePos2Layer == (int)entity["track"];
|
|
|
|
eventLabel.overflowMode = (mouseHovering || moving || resizing || inResizeRegion) ? TextOverflowModes.Overflow : TextOverflowModes.Ellipsis;
|
|
|
|
if (selected)
|
|
{
|
|
if (TimelineBlockManager.Instance.MovingAnyEvents)
|
|
{
|
|
outline.color = Color.magenta;
|
|
SetColor((int)entity["track"]);
|
|
}
|
|
else
|
|
outline.color = Color.cyan;
|
|
}
|
|
else
|
|
{
|
|
outline.color = new Color32(0, 0, 0, 51);
|
|
}
|
|
|
|
if (Conductor.instance.NotStopped())
|
|
{
|
|
if (moving)
|
|
{
|
|
moving = false;
|
|
}
|
|
|
|
if (selected)
|
|
{
|
|
Selections.instance.Deselect(this);
|
|
outline.color = new Color32(0, 0, 0, 51);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (resizingRight)
|
|
{
|
|
if (moving) moving = false;
|
|
|
|
entity.length = Mathf.Max(Timeline.instance.MousePos2BeatSnap - (float)entity.beat, Timeline.instance.snapInterval);
|
|
|
|
SetWidthHeight();
|
|
}
|
|
else if (resizingLeft)
|
|
{
|
|
if (moving) moving = false;
|
|
|
|
entity.beat = Mathf.Min(Timeline.instance.MousePos2BeatSnap, resizingLeftBL - Timeline.instance.snapInterval);
|
|
entity.length = Mathf.Max(resizingLeftBL - (float)entity.beat, Timeline.instance.snapInterval);
|
|
|
|
SetWidthHeight();
|
|
}
|
|
else
|
|
{
|
|
if (Input.GetMouseButtonUp(0))
|
|
{
|
|
if (moving)
|
|
{
|
|
moving = false;
|
|
|
|
if (!isCreating && movedEntity)
|
|
{
|
|
// NOTE (PELLY): Replace with arrays soon
|
|
List<double> lastBeats = new();
|
|
List<int> lastLayers = new();
|
|
foreach (var marker in Selections.instance.eventsSelected)
|
|
{
|
|
var entity = marker.entity;
|
|
|
|
lastBeats.Add(marker.entity.beat);
|
|
lastLayers.Add((int)marker.entity["track"]);
|
|
|
|
entity.beat = marker.lastBeat;
|
|
entity["track"] = marker.lastLayer;
|
|
}
|
|
CommandManager.Instance.AddCommand(new Commands.Move(Selections.instance.eventsSelected.Select(c => c.entity).ToList(), lastBeats, lastLayers));
|
|
}
|
|
|
|
isCreating = false;
|
|
|
|
GameManager.instance.SortEventsList();
|
|
TimelineBlockManager.Instance.SortMarkers();
|
|
}
|
|
|
|
altWhenClicked = false;
|
|
dragging = false;
|
|
}
|
|
|
|
if (moving)
|
|
{
|
|
foreach (var marker in Selections.instance.eventsSelected)
|
|
{
|
|
var nextBeat = System.Math.Max(Timeline.instance.MousePos2BeatSnap, selectedMaxInitMoveX) - marker.initMoveX;
|
|
var nextTrack = Mathf.Clamp(Timeline.instance.MousePos2Layer, selectedMaxInitMoveY, Timeline.instance.LayerCount - 1 + selectedMinInitMoveY) - marker.initMoveY;
|
|
marker.entity.beat = System.Math.Max(nextBeat, 0);
|
|
marker.entity["track"] = Mathf.Clamp(nextTrack, 0, Timeline.instance.LayerCount - 1);
|
|
marker.SetColor((int)entity["track"]);
|
|
marker.SetWidthHeight();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Input.GetMouseButtonUp(0))
|
|
{
|
|
OnLeftUp();
|
|
OnRightUp();
|
|
}
|
|
|
|
// should consider adding this someday
|
|
// else if (moving && selected || mouseHovering && selected)
|
|
// {
|
|
// Cursor.SetCursor(Resources.Load<Texture2D>("Cursors/move"), new Vector2(8, 8), CursorMode.Auto);
|
|
// }
|
|
|
|
zPriority = entity.length;
|
|
|
|
if (selected)
|
|
zPriority += 10000;
|
|
}
|
|
|
|
public void LateUpdate()
|
|
{
|
|
rectTransform.anchoredPosition = new Vector2((float)entity.beat * Timeline.instance.PixelsPerBeat, -(int)entity["track"] * Timeline.instance.LayerHeight());
|
|
SetWidthHeight();
|
|
|
|
var followXL = (Timeline.instance.leftSide - (float)entity.beat) * Timeline.instance.PixelsPerBeat;
|
|
visibleRegion.offsetMin = new Vector2(
|
|
Mathf.Clamp(followXL - 2, 0, (entity.length * Timeline.instance.PixelsPerBeat) - Timeline.instance.LayerHeight()),
|
|
visibleRegion.offsetMin.y);
|
|
|
|
var followXR = (Timeline.instance.rightSide - ((float)entity.beat + entity.length)) * Timeline.instance.PixelsPerBeat;
|
|
visibleRegion.offsetMax = new Vector2(
|
|
Mathf.Clamp(followXR, -(entity.length * Timeline.instance.PixelsPerBeat) + 8, 0),
|
|
visibleRegion.offsetMax.y);
|
|
}
|
|
|
|
public void BeginMoving(bool setMovedEntity = true)
|
|
{
|
|
moving = true;
|
|
|
|
foreach (var marker in Selections.instance.eventsSelected)
|
|
{
|
|
if (setMovedEntity) marker.movedEntity = true;
|
|
marker.lastBeat = marker.entity.beat;
|
|
marker.lastLayer = (int)marker.entity["track"];
|
|
|
|
marker.initMoveX = Timeline.instance.MousePos2BeatSnap - marker.entity.beat;
|
|
marker.initMoveY = Timeline.instance.MousePos2Layer - (int)marker.entity["track"];
|
|
}
|
|
selectedMinInitMoveX = Selections.instance.eventsSelected.Min(marker => marker.initMoveX);
|
|
selectedMaxInitMoveX = Selections.instance.eventsSelected.Max(marker => marker.initMoveX);
|
|
selectedMinInitMoveY = Selections.instance.eventsSelected.Min(marker => marker.initMoveY);
|
|
selectedMaxInitMoveY = Selections.instance.eventsSelected.Max(marker => marker.initMoveY);
|
|
}
|
|
|
|
#region ClickEvents
|
|
|
|
public void HoverEnter()
|
|
{
|
|
if (!TimelineBlockManager.Instance.MovingAnyEvents)
|
|
{
|
|
lastSiblingIndex = gameObject.transform.GetSiblingIndex();
|
|
gameObject.transform.SetAsLastSibling();
|
|
changedSiblingIndex = true;
|
|
}
|
|
else
|
|
changedSiblingIndex = false;
|
|
|
|
mouseHovering = true;
|
|
if (!selected && !TimelineBlockManager.Instance.MovingAnyEvents) selectedImage.gameObject.SetActive(true);
|
|
}
|
|
|
|
public void HoverExit()
|
|
{
|
|
if (changedSiblingIndex)
|
|
gameObject.transform.SetSiblingIndex(lastSiblingIndex);
|
|
|
|
mouseHovering = false;
|
|
selectedImage.gameObject.SetActive(false);
|
|
}
|
|
|
|
public void OnDragMain()
|
|
{
|
|
if (Conductor.instance.NotStopped()) return;
|
|
|
|
if (Input.GetMouseButton(1) || Input.GetMouseButton(2)) return;
|
|
if (!moving)
|
|
if (!altWhenClicked)
|
|
altWhenClicked = Input.GetKey(KeyCode.LeftAlt);
|
|
|
|
if (!altWhenClicked)
|
|
{
|
|
if (!selected)
|
|
Selections.instance.ClickSelect(this);
|
|
if (!moving)
|
|
BeginMoving();
|
|
|
|
return;
|
|
}
|
|
|
|
if (dragging) return;
|
|
|
|
var entities = Selections.instance.eventsSelected;
|
|
if (entities.Count == 0)
|
|
{
|
|
entities = new() { this };
|
|
}
|
|
CommandManager.Instance.AddCommand(new Commands.Duplicate(entities));
|
|
|
|
dragging = true;
|
|
}
|
|
|
|
public void OnDown()
|
|
{
|
|
if (Conductor.instance.NotStopped()) return;
|
|
if (moving) return;
|
|
|
|
if (Input.GetMouseButton(0) && Timeline.instance.timelineState.selected)
|
|
{
|
|
if (Input.GetKey(KeyCode.LeftShift))
|
|
{
|
|
Selections.instance.ShiftClickSelect(this);
|
|
}
|
|
else
|
|
{
|
|
if (selected && clickTimer < 0.315f)
|
|
{
|
|
foreach (var marker in TimelineBlockManager.Instance.EntityMarkers.Values)
|
|
{
|
|
if (marker == this) continue;
|
|
if (marker.mouseOver)
|
|
{
|
|
Selections.instance.ClickSelect(marker);
|
|
marker.clickTimer = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (!selected)
|
|
Selections.instance.ClickSelect(this);
|
|
}
|
|
}
|
|
else if (Input.GetMouseButton(1))
|
|
{
|
|
EventParameterManager.instance.StartParams(entity);
|
|
}
|
|
else if (Input.GetMouseButton(2))
|
|
{
|
|
string[] datamodels = entity.datamodel.Split('/');
|
|
Debug.Log("Selected entity's datamodel : " + entity.datamodel);
|
|
|
|
bool isSwitchGame = datamodels[1] == "switchGame";
|
|
var game = EventCaller.instance.minigames[datamodels[isSwitchGame ? 2 : 0]];
|
|
int block = isSwitchGame ? 0 : game.actions.FindIndex(c => c.actionName == datamodels[1]) + 1;
|
|
|
|
if (!isSwitchGame)
|
|
{
|
|
// hardcoded stuff
|
|
// needs to happen because hidden blocks technically change the event index
|
|
if (game.fxOnly) block--;
|
|
if (datamodels[0] == "gameManager") block --;
|
|
}
|
|
|
|
GridGameSelector.instance.SelectGame(datamodels[isSwitchGame ? 2 : 0], block);
|
|
}
|
|
|
|
clickTimer = 0;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ResizeEvents
|
|
|
|
public void ResizeEnter()
|
|
{
|
|
if (Conductor.instance.NotStopped()) return;
|
|
if (BoxSelection.instance.ActivelySelecting || !resizable || moving) return;
|
|
|
|
inResizeRegion = true;
|
|
|
|
Cursor.SetCursor(Timeline.instance.resizeCursor, new Vector2(14, 14), CursorMode.Auto);
|
|
}
|
|
|
|
public void ResizeExit()
|
|
{
|
|
inResizeRegion = false;
|
|
|
|
if (!resizing)
|
|
Cursor.SetCursor(null, Vector2.zero, CursorMode.Auto);
|
|
}
|
|
|
|
public void OnLeftDown()
|
|
{
|
|
if (BoxSelection.instance.ActivelySelecting) return;
|
|
|
|
if (resizable && selected)
|
|
{
|
|
ResetResize();
|
|
|
|
resizingLeft = true;
|
|
|
|
resizingLeftBL = (float)entity.beat + entity.length;
|
|
|
|
lastResizeBeat = entity.beat;
|
|
lastResizeLength = entity.length;
|
|
}
|
|
}
|
|
|
|
public void OnLeftUp()
|
|
{
|
|
if (resizable && resizingLeft)
|
|
{
|
|
ResetResize();
|
|
Cursor.SetCursor(null, Vector2.zero, CursorMode.Auto);
|
|
|
|
var b = entity.beat;
|
|
var l = entity.length;
|
|
|
|
entity.beat = lastResizeBeat;
|
|
entity.length = lastResizeLength;
|
|
|
|
CommandManager.Instance.AddCommand(new Commands.Resize(entity.guid, b, l));
|
|
}
|
|
}
|
|
|
|
public void OnRightDown()
|
|
{
|
|
if (BoxSelection.instance.ActivelySelecting) return;
|
|
|
|
if (resizable && selected)
|
|
{
|
|
ResetResize();
|
|
|
|
resizingRight = true;
|
|
|
|
lastResizeBeat = entity.beat;
|
|
lastResizeLength = entity.length;
|
|
}
|
|
}
|
|
|
|
public void OnRightUp()
|
|
{
|
|
if (resizable && resizingRight)
|
|
{
|
|
ResetResize();
|
|
Cursor.SetCursor(null, Vector2.zero, CursorMode.Auto);
|
|
|
|
var b = entity.beat;
|
|
var l = entity.length;
|
|
|
|
entity.beat = lastResizeBeat;
|
|
entity.length = lastResizeLength;
|
|
|
|
CommandManager.Instance.AddCommand(new Commands.Resize(entity.guid, b, l));
|
|
}
|
|
}
|
|
|
|
private void ResetResize()
|
|
{
|
|
resizingLeft = false;
|
|
resizingRight = false;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Extra
|
|
|
|
public void SetColor(int type)
|
|
{
|
|
var c = EditorTheme.theme.LayerGradientIndex(type);
|
|
transform.GetChild(0).GetComponent<Image>().color = c;
|
|
|
|
if (resizable)
|
|
{
|
|
c = new Color(0, 0, 0, 0.35f);
|
|
resizeGraphic.color = c;
|
|
}
|
|
}
|
|
|
|
public void SetWidthHeight()
|
|
{
|
|
rectTransform.sizeDelta = new Vector2(entity.length * Timeline.instance.PixelsPerBeat, Timeline.instance.LayerHeight());
|
|
Icon.rectTransform.sizeDelta = new Vector2(Timeline.instance.LayerHeight() - 8, Timeline.instance.LayerHeight() - 8);
|
|
eventLabel.rectTransform.offsetMin = new Vector2(Icon.rectTransform.anchoredPosition.x + Icon.rectTransform.sizeDelta.x + 4, eventLabel.rectTransform.offsetMin.y);
|
|
}
|
|
|
|
public int GetTrack()
|
|
{
|
|
return (int)Mathf.Round(this.transform.localPosition.y / Timeline.instance.LayerHeight()) * -1;
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
// better safety net than canada's healthcare system
|
|
// this is still hilarious
|
|
// GameManager.instance.Beatmap.Entities.Remove(GameManager.instance.Beatmap.Entities.Find(c => c.eventObj = this));
|
|
}
|
|
|
|
#endregion
|
|
|
|
public void OnSelect()
|
|
{
|
|
// selectedImage.gameObject.SetActive(true);
|
|
}
|
|
|
|
public void OnDeselect()
|
|
{
|
|
// selectedImage.gameObject.SetActive(false);
|
|
}
|
|
}
|
|
} |