322 lines
9.2 KiB
C#
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
|
|
}
|
|
}
|