Files
HDRobotics/Assets/Scripts/View/ProgramInfoView.cs
2025-12-03 21:19:07 +09:00

189 lines
6.1 KiB
C#

using System;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;
/// <summary>
/// VR 환경에서 로봇 프로그램의 상세 정보(스텝 리스트, 속도 등)를 표시하고 제어하는 뷰(View) 클래스
/// 프로그램 실행/정지, 리셋, 속도 조절 등의 사용자 입력을 받아 ProgramPresenter로 전달
/// </summary>
public class ProgramInfoView : MonoBehaviour
{
// --- 프로그램 정보 패널 ---
/// <summary>
/// 정보 패널이 활성화될 때 부착될 VR 컨트롤러(왼손)의 Transform
/// </summary>
[SerializeField] private Transform leftControllerTransform;
[SerializeField] private GameObject infoPanel; // 실제 켜고 끌 정보 패널의 최상위 게임 오브젝트
public InputActionReference showInfoPanel; // 패널을 토글(켜기/끄기)하는 입력 액션
public InputActionReference hideInfoPanel; // 패널을 강제로 숨기는 입력 액션
public InputActionReference[] playProgram; // 프로그램을 재생/정지하는 입력 액션 (예: A 또는 B버튼)
// 토글 상태 관리를 위한 플래그 변수들
private bool isPressingX = false;
private bool isPressingAorB = false;
[SerializeField] public TextMeshProUGUI jobName; // 작업 이름
[SerializeField] public TextMeshProUGUI jobSpeed; // 재생 속도
[SerializeField] private GameObject orderPrefab; // step의 UI 프리팹
[SerializeField] private GameObject endPrefab; // end의 UI 프리팹
[SerializeField] private Transform contentParent; // 스텝 UI 아이템들이 생성될 부모 Transform (Scroll View의 Content)
// 속도 관련 버튼
[SerializeField] private Button resetBtn;
[SerializeField] private Button startBtn;
[SerializeField] private Button stopBtn;
[SerializeField] private Button minusBtn;
[SerializeField] private Button plusBtn;
// 생성된 스텝 UI 아이템들을 관리하기 위한 리스트
private List<StepInfoItem> instantiatedStepItems = new List<StepInfoItem>();
// --- 이벤트 정의 (ProgramPresenter로 신호 전달) ---
public event Action OnResetClicked;
public event Action OnStartClicked;
public event Action OnStopClicked;
public event Action<int> OnMinusClicked;
public event Action<int> OnPlusClicked;
void Start()
{
infoPanel.SetActive(false);
// 입력 액션 이벤트 연결 (패널 표시/숨김)
if (showInfoPanel != null)
{
showInfoPanel.action.Enable();
showInfoPanel.action.performed += ShowProgramInfoPanel;
}
if (hideInfoPanel != null)
{
hideInfoPanel.action.Enable();
hideInfoPanel.action.performed += HideProgramInfoPanel;
}
// 입력 액션 이벤트 연결 (A/B 버튼)
if (playProgram != null)
{
for (int i = 0; i < playProgram.Length; i++)
{
playProgram[i].action.Enable();
playProgram[i].action.performed += PlayProgram;
}
}
resetBtn.onClick.AddListener(() => OnResetClicked?.Invoke());
startBtn.onClick.AddListener(() => OnStartClicked?.Invoke());
stopBtn.onClick.AddListener(() => OnStopClicked?.Invoke());
minusBtn.onClick.AddListener(() => OnMinusClicked?.Invoke(-1));
plusBtn.onClick.AddListener(() => OnPlusClicked?.Invoke(1));
}
private void OnDestroy()
{
if (showInfoPanel != null)
{
showInfoPanel.action.performed -= ShowProgramInfoPanel;
}
if (hideInfoPanel != null)
{
hideInfoPanel.action.performed -= HideProgramInfoPanel;
}
if (playProgram != null)
{
for (int i = 0; i < playProgram.Length; i++)
{
playProgram[i].action.performed -= PlayProgram;
}
}
}
/// <summary>
/// Presenter로부터 데이터를 받아 UI 리스트를 갱신
/// 기존 목록을 모두 지우고, 새로운 스텝 데이터로 다시 채움
/// </summary>
/// <param name="program">로봇 프로그램 정보 (없으면 리턴)</param>
/// <param name="steps">파싱된 개별 스텝 리스트</param>
public void UpdateProgramInfo(RobotProgram program, List<RobotMoveStep> steps)
{
if (program == null) return;
// 기존 리스트 초기화 (UI 오브젝트 삭제)
foreach (Transform child in contentParent)
{
Destroy(child.gameObject);
}
instantiatedStepItems.Clear();
// 새 스텝 목록 생성
if (steps == null) return;
foreach (RobotMoveStep step in steps)
{
GameObject newPrefab = Instantiate(orderPrefab, contentParent);
StepInfoItem stepItemUI = newPrefab.GetComponent<StepInfoItem>();
if (stepItemUI != null)
{
stepItemUI.SetData(step);
instantiatedStepItems.Add(stepItemUI);
}
else
{
Debug.LogError("orderPrefab에 StepInfoItem.cs 스크립트가 없습니다");
}
if (jobSpeed.text == "0%")
jobSpeed.text = $"{step.Speed}%";
}
// 마지막에 END 추가
Instantiate(endPrefab, contentParent);
}
/// <summary>
/// 컨트롤러 입력(X버튼)으로 정보 패널을 켜거나 끔 (토글 방식)
/// </summary>
private void ShowProgramInfoPanel(InputAction.CallbackContext obj)
{
isPressingX = !isPressingX;
if (isPressingX)
{
infoPanel.transform.SetParent(leftControllerTransform);
infoPanel.transform.localPosition = new Vector3(0f, 0.2f, 0f);
infoPanel.transform.localRotation = Quaternion.Euler(0, 180, 0);
infoPanel.SetActive(true);
}
else
{
infoPanel.SetActive(false);
}
}
/// <summary>
/// 컨트롤러 입력으로 정보 패널을 숨김
/// </summary>
private void HideProgramInfoPanel(InputAction.CallbackContext obj)
{
infoPanel.SetActive(false);
}
/// <summary>
/// 컨트롤러 입력(A/B버튼)으로 프로그램을 재생하거나 정지 (토글 방식)
/// </summary>
private void PlayProgram(InputAction.CallbackContext obj)
{
isPressingAorB = !isPressingAorB;
if (isPressingAorB)
{
OnStartClicked?.Invoke();
}
else
{
OnStopClicked?.Invoke();
}
}
}