2018-12-18 18:21:25 +08:00
using System.Collections.Generic ;
2018-12-17 09:08:40 +08:00
using UnityEngine ;
using UnityEngine.UI ;
using UnityEditor ;
using System.Linq ;
using System ;
using System.Reflection ;
using Object = UnityEngine . Object ;
using System.IO ;
namespace Coffee.UIExtensions.Editors
{
/// <summary>
2018-12-18 18:21:25 +08:00
/// SoftMaskable editor.
2018-12-17 09:08:40 +08:00
/// </summary>
2018-12-18 18:21:25 +08:00
[CustomEditor (typeof (SoftMaskable))]
2018-12-17 09:08:40 +08:00
[CanEditMultipleObjects]
public class SoftMaskableEditor : Editor
{
2018-12-18 18:21:25 +08:00
static readonly Type s_TypeTMPro = AppDomain . CurrentDomain . GetAssemblies ( ) . SelectMany ( x = > x . GetTypes ( ) ) . FirstOrDefault ( x = > x . Name = = "TMP_Text" ) ;
static readonly Type s_TypeTMP_SpriteAsset = AppDomain . CurrentDomain . GetAssemblies ( ) . SelectMany ( x = > x . GetTypes ( ) ) . FirstOrDefault ( x = > x . Name = = "TMP_SpriteAsset" ) ;
static readonly Type s_TypeTMProSettings = AppDomain . CurrentDomain . GetAssemblies ( ) . SelectMany ( x = > x . GetTypes ( ) ) . FirstOrDefault ( x = > x . Name = = "TMP_Settings" ) ;
static readonly Type s_TypeTMP_SubMesh = AppDomain . CurrentDomain . GetAssemblies ( ) . SelectMany ( x = > x . GetTypes ( ) ) . FirstOrDefault ( x = > x . Name = = "TMP_SubMesh" ) ;
static readonly Type s_TypeTMP_SubMeshUI = AppDomain . CurrentDomain . GetAssemblies ( ) . SelectMany ( x = > x . GetTypes ( ) ) . FirstOrDefault ( x = > x . Name = = "TMP_SubMeshUI" ) ;
static PropertyInfo s_PiFontSharedMaterial ;
static PropertyInfo s_PiFontSharedMaterials ;
static PropertyInfo s_PiSpriteAsset ;
static PropertyInfo s_PiRichText ;
static PropertyInfo s_PiText ;
static PropertyInfo s_PiDefaultFontAssetPath ;
static PropertyInfo s_PiDefaultSpriteAssetPath ;
static FieldInfo s_FiMaterial ;
static MethodInfo s_miGetSpriteAsset ;
2018-12-17 09:08:40 +08:00
static readonly List < Graphic > s_Graphics = new List < Graphic > ( ) ;
Shader _shader ;
Shader _mobileShader ;
Shader _spriteShader ;
2018-12-18 18:21:25 +08:00
List < MaterialEditor > _materialEditors = new List < MaterialEditor > ( ) ;
2018-12-17 09:08:40 +08:00
private void OnEnable ( )
{
ClearMaterialEditors ( ) ;
_shader = Shader . Find ( "TextMeshPro/Distance Field (SoftMaskable)" ) ;
_mobileShader = Shader . Find ( "TextMeshPro/Mobile/Distance Field (SoftMaskable)" ) ;
_spriteShader = Shader . Find ( "TextMeshPro/Sprite (SoftMaskable)" ) ;
2018-12-18 18:21:25 +08:00
if ( s_TypeTMPro ! = null )
{
s_PiFontSharedMaterial = s_TypeTMPro . GetProperty ( "fontSharedMaterial" ) ;
s_PiSpriteAsset = s_TypeTMPro . GetProperty ( "spriteAsset" ) ;
s_PiRichText = s_TypeTMPro . GetProperty ( "richText" ) ;
s_PiText = s_TypeTMPro . GetProperty ( "text" ) ;
s_FiMaterial = s_TypeTMP_SpriteAsset . GetField ( "material" ) ;
s_PiFontSharedMaterials = s_TypeTMPro . GetProperty ( "fontSharedMaterials" ) ;
s_miGetSpriteAsset = s_TypeTMProSettings . GetMethod ( "GetSpriteAsset" , BindingFlags . Static | BindingFlags . Public ) ;
s_PiDefaultFontAssetPath = s_TypeTMProSettings . GetProperty ( "defaultFontAssetPath" , BindingFlags . Static | BindingFlags . Public ) ;
s_PiDefaultSpriteAssetPath = s_TypeTMProSettings . GetProperty ( "defaultSpriteAssetPath" , BindingFlags . Static | BindingFlags . Public ) ;
}
2018-12-17 09:08:40 +08:00
}
private void OnDisable ( )
{
ClearMaterialEditors ( ) ;
}
public override void OnInspectorGUI ( )
{
base . OnInspectorGUI ( ) ;
var current = target as SoftMaskable ;
current . GetComponentsInChildren < Graphic > ( true , s_Graphics ) ;
var fixTargets = s_Graphics . Where ( x = > x . gameObject ! = current . gameObject & & ! x . GetComponent < SoftMaskable > ( ) & & ( ! x . GetComponent < Mask > ( ) | | x . GetComponent < Mask > ( ) . showMaskGraphic ) ) . ToList ( ) ;
if ( 0 < fixTargets . Count )
{
GUILayout . BeginHorizontal ( ) ;
EditorGUILayout . HelpBox ( "There are child Graphicss that does not have a SoftMaskable component.\nAdd SoftMaskable component to them." , MessageType . Warning ) ;
GUILayout . BeginVertical ( ) ;
if ( GUILayout . Button ( "Fix" ) )
{
foreach ( var p in fixTargets )
{
p . gameObject . AddComponent < SoftMaskable > ( ) ;
}
}
if ( GUILayout . Button ( "Ping" ) )
{
EditorGUIUtility . PingObject ( fixTargets [ 0 ] ) ;
}
GUILayout . EndVertical ( ) ;
GUILayout . EndHorizontal ( ) ;
}
2018-12-18 18:21:25 +08:00
if ( s_TypeTMPro ! = null )
2018-12-17 09:08:40 +08:00
{
2018-12-18 18:21:25 +08:00
ShowTMProWarning ( _shader , _mobileShader , _spriteShader , m = > { } ) ;
var textMeshPro = current . GetComponent ( s_TypeTMPro ) ;
if ( textMeshPro ! = null )
{
Material [ ] fontSharedMaterials = s_PiFontSharedMaterials . GetValue ( textMeshPro , new object [ 0 ] ) as Material [ ] ;
ShowMaterialEditors ( fontSharedMaterials , 1 , fontSharedMaterials . Length - 1 ) ;
}
2018-12-17 09:08:40 +08:00
}
}
void ClearMaterialEditors ( )
{
foreach ( var e in _materialEditors )
{
if ( e )
{
DestroyImmediate ( e ) ;
}
}
_materialEditors . Clear ( ) ;
}
protected void ShowMaterialEditors ( Material [ ] materials , int startIndex , int count )
{
for ( int i = 0 ; i < count ; i + + )
{
if ( _materialEditors . Count = = i )
{
_materialEditors . Add ( null ) ;
}
var mat = materials [ startIndex + i ] ;
var editor = _materialEditors [ i ] ;
if ( editor & & editor . target ! = mat )
{
DestroyImmediate ( editor ) ;
editor = null ;
}
if ( ! editor )
{
editor = _materialEditors [ i ] = Editor . CreateEditor ( mat ) as MaterialEditor ;
}
editor . DrawHeader ( ) ;
editor . OnInspectorGUI ( ) ;
}
}
public void ShowTMProWarning ( Shader shader , Shader mobileShader , Shader spriteShader , System . Action < Material > onCreatedMaterial )
{
var current = target as SoftMaskable ;
var textMeshPro = current . GetComponent ( s_TypeTMPro ) ;
2018-12-18 18:21:25 +08:00
if ( textMeshPro = = null )
2018-12-17 09:08:40 +08:00
{
return ;
}
2018-12-18 18:21:25 +08:00
Material fontSharedMaterial = s_PiFontSharedMaterial . GetValue ( textMeshPro , new object [ 0 ] ) as Material ;
2018-12-17 09:08:40 +08:00
if ( fontSharedMaterial = = null )
{
return ;
}
// Is the material preset for dissolve?
Material m = fontSharedMaterial ;
if ( m . shader ! = shader & & m . shader ! = mobileShader )
{
EditorGUILayout . BeginHorizontal ( ) ;
EditorGUILayout . HelpBox ( string . Format ( "{0} requires '{1}' or '{2}' as a shader for material preset." , current . GetType ( ) . Name , shader . name , mobileShader . name ) , MessageType . Warning ) ;
if ( GUILayout . Button ( "Fix" ) )
{
var correctShader = m . shader . name . Contains ( "Mobile" ) ? mobileShader : shader ;
m = ModifyTMProMaterialPreset ( m , correctShader , onCreatedMaterial ) ;
2018-12-18 18:21:25 +08:00
s_PiFontSharedMaterial . SetValue ( textMeshPro , m , new object [ 0 ] ) ;
2018-12-17 09:08:40 +08:00
}
EditorGUILayout . EndHorizontal ( ) ;
return ;
}
// Is the sprite asset for dissolve?
2018-12-18 18:21:25 +08:00
object spriteAsset = s_PiSpriteAsset . GetValue ( textMeshPro , new object [ 0 ] ) ? ? s_miGetSpriteAsset . Invoke ( null , new object [ 0 ] ) ;
2018-12-17 09:08:40 +08:00
//TMP_SpriteAsset spriteAsset = textMeshPro.spriteAsset ?? TMP_Settings.GetSpriteAsset ();
2018-12-18 18:21:25 +08:00
m = s_FiMaterial . GetValue ( spriteAsset ) as Material ;
2018-12-17 09:08:40 +08:00
bool hasSprite = ( bool ) s_PiRichText . GetValue ( textMeshPro , new object [ 0 ] ) & & ( s_PiText . GetValue ( textMeshPro , new object [ 0 ] ) as string ) . Contains ( "<sprite=" ) ;
if ( m & & m . shader ! = spriteShader & & hasSprite )
{
EditorGUILayout . BeginHorizontal ( ) ;
EditorGUILayout . HelpBox ( string . Format ( "{0} requires '{1}' as a shader for sprite asset." , GetType ( ) . Name , spriteShader . name ) , MessageType . Warning ) ;
if ( GUILayout . Button ( "Fix" ) )
{
current . GetComponentsInChildren ( s_TypeTMP_SubMesh ) . Select ( x = > x . gameObject ) . ToList ( ) . ForEach ( DestroyImmediate ) ;
current . GetComponentsInChildren ( s_TypeTMP_SubMeshUI ) . Select ( x = > x . gameObject ) . ToList ( ) . ForEach ( DestroyImmediate ) ;
2018-12-18 18:21:25 +08:00
spriteAsset = ModifyTMProSpriteAsset ( m , _spriteShader , mat = > { } ) ;
s_PiSpriteAsset . SetValue ( textMeshPro , spriteAsset , new object [ 0 ] ) ;
2018-12-17 09:08:40 +08:00
}
EditorGUILayout . EndHorizontal ( ) ;
return ;
}
}
Material ModifyTMProMaterialPreset ( Material baseMaterial , Shader shader , System . Action < Material > onCreatedMaterial )
{
string path = AssetDatabase . GetAssetPath ( baseMaterial ) ;
2018-12-18 18:21:25 +08:00
string filename = Path . GetFileNameWithoutExtension ( path ) + " (" + typeof ( SoftMaskable ) . Name + ")" ;
2018-12-17 09:08:40 +08:00
string defaultAssetPath = s_PiDefaultFontAssetPath . GetValue ( null , new object [ 0 ] ) as string ;
Material mat = Resources . Load < Material > ( defaultAssetPath + filename ) ;
if ( ! mat )
{
mat = new Material ( baseMaterial )
{
shaderKeywords = baseMaterial . shaderKeywords ,
shader = shader ,
} ;
onCreatedMaterial ( mat ) ;
AssetDatabase . CreateAsset ( mat , Path . GetDirectoryName ( path ) + "/" + filename + ".mat" ) ;
EditorUtility . FocusProjectWindow ( ) ;
EditorGUIUtility . PingObject ( mat ) ;
}
else
{
mat . shader = shader ;
}
EditorUtility . SetDirty ( mat ) ;
return mat ;
}
object ModifyTMProSpriteAsset ( Material baseMaterial , Shader shader , System . Action < Material > onCreatedMaterial )
{
string path = AssetDatabase . GetAssetPath ( baseMaterial ) ;
string filename = Path . GetFileNameWithoutExtension ( path ) + " (" + typeof ( SoftMaskable ) . Name + ")" ;
string defaultAssetPath = s_PiDefaultSpriteAssetPath . GetValue ( null , new object [ 0 ] ) as string ;
Object spriteAsset = Resources . Load ( defaultAssetPath + filename , s_TypeTMP_SpriteAsset ) ;
if ( spriteAsset = = null )
{
AssetDatabase . CopyAsset ( path , Path . GetDirectoryName ( path ) + "/" + filename + ".mat" ) ;
spriteAsset = Resources . Load ( defaultAssetPath + filename , s_TypeTMP_SpriteAsset ) ;
Material m = s_FiMaterial . GetValue ( spriteAsset ) as Material ;
m . shader = shader ;
m . name = shader . name ;
onCreatedMaterial ( m ) ;
EditorUtility . FocusProjectWindow ( ) ;
EditorGUIUtility . PingObject ( spriteAsset ) ;
}
else
{
Material m = s_FiMaterial . GetValue ( spriteAsset ) as Material ;
m . shader = shader ;
}
EditorUtility . SetDirty ( spriteAsset ) ;
return spriteAsset ;
}
}
}