Files
EnglewoodLAB/Assets/Scripts/UVC/UIToolkit/Menu/UTKTopMenuImageItem.cs

322 lines
9.2 KiB
C#

#nullable enable
using UnityEngine;
using UnityEngine.UIElements;
namespace UVC.UIToolkit
{
/// <summary>
/// UIToolkit 기반 이미지 메뉴 아이템 UI 컴포넌트입니다 (Image 또는 Material Icon 기반).
/// 메뉴 아이템의 시각적 표현과 클릭 이벤트를 처리합니다.
/// </summary>
/// <example>
/// <code>
/// // 이미지 메뉴 아이템 생성
/// var menuItem = new UTKTopMenuImageItem();
/// menuItem.SetData(imageItemData);
///
/// // 클릭 이벤트 구독
/// menuItem.OnClicked += (data) => Debug.Log($"Clicked: {data.ItemId}");
///
/// // 사용 후 정리
/// menuItem.Dispose();
/// </code>
/// </example>
[UxmlElement]
public partial class UTKTopMenuImageItem : UTKMenuItemBase
{
#region Constants
private const string UXML_PATH = "UIToolkit/Menu/UTKMenuImageItem";
private const string USS_PATH = "UIToolkit/Menu/UTKMenuImageItemUss";
private const string MATERIAL_ICONS_FONT_PATH = "Fonts/MaterialIcons-Regular";
#endregion
#region Fields
private UTKLabel? _iconLabel; // Material Icon용
private Image? _image; // 일반 이미지용
private bool _useMaterialIcon;
#endregion
#region Constructor
/// <summary>
/// UTKTopMenuImageItem의 새 인스턴스를 초기화합니다.
/// </summary>
public UTKTopMenuImageItem() : base()
{
_ussPath = USS_PATH;
}
#endregion
#region Setup
/// <summary>
/// UI를 생성합니다.
/// </summary>
protected override void CreateUI()
{
AddToClassList("utk-menu-item");
AddToClassList("utk-menu-item--image");
var asset = Resources.Load<VisualTreeAsset>(UXML_PATH);
if (asset != null)
{
CreateUIFromUxml(asset);
}
else
{
CreateUIFallback();
}
}
/// <summary>
/// UXML에서 UI를 생성합니다.
/// </summary>
/// <param name="asset">UXML 에셋</param>
private void CreateUIFromUxml(VisualTreeAsset asset)
{
var root = asset.Instantiate();
// USS를 root에 추가
var uss = Resources.Load<StyleSheet>(USS_PATH);
if (uss != null)
{
root.styleSheets.Add(uss);
}
// UI 요소 참조 가져오기 (쿼리 캐싱)
_button = root.Q<Button>("menu-button");
_iconLabel = root.Q<UTKLabel>("icon-label");
_arrow = root.Q<VisualElement>("arrow");
_image = root.Q<Image>("icon-image");
if(_button == null)
{
_button = new Button();
_button.name = "menu-button";
_button.AddToClassList("menu-item");
}
if(_iconLabel == null)
{
_iconLabel = new UTKLabel();
_iconLabel.name = "icon-label";
_iconLabel.AddToClassList("menu-item__icon");
_iconLabel.style.display = DisplayStyle.None;
_button.Add(_iconLabel);
}
if(_image == null)
{
_image = new Image();
_image.name = "icon-image";
_image.AddToClassList("menu-item__image");
_image.style.display = DisplayStyle.None;
_button.Add(_image);
}
if(_arrow == null)
{
_arrow = new VisualElement();
_arrow.name = "arrow";
_arrow.AddToClassList("menu-item__arrow");
_arrow.style.display = DisplayStyle.None;
_button.Add(_arrow);
}
Add(root);
// 버튼 클릭 이벤트 등록
if (_button != null)
{
_onClickCallback = OnButtonClicked;
_button.RegisterCallback(_onClickCallback);
}
}
/// <summary>
/// UI를 생성합니다 (이미지 버전).
/// </summary>
private void CreateUIFallback()
{
_button = new Button();
_button.name = "menu-button";
_button.AddToClassList("menu-item");
// Material Icon용 Label (기본값)
_iconLabel = new UTKLabel();
_iconLabel.name = "icon-label";
_iconLabel.AddToClassList("menu-item__icon");
_iconLabel.style.display = DisplayStyle.None;
// 일반 이미지용 Image
_image = new Image();
_image.name = "icon-image";
_image.AddToClassList("menu-item__image");
_image.style.display = DisplayStyle.None;
_arrow = new VisualElement();
_arrow.name = "arrow";
_arrow.AddToClassList("menu-item__arrow");
_arrow.style.display = DisplayStyle.None;
_button.Add(_iconLabel);
_button.Add(_image);
_button.Add(_arrow);
Add(_button);
_onClickCallback = OnButtonClicked;
_button.RegisterCallback(_onClickCallback);
}
#endregion
#region Public Methods
/// <summary>
/// 메뉴 아이템 데이터를 설정합니다.
/// </summary>
/// <param name="data">메뉴 아이템 데이터</param>
public override void SetData(UTKMenuItemData data)
{
base.SetData(data);
// UTKMenuImageItemData인 경우 추가 설정
if (data is UTKMenuImageItemData imageData)
{
_useMaterialIcon = imageData.UseMaterialIcon;
if (_useMaterialIcon)
{
SetupMaterialIcon(imageData);
}
else
{
SetupImage(imageData);
}
}
}
#endregion
#region Protected Methods
/// <summary>
/// UI를 업데이트합니다.
/// </summary>
protected override void UpdateUI()
{
// 이미지는 SetData에서 설정되므로 여기서는 추가 작업 없음
UpdateOpacity();
}
/// <summary>
/// 활성화 상태에 따라 투명도를 업데이트합니다.
/// </summary>
protected override void UpdateOpacity()
{
float opacity = IsEnabled ? 1f : 0.5f;
if (_iconLabel != null)
{
_iconLabel.style.opacity = opacity;
}
if (_image != null)
{
_image.style.opacity = opacity;
}
}
#endregion
#region Private Methods
/// <summary>
/// Material Icon을 설정합니다.
/// </summary>
private void SetupMaterialIcon(UTKMenuImageItemData imageData)
{
if (_iconLabel == null) return;
// Material Icons 폰트 로드
var font = Resources.Load<Font>(MATERIAL_ICONS_FONT_PATH);
if (font != null)
{
_iconLabel.style.unityFont = new StyleFont(font);
}
// Unicode 문자 설정
_iconLabel.SetMaterialIcon(imageData.ImagePath);
_iconLabel.style.fontSize = imageData.ImageSize;
if (imageData.ImageColor.HasValue)
{
_iconLabel.style.color = imageData.ImageColor.Value;
}
// Material Icon 표시, Image 숨김
_iconLabel.style.display = DisplayStyle.Flex;
if (_image != null)
{
_image.style.display = DisplayStyle.None;
}
}
/// <summary>
/// 일반 이미지를 설정합니다.
/// </summary>
private void SetupImage(UTKMenuImageItemData imageData)
{
if (_image == null) return;
// 이미지 리소스 로드
var texture = Resources.Load<Texture2D>(imageData.ImagePath);
if (texture != null)
{
_image.image = texture;
_image.style.width = imageData.ImageSize;
_image.style.height = imageData.ImageSize;
if (imageData.ImageColor.HasValue)
{
_image.tintColor = imageData.ImageColor.Value;
}
// Image 표시, Material Icon 숨김
_image.style.display = DisplayStyle.Flex;
if (_iconLabel != null)
{
_iconLabel.style.display = DisplayStyle.None;
}
}
else
{
Debug.LogWarning($"이미지를 로드할 수 없습니다: {imageData.ImagePath}");
}
}
#endregion
#region IDisposable
/// <summary>
/// 리소스를 정리합니다.
/// </summary>
public override void Dispose()
{
base.Dispose();
_iconLabel = null;
_image = null;
}
#endregion
}
}