using TMPro; using UnityEngine; using UnityEngine.UI; namespace InteractiveVideo.Examples { /// /// Minimal transport for testing: play/pause button, scrub slider, frame label, highlight-mode cycling and a /// debug toggle. Not part of the core system. /// [AddComponentMenu("Interactive Video/Examples/Demo Controls")] public sealed class InteractiveVideoDemoControls : MonoBehaviour { [SerializeField] private InteractiveVideoPlayer player; [SerializeField] private VideoTrackingManager trackingManager; [SerializeField] private VideoHighlightController highlightController; [Header("UI")] [SerializeField] private Button playPauseButton; [SerializeField] private TMP_Text playPauseLabel; [SerializeField] private Slider scrubber; [SerializeField] private TMP_Text frameLabel; [SerializeField] private Button modeButton; [SerializeField] private TMP_Text modeLabel; [SerializeField] private Toggle debugToggle; private float _scrubHoldUntil = -1f; private long _lastFrame = long.MinValue; private void Awake() { if (player == null) player = FindAnyObjectByType(); if (player != null) { if (trackingManager == null) trackingManager = player.TrackingManager; if (highlightController == null) highlightController = player.HighlightController; } } private void OnEnable() { if (playPauseButton != null) playPauseButton.onClick.AddListener(OnPlayPause); if (modeButton != null) modeButton.onClick.AddListener(OnCycleMode); if (scrubber != null) scrubber.onValueChanged.AddListener(OnScrub); if (debugToggle != null) { debugToggle.SetIsOnWithoutNotify(trackingManager != null && trackingManager.ShowTrackingDebug); debugToggle.onValueChanged.AddListener(OnDebugToggled); } UpdateModeLabel(); } private void OnDisable() { if (playPauseButton != null) playPauseButton.onClick.RemoveListener(OnPlayPause); if (modeButton != null) modeButton.onClick.RemoveListener(OnCycleMode); if (scrubber != null) scrubber.onValueChanged.RemoveListener(OnScrub); if (debugToggle != null) debugToggle.onValueChanged.RemoveListener(OnDebugToggled); } private void Update() { if (player == null) return; if (playPauseLabel != null) { string want = player.IsPlaying ? "Pause" : "Play"; if (playPauseLabel.text != want) playPauseLabel.text = want; } long frame = player.CurrentFrame; if (frame == _lastFrame) return; _lastFrame = frame; if (frameLabel != null) frameLabel.text = player.IsPrepared ? $"{frame} / {player.FrameCount}" : "-"; // Seeks are asynchronous: keep the slider under the user's control for a moment so the old frame // does not yank it back before seekCompleted arrives. if (scrubber != null && Time.unscaledTime > _scrubHoldUntil && player.IsPrepared && player.FrameCount > 1) scrubber.SetValueWithoutNotify((float)frame / (player.FrameCount - 1)); } private void OnPlayPause() => player?.TogglePlayPause(); private void OnScrub(float value) { if (player == null || !player.IsPrepared) return; _scrubHoldUntil = Time.unscaledTime + 0.3f; player.SeekNormalized(value); } private void OnCycleMode() { if (highlightController == null) return; int next = ((int)highlightController.Mode + 1) % 5; highlightController.SetHighlightMode(next); UpdateModeLabel(); } private void UpdateModeLabel() { if (modeLabel != null && highlightController != null) modeLabel.text = highlightController.Mode.ToString(); } private void OnDebugToggled(bool on) { if (trackingManager != null) trackingManager.ShowTrackingDebug = on; } } }