using System;
using System.Collections.Generic;
using UnityEditor.EditorTools;
using UnityEditor.ShortcutManagement;
using UnityEditor.Tilemaps.External;
using UnityEditor.Toolbars;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.Tilemaps
{
[UxmlElement]
internal partial class TilePaletteBrushPickElement : VisualElement
{
///
/// Factory for TilePaletteBrushPickElement.
///
[Obsolete("TilePaletteBrushPickElementFactory is deprecated and will be removed. Use UxmlElementAttribute instead.", false)]
public class TilePaletteBrushPickElementFactory : UxmlFactory {}
///
/// UxmlTraits for TilePaletteBrushPickElement.
///
[Obsolete("TilePaletteBrushPickElementUxmlTraits is deprecated and will be removed. Use UxmlElementAttribute instead.", false)]
public class TilePaletteBrushPickElementUxmlTraits : UxmlTraits {}
///
/// USS class name of elements of this type.
///
private static readonly string ussClassName = "unity-tilepalette-brushpick";
private static readonly string labelToolbarUssClassName = "unity-tilepalette-label-toolbar";
private static readonly string viewToolbarUssClassName = "unity-tilepalette-brushpick-view-toolbar";
private static readonly string lastUsedUssClassName = "unity-tilepalette-brushpick-lastused";
private static readonly string emptyViewUssClassName = "unity-tilepalette-brushpick-emptyview";
private static readonly string kTilePaletteBrushPickHideOnPickEditorPref = "TilePaletteBrushPickHideOnPick";
private static readonly string kTilePaletteBrushPickLastSelectionEditorPref = "TilePaletteBrushPickLastSelection";
private static readonly string kLastUsed = L10n.Tr("Last Picked");
private static readonly string kPersonal = L10n.Tr("Saved Picks");
private static readonly string kSizeSliderTooltip = L10n.Tr("Adjusts the size of the Picks");
private static readonly string kGridViewTooltip = L10n.Tr("View Picks in a Grid");
private static readonly string kListViewTooltip = L10n.Tr("View Picks in a List");
private static readonly string kListViewNameColumn = L10n.Tr("Name");
private static readonly string kListViewTypeColumn = L10n.Tr("Type");
private static readonly string kEmptyViewSaveBrushPickText = L10n.Tr("To save a Brush Pick: ");
private static readonly string kEmptyViewSaveBrushPickText1 = L10n.Tr("\u2022Activate the Pick Tool ");
private static readonly string kEmptyViewSaveBrushPickText2 = L10n.Tr("\u2022Pick with the Brush from the Tile Palette or SceneView");
private static readonly string kEmptyViewSaveBrushPickText3 = L10n.Tr("\u2022Hit the Save Button ");
private static readonly string kEmptyViewSaveBrushPickText3a = L10n.Tr(" above to save it");
private static readonly string kEmptyViewSaveBrushPickText1Alt = L10n.Tr("\u2022Set up the Brush in Brush Settings");
private static readonly string brushPickUserViewEditorPref = "TilePaletteBrushPickUserView";
private static readonly string brushPickScaleEditorPref = "TilePaletteBrushPickScale";
private static readonly string brushPickFilteredEditorPref = "TilePaletteBrushPickFiltered";
private static readonly string brushPickFilterTextEditorPref = "TilePaletteBrushPickFilterText";
private static int kDefaultTextSize = 220;
private static int kDefaultTypeTextSize = 160;
private static int kDefaultItemSize = 96;
private static int kDefaultBorderSize = 8;
private static int kMinItemSize = kDefaultItemSize + kDefaultBorderSize;
private static float kSliderScaleMinValue = 0.4f;
private static float kSliderScaleMaxValue = 2.0f;
private static float kSliderListThreshold = 0.8f;
private static float kSliderGridThreshold = 1.2f;
private static string[] k_RightToolbarElements = new[] {
TilePaletteBrushPickActiveBrushToggle.k_ToolbarId,
TilePaletteBrushPickSaveButton.k_ToolbarId,
TilePaletteHidePicksToggle.k_ToolbarId
};
private static bool[] k_TilePaletteWindowActiveRightToolbar = new[] { true, true, false };
private static bool[] k_TilePaletteOverlayActiveRightToolbar = new[] { true, true, true };
private readonly VisualElement m_EmptyPicksView;
private readonly GridView m_PersonalGridView;
private readonly MultiColumnListView m_PersonalListView;
private readonly TilePaletteHidePicksToggle m_HideToggle;
private readonly VisualElement m_RightToolbar;
private readonly VisualElement m_ViewToolbar;
private readonly Slider m_Slider;
private readonly EditorToolbarToggle m_ListToggle;
private readonly EditorToolbarToggle m_GridToggle;
private IVisualElementScheduledItem m_GeometryResizeItem;
private IVisualElementScheduledItem m_FilterTextItem;
private GridBrushPickStore pickStore => GridPaintingState.brushPickStore;
private int itemSize
{
get => Mathf.FloorToInt(kDefaultItemSize * brushPickScale);
}
private bool isShowGrid
{
get => EditorPrefs.GetBool(brushPickUserViewEditorPref, true);
set => EditorPrefs.SetBool(brushPickUserViewEditorPref, value);
}
private float brushPickScale
{
get => EditorPrefs.GetFloat(brushPickScaleEditorPref, 1.0f);
set => EditorPrefs.SetFloat(brushPickScaleEditorPref, Mathf.Clamp(value, kSliderScaleMinValue, kSliderScaleMaxValue));
}
private bool isBrushPickFiltered => brushPickFiltered || !String.IsNullOrWhiteSpace(brushPickFilterText);
private bool brushPickFiltered
{
get => EditorPrefs.GetBool(brushPickFilteredEditorPref, false);
set => EditorPrefs.SetBool(brushPickFilteredEditorPref, value);
}
private string brushPickFilterText
{
get => EditorPrefs.GetString(brushPickFilterTextEditorPref, "");
set => EditorPrefs.SetString(brushPickFilterTextEditorPref, value);
}
///
/// Whether the Brush Picks overlay is hidden when a Brush Pick is selected.
///
public bool hideOnPick
{
get => EditorPrefs.GetBool(kTilePaletteBrushPickHideOnPickEditorPref, true);
set
{
EditorPrefs.SetBool(kTilePaletteBrushPickHideOnPickEditorPref, value);
m_HideToggle.SetValueWithoutNotify(value);
}
}
internal int lastSelection
{
get => EditorPrefs.GetInt(kTilePaletteBrushPickLastSelectionEditorPref, -1);
set => EditorPrefs.SetInt(kTilePaletteBrushPickLastSelectionEditorPref, value);
}
private bool m_InitialScrollToLastSelection;
///
/// Callback when the active Brush does a Pick on the Clipboard.
///
public event Action onBrushPicked
{
add
{
onBrushPickedInternal += value;
if (onBrushPickedInternal != null)
{
TilePaletteOverlayUtility.SetupChildrenAsButtonStripForVisible(m_RightToolbar, k_TilePaletteOverlayActiveRightToolbar);
}
}
remove
{
onBrushPickedInternal -= value;
if (onBrushPickedInternal == null)
{
TilePaletteOverlayUtility.SetupChildrenAsButtonStripForVisible(m_RightToolbar, k_TilePaletteWindowActiveRightToolbar);
}
}
}
private event Action onBrushPickedInternal;
///
/// Initializes and returns an instance of TilePaletteBrushPickElement.
///
public TilePaletteBrushPickElement()
{
AddToClassList(ussClassName);
TilePaletteOverlayUtility.SetStyleSheet(this);
m_EmptyPicksView = new VisualElement();
m_EmptyPicksView.AddToClassList(emptyViewUssClassName);
m_EmptyPicksView.style.display = DisplayStyle.None;
m_EmptyPicksView.style.visibility = Visibility.Hidden;
UpdateEmptyPicksView();
m_PersonalListView = new MultiColumnListView
{
showAlternatingRowBackgrounds = AlternatingRowBackground.ContentOnly,
reorderable = true,
reorderMode = ListViewReorderMode.Animated,
columns =
{
new Column()
{
title = kListViewNameColumn,
minWidth = kDefaultItemSize * kSliderScaleMinValue + kDefaultTextSize,
width = itemSize + kDefaultTextSize,
},
new Column()
{
title = kListViewTypeColumn,
minWidth = kDefaultTypeTextSize,
width = kDefaultTypeTextSize,
},
}
};
m_PersonalListView.itemIndexChanged += UserItemIndexChanged;
m_PersonalListView.columns[0].makeCell = MakeUserItem;
m_PersonalListView.columns[0].bindCell = BindUserItem;
m_PersonalListView.columns[1].makeCell = MakeUserType;
m_PersonalListView.columns[1].bindCell = BindUserType;
m_PersonalListView.itemsChosen += OnUserItemChosen;
m_PersonalListView.selectionChanged += OnUserSelectionChanged;
m_PersonalListView.style.display = isShowGrid ? DisplayStyle.None : DisplayStyle.Flex;
m_PersonalGridView = new GridView();
m_PersonalGridView.selectionType = SelectionType.Single;
m_PersonalGridView.showBorder = true;
m_PersonalGridView.makeItem = MakeUserItem;
m_PersonalGridView.bindItem = BindUserItem;
m_PersonalGridView.onItemsChosen += OnUserItemChosen;
m_PersonalGridView.onSelectionChange += OnUserSelectionChanged;
m_PersonalGridView.style.display = isShowGrid ? DisplayStyle.Flex : DisplayStyle.None;
var personalToolbar = new VisualElement();
personalToolbar.AddToClassList(labelToolbarUssClassName);
personalToolbar.Add(new Label(kPersonal));
var emptySpace = new VisualElement();
emptySpace.style.flexGrow = 1.0f;
emptySpace.style.flexShrink = 0f;
personalToolbar.Add(emptySpace);
var filterField = new ToolbarSearchField();
filterField.SetValueWithoutNotify(brushPickFilterText);
filterField.RegisterValueChangedCallback(FilterTextChanged);
personalToolbar.Add(filterField);
m_RightToolbar = EditorToolbar.CreateOverlay(k_RightToolbarElements);
TilePaletteOverlayUtility.SetupChildrenAsButtonStripForVisible(m_RightToolbar, k_TilePaletteWindowActiveRightToolbar);
var filterButton = m_RightToolbar.Q(null, TilePaletteBrushPickActiveBrushToggle.k_ElementClass);
filterButton.RegisterValueChangedCallback(FilterChanged);
filterButton.SetValueWithoutNotify(brushPickFiltered);
var saveButton = m_RightToolbar.Q(null, TilePaletteBrushPickSaveButton.k_ElementClass);
saveButton.clicked += AddCurrent;
m_HideToggle = m_RightToolbar.Q();
m_HideToggle.SetValueWithoutNotify(hideOnPick);
m_HideToggle.ToggleChanged += OnHidePicksToggleChanged;
personalToolbar.Add(m_RightToolbar);
Add(personalToolbar);
Add(m_EmptyPicksView);
Add(m_PersonalListView);
Add(m_PersonalGridView);
m_ViewToolbar = new VisualElement();
m_ViewToolbar.AddToClassList(viewToolbarUssClassName);
emptySpace = new VisualElement();
emptySpace.style.flexGrow = 1f;
emptySpace.style.flexShrink = 0f;
m_ViewToolbar.Add(emptySpace);
m_Slider = new Slider(kSliderScaleMinValue, kSliderScaleMaxValue);
m_Slider.SetValueWithoutNotify(brushPickScale);
m_Slider.RegisterValueChangedCallback(SliderChanged);
m_Slider.tooltip = kSizeSliderTooltip;
m_ViewToolbar.Add(m_Slider);
m_ListToggle = new EditorToolbarToggle();
m_ListToggle.AddToClassList("list-button");
m_ListToggle.RegisterValueChangedCallback(ListToggleChanged);
m_ListToggle.SetValueWithoutNotify(!isShowGrid);
m_ListToggle.tooltip = kListViewTooltip;
m_ViewToolbar.Add(m_ListToggle);
m_GridToggle = new EditorToolbarToggle();
m_GridToggle.AddToClassList("grid-button");
m_GridToggle.RegisterValueChangedCallback(GridToggleChanged);
m_GridToggle.SetValueWithoutNotify(isShowGrid);
m_GridToggle.tooltip = kGridViewTooltip;
m_ViewToolbar.Add(m_GridToggle);
Add(m_ViewToolbar);
var lastUsedToolbar = new VisualElement();
lastUsedToolbar.AddToClassList(labelToolbarUssClassName);
lastUsedToolbar.AddToClassList(lastUsedUssClassName);
lastUsedToolbar.Add(new Label(kLastUsed));
Add(lastUsedToolbar);
RegisterCallback(OnAttachedToPanel);
RegisterCallback(OnDetachFromPanel);
RegisterCallback(GeometryChanged);
}
private void UpdateEmptyPicksView()
{
m_EmptyPicksView.Clear();
TilemapEditorTool pickingTool = null;
foreach (var tool in TilemapEditorTool.tilemapEditorTools)
{
if (tool is PickingTool editorTool)
{
pickingTool = editorTool;
break;
}
}
if (pickingTool != null)
{
m_EmptyPicksView.Add(new Label(kEmptyViewSaveBrushPickText));
var line1Text = new VisualElement();
line1Text.style.flexDirection = FlexDirection.Row;
line1Text.Add(new Label(kEmptyViewSaveBrushPickText1));
var pickToolButton = new TilemapEditorToolButton(pickingTool);
var pickToolStrip = new VisualElement();
pickToolStrip.Add(pickToolButton);
EditorToolbarUtility.SetupChildrenAsButtonStrip(pickToolStrip);
line1Text.Add(pickToolStrip);
m_EmptyPicksView.Add(line1Text);
m_EmptyPicksView.Add(new Label(kEmptyViewSaveBrushPickText2));
}
else
{
m_EmptyPicksView.Add(new Label(kEmptyViewSaveBrushPickText1Alt));
}
// Save
var line3Text = new VisualElement();
line3Text.style.flexDirection = FlexDirection.Row;
line3Text.Add(new Label(kEmptyViewSaveBrushPickText3));
var saveButton = new TilePaletteBrushPickSaveButton();
saveButton.clicked += AddCurrent;
var saveStrip = new VisualElement();
saveStrip.Add(saveButton);
EditorToolbarUtility.SetupChildrenAsButtonStrip(saveStrip);
line3Text.Add(saveStrip);
line3Text.Add(new Label(kEmptyViewSaveBrushPickText3a));
m_EmptyPicksView.Add(line3Text);
}
private void OnAttachedToPanel(AttachToPanelEvent evt)
{
GridPaintingState.brushChanged += OnBrushChanged;
GridPaintingState.brushPickChanged += OnBrushPickChanged;
GridPaintingState.brushPickStoreChanged += UpdatePick;
AssemblyReloadEvents.afterAssemblyReload += UpdatePick;
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
RegisterCallback(OnKeyPress);
UpdatePick();
}
private void OnDetachFromPanel(DetachFromPanelEvent evt)
{
UnregisterCallback(OnKeyPress);
AssemblyReloadEvents.afterAssemblyReload -= UpdatePick;
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
GridPaintingState.brushPickStoreChanged -= UpdatePick;
GridPaintingState.brushPickChanged -= OnBrushPickChanged;
GridPaintingState.brushChanged -= OnBrushChanged;
}
private void FilterTextChanged(ChangeEvent evt)
{
brushPickFilterText = evt.newValue;
ClearFilterTextEvent();
var count = 500;
if (String.IsNullOrWhiteSpace(brushPickFilterText))
count = 200;
m_FilterTextItem = schedule.Execute(UpdatePick).StartingIn(count);
}
private void FilterChanged(ChangeEvent evt)
{
brushPickFiltered = evt.newValue;
UpdatePick();
}
private void SliderChanged(ChangeEvent evt)
{
brushPickScale = evt.newValue;
var changed = false;
if (evt.newValue < evt.previousValue && evt.newValue < kSliderListThreshold)
{
m_GridToggle.SetValueWithoutNotify(false);
m_ListToggle.SetValueWithoutNotify(true);
changed = true;
}
else if (evt.newValue > evt.previousValue && evt.newValue > kSliderGridThreshold)
{
m_GridToggle.SetValueWithoutNotify(true);
m_ListToggle.SetValueWithoutNotify(false);
changed = true;
}
if (changed)
UpdatePersonalDisplay();
else
UpdateSize();
}
private void ListToggleChanged(ChangeEvent evt)
{
m_GridToggle.SetValueWithoutNotify(!evt.newValue);
UpdatePersonalDisplay();
}
private void GridToggleChanged(ChangeEvent evt)
{
m_ListToggle.SetValueWithoutNotify(!evt.newValue);
UpdatePersonalDisplay();
}
private void ClearGeometryResizeEvent()
{
if (m_GeometryResizeItem == null)
return;
m_GeometryResizeItem.Pause();
m_GeometryResizeItem = null;
}
private void GeometryChanged(GeometryChangedEvent evt)
{
ClearGeometryResizeEvent();
var count = 100;
m_GeometryResizeItem = schedule.Execute(UpdateSize).StartingIn(count);
}
private void UpdateSize()
{
m_PersonalListView.fixedItemHeight = itemSize;
if (!isShowGrid)
EditorApplication.delayCall += () => m_PersonalListView.Rebuild();
var inspectorWidth = resolvedStyle.width;
var gridColumnCount = Mathf.Max(1, Mathf.FloorToInt(inspectorWidth / itemSize));
m_PersonalGridView.itemHeight = itemSize;
m_PersonalGridView.columnCount = gridColumnCount;
if (isShowGrid)
EditorApplication.delayCall += () => m_PersonalGridView.Refresh();
var scrollIndex = m_PersonalGridView.selectedIndex;
if (!m_InitialScrollToLastSelection)
{
scrollIndex = lastSelection;
m_InitialScrollToLastSelection = true;
}
ScrollToSelectedDelayed(scrollIndex);
}
private void UpdatePersonalDisplay()
{
var showGrid = m_GridToggle.value;
isShowGrid = showGrid;
if (showGrid)
{
m_PersonalGridView.style.display = DisplayStyle.Flex;
m_PersonalListView.style.display = DisplayStyle.None;
m_PersonalGridView.selectedIndex = m_PersonalListView.selectedIndex;
if (m_Slider.value < kSliderListThreshold)
{
m_Slider.SetValueWithoutNotify(kSliderListThreshold);
brushPickScale = kSliderListThreshold;
}
}
else
{
m_PersonalGridView.style.display = DisplayStyle.None;
m_PersonalListView.style.display = DisplayStyle.Flex;
m_PersonalListView.selectedIndex = m_PersonalGridView.selectedIndex;
if (m_Slider.value > kSliderGridThreshold)
{
m_Slider.SetValueWithoutNotify(kSliderGridThreshold);
brushPickScale = kSliderGridThreshold;
}
}
UpdateSize();
}
private void ClearFilterTextEvent()
{
if (m_FilterTextItem == null)
return;
m_FilterTextItem.Pause();
m_FilterTextItem = null;
}
private void UpdatePick()
{
ClearFilterTextEvent();
pickStore.SetUserBrushFilterType(brushPickFiltered ? GridPaintingState.gridBrush.GetType() : null, brushPickFilterText);
m_PersonalListView.itemsSource = pickStore.filteredUserSavedBrushes;
m_PersonalListView.RefreshItems();
m_PersonalGridView.itemsSource = pickStore.filteredUserSavedBrushes;
if (pickStore.userSavedBrushes.Count == 0)
{
m_EmptyPicksView.style.display = DisplayStyle.Flex;
m_EmptyPicksView.style.visibility = Visibility.Visible;
m_PersonalListView.style.display = DisplayStyle.None;
m_PersonalGridView.style.display = DisplayStyle.None;
m_ViewToolbar.SetEnabled(false);
}
else
{
m_EmptyPicksView.style.display = DisplayStyle.None;
m_EmptyPicksView.style.visibility = Visibility.Hidden;
m_ViewToolbar.SetEnabled(true);
if (m_PersonalGridView.style.display == DisplayStyle.None
&& m_PersonalListView.style.display == DisplayStyle.None)
{
UpdatePersonalDisplay();
if (!isShowGrid)
EditorApplication.delayCall += () => m_PersonalListView.Rebuild();
if (isShowGrid)
EditorApplication.delayCall += () => m_PersonalGridView.Refresh();
}
}
}
private void UserItemIndexChanged(int oldIdx, int newIdx)
{
if (oldIdx == newIdx)
return;
if (isBrushPickFiltered)
{
oldIdx = pickStore.GetIndexOfUserBrush(pickStore.filteredUserSavedBrushes[oldIdx]);
newIdx = pickStore.GetIndexOfUserBrush(pickStore.filteredUserSavedBrushes[newIdx]);
}
pickStore.SwapUserSavedBrushes(oldIdx, newIdx);
UpdatePick();
}
private void OnUserSelectionChanged(IEnumerable