2243 lines
89 KiB
C#
2243 lines
89 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using TMPro;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
#if UNITY_EDITOR
|
|
using UnityEditor;
|
|
#endif
|
|
|
|
public enum InventoryRootUIMode
|
|
{
|
|
TestMode,
|
|
PlayMode,
|
|
BuildMode,
|
|
HiddenMode,
|
|
LayoutOnly
|
|
}
|
|
|
|
public enum InventoryUIAnchorPreset
|
|
{
|
|
Custom,
|
|
MiddleCenter,
|
|
TopLeft,
|
|
TopCenter,
|
|
TopRight,
|
|
MiddleLeft,
|
|
MiddleRight,
|
|
BottomLeft,
|
|
BottomCenter,
|
|
BottomRight,
|
|
StretchAll
|
|
}
|
|
|
|
[Serializable]
|
|
public class InventoryControlledRectTarget
|
|
{
|
|
[Header("Target")]
|
|
public string name;
|
|
public RectTransform rectTransform;
|
|
public GameObject activeTarget;
|
|
|
|
[Header("Rect Layout")]
|
|
public bool applyRect = true;
|
|
public InventoryUIAnchorPreset anchorPreset = InventoryUIAnchorPreset.MiddleCenter;
|
|
public Vector2 customAnchorMin = new Vector2(0.5f, 0.5f);
|
|
public Vector2 customAnchorMax = new Vector2(0.5f, 0.5f);
|
|
public Vector2 customPivot = new Vector2(0.5f, 0.5f);
|
|
public Vector2 size = new Vector2(100f, 100f);
|
|
public Vector2 anchoredPosition = Vector2.zero;
|
|
|
|
[Header("Transform")]
|
|
public bool resetScaleToOne = true;
|
|
public bool applyLocalScale = false;
|
|
public Vector3 localScale = Vector3.one;
|
|
public bool applyLocalRotation = false;
|
|
public Vector3 localEulerAngles = Vector3.zero;
|
|
public bool applySiblingIndex = false;
|
|
public int siblingIndex = 0;
|
|
|
|
[Header("Active By Mode")]
|
|
public bool controlActiveState = false;
|
|
public bool activeInTestMode = true;
|
|
public bool activeInPlayMode = true;
|
|
public bool activeInBuildMode = true;
|
|
public bool activeInHiddenMode = false;
|
|
|
|
[Header("CanvasGroup")]
|
|
public bool applyCanvasGroup = false;
|
|
public bool addCanvasGroupIfMissing = true;
|
|
[Range(0f, 1f)] public float canvasAlpha = 1f;
|
|
public bool canvasInteractable = false;
|
|
public bool canvasBlocksRaycasts = false;
|
|
|
|
[Header("Raycast")]
|
|
public bool applySelfImageRaycast = false;
|
|
public bool selfImageRaycastTarget = false;
|
|
public bool applyChildImageRaycasts = false;
|
|
public bool childImageRaycastTarget = false;
|
|
public bool preserveButtonImageRaycasts = true;
|
|
public bool applyChildTextRaycasts = false;
|
|
public bool childTextRaycastTarget = false;
|
|
}
|
|
|
|
[Serializable]
|
|
public class InventoryControlledTextTarget
|
|
{
|
|
[Header("Target")]
|
|
public string name;
|
|
public TMP_Text text;
|
|
|
|
[Header("Rect Layout")]
|
|
public bool applyRect = false;
|
|
public InventoryUIAnchorPreset anchorPreset = InventoryUIAnchorPreset.MiddleCenter;
|
|
public Vector2 customAnchorMin = new Vector2(0.5f, 0.5f);
|
|
public Vector2 customAnchorMax = new Vector2(0.5f, 0.5f);
|
|
public Vector2 customPivot = new Vector2(0.5f, 0.5f);
|
|
public Vector2 size = new Vector2(100f, 30f);
|
|
public Vector2 anchoredPosition = Vector2.zero;
|
|
|
|
[Header("Text Settings")]
|
|
public bool applyFontSize = false;
|
|
public float fontSize = 20f;
|
|
public bool applyAlignment = false;
|
|
public TextAlignmentOptions alignment = TextAlignmentOptions.Center;
|
|
public bool applyColor = false;
|
|
public Color color = Color.white;
|
|
public bool applyRaycastTarget = true;
|
|
public bool raycastTarget = false;
|
|
public bool resetScaleToOne = true;
|
|
|
|
[Header("Outline / Shadow")]
|
|
public bool applyOutline = false;
|
|
public bool addOutlineIfMissing = true;
|
|
public Color outlineColor = new Color(0f, 0.75f, 1f, 0.8f);
|
|
public Vector2 outlineEffectDistance = new Vector2(1f, -1f);
|
|
public bool outlineUseGraphicAlpha = true;
|
|
public bool applyShadow = false;
|
|
public bool addShadowIfMissing = true;
|
|
public Color shadowColor = new Color(0f, 0f, 0f, 0.65f);
|
|
public Vector2 shadowEffectDistance = new Vector2(2f, -2f);
|
|
public bool shadowUseGraphicAlpha = true;
|
|
}
|
|
|
|
[Serializable]
|
|
public class InventoryControlledImageTarget
|
|
{
|
|
[Header("Target")]
|
|
public string name;
|
|
public Image image;
|
|
|
|
[Header("Rect Layout")]
|
|
public bool applyRect = false;
|
|
public InventoryUIAnchorPreset anchorPreset = InventoryUIAnchorPreset.MiddleCenter;
|
|
public Vector2 customAnchorMin = new Vector2(0.5f, 0.5f);
|
|
public Vector2 customAnchorMax = new Vector2(0.5f, 0.5f);
|
|
public Vector2 customPivot = new Vector2(0.5f, 0.5f);
|
|
public Vector2 size = new Vector2(64f, 64f);
|
|
public Vector2 anchoredPosition = Vector2.zero;
|
|
|
|
[Header("Image Settings")]
|
|
public bool applyColor = false;
|
|
public Color color = Color.white;
|
|
public bool applySprite = false;
|
|
public Sprite sprite;
|
|
public bool applyRaycastTarget = true;
|
|
public bool raycastTarget = false;
|
|
public bool resetScaleToOne = true;
|
|
|
|
[Header("Outline / Shadow")]
|
|
public bool applyOutline = false;
|
|
public bool addOutlineIfMissing = true;
|
|
public Color outlineColor = new Color(0f, 0.75f, 1f, 0.8f);
|
|
public Vector2 outlineEffectDistance = new Vector2(1f, -1f);
|
|
public bool outlineUseGraphicAlpha = true;
|
|
public bool applyShadow = false;
|
|
public bool addShadowIfMissing = true;
|
|
public Color shadowColor = new Color(0f, 0f, 0f, 0.55f);
|
|
public Vector2 shadowEffectDistance = new Vector2(2f, -2f);
|
|
public bool shadowUseGraphicAlpha = true;
|
|
}
|
|
|
|
[Serializable]
|
|
public class InventoryControlledButtonTarget
|
|
{
|
|
[Header("Target")]
|
|
public string name;
|
|
public Button button;
|
|
|
|
[Header("Rect Layout")]
|
|
public bool applyRect = false;
|
|
public InventoryUIAnchorPreset anchorPreset = InventoryUIAnchorPreset.MiddleCenter;
|
|
public Vector2 customAnchorMin = new Vector2(0.5f, 0.5f);
|
|
public Vector2 customAnchorMax = new Vector2(0.5f, 0.5f);
|
|
public Vector2 customPivot = new Vector2(0.5f, 0.5f);
|
|
public Vector2 size = new Vector2(100f, 35f);
|
|
public Vector2 anchoredPosition = Vector2.zero;
|
|
|
|
[Header("Button Settings")]
|
|
public bool applyInteractable = false;
|
|
public bool interactable = true;
|
|
public bool applyImageRaycastTarget = true;
|
|
public bool imageRaycastTarget = true;
|
|
public bool disableChildTextRaycasts = true;
|
|
public bool resetScaleToOne = true;
|
|
|
|
[Header("Button Colors")]
|
|
public bool applyButtonColors = false;
|
|
public Color normalColor = new Color(0.07f, 0.18f, 0.30f, 0.90f);
|
|
public Color highlightedColor = new Color(0.12f, 0.42f, 0.70f, 1f);
|
|
public Color pressedColor = new Color(0.04f, 0.12f, 0.20f, 1f);
|
|
public Color selectedColor = new Color(0.15f, 0.50f, 0.85f, 1f);
|
|
public Color disabledColor = new Color(0.20f, 0.20f, 0.20f, 0.45f);
|
|
public float colorMultiplier = 1f;
|
|
public float fadeDuration = 0.1f;
|
|
|
|
[Header("Outline / Shadow")]
|
|
public bool applyOutline = false;
|
|
public bool addOutlineIfMissing = true;
|
|
public Color outlineColor = new Color(0f, 0.75f, 1f, 0.8f);
|
|
public Vector2 outlineEffectDistance = new Vector2(1f, -1f);
|
|
public bool outlineUseGraphicAlpha = true;
|
|
public bool applyShadow = false;
|
|
public bool addShadowIfMissing = true;
|
|
public Color shadowColor = new Color(0f, 0f, 0f, 0.55f);
|
|
public Vector2 shadowEffectDistance = new Vector2(2f, -2f);
|
|
public bool shadowUseGraphicAlpha = true;
|
|
}
|
|
|
|
[Serializable]
|
|
public class InventoryLayoutPadding
|
|
{
|
|
public int left;
|
|
public int right;
|
|
public int top;
|
|
public int bottom;
|
|
|
|
public InventoryLayoutPadding() { }
|
|
|
|
public InventoryLayoutPadding(int left, int right, int top, int bottom)
|
|
{
|
|
this.left = left;
|
|
this.right = right;
|
|
this.top = top;
|
|
this.bottom = bottom;
|
|
}
|
|
|
|
public RectOffset ToRectOffset()
|
|
{
|
|
return new RectOffset(left, right, top, bottom);
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public class InventoryControlledGridLayoutTarget
|
|
{
|
|
[Header("Target")]
|
|
public string name;
|
|
public GridLayoutGroup grid;
|
|
|
|
[Header("Grid Settings")]
|
|
public bool applyGrid = true;
|
|
public Vector2 cellSize = new Vector2(100f, 100f);
|
|
public Vector2 spacing = Vector2.zero;
|
|
public TextAnchor childAlignment = TextAnchor.MiddleCenter;
|
|
public GridLayoutGroup.Constraint constraint = GridLayoutGroup.Constraint.FixedColumnCount;
|
|
public int constraintCount = 5;
|
|
public InventoryLayoutPadding padding;
|
|
}
|
|
|
|
/// <summary>
|
|
/// InventoryRoot 아래 UI를 한 곳에서 정리하는 컨트롤러입니다.
|
|
/// - 기본 인벤토리 패널들의 위치/크기/배치를 제어합니다.
|
|
/// - Inspector에 직접 연결한 Rect/Text/Image/Button/Grid 대상도 제어합니다.
|
|
/// - 없는 CanvasGroup, Image, GridLayoutGroup, AudioSource 등을 자동으로 붙일 수 있습니다.
|
|
/// - Text 내용 자체는 바꾸지 않습니다. 내용 변경은 InventoryUI가 담당하게 두는 것을 권장합니다.
|
|
/// </summary>
|
|
[ExecuteAlways]
|
|
[DisallowMultipleComponent]
|
|
public class InventoryUILayoutController : MonoBehaviour
|
|
{
|
|
[Header("Root / Canvas")]
|
|
[SerializeField] private bool configureRootCanvas = true;
|
|
[SerializeField] private Vector2 rootCanvasSize = new Vector2(800f, 500f);
|
|
[SerializeField] private bool applyRootWorldScale = false;
|
|
[SerializeField] private Vector3 rootWorldScale = new Vector3(0.0015f, 0.0015f, 0.0015f);
|
|
[SerializeField] private bool addGraphicRaycasterIfMissing = true;
|
|
[SerializeField] private bool addTrackedDeviceGraphicRaycasterIfAvailable = true;
|
|
|
|
[Header("Known UI References")]
|
|
[SerializeField] private RectTransform inventoryPanel;
|
|
[SerializeField] private RectTransform titleText;
|
|
[SerializeField] private RectTransform closeButton;
|
|
[SerializeField] private RectTransform categoryButtons;
|
|
[SerializeField] private RectTransform memoryProgressArea;
|
|
[SerializeField] private RectTransform slotContainer;
|
|
[SerializeField] private RectTransform recentLogArea;
|
|
[SerializeField] private RectTransform debugPanel;
|
|
[SerializeField] private RectTransform quickUseButtons;
|
|
|
|
[Header("Popup / Floating Panels")]
|
|
[SerializeField] private RectTransform tooltipPanel;
|
|
[SerializeField] private RectTransform acquisitionPopupPanel;
|
|
[SerializeField] private RectTransform messagePanel;
|
|
[SerializeField] private RectTransform confirmationPanel;
|
|
[SerializeField] private RectTransform detailPanel;
|
|
|
|
[Header("Inventory Scripts")]
|
|
[SerializeField] private InventoryUI inventoryUI;
|
|
[SerializeField] private InventorySlotUI[] slots;
|
|
|
|
[Header("Auto Find Names")]
|
|
[SerializeField] private string inventoryPanelName = "InventoryPanel";
|
|
[SerializeField] private string titleTextName = "TitleText";
|
|
[SerializeField] private string closeButtonName = "CloseButton";
|
|
[SerializeField] private string categoryButtonsName = "CategoryButtons";
|
|
[SerializeField] private string memoryProgressAreaName = "MemoryProgressArea";
|
|
[SerializeField] private string slotContainerName = "SlotContainer";
|
|
[SerializeField] private string recentLogAreaName = "RecentLogArea";
|
|
[SerializeField] private string debugPanelName = "DebugPanel";
|
|
[SerializeField] private string quickUseButtonsName = "QuickUseButtons";
|
|
[SerializeField] private string tooltipPanelName = "TooltipPanel";
|
|
[SerializeField] private string acquisitionPopupPanelName = "AcquisitionPopupPanel";
|
|
[SerializeField] private string messagePanelName = "MessagePanel";
|
|
[SerializeField] private string confirmationPanelName = "ConfirmationPanel";
|
|
[SerializeField] private string detailPanelName = "DetailPanel";
|
|
|
|
[Header("Apply Settings")]
|
|
[SerializeField] private bool autoFindReferences = true;
|
|
[SerializeField] private bool autoAddMissingComponents = true;
|
|
[SerializeField] private bool applyKnownLayout = true;
|
|
[SerializeField] private bool applyCustomControlledTargets = true;
|
|
[SerializeField] private bool resetChildScaleToOne = true;
|
|
[SerializeField] private bool applyLayoutOnAwake = true;
|
|
[SerializeField] private bool applyModeOnAwake = true;
|
|
[Tooltip("InventoryUI.Start()의 visibleOnStart 처리 이후에 모드를 한 번 더 적용해 패널 ON/OFF 충돌을 줄입니다.")]
|
|
[SerializeField] private bool applyModeAfterOneFrame = true;
|
|
[SerializeField] private bool applyInEditor = true;
|
|
[SerializeField] private InventoryRootUIMode initialMode = InventoryRootUIMode.TestMode;
|
|
|
|
[Header("Known Panel Layout")]
|
|
[SerializeField] private Vector2 inventoryPanelSize = new Vector2(760f, 460f);
|
|
[SerializeField] private Vector2 inventoryPanelPos = Vector2.zero;
|
|
[SerializeField] private Vector2 titleTextSize = new Vector2(360f, 50f);
|
|
[SerializeField] private Vector2 titleTextPos = new Vector2(0f, -18f);
|
|
[SerializeField] private Vector2 closeButtonSize = new Vector2(70f, 38f);
|
|
[SerializeField] private Vector2 closeButtonPos = new Vector2(-18f, -18f);
|
|
[SerializeField] private Vector2 categoryButtonsSize = new Vector2(620f, 45f);
|
|
[SerializeField] private Vector2 categoryButtonsPos = new Vector2(0f, -75f);
|
|
[SerializeField] private Vector2 memoryProgressAreaSize = new Vector2(620f, 55f);
|
|
[SerializeField] private Vector2 memoryProgressAreaPos = new Vector2(0f, -125f);
|
|
[SerializeField] private Vector2 slotContainerSize = new Vector2(500f, 145f);
|
|
[SerializeField] private Vector2 slotContainerPos = new Vector2(-80f, 20f);
|
|
[SerializeField] private Vector2 recentLogSize = new Vector2(340f, 110f);
|
|
[SerializeField] private Vector2 recentLogPos = new Vector2(25f, 25f);
|
|
[SerializeField] private Vector2 debugPanelSize = new Vector2(300f, 110f);
|
|
[SerializeField] private Vector2 debugPanelPos = new Vector2(-25f, 25f);
|
|
[SerializeField] private Vector2 quickUseButtonsSize = new Vector2(130f, 160f);
|
|
[SerializeField] private Vector2 quickUseButtonsPos = new Vector2(-20f, -35f);
|
|
|
|
[Header("Known Popup / Detail Layout")]
|
|
[SerializeField] private Vector2 tooltipPanelSize = new Vector2(520f, 120f);
|
|
[SerializeField] private Vector2 tooltipPanelPos = new Vector2(0f, -15f);
|
|
[SerializeField] private Vector2 acquisitionPopupSize = new Vector2(360f, 70f);
|
|
[SerializeField] private Vector2 acquisitionPopupPos = new Vector2(0f, 40f);
|
|
[SerializeField] private Vector2 messagePanelSize = new Vector2(460f, 60f);
|
|
[SerializeField] private Vector2 messagePanelPos = new Vector2(0f, -85f);
|
|
[SerializeField] private Vector2 confirmationPanelSize = new Vector2(420f, 220f);
|
|
[SerializeField] private Vector2 confirmationPanelPos = Vector2.zero;
|
|
[SerializeField] private Vector2 detailPanelSize = new Vector2(260f, 340f);
|
|
[SerializeField] private Vector2 detailPanelPos = new Vector2(-25f, 0f);
|
|
|
|
[Header("Known LayoutGroup Defaults")]
|
|
[SerializeField] private Vector2 slotCellSize = new Vector2(85f, 120f);
|
|
[SerializeField] private Vector2 slotSpacing = new Vector2(8f, 0f);
|
|
[SerializeField] private int slotColumnCount = 5;
|
|
[SerializeField] private Vector2 debugButtonCellSize = new Vector2(85f, 28f);
|
|
[SerializeField] private Vector2 debugButtonSpacing = new Vector2(5f, 5f);
|
|
[SerializeField] private int debugButtonColumnCount = 3;
|
|
[SerializeField] private Vector2 quickUseButtonCellSize = new Vector2(115f, 26f);
|
|
[SerializeField] private Vector2 quickUseButtonSpacing = new Vector2(0f, 5f);
|
|
|
|
[Header("Known Slot Child Layout")]
|
|
[SerializeField] private bool arrangeSlotChildren = true;
|
|
[SerializeField] private Vector2 slotIconSize = new Vector2(64f, 64f);
|
|
[SerializeField] private Vector2 slotIconPos = new Vector2(0f, 18f);
|
|
[SerializeField] private Vector2 slotCountTextSize = new Vector2(100f, 28f);
|
|
[SerializeField] private Vector2 slotCountTextPos = new Vector2(0f, 8f);
|
|
[SerializeField] private Vector2 slotNewBadgeSize = new Vector2(52f, 24f);
|
|
[SerializeField] private Vector2 slotNewBadgePos = new Vector2(-4f, -4f);
|
|
|
|
[Header("Mode Active States")]
|
|
[SerializeField] private bool testShowInventoryPanel = true;
|
|
[SerializeField] private bool testShowDebugPanel = true;
|
|
[SerializeField] private bool testShowRecentLogArea = true;
|
|
[SerializeField] private bool testShowCategoryButtons = true;
|
|
[SerializeField] private bool testShowMemoryProgressArea = true;
|
|
[SerializeField] private bool testShowQuickUseButtons = false;
|
|
|
|
[SerializeField] private bool playShowInventoryPanel = false;
|
|
[SerializeField] private bool playShowDebugPanel = false;
|
|
[SerializeField] private bool playShowRecentLogArea = true;
|
|
[SerializeField] private bool playShowCategoryButtons = true;
|
|
[SerializeField] private bool playShowMemoryProgressArea = true;
|
|
[SerializeField] private bool playShowQuickUseButtons = false;
|
|
|
|
[SerializeField] private bool buildShowInventoryPanel = false;
|
|
[SerializeField] private bool buildShowDebugPanel = false;
|
|
[SerializeField] private bool buildShowRecentLogArea = true;
|
|
[SerializeField] private bool buildShowCategoryButtons = true;
|
|
[SerializeField] private bool buildShowMemoryProgressArea = true;
|
|
[SerializeField] private bool buildShowQuickUseButtons = false;
|
|
|
|
[Header("Custom Inspector-Controlled Targets")]
|
|
[Tooltip("패널, 영역, 빈 오브젝트 등 RectTransform 기준으로 제어할 대상입니다.")]
|
|
[SerializeField] private List<InventoryControlledRectTarget> controlledRects = new List<InventoryControlledRectTarget>();
|
|
[Tooltip("패널 자식 TMP_Text의 위치, 크기, 폰트 크기, 정렬, Raycast를 제어합니다. Text 내용은 바꾸지 않습니다.")]
|
|
[SerializeField] private List<InventoryControlledTextTarget> controlledTexts = new List<InventoryControlledTextTarget>();
|
|
[Tooltip("패널 자식 Image의 위치, 크기, 색상, Raycast를 제어합니다. Sprite는 Apply Sprite를 켰을 때만 바꿉니다.")]
|
|
[SerializeField] private List<InventoryControlledImageTarget> controlledImages = new List<InventoryControlledImageTarget>();
|
|
[Tooltip("패널 자식 Button의 위치, 크기, Interactable, Raycast를 제어합니다.")]
|
|
[SerializeField] private List<InventoryControlledButtonTarget> controlledButtons = new List<InventoryControlledButtonTarget>();
|
|
[Tooltip("SlotContainer, DebugPanel 같은 GridLayoutGroup의 Cell Size, Spacing, Count를 제어합니다.")]
|
|
[SerializeField] private List<InventoryControlledGridLayoutTarget> controlledGridLayouts = new List<InventoryControlledGridLayoutTarget>();
|
|
|
|
[Header("Basic Visual Theme")]
|
|
[SerializeField] private bool applyBasicVisualTheme = true;
|
|
[SerializeField] private bool styleKnownPanels = true;
|
|
[SerializeField] private bool styleKnownButtons = true;
|
|
[SerializeField] private bool styleKnownTexts = true;
|
|
[SerializeField] private bool styleKnownSlots = true;
|
|
[SerializeField] private bool addOutlineToKnownGraphics = true;
|
|
[SerializeField] private bool addShadowToKnownTexts = true;
|
|
|
|
[Header("Theme Colors - Ocean VR")]
|
|
[SerializeField] private Color mainPanelColor = new Color(0.03f, 0.08f, 0.15f, 0.88f);
|
|
[SerializeField] private Color subPanelColor = new Color(0.04f, 0.14f, 0.24f, 0.82f);
|
|
[SerializeField] private Color popupPanelColor = new Color(0.02f, 0.10f, 0.18f, 0.92f);
|
|
[SerializeField] private Color slotColor = new Color(0.05f, 0.16f, 0.26f, 0.90f);
|
|
[SerializeField] private Color slotImportantGlowColor = new Color(1.0f, 0.72f, 0.20f, 0.38f);
|
|
[SerializeField] private Color filteredOverlayColor = new Color(0f, 0f, 0f, 0.55f);
|
|
[SerializeField] private Color newBadgeColor = new Color(1.0f, 0.82f, 0.12f, 0.95f);
|
|
[SerializeField] private Color mainTextColor = new Color(0.95f, 0.92f, 0.82f, 1f);
|
|
[SerializeField] private Color accentTextColor = new Color(1.0f, 0.78f, 0.35f, 1f);
|
|
[SerializeField] private Color mutedTextColor = new Color(0.70f, 0.86f, 0.95f, 1f);
|
|
[SerializeField] private Color outlineColor = new Color(0.18f, 0.76f, 1f, 0.65f);
|
|
[SerializeField] private Color goldOutlineColor = new Color(1.0f, 0.72f, 0.20f, 0.80f);
|
|
[SerializeField] private Color shadowColor = new Color(0f, 0f, 0f, 0.62f);
|
|
|
|
[Header("Theme Button Colors")]
|
|
[SerializeField] private Color buttonNormalColor = new Color(0.06f, 0.20f, 0.33f, 0.95f);
|
|
[SerializeField] private Color buttonHighlightedColor = new Color(0.12f, 0.44f, 0.74f, 1f);
|
|
[SerializeField] private Color buttonPressedColor = new Color(0.03f, 0.12f, 0.22f, 1f);
|
|
[SerializeField] private Color buttonSelectedColor = new Color(0.16f, 0.50f, 0.82f, 1f);
|
|
[SerializeField] private Color buttonDisabledColor = new Color(0.20f, 0.22f, 0.24f, 0.45f);
|
|
[SerializeField] private Color debugButtonColor = new Color(0.07f, 0.22f, 0.32f, 0.95f);
|
|
[SerializeField] private Color dangerButtonColor = new Color(0.45f, 0.10f, 0.12f, 0.95f);
|
|
|
|
[Header("Popup Groups")]
|
|
[SerializeField] private GameObject[] extraPopupPanelsToHide;
|
|
|
|
[Header("Raycast / Component Fix")]
|
|
[SerializeField] private bool fixRaycastTargets = true;
|
|
[SerializeField] private bool fixCanvasGroups = true;
|
|
[SerializeField] private bool disableTextRaycasts = true;
|
|
[SerializeField] private bool disableNonInteractiveImageRaycasts = true;
|
|
[SerializeField] private bool setSliderInteractableFalse = true;
|
|
[SerializeField] private bool setSlotHoverSafeValues = true;
|
|
[SerializeField] private bool slotUseHoverScale = true;
|
|
[SerializeField] private float slotHoverScale = 1.03f;
|
|
[SerializeField] private bool slotBringToFrontOnHover = false;
|
|
|
|
private bool isApplying;
|
|
|
|
private void Reset()
|
|
{
|
|
AutoFindReferences();
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
if (!Application.isPlaying)
|
|
return;
|
|
|
|
if (autoFindReferences)
|
|
AutoFindReferences();
|
|
|
|
if (autoAddMissingComponents)
|
|
AutoSetupMissingComponents();
|
|
|
|
if (applyLayoutOnAwake)
|
|
ApplyFullInventoryRootLayout();
|
|
|
|
if (applyModeOnAwake)
|
|
ApplyInitialMode();
|
|
}
|
|
|
|
private System.Collections.IEnumerator Start()
|
|
{
|
|
if (!Application.isPlaying || !applyModeAfterOneFrame)
|
|
yield break;
|
|
|
|
// InventoryUI.Start()의 visibleOnStart 적용이 끝난 뒤 모드를 다시 적용합니다.
|
|
yield return null;
|
|
ApplyInitialMode();
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
private void OnValidate()
|
|
{
|
|
if (!applyInEditor)
|
|
return;
|
|
|
|
EditorApplication.delayCall -= DelayedApplyInEditor;
|
|
EditorApplication.delayCall += DelayedApplyInEditor;
|
|
}
|
|
|
|
private void DelayedApplyInEditor()
|
|
{
|
|
if (this == null || isApplying)
|
|
return;
|
|
|
|
ApplyFullInventoryRootLayout();
|
|
}
|
|
#endif
|
|
|
|
[ContextMenu("Inventory UI/Apply Full Inventory Root Layout")]
|
|
public void ApplyFullInventoryRootLayout()
|
|
{
|
|
if (isApplying)
|
|
return;
|
|
|
|
isApplying = true;
|
|
|
|
if (autoFindReferences)
|
|
AutoFindReferences();
|
|
|
|
if (autoAddMissingComponents)
|
|
AutoSetupMissingComponents();
|
|
|
|
if (configureRootCanvas)
|
|
ConfigureRootCanvas();
|
|
|
|
if (applyKnownLayout)
|
|
ApplyKnownLayout();
|
|
|
|
if (arrangeSlotChildren)
|
|
ArrangeSlotChildren();
|
|
|
|
if (applyCustomControlledTargets)
|
|
ApplyCustomTargets();
|
|
|
|
if (applyBasicVisualTheme)
|
|
ApplyBasicVisualTheme();
|
|
|
|
if (fixRaycastTargets)
|
|
FixAllRaycastTargets();
|
|
|
|
isApplying = false;
|
|
}
|
|
|
|
[ContextMenu("Inventory UI/Apply Custom Inspector Targets Only")]
|
|
public void ApplyCustomTargets()
|
|
{
|
|
ApplyControlledRectTargets();
|
|
ApplyControlledTextTargets();
|
|
ApplyControlledImageTargets();
|
|
ApplyControlledButtonTargets();
|
|
ApplyControlledGridLayoutTargets();
|
|
}
|
|
|
|
[ContextMenu("Inventory UI/Auto Find References")]
|
|
public void AutoFindReferences()
|
|
{
|
|
inventoryPanel = FindRectIfNull(inventoryPanel, inventoryPanelName);
|
|
titleText = FindRectIfNull(titleText, titleTextName);
|
|
closeButton = FindRectIfNull(closeButton, closeButtonName);
|
|
categoryButtons = FindRectIfNull(categoryButtons, categoryButtonsName);
|
|
memoryProgressArea = FindRectIfNull(memoryProgressArea, memoryProgressAreaName);
|
|
slotContainer = FindRectIfNull(slotContainer, slotContainerName);
|
|
recentLogArea = FindRectIfNull(recentLogArea, recentLogAreaName);
|
|
debugPanel = FindRectIfNull(debugPanel, debugPanelName);
|
|
quickUseButtons = FindRectIfNull(quickUseButtons, quickUseButtonsName);
|
|
tooltipPanel = FindRectIfNull(tooltipPanel, tooltipPanelName);
|
|
acquisitionPopupPanel = FindRectIfNull(acquisitionPopupPanel, acquisitionPopupPanelName);
|
|
messagePanel = FindRectIfNull(messagePanel, messagePanelName);
|
|
confirmationPanel = FindRectIfNull(confirmationPanel, confirmationPanelName);
|
|
detailPanel = FindRectIfNull(detailPanel, detailPanelName);
|
|
|
|
if (inventoryUI == null)
|
|
inventoryUI = GetComponent<InventoryUI>();
|
|
|
|
if (slots == null || slots.Length == 0)
|
|
slots = GetComponentsInChildren<InventorySlotUI>(true);
|
|
}
|
|
|
|
[ContextMenu("Inventory UI/Auto Setup Missing Components")]
|
|
public void AutoSetupMissingComponents()
|
|
{
|
|
Canvas canvas = GetOrAdd<Canvas>(gameObject);
|
|
canvas.renderMode = RenderMode.WorldSpace;
|
|
|
|
GetOrAdd<CanvasScaler>(gameObject);
|
|
|
|
if (addGraphicRaycasterIfMissing)
|
|
GetOrAdd<GraphicRaycaster>(gameObject);
|
|
|
|
if (addTrackedDeviceGraphicRaycasterIfAvailable)
|
|
TryAddComponentByTypeName(gameObject, "UnityEngine.XR.Interaction.Toolkit.UI.TrackedDeviceGraphicRaycaster");
|
|
|
|
GetOrAdd<AudioSource>(gameObject).playOnAwake = false;
|
|
|
|
AddCanvasGroupIfNeeded(tooltipPanel, false, false);
|
|
AddCanvasGroupIfNeeded(acquisitionPopupPanel, false, false);
|
|
AddCanvasGroupIfNeeded(messagePanel, false, false);
|
|
AddCanvasGroupIfNeeded(confirmationPanel, true, true);
|
|
AddCanvasGroupIfNeeded(detailPanel, true, true);
|
|
|
|
if (slotContainer != null)
|
|
GetOrAdd<GridLayoutGroup>(slotContainer.gameObject);
|
|
|
|
if (debugPanel != null)
|
|
GetOrAdd<GridLayoutGroup>(debugPanel.gameObject);
|
|
|
|
if (quickUseButtons != null && quickUseButtons.GetComponent<LayoutGroup>() == null)
|
|
quickUseButtons.gameObject.AddComponent<VerticalLayoutGroup>();
|
|
}
|
|
|
|
[ContextMenu("Inventory UI/Add Default Known Targets To Inspector Lists")]
|
|
public void AddDefaultKnownTargetsToInspectorLists()
|
|
{
|
|
AutoFindReferences();
|
|
|
|
AddControlledRect("InventoryPanel", inventoryPanel, null, InventoryUIAnchorPreset.MiddleCenter, inventoryPanelSize, inventoryPanelPos, false, true, true, true, false);
|
|
AddControlledRect("TitleText", titleText, null, InventoryUIAnchorPreset.TopCenter, titleTextSize, titleTextPos, false, true, true, true, false);
|
|
AddControlledRect("CloseButton", closeButton, null, InventoryUIAnchorPreset.TopRight, closeButtonSize, closeButtonPos, false, true, true, true, false);
|
|
AddControlledRect("CategoryButtons", categoryButtons, null, InventoryUIAnchorPreset.TopCenter, categoryButtonsSize, categoryButtonsPos, true, testShowCategoryButtons, playShowCategoryButtons, buildShowCategoryButtons, false);
|
|
AddControlledRect("MemoryProgressArea", memoryProgressArea, null, InventoryUIAnchorPreset.TopCenter, memoryProgressAreaSize, memoryProgressAreaPos, true, testShowMemoryProgressArea, playShowMemoryProgressArea, buildShowMemoryProgressArea, false);
|
|
AddControlledRect("SlotContainer", slotContainer, null, InventoryUIAnchorPreset.MiddleCenter, slotContainerSize, slotContainerPos, false, true, true, true, false);
|
|
AddControlledRect("RecentLogArea", recentLogArea, null, InventoryUIAnchorPreset.BottomLeft, recentLogSize, recentLogPos, true, testShowRecentLogArea, playShowRecentLogArea, buildShowRecentLogArea, false);
|
|
AddControlledRect("DebugPanel", debugPanel, null, InventoryUIAnchorPreset.BottomRight, debugPanelSize, debugPanelPos, true, testShowDebugPanel, playShowDebugPanel, buildShowDebugPanel, false);
|
|
AddControlledRect("QuickUseButtons", quickUseButtons, null, InventoryUIAnchorPreset.MiddleRight, quickUseButtonsSize, quickUseButtonsPos, true, testShowQuickUseButtons, playShowQuickUseButtons, buildShowQuickUseButtons, false);
|
|
AddControlledRect("TooltipPanel", tooltipPanel, null, InventoryUIAnchorPreset.BottomCenter, tooltipPanelSize, tooltipPanelPos, true, false, false, false, false);
|
|
AddControlledRect("AcquisitionPopupPanel", acquisitionPopupPanel, null, InventoryUIAnchorPreset.TopCenter, acquisitionPopupSize, acquisitionPopupPos, true, false, false, false, false);
|
|
AddControlledRect("MessagePanel", messagePanel, null, InventoryUIAnchorPreset.BottomCenter, messagePanelSize, messagePanelPos, true, false, false, false, false);
|
|
AddControlledRect("ConfirmationPanel", confirmationPanel, null, InventoryUIAnchorPreset.MiddleCenter, confirmationPanelSize, confirmationPanelPos, true, false, false, false, false);
|
|
AddControlledRect("DetailPanel", detailPanel, null, InventoryUIAnchorPreset.MiddleRight, detailPanelSize, detailPanelPos, true, false, false, false, false);
|
|
|
|
AddGrid("SlotContainer Grid", slotContainer != null ? slotContainer.GetComponent<GridLayoutGroup>() : null, slotCellSize, slotSpacing, GridLayoutGroup.Constraint.FixedColumnCount, slotColumnCount);
|
|
AddGrid("DebugPanel Grid", debugPanel != null ? debugPanel.GetComponent<GridLayoutGroup>() : null, debugButtonCellSize, debugButtonSpacing, GridLayoutGroup.Constraint.FixedColumnCount, debugButtonColumnCount);
|
|
|
|
AddChildrenOfPanelsToInspectorLists();
|
|
}
|
|
|
|
[ContextMenu("Inventory UI/Add Current Panel Children Texts Images Buttons")]
|
|
public void AddChildrenOfPanelsToInspectorLists()
|
|
{
|
|
RectTransform[] panels = new[] { inventoryPanel, tooltipPanel, acquisitionPopupPanel, messagePanel, confirmationPanel, detailPanel, recentLogArea, debugPanel };
|
|
|
|
foreach (RectTransform panel in panels)
|
|
{
|
|
if (panel == null)
|
|
continue;
|
|
|
|
foreach (TMP_Text text in panel.GetComponentsInChildren<TMP_Text>(true))
|
|
AddText(text.name, text);
|
|
|
|
foreach (Image image in panel.GetComponentsInChildren<Image>(true))
|
|
AddImage(image.name, image);
|
|
|
|
foreach (Button button in panel.GetComponentsInChildren<Button>(true))
|
|
AddButton(button.name, button);
|
|
}
|
|
}
|
|
|
|
[ContextMenu("Inventory UI/Clear Custom Inspector Lists")]
|
|
public void ClearCustomInspectorLists()
|
|
{
|
|
controlledRects.Clear();
|
|
controlledTexts.Clear();
|
|
controlledImages.Clear();
|
|
controlledButtons.Clear();
|
|
controlledGridLayouts.Clear();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Scene View/RectTransform에서 직접 옮긴 현재 위치와 크기를 컨트롤러 값으로 저장합니다.
|
|
/// 이후 Apply Full Inventory Root Layout을 실행해도 캡처한 위치가 유지됩니다.
|
|
/// </summary>
|
|
[ContextMenu("Inventory UI/Capture Current Layout")]
|
|
public void CaptureCurrentLayout()
|
|
{
|
|
if (autoFindReferences)
|
|
AutoFindReferences();
|
|
|
|
CaptureKnownLayoutValues();
|
|
CaptureCustomTargetLayoutValues();
|
|
CaptureKnownGridLayoutValues();
|
|
|
|
MarkControllerDirty();
|
|
Debug.Log("[InventoryUILayoutController] 현재 UI 위치/크기/배치 값을 컨트롤러에 저장했습니다.", this);
|
|
}
|
|
|
|
[ContextMenu("Inventory UI/Capture Current Known Layout")]
|
|
public void CaptureCurrentKnownLayout()
|
|
{
|
|
if (autoFindReferences)
|
|
AutoFindReferences();
|
|
|
|
CaptureKnownLayoutValues();
|
|
CaptureKnownGridLayoutValues();
|
|
MarkControllerDirty();
|
|
Debug.Log("[InventoryUILayoutController] Known UI References의 현재 위치/크기를 저장했습니다.", this);
|
|
}
|
|
|
|
[ContextMenu("Inventory UI/Capture Current Custom Targets")]
|
|
public void CaptureCurrentCustomTargets()
|
|
{
|
|
CaptureCustomTargetLayoutValues();
|
|
MarkControllerDirty();
|
|
Debug.Log("[InventoryUILayoutController] Custom Inspector-Controlled Targets의 현재 위치/크기를 저장했습니다.", this);
|
|
}
|
|
|
|
[ContextMenu("Inventory UI/Capture Known Layout Into Controlled Rects")]
|
|
public void CaptureKnownLayoutIntoControlledRects()
|
|
{
|
|
if (autoFindReferences)
|
|
AutoFindReferences();
|
|
|
|
CaptureOrAddControlledRect("InventoryPanel", inventoryPanel, false, true, true, true, false);
|
|
CaptureOrAddControlledRect("TitleText", titleText, false, true, true, true, false);
|
|
CaptureOrAddControlledRect("CloseButton", closeButton, false, true, true, true, false);
|
|
CaptureOrAddControlledRect("CategoryButtons", categoryButtons, true, testShowCategoryButtons, playShowCategoryButtons, buildShowCategoryButtons, false);
|
|
CaptureOrAddControlledRect("MemoryProgressArea", memoryProgressArea, true, testShowMemoryProgressArea, playShowMemoryProgressArea, buildShowMemoryProgressArea, false);
|
|
CaptureOrAddControlledRect("SlotContainer", slotContainer, false, true, true, true, false);
|
|
CaptureOrAddControlledRect("RecentLogArea", recentLogArea, true, testShowRecentLogArea, playShowRecentLogArea, buildShowRecentLogArea, false);
|
|
CaptureOrAddControlledRect("DebugPanel", debugPanel, true, testShowDebugPanel, playShowDebugPanel, buildShowDebugPanel, false);
|
|
CaptureOrAddControlledRect("QuickUseButtons", quickUseButtons, true, testShowQuickUseButtons, playShowQuickUseButtons, buildShowQuickUseButtons, false);
|
|
CaptureOrAddControlledRect("TooltipPanel", tooltipPanel, true, false, false, false, false);
|
|
CaptureOrAddControlledRect("AcquisitionPopupPanel", acquisitionPopupPanel, true, false, false, false, false);
|
|
CaptureOrAddControlledRect("MessagePanel", messagePanel, true, false, false, false, false);
|
|
CaptureOrAddControlledRect("ConfirmationPanel", confirmationPanel, true, false, false, false, false);
|
|
CaptureOrAddControlledRect("DetailPanel", detailPanel, true, false, false, false, false);
|
|
|
|
MarkControllerDirty();
|
|
Debug.Log("[InventoryUILayoutController] 현재 Known UI 위치를 Controlled Rects에 저장했습니다.", this);
|
|
}
|
|
|
|
private void CaptureKnownLayoutValues()
|
|
{
|
|
RectTransform rootRect = GetComponent<RectTransform>();
|
|
if (rootRect != null)
|
|
{
|
|
rootCanvasSize = rootRect.sizeDelta;
|
|
rootWorldScale = rootRect.localScale;
|
|
}
|
|
|
|
CaptureKnownRect(inventoryPanel, ref inventoryPanelSize, ref inventoryPanelPos);
|
|
CaptureKnownRect(titleText, ref titleTextSize, ref titleTextPos);
|
|
CaptureKnownRect(closeButton, ref closeButtonSize, ref closeButtonPos);
|
|
CaptureKnownRect(categoryButtons, ref categoryButtonsSize, ref categoryButtonsPos);
|
|
CaptureKnownRect(memoryProgressArea, ref memoryProgressAreaSize, ref memoryProgressAreaPos);
|
|
CaptureKnownRect(slotContainer, ref slotContainerSize, ref slotContainerPos);
|
|
CaptureKnownRect(recentLogArea, ref recentLogSize, ref recentLogPos);
|
|
CaptureKnownRect(debugPanel, ref debugPanelSize, ref debugPanelPos);
|
|
CaptureKnownRect(quickUseButtons, ref quickUseButtonsSize, ref quickUseButtonsPos);
|
|
CaptureKnownRect(tooltipPanel, ref tooltipPanelSize, ref tooltipPanelPos);
|
|
CaptureKnownRect(acquisitionPopupPanel, ref acquisitionPopupSize, ref acquisitionPopupPos);
|
|
CaptureKnownRect(messagePanel, ref messagePanelSize, ref messagePanelPos);
|
|
CaptureKnownRect(confirmationPanel, ref confirmationPanelSize, ref confirmationPanelPos);
|
|
CaptureKnownRect(detailPanel, ref detailPanelSize, ref detailPanelPos);
|
|
}
|
|
|
|
private void CaptureKnownRect(RectTransform rect, ref Vector2 sizeField, ref Vector2 posField)
|
|
{
|
|
if (rect == null)
|
|
return;
|
|
|
|
sizeField = rect.sizeDelta;
|
|
posField = rect.anchoredPosition;
|
|
}
|
|
|
|
private void CaptureCustomTargetLayoutValues()
|
|
{
|
|
if (controlledRects != null)
|
|
{
|
|
foreach (InventoryControlledRectTarget target in controlledRects)
|
|
{
|
|
if (target == null || target.rectTransform == null)
|
|
continue;
|
|
|
|
CaptureRectData(target.rectTransform, target);
|
|
}
|
|
}
|
|
|
|
if (controlledTexts != null)
|
|
{
|
|
foreach (InventoryControlledTextTarget target in controlledTexts)
|
|
{
|
|
if (target == null || target.text == null)
|
|
continue;
|
|
|
|
CaptureRectData(target.text.rectTransform, target);
|
|
}
|
|
}
|
|
|
|
if (controlledImages != null)
|
|
{
|
|
foreach (InventoryControlledImageTarget target in controlledImages)
|
|
{
|
|
if (target == null || target.image == null)
|
|
continue;
|
|
|
|
CaptureRectData(target.image.rectTransform, target);
|
|
}
|
|
}
|
|
|
|
if (controlledButtons != null)
|
|
{
|
|
foreach (InventoryControlledButtonTarget target in controlledButtons)
|
|
{
|
|
if (target == null || target.button == null)
|
|
continue;
|
|
|
|
CaptureRectData(target.button.GetComponent<RectTransform>(), target);
|
|
}
|
|
}
|
|
|
|
if (controlledGridLayouts != null)
|
|
{
|
|
foreach (InventoryControlledGridLayoutTarget target in controlledGridLayouts)
|
|
{
|
|
if (target == null || target.grid == null)
|
|
continue;
|
|
|
|
CaptureGridData(target.grid, target);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CaptureKnownGridLayoutValues()
|
|
{
|
|
GridLayoutGroup slotGrid = slotContainer != null ? slotContainer.GetComponent<GridLayoutGroup>() : null;
|
|
if (slotGrid != null)
|
|
{
|
|
slotCellSize = slotGrid.cellSize;
|
|
slotSpacing = slotGrid.spacing;
|
|
slotColumnCount = Mathf.Max(1, slotGrid.constraintCount);
|
|
}
|
|
|
|
GridLayoutGroup debugGrid = debugPanel != null ? debugPanel.GetComponent<GridLayoutGroup>() : null;
|
|
if (debugGrid != null)
|
|
{
|
|
debugButtonCellSize = debugGrid.cellSize;
|
|
debugButtonSpacing = debugGrid.spacing;
|
|
debugButtonColumnCount = Mathf.Max(1, debugGrid.constraintCount);
|
|
}
|
|
|
|
GridLayoutGroup quickUseGrid = quickUseButtons != null ? quickUseButtons.GetComponent<GridLayoutGroup>() : null;
|
|
if (quickUseGrid != null)
|
|
{
|
|
quickUseButtonCellSize = quickUseGrid.cellSize;
|
|
quickUseButtonSpacing = quickUseGrid.spacing;
|
|
}
|
|
else if (quickUseButtons != null)
|
|
{
|
|
VerticalLayoutGroup vertical = quickUseButtons.GetComponent<VerticalLayoutGroup>();
|
|
if (vertical != null)
|
|
quickUseButtonSpacing = new Vector2(quickUseButtonSpacing.x, vertical.spacing);
|
|
}
|
|
}
|
|
|
|
private void CaptureRectData(RectTransform rect, InventoryControlledRectTarget target)
|
|
{
|
|
if (rect == null || target == null)
|
|
return;
|
|
|
|
target.applyRect = true;
|
|
target.anchorPreset = DetectAnchorPreset(rect);
|
|
target.customAnchorMin = rect.anchorMin;
|
|
target.customAnchorMax = rect.anchorMax;
|
|
target.customPivot = rect.pivot;
|
|
target.size = rect.sizeDelta;
|
|
target.anchoredPosition = rect.anchoredPosition;
|
|
target.localScale = rect.localScale;
|
|
target.localEulerAngles = rect.localEulerAngles;
|
|
target.siblingIndex = rect.GetSiblingIndex();
|
|
}
|
|
|
|
private void CaptureRectData(RectTransform rect, InventoryControlledTextTarget target)
|
|
{
|
|
if (rect == null || target == null)
|
|
return;
|
|
|
|
target.applyRect = true;
|
|
target.anchorPreset = DetectAnchorPreset(rect);
|
|
target.customAnchorMin = rect.anchorMin;
|
|
target.customAnchorMax = rect.anchorMax;
|
|
target.customPivot = rect.pivot;
|
|
target.size = rect.sizeDelta;
|
|
target.anchoredPosition = rect.anchoredPosition;
|
|
}
|
|
|
|
private void CaptureRectData(RectTransform rect, InventoryControlledImageTarget target)
|
|
{
|
|
if (rect == null || target == null)
|
|
return;
|
|
|
|
target.applyRect = true;
|
|
target.anchorPreset = DetectAnchorPreset(rect);
|
|
target.customAnchorMin = rect.anchorMin;
|
|
target.customAnchorMax = rect.anchorMax;
|
|
target.customPivot = rect.pivot;
|
|
target.size = rect.sizeDelta;
|
|
target.anchoredPosition = rect.anchoredPosition;
|
|
}
|
|
|
|
private void CaptureRectData(RectTransform rect, InventoryControlledButtonTarget target)
|
|
{
|
|
if (rect == null || target == null)
|
|
return;
|
|
|
|
target.applyRect = true;
|
|
target.anchorPreset = DetectAnchorPreset(rect);
|
|
target.customAnchorMin = rect.anchorMin;
|
|
target.customAnchorMax = rect.anchorMax;
|
|
target.customPivot = rect.pivot;
|
|
target.size = rect.sizeDelta;
|
|
target.anchoredPosition = rect.anchoredPosition;
|
|
}
|
|
|
|
private void CaptureGridData(GridLayoutGroup grid, InventoryControlledGridLayoutTarget target)
|
|
{
|
|
if (grid == null || target == null)
|
|
return;
|
|
|
|
target.applyGrid = true;
|
|
target.cellSize = grid.cellSize;
|
|
target.spacing = grid.spacing;
|
|
target.childAlignment = grid.childAlignment;
|
|
target.constraint = grid.constraint;
|
|
target.constraintCount = Mathf.Max(1, grid.constraintCount);
|
|
target.padding = new InventoryLayoutPadding(grid.padding.left, grid.padding.right, grid.padding.top, grid.padding.bottom);
|
|
}
|
|
|
|
private void CaptureOrAddControlledRect(string targetName, RectTransform rect, bool controlActive, bool testActive, bool playActive, bool buildActive, bool hiddenActive)
|
|
{
|
|
if (rect == null)
|
|
return;
|
|
|
|
if (controlledRects == null)
|
|
controlledRects = new List<InventoryControlledRectTarget>();
|
|
|
|
InventoryControlledRectTarget target = FindControlledRect(rect);
|
|
if (target == null)
|
|
{
|
|
target = new InventoryControlledRectTarget();
|
|
controlledRects.Add(target);
|
|
}
|
|
|
|
target.name = targetName;
|
|
target.rectTransform = rect;
|
|
target.activeTarget = rect.gameObject;
|
|
target.controlActiveState = controlActive;
|
|
target.activeInTestMode = testActive;
|
|
target.activeInPlayMode = playActive;
|
|
target.activeInBuildMode = buildActive;
|
|
target.activeInHiddenMode = hiddenActive;
|
|
CaptureRectData(rect, target);
|
|
}
|
|
|
|
private InventoryControlledRectTarget FindControlledRect(RectTransform rect)
|
|
{
|
|
if (rect == null || controlledRects == null)
|
|
return null;
|
|
|
|
foreach (InventoryControlledRectTarget target in controlledRects)
|
|
{
|
|
if (target != null && target.rectTransform == rect)
|
|
return target;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private InventoryUIAnchorPreset DetectAnchorPreset(RectTransform rect)
|
|
{
|
|
if (rect == null)
|
|
return InventoryUIAnchorPreset.MiddleCenter;
|
|
|
|
if (Approximately(rect.anchorMin, Vector2.zero) && Approximately(rect.anchorMax, Vector2.one))
|
|
return InventoryUIAnchorPreset.StretchAll;
|
|
|
|
if (!Approximately(rect.anchorMin, rect.anchorMax))
|
|
return InventoryUIAnchorPreset.Custom;
|
|
|
|
Vector2 anchor = rect.anchorMin;
|
|
Vector2 pivot = rect.pivot;
|
|
|
|
if (Approximately(anchor, new Vector2(0.5f, 0.5f)) && Approximately(pivot, new Vector2(0.5f, 0.5f))) return InventoryUIAnchorPreset.MiddleCenter;
|
|
if (Approximately(anchor, new Vector2(0f, 1f)) && Approximately(pivot, new Vector2(0f, 1f))) return InventoryUIAnchorPreset.TopLeft;
|
|
if (Approximately(anchor, new Vector2(0.5f, 1f)) && Approximately(pivot, new Vector2(0.5f, 1f))) return InventoryUIAnchorPreset.TopCenter;
|
|
if (Approximately(anchor, new Vector2(1f, 1f)) && Approximately(pivot, new Vector2(1f, 1f))) return InventoryUIAnchorPreset.TopRight;
|
|
if (Approximately(anchor, new Vector2(0f, 0.5f)) && Approximately(pivot, new Vector2(0f, 0.5f))) return InventoryUIAnchorPreset.MiddleLeft;
|
|
if (Approximately(anchor, new Vector2(1f, 0.5f)) && Approximately(pivot, new Vector2(1f, 0.5f))) return InventoryUIAnchorPreset.MiddleRight;
|
|
if (Approximately(anchor, new Vector2(0f, 0f)) && Approximately(pivot, new Vector2(0f, 0f))) return InventoryUIAnchorPreset.BottomLeft;
|
|
if (Approximately(anchor, new Vector2(0.5f, 0f)) && Approximately(pivot, new Vector2(0.5f, 0f))) return InventoryUIAnchorPreset.BottomCenter;
|
|
if (Approximately(anchor, new Vector2(1f, 0f)) && Approximately(pivot, new Vector2(1f, 0f))) return InventoryUIAnchorPreset.BottomRight;
|
|
|
|
return InventoryUIAnchorPreset.Custom;
|
|
}
|
|
|
|
private bool Approximately(Vector2 a, Vector2 b)
|
|
{
|
|
return Mathf.Abs(a.x - b.x) <= 0.0001f && Mathf.Abs(a.y - b.y) <= 0.0001f;
|
|
}
|
|
|
|
private void MarkControllerDirty()
|
|
{
|
|
#if UNITY_EDITOR
|
|
if (!Application.isPlaying)
|
|
{
|
|
EditorUtility.SetDirty(this);
|
|
PrefabUtility.RecordPrefabInstancePropertyModifications(this);
|
|
UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(gameObject.scene);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
private void ConfigureRootCanvas()
|
|
{
|
|
RectTransform rootRect = GetComponent<RectTransform>();
|
|
if (rootRect != null)
|
|
{
|
|
rootRect.sizeDelta = rootCanvasSize;
|
|
if (applyRootWorldScale)
|
|
rootRect.localScale = rootWorldScale;
|
|
}
|
|
|
|
Canvas canvas = GetComponent<Canvas>();
|
|
if (canvas != null)
|
|
canvas.renderMode = RenderMode.WorldSpace;
|
|
}
|
|
|
|
private void ApplyKnownLayout()
|
|
{
|
|
ApplyRect(inventoryPanel, InventoryUIAnchorPreset.MiddleCenter, inventoryPanelSize, inventoryPanelPos);
|
|
ApplyRect(titleText, InventoryUIAnchorPreset.TopCenter, titleTextSize, titleTextPos);
|
|
ApplyRect(closeButton, InventoryUIAnchorPreset.TopRight, closeButtonSize, closeButtonPos);
|
|
ApplyRect(categoryButtons, InventoryUIAnchorPreset.TopCenter, categoryButtonsSize, categoryButtonsPos);
|
|
ApplyRect(memoryProgressArea, InventoryUIAnchorPreset.TopCenter, memoryProgressAreaSize, memoryProgressAreaPos);
|
|
ApplyRect(slotContainer, InventoryUIAnchorPreset.MiddleCenter, slotContainerSize, slotContainerPos);
|
|
ApplyRect(recentLogArea, InventoryUIAnchorPreset.BottomLeft, recentLogSize, recentLogPos);
|
|
ApplyRect(debugPanel, InventoryUIAnchorPreset.BottomRight, debugPanelSize, debugPanelPos);
|
|
ApplyRect(quickUseButtons, InventoryUIAnchorPreset.MiddleRight, quickUseButtonsSize, quickUseButtonsPos);
|
|
ApplyRect(tooltipPanel, InventoryUIAnchorPreset.BottomCenter, tooltipPanelSize, tooltipPanelPos);
|
|
ApplyRect(acquisitionPopupPanel, InventoryUIAnchorPreset.TopCenter, acquisitionPopupSize, acquisitionPopupPos);
|
|
ApplyRect(messagePanel, InventoryUIAnchorPreset.BottomCenter, messagePanelSize, messagePanelPos);
|
|
ApplyRect(confirmationPanel, InventoryUIAnchorPreset.MiddleCenter, confirmationPanelSize, confirmationPanelPos);
|
|
ApplyRect(detailPanel, InventoryUIAnchorPreset.MiddleRight, detailPanelSize, detailPanelPos);
|
|
|
|
ConfigureKnownLayoutGroups();
|
|
}
|
|
|
|
private void ConfigureKnownLayoutGroups()
|
|
{
|
|
if (slotContainer != null)
|
|
{
|
|
GridLayoutGroup grid = GetOrAdd<GridLayoutGroup>(slotContainer.gameObject);
|
|
ConfigureGrid(grid, slotCellSize, slotSpacing, GridLayoutGroup.Constraint.FixedColumnCount, slotColumnCount, TextAnchor.MiddleCenter, new InventoryLayoutPadding(0, 0, 0, 0));
|
|
}
|
|
|
|
if (debugPanel != null)
|
|
{
|
|
GridLayoutGroup grid = GetOrAdd<GridLayoutGroup>(debugPanel.gameObject);
|
|
ConfigureGrid(grid, debugButtonCellSize, debugButtonSpacing, GridLayoutGroup.Constraint.FixedColumnCount, debugButtonColumnCount, TextAnchor.MiddleCenter, new InventoryLayoutPadding(0, 0, 0, 0));
|
|
}
|
|
|
|
ConfigureQuickUseButtonsLayout();
|
|
}
|
|
|
|
private void ConfigureQuickUseButtonsLayout()
|
|
{
|
|
if (quickUseButtons == null)
|
|
return;
|
|
|
|
// Unity UI는 한 GameObject에 LayoutGroup을 하나만 붙일 수 있습니다.
|
|
// QuickUseButtons에 이미 GridLayoutGroup이 있으면 VerticalLayoutGroup을 추가하지 않고 GridLayoutGroup을 그대로 설정합니다.
|
|
VerticalLayoutGroup vertical = quickUseButtons.GetComponent<VerticalLayoutGroup>();
|
|
if (vertical != null)
|
|
{
|
|
vertical.childAlignment = TextAnchor.MiddleCenter;
|
|
vertical.spacing = quickUseButtonSpacing.y;
|
|
vertical.childControlWidth = true;
|
|
vertical.childControlHeight = true;
|
|
vertical.childForceExpandWidth = false;
|
|
vertical.childForceExpandHeight = false;
|
|
return;
|
|
}
|
|
|
|
GridLayoutGroup grid = quickUseButtons.GetComponent<GridLayoutGroup>();
|
|
if (grid != null)
|
|
{
|
|
ConfigureGrid(grid, quickUseButtonCellSize, quickUseButtonSpacing, GridLayoutGroup.Constraint.FixedColumnCount, 1, TextAnchor.MiddleCenter, new InventoryLayoutPadding(0, 0, 0, 0));
|
|
return;
|
|
}
|
|
|
|
LayoutGroup existingLayoutGroup = quickUseButtons.GetComponent<LayoutGroup>();
|
|
if (existingLayoutGroup != null)
|
|
{
|
|
Debug.LogWarning($"[InventoryUILayoutController] QuickUseButtons에 지원하지 않는 LayoutGroup({existingLayoutGroup.GetType().Name})이 이미 있습니다. 자동 배치를 건너뜁니다.", quickUseButtons);
|
|
return;
|
|
}
|
|
|
|
VerticalLayoutGroup added = quickUseButtons.gameObject.AddComponent<VerticalLayoutGroup>();
|
|
if (added == null)
|
|
return;
|
|
|
|
added.childAlignment = TextAnchor.MiddleCenter;
|
|
added.spacing = quickUseButtonSpacing.y;
|
|
added.childControlWidth = true;
|
|
added.childControlHeight = true;
|
|
added.childForceExpandWidth = false;
|
|
added.childForceExpandHeight = false;
|
|
}
|
|
|
|
private void ArrangeSlotChildren()
|
|
{
|
|
if (slots == null || slots.Length == 0)
|
|
slots = GetComponentsInChildren<InventorySlotUI>(true);
|
|
|
|
foreach (InventorySlotUI slot in slots)
|
|
{
|
|
if (slot == null)
|
|
continue;
|
|
|
|
RectTransform slotRect = slot.GetComponent<RectTransform>();
|
|
if (slotRect != null && resetChildScaleToOne)
|
|
slotRect.localScale = Vector3.one;
|
|
|
|
RectTransform icon = FindChildRect(slot.transform, "Icon");
|
|
RectTransform count = FindChildRect(slot.transform, "CountText");
|
|
RectTransform newBadge = FindChildRect(slot.transform, "NewBadge");
|
|
RectTransform importantGlow = FindChildRect(slot.transform, "ImportantGlow");
|
|
RectTransform filteredOverlay = FindChildRect(slot.transform, "FilteredOutOverlay");
|
|
|
|
ApplyRect(icon, InventoryUIAnchorPreset.MiddleCenter, slotIconSize, slotIconPos);
|
|
ApplyRect(count, InventoryUIAnchorPreset.BottomCenter, slotCountTextSize, slotCountTextPos);
|
|
ApplyRect(newBadge, InventoryUIAnchorPreset.TopRight, slotNewBadgeSize, slotNewBadgePos);
|
|
ApplyStretch(importantGlow, new Vector2(-4f, -4f), new Vector2(4f, 4f));
|
|
ApplyStretch(filteredOverlay, Vector2.zero, Vector2.zero);
|
|
}
|
|
}
|
|
|
|
private void ApplyControlledRectTargets()
|
|
{
|
|
if (controlledRects == null)
|
|
return;
|
|
|
|
foreach (InventoryControlledRectTarget target in controlledRects)
|
|
{
|
|
if (target == null)
|
|
continue;
|
|
|
|
RectTransform rect = target.rectTransform;
|
|
if (rect == null)
|
|
continue;
|
|
|
|
if (target.applyRect)
|
|
ApplyRect(rect, target.anchorPreset, target.size, target.anchoredPosition, target.customAnchorMin, target.customAnchorMax, target.customPivot);
|
|
|
|
if (target.resetScaleToOne)
|
|
rect.localScale = Vector3.one;
|
|
|
|
if (target.applyLocalScale)
|
|
rect.localScale = target.localScale;
|
|
|
|
if (target.applyLocalRotation)
|
|
rect.localEulerAngles = target.localEulerAngles;
|
|
|
|
if (target.applySiblingIndex)
|
|
rect.SetSiblingIndex(Mathf.Max(0, target.siblingIndex));
|
|
|
|
if (target.applyCanvasGroup)
|
|
{
|
|
CanvasGroup group = target.addCanvasGroupIfMissing ? GetOrAdd<CanvasGroup>(rect.gameObject) : rect.GetComponent<CanvasGroup>();
|
|
if (group != null)
|
|
{
|
|
group.alpha = target.canvasAlpha;
|
|
group.interactable = target.canvasInteractable;
|
|
group.blocksRaycasts = target.canvasBlocksRaycasts;
|
|
}
|
|
}
|
|
|
|
if (target.applySelfImageRaycast)
|
|
{
|
|
Image image = rect.GetComponent<Image>();
|
|
if (image != null)
|
|
image.raycastTarget = target.selfImageRaycastTarget;
|
|
}
|
|
|
|
if (target.applyChildImageRaycasts)
|
|
{
|
|
foreach (Image image in rect.GetComponentsInChildren<Image>(true))
|
|
{
|
|
if (target.preserveButtonImageRaycasts && image.GetComponentInParent<Button>() != null)
|
|
continue;
|
|
|
|
image.raycastTarget = target.childImageRaycastTarget;
|
|
}
|
|
}
|
|
|
|
if (target.applyChildTextRaycasts)
|
|
{
|
|
foreach (TMP_Text text in rect.GetComponentsInChildren<TMP_Text>(true))
|
|
text.raycastTarget = target.childTextRaycastTarget;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ApplyControlledTextTargets()
|
|
{
|
|
if (controlledTexts == null)
|
|
return;
|
|
|
|
foreach (InventoryControlledTextTarget target in controlledTexts)
|
|
{
|
|
if (target == null || target.text == null)
|
|
continue;
|
|
|
|
RectTransform rect = target.text.rectTransform;
|
|
if (target.applyRect)
|
|
ApplyRect(rect, target.anchorPreset, target.size, target.anchoredPosition, target.customAnchorMin, target.customAnchorMax, target.customPivot);
|
|
|
|
if (target.resetScaleToOne && rect != null)
|
|
rect.localScale = Vector3.one;
|
|
|
|
if (target.applyFontSize)
|
|
target.text.fontSize = target.fontSize;
|
|
|
|
if (target.applyAlignment)
|
|
target.text.alignment = target.alignment;
|
|
|
|
if (target.applyColor)
|
|
target.text.color = target.color;
|
|
|
|
if (target.applyRaycastTarget)
|
|
target.text.raycastTarget = target.raycastTarget;
|
|
|
|
if (target.applyOutline)
|
|
ApplyOutline(target.text.gameObject, target.outlineColor, target.outlineEffectDistance, target.outlineUseGraphicAlpha, target.addOutlineIfMissing);
|
|
|
|
if (target.applyShadow)
|
|
ApplyShadow(target.text.gameObject, target.shadowColor, target.shadowEffectDistance, target.shadowUseGraphicAlpha, target.addShadowIfMissing);
|
|
}
|
|
}
|
|
|
|
private void ApplyControlledImageTargets()
|
|
{
|
|
if (controlledImages == null)
|
|
return;
|
|
|
|
foreach (InventoryControlledImageTarget target in controlledImages)
|
|
{
|
|
if (target == null || target.image == null)
|
|
continue;
|
|
|
|
RectTransform rect = target.image.rectTransform;
|
|
if (target.applyRect)
|
|
ApplyRect(rect, target.anchorPreset, target.size, target.anchoredPosition, target.customAnchorMin, target.customAnchorMax, target.customPivot);
|
|
|
|
if (target.resetScaleToOne && rect != null)
|
|
rect.localScale = Vector3.one;
|
|
|
|
if (target.applyColor)
|
|
target.image.color = target.color;
|
|
|
|
if (target.applySprite)
|
|
target.image.sprite = target.sprite;
|
|
|
|
if (target.applyRaycastTarget)
|
|
target.image.raycastTarget = target.raycastTarget;
|
|
|
|
if (target.applyOutline)
|
|
ApplyOutline(target.image.gameObject, target.outlineColor, target.outlineEffectDistance, target.outlineUseGraphicAlpha, target.addOutlineIfMissing);
|
|
|
|
if (target.applyShadow)
|
|
ApplyShadow(target.image.gameObject, target.shadowColor, target.shadowEffectDistance, target.shadowUseGraphicAlpha, target.addShadowIfMissing);
|
|
}
|
|
}
|
|
|
|
private void ApplyControlledButtonTargets()
|
|
{
|
|
if (controlledButtons == null)
|
|
return;
|
|
|
|
foreach (InventoryControlledButtonTarget target in controlledButtons)
|
|
{
|
|
if (target == null || target.button == null)
|
|
continue;
|
|
|
|
RectTransform rect = target.button.GetComponent<RectTransform>();
|
|
if (target.applyRect)
|
|
ApplyRect(rect, target.anchorPreset, target.size, target.anchoredPosition, target.customAnchorMin, target.customAnchorMax, target.customPivot);
|
|
|
|
if (target.resetScaleToOne && rect != null)
|
|
rect.localScale = Vector3.one;
|
|
|
|
if (target.applyInteractable)
|
|
target.button.interactable = target.interactable;
|
|
|
|
if (target.applyImageRaycastTarget)
|
|
{
|
|
Image image = target.button.GetComponent<Image>();
|
|
if (image != null)
|
|
image.raycastTarget = target.imageRaycastTarget;
|
|
}
|
|
|
|
if (target.applyButtonColors)
|
|
ApplyButtonColorBlock(target.button, target.normalColor, target.highlightedColor, target.pressedColor, target.selectedColor, target.disabledColor, target.colorMultiplier, target.fadeDuration);
|
|
|
|
if (target.disableChildTextRaycasts)
|
|
{
|
|
foreach (TMP_Text text in target.button.GetComponentsInChildren<TMP_Text>(true))
|
|
text.raycastTarget = false;
|
|
}
|
|
|
|
if (target.applyOutline)
|
|
ApplyOutline(target.button.gameObject, target.outlineColor, target.outlineEffectDistance, target.outlineUseGraphicAlpha, target.addOutlineIfMissing);
|
|
|
|
if (target.applyShadow)
|
|
ApplyShadow(target.button.gameObject, target.shadowColor, target.shadowEffectDistance, target.shadowUseGraphicAlpha, target.addShadowIfMissing);
|
|
}
|
|
}
|
|
|
|
private void ApplyControlledGridLayoutTargets()
|
|
{
|
|
if (controlledGridLayouts == null)
|
|
return;
|
|
|
|
foreach (InventoryControlledGridLayoutTarget target in controlledGridLayouts)
|
|
{
|
|
if (target == null || target.grid == null || !target.applyGrid)
|
|
continue;
|
|
|
|
ConfigureGrid(target.grid, target.cellSize, target.spacing, target.constraint, target.constraintCount, target.childAlignment, target.padding);
|
|
}
|
|
}
|
|
|
|
[ContextMenu("Inventory UI/Apply Basic Visual Theme")]
|
|
public void ApplyBasicVisualTheme()
|
|
{
|
|
if (styleKnownPanels)
|
|
ApplyKnownPanelTheme();
|
|
|
|
if (styleKnownButtons)
|
|
ApplyKnownButtonTheme();
|
|
|
|
if (styleKnownTexts)
|
|
ApplyKnownTextTheme();
|
|
|
|
if (styleKnownSlots)
|
|
ApplyKnownSlotTheme();
|
|
}
|
|
|
|
private void ApplyKnownPanelTheme()
|
|
{
|
|
ApplyImageColor(inventoryPanel, mainPanelColor, false);
|
|
ApplyImageColor(recentLogArea, subPanelColor, false);
|
|
ApplyImageColor(debugPanel, subPanelColor, false);
|
|
ApplyImageColor(tooltipPanel, popupPanelColor, false);
|
|
ApplyImageColor(acquisitionPopupPanel, popupPanelColor, false);
|
|
ApplyImageColor(messagePanel, popupPanelColor, false);
|
|
ApplyImageColor(confirmationPanel, popupPanelColor, true);
|
|
ApplyImageColor(detailPanel, popupPanelColor, true);
|
|
ApplyImageColor(memoryProgressArea, new Color(subPanelColor.r, subPanelColor.g, subPanelColor.b, Mathf.Min(subPanelColor.a, 0.55f)), false);
|
|
|
|
if (addOutlineToKnownGraphics)
|
|
{
|
|
ApplyOutline(inventoryPanel != null ? inventoryPanel.gameObject : null, outlineColor, new Vector2(2f, -2f), true, true);
|
|
ApplyOutline(recentLogArea != null ? recentLogArea.gameObject : null, outlineColor, new Vector2(1f, -1f), true, true);
|
|
ApplyOutline(debugPanel != null ? debugPanel.gameObject : null, outlineColor, new Vector2(1f, -1f), true, true);
|
|
ApplyOutline(detailPanel != null ? detailPanel.gameObject : null, goldOutlineColor, new Vector2(1.5f, -1.5f), true, true);
|
|
ApplyOutline(confirmationPanel != null ? confirmationPanel.gameObject : null, goldOutlineColor, new Vector2(1.5f, -1.5f), true, true);
|
|
}
|
|
}
|
|
|
|
private void ApplyKnownButtonTheme()
|
|
{
|
|
ApplyButtonTheme(closeButton != null ? closeButton.GetComponent<Button>() : null, buttonNormalColor, false);
|
|
ApplyButtonsIn(categoryButtons, buttonNormalColor, false);
|
|
ApplyButtonsIn(detailPanel, buttonNormalColor, false);
|
|
ApplyButtonsIn(confirmationPanel, buttonNormalColor, false);
|
|
ApplyButtonsIn(quickUseButtons, buttonNormalColor, false);
|
|
ApplyButtonsIn(debugPanel, debugButtonColor, true);
|
|
}
|
|
|
|
private void ApplyButtonsIn(RectTransform root, Color baseColor, bool allowDangerColor)
|
|
{
|
|
if (root == null)
|
|
return;
|
|
|
|
Button[] buttons = root.GetComponentsInChildren<Button>(true);
|
|
foreach (Button button in buttons)
|
|
ApplyButtonTheme(button, baseColor, allowDangerColor);
|
|
}
|
|
|
|
private void ApplyButtonTheme(Button button, Color baseColor, bool allowDangerColor)
|
|
{
|
|
if (button == null)
|
|
return;
|
|
|
|
Color chosenNormal = baseColor;
|
|
if (allowDangerColor && IsDangerButton(button))
|
|
chosenNormal = dangerButtonColor;
|
|
|
|
ColorBlock colors = button.colors;
|
|
colors.normalColor = chosenNormal;
|
|
colors.highlightedColor = buttonHighlightedColor;
|
|
colors.pressedColor = buttonPressedColor;
|
|
colors.selectedColor = buttonSelectedColor;
|
|
colors.disabledColor = buttonDisabledColor;
|
|
colors.colorMultiplier = 1f;
|
|
colors.fadeDuration = 0.1f;
|
|
button.colors = colors;
|
|
|
|
Image image = button.GetComponent<Image>();
|
|
if (image != null)
|
|
{
|
|
image.color = chosenNormal;
|
|
image.raycastTarget = true;
|
|
}
|
|
|
|
if (addOutlineToKnownGraphics)
|
|
ApplyOutline(button.gameObject, outlineColor, new Vector2(1f, -1f), true, true);
|
|
|
|
TMP_Text[] texts = button.GetComponentsInChildren<TMP_Text>(true);
|
|
foreach (TMP_Text text in texts)
|
|
{
|
|
text.color = mainTextColor;
|
|
text.raycastTarget = false;
|
|
|
|
if (addShadowToKnownTexts)
|
|
ApplyShadow(text.gameObject, shadowColor, new Vector2(1.5f, -1.5f), true, true);
|
|
}
|
|
}
|
|
|
|
private bool IsDangerButton(Button button)
|
|
{
|
|
if (button == null)
|
|
return false;
|
|
|
|
string lowerName = button.name.ToLowerInvariant();
|
|
if (lowerName.Contains("delete") || lowerName.Contains("reset") || lowerName.Contains("clear"))
|
|
return true;
|
|
|
|
TMP_Text[] texts = button.GetComponentsInChildren<TMP_Text>(true);
|
|
foreach (TMP_Text text in texts)
|
|
{
|
|
if (text == null || string.IsNullOrEmpty(text.text))
|
|
continue;
|
|
|
|
if (text.text.Contains("삭제") || text.text.Contains("초기화") || text.text.Contains("저장삭제"))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void ApplyKnownTextTheme()
|
|
{
|
|
TMP_Text[] texts = GetComponentsInChildren<TMP_Text>(true);
|
|
foreach (TMP_Text text in texts)
|
|
{
|
|
if (text == null)
|
|
continue;
|
|
|
|
text.raycastTarget = false;
|
|
text.color = IsAccentText(text) ? accentTextColor : mainTextColor;
|
|
|
|
if (IsMutedText(text))
|
|
text.color = mutedTextColor;
|
|
|
|
if (addShadowToKnownTexts)
|
|
ApplyShadow(text.gameObject, shadowColor, new Vector2(1.5f, -1.5f), true, true);
|
|
}
|
|
}
|
|
|
|
private bool IsAccentText(TMP_Text text)
|
|
{
|
|
if (text == null)
|
|
return false;
|
|
|
|
string lowerName = text.name.ToLowerInvariant();
|
|
return text.rectTransform == titleText || lowerName.Contains("title") || lowerName.Contains("goal") || lowerName.Contains("new");
|
|
}
|
|
|
|
private bool IsMutedText(TMP_Text text)
|
|
{
|
|
if (text == null)
|
|
return false;
|
|
|
|
string lowerName = text.name.ToLowerInvariant();
|
|
return lowerName.Contains("description") || lowerName.Contains("desc") || lowerName.Contains("count") || lowerName.Contains("log");
|
|
}
|
|
|
|
private void ApplyKnownSlotTheme()
|
|
{
|
|
if (slots == null || slots.Length == 0)
|
|
slots = GetComponentsInChildren<InventorySlotUI>(true);
|
|
|
|
foreach (InventorySlotUI slot in slots)
|
|
{
|
|
if (slot == null)
|
|
continue;
|
|
|
|
Image slotImage = slot.GetComponent<Image>();
|
|
if (slotImage != null)
|
|
{
|
|
slotImage.color = slotColor;
|
|
slotImage.raycastTarget = true;
|
|
}
|
|
|
|
if (addOutlineToKnownGraphics)
|
|
ApplyOutline(slot.gameObject, outlineColor, new Vector2(1f, -1f), true, true);
|
|
|
|
foreach (Transform child in slot.GetComponentsInChildren<Transform>(true))
|
|
{
|
|
if (child == null || child == slot.transform)
|
|
continue;
|
|
|
|
string lowerName = child.name.ToLowerInvariant();
|
|
Image image = child.GetComponent<Image>();
|
|
TMP_Text text = child.GetComponent<TMP_Text>();
|
|
|
|
if (image != null)
|
|
{
|
|
if (lowerName.Contains("glow") || lowerName.Contains("important"))
|
|
image.color = slotImportantGlowColor;
|
|
else if (lowerName.Contains("new"))
|
|
image.color = newBadgeColor;
|
|
else if (lowerName.Contains("overlay") || lowerName.Contains("filter"))
|
|
image.color = filteredOverlayColor;
|
|
|
|
image.raycastTarget = false;
|
|
}
|
|
|
|
if (text != null)
|
|
{
|
|
text.color = lowerName.Contains("new") ? new Color(0.08f, 0.06f, 0.02f, 1f) : mainTextColor;
|
|
text.raycastTarget = false;
|
|
|
|
if (addShadowToKnownTexts)
|
|
ApplyShadow(text.gameObject, shadowColor, new Vector2(1.2f, -1.2f), true, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[ContextMenu("Inventory UI/Apply Initial Mode")]
|
|
public void ApplyInitialMode()
|
|
{
|
|
ApplyMode(initialMode);
|
|
}
|
|
|
|
[ContextMenu("Inventory UI/Apply Test Mode")]
|
|
public void ApplyTestMode() => ApplyMode(InventoryRootUIMode.TestMode);
|
|
|
|
[ContextMenu("Inventory UI/Apply Play Mode")]
|
|
public void ApplyPlayMode() => ApplyMode(InventoryRootUIMode.PlayMode);
|
|
|
|
[ContextMenu("Inventory UI/Apply Build Mode")]
|
|
public void ApplyBuildMode() => ApplyMode(InventoryRootUIMode.BuildMode);
|
|
|
|
[ContextMenu("Inventory UI/Apply Hidden Mode")]
|
|
public void ApplyHiddenMode() => ApplyMode(InventoryRootUIMode.HiddenMode);
|
|
|
|
public void ApplyMode(InventoryRootUIMode mode)
|
|
{
|
|
if (mode == InventoryRootUIMode.LayoutOnly)
|
|
return;
|
|
|
|
switch (mode)
|
|
{
|
|
case InventoryRootUIMode.TestMode:
|
|
SetActive(inventoryPanel, testShowInventoryPanel);
|
|
SetActive(debugPanel, testShowDebugPanel);
|
|
SetActive(recentLogArea, testShowRecentLogArea);
|
|
SetActive(categoryButtons, testShowCategoryButtons);
|
|
SetActive(memoryProgressArea, testShowMemoryProgressArea);
|
|
SetActive(quickUseButtons, testShowQuickUseButtons);
|
|
HideAllPopups();
|
|
break;
|
|
|
|
case InventoryRootUIMode.PlayMode:
|
|
SetActive(inventoryPanel, playShowInventoryPanel);
|
|
SetActive(debugPanel, playShowDebugPanel);
|
|
SetActive(recentLogArea, playShowRecentLogArea);
|
|
SetActive(categoryButtons, playShowCategoryButtons);
|
|
SetActive(memoryProgressArea, playShowMemoryProgressArea);
|
|
SetActive(quickUseButtons, playShowQuickUseButtons);
|
|
HideAllPopups();
|
|
break;
|
|
|
|
case InventoryRootUIMode.BuildMode:
|
|
SetActive(inventoryPanel, buildShowInventoryPanel);
|
|
SetActive(debugPanel, buildShowDebugPanel);
|
|
SetActive(recentLogArea, buildShowRecentLogArea);
|
|
SetActive(categoryButtons, buildShowCategoryButtons);
|
|
SetActive(memoryProgressArea, buildShowMemoryProgressArea);
|
|
SetActive(quickUseButtons, buildShowQuickUseButtons);
|
|
HideAllPopups();
|
|
break;
|
|
|
|
case InventoryRootUIMode.HiddenMode:
|
|
SetActive(inventoryPanel, false);
|
|
SetActive(debugPanel, false);
|
|
SetActive(recentLogArea, false);
|
|
SetActive(categoryButtons, false);
|
|
SetActive(memoryProgressArea, false);
|
|
SetActive(quickUseButtons, false);
|
|
HideAllPopups();
|
|
break;
|
|
}
|
|
|
|
ApplyControlledActiveStates(mode);
|
|
}
|
|
|
|
private void ApplyControlledActiveStates(InventoryRootUIMode mode)
|
|
{
|
|
if (controlledRects == null)
|
|
return;
|
|
|
|
foreach (InventoryControlledRectTarget target in controlledRects)
|
|
{
|
|
if (target == null || !target.controlActiveState)
|
|
continue;
|
|
|
|
GameObject go = target.activeTarget != null ? target.activeTarget : target.rectTransform != null ? target.rectTransform.gameObject : null;
|
|
if (go == null)
|
|
continue;
|
|
|
|
bool active = true;
|
|
switch (mode)
|
|
{
|
|
case InventoryRootUIMode.TestMode:
|
|
active = target.activeInTestMode;
|
|
break;
|
|
case InventoryRootUIMode.PlayMode:
|
|
active = target.activeInPlayMode;
|
|
break;
|
|
case InventoryRootUIMode.BuildMode:
|
|
active = target.activeInBuildMode;
|
|
break;
|
|
case InventoryRootUIMode.HiddenMode:
|
|
active = target.activeInHiddenMode;
|
|
break;
|
|
}
|
|
|
|
go.SetActive(active);
|
|
}
|
|
}
|
|
|
|
[ContextMenu("Inventory UI/Hide All Popups")]
|
|
public void HideAllPopups()
|
|
{
|
|
SetActive(tooltipPanel, false);
|
|
SetActive(acquisitionPopupPanel, false);
|
|
SetActive(messagePanel, false);
|
|
SetActive(confirmationPanel, false);
|
|
SetActive(detailPanel, false);
|
|
|
|
if (extraPopupPanelsToHide != null)
|
|
{
|
|
foreach (GameObject panel in extraPopupPanelsToHide)
|
|
{
|
|
if (panel != null)
|
|
panel.SetActive(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
[ContextMenu("Inventory UI/Show Inventory Panel")]
|
|
public void ShowInventoryPanel() => SetActive(inventoryPanel, true);
|
|
|
|
[ContextMenu("Inventory UI/Hide Inventory Panel")]
|
|
public void HideInventoryPanel() => SetActive(inventoryPanel, false);
|
|
|
|
[ContextMenu("Inventory UI/Show Debug Panel")]
|
|
public void ShowDebugPanel() => SetActive(debugPanel, true);
|
|
|
|
[ContextMenu("Inventory UI/Hide Debug Panel")]
|
|
public void HideDebugPanel() => SetActive(debugPanel, false);
|
|
|
|
[ContextMenu("Inventory UI/Toggle Debug Panel")]
|
|
public void ToggleDebugPanel()
|
|
{
|
|
if (debugPanel != null)
|
|
debugPanel.gameObject.SetActive(!debugPanel.gameObject.activeSelf);
|
|
}
|
|
|
|
|
|
[ContextMenu("Inventory UI/Check Setup")]
|
|
public void CheckSetup()
|
|
{
|
|
if (inventoryUI == null)
|
|
Debug.LogWarning("[InventoryUILayoutController] InventoryUI가 연결되어 있지 않습니다.", this);
|
|
|
|
if (inventoryPanel == null)
|
|
Debug.LogWarning("[InventoryUILayoutController] InventoryPanel이 연결되어 있지 않습니다.", this);
|
|
|
|
if (slots == null || slots.Length == 0)
|
|
Debug.LogWarning("[InventoryUILayoutController] Slots 배열이 비어 있습니다.", this);
|
|
|
|
if (tooltipPanel != null)
|
|
{
|
|
CanvasGroup group = tooltipPanel.GetComponent<CanvasGroup>();
|
|
if (group != null && group.blocksRaycasts)
|
|
Debug.LogWarning("[InventoryUILayoutController] TooltipPanel CanvasGroup Blocks Raycasts가 켜져 있습니다. 슬롯 Hover 흔들림 원인이 될 수 있습니다.", tooltipPanel);
|
|
}
|
|
|
|
Slider[] sliders = GetComponentsInChildren<Slider>(true);
|
|
foreach (Slider slider in sliders)
|
|
{
|
|
if (slider != null && slider.interactable)
|
|
Debug.LogWarning($"[InventoryUILayoutController] Slider '{slider.name}'의 Interactable이 켜져 있습니다. 진행도 표시용이면 꺼두는 것을 권장합니다.", slider);
|
|
}
|
|
|
|
if (debugPanel != null && buildShowDebugPanel)
|
|
Debug.LogWarning("[InventoryUILayoutController] BuildMode에서도 DebugPanel이 보이도록 설정되어 있습니다.", debugPanel);
|
|
}
|
|
|
|
[ContextMenu("Inventory UI/Fix All Raycast Targets")]
|
|
public void FixAllRaycastTargets()
|
|
{
|
|
if (disableTextRaycasts)
|
|
{
|
|
TMP_Text[] texts = GetComponentsInChildren<TMP_Text>(true);
|
|
foreach (TMP_Text text in texts)
|
|
text.raycastTarget = false;
|
|
}
|
|
|
|
if (disableNonInteractiveImageRaycasts)
|
|
{
|
|
Image[] images = GetComponentsInChildren<Image>(true);
|
|
foreach (Image image in images)
|
|
{
|
|
if (image == null)
|
|
continue;
|
|
|
|
Button buttonOnSameObject = image.GetComponent<Button>();
|
|
if (buttonOnSameObject != null)
|
|
{
|
|
image.raycastTarget = true;
|
|
continue;
|
|
}
|
|
|
|
InventorySlotUI slotOnSameObject = image.GetComponent<InventorySlotUI>();
|
|
if (slotOnSameObject != null)
|
|
{
|
|
image.raycastTarget = true;
|
|
continue;
|
|
}
|
|
|
|
image.raycastTarget = false;
|
|
}
|
|
}
|
|
|
|
if (fixCanvasGroups)
|
|
{
|
|
ConfigurePassiveCanvasGroup(tooltipPanel);
|
|
ConfigurePassiveCanvasGroup(acquisitionPopupPanel);
|
|
ConfigurePassiveCanvasGroup(messagePanel);
|
|
ConfigureInteractiveCanvasGroup(confirmationPanel);
|
|
ConfigureInteractiveCanvasGroup(detailPanel);
|
|
}
|
|
|
|
if (setSliderInteractableFalse)
|
|
FixSlidersForDisplayOnly();
|
|
|
|
if (setSlotHoverSafeValues)
|
|
ApplySlotHoverSettings();
|
|
}
|
|
|
|
|
|
private void ApplyImageColor(RectTransform rect, Color color, bool raycastTarget)
|
|
{
|
|
if (rect == null)
|
|
return;
|
|
|
|
Image image = rect.GetComponent<Image>();
|
|
if (image == null && autoAddMissingComponents)
|
|
image = rect.gameObject.AddComponent<Image>();
|
|
|
|
if (image == null)
|
|
return;
|
|
|
|
image.color = color;
|
|
image.raycastTarget = raycastTarget;
|
|
}
|
|
|
|
private void ApplyButtonColorBlock(Button button, Color normal, Color highlighted, Color pressed, Color selected, Color disabled, float multiplier, float fade)
|
|
{
|
|
if (button == null)
|
|
return;
|
|
|
|
ColorBlock colors = button.colors;
|
|
colors.normalColor = normal;
|
|
colors.highlightedColor = highlighted;
|
|
colors.pressedColor = pressed;
|
|
colors.selectedColor = selected;
|
|
colors.disabledColor = disabled;
|
|
colors.colorMultiplier = Mathf.Max(0f, multiplier);
|
|
colors.fadeDuration = Mathf.Max(0f, fade);
|
|
button.colors = colors;
|
|
|
|
Image image = button.GetComponent<Image>();
|
|
if (image != null)
|
|
image.color = normal;
|
|
}
|
|
|
|
private void ApplyOutline(GameObject target, Color color, Vector2 effectDistance, bool useGraphicAlpha, bool addIfMissing)
|
|
{
|
|
if (target == null)
|
|
return;
|
|
|
|
Outline outline = target.GetComponent<Outline>();
|
|
if (outline == null && addIfMissing)
|
|
outline = target.AddComponent<Outline>();
|
|
|
|
if (outline == null)
|
|
return;
|
|
|
|
outline.effectColor = color;
|
|
outline.effectDistance = effectDistance;
|
|
outline.useGraphicAlpha = useGraphicAlpha;
|
|
}
|
|
|
|
private void ApplyShadow(GameObject target, Color color, Vector2 effectDistance, bool useGraphicAlpha, bool addIfMissing)
|
|
{
|
|
if (target == null)
|
|
return;
|
|
|
|
Shadow shadow = GetPlainShadow(target);
|
|
if (shadow == null && addIfMissing)
|
|
shadow = target.AddComponent<Shadow>();
|
|
|
|
if (shadow == null)
|
|
return;
|
|
|
|
shadow.effectColor = color;
|
|
shadow.effectDistance = effectDistance;
|
|
shadow.useGraphicAlpha = useGraphicAlpha;
|
|
}
|
|
|
|
private Shadow GetPlainShadow(GameObject target)
|
|
{
|
|
if (target == null)
|
|
return null;
|
|
|
|
Shadow[] shadows = target.GetComponents<Shadow>();
|
|
foreach (Shadow shadow in shadows)
|
|
{
|
|
if (shadow != null && shadow.GetType() == typeof(Shadow))
|
|
return shadow;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private void FixSlidersForDisplayOnly()
|
|
{
|
|
Slider[] sliders = GetComponentsInChildren<Slider>(true);
|
|
foreach (Slider slider in sliders)
|
|
{
|
|
if (slider == null)
|
|
continue;
|
|
|
|
slider.interactable = false;
|
|
|
|
foreach (Graphic graphic in slider.GetComponentsInChildren<Graphic>(true))
|
|
{
|
|
if (graphic != null)
|
|
graphic.raycastTarget = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ApplySlotHoverSettings()
|
|
{
|
|
if (slots == null || slots.Length == 0)
|
|
slots = GetComponentsInChildren<InventorySlotUI>(true);
|
|
|
|
foreach (InventorySlotUI slot in slots)
|
|
{
|
|
if (slot == null)
|
|
continue;
|
|
|
|
slot.SetHoverSettings(slotUseHoverScale, slotHoverScale, slotBringToFrontOnHover);
|
|
}
|
|
}
|
|
|
|
private void ApplyRect(RectTransform rect, InventoryUIAnchorPreset preset, Vector2 size, Vector2 pos)
|
|
{
|
|
ApplyRect(rect, preset, size, pos, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f));
|
|
}
|
|
|
|
private void ApplyRect(RectTransform rect, InventoryUIAnchorPreset preset, Vector2 size, Vector2 pos, Vector2 customMin, Vector2 customMax, Vector2 customPivot)
|
|
{
|
|
if (rect == null)
|
|
return;
|
|
|
|
SetAnchorPreset(rect, preset, customMin, customMax, customPivot);
|
|
|
|
if (preset == InventoryUIAnchorPreset.StretchAll)
|
|
{
|
|
rect.offsetMin = Vector2.zero;
|
|
rect.offsetMax = Vector2.zero;
|
|
}
|
|
else
|
|
{
|
|
rect.sizeDelta = size;
|
|
rect.anchoredPosition = pos;
|
|
}
|
|
|
|
if (resetChildScaleToOne)
|
|
rect.localScale = Vector3.one;
|
|
}
|
|
|
|
private void ApplyStretch(RectTransform rect, Vector2 offsetMin, Vector2 offsetMax)
|
|
{
|
|
if (rect == null)
|
|
return;
|
|
|
|
rect.anchorMin = Vector2.zero;
|
|
rect.anchorMax = Vector2.one;
|
|
rect.pivot = new Vector2(0.5f, 0.5f);
|
|
rect.offsetMin = offsetMin;
|
|
rect.offsetMax = offsetMax;
|
|
|
|
if (resetChildScaleToOne)
|
|
rect.localScale = Vector3.one;
|
|
}
|
|
|
|
private void SetAnchorPreset(RectTransform rect, InventoryUIAnchorPreset preset, Vector2 customMin, Vector2 customMax, Vector2 customPivot)
|
|
{
|
|
switch (preset)
|
|
{
|
|
case InventoryUIAnchorPreset.TopLeft:
|
|
rect.anchorMin = rect.anchorMax = new Vector2(0f, 1f);
|
|
rect.pivot = new Vector2(0f, 1f);
|
|
break;
|
|
case InventoryUIAnchorPreset.TopCenter:
|
|
rect.anchorMin = rect.anchorMax = new Vector2(0.5f, 1f);
|
|
rect.pivot = new Vector2(0.5f, 1f);
|
|
break;
|
|
case InventoryUIAnchorPreset.TopRight:
|
|
rect.anchorMin = rect.anchorMax = new Vector2(1f, 1f);
|
|
rect.pivot = new Vector2(1f, 1f);
|
|
break;
|
|
case InventoryUIAnchorPreset.MiddleLeft:
|
|
rect.anchorMin = rect.anchorMax = new Vector2(0f, 0.5f);
|
|
rect.pivot = new Vector2(0f, 0.5f);
|
|
break;
|
|
case InventoryUIAnchorPreset.MiddleRight:
|
|
rect.anchorMin = rect.anchorMax = new Vector2(1f, 0.5f);
|
|
rect.pivot = new Vector2(1f, 0.5f);
|
|
break;
|
|
case InventoryUIAnchorPreset.BottomLeft:
|
|
rect.anchorMin = rect.anchorMax = new Vector2(0f, 0f);
|
|
rect.pivot = new Vector2(0f, 0f);
|
|
break;
|
|
case InventoryUIAnchorPreset.BottomCenter:
|
|
rect.anchorMin = rect.anchorMax = new Vector2(0.5f, 0f);
|
|
rect.pivot = new Vector2(0.5f, 0f);
|
|
break;
|
|
case InventoryUIAnchorPreset.BottomRight:
|
|
rect.anchorMin = rect.anchorMax = new Vector2(1f, 0f);
|
|
rect.pivot = new Vector2(1f, 0f);
|
|
break;
|
|
case InventoryUIAnchorPreset.StretchAll:
|
|
rect.anchorMin = Vector2.zero;
|
|
rect.anchorMax = Vector2.one;
|
|
rect.pivot = new Vector2(0.5f, 0.5f);
|
|
break;
|
|
case InventoryUIAnchorPreset.Custom:
|
|
rect.anchorMin = customMin;
|
|
rect.anchorMax = customMax;
|
|
rect.pivot = customPivot;
|
|
break;
|
|
default:
|
|
rect.anchorMin = rect.anchorMax = new Vector2(0.5f, 0.5f);
|
|
rect.pivot = new Vector2(0.5f, 0.5f);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void ConfigureGrid(GridLayoutGroup grid, Vector2 cell, Vector2 spacingValue, GridLayoutGroup.Constraint constraint, int count, TextAnchor alignment, InventoryLayoutPadding padding)
|
|
{
|
|
if (grid == null)
|
|
return;
|
|
|
|
grid.cellSize = cell;
|
|
grid.spacing = spacingValue;
|
|
grid.constraint = constraint;
|
|
grid.constraintCount = Mathf.Max(1, count);
|
|
grid.childAlignment = alignment;
|
|
grid.padding = padding != null ? padding.ToRectOffset() : new RectOffset(0, 0, 0, 0);
|
|
}
|
|
|
|
private CanvasGroup AddCanvasGroupIfNeeded(RectTransform rect, bool interactable, bool blocksRaycasts)
|
|
{
|
|
if (rect == null)
|
|
return null;
|
|
|
|
CanvasGroup group = GetOrAdd<CanvasGroup>(rect.gameObject);
|
|
group.interactable = interactable;
|
|
group.blocksRaycasts = blocksRaycasts;
|
|
return group;
|
|
}
|
|
|
|
private void ConfigurePassiveCanvasGroup(RectTransform rect)
|
|
{
|
|
CanvasGroup group = AddCanvasGroupIfNeeded(rect, false, false);
|
|
if (group != null)
|
|
group.alpha = 1f;
|
|
}
|
|
|
|
private void ConfigureInteractiveCanvasGroup(RectTransform rect)
|
|
{
|
|
CanvasGroup group = AddCanvasGroupIfNeeded(rect, true, true);
|
|
if (group != null)
|
|
group.alpha = 1f;
|
|
}
|
|
|
|
private T GetOrAdd<T>(GameObject target) where T : Component
|
|
{
|
|
if (target == null)
|
|
return null;
|
|
|
|
T component = target.GetComponent<T>();
|
|
if (component == null)
|
|
component = target.AddComponent<T>();
|
|
|
|
return component;
|
|
}
|
|
|
|
private void TryAddComponentByTypeName(GameObject target, string typeName)
|
|
{
|
|
if (target == null || string.IsNullOrWhiteSpace(typeName))
|
|
return;
|
|
|
|
Type type = Type.GetType(typeName);
|
|
if (type == null)
|
|
{
|
|
foreach (System.Reflection.Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
|
|
{
|
|
type = assembly.GetType(typeName);
|
|
if (type != null)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (type == null || !typeof(Component).IsAssignableFrom(type))
|
|
return;
|
|
|
|
if (target.GetComponent(type) == null)
|
|
target.AddComponent(type);
|
|
}
|
|
|
|
private RectTransform FindRectIfNull(RectTransform current, string objectName)
|
|
{
|
|
if (current != null)
|
|
return current;
|
|
|
|
Transform found = FindDeepChild(transform, objectName);
|
|
return found != null ? found.GetComponent<RectTransform>() : null;
|
|
}
|
|
|
|
private RectTransform FindChildRect(Transform parent, string objectName)
|
|
{
|
|
Transform found = FindDeepChild(parent, objectName);
|
|
return found != null ? found.GetComponent<RectTransform>() : null;
|
|
}
|
|
|
|
private Transform FindDeepChild(Transform parent, string objectName)
|
|
{
|
|
if (parent == null || string.IsNullOrWhiteSpace(objectName))
|
|
return null;
|
|
|
|
foreach (Transform child in parent)
|
|
{
|
|
if (child.name == objectName)
|
|
return child;
|
|
|
|
Transform result = FindDeepChild(child, objectName);
|
|
if (result != null)
|
|
return result;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private void SetActive(RectTransform rect, bool active)
|
|
{
|
|
if (rect != null)
|
|
rect.gameObject.SetActive(active);
|
|
}
|
|
|
|
private void AddControlledRect(string targetName, RectTransform rect, GameObject activeObject, InventoryUIAnchorPreset preset, Vector2 size, Vector2 pos, bool controlActive, bool testActive, bool playActive, bool buildActive, bool hiddenActive)
|
|
{
|
|
if (rect == null || ContainsRectTarget(rect))
|
|
return;
|
|
|
|
controlledRects.Add(new InventoryControlledRectTarget
|
|
{
|
|
name = targetName,
|
|
rectTransform = rect,
|
|
activeTarget = activeObject != null ? activeObject : rect.gameObject,
|
|
applyRect = true,
|
|
anchorPreset = preset,
|
|
size = size,
|
|
anchoredPosition = pos,
|
|
controlActiveState = controlActive,
|
|
activeInTestMode = testActive,
|
|
activeInPlayMode = playActive,
|
|
activeInBuildMode = buildActive,
|
|
activeInHiddenMode = hiddenActive,
|
|
resetScaleToOne = true
|
|
});
|
|
}
|
|
|
|
private void AddText(string targetName, TMP_Text text)
|
|
{
|
|
if (text == null || ContainsTextTarget(text))
|
|
return;
|
|
|
|
controlledTexts.Add(new InventoryControlledTextTarget
|
|
{
|
|
name = targetName,
|
|
text = text,
|
|
applyRect = false,
|
|
applyRaycastTarget = true,
|
|
raycastTarget = false,
|
|
resetScaleToOne = true
|
|
});
|
|
}
|
|
|
|
private void AddImage(string targetName, Image image)
|
|
{
|
|
if (image == null || ContainsImageTarget(image))
|
|
return;
|
|
|
|
bool shouldRaycast = image.GetComponent<Button>() != null || image.GetComponent<InventorySlotUI>() != null;
|
|
controlledImages.Add(new InventoryControlledImageTarget
|
|
{
|
|
name = targetName,
|
|
image = image,
|
|
applyRect = false,
|
|
applyRaycastTarget = true,
|
|
raycastTarget = shouldRaycast,
|
|
resetScaleToOne = true
|
|
});
|
|
}
|
|
|
|
private void AddButton(string targetName, Button button)
|
|
{
|
|
if (button == null || ContainsButtonTarget(button))
|
|
return;
|
|
|
|
controlledButtons.Add(new InventoryControlledButtonTarget
|
|
{
|
|
name = targetName,
|
|
button = button,
|
|
applyRect = false,
|
|
applyInteractable = false,
|
|
applyImageRaycastTarget = true,
|
|
imageRaycastTarget = true,
|
|
disableChildTextRaycasts = true,
|
|
resetScaleToOne = true
|
|
});
|
|
}
|
|
|
|
private void AddGrid(string targetName, GridLayoutGroup grid, Vector2 cellSize, Vector2 spacing, GridLayoutGroup.Constraint constraint, int count)
|
|
{
|
|
if (grid == null || ContainsGridTarget(grid))
|
|
return;
|
|
|
|
controlledGridLayouts.Add(new InventoryControlledGridLayoutTarget
|
|
{
|
|
name = targetName,
|
|
grid = grid,
|
|
applyGrid = true,
|
|
cellSize = cellSize,
|
|
spacing = spacing,
|
|
constraint = constraint,
|
|
constraintCount = count,
|
|
childAlignment = TextAnchor.MiddleCenter,
|
|
padding = new InventoryLayoutPadding(0, 0, 0, 0)
|
|
});
|
|
}
|
|
|
|
private bool ContainsRectTarget(RectTransform rect)
|
|
{
|
|
foreach (InventoryControlledRectTarget target in controlledRects)
|
|
{
|
|
if (target != null && target.rectTransform == rect)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool ContainsTextTarget(TMP_Text text)
|
|
{
|
|
foreach (InventoryControlledTextTarget target in controlledTexts)
|
|
{
|
|
if (target != null && target.text == text)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool ContainsImageTarget(Image image)
|
|
{
|
|
foreach (InventoryControlledImageTarget target in controlledImages)
|
|
{
|
|
if (target != null && target.image == image)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool ContainsButtonTarget(Button button)
|
|
{
|
|
foreach (InventoryControlledButtonTarget target in controlledButtons)
|
|
{
|
|
if (target != null && target.button == button)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool ContainsGridTarget(GridLayoutGroup grid)
|
|
{
|
|
foreach (InventoryControlledGridLayoutTarget target in controlledGridLayouts)
|
|
{
|
|
if (target != null && target.grid == grid)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void SetPrivateFieldIfExists(object target, string fieldName, object value)
|
|
{
|
|
if (target == null || string.IsNullOrWhiteSpace(fieldName))
|
|
return;
|
|
|
|
System.Reflection.FieldInfo field = target.GetType().GetField(fieldName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
|
|
if (field != null)
|
|
field.SetValue(target, value);
|
|
}
|
|
}
|