Fix box selection

This commit is contained in:
Braedon Lewis 2023-09-23 12:27:53 -04:00
parent 638e6dcd3f
commit e0f13e5da4
14 changed files with 1873 additions and 581 deletions

View file

@ -73,6 +73,14 @@ namespace Starpelly
return val >= min && val <= max;
}
/// <summary>
/// Returns true if a value is within a certain range.
/// </summary>
public static bool IsWithin(this Vector2 val, Vector2 min, Vector2 max)
{
return val.x.IsWithin(min.x, max.x) && val.y.IsWithin(min.y, max.y);
}
/// <summary>
/// Returns true if value is between two numbers.
/// </summary>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -14,7 +14,7 @@ RenderTexture:
m_DownscaleFallback: 0
m_IsAlphaChannelOptional: 0
serializedVersion: 5
m_Width: 1130
m_Width: 1129
m_Height: 635
m_AntiAliasing: 2
m_MipCount: -1

View file

@ -14,7 +14,7 @@ RenderTexture:
m_DownscaleFallback: 0
m_IsAlphaChannelOptional: 0
serializedVersion: 5
m_Width: 1695
m_Width: 1693
m_Height: 952
m_AntiAliasing: 1
m_MipCount: -1

View file

@ -33,7 +33,7 @@ TextureImporter:
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
filterMode: 0
aniso: 1
mipBias: 0
wrapU: 1
@ -48,7 +48,7 @@ TextureImporter:
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 6, y: 6, z: 6, w: 6}
spriteBorder: {x: 2, y: 2, z: 2, w: 2}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

File diff suppressed because it is too large Load diff

View file

@ -1,201 +1,122 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Starpelly;
using HeavenStudio.Editor.Track;
using DG.Tweening;
using Starpelly;
namespace HeavenStudio.Editor
{
public class BoxSelection : MonoBehaviour
{
[SerializeField] private RectTransform boxVisual;
[SerializeField] private RectTransform timelineContent;
private Rect selectionBox;
private Vector2 startPosition = Vector2.zero;
private Vector2 endPosition = Vector2.zero;
public bool selecting = false;
/// <summary>
/// Are we currently drag selecting?
/// </summary>
public bool ActivelySelecting = false;
private bool clickedInTimeline = false;
private Vector2 startPosition = Vector2.zero;
private Vector2 endPosition = Vector2.zero;
private bool validClick = false;
[SerializeField] private RectTransform boxVisual;
private CanvasGroup boxGroup;
private TMPro.TMP_Text sizeText;
private RectTransform text;
private float timelineLastX;
public static BoxSelection instance { get; private set; }
private void Awake()
{
instance = this;
}
private void Start()
{
DrawVisual();
instance = this;
Color boxCol = EditorTheme.theme.properties.BoxSelectionCol.Hex2RGB();
boxVisual.GetComponent<Image>().color = new Color(boxCol.r, boxCol.g, boxCol.b, 0.3f);
boxVisual.transform.GetChild(0).GetComponent<Image>().color = EditorTheme.theme.properties.BoxSelectionOutlineCol.Hex2RGB();
boxVisual.GetChild(0).GetComponent<Image>().color = new Color(boxCol.r, boxCol.g, boxCol.b, 0.3f);
boxVisual.GetChild(0).GetChild(0).GetComponent<Image>().color = EditorTheme.theme.properties.BoxSelectionOutlineCol.Hex2RGB();
sizeText = boxVisual.transform.GetChild(1).GetComponent<TMPro.TMP_Text>();
text = boxVisual.transform.GetChild(1).GetComponent<RectTransform>();
sizeText = boxVisual.GetChild(0).GetChild(1).GetComponent<TMPro.TMP_Text>();
boxGroup = boxVisual.GetComponent<CanvasGroup>();
}
public void UpdateSelection()
public void LayerSelectUpdate()
{
if (Editor.instance == null) return;
float deltaTimelineX = timelineContent.transform.localPosition.x - timelineLastX;
if (Selections.instance.eventsSelected.Count > 0 && TimelineBlockManager.Instance.InteractingWithEvents)
if (Input.GetMouseButtonDown(0))
{
startPosition = Vector2.zero;
endPosition = Vector2.zero;
DrawVisual();
if (!Timeline.instance.CheckIfMouseInTimeline() || TimelineBlockManager.Instance.InteractingWithEvents)
{
return;
}
validClick = true;
startPosition = new Vector2(Timeline.instance.MousePos2Beat, Timeline.instance.MousePos2Layer);
boxGroup.DOKill();
boxGroup.alpha = 1.0f;
}
if (!validClick) return;
var startPos = startPosition;
var endPos = endPosition;
if (Input.GetMouseButton(0))
{
endPos = new Vector2(Timeline.instance.MousePos2Beat,
Timeline.instance.MousePos2Layer +
(Timeline.instance.MousePos2Layer < startPosition.y ? 0 : 1));
startPos = new Vector2(startPos.x,
startPos.y + ((Timeline.instance.MousePos2Layer < startPosition.y) ? 1 : 0));
startPos = new Vector2(startPos.x, Mathf.Clamp(startPos.y, 0, Timeline.instance.LayerCount));
endPos = new Vector2(endPos.x, Mathf.Clamp(endPos.y, 0, Timeline.instance.LayerCount));
}
var start = new Vector2(Mathf.Min(startPos.x, endPos.x),
Mathf.Min(startPos.y, endPos.y));
var end = new Vector2(Mathf.Max(startPos.x, endPos.x),
Mathf.Max(startPos.y, endPos.y));
if (Input.GetMouseButtonUp(0))
{
validClick = false;
boxGroup.DOFade(0.0f, 0.3f).SetEase(Ease.OutExpo);
return;
}
if (Conductor.instance.NotStopped() || !Timeline.instance.timelineState.selected)
{
startPosition = Vector2.zero;
endPosition = Vector2.zero;
DrawVisual();
return;
}
boxVisual.anchoredPosition = new Vector2(start.x * Timeline.instance.PixelsPerBeat, Timeline.instance.LayerToY(Mathf.FloorToInt(start.y)));
boxVisual.sizeDelta = new Vector2((end.x - start.x) * Timeline.instance.PixelsPerBeat,
(end.y - start.y) * Timeline.instance.LayerHeight());
float beatLen = boxVisual.rect.width * boxVisual.transform.localScale.x;
if (beatLen >= 0.5f)
sizeText.text = $"{string.Format("{0:0.000}", beatLen)}";
var boxLength = end.x - start.x;
if (boxLength > 0.01f)
sizeText.text = (boxLength).ToString("F");
else
sizeText.text = string.Empty;
// click
if (Input.GetMouseButtonDown(0))
{
clickedInTimeline = Timeline.instance.CheckIfMouseInTimeline();
startPosition = MousePosition();
selectionBox = new Rect();
ActivelySelecting = true;
}
// dragging
if (Input.GetMouseButton(0) && clickedInTimeline)
{
startPosition.x += deltaTimelineX;
endPosition = MousePosition();
DrawSelection();
SelectEvents(); //kek
DrawVisual();
}
// release click
if (Input.GetMouseButtonUp(0))
{
startPosition = Vector2.zero;
endPosition = Vector2.zero;
SelectEvents();
DrawVisual();
ActivelySelecting = false;
}
timelineLastX = timelineContent.transform.localPosition.x;
Select(start, end);
}
private void DrawVisual()
private void Select(Vector2 start, Vector2 end)
{
Vector2 boxStart = startPosition;
Vector2 boxEnd = endPosition;
var boxRect = new Rect(start.x, start.y, end.x - start.x, end.y - start.y);
Vector2 boxCenter = (boxStart + boxEnd) / 2;
boxVisual.position = boxCenter;
Vector2 boxSize = new Vector2(Mathf.Abs(boxStart.x - boxEnd.x), Mathf.Abs(boxStart.y - boxEnd.y));
boxVisual.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, boxSize.x);
boxVisual.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, boxSize.y);
}
private void DrawSelection()
{
// X
if (MousePosition().x < startPosition.x)
// This doesn't take into account blocks the user cannot see, this is intentional.
foreach (var marker in TimelineBlockManager.Instance.EntityMarkers.Values)
{
// dragging left
selectionBox.xMin = MousePosition().x;
selectionBox.xMax = startPosition.x;
}
else
{
// dragging right
selectionBox.xMin = startPosition.x;
selectionBox.xMax = MousePosition().x;
}
var markerRect = new Rect((float)marker.entity.beat, marker.entity["track"], marker.entity.length, 1);
// Y
if (MousePosition().y < startPosition.y)
{
// dragging down
selectionBox.yMin = MousePosition().y;
selectionBox.yMax = startPosition.y;
}
else
{
// dragging up
selectionBox.yMin = startPosition.y;
selectionBox.yMax = MousePosition().y;
}
}
private void SelectEvents()
{
if (!Input.GetKey(KeyCode.LeftShift) && !TimelineBlockManager.Instance.InteractingWithEvents && Editor.instance.canSelect)
Selections.instance.DeselectAll();
int selected = 0;
for (int i = 0; i < Timeline.instance.eventObjs.Count; i++)
{
TimelineEventObj e = Timeline.instance.eventObjs[i];
if (selectionBox.Overlaps(GetWorldRect(e.GetComponent<RectTransform>())))
var boxOverMarker = boxRect.Overlaps(markerRect);
if (boxOverMarker)
{
Selections.instance.DragSelect(e);
selected++;
if (!marker.selected)
Selections.instance.DragSelect(marker);
}
else
{
if (marker.selected && !Input.GetKey(KeyCode.LeftShift))
Selections.instance.Deselect(marker);
}
}
selecting = selected > 0;
}
public Vector3 MousePosition()
{
var mousePos = Editor.instance.EditorCamera.ScreenToWorldPoint(Input.mousePosition);
return new Vector3(mousePos.x, mousePos.y, 0);
}
public Rect GetWorldRect(RectTransform rectTransform)
{
Vector3[] corners = new Vector3[4];
rectTransform.GetWorldCorners(corners);
// Get the bottom left corner.
Vector3 position = corners[0];
Vector2 size = new Vector2(
rectTransform.lossyScale.x * rectTransform.rect.size.x,
rectTransform.lossyScale.y * rectTransform.rect.size.y);
return new Rect(position, size);
}
}
}

View file

@ -13,6 +13,7 @@ using HeavenStudio.Editor.Track;
namespace HeavenStudio.Editor
{
// I hate the antichrist.
public class GridGameSelector : MonoBehaviour
{
public Minigames.Minigame SelectedMinigame;
@ -39,6 +40,7 @@ namespace HeavenStudio.Editor
private bool gameOpen;
private float selectorHeight;
private float eventSize;
private float timeSinceUpdateIndex = 0.0f;
public static GridGameSelector instance;
@ -93,6 +95,7 @@ namespace HeavenStudio.Editor
currentEventIndex = 0;
CurrentSelected.transform.DOLocalMoveY(eventsParent.transform.GetChild(currentEventIndex).localPosition.y + eventsParent.transform.localPosition.y, 0.35f).SetEase(Ease.OutExpo);
timeSinceUpdateIndex = 0;
}
private void UpdateScrollPosition()
@ -115,6 +118,13 @@ namespace HeavenStudio.Editor
Mathf.Lerp(lastPos.y, end, 12 * Time.deltaTime),
lastPos.z
);
timeSinceUpdateIndex += Time.deltaTime;
CurrentSelected.GetComponent<RectTransform>().anchoredPosition =
new Vector2(
(Mathf.Cos(timeSinceUpdateIndex * 2.65f) * 12) + 12,
CurrentSelected.GetComponent<RectTransform>().anchoredPosition.y);
SetColors();
}
@ -192,9 +202,23 @@ namespace HeavenStudio.Editor
//CurrentSelected.GetComponent<Image>().color = EditorTheme.theme.properties.EventSelectedCol.Hex2RGB();
for (int i = 0; i < eventsParent.transform.childCount; i++)
eventsParent.GetChild(i).GetComponent<TMP_Text>().color = EditorTheme.theme.properties.EventNormalCol.Hex2RGB();
eventsParent.GetChild(currentEventIndex).GetComponent<TMP_Text>().color = EditorTheme.theme.properties.EventSelectedCol.Hex2RGB();
{
var eventTxt = eventsParent.GetChild(i).GetComponent<TMP_Text>();
var goalX = 25;
if (i == currentEventIndex)
{
eventTxt.color = EditorTheme.theme.properties.EventSelectedCol.Hex2RGB();
goalX = 45 + 16;
}
else
{
eventTxt.color = EditorTheme.theme.properties.EventNormalCol.Hex2RGB();
}
eventTxt.rectTransform.anchoredPosition =
new Vector2(
Mathf.Lerp(eventTxt.rectTransform.anchoredPosition.x, goalX, Time.deltaTime * 12f),
eventTxt.rectTransform.anchoredPosition.y);
}
}
// TODO: find the equation to get the sizes automatically, nobody's been able to figure one out yet (might have to be manual?)

View file

@ -34,6 +34,7 @@ namespace HeavenStudio.Editor.Track
[Header("Components")]
[SerializeField] private RawImage waveform;
[SerializeField] private RawImage layerBG;
public Texture2D resizeCursor;
public float WidthPerBeat { get; private set; } = 100.0f;
@ -142,6 +143,7 @@ namespace HeavenStudio.Editor.Track
[SerializeField] private TMP_Text TimelinePlaybackBeat;
public ScrollRect TimelineScroll;
public RectTransform TimelineContent;
public RectTransform EventContent;
[SerializeField] private ZoomComponent zoomComponent;
[SerializeField] private RectTransform TimelineSongPosLineRef;
[SerializeField] private RectTransform TimelineEventObjRef;
@ -223,6 +225,13 @@ namespace HeavenStudio.Editor.Track
{
instance = this;
for (var i = 0; i < LayerCount; i++)
{
var bg = Instantiate(layerBG.gameObject, layerBG.rectTransform.parent).GetComponent<RawImage>();
if (i % 2 == 0) bg.enabled = false;
}
layerBG.gameObject.SetActive(false);
LoadRemix();
TimelineSlider.GetChild(0).GetComponent<Image>().color = EditorTheme.theme.properties.BeatMarkerCol.Hex2RGB();
@ -389,10 +398,10 @@ namespace HeavenStudio.Editor.Track
private void Update()
{
RectTransformUtility.ScreenPointToLocalPointInRectangle(TimelineContent, Input.mousePosition, Editor.instance.EditorCamera, out relativeMousePos);
RectTransformUtility.ScreenPointToLocalPointInRectangle(EventContent, Input.mousePosition, Editor.instance.EditorCamera, out relativeMousePos);
MousePos2Beat = relativeMousePos.x / PixelsPerBeat;
MousePos2Layer = Mathf.Clamp(Mathf.FloorToInt(-(relativeMousePos.y - TimelineEventsHolder.offsetMax.y) / LayerHeight()), 0, LayerCount - 1);
MousePos2Layer = Mathf.Clamp(Mathf.FloorToInt(-(relativeMousePos.y) / LayerHeight()), 0, LayerCount - 1);
Conductor cond = Conductor.instance;
// waveform.rectTransform.anchoredPosition = new Vector2(
@ -503,7 +512,7 @@ namespace HeavenStudio.Editor.Track
LayersRect.GetWorldCorners(LayerCorners);
TimelineBlockManager.Instance.UpdateMarkers();
BoxSelection.instance.UpdateSelection();
BoxSelection.instance.LayerSelectUpdate();
}
public static float GetScaleModifier()
@ -647,7 +656,7 @@ namespace HeavenStudio.Editor.Track
public bool CheckIfMouseInTimeline()
{
return (this.gameObject.activeSelf && RectTransformUtility.RectangleContainsScreenPoint(TimelineEventGrid, Input.mousePosition, Editor.instance.EditorCamera));
return (this.gameObject.activeSelf && RectTransformUtility.RectangleContainsScreenPoint(EventContent, Input.mousePosition, Editor.instance.EditorCamera));
}
#endregion
@ -1001,6 +1010,11 @@ namespace HeavenStudio.Editor.Track
return LayersRect.rect.height / LayerCount;
}
public float LayerToY(int layer)
{
return (-layer * LayerHeight());
}
const float SpeedSnap = 0.25f;
public void SetPlaybackSpeed(float speed)
{

View file

@ -69,12 +69,22 @@ namespace HeavenStudio.Editor.Track
var timeLeft = timeline.leftSide;
var timeRight = timeline.rightSide;
var markersActiveBeats = new List<float>();
foreach (var marker in EntityMarkers.Values)
{
if (marker.selected || marker.moving)
{
markersActiveBeats.Add((float)marker.entity.beat);
}
}
for (var i = 0; i < GameManager.instance.Beatmap.Entities.Count; i++)
{
var entity = GameManager.instance.Beatmap.Entities[i];
var vLeft = entity.beat + entity.length >= timeLeft;
var vRight = entity.beat < timeRight;
var active = vLeft && vRight;
var containsMarker = EntityMarkers.ContainsKey(entity.uid);

View file

@ -96,7 +96,7 @@ namespace HeavenStudio.Editor.Track
}
}
rectTransform.anchoredPosition = new Vector2((float)entity.beat * Timeline.instance.PixelsPerBeat, -entity["track"] * 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;
@ -110,7 +110,9 @@ namespace HeavenStudio.Editor.Track
public void UpdateMarker()
{
mouseHovering = Timeline.instance.timelineState.selected && Timeline.instance.MousePos2Beat.IsWithin((float)entity.beat, (float)entity.beat + entity.length);
mouseHovering = Timeline.instance.timelineState.selected &&
Timeline.instance.MousePos2Beat.IsWithin((float)entity.beat, (float)entity.beat + entity.length) &&
Timeline.instance.MousePos2Layer == (int)entity["track"];
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);
@ -277,7 +279,7 @@ namespace HeavenStudio.Editor.Track
}
rectTransform.sizeDelta = new Vector2(rectTransform.sizeDelta.x, Timeline.instance.LayerHeight());
rectTransform.anchoredPosition = new Vector2((float)entity.beat * Timeline.instance.PixelsPerBeat, -entity["track"] * Timeline.instance.LayerHeight());
rectTransform.anchoredPosition = new Vector2((float)entity.beat * Timeline.instance.PixelsPerBeat, -(int)entity["track"] * Timeline.instance.LayerHeight());
}
public void BeginMoving(bool setMovedEntity = true)

File diff suppressed because one or more lines are too long