using System; namespace UVC.UI.Toolbar.Model { /// /// 라디오 버튼 그룹 내에서 사용되는 버튼입니다. 동일한 GroupName을 가진 라디오 버튼들 중에서 /// 단 하나만 선택될 수 있도록 동작합니다. ToolbarToggleButton을 상속받습니다. /// /// /// 각 ToolbarRadioButton은 GroupName을 가지며, 이 GroupName을 기준으로 ToolbarModel에서 /// ToolbarRadioButtonGroup에 의해 관리됩니다. 사용자가 라디오 버튼을 클릭하면, /// 이 버튼은 자신이 속한 RadioGroup에 선택 상태 변경을 요청하고, RadioGroup은 /// 그룹 내 다른 버튼들의 선택을 해제하고 이 버튼만 선택된 상태로 만듭니다. /// IsSelected 상태 변경 시 OnToggle, OnStateChanged, OnToggleStateChanged 이벤트가 발생합니다. /// /// /// /// // Toolbar 또는 ToolbarModel 등에서 ToolbarRadioButton 생성 및 사용 예시 /// /// string cameraViewGroupName = "CameraViewOptions"; /// /// // 1. 라디오 버튼1: 탑뷰 /// ToolbarRadioButton topViewRadio = new ToolbarRadioButton(cameraViewGroupName) /// { /// Text = "view_top", /// IconSpritePath = "icons/toolbar/view_top_on", /// OffIconSpritePath = "icons/toolbar/view_top_off", /// Tooltip = "tooltip_top_view", /// IsSelected = true, // 초기 선택 상태 /// OnToggle = (IsSelected) => /// { /// if (IsSelected) UnityEngine.Debug.Log("탑뷰 선택됨 (OnToggle)"); /// }, /// ClickCommand = new ActionCommand(() => /// { /// UnityEngine.Debug.Log("탑뷰 커맨드 실행"); /// // 실제 탑뷰로 변경하는 로직 /// }) /// }; /// /// // 2. 라디오 버튼2: 프론트뷰 /// ToolbarRadioButton frontViewRadio = new ToolbarRadioButton(cameraViewGroupName) /// { /// Text = "view_front", /// IconSpritePath = "icons/toolbar/view_front_on", /// OffIconSpritePath = "icons/toolbar/view_front_off", /// Tooltip = "tooltip_front_view", /// IsSelected = false, // 초기 선택 안됨 /// OnToggle = (IsSelected) => /// { /// if (IsSelected) UnityEngine.Debug.Log("프론트뷰 선택됨 (OnToggle)"); /// }, /// ClickCommand = new ActionCommand(() => /// { /// UnityEngine.Debug.Log("프론트뷰 커맨드 실행"); /// // 실제 프론트뷰로 변경하는 로직 /// }) /// }; /// /// // 3. 생성된 라디오 버튼들을 ToolbarModel에 추가 /// // toolbarModel.AddItem(topViewRadio); /// // toolbarModel.AddItem(frontViewRadio); /// // 또는 ToolbarModel의 AddRadioButton 헬퍼 메서드 사용 /// // toolbarModel.AddRadioButton(cameraViewGroupName, "view_top", true, "icons/toolbar/view_top_on", ...); /// // toolbarModel.AddRadioButton(cameraViewGroupName, "view_front", false, "icons/toolbar/view_front_on", ...); /// /// // ToolbarModel은 AddItem 시 GroupName을 보고 내부적으로 ToolbarRadioButtonGroup을 생성/관리하며 /// // 각 라디오 버튼을 해당 그룹에 등록합니다. /// /// public class ToolbarRadioButton : ToolbarToggleButton { /// /// 이 라디오 버튼이 속한 그룹의 이름입니다. /// 동일한 GroupName을 가진 라디오 버튼들은 하나의 그룹으로 묶여 동작합니다. /// public string GroupName { get; private set; } /// /// 이 라디오 버튼을 관리하는 ToolbarRadioButtonGroup의 내부 참조입니다. /// ToolbarModel에 의해 설정되며, 버튼이 그룹에 등록될 때 할당됩니다. /// internal ToolbarRadioButtonGroup RadioGroup { get; set; } /// /// 지정된 그룹 이름을 사용하여 ToolbarRadioButton의 새 인스턴스를 초기화합니다. /// /// 이 라디오 버튼이 속할 그룹의 이름입니다. null이거나 비어있을 수 없습니다. /// groupName이 null이거나 빈 문자열일 경우 발생합니다. public ToolbarRadioButton(string groupName) { if (string.IsNullOrEmpty(groupName)) { throw new ArgumentNullException(nameof(groupName), "라디오 버튼은 반드시 GroupName을 가져야 합니다."); } GroupName = groupName; } /// /// 라디오 버튼 클릭 로직을 실행합니다. /// 버튼이 활성화되어 있다면, 자신이 속한 RadioGroup에 자신을 선택하도록 요청합니다. /// RadioGroup은 이 요청을 받아 그룹 내 다른 버튼들의 선택을 해제하고 이 버튼만 선택 상태로 만듭니다. /// 그 후, 이 버튼의 ClickCommand가 실행됩니다 (선택된 상태에서만). /// /// /// 이 파라미터는 ClickCommand에 전달될 수 있습니다. /// ToolbarView에서 UI 이벤트 연결 시, 라디오 버튼의 경우 보통 선택 상태(true)를 전달하거나, /// 버튼 모델 자체를 전달하여 Command가 필요한 정보를 추출하도록 할 수 있습니다. /// 기본적으로는 현재 IsSelected 상태가 ClickCommand에 전달되도록 고려할 수 있습니다. /// public override void ExecuteClick(object parameter = null) { if (!IsEnabled) return; // bool previousSelectionState = IsSelected; // 이전 선택 상태 (필요하다면) if (RadioGroup != null) { // RadioGroup의 SetSelected 메서드를 호출하여 그룹 내 선택 상태를 관리합니다. // SetSelected 내부에서 이 버튼의 IsSelected가 true로 설정되고, // 다른 버튼들은 false로 설정됩니다. // IsSelected setter는 OnToggle, OnStateChanged, OnToggleStateChanged 이벤트를 발생시킵니다. RadioGroup.SetSelected(this); } else { // RadioGroup이 할당되지 않은 경우 (예: ToolbarModel에 추가되기 전 또는 독립적으로 사용 시도) // 이 경우 일반 토글 버튼처럼 동작하거나, 경고를 로깅할 수 있습니다. // 현재 구현은 그룹이 없으면 단독으로 선택되는 것을 방지하거나 특별 처리를 하도록 되어 있습니다. UnityEngine.Debug.LogWarning($"ToolbarRadioButton '{Text}' (그룹: {GroupName})에 RadioGroup이 할당되지 않았습니다. 단독으로 상태가 변경될 수 없습니다. ToolbarModel에 먼저 추가되어야 합니다."); // 만약 그룹 없이도 토글 가능하게 하려면 아래 주석 해제 및 로직 수정 필요 // IsSelected = !IsSelected; } // ClickCommand 실행: // 라디오 버튼의 ClickCommand는 일반적으로 해당 버튼이 "선택되었을 때"의 액션을 정의합니다. // RadioGroup.SetSelected에 의해 IsSelected 상태가 true로 변경된 후에 실행되어야 합니다. if (IsSelected && ClickCommand != null) { // 파라미터 처리: parameter가 null이 아니면 그것을 우선 사용하고, // 아니면 현재 IsSelected 상태(true) 또는 버튼 자체(this)를 전달할 수 있습니다. // ToolbarView의 SetupButtonVisualsAndInteractions에서 radioModel.ExecuteClick(true)로 호출하는 경우, // parameter는 true가 됩니다. object commandParameterToUse = parameter ?? this; // 예: 명시적 파라미터가 없으면 버튼 인스턴스 전달 ClickCommand.Execute(commandParameterToUse); } // 만약 선택 해제 시(다른 라디오 버튼이 선택되어 이 버튼이 해제될 때)에도 Command를 실행해야 한다면, // 위 if(IsSelected) 조건을 제거하거나, 별도의 Command(예: DeselectCommand)를 고려해야 합니다. // 하지만 일반적인 라디오 버튼의 사용 패턴은 선택 시의 액션에 중점을 둡니다. } /// /// 이 버튼 모델에 연결된 모든 이벤트 핸들러를 정리합니다. /// ToolbarRadioButton은 ToolbarToggleButton에서 상속받은 이벤트 외에 추가적인 이벤트가 없으므로, /// 부모 클래스의 ClearEventHandlers를 호출합니다. /// public override void ClearEventHandlers() { base.ClearEventHandlers(); // 부모 클래스(ToolbarToggleButton)의 이벤트 정리 // ToolbarRadioButton에 특화된 이벤트가 있다면 여기서 정리합니다. } } }