diff --git a/.DS_Store b/.DS_Store index bb0422a..d656975 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/Assets/.DS_Store b/Assets/.DS_Store index 5c754dd..8c0781f 100644 Binary files a/Assets/.DS_Store and b/Assets/.DS_Store differ diff --git a/Assets/ControlPanel.cs b/Assets/ControlPanel.cs new file mode 100644 index 0000000..fc528db --- /dev/null +++ b/Assets/ControlPanel.cs @@ -0,0 +1,419 @@ +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +public class ControlPanel : MonoBehaviour +{ + [Header("Core UI (assign in Inspector)")] + public TMP_InputField inputField; + public TMP_Dropdown directionDropdown; + public Button button; // existing Send/Rotate button in hierarchy + + private enum Mode { None, DC, Display, Speaker } + private Mode _mode = Mode.None; + + private DCMotorModule _dc; + private DisplayModule _display; + private SpeakerModule _speaker; + + private string _savedDCInput = ""; + private int _savedDirectionIndex = 0; + private string _savedDisplayInput = ""; + + // Found automatically (no hierarchy edits) + private TextMeshProUGUI _caption; // child "DegreesCaption" + private TextMeshProUGUI _buttonText; // child "RotateButton/Text (TMP)" + private GameObject _directionCaptionGO; + private GameObject _directionDropdownGO; + + // Created in code (Speaker mode only) + private Button _uploadButton; + private TextMeshProUGUI _uploadButtonText; + private Button _playButton; + private TextMeshProUGUI _playButtonText; + + private void Awake() + { + CacheUIFromHierarchy(); + + // Create these once; hide unless Speaker mode + CreateUploadButtonIfNeeded(); + CreatePlayButtonIfNeeded(); + + if (button != null) + { + button.onClick.RemoveAllListeners(); + button.onClick.AddListener(OnMainButtonClicked); + } + + if (inputField != null) + { + inputField.onValueChanged.AddListener(_ => CacheCurrentInput()); + inputField.onEndEdit.AddListener(_ => CacheCurrentInput()); + } + + if (directionDropdown != null) + { + directionDropdown.onValueChanged.AddListener(v => + { + if (_mode == Mode.DC) _savedDirectionIndex = v; + }); + } + } + + public void Initialize(ModuleBase module) + { + CacheCurrentInput(); + + _dc = module as DCMotorModule; + _display = module as DisplayModule; + _speaker = module as SpeakerModule; + + if (_dc != null) { SwitchMode(Mode.DC); gameObject.SetActive(true); return; } + if (_display != null) { SwitchMode(Mode.Display); gameObject.SetActive(true); return; } + if (_speaker != null) { SwitchMode(Mode.Speaker); gameObject.SetActive(true); return; } + + HidePanel(); + } + + public void HidePanel() + { + CacheCurrentInput(); + gameObject.SetActive(false); + _mode = Mode.None; + _dc = null; + _display = null; + _speaker = null; + SetUploadVisible(false); + SetPlayVisible(false); + } + + private void CacheUIFromHierarchy() + { + var captionT = transform.Find("DegreesCaption"); + if (captionT != null) _caption = captionT.GetComponent(); + + var buttonTextT = transform.Find("RotateButton/Text (TMP)"); + if (buttonTextT != null) _buttonText = buttonTextT.GetComponent(); + + var dirCaptionT = transform.Find("DirectionCaption"); + if (dirCaptionT != null) _directionCaptionGO = dirCaptionT.gameObject; + + var dirDropdownT = transform.Find("DirectionDropdown"); + if (dirDropdownT != null) _directionDropdownGO = dirDropdownT.gameObject; + } + + private void SwitchMode(Mode newMode) + { + CacheCurrentInput(); + _mode = newMode; + + if (_mode == Mode.DC) + { + SetCaption("Degrees"); + SetCaptionVisible(true); + SetMainButtonText("Rotate"); + SetDirectionVisible(true); + SetInputVisible(true); + SetUploadVisible(false); + SetPlayVisible(false); + + if (inputField != null) + { + inputField.readOnly = false; + inputField.SetTextWithoutNotify(_savedDCInput); + } + + if (directionDropdown != null) + directionDropdown.SetValueWithoutNotify(_savedDirectionIndex); + } + else if (_mode == Mode.Display) + { + SetCaption("Text"); + SetCaptionVisible(true); + SetMainButtonText("Send"); + SetDirectionVisible(false); + SetInputVisible(true); + SetUploadVisible(false); + SetPlayVisible(false); + + if (inputField != null) + { + inputField.readOnly = false; + string toShow = _savedDisplayInput; + if (_display != null && !string.IsNullOrEmpty(_display.displayText)) + toShow = _display.displayText; + inputField.SetTextWithoutNotify(toShow); + } + } + else if (_mode == Mode.Speaker) + { + // Speaker UI: no input field (removes the white box behind buttons) + SetMainButtonText("Send Audio"); + SetCaptionVisible(false); + SetDirectionVisible(false); + SetInputVisible(false); + + // Show speaker buttons + SetUploadVisible(true); + SetPlayVisible(true); + } + } + + private void SetCaption(string text) + { + if (_caption != null) _caption.text = text; + } + + private void SetMainButtonText(string text) + { + if (_buttonText != null) _buttonText.text = text; + } + + private void SetDirectionVisible(bool visible) + { + if (_directionCaptionGO != null) _directionCaptionGO.SetActive(visible); + if (_directionDropdownGO != null) _directionDropdownGO.SetActive(visible); + } + + private void SetInputVisible(bool visible) + { + if (inputField != null && inputField.gameObject.activeSelf != visible) + inputField.gameObject.SetActive(visible); + } + + private void CacheCurrentInput() + { + if (inputField == null) return; + + if (_mode == Mode.DC) + { + _savedDCInput = inputField.text; + if (directionDropdown != null) _savedDirectionIndex = directionDropdown.value; + } + else if (_mode == Mode.Display) + { + _savedDisplayInput = inputField.text; + } + } + + private void OnMainButtonClicked() + { + if (_mode == Mode.DC) + { + if (_dc == null) return; + + if (!float.TryParse(inputField.text, out float degrees)) + { + Debug.LogWarning("ControlPanel: Invalid degree input."); + return; + } + + int direction = (directionDropdown != null && directionDropdown.value == 0) ? 1 : -1; + _dc.Rotate(degrees, direction); + } + else if (_mode == Mode.Display) + { + if (_display == null) return; + _display.SetDisplayText(inputField != null ? inputField.text : ""); + } + else if (_mode == Mode.Speaker) + { + if (_speaker == null) return; + _speaker.SendAudioToHardware(); // Send Audio = upload to hardware (your implementation) + } + } + + // ------------------------- + // Styling helpers (copy Send button look) + // ------------------------- + + private void CopyButtonStyle(Button source, Button target) + { + if (source == null || target == null) return; + + // Button settings + target.transition = source.transition; + target.colors = source.colors; + target.spriteState = source.spriteState; + target.navigation = source.navigation; + target.interactable = source.interactable; + + // Image settings + var srcImg = source.GetComponent(); + var dstImg = target.GetComponent(); + if (srcImg != null && dstImg != null) + { + dstImg.sprite = srcImg.sprite; + dstImg.type = srcImg.type; + dstImg.pixelsPerUnitMultiplier = srcImg.pixelsPerUnitMultiplier; + dstImg.material = srcImg.material; + dstImg.color = srcImg.color; + dstImg.raycastTarget = srcImg.raycastTarget; + } + } + + private void CopyTMPStyle(TextMeshProUGUI source, TextMeshProUGUI target) + { + if (source == null || target == null) return; + + target.font = source.font; + target.fontSharedMaterial = source.fontSharedMaterial; + target.fontStyle = source.fontStyle; + target.fontSize = source.fontSize; + target.enableAutoSizing = source.enableAutoSizing; + target.color = source.color; + target.enableVertexGradient = source.enableVertexGradient; + target.alignment = source.alignment; + target.enableWordWrapping = source.enableWordWrapping; + target.richText = source.richText; + } + + // ------------------------- + // Upload button (code-created) + // ------------------------- + + private void CreateUploadButtonIfNeeded() + { + if (_uploadButton != null) return; + + var go = new GameObject("UploadButton"); + go.transform.SetParent(transform, false); + + var img = go.AddComponent(); + img.raycastTarget = true; + + _uploadButton = go.AddComponent