Danro/Assets/Scripts/UI/ButtonTextFocusColor.cs
Danil Iarosh cb2e83a596
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
feat(ui, prizes, spawners, editor): expand prize flow and add spawning/editor tooling
- доработан flow призовой витрины и связанного UI:
  добавлены `PrizeStandButtonView` и `RulesPrizeListPage`, обновлены
  `PrizeStandController`, `PrizeStandPrize`, `PrizeStandModal`,
  `PrizeStandSettingsModal`, `LevelPrizeSettingsModal`, `QRCodeSettingsModal`,
  `BalanceDisplay`, `ButtonTextFocusColor` и связанные prefab'ы,
  чтобы улучшить настройку, навигацию, отображение кнопок и prize flow
- расширена система настроек и сохранения значений:
  `OptionPicker` получил отдельный формат `ValueSelector`,
  обновлены `SettingsDatabase`, `SettingEntryDrawer`, `SettingUIItem`,
  `SettingsUIGenerator`, `ValueSelectorRow` и `MainSettingsDatabase.asset`,
  а сохранение option picker-значений, включая `gameplay.gameDifficulty`,
  исправлено и синхронизировано с остальными настройками
- добавлены универсальные спавнеры сущностей:
  реализованы `EntitySpawner` и `EntitySpawnerManager` с поддержкой
  весов префабов, точек спавна, заполнения по проценту, ограничений
  на количество и автоспавна при инициализации
- доработана логика игрового спавна и сложности:
  процент инициализационного спавна может зависеть от настройки
  `gameplay.gameDifficulty` с градациями 25/50/75/100,
  в одном цикле массового спавна повторно не используется та же точка,
  а gizmo спавнера теперь показывает только сами точки без линий
- упрощена работа в редакторе Unity и добавлены editor-инструменты:
  в `GameManager` лицензия пропускается при запуске в `UNITY_EDITOR`,
  а `HierarchySelectionCounter`, `HierarchySelectionCountOverlay`
  и `HierarchyBulkRenamerWindow` добавляют подсчет выделения,
  realtime overlay в `SceneView` и массовое переименование объектов
  по правилам нумерации из Unity Project Settings
- синхронизированы сцены, ресурсы и UI-ассеты под новый flow:
  обновлены `MainMenu`, `Level UI`, уровни `1-1` и `1-2`,
  строки настроек, кнопки, TMP/font assets, изображения UI,
  `prizes.json` и recovery-данные после правок интерфейса и логики
- очищены и переразложены часть внешних и служебных ресурсов:
  удалён пакет `Lava_Flowing_Shader`, переименованы/заменены
  отдельные UI-prefab'ы и добавлены сопутствующие проектные артефакты,
  которые сейчас используются обновлённой конфигурацией проекта
2026-04-28 14:05:05 +03:00

143 lines
3.6 KiB
C#

using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace RR.Common.UI
{
/// <summary>
/// Меняет цвет TMP-текста внутри кнопки при фокусе и наведении.
/// </summary>
public class ButtonTextFocusColor : MonoBehaviour, ISelectHandler, IDeselectHandler, IPointerEnterHandler, IPointerExitHandler
{
[SerializeField] private TextMeshProUGUI targetText;
[SerializeField] private Color normalColor = new(0f, 0.29411766f, 0.1882353f, 1f);
[SerializeField] private Color focusedColor = Color.white;
private Selectable _selectable;
private bool _isPointerInside;
private bool _lastFocusedState;
private bool _hasAppliedState;
private void Awake()
{
ResolveReferences();
RefreshVisualState(force: true);
}
private void OnEnable()
{
ResolveReferences();
RefreshVisualState(force: true);
}
private void OnDisable()
{
_isPointerInside = false;
_lastFocusedState = false;
_hasAppliedState = false;
ApplyTextColor(normalColor);
}
private void LateUpdate()
{
RefreshVisualState();
}
public void OnSelect(BaseEventData eventData)
{
RefreshVisualState(force: true);
}
public void OnDeselect(BaseEventData eventData)
{
RefreshVisualState(force: true);
}
public void OnPointerEnter(PointerEventData eventData)
{
_isPointerInside = true;
RefreshVisualState(force: true);
}
public void OnPointerExit(PointerEventData eventData)
{
_isPointerInside = false;
RefreshVisualState(force: true);
}
private void RefreshVisualState(bool force = false)
{
ResolveReferences();
bool isFocused = IsFocusedNow();
if (!force && _hasAppliedState && _lastFocusedState == isFocused)
{
return;
}
_lastFocusedState = isFocused;
_hasAppliedState = true;
ApplyTextColor(isFocused ? focusedColor : normalColor);
}
private bool IsFocusedNow()
{
if (!isActiveAndEnabled)
{
return false;
}
if (_selectable != null && (!_selectable.IsActive() || !_selectable.IsInteractable()))
{
return false;
}
bool isSelected = EventSystem.current != null
&& EventSystem.current.currentSelectedGameObject == gameObject;
return isSelected || _isPointerInside;
}
private void ApplyTextColor(Color color)
{
if (targetText == null)
{
return;
}
targetText.color = color;
}
private void ResolveReferences()
{
if (_selectable == null)
{
_selectable = GetComponent<Selectable>();
}
if (targetText == null)
{
targetText = GetComponentInChildren<TextMeshProUGUI>(true);
}
}
#if UNITY_EDITOR
private void Reset()
{
ResolveReferences();
}
private void OnValidate()
{
ResolveReferences();
if (!Application.isPlaying)
{
RefreshVisualState(force: true);
}
}
#endif
}
}