You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

207 lines
7.2 KiB
C#

namespace Fusion.Statistics {
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
/// <summary>
/// The side to attach the statistics panel anchor.
/// </summary>
public enum CanvasAnchor {TopLeft, TopRight}
public class FusionStatsCanvas : MonoBehaviour, IDragHandler, IEndDragHandler, IBeginDragHandler {
[Header("General References")]
[SerializeField] private Canvas _canvas;
[SerializeField] private CanvasScaler _canvasScaler;
[SerializeField] private RectTransform _canvasPanel;
[Space] [Header("Panel References")]
[SerializeField] private RectTransform _contentPanel;
[SerializeField] private RectTransform _contentContainer;
[SerializeField] private RectTransform _bottomPanel;
[SerializeField] private FusionStatsPanelHeader _header;
[Space] [Header("Misc")]
[SerializeField] private Button _hideButton;
[SerializeField] private Button _closeButton;
[Space] [Header("World Anchor Panel Settings")]
[SerializeField] private FusionStatsConfig _config;
private bool _isColapsed => !_contentPanel.gameObject.activeSelf;
private CanvasAnchor _anchor;
private enum DragMode {None, DragCanvas, ResizeContent}
private DragMode _dragMode;
private static int _statsCanvasActiveCount = 0;
internal void SetupStatsCanvas(FusionStatistics fusionStatistics, CanvasAnchor canvasAnchor, UnityAction closeButtonAction) {
_anchor = canvasAnchor;
_canvasPanel.anchoredPosition = GetDefinedAnchorPosition();
var maxOffsetMultiplier = Mathf.Min(_statsCanvasActiveCount, 3);
_canvasPanel.anchoredPosition += Vector2.down * (FusionStatisticsHelper.DEFAULT_HEADER_HEIGHT * maxOffsetMultiplier);
//Setup buttons
_closeButton.onClick.RemoveAllListeners();
_closeButton.onClick.AddListener(closeButtonAction);
_hideButton.onClick.RemoveAllListeners();
_hideButton.onClick.AddListener(ToggleHide);
// Setup runner statistics ref
_config.SetupStatisticReference(fusionStatistics);
}
public void OnBeginDrag(PointerEventData eventData) {
if (_config.IsWorldAnchored) return;
if (_dragMode != DragMode.None) return; // Already dragging.
var dragBeginPos = eventData.pressPosition;
var rectT = _bottomPanel;
dragBeginPos = rectT.InverseTransformPoint(dragBeginPos);
var resize = rectT.rect.Contains(dragBeginPos) && eventData.button == PointerEventData.InputButton.Right;
_dragMode = resize ? DragMode.ResizeContent : DragMode.DragCanvas;
}
public void OnDrag(PointerEventData eventData) {
if (_config.IsWorldAnchored) return;
switch (_dragMode) {
case DragMode.DragCanvas:
_canvasPanel.anchoredPosition += eventData.delta / _canvas.scaleFactor;
break;
case DragMode.ResizeContent:
UpdateContentContainerHeight(eventData.delta.y / _canvas.scaleFactor);
break;
}
}
public void OnEndDrag(PointerEventData eventData) {
if (_config.IsWorldAnchored) return;
if (CheckDraggableRectVisibility(_canvasPanel) == false)
SnapPanelBackToOriginPos();
if (_dragMode == DragMode.ResizeContent) {
var currentSize = _contentPanel.sizeDelta.y;
var visibleGraphHeight = 0f;
var remaining = 0f;
for (int i = 0; i < _contentContainer.childCount; i++) {
var prevHeight = visibleGraphHeight;
visibleGraphHeight += ((RectTransform)_contentContainer.GetChild(i)).sizeDelta.y + 10;
if (visibleGraphHeight >= currentSize) {
if (currentSize - prevHeight < visibleGraphHeight - currentSize) {
remaining = currentSize - prevHeight;
} else {
remaining = -(visibleGraphHeight - currentSize);
}
break;
}
}
UpdateContentContainerHeight(remaining);
}
_dragMode = DragMode.None;
}
public void SnapPanelBackToOriginPos() {
_canvasPanel.anchoredPosition = GetDefinedAnchorPosition();
}
private void UpdateContentContainerHeight(float yDelta) {
var height = _contentPanel.sizeDelta.y;
var targetHeight = height - yDelta;
SetContentPanelHeight(targetHeight);
}
internal void ToggleHide() {
var active = _contentPanel.gameObject.activeSelf;
_hideButton.transform.rotation = active ? Quaternion.Euler(0, 0, 90) : Quaternion.identity;
_contentPanel.gameObject.SetActive(!active);
_bottomPanel.gameObject.SetActive(!active);
}
// Better offscreen check for later.
private bool CheckDraggableRectVisibility(RectTransform rectTransform) {
var anchoredPos = rectTransform.anchoredPosition;
var size = rectTransform.rect.size;
if (Mathf.Abs(anchoredPos.x) >= _canvasScaler.referenceResolution.x * .5f + size.x * .5f)
return false;
// anchor is on top.
if (anchoredPos.y >= _canvasScaler.referenceResolution.y * .5f + size.y || anchoredPos.y <= -_canvasScaler.referenceResolution.y * .5f)
return false;
return true;
}
private void SetContentPanelHeight(float value) {
if (value < FusionStatisticsHelper.DEFAULT_GRAPH_HEIGHT) {
value = FusionStatisticsHelper.DEFAULT_GRAPH_HEIGHT;
}else {
var maxHeight = Screen.height / _canvas.scaleFactor - 2 * FusionStatisticsHelper.DEFAULT_HEADER_HEIGHT;
if (value > maxHeight) {
value = maxHeight;
}
}
_contentPanel.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, value);
_contentPanel.gameObject.SetActive(false);
_contentPanel.gameObject.SetActive(true);
}
private void AdaptContentHeightToGraphs() {
var neededHeight = 0f;
for (int i = 0; i < _contentContainer.childCount; i++) {
neededHeight += ((RectTransform)_contentContainer.GetChild(i)).sizeDelta.y + 10; // +10 spacing
}
float maxHeight = Screen.height / _canvas.scaleFactor - 2 * FusionStatisticsHelper.DEFAULT_HEADER_HEIGHT;
if (neededHeight > maxHeight) {
neededHeight = maxHeight;
}
if (neededHeight < FusionStatisticsHelper.DEFAULT_GRAPH_HEIGHT) {
neededHeight = FusionStatisticsHelper.DEFAULT_GRAPH_HEIGHT;
}
SetContentPanelHeight(neededHeight);
}
private void OnEnable() {
_statsCanvasActiveCount++;
_header.OnRenderStatsUpdate += AdaptContentHeightToGraphs;
}
private void OnDisable() {
_statsCanvasActiveCount--;
_header.OnRenderStatsUpdate -= AdaptContentHeightToGraphs;
}
public void SetCanvasAnchor(CanvasAnchor anchor) {
_anchor = anchor;
SnapPanelBackToOriginPos();
}
private Vector2 GetDefinedAnchorPosition() {
var refRes = _canvasScaler.referenceResolution;
switch (_anchor) {
case CanvasAnchor.TopRight:
return refRes * .5f - Vector2.right * (_canvasPanel.sizeDelta.x * .5f);
case CanvasAnchor.TopLeft:
refRes.x *= -1;
return refRes * .5f + Vector2.right * (_canvasPanel.sizeDelta.x * .5f);
default:
return Vector2.zero;
}
}
}
}