diff --git a/Packages/com.unity.ugui/CHANGELOG.md b/Packages/com.unity.ugui/CHANGELOG.md new file mode 100644 index 00000000..cbdca122 --- /dev/null +++ b/Packages/com.unity.ugui/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog + +## [2.0.0] - 2023-03-08 +Merge of the com.unity.textmeshpro package. + +## [1.0.0] - 2019-01-08 +This is the first release of Unity UI as a built in package. diff --git a/Packages/com.unity.ugui/CHANGELOG.md.meta b/Packages/com.unity.ugui/CHANGELOG.md.meta new file mode 100644 index 00000000..4a339bda --- /dev/null +++ b/Packages/com.unity.ugui/CHANGELOG.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c851bee4305bddf438cc6ffc515991ce +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources.meta b/Packages/com.unity.ugui/Editor Resources.meta new file mode 100644 index 00000000..7c07b007 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d1a0a27327b54c3bac52a08929c33f81 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Gizmos.meta b/Packages/com.unity.ugui/Editor Resources/Gizmos.meta new file mode 100644 index 00000000..f2596c78 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Gizmos.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e93ec7eb6de342aabd156833e253f838 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Dropdown Icon.psd b/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Dropdown Icon.psd new file mode 100644 index 00000000..93f5a2cb Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Dropdown Icon.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Dropdown Icon.psd.meta b/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Dropdown Icon.psd.meta new file mode 100644 index 00000000..7bdb473e --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Dropdown Icon.psd.meta @@ -0,0 +1,143 @@ +fileFormatVersion: 2 +guid: a7ec9e7ad8b847b7ae4510af83c5d868 +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 7 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 1 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: -2 + maxTextureSize: 128 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: 1 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 128 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 128 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: iPhone + maxTextureSize: 128 + resizeAlgorithm: 0 + textureFormat: 2 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 128 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Windows Store Apps + maxTextureSize: 128 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: WebGL + maxTextureSize: 128 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 1 + pSDShowRemoveMatteOption: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Font Asset Icon.psd b/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Font Asset Icon.psd new file mode 100644 index 00000000..2fb1164d Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Font Asset Icon.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Font Asset Icon.psd.meta b/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Font Asset Icon.psd.meta new file mode 100644 index 00000000..bd64ad7d --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Font Asset Icon.psd.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: ee148e281f3c41c5b4ff5f8a5afe5a6c +timeCreated: 1463559213 +licenseType: Pro +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 128 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Input Field Icon.psd b/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Input Field Icon.psd new file mode 100644 index 00000000..f0360d34 Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Input Field Icon.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Input Field Icon.psd.meta b/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Input Field Icon.psd.meta new file mode 100644 index 00000000..eb2e1ce2 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Input Field Icon.psd.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 3ee40aa79cd242a5b53b0b0ca4f13f0f +timeCreated: 1457860876 +licenseType: Pro +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 128 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Sprite Asset Icon.psd b/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Sprite Asset Icon.psd new file mode 100644 index 00000000..7036296e Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Sprite Asset Icon.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Sprite Asset Icon.psd.meta b/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Sprite Asset Icon.psd.meta new file mode 100644 index 00000000..a22cdf1c --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Sprite Asset Icon.psd.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: ec7c645d93308c04d8840982af12101e +timeCreated: 1463559213 +licenseType: Pro +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 128 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Text Component Icon.psd b/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Text Component Icon.psd new file mode 100644 index 00000000..3cc41630 Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Text Component Icon.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Text Component Icon.psd.meta b/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Text Component Icon.psd.meta new file mode 100644 index 00000000..623993d2 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Gizmos/TMP - Text Component Icon.psd.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: 2fd6421f253b4ef1a19526541f9ffc0c +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 128 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Shaders.meta b/Packages/com.unity.ugui/Editor Resources/Shaders.meta new file mode 100644 index 00000000..95efe2ba --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Shaders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2da27f5fe80a3a549ac7331d9f52f5f0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Shaders/TMP_Properties.cginc b/Packages/com.unity.ugui/Editor Resources/Shaders/TMP_Properties.cginc new file mode 100644 index 00000000..2e962588 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Shaders/TMP_Properties.cginc @@ -0,0 +1,85 @@ +// UI Editable properties +uniform sampler2D _FaceTex; // Alpha : Signed Distance +uniform float _FaceUVSpeedX; +uniform float _FaceUVSpeedY; +uniform fixed4 _FaceColor; // RGBA : Color + Opacity +uniform float _FaceDilate; // v[ 0, 1] +uniform float _OutlineSoftness; // v[ 0, 1] + +uniform sampler2D _OutlineTex; // RGBA : Color + Opacity +uniform float _OutlineUVSpeedX; +uniform float _OutlineUVSpeedY; +uniform fixed4 _OutlineColor; // RGBA : Color + Opacity +uniform float _OutlineWidth; // v[ 0, 1] + +uniform float _Bevel; // v[ 0, 1] +uniform float _BevelOffset; // v[-1, 1] +uniform float _BevelWidth; // v[-1, 1] +uniform float _BevelClamp; // v[ 0, 1] +uniform float _BevelRoundness; // v[ 0, 1] + +uniform sampler2D _BumpMap; // Normal map +uniform float _BumpOutline; // v[ 0, 1] +uniform float _BumpFace; // v[ 0, 1] + +uniform samplerCUBE _Cube; // Cube / sphere map +uniform fixed4 _ReflectFaceColor; // RGB intensity +uniform fixed4 _ReflectOutlineColor; +//uniform float _EnvTiltX; // v[-1, 1] +//uniform float _EnvTiltY; // v[-1, 1] +uniform float3 _EnvMatrixRotation; +uniform float4x4 _EnvMatrix; + +uniform fixed4 _SpecularColor; // RGB intensity +uniform float _LightAngle; // v[ 0,Tau] +uniform float _SpecularPower; // v[ 0, 1] +uniform float _Reflectivity; // v[ 5, 15] +uniform float _Diffuse; // v[ 0, 1] +uniform float _Ambient; // v[ 0, 1] + +uniform fixed4 _UnderlayColor; // RGBA : Color + Opacity +uniform float _UnderlayOffsetX; // v[-1, 1] +uniform float _UnderlayOffsetY; // v[-1, 1] +uniform float _UnderlayDilate; // v[-1, 1] +uniform float _UnderlaySoftness; // v[ 0, 1] + +uniform fixed4 _GlowColor; // RGBA : Color + Intesity +uniform float _GlowOffset; // v[-1, 1] +uniform float _GlowOuter; // v[ 0, 1] +uniform float _GlowInner; // v[ 0, 1] +uniform float _GlowPower; // v[ 1, 1/(1+4*4)] + +// API Editable properties +uniform float _ShaderFlags; +uniform float _WeightNormal; +uniform float _WeightBold; + +uniform float _ScaleRatioA; +uniform float _ScaleRatioB; +uniform float _ScaleRatioC; + +uniform float _VertexOffsetX; +uniform float _VertexOffsetY; + +//uniform float _UseClipRect; +uniform float _MaskID; +uniform sampler2D _MaskTex; +uniform float4 _MaskCoord; +uniform float4 _ClipRect; // bottom left(x,y) : top right(z,w) +//uniform float _MaskWipeControl; +//uniform float _MaskEdgeSoftness; +//uniform fixed4 _MaskEdgeColor; +//uniform bool _MaskInverse; + +uniform float _MaskSoftnessX; +uniform float _MaskSoftnessY; + +// Font Atlas properties +uniform sampler2D _MainTex; +uniform float _TextureWidth; +uniform float _TextureHeight; +uniform float _GradientScale; +uniform float _ScaleX; +uniform float _ScaleY; +uniform float _PerspectiveFilter; +uniform float _Sharpness; diff --git a/Packages/com.unity.ugui/Editor Resources/Shaders/TMP_Properties.cginc.meta b/Packages/com.unity.ugui/Editor Resources/Shaders/TMP_Properties.cginc.meta new file mode 100644 index 00000000..e6dcc0a0 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Shaders/TMP_Properties.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 3c6c403084eacec478a1129ce20061ea +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Shaders/TMP_SDF Internal Editor.shader b/Packages/com.unity.ugui/Editor Resources/Shaders/TMP_SDF Internal Editor.shader new file mode 100644 index 00000000..baf4501c --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Shaders/TMP_SDF Internal Editor.shader @@ -0,0 +1,75 @@ +// Simplified SDF shader: +// - No Shading Option (bevel / bump / env map) +// - No Glow Option +// - Softness is applied on both side of the outline + +Shader "Hidden/TMP/Internal/Editor/Distance Field SSD" { + + Properties{ + _FaceColor("Face Color", Color) = (1,1,1,1) + _FaceDilate("Face Dilate", Range(-1,1)) = 0 + + _OutlineColor("Outline Color", Color) = (0,0,0,1) + _OutlineWidth("Outline Thickness", Range(0,1)) = 0 + _OutlineSoftness("Outline Softness", Range(0,1)) = 0 + + _UnderlayColor("Border Color", Color) = (0,0,0,.5) + _UnderlayOffsetX("Border OffsetX", Range(-1,1)) = 0 + _UnderlayOffsetY("Border OffsetY", Range(-1,1)) = 0 + _UnderlayDilate("Border Dilate", Range(-1,1)) = 0 + _UnderlaySoftness("Border Softness", Range(0,1)) = 0 + + _WeightNormal("Weight Normal", float) = 0 + _WeightBold("Weight Bold", float) = .5 + + _ShaderFlags("Flags", float) = 0 + _ScaleRatioA("Scale RatioA", float) = 1 + _ScaleRatioB("Scale RatioB", float) = 1 + _ScaleRatioC("Scale RatioC", float) = 1 + + _MainTex("Font Atlas", 2D) = "white" {} + _TextureWidth("Texture Width", float) = 1024 + _TextureHeight("Texture Height", float) = 1024 + _GradientScale("Gradient Scale", float) = 1 + _ScaleX("Scale X", float) = 1 + _ScaleY("Scale Y", float) = 1 + _PerspectiveFilter("Perspective Correction", Range(0, 1)) = 0.875 + _Sharpness("Sharpness", Range(-1,1)) = 0 + + _VertexOffsetX("Vertex OffsetX", float) = 0 + _VertexOffsetY("Vertex OffsetY", float) = 0 + } + + SubShader + { + Tags + { + "ForceSupported" = "True" + } + + Lighting Off + Blend One OneMinusSrcAlpha + Cull Off + ZWrite Off + ZTest Always + + Pass + { + CGPROGRAM + #pragma vertex VertShader + #pragma fragment PixShader + #pragma shader_feature __ OUTLINE_ON + #pragma shader_feature __ UNDERLAY_ON UNDERLAY_INNER + + #include "UnityCG.cginc" + #include "UnityUI.cginc" + #include "TMP_Properties.cginc" + + #include "TMP_SDF_SSD.cginc" + + ENDCG + } + } + + CustomEditor "TMPro.EditorUtilities.TMP_SDFShaderGUI" +} diff --git a/Packages/com.unity.ugui/Editor Resources/Shaders/TMP_SDF Internal Editor.shader.meta b/Packages/com.unity.ugui/Editor Resources/Shaders/TMP_SDF Internal Editor.shader.meta new file mode 100644 index 00000000..5ba708d8 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Shaders/TMP_SDF Internal Editor.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 9c442dc870b456e48b615cd8add0e9ef +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Shaders/TMP_SDF_SSD.cginc b/Packages/com.unity.ugui/Editor Resources/Shaders/TMP_SDF_SSD.cginc new file mode 100644 index 00000000..b16f2695 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Shaders/TMP_SDF_SSD.cginc @@ -0,0 +1,132 @@ +struct vertex_t +{ + float4 position : POSITION; + float3 normal : NORMAL; + float4 color : COLOR; + float4 texcoord0 : TEXCOORD0; + float2 texcoord1 : TEXCOORD1; +}; + +struct pixel_t +{ + float4 position : SV_POSITION; + float4 faceColor : COLOR; + float4 outlineColor : COLOR1; + float2 texcoord0 : TEXCOORD0; + float4 param : TEXCOORD1; // weight, scaleRatio + float2 clipUV : TEXCOORD2; + #if (UNDERLAY_ON || UNDERLAY_INNER) + float4 texcoord2 : TEXCOORD3; + float4 underlayColor : COLOR2; + #endif +}; + +sampler2D _GUIClipTexture; +uniform float4x4 unity_GUIClipTextureMatrix; +float4 _MainTex_TexelSize; + +float4 SRGBToLinear(float4 rgba) +{ + return float4(lerp(rgba.rgb / 12.92f, pow((rgba.rgb + 0.055f) / 1.055f, 2.4f), step(0.04045f, rgba.rgb)), rgba.a); +} + +pixel_t VertShader(vertex_t input) +{ + pixel_t output; + + float bold = step(input.texcoord0.w, 0); + + float4 vert = input.position; + vert.x += _VertexOffsetX; + vert.y += _VertexOffsetY; + + float4 vPosition = UnityObjectToClipPos(vert); + + float weight = lerp(_WeightNormal, _WeightBold, bold) / 4.0; + weight = (weight + _FaceDilate) * _ScaleRatioA * 0.5; + + // Generate UV for the Clip Texture + float3 eyePos = UnityObjectToViewPos(input.position); + float2 clipUV = mul(unity_GUIClipTextureMatrix, float4(eyePos.xy, 0, 1.0)); + + float4 color = input.color; + #if (FORCE_LINEAR && !UNITY_COLORSPACE_GAMMA) + color = SRGBToLinear(input.color); + #endif + + float opacity = color.a; + #if (UNDERLAY_ON | UNDERLAY_INNER) + opacity = 1.0; + #endif + + float4 faceColor = float4(color.rgb, opacity) * _FaceColor; + faceColor.rgb *= faceColor.a; + + float4 outlineColor = _OutlineColor; + outlineColor.a *= opacity; + outlineColor.rgb *= outlineColor.a; + + output.position = vPosition; + output.faceColor = faceColor; + output.outlineColor = outlineColor; + output.texcoord0 = float2(input.texcoord0.xy); + output.param = float4(0.5 - weight, 1.3333 * _GradientScale * (_Sharpness + 1) / _MainTex_TexelSize.z , _OutlineWidth * _ScaleRatioA * 0.5, 0); + output.clipUV = clipUV; + + #if (UNDERLAY_ON || UNDERLAY_INNER) + float4 underlayColor = _UnderlayColor; + underlayColor.rgb *= underlayColor.a; + + float x = -(_UnderlayOffsetX * _ScaleRatioC) * _GradientScale / _MainTex_TexelSize.z; + float y = -(_UnderlayOffsetY * _ScaleRatioC) * _GradientScale / _MainTex_TexelSize.w; + + output.texcoord2 = float4(input.texcoord0 + float2(x, y), input.color.a, 0); + output.underlayColor = underlayColor; + #endif + + return output; +} + +float4 PixShader(pixel_t input) : SV_Target +{ + float d = tex2D(_MainTex, input.texcoord0.xy).a; + + float2 UV = input.texcoord0.xy; + float scale = rsqrt(abs(ddx(UV.x) * ddy(UV.y) - ddy(UV.x) * ddx(UV.y))) * input.param.y; + + #if (UNDERLAY_ON | UNDERLAY_INNER) + float layerScale = scale; + layerScale /= 1 + ((_UnderlaySoftness * _ScaleRatioC) * layerScale); + float layerBias = input.param.x * layerScale - .5 - ((_UnderlayDilate * _ScaleRatioC) * .5 * layerScale); + #endif + + scale /= 1 + (_OutlineSoftness * _ScaleRatioA * scale); + + float4 faceColor = input.faceColor * saturate((d - input.param.x) * scale + 0.5); + + #ifdef OUTLINE_ON + float4 outlineColor = lerp(input.faceColor, input.outlineColor, sqrt(min(1.0, input.param.z * scale * 2))); + faceColor = lerp(outlineColor, input.faceColor, saturate((d - input.param.x - input.param.z) * scale + 0.5)); + faceColor *= saturate((d - input.param.x + input.param.z) * scale + 0.5); + #endif + + #if UNDERLAY_ON + d = tex2D(_MainTex, input.texcoord2.xy).a * layerScale; + faceColor += float4(_UnderlayColor.rgb * _UnderlayColor.a, _UnderlayColor.a) * saturate(d - layerBias) * (1 - faceColor.a); + #endif + + #if UNDERLAY_INNER + float bias = input.param.x * scale - 0.5; + float sd = saturate(d * scale - bias - input.param.z); + d = tex2D(_MainTex, input.texcoord2.xy).a * layerScale; + faceColor += float4(_UnderlayColor.rgb * _UnderlayColor.a, _UnderlayColor.a) * (1 - saturate(d - layerBias)) * sd * (1 - faceColor.a); + #endif + + #if (UNDERLAY_ON | UNDERLAY_INNER) + faceColor *= input.texcoord2.z; + #endif + + faceColor *= tex2D(_GUIClipTexture, input.clipUV).a; + + return faceColor; +} diff --git a/Packages/com.unity.ugui/Editor Resources/Shaders/TMP_SDF_SSD.cginc.meta b/Packages/com.unity.ugui/Editor Resources/Shaders/TMP_SDF_SSD.cginc.meta new file mode 100644 index 00000000..3d0b3bf4 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Shaders/TMP_SDF_SSD.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: abe6991365a27d341a10580f3b7c0f44 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures.meta b/Packages/com.unity.ugui/Editor Resources/Textures.meta new file mode 100644 index 00000000..d6754b05 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f8e6a2d47aba4c6c9b3c5a72d9f48da5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/SectionHeader_Dark.psd b/Packages/com.unity.ugui/Editor Resources/Textures/SectionHeader_Dark.psd new file mode 100644 index 00000000..8ebaa27a Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/SectionHeader_Dark.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/SectionHeader_Dark.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/SectionHeader_Dark.psd.meta new file mode 100644 index 00000000..ed7250a7 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/SectionHeader_Dark.psd.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: fb5730e24283d0c489e5c7d0bee023d9 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/SectionHeader_Light.psd b/Packages/com.unity.ugui/Editor Resources/Textures/SectionHeader_Light.psd new file mode 100644 index 00000000..e598e6d9 Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/SectionHeader_Light.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/SectionHeader_Light.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/SectionHeader_Light.psd.meta new file mode 100644 index 00000000..1e747b22 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/SectionHeader_Light.psd.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: e3b0f810fdea84e40ab4ba20f256f7e8 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBaseLine.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBaseLine.psd new file mode 100644 index 00000000..3da358a1 Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBaseLine.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBaseLine.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBaseLine.psd.meta new file mode 100644 index 00000000..09deb3c8 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBaseLine.psd.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: 8bc445bb79654bf496c92d0407840a92 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBaseLine_Light.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBaseLine_Light.psd new file mode 100644 index 00000000..cf49b6cb Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBaseLine_Light.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBaseLine_Light.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBaseLine_Light.psd.meta new file mode 100644 index 00000000..78e14cba --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBaseLine_Light.psd.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: 18775b51e3bd42299fd30bd036ea982f +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBottom.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBottom.psd new file mode 100644 index 00000000..1f35779e Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBottom.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBottom.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBottom.psd.meta new file mode 100644 index 00000000..8e79b489 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBottom.psd.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: ca51b19024094d1b87f3e07edb0a75fb +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBottom_Light.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBottom_Light.psd new file mode 100644 index 00000000..d8af55bd Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBottom_Light.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBottom_Light.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBottom_Light.psd.meta new file mode 100644 index 00000000..9c9a6fc0 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignBottom_Light.psd.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: 585b70cb75dd43efbfead809c30a1731 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCapLine.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCapLine.psd new file mode 100644 index 00000000..7eefe6b2 Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCapLine.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCapLine.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCapLine.psd.meta new file mode 100644 index 00000000..0455a2fc --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCapLine.psd.meta @@ -0,0 +1,58 @@ +fileFormatVersion: 2 +guid: 0d9a36012a224080966c7b55896aa0f9 +timeCreated: 1467964791 +licenseType: Pro +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCapLine_Light.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCapLine_Light.psd new file mode 100644 index 00000000..f08bb6ce Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCapLine_Light.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCapLine_Light.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCapLine_Light.psd.meta new file mode 100644 index 00000000..dfd05a11 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCapLine_Light.psd.meta @@ -0,0 +1,58 @@ +fileFormatVersion: 2 +guid: 49679f302ac6408697f6b9314a38985c +timeCreated: 1467964413 +licenseType: Pro +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenter.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenter.psd new file mode 100644 index 00000000..939bc6dc Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenter.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenter.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenter.psd.meta new file mode 100644 index 00000000..d189fc27 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenter.psd.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: 81ed8c76d2bc4a4c95d092c98af4e58f +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenterGeo.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenterGeo.psd new file mode 100644 index 00000000..f9ce9a8b Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenterGeo.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenterGeo.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenterGeo.psd.meta new file mode 100644 index 00000000..555bb1bb --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenterGeo.psd.meta @@ -0,0 +1,56 @@ +fileFormatVersion: 2 +guid: c76700ea0062413d9f69409b4e9e151b +timeCreated: 1484171296 +licenseType: Pro +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenterGeo_Light.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenterGeo_Light.psd new file mode 100644 index 00000000..e37b2e25 Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenterGeo_Light.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenterGeo_Light.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenterGeo_Light.psd.meta new file mode 100644 index 00000000..044d0c21 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenterGeo_Light.psd.meta @@ -0,0 +1,56 @@ +fileFormatVersion: 2 +guid: 35ff0937876540d3bd4b6a941df62a92 +timeCreated: 1484171296 +licenseType: Pro +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenter_Light.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenter_Light.psd new file mode 100644 index 00000000..7274887f Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenter_Light.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenter_Light.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenter_Light.psd.meta new file mode 100644 index 00000000..d98d3772 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignCenter_Light.psd.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: 6ace62d30f494c948b71d5594afce11d +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignFlush.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignFlush.psd new file mode 100644 index 00000000..eeeea67b Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignFlush.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignFlush.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignFlush.psd.meta new file mode 100644 index 00000000..84ed28c0 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignFlush.psd.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: 691475c57a824010be0c6f474caeb7e1 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignFlush_Light.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignFlush_Light.psd new file mode 100644 index 00000000..b69f6a2e Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignFlush_Light.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignFlush_Light.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignFlush_Light.psd.meta new file mode 100644 index 00000000..b9e61247 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignFlush_Light.psd.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: 64b9fad609434c489c32b1cdf2004a1c +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignJustified.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignJustified.psd new file mode 100644 index 00000000..3ce55c49 Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignJustified.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignJustified.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignJustified.psd.meta new file mode 100644 index 00000000..f8a90b42 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignJustified.psd.meta @@ -0,0 +1,59 @@ +fileFormatVersion: 2 +guid: 92027f7f8cfc4feaa477da0dc38d3d46 +timeCreated: 1472535271 +licenseType: Pro +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignJustified_Light.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignJustified_Light.psd new file mode 100644 index 00000000..d7fd5c82 Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignJustified_Light.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignJustified_Light.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignJustified_Light.psd.meta new file mode 100644 index 00000000..e5b5aa85 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignJustified_Light.psd.meta @@ -0,0 +1,59 @@ +fileFormatVersion: 2 +guid: fa6bd40a216346b783a4cce741d277a5 +timeCreated: 1472535778 +licenseType: Pro +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignLeft.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignLeft.psd new file mode 100644 index 00000000..fc7e10b2 Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignLeft.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignLeft.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignLeft.psd.meta new file mode 100644 index 00000000..8023379e --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignLeft.psd.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: 9288066c33474b94b6ee5465f4df1cc0 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignLeft_Light.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignLeft_Light.psd new file mode 100644 index 00000000..5522c373 Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignLeft_Light.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignLeft_Light.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignLeft_Light.psd.meta new file mode 100644 index 00000000..aaa8b81d --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignLeft_Light.psd.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: 12736c98af174f91827a26b66d2b01b9 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMidLine.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMidLine.psd new file mode 100644 index 00000000..14d28a2d Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMidLine.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMidLine.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMidLine.psd.meta new file mode 100644 index 00000000..e481463b --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMidLine.psd.meta @@ -0,0 +1,58 @@ +fileFormatVersion: 2 +guid: c2f7f6a88b4c4f20a53deb72f3d9144c +timeCreated: 1426240649 +licenseType: Store +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMiddle.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMiddle.psd new file mode 100644 index 00000000..c4483dbd Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMiddle.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMiddle.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMiddle.psd.meta new file mode 100644 index 00000000..d1ec5285 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMiddle.psd.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: 41b96614b2e6494ba995ddcd252d11ae +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMiddle_Light.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMiddle_Light.psd new file mode 100644 index 00000000..4263bf9b Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMiddle_Light.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMiddle_Light.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMiddle_Light.psd.meta new file mode 100644 index 00000000..7cda20b7 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMiddle_Light.psd.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: 066619c9c9c84f89acb1b48c11a7efe2 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMidline_Light.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMidline_Light.psd new file mode 100644 index 00000000..a5bed371 Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMidline_Light.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMidline_Light.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMidline_Light.psd.meta new file mode 100644 index 00000000..6fabec54 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignMidline_Light.psd.meta @@ -0,0 +1,58 @@ +fileFormatVersion: 2 +guid: bb42b2d967d6427983c901a4ffc8ecd9 +timeCreated: 1426240650 +licenseType: Store +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignRight.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignRight.psd new file mode 100644 index 00000000..4ef1998b Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignRight.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignRight.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignRight.psd.meta new file mode 100644 index 00000000..cf5c7649 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignRight.psd.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: 342a0f8aca7f4f0691338912faec0494 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignRight_Light.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignRight_Light.psd new file mode 100644 index 00000000..bdeff413 Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignRight_Light.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignRight_Light.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignRight_Light.psd.meta new file mode 100644 index 00000000..dab7997c --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignRight_Light.psd.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: e05ace3bd15740cda0bad60d89092a5b +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignTop.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignTop.psd new file mode 100644 index 00000000..b00d4585 Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignTop.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignTop.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignTop.psd.meta new file mode 100644 index 00000000..74931bf8 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignTop.psd.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: 48d034c499ee4697af9dd6e327110249 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignTop_Light.psd b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignTop_Light.psd new file mode 100644 index 00000000..84f0e61c Binary files /dev/null and b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignTop_Light.psd differ diff --git a/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignTop_Light.psd.meta b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignTop_Light.psd.meta new file mode 100644 index 00000000..bbd509d1 --- /dev/null +++ b/Packages/com.unity.ugui/Editor Resources/Textures/btn_AlignTop_Light.psd.meta @@ -0,0 +1,53 @@ +fileFormatVersion: 2 +guid: ed041e68439749a69d0efa0e3d896c2e +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor.meta b/Packages/com.unity.ugui/Editor.meta new file mode 100644 index 00000000..15d7b8f9 --- /dev/null +++ b/Packages/com.unity.ugui/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bee384ad5b4d1a843a018082e7db53cd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP.meta b/Packages/com.unity.ugui/Editor/TMP.meta new file mode 100644 index 00000000..24f73adc --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 10d1425d9e87841d9a9deafe9e93a6f2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/HDRP.meta b/Packages/com.unity.ugui/Editor/TMP/HDRP.meta new file mode 100644 index 00000000..40810974 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/HDRP.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eecc124dc0b994047aac97ccf8c8ed0a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_BaseHDRPLitShaderGUI.cs b/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_BaseHDRPLitShaderGUI.cs new file mode 100644 index 00000000..b4e8e081 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_BaseHDRPLitShaderGUI.cs @@ -0,0 +1,677 @@ +#if HDRP_10_7_OR_NEWER +using UnityEngine; +using UnityEditor; +using UnityEditor.Rendering.HighDefinition; + + +namespace TMPro.EditorUtilities +{ + /// Base class for TextMesh Pro shader GUIs. + internal abstract class TMP_BaseHDRPLitShaderGUI : LightingShaderGraphGUI + { + /// Representation of a #pragma shader_feature. + /// It is assumed that the first feature option is for no keyword (underscores). + protected class ShaderFeature + { + public string undoLabel; + + public GUIContent label; + + /// The keyword labels, for display. Include the no-keyword as the first option. + public GUIContent[] keywordLabels; + + /// The shader keywords. Exclude the no-keyword option. + public string[] keywords; + + int m_State; + + public bool Active + { + get { return m_State >= 0; } + } + + public int State + { + get { return m_State; } + } + + public void ReadState(Material material) + { + for (int i = 0; i < keywords.Length; i++) + { + if (material.IsKeywordEnabled(keywords[i])) + { + m_State = i; + return; + } + } + + m_State = -1; + } + + public void SetActive(bool active, Material material) + { + m_State = active ? 0 : -1; + SetStateKeywords(material); + } + + public void DoPopup(MaterialEditor editor, Material material) + { + EditorGUI.BeginChangeCheck(); + int selection = EditorGUILayout.Popup(label, m_State + 1, keywordLabels); + if (EditorGUI.EndChangeCheck()) + { + m_State = selection - 1; + editor.RegisterPropertyChangeUndo(undoLabel); + SetStateKeywords(material); + } + } + + void SetStateKeywords(Material material) + { + for (int i = 0; i < keywords.Length; i++) + { + if (i == m_State) + { + material.EnableKeyword(keywords[i]); + } + else + { + material.DisableKeyword(keywords[i]); + } + } + } + } + + static GUIContent s_TempLabel = new GUIContent(); + + protected static bool s_DebugExtended; + + static int s_UndoRedoCount, s_LastSeenUndoRedoCount; + + static float[][] s_TempFloats = + { + null, new float[1], new float[2], new float[3], new float[4] + }; + + protected static GUIContent[] s_XywhVectorLabels = + { + new GUIContent("X"), + new GUIContent("Y"), + new GUIContent("W", "Width"), + new GUIContent("H", "Height") + }; + + protected static GUIContent[] s_LbrtVectorLabels = + { + new GUIContent("L", "Left"), + new GUIContent("B", "Bottom"), + new GUIContent("R", "Right"), + new GUIContent("T", "Top") + }; + + protected static GUIContent[] s_CullingTypeLabels = + { + new GUIContent("Off"), + new GUIContent("Front"), + new GUIContent("Back") + }; + + static TMP_BaseHDRPLitShaderGUI() + { + // Keep track of how many undo/redo events happened. + Undo.undoRedoPerformed += () => s_UndoRedoCount += 1; + } + + bool m_IsNewGUI = true; + + float m_DragAndDropMinY; + + protected MaterialEditor m_Editor; + + protected Material m_Material; + + protected MaterialProperty[] m_Properties; + + void PrepareGUI() + { + m_IsNewGUI = false; + ShaderUtilities.GetShaderPropertyIDs(); + + // New GUI just got constructed. This happens in response to a selection, + // but also after undo/redo events. + if (s_LastSeenUndoRedoCount != s_UndoRedoCount) + { + // There's been at least one undo/redo since the last time this GUI got constructed. + // Maybe the undo/redo was for this material? Assume that is was. + TMPro_EventManager.ON_MATERIAL_PROPERTY_CHANGED(true, m_Material as Material); + } + + s_LastSeenUndoRedoCount = s_UndoRedoCount; + } + + protected override void OnMaterialGUI(MaterialEditor materialEditor, MaterialProperty[] properties) + { + m_Editor = materialEditor; + m_Material = materialEditor.target as Material; + this.m_Properties = properties; + + if (m_IsNewGUI) + { + PrepareGUI(); + } + + DoDragAndDropBegin(); + EditorGUI.BeginChangeCheck(); + DoGUI(); + if (EditorGUI.EndChangeCheck()) + { + TMPro_EventManager.ON_MATERIAL_PROPERTY_CHANGED(true, m_Material); + } + + DoDragAndDropEnd(); + } + + /// Override this method to create the specific shader GUI. + protected abstract void DoGUI(); + + static string[] s_PanelStateLabel = new string[] { "\t- Click to collapse -", "\t- Click to expand -" }; + + protected bool BeginPanel(string panel, bool expanded) + { + EditorGUI.indentLevel = 0; + + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + Rect r = EditorGUI.IndentedRect(GUILayoutUtility.GetRect(20, 18)); + r.x += 20; + r.width += 6; + + bool enabled = GUI.enabled; + GUI.enabled = true; + expanded = TMP_EditorUtility.EditorToggle(r, expanded, new GUIContent(panel), TMP_UIStyleManager.panelTitle); + r.width -= 30; + EditorGUI.LabelField(r, new GUIContent(expanded ? s_PanelStateLabel[0] : s_PanelStateLabel[1]), TMP_UIStyleManager.rightLabel); + GUI.enabled = enabled; + + EditorGUI.indentLevel += 1; + EditorGUI.BeginDisabledGroup(false); + + return expanded; + } + + protected bool BeginPanel(string panel, ShaderFeature feature, bool expanded, bool readState = true) + { + EditorGUI.indentLevel = 0; + + if (readState) + { + feature.ReadState(m_Material); + } + + EditorGUI.BeginChangeCheck(); + + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + GUILayout.BeginHorizontal(); + + Rect r = EditorGUI.IndentedRect(GUILayoutUtility.GetRect(20, 20, GUILayout.Width(20f))); + bool active = EditorGUI.Toggle(r, feature.Active); + + if (EditorGUI.EndChangeCheck()) + { + m_Editor.RegisterPropertyChangeUndo(feature.undoLabel); + feature.SetActive(active, m_Material); + } + + r = EditorGUI.IndentedRect(GUILayoutUtility.GetRect(20, 18)); + r.width += 6; + + bool enabled = GUI.enabled; + GUI.enabled = true; + expanded = TMP_EditorUtility.EditorToggle(r, expanded, new GUIContent(panel), TMP_UIStyleManager.panelTitle); + r.width -= 10; + EditorGUI.LabelField(r, new GUIContent(expanded ? s_PanelStateLabel[0] : s_PanelStateLabel[1]), TMP_UIStyleManager.rightLabel); + GUI.enabled = enabled; + + GUILayout.EndHorizontal(); + + EditorGUI.indentLevel += 1; + EditorGUI.BeginDisabledGroup(!active); + + return expanded; + } + + protected void EndPanel() + { + EditorGUI.EndDisabledGroup(); + EditorGUI.indentLevel -= 1; + EditorGUILayout.EndVertical(); + } + + MaterialProperty BeginProperty(string name) + { + MaterialProperty property = FindProperty(name, m_Properties); + EditorGUI.BeginChangeCheck(); + EditorGUI.showMixedValue = property.hasMixedValue; + m_Editor.BeginAnimatedCheck(Rect.zero, property); + + return property; + } + + bool EndProperty() + { + m_Editor.EndAnimatedCheck(); + EditorGUI.showMixedValue = false; + return EditorGUI.EndChangeCheck(); + } + + protected void DoPopup(string name, string label, GUIContent[] options) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + int index = EditorGUILayout.Popup(s_TempLabel, (int)property.floatValue, options); + if (EndProperty()) + { + property.floatValue = index; + } + } + + protected void DoCubeMap(string name, string label) + { + DoTexture(name, label, typeof(Cubemap)); + } + + protected void DoTexture2D(string name, string label, bool withTilingOffset = false, string[] speedNames = null) + { + DoTexture(name, label, typeof(Texture2D), withTilingOffset, speedNames); + } + + void DoTexture(string name, string label, System.Type type, bool withTilingOffset = false, string[] speedNames = null) + { + float objFieldSize = 60f; + bool smallLayout = EditorGUIUtility.currentViewWidth <= 440f && (withTilingOffset || speedNames != null); + float controlHeight = smallLayout ? objFieldSize * 2 : objFieldSize; + + MaterialProperty property = FindProperty(name, m_Properties); + m_Editor.BeginAnimatedCheck(Rect.zero, property); + + Rect rect = EditorGUILayout.GetControlRect(true, controlHeight); + float totalWidth = rect.width; + rect.width = EditorGUIUtility.labelWidth + objFieldSize; + rect.height = objFieldSize; + s_TempLabel.text = label; + + EditorGUI.BeginChangeCheck(); + Object tex = EditorGUI.ObjectField(rect, s_TempLabel, property.textureValue, type, false); + if (EditorGUI.EndChangeCheck()) + { + property.textureValue = tex as Texture; + } + + float additionalHeight = controlHeight - objFieldSize; + float xOffset = smallLayout ? rect.width - objFieldSize : rect.width; + + rect.y += additionalHeight; + rect.x += xOffset; + rect.width = totalWidth - xOffset; + rect.height = EditorGUIUtility.singleLineHeight; + + if (withTilingOffset) + { + DoTilingOffset(rect, property); + rect.y += (rect.height + 2f) * 2f; + } + + m_Editor.EndAnimatedCheck(); + + if (speedNames != null) + { + DoUVSpeed(rect, speedNames); + } + } + + void DoTilingOffset(Rect rect, MaterialProperty property) + { + float labelWidth = EditorGUIUtility.labelWidth; + int indentLevel = EditorGUI.indentLevel; + EditorGUI.indentLevel = 0; + EditorGUIUtility.labelWidth = Mathf.Min(40f, rect.width * 0.40f); + + Vector4 vector = property.textureScaleAndOffset; + + bool changed = false; + float[] values = s_TempFloats[2]; + + s_TempLabel.text = "Tiling"; + Rect vectorRect = EditorGUI.PrefixLabel(rect, s_TempLabel); + values[0] = vector.x; + values[1] = vector.y; + + EditorGUI.BeginChangeCheck(); + EditorGUI.MultiFloatField(vectorRect, s_XywhVectorLabels, values); + if (EditorGUI.EndChangeCheck()) + { + vector.x = values[0]; + vector.y = values[1]; + changed = true; + } + + rect.y += rect.height + 2f; + s_TempLabel.text = "Offset"; + vectorRect = EditorGUI.PrefixLabel(rect, s_TempLabel); + values[0] = vector.z; + values[1] = vector.w; + + EditorGUI.BeginChangeCheck(); + EditorGUI.MultiFloatField(vectorRect, s_XywhVectorLabels, values); + if (EditorGUI.EndChangeCheck()) + { + vector.z = values[0]; + vector.w = values[1]; + changed = true; + } + + if (changed) + { + property.textureScaleAndOffset = vector; + } + + EditorGUIUtility.labelWidth = labelWidth; + EditorGUI.indentLevel = indentLevel; + } + + void DoUVSpeed(Rect rect, string[] names) + { + float labelWidth = EditorGUIUtility.labelWidth; + int indentLevel = EditorGUI.indentLevel; + EditorGUI.indentLevel = 0; + EditorGUIUtility.labelWidth = Mathf.Min(40f, rect.width * 0.40f); + + s_TempLabel.text = "Speed"; + rect = EditorGUI.PrefixLabel(rect, s_TempLabel); + + EditorGUIUtility.labelWidth = 10f; + rect.width = rect.width * 0.5f - 2f; + + if (names.Length == 1) + { + DoFloat2(rect, names[0]); + } + else + { + DoFloat(rect, names[0], "X"); + rect.x += rect.width + 4f; + DoFloat(rect, names[1], "Y"); + } + + EditorGUIUtility.labelWidth = labelWidth; + EditorGUI.indentLevel = indentLevel; + } + + protected void DoToggle(string name, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + bool value = EditorGUILayout.Toggle(s_TempLabel, property.floatValue == 1f); + if (EndProperty()) + { + property.floatValue = value ? 1f : 0f; + } + } + + protected void DoFloat(string name, string label) + { + MaterialProperty property = BeginProperty(name); + Rect rect = EditorGUILayout.GetControlRect(); + rect.width = EditorGUIUtility.labelWidth + 55f; + s_TempLabel.text = label; + float value = EditorGUI.FloatField(rect, s_TempLabel, property.floatValue); + if (EndProperty()) + { + property.floatValue = value; + } + } + + protected void DoColor(string name, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + Color value = EditorGUI.ColorField(EditorGUILayout.GetControlRect(), s_TempLabel, property.colorValue, false, true, true); + if (EndProperty()) + { + property.colorValue = value; + } + } + + void DoFloat(Rect rect, string name, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + float value = EditorGUI.FloatField(rect, s_TempLabel, property.floatValue); + if (EndProperty()) + { + property.floatValue = value; + } + } + + void DoFloat2(Rect rect, string name) + { + MaterialProperty property = BeginProperty(name); + + float x = EditorGUI.FloatField(rect, "X", property.vectorValue.x); + rect.x += rect.width + 4f; + float y = EditorGUI.FloatField(rect, "Y", property.vectorValue.y); + + if (EndProperty()) + { + property.vectorValue = new Vector2(x, y); + } + } + + protected void DoOffset(string name, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + Vector2 value = EditorGUI.Vector2Field(EditorGUILayout.GetControlRect(), s_TempLabel, property.vectorValue); + if (EndProperty()) + { + property.vectorValue = value; + } + } + + protected void DoSlider(string name, string label) + { + MaterialProperty property = BeginProperty(name); + Vector2 range = property.rangeLimits; + s_TempLabel.text = label; + float value = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, property.floatValue, range.x, range.y); + if (EndProperty()) + { + property.floatValue = value; + } + } + + protected void DoSlider(string name, Vector2 range, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + float value = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, property.floatValue, range.x, range.y); + if (EndProperty()) + { + property.floatValue = value; + } + } + + protected void DoSlider(string propertyName, string propertyField, string label) + { + MaterialProperty property = BeginProperty(propertyName); + Vector2 range = property.rangeLimits; + s_TempLabel.text = label; + + Vector4 value = property.vectorValue; + + switch (propertyField) + { + case "X": + value.x = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.x, range.x, range.y); + break; + case "Y": + value.y = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.y, range.x, range.y); + break; + case "Z": + value.z = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.z, range.x, range.y); + break; + case "W": + value.w = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.w, range.x, range.y); + break; + } + + if (EndProperty()) + { + property.vectorValue = value; + } + } + + protected void DoSlider(string propertyName, string propertyField, Vector2 range, string label) + { + MaterialProperty property = BeginProperty(propertyName); + s_TempLabel.text = label; + + Vector4 value = property.vectorValue; + + switch (propertyField) + { + case "X": + value.x = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.x, range.x, range.y); + break; + case "Y": + value.y = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.y, range.x, range.y); + break; + case "Z": + value.z = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.z, range.x, range.y); + break; + case "W": + value.w = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.w, range.x, range.y); + break; + } + + if (EndProperty()) + { + property.vectorValue = value; + } + } + + protected void DoVector2(string name, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + Vector4 value = EditorGUILayout.Vector3Field(s_TempLabel, property.vectorValue); + if (EndProperty()) + { + property.vectorValue = value; + } + } + + protected void DoVector3(string name, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + Vector4 value = EditorGUILayout.Vector3Field(s_TempLabel, property.vectorValue); + if (EndProperty()) + { + property.vectorValue = value; + } + } + + protected void DoVector(string name, string label, GUIContent[] subLabels) + { + MaterialProperty property = BeginProperty(name); + Rect rect = EditorGUILayout.GetControlRect(); + s_TempLabel.text = label; + rect = EditorGUI.PrefixLabel(rect, s_TempLabel); + Vector4 vector = property.vectorValue; + + float[] values = s_TempFloats[subLabels.Length]; + for (int i = 0; i < subLabels.Length; i++) + { + values[i] = vector[i]; + } + + EditorGUI.MultiFloatField(rect, subLabels, values); + if (EndProperty()) + { + for (int i = 0; i < subLabels.Length; i++) + { + vector[i] = values[i]; + } + + property.vectorValue = vector; + } + } + + void DoDragAndDropBegin() + { + m_DragAndDropMinY = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)).y; + } + + void DoDragAndDropEnd() + { + Rect rect = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + Event evt = Event.current; + if (evt.type == EventType.DragUpdated) + { + DragAndDrop.visualMode = DragAndDropVisualMode.Generic; + evt.Use(); + } + else if ( + evt.type == EventType.DragPerform && + Rect.MinMaxRect(rect.xMin, m_DragAndDropMinY, rect.xMax, rect.yMax).Contains(evt.mousePosition) + ) + { + DragAndDrop.AcceptDrag(); + evt.Use(); + Material droppedMaterial = DragAndDrop.objectReferences[0] as Material; + if (droppedMaterial && droppedMaterial != m_Material) + { + PerformDrop(droppedMaterial); + } + } + } + + void PerformDrop(Material droppedMaterial) + { + Texture droppedTex = droppedMaterial.GetTexture(ShaderUtilities.ID_MainTex); + if (!droppedTex) + { + return; + } + + Texture currentTex = m_Material.GetTexture(ShaderUtilities.ID_MainTex); + TMP_FontAsset requiredFontAsset = null; + if (droppedTex != currentTex) + { + requiredFontAsset = TMP_EditorUtility.FindMatchingFontAsset(droppedMaterial); + if (!requiredFontAsset) + { + return; + } + } + + foreach (GameObject o in Selection.gameObjects) + { + if (requiredFontAsset) + { + TMP_Text textComponent = o.GetComponent(); + if (textComponent) + { + Undo.RecordObject(textComponent, "Font Asset Change"); + textComponent.font = requiredFontAsset; + } + } + + TMPro_EventManager.ON_DRAG_AND_DROP_MATERIAL_CHANGED(o, m_Material, droppedMaterial); + EditorUtility.SetDirty(o); + } + } + } +} +#endif diff --git a/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_BaseHDRPLitShaderGUI.cs.meta b/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_BaseHDRPLitShaderGUI.cs.meta new file mode 100644 index 00000000..6520fedf --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_BaseHDRPLitShaderGUI.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e3795795b029fde4395e6953ce72b5a6 +timeCreated: 1469844810 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_BaseHDRPUnlitShaderGUI.cs b/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_BaseHDRPUnlitShaderGUI.cs new file mode 100644 index 00000000..f1658249 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_BaseHDRPUnlitShaderGUI.cs @@ -0,0 +1,681 @@ +#if HDRP_10_7_OR_NEWER +using UnityEngine; +using UnityEditor; +using UnityEditor.Rendering.HighDefinition; + + +namespace TMPro.EditorUtilities +{ + /// Base class for TextMesh Pro shader GUIs. + #if HDRP_11_OR_NEWER + internal abstract class TMP_BaseHDRPUnlitShaderGUI : UnlitShaderGraphGUI + #else + internal abstract class TMP_BaseHDRPUnlitShaderGUI : HDUnlitGUI + #endif + { + /// Representation of a #pragma shader_feature. + /// It is assumed that the first feature option is for no keyword (underscores). + protected class ShaderFeature + { + public string undoLabel; + + public GUIContent label; + + /// The keyword labels, for display. Include the no-keyword as the first option. + public GUIContent[] keywordLabels; + + /// The shader keywords. Exclude the no-keyword option. + public string[] keywords; + + int m_State; + + public bool Active + { + get { return m_State >= 0; } + } + + public int State + { + get { return m_State; } + } + + public void ReadState(Material material) + { + for (int i = 0; i < keywords.Length; i++) + { + if (material.IsKeywordEnabled(keywords[i])) + { + m_State = i; + return; + } + } + + m_State = -1; + } + + public void SetActive(bool active, Material material) + { + m_State = active ? 0 : -1; + SetStateKeywords(material); + } + + public void DoPopup(MaterialEditor editor, Material material) + { + EditorGUI.BeginChangeCheck(); + int selection = EditorGUILayout.Popup(label, m_State + 1, keywordLabels); + if (EditorGUI.EndChangeCheck()) + { + m_State = selection - 1; + editor.RegisterPropertyChangeUndo(undoLabel); + SetStateKeywords(material); + } + } + + void SetStateKeywords(Material material) + { + for (int i = 0; i < keywords.Length; i++) + { + if (i == m_State) + { + material.EnableKeyword(keywords[i]); + } + else + { + material.DisableKeyword(keywords[i]); + } + } + } + } + + static GUIContent s_TempLabel = new GUIContent(); + + protected static bool s_DebugExtended; + + static int s_UndoRedoCount, s_LastSeenUndoRedoCount; + + static float[][] s_TempFloats = + { + null, new float[1], new float[2], new float[3], new float[4] + }; + + protected static GUIContent[] s_XywhVectorLabels = + { + new GUIContent("X"), + new GUIContent("Y"), + new GUIContent("W", "Width"), + new GUIContent("H", "Height") + }; + + protected static GUIContent[] s_LbrtVectorLabels = + { + new GUIContent("L", "Left"), + new GUIContent("B", "Bottom"), + new GUIContent("R", "Right"), + new GUIContent("T", "Top") + }; + + protected static GUIContent[] s_CullingTypeLabels = + { + new GUIContent("Off"), + new GUIContent("Front"), + new GUIContent("Back") + }; + + static TMP_BaseHDRPUnlitShaderGUI() + { + // Keep track of how many undo/redo events happened. + Undo.undoRedoPerformed += () => s_UndoRedoCount += 1; + } + + bool m_IsNewGUI = true; + + float m_DragAndDropMinY; + + protected MaterialEditor m_Editor; + + protected Material m_Material; + + protected MaterialProperty[] m_Properties; + + void PrepareGUI() + { + m_IsNewGUI = false; + ShaderUtilities.GetShaderPropertyIDs(); + + // New GUI just got constructed. This happens in response to a selection, + // but also after undo/redo events. + if (s_LastSeenUndoRedoCount != s_UndoRedoCount) + { + // There's been at least one undo/redo since the last time this GUI got constructed. + // Maybe the undo/redo was for this material? Assume that is was. + TMPro_EventManager.ON_MATERIAL_PROPERTY_CHANGED(true, m_Material as Material); + } + + s_LastSeenUndoRedoCount = s_UndoRedoCount; + } + + protected override void OnMaterialGUI(MaterialEditor materialEditor, MaterialProperty[] properties) + { + m_Editor = materialEditor; + m_Material = materialEditor.target as Material; + this.m_Properties = properties; + + if (m_IsNewGUI) + { + PrepareGUI(); + } + + DoDragAndDropBegin(); + EditorGUI.BeginChangeCheck(); + DoGUI(); + if (EditorGUI.EndChangeCheck()) + { + TMPro_EventManager.ON_MATERIAL_PROPERTY_CHANGED(true, m_Material); + } + + DoDragAndDropEnd(); + } + + /// Override this method to create the specific shader GUI. + protected abstract void DoGUI(); + + static string[] s_PanelStateLabel = new string[] { "\t- Click to collapse -", "\t- Click to expand -" }; + + protected bool BeginPanel(string panel, bool expanded) + { + EditorGUI.indentLevel = 0; + + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + Rect r = EditorGUI.IndentedRect(GUILayoutUtility.GetRect(20, 18)); + r.x += 20; + r.width += 6; + + bool enabled = GUI.enabled; + GUI.enabled = true; + expanded = TMP_EditorUtility.EditorToggle(r, expanded, new GUIContent(panel), TMP_UIStyleManager.panelTitle); + r.width -= 30; + EditorGUI.LabelField(r, new GUIContent(expanded ? s_PanelStateLabel[0] : s_PanelStateLabel[1]), TMP_UIStyleManager.rightLabel); + GUI.enabled = enabled; + + EditorGUI.indentLevel += 1; + EditorGUI.BeginDisabledGroup(false); + + return expanded; + } + + protected bool BeginPanel(string panel, ShaderFeature feature, bool expanded, bool readState = true) + { + EditorGUI.indentLevel = 0; + + if (readState) + { + feature.ReadState(m_Material); + } + + EditorGUI.BeginChangeCheck(); + + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + GUILayout.BeginHorizontal(); + + Rect r = EditorGUI.IndentedRect(GUILayoutUtility.GetRect(20, 20, GUILayout.Width(20f))); + bool active = EditorGUI.Toggle(r, feature.Active); + + if (EditorGUI.EndChangeCheck()) + { + m_Editor.RegisterPropertyChangeUndo(feature.undoLabel); + feature.SetActive(active, m_Material); + } + + r = EditorGUI.IndentedRect(GUILayoutUtility.GetRect(20, 18)); + r.width += 6; + + bool enabled = GUI.enabled; + GUI.enabled = true; + expanded = TMP_EditorUtility.EditorToggle(r, expanded, new GUIContent(panel), TMP_UIStyleManager.panelTitle); + r.width -= 10; + EditorGUI.LabelField(r, new GUIContent(expanded ? s_PanelStateLabel[0] : s_PanelStateLabel[1]), TMP_UIStyleManager.rightLabel); + GUI.enabled = enabled; + + GUILayout.EndHorizontal(); + + EditorGUI.indentLevel += 1; + EditorGUI.BeginDisabledGroup(!active); + + return expanded; + } + + protected void EndPanel() + { + EditorGUI.EndDisabledGroup(); + EditorGUI.indentLevel -= 1; + EditorGUILayout.EndVertical(); + } + + MaterialProperty BeginProperty(string name) + { + MaterialProperty property = FindProperty(name, m_Properties); + EditorGUI.BeginChangeCheck(); + EditorGUI.showMixedValue = property.hasMixedValue; + m_Editor.BeginAnimatedCheck(Rect.zero, property); + + return property; + } + + bool EndProperty() + { + m_Editor.EndAnimatedCheck(); + EditorGUI.showMixedValue = false; + return EditorGUI.EndChangeCheck(); + } + + protected void DoPopup(string name, string label, GUIContent[] options) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + int index = EditorGUILayout.Popup(s_TempLabel, (int)property.floatValue, options); + if (EndProperty()) + { + property.floatValue = index; + } + } + + protected void DoCubeMap(string name, string label) + { + DoTexture(name, label, typeof(Cubemap)); + } + + protected void DoTexture2D(string name, string label, bool withTilingOffset = false, string[] speedNames = null) + { + DoTexture(name, label, typeof(Texture2D), withTilingOffset, speedNames); + } + + void DoTexture(string name, string label, System.Type type, bool withTilingOffset = false, string[] speedNames = null) + { + float objFieldSize = 60f; + bool smallLayout = EditorGUIUtility.currentViewWidth <= 440f && (withTilingOffset || speedNames != null); + float controlHeight = smallLayout ? objFieldSize * 2 : objFieldSize; + + MaterialProperty property = FindProperty(name, m_Properties); + m_Editor.BeginAnimatedCheck(Rect.zero, property); + + Rect rect = EditorGUILayout.GetControlRect(true, controlHeight); + float totalWidth = rect.width; + rect.width = EditorGUIUtility.labelWidth + objFieldSize; + rect.height = objFieldSize; + s_TempLabel.text = label; + + EditorGUI.BeginChangeCheck(); + Object tex = EditorGUI.ObjectField(rect, s_TempLabel, property.textureValue, type, false); + if (EditorGUI.EndChangeCheck()) + { + property.textureValue = tex as Texture; + } + + float additionalHeight = controlHeight - objFieldSize; + float xOffset = smallLayout ? rect.width - objFieldSize : rect.width; + + rect.y += additionalHeight; + rect.x += xOffset; + rect.width = totalWidth - xOffset; + rect.height = EditorGUIUtility.singleLineHeight; + + if (withTilingOffset) + { + DoTilingOffset(rect, property); + rect.y += (rect.height + 2f) * 2f; + } + + m_Editor.EndAnimatedCheck(); + + if (speedNames != null) + { + DoUVSpeed(rect, speedNames); + } + } + + void DoTilingOffset(Rect rect, MaterialProperty property) + { + float labelWidth = EditorGUIUtility.labelWidth; + int indentLevel = EditorGUI.indentLevel; + EditorGUI.indentLevel = 0; + EditorGUIUtility.labelWidth = Mathf.Min(40f, rect.width * 0.40f); + + Vector4 vector = property.textureScaleAndOffset; + + bool changed = false; + float[] values = s_TempFloats[2]; + + s_TempLabel.text = "Tiling"; + Rect vectorRect = EditorGUI.PrefixLabel(rect, s_TempLabel); + values[0] = vector.x; + values[1] = vector.y; + + EditorGUI.BeginChangeCheck(); + EditorGUI.MultiFloatField(vectorRect, s_XywhVectorLabels, values); + if (EditorGUI.EndChangeCheck()) + { + vector.x = values[0]; + vector.y = values[1]; + changed = true; + } + + rect.y += rect.height + 2f; + s_TempLabel.text = "Offset"; + vectorRect = EditorGUI.PrefixLabel(rect, s_TempLabel); + values[0] = vector.z; + values[1] = vector.w; + + EditorGUI.BeginChangeCheck(); + EditorGUI.MultiFloatField(vectorRect, s_XywhVectorLabels, values); + if (EditorGUI.EndChangeCheck()) + { + vector.z = values[0]; + vector.w = values[1]; + changed = true; + } + + if (changed) + { + property.textureScaleAndOffset = vector; + } + + EditorGUIUtility.labelWidth = labelWidth; + EditorGUI.indentLevel = indentLevel; + } + + void DoUVSpeed(Rect rect, string[] names) + { + float labelWidth = EditorGUIUtility.labelWidth; + int indentLevel = EditorGUI.indentLevel; + EditorGUI.indentLevel = 0; + EditorGUIUtility.labelWidth = Mathf.Min(40f, rect.width * 0.40f); + + s_TempLabel.text = "Speed"; + rect = EditorGUI.PrefixLabel(rect, s_TempLabel); + + EditorGUIUtility.labelWidth = 10f; + rect.width = rect.width * 0.5f - 2f; + + if (names.Length == 1) + { + DoFloat2(rect, names[0]); + } + else + { + DoFloat(rect, names[0], "X"); + rect.x += rect.width + 4f; + DoFloat(rect, names[1], "Y"); + } + + EditorGUIUtility.labelWidth = labelWidth; + EditorGUI.indentLevel = indentLevel; + } + + protected void DoToggle(string name, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + bool value = EditorGUILayout.Toggle(s_TempLabel, property.floatValue == 1f); + if (EndProperty()) + { + property.floatValue = value ? 1f : 0f; + } + } + + protected void DoFloat(string name, string label) + { + MaterialProperty property = BeginProperty(name); + Rect rect = EditorGUILayout.GetControlRect(); + rect.width = EditorGUIUtility.labelWidth + 55f; + s_TempLabel.text = label; + float value = EditorGUI.FloatField(rect, s_TempLabel, property.floatValue); + if (EndProperty()) + { + property.floatValue = value; + } + } + + protected void DoColor(string name, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + Color value = EditorGUI.ColorField(EditorGUILayout.GetControlRect(), s_TempLabel, property.colorValue, false, true, true); + if (EndProperty()) + { + property.colorValue = value; + } + } + + void DoFloat(Rect rect, string name, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + float value = EditorGUI.FloatField(rect, s_TempLabel, property.floatValue); + if (EndProperty()) + { + property.floatValue = value; + } + } + + void DoFloat2(Rect rect, string name) + { + MaterialProperty property = BeginProperty(name); + + float x = EditorGUI.FloatField(rect, "X", property.vectorValue.x); + rect.x += rect.width + 4f; + float y = EditorGUI.FloatField(rect, "Y", property.vectorValue.y); + + if (EndProperty()) + { + property.vectorValue = new Vector2(x, y); + } + } + + protected void DoOffset(string name, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + Vector2 value = EditorGUI.Vector2Field(EditorGUILayout.GetControlRect(), s_TempLabel, property.vectorValue); + if (EndProperty()) + { + property.vectorValue = value; + } + } + + protected void DoSlider(string name, string label) + { + MaterialProperty property = BeginProperty(name); + Vector2 range = property.rangeLimits; + s_TempLabel.text = label; + float value = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, property.floatValue, range.x, range.y); + if (EndProperty()) + { + property.floatValue = value; + } + } + + protected void DoSlider(string name, Vector2 range, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + float value = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, property.floatValue, range.x, range.y); + if (EndProperty()) + { + property.floatValue = value; + } + } + + protected void DoSlider(string propertyName, string propertyField, string label) + { + MaterialProperty property = BeginProperty(propertyName); + Vector2 range = property.rangeLimits; + s_TempLabel.text = label; + + Vector4 value = property.vectorValue; + + switch (propertyField) + { + case "X": + value.x = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.x, range.x, range.y); + break; + case "Y": + value.y = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.y, range.x, range.y); + break; + case "Z": + value.z = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.z, range.x, range.y); + break; + case "W": + value.w = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.w, range.x, range.y); + break; + } + + if (EndProperty()) + { + property.vectorValue = value; + } + } + + protected void DoSlider(string propertyName, string propertyField, Vector2 range, string label) + { + MaterialProperty property = BeginProperty(propertyName); + s_TempLabel.text = label; + + Vector4 value = property.vectorValue; + + switch (propertyField) + { + case "X": + value.x = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.x, range.x, range.y); + break; + case "Y": + value.y = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.y, range.x, range.y); + break; + case "Z": + value.z = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.z, range.x, range.y); + break; + case "W": + value.w = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.w, range.x, range.y); + break; + } + + if (EndProperty()) + { + property.vectorValue = value; + } + } + + protected void DoVector2(string name, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + Vector4 value = EditorGUILayout.Vector3Field(s_TempLabel, property.vectorValue); + if (EndProperty()) + { + property.vectorValue = value; + } + } + + protected void DoVector3(string name, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + Vector4 value = EditorGUILayout.Vector3Field(s_TempLabel, property.vectorValue); + if (EndProperty()) + { + property.vectorValue = value; + } + } + + protected void DoVector(string name, string label, GUIContent[] subLabels) + { + MaterialProperty property = BeginProperty(name); + Rect rect = EditorGUILayout.GetControlRect(); + s_TempLabel.text = label; + rect = EditorGUI.PrefixLabel(rect, s_TempLabel); + Vector4 vector = property.vectorValue; + + float[] values = s_TempFloats[subLabels.Length]; + for (int i = 0; i < subLabels.Length; i++) + { + values[i] = vector[i]; + } + + EditorGUI.MultiFloatField(rect, subLabels, values); + if (EndProperty()) + { + for (int i = 0; i < subLabels.Length; i++) + { + vector[i] = values[i]; + } + + property.vectorValue = vector; + } + } + + void DoDragAndDropBegin() + { + m_DragAndDropMinY = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)).y; + } + + void DoDragAndDropEnd() + { + Rect rect = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + Event evt = Event.current; + if (evt.type == EventType.DragUpdated) + { + DragAndDrop.visualMode = DragAndDropVisualMode.Generic; + evt.Use(); + } + else if ( + evt.type == EventType.DragPerform && + Rect.MinMaxRect(rect.xMin, m_DragAndDropMinY, rect.xMax, rect.yMax).Contains(evt.mousePosition) + ) + { + DragAndDrop.AcceptDrag(); + evt.Use(); + Material droppedMaterial = DragAndDrop.objectReferences[0] as Material; + if (droppedMaterial && droppedMaterial != m_Material) + { + PerformDrop(droppedMaterial); + } + } + } + + void PerformDrop(Material droppedMaterial) + { + Texture droppedTex = droppedMaterial.GetTexture(ShaderUtilities.ID_MainTex); + if (!droppedTex) + { + return; + } + + Texture currentTex = m_Material.GetTexture(ShaderUtilities.ID_MainTex); + TMP_FontAsset requiredFontAsset = null; + if (droppedTex != currentTex) + { + requiredFontAsset = TMP_EditorUtility.FindMatchingFontAsset(droppedMaterial); + if (!requiredFontAsset) + { + return; + } + } + + foreach (GameObject o in Selection.gameObjects) + { + if (requiredFontAsset) + { + TMP_Text textComponent = o.GetComponent(); + if (textComponent) + { + Undo.RecordObject(textComponent, "Font Asset Change"); + textComponent.font = requiredFontAsset; + } + } + + TMPro_EventManager.ON_DRAG_AND_DROP_MATERIAL_CHANGED(o, m_Material, droppedMaterial); + EditorUtility.SetDirty(o); + } + } + } +} +#endif diff --git a/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_BaseHDRPUnlitShaderGUI.cs.meta b/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_BaseHDRPUnlitShaderGUI.cs.meta new file mode 100644 index 00000000..e7f11a6c --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_BaseHDRPUnlitShaderGUI.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 645409e9544820042937871953f20509 +timeCreated: 1469844810 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_SDF_HDRPLitShaderGUI.cs b/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_SDF_HDRPLitShaderGUI.cs new file mode 100644 index 00000000..8cfc7273 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_SDF_HDRPLitShaderGUI.cs @@ -0,0 +1,631 @@ +#if HDRP_10_7_OR_NEWER +using UnityEngine; +using UnityEditor; + +using UnityEditor.Rendering.HighDefinition; + +namespace TMPro.EditorUtilities +{ + internal class TMP_SDF_HDRPLitShaderGUI : TMP_BaseHDRPLitShaderGUI + { + static ShaderFeature s_OutlineFeature, s_UnderlayFeature, s_BevelFeature, s_GlowFeature, s_MaskFeature; + + static bool s_Face = true, s_Outline = true, s_Outline2 = true, s_Outline3 = true, s_Underlay = true, s_Lighting = true, s_Glow, s_Bevel, s_Light, s_Bump, s_Env; + + static string[] + s_FaceUVSpeedName = { "_FaceUVSpeed" }, + s_FaceUvSpeedNames = { "_FaceUVSpeedX", "_FaceUVSpeedY" }, + s_OutlineUvSpeedNames = { "_OutlineUVSpeedX", "_OutlineUVSpeedY" }, + s_OutlineUvSpeedName = { "_OutlineUVSpeed" }; + + /// + /// + /// + static TMP_SDF_HDRPLitShaderGUI() + { + s_OutlineFeature = new ShaderFeature() + { + undoLabel = "Outline", + keywords = new[] { "OUTLINE_ON" } + }; + + s_UnderlayFeature = new ShaderFeature() + { + undoLabel = "Underlay", + keywords = new[] { "UNDERLAY_ON", "UNDERLAY_INNER" }, + label = new GUIContent("Underlay Type"), + keywordLabels = new[] + { + new GUIContent("None"), new GUIContent("Normal"), new GUIContent("Inner") + } + }; + + s_BevelFeature = new ShaderFeature() + { + undoLabel = "Bevel", + keywords = new[] { "BEVEL_ON" } + }; + + s_GlowFeature = new ShaderFeature() + { + undoLabel = "Glow", + keywords = new[] { "GLOW_ON" } + }; + + s_MaskFeature = new ShaderFeature() + { + undoLabel = "Mask", + keywords = new[] { "MASK_HARD", "MASK_SOFT" }, + label = new GUIContent("Mask"), + keywordLabels = new[] + { + new GUIContent("Mask Off"), new GUIContent("Mask Hard"), new GUIContent("Mask Soft") + } + }; + } + + /// + /// + /// + public TMP_SDF_HDRPLitShaderGUI() + { + // Remove the ShaderGraphUIBlock to avoid having duplicated properties in the UI. + uiBlocks.RemoveAll(b => b is ShaderGraphUIBlock); + } + + protected override void DoGUI() + { + s_Face = BeginPanel("Face", s_Face); + if (s_Face) + { + DoFacePanel(); + } + + EndPanel(); + + // Outline panels + DoOutlinePanels(); + + // Underlay panel + s_Underlay = BeginPanel("Underlay", s_Underlay); + if (s_Underlay) + { + DoUnderlayPanel(); + } + + EndPanel(); + + // Lighting panel + DrawLightingPanel(); + + /* + if (m_Material.HasProperty(ShaderUtilities.ID_GlowColor)) + { + s_Glow = BeginPanel("Glow", s_GlowFeature, s_Glow); + if (s_Glow) + { + DoGlowPanel(); + } + + EndPanel(); + } + */ + + s_DebugExtended = BeginPanel("Debug Settings", s_DebugExtended); + if (s_DebugExtended) + { + DoDebugPanelSRP(); + } + EndPanel(); + + EditorGUILayout.Space(); + EditorGUILayout.Space(); + + // Draw HDRP panels + uiBlocks.OnGUI(m_Editor, m_Properties); + #if HDRP_12_OR_NEWER + ValidateMaterial(m_Material); + #else + SetupMaterialKeywordsAndPass(m_Material); + #endif + } + + void DoFacePanel() + { + EditorGUI.indentLevel += 1; + + DoColor("_FaceColor", "Color"); + + if (m_Material.HasProperty(ShaderUtilities.ID_FaceTex)) + { + if (m_Material.HasProperty("_FaceUVSpeedX")) + { + DoTexture2D("_FaceTex", "Texture", true, s_FaceUvSpeedNames); + } + else if (m_Material.HasProperty("_FaceUVSpeed")) + { + DoTexture2D("_FaceTex", "Texture", true, s_FaceUVSpeedName); + } + else + { + DoTexture2D("_FaceTex", "Texture", true); + } + } + + if (m_Material.HasProperty("_Softness")) + { + DoSlider("_Softness", "X", new Vector2(0, 1), "Softness"); + } + + if (m_Material.HasProperty("_OutlineSoftness")) + { + DoSlider("_OutlineSoftness", "Softness"); + } + + if (m_Material.HasProperty(ShaderUtilities.ID_FaceDilate)) + { + DoSlider("_FaceDilate", "Dilate"); + if (m_Material.HasProperty(ShaderUtilities.ID_Shininess)) + { + DoSlider("_FaceShininess", "Gloss"); + } + } + + if (m_Material.HasProperty(ShaderUtilities.ID_IsoPerimeter)) + { + DoSlider("_IsoPerimeter", "X", new Vector2(-1, 1), "Dilate"); + } + + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoOutlinePanels() + { + s_Outline = BeginPanel("Outline 1", s_Outline); + if (s_Outline) + DoOutlinePanelWithTexture(1, "Y", "Color"); + + EndPanel(); + + s_Outline2 = BeginPanel("Outline 2", s_Outline2); + if (s_Outline2) + DoOutlinePanel(2, "Z", "Color"); + + EndPanel(); + + s_Outline3 = BeginPanel("Outline 3", s_Outline3); + if (s_Outline3) + DoOutlinePanel(3, "W", "Color"); + + EndPanel(); + } + + void DoOutlinePanel(int outlineID, string propertyField, string label) + { + EditorGUI.indentLevel += 1; + DoColor("_OutlineColor" + outlineID, label); + + if (outlineID != 3) + DoOffset("_OutlineOffset" + outlineID, "Offset"); + else + { + if (m_Material.GetFloat(ShaderUtilities.ID_OutlineMode) == 0) + DoOffset("_OutlineOffset" + outlineID, "Offset"); + } + + DoSlider("_Softness", propertyField, new Vector2(0, 1), "Softness"); + DoSlider("_IsoPerimeter", propertyField, new Vector2(-1, 1), "Dilate"); + + if (outlineID == 3) + { + DoToggle("_OutlineMode", "Outline Mode"); + } + + if (m_Material.HasProperty("_OutlineShininess")) + { + //DoSlider("_OutlineShininess", "Gloss"); + } + + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoOutlinePanelWithTexture(int outlineID, string propertyField, string label) + { + EditorGUI.indentLevel += 1; + DoColor("_OutlineColor" + outlineID, label); + if (m_Material.HasProperty(ShaderUtilities.ID_OutlineTex)) + { + if (m_Material.HasProperty("_OutlineUVSpeedX")) + { + DoTexture2D("_OutlineTex", "Texture", true, s_OutlineUvSpeedNames); + } + else if (m_Material.HasProperty("_OutlineUVSpeed")) + { + DoTexture2D("_OutlineTex", "Texture", true, s_OutlineUvSpeedName); + } + else + { + DoTexture2D("_OutlineTex", "Texture", true); + } + } + + DoOffset("_OutlineOffset" + outlineID, "Offset"); + DoSlider("_Softness", propertyField, new Vector2(0, 1), "Softness"); + DoSlider("_IsoPerimeter", propertyField, new Vector2(-1, 1), "Dilate"); + + if (m_Material.HasProperty("_OutlineShininess")) + { + //DoSlider("_OutlineShininess", "Gloss"); + } + + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoUnderlayPanel() + { + EditorGUI.indentLevel += 1; + + if (m_Material.HasProperty(ShaderUtilities.ID_IsoPerimeter)) + { + DoColor("_UnderlayColor", "Color"); + DoSlider("_UnderlayOffset", "X", new Vector2(-1, 1), "Offset X"); + DoSlider("_UnderlayOffset", "Y", new Vector2(-1, 1), "Offset Y"); + DoSlider("_UnderlayDilate", new Vector2(-1, 1), "Dilate"); + DoSlider("_UnderlaySoftness", new Vector2(0, 1), "Softness"); + } + else + { + s_UnderlayFeature.DoPopup(m_Editor, m_Material); + DoColor("_UnderlayColor", "Color"); + DoSlider("_UnderlayOffsetX", "Offset X"); + DoSlider("_UnderlayOffsetY", "Offset Y"); + DoSlider("_UnderlayDilate", "Dilate"); + DoSlider("_UnderlaySoftness", "Softness"); + } + + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + static GUIContent[] s_BevelTypeLabels = + { + new GUIContent("Outer Bevel"), + new GUIContent("Inner Bevel") + }; + + void DrawLightingPanel() + { + s_Lighting = BeginPanel("Lighting", s_Lighting); + if (s_Lighting) + { + s_Bevel = BeginPanel("Bevel", s_Bevel); + if (s_Bevel) + { + DoBevelPanel(); + } + EndPanel(); + + s_Light = BeginPanel("Local Lighting", s_Light); + if (s_Light) + { + DoLocalLightingPanel(); + } + EndPanel(); + + /* + s_Bump = BeginPanel("Bump Map", s_Bump); + if (s_Bump) + { + DoBumpMapPanel(); + } + + EndPanel(); + + s_Env = BeginPanel("Environment Map", s_Env); + if (s_Env) + { + DoEnvMapPanel(); + } + + EndPanel(); + */ + } + + EndPanel(); + } + + void DoBevelPanel() + { + EditorGUI.indentLevel += 1; + DoPopup("_BevelType", "Type", s_BevelTypeLabels); + DoSlider("_BevelAmount", "Amount"); + DoSlider("_BevelOffset", "Offset"); + DoSlider("_BevelWidth", "Width"); + DoSlider("_BevelRoundness", "Roundness"); + DoSlider("_BevelClamp", "Clamp"); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoLocalLightingPanel() + { + EditorGUI.indentLevel += 1; + DoSlider("_LightAngle", "Light Angle"); + DoColor("_SpecularColor", "Specular Color"); + DoSlider("_SpecularPower", "Specular Power"); + DoSlider("_Reflectivity", "Reflectivity Power"); + DoSlider("_Diffuse", "Diffuse Shadow"); + DoSlider("_Ambient", "Ambient Shadow"); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoSurfaceLightingPanel() + { + EditorGUI.indentLevel += 1; + DoColor("_SpecColor", "Specular Color"); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoBumpMapPanel() + { + EditorGUI.indentLevel += 1; + DoTexture2D("_BumpMap", "Texture"); + DoSlider("_BumpFace", "Face"); + DoSlider("_BumpOutline", "Outline"); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoEnvMapPanel() + { + EditorGUI.indentLevel += 1; + DoColor("_ReflectFaceColor", "Face Color"); + DoColor("_ReflectOutlineColor", "Outline Color"); + DoCubeMap("_Cube", "Texture"); + DoVector3("_EnvMatrixRotation", "Rotation"); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoGlowPanel() + { + EditorGUI.indentLevel += 1; + DoColor("_GlowColor", "Color"); + DoSlider("_GlowOffset", "Offset"); + DoSlider("_GlowInner", "Inner"); + DoSlider("_GlowOuter", "Outer"); + DoSlider("_GlowPower", "Power"); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoDebugPanel() + { + EditorGUI.indentLevel += 1; + DoTexture2D("_MainTex", "Font Atlas"); + DoFloat("_GradientScale", "Gradient Scale"); + DoFloat("_TextureWidth", "Texture Width"); + DoFloat("_TextureHeight", "Texture Height"); + EditorGUILayout.Space(); + DoFloat("_ScaleX", "Scale X"); + DoFloat("_ScaleY", "Scale Y"); + + if (m_Material.HasProperty(ShaderUtilities.ID_Sharpness)) + DoSlider("_Sharpness", "Sharpness"); + + DoSlider("_PerspectiveFilter", "Perspective Filter"); + EditorGUILayout.Space(); + DoFloat("_VertexOffsetX", "Offset X"); + DoFloat("_VertexOffsetY", "Offset Y"); + + if (m_Material.HasProperty(ShaderUtilities.ID_MaskCoord)) + { + EditorGUILayout.Space(); + s_MaskFeature.ReadState(m_Material); + s_MaskFeature.DoPopup(m_Editor, m_Material); + if (s_MaskFeature.Active) + { + DoMaskSubgroup(); + } + + EditorGUILayout.Space(); + DoVector("_ClipRect", "Clip Rect", s_LbrtVectorLabels); + } + else if (m_Material.HasProperty("_MaskTex")) + { + DoMaskTexSubgroup(); + } + else if (m_Material.HasProperty(ShaderUtilities.ID_MaskSoftnessX)) + { + EditorGUILayout.Space(); + DoFloat("_MaskSoftnessX", "Softness X"); + DoFloat("_MaskSoftnessY", "Softness Y"); + DoVector("_ClipRect", "Clip Rect", s_LbrtVectorLabels); + } + + if (m_Material.HasProperty(ShaderUtilities.ID_StencilID)) + { + EditorGUILayout.Space(); + DoFloat("_Stencil", "Stencil ID"); + DoFloat("_StencilComp", "Stencil Comp"); + } + + EditorGUILayout.Space(); + + EditorGUI.BeginChangeCheck(); + bool useRatios = EditorGUILayout.Toggle("Use Ratios", !m_Material.IsKeywordEnabled("RATIOS_OFF")); + if (EditorGUI.EndChangeCheck()) + { + m_Editor.RegisterPropertyChangeUndo("Use Ratios"); + if (useRatios) + { + m_Material.DisableKeyword("RATIOS_OFF"); + } + else + { + m_Material.EnableKeyword("RATIOS_OFF"); + } + } + + if (m_Material.HasProperty(ShaderUtilities.ShaderTag_CullMode)) + { + EditorGUILayout.Space(); + DoPopup("_CullMode", "Cull Mode", s_CullingTypeLabels); + } + + EditorGUILayout.Space(); + + EditorGUI.BeginDisabledGroup(true); + DoFloat("_ScaleRatioA", "Scale Ratio A"); + DoFloat("_ScaleRatioB", "Scale Ratio B"); + DoFloat("_ScaleRatioC", "Scale Ratio C"); + EditorGUI.EndDisabledGroup(); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoDebugPanelSRP() + { + EditorGUI.indentLevel += 1; + DoTexture2D("_MainTex", "Font Atlas"); + DoFloat("_GradientScale", "Gradient Scale"); + //DoFloat("_TextureWidth", "Texture Width"); + //DoFloat("_TextureHeight", "Texture Height"); + EditorGUILayout.Space(); + + /* + DoFloat("_ScaleX", "Scale X"); + DoFloat("_ScaleY", "Scale Y"); + + if (m_Material.HasProperty(ShaderUtilities.ID_Sharpness)) + DoSlider("_Sharpness", "Sharpness"); + + DoSlider("_PerspectiveFilter", "Perspective Filter"); + EditorGUILayout.Space(); + DoFloat("_VertexOffsetX", "Offset X"); + DoFloat("_VertexOffsetY", "Offset Y"); + + if (m_Material.HasProperty(ShaderUtilities.ID_MaskCoord)) + { + EditorGUILayout.Space(); + s_MaskFeature.ReadState(m_Material); + s_MaskFeature.DoPopup(m_Editor, m_Material); + if (s_MaskFeature.Active) + { + DoMaskSubgroup(); + } + + EditorGUILayout.Space(); + DoVector("_ClipRect", "Clip Rect", s_LbrtVectorLabels); + } + else if (m_Material.HasProperty("_MaskTex")) + { + DoMaskTexSubgroup(); + } + else if (m_Material.HasProperty(ShaderUtilities.ID_MaskSoftnessX)) + { + EditorGUILayout.Space(); + DoFloat("_MaskSoftnessX", "Softness X"); + DoFloat("_MaskSoftnessY", "Softness Y"); + DoVector("_ClipRect", "Clip Rect", s_LbrtVectorLabels); + } + + if (m_Material.HasProperty(ShaderUtilities.ID_StencilID)) + { + EditorGUILayout.Space(); + DoFloat("_Stencil", "Stencil ID"); + DoFloat("_StencilComp", "Stencil Comp"); + } + + EditorGUILayout.Space(); + + EditorGUI.BeginChangeCheck(); + bool useRatios = EditorGUILayout.Toggle("Use Ratios", !m_Material.IsKeywordEnabled("RATIOS_OFF")); + if (EditorGUI.EndChangeCheck()) + { + m_Editor.RegisterPropertyChangeUndo("Use Ratios"); + if (useRatios) + { + m_Material.DisableKeyword("RATIOS_OFF"); + } + else + { + m_Material.EnableKeyword("RATIOS_OFF"); + } + } + */ + if (m_Material.HasProperty(ShaderUtilities.ShaderTag_CullMode)) + { + EditorGUILayout.Space(); + DoPopup("_CullMode", "Cull Mode", s_CullingTypeLabels); + } + + EditorGUILayout.Space(); + /* + EditorGUI.BeginDisabledGroup(true); + DoFloat("_ScaleRatioA", "Scale Ratio A"); + DoFloat("_ScaleRatioB", "Scale Ratio B"); + DoFloat("_ScaleRatioC", "Scale Ratio C"); + EditorGUI.EndDisabledGroup(); + */ + + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoMaskSubgroup() + { + DoVector("_MaskCoord", "Mask Bounds", s_XywhVectorLabels); + if (Selection.activeGameObject != null) + { + Renderer renderer = Selection.activeGameObject.GetComponent(); + if (renderer != null) + { + Rect rect = EditorGUILayout.GetControlRect(); + rect.x += EditorGUIUtility.labelWidth; + rect.width -= EditorGUIUtility.labelWidth; + if (GUI.Button(rect, "Match Renderer Bounds")) + { + FindProperty("_MaskCoord", m_Properties).vectorValue = new Vector4( + 0, + 0, + Mathf.Round(renderer.bounds.extents.x * 1000) / 1000, + Mathf.Round(renderer.bounds.extents.y * 1000) / 1000 + ); + } + } + } + + if (s_MaskFeature.State == 1) + { + DoFloat("_MaskSoftnessX", "Softness X"); + DoFloat("_MaskSoftnessY", "Softness Y"); + } + } + + void DoMaskTexSubgroup() + { + EditorGUILayout.Space(); + DoTexture2D("_MaskTex", "Mask Texture"); + DoToggle("_MaskInverse", "Inverse Mask"); + DoColor("_MaskEdgeColor", "Edge Color"); + DoSlider("_MaskEdgeSoftness", "Edge Softness"); + DoSlider("_MaskWipeControl", "Wipe Position"); + DoFloat("_MaskSoftnessX", "Softness X"); + DoFloat("_MaskSoftnessY", "Softness Y"); + DoVector("_ClipRect", "Clip Rect", s_LbrtVectorLabels); + } + + // protected override void SetupMaterialKeywordsAndPassInternal(Material material) + // { + // BaseLitGUI.SetupBaseLitKeywords(material); + // BaseLitGUI.SetupBaseLitMaterialPass(material); + // } + } +} +#endif diff --git a/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_SDF_HDRPLitShaderGUI.cs.meta b/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_SDF_HDRPLitShaderGUI.cs.meta new file mode 100644 index 00000000..9fbf55e1 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_SDF_HDRPLitShaderGUI.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 85016528879d5d644981050d1d0a4368 +timeCreated: 1469844718 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_SDF_HDRPUnlitShaderGUI.cs b/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_SDF_HDRPUnlitShaderGUI.cs new file mode 100644 index 00000000..8290fb39 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_SDF_HDRPUnlitShaderGUI.cs @@ -0,0 +1,642 @@ +#if HDRP_10_7_OR_NEWER +using UnityEngine; +using UnityEditor; + +using UnityEditor.Rendering.HighDefinition; + +namespace TMPro.EditorUtilities +{ + internal class TMP_SDF_HDRPUnlitShaderGUI : TMP_BaseHDRPUnlitShaderGUI + { + #if !HDRP_11_OR_NEWER + const SurfaceOptionUIBlock.Features surfaceOptionFeatures = SurfaceOptionUIBlock.Features.Unlit; + + private readonly MaterialUIBlockList uiBlocks = new MaterialUIBlockList + { + new SurfaceOptionUIBlock(MaterialUIBlock.Expandable.Base, features: surfaceOptionFeatures), + new ShaderGraphUIBlock(MaterialUIBlock.Expandable.ShaderGraph, ShaderGraphUIBlock.Features.Unlit), + new AdvancedOptionsUIBlock(MaterialUIBlock.Expandable.Advance, ~AdvancedOptionsUIBlock.Features.SpecularOcclusion) + }; + #endif + + static ShaderFeature s_OutlineFeature, s_UnderlayFeature, s_BevelFeature, s_GlowFeature, s_MaskFeature; + + static bool s_Face = true, s_Outline = true, s_Outline2 = true, s_Outline3 = true, s_Underlay = true, s_Lighting = true, s_Glow, s_Bevel, s_Light, s_Bump, s_Env; + + static string[] + s_FaceUVSpeedName = { "_FaceUVSpeed" }, + s_FaceUvSpeedNames = { "_FaceUVSpeedX", "_FaceUVSpeedY" }, + s_OutlineUvSpeedNames = { "_OutlineUVSpeedX", "_OutlineUVSpeedY" }, + s_OutlineUvSpeedName = { "_OutlineUVSpeed" }; + + /// + /// + /// + static TMP_SDF_HDRPUnlitShaderGUI() + { + s_OutlineFeature = new ShaderFeature() + { + undoLabel = "Outline", + keywords = new[] { "OUTLINE_ON" } + }; + + s_UnderlayFeature = new ShaderFeature() + { + undoLabel = "Underlay", + keywords = new[] { "UNDERLAY_ON", "UNDERLAY_INNER" }, + label = new GUIContent("Underlay Type"), + keywordLabels = new[] + { + new GUIContent("None"), new GUIContent("Normal"), new GUIContent("Inner") + } + }; + + s_BevelFeature = new ShaderFeature() + { + undoLabel = "Bevel", + keywords = new[] { "BEVEL_ON" } + }; + + s_GlowFeature = new ShaderFeature() + { + undoLabel = "Glow", + keywords = new[] { "GLOW_ON" } + }; + + s_MaskFeature = new ShaderFeature() + { + undoLabel = "Mask", + keywords = new[] { "MASK_HARD", "MASK_SOFT" }, + label = new GUIContent("Mask"), + keywordLabels = new[] + { + new GUIContent("Mask Off"), new GUIContent("Mask Hard"), new GUIContent("Mask Soft") + } + }; + } + + /// + /// + /// + public TMP_SDF_HDRPUnlitShaderGUI() + { + // Remove the ShaderGraphUIBlock to avoid having duplicated properties in the UI. + uiBlocks.RemoveAll(b => b is ShaderGraphUIBlock); + } + + protected override void DoGUI() + { + s_Face = BeginPanel("Face", s_Face); + if (s_Face) + { + DoFacePanel(); + } + + EndPanel(); + + // Outline panels + DoOutlinePanels(); + + // Underlay panel + s_Underlay = BeginPanel("Underlay", s_Underlay); + if (s_Underlay) + { + DoUnderlayPanel(); + } + + EndPanel(); + + // Lighting panel + DrawLightingPanel(); + + /* + if (m_Material.HasProperty(ShaderUtilities.ID_GlowColor)) + { + s_Glow = BeginPanel("Glow", s_GlowFeature, s_Glow); + if (s_Glow) + { + DoGlowPanel(); + } + + EndPanel(); + } + */ + + s_DebugExtended = BeginPanel("Debug Settings", s_DebugExtended); + if (s_DebugExtended) + { + DoDebugPanelSRP(); + } + EndPanel(); + + EditorGUILayout.Space(); + EditorGUILayout.Space(); + + // Draw HDRP panels + uiBlocks.OnGUI(m_Editor, m_Properties); + #if HDRP_12_OR_NEWER + ValidateMaterial(m_Material); + #else + SetupMaterialKeywordsAndPass(m_Material); + #endif + } + + void DoFacePanel() + { + EditorGUI.indentLevel += 1; + + DoColor("_FaceColor", "Color"); + + if (m_Material.HasProperty(ShaderUtilities.ID_FaceTex)) + { + if (m_Material.HasProperty("_FaceUVSpeedX")) + { + DoTexture2D("_FaceTex", "Texture", true, s_FaceUvSpeedNames); + } + else if (m_Material.HasProperty("_FaceUVSpeed")) + { + DoTexture2D("_FaceTex", "Texture", true, s_FaceUVSpeedName); + } + else + { + DoTexture2D("_FaceTex", "Texture", true); + } + } + + if (m_Material.HasProperty("_Softness")) + { + DoSlider("_Softness", "X", new Vector2(0, 1), "Softness"); + } + + if (m_Material.HasProperty("_OutlineSoftness")) + { + DoSlider("_OutlineSoftness", "Softness"); + } + + if (m_Material.HasProperty(ShaderUtilities.ID_FaceDilate)) + { + DoSlider("_FaceDilate", "Dilate"); + if (m_Material.HasProperty(ShaderUtilities.ID_Shininess)) + { + DoSlider("_FaceShininess", "Gloss"); + } + } + + if (m_Material.HasProperty(ShaderUtilities.ID_IsoPerimeter)) + { + DoSlider("_IsoPerimeter", "X", new Vector2(-1, 1), "Dilate"); + } + + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoOutlinePanels() + { + s_Outline = BeginPanel("Outline 1", s_Outline); + if (s_Outline) + DoOutlinePanelWithTexture(1, "Y", "Color"); + + EndPanel(); + + s_Outline2 = BeginPanel("Outline 2", s_Outline2); + if (s_Outline2) + DoOutlinePanel(2, "Z", "Color"); + + EndPanel(); + + s_Outline3 = BeginPanel("Outline 3", s_Outline3); + if (s_Outline3) + DoOutlinePanel(3, "W", "Color"); + + EndPanel(); + } + + void DoOutlinePanel(int outlineID, string propertyField, string label) + { + EditorGUI.indentLevel += 1; + DoColor("_OutlineColor" + outlineID, label); + + if (outlineID != 3) + DoOffset("_OutlineOffset" + outlineID, "Offset"); + else + { + if (m_Material.GetFloat(ShaderUtilities.ID_OutlineMode) == 0) + DoOffset("_OutlineOffset" + outlineID, "Offset"); + } + + DoSlider("_Softness", propertyField, new Vector2(0, 1), "Softness"); + DoSlider("_IsoPerimeter", propertyField, new Vector2(-1, 1), "Dilate"); + + if (outlineID == 3) + { + DoToggle("_OutlineMode", "Outline Mode"); + } + + if (m_Material.HasProperty("_OutlineShininess")) + { + //DoSlider("_OutlineShininess", "Gloss"); + } + + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoOutlinePanelWithTexture(int outlineID, string propertyField, string label) + { + EditorGUI.indentLevel += 1; + DoColor("_OutlineColor" + outlineID, label); + if (m_Material.HasProperty(ShaderUtilities.ID_OutlineTex)) + { + if (m_Material.HasProperty("_OutlineUVSpeedX")) + { + DoTexture2D("_OutlineTex", "Texture", true, s_OutlineUvSpeedNames); + } + else if (m_Material.HasProperty("_OutlineUVSpeed")) + { + DoTexture2D("_OutlineTex", "Texture", true, s_OutlineUvSpeedName); + } + else + { + DoTexture2D("_OutlineTex", "Texture", true); + } + } + + DoOffset("_OutlineOffset" + outlineID, "Offset"); + DoSlider("_Softness", propertyField, new Vector2(0, 1), "Softness"); + DoSlider("_IsoPerimeter", propertyField, new Vector2(-1, 1), "Dilate"); + + if (m_Material.HasProperty("_OutlineShininess")) + { + //DoSlider("_OutlineShininess", "Gloss"); + } + + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoUnderlayPanel() + { + EditorGUI.indentLevel += 1; + + if (m_Material.HasProperty(ShaderUtilities.ID_IsoPerimeter)) + { + DoColor("_UnderlayColor", "Color"); + DoSlider("_UnderlayOffset", "X", new Vector2(-1, 1), "Offset X"); + DoSlider("_UnderlayOffset", "Y", new Vector2(-1, 1), "Offset Y"); + DoSlider("_UnderlayDilate", new Vector2(-1, 1), "Dilate"); + DoSlider("_UnderlaySoftness", new Vector2(0, 1), "Softness"); + } + else + { + s_UnderlayFeature.DoPopup(m_Editor, m_Material); + DoColor("_UnderlayColor", "Color"); + DoSlider("_UnderlayOffsetX", "Offset X"); + DoSlider("_UnderlayOffsetY", "Offset Y"); + DoSlider("_UnderlayDilate", "Dilate"); + DoSlider("_UnderlaySoftness", "Softness"); + } + + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + static GUIContent[] s_BevelTypeLabels = + { + new GUIContent("Outer Bevel"), + new GUIContent("Inner Bevel") + }; + + void DrawLightingPanel() + { + s_Lighting = BeginPanel("Lighting", s_Lighting); + if (s_Lighting) + { + s_Bevel = BeginPanel("Bevel", s_Bevel); + if (s_Bevel) + { + DoBevelPanel(); + } + EndPanel(); + + s_Light = BeginPanel("Local Lighting", s_Light); + if (s_Light) + { + DoLocalLightingPanel(); + } + EndPanel(); + + /* + s_Bump = BeginPanel("Bump Map", s_Bump); + if (s_Bump) + { + DoBumpMapPanel(); + } + + EndPanel(); + + s_Env = BeginPanel("Environment Map", s_Env); + if (s_Env) + { + DoEnvMapPanel(); + } + + EndPanel(); + */ + } + + EndPanel(); + } + + void DoBevelPanel() + { + EditorGUI.indentLevel += 1; + DoPopup("_BevelType", "Type", s_BevelTypeLabels); + DoSlider("_BevelAmount", "Amount"); + DoSlider("_BevelOffset", "Offset"); + DoSlider("_BevelWidth", "Width"); + DoSlider("_BevelRoundness", "Roundness"); + DoSlider("_BevelClamp", "Clamp"); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoLocalLightingPanel() + { + EditorGUI.indentLevel += 1; + DoSlider("_LightAngle", "Light Angle"); + DoColor("_SpecularColor", "Specular Color"); + DoSlider("_SpecularPower", "Specular Power"); + DoSlider("_Reflectivity", "Reflectivity Power"); + DoSlider("_Diffuse", "Diffuse Shadow"); + DoSlider("_Ambient", "Ambient Shadow"); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoSurfaceLightingPanel() + { + EditorGUI.indentLevel += 1; + DoColor("_SpecColor", "Specular Color"); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoBumpMapPanel() + { + EditorGUI.indentLevel += 1; + DoTexture2D("_BumpMap", "Texture"); + DoSlider("_BumpFace", "Face"); + DoSlider("_BumpOutline", "Outline"); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoEnvMapPanel() + { + EditorGUI.indentLevel += 1; + DoColor("_ReflectFaceColor", "Face Color"); + DoColor("_ReflectOutlineColor", "Outline Color"); + DoCubeMap("_Cube", "Texture"); + DoVector3("_EnvMatrixRotation", "Rotation"); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoGlowPanel() + { + EditorGUI.indentLevel += 1; + DoColor("_GlowColor", "Color"); + DoSlider("_GlowOffset", "Offset"); + DoSlider("_GlowInner", "Inner"); + DoSlider("_GlowOuter", "Outer"); + DoSlider("_GlowPower", "Power"); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoDebugPanel() + { + EditorGUI.indentLevel += 1; + DoTexture2D("_MainTex", "Font Atlas"); + DoFloat("_GradientScale", "Gradient Scale"); + DoFloat("_TextureWidth", "Texture Width"); + DoFloat("_TextureHeight", "Texture Height"); + EditorGUILayout.Space(); + DoFloat("_ScaleX", "Scale X"); + DoFloat("_ScaleY", "Scale Y"); + + if (m_Material.HasProperty(ShaderUtilities.ID_Sharpness)) + DoSlider("_Sharpness", "Sharpness"); + + DoSlider("_PerspectiveFilter", "Perspective Filter"); + EditorGUILayout.Space(); + DoFloat("_VertexOffsetX", "Offset X"); + DoFloat("_VertexOffsetY", "Offset Y"); + + if (m_Material.HasProperty(ShaderUtilities.ID_MaskCoord)) + { + EditorGUILayout.Space(); + s_MaskFeature.ReadState(m_Material); + s_MaskFeature.DoPopup(m_Editor, m_Material); + if (s_MaskFeature.Active) + { + DoMaskSubgroup(); + } + + EditorGUILayout.Space(); + DoVector("_ClipRect", "Clip Rect", s_LbrtVectorLabels); + } + else if (m_Material.HasProperty("_MaskTex")) + { + DoMaskTexSubgroup(); + } + else if (m_Material.HasProperty(ShaderUtilities.ID_MaskSoftnessX)) + { + EditorGUILayout.Space(); + DoFloat("_MaskSoftnessX", "Softness X"); + DoFloat("_MaskSoftnessY", "Softness Y"); + DoVector("_ClipRect", "Clip Rect", s_LbrtVectorLabels); + } + + if (m_Material.HasProperty(ShaderUtilities.ID_StencilID)) + { + EditorGUILayout.Space(); + DoFloat("_Stencil", "Stencil ID"); + DoFloat("_StencilComp", "Stencil Comp"); + } + + EditorGUILayout.Space(); + + EditorGUI.BeginChangeCheck(); + bool useRatios = EditorGUILayout.Toggle("Use Ratios", !m_Material.IsKeywordEnabled("RATIOS_OFF")); + if (EditorGUI.EndChangeCheck()) + { + m_Editor.RegisterPropertyChangeUndo("Use Ratios"); + if (useRatios) + { + m_Material.DisableKeyword("RATIOS_OFF"); + } + else + { + m_Material.EnableKeyword("RATIOS_OFF"); + } + } + + if (m_Material.HasProperty(ShaderUtilities.ShaderTag_CullMode)) + { + EditorGUILayout.Space(); + DoPopup("_CullMode", "Cull Mode", s_CullingTypeLabels); + } + + EditorGUILayout.Space(); + + EditorGUI.BeginDisabledGroup(true); + DoFloat("_ScaleRatioA", "Scale Ratio A"); + DoFloat("_ScaleRatioB", "Scale Ratio B"); + DoFloat("_ScaleRatioC", "Scale Ratio C"); + EditorGUI.EndDisabledGroup(); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoDebugPanelSRP() + { + EditorGUI.indentLevel += 1; + DoTexture2D("_MainTex", "Font Atlas"); + DoFloat("_GradientScale", "Gradient Scale"); + //DoFloat("_TextureWidth", "Texture Width"); + //DoFloat("_TextureHeight", "Texture Height"); + EditorGUILayout.Space(); + + /* + DoFloat("_ScaleX", "Scale X"); + DoFloat("_ScaleY", "Scale Y"); + + if (m_Material.HasProperty(ShaderUtilities.ID_Sharpness)) + DoSlider("_Sharpness", "Sharpness"); + + DoSlider("_PerspectiveFilter", "Perspective Filter"); + EditorGUILayout.Space(); + DoFloat("_VertexOffsetX", "Offset X"); + DoFloat("_VertexOffsetY", "Offset Y"); + + if (m_Material.HasProperty(ShaderUtilities.ID_MaskCoord)) + { + EditorGUILayout.Space(); + s_MaskFeature.ReadState(m_Material); + s_MaskFeature.DoPopup(m_Editor, m_Material); + if (s_MaskFeature.Active) + { + DoMaskSubgroup(); + } + + EditorGUILayout.Space(); + DoVector("_ClipRect", "Clip Rect", s_LbrtVectorLabels); + } + else if (m_Material.HasProperty("_MaskTex")) + { + DoMaskTexSubgroup(); + } + else if (m_Material.HasProperty(ShaderUtilities.ID_MaskSoftnessX)) + { + EditorGUILayout.Space(); + DoFloat("_MaskSoftnessX", "Softness X"); + DoFloat("_MaskSoftnessY", "Softness Y"); + DoVector("_ClipRect", "Clip Rect", s_LbrtVectorLabels); + } + + if (m_Material.HasProperty(ShaderUtilities.ID_StencilID)) + { + EditorGUILayout.Space(); + DoFloat("_Stencil", "Stencil ID"); + DoFloat("_StencilComp", "Stencil Comp"); + } + + EditorGUILayout.Space(); + + EditorGUI.BeginChangeCheck(); + bool useRatios = EditorGUILayout.Toggle("Use Ratios", !m_Material.IsKeywordEnabled("RATIOS_OFF")); + if (EditorGUI.EndChangeCheck()) + { + m_Editor.RegisterPropertyChangeUndo("Use Ratios"); + if (useRatios) + { + m_Material.DisableKeyword("RATIOS_OFF"); + } + else + { + m_Material.EnableKeyword("RATIOS_OFF"); + } + } + */ + if (m_Material.HasProperty(ShaderUtilities.ShaderTag_CullMode)) + { + EditorGUILayout.Space(); + DoPopup("_CullMode", "Cull Mode", s_CullingTypeLabels); + } + + EditorGUILayout.Space(); + /* + EditorGUI.BeginDisabledGroup(true); + DoFloat("_ScaleRatioA", "Scale Ratio A"); + DoFloat("_ScaleRatioB", "Scale Ratio B"); + DoFloat("_ScaleRatioC", "Scale Ratio C"); + EditorGUI.EndDisabledGroup(); + */ + + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoMaskSubgroup() + { + DoVector("_MaskCoord", "Mask Bounds", s_XywhVectorLabels); + if (Selection.activeGameObject != null) + { + Renderer renderer = Selection.activeGameObject.GetComponent(); + if (renderer != null) + { + Rect rect = EditorGUILayout.GetControlRect(); + rect.x += EditorGUIUtility.labelWidth; + rect.width -= EditorGUIUtility.labelWidth; + if (GUI.Button(rect, "Match Renderer Bounds")) + { + FindProperty("_MaskCoord", m_Properties).vectorValue = new Vector4( + 0, + 0, + Mathf.Round(renderer.bounds.extents.x * 1000) / 1000, + Mathf.Round(renderer.bounds.extents.y * 1000) / 1000 + ); + } + } + } + + if (s_MaskFeature.State == 1) + { + DoFloat("_MaskSoftnessX", "Softness X"); + DoFloat("_MaskSoftnessY", "Softness Y"); + } + } + + void DoMaskTexSubgroup() + { + EditorGUILayout.Space(); + DoTexture2D("_MaskTex", "Mask Texture"); + DoToggle("_MaskInverse", "Inverse Mask"); + DoColor("_MaskEdgeColor", "Edge Color"); + DoSlider("_MaskEdgeSoftness", "Edge Softness"); + DoSlider("_MaskWipeControl", "Wipe Position"); + DoFloat("_MaskSoftnessX", "Softness X"); + DoFloat("_MaskSoftnessY", "Softness Y"); + DoVector("_ClipRect", "Clip Rect", s_LbrtVectorLabels); + } + + // protected override void SetupMaterialKeywordsAndPassInternal(Material material) + // { + // BaseLitGUI.SetupBaseLitKeywords(material); + // BaseLitGUI.SetupBaseLitMaterialPass(material); + // } + } +} +#endif diff --git a/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_SDF_HDRPUnlitShaderGUI.cs.meta b/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_SDF_HDRPUnlitShaderGUI.cs.meta new file mode 100644 index 00000000..f1406409 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/HDRP/TMP_SDF_HDRPUnlitShaderGUI.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: bad96c2cfa78a124cb8ec890d2386dfe +timeCreated: 1469844718 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers.meta b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers.meta new file mode 100644 index 00000000..13f652df --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ea7c31b5b377c314db28ad3fabbbd38d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/DropdownOptionListDrawer.cs b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/DropdownOptionListDrawer.cs new file mode 100644 index 00000000..144085e6 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/DropdownOptionListDrawer.cs @@ -0,0 +1,63 @@ +using UnityEditorInternal; +using UnityEngine; +using UnityEngine.UI; +using UnityEditor; + +namespace TMPro.EditorUtilities +{ + [CustomPropertyDrawer(typeof(TMP_Dropdown.OptionDataList), true)] + class DropdownOptionListDrawer : PropertyDrawer + { + private ReorderableList m_ReorderableList; + + private void Init(SerializedProperty property) + { + if (m_ReorderableList != null) + return; + + SerializedProperty array = property.FindPropertyRelative("m_Options"); + + m_ReorderableList = new ReorderableList(property.serializedObject, array); + m_ReorderableList.drawElementCallback = DrawOptionData; + m_ReorderableList.drawHeaderCallback = DrawHeader; + m_ReorderableList.elementHeight += 40; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + Init(property); + + m_ReorderableList.DoList(position); + } + + private void DrawHeader(Rect rect) + { + GUI.Label(rect, "Options"); + } + + private void DrawOptionData(Rect rect, int index, bool isActive, bool isFocused) + { + SerializedProperty itemData = m_ReorderableList.serializedProperty.GetArrayElementAtIndex(index); + SerializedProperty itemText = itemData.FindPropertyRelative("m_Text"); + SerializedProperty itemImage = itemData.FindPropertyRelative("m_Image"); + SerializedProperty itemColor = itemData.FindPropertyRelative("m_Color"); + + RectOffset offset = new RectOffset(0, 0, -1, -3); + rect = offset.Add(rect); + rect.height = EditorGUIUtility.singleLineHeight; + + EditorGUI.PropertyField(rect, itemText, GUIContent.none); + rect.y += EditorGUIUtility.singleLineHeight + 2; + EditorGUI.PropertyField(rect, itemImage, GUIContent.none); + rect.y += EditorGUIUtility.singleLineHeight + 2; + EditorGUI.PropertyField(rect, itemColor, GUIContent.none); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + Init(property); + + return m_ReorderableList.GetHeight(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/DropdownOptionListDrawer.cs.meta b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/DropdownOptionListDrawer.cs.meta new file mode 100644 index 00000000..f7f4c565 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/DropdownOptionListDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9545c9eb3bf94265810463794fec8334 +timeCreated: 1464818008 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/GlyphMetricsPropertyDrawer.cs b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/GlyphMetricsPropertyDrawer.cs new file mode 100644 index 00000000..dcc4d91d --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/GlyphMetricsPropertyDrawer.cs @@ -0,0 +1,60 @@ +using UnityEngine; +using UnityEngine.TextCore; +using UnityEditor; +using System.Collections; + + +namespace TMPro.EditorUtilities +{ + + [CustomPropertyDrawer(typeof(GlyphMetrics))] + internal class GlyphMetricsPropertyDrawer : PropertyDrawer + { + private static readonly GUIContent k_GlyphMetricLabel = new GUIContent("Glyph Metrics", "The layout metrics of the glyph."); + private static readonly GUIContent k_WidthPropertyLabel = new GUIContent("W:", "The width of the glyph."); + private static readonly GUIContent k_HeightPropertyLabel = new GUIContent("H:", "The height of the glyph."); + private static readonly GUIContent k_BearingXPropertyLabel = new GUIContent("BX:", "The horizontal bearing X of the glyph."); + private static readonly GUIContent k_BearingYPropertyLabel = new GUIContent("BY:", "The horizontal bearing Y of the glyph."); + private static readonly GUIContent k_HorizontalAdvancePropertyLabel = new GUIContent("AD:", "The horizontal advance of the glyph."); + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + SerializedProperty prop_Width = property.FindPropertyRelative("m_Width"); + SerializedProperty prop_Height = property.FindPropertyRelative("m_Height"); + SerializedProperty prop_HoriBearingX = property.FindPropertyRelative("m_HorizontalBearingX"); + SerializedProperty prop_HoriBearingY = property.FindPropertyRelative("m_HorizontalBearingY"); + SerializedProperty prop_HoriAdvance = property.FindPropertyRelative("m_HorizontalAdvance"); + + // We get Rect since a valid position may not be provided by the caller. + Rect rect = new Rect(position.x, position.y, position.width, 49); + + EditorGUI.LabelField(new Rect(rect.x, rect.y - 2.5f, rect.width, 18), k_GlyphMetricLabel); + + EditorGUIUtility.labelWidth = 20f; + EditorGUIUtility.fieldWidth = 15f; + + //GUI.enabled = false; + float width = (rect.width - 75f) / 2; + EditorGUI.PropertyField(new Rect(rect.x + width * 0, rect.y + 20, width - 5f, 18), prop_Width, k_WidthPropertyLabel); + EditorGUI.PropertyField(new Rect(rect.x + width * 1, rect.y + 20, width - 5f, 18), prop_Height, k_HeightPropertyLabel); + + //GUI.enabled = true; + + width = (rect.width - 75f) / 3; + EditorGUI.BeginChangeCheck(); + EditorGUI.PropertyField(new Rect(rect.x + width * 0, rect.y + 40, width - 5f, 18), prop_HoriBearingX, k_BearingXPropertyLabel); + EditorGUI.PropertyField(new Rect(rect.x + width * 1, rect.y + 40, width - 5f, 18), prop_HoriBearingY, k_BearingYPropertyLabel); + EditorGUI.PropertyField(new Rect(rect.x + width * 2, rect.y + 40, width - 5f, 18), prop_HoriAdvance, k_HorizontalAdvancePropertyLabel); + if (EditorGUI.EndChangeCheck()) + { + + } + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return 65f; + } + + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/GlyphMetricsPropertyDrawer.cs.meta b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/GlyphMetricsPropertyDrawer.cs.meta new file mode 100644 index 00000000..d91f5791 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/GlyphMetricsPropertyDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e3882522a08b6f5459b4dea6f8791278 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/GlyphPairAdjustmentRecordPropertyDrawer.cs b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/GlyphPairAdjustmentRecordPropertyDrawer.cs new file mode 100644 index 00000000..1458ccd8 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/GlyphPairAdjustmentRecordPropertyDrawer.cs @@ -0,0 +1,372 @@ +using UnityEngine; +using UnityEngine.TextCore; +using UnityEngine.TextCore.LowLevel; +using UnityEditor; +using System.Collections.Generic; + + +namespace TMPro.EditorUtilities +{ + + [CustomPropertyDrawer(typeof(GlyphPairAdjustmentRecord))] + internal class GlyphPairAdjustmentRecordPropertyDrawer : PropertyDrawer + { + private bool isEditingEnabled; + private bool isSelectable; + + private Dictionary m_GlyphLookupDictionary; + + private string m_FirstCharacter = string.Empty; + private string m_SecondCharacter = string.Empty; + private string m_PreviousInput; + + static GUIContent s_CharacterTextFieldLabel = new GUIContent("Char:", "Enter the character or its UTF16 or UTF32 Unicode character escape sequence. For UTF16 use \"\\uFF00\" and for UTF32 use \"\\UFF00FF00\" representation."); + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + SerializedProperty prop_FirstAdjustmentRecord = property.FindPropertyRelative("m_FirstAdjustmentRecord"); + SerializedProperty prop_SecondAdjustmentRecord = property.FindPropertyRelative("m_SecondAdjustmentRecord"); + + SerializedProperty prop_FirstGlyphIndex = prop_FirstAdjustmentRecord.FindPropertyRelative("m_GlyphIndex"); + SerializedProperty prop_FirstGlyphValueRecord = prop_FirstAdjustmentRecord.FindPropertyRelative("m_GlyphValueRecord"); + + SerializedProperty prop_SecondGlyphIndex = prop_SecondAdjustmentRecord.FindPropertyRelative("m_GlyphIndex"); + SerializedProperty prop_SecondGlyphValueRecord = prop_SecondAdjustmentRecord.FindPropertyRelative("m_GlyphValueRecord"); + + SerializedProperty prop_FontFeatureLookupFlags = property.FindPropertyRelative("m_FeatureLookupFlags"); + + // Refresh glyph proxy lookup dictionary if needed + if (TMP_PropertyDrawerUtilities.s_RefreshGlyphProxyLookup) + TMP_PropertyDrawerUtilities.RefreshGlyphProxyLookup(property.serializedObject); + + position.yMin += 2; + + float width = position.width / 2; + float padding = 5.0f; + + Rect rect; + + isEditingEnabled = GUI.enabled; + isSelectable = label.text == "Selectable"; + + if (isSelectable) + GUILayoutUtility.GetRect(position.width, 80); + else + GUILayoutUtility.GetRect(position.width, 55); + + GUIStyle style = new GUIStyle(EditorStyles.label); + style.richText = true; + + // First Glyph + GUI.enabled = isEditingEnabled; + if (isSelectable) + { + rect = new Rect(position.x + 70, position.y, position.width, 49); + + float labelWidth = GUI.skin.label.CalcSize(new GUIContent("ID: " + prop_FirstGlyphIndex.intValue)).x; + EditorGUI.LabelField(new Rect(position.x + (64 - labelWidth) / 2, position.y + 60, 64f, 18f), new GUIContent("ID: " + prop_FirstGlyphIndex.intValue + ""), style); + + GUI.enabled = isEditingEnabled; + EditorGUIUtility.labelWidth = 25f; + + rect = new Rect(position.x + 70, position.y + 10, (width - 70) - padding, 18); + EditorGUI.PropertyField(rect, prop_FirstGlyphValueRecord.FindPropertyRelative("m_XPlacement"), new GUIContent("OX:")); + + rect.y += 20; + EditorGUI.PropertyField(rect, prop_FirstGlyphValueRecord.FindPropertyRelative("m_YPlacement"), new GUIContent("OY:")); + + rect.y += 20; + EditorGUI.PropertyField(rect, prop_FirstGlyphValueRecord.FindPropertyRelative("m_XAdvance"), new GUIContent("AX:")); + + //rect.y += 20; + //EditorGUI.PropertyField(rect, prop_FirstGlyphValueRecord.FindPropertyRelative("m_YAdvance"), new GUIContent("AY:")); + + DrawGlyph((uint)prop_FirstGlyphIndex.intValue, new Rect(position.x, position.y + 2, 64, 60), property); + } + else + { + rect = new Rect(position.x, position.y, width / 2 * 0.8f - padding, 18); + EditorGUIUtility.labelWidth = 40f; + + // First Character Lookup + GUI.SetNextControlName("FirstCharacterField"); + EditorGUI.BeginChangeCheck(); + string firstCharacter = EditorGUI.TextField(rect, s_CharacterTextFieldLabel, m_FirstCharacter); + + if (GUI.GetNameOfFocusedControl() == "FirstCharacterField") + { + if (ValidateInput(firstCharacter)) + { + //Debug.Log("1st Unicode value: [" + firstCharacter + "]"); + + uint unicode = GetUnicodeCharacter(firstCharacter); + + // Lookup glyph index + TMP_SerializedPropertyHolder propertyHolder = property.serializedObject.targetObject as TMP_SerializedPropertyHolder; + TMP_FontAsset fontAsset = propertyHolder.fontAsset; + if (fontAsset != null) + { + prop_FirstGlyphIndex.intValue = (int)fontAsset.GetGlyphIndex(unicode); + propertyHolder.firstCharacter = unicode; + } + } + } + + if (EditorGUI.EndChangeCheck()) + m_FirstCharacter = firstCharacter; + + // First Glyph Index + rect.x += width / 2 * 0.8f; + + EditorGUIUtility.labelWidth = 25f; + EditorGUI.BeginChangeCheck(); + EditorGUI.PropertyField(rect, prop_FirstGlyphIndex, new GUIContent("ID:")); + if (EditorGUI.EndChangeCheck()) + { + + } + + GUI.enabled = isEditingEnabled; + EditorGUIUtility.labelWidth = 25f; + + rect = new Rect(position.x, position.y + 20, width * 0.5f - padding, 18); + EditorGUI.PropertyField(rect, prop_FirstGlyphValueRecord.FindPropertyRelative("m_XPlacement"), new GUIContent("OX")); + + rect.x += width * 0.5f; + EditorGUI.PropertyField(rect, prop_FirstGlyphValueRecord.FindPropertyRelative("m_YPlacement"), new GUIContent("OY")); + + rect.x = position.x; + rect.y += 20; + EditorGUI.PropertyField(rect, prop_FirstGlyphValueRecord.FindPropertyRelative("m_XAdvance"), new GUIContent("AX")); + + //rect.x += width * 0.5f; + //EditorGUI.PropertyField(rect, prop_FirstGlyphAdjustment.FindPropertyRelative("m_YAdvance"), new GUIContent("AY")); + + } + + + // Second Glyph + GUI.enabled = isEditingEnabled; + if (isSelectable) + { + float labelWidth = GUI.skin.label.CalcSize(new GUIContent("ID: " + prop_SecondGlyphIndex.intValue)).x; + EditorGUI.LabelField(new Rect(position.width / 2 + 20 + (64 - labelWidth) / 2, position.y + 60, 64f, 18f), new GUIContent("ID: " + prop_SecondGlyphIndex.intValue + ""), style); + + GUI.enabled = isEditingEnabled; + EditorGUIUtility.labelWidth = 25f; + + rect = new Rect(position.width / 2 + 20 + 70, position.y + 10, (width - 70) - padding, 18); + EditorGUI.PropertyField(rect, prop_SecondGlyphValueRecord.FindPropertyRelative("m_XPlacement"), new GUIContent("OX:")); + + rect.y += 20; + EditorGUI.PropertyField(rect, prop_SecondGlyphValueRecord.FindPropertyRelative("m_YPlacement"), new GUIContent("OY:")); + + rect.y += 20; + EditorGUI.PropertyField(rect, prop_SecondGlyphValueRecord.FindPropertyRelative("m_XAdvance"), new GUIContent("AX:")); + + //rect.y += 20; + //EditorGUI.PropertyField(rect, prop_SecondGlyphAdjustment.FindPropertyRelative("m_YAdvance"), new GUIContent("AY")); + + DrawGlyph((uint)prop_SecondGlyphIndex.intValue, new Rect(position.width / 2 + 20, position.y + 2, 64, 60), property); + } + else + { + rect = new Rect(position.width / 2 + 20, position.y, width / 2 * 0.8f - padding, 18); + EditorGUIUtility.labelWidth = 40f; + + // Second Character Lookup + GUI.SetNextControlName("SecondCharacterField"); + EditorGUI.BeginChangeCheck(); + string secondCharacter = EditorGUI.TextField(rect, s_CharacterTextFieldLabel, m_SecondCharacter); + + if (GUI.GetNameOfFocusedControl() == "SecondCharacterField") + { + if (ValidateInput(secondCharacter)) + { + //Debug.Log("2nd Unicode value: [" + secondCharacter + "]"); + + uint unicode = GetUnicodeCharacter(secondCharacter); + + // Lookup glyph index + TMP_SerializedPropertyHolder propertyHolder = property.serializedObject.targetObject as TMP_SerializedPropertyHolder; + TMP_FontAsset fontAsset = propertyHolder.fontAsset; + if (fontAsset != null) + { + prop_SecondGlyphIndex.intValue = (int)fontAsset.GetGlyphIndex(unicode); + propertyHolder.secondCharacter = unicode; + } + } + } + + if (EditorGUI.EndChangeCheck()) + m_SecondCharacter = secondCharacter; + + // Second Glyph Index + rect.x += width / 2 * 0.8f; + + EditorGUIUtility.labelWidth = 25f; + EditorGUI.BeginChangeCheck(); + EditorGUI.PropertyField(rect, prop_SecondGlyphIndex, new GUIContent("ID:")); + if (EditorGUI.EndChangeCheck()) + { + + } + + GUI.enabled = isEditingEnabled; + EditorGUIUtility.labelWidth = 25f; + + rect = new Rect(position.width / 2 + 20, position.y + 20, width * 0.5f - padding, 18); + EditorGUI.PropertyField(rect, prop_SecondGlyphValueRecord.FindPropertyRelative("m_XPlacement"), new GUIContent("OX")); + + rect.x += width * 0.5f; + EditorGUI.PropertyField(rect, prop_SecondGlyphValueRecord.FindPropertyRelative("m_YPlacement"), new GUIContent("OY")); + + rect.x = position.width / 2 + 20; + rect.y += 20; + EditorGUI.PropertyField(rect, prop_SecondGlyphValueRecord.FindPropertyRelative("m_XAdvance"), new GUIContent("AX")); + + //rect.x += width * 0.5f; + //EditorGUI.PropertyField(rect, prop_SecondGlyphAdjustment.FindPropertyRelative("m_YAdvance"), new GUIContent("AY")); + } + + // Font Feature Lookup Flags + if (isSelectable) + { + EditorGUIUtility.labelWidth = 50f; + + rect.width = position.width * 0.5f; + rect.x = rect.width + 16; + rect.y += 28; + + FontFeatureLookupFlags flags = (FontFeatureLookupFlags)prop_FontFeatureLookupFlags.intValue; + + EditorGUI.BeginChangeCheck(); + flags = (FontFeatureLookupFlags)EditorGUI.EnumFlagsField(rect, new GUIContent("Options:"), flags); + if (EditorGUI.EndChangeCheck()) + { + prop_FontFeatureLookupFlags.intValue = (int)flags; + } + } + } + + bool ValidateInput(string source) + { + int length = string.IsNullOrEmpty(source) ? 0 : source.Length; + + ////Filter out unwanted characters. + Event evt = Event.current; + + char c = evt.character; + + if (c != '\0') + { + switch (length) + { + case 0: + break; + case 1: + if (source != m_PreviousInput) + return true; + + if ((source[0] == '\\' && (c == 'u' || c == 'U')) == false) + evt.character = '\0'; + + break; + case 2: + case 3: + case 4: + case 5: + if ((c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F')) + evt.character = '\0'; + break; + case 6: + case 7: + case 8: + case 9: + if (source[1] == 'u' || (c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F')) + evt.character = '\0'; + + // Validate input + if (length == 6 && source[1] == 'u' && source != m_PreviousInput) + return true; + break; + case 10: + if (source != m_PreviousInput) + return true; + + evt.character = '\0'; + break; + } + } + + m_PreviousInput = source; + + return false; + } + + uint GetUnicodeCharacter (string source) + { + uint unicode; + + if (source.Length == 1) + unicode = source[0]; + else if (source.Length == 6) + unicode = (uint)TMP_TextUtilities.StringHexToInt(source.Replace("\\u", "")); + else + unicode = (uint)TMP_TextUtilities.StringHexToInt(source.Replace("\\U", "")); + + return unicode; + } + + void DrawGlyph(uint glyphIndex, Rect glyphDrawPosition, SerializedProperty property) + { + // Get a reference to the serialized object which can either be a TMP_FontAsset or FontAsset. + SerializedObject so = property.serializedObject; + if (so == null) + return; + + if (m_GlyphLookupDictionary == null) + m_GlyphLookupDictionary = TMP_PropertyDrawerUtilities.GetGlyphProxyLookupDictionary(so); + + // Try getting a reference to the glyph for the given glyph index. + if (!m_GlyphLookupDictionary.TryGetValue(glyphIndex, out GlyphProxy glyph)) + return; + + Texture2D atlasTexture; + if (TMP_PropertyDrawerUtilities.TryGetAtlasTextureFromSerializedObject(so, glyph.atlasIndex, out atlasTexture) == false) + return; + + Material mat; + if (TMP_PropertyDrawerUtilities.TryGetMaterial(so, atlasTexture, out mat) == false) + return; + + int padding = so.FindProperty("m_AtlasPadding").intValue; + GlyphRect glyphRect = glyph.glyphRect; + int glyphOriginX = glyphRect.x - padding; + int glyphOriginY = glyphRect.y - padding; + int glyphWidth = glyphRect.width + padding * 2; + int glyphHeight = glyphRect.height + padding * 2; + + SerializedProperty faceInfoProperty = so.FindProperty("m_FaceInfo"); + float ascentLine = faceInfoProperty.FindPropertyRelative("m_AscentLine").floatValue; + float descentLine = faceInfoProperty.FindPropertyRelative("m_DescentLine").floatValue; + + float normalizedHeight = ascentLine - descentLine; + float scale = glyphDrawPosition.width / normalizedHeight; + + // Compute the normalized texture coordinates + Rect texCoords = new Rect((float)glyphOriginX / atlasTexture.width, (float)glyphOriginY / atlasTexture.height, (float)glyphWidth / atlasTexture.width, (float)glyphHeight / atlasTexture.height); + + if (Event.current.type == EventType.Repaint) + { + glyphDrawPosition.x += (glyphDrawPosition.width - glyphWidth * scale) / 2; + glyphDrawPosition.y += (glyphDrawPosition.height - glyphHeight * scale) / 2; + glyphDrawPosition.width = glyphWidth * scale; + glyphDrawPosition.height = glyphHeight * scale; + + // Could switch to using the default material of the font asset which would require passing scale to the shader. + Graphics.DrawTexture(glyphDrawPosition, atlasTexture, texCoords, 0, 0, 0, 0, new Color(1f, 1f, 1f), mat); + } + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/GlyphPairAdjustmentRecordPropertyDrawer.cs.meta b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/GlyphPairAdjustmentRecordPropertyDrawer.cs.meta new file mode 100644 index 00000000..b95203f5 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/GlyphPairAdjustmentRecordPropertyDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d256fa541faf5d4409992c631adb98a1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/GlyphRectPropertyDrawer.cs b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/GlyphRectPropertyDrawer.cs new file mode 100644 index 00000000..c3a2f816 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/GlyphRectPropertyDrawer.cs @@ -0,0 +1,50 @@ +using UnityEngine; +using UnityEngine.TextCore; +using UnityEditor; +using System.Collections; + + +namespace TMPro.EditorUtilities +{ + + [CustomPropertyDrawer(typeof(GlyphRect))] + public class GlyphRectPropertyDrawer : PropertyDrawer + { + private static readonly GUIContent k_GlyphRectLabel = new GUIContent("Glyph Rect", "A rectangle (rect) that represents the position of the glyph in the atlas texture."); + private static readonly GUIContent k_XPropertyLabel = new GUIContent("X:", "The X coordinate of the glyph in the atlas texture."); + private static readonly GUIContent k_YPropertyLabel = new GUIContent("Y:", "The Y coordinate of the glyph in the atlas texture."); + private static readonly GUIContent k_WidthPropertyLabel = new GUIContent("W:", "The width of the glyph in the atlas texture."); + private static readonly GUIContent k_HeightPropertyLabel = new GUIContent("H:", "The height of the glyph in the atlas texture."); + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + //EditorGUI.BeginProperty(position, label, property); + + SerializedProperty prop_X = property.FindPropertyRelative("m_X"); + SerializedProperty prop_Y = property.FindPropertyRelative("m_Y"); + SerializedProperty prop_Width = property.FindPropertyRelative("m_Width"); + SerializedProperty prop_Height = property.FindPropertyRelative("m_Height"); + + // We get Rect since a valid position may not be provided by the caller. + Rect rect = new Rect(position.x, position.y, position.width, 49); + EditorGUI.LabelField(new Rect(rect.x, rect.y - 2.5f, rect.width, 18), k_GlyphRectLabel); + + EditorGUIUtility.labelWidth = 20f; + EditorGUIUtility.fieldWidth = 20f; + + //GUI.enabled = false; + float width = (rect.width - 75f) / 4; + EditorGUI.PropertyField(new Rect(rect.x + width * 0, rect.y + 20, width - 5f, 18), prop_X, k_XPropertyLabel); + EditorGUI.PropertyField(new Rect(rect.x + width * 1, rect.y + 20, width - 5f, 18), prop_Y, k_YPropertyLabel); + EditorGUI.PropertyField(new Rect(rect.x + width * 2, rect.y + 20, width - 5f, 18), prop_Width, k_WidthPropertyLabel); + EditorGUI.PropertyField(new Rect(rect.x + width * 3, rect.y + 20, width - 5f, 18), prop_Height, k_HeightPropertyLabel); + + //EditorGUI.EndProperty(); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return 45f; + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/GlyphRectPropertyDrawer.cs.meta b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/GlyphRectPropertyDrawer.cs.meta new file mode 100644 index 00000000..93232794 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/GlyphRectPropertyDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8bc2b083b068f3546a9509c805e0541c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/LigatureSubstitutionRecordPropertyDrawer.cs b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/LigatureSubstitutionRecordPropertyDrawer.cs new file mode 100644 index 00000000..c2d38215 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/LigatureSubstitutionRecordPropertyDrawer.cs @@ -0,0 +1,123 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; +using UnityEngine.TextCore; +using UnityEngine.TextCore.LowLevel; + +namespace TMPro.EditorUtilities +{ + [CustomPropertyDrawer(typeof(LigatureSubstitutionRecord))] + class LigatureSubstitutionRecordPropertyDrawer : PropertyDrawer + { + private Dictionary m_GlyphLookupDictionary; + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + SerializedProperty prop_ComponentGlyphIDs = property.FindPropertyRelative("m_ComponentGlyphIDs"); + int ComponentGlyphIDCount = prop_ComponentGlyphIDs.arraySize; + SerializedProperty prop_LigatureGlyphID = property.FindPropertyRelative("m_LigatureGlyphID"); + + // Refresh glyph proxy lookup dictionary if needed + if (TMP_PropertyDrawerUtilities.s_RefreshGlyphProxyLookup) + TMP_PropertyDrawerUtilities.RefreshGlyphProxyLookup(property.serializedObject); + + Rect rect = position; + GUILayoutUtility.GetRect(position.width, 100); + + EditorGUIUtility.labelWidth = 115; + EditorGUI.BeginChangeCheck(); + int size = EditorGUI.DelayedIntField(new Rect(rect.x, position.y + 3, 130, rect.height), new GUIContent("Component Glyphs"), prop_ComponentGlyphIDs.arraySize); + if (EditorGUI.EndChangeCheck()) + { + size = Mathf.Clamp(size, 0, 20); + prop_ComponentGlyphIDs.arraySize = size; + return; + } + + // Spacing between glyphs + int glyphSpacing = 60; + + // Draw Component Glyphs + for (int i = 0; i < ComponentGlyphIDCount; i++) + { + Rect componentGlyphPosition = new Rect(50 + (glyphSpacing * i), position.y + 24, 48, 48); + + // Draw glyph + uint glyphIndex = (uint)prop_ComponentGlyphIDs.GetArrayElementAtIndex(i).intValue; + DrawGlyph(glyphIndex, componentGlyphPosition, property); + + EditorGUI.BeginChangeCheck(); + EditorGUI.DelayedIntField(new Rect(componentGlyphPosition.x - 13, componentGlyphPosition.y + 73, 40, EditorGUIUtility.singleLineHeight), prop_ComponentGlyphIDs.GetArrayElementAtIndex(i), GUIContent.none); + if (EditorGUI.EndChangeCheck()) + { + + } + } + + // Draw Ligature glyph + Rect ligatureGlyphPosition = new Rect(50 + (glyphSpacing * ComponentGlyphIDCount + 1), position.y + 3, 95, EditorGUIUtility.singleLineHeight); + ligatureGlyphPosition.x = Mathf.Max(200, ligatureGlyphPosition.x); + EditorGUI.LabelField(ligatureGlyphPosition, new GUIContent("Ligature Glyph")); + + DrawGlyph((uint)prop_LigatureGlyphID.intValue, new Rect(ligatureGlyphPosition.x + 37, ligatureGlyphPosition.y + 21, 48, 48), property); + + EditorGUI.BeginChangeCheck(); + EditorGUI.DelayedIntField(new Rect(ligatureGlyphPosition.x + 24, ligatureGlyphPosition.y + 94, 40, EditorGUIUtility.singleLineHeight), prop_LigatureGlyphID, GUIContent.none); + if (EditorGUI.EndChangeCheck()) + { + + } + } + + void DrawGlyph(uint glyphIndex, Rect glyphDrawPosition, SerializedProperty property) + { + // Get a reference to the serialized object which can either be a TMP_FontAsset or FontAsset. + SerializedObject so = property.serializedObject; + if (so == null) + return; + + if (m_GlyphLookupDictionary == null) + m_GlyphLookupDictionary = TMP_PropertyDrawerUtilities.GetGlyphProxyLookupDictionary(so); + + // Try getting a reference to the glyph for the given glyph index. + if (!m_GlyphLookupDictionary.TryGetValue(glyphIndex, out GlyphProxy glyph)) + return; + + Texture2D atlasTexture; + if (TMP_PropertyDrawerUtilities.TryGetAtlasTextureFromSerializedObject(so, glyph.atlasIndex, out atlasTexture) == false) + return; + + Material mat; + if (TMP_PropertyDrawerUtilities.TryGetMaterial(so, atlasTexture, out mat) == false) + return; + + int padding = so.FindProperty("m_AtlasPadding").intValue; + GlyphRect glyphRect = glyph.glyphRect; + int glyphOriginX = glyphRect.x - padding; + int glyphOriginY = glyphRect.y - padding; + int glyphWidth = glyphRect.width + padding * 2; + int glyphHeight = glyphRect.height + padding * 2; + + SerializedProperty faceInfoProperty = so.FindProperty("m_FaceInfo"); + float ascentLine = faceInfoProperty.FindPropertyRelative("m_AscentLine").floatValue; + float descentLine = faceInfoProperty.FindPropertyRelative("m_DescentLine").floatValue; + + float normalizedHeight = ascentLine - descentLine; + float scale = glyphDrawPosition.width / normalizedHeight; + + // Compute the normalized texture coordinates + Rect texCoords = new Rect((float)glyphOriginX / atlasTexture.width, (float)glyphOriginY / atlasTexture.height, (float)glyphWidth / atlasTexture.width, (float)glyphHeight / atlasTexture.height); + + if (Event.current.type == EventType.Repaint) + { + glyphDrawPosition.x += -(glyphWidth * scale / 2 - padding * scale); + glyphDrawPosition.y += glyphDrawPosition.height - glyph.metrics.horizontalBearingY * scale; + glyphDrawPosition.width = glyphWidth * scale; + glyphDrawPosition.height = glyphHeight * scale; + + // Could switch to using the default material of the font asset which would require passing scale to the shader. + Graphics.DrawTexture(glyphDrawPosition, atlasTexture, texCoords, 0, 0, 0, 0, new Color(1f, 1f, 1f), mat); + } + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/LigatureSubstitutionRecordPropertyDrawer.cs.meta b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/LigatureSubstitutionRecordPropertyDrawer.cs.meta new file mode 100644 index 00000000..d048e343 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/LigatureSubstitutionRecordPropertyDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7b6c2e51603686247afd5ab620c490e6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_CharacterPropertyDrawer.cs b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_CharacterPropertyDrawer.cs new file mode 100644 index 00000000..7034ffae --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_CharacterPropertyDrawer.cs @@ -0,0 +1,209 @@ +using UnityEngine; +using UnityEngine.TextCore; +using UnityEngine.TextCore.LowLevel; +using UnityEditor; +using System.Collections.Generic; + + +namespace TMPro.EditorUtilities +{ + [CustomPropertyDrawer(typeof(TMP_Character))] + public class TMP_CharacterPropertyDrawer : PropertyDrawer + { + private Dictionary m_GlyphLookupDictionary; + int m_GlyphSelectedForEditing = -1; + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + SerializedProperty prop_Unicode = property.FindPropertyRelative("m_Unicode"); + SerializedProperty prop_GlyphIndex = property.FindPropertyRelative("m_GlyphIndex"); + SerializedProperty prop_Scale = property.FindPropertyRelative("m_Scale"); + + // Refresh glyph proxy lookup dictionary if needed + if (TMP_PropertyDrawerUtilities.s_RefreshGlyphProxyLookup) + TMP_PropertyDrawerUtilities.RefreshGlyphProxyLookup(property.serializedObject); + + GUIStyle style = new GUIStyle(EditorStyles.label); + style.richText = true; + + EditorGUIUtility.labelWidth = 40f; + EditorGUIUtility.fieldWidth = 50; + + Rect rect = new Rect(position.x + 50, position.y, position.width, 49); + + // Display non-editable fields + if (GUI.enabled == false) + { + int unicode = prop_Unicode.intValue; + EditorGUI.LabelField(new Rect(rect.x, rect.y, 120f, 18), new GUIContent("Unicode: 0x" + unicode.ToString("X") + ""), style); + EditorGUI.LabelField(new Rect(rect.x + 115, rect.y, 120f, 18), unicode <= 0xFFFF ? new GUIContent("UTF16: \\u" + unicode.ToString("X4") + "") : new GUIContent("UTF32: \\U" + unicode.ToString("X8") + ""), style); + EditorGUI.LabelField(new Rect(rect.x, rect.y + 18, 120, 18), new GUIContent("Glyph ID: " + prop_GlyphIndex.intValue + ""), style); + EditorGUI.LabelField(new Rect(rect.x, rect.y + 36, 80, 18), new GUIContent("Scale: " + prop_Scale.floatValue + ""), style); + + // Draw Glyph (if exists) + DrawGlyph((uint)prop_GlyphIndex.intValue, new Rect(position.x, position.y, 48, 58), property); + } + else // Display editable fields + { + EditorGUIUtility.labelWidth = 55f; + GUI.SetNextControlName("Unicode Input"); + EditorGUI.BeginChangeCheck(); + string unicode = EditorGUI.TextField(new Rect(rect.x, rect.y, 120, 18), "Unicode:", prop_Unicode.intValue.ToString("X")); + + if (GUI.GetNameOfFocusedControl() == "Unicode Input") + { + //Filter out unwanted characters. + char chr = Event.current.character; + if ((chr < '0' || chr > '9') && (chr < 'a' || chr > 'f') && (chr < 'A' || chr > 'F')) + { + Event.current.character = '\0'; + } + } + + if (EditorGUI.EndChangeCheck()) + { + // Update Unicode value + prop_Unicode.intValue = TMP_TextUtilities.StringHexToInt(unicode); + } + + // Cache current glyph index in case it needs to be restored if the new glyph index is invalid. + int currentGlyphIndex = prop_GlyphIndex.intValue; + + EditorGUIUtility.labelWidth = 59f; + EditorGUI.BeginChangeCheck(); + EditorGUI.DelayedIntField(new Rect(rect.x, rect.y + 18, 100, 18), prop_GlyphIndex, new GUIContent("Glyph ID:")); + if (EditorGUI.EndChangeCheck()) + { + // Get a reference to the font asset + TMP_FontAsset fontAsset = property.serializedObject.targetObject as TMP_FontAsset; + + // Make sure new glyph index is valid. + int elementIndex = fontAsset.glyphTable.FindIndex(item => item.index == prop_GlyphIndex.intValue); + + if (elementIndex == -1) + prop_GlyphIndex.intValue = currentGlyphIndex; + else + fontAsset.IsFontAssetLookupTablesDirty = true; + } + + int glyphIndex = prop_GlyphIndex.intValue; + + // Reset glyph selection if new character has been selected. + if (GUI.enabled && m_GlyphSelectedForEditing != glyphIndex) + m_GlyphSelectedForEditing = -1; + + // Display button to edit the glyph data. + if (GUI.Button(new Rect(rect.x + 120, rect.y + 18, 75, 18), new GUIContent("Edit Glyph"))) + { + if (m_GlyphSelectedForEditing == -1) + m_GlyphSelectedForEditing = glyphIndex; + else + m_GlyphSelectedForEditing = -1; + + // Button clicks should not result in potential change. + GUI.changed = false; + } + + // Show the glyph property drawer if selected + if (glyphIndex == m_GlyphSelectedForEditing && GUI.enabled) + { + // Get a reference to the font asset + TMP_FontAsset fontAsset = property.serializedObject.targetObject as TMP_FontAsset; + + if (fontAsset != null) + { + // Get the index of the glyph in the font asset glyph table. + int elementIndex = fontAsset.glyphTable.FindIndex(item => item.index == glyphIndex); + + if (elementIndex != -1) + { + SerializedProperty prop_GlyphTable = property.serializedObject.FindProperty("m_GlyphTable"); + SerializedProperty prop_Glyph = prop_GlyphTable.GetArrayElementAtIndex(elementIndex); + + SerializedProperty prop_GlyphMetrics = prop_Glyph.FindPropertyRelative("m_Metrics"); + SerializedProperty prop_GlyphRect = prop_Glyph.FindPropertyRelative("m_GlyphRect"); + + Rect newRect = EditorGUILayout.GetControlRect(false, 115); + EditorGUI.DrawRect(new Rect(newRect.x + 52, newRect.y - 20, newRect.width - 52, newRect.height - 5), new Color(0.1f, 0.1f, 0.1f, 0.45f)); + EditorGUI.DrawRect(new Rect(newRect.x + 53, newRect.y - 19, newRect.width - 54, newRect.height - 7), new Color(0.3f, 0.3f, 0.3f, 0.8f)); + + // Display GlyphRect + newRect.x += 55; + newRect.y -= 18; + newRect.width += 5; + EditorGUI.PropertyField(newRect, prop_GlyphRect); + + // Display GlyphMetrics + newRect.y += 45; + EditorGUI.PropertyField(newRect, prop_GlyphMetrics); + + rect.y += 120; + } + } + } + + EditorGUIUtility.labelWidth = 39f; + EditorGUI.PropertyField(new Rect(rect.x, rect.y + 36, 80, 18), prop_Scale, new GUIContent("Scale:")); + + // Draw Glyph (if exists) + DrawGlyph((uint)prop_GlyphIndex.intValue, new Rect(position.x, position.y, 48, 58), property); + } + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return 58; + } + + void DrawGlyph(uint glyphIndex, Rect glyphDrawPosition, SerializedProperty property) + { + // Get a reference to the serialized object which can either be a TMP_FontAsset or FontAsset. + SerializedObject so = property.serializedObject; + if (so == null) + return; + + if (m_GlyphLookupDictionary == null) + m_GlyphLookupDictionary = TMP_PropertyDrawerUtilities.GetGlyphProxyLookupDictionary(so); + + // Try getting a reference to the glyph for the given glyph index. + if (!m_GlyphLookupDictionary.TryGetValue(glyphIndex, out GlyphProxy glyph)) + return; + + Texture2D atlasTexture; + if (TMP_PropertyDrawerUtilities.TryGetAtlasTextureFromSerializedObject(so, glyph.atlasIndex, out atlasTexture) == false) + return; + + Material mat; + if (TMP_PropertyDrawerUtilities.TryGetMaterial(so, atlasTexture, out mat) == false) + return; + + int padding = so.FindProperty("m_AtlasPadding").intValue; + GlyphRect glyphRect = glyph.glyphRect; + int glyphOriginX = glyphRect.x - padding; + int glyphOriginY = glyphRect.y - padding; + int glyphWidth = glyphRect.width + padding * 2; + int glyphHeight = glyphRect.height + padding * 2; + + SerializedProperty faceInfoProperty = so.FindProperty("m_FaceInfo"); + float ascentLine = faceInfoProperty.FindPropertyRelative("m_AscentLine").floatValue; + float descentLine = faceInfoProperty.FindPropertyRelative("m_DescentLine").floatValue; + + float normalizedHeight = ascentLine - descentLine; + float scale = glyphDrawPosition.width / normalizedHeight; + + // Compute the normalized texture coordinates + Rect texCoords = new Rect((float)glyphOriginX / atlasTexture.width, (float)glyphOriginY / atlasTexture.height, (float)glyphWidth / atlasTexture.width, (float)glyphHeight / atlasTexture.height); + + if (Event.current.type == EventType.Repaint) + { + glyphDrawPosition.x += (glyphDrawPosition.width - glyphWidth * scale) / 2; + glyphDrawPosition.y += (glyphDrawPosition.height - glyphHeight * scale) / 2; + glyphDrawPosition.width = glyphWidth * scale; + glyphDrawPosition.height = glyphHeight * scale; + + // Could switch to using the default material of the font asset which would require passing scale to the shader. + Graphics.DrawTexture(glyphDrawPosition, atlasTexture, texCoords, 0, 0, 0, 0, new Color(1f, 1f, 1f), mat); + } + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_CharacterPropertyDrawer.cs.meta b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_CharacterPropertyDrawer.cs.meta new file mode 100644 index 00000000..3bf78921 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_CharacterPropertyDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 01ada73c4792aba4c937ff5d92cce866 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_GlyphPropertyDrawer.cs b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_GlyphPropertyDrawer.cs new file mode 100644 index 00000000..69fb0d05 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_GlyphPropertyDrawer.cs @@ -0,0 +1,106 @@ +using UnityEngine; +using UnityEngine.TextCore; +using UnityEditor; +using System.Collections.Generic; + + +namespace TMPro.EditorUtilities +{ + + [CustomPropertyDrawer(typeof(Glyph))] + public class TMP_GlyphPropertyDrawer : PropertyDrawer + { + private static readonly GUIContent k_ScaleLabel = new GUIContent("Scale:", "The scale of this glyph."); + private static readonly GUIContent k_AtlasIndexLabel = new GUIContent("Atlas Index:", "The index of the atlas texture that contains this glyph."); + private static readonly GUIContent k_ClassTypeLabel = new GUIContent("Class Type:", "The class definition type of this glyph."); + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + SerializedProperty prop_GlyphIndex = property.FindPropertyRelative("m_Index"); + SerializedProperty prop_GlyphMetrics = property.FindPropertyRelative("m_Metrics"); + SerializedProperty prop_GlyphRect = property.FindPropertyRelative("m_GlyphRect"); + SerializedProperty prop_Scale = property.FindPropertyRelative("m_Scale"); + SerializedProperty prop_AtlasIndex = property.FindPropertyRelative("m_AtlasIndex"); + SerializedProperty prop_ClassDefinitionType = property.FindPropertyRelative("m_ClassDefinitionType"); + + GUIStyle style = new GUIStyle(EditorStyles.label); + style.richText = true; + + Rect rect = new Rect(position.x + 70, position.y, position.width, 49); + + float labelWidth = GUI.skin.label.CalcSize(new GUIContent("ID: " + prop_GlyphIndex.intValue)).x; + EditorGUI.LabelField(new Rect(position.x + (64 - labelWidth) / 2, position.y + 85, 64f, 18f), new GUIContent("ID: " + prop_GlyphIndex.intValue + ""), style); + + // We get Rect since a valid position may not be provided by the caller. + EditorGUI.PropertyField(new Rect(rect.x, rect.y, position.width, 49), prop_GlyphRect); + + rect.y += 45; + EditorGUI.PropertyField(rect, prop_GlyphMetrics); + + EditorGUIUtility.labelWidth = 40f; + EditorGUI.PropertyField(new Rect(rect.x, rect.y + 65, 75, 18), prop_Scale, k_ScaleLabel); + + EditorGUIUtility.labelWidth = 70f; + EditorGUI.PropertyField(new Rect(rect.x + 85, rect.y + 65, 95, 18), prop_AtlasIndex, k_AtlasIndexLabel); + + if (prop_ClassDefinitionType != null) + { + EditorGUIUtility.labelWidth = 70f; + float minWidth = Mathf.Max(90, rect.width - 270); + EditorGUI.PropertyField(new Rect(rect.x + 190, rect.y + 65, minWidth, 18), prop_ClassDefinitionType, k_ClassTypeLabel); + } + + DrawGlyph(new Rect(position.x, position.y + 2, 64, 80), property); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return 130f; + } + + void DrawGlyph(Rect glyphDrawPosition, SerializedProperty property) + { + // Get a reference to the serialized object which can either be a TMP_FontAsset or FontAsset. + SerializedObject so = property.serializedObject; + if (so == null) + return; + + Texture2D atlasTexture; + int atlasIndex = property.FindPropertyRelative("m_AtlasIndex").intValue; + int padding = so.FindProperty("m_AtlasPadding").intValue; + if (TMP_PropertyDrawerUtilities.TryGetAtlasTextureFromSerializedObject(so, atlasIndex, out atlasTexture) == false) + return; + + Material mat; + if (TMP_PropertyDrawerUtilities.TryGetMaterial(so, atlasTexture, out mat) == false) + return; + + GlyphRect glyphRect = TMP_PropertyDrawerUtilities.GetGlyphRectFromGlyphSerializedProperty(property); + int glyphOriginX = glyphRect.x - padding; + int glyphOriginY = glyphRect.y - padding; + int glyphWidth = glyphRect.width + padding * 2; + int glyphHeight = glyphRect.height + padding * 2; + + SerializedProperty faceInfoProperty = so.FindProperty("m_FaceInfo"); + float ascentLine = faceInfoProperty.FindPropertyRelative("m_AscentLine").floatValue; + float descentLine = faceInfoProperty.FindPropertyRelative("m_DescentLine").floatValue; + + float normalizedHeight = ascentLine - descentLine; + float scale = glyphDrawPosition.width / normalizedHeight; + + // Compute the normalized texture coordinates + Rect texCoords = new Rect((float)glyphOriginX / atlasTexture.width, (float)glyphOriginY / atlasTexture.height, (float)glyphWidth / atlasTexture.width, (float)glyphHeight / atlasTexture.height); + + if (Event.current.type == EventType.Repaint) + { + glyphDrawPosition.x += (glyphDrawPosition.width - glyphWidth * scale) / 2; + glyphDrawPosition.y += (glyphDrawPosition.height - glyphHeight * scale) / 2; + glyphDrawPosition.width = glyphWidth * scale; + glyphDrawPosition.height = glyphHeight * scale; + + // Could switch to using the default material of the font asset which would require passing scale to the shader. + Graphics.DrawTexture(glyphDrawPosition, atlasTexture, texCoords, 0, 0, 0, 0, new Color(1f, 1f, 1f), mat); + } + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_GlyphPropertyDrawer.cs.meta b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_GlyphPropertyDrawer.cs.meta new file mode 100644 index 00000000..ce08447f --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_GlyphPropertyDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c4777500b5da6094e956c3d4f04de4db +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_MarkToBaseAdjustmentRecordPropertyDrawer.cs b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_MarkToBaseAdjustmentRecordPropertyDrawer.cs new file mode 100644 index 00000000..fc3c2899 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_MarkToBaseAdjustmentRecordPropertyDrawer.cs @@ -0,0 +1,236 @@ +using UnityEngine; +using UnityEngine.TextCore; +using UnityEditor; +using System.Collections.Generic; + + +namespace TMPro.EditorUtilities +{ + [CustomPropertyDrawer(typeof(MarkToBaseAdjustmentRecord))] + internal class TMP_MarkToBaseAdjustmentRecordPropertyDrawer : PropertyDrawer + { + private bool isEditingEnabled; + private bool isSelectable; + private Dictionary m_GlyphLookupDictionary; + + private string m_PreviousInput; + + //static GUIContent s_CharacterTextFieldLabel = new GUIContent("Char:", "Enter the character or its UTF16 or UTF32 Unicode character escape sequence. For UTF16 use \"\\uFF00\" and for UTF32 use \"\\UFF00FF00\" representation."); + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + SerializedProperty prop_BaseGlyphID = property.FindPropertyRelative("m_BaseGlyphID"); + SerializedProperty prop_BaseGlyphAnchorPoint = property.FindPropertyRelative("m_BaseGlyphAnchorPoint"); + + SerializedProperty prop_MarkGlyphID = property.FindPropertyRelative("m_MarkGlyphID"); + SerializedProperty prop_MarkAdjustmentRecord = property.FindPropertyRelative("m_MarkPositionAdjustment"); + + // Refresh glyph proxy lookup dictionary if needed + if (TMP_PropertyDrawerUtilities.s_RefreshGlyphProxyLookup) + TMP_PropertyDrawerUtilities.RefreshGlyphProxyLookup(property.serializedObject); + + position.yMin += 2; + + float width = position.width / 2; + float padding = 5.0f; + + Rect rect; + + isEditingEnabled = GUI.enabled; + isSelectable = label.text == "Selectable"; + + if (isSelectable) + GUILayoutUtility.GetRect(position.width, 75); + else + GUILayoutUtility.GetRect(position.width, 55); + + GUIStyle style = new GUIStyle(EditorStyles.label) {richText = true}; + + // Base Glyph + GUI.enabled = isEditingEnabled; + if (isSelectable) + { + float labelWidth = GUI.skin.label.CalcSize(new GUIContent("ID: " + prop_BaseGlyphID.intValue)).x; + + if (!isEditingEnabled) + { + EditorGUI.LabelField(new Rect(position.x + (64 - labelWidth) / 2, position.y + 60, 64f, 18f), new GUIContent("ID: " + prop_BaseGlyphID.intValue + ""), style); + } + else + { + EditorGUI.BeginChangeCheck(); + EditorGUIUtility.labelWidth = 25f; + EditorGUI.DelayedIntField(new Rect(position.x + (64 - labelWidth) / 2, position.y + 60, 64, 18), prop_BaseGlyphID, new GUIContent("ID:")); + if (EditorGUI.EndChangeCheck()) + { + + } + } + + GUI.enabled = isEditingEnabled; + EditorGUIUtility.labelWidth = 30f; + + rect = new Rect(position.x + 70, position.y + 10, (width - 70) - padding, 18); + EditorGUI.PropertyField(rect, prop_BaseGlyphAnchorPoint.FindPropertyRelative("m_XCoordinate"), new GUIContent("X:")); + + rect.y += 20; + EditorGUI.PropertyField(rect, prop_BaseGlyphAnchorPoint.FindPropertyRelative("m_YCoordinate"), new GUIContent("Y:")); + + DrawGlyph((uint)prop_BaseGlyphID.intValue, new Rect(position.x, position.y + 2, 64, 60), property); + } + + // Mark Glyph + GUI.enabled = isEditingEnabled; + if (isSelectable) + { + float labelWidth = GUI.skin.label.CalcSize(new GUIContent("ID: " + prop_MarkGlyphID.intValue)).x; + + if (!isEditingEnabled) + { + EditorGUI.LabelField(new Rect(position.width / 2 + 20 + (64 - labelWidth) / 2, position.y + 60, 64f, 18f), new GUIContent("ID: " + prop_MarkGlyphID.intValue + ""), style); + } + else + { + EditorGUI.BeginChangeCheck(); + EditorGUIUtility.labelWidth = 25f; + EditorGUI.DelayedIntField(new Rect(position.width / 2 + 20 + (64 - labelWidth) / 2, position.y + 60, 64, 18), prop_MarkGlyphID, new GUIContent("ID:")); + if (EditorGUI.EndChangeCheck()) + { + + } + } + + GUI.enabled = isEditingEnabled; + EditorGUIUtility.labelWidth = 30f; + + rect = new Rect(position.width / 2 + 20 + 70, position.y + 10, (width - 70) - padding, 18); + EditorGUI.PropertyField(rect, prop_MarkAdjustmentRecord.FindPropertyRelative("m_XPositionAdjustment"), new GUIContent("X:")); + + rect.y += 20; + EditorGUI.PropertyField(rect, prop_MarkAdjustmentRecord.FindPropertyRelative("m_YPositionAdjustment"), new GUIContent("Y:")); + + DrawGlyph((uint)prop_MarkGlyphID.intValue, new Rect(position.width / 2 + 20, position.y + 2, 64, 60), property); + } + } + + bool ValidateInput(string source) + { + int length = string.IsNullOrEmpty(source) ? 0 : source.Length; + + ////Filter out unwanted characters. + Event evt = Event.current; + + char c = evt.character; + + if (c != '\0') + { + switch (length) + { + case 0: + break; + case 1: + if (source != m_PreviousInput) + return true; + + if ((source[0] == '\\' && (c == 'u' || c == 'U')) == false) + evt.character = '\0'; + + break; + case 2: + case 3: + case 4: + case 5: + if ((c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F')) + evt.character = '\0'; + break; + case 6: + case 7: + case 8: + case 9: + if (source[1] == 'u' || (c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F')) + evt.character = '\0'; + + // Validate input + if (length == 6 && source[1] == 'u' && source != m_PreviousInput) + return true; + break; + case 10: + if (source != m_PreviousInput) + return true; + + evt.character = '\0'; + break; + } + } + + m_PreviousInput = source; + + return false; + } + + uint GetUnicodeCharacter (string source) + { + uint unicode; + + if (source.Length == 1) + unicode = source[0]; + else if (source.Length == 6) + unicode = (uint)TMP_TextUtilities.StringHexToInt(source.Replace("\\u", "")); + else + unicode = (uint)TMP_TextUtilities.StringHexToInt(source.Replace("\\U", "")); + + return unicode; + } + + void DrawGlyph(uint glyphIndex, Rect glyphDrawPosition, SerializedProperty property) + { + // Get a reference to the serialized object which can either be a TMP_FontAsset or FontAsset. + SerializedObject so = property.serializedObject; + if (so == null) + return; + + if (m_GlyphLookupDictionary == null) + m_GlyphLookupDictionary = TMP_PropertyDrawerUtilities.GetGlyphProxyLookupDictionary(so); + + // Try getting a reference to the glyph for the given glyph index. + if (!m_GlyphLookupDictionary.TryGetValue(glyphIndex, out GlyphProxy glyph)) + return; + + Texture2D atlasTexture; + if (TMP_PropertyDrawerUtilities.TryGetAtlasTextureFromSerializedObject(so, glyph.atlasIndex, out atlasTexture) == false) + return; + + Material mat; + if (TMP_PropertyDrawerUtilities.TryGetMaterial(so, atlasTexture, out mat) == false) + return; + + int padding = so.FindProperty("m_AtlasPadding").intValue; + GlyphRect glyphRect = glyph.glyphRect; + int glyphOriginX = glyphRect.x - padding; + int glyphOriginY = glyphRect.y - padding; + int glyphWidth = glyphRect.width + padding * 2; + int glyphHeight = glyphRect.height + padding * 2; + + SerializedProperty faceInfoProperty = so.FindProperty("m_FaceInfo"); + float ascentLine = faceInfoProperty.FindPropertyRelative("m_AscentLine").floatValue; + float descentLine = faceInfoProperty.FindPropertyRelative("m_DescentLine").floatValue; + + float normalizedHeight = ascentLine - descentLine; + float scale = glyphDrawPosition.width / normalizedHeight; + + // Compute the normalized texture coordinates + Rect texCoords = new Rect((float)glyphOriginX / atlasTexture.width, (float)glyphOriginY / atlasTexture.height, (float)glyphWidth / atlasTexture.width, (float)glyphHeight / atlasTexture.height); + + if (Event.current.type == EventType.Repaint) + { + glyphDrawPosition.x += (glyphDrawPosition.width - glyphWidth * scale) / 2; + glyphDrawPosition.y += (glyphDrawPosition.height - glyphHeight * scale) / 2; + glyphDrawPosition.width = glyphWidth * scale; + glyphDrawPosition.height = glyphHeight * scale; + + // Could switch to using the default material of the font asset which would require passing scale to the shader. + Graphics.DrawTexture(glyphDrawPosition, atlasTexture, texCoords, 0, 0, 0, 0, new Color(1f, 1f, 1f), mat); + } + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_MarkToBaseAdjustmentRecordPropertyDrawer.cs.meta b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_MarkToBaseAdjustmentRecordPropertyDrawer.cs.meta new file mode 100644 index 00000000..8f5655a4 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_MarkToBaseAdjustmentRecordPropertyDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 065a7fcf0d7286d418f3114ec18d1a2d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_MarkToMarkAdjustmentRecordPropertyDrawer.cs b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_MarkToMarkAdjustmentRecordPropertyDrawer.cs new file mode 100644 index 00000000..7a581261 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_MarkToMarkAdjustmentRecordPropertyDrawer.cs @@ -0,0 +1,237 @@ +using UnityEngine; +using UnityEngine.TextCore; +using UnityEditor; +using System.Collections.Generic; + + +namespace TMPro.EditorUtilities +{ + [CustomPropertyDrawer(typeof(MarkToMarkAdjustmentRecord))] + public class TMP_MarkToMarkAdjustmentRecordPropertyDrawer : PropertyDrawer + { + private bool isEditingEnabled; + private bool isSelectable; + + private Dictionary m_GlyphLookupDictionary; + + private string m_PreviousInput; + + static GUIContent s_CharacterTextFieldLabel = new GUIContent("Char:", "Enter the character or its UTF16 or UTF32 Unicode character escape sequence. For UTF16 use \"\\uFF00\" and for UTF32 use \"\\UFF00FF00\" representation."); + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + SerializedProperty prop_BaseGlyphID = property.FindPropertyRelative("m_BaseMarkGlyphID"); + SerializedProperty prop_BaseGlyphAnchorPoint = property.FindPropertyRelative("m_BaseMarkGlyphAnchorPoint"); + + SerializedProperty prop_MarkGlyphID = property.FindPropertyRelative("m_CombiningMarkGlyphID"); + SerializedProperty prop_MarkAdjustmentRecord = property.FindPropertyRelative("m_CombiningMarkPositionAdjustment"); + + // Refresh glyph proxy lookup dictionary if needed + if (TMP_PropertyDrawerUtilities.s_RefreshGlyphProxyLookup) + TMP_PropertyDrawerUtilities.RefreshGlyphProxyLookup(property.serializedObject); + + position.yMin += 2; + + float width = position.width / 2; + float padding = 5.0f; + + Rect rect; + + isEditingEnabled = GUI.enabled; + isSelectable = label.text == "Selectable"; + + if (isSelectable) + GUILayoutUtility.GetRect(position.width, 75); + else + GUILayoutUtility.GetRect(position.width, 55); + + GUIStyle style = new GUIStyle(EditorStyles.label) {richText = true}; + + // Base Glyph + GUI.enabled = isEditingEnabled; + if (isSelectable) + { + float labelWidth = GUI.skin.label.CalcSize(new GUIContent("ID: " + prop_BaseGlyphID.intValue)).x; + + if (!isEditingEnabled) + { + EditorGUI.LabelField(new Rect(position.x + (64 - labelWidth) / 2, position.y + 60, 64f, 18f), new GUIContent("ID: " + prop_BaseGlyphID.intValue + ""), style); + } + else + { + EditorGUI.BeginChangeCheck(); + EditorGUIUtility.labelWidth = 25f; + EditorGUI.DelayedIntField(new Rect(position.x + (64 - labelWidth) / 2, position.y + 60, 64, 18), prop_BaseGlyphID, new GUIContent("ID:")); + if (EditorGUI.EndChangeCheck()) + { + + } + } + + GUI.enabled = isEditingEnabled; + EditorGUIUtility.labelWidth = 30f; + + rect = new Rect(position.x + 70, position.y + 10, (width - 70) - padding, 18); + EditorGUI.PropertyField(rect, prop_BaseGlyphAnchorPoint.FindPropertyRelative("m_XCoordinate"), new GUIContent("X:")); + + rect.y += 20; + EditorGUI.PropertyField(rect, prop_BaseGlyphAnchorPoint.FindPropertyRelative("m_YCoordinate"), new GUIContent("Y:")); + + DrawGlyph((uint)prop_BaseGlyphID.intValue, new Rect(position.x, position.y + 2, 64, 60), property); + } + + // Mark Glyph + GUI.enabled = isEditingEnabled; + if (isSelectable) + { + float labelWidth = GUI.skin.label.CalcSize(new GUIContent("ID: " + prop_MarkGlyphID.intValue)).x; + + if (!isEditingEnabled) + { + EditorGUI.LabelField(new Rect(position.width / 2 + 20 + (64 - labelWidth) / 2, position.y + 60, 64f, 18f), new GUIContent("ID: " + prop_MarkGlyphID.intValue + ""), style); + } + else + { + EditorGUI.BeginChangeCheck(); + EditorGUIUtility.labelWidth = 25f; + EditorGUI.DelayedIntField(new Rect(position.width / 2 + 20 + (64 - labelWidth) / 2, position.y + 60, 64, 18), prop_MarkGlyphID, new GUIContent("ID:")); + if (EditorGUI.EndChangeCheck()) + { + + } + } + + GUI.enabled = isEditingEnabled; + EditorGUIUtility.labelWidth = 30f; + + rect = new Rect(position.width / 2 + 20 + 70, position.y + 10, (width - 70) - padding, 18); + EditorGUI.PropertyField(rect, prop_MarkAdjustmentRecord.FindPropertyRelative("m_XPositionAdjustment"), new GUIContent("X:")); + + rect.y += 20; + EditorGUI.PropertyField(rect, prop_MarkAdjustmentRecord.FindPropertyRelative("m_YPositionAdjustment"), new GUIContent("Y:")); + + DrawGlyph((uint)prop_MarkGlyphID.intValue, new Rect(position.width / 2 + 20, position.y + 2, 64, 60), property); + } + } + + bool ValidateInput(string source) + { + int length = string.IsNullOrEmpty(source) ? 0 : source.Length; + + ////Filter out unwanted characters. + Event evt = Event.current; + + char c = evt.character; + + if (c != '\0') + { + switch (length) + { + case 0: + break; + case 1: + if (source != m_PreviousInput) + return true; + + if ((source[0] == '\\' && (c == 'u' || c == 'U')) == false) + evt.character = '\0'; + + break; + case 2: + case 3: + case 4: + case 5: + if ((c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F')) + evt.character = '\0'; + break; + case 6: + case 7: + case 8: + case 9: + if (source[1] == 'u' || (c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F')) + evt.character = '\0'; + + // Validate input + if (length == 6 && source[1] == 'u' && source != m_PreviousInput) + return true; + break; + case 10: + if (source != m_PreviousInput) + return true; + + evt.character = '\0'; + break; + } + } + + m_PreviousInput = source; + + return false; + } + + uint GetUnicodeCharacter (string source) + { + uint unicode; + + if (source.Length == 1) + unicode = source[0]; + else if (source.Length == 6) + unicode = (uint)TMP_TextUtilities.StringHexToInt(source.Replace("\\u", "")); + else + unicode = (uint)TMP_TextUtilities.StringHexToInt(source.Replace("\\U", "")); + + return unicode; + } + + void DrawGlyph(uint glyphIndex, Rect glyphDrawPosition, SerializedProperty property) + { + // Get a reference to the serialized object which can either be a TMP_FontAsset or FontAsset. + SerializedObject so = property.serializedObject; + if (so == null) + return; + + if (m_GlyphLookupDictionary == null) + m_GlyphLookupDictionary = TMP_PropertyDrawerUtilities.GetGlyphProxyLookupDictionary(so); + + // Try getting a reference to the glyph for the given glyph index. + if (!m_GlyphLookupDictionary.TryGetValue(glyphIndex, out GlyphProxy glyph)) + return; + + Texture2D atlasTexture; + if (TMP_PropertyDrawerUtilities.TryGetAtlasTextureFromSerializedObject(so, glyph.atlasIndex, out atlasTexture) == false) + return; + + Material mat; + if (TMP_PropertyDrawerUtilities.TryGetMaterial(so, atlasTexture, out mat) == false) + return; + + int padding = so.FindProperty("m_AtlasPadding").intValue; + GlyphRect glyphRect = glyph.glyphRect; + int glyphOriginX = glyphRect.x - padding; + int glyphOriginY = glyphRect.y - padding; + int glyphWidth = glyphRect.width + padding * 2; + int glyphHeight = glyphRect.height + padding * 2; + + SerializedProperty faceInfoProperty = so.FindProperty("m_FaceInfo"); + float ascentLine = faceInfoProperty.FindPropertyRelative("m_AscentLine").floatValue; + float descentLine = faceInfoProperty.FindPropertyRelative("m_DescentLine").floatValue; + + float normalizedHeight = ascentLine - descentLine; + float scale = glyphDrawPosition.width / normalizedHeight; + + // Compute the normalized texture coordinates + Rect texCoords = new Rect((float)glyphOriginX / atlasTexture.width, (float)glyphOriginY / atlasTexture.height, (float)glyphWidth / atlasTexture.width, (float)glyphHeight / atlasTexture.height); + + if (Event.current.type == EventType.Repaint) + { + glyphDrawPosition.x += (glyphDrawPosition.width - glyphWidth * scale) / 2; + glyphDrawPosition.y += (glyphDrawPosition.height - glyphHeight * scale) / 2; + glyphDrawPosition.width = glyphWidth * scale; + glyphDrawPosition.height = glyphHeight * scale; + + // Could switch to using the default material of the font asset which would require passing scale to the shader. + Graphics.DrawTexture(glyphDrawPosition, atlasTexture, texCoords, 0, 0, 0, 0, new Color(1f, 1f, 1f), mat); + } + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_MarkToMarkAdjustmentRecordPropertyDrawer.cs.meta b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_MarkToMarkAdjustmentRecordPropertyDrawer.cs.meta new file mode 100644 index 00000000..8e3062e2 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_MarkToMarkAdjustmentRecordPropertyDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 149e85704eb73624ba2d705408274f3e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_PropertyDrawerUtilities.cs b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_PropertyDrawerUtilities.cs new file mode 100644 index 00000000..5f8c9e9e --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_PropertyDrawerUtilities.cs @@ -0,0 +1,180 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; +using UnityEngine.TextCore; +using UnityEngine.TextCore.LowLevel; + + +namespace TMPro.EditorUtilities +{ + internal struct GlyphProxy + { + public uint index; + public GlyphRect glyphRect; + public GlyphMetrics metrics; + public int atlasIndex; + } + + internal static class TMP_PropertyDrawerUtilities + { + internal static bool s_RefreshGlyphProxyLookup; + private static Dictionary> s_GlyphProxyLookups = new Dictionary>(); + + internal static void ClearGlyphProxyLookups() + { + s_GlyphProxyLookups.Clear(); + } + + internal static void RefreshGlyphProxyLookup(SerializedObject so) + { + if (!s_GlyphProxyLookups.ContainsKey(so)) + return; + + Dictionary glyphProxyLookup = s_GlyphProxyLookups[so]; + + glyphProxyLookup.Clear(); + PopulateGlyphProxyLookupDictionary(so, glyphProxyLookup); + + s_RefreshGlyphProxyLookup = false; + } + + internal static Dictionary GetGlyphProxyLookupDictionary(SerializedObject so) + { + if (s_GlyphProxyLookups.ContainsKey(so)) + return s_GlyphProxyLookups[so]; + + Dictionary glyphProxyLookup = new Dictionary(); + PopulateGlyphProxyLookupDictionary(so, glyphProxyLookup); + s_GlyphProxyLookups.Add(so, glyphProxyLookup); + + return glyphProxyLookup; + } + + /// + /// + /// + /// + /// + static void PopulateGlyphProxyLookupDictionary(SerializedObject so, Dictionary lookupDictionary) + { + if (lookupDictionary == null) + return; + + // Get reference to serialized property for the glyph table + SerializedProperty glyphTable = so.FindProperty("m_GlyphTable"); + + for (int i = 0; i < glyphTable.arraySize; i++) + { + SerializedProperty glyphProperty = glyphTable.GetArrayElementAtIndex(i); + GlyphProxy proxy = GetGlyphProxyFromSerializedProperty(glyphProperty); + + lookupDictionary.Add(proxy.index, proxy); + } + } + + internal static GlyphRect GetGlyphRectFromGlyphSerializedProperty(SerializedProperty property) + { + SerializedProperty glyphRectProp = property.FindPropertyRelative("m_GlyphRect"); + + GlyphRect glyphRect = new GlyphRect(); + glyphRect.x = glyphRectProp.FindPropertyRelative("m_X").intValue; + glyphRect.y = glyphRectProp.FindPropertyRelative("m_Y").intValue; + glyphRect.width = glyphRectProp.FindPropertyRelative("m_Width").intValue; + glyphRect.height = glyphRectProp.FindPropertyRelative("m_Height").intValue; + + return glyphRect; + } + + internal static GlyphMetrics GetGlyphMetricsFromGlyphSerializedProperty(SerializedProperty property) + { + SerializedProperty glyphMetricsProperty = property.FindPropertyRelative("m_Metrics"); + + GlyphMetrics glyphMetrics = new GlyphMetrics(); + glyphMetrics.horizontalBearingX = glyphMetricsProperty.FindPropertyRelative("m_HorizontalBearingX").floatValue; + glyphMetrics.horizontalBearingY = glyphMetricsProperty.FindPropertyRelative("m_HorizontalBearingY").floatValue; + glyphMetrics.horizontalAdvance = glyphMetricsProperty.FindPropertyRelative("m_HorizontalAdvance").floatValue; + glyphMetrics.width = glyphMetricsProperty.FindPropertyRelative("m_Width").floatValue; + glyphMetrics.height = glyphMetricsProperty.FindPropertyRelative("m_Height").floatValue; + + return glyphMetrics; + } + + /// + /// + /// + /// + /// + internal static GlyphProxy GetGlyphProxyFromSerializedProperty(SerializedProperty property) + { + GlyphProxy proxy = new GlyphProxy(); + proxy.index = (uint)property.FindPropertyRelative("m_Index").intValue; + proxy.glyphRect = GetGlyphRectFromGlyphSerializedProperty(property); + proxy.metrics = GetGlyphMetricsFromGlyphSerializedProperty(property); + proxy.atlasIndex = property.FindPropertyRelative("m_AtlasIndex").intValue; + + return proxy; + } + + /// + /// + /// + /// + /// + /// + /// + internal static bool TryGetAtlasTextureFromSerializedObject(SerializedObject serializedObject, int glyphIndex, out Texture2D texture) + { + SerializedProperty atlasTextureProperty = serializedObject.FindProperty("m_AtlasTextures"); + + texture = atlasTextureProperty.GetArrayElementAtIndex(glyphIndex).objectReferenceValue as Texture2D; + + if (texture == null) + return false; + + return true; + } + + /// + /// + /// + /// + /// + /// + /// + internal static bool TryGetMaterial(SerializedObject serializedObject, Texture2D texture, out Material mat) + { + GlyphRenderMode atlasRenderMode = (GlyphRenderMode)serializedObject.FindProperty("m_AtlasRenderMode").intValue; + + if (((GlyphRasterModes)atlasRenderMode & GlyphRasterModes.RASTER_MODE_BITMAP) == GlyphRasterModes.RASTER_MODE_BITMAP) + { + #if TEXTCORE_FONT_ENGINE_1_5_OR_NEWER + if (atlasRenderMode == GlyphRenderMode.COLOR || atlasRenderMode == GlyphRenderMode.COLOR_HINTED) + mat = TMP_FontAssetEditor.internalRGBABitmapMaterial; + else + mat = TMP_FontAssetEditor.internalBitmapMaterial; + #else + mat = TMP_FontAssetEditor.internalBitmapMaterial; + #endif + + if (mat == null) + return false; + + mat.mainTexture = texture; + mat.color = Color.white; + } + else + { + mat = TMP_FontAssetEditor.internalSDFMaterial; + + if (mat == null) + return false; + + int padding = serializedObject.FindProperty("m_AtlasPadding").intValue; + mat.mainTexture = texture; + mat.SetFloat(ShaderUtilities.ID_GradientScale, padding + 1); + } + + return true; + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_PropertyDrawerUtilities.cs.meta b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_PropertyDrawerUtilities.cs.meta new file mode 100644 index 00000000..7698504e --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_PropertyDrawerUtilities.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 371a2245f9a9ff344997fec3609bf73e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_SpriteCharacterPropertyDrawer.cs b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_SpriteCharacterPropertyDrawer.cs new file mode 100644 index 00000000..86dda644 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_SpriteCharacterPropertyDrawer.cs @@ -0,0 +1,212 @@ +using UnityEngine; +using UnityEngine.TextCore; +using UnityEditor; +using System.Collections.Generic; + + +namespace TMPro.EditorUtilities +{ + + [CustomPropertyDrawer(typeof(TMP_SpriteCharacter))] + public class TMP_SpriteCharacterPropertyDrawer : PropertyDrawer + { + int m_GlyphSelectedForEditing = -1; + private Dictionary m_GlyphLookupDictionary; + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + SerializedProperty prop_SpriteName = property.FindPropertyRelative("m_Name"); + SerializedProperty prop_SpriteUnicode = property.FindPropertyRelative("m_Unicode"); + SerializedProperty prop_SpriteGlyphIndex = property.FindPropertyRelative("m_GlyphIndex"); + SerializedProperty prop_SpriteScale = property.FindPropertyRelative("m_Scale"); + + GUIStyle style = new GUIStyle(EditorStyles.label); + style.richText = true; + + EditorGUIUtility.labelWidth = 40f; + EditorGUIUtility.fieldWidth = 50; + + Rect rect = new Rect(position.x + 60, position.y, position.width, 49); + + // Display non-editable fields + if (GUI.enabled == false) + { + // Sprite Character Index + int spriteCharacterIndex; + int.TryParse(property.displayName.Split(' ')[1], out spriteCharacterIndex); + EditorGUI.LabelField(new Rect(rect.x, rect.y, 75f, 18), new GUIContent("Index: " + spriteCharacterIndex + ""), style); + + EditorGUI.LabelField(new Rect(rect.x + 75f, rect.y, 120f, 18), new GUIContent("Unicode: 0x" + prop_SpriteUnicode.intValue.ToString("X") + ""), style); + EditorGUI.LabelField(new Rect(rect.x + 195f, rect.y, rect.width - 255, 18), new GUIContent("Name: " + prop_SpriteName.stringValue + ""), style); + + EditorGUI.LabelField(new Rect(rect.x, rect.y + 18, 120, 18), new GUIContent("Glyph ID: " + prop_SpriteGlyphIndex.intValue + ""), style); + + // Draw Sprite Glyph (if exists) + DrawSpriteGlyph((uint)prop_SpriteGlyphIndex.intValue, position, property); + + EditorGUI.LabelField(new Rect(rect.x, rect.y + 36, 80, 18), new GUIContent("Scale: " + prop_SpriteScale.floatValue + ""), style); + } + else // Display editable fields + { + // Get a reference to the underlying Sprite Asset + TMP_SpriteAsset spriteAsset = property.serializedObject.targetObject as TMP_SpriteAsset; + + // Sprite Character Index + int spriteCharacterIndex; + int.TryParse(property.displayName.Split(' ')[1], out spriteCharacterIndex); + + EditorGUI.LabelField(new Rect(rect.x, rect.y, 75f, 18), new GUIContent("Index: " + spriteCharacterIndex + ""), style); + + EditorGUIUtility.labelWidth = 55f; + GUI.SetNextControlName("Unicode Input"); + EditorGUI.BeginChangeCheck(); + string unicode = EditorGUI.DelayedTextField(new Rect(rect.x + 75f, rect.y, 120, 18), "Unicode:", prop_SpriteUnicode.intValue.ToString("X")); + + if (GUI.GetNameOfFocusedControl() == "Unicode Input") + { + //Filter out unwanted characters. + char chr = Event.current.character; + if ((chr < '0' || chr > '9') && (chr < 'a' || chr > 'f') && (chr < 'A' || chr > 'F')) + { + Event.current.character = '\0'; + } + } + + if (EditorGUI.EndChangeCheck()) + { + // Update Unicode value + prop_SpriteUnicode.intValue = TMP_TextUtilities.StringHexToInt(unicode); + spriteAsset.m_IsSpriteAssetLookupTablesDirty = true; + } + + EditorGUIUtility.labelWidth = 41f; + EditorGUI.BeginChangeCheck(); + EditorGUI.DelayedTextField(new Rect(rect.x + 195f, rect.y, rect.width - 255, 18), prop_SpriteName, new GUIContent("Name:")); + if (EditorGUI.EndChangeCheck()) + { + spriteAsset.m_IsSpriteAssetLookupTablesDirty = true; + } + + EditorGUIUtility.labelWidth = 59f; + EditorGUI.BeginChangeCheck(); + EditorGUI.DelayedIntField(new Rect(rect.x, rect.y + 18, 100, 18), prop_SpriteGlyphIndex, new GUIContent("Glyph ID:")); + if (EditorGUI.EndChangeCheck()) + { + spriteAsset.m_IsSpriteAssetLookupTablesDirty = true; + } + + // Draw Sprite Glyph (if exists) + DrawSpriteGlyph((uint)prop_SpriteGlyphIndex.intValue, position, property); + + int glyphIndex = prop_SpriteGlyphIndex.intValue; + + // Reset glyph selection if new character has been selected. + if (GUI.enabled && m_GlyphSelectedForEditing != glyphIndex) + m_GlyphSelectedForEditing = -1; + + // Display button to edit the glyph data. + if (GUI.Button(new Rect(rect.x + 120, rect.y + 18, 75, 18), new GUIContent("Edit Glyph"))) + { + if (m_GlyphSelectedForEditing == -1) + m_GlyphSelectedForEditing = glyphIndex; + else + m_GlyphSelectedForEditing = -1; + + // Button clicks should not result in potential change. + GUI.changed = false; + } + + // Show the glyph property drawer if selected + if (glyphIndex == m_GlyphSelectedForEditing && GUI.enabled) + { + if (spriteAsset != null) + { + // Lookup glyph and draw glyph (if available) + int elementIndex = spriteAsset.spriteGlyphTable.FindIndex(item => item.index == glyphIndex); + + if (elementIndex != -1) + { + // Get a reference to the Sprite Glyph Table + SerializedProperty prop_SpriteGlyphTable = property.serializedObject.FindProperty("m_GlyphTable"); + + SerializedProperty prop_SpriteGlyph = prop_SpriteGlyphTable.GetArrayElementAtIndex(elementIndex); + SerializedProperty prop_GlyphMetrics = prop_SpriteGlyph.FindPropertyRelative("m_Metrics"); + SerializedProperty prop_GlyphRect = prop_SpriteGlyph.FindPropertyRelative("m_GlyphRect"); + + Rect newRect = EditorGUILayout.GetControlRect(false, 115); + EditorGUI.DrawRect(new Rect(newRect.x + 62, newRect.y - 20, newRect.width - 62, newRect.height - 5), new Color(0.1f, 0.1f, 0.1f, 0.45f)); + EditorGUI.DrawRect(new Rect(newRect.x + 63, newRect.y - 19, newRect.width - 64, newRect.height - 7), new Color(0.3f, 0.3f, 0.3f, 0.8f)); + + // Display GlyphRect + newRect.x += 65; + newRect.y -= 18; + newRect.width += 5; + EditorGUI.PropertyField(newRect, prop_GlyphRect); + + // Display GlyphMetrics + newRect.y += 45; + EditorGUI.PropertyField(newRect, prop_GlyphMetrics); + + rect.y += 120; + } + } + } + + EditorGUIUtility.labelWidth = 39f; + EditorGUI.PropertyField(new Rect(rect.x, rect.y + 36, 80, 18), prop_SpriteScale, new GUIContent("Scale:")); + } + } + + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return 58; + } + + + void DrawSpriteGlyph(uint glyphIndex, Rect position, SerializedProperty property) + { + if (m_GlyphLookupDictionary == null) + m_GlyphLookupDictionary = TMP_PropertyDrawerUtilities.GetGlyphProxyLookupDictionary(property.serializedObject); + + // Try getting a reference to the glyph for the given glyph index. + if (!m_GlyphLookupDictionary.TryGetValue(glyphIndex, out GlyphProxy glyph)) + return; + + GlyphRect glyphRect = glyph.glyphRect; + + // Get a reference to the sprite texture + Texture tex = property.serializedObject.FindProperty("spriteSheet").objectReferenceValue as Texture; + if (tex == null) + { + Debug.LogWarning("Please assign a valid Sprite Atlas texture to the [" + property.serializedObject.targetObject.name + "] Sprite Asset.", property.serializedObject.targetObject); + return; + } + + Vector2 spriteTexPosition = new Vector2(position.x, position.y); + Vector2 spriteSize = new Vector2(48, 48); + Vector2 alignmentOffset = new Vector2((58 - spriteSize.x) / 2, (58 - spriteSize.y) / 2); + + float x = glyphRect.x; + float y = glyphRect.y; + float spriteWidth = glyphRect.width; + float spriteHeight = glyphRect.height; + + if (spriteWidth >= spriteHeight) + { + spriteSize.y = spriteHeight * spriteSize.x / spriteWidth; + spriteTexPosition.y += (spriteSize.x - spriteSize.y) / 2; + } + else + { + spriteSize.x = spriteWidth * spriteSize.y / spriteHeight; + spriteTexPosition.x += (spriteSize.y - spriteSize.x) / 2; + } + + // Compute the normalized texture coordinates + Rect texCoords = new Rect(x / tex.width, y / tex.height, spriteWidth / tex.width, spriteHeight / tex.height); + GUI.DrawTextureWithTexCoords(new Rect(spriteTexPosition.x + alignmentOffset.x, spriteTexPosition.y + alignmentOffset.y, spriteSize.x, spriteSize.y), tex, texCoords, true); + } + + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_SpriteCharacterPropertyDrawer.cs.meta b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_SpriteCharacterPropertyDrawer.cs.meta new file mode 100644 index 00000000..0733749d --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_SpriteCharacterPropertyDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37cff9f5a86ae494c8cb04423580480d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_SpriteGlyphPropertyDrawer.cs b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_SpriteGlyphPropertyDrawer.cs new file mode 100644 index 00000000..566b93b8 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_SpriteGlyphPropertyDrawer.cs @@ -0,0 +1,88 @@ +using UnityEngine; +using UnityEngine.TextCore; +using UnityEditor; +using System.Collections.Generic; + + +namespace TMPro.EditorUtilities +{ + + [CustomPropertyDrawer(typeof(TMP_SpriteGlyph))] + public class TMP_SpriteGlyphPropertyDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + SerializedProperty prop_GlyphIndex = property.FindPropertyRelative("m_Index"); + SerializedProperty prop_GlyphMetrics = property.FindPropertyRelative("m_Metrics"); + SerializedProperty prop_GlyphRect = property.FindPropertyRelative("m_GlyphRect"); + SerializedProperty prop_Scale = property.FindPropertyRelative("m_Scale"); + SerializedProperty prop_AtlasIndex = property.FindPropertyRelative("m_AtlasIndex"); + + GUIStyle style = new GUIStyle(EditorStyles.label); + style.richText = true; + + Rect rect = new Rect(position.x + 70, position.y, position.width, 49); + + // Draw GlyphRect + EditorGUI.PropertyField(rect, prop_GlyphRect); + + // Draw GlyphMetrics + rect.y += 45; + EditorGUI.PropertyField(rect, prop_GlyphMetrics); + + EditorGUIUtility.labelWidth = 40f; + EditorGUI.PropertyField(new Rect(rect.x, rect.y + 65, 75, 18), prop_Scale, new GUIContent("Scale:")); + + EditorGUIUtility.labelWidth = 74f; + EditorGUI.PropertyField(new Rect(rect.x + 85, rect.y + 65, 95, 18), prop_AtlasIndex, new GUIContent("Atlas Index:")); + + DrawGlyph(position, property); + + int spriteCharacterIndex; + int.TryParse(property.displayName.Split(' ')[1], out spriteCharacterIndex); + + EditorGUI.LabelField(new Rect(position.x, position.y + 5, 64f, 18f), new GUIContent("#" + spriteCharacterIndex), style); + + float labelWidthID = GUI.skin.label.CalcSize(new GUIContent("ID: " + prop_GlyphIndex.intValue)).x; + EditorGUI.LabelField(new Rect(position.x + (64 - labelWidthID) / 2, position.y + 110, 64f, 18f), new GUIContent("ID: " + prop_GlyphIndex.intValue + ""), style); + } + + void DrawGlyph(Rect position, SerializedProperty property) + { + // Get a reference to the sprite texture + Texture tex = property.serializedObject.FindProperty("spriteSheet").objectReferenceValue as Texture; + + // Return if we don't have a texture assigned to the sprite asset. + if (tex == null) + { + Debug.LogWarning("Please assign a valid Sprite Atlas texture to the [" + property.serializedObject.targetObject.name + "] Sprite Asset.", property.serializedObject.targetObject); + return; + } + + Vector2 spriteTexPosition = new Vector2(position.x, position.y); + Vector2 spriteSize = new Vector2(65, 65); + GlyphRect glyphRect = TMP_PropertyDrawerUtilities.GetGlyphRectFromGlyphSerializedProperty(property); + + if (glyphRect.width >= glyphRect.height) + { + spriteSize.y = glyphRect.height * spriteSize.x / glyphRect.width; + spriteTexPosition.y += (spriteSize.x - spriteSize.y) / 2; + } + else + { + spriteSize.x = glyphRect.width * spriteSize.y / glyphRect.height; + spriteTexPosition.x += (spriteSize.y - spriteSize.x) / 2; + } + + // Compute the normalized texture coordinates + Rect texCoords = new Rect((float)glyphRect.x / tex.width, (float)glyphRect.y / tex.height, (float)glyphRect.width / tex.width, (float)glyphRect.height / tex.height); + GUI.DrawTextureWithTexCoords(new Rect(spriteTexPosition.x + 5, spriteTexPosition.y + 32f, spriteSize.x, spriteSize.y), tex, texCoords, true); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return 130f; + } + + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_SpriteGlyphPropertyDrawer.cs.meta b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_SpriteGlyphPropertyDrawer.cs.meta new file mode 100644 index 00000000..04145626 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_SpriteGlyphPropertyDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 056819c66570ca54cadb72330a354050 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_TextAlignmentDrawer.cs b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_TextAlignmentDrawer.cs new file mode 100644 index 00000000..1361de73 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_TextAlignmentDrawer.cs @@ -0,0 +1,273 @@ +using UnityEngine; +using UnityEditor; + +namespace TMPro.EditorUtilities +{ + + [CustomPropertyDrawer(typeof(TextAlignmentOptions))] + public class TMP_TextAlignmentDrawer : PropertyDrawer + { + const int k_AlignmentButtonWidth = 24; + const int k_AlignmentButtonHeight = 20; + const int k_WideViewWidth = 504; + const int k_ControlsSpacing = 6; + const int k_GroupWidth = k_AlignmentButtonWidth * 6; + static readonly int k_TextAlignmentHash = "DoTextAligmentControl".GetHashCode(); + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return EditorGUIUtility.currentViewWidth > k_WideViewWidth ? k_AlignmentButtonHeight : k_AlignmentButtonHeight * 2 + 3; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + var id = GUIUtility.GetControlID(k_TextAlignmentHash, FocusType.Keyboard, position); + + EditorGUI.BeginProperty(position, label, property); + { + var controlArea = EditorGUI.PrefixLabel(position, id, label); + + var horizontalAligment = new Rect(controlArea.x, controlArea.y, k_GroupWidth, k_AlignmentButtonHeight); + var verticalAligment = new Rect(!(EditorGUIUtility.currentViewWidth > k_WideViewWidth) ? controlArea.x : horizontalAligment.xMax + k_ControlsSpacing, !(EditorGUIUtility.currentViewWidth > k_WideViewWidth) ? controlArea.y + k_AlignmentButtonHeight + 3 : controlArea.y, k_GroupWidth, k_AlignmentButtonHeight); + + EditorGUI.BeginChangeCheck(); + + var selectedHorizontal = DoHorizontalAligmentControl(horizontalAligment, property); + var selectedVertical = DoVerticalAligmentControl(verticalAligment, property); + + if (EditorGUI.EndChangeCheck()) + { + var value = (0x1 << selectedHorizontal) | (0x100 << selectedVertical); + property.intValue = value; + } + } + EditorGUI.EndProperty(); + } + + static int DoHorizontalAligmentControl(Rect position, SerializedProperty alignment) + { + var selected = TMP_EditorUtility.GetHorizontalAlignmentGridValue(alignment.intValue); + + var values = new bool[6]; + + values[selected] = true; + + if (alignment.hasMultipleDifferentValues) + { + foreach (var obj in alignment.serializedObject.targetObjects) + { + var text = obj as TMP_Text; + if (text != null) + { + values[TMP_EditorUtility.GetHorizontalAlignmentGridValue((int)text.alignment)] = true; + } + } + } + + position.width = k_AlignmentButtonWidth; + + for (var i = 0; i < values.Length; i++) + { + var oldValue = values[i]; + var newValue = TMP_EditorUtility.EditorToggle(position, oldValue, TMP_UIStyleManager.alignContentA[i], i == 0 ? TMP_UIStyleManager.alignmentButtonLeft : (i == 5 ? TMP_UIStyleManager.alignmentButtonRight : TMP_UIStyleManager.alignmentButtonMid)); + if (newValue != oldValue) + { + selected = i; + } + position.x += position.width; + } + + return selected; + } + + static int DoVerticalAligmentControl(Rect position, SerializedProperty alignment) + { + var selected = TMP_EditorUtility.GetVerticalAlignmentGridValue(alignment.intValue); + + var values = new bool[6]; + + values[selected] = true; + + if (alignment.hasMultipleDifferentValues) + { + foreach (var obj in alignment.serializedObject.targetObjects) + { + var text = obj as TMP_Text; + if (text != null) + { + values[TMP_EditorUtility.GetVerticalAlignmentGridValue((int)text.alignment)] = true; + } + } + } + + position.width = k_AlignmentButtonWidth; + + for (var i = 0; i < values.Length; i++) + { + var oldValue = values[i]; + var newValue = TMP_EditorUtility.EditorToggle(position, oldValue, TMP_UIStyleManager.alignContentB[i], i == 0 ? TMP_UIStyleManager.alignmentButtonLeft : (i == 5 ? TMP_UIStyleManager.alignmentButtonRight : TMP_UIStyleManager.alignmentButtonMid)); + if (newValue != oldValue) + { + selected = i; + } + position.x += position.width; + } + + return selected; + } + } + + [CustomPropertyDrawer(typeof(HorizontalAlignmentOptions))] + public class TMP_HorizontalAlignmentDrawer : PropertyDrawer + { + const int k_AlignmentButtonWidth = 24; + const int k_AlignmentButtonHeight = 20; + const int k_WideViewWidth = 504; + const int k_ControlsSpacing = 6; + const int k_GroupWidth = k_AlignmentButtonWidth * 6; + static readonly int k_TextAlignmentHash = "DoTextAligmentControl".GetHashCode(); + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return EditorGUIUtility.currentViewWidth > k_WideViewWidth ? k_AlignmentButtonHeight : k_AlignmentButtonHeight * 2 + 3; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + var id = GUIUtility.GetControlID(k_TextAlignmentHash, FocusType.Keyboard, position); + + EditorGUI.BeginProperty(position, label, property); + { + var controlArea = EditorGUI.PrefixLabel(position, id, label); + + var horizontalAligment = new Rect(controlArea.x, controlArea.y, k_GroupWidth, k_AlignmentButtonHeight); + //var verticalAligment = new Rect(!(EditorGUIUtility.currentViewWidth > k_WideViewWidth) ? controlArea.x : horizontalAligment.xMax + k_ControlsSpacing, !(EditorGUIUtility.currentViewWidth > k_WideViewWidth) ? controlArea.y + k_AlignmentButtonHeight + 3 : controlArea.y, k_GroupWidth, k_AlignmentButtonHeight); + + EditorGUI.BeginChangeCheck(); + + var selectedHorizontal = DoHorizontalAligmentControl(horizontalAligment, property); + + if (EditorGUI.EndChangeCheck()) + { + var value = 0x1 << selectedHorizontal; + property.intValue = value; + } + } + EditorGUI.EndProperty(); + } + + static int DoHorizontalAligmentControl(Rect position, SerializedProperty alignment) + { + var selected = TMP_EditorUtility.GetHorizontalAlignmentGridValue(alignment.intValue); + + var values = new bool[6]; + + values[selected] = true; + + if (alignment.hasMultipleDifferentValues) + { + foreach (var obj in alignment.serializedObject.targetObjects) + { + var text = obj as TMP_Text; + if (text != null) + { + values[TMP_EditorUtility.GetHorizontalAlignmentGridValue((int)text.horizontalAlignment)] = true; + } + } + } + + position.width = k_AlignmentButtonWidth; + + for (var i = 0; i < values.Length; i++) + { + var oldValue = values[i]; + var newValue = TMP_EditorUtility.EditorToggle(position, oldValue, TMP_UIStyleManager.alignContentA[i], i == 0 ? TMP_UIStyleManager.alignmentButtonLeft : (i == 5 ? TMP_UIStyleManager.alignmentButtonRight : TMP_UIStyleManager.alignmentButtonMid)); + if (newValue != oldValue) + { + selected = i; + } + position.x += position.width; + } + + return selected; + } + } + + + [CustomPropertyDrawer(typeof(VerticalAlignmentOptions))] + public class TMP_VerticalAlignmentDrawer : PropertyDrawer + { + const int k_AlignmentButtonWidth = 24; + const int k_AlignmentButtonHeight = 20; + const int k_WideViewWidth = 504; + const int k_ControlsSpacing = 6; + const int k_GroupWidth = k_AlignmentButtonWidth * 6; + static readonly int k_TextAlignmentHash = "DoTextAligmentControl".GetHashCode(); + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return EditorGUIUtility.currentViewWidth > k_WideViewWidth ? k_AlignmentButtonHeight : k_AlignmentButtonHeight * 2 + 3; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + var id = GUIUtility.GetControlID(k_TextAlignmentHash, FocusType.Keyboard, position); + + EditorGUI.BeginProperty(position, label, property); + { + var controlArea = EditorGUI.PrefixLabel(position, id, label); + + var horizontalAligment = new Rect(controlArea.x, controlArea.y, k_GroupWidth, k_AlignmentButtonHeight); + var verticalAligment = new Rect(!(EditorGUIUtility.currentViewWidth > k_WideViewWidth) ? controlArea.x : horizontalAligment.xMax + k_ControlsSpacing, !(EditorGUIUtility.currentViewWidth > k_WideViewWidth) ? controlArea.y + k_AlignmentButtonHeight + 3 : controlArea.y, k_GroupWidth, k_AlignmentButtonHeight); + + EditorGUI.BeginChangeCheck(); + + //var selectedHorizontal = DoHorizontalAligmentControl(horizontalAligment, property); + var selectedVertical = DoVerticalAligmentControl(verticalAligment, property); + + if (EditorGUI.EndChangeCheck()) + { + var value = 0x100 << selectedVertical; + property.intValue = value; + } + } + EditorGUI.EndProperty(); + } + + static int DoVerticalAligmentControl(Rect position, SerializedProperty alignment) + { + var selected = TMP_EditorUtility.GetVerticalAlignmentGridValue(alignment.intValue); + + var values = new bool[6]; + + values[selected] = true; + + if (alignment.hasMultipleDifferentValues) + { + foreach (var obj in alignment.serializedObject.targetObjects) + { + var text = obj as TMP_Text; + if (text != null) + { + values[TMP_EditorUtility.GetVerticalAlignmentGridValue((int)text.verticalAlignment)] = true; + } + } + } + + position.width = k_AlignmentButtonWidth; + + for (var i = 0; i < values.Length; i++) + { + var oldValue = values[i]; + var newValue = TMP_EditorUtility.EditorToggle(position, oldValue, TMP_UIStyleManager.alignContentB[i], i == 0 ? TMP_UIStyleManager.alignmentButtonLeft : (i == 5 ? TMP_UIStyleManager.alignmentButtonRight : TMP_UIStyleManager.alignmentButtonMid)); + if (newValue != oldValue) + { + selected = i; + } + position.x += position.width; + } + + return selected; + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_TextAlignmentDrawer.cs.meta b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_TextAlignmentDrawer.cs.meta new file mode 100644 index 00000000..a68a2739 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/PropertyDrawers/TMP_TextAlignmentDrawer.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: c55a64c7570474f47a94abe39ebfef04 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_BaseEditorPanel.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_BaseEditorPanel.cs new file mode 100644 index 00000000..5881c773 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_BaseEditorPanel.cs @@ -0,0 +1,1472 @@ +using UnityEngine; +using UnityEditor; +using System.Collections.Generic; +using System.Linq; +using UnityEngine.TextCore.LowLevel; + + +namespace TMPro.EditorUtilities +{ + public abstract class TMP_BaseEditorPanel : Editor + { + //Labels and Tooltips + static readonly GUIContent k_RtlToggleLabel = new GUIContent("Enable RTL Editor", "Reverses text direction and allows right to left editing."); + //static readonly GUIContent k_MainSettingsLabel = new GUIContent("Main Settings"); + static readonly GUIContent k_FontAssetLabel = new GUIContent("Font Asset", "The Font Asset containing the glyphs that can be rendered for this text."); + static readonly GUIContent k_MaterialPresetLabel = new GUIContent("Material Preset", "The material used for rendering. Only materials created from the Font Asset can be used."); + static readonly GUIContent k_StyleLabel = new GUIContent("Text Style", "The style from a style sheet to be applied to the text."); + static readonly GUIContent k_AutoSizeLabel = new GUIContent("Auto Size", "Auto sizes the text to fit the available space."); + static readonly GUIContent k_FontSizeLabel = new GUIContent("Font Size", "The size the text will be rendered at in points."); + static readonly GUIContent k_AutoSizeOptionsLabel = new GUIContent("Auto Size Options"); + static readonly GUIContent k_MinLabel = new GUIContent("Min", "The minimum font size."); + static readonly GUIContent k_MaxLabel = new GUIContent("Max", "The maximum font size."); + static readonly GUIContent k_WdLabel = new GUIContent("WD%", "Compresses character width up to this value before reducing font size."); + static readonly GUIContent k_LineLabel = new GUIContent("Line", "Negative value only. Compresses line height down to this value before reducing font size."); + static readonly GUIContent k_FontStyleLabel = new GUIContent("Font Style", "Styles to apply to the text such as Bold or Italic."); + + static readonly GUIContent k_BoldLabel = new GUIContent("B", "Bold"); + static readonly GUIContent k_ItalicLabel = new GUIContent("I", "Italic"); + static readonly GUIContent k_UnderlineLabel = new GUIContent("U", "Underline"); + static readonly GUIContent k_StrikethroughLabel = new GUIContent("S", "Strikethrough"); + static readonly GUIContent k_LowercaseLabel = new GUIContent("ab", "Lowercase"); + static readonly GUIContent k_UppercaseLabel = new GUIContent("AB", "Uppercase"); + static readonly GUIContent k_SmallcapsLabel = new GUIContent("SC", "Smallcaps"); + + static readonly GUIContent k_ColorModeLabel = new GUIContent("Color Mode", "The type of gradient to use."); + static readonly GUIContent k_BaseColorLabel = new GUIContent("Vertex Color", "The base color of the text vertices."); + static readonly GUIContent k_ColorPresetLabel = new GUIContent("Color Preset", "A Color Preset which override the local color settings."); + static readonly GUIContent k_ColorGradientLabel = new GUIContent("Color Gradient", "The gradient color applied over the Vertex Color. Can be locally set or driven by a Gradient Asset."); + static readonly GUIContent k_CorenerColorsLabel = new GUIContent("Colors", "The color composition of the gradient."); + static readonly GUIContent k_OverrideTagsLabel = new GUIContent("Override Tags", "Whether the color settings override the tag."); + + static readonly GUIContent k_SpacingOptionsLabel = new GUIContent("Spacing Options (em)", "Spacing adjustments between different elements of the text. Values are in font units where a value of 1 equals 1/100em."); + static readonly GUIContent k_CharacterSpacingLabel = new GUIContent("Character"); + static readonly GUIContent k_WordSpacingLabel = new GUIContent("Word"); + static readonly GUIContent k_LineSpacingLabel = new GUIContent("Line"); + static readonly GUIContent k_ParagraphSpacingLabel = new GUIContent("Paragraph"); + + static readonly GUIContent k_AlignmentLabel = new GUIContent("Alignment", "Horizontal and vertical alignment of the text within its container."); + static readonly GUIContent k_WrapMixLabel = new GUIContent("Wrap Mix (W <-> C)", "How much to favor words versus characters when distributing the text."); + + static readonly GUIContent k_WrappingLabel = new GUIContent("Wrapping", "Wraps text to the next line when reaching the edge of the container."); + static readonly GUIContent[] k_WrappingOptions = { new GUIContent("Disabled"), new GUIContent("Enabled") }; + static readonly GUIContent k_OverflowLabel = new GUIContent("Overflow", "How to display text which goes past the edge of the container."); + + static readonly GUIContent k_MarginsLabel = new GUIContent("Margins", "The space between the text and the edge of its container."); + static readonly GUIContent k_GeometrySortingLabel = new GUIContent("Geometry Sorting", "The order in which text geometry is sorted. Used to adjust the way overlapping characters are displayed."); + static readonly GUIContent k_IsTextObjectScaleStatic = new GUIContent("Is Scale Static", "Controls whether a text object will be excluded from the InteralUpdate callback to handle scale changes of the text object or its parent(s)."); + static readonly GUIContent k_RichTextLabel = new GUIContent("Rich Text", "Enables the use of rich text tags such as and ."); + static readonly GUIContent k_EscapeCharactersLabel = new GUIContent("Parse Escape Characters", "Whether to display strings such as \"\\n\" as is or replace them by the character they represent."); + static readonly GUIContent k_VisibleDescenderLabel = new GUIContent("Visible Descender", "Compute descender values from visible characters only. Used to adjust layout behavior when hiding and revealing characters dynamically."); + static readonly GUIContent k_EmojiFallbackSupportLabel = new GUIContent("Emoji Fallback Support", "When text contains Emojis, try using and displaying those from the potential Text Assets assigned in the TMP Settings Emoji Fallback Text Assets."); + static readonly GUIContent k_SpriteAssetLabel = new GUIContent("Sprite Asset", "The Sprite Asset used when NOT specifically referencing one using ."); + static readonly GUIContent k_StyleSheetAssetLabel = new GUIContent("Style Sheet Asset", "The Style Sheet Asset used by this text object."); + + static readonly GUIContent k_HorizontalMappingLabel = new GUIContent("Horizontal Mapping", "Horizontal UV mapping when using a shader with a texture face option."); + static readonly GUIContent k_VerticalMappingLabel = new GUIContent("Vertical Mapping", "Vertical UV mapping when using a shader with a texture face option."); + static readonly GUIContent k_LineOffsetLabel = new GUIContent("Line Offset", "Adds an horizontal offset to each successive line. Used for slanted texturing."); + + static readonly GUIContent k_FontFeaturesLabel = new GUIContent("Font Features", "Font features available for the primary font asset assigned to the text component."); + static readonly GUIContent k_PaddingLabel = new GUIContent("Extra Padding", "Adds some padding between the characters and the edge of the text mesh. Can reduce graphical errors when displaying small text."); + + static readonly GUIContent k_LeftLabel = new GUIContent("Left"); + static readonly GUIContent k_TopLabel = new GUIContent("Top"); + static readonly GUIContent k_RightLabel = new GUIContent("Right"); + static readonly GUIContent k_BottomLabel = new GUIContent("Bottom"); + + protected static readonly GUIContent k_ExtraSettingsLabel = new GUIContent("Extra Settings"); + protected static string[] k_UiStateLabel = new string[] { "(Click to collapse) ", "(Click to expand) " }; + + static Dictionary k_AvailableStyles = new Dictionary(); + protected Dictionary m_TextStyleIndexLookup = new Dictionary(); + + protected struct Foldout + { + // Track Inspector foldout panel states, globally. + public static bool extraSettings = false; + public static bool materialInspector = true; + } + + protected static int s_EventId; + + public int selAlignGridA; + public int selAlignGridB; + + protected SerializedProperty m_TextProp; + + protected SerializedProperty m_IsRightToLeftProp; + protected string m_RtlText; + + protected SerializedProperty m_FontAssetProp; + + protected SerializedProperty m_FontSharedMaterialProp; + protected Material[] m_MaterialPresets; + protected GUIContent[] m_MaterialPresetNames; + protected Dictionary m_MaterialPresetIndexLookup = new Dictionary(); + protected int m_MaterialPresetSelectionIndex; + protected bool m_IsPresetListDirty; + + protected List m_Styles = new List(); + protected GUIContent[] m_StyleNames; + protected int m_StyleSelectionIndex; + + protected SerializedProperty m_FontStyleProp; + + protected SerializedProperty m_FontColorProp; + protected SerializedProperty m_EnableVertexGradientProp; + protected SerializedProperty m_FontColorGradientProp; + protected SerializedProperty m_FontColorGradientPresetProp; + protected SerializedProperty m_OverrideHtmlColorProp; + + protected SerializedProperty m_FontSizeProp; + protected SerializedProperty m_FontSizeBaseProp; + + protected SerializedProperty m_AutoSizingProp; + protected SerializedProperty m_FontSizeMinProp; + protected SerializedProperty m_FontSizeMaxProp; + + protected SerializedProperty m_LineSpacingMaxProp; + protected SerializedProperty m_CharWidthMaxAdjProp; + + protected SerializedProperty m_CharacterSpacingProp; + protected SerializedProperty m_WordSpacingProp; + protected SerializedProperty m_LineSpacingProp; + protected SerializedProperty m_ParagraphSpacingProp; + + protected SerializedProperty m_TextAlignmentProp; + + protected SerializedProperty m_HorizontalAlignmentProp; + protected SerializedProperty m_VerticalAlignmentProp; + + protected SerializedProperty m_HorizontalMappingProp; + protected SerializedProperty m_VerticalMappingProp; + protected SerializedProperty m_UvLineOffsetProp; + + protected SerializedProperty m_TextWrappingModeProp; + protected SerializedProperty m_WordWrappingRatiosProp; + protected SerializedProperty m_TextOverflowModeProp; + protected SerializedProperty m_PageToDisplayProp; + protected SerializedProperty m_LinkedTextComponentProp; + protected SerializedProperty m_ParentLinkedTextComponentProp; + + protected SerializedProperty m_FontFeaturesActiveProp; + + protected SerializedProperty m_IsRichTextProp; + + protected SerializedProperty m_HasFontAssetChangedProp; + + protected SerializedProperty m_EnableExtraPaddingProp; + protected SerializedProperty m_CheckPaddingRequiredProp; + protected SerializedProperty m_EnableEscapeCharacterParsingProp; + protected SerializedProperty m_UseMaxVisibleDescenderProp; + protected SerializedProperty m_GeometrySortingOrderProp; + protected SerializedProperty m_IsTextObjectScaleStaticProp; + + protected SerializedProperty m_EmojiFallbackSupportProp; + + protected SerializedProperty m_SpriteAssetProp; + + protected SerializedProperty m_StyleSheetAssetProp; + protected SerializedProperty m_TextStyleHashCodeProp; + + protected SerializedProperty m_MarginProp; + + protected SerializedProperty m_ColorModeProp; + + protected bool m_HavePropertiesChanged; + + protected TMP_Text m_TextComponent; + protected TMP_Text m_PreviousLinkedTextComponent; + protected RectTransform m_RectTransform; + + protected Material m_TargetMaterial; + + protected Vector3[] m_RectCorners = new Vector3[4]; + protected Vector3[] m_HandlePoints = new Vector3[4]; + + private static readonly string[] k_FontFeatures = new string[] { "kern", "liga", "mark", "mkmk" }; + + protected virtual void OnEnable() + { + m_TextProp = serializedObject.FindProperty("m_text"); + m_IsRightToLeftProp = serializedObject.FindProperty("m_isRightToLeft"); + m_FontAssetProp = serializedObject.FindProperty("m_fontAsset"); + m_FontSharedMaterialProp = serializedObject.FindProperty("m_sharedMaterial"); + + m_FontStyleProp = serializedObject.FindProperty("m_fontStyle"); + + m_FontSizeProp = serializedObject.FindProperty("m_fontSize"); + m_FontSizeBaseProp = serializedObject.FindProperty("m_fontSizeBase"); + + m_AutoSizingProp = serializedObject.FindProperty("m_enableAutoSizing"); + m_FontSizeMinProp = serializedObject.FindProperty("m_fontSizeMin"); + m_FontSizeMaxProp = serializedObject.FindProperty("m_fontSizeMax"); + + m_LineSpacingMaxProp = serializedObject.FindProperty("m_lineSpacingMax"); + m_CharWidthMaxAdjProp = serializedObject.FindProperty("m_charWidthMaxAdj"); + + // Colors & Gradient + m_FontColorProp = serializedObject.FindProperty("m_fontColor"); + m_EnableVertexGradientProp = serializedObject.FindProperty("m_enableVertexGradient"); + m_FontColorGradientProp = serializedObject.FindProperty("m_fontColorGradient"); + m_FontColorGradientPresetProp = serializedObject.FindProperty("m_fontColorGradientPreset"); + m_OverrideHtmlColorProp = serializedObject.FindProperty("m_overrideHtmlColors"); + + m_CharacterSpacingProp = serializedObject.FindProperty("m_characterSpacing"); + m_WordSpacingProp = serializedObject.FindProperty("m_wordSpacing"); + m_LineSpacingProp = serializedObject.FindProperty("m_lineSpacing"); + m_ParagraphSpacingProp = serializedObject.FindProperty("m_paragraphSpacing"); + + m_TextAlignmentProp = serializedObject.FindProperty("m_textAlignment"); + m_HorizontalAlignmentProp = serializedObject.FindProperty("m_HorizontalAlignment"); + m_VerticalAlignmentProp = serializedObject.FindProperty("m_VerticalAlignment"); + + m_HorizontalMappingProp = serializedObject.FindProperty("m_horizontalMapping"); + m_VerticalMappingProp = serializedObject.FindProperty("m_verticalMapping"); + m_UvLineOffsetProp = serializedObject.FindProperty("m_uvLineOffset"); + + m_TextWrappingModeProp = serializedObject.FindProperty("m_TextWrappingMode"); + m_WordWrappingRatiosProp = serializedObject.FindProperty("m_wordWrappingRatios"); + m_TextOverflowModeProp = serializedObject.FindProperty("m_overflowMode"); + m_PageToDisplayProp = serializedObject.FindProperty("m_pageToDisplay"); + m_LinkedTextComponentProp = serializedObject.FindProperty("m_linkedTextComponent"); + m_ParentLinkedTextComponentProp = serializedObject.FindProperty("parentLinkedComponent"); + + m_FontFeaturesActiveProp = serializedObject.FindProperty("m_ActiveFontFeatures"); + + m_EnableExtraPaddingProp = serializedObject.FindProperty("m_enableExtraPadding"); + m_IsRichTextProp = serializedObject.FindProperty("m_isRichText"); + m_CheckPaddingRequiredProp = serializedObject.FindProperty("checkPaddingRequired"); + m_EnableEscapeCharacterParsingProp = serializedObject.FindProperty("m_parseCtrlCharacters"); + m_UseMaxVisibleDescenderProp = serializedObject.FindProperty("m_useMaxVisibleDescender"); + + m_GeometrySortingOrderProp = serializedObject.FindProperty("m_geometrySortingOrder"); + m_IsTextObjectScaleStaticProp = serializedObject.FindProperty("m_IsTextObjectScaleStatic"); + + m_EmojiFallbackSupportProp = serializedObject.FindProperty("m_EmojiFallbackSupport"); + + m_SpriteAssetProp = serializedObject.FindProperty("m_spriteAsset"); + + m_StyleSheetAssetProp = serializedObject.FindProperty("m_StyleSheet"); + m_TextStyleHashCodeProp = serializedObject.FindProperty("m_TextStyleHashCode"); + + m_MarginProp = serializedObject.FindProperty("m_margin"); + + m_HasFontAssetChangedProp = serializedObject.FindProperty("m_hasFontAssetChanged"); + + m_ColorModeProp = serializedObject.FindProperty("m_colorMode"); + + m_TextComponent = (TMP_Text)target; + m_RectTransform = m_TextComponent.rectTransform; + + // Restore Previous Linked Text Component + m_PreviousLinkedTextComponent = m_TextComponent.linkedTextComponent; + + // Create new Material Editor if one does not exists + m_TargetMaterial = m_TextComponent.fontSharedMaterial; + + // Set material inspector visibility + if (m_TargetMaterial != null) + UnityEditorInternal.InternalEditorUtility.SetIsInspectorExpanded(m_TargetMaterial, Foldout.materialInspector); + + // Find all Material Presets matching the current Font Asset Material + m_MaterialPresetNames = GetMaterialPresets(); + + // Get Styles from Style Sheet + if (TMP_Settings.instance != null) + m_StyleNames = GetStyleNames(); + + // Get list of font features for the primary font asset assigned to the text component + // FontEngine.LoadFontFace(m_TextComponent.font.SourceFont_EditorRef); + // OTL_Table gposTable = UnityEngine.TextCore.LowLevel.FontEngine.GetOpenTypeLayoutTable(OTL_TableType.GPOS); + // OTL_Table gsubTable = UnityEngine.TextCore.LowLevel.FontEngine.GetOpenTypeLayoutTable(OTL_TableType.GSUB); + // + // HashSet fontFeatures = new HashSet(); + // + // foreach (OTL_Feature feature in gposTable.features) + // { + // fontFeatures.Add(feature.tag); + // } + // + // foreach (OTL_Feature feature in gsubTable.features) + // { + // fontFeatures.Add(feature.tag); + // } + // + // m_FontFeatures = fontFeatures.OrderBy(item => item).ToArray(); + + // Register to receive events when style sheets are modified. + TMPro_EventManager.TEXT_STYLE_PROPERTY_EVENT.Add(ON_TEXT_STYLE_CHANGED); + + // Initialize the Event Listener for Undo Events. + Undo.undoRedoPerformed += OnUndoRedo; + } + + protected virtual void OnDisable() + { + // Set material inspector visibility + if (m_TargetMaterial != null) + Foldout.materialInspector = UnityEditorInternal.InternalEditorUtility.GetIsInspectorExpanded(m_TargetMaterial); + + if (Undo.undoRedoPerformed != null) + Undo.undoRedoPerformed -= OnUndoRedo; + + // Unregister from style sheet related events. + TMPro_EventManager.TEXT_STYLE_PROPERTY_EVENT.Remove(ON_TEXT_STYLE_CHANGED); + } + + // Event received when Text Styles are changed. + void ON_TEXT_STYLE_CHANGED(bool isChanged) + { + m_StyleNames = GetStyleNames(); + } + + public override void OnInspectorGUI() + { + // Make sure Multi selection only includes TMP Text objects. + if (IsMixSelectionTypes()) return; + + serializedObject.Update(); + + DrawTextInput(); + + DrawMainSettings(); + + DrawExtraSettings(); + + EditorGUILayout.Space(); + + if (serializedObject.ApplyModifiedProperties() || m_HavePropertiesChanged) + { + m_TextComponent.havePropertiesChanged = true; + m_HavePropertiesChanged = false; + } + } + + public void OnSceneGUI() + { + if (IsMixSelectionTypes()) return; + + // Margin Frame & Handles + m_RectTransform.GetWorldCorners(m_RectCorners); + Vector4 marginOffset = m_TextComponent.margin; + Vector3 lossyScale = m_RectTransform.lossyScale; + + m_HandlePoints[0] = m_RectCorners[0] + m_RectTransform.TransformDirection(new Vector3(marginOffset.x * lossyScale.x, marginOffset.w * lossyScale.y, 0)); + m_HandlePoints[1] = m_RectCorners[1] + m_RectTransform.TransformDirection(new Vector3(marginOffset.x * lossyScale.x, -marginOffset.y * lossyScale.y, 0)); + m_HandlePoints[2] = m_RectCorners[2] + m_RectTransform.TransformDirection(new Vector3(-marginOffset.z * lossyScale.x, -marginOffset.y * lossyScale.y, 0)); + m_HandlePoints[3] = m_RectCorners[3] + m_RectTransform.TransformDirection(new Vector3(-marginOffset.z * lossyScale.x, marginOffset.w * lossyScale.y, 0)); + + Handles.DrawSolidRectangleWithOutline(m_HandlePoints, new Color32(255, 255, 255, 0), new Color32(255, 255, 0, 255)); + + Matrix4x4 matrix = m_RectTransform.worldToLocalMatrix; + + // Draw & process FreeMoveHandles + + // LEFT HANDLE + Vector3 oldLeft = (m_HandlePoints[0] + m_HandlePoints[1]) * 0.5f; + #if UNITY_2022_1_OR_NEWER + Vector3 newLeft = Handles.FreeMoveHandle(oldLeft, HandleUtility.GetHandleSize(m_RectTransform.position) * 0.05f, Vector3.zero, Handles.DotHandleCap); + #else + Vector3 newLeft = Handles.FreeMoveHandle(oldLeft, Quaternion.identity, HandleUtility.GetHandleSize(m_RectTransform.position) * 0.05f, Vector3.zero, Handles.DotHandleCap); + #endif + bool hasChanged = false; + if (oldLeft != newLeft) + { + oldLeft = matrix.MultiplyPoint(oldLeft); + newLeft = matrix.MultiplyPoint(newLeft); + + float delta = (oldLeft.x - newLeft.x) * lossyScale.x; + marginOffset.x += -delta / lossyScale.x; + //Debug.Log("Left Margin H0:" + handlePoints[0] + " H1:" + handlePoints[1]); + hasChanged = true; + } + + // TOP HANDLE + Vector3 oldTop = (m_HandlePoints[1] + m_HandlePoints[2]) * 0.5f; + #if UNITY_2022_1_OR_NEWER + Vector3 newTop = Handles.FreeMoveHandle(oldTop, HandleUtility.GetHandleSize(m_RectTransform.position) * 0.05f, Vector3.zero, Handles.DotHandleCap); + #else + Vector3 newTop = Handles.FreeMoveHandle(oldTop, Quaternion.identity, HandleUtility.GetHandleSize(m_RectTransform.position) * 0.05f, Vector3.zero, Handles.DotHandleCap); + #endif + if (oldTop != newTop) + { + oldTop = matrix.MultiplyPoint(oldTop); + newTop = matrix.MultiplyPoint(newTop); + + float delta = (oldTop.y - newTop.y) * lossyScale.y; + marginOffset.y += delta / lossyScale.y; + //Debug.Log("Top Margin H1:" + handlePoints[1] + " H2:" + handlePoints[2]); + hasChanged = true; + } + + // RIGHT HANDLE + Vector3 oldRight = (m_HandlePoints[2] + m_HandlePoints[3]) * 0.5f; + #if UNITY_2022_1_OR_NEWER + Vector3 newRight = Handles.FreeMoveHandle(oldRight, HandleUtility.GetHandleSize(m_RectTransform.position) * 0.05f, Vector3.zero, Handles.DotHandleCap); + #else + Vector3 newRight = Handles.FreeMoveHandle(oldRight, Quaternion.identity, HandleUtility.GetHandleSize(m_RectTransform.position) * 0.05f, Vector3.zero, Handles.DotHandleCap); + #endif + if (oldRight != newRight) + { + oldRight = matrix.MultiplyPoint(oldRight); + newRight = matrix.MultiplyPoint(newRight); + + float delta = (oldRight.x - newRight.x) * lossyScale.x; + marginOffset.z += delta / lossyScale.x; + hasChanged = true; + //Debug.Log("Right Margin H2:" + handlePoints[2] + " H3:" + handlePoints[3]); + } + + // BOTTOM HANDLE + Vector3 oldBottom = (m_HandlePoints[3] + m_HandlePoints[0]) * 0.5f; + #if UNITY_2022_1_OR_NEWER + Vector3 newBottom = Handles.FreeMoveHandle(oldBottom, HandleUtility.GetHandleSize(m_RectTransform.position) * 0.05f, Vector3.zero, Handles.DotHandleCap); + #else + Vector3 newBottom = Handles.FreeMoveHandle(oldBottom, Quaternion.identity, HandleUtility.GetHandleSize(m_RectTransform.position) * 0.05f, Vector3.zero, Handles.DotHandleCap); + #endif + if (oldBottom != newBottom) + { + oldBottom = matrix.MultiplyPoint(oldBottom); + newBottom = matrix.MultiplyPoint(newBottom); + + float delta = (oldBottom.y - newBottom.y) * lossyScale.y; + marginOffset.w += -delta / lossyScale.y; + hasChanged = true; + //Debug.Log("Bottom Margin H0:" + handlePoints[0] + " H3:" + handlePoints[3]); + } + + if (hasChanged) + { + Undo.RecordObjects(new Object[] {m_RectTransform, m_TextComponent }, "Margin Changes"); + m_TextComponent.margin = marginOffset; + EditorUtility.SetDirty(target); + } + } + + protected void DrawTextInput() + { + EditorGUILayout.Space(); + + Rect rect = EditorGUILayout.GetControlRect(false, 22); + GUI.Label(rect, new GUIContent("Text Input"), TMP_UIStyleManager.sectionHeader); + + EditorGUI.indentLevel = 0; + + // If the text component is linked, disable the text input box. + if (m_ParentLinkedTextComponentProp.objectReferenceValue != null) + { + EditorGUILayout.HelpBox("The Text Input Box is disabled due to this text component being linked to another.", MessageType.Info); + } + else + { + // Display RTL Toggle + float labelWidth = EditorGUIUtility.labelWidth; + EditorGUIUtility.labelWidth = 110f; + + m_IsRightToLeftProp.boolValue = EditorGUI.Toggle(new Rect(rect.width - 120, rect.y + 3, 130, 20), k_RtlToggleLabel, m_IsRightToLeftProp.boolValue); + + EditorGUIUtility.labelWidth = labelWidth; + + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_TextProp, GUIContent.none); + + // Need to also compare string content due to issue related to scroll bar drag handle + if (EditorGUI.EndChangeCheck() && m_TextProp.stringValue != m_TextComponent.text) + { + m_TextComponent.m_inputSource = TMP_Text.TextInputSources.TextInputBox; + m_HavePropertiesChanged = true; + } + + if (m_IsRightToLeftProp.boolValue) + { + // Copy source text to RTL string + m_RtlText = string.Empty; + string sourceText = m_TextProp.stringValue; + + // Reverse Text displayed in Text Input Box + for (int i = 0; i < sourceText.Length; i++) + m_RtlText += sourceText[sourceText.Length - i - 1]; + + GUILayout.Label("RTL Text Input"); + + EditorGUI.BeginChangeCheck(); + m_RtlText = EditorGUILayout.TextArea(m_RtlText, TMP_UIStyleManager.wrappingTextArea, GUILayout.Height(EditorGUI.GetPropertyHeight(m_TextProp) - EditorGUIUtility.singleLineHeight), GUILayout.ExpandWidth(true)); + + if (EditorGUI.EndChangeCheck()) + { + // Convert RTL input + sourceText = string.Empty; + + // Reverse Text displayed in Text Input Box + for (int i = 0; i < m_RtlText.Length; i++) + sourceText += m_RtlText[m_RtlText.Length - i - 1]; + + m_TextProp.stringValue = sourceText; + } + } + + // TEXT STYLE + if (m_StyleNames != null) + { + rect = EditorGUILayout.GetControlRect(false, 17); + + EditorGUI.BeginProperty(rect, k_StyleLabel, m_TextStyleHashCodeProp); + + m_TextStyleIndexLookup.TryGetValue(m_TextStyleHashCodeProp.intValue, out m_StyleSelectionIndex); + + EditorGUI.BeginChangeCheck(); + m_StyleSelectionIndex = EditorGUI.Popup(rect, k_StyleLabel, m_StyleSelectionIndex, m_StyleNames); + if (EditorGUI.EndChangeCheck()) + { + m_TextStyleHashCodeProp.intValue = m_Styles[m_StyleSelectionIndex].hashCode; + m_TextComponent.m_TextStyle = m_Styles[m_StyleSelectionIndex]; + m_HavePropertiesChanged = true; + } + + EditorGUI.EndProperty(); + } + } + } + + protected void DrawMainSettings() + { + // MAIN SETTINGS SECTION + GUILayout.Label(new GUIContent("Main Settings"), TMP_UIStyleManager.sectionHeader); + + //EditorGUI.indentLevel += 1; + + DrawFont(); + + DrawColor(); + + DrawSpacing(); + + DrawAlignment(); + + DrawWrappingOverflow(); + + DrawTextureMapping(); + + //EditorGUI.indentLevel -= 1; + } + + void DrawFont() + { + bool isFontAssetDirty = false; + + // FONT ASSET + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_FontAssetProp, k_FontAssetLabel); + if (EditorGUI.EndChangeCheck()) + { + m_HavePropertiesChanged = true; + m_HasFontAssetChangedProp.boolValue = true; + + // Get new Material Presets for the new font asset + m_MaterialPresetNames = GetMaterialPresets(); + m_MaterialPresetSelectionIndex = 0; + + isFontAssetDirty = true; + } + + Rect rect; + + // MATERIAL PRESET + if (m_MaterialPresetNames != null && !isFontAssetDirty ) + { + EditorGUI.BeginChangeCheck(); + rect = EditorGUILayout.GetControlRect(false, 17); + + EditorGUI.BeginProperty(rect, k_MaterialPresetLabel, m_FontSharedMaterialProp); + + float oldHeight = EditorStyles.popup.fixedHeight; + EditorStyles.popup.fixedHeight = rect.height; + + int oldSize = EditorStyles.popup.fontSize; + EditorStyles.popup.fontSize = 11; + + if (m_FontSharedMaterialProp.objectReferenceValue != null) + m_MaterialPresetIndexLookup.TryGetValue(m_FontSharedMaterialProp.objectReferenceValue.GetInstanceID(), out m_MaterialPresetSelectionIndex); + + m_MaterialPresetSelectionIndex = EditorGUI.Popup(rect, k_MaterialPresetLabel, m_MaterialPresetSelectionIndex, m_MaterialPresetNames); + + EditorGUI.EndProperty(); + + if (EditorGUI.EndChangeCheck()) + { + m_FontSharedMaterialProp.objectReferenceValue = m_MaterialPresets[m_MaterialPresetSelectionIndex]; + m_HavePropertiesChanged = true; + } + + EditorStyles.popup.fixedHeight = oldHeight; + EditorStyles.popup.fontSize = oldSize; + } + + // FONT STYLE + EditorGUI.BeginChangeCheck(); + + int v1, v2, v3, v4, v5, v6, v7; + + if (EditorGUIUtility.wideMode) + { + rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight + 2f); + + EditorGUI.BeginProperty(rect, k_FontStyleLabel, m_FontStyleProp); + + EditorGUI.PrefixLabel(rect, k_FontStyleLabel); + + int styleValue = m_FontStyleProp.intValue; + + rect.x += EditorGUIUtility.labelWidth; + rect.width -= EditorGUIUtility.labelWidth; + + rect.width = Mathf.Max(25f, rect.width / 7f); + + v1 = TMP_EditorUtility.EditorToggle(rect, (styleValue & 1) == 1, k_BoldLabel, TMP_UIStyleManager.alignmentButtonLeft) ? 1 : 0; // Bold + rect.x += rect.width; + v2 = TMP_EditorUtility.EditorToggle(rect, (styleValue & 2) == 2, k_ItalicLabel, TMP_UIStyleManager.alignmentButtonMid) ? 2 : 0; // Italics + rect.x += rect.width; + v3 = TMP_EditorUtility.EditorToggle(rect, (styleValue & 4) == 4, k_UnderlineLabel, TMP_UIStyleManager.alignmentButtonMid) ? 4 : 0; // Underline + rect.x += rect.width; + v7 = TMP_EditorUtility.EditorToggle(rect, (styleValue & 64) == 64, k_StrikethroughLabel, TMP_UIStyleManager.alignmentButtonRight) ? 64 : 0; // Strikethrough + rect.x += rect.width; + + int selected = 0; + + EditorGUI.BeginChangeCheck(); + v4 = TMP_EditorUtility.EditorToggle(rect, (styleValue & 8) == 8, k_LowercaseLabel, TMP_UIStyleManager.alignmentButtonLeft) ? 8 : 0; // Lowercase + if (EditorGUI.EndChangeCheck() && v4 > 0) + { + selected = v4; + } + rect.x += rect.width; + EditorGUI.BeginChangeCheck(); + v5 = TMP_EditorUtility.EditorToggle(rect, (styleValue & 16) == 16, k_UppercaseLabel, TMP_UIStyleManager.alignmentButtonMid) ? 16 : 0; // Uppercase + if (EditorGUI.EndChangeCheck() && v5 > 0) + { + selected = v5; + } + rect.x += rect.width; + EditorGUI.BeginChangeCheck(); + v6 = TMP_EditorUtility.EditorToggle(rect, (styleValue & 32) == 32, k_SmallcapsLabel, TMP_UIStyleManager.alignmentButtonRight) ? 32 : 0; // Smallcaps + if (EditorGUI.EndChangeCheck() && v6 > 0) + { + selected = v6; + } + + if (selected > 0) + { + v4 = selected == 8 ? 8 : 0; + v5 = selected == 16 ? 16 : 0; + v6 = selected == 32 ? 32 : 0; + } + + EditorGUI.EndProperty(); + } + else + { + rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight + 2f); + + EditorGUI.BeginProperty(rect, k_FontStyleLabel, m_FontStyleProp); + + EditorGUI.PrefixLabel(rect, k_FontStyleLabel); + + int styleValue = m_FontStyleProp.intValue; + + rect.x += EditorGUIUtility.labelWidth; + rect.width -= EditorGUIUtility.labelWidth; + rect.width = Mathf.Max(25f, rect.width / 4f); + + v1 = TMP_EditorUtility.EditorToggle(rect, (styleValue & 1) == 1, k_BoldLabel, TMP_UIStyleManager.alignmentButtonLeft) ? 1 : 0; // Bold + rect.x += rect.width; + v2 = TMP_EditorUtility.EditorToggle(rect, (styleValue & 2) == 2, k_ItalicLabel, TMP_UIStyleManager.alignmentButtonMid) ? 2 : 0; // Italics + rect.x += rect.width; + v3 = TMP_EditorUtility.EditorToggle(rect, (styleValue & 4) == 4, k_UnderlineLabel, TMP_UIStyleManager.alignmentButtonMid) ? 4 : 0; // Underline + rect.x += rect.width; + v7 = TMP_EditorUtility.EditorToggle(rect, (styleValue & 64) == 64, k_StrikethroughLabel, TMP_UIStyleManager.alignmentButtonRight) ? 64 : 0; // Strikethrough + + rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight + 2f); + + rect.x += EditorGUIUtility.labelWidth; + rect.width -= EditorGUIUtility.labelWidth; + + rect.width = Mathf.Max(25f, rect.width / 4f); + + int selected = 0; + + EditorGUI.BeginChangeCheck(); + v4 = TMP_EditorUtility.EditorToggle(rect, (styleValue & 8) == 8, k_LowercaseLabel, TMP_UIStyleManager.alignmentButtonLeft) ? 8 : 0; // Lowercase + if (EditorGUI.EndChangeCheck() && v4 > 0) + { + selected = v4; + } + rect.x += rect.width; + EditorGUI.BeginChangeCheck(); + v5 = TMP_EditorUtility.EditorToggle(rect, (styleValue & 16) == 16, k_UppercaseLabel, TMP_UIStyleManager.alignmentButtonMid) ? 16 : 0; // Uppercase + if (EditorGUI.EndChangeCheck() && v5 > 0) + { + selected = v5; + } + rect.x += rect.width; + EditorGUI.BeginChangeCheck(); + v6 = TMP_EditorUtility.EditorToggle(rect, (styleValue & 32) == 32, k_SmallcapsLabel, TMP_UIStyleManager.alignmentButtonRight) ? 32 : 0; // Smallcaps + if (EditorGUI.EndChangeCheck() && v6 > 0) + { + selected = v6; + } + + if (selected > 0) + { + v4 = selected == 8 ? 8 : 0; + v5 = selected == 16 ? 16 : 0; + v6 = selected == 32 ? 32 : 0; + } + + EditorGUI.EndProperty(); + } + + if (EditorGUI.EndChangeCheck()) + { + m_FontStyleProp.intValue = v1 + v2 + v3 + v4 + v5 + v6 + v7; + m_HavePropertiesChanged = true; + } + + // FONT SIZE + EditorGUI.BeginChangeCheck(); + + EditorGUI.BeginDisabledGroup(m_AutoSizingProp.boolValue); + EditorGUILayout.PropertyField(m_FontSizeProp, k_FontSizeLabel, GUILayout.MaxWidth(EditorGUIUtility.labelWidth + 50f)); + EditorGUI.EndDisabledGroup(); + + if (EditorGUI.EndChangeCheck()) + { + float fontSize = Mathf.Clamp(m_FontSizeProp.floatValue, 0, 32767); + + m_FontSizeProp.floatValue = fontSize; + m_FontSizeBaseProp.floatValue = fontSize; + m_HavePropertiesChanged = true; + } + + EditorGUI.indentLevel += 1; + + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_AutoSizingProp, k_AutoSizeLabel); + if (EditorGUI.EndChangeCheck()) + { + if (m_AutoSizingProp.boolValue == false) + m_FontSizeProp.floatValue = m_FontSizeBaseProp.floatValue; + + m_HavePropertiesChanged = true; + } + + // Show auto sizing options + if (m_AutoSizingProp.boolValue) + { + rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight); + + EditorGUI.PrefixLabel(rect, k_AutoSizeOptionsLabel); + + int previousIndent = EditorGUI.indentLevel; + + EditorGUI.indentLevel = 0; + + rect.width = (rect.width - EditorGUIUtility.labelWidth) / 4f; + rect.x += EditorGUIUtility.labelWidth; + + EditorGUIUtility.labelWidth = 24; + EditorGUI.BeginChangeCheck(); + EditorGUI.PropertyField(rect, m_FontSizeMinProp, k_MinLabel); + if (EditorGUI.EndChangeCheck()) + { + float minSize = m_FontSizeMinProp.floatValue; + + minSize = Mathf.Max(0, minSize); + + m_FontSizeMinProp.floatValue = Mathf.Min(minSize, m_FontSizeMaxProp.floatValue); + m_HavePropertiesChanged = true; + } + rect.x += rect.width; + + EditorGUIUtility.labelWidth = 27; + EditorGUI.BeginChangeCheck(); + EditorGUI.PropertyField(rect, m_FontSizeMaxProp, k_MaxLabel); + if (EditorGUI.EndChangeCheck()) + { + float maxSize = Mathf.Clamp(m_FontSizeMaxProp.floatValue, 0, 32767); + + m_FontSizeMaxProp.floatValue = Mathf.Max(m_FontSizeMinProp.floatValue, maxSize); + m_HavePropertiesChanged = true; + } + rect.x += rect.width; + + EditorGUI.BeginChangeCheck(); + EditorGUIUtility.labelWidth = 36; + EditorGUI.PropertyField(rect, m_CharWidthMaxAdjProp, k_WdLabel); + rect.x += rect.width; + EditorGUIUtility.labelWidth = 28; + EditorGUI.PropertyField(rect, m_LineSpacingMaxProp, k_LineLabel); + + EditorGUIUtility.labelWidth = 0; + + if (EditorGUI.EndChangeCheck()) + { + m_CharWidthMaxAdjProp.floatValue = Mathf.Clamp(m_CharWidthMaxAdjProp.floatValue, 0, 50); + m_LineSpacingMaxProp.floatValue = Mathf.Min(0, m_LineSpacingMaxProp.floatValue); + m_HavePropertiesChanged = true; + } + + EditorGUI.indentLevel = previousIndent; + } + + EditorGUI.indentLevel -= 1; + + + + EditorGUILayout.Space(); + } + + void DrawColor() + { + // FACE VERTEX COLOR + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_FontColorProp, k_BaseColorLabel); + if (EditorGUI.EndChangeCheck()) + { + m_HavePropertiesChanged = true; + } + + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_EnableVertexGradientProp, k_ColorGradientLabel); + if (EditorGUI.EndChangeCheck()) + { + m_HavePropertiesChanged = true; + } + + EditorGUIUtility.fieldWidth = 0; + + if (m_EnableVertexGradientProp.boolValue) + { + EditorGUI.indentLevel += 1; + + EditorGUI.BeginChangeCheck(); + + EditorGUILayout.PropertyField(m_FontColorGradientPresetProp, k_ColorPresetLabel); + + SerializedObject obj = null; + + SerializedProperty colorMode; + + SerializedProperty topLeft; + SerializedProperty topRight; + SerializedProperty bottomLeft; + SerializedProperty bottomRight; + + if (m_FontColorGradientPresetProp.objectReferenceValue == null) + { + colorMode = m_ColorModeProp; + topLeft = m_FontColorGradientProp.FindPropertyRelative("topLeft"); + topRight = m_FontColorGradientProp.FindPropertyRelative("topRight"); + bottomLeft = m_FontColorGradientProp.FindPropertyRelative("bottomLeft"); + bottomRight = m_FontColorGradientProp.FindPropertyRelative("bottomRight"); + } + else + { + obj = new SerializedObject(m_FontColorGradientPresetProp.objectReferenceValue); + colorMode = obj.FindProperty("colorMode"); + topLeft = obj.FindProperty("topLeft"); + topRight = obj.FindProperty("topRight"); + bottomLeft = obj.FindProperty("bottomLeft"); + bottomRight = obj.FindProperty("bottomRight"); + } + + EditorGUILayout.PropertyField(colorMode, k_ColorModeLabel); + + Rect rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight * (EditorGUIUtility.wideMode ? 1 : 2)); + + EditorGUI.PrefixLabel(rect, k_CorenerColorsLabel); + + rect.x += EditorGUIUtility.labelWidth; + rect.width = rect.width - EditorGUIUtility.labelWidth; + + switch ((ColorMode)colorMode.enumValueIndex) + { + case ColorMode.Single: + TMP_EditorUtility.DrawColorProperty(rect, topLeft); + + topRight.colorValue = topLeft.colorValue; + bottomLeft.colorValue = topLeft.colorValue; + bottomRight.colorValue = topLeft.colorValue; + break; + case ColorMode.HorizontalGradient: + rect.width /= 2f; + + TMP_EditorUtility.DrawColorProperty(rect, topLeft); + + rect.x += rect.width; + + TMP_EditorUtility.DrawColorProperty(rect, topRight); + + bottomLeft.colorValue = topLeft.colorValue; + bottomRight.colorValue = topRight.colorValue; + break; + case ColorMode.VerticalGradient: + TMP_EditorUtility.DrawColorProperty(rect, topLeft); + + rect = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight * (EditorGUIUtility.wideMode ? 1 : 2)); + rect.x += EditorGUIUtility.labelWidth; + + TMP_EditorUtility.DrawColorProperty(rect, bottomLeft); + + topRight.colorValue = topLeft.colorValue; + bottomRight.colorValue = bottomLeft.colorValue; + break; + case ColorMode.FourCornersGradient: + rect.width /= 2f; + + TMP_EditorUtility.DrawColorProperty(rect, topLeft); + + rect.x += rect.width; + + TMP_EditorUtility.DrawColorProperty(rect, topRight); + + rect = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight * (EditorGUIUtility.wideMode ? 1 : 2)); + rect.x += EditorGUIUtility.labelWidth; + rect.width = (rect.width - EditorGUIUtility.labelWidth) / 2f; + + TMP_EditorUtility.DrawColorProperty(rect, bottomLeft); + + rect.x += rect.width; + + TMP_EditorUtility.DrawColorProperty(rect, bottomRight); + break; + } + + if (EditorGUI.EndChangeCheck()) + { + m_HavePropertiesChanged = true; + if (obj != null) + { + obj.ApplyModifiedProperties(); + TMPro_EventManager.ON_COLOR_GRADIENT_PROPERTY_CHANGED(m_FontColorGradientPresetProp.objectReferenceValue as TMP_ColorGradient); + } + } + + EditorGUI.indentLevel -= 1; + } + + EditorGUILayout.PropertyField(m_OverrideHtmlColorProp, k_OverrideTagsLabel); + + EditorGUILayout.Space(); + } + + void DrawSpacing() + { + // CHARACTER, LINE & PARAGRAPH SPACING + EditorGUI.BeginChangeCheck(); + + Rect rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight); + + EditorGUI.PrefixLabel(rect, k_SpacingOptionsLabel); + + int oldIndent = EditorGUI.indentLevel; + EditorGUI.indentLevel = 0; + + float currentLabelWidth = EditorGUIUtility.labelWidth; + rect.x += currentLabelWidth; + rect.width = (rect.width - currentLabelWidth - 3f) / 2f; + + EditorGUIUtility.labelWidth = Mathf.Min(rect.width * 0.55f, 80f); + + EditorGUI.PropertyField(rect, m_CharacterSpacingProp, k_CharacterSpacingLabel); + rect.x += rect.width + 3f; + EditorGUI.PropertyField(rect, m_WordSpacingProp, k_WordSpacingLabel); + + rect = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight); + + rect.x += currentLabelWidth; + rect.width = (rect.width - currentLabelWidth -3f) / 2f; + EditorGUIUtility.labelWidth = Mathf.Min(rect.width * 0.55f, 80f); + + EditorGUI.PropertyField(rect, m_LineSpacingProp, k_LineSpacingLabel); + rect.x += rect.width + 3f; + EditorGUI.PropertyField(rect, m_ParagraphSpacingProp, k_ParagraphSpacingLabel); + + EditorGUIUtility.labelWidth = currentLabelWidth; + EditorGUI.indentLevel = oldIndent; + + if (EditorGUI.EndChangeCheck()) + { + m_HavePropertiesChanged = true; + } + + EditorGUILayout.Space(); + } + + void DrawAlignment() + { + // TEXT ALIGNMENT + EditorGUI.BeginChangeCheck(); + + Rect rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.currentViewWidth > 504 ? 20 : 40 + 3); + EditorGUI.BeginProperty(rect, k_AlignmentLabel, m_HorizontalAlignmentProp); + EditorGUI.BeginProperty(rect, k_AlignmentLabel, m_VerticalAlignmentProp); + + EditorGUI.PrefixLabel(rect, k_AlignmentLabel); + rect.x += EditorGUIUtility.labelWidth; + + EditorGUI.PropertyField(rect, m_HorizontalAlignmentProp, GUIContent.none); + EditorGUI.PropertyField(rect, m_VerticalAlignmentProp, GUIContent.none); + + // WRAPPING RATIOS shown if Justified mode is selected. + if (((HorizontalAlignmentOptions)m_HorizontalAlignmentProp.intValue & HorizontalAlignmentOptions.Justified) == HorizontalAlignmentOptions.Justified || ((HorizontalAlignmentOptions)m_HorizontalAlignmentProp.intValue & HorizontalAlignmentOptions.Flush) == HorizontalAlignmentOptions.Flush) + DrawPropertySlider(k_WrapMixLabel, m_WordWrappingRatiosProp); + + if (EditorGUI.EndChangeCheck()) + m_HavePropertiesChanged = true; + + EditorGUI.EndProperty(); + EditorGUI.EndProperty(); + + EditorGUILayout.Space(); + } + + void DrawWrappingOverflow() + { + // TEXT WRAPPING + Rect rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight); + EditorGUI.BeginProperty(rect, k_WrappingLabel, m_TextWrappingModeProp); + + EditorGUI.BeginChangeCheck(); + EditorGUI.PropertyField(rect, m_TextWrappingModeProp); + if (EditorGUI.EndChangeCheck()) + { + m_HavePropertiesChanged = true; + } + + EditorGUI.EndProperty(); + + // TEXT OVERFLOW + EditorGUI.BeginChangeCheck(); + + if ((TextOverflowModes)m_TextOverflowModeProp.enumValueIndex == TextOverflowModes.Linked) + { + EditorGUILayout.BeginHorizontal(); + + float fieldWidth = EditorGUIUtility.fieldWidth; + EditorGUIUtility.fieldWidth = 65; + EditorGUILayout.PropertyField(m_TextOverflowModeProp, k_OverflowLabel); + EditorGUIUtility.fieldWidth = fieldWidth; + + EditorGUILayout.PropertyField(m_LinkedTextComponentProp, GUIContent.none); + + EditorGUILayout.EndHorizontal(); + + if (GUI.changed) + { + TMP_Text linkedComponent = m_LinkedTextComponentProp.objectReferenceValue as TMP_Text; + + if (linkedComponent == null) + { + m_LinkedTextComponentProp.objectReferenceValue = null; + + if (m_PreviousLinkedTextComponent != null) + m_TextComponent.ReleaseLinkedTextComponent(m_PreviousLinkedTextComponent); + } + else if (m_TextComponent.IsSelfOrLinkedAncestor(linkedComponent)) + { + m_LinkedTextComponentProp.objectReferenceValue = m_PreviousLinkedTextComponent; + } + else + { + if (m_PreviousLinkedTextComponent != null) + m_TextComponent.ReleaseLinkedTextComponent(m_PreviousLinkedTextComponent); + + m_LinkedTextComponentProp.objectReferenceValue = linkedComponent; + linkedComponent.parentLinkedComponent = m_TextComponent; + m_PreviousLinkedTextComponent = linkedComponent; + } + } + } + else if ((TextOverflowModes)m_TextOverflowModeProp.enumValueIndex == TextOverflowModes.Page) + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PropertyField(m_TextOverflowModeProp, k_OverflowLabel); + EditorGUILayout.PropertyField(m_PageToDisplayProp, GUIContent.none); + EditorGUILayout.EndHorizontal(); + + if (m_PreviousLinkedTextComponent) + { + m_TextComponent.ReleaseLinkedTextComponent(m_PreviousLinkedTextComponent); + + m_TextComponent.linkedTextComponent = null; + } + } + else + { + EditorGUILayout.PropertyField(m_TextOverflowModeProp, k_OverflowLabel); + + if (m_PreviousLinkedTextComponent) + { + m_TextComponent.ReleaseLinkedTextComponent(m_PreviousLinkedTextComponent); + + m_TextComponent.linkedTextComponent = null; + } + } + + if (EditorGUI.EndChangeCheck()) + { + m_HavePropertiesChanged = true; + } + + EditorGUILayout.Space(); + } + + protected abstract void DrawExtraSettings(); + + protected void DrawMargins() + { + EditorGUI.BeginChangeCheck(); + DrawMarginProperty(m_MarginProp, k_MarginsLabel); + if (EditorGUI.EndChangeCheck()) + { + // Value range check on margins to make sure they are not excessive. + Vector4 margins = m_MarginProp.vector4Value; + Rect textContainerSize = m_RectTransform.rect; + + margins.x = Mathf.Clamp(margins.x, -textContainerSize.width, textContainerSize.width); + margins.z = Mathf.Clamp(margins.z, -textContainerSize.width, textContainerSize.width); + + margins.y = Mathf.Clamp(margins.y, -textContainerSize.height, textContainerSize.height); + margins.w = Mathf.Clamp(margins.w, -textContainerSize.height, textContainerSize.height); + + m_MarginProp.vector4Value = margins; + + m_HavePropertiesChanged = true; + } + + EditorGUILayout.Space(); + } + + protected void DrawGeometrySorting() + { + EditorGUI.BeginChangeCheck(); + + EditorGUILayout.PropertyField(m_GeometrySortingOrderProp, k_GeometrySortingLabel); + + if (EditorGUI.EndChangeCheck()) + m_HavePropertiesChanged = true; + + EditorGUILayout.Space(); + } + + protected void DrawIsTextObjectScaleStatic() + { + EditorGUI.BeginChangeCheck(); + + EditorGUILayout.PropertyField(m_IsTextObjectScaleStaticProp, k_IsTextObjectScaleStatic); + + if (EditorGUI.EndChangeCheck()) + { + m_TextComponent.isTextObjectScaleStatic = m_IsTextObjectScaleStaticProp.boolValue; + m_HavePropertiesChanged = true; + } + + EditorGUILayout.Space(); + } + + + protected void DrawRichText() + { + EditorGUI.BeginChangeCheck(); + + EditorGUILayout.PropertyField(m_IsRichTextProp, k_RichTextLabel); + if (EditorGUI.EndChangeCheck()) + m_HavePropertiesChanged = true; + } + + protected void DrawParsing() + { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_EnableEscapeCharacterParsingProp, k_EscapeCharactersLabel); + EditorGUILayout.PropertyField(m_UseMaxVisibleDescenderProp, k_VisibleDescenderLabel); + + if (EditorGUI.EndChangeCheck()) + m_HavePropertiesChanged = true; + + EditorGUILayout.Space(); + } + + protected void DrawEmojiFallbackSupport() + { + EditorGUI.BeginChangeCheck(); + + EditorGUILayout.PropertyField(m_EmojiFallbackSupportProp, k_EmojiFallbackSupportLabel); + if (EditorGUI.EndChangeCheck()) + m_HavePropertiesChanged = true; + } + + protected void DrawSpriteAsset() + { + EditorGUI.BeginChangeCheck(); + + EditorGUILayout.PropertyField(m_SpriteAssetProp, k_SpriteAssetLabel, true); + + if (EditorGUI.EndChangeCheck()) + m_HavePropertiesChanged = true; + + EditorGUILayout.Space(); + } + + protected void DrawStyleSheet() + { + EditorGUI.BeginChangeCheck(); + + EditorGUILayout.PropertyField(m_StyleSheetAssetProp, k_StyleSheetAssetLabel, true); + + if (EditorGUI.EndChangeCheck()) + { + m_StyleNames = GetStyleNames(); + m_HavePropertiesChanged = true; + } + + EditorGUILayout.Space(); + } + + protected void DrawTextureMapping() + { + // TEXTURE MAPPING OPTIONS + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_HorizontalMappingProp, k_HorizontalMappingLabel); + EditorGUILayout.PropertyField(m_VerticalMappingProp, k_VerticalMappingLabel); + if (EditorGUI.EndChangeCheck()) + { + m_HavePropertiesChanged = true; + } + + // UV OPTIONS + if (m_HorizontalMappingProp.enumValueIndex > 0) + { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_UvLineOffsetProp, k_LineOffsetLabel, GUILayout.MinWidth(70f)); + if (EditorGUI.EndChangeCheck()) + { + m_HavePropertiesChanged = true; + } + } + + EditorGUILayout.Space(); + } + + protected void DrawFontFeatures() + { + int srcMask = 0; + + int featureCount = m_FontFeaturesActiveProp.arraySize; + for (int i = 0; i < featureCount; i++) + { + SerializedProperty activeFeatureProperty = m_FontFeaturesActiveProp.GetArrayElementAtIndex(i); + + for (int j = 0; j < k_FontFeatures.Length; j++) + { + if (activeFeatureProperty.intValue == k_FontFeatures[j].TagToInt()) + { + srcMask |= 0x1 << j; + break; + } + } + } + + EditorGUI.BeginChangeCheck(); + + int mask = EditorGUILayout.MaskField(k_FontFeaturesLabel, srcMask, k_FontFeatures); + + if (EditorGUI.EndChangeCheck()) + { + m_FontFeaturesActiveProp.ClearArray(); + + int writeIndex = 0; + + for (int i = 0; i < k_FontFeatures.Length; i++) + { + int bit = 0x1 << i; + if ((mask & bit) == bit) + { + m_FontFeaturesActiveProp.InsertArrayElementAtIndex(writeIndex); + SerializedProperty newFeature = m_FontFeaturesActiveProp.GetArrayElementAtIndex(writeIndex); + newFeature.intValue = k_FontFeatures[i].TagToInt(); + + writeIndex += 1; + } + } + + m_HavePropertiesChanged = true; + } + } + + protected void DrawPadding() + { + // EXTRA PADDING + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_EnableExtraPaddingProp, k_PaddingLabel); + if (EditorGUI.EndChangeCheck()) + { + m_HavePropertiesChanged = true; + m_CheckPaddingRequiredProp.boolValue = true; + } + } + + /// + /// Method to retrieve the material presets that match the currently selected font asset. + /// + protected GUIContent[] GetMaterialPresets() + { + TMP_FontAsset fontAsset = m_FontAssetProp.objectReferenceValue as TMP_FontAsset; + if (fontAsset == null) return null; + + m_MaterialPresets = TMP_EditorUtility.FindMaterialReferences(fontAsset); + m_MaterialPresetNames = new GUIContent[m_MaterialPresets.Length]; + + m_MaterialPresetIndexLookup.Clear(); + + for (int i = 0; i < m_MaterialPresetNames.Length; i++) + { + m_MaterialPresetNames[i] = new GUIContent(m_MaterialPresets[i].name); + + m_MaterialPresetIndexLookup.Add(m_MaterialPresets[i].GetInstanceID(), i); + + //if (m_TargetMaterial.GetInstanceID() == m_MaterialPresets[i].GetInstanceID()) + // m_MaterialPresetSelectionIndex = i; + } + + m_IsPresetListDirty = false; + + return m_MaterialPresetNames; + } + + protected GUIContent[] GetStyleNames() + { + k_AvailableStyles.Clear(); + m_TextStyleIndexLookup.Clear(); + m_Styles.Clear(); + + // First style on the list is always the Normal default style. + TMP_Style styleNormal = TMP_Style.NormalStyle; + + m_Styles.Add(styleNormal); + m_TextStyleIndexLookup.Add(styleNormal.hashCode, 0); + + k_AvailableStyles.Add(styleNormal.hashCode, styleNormal); + + // Get styles from Style Sheet potentially assigned to the text object. + TMP_StyleSheet localStyleSheet = (TMP_StyleSheet)m_StyleSheetAssetProp.objectReferenceValue; + + if (localStyleSheet != null) + { + int styleCount = localStyleSheet.styles.Count; + + for (int i = 0; i < styleCount; i++) + { + TMP_Style style = localStyleSheet.styles[i]; + + if (k_AvailableStyles.ContainsKey(style.hashCode) == false) + { + k_AvailableStyles.Add(style.hashCode, style); + m_Styles.Add(style); + m_TextStyleIndexLookup.Add(style.hashCode, m_TextStyleIndexLookup.Count); + } + } + } + + // Get styles from TMP Settings' default style sheet. + TMP_StyleSheet globalStyleSheet = TMP_Settings.defaultStyleSheet; + + if (globalStyleSheet != null) + { + int styleCount = globalStyleSheet.styles.Count; + + for (int i = 0; i < styleCount; i++) + { + TMP_Style style = globalStyleSheet.styles[i]; + + if (k_AvailableStyles.ContainsKey(style.hashCode) == false) + { + k_AvailableStyles.Add(style.hashCode, style); + m_Styles.Add(style); + m_TextStyleIndexLookup.Add(style.hashCode, m_TextStyleIndexLookup.Count); + } + } + } + + // Create array that will contain the list of available styles. + GUIContent[] styleNames = k_AvailableStyles.Values.Select(item => new GUIContent(item.name)).ToArray(); + + // Set text style index + m_TextStyleIndexLookup.TryGetValue(m_TextStyleHashCodeProp.intValue, out m_StyleSelectionIndex); + + return styleNames; + } + + // DRAW MARGIN PROPERTY + protected void DrawMarginProperty(SerializedProperty property, GUIContent label) + { + Rect rect = EditorGUILayout.GetControlRect(false, 2 * 18); + + EditorGUI.BeginProperty(rect, label, property); + + Rect pos0 = new Rect(rect.x, rect.y + 2, rect.width - 15, 18); + + float width = rect.width + 3; + pos0.width = EditorGUIUtility.labelWidth; + EditorGUI.PrefixLabel(pos0, label); + + Vector4 margins = property.vector4Value; + + float widthB = width - EditorGUIUtility.labelWidth; + float fieldWidth = widthB / 4; + pos0.width = Mathf.Max(fieldWidth - 5, 45f); + + // Labels + pos0.x = EditorGUIUtility.labelWidth + 15; + margins.x = DrawMarginField(pos0, "Left", margins.x); + + pos0.x += fieldWidth; + margins.y = DrawMarginField(pos0, "Top", margins.y); + + pos0.x += fieldWidth; + margins.z = DrawMarginField(pos0, "Right", margins.z); + + pos0.x += fieldWidth; + margins.w = DrawMarginField(pos0, "Bottom", margins.w); + + property.vector4Value = margins; + + EditorGUI.EndProperty(); + } + + float DrawMarginField(Rect position, string label, float value) + { + int controlId = GUIUtility.GetControlID(FocusType.Keyboard, position); + EditorGUI.PrefixLabel(position, controlId, new GUIContent(label)); + + Rect dragZone = new Rect(position.x, position.y, position.width, position.height); + position.y += EditorGUIUtility.singleLineHeight; + + return EditorGUI.DoFloatField(EditorGUI.s_RecycledEditor, position, dragZone, controlId, value, EditorGUI.kFloatFieldFormatString, EditorStyles.numberField, true); + } + + protected void DrawPropertySlider(GUIContent label, SerializedProperty property) + { + Rect rect = EditorGUILayout.GetControlRect(false, 17); + + GUIContent content = label ?? GUIContent.none; + EditorGUI.Slider(new Rect(rect.x, rect.y, rect.width, rect.height), property, 0.0f, 1.0f, content); + } + + protected abstract bool IsMixSelectionTypes(); + + // Special Handling of Undo / Redo Events. + protected abstract void OnUndoRedo(); + + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_BaseEditorPanel.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_BaseEditorPanel.cs.meta new file mode 100644 index 00000000..87bd7391 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_BaseEditorPanel.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 91950f78729ab144aa36e94690b28fad +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_BaseShaderGUI.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_BaseShaderGUI.cs new file mode 100644 index 00000000..b712fc8d --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_BaseShaderGUI.cs @@ -0,0 +1,697 @@ +using UnityEngine; +using UnityEditor; + +namespace TMPro.EditorUtilities +{ + /// Base class for TextMesh Pro shader GUIs. + public abstract class TMP_BaseShaderGUI : ShaderGUI + { + /// Representation of a #pragma shader_feature. + /// It is assumed that the first feature option is for no keyword (underscores). + protected class ShaderFeature + { + public string undoLabel; + + public GUIContent label; + + /// The keyword labels, for display. Include the no-keyword as the first option. + public GUIContent[] keywordLabels; + + /// The shader keywords. Exclude the no-keyword option. + public string[] keywords; + + int m_State; + + public bool Active + { + get { return m_State >= 0; } + } + + public int State + { + get { return m_State; } + } + + public void ReadState(Material material) + { + for (int i = 0; i < keywords.Length; i++) + { + if (material.IsKeywordEnabled(keywords[i])) + { + m_State = i; + return; + } + } + + m_State = -1; + } + + public void SetActive(bool active, Material material) + { + m_State = active ? 0 : -1; + SetStateKeywords(material); + } + + public void DoPopup(MaterialEditor editor, Material material) + { + EditorGUI.BeginChangeCheck(); + int selection = EditorGUILayout.Popup(label, m_State + 1, keywordLabels); + if (EditorGUI.EndChangeCheck()) + { + m_State = selection - 1; + editor.RegisterPropertyChangeUndo(undoLabel); + SetStateKeywords(material); + } + } + + void SetStateKeywords(Material material) + { + for (int i = 0; i < keywords.Length; i++) + { + if (i == m_State) + { + material.EnableKeyword(keywords[i]); + } + else + { + material.DisableKeyword(keywords[i]); + } + } + } + } + + static GUIContent s_TempLabel = new GUIContent(); + + protected static bool s_DebugExtended; + + static int s_UndoRedoCount, s_LastSeenUndoRedoCount; + + static float[][] s_TempFloats = + { + null, new float[1], new float[2], new float[3], new float[4] + }; + + protected static GUIContent[] s_XywhVectorLabels = + { + new GUIContent("X"), + new GUIContent("Y"), + new GUIContent("W", "Width"), + new GUIContent("H", "Height") + }; + + protected static GUIContent[] s_LbrtVectorLabels = + { + new GUIContent("L", "Left"), + new GUIContent("B", "Bottom"), + new GUIContent("R", "Right"), + new GUIContent("T", "Top") + }; + + protected static GUIContent[] s_CullingTypeLabels = + { + new GUIContent("Off"), + new GUIContent("Front"), + new GUIContent("Back") + }; + + static TMP_BaseShaderGUI() + { + // Keep track of how many undo/redo events happened. + Undo.undoRedoPerformed += () => s_UndoRedoCount += 1; + } + + bool m_IsNewGUI = true; + + float m_DragAndDropMinY; + + protected MaterialEditor m_Editor; + + protected Material m_Material; + private int m_ShaderID; + + protected MaterialProperty[] m_Properties; + + void PrepareGUI() + { + m_IsNewGUI = false; + ShaderUtilities.GetShaderPropertyIDs(); + + // New GUI just got constructed. This happens in response to a selection, + // but also after undo/redo events. + if (s_LastSeenUndoRedoCount != s_UndoRedoCount) + { + // There's been at least one undo/redo since the last time this GUI got constructed. + // Maybe the undo/redo was for this material? Assume that is was. + TMPro_EventManager.ON_MATERIAL_PROPERTY_CHANGED(true, m_Material); + } + + s_LastSeenUndoRedoCount = s_UndoRedoCount; + } + + public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties) + { + m_Editor = materialEditor; + m_Material = materialEditor.target as Material; + this.m_Properties = properties; + + if (m_IsNewGUI) + PrepareGUI(); + + DoDragAndDropBegin(); + EditorGUI.BeginChangeCheck(); + DoGUI(); + if (EditorGUI.EndChangeCheck()) + { + TMPro_EventManager.ON_MATERIAL_PROPERTY_CHANGED(true, m_Material); + } + + DoDragAndDropEnd(); + } + + public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader) + { + base.AssignNewShaderToMaterial(material, oldShader, newShader); + + TMPro_EventManager.ON_MATERIAL_PROPERTY_CHANGED(true, material); + } + + /// Override this method to create the specific shader GUI. + protected abstract void DoGUI(); + + static string[] s_PanelStateLabel = new string[] { "\t- Click to collapse -", "\t- Click to expand -" }; + + protected bool BeginPanel(string panel, bool expanded) + { + EditorGUI.indentLevel = 0; + + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + Rect r = EditorGUI.IndentedRect(GUILayoutUtility.GetRect(20, 18)); + r.x += 20; + r.width += 6; + + bool enabled = GUI.enabled; + GUI.enabled = true; + expanded = TMP_EditorUtility.EditorToggle(r, expanded, new GUIContent(panel), TMP_UIStyleManager.panelTitle); + r.width -= 30; + EditorGUI.LabelField(r, new GUIContent(expanded ? s_PanelStateLabel[0] : s_PanelStateLabel[1]), TMP_UIStyleManager.rightLabel); + GUI.enabled = enabled; + + EditorGUI.indentLevel += 1; + EditorGUI.BeginDisabledGroup(false); + + return expanded; + } + + protected bool BeginPanel(string panel, ShaderFeature feature, bool expanded, bool readState = true) + { + EditorGUI.indentLevel = 0; + + if (readState) + { + feature.ReadState(m_Material); + } + + EditorGUI.BeginChangeCheck(); + + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + GUILayout.BeginHorizontal(); + + Rect r = EditorGUI.IndentedRect(GUILayoutUtility.GetRect(20, 20, GUILayout.Width(20f))); + bool active = EditorGUI.Toggle(r, feature.Active); + + if (EditorGUI.EndChangeCheck()) + { + m_Editor.RegisterPropertyChangeUndo(feature.undoLabel); + feature.SetActive(active, m_Material); + } + + r = EditorGUI.IndentedRect(GUILayoutUtility.GetRect(20, 18)); + r.width += 6; + + bool enabled = GUI.enabled; + GUI.enabled = true; + expanded = TMP_EditorUtility.EditorToggle(r, expanded, new GUIContent(panel), TMP_UIStyleManager.panelTitle); + r.width -= 10; + EditorGUI.LabelField(r, new GUIContent(expanded ? s_PanelStateLabel[0] : s_PanelStateLabel[1]), TMP_UIStyleManager.rightLabel); + GUI.enabled = enabled; + + GUILayout.EndHorizontal(); + + EditorGUI.indentLevel += 1; + EditorGUI.BeginDisabledGroup(!active); + + return expanded; + } + + public void EndPanel() + { + EditorGUI.EndDisabledGroup(); + EditorGUI.indentLevel -= 1; + EditorGUILayout.EndVertical(); + } + + MaterialProperty BeginProperty(string name) + { + MaterialProperty property = FindProperty(name, m_Properties); + EditorGUI.BeginChangeCheck(); + EditorGUI.showMixedValue = property.hasMixedValue; + m_Editor.BeginAnimatedCheck(Rect.zero, property); + + return property; + } + + bool EndProperty() + { + m_Editor.EndAnimatedCheck(); + EditorGUI.showMixedValue = false; + return EditorGUI.EndChangeCheck(); + } + + protected void DoPopup(string name, string label, GUIContent[] options) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + int index = EditorGUILayout.Popup(s_TempLabel, (int)property.floatValue, options); + if (EndProperty()) + { + property.floatValue = index; + } + } + + protected void DoCubeMap(string name, string label) + { + DoTexture(name, label, typeof(Cubemap)); + } + + protected void DoTexture2D(string name, string label, bool withTilingOffset = false, string[] speedNames = null) + { + DoTexture(name, label, typeof(Texture2D), withTilingOffset, speedNames); + } + + void DoTexture(string name, string label, System.Type type, bool withTilingOffset = false, string[] speedNames = null) + { + float objFieldSize = 60f; + bool smallLayout = EditorGUIUtility.currentViewWidth <= 330f && (withTilingOffset || speedNames != null); + float controlHeight = smallLayout ? objFieldSize * 2 : objFieldSize; + + MaterialProperty property = FindProperty(name, m_Properties); + m_Editor.BeginAnimatedCheck(Rect.zero, property); + + Rect rect = EditorGUILayout.GetControlRect(true, controlHeight); + float totalWidth = rect.width; + rect.width = EditorGUIUtility.labelWidth + objFieldSize; + rect.height = objFieldSize; + s_TempLabel.text = label; + + EditorGUI.BeginChangeCheck(); + Object tex = EditorGUI.ObjectField(rect, s_TempLabel, property.textureValue, type, false); + if (EditorGUI.EndChangeCheck()) + { + property.textureValue = tex as Texture; + } + + float additionalHeight = controlHeight - objFieldSize; + float xOffset = smallLayout ? rect.width - objFieldSize : rect.width; + + rect.y += additionalHeight; + rect.x += xOffset; + rect.width = totalWidth - xOffset; + rect.height = EditorGUIUtility.singleLineHeight; + + if (withTilingOffset) + { + DoTilingOffset(rect, property); + rect.y += (rect.height + 2f) * 2f; + } + + m_Editor.EndAnimatedCheck(); + + if (speedNames != null) + { + DoUVSpeed(rect, speedNames); + } + } + + void DoTilingOffset(Rect rect, MaterialProperty property) + { + float labelWidth = EditorGUIUtility.labelWidth; + int indentLevel = EditorGUI.indentLevel; + EditorGUI.indentLevel = 0; + EditorGUIUtility.labelWidth = Mathf.Min(40f, rect.width * 0.40f); + + Vector4 vector = property.textureScaleAndOffset; + + bool changed = false; + float[] values = s_TempFloats[2]; + + s_TempLabel.text = "Tiling"; + Rect vectorRect = EditorGUI.PrefixLabel(rect, s_TempLabel); + values[0] = vector.x; + values[1] = vector.y; + + EditorGUI.BeginChangeCheck(); + EditorGUI.MultiFloatField(vectorRect, s_XywhVectorLabels, values); + if (EditorGUI.EndChangeCheck()) + { + vector.x = values[0]; + vector.y = values[1]; + changed = true; + } + + rect.y += rect.height + 2f; + s_TempLabel.text = "Offset"; + vectorRect = EditorGUI.PrefixLabel(rect, s_TempLabel); + values[0] = vector.z; + values[1] = vector.w; + + EditorGUI.BeginChangeCheck(); + EditorGUI.MultiFloatField(vectorRect, s_XywhVectorLabels, values); + if (EditorGUI.EndChangeCheck()) + { + vector.z = values[0]; + vector.w = values[1]; + changed = true; + } + + if (changed) + { + property.textureScaleAndOffset = vector; + } + + EditorGUIUtility.labelWidth = labelWidth; + EditorGUI.indentLevel = indentLevel; + } + + protected void DoUVSpeed(Rect rect, string[] names) + { + float labelWidth = EditorGUIUtility.labelWidth; + int indentLevel = EditorGUI.indentLevel; + EditorGUI.indentLevel = 0; + EditorGUIUtility.labelWidth = Mathf.Min(40f, rect.width * 0.40f); + + s_TempLabel.text = "Speed"; + rect = EditorGUI.PrefixLabel(rect, s_TempLabel); + + EditorGUIUtility.labelWidth = 10f; + rect.width = rect.width * 0.5f - 2f; + + if (names.Length == 1) + { + DoFloat2(rect, names[0]); + } + else + { + DoFloat(rect, names[0], "X"); + rect.x += rect.width + 4f; + DoFloat(rect, names[1], "Y"); + } + + EditorGUIUtility.labelWidth = labelWidth; + EditorGUI.indentLevel = indentLevel; + } + + protected void DoToggle(string name, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + bool value = EditorGUILayout.Toggle(s_TempLabel, property.floatValue == 1f); + if (EndProperty()) + { + property.floatValue = value ? 1f : 0f; + } + } + + protected void DoFloat(string name, string label) + { + MaterialProperty property = BeginProperty(name); + Rect rect = EditorGUILayout.GetControlRect(); + rect.width = EditorGUIUtility.labelWidth + 55f; + s_TempLabel.text = label; + float value = EditorGUI.FloatField(rect, s_TempLabel, property.floatValue); + if (EndProperty()) + { + property.floatValue = value; + } + } + + protected void DoColor(string name, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + Color value = EditorGUI.ColorField(EditorGUILayout.GetControlRect(), s_TempLabel, property.colorValue, false, true, false); + if (EndProperty()) + { + property.colorValue = value; + } + } + + void DoFloat(Rect rect, string name, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + float value = EditorGUI.FloatField(rect, s_TempLabel, property.floatValue); + if (EndProperty()) + { + property.floatValue = value; + } + } + + void DoFloat2(Rect rect, string name) + { + MaterialProperty property = BeginProperty(name); + + float x = EditorGUI.FloatField(rect, "X", property.vectorValue.x); + rect.x += rect.width + 4f; + float y = EditorGUI.FloatField(rect, "Y", property.vectorValue.y); + + if (EndProperty()) + { + property.vectorValue = new Vector2(x, y); + } + } + + protected void DoOffset(string name, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + Vector2 value = EditorGUI.Vector2Field(EditorGUILayout.GetControlRect(), s_TempLabel, property.vectorValue); + if (EndProperty()) + { + property.vectorValue = value; + } + } + + protected void DoSlider(string name, string label) + { + MaterialProperty property = BeginProperty(name); + Vector2 range = property.rangeLimits; + s_TempLabel.text = label; + float value = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, property.floatValue, range.x, range.y); + if (EndProperty()) + { + property.floatValue = value; + } + } + + protected void DoSlider(string name, Vector2 range, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + float value = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, property.floatValue, range.x, range.y); + if (EndProperty()) + { + property.floatValue = value; + } + } + + protected void DoSlider(string propertyName, string propertyField, string label) + { + MaterialProperty property = BeginProperty(propertyName); + Vector2 range = property.rangeLimits; + s_TempLabel.text = label; + + Vector4 value = property.vectorValue; + + switch (propertyField) + { + case "X": + value.x = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.x, range.x, range.y); + break; + case "Y": + value.y = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.y, range.x, range.y); + break; + case "Z": + value.z = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.z, range.x, range.y); + break; + case "W": + value.w = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.w, range.x, range.y); + break; + } + + if (EndProperty()) + { + property.vectorValue = value; + } + } + + protected void DoSlider(string propertyName, string propertyField, Vector2 range, string label) + { + MaterialProperty property = BeginProperty(propertyName); + s_TempLabel.text = label; + + Vector4 value = property.vectorValue; + + switch (propertyField) + { + case "X": + value.x = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.x, range.x, range.y); + break; + case "Y": + value.y = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.y, range.x, range.y); + break; + case "Z": + value.z = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.z, range.x, range.y); + break; + case "W": + value.w = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.w, range.x, range.y); + break; + } + + if (EndProperty()) + { + property.vectorValue = value; + } + } + + protected void DoVector2(string name, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + Vector4 value = EditorGUILayout.Vector3Field(s_TempLabel, property.vectorValue); + if (EndProperty()) + { + property.vectorValue = value; + } + } + + protected void DoVector3(string name, string label) + { + MaterialProperty property = BeginProperty(name); + s_TempLabel.text = label; + Vector4 value = EditorGUILayout.Vector3Field(s_TempLabel, property.vectorValue); + if (EndProperty()) + { + property.vectorValue = value; + } + } + + protected void DoVector(string name, string label, GUIContent[] subLabels) + { + MaterialProperty property = BeginProperty(name); + Rect rect = EditorGUILayout.GetControlRect(); + s_TempLabel.text = label; + rect = EditorGUI.PrefixLabel(rect, s_TempLabel); + Vector4 vector = property.vectorValue; + + float[] values = s_TempFloats[subLabels.Length]; + for (int i = 0; i < subLabels.Length; i++) + { + values[i] = vector[i]; + } + + EditorGUI.MultiFloatField(rect, subLabels, values); + if (EndProperty()) + { + for (int i = 0; i < subLabels.Length; i++) + { + vector[i] = values[i]; + } + + property.vectorValue = vector; + } + } + + bool IsNewShader() + { + if (m_Material == null) + return false; + + int currentShaderID = m_Material.shader.GetInstanceID(); + + if (m_ShaderID == currentShaderID) + return false; + + m_ShaderID = currentShaderID; + + return true; + } + + void DoDragAndDropBegin() + { + m_DragAndDropMinY = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)).y; + } + + void DoDragAndDropEnd() + { + Rect rect = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + Event evt = Event.current; + + if (evt.type == EventType.DragUpdated) + { + DragAndDrop.visualMode = DragAndDropVisualMode.Generic; + evt.Use(); + } + else if (evt.type == EventType.DragPerform && Rect.MinMaxRect(rect.xMin, m_DragAndDropMinY, rect.xMax, rect.yMax).Contains(evt.mousePosition)) + { + DragAndDrop.AcceptDrag(); + evt.Use(); + Material droppedMaterial = DragAndDrop.objectReferences[0] as Material; + if (droppedMaterial && droppedMaterial != m_Material) + { + PerformDrop(droppedMaterial); + } + } + else if (evt.type == EventType.DragExited) + { + if (IsNewShader()) + TMPro_EventManager.ON_MATERIAL_PROPERTY_CHANGED(true, m_Material); + } + } + + void PerformDrop(Material droppedMaterial) + { + Texture droppedTex = droppedMaterial.GetTexture(ShaderUtilities.ID_MainTex); + if (!droppedTex) + { + return; + } + + Texture currentTex = m_Material.GetTexture(ShaderUtilities.ID_MainTex); + TMP_FontAsset requiredFontAsset = null; + if (droppedTex != currentTex) + { + requiredFontAsset = TMP_EditorUtility.FindMatchingFontAsset(droppedMaterial); + if (!requiredFontAsset) + { + return; + } + } + + foreach (GameObject o in Selection.gameObjects) + { + if (requiredFontAsset) + { + TMP_Text textComponent = o.GetComponent(); + if (textComponent) + { + Undo.RecordObject(textComponent, "Font Asset Change"); + textComponent.font = requiredFontAsset; + } + } + + TMPro_EventManager.ON_DRAG_AND_DROP_MATERIAL_CHANGED(o, m_Material, droppedMaterial); + EditorUtility.SetDirty(o); + } + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_BaseShaderGUI.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_BaseShaderGUI.cs.meta new file mode 100644 index 00000000..f07bd856 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_BaseShaderGUI.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 438efd46088d408d8a53f707fa68d976 +timeCreated: 1469844810 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_BitmapShaderGUI.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_BitmapShaderGUI.cs new file mode 100644 index 00000000..be399599 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_BitmapShaderGUI.cs @@ -0,0 +1,93 @@ +using UnityEngine; +using UnityEditor; + +namespace TMPro.EditorUtilities +{ + public class TMP_BitmapShaderGUI : TMP_BaseShaderGUI + { + static bool s_Face = true; + + protected override void DoGUI() + { + s_Face = BeginPanel("Face", s_Face); + if (s_Face) + { + DoFacePanel(); + } + + EndPanel(); + + s_DebugExtended = BeginPanel("Debug Settings", s_DebugExtended); + if (s_DebugExtended) + { + DoDebugPanel(); + } + + EndPanel(); + } + + void DoFacePanel() + { + EditorGUI.indentLevel += 1; + if (m_Material.HasProperty(ShaderUtilities.ID_FaceTex)) + { + DoColor("_FaceColor", "Color"); + DoTexture2D("_FaceTex", "Texture", true); + } + else + { + DoColor("_Color", "Color"); + DoSlider("_DiffusePower", "Diffuse Power"); + } + + EditorGUI.indentLevel -= 1; + + EditorGUILayout.Space(); + } + + void DoDebugPanel() + { + EditorGUI.indentLevel += 1; + DoTexture2D("_MainTex", "Font Atlas"); + if (m_Material.HasProperty(ShaderUtilities.ID_VertexOffsetX)) + { + if (m_Material.HasProperty(ShaderUtilities.ID_Padding)) + { + EditorGUILayout.Space(); + DoFloat("_Padding", "Padding"); + } + + EditorGUILayout.Space(); + DoFloat("_VertexOffsetX", "Offset X"); + DoFloat("_VertexOffsetY", "Offset Y"); + } + + if (m_Material.HasProperty(ShaderUtilities.ID_MaskSoftnessX)) + { + EditorGUILayout.Space(); + DoFloat("_MaskSoftnessX", "Softness X"); + DoFloat("_MaskSoftnessY", "Softness Y"); + DoVector("_ClipRect", "Clip Rect", s_LbrtVectorLabels); + } + + if (m_Material.HasProperty(ShaderUtilities.ID_StencilID)) + { + EditorGUILayout.Space(); + DoFloat("_Stencil", "Stencil ID"); + DoFloat("_StencilComp", "Stencil Comp"); + } + + if (m_Material.HasProperty(ShaderUtilities.ShaderTag_CullMode)) + { + EditorGUILayout.Space(); + DoPopup("_CullMode", "Cull Mode", s_CullingTypeLabels); + } + + EditorGUILayout.Space(); + + EditorGUI.indentLevel -= 1; + + EditorGUILayout.Space(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_BitmapShaderGUI.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_BitmapShaderGUI.cs.meta new file mode 100644 index 00000000..6d0e0529 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_BitmapShaderGUI.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 806de5a9211448c8b65c8435ebb48dd4 +timeCreated: 1469998850 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_ColorGradientAssetMenu.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_ColorGradientAssetMenu.cs new file mode 100644 index 00000000..0e232ba5 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_ColorGradientAssetMenu.cs @@ -0,0 +1,47 @@ +using UnityEditor; +using UnityEngine; +using System.IO; + + +namespace TMPro.EditorUtilities +{ + public static class TMP_ColorGradientAssetMenu + { + [MenuItem("Assets/Create/TextMeshPro/Color Gradient", false, 220)] + internal static void CreateColorGradient(MenuCommand context) + { + string filePath; + + if (Selection.assetGUIDs.Length == 0) + filePath = "Assets/New TMP Color Gradient.asset"; + else + filePath = AssetDatabase.GUIDToAssetPath(Selection.assetGUIDs[0]); + + if (Directory.Exists(filePath)) + { + filePath += "/New TMP Color Gradient.asset"; + } + else + { + filePath = Path.GetDirectoryName(filePath) + "/New TMP Color Gradient.asset"; + } + + filePath = AssetDatabase.GenerateUniqueAssetPath(filePath); + + // Create new Color Gradient Asset. + TMP_ColorGradient colorGradient = ScriptableObject.CreateInstance(); + + // Create Asset + AssetDatabase.CreateAsset(colorGradient, filePath); + + //EditorUtility.SetDirty(colorGradient); + + AssetDatabase.SaveAssets(); + + AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(colorGradient)); + + EditorUtility.FocusProjectWindow(); + EditorGUIUtility.PingObject(colorGradient); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_ColorGradientAssetMenu.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_ColorGradientAssetMenu.cs.meta new file mode 100644 index 00000000..a2201ee6 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_ColorGradientAssetMenu.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d9647b571c5e44729b71d756b3d55317 +timeCreated: 1468187791 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_ColorGradientEditor.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_ColorGradientEditor.cs new file mode 100644 index 00000000..ca79435f --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_ColorGradientEditor.cs @@ -0,0 +1,146 @@ +using UnityEngine; +using UnityEditor; +using System.Collections; + + +namespace TMPro.EditorUtilities +{ + [CustomEditor(typeof(TMP_ColorGradient))] + public class TMP_ColorGradientEditor : Editor + { + SerializedProperty m_ColorMode; + SerializedProperty m_TopLeftColor; + SerializedProperty m_TopRightColor; + SerializedProperty m_BottomLeftColor; + SerializedProperty m_BottomRightColor; + + void OnEnable() + { + m_ColorMode = serializedObject.FindProperty("colorMode"); + m_TopLeftColor = serializedObject.FindProperty("topLeft"); + m_TopRightColor = serializedObject.FindProperty("topRight"); + m_BottomLeftColor = serializedObject.FindProperty("bottomLeft"); + m_BottomRightColor = serializedObject.FindProperty("bottomRight"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_ColorMode, new GUIContent("Color Mode")); + if (EditorGUI.EndChangeCheck()) + { + switch ((ColorMode)m_ColorMode.enumValueIndex) + { + case ColorMode.Single: + m_TopRightColor.colorValue = m_TopLeftColor.colorValue; + m_BottomLeftColor.colorValue = m_TopLeftColor.colorValue; + m_BottomRightColor.colorValue = m_TopLeftColor.colorValue; + break; + case ColorMode.HorizontalGradient: + m_BottomLeftColor.colorValue = m_TopLeftColor.colorValue; + m_BottomRightColor.colorValue = m_TopRightColor.colorValue; + break; + case ColorMode.VerticalGradient: + m_TopRightColor.colorValue = m_TopLeftColor.colorValue; + m_BottomRightColor.colorValue = m_BottomLeftColor.colorValue; + break; + } + } + Rect rect; + switch ((ColorMode)m_ColorMode.enumValueIndex) + { + case ColorMode.Single: + EditorGUI.BeginChangeCheck(); + rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight * (EditorGUIUtility.wideMode ? 1 : 2)); + EditorGUI.PrefixLabel(rect, new GUIContent("Colors")); + rect.x += EditorGUIUtility.labelWidth; + rect.width = (rect.width - EditorGUIUtility.labelWidth) / (EditorGUIUtility.wideMode ? 1f : 2f); + TMP_EditorUtility.DrawColorProperty(rect, m_TopLeftColor); + if (EditorGUI.EndChangeCheck()) + { + m_TopRightColor.colorValue = m_TopLeftColor.colorValue; + m_BottomLeftColor.colorValue = m_TopLeftColor.colorValue; + m_BottomRightColor.colorValue = m_TopLeftColor.colorValue; + } + break; + + case ColorMode.HorizontalGradient: + rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight * (EditorGUIUtility.wideMode ? 1 : 2)); + EditorGUI.PrefixLabel(rect, new GUIContent("Colors")); + rect.x += EditorGUIUtility.labelWidth; + rect.width = (rect.width - EditorGUIUtility.labelWidth) / 2f; + + EditorGUI.BeginChangeCheck(); + TMP_EditorUtility.DrawColorProperty(rect, m_TopLeftColor); + if (EditorGUI.EndChangeCheck()) + { + m_BottomLeftColor.colorValue = m_TopLeftColor.colorValue; + } + + rect.x += rect.width; + + EditorGUI.BeginChangeCheck(); + TMP_EditorUtility.DrawColorProperty(rect, m_TopRightColor); + if (EditorGUI.EndChangeCheck()) + { + m_BottomRightColor.colorValue = m_TopRightColor.colorValue; + } + break; + + case ColorMode.VerticalGradient: + rect = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight * (EditorGUIUtility.wideMode ? 1 : 2)); + EditorGUI.PrefixLabel(rect, new GUIContent("Colors")); + rect.x += EditorGUIUtility.labelWidth; + rect.width = (rect.width - EditorGUIUtility.labelWidth) / (EditorGUIUtility.wideMode ? 1f : 2f); + rect.height = EditorGUIUtility.singleLineHeight * (EditorGUIUtility.wideMode ? 1 : 2); + + EditorGUI.BeginChangeCheck(); + TMP_EditorUtility.DrawColorProperty(rect, m_TopLeftColor); + if (EditorGUI.EndChangeCheck()) + { + m_TopRightColor.colorValue = m_TopLeftColor.colorValue; + } + + rect = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight * (EditorGUIUtility.wideMode ? 1 : 2)); + rect.x += EditorGUIUtility.labelWidth; + rect.width = (rect.width - EditorGUIUtility.labelWidth) / (EditorGUIUtility.wideMode ? 1f : 2f); + rect.height = EditorGUIUtility.singleLineHeight * (EditorGUIUtility.wideMode ? 1 : 2); + + EditorGUI.BeginChangeCheck(); + TMP_EditorUtility.DrawColorProperty(rect, m_BottomLeftColor); + if (EditorGUI.EndChangeCheck()) + { + m_BottomRightColor.colorValue = m_BottomLeftColor.colorValue; + } + break; + + case ColorMode.FourCornersGradient: + rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight * (EditorGUIUtility.wideMode ? 1 : 2)); + EditorGUI.PrefixLabel(rect, new GUIContent("Colors")); + rect.x += EditorGUIUtility.labelWidth; + rect.width = (rect.width - EditorGUIUtility.labelWidth) / 2f; + rect.height = EditorGUIUtility.singleLineHeight * (EditorGUIUtility.wideMode ? 1 : 2); + + TMP_EditorUtility.DrawColorProperty(rect, m_TopLeftColor); + rect.x += rect.width; + TMP_EditorUtility.DrawColorProperty(rect, m_TopRightColor); + + rect = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight * (EditorGUIUtility.wideMode ? 1 : 2)); + rect.x += EditorGUIUtility.labelWidth; + rect.width = (rect.width - EditorGUIUtility.labelWidth) / 2f; + rect.height = EditorGUIUtility.singleLineHeight * (EditorGUIUtility.wideMode ? 1 : 2); + + TMP_EditorUtility.DrawColorProperty(rect, m_BottomLeftColor); + rect.x += rect.width; + TMP_EditorUtility.DrawColorProperty(rect, m_BottomRightColor); + break; + } + + if (serializedObject.ApplyModifiedProperties()) + TMPro_EventManager.ON_COLOR_GRADIENT_PROPERTY_CHANGED(target as TMP_ColorGradient); + + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_ColorGradientEditor.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_ColorGradientEditor.cs.meta new file mode 100644 index 00000000..dc58116c --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_ColorGradientEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: fcc60c1d6bb544d9b712b652f418ff3a +timeCreated: 1468400050 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_DropdownEditor.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_DropdownEditor.cs new file mode 100644 index 00000000..5e63fd83 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_DropdownEditor.cs @@ -0,0 +1,60 @@ +using UnityEngine; +using UnityEditor; +using UnityEditor.UI; +using UnityEngine.UI; + +namespace TMPro.EditorUtilities +{ + [CustomEditor(typeof(TMP_Dropdown), true)] + [CanEditMultipleObjects] + public class DropdownEditor : SelectableEditor + { + SerializedProperty m_Template; + SerializedProperty m_CaptionText; + SerializedProperty m_CaptionImage; + SerializedProperty m_Placeholder; + SerializedProperty m_ItemText; + SerializedProperty m_ItemImage; + SerializedProperty m_OnSelectionChanged; + SerializedProperty m_Value; + SerializedProperty m_MultiSelect; + SerializedProperty m_AlphaFadeSpeed; + SerializedProperty m_Options; + + protected override void OnEnable() + { + base.OnEnable(); + m_Template = serializedObject.FindProperty("m_Template"); + m_CaptionText = serializedObject.FindProperty("m_CaptionText"); + m_CaptionImage = serializedObject.FindProperty("m_CaptionImage"); + m_Placeholder = serializedObject.FindProperty("m_Placeholder"); + m_ItemText = serializedObject.FindProperty("m_ItemText"); + m_ItemImage = serializedObject.FindProperty("m_ItemImage"); + m_OnSelectionChanged = serializedObject.FindProperty("m_OnValueChanged"); + m_Value = serializedObject.FindProperty("m_Value"); + m_MultiSelect = serializedObject.FindProperty("m_MultiSelect"); + m_AlphaFadeSpeed = serializedObject.FindProperty("m_AlphaFadeSpeed"); + m_Options = serializedObject.FindProperty("m_Options"); + } + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + EditorGUILayout.Space(); + + serializedObject.Update(); + EditorGUILayout.PropertyField(m_Template); + EditorGUILayout.PropertyField(m_CaptionText); + EditorGUILayout.PropertyField(m_CaptionImage); + EditorGUILayout.PropertyField(m_Placeholder); + EditorGUILayout.PropertyField(m_ItemText); + EditorGUILayout.PropertyField(m_ItemImage); + EditorGUILayout.PropertyField(m_Value); + EditorGUILayout.PropertyField(m_MultiSelect); + EditorGUILayout.PropertyField(m_AlphaFadeSpeed); + EditorGUILayout.PropertyField(m_Options); + EditorGUILayout.PropertyField(m_OnSelectionChanged); + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_DropdownEditor.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_DropdownEditor.cs.meta new file mode 100644 index 00000000..75030cfd --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_DropdownEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6dbcf248c987476181a37f01a1814975 +timeCreated: 1446377461 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_EditorCoroutine.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_EditorCoroutine.cs new file mode 100644 index 00000000..e0056039 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_EditorCoroutine.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + + +namespace TMPro.EditorUtilities +{ + /// + /// Simple implementation of coroutine working in the Unity Editor. + /// + public class TMP_EditorCoroutine + { + //private static Dictionary s_ActiveCoroutines; + + readonly IEnumerator coroutine; + + /// + /// Constructor + /// + /// + TMP_EditorCoroutine(IEnumerator routine) + { + this.coroutine = routine; + } + + + /// + /// Starts a new EditorCoroutine. + /// + /// Coroutine + /// new EditorCoroutine + public static TMP_EditorCoroutine StartCoroutine(IEnumerator routine) + { + TMP_EditorCoroutine coroutine = new TMP_EditorCoroutine(routine); + coroutine.Start(); + + // Add coroutine to tracking list + //if (s_ActiveCoroutines == null) + // s_ActiveCoroutines = new Dictionary(); + + // Add new instance of editor coroutine to dictionary. + //s_ActiveCoroutines.Add(coroutine.GetHashCode(), coroutine); + + return coroutine; + } + + + /// + /// Clear delegate list + /// + //public static void StopAllEditorCoroutines() + //{ + // EditorApplication.update = null; + //} + + + /// + /// Register callback for editor updates + /// + void Start() + { + EditorApplication.update += EditorUpdate; + } + + + /// + /// Unregister callback for editor updates. + /// + public void Stop() + { + if (EditorApplication.update != null) + EditorApplication.update -= EditorUpdate; + + //s_ActiveCoroutines.Remove(this.GetHashCode()); + } + + + /// + /// Delegate function called on editor updates. + /// + void EditorUpdate() + { + // Stop editor coroutine if it does not continue. + if (coroutine.MoveNext() == false) + Stop(); + + // Process the different types of EditorCoroutines. + if (coroutine.Current != null) + { + + } + } + } +} \ No newline at end of file diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_EditorCoroutine.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_EditorCoroutine.cs.meta new file mode 100644 index 00000000..16e03fa8 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_EditorCoroutine.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 27a0335dab59ec542aadd6636a5b4ebd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_EditorPanel.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_EditorPanel.cs new file mode 100644 index 00000000..45265c68 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_EditorPanel.cs @@ -0,0 +1,202 @@ +using UnityEngine; +using UnityEditor; + + +namespace TMPro.EditorUtilities +{ + + [CustomEditor(typeof(TextMeshPro), true), CanEditMultipleObjects] + public class TMP_EditorPanel : TMP_BaseEditorPanel + { + static readonly GUIContent k_SortingLayerLabel = new GUIContent("Sorting Layer", "Name of the Renderer's sorting layer."); + static readonly GUIContent k_OrderInLayerLabel = new GUIContent("Order in Layer", "Renderer's order within a sorting layer."); + static readonly GUIContent k_OrthographicLabel = new GUIContent("Orthographic Mode", "Should be enabled when using an orthographic camera. Instructs the shader to not perform any perspective correction."); + static readonly GUIContent k_VolumetricLabel = new GUIContent("Volumetric Setup", "Use cubes rather than quads to render the text. Allows for volumetric rendering when combined with a compatible shader."); + + private static string[] k_SortingLayerNames; + bool IsPreset; + + SerializedProperty m_IsVolumetricTextProp; + SerializedProperty m_IsOrthographicProp; + Object[] m_Renderers; + + SerializedObject m_RendererSerializedObject; + SerializedProperty m_RendererSortingLayerProp; + SerializedProperty m_RendererSortingLayerIDProp; + SerializedProperty m_RendererSortingOrderProp; + + SerializedProperty m_TextSortingLayerProp; + SerializedProperty m_TextSortingLayerIDProp; + SerializedProperty m_TextSortingOrderProp; + + + protected override void OnEnable() + { + base.OnEnable(); + + // Determine if the inspected object is a Preset + IsPreset = (int)(target as Component).gameObject.hideFlags == 93; + + m_IsOrthographicProp = serializedObject.FindProperty("m_isOrthographic"); + + m_IsVolumetricTextProp = serializedObject.FindProperty("m_isVolumetricText"); + + m_Renderers = new Object[targets.Length]; + for (int i = 0; i < m_Renderers.Length; i++) + m_Renderers[i] = (targets[i] as TextMeshPro)?.GetComponent(); + + m_RendererSerializedObject = new SerializedObject(m_Renderers); + m_RendererSortingLayerProp = m_RendererSerializedObject.FindProperty("m_SortingLayer"); + m_RendererSortingLayerIDProp = m_RendererSerializedObject.FindProperty("m_SortingLayerID"); + m_RendererSortingOrderProp = m_RendererSerializedObject.FindProperty("m_SortingOrder"); + + m_TextSortingLayerProp = serializedObject.FindProperty("_SortingLayer"); + m_TextSortingLayerIDProp = serializedObject.FindProperty("_SortingLayerID"); + m_TextSortingOrderProp = serializedObject.FindProperty("_SortingOrder"); + + // Populate Sorting Layer Names + k_SortingLayerNames = SortingLayerHelper.sortingLayerNames; + } + + protected override void DrawExtraSettings() + { + Rect rect = EditorGUILayout.GetControlRect(false, 24); + + if (GUI.Button(rect, new GUIContent("Extra Settings"), TMP_UIStyleManager.sectionHeader)) + Foldout.extraSettings = !Foldout.extraSettings; + + GUI.Label(rect, (Foldout.extraSettings ? "" : k_UiStateLabel[1]), TMP_UIStyleManager.rightLabel); + + if (Foldout.extraSettings) + { + + DrawMargins(); + + DrawSortingLayer(); + + DrawGeometrySorting(); + + DrawIsTextObjectScaleStatic(); + + DrawOrthographicMode(); + + DrawRichText(); + + DrawParsing(); + + DrawEmojiFallbackSupport(); + + DrawSpriteAsset(); + + DrawStyleSheet(); + + DrawFontFeatures(); + + DrawPadding(); + + } + } + + private void DrawSortingLayer() + { + m_RendererSerializedObject.Update(); + + Rect rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight); + + // Special handling for Presets where the sorting layer, id and order is serialized with the text object instead of on the MeshRenderer. + SerializedProperty sortingLayerProp = IsPreset ? m_TextSortingLayerProp : m_RendererSortingLayerProp; + SerializedProperty sortingLayerIDProp = IsPreset ? m_TextSortingLayerIDProp : m_RendererSortingLayerIDProp; + + EditorGUI.BeginProperty(rect, k_SortingLayerLabel, sortingLayerIDProp); + EditorGUI.BeginChangeCheck(); + + int currentLayerIndex = SortingLayerHelper.GetSortingLayerIndexFromSortingLayerID(sortingLayerIDProp.intValue); + int newLayerIndex = EditorGUI.Popup(rect, k_SortingLayerLabel, currentLayerIndex, k_SortingLayerNames); + + if (EditorGUI.EndChangeCheck()) + { + sortingLayerIDProp.intValue = SortingLayer.NameToID(k_SortingLayerNames[newLayerIndex]); + sortingLayerProp.intValue = SortingLayer.GetLayerValueFromName(k_SortingLayerNames[newLayerIndex]); + m_HavePropertiesChanged = true; + + // Sync Sorting Layer ID change on potential sub text object. + TextMeshPro textComponent = m_TextComponent as TextMeshPro; + textComponent.UpdateSubMeshSortingLayerID(sortingLayerIDProp.intValue); + } + + EditorGUI.EndProperty(); + + // Sorting Order + SerializedProperty sortingOrderLayerProp = IsPreset ? m_TextSortingOrderProp : m_RendererSortingOrderProp; + + EditorGUI.BeginChangeCheck(); + + EditorGUILayout.PropertyField(sortingOrderLayerProp, k_OrderInLayerLabel); + + if (EditorGUI.EndChangeCheck()) + { + m_HavePropertiesChanged = true; + + TextMeshPro textComponent = m_TextComponent as TextMeshPro; + textComponent.UpdateSubMeshSortingOrder(sortingOrderLayerProp.intValue); + } + + m_RendererSerializedObject.ApplyModifiedProperties(); + + EditorGUILayout.Space(); + } + + private void DrawOrthographicMode() + { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_IsOrthographicProp, k_OrthographicLabel); + if (EditorGUI.EndChangeCheck()) + m_HavePropertiesChanged = true; + } + + protected void DrawVolumetricSetup() + { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_IsVolumetricTextProp, k_VolumetricLabel); + if (EditorGUI.EndChangeCheck()) + { + m_HavePropertiesChanged = true; + m_TextComponent.textInfo.ResetVertexLayout(m_IsVolumetricTextProp.boolValue); + } + + EditorGUILayout.Space(); + } + + // Method to handle multi object selection + protected override bool IsMixSelectionTypes() + { + GameObject[] objects = Selection.gameObjects; + if (objects.Length > 1) + { + for (int i = 0; i < objects.Length; i++) + { + if (objects[i].GetComponent() == null) + return true; + } + } + return false; + } + + protected override void OnUndoRedo() + { + int undoEventId = Undo.GetCurrentGroup(); + int lastUndoEventId = s_EventId; + + if (undoEventId != lastUndoEventId) + { + for (int i = 0; i < targets.Length; i++) + { + //Debug.Log("Undo & Redo Performed detected in Editor Panel. Event ID:" + Undo.GetCurrentGroup()); + TMPro_EventManager.ON_TEXTMESHPRO_PROPERTY_CHANGED(true, targets[i] as TextMeshPro); + s_EventId = undoEventId; + } + } + } + + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_EditorPanel.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_EditorPanel.cs.meta new file mode 100644 index 00000000..54fd8048 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_EditorPanel.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 34f6695d37a94370a3697f6b068f5d5e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_EditorPanelUI.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_EditorPanelUI.cs new file mode 100644 index 00000000..2b22a033 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_EditorPanelUI.cs @@ -0,0 +1,127 @@ +using UnityEngine; +using UnityEngine.UI; +using UnityEditor; + +namespace TMPro.EditorUtilities +{ + + [CustomEditor(typeof(TextMeshProUGUI), true), CanEditMultipleObjects] + public class TMP_EditorPanelUI : TMP_BaseEditorPanel + { + static readonly GUIContent k_RaycastTargetLabel = new GUIContent("Raycast Target", "Whether the text blocks raycasts from the Graphic Raycaster."); + static readonly GUIContent k_MaskableLabel = new GUIContent("Maskable", "Determines if the text object will be affected by UI Mask."); + + SerializedProperty m_RaycastTargetProp; + private SerializedProperty m_MaskableProp; + + protected override void OnEnable() + { + base.OnEnable(); + m_RaycastTargetProp = serializedObject.FindProperty("m_RaycastTarget"); + m_MaskableProp = serializedObject.FindProperty("m_Maskable"); + } + + protected override void DrawExtraSettings() + { + Rect rect = EditorGUILayout.GetControlRect(false, 24); + + if (GUI.Button(rect, new GUIContent("Extra Settings"), TMP_UIStyleManager.sectionHeader)) + Foldout.extraSettings = !Foldout.extraSettings; + + GUI.Label(rect, (Foldout.extraSettings ? k_UiStateLabel[0] : k_UiStateLabel[1]), TMP_UIStyleManager.rightLabel); + if (Foldout.extraSettings) + { + + DrawMargins(); + + DrawGeometrySorting(); + + DrawIsTextObjectScaleStatic(); + + DrawRichText(); + + DrawRaycastTarget(); + + DrawMaskable(); + + DrawParsing(); + + DrawEmojiFallbackSupport(); + + DrawSpriteAsset(); + + DrawStyleSheet(); + + DrawFontFeatures(); + + DrawPadding(); + + } + } + + protected void DrawRaycastTarget() + { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_RaycastTargetProp, k_RaycastTargetLabel); + if (EditorGUI.EndChangeCheck()) + { + // Change needs to propagate to the child sub objects. + Graphic[] graphicComponents = m_TextComponent.GetComponentsInChildren(); + for (int i = 1; i < graphicComponents.Length; i++) + graphicComponents[i].raycastTarget = m_RaycastTargetProp.boolValue; + + m_HavePropertiesChanged = true; + } + } + + protected void DrawMaskable() + { + if (m_MaskableProp == null) + return; + + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_MaskableProp, k_MaskableLabel); + if (EditorGUI.EndChangeCheck()) + { + m_TextComponent.maskable = m_MaskableProp.boolValue; + + // Change needs to propagate to the child sub objects. + MaskableGraphic[] maskableGraphics = m_TextComponent.GetComponentsInChildren(); + for (int i = 1; i < maskableGraphics.Length; i++) + maskableGraphics[i].maskable = m_MaskableProp.boolValue; + + m_HavePropertiesChanged = true; + } + } + + // Method to handle multi object selection + protected override bool IsMixSelectionTypes() + { + GameObject[] objects = Selection.gameObjects; + if (objects.Length > 1) + { + for (int i = 0; i < objects.Length; i++) + { + if (objects[i].GetComponent() == null) + return true; + } + } + return false; + } + protected override void OnUndoRedo() + { + int undoEventId = Undo.GetCurrentGroup(); + int lastUndoEventId = s_EventId; + + if (undoEventId != lastUndoEventId) + { + for (int i = 0; i < targets.Length; i++) + { + //Debug.Log("Undo & Redo Performed detected in Editor Panel. Event ID:" + Undo.GetCurrentGroup()); + TMPro_EventManager.ON_TEXTMESHPRO_UGUI_PROPERTY_CHANGED(true, targets[i] as TextMeshProUGUI); + s_EventId = undoEventId; + } + } + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_EditorPanelUI.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_EditorPanelUI.cs.meta new file mode 100644 index 00000000..ea3b36b3 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_EditorPanelUI.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 21c0044a7f964773be90d197a78e4703 +timeCreated: 1443571501 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_EditorResourceManager.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_EditorResourceManager.cs new file mode 100644 index 00000000..c63485d7 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_EditorResourceManager.cs @@ -0,0 +1,295 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEditor; +using UnityEditor.TextCore.LowLevel; + + +namespace TMPro +{ + static class EditorEventCallbacks + { + [InitializeOnLoadMethod] + internal static void InitializeFontAssetResourceChangeCallBacks() + { + TMP_FontAsset.RegisterResourceForUpdate += TMP_EditorResourceManager.RegisterResourceForUpdate; + TMP_FontAsset.RegisterResourceForReimport += TMP_EditorResourceManager.RegisterResourceForReimport; + TMP_FontAsset.OnFontAssetTextureChanged += TMP_EditorResourceManager.AddTextureToAsset; + TMP_FontAsset.SetAtlasTextureIsReadable += FontEngineEditorUtilities.SetAtlasTextureIsReadable; + TMP_FontAsset.GetSourceFontRef += TMP_EditorResourceManager.GetSourceFontRef; + TMP_FontAsset.SetSourceFontGUID += TMP_EditorResourceManager.SetSourceFontGUID; + + // Callback to handle clearing dynamic font asset data when closing the Editor + EditorApplication.quitting += () => + { + // Find all font assets in the project + string searchPattern = "t:TMP_FontAsset"; + string[] fontAssetGUIDs = AssetDatabase.FindAssets(searchPattern); + + for (int i = 0; i < fontAssetGUIDs.Length; i++) + { + string fontAssetPath = AssetDatabase.GUIDToAssetPath(fontAssetGUIDs[i]); + TMP_FontAsset fontAsset = AssetDatabase.LoadAssetAtPath(fontAssetPath); + + if (fontAsset != null && (fontAsset.atlasPopulationMode == AtlasPopulationMode.Dynamic || fontAsset.atlasPopulationMode == AtlasPopulationMode.DynamicOS) && fontAsset.clearDynamicDataOnBuild && fontAsset.atlasTexture.width > 1) + { + Debug.Log("Clearing [" + fontAsset.name + "] dynamic font asset data."); + fontAsset.ClearCharacterAndGlyphTablesInternal(); + } + } + }; + } + } + + internal class TMP_EditorResourceManager + { + private static TMP_EditorResourceManager s_Instance; + + private readonly List m_ObjectUpdateQueue = new List(); + private HashSet m_ObjectUpdateQueueLookup = new HashSet(); + + private readonly List m_ObjectReImportQueue = new List(); + private HashSet m_ObjectReImportQueueLookup = new HashSet(); + + private readonly List m_FontAssetDefinitionRefreshQueue = new List(); + private HashSet m_FontAssetDefinitionRefreshQueueLookup = new HashSet(); + + /// + /// Get a singleton instance of the manager. + /// + internal static TMP_EditorResourceManager instance + { + get + { + if (s_Instance == null) + s_Instance = new TMP_EditorResourceManager(); + + return s_Instance; + } + } + + /// + /// Register to receive rendering callbacks. + /// + private TMP_EditorResourceManager() + { + // Register to the appropriate callback for the given render pipeline. + if (RenderPipelineManager.currentPipeline == null) + Camera.onPostRender += OnCameraPostRender; + else + { + #if UNITY_2023_3_OR_NEWER + RenderPipelineManager.endContextRendering += OnEndOfFrame; + #else + RenderPipelineManager.endFrameRendering += OnEndOfFrame; + #endif + } + + Canvas.willRenderCanvases += OnPreRenderCanvases; + } + + void OnCameraPostRender(Camera cam) + { + // Exclude the PreRenderCamera + if (cam.cameraType != CameraType.SceneView) + return; + + DoPostRenderUpdates(); + } + + void OnPreRenderCanvases() + { + DoPreRenderUpdates(); + } + + #if UNITY_2023_3_OR_NEWER + void OnEndOfFrame(ScriptableRenderContext renderContext, List cameras) + { + DoPostRenderUpdates(); + } + #else + void OnEndOfFrame(ScriptableRenderContext renderContext, Camera[] cameras) + { + DoPostRenderUpdates(); + } + #endif + + /// + /// Register resource for re-import. + /// + /// + internal static void RegisterResourceForReimport(Object obj) + { + // Return if referenced object is not a persistent asset + if (!EditorUtility.IsPersistent(obj)) + return; + + instance.InternalRegisterResourceForReimport(obj); + } + + private void InternalRegisterResourceForReimport(Object obj) + { + int id = obj.GetInstanceID(); + + if (m_ObjectReImportQueueLookup.Contains(id)) + return; + + m_ObjectReImportQueueLookup.Add(id); + m_ObjectReImportQueue.Add(obj); + } + + /// + /// Register resource to be updated. + /// + /// + internal static void RegisterResourceForUpdate(Object obj) + { + // Return if referenced object is not a persistent asset + if (!EditorUtility.IsPersistent(obj)) + return; + + instance.InternalRegisterResourceForUpdate(obj); + } + + private void InternalRegisterResourceForUpdate(Object obj) + { + int id = obj.GetInstanceID(); + + if (m_ObjectUpdateQueueLookup.Contains(id)) + return; + + m_ObjectUpdateQueueLookup.Add(id); + m_ObjectUpdateQueue.Add(obj); + } + + /// + /// + /// + /// + internal static void RegisterFontAssetForDefinitionRefresh(TMP_FontAsset fontAsset) + { + instance.InternalRegisterFontAssetForDefinitionRefresh(fontAsset); + } + + private void InternalRegisterFontAssetForDefinitionRefresh(TMP_FontAsset fontAsset) + { + int id = fontAsset.GetInstanceID(); + + if (m_FontAssetDefinitionRefreshQueueLookup.Contains(id)) + return; + + m_FontAssetDefinitionRefreshQueueLookup.Add(id); + m_FontAssetDefinitionRefreshQueue.Add(fontAsset); + } + + /// + /// Add texture as sub asset to the referenced object. + /// + /// The texture to be added as sub object. + /// The object to which this texture sub object will be added. + internal static void AddTextureToAsset(Texture tex, Object obj) + { + // Return if referenced object is not a persistent asset + if (!EditorUtility.IsPersistent(obj)) + return; + + if (tex != null) + AssetDatabase.AddObjectToAsset(tex, obj); + + RegisterResourceForReimport(obj); + } + + /// + /// + /// + /// + /// + internal static Font GetSourceFontRef(string guid) + { + string path = AssetDatabase.GUIDToAssetPath(guid); + return AssetDatabase.LoadAssetAtPath(path); + } + + /// + /// + /// + /// + /// + internal static string SetSourceFontGUID(Font font) + { + return AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(font)); + } + + void DoPostRenderUpdates() + { + // Handle objects that need updating + int objUpdateCount = m_ObjectUpdateQueue.Count; + + for (int i = 0; i < objUpdateCount; i++) + { + EditorUtilities.TMP_PropertyDrawerUtilities.s_RefreshGlyphProxyLookup = true; + #if TEXTCORE_FONT_ENGINE_1_5_OR_NEWER + UnityEditor.TextCore.Text.TextCorePropertyDrawerUtilities.s_RefreshGlyphProxyLookup = true; + #endif + + Object obj = m_ObjectUpdateQueue[i]; + if (obj != null) + { + //EditorUtility.SetDirty(obj); + } + } + + if (objUpdateCount > 0) + { + //Debug.Log("Saving assets"); + //AssetDatabase.SaveAssets(); + + m_ObjectUpdateQueue.Clear(); + m_ObjectUpdateQueueLookup.Clear(); + } + + // Handle objects that need re-importing + int objReImportCount = m_ObjectReImportQueue.Count; + + for (int i = 0; i < objReImportCount; i++) + { + Object obj = m_ObjectReImportQueue[i]; + if (obj != null) + { + string assetPath = AssetDatabase.GetAssetPath(obj); + + // Exclude Assets not located in the project + if (assetPath.StartsWith("Assets/", System.StringComparison.OrdinalIgnoreCase)) + AssetDatabase.ImportAsset(assetPath); + } + } + + if (objReImportCount > 0) + { + m_ObjectReImportQueue.Clear(); + m_ObjectReImportQueueLookup.Clear(); + } + } + + void DoPreRenderUpdates() + { + // Handle Font Asset Definition Refresh + for (int i = 0; i < m_FontAssetDefinitionRefreshQueue.Count; i++) + { + TMP_FontAsset fontAsset = m_FontAssetDefinitionRefreshQueue[i]; + + if (fontAsset != null) + { + fontAsset.ReadFontAssetDefinition(); + TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(true, fontAsset); + } + } + + if (m_FontAssetDefinitionRefreshQueue.Count > 0) + { + m_FontAssetDefinitionRefreshQueue.Clear(); + m_FontAssetDefinitionRefreshQueueLookup.Clear(); + } + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_EditorResourceManager.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_EditorResourceManager.cs.meta new file mode 100644 index 00000000..0759a53a --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_EditorResourceManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6b259c4003a802847b9ada90744e34c5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_EditorUtility.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_EditorUtility.cs new file mode 100644 index 00000000..f5faa6e4 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_EditorUtility.cs @@ -0,0 +1,437 @@ +using UnityEngine; +using UnityEditor; +using System.Text; +using System.IO; +using System.Collections; +using System.Collections.Generic; + + +namespace TMPro.EditorUtilities +{ + public static class TMP_EditorUtility + { + /// + /// Returns the relative path of the package. + /// + public static string packageRelativePath + { + get + { + if (string.IsNullOrEmpty(m_PackagePath)) + m_PackagePath = GetPackageRelativePath(); + + return m_PackagePath; + } + } + [SerializeField] + private static string m_PackagePath; + + /// + /// Returns the fully qualified path of the package. + /// + public static string packageFullPath + { + get + { + if (string.IsNullOrEmpty(m_PackageFullPath)) + m_PackageFullPath = GetPackageFullPath(); + + return m_PackageFullPath; + } + } + [SerializeField] + private static string m_PackageFullPath; + + // Static Fields Related to locating the TextMesh Pro Asset + private static string folderPath = "Not Found"; + + private static EditorWindow Gameview; + private static bool isInitialized = false; + + private static void GetGameview() + { + System.Reflection.Assembly assembly = typeof(UnityEditor.EditorWindow).Assembly; + System.Type type = assembly.GetType("UnityEditor.GameView"); + Gameview = EditorWindow.GetWindow(type); + } + + + internal static void RepaintAll() + { + if (isInitialized == false) + { + GetGameview(); + isInitialized = true; + } + + SceneView.RepaintAll(); + Gameview.Repaint(); + } + + + /// + /// Create and return a new asset in a smart location based on the current selection and then select it. + /// + /// + /// Name of the new asset. Do not include the .asset extension. + /// + /// + /// The new asset. + /// + internal static T CreateAsset(string name) where T : ScriptableObject + { + string path = AssetDatabase.GetAssetPath(Selection.activeObject); + if (path.Length == 0) + { + // no asset selected, place in asset root + path = "Assets/" + name + ".asset"; + } + else if (Directory.Exists(path)) + { + // place in currently selected directory + path += "/" + name + ".asset"; + } + else { + // place in current selection's containing directory + path = Path.GetDirectoryName(path) + "/" + name + ".asset"; + } + T asset = ScriptableObject.CreateInstance(); + AssetDatabase.CreateAsset(asset, AssetDatabase.GenerateUniqueAssetPath(path)); + EditorUtility.FocusProjectWindow(); + Selection.activeObject = asset; + return asset; + } + + + + // Function used to find all materials which reference a font atlas so we can update all their references. + internal static Material[] FindMaterialReferences(TMP_FontAsset fontAsset) + { + List refs = new List(); + Material mat = fontAsset.material; + refs.Add(mat); + + // Get materials matching the search pattern. + string searchPattern = "t:Material" + " " + fontAsset.name.Split(new char[] { ' ' })[0]; + string[] materialAssetGUIDs = AssetDatabase.FindAssets(searchPattern); + + for (int i = 0; i < materialAssetGUIDs.Length; i++) + { + string materialPath = AssetDatabase.GUIDToAssetPath(materialAssetGUIDs[i]); + Material targetMaterial = AssetDatabase.LoadAssetAtPath(materialPath); + + if (targetMaterial.HasProperty(ShaderUtilities.ID_MainTex) && targetMaterial.GetTexture(ShaderUtilities.ID_MainTex) != null && mat.GetTexture(ShaderUtilities.ID_MainTex) != null && targetMaterial.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID() == mat.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID()) + { + if (!refs.Contains(targetMaterial)) + refs.Add(targetMaterial); + } + else + { + // TODO: Find a more efficient method to unload resources. + //Resources.UnloadAsset(targetMaterial.GetTexture(ShaderUtilities.ID_MainTex)); + } + } + + return refs.ToArray(); + } + + + // Function used to find the Font Asset which matches the given Material Preset and Font Atlas Texture. + internal static TMP_FontAsset FindMatchingFontAsset(Material mat) + { + if (mat.GetTexture(ShaderUtilities.ID_MainTex) == null) return null; + + // Find the dependent assets of this material. + string[] dependentAssets = AssetDatabase.GetDependencies(AssetDatabase.GetAssetPath(mat), false); + + for (int i = 0; i < dependentAssets.Length; i++) + { + TMP_FontAsset fontAsset = AssetDatabase.LoadAssetAtPath(dependentAssets[i]); + if (fontAsset != null) + return fontAsset; + } + + return null; + } + + + private static string GetPackageRelativePath() + { + // Check for potential UPM package + string packagePath = Path.GetFullPath("Packages/com.unity.ugui"); + if (Directory.Exists(packagePath)) + { + return "Packages/com.unity.ugui"; + } + + packagePath = Path.GetFullPath("Assets/.."); + if (Directory.Exists(packagePath)) + { + // Search default location for development package + if (Directory.Exists(packagePath + "/Assets/Packages/com.unity.ugui/Editor Resources")) + { + return "Assets/Packages/com.unity.ugui"; + } + + // Search for potential alternative locations in the user project + string[] matchingPaths = Directory.GetDirectories(packagePath, "TextMesh Pro", SearchOption.AllDirectories); + packagePath = ValidateLocation(matchingPaths, packagePath); + if (packagePath != null) return packagePath; + } + + return null; + } + + private static string GetPackageFullPath() + { + // Check for potential UPM package + string packagePath = Path.GetFullPath("Packages/com.unity.ugui"); + if (Directory.Exists(packagePath)) + { + return packagePath; + } + + packagePath = Path.GetFullPath("Assets/.."); + if (Directory.Exists(packagePath)) + { + // Search default location for development package + if (Directory.Exists(packagePath + "/Assets/Packages/com.unity.ugui/Editor Resources")) + { + return packagePath + "/Assets/Packages/com.unity.ugui"; + } + + // Search for potential alternative locations in the user project + string[] matchingPaths = Directory.GetDirectories(packagePath, "TextMesh Pro", SearchOption.AllDirectories); + string path = ValidateLocation(matchingPaths, packagePath); + if (path != null) return packagePath + path; + } + + return null; + } + + + /// + /// Method to validate the location of the asset folder by making sure the GUISkins folder exists. + /// + /// + /// + private static string ValidateLocation(string[] paths, string projectPath) + { + for (int i = 0; i < paths.Length; i++) + { + // Check if any of the matching directories contain a GUISkins directory. + if (Directory.Exists(paths[i] + "/Editor Resources")) + { + folderPath = paths[i].Replace(projectPath, ""); + folderPath = folderPath.TrimStart('\\', '/'); + return folderPath; + } + } + + return null; + } + + + /// + /// Function which returns a string containing a sequence of Decimal character ranges. + /// + /// + /// + internal static string GetDecimalCharacterSequence(int[] characterSet) + { + if (characterSet == null || characterSet.Length == 0) + return string.Empty; + + string characterSequence = string.Empty; + int count = characterSet.Length; + int first = characterSet[0]; + int last = first; + + for (int i = 1; i < count; i++) + { + if (characterSet[i - 1] + 1 == characterSet[i]) + { + last = characterSet[i]; + } + else + { + if (first == last) + characterSequence += first + ","; + else + characterSequence += first + "-" + last + ","; + + first = last = characterSet[i]; + } + + } + + // handle the final group + if (first == last) + characterSequence += first; + else + characterSequence += first + "-" + last; + + return characterSequence; + } + + + /// + /// Function which returns a string containing a sequence of Unicode (Hex) character ranges. + /// + /// + /// + internal static string GetUnicodeCharacterSequence(int[] characterSet) + { + if (characterSet == null || characterSet.Length == 0) + return string.Empty; + + string characterSequence = string.Empty; + int count = characterSet.Length; + int first = characterSet[0]; + int last = first; + + for (int i = 1; i < count; i++) + { + if (characterSet[i - 1] + 1 == characterSet[i]) + { + last = characterSet[i]; + } + else + { + if (first == last) + characterSequence += first.ToString("X2") + ","; + else + characterSequence += first.ToString("X2") + "-" + last.ToString("X2") + ","; + + first = last = characterSet[i]; + } + + } + + // handle the final group + if (first == last) + characterSequence += first.ToString("X2"); + else + characterSequence += first.ToString("X2") + "-" + last.ToString("X2"); + + return characterSequence; + } + + + /// + /// + /// + /// + /// + /// + internal static void DrawBox(Rect rect, float thickness, Color color) + { + EditorGUI.DrawRect(new Rect(rect.x - thickness, rect.y + thickness, rect.width + thickness * 2, thickness), color); + EditorGUI.DrawRect(new Rect(rect.x - thickness, rect.y + thickness, thickness, rect.height - thickness * 2), color); + EditorGUI.DrawRect(new Rect(rect.x - thickness, rect.y + rect.height - thickness * 2, rect.width + thickness * 2, thickness), color); + EditorGUI.DrawRect(new Rect(rect.x + rect.width, rect.y + thickness, thickness, rect.height - thickness * 2), color); + } + + + /// + /// Function to return the horizontal alignment grid value. + /// + /// + /// + internal static int GetHorizontalAlignmentGridValue(int value) + { + if ((value & 0x1) == 0x1) + return 0; + else if ((value & 0x2) == 0x2) + return 1; + else if ((value & 0x4) == 0x4) + return 2; + else if ((value & 0x8) == 0x8) + return 3; + else if ((value & 0x10) == 0x10) + return 4; + else if ((value & 0x20) == 0x20) + return 5; + + return 0; + } + + /// + /// Function to return the vertical alignment grid value. + /// + /// + /// + internal static int GetVerticalAlignmentGridValue(int value) + { + if ((value & 0x100) == 0x100) + return 0; + if ((value & 0x200) == 0x200) + return 1; + if ((value & 0x400) == 0x400) + return 2; + if ((value & 0x800) == 0x800) + return 3; + if ((value & 0x1000) == 0x1000) + return 4; + if ((value & 0x2000) == 0x2000) + return 5; + + return 0; + } + + internal static void DrawColorProperty(Rect rect, SerializedProperty property) + { + int oldIndent = EditorGUI.indentLevel; + EditorGUI.indentLevel = 0; + if (EditorGUIUtility.wideMode) + { + EditorGUI.PropertyField(new Rect(rect.x, rect.y, 50f, rect.height), property, GUIContent.none); + rect.x += 50f; + rect.width = Mathf.Min(100f, rect.width - 55f); + } + else + { + rect.height /= 2f; + rect.width = Mathf.Min(100f, rect.width - 5f); + EditorGUI.PropertyField(rect, property, GUIContent.none); + rect.y += rect.height; + } + + EditorGUI.BeginChangeCheck(); + string colorString = EditorGUI.TextField(rect, string.Format("#{0}", ColorUtility.ToHtmlStringRGBA(property.colorValue))); + if (EditorGUI.EndChangeCheck()) + { + Color color; + if (ColorUtility.TryParseHtmlString(colorString, out color)) + { + property.colorValue = color; + } + } + EditorGUI.indentLevel = oldIndent; + } + + internal static bool EditorToggle(Rect position, bool value, GUIContent content, GUIStyle style) + { + var id = GUIUtility.GetControlID(content, FocusType.Keyboard, position); + var evt = Event.current; + + // Toggle selected toggle on space or return key + if (GUIUtility.keyboardControl == id && evt.type == EventType.KeyDown && (evt.keyCode == KeyCode.Space || evt.keyCode == KeyCode.Return || evt.keyCode == KeyCode.KeypadEnter)) + { + value = !value; + evt.Use(); + GUI.changed = true; + } + + if (evt.type == EventType.MouseDown && position.Contains(Event.current.mousePosition)) + { + GUIUtility.keyboardControl = id; + EditorGUIUtility.editingTextField = false; + HandleUtility.Repaint(); + } + + return GUI.Toggle(position, id, value, content, style); + } + + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_EditorUtility.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_EditorUtility.cs.meta new file mode 100644 index 00000000..5088b1bd --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_EditorUtility.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 2300e75732d74890b38a8ff257a3ae15 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_FontAssetEditor.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_FontAssetEditor.cs new file mode 100644 index 00000000..03175494 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_FontAssetEditor.cs @@ -0,0 +1,3000 @@ +using UnityEngine; +using UnityEditor; +using UnityEditorInternal; +using System.Collections.Generic; +using JetBrains.Annotations; +using UnityEngine.TextCore; +using UnityEngine.TextCore.LowLevel; +using UnityEditor.TextCore.LowLevel; + + +namespace TMPro.EditorUtilities +{ + + [CustomPropertyDrawer(typeof(TMP_FontWeightPair))] + public class FontWeightDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + SerializedProperty prop_regular = property.FindPropertyRelative("regularTypeface"); + SerializedProperty prop_italic = property.FindPropertyRelative("italicTypeface"); + + float width = position.width; + + position.width = EditorGUIUtility.labelWidth; + EditorGUI.LabelField(position, label); + + int oldIndent = EditorGUI.indentLevel; + EditorGUI.indentLevel = 0; + + // NORMAL TYPEFACE + if (label.text[0] == '4') GUI.enabled = false; + position.x += position.width; position.width = (width - position.width) / 2; + EditorGUI.PropertyField(position, prop_regular, GUIContent.none); + + // ITALIC TYPEFACE + GUI.enabled = true; + position.x += position.width; + EditorGUI.PropertyField(position, prop_italic, GUIContent.none); + + EditorGUI.indentLevel = oldIndent; + } + } + + [CustomEditor(typeof(TMP_FontAsset))] + public class TMP_FontAssetEditor : Editor + { + private struct UI_PanelState + { + public static bool faceInfoPanel = true; + public static bool generationSettingsPanel = true; + public static bool fontAtlasInfoPanel = true; + public static bool fontWeightPanel = true; + public static bool fallbackFontAssetPanel = true; + public static bool glyphTablePanel = false; + public static bool characterTablePanel = false; + public static bool LigatureSubstitutionTablePanel; + public static bool PairAdjustmentTablePanel = false; + public static bool MarkToBaseTablePanel = false; + public static bool MarkToMarkTablePanel = false; + } + + private struct GenerationSettings + { + public Font sourceFont; + public int faceIndex; + public GlyphRenderMode glyphRenderMode; + public int pointSize; + public int padding; + public int atlasWidth; + public int atlasHeight; + } + + /// + /// Material used to display SDF glyphs in the Character and Glyph tables. + /// + internal static Material internalSDFMaterial + { + get + { + if (s_InternalSDFMaterial == null) + { + Shader shader = Shader.Find("Hidden/TMP/Internal/Editor/Distance Field SSD"); + + if (shader != null) + s_InternalSDFMaterial = new Material(shader); + } + + return s_InternalSDFMaterial; + } + } + static Material s_InternalSDFMaterial; + + /// + /// Material used to display Bitmap glyphs in the Character and Glyph tables. + /// + internal static Material internalBitmapMaterial + { + get + { + if (s_InternalBitmapMaterial == null) + { + Shader shader = Shader.Find("Hidden/Internal-GUITextureClipText"); + + if (shader != null) + s_InternalBitmapMaterial = new Material(shader); + } + + return s_InternalBitmapMaterial; + } + } + static Material s_InternalBitmapMaterial; + + /// + /// Material used to display color glyphs in the Character and Glyph tables. + /// + internal static Material internalRGBABitmapMaterial + { + get + { + if (s_Internal_Bitmap_RGBA_Material == null) + { + Shader shader = Shader.Find("Hidden/Internal-GUITextureClip"); + + if (shader != null) + s_Internal_Bitmap_RGBA_Material = new Material(shader); + } + + return s_Internal_Bitmap_RGBA_Material; + } + } + static Material s_Internal_Bitmap_RGBA_Material; + + + + private static string[] s_UiStateLabel = new string[] { "(Click to collapse) ", "(Click to expand) " }; + public static readonly GUIContent getFontFeaturesLabel = new GUIContent("Get Font Features", "Determines if OpenType font features should be retrieved from the source font file as new characters and glyphs are added to the font asset."); + private GUIContent[] m_AtlasResolutionLabels = { new GUIContent("8"), new GUIContent("16"), new GUIContent("32"), new GUIContent("64"), new GUIContent("128"), new GUIContent("256"), new GUIContent("512"), new GUIContent("1024"), new GUIContent("2048"), new GUIContent("4096"), new GUIContent("8192") }; + private int[] m_AtlasResolutions = { 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 }; + + private struct Warning + { + public bool isEnabled; + public double expirationTime; + } + + private int m_CurrentGlyphPage = 0; + private int m_CurrentCharacterPage = 0; + private int m_CurrentLigaturePage = 0; + private int m_CurrentAdjustmentPairPage = 0; + private int m_CurrentMarkToBasePage = 0; + private int m_CurrentMarkToMarkPage = 0; + + private int m_SelectedGlyphRecord = -1; + private int m_SelectedCharacterRecord = -1; + private int m_SelectedLigatureRecord = -1; + private int m_SelectedAdjustmentRecord = -1; + private int m_SelectedMarkToBaseRecord = -1; + private int m_SelectedMarkToMarkRecord = -1; + + enum RecordSelectionType { CharacterRecord, GlyphRecord, LigatureSubstitutionRecord, AdjustmentPairRecord, MarkToBaseRecord, MarkToMarkRecord } + + private string m_dstGlyphID; + private string m_dstUnicode; + private const string k_placeholderUnicodeHex = "New Unicode (Hex)"; + private string m_unicodeHexLabel = k_placeholderUnicodeHex; + private const string k_placeholderGlyphID = "New Glyph ID"; + private string m_GlyphIDLabel = k_placeholderGlyphID; + + private Warning m_AddGlyphWarning; + private Warning m_AddCharacterWarning; + private bool m_DisplayDestructiveChangeWarning; + private GenerationSettings m_GenerationSettings; + private bool m_MaterialPresetsRequireUpdate; + + private static readonly string[] k_InvalidFontFaces = { string.Empty }; + private string[] m_FontFaces; + private bool m_FaceInfoDirty; + + private string m_GlyphSearchPattern; + private List m_GlyphSearchList; + + private string m_CharacterSearchPattern; + private List m_CharacterSearchList; + + private string m_LigatureTableSearchPattern; + private List m_LigatureTableSearchList; + + private string m_KerningTableSearchPattern; + private List m_KerningTableSearchList; + + private string m_MarkToBaseTableSearchPattern; + private List m_MarkToBaseTableSearchList; + + private string m_MarkToMarkTableSearchPattern; + private List m_MarkToMarkTableSearchList; + + private HashSet m_GlyphsToAdd; + + private bool m_isSearchDirty; + + private const string k_UndoRedo = "UndoRedoPerformed"; + + private SerializedProperty m_AtlasPopulationMode_prop; + private SerializedProperty font_atlas_prop; + private SerializedProperty font_material_prop; + + private SerializedProperty m_FontFaceIndex_prop; + private SerializedProperty m_AtlasRenderMode_prop; + private SerializedProperty m_SamplingPointSize_prop; + private SerializedProperty m_AtlasPadding_prop; + private SerializedProperty m_AtlasWidth_prop; + private SerializedProperty m_AtlasHeight_prop; + private SerializedProperty m_IsMultiAtlasTexturesEnabled_prop; + private SerializedProperty m_ClearDynamicDataOnBuild_prop; + private SerializedProperty m_GetFontFeatures_prop; + + private SerializedProperty fontWeights_prop; + + //private SerializedProperty fallbackFontAssets_prop; + private ReorderableList m_FallbackFontAssetList; + + private SerializedProperty font_normalStyle_prop; + private SerializedProperty font_normalSpacing_prop; + + private SerializedProperty font_boldStyle_prop; + private SerializedProperty font_boldSpacing_prop; + + private SerializedProperty font_italicStyle_prop; + private SerializedProperty font_tabSize_prop; + + private SerializedProperty m_FaceInfo_prop; + private SerializedProperty m_GlyphTable_prop; + private SerializedProperty m_CharacterTable_prop; + + private TMP_FontFeatureTable m_FontFeatureTable; + private SerializedProperty m_FontFeatureTable_prop; + private SerializedProperty m_LigatureSubstitutionRecords_prop; + private SerializedProperty m_GlyphPairAdjustmentRecords_prop; + private SerializedProperty m_MarkToBaseAdjustmentRecords_prop; + private SerializedProperty m_MarkToMarkAdjustmentRecords_prop; + + private TMP_SerializedPropertyHolder m_SerializedPropertyHolder; + private SerializedProperty m_EmptyGlyphPairAdjustmentRecord_prop; + private SerializedProperty m_FirstCharacterUnicode_prop; + private SerializedProperty m_SecondCharacterUnicode_prop; + + private TMP_FontAsset m_fontAsset; + + private Material[] m_materialPresets; + + private bool isAssetDirty = false; + private bool m_IsFallbackGlyphCacheDirty; + + private int errorCode; + + private System.DateTime timeStamp; + + + public void OnEnable() + { + m_FaceInfo_prop = serializedObject.FindProperty("m_FaceInfo"); + + font_atlas_prop = serializedObject.FindProperty("m_AtlasTextures").GetArrayElementAtIndex(0); + font_material_prop = serializedObject.FindProperty("m_Material"); + + m_FontFaceIndex_prop = m_FaceInfo_prop.FindPropertyRelative("m_FaceIndex"); + m_AtlasPopulationMode_prop = serializedObject.FindProperty("m_AtlasPopulationMode"); + m_AtlasRenderMode_prop = serializedObject.FindProperty("m_AtlasRenderMode"); + m_SamplingPointSize_prop = m_FaceInfo_prop.FindPropertyRelative("m_PointSize"); + m_AtlasPadding_prop = serializedObject.FindProperty("m_AtlasPadding"); + m_AtlasWidth_prop = serializedObject.FindProperty("m_AtlasWidth"); + m_AtlasHeight_prop = serializedObject.FindProperty("m_AtlasHeight"); + m_IsMultiAtlasTexturesEnabled_prop = serializedObject.FindProperty("m_IsMultiAtlasTexturesEnabled"); + m_ClearDynamicDataOnBuild_prop = serializedObject.FindProperty("m_ClearDynamicDataOnBuild"); + m_GetFontFeatures_prop = serializedObject.FindProperty("m_GetFontFeatures"); + + fontWeights_prop = serializedObject.FindProperty("m_FontWeightTable"); + + m_FallbackFontAssetList = PrepareReorderableList(serializedObject.FindProperty("m_FallbackFontAssetTable"), "Fallback Font Assets"); + + // Clean up fallback list in the event if contains null elements. + CleanFallbackFontAssetTable(); + + font_normalStyle_prop = serializedObject.FindProperty("normalStyle"); + font_normalSpacing_prop = serializedObject.FindProperty("normalSpacingOffset"); + + font_boldStyle_prop = serializedObject.FindProperty("boldStyle"); + font_boldSpacing_prop = serializedObject.FindProperty("boldSpacing"); + + font_italicStyle_prop = serializedObject.FindProperty("italicStyle"); + font_tabSize_prop = serializedObject.FindProperty("tabSize"); + + m_CharacterTable_prop = serializedObject.FindProperty("m_CharacterTable"); + m_GlyphTable_prop = serializedObject.FindProperty("m_GlyphTable"); + + m_FontFeatureTable_prop = serializedObject.FindProperty("m_FontFeatureTable"); + m_LigatureSubstitutionRecords_prop = m_FontFeatureTable_prop.FindPropertyRelative("m_LigatureSubstitutionRecords"); + m_GlyphPairAdjustmentRecords_prop = m_FontFeatureTable_prop.FindPropertyRelative("m_GlyphPairAdjustmentRecords"); + m_MarkToBaseAdjustmentRecords_prop = m_FontFeatureTable_prop.FindPropertyRelative("m_MarkToBaseAdjustmentRecords"); + m_MarkToMarkAdjustmentRecords_prop = m_FontFeatureTable_prop.FindPropertyRelative("m_MarkToMarkAdjustmentRecords"); + + m_fontAsset = target as TMP_FontAsset; + m_FontFeatureTable = m_fontAsset.fontFeatureTable; + + // Get Font Faces and Styles + m_FontFaces = GetFontFaces(); + + // Upgrade Font Feature Table if necessary + if (m_fontAsset.m_KerningTable != null && m_fontAsset.m_KerningTable.kerningPairs != null && m_fontAsset.m_KerningTable.kerningPairs.Count > 0) + m_fontAsset.ReadFontAssetDefinition(); + + // Create serialized object to allow us to use a serialized property of an empty kerning pair. + m_SerializedPropertyHolder = CreateInstance(); + m_SerializedPropertyHolder.fontAsset = m_fontAsset; + SerializedObject internalSerializedObject = new SerializedObject(m_SerializedPropertyHolder); + m_FirstCharacterUnicode_prop = internalSerializedObject.FindProperty("firstCharacter"); + m_SecondCharacterUnicode_prop = internalSerializedObject.FindProperty("secondCharacter"); + m_EmptyGlyphPairAdjustmentRecord_prop = internalSerializedObject.FindProperty("glyphPairAdjustmentRecord"); + + m_materialPresets = TMP_EditorUtility.FindMaterialReferences(m_fontAsset); + + m_GlyphSearchList = new List(); + m_KerningTableSearchList = new List(); + + // Sort Font Asset Tables + m_fontAsset.SortAllTables(); + + // Clear glyph proxy lookups + TMP_PropertyDrawerUtilities.ClearGlyphProxyLookups(); + } + + private ReorderableList PrepareReorderableList(SerializedProperty property, string label) + { + SerializedObject so = property.serializedObject; + + ReorderableList list = new ReorderableList(so, property, true, true, true, true); + + list.drawHeaderCallback = rect => + { + EditorGUI.LabelField(rect, label); + }; + + list.drawElementCallback = (rect, index, isActive, isFocused) => + { + var element = list.serializedProperty.GetArrayElementAtIndex(index); + rect.y += 2; + EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), element, GUIContent.none); + }; + + list.onChangedCallback = itemList => { }; + + return list; + } + + + public void OnDisable() + { + // Revert changes if user closes or changes selection without having made a choice. + if (m_DisplayDestructiveChangeWarning) + { + m_DisplayDestructiveChangeWarning = false; + RestoreGenerationSettings(); + GUIUtility.keyboardControl = 0; + + serializedObject.ApplyModifiedProperties(); + } + } + + + public override void OnInspectorGUI() + { + //Debug.Log("OnInspectorGUI Called."); + + Event currentEvent = Event.current; + + serializedObject.Update(); + + Rect rect = EditorGUILayout.GetControlRect(false, 24); + float labelWidth = EditorGUIUtility.labelWidth; + float fieldWidth = EditorGUIUtility.fieldWidth; + + // FACE INFO PANEL + #region Face info + GUI.Label(rect, new GUIContent("Face Info - v" + m_fontAsset.version), TMP_UIStyleManager.sectionHeader); + + rect.x += rect.width - 132f; + rect.y += 2; + rect.width = 130f; + rect.height = 18f; + if (GUI.Button(rect, new GUIContent("Update Atlas Texture"))) + { + TMPro_FontAssetCreatorWindow.ShowFontAtlasCreatorWindow(target as TMP_FontAsset); + } + + EditorGUI.indentLevel = 1; + GUI.enabled = false; // Lock UI + + // TODO : Consider creating a property drawer for these. + EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_FamilyName")); + EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_StyleName")); + EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_PointSize")); + + GUI.enabled = true; + + EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_Scale")); + EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_LineHeight")); + + EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_AscentLine")); + EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_CapLine")); + EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_MeanLine")); + EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_Baseline")); + EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_DescentLine")); + EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_UnderlineOffset")); + EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_UnderlineThickness")); + EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_StrikethroughOffset")); + //EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("strikethroughThickness")); + EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_SuperscriptOffset")); + EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_SuperscriptSize")); + EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_SubscriptOffset")); + EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_SubscriptSize")); + EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_TabWidth")); + // TODO : Add clamping for some of these values. + //subSize_prop.floatValue = Mathf.Clamp(subSize_prop.floatValue, 0.25f, 1f); + + EditorGUILayout.Space(); + #endregion + + // GENERATION SETTINGS + #region Generation Settings + rect = EditorGUILayout.GetControlRect(false, 24); + + if (GUI.Button(rect, new GUIContent("Generation Settings"), TMP_UIStyleManager.sectionHeader)) + UI_PanelState.generationSettingsPanel = !UI_PanelState.generationSettingsPanel; + + GUI.Label(rect, (UI_PanelState.generationSettingsPanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel); + + if (UI_PanelState.generationSettingsPanel) + { + EditorGUI.indentLevel = 1; + + EditorGUI.BeginChangeCheck(); + Font sourceFont = (Font)EditorGUILayout.ObjectField("Source Font File", m_fontAsset.SourceFont_EditorRef, typeof(Font), false); + if (EditorGUI.EndChangeCheck()) + { + m_GenerationSettings.sourceFont = m_fontAsset.SourceFont_EditorRef; + m_fontAsset.SourceFont_EditorRef = sourceFont; + m_FontFaces = GetFontFaces(0); + m_FaceInfoDirty = true; + m_DisplayDestructiveChangeWarning = true; + //m_MaterialPresetsRequireUpdate = true; + } + + EditorGUI.BeginDisabledGroup(sourceFont == null); + { + EditorGUI.BeginChangeCheck(); + m_FontFaceIndex_prop.intValue = EditorGUILayout.Popup(new GUIContent("Font Face"), m_FontFaceIndex_prop.intValue, m_FontFaces); + if (EditorGUI.EndChangeCheck()) + { + m_MaterialPresetsRequireUpdate = true; + m_DisplayDestructiveChangeWarning = true; + m_FaceInfoDirty = true; + } + + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_AtlasPopulationMode_prop, new GUIContent("Atlas Population Mode")); + if (EditorGUI.EndChangeCheck()) + { + serializedObject.ApplyModifiedProperties(); + + bool isDatabaseRefreshRequired = false; + + // Static font asset + if (m_AtlasPopulationMode_prop.intValue == 0) + { + m_fontAsset.sourceFontFile = null; + + //Set atlas textures to non readable. + for (int i = 0; i < m_fontAsset.atlasTextures.Length; i++) + { + Texture2D tex = m_fontAsset.atlasTextures[i]; + + if (tex != null && tex.isReadable) + FontEngineEditorUtilities.SetAtlasTextureIsReadable(tex, false); + } + + //Debug.Log("Atlas Population mode set to [Static]."); + } + else // Dynamic font asset + { + if (m_fontAsset.m_SourceFontFile_EditorRef.dynamic == false) + { + Debug.LogWarning("Please set the [" + m_fontAsset.name + "] font to dynamic mode as this is required for Dynamic SDF support.", m_fontAsset.m_SourceFontFile_EditorRef); + m_AtlasPopulationMode_prop.intValue = 0; + + serializedObject.ApplyModifiedProperties(); + } + else + { + m_fontAsset.sourceFontFile = m_fontAsset.m_SourceFontFile_EditorRef; + + // Set atlas textures to non readable. + for (int i = 0; i < m_fontAsset.atlasTextures.Length; i++) + { + Texture2D tex = m_fontAsset.atlasTextures[i]; + + if (tex != null && tex.isReadable == false) + FontEngineEditorUtilities.SetAtlasTextureIsReadable(tex, true); + } + + //Debug.Log("Atlas Population mode set to [" + (m_AtlasPopulationMode_prop.intValue == 1 ? "Dynamic" : "Dynamic OS") + "]."); + } + + // Dynamic OS font asset + if (m_AtlasPopulationMode_prop.intValue == 2) + m_fontAsset.sourceFontFile = null; + } + + if (isDatabaseRefreshRequired) + AssetDatabase.Refresh(); + + serializedObject.Update(); + isAssetDirty = true; + } + + // Save state of atlas settings + if (m_DisplayDestructiveChangeWarning == false) + { + SavedGenerationSettings(); + //Undo.RegisterCompleteObjectUndo(m_fontAsset, "Font Asset Changes"); + } + + EditorGUI.BeginDisabledGroup(m_AtlasPopulationMode_prop.intValue == (int)AtlasPopulationMode.Static); + { + EditorGUI.BeginChangeCheck(); + // TODO: Switch shaders depending on GlyphRenderMode. + EditorGUILayout.PropertyField(m_AtlasRenderMode_prop); + EditorGUILayout.PropertyField(m_SamplingPointSize_prop, new GUIContent("Sampling Point Size")); + if (EditorGUI.EndChangeCheck()) + { + m_DisplayDestructiveChangeWarning = true; + } + + // Changes to these properties require updating Material Presets for this font asset. + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_AtlasPadding_prop, new GUIContent("Padding")); + EditorGUILayout.IntPopup(m_AtlasWidth_prop, m_AtlasResolutionLabels, m_AtlasResolutions, new GUIContent("Atlas Width")); + EditorGUILayout.IntPopup(m_AtlasHeight_prop, m_AtlasResolutionLabels, m_AtlasResolutions, new GUIContent("Atlas Height")); + EditorGUILayout.PropertyField(m_IsMultiAtlasTexturesEnabled_prop, new GUIContent("Multi Atlas Textures", "Determines if the font asset will store glyphs in multiple atlas textures.")); + if (EditorGUI.EndChangeCheck()) + { + if (m_AtlasPadding_prop.intValue < 0) + { + m_AtlasPadding_prop.intValue = 0; + serializedObject.ApplyModifiedProperties(); + } + + m_MaterialPresetsRequireUpdate = true; + m_DisplayDestructiveChangeWarning = true; + } + EditorGUILayout.PropertyField(m_ClearDynamicDataOnBuild_prop, new GUIContent("Clear Dynamic Data On Build", "Clears all dynamic data restoring the font asset back to its default creation and empty state.")); + EditorGUILayout.PropertyField(m_GetFontFeatures_prop, getFontFeaturesLabel); + + EditorGUILayout.Space(); + + if (m_DisplayDestructiveChangeWarning) + { + bool guiEnabledState = GUI.enabled; + GUI.enabled = true; + + // These changes are destructive on the font asset + rect = EditorGUILayout.GetControlRect(false, 60); + rect.x += 15; + rect.width -= 15; + EditorGUI.HelpBox(rect, "Changing these settings will clear the font asset's character, glyph and texture data.", MessageType.Warning); + + if (GUI.Button(new Rect(rect.width - 140, rect.y + 36, 80, 18), new GUIContent("Apply"))) + { + m_DisplayDestructiveChangeWarning = false; + + // Update face info if sampling point size was changed. +#if UNITY_2023_3_OR_NEWER + if (m_GenerationSettings.pointSize != m_SamplingPointSize_prop.floatValue || m_FaceInfoDirty) + { + LoadFontFace((int)m_SamplingPointSize_prop.floatValue, m_FontFaceIndex_prop.intValue); +#else + if (m_GenerationSettings.pointSize != m_SamplingPointSize_prop.intValue || m_FaceInfoDirty) + { + LoadFontFace(m_SamplingPointSize_prop.intValue, m_FontFaceIndex_prop.intValue); +#endif + m_fontAsset.faceInfo = FontEngine.GetFaceInfo(); + m_FaceInfoDirty = false; + } + + Material mat = m_fontAsset.material; + + // Update material + mat.SetFloat(ShaderUtilities.ID_TextureWidth, m_AtlasWidth_prop.intValue); + mat.SetFloat(ShaderUtilities.ID_TextureHeight, m_AtlasHeight_prop.intValue); + + if (mat.HasProperty(ShaderUtilities.ID_GradientScale)) + mat.SetFloat(ShaderUtilities.ID_GradientScale, m_AtlasPadding_prop.intValue + 1); + + // Update material presets if any of the relevant properties have been changed. + if (m_MaterialPresetsRequireUpdate) + { + m_MaterialPresetsRequireUpdate = false; + + Material[] materialPresets = TMP_EditorUtility.FindMaterialReferences(m_fontAsset); + for (int i = 0; i < materialPresets.Length; i++) + { + mat = materialPresets[i]; + + mat.SetFloat(ShaderUtilities.ID_TextureWidth, m_AtlasWidth_prop.intValue); + mat.SetFloat(ShaderUtilities.ID_TextureHeight, m_AtlasHeight_prop.intValue); + + if (mat.HasProperty(ShaderUtilities.ID_GradientScale)) + mat.SetFloat(ShaderUtilities.ID_GradientScale, m_AtlasPadding_prop.intValue + 1); + } + } + + m_fontAsset.UpdateFontAssetData(); + GUIUtility.keyboardControl = 0; + isAssetDirty = true; + + // Update Font Asset Creation Settings to reflect new changes. + UpdateFontAssetCreationSettings(); + + // TODO: Clear undo buffers. + //Undo.ClearUndo(m_fontAsset); + } + + if (GUI.Button(new Rect(rect.width - 56, rect.y + 36, 80, 18), new GUIContent("Revert"))) + { + m_DisplayDestructiveChangeWarning = false; + RestoreGenerationSettings(); + GUIUtility.keyboardControl = 0; + + // TODO: Clear undo buffers. + //Undo.ClearUndo(m_fontAsset); + } + + GUI.enabled = guiEnabledState; + } + } + EditorGUI.EndDisabledGroup(); + } + EditorGUI.EndDisabledGroup(); + EditorGUILayout.Space(); + } + #endregion + + // ATLAS & MATERIAL PANEL + #region Atlas & Material + rect = EditorGUILayout.GetControlRect(false, 24); + + if (GUI.Button(rect, new GUIContent("Atlas & Material"), TMP_UIStyleManager.sectionHeader)) + UI_PanelState.fontAtlasInfoPanel = !UI_PanelState.fontAtlasInfoPanel; + + GUI.Label(rect, (UI_PanelState.fontAtlasInfoPanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel); + + if (UI_PanelState.fontAtlasInfoPanel) + { + EditorGUI.indentLevel = 1; + + GUI.enabled = false; + EditorGUILayout.PropertyField(font_atlas_prop, new GUIContent("Font Atlas")); + EditorGUILayout.PropertyField(font_material_prop, new GUIContent("Font Material")); + GUI.enabled = true; + EditorGUILayout.Space(); + } + #endregion + + string evt_cmd = Event.current.commandName; // Get Current Event CommandName to check for Undo Events + + // FONT WEIGHT PANEL + #region Font Weights + rect = EditorGUILayout.GetControlRect(false, 24); + + if (GUI.Button(rect, new GUIContent("Font Weights", "The Font Assets that will be used for different font weights and the settings used to simulate a typeface when no asset is available."), TMP_UIStyleManager.sectionHeader)) + UI_PanelState.fontWeightPanel = !UI_PanelState.fontWeightPanel; + + GUI.Label(rect, (UI_PanelState.fontWeightPanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel); + + if (UI_PanelState.fontWeightPanel) + { + EditorGUIUtility.labelWidth *= 0.75f; + EditorGUIUtility.fieldWidth *= 0.25f; + + EditorGUILayout.BeginVertical(); + EditorGUI.indentLevel = 1; + rect = EditorGUILayout.GetControlRect(true); + rect.x += EditorGUIUtility.labelWidth; + rect.width = (rect.width - EditorGUIUtility.labelWidth) / 2f; + GUI.Label(rect, "Regular Typeface", EditorStyles.label); + rect.x += rect.width; + GUI.Label(rect, "Italic Typeface", EditorStyles.label); + + EditorGUI.indentLevel = 1; + + EditorGUILayout.PropertyField(fontWeights_prop.GetArrayElementAtIndex(1), new GUIContent("100 - Thin")); + EditorGUILayout.PropertyField(fontWeights_prop.GetArrayElementAtIndex(2), new GUIContent("200 - Extra-Light")); + EditorGUILayout.PropertyField(fontWeights_prop.GetArrayElementAtIndex(3), new GUIContent("300 - Light")); + EditorGUILayout.PropertyField(fontWeights_prop.GetArrayElementAtIndex(4), new GUIContent("400 - Regular")); + EditorGUILayout.PropertyField(fontWeights_prop.GetArrayElementAtIndex(5), new GUIContent("500 - Medium")); + EditorGUILayout.PropertyField(fontWeights_prop.GetArrayElementAtIndex(6), new GUIContent("600 - Semi-Bold")); + EditorGUILayout.PropertyField(fontWeights_prop.GetArrayElementAtIndex(7), new GUIContent("700 - Bold")); + EditorGUILayout.PropertyField(fontWeights_prop.GetArrayElementAtIndex(8), new GUIContent("800 - Heavy")); + EditorGUILayout.PropertyField(fontWeights_prop.GetArrayElementAtIndex(9), new GUIContent("900 - Black")); + + EditorGUILayout.EndVertical(); + + EditorGUILayout.Space(); + + EditorGUILayout.BeginVertical(); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PropertyField(font_normalStyle_prop, new GUIContent("Normal Weight")); + font_normalStyle_prop.floatValue = Mathf.Clamp(font_normalStyle_prop.floatValue, -3.0f, 3.0f); + if (GUI.changed || evt_cmd == k_UndoRedo) + { + GUI.changed = false; + + // Modify the material property on matching material presets. + for (int i = 0; i < m_materialPresets.Length; i++) + m_materialPresets[i].SetFloat("_WeightNormal", font_normalStyle_prop.floatValue); + } + + EditorGUILayout.PropertyField(font_boldStyle_prop, new GUIContent("Bold Weight")); + font_boldStyle_prop.floatValue = Mathf.Clamp(font_boldStyle_prop.floatValue, -3.0f, 3.0f); + if (GUI.changed || evt_cmd == k_UndoRedo) + { + GUI.changed = false; + + // Modify the material property on matching material presets. + for (int i = 0; i < m_materialPresets.Length; i++) + m_materialPresets[i].SetFloat("_WeightBold", font_boldStyle_prop.floatValue); + } + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PropertyField(font_normalSpacing_prop, new GUIContent("Spacing Offset")); + font_normalSpacing_prop.floatValue = Mathf.Clamp(font_normalSpacing_prop.floatValue, -100, 100); + if (GUI.changed || evt_cmd == k_UndoRedo) + { + GUI.changed = false; + } + + EditorGUILayout.PropertyField(font_boldSpacing_prop, new GUIContent("Bold Spacing")); + font_boldSpacing_prop.floatValue = Mathf.Clamp(font_boldSpacing_prop.floatValue, 0, 100); + if (GUI.changed || evt_cmd == k_UndoRedo) + { + GUI.changed = false; + } + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PropertyField(font_italicStyle_prop, new GUIContent("Italic Style")); + font_italicStyle_prop.intValue = Mathf.Clamp(font_italicStyle_prop.intValue, 15, 60); + + EditorGUILayout.PropertyField(font_tabSize_prop, new GUIContent("Tab Multiple")); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.EndVertical(); + EditorGUILayout.Space(); + } + + EditorGUIUtility.labelWidth = 0; + EditorGUIUtility.fieldWidth = 0; + #endregion + + // FALLBACK FONT ASSETS + #region Fallback Font Asset + rect = EditorGUILayout.GetControlRect(false, 24); + EditorGUI.indentLevel = 0; + if (GUI.Button(rect, new GUIContent("Fallback Font Assets", "Select the Font Assets that will be searched and used as fallback when characters are missing from this font asset."), TMP_UIStyleManager.sectionHeader)) + UI_PanelState.fallbackFontAssetPanel = !UI_PanelState.fallbackFontAssetPanel; + + GUI.Label(rect, (UI_PanelState.fallbackFontAssetPanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel); + + if (UI_PanelState.fallbackFontAssetPanel) + { + EditorGUIUtility.labelWidth = 120; + EditorGUI.indentLevel = 0; + EditorGUI.BeginChangeCheck(); + m_FallbackFontAssetList.DoLayoutList(); + if (EditorGUI.EndChangeCheck()) + { + m_IsFallbackGlyphCacheDirty = true; + } + EditorGUILayout.Space(); + } + #endregion + + // CHARACTER TABLE TABLE + #region Character Table + EditorGUIUtility.labelWidth = labelWidth; + EditorGUIUtility.fieldWidth = fieldWidth; + EditorGUI.indentLevel = 0; + rect = EditorGUILayout.GetControlRect(false, 24); + + int characterCount = m_fontAsset.characterTable.Count; + + if (GUI.Button(rect, new GUIContent("Character Table [" + characterCount + "]" + (rect.width > 320 ? " Characters" : ""), "List of characters contained in this font asset."), TMP_UIStyleManager.sectionHeader)) + UI_PanelState.characterTablePanel = !UI_PanelState.characterTablePanel; + + GUI.Label(rect, (UI_PanelState.characterTablePanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel); + + if (UI_PanelState.characterTablePanel) + { + int arraySize = m_CharacterTable_prop.arraySize; + int itemsPerPage = 15; + + // Display Glyph Management Tools + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + { + // Search Bar implementation + #region DISPLAY SEARCH BAR + EditorGUILayout.BeginHorizontal(); + { + EditorGUIUtility.labelWidth = 130f; + EditorGUI.BeginChangeCheck(); + string searchPattern = EditorGUILayout.TextField("Character Search", m_CharacterSearchPattern, "SearchTextField"); + if (EditorGUI.EndChangeCheck() || m_isSearchDirty) + { + if (string.IsNullOrEmpty(searchPattern) == false) + { + m_CharacterSearchPattern = searchPattern; + + // Search Character Table for potential matches + SearchCharacterTable(m_CharacterSearchPattern, ref m_CharacterSearchList); + } + else + m_CharacterSearchPattern = null; + + m_isSearchDirty = false; + } + + string styleName = string.IsNullOrEmpty(m_CharacterSearchPattern) ? "SearchCancelButtonEmpty" : "SearchCancelButton"; + if (GUILayout.Button(GUIContent.none, styleName)) + { + GUIUtility.keyboardControl = 0; + m_CharacterSearchPattern = string.Empty; + } + } + EditorGUILayout.EndHorizontal(); + #endregion + + // Display Page Navigation + if (!string.IsNullOrEmpty(m_CharacterSearchPattern)) + arraySize = m_CharacterSearchList.Count; + + DisplayPageNavigation(ref m_CurrentCharacterPage, arraySize, itemsPerPage); + } + EditorGUILayout.EndVertical(); + + // Display Character Table Elements + if (arraySize > 0) + { + // Display each character entry using the CharacterPropertyDrawer. + for (int i = itemsPerPage * m_CurrentCharacterPage; i < arraySize && i < itemsPerPage * (m_CurrentCharacterPage + 1); i++) + { + // Define the start of the selection region of the element. + Rect elementStartRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + + int elementIndex = i; + if (!string.IsNullOrEmpty(m_CharacterSearchPattern)) + elementIndex = m_CharacterSearchList[i]; + + SerializedProperty characterProperty = m_CharacterTable_prop.GetArrayElementAtIndex(elementIndex); + + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + + EditorGUI.BeginDisabledGroup(i != m_SelectedCharacterRecord); + { + EditorGUILayout.PropertyField(characterProperty); + } + EditorGUI.EndDisabledGroup(); + + EditorGUILayout.EndVertical(); + + // Define the end of the selection region of the element. + Rect elementEndRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + + // Check for Item selection + Rect selectionArea = new Rect(elementStartRegion.x, elementStartRegion.y, elementEndRegion.width, elementEndRegion.y - elementStartRegion.y); + if (DoSelectionCheck(selectionArea)) + { + if (m_SelectedCharacterRecord == i) + m_SelectedCharacterRecord = -1; + else + { + m_SelectedCharacterRecord = i; + m_AddCharacterWarning.isEnabled = false; + m_unicodeHexLabel = k_placeholderUnicodeHex; + GUIUtility.keyboardControl = 0; + } + } + + // Draw Selection Highlight and Glyph Options + if (m_SelectedCharacterRecord == i) + { + // Reset other selections + ResetSelections(RecordSelectionType.CharacterRecord); + + TMP_EditorUtility.DrawBox(selectionArea, 2f, new Color32(40, 192, 255, 255)); + + // Draw Glyph management options + Rect controlRect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight * 1f); + float optionAreaWidth = controlRect.width * 0.6f; + float btnWidth = optionAreaWidth / 3; + + Rect position = new Rect(controlRect.x + controlRect.width * .4f, controlRect.y, btnWidth, controlRect.height); + + // Copy Selected Glyph to Target Glyph ID + GUI.enabled = !string.IsNullOrEmpty(m_dstUnicode); + if (GUI.Button(position, new GUIContent("Copy to"))) + { + GUIUtility.keyboardControl = 0; + + // Convert Hex Value to Decimal + int dstGlyphID = TMP_TextUtilities.StringHexToInt(m_dstUnicode); + + //Add new glyph at target Unicode hex id. + if (!AddNewCharacter(elementIndex, dstGlyphID)) + { + m_AddCharacterWarning.isEnabled = true; + m_AddCharacterWarning.expirationTime = EditorApplication.timeSinceStartup + 1; + } + + m_dstUnicode = string.Empty; + m_isSearchDirty = true; + + TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(true, m_fontAsset); + } + + // Target Glyph ID + GUI.enabled = true; + position.x += btnWidth; + + GUI.SetNextControlName("CharacterID_Input"); + m_dstUnicode = EditorGUI.TextField(position, m_dstUnicode); + + // Placeholder text + EditorGUI.LabelField(position, new GUIContent(m_unicodeHexLabel, "The Unicode (Hex) ID of the duplicated Character"), TMP_UIStyleManager.label); + + // Only filter the input when the destination glyph ID text field has focus. + if (GUI.GetNameOfFocusedControl() == "CharacterID_Input") + { + m_unicodeHexLabel = string.Empty; + + //Filter out unwanted characters. + char chr = Event.current.character; + if ((chr < '0' || chr > '9') && (chr < 'a' || chr > 'f') && (chr < 'A' || chr > 'F')) + { + Event.current.character = '\0'; + } + } + else + { + m_unicodeHexLabel = k_placeholderUnicodeHex; + //m_dstUnicode = string.Empty; + } + + + // Remove Glyph + position.x += btnWidth; + if (GUI.Button(position, "Remove")) + { + GUIUtility.keyboardControl = 0; + + RemoveCharacterFromList(elementIndex); + + isAssetDirty = true; + m_SelectedCharacterRecord = -1; + m_isSearchDirty = true; + break; + } + + if (m_AddCharacterWarning.isEnabled && EditorApplication.timeSinceStartup < m_AddCharacterWarning.expirationTime) + { + EditorGUILayout.HelpBox("The Destination Character ID already exists", MessageType.Warning); + } + } + } + } + + DisplayPageNavigation(ref m_CurrentCharacterPage, arraySize, itemsPerPage); + + EditorGUILayout.Space(); + } + #endregion + + // GLYPH TABLE + #region Glyph Table + EditorGUIUtility.labelWidth = labelWidth; + EditorGUIUtility.fieldWidth = fieldWidth; + EditorGUI.indentLevel = 0; + rect = EditorGUILayout.GetControlRect(false, 24); + + GUIStyle glyphPanelStyle = new GUIStyle(EditorStyles.helpBox); + + int glyphRecordCount = m_fontAsset.glyphTable.Count; + + if (GUI.Button(rect, new GUIContent("Glyph Table [" + glyphRecordCount + "]" + (rect.width > 275 ? " Glyphs" : ""), "List of glyphs contained in this font asset."), TMP_UIStyleManager.sectionHeader)) + UI_PanelState.glyphTablePanel = !UI_PanelState.glyphTablePanel; + + GUI.Label(rect, (UI_PanelState.glyphTablePanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel); + + if (UI_PanelState.glyphTablePanel) + { + int arraySize = m_GlyphTable_prop.arraySize; + int itemsPerPage = 15; + + // Display Glyph Management Tools + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + { + // Search Bar implementation + #region DISPLAY SEARCH BAR + EditorGUILayout.BeginHorizontal(); + { + EditorGUIUtility.labelWidth = 130f; + EditorGUI.BeginChangeCheck(); + string searchPattern = EditorGUILayout.TextField("Glyph Search", m_GlyphSearchPattern, "SearchTextField"); + if (EditorGUI.EndChangeCheck() || m_isSearchDirty) + { + if (string.IsNullOrEmpty(searchPattern) == false) + { + m_GlyphSearchPattern = searchPattern; + + // Search Glyph Table for potential matches + SearchGlyphTable(m_GlyphSearchPattern, ref m_GlyphSearchList); + } + else + m_GlyphSearchPattern = null; + + m_isSearchDirty = false; + } + + string styleName = string.IsNullOrEmpty(m_GlyphSearchPattern) ? "SearchCancelButtonEmpty" : "SearchCancelButton"; + if (GUILayout.Button(GUIContent.none, styleName)) + { + GUIUtility.keyboardControl = 0; + m_GlyphSearchPattern = string.Empty; + } + } + EditorGUILayout.EndHorizontal(); + #endregion + + // Display Page Navigation + if (!string.IsNullOrEmpty(m_GlyphSearchPattern)) + arraySize = m_GlyphSearchList.Count; + + DisplayPageNavigation(ref m_CurrentGlyphPage, arraySize, itemsPerPage); + } + EditorGUILayout.EndVertical(); + + // Display Glyph Table Elements + + if (arraySize > 0) + { + // Display each GlyphInfo entry using the GlyphInfo property drawer. + for (int i = itemsPerPage * m_CurrentGlyphPage; i < arraySize && i < itemsPerPage * (m_CurrentGlyphPage + 1); i++) + { + // Define the start of the selection region of the element. + Rect elementStartRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + + int elementIndex = i; + if (!string.IsNullOrEmpty(m_GlyphSearchPattern)) + elementIndex = m_GlyphSearchList[i]; + + SerializedProperty glyphProperty = m_GlyphTable_prop.GetArrayElementAtIndex(elementIndex); + + EditorGUILayout.BeginVertical(glyphPanelStyle); + + using (new EditorGUI.DisabledScope(i != m_SelectedGlyphRecord)) + { + EditorGUILayout.PropertyField(glyphProperty); + } + + EditorGUILayout.EndVertical(); + + // Define the end of the selection region of the element. + Rect elementEndRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + + // Check for Item selection + Rect selectionArea = new Rect(elementStartRegion.x, elementStartRegion.y, elementEndRegion.width, elementEndRegion.y - elementStartRegion.y); + if (DoSelectionCheck(selectionArea)) + { + if (m_SelectedGlyphRecord == i) + m_SelectedGlyphRecord = -1; + else + { + m_SelectedGlyphRecord = i; + m_AddGlyphWarning.isEnabled = false; + m_unicodeHexLabel = k_placeholderUnicodeHex; + GUIUtility.keyboardControl = 0; + } + } + + // Draw Selection Highlight and Glyph Options + if (m_SelectedGlyphRecord == i) + { + // Reset other selections + ResetSelections(RecordSelectionType.GlyphRecord); + + TMP_EditorUtility.DrawBox(selectionArea, 2f, new Color32(40, 192, 255, 255)); + + // Draw Glyph management options + Rect controlRect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight * 1f); + float optionAreaWidth = controlRect.width * 0.6f; + float btnWidth = optionAreaWidth / 3; + + Rect position = new Rect(controlRect.x + controlRect.width * .4f, controlRect.y, btnWidth, controlRect.height); + + // Copy Selected Glyph to Target Glyph ID + GUI.enabled = !string.IsNullOrEmpty(m_dstGlyphID); + if (GUI.Button(position, new GUIContent("Copy to"))) + { + GUIUtility.keyboardControl = 0; + int dstGlyphID; + + // Convert Hex Value to Decimal + int.TryParse(m_dstGlyphID, out dstGlyphID); + + //Add new glyph at target Unicode hex id. + if (!AddNewGlyph(elementIndex, dstGlyphID)) + { + m_AddGlyphWarning.isEnabled = true; + m_AddGlyphWarning.expirationTime = EditorApplication.timeSinceStartup + 1; + } + + m_dstGlyphID = string.Empty; + m_isSearchDirty = true; + + TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(true, m_fontAsset); + } + + // Target Glyph ID + GUI.enabled = true; + position.x += btnWidth; + + GUI.SetNextControlName("GlyphID_Input"); + m_dstGlyphID = EditorGUI.TextField(position, m_dstGlyphID); + + // Placeholder text + EditorGUI.LabelField(position, new GUIContent(m_GlyphIDLabel, "The Glyph ID of the duplicated Glyph"), TMP_UIStyleManager.label); + + // Only filter the input when the destination glyph ID text field has focus. + if (GUI.GetNameOfFocusedControl() == "GlyphID_Input") + { + m_GlyphIDLabel = string.Empty; + + //Filter out unwanted characters. + char chr = Event.current.character; + if ((chr < '0' || chr > '9')) + { + Event.current.character = '\0'; + } + } + else + { + m_GlyphIDLabel = k_placeholderGlyphID; + //m_dstGlyphID = string.Empty; + } + + // Remove Glyph + position.x += btnWidth; + if (GUI.Button(position, "Remove")) + { + GUIUtility.keyboardControl = 0; + + RemoveGlyphFromList(elementIndex); + + isAssetDirty = true; + m_SelectedGlyphRecord = -1; + m_isSearchDirty = true; + break; + } + + if (m_AddGlyphWarning.isEnabled && EditorApplication.timeSinceStartup < m_AddGlyphWarning.expirationTime) + { + EditorGUILayout.HelpBox("The Destination Glyph ID already exists", MessageType.Warning); + } + } + } + } + + //DisplayAddRemoveButtons(m_GlyphTable_prop, m_SelectedGlyphRecord, glyphRecordCount); + + DisplayPageNavigation(ref m_CurrentGlyphPage, arraySize, itemsPerPage); + + EditorGUILayout.Space(); + } + #endregion + + // FONT FEATURE TABLES + + // LIGATURE SUBSTITUTION TABLE + #region LIGATURE + EditorGUIUtility.labelWidth = labelWidth; + EditorGUIUtility.fieldWidth = fieldWidth; + EditorGUI.indentLevel = 0; + rect = EditorGUILayout.GetControlRect(false, 24); + + int ligatureSubstitutionRecordCount = m_fontAsset.fontFeatureTable.ligatureRecords.Count; + + if (GUI.Button(rect, new GUIContent("Ligature Table [" + ligatureSubstitutionRecordCount + "]" + (rect.width > 340 ? " Records" : ""), "List of Ligature substitution records."), TMP_UIStyleManager.sectionHeader)) + UI_PanelState.LigatureSubstitutionTablePanel = !UI_PanelState.LigatureSubstitutionTablePanel; + + GUI.Label(rect, (UI_PanelState.LigatureSubstitutionTablePanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel); + + if (UI_PanelState.LigatureSubstitutionTablePanel) + { + int arraySize = m_LigatureSubstitutionRecords_prop.arraySize; + int itemsPerPage = 20; + + // Display Mark Adjust Records Management Tools + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + { + // Search Bar implementation + #region DISPLAY SEARCH BAR + EditorGUILayout.BeginHorizontal(); + { + EditorGUIUtility.labelWidth = 150f; + EditorGUI.BeginChangeCheck(); + string searchPattern = EditorGUILayout.TextField("Ligature Search", m_LigatureTableSearchPattern, "SearchTextField"); + if (EditorGUI.EndChangeCheck() || m_isSearchDirty) + { + if (string.IsNullOrEmpty(searchPattern) == false) + { + m_LigatureTableSearchPattern = searchPattern; + + // Search Glyph Table for potential matches + SearchLigatureTable(m_LigatureTableSearchPattern, ref m_LigatureTableSearchList); + } + else + m_LigatureTableSearchPattern = null; + + m_isSearchDirty = false; + } + + string styleName = string.IsNullOrEmpty(m_LigatureTableSearchPattern) ? "SearchCancelButtonEmpty" : "SearchCancelButton"; + if (GUILayout.Button(GUIContent.none, styleName)) + { + GUIUtility.keyboardControl = 0; + m_LigatureTableSearchPattern = string.Empty; + } + } + EditorGUILayout.EndHorizontal(); + #endregion + + // Display Page Navigation + if (!string.IsNullOrEmpty(m_LigatureTableSearchPattern)) + arraySize = m_LigatureTableSearchList.Count; + + DisplayPageNavigation(ref m_CurrentLigaturePage, arraySize, itemsPerPage); + } + EditorGUILayout.EndVertical(); + + if (arraySize > 0) + { + // Display each GlyphInfo entry using the GlyphInfo property drawer. + for (int i = itemsPerPage * m_CurrentLigaturePage; i < arraySize && i < itemsPerPage * (m_CurrentLigaturePage + 1); i++) + { + // Define the start of the selection region of the element. + Rect elementStartRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + + int elementIndex = i; + if (!string.IsNullOrEmpty(m_LigatureTableSearchPattern)) + elementIndex = m_LigatureTableSearchList[i]; + + SerializedProperty ligaturePropertyRecord = m_LigatureSubstitutionRecords_prop.GetArrayElementAtIndex(elementIndex); + + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + + using (new EditorGUI.DisabledScope(i != m_SelectedLigatureRecord)) + { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(ligaturePropertyRecord); + + if (EditorGUI.EndChangeCheck()) + { + UpdateLigatureSubstitutionRecordLookup(ligaturePropertyRecord); + } + } + + EditorGUILayout.EndVertical(); + + // Define the end of the selection region of the element. + Rect elementEndRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + + // Check for Item selection + Rect selectionArea = new Rect(elementStartRegion.x, elementStartRegion.y, elementEndRegion.width, elementEndRegion.y - elementStartRegion.y); + if (DoSelectionCheck(selectionArea)) + { + if (m_SelectedLigatureRecord == i) + { + m_SelectedLigatureRecord = -1; + } + else + { + m_SelectedLigatureRecord = i; + GUIUtility.keyboardControl = 0; + } + } + + // Draw Selection Highlight and Kerning Pair Options + if (m_SelectedLigatureRecord == i) + { + // Reset other selections + ResetSelections(RecordSelectionType.LigatureSubstitutionRecord); + + TMP_EditorUtility.DrawBox(selectionArea, 2f, new Color32(40, 192, 255, 255)); + + // Draw Glyph management options + Rect controlRect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight * 1f); + float optionAreaWidth = controlRect.width; + float btnWidth = optionAreaWidth / 4; + + Rect position = new Rect(controlRect.x + controlRect.width - btnWidth, controlRect.y, btnWidth, controlRect.height); + + // Move record up + bool guiEnabled = GUI.enabled; + if (m_SelectedLigatureRecord == 0) { GUI.enabled = false; } + if (GUI.Button(new Rect(controlRect.x, controlRect.y, btnWidth, controlRect.height), "Up")) + { + SwapCharacterElements(m_LigatureSubstitutionRecords_prop, m_SelectedLigatureRecord, m_SelectedLigatureRecord - 1); + serializedObject.ApplyModifiedProperties(); + m_SelectedLigatureRecord -= 1; + isAssetDirty = true; + m_isSearchDirty = true; + m_fontAsset.InitializeLigatureSubstitutionLookupDictionary(); + } + GUI.enabled = guiEnabled; + + // Move record down + if (m_SelectedLigatureRecord == arraySize - 1) { GUI.enabled = false; } + if (GUI.Button(new Rect(controlRect.x + btnWidth, controlRect.y, btnWidth, controlRect.height), "Down")) + { + SwapCharacterElements(m_LigatureSubstitutionRecords_prop, m_SelectedLigatureRecord, m_SelectedLigatureRecord + 1); + serializedObject.ApplyModifiedProperties(); + m_SelectedLigatureRecord += 1; + isAssetDirty = true; + m_isSearchDirty = true; + m_fontAsset.InitializeLigatureSubstitutionLookupDictionary(); + } + GUI.enabled = guiEnabled; + + // Remove record + GUI.enabled = true; + if (GUI.Button(position, "Remove")) + { + GUIUtility.keyboardControl = 0; + + RemoveRecord(m_LigatureSubstitutionRecords_prop, m_SelectedLigatureRecord); + + isAssetDirty = true; + m_SelectedLigatureRecord = -1; + m_isSearchDirty = true; + break; + } + } + } + } + + DisplayAddRemoveButtons(m_LigatureSubstitutionRecords_prop, m_SelectedLigatureRecord, ligatureSubstitutionRecordCount); + + DisplayPageNavigation(ref m_CurrentLigaturePage, arraySize, itemsPerPage); + + GUILayout.Space(5); + } + #endregion + + // PAIR ADJUSTMENT TABLE + #region Pair Adjustment Table + EditorGUIUtility.labelWidth = labelWidth; + EditorGUIUtility.fieldWidth = fieldWidth; + EditorGUI.indentLevel = 0; + rect = EditorGUILayout.GetControlRect(false, 24); + + int adjustmentPairCount = m_fontAsset.fontFeatureTable.glyphPairAdjustmentRecords.Count; + + if (GUI.Button(rect, new GUIContent("Glyph Adjustment Table [" + adjustmentPairCount + "]" + (rect.width > 340 ? " Records" : ""), "List of glyph adjustment / advanced kerning pairs."), TMP_UIStyleManager.sectionHeader)) + UI_PanelState.PairAdjustmentTablePanel = !UI_PanelState.PairAdjustmentTablePanel; + + GUI.Label(rect, (UI_PanelState.PairAdjustmentTablePanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel); + + if (UI_PanelState.PairAdjustmentTablePanel) + { + int arraySize = m_GlyphPairAdjustmentRecords_prop.arraySize; + int itemsPerPage = 20; + + // Display Kerning Pair Management Tools + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + { + // Search Bar implementation + #region DISPLAY SEARCH BAR + EditorGUILayout.BeginHorizontal(); + { + EditorGUIUtility.labelWidth = 150f; + EditorGUI.BeginChangeCheck(); + string searchPattern = EditorGUILayout.TextField("Adjustment Pair Search", m_KerningTableSearchPattern, "SearchTextField"); + if (EditorGUI.EndChangeCheck() || m_isSearchDirty) + { + if (string.IsNullOrEmpty(searchPattern) == false) + { + m_KerningTableSearchPattern = searchPattern; + + // Search Glyph Table for potential matches + SearchKerningTable(m_KerningTableSearchPattern, ref m_KerningTableSearchList); + } + else + m_KerningTableSearchPattern = null; + + m_isSearchDirty = false; + } + + string styleName = string.IsNullOrEmpty(m_KerningTableSearchPattern) ? "SearchCancelButtonEmpty" : "SearchCancelButton"; + if (GUILayout.Button(GUIContent.none, styleName)) + { + GUIUtility.keyboardControl = 0; + m_KerningTableSearchPattern = string.Empty; + } + } + EditorGUILayout.EndHorizontal(); + #endregion + + // Display Page Navigation + if (!string.IsNullOrEmpty(m_KerningTableSearchPattern)) + arraySize = m_KerningTableSearchList.Count; + + DisplayPageNavigation(ref m_CurrentAdjustmentPairPage, arraySize, itemsPerPage); + } + EditorGUILayout.EndVertical(); + + if (arraySize > 0) + { + // Display each GlyphInfo entry using the GlyphInfo property drawer. + for (int i = itemsPerPage * m_CurrentAdjustmentPairPage; i < arraySize && i < itemsPerPage * (m_CurrentAdjustmentPairPage + 1); i++) + { + // Define the start of the selection region of the element. + Rect elementStartRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + + int elementIndex = i; + if (!string.IsNullOrEmpty(m_KerningTableSearchPattern)) + elementIndex = m_KerningTableSearchList[i]; + + SerializedProperty pairAdjustmentRecordProperty = m_GlyphPairAdjustmentRecords_prop.GetArrayElementAtIndex(elementIndex); + + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + + using (new EditorGUI.DisabledScope(i != m_SelectedAdjustmentRecord)) + { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(pairAdjustmentRecordProperty, new GUIContent("Selectable")); + if (EditorGUI.EndChangeCheck()) + { + UpdatePairAdjustmentRecordLookup(pairAdjustmentRecordProperty); + } + } + + EditorGUILayout.EndVertical(); + + // Define the end of the selection region of the element. + Rect elementEndRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + + // Check for Item selection + Rect selectionArea = new Rect(elementStartRegion.x, elementStartRegion.y, elementEndRegion.width, elementEndRegion.y - elementStartRegion.y); + if (DoSelectionCheck(selectionArea)) + { + if (m_SelectedAdjustmentRecord == i) + { + m_SelectedAdjustmentRecord = -1; + } + else + { + m_SelectedAdjustmentRecord = i; + GUIUtility.keyboardControl = 0; + } + } + + // Draw Selection Highlight and Kerning Pair Options + if (m_SelectedAdjustmentRecord == i) + { + // Reset other selections + ResetSelections(RecordSelectionType.AdjustmentPairRecord); + + TMP_EditorUtility.DrawBox(selectionArea, 2f, new Color32(40, 192, 255, 255)); + + // Draw Glyph management options + Rect controlRect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight * 1f); + float optionAreaWidth = controlRect.width; + float btnWidth = optionAreaWidth / 4; + + Rect position = new Rect(controlRect.x + controlRect.width - btnWidth, controlRect.y, btnWidth, controlRect.height); + + // Remove Kerning pair + GUI.enabled = true; + if (GUI.Button(position, "Remove")) + { + GUIUtility.keyboardControl = 0; + + RemoveRecord(m_GlyphPairAdjustmentRecords_prop, i); + + isAssetDirty = true; + m_SelectedAdjustmentRecord = -1; + m_isSearchDirty = true; + break; + } + } + } + } + + DisplayPageNavigation(ref m_CurrentAdjustmentPairPage, arraySize, itemsPerPage); + + GUILayout.Space(5); + + // Add new kerning pair + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_EmptyGlyphPairAdjustmentRecord_prop); + if (EditorGUI.EndChangeCheck()) + { + SetPropertyHolderGlyphIndexes(); + } + } + EditorGUILayout.EndVertical(); + + if (GUILayout.Button("Add New Glyph Adjustment Record")) + { + SerializedProperty firstAdjustmentRecordProperty = m_EmptyGlyphPairAdjustmentRecord_prop.FindPropertyRelative("m_FirstAdjustmentRecord"); + SerializedProperty secondAdjustmentRecordProperty = m_EmptyGlyphPairAdjustmentRecord_prop.FindPropertyRelative("m_SecondAdjustmentRecord"); + + uint firstGlyphIndex = (uint)firstAdjustmentRecordProperty.FindPropertyRelative("m_GlyphIndex").intValue; + uint secondGlyphIndex = (uint)secondAdjustmentRecordProperty.FindPropertyRelative("m_GlyphIndex").intValue; + + GlyphValueRecord firstValueRecord = GetValueRecord(firstAdjustmentRecordProperty.FindPropertyRelative("m_GlyphValueRecord")); + GlyphValueRecord secondValueRecord = GetValueRecord(secondAdjustmentRecordProperty.FindPropertyRelative("m_GlyphValueRecord")); + + errorCode = -1; + uint pairKey = secondGlyphIndex << 16 | firstGlyphIndex; + if (m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookup.ContainsKey(pairKey) == false) + { + GlyphPairAdjustmentRecord adjustmentRecord = new GlyphPairAdjustmentRecord(new GlyphAdjustmentRecord(firstGlyphIndex, firstValueRecord), new GlyphAdjustmentRecord(secondGlyphIndex, secondValueRecord)); + m_FontFeatureTable.m_GlyphPairAdjustmentRecords.Add(adjustmentRecord); + m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookup.Add(pairKey, adjustmentRecord); + errorCode = 0; + } + + // Add glyphs and characters + TMP_Character character; + + uint firstCharacter = m_SerializedPropertyHolder.firstCharacter; + if (!m_fontAsset.characterLookupTable.ContainsKey(firstCharacter)) + m_fontAsset.TryAddCharacterInternal(firstCharacter, out character); + + uint secondCharacter = m_SerializedPropertyHolder.secondCharacter; + if (!m_fontAsset.characterLookupTable.ContainsKey(secondCharacter)) + m_fontAsset.TryAddCharacterInternal(secondCharacter, out character); + + // Sort Kerning Pairs & Reload Font Asset if new kerning pair was added. + if (errorCode != -1) + { + m_FontFeatureTable.SortGlyphPairAdjustmentRecords(); + serializedObject.ApplyModifiedProperties(); + isAssetDirty = true; + m_isSearchDirty = true; + } + else + { + timeStamp = System.DateTime.Now.AddSeconds(5); + } + + // Clear Add Kerning Pair Panel + // TODO + } + + if (errorCode == -1) + { + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.Label("Kerning Pair already exists!", TMP_UIStyleManager.label); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + if (System.DateTime.Now > timeStamp) + errorCode = 0; + } + } + #endregion + + // MARK TO BASE Font Feature Table + #region MARK TO BASE + EditorGUIUtility.labelWidth = labelWidth; + EditorGUIUtility.fieldWidth = fieldWidth; + EditorGUI.indentLevel = 0; + rect = EditorGUILayout.GetControlRect(false, 24); + + int markToBaseAdjustmentRecordCount = m_fontAsset.fontFeatureTable.MarkToBaseAdjustmentRecords.Count; + + if (GUI.Button(rect, new GUIContent("Mark To Base Adjustment Table [" + markToBaseAdjustmentRecordCount + "]" + (rect.width > 340 ? " Records" : ""), "List of Mark to Base adjustment records."), TMP_UIStyleManager.sectionHeader)) + UI_PanelState.MarkToBaseTablePanel = !UI_PanelState.MarkToBaseTablePanel; + + GUI.Label(rect, (UI_PanelState.MarkToBaseTablePanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel); + + if (UI_PanelState.MarkToBaseTablePanel) + { + int arraySize = m_MarkToBaseAdjustmentRecords_prop.arraySize; + int itemsPerPage = 20; + + // Display Mark Adjust Records Management Tools + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + { + // Search Bar implementation + #region DISPLAY SEARCH BAR + EditorGUILayout.BeginHorizontal(); + { + EditorGUIUtility.labelWidth = 150f; + EditorGUI.BeginChangeCheck(); + string searchPattern = EditorGUILayout.TextField("Mark to Base Search", m_MarkToBaseTableSearchPattern, "SearchTextField"); + if (EditorGUI.EndChangeCheck() || m_isSearchDirty) + { + if (string.IsNullOrEmpty(searchPattern) == false) + { + m_MarkToBaseTableSearchPattern = searchPattern; + + // Search Glyph Table for potential matches + SearchMarkToBaseTable(m_MarkToBaseTableSearchPattern, ref m_MarkToBaseTableSearchList); + } + else + m_MarkToBaseTableSearchPattern = null; + + m_isSearchDirty = false; + } + + string styleName = string.IsNullOrEmpty(m_MarkToBaseTableSearchPattern) ? "SearchCancelButtonEmpty" : "SearchCancelButton"; + if (GUILayout.Button(GUIContent.none, styleName)) + { + GUIUtility.keyboardControl = 0; + m_MarkToBaseTableSearchPattern = string.Empty; + } + } + EditorGUILayout.EndHorizontal(); + #endregion + + // Display Page Navigation + if (!string.IsNullOrEmpty(m_MarkToBaseTableSearchPattern)) + arraySize = m_MarkToBaseTableSearchList.Count; + + DisplayPageNavigation(ref m_CurrentMarkToBasePage, arraySize, itemsPerPage); + } + EditorGUILayout.EndVertical(); + + if (arraySize > 0) + { + // Display each GlyphInfo entry using the GlyphInfo property drawer. + for (int i = itemsPerPage * m_CurrentMarkToBasePage; i < arraySize && i < itemsPerPage * (m_CurrentMarkToBasePage + 1); i++) + { + // Define the start of the selection region of the element. + Rect elementStartRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + + int elementIndex = i; + if (!string.IsNullOrEmpty(m_MarkToBaseTableSearchPattern)) + elementIndex = m_MarkToBaseTableSearchList[i]; + + SerializedProperty markToBasePropertyRecord = m_MarkToBaseAdjustmentRecords_prop.GetArrayElementAtIndex(elementIndex); + + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + + using (new EditorGUI.DisabledScope(i != m_SelectedMarkToBaseRecord)) + { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(markToBasePropertyRecord, new GUIContent("Selectable")); + + if (EditorGUI.EndChangeCheck()) + { + UpdateMarkToBaseAdjustmentRecordLookup(markToBasePropertyRecord); + } + } + + EditorGUILayout.EndVertical(); + + // Define the end of the selection region of the element. + Rect elementEndRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + + // Check for Item selection + Rect selectionArea = new Rect(elementStartRegion.x, elementStartRegion.y, elementEndRegion.width, elementEndRegion.y - elementStartRegion.y); + if (DoSelectionCheck(selectionArea)) + { + if (m_SelectedMarkToBaseRecord == i) + { + m_SelectedMarkToBaseRecord = -1; + } + else + { + m_SelectedMarkToBaseRecord = i; + GUIUtility.keyboardControl = 0; + } + } + + // Draw Selection Highlight and Kerning Pair Options + if (m_SelectedMarkToBaseRecord == i) + { + // Reset other selections + ResetSelections(RecordSelectionType.MarkToBaseRecord); + + TMP_EditorUtility.DrawBox(selectionArea, 2f, new Color32(40, 192, 255, 255)); + + // Draw Glyph management options + Rect controlRect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight * 1f); + float optionAreaWidth = controlRect.width; + float btnWidth = optionAreaWidth / 4; + + Rect position = new Rect(controlRect.x + controlRect.width - btnWidth, controlRect.y, btnWidth, controlRect.height); + + // Remove Mark to Base Record + GUI.enabled = true; + if (GUI.Button(position, "Remove")) + { + GUIUtility.keyboardControl = 0; + + RemoveRecord(m_MarkToBaseAdjustmentRecords_prop, i); + + isAssetDirty = true; + m_SelectedMarkToBaseRecord = -1; + m_isSearchDirty = true; + break; + } + } + } + } + + DisplayAddRemoveButtons(m_MarkToBaseAdjustmentRecords_prop, m_SelectedMarkToBaseRecord, markToBaseAdjustmentRecordCount); + + DisplayPageNavigation(ref m_CurrentMarkToBasePage, arraySize, itemsPerPage); + + GUILayout.Space(5); + } + #endregion + + // MARK TO MARK Font Feature Table + #region MARK TO MARK + EditorGUIUtility.labelWidth = labelWidth; + EditorGUIUtility.fieldWidth = fieldWidth; + EditorGUI.indentLevel = 0; + rect = EditorGUILayout.GetControlRect(false, 24); + + int markToMarkAdjustmentRecordCount = m_fontAsset.fontFeatureTable.MarkToMarkAdjustmentRecords.Count; + + if (GUI.Button(rect, new GUIContent("Mark To Mark Adjustment Table [" + markToMarkAdjustmentRecordCount + "]" + (rect.width > 340 ? " Records" : ""), "List of Mark to Mark adjustment records."), TMP_UIStyleManager.sectionHeader)) + UI_PanelState.MarkToMarkTablePanel = !UI_PanelState.MarkToMarkTablePanel; + + GUI.Label(rect, (UI_PanelState.MarkToMarkTablePanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel); + + if (UI_PanelState.MarkToMarkTablePanel) + { + int arraySize = m_MarkToMarkAdjustmentRecords_prop.arraySize; + int itemsPerPage = 20; + + // Display Kerning Pair Management Tools + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + { + // Search Bar implementation + #region DISPLAY SEARCH BAR + EditorGUILayout.BeginHorizontal(); + { + EditorGUIUtility.labelWidth = 150f; + EditorGUI.BeginChangeCheck(); + string searchPattern = EditorGUILayout.TextField("Mark to Mark Search", m_MarkToMarkTableSearchPattern, "SearchTextField"); + if (EditorGUI.EndChangeCheck() || m_isSearchDirty) + { + if (string.IsNullOrEmpty(searchPattern) == false) + { + m_MarkToMarkTableSearchPattern = searchPattern; + + // Search Glyph Table for potential matches + SearchMarkToMarkTable(m_MarkToMarkTableSearchPattern, ref m_MarkToMarkTableSearchList); + } + else + m_MarkToMarkTableSearchPattern = null; + + m_isSearchDirty = false; + } + + string styleName = string.IsNullOrEmpty(m_MarkToMarkTableSearchPattern) ? "SearchCancelButtonEmpty" : "SearchCancelButton"; + if (GUILayout.Button(GUIContent.none, styleName)) + { + GUIUtility.keyboardControl = 0; + m_MarkToMarkTableSearchPattern = string.Empty; + } + } + EditorGUILayout.EndHorizontal(); + #endregion + + // Display Page Navigation + if (!string.IsNullOrEmpty(m_MarkToMarkTableSearchPattern)) + arraySize = m_MarkToMarkTableSearchList.Count; + + DisplayPageNavigation(ref m_CurrentMarkToMarkPage, arraySize, itemsPerPage); + } + EditorGUILayout.EndVertical(); + + if (arraySize > 0) + { + // Display each GlyphInfo entry using the GlyphInfo property drawer. + for (int i = itemsPerPage * m_CurrentMarkToMarkPage; i < arraySize && i < itemsPerPage * (m_CurrentMarkToMarkPage + 1); i++) + { + // Define the start of the selection region of the element. + Rect elementStartRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + + int elementIndex = i; + if (!string.IsNullOrEmpty(m_MarkToMarkTableSearchPattern)) + elementIndex = m_MarkToMarkTableSearchList[i]; + + SerializedProperty markToMarkPropertyRecord = m_MarkToMarkAdjustmentRecords_prop.GetArrayElementAtIndex(elementIndex); + + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + + using (new EditorGUI.DisabledScope(i != m_SelectedMarkToMarkRecord)) + { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(markToMarkPropertyRecord, new GUIContent("Selectable")); + + if (EditorGUI.EndChangeCheck()) + { + UpdateMarkToMarkAdjustmentRecordLookup(markToMarkPropertyRecord); + } + } + + EditorGUILayout.EndVertical(); + + // Define the end of the selection region of the element. + Rect elementEndRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + + // Check for Item selection + Rect selectionArea = new Rect(elementStartRegion.x, elementStartRegion.y, elementEndRegion.width, elementEndRegion.y - elementStartRegion.y); + if (DoSelectionCheck(selectionArea)) + { + if (m_SelectedMarkToMarkRecord == i) + { + m_SelectedMarkToMarkRecord = -1; + } + else + { + m_SelectedMarkToMarkRecord = i; + GUIUtility.keyboardControl = 0; + } + } + + // Draw Selection Highlight and Kerning Pair Options + if (m_SelectedMarkToMarkRecord == i) + { + // Reset other selections + ResetSelections(RecordSelectionType.MarkToMarkRecord); + + TMP_EditorUtility.DrawBox(selectionArea, 2f, new Color32(40, 192, 255, 255)); + + // Draw Glyph management options + Rect controlRect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight * 1f); + float optionAreaWidth = controlRect.width; + float btnWidth = optionAreaWidth / 4; + + Rect position = new Rect(controlRect.x + controlRect.width - btnWidth, controlRect.y, btnWidth, controlRect.height); + + // Remove Mark to Base Record + GUI.enabled = true; + if (GUI.Button(position, "Remove")) + { + GUIUtility.keyboardControl = 0; + + RemoveRecord(m_MarkToMarkAdjustmentRecords_prop, i); + + isAssetDirty = true; + m_SelectedMarkToMarkRecord = -1; + m_isSearchDirty = true; + break; + } + } + } + } + + DisplayAddRemoveButtons(m_MarkToMarkAdjustmentRecords_prop, m_SelectedMarkToMarkRecord, markToMarkAdjustmentRecordCount); + + DisplayPageNavigation(ref m_CurrentMarkToMarkPage, arraySize, itemsPerPage); + + GUILayout.Space(5); + } + #endregion + + if (serializedObject.ApplyModifiedProperties() || evt_cmd == k_UndoRedo || isAssetDirty || m_IsFallbackGlyphCacheDirty) + { + // Delay callback until user has decided to Apply or Revert the changes. + if (m_DisplayDestructiveChangeWarning == false) + { + TMP_ResourceManager.RebuildFontAssetCache(); + TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(true, m_fontAsset); + m_IsFallbackGlyphCacheDirty = false; + } + + if (m_fontAsset.IsFontAssetLookupTablesDirty || evt_cmd == k_UndoRedo) + m_fontAsset.ReadFontAssetDefinition(); + + isAssetDirty = false; + EditorUtility.SetDirty(target); + } + + + // Clear selection if mouse event was not consumed. + GUI.enabled = true; + if (currentEvent.type == EventType.MouseDown && currentEvent.button == 0) + { + m_SelectedAdjustmentRecord = -1; + m_SelectedMarkToBaseRecord = -1; + m_SelectedMarkToMarkRecord = -1; + } + } + + /// + /// Overrided method from the Editor class. + /// + /// + public override bool HasPreviewGUI() + { + return true; + } + + /// + /// Overrided method to implement custom preview inspector. + /// + /// + /// + public override void OnPreviewGUI(Rect rect, GUIStyle background) + { + if (m_SelectedMarkToBaseRecord != -1) + DrawMarkToBasePreview(m_SelectedMarkToBaseRecord, rect); + + if (m_SelectedMarkToMarkRecord != -1) + DrawMarkToMarkPreview(m_SelectedMarkToMarkRecord, rect); + + } + + void ResetSelections(RecordSelectionType type) + { + switch (type) + { + case RecordSelectionType.CharacterRecord: + m_SelectedGlyphRecord = -1; + m_SelectedLigatureRecord = -1; + m_SelectedAdjustmentRecord = -1; + m_SelectedMarkToBaseRecord = -1; + m_SelectedMarkToMarkRecord = -1; + break; + case RecordSelectionType.GlyphRecord: + m_SelectedCharacterRecord = -1; + m_SelectedLigatureRecord = -1; + m_SelectedAdjustmentRecord = -1; + m_SelectedMarkToBaseRecord = -1; + m_SelectedMarkToMarkRecord = -1; + break; + case RecordSelectionType.LigatureSubstitutionRecord: + m_SelectedCharacterRecord = -1; + m_SelectedGlyphRecord = -1; + m_SelectedAdjustmentRecord = -1; + m_SelectedMarkToBaseRecord = -1; + m_SelectedMarkToMarkRecord = -1; + break; + case RecordSelectionType.AdjustmentPairRecord: + m_SelectedCharacterRecord = -1; + m_SelectedGlyphRecord = -1; + m_SelectedLigatureRecord = -1; + m_SelectedMarkToBaseRecord = -1; + m_SelectedMarkToMarkRecord = -1; + break; + case RecordSelectionType.MarkToBaseRecord: + m_SelectedCharacterRecord = -1; + m_SelectedGlyphRecord = -1; + m_SelectedLigatureRecord = -1; + m_SelectedAdjustmentRecord = -1; + m_SelectedMarkToMarkRecord = -1; + break; + case RecordSelectionType.MarkToMarkRecord: + m_SelectedCharacterRecord = -1; + m_SelectedGlyphRecord = -1; + m_SelectedLigatureRecord = -1; + m_SelectedAdjustmentRecord = -1; + m_SelectedMarkToBaseRecord = -1; + break; + } + } + + + string[] GetFontFaces() + { + return GetFontFaces(m_FontFaceIndex_prop.intValue); + } + + string[] GetFontFaces(int faceIndex) + { +#if UNITY_2023_3_OR_NEWER + if (LoadFontFace((int)m_SamplingPointSize_prop.floatValue, faceIndex) == FontEngineError.Success) +#else + if (LoadFontFace(m_SamplingPointSize_prop.intValue, faceIndex) == FontEngineError.Success) +#endif + return FontEngine.GetFontFaces(); + + return k_InvalidFontFaces; + } + + FontEngineError LoadFontFace(int pointSize, int faceIndex) + { + if (m_fontAsset.SourceFont_EditorRef != null) + { + if (FontEngine.LoadFontFace(m_fontAsset.SourceFont_EditorRef, pointSize, faceIndex) == FontEngineError.Success) + return FontEngineError.Success; + } + + // Requires Unity 2018.4.35f1 + return FontEngine.LoadFontFace(m_fontAsset.faceInfo.familyName, m_fontAsset.faceInfo.styleName, pointSize); + } + + + void CleanFallbackFontAssetTable() + { + SerializedProperty m_FallbackFontAsseTable = serializedObject.FindProperty("m_FallbackFontAssetTable"); + + bool isListDirty = false; + + int elementCount = m_FallbackFontAsseTable.arraySize; + + for (int i = 0; i < elementCount; i++) + { + SerializedProperty element = m_FallbackFontAsseTable.GetArrayElementAtIndex(i); + if (element.objectReferenceValue == null) + { + m_FallbackFontAsseTable.DeleteArrayElementAtIndex(i); + elementCount -= 1; + i -= 1; + + isListDirty = true; + } + } + + if (isListDirty) + { + serializedObject.ApplyModifiedProperties(); + serializedObject.Update(); + } + } + + + void SavedGenerationSettings() + { + m_GenerationSettings.faceIndex = m_FontFaceIndex_prop.intValue; + m_GenerationSettings.glyphRenderMode = (GlyphRenderMode)m_AtlasRenderMode_prop.intValue; +#if UNITY_2023_3_OR_NEWER + m_GenerationSettings.pointSize = (int)m_SamplingPointSize_prop.floatValue; +#else + m_GenerationSettings.pointSize = m_SamplingPointSize_prop.intValue; +#endif + m_GenerationSettings.padding = m_AtlasPadding_prop.intValue; + m_GenerationSettings.atlasWidth = m_AtlasWidth_prop.intValue; + m_GenerationSettings.atlasHeight = m_AtlasHeight_prop.intValue; + } + + void RestoreGenerationSettings() + { + m_fontAsset.SourceFont_EditorRef = m_GenerationSettings.sourceFont; + m_FontFaceIndex_prop.intValue = m_GenerationSettings.faceIndex; +#if UNITY_2023_3_OR_NEWER + m_SamplingPointSize_prop.floatValue = m_GenerationSettings.pointSize; +#else + m_SamplingPointSize_prop.intValue = m_GenerationSettings.pointSize; +#endif + m_FontFaces = GetFontFaces(); + + m_AtlasRenderMode_prop.intValue = (int)m_GenerationSettings.glyphRenderMode; + m_AtlasPadding_prop.intValue = m_GenerationSettings.padding; + m_AtlasWidth_prop.intValue = m_GenerationSettings.atlasWidth; + m_AtlasHeight_prop.intValue = m_GenerationSettings.atlasHeight; + } + + + void UpdateFontAssetCreationSettings() + { + m_fontAsset.m_CreationSettings.faceIndex = m_FontFaceIndex_prop.intValue; +#if UNITY_2023_3_OR_NEWER + m_fontAsset.m_CreationSettings.pointSize = (int)m_SamplingPointSize_prop.floatValue; +#else + m_fontAsset.m_CreationSettings.pointSize = m_SamplingPointSize_prop.intValue; +#endif + m_fontAsset.m_CreationSettings.renderMode = m_AtlasRenderMode_prop.intValue; + m_fontAsset.m_CreationSettings.padding = m_AtlasPadding_prop.intValue; + m_fontAsset.m_CreationSettings.atlasWidth = m_AtlasWidth_prop.intValue; + m_fontAsset.m_CreationSettings.atlasHeight = m_AtlasHeight_prop.intValue; + } + + + void UpdateCharacterData(SerializedProperty property, int index) + { + TMP_Character character = m_fontAsset.characterTable[index]; + + character.unicode = (uint)property.FindPropertyRelative("m_Unicode").intValue; + character.scale = property.FindPropertyRelative("m_Scale").floatValue; + + SerializedProperty glyphProperty = property.FindPropertyRelative("m_Glyph"); + character.glyph.index = (uint)glyphProperty.FindPropertyRelative("m_Index").intValue; + + SerializedProperty glyphRectProperty = glyphProperty.FindPropertyRelative("m_GlyphRect"); + character.glyph.glyphRect = new GlyphRect(glyphRectProperty.FindPropertyRelative("m_X").intValue, glyphRectProperty.FindPropertyRelative("m_Y").intValue, glyphRectProperty.FindPropertyRelative("m_Width").intValue, glyphRectProperty.FindPropertyRelative("m_Height").intValue); + + SerializedProperty glyphMetricsProperty = glyphProperty.FindPropertyRelative("m_Metrics"); + character.glyph.metrics = new GlyphMetrics(glyphMetricsProperty.FindPropertyRelative("m_Width").floatValue, glyphMetricsProperty.FindPropertyRelative("m_Height").floatValue, glyphMetricsProperty.FindPropertyRelative("m_HorizontalBearingX").floatValue, glyphMetricsProperty.FindPropertyRelative("m_HorizontalBearingY").floatValue, glyphMetricsProperty.FindPropertyRelative("m_HorizontalAdvance").floatValue); + + character.glyph.scale = glyphProperty.FindPropertyRelative("m_Scale").floatValue; + + character.glyph.atlasIndex = glyphProperty.FindPropertyRelative("m_AtlasIndex").intValue; + } + + + void UpdateGlyphData(SerializedProperty property, int index) + { + Glyph glyph = m_fontAsset.glyphTable[index]; + + glyph.index = (uint)property.FindPropertyRelative("m_Index").intValue; + + SerializedProperty glyphRect = property.FindPropertyRelative("m_GlyphRect"); + glyph.glyphRect = new GlyphRect(glyphRect.FindPropertyRelative("m_X").intValue, glyphRect.FindPropertyRelative("m_Y").intValue, glyphRect.FindPropertyRelative("m_Width").intValue, glyphRect.FindPropertyRelative("m_Height").intValue); + + SerializedProperty glyphMetrics = property.FindPropertyRelative("m_Metrics"); + glyph.metrics = new GlyphMetrics(glyphMetrics.FindPropertyRelative("m_Width").floatValue, glyphMetrics.FindPropertyRelative("m_Height").floatValue, glyphMetrics.FindPropertyRelative("m_HorizontalBearingX").floatValue, glyphMetrics.FindPropertyRelative("m_HorizontalBearingY").floatValue, glyphMetrics.FindPropertyRelative("m_HorizontalAdvance").floatValue); + + glyph.scale = property.FindPropertyRelative("m_Scale").floatValue; + } + + + void DisplayAddRemoveButtons(SerializedProperty property, int selectedRecord, int recordCount) + { + Rect rect = EditorGUILayout.GetControlRect(false, 20); + + rect.width /= 6; + // Add Style + rect.x = rect.width * 4 + 17; + if (GUI.Button(rect, "+")) + { + int index = selectedRecord == -1 ? 0 : selectedRecord; + + if (index > recordCount) + index = recordCount; + + // Copy selected element + property.InsertArrayElementAtIndex(index); + + // Select newly inserted element + selectedRecord = index + 1; + + serializedObject.ApplyModifiedProperties(); + + m_fontAsset.ReadFontAssetDefinition(); + + } + + // Delete style + rect.x += rect.width; + if (selectedRecord == -1 || selectedRecord >= recordCount) GUI.enabled = false; + if (GUI.Button(rect, "-")) + { + int index = selectedRecord == -1 ? 0 : selectedRecord; + + property.DeleteArrayElementAtIndex(index); + + selectedRecord = -1; + serializedObject.ApplyModifiedProperties(); + + m_fontAsset.ReadFontAssetDefinition(); + return; + } + + GUI.enabled = true; + } + + + void DisplayPageNavigation(ref int currentPage, int arraySize, int itemsPerPage) + { + Rect pagePos = EditorGUILayout.GetControlRect(false, 20); + pagePos.width /= 3; + + int shiftMultiplier = Event.current.shift ? 10 : 1; // Page + Shift goes 10 page forward + + // Previous Page + GUI.enabled = currentPage > 0; + + if (GUI.Button(pagePos, "Previous Page")) + currentPage -= 1 * shiftMultiplier; + + + // Page Counter + GUI.enabled = true; + pagePos.x += pagePos.width; + int totalPages = (int)(arraySize / (float)itemsPerPage + 0.999f); + GUI.Label(pagePos, "Page " + (currentPage + 1) + " / " + totalPages, TMP_UIStyleManager.centeredLabel); + + // Next Page + pagePos.x += pagePos.width; + GUI.enabled = itemsPerPage * (currentPage + 1) < arraySize; + + if (GUI.Button(pagePos, "Next Page")) + currentPage += 1 * shiftMultiplier; + + // Clamp page range + currentPage = Mathf.Clamp(currentPage, 0, arraySize / itemsPerPage); + + GUI.enabled = true; + } + + + /// + /// + /// + /// + /// + bool AddNewGlyph(int srcIndex, int dstGlyphID) + { + // Make sure Destination Glyph ID doesn't already contain a Glyph + if (m_fontAsset.glyphLookupTable.ContainsKey((uint)dstGlyphID)) + return false; + + // Add new element to glyph list. + m_GlyphTable_prop.arraySize += 1; + + // Get a reference to the source glyph. + SerializedProperty sourceGlyph = m_GlyphTable_prop.GetArrayElementAtIndex(srcIndex); + + int dstIndex = m_GlyphTable_prop.arraySize - 1; + + // Get a reference to the target / destination glyph. + SerializedProperty targetGlyph = m_GlyphTable_prop.GetArrayElementAtIndex(dstIndex); + + CopyGlyphSerializedProperty(sourceGlyph, ref targetGlyph); + + // Update the ID of the glyph + targetGlyph.FindPropertyRelative("m_Index").intValue = dstGlyphID; + + serializedObject.ApplyModifiedProperties(); + + m_fontAsset.SortGlyphTable(); + + m_fontAsset.ReadFontAssetDefinition(); + + return true; + } + + /// + /// + /// + /// + void RemoveGlyphFromList(int index) + { + if (index > m_GlyphTable_prop.arraySize) + return; + + int targetGlyphIndex = m_GlyphTable_prop.GetArrayElementAtIndex(index).FindPropertyRelative("m_Index").intValue; + + m_GlyphTable_prop.DeleteArrayElementAtIndex(index); + + // Remove all characters referencing this glyph. + for (int i = 0; i < m_CharacterTable_prop.arraySize; i++) + { + int glyphIndex = m_CharacterTable_prop.GetArrayElementAtIndex(i).FindPropertyRelative("m_GlyphIndex").intValue; + + if (glyphIndex == targetGlyphIndex) + { + // Remove character + m_CharacterTable_prop.DeleteArrayElementAtIndex(i); + } + } + + serializedObject.ApplyModifiedProperties(); + + m_fontAsset.ReadFontAssetDefinition(); + } + + bool AddNewCharacter(int srcIndex, int dstGlyphID) + { + // Make sure Destination Glyph ID doesn't already contain a Glyph + if (m_fontAsset.characterLookupTable.ContainsKey((uint)dstGlyphID)) + return false; + + // Add new element to glyph list. + m_CharacterTable_prop.arraySize += 1; + + // Get a reference to the source glyph. + SerializedProperty sourceCharacter = m_CharacterTable_prop.GetArrayElementAtIndex(srcIndex); + + int dstIndex = m_CharacterTable_prop.arraySize - 1; + + // Get a reference to the target / destination glyph. + SerializedProperty targetCharacter = m_CharacterTable_prop.GetArrayElementAtIndex(dstIndex); + + CopyCharacterSerializedProperty(sourceCharacter, ref targetCharacter); + + // Update the ID of the glyph + targetCharacter.FindPropertyRelative("m_Unicode").intValue = dstGlyphID; + + serializedObject.ApplyModifiedProperties(); + + m_fontAsset.SortCharacterTable(); + + m_fontAsset.ReadFontAssetDefinition(); + + return true; + } + + void RemoveCharacterFromList(int index) + { + if (index > m_CharacterTable_prop.arraySize) + return; + + m_CharacterTable_prop.DeleteArrayElementAtIndex(index); + + serializedObject.ApplyModifiedProperties(); + + m_fontAsset.ReadFontAssetDefinition(); + } + + void AddNewGlyphsFromProperty(SerializedProperty property) + { + if (m_GlyphsToAdd == null) + m_GlyphsToAdd = new HashSet(); + else + m_GlyphsToAdd.Clear(); + + string propertyType = property.type; + + switch (propertyType) + { + case "LigatureSubstitutionRecord": + int componentCount = property.FindPropertyRelative("m_ComponentGlyphIDs").arraySize; + for (int i = 0; i < componentCount; i++) + { + uint glyphIndex = (uint)property.FindPropertyRelative("m_ComponentGlyphIDs").GetArrayElementAtIndex(i).intValue; + m_GlyphsToAdd.Add(glyphIndex); + } + + m_GlyphsToAdd.Add((uint)property.FindPropertyRelative("m_LigatureGlyphID").intValue); + + foreach (uint glyphIndex in m_GlyphsToAdd) + { + if (glyphIndex != 0) + m_fontAsset.AddGlyphInternal(glyphIndex); + } + + break; + } + + } + + + // Check if any of the Style elements were clicked on. + private bool DoSelectionCheck(Rect selectionArea) + { + Event currentEvent = Event.current; + + switch (currentEvent.type) + { + case EventType.MouseDown: + if (selectionArea.Contains(currentEvent.mousePosition) && currentEvent.button == 0) + { + currentEvent.Use(); + return true; + } + + break; + } + + return false; + } + + private void UpdateLigatureSubstitutionRecordLookup(SerializedProperty property) + { + serializedObject.ApplyModifiedProperties(); + AddNewGlyphsFromProperty(property); + m_fontAsset.InitializeLigatureSubstitutionLookupDictionary(); + isAssetDirty = true; + } + + void SetPropertyHolderGlyphIndexes() + { + uint firstCharacterUnicode = (uint)m_FirstCharacterUnicode_prop.intValue; + if (firstCharacterUnicode != 0) + { + uint glyphIndex = m_fontAsset.GetGlyphIndex(firstCharacterUnicode); + if (glyphIndex != 0) + m_EmptyGlyphPairAdjustmentRecord_prop.FindPropertyRelative("m_FirstAdjustmentRecord").FindPropertyRelative("m_GlyphIndex").intValue = (int)glyphIndex; + } + + uint secondCharacterUnicode = (uint)m_SecondCharacterUnicode_prop.intValue; + if (secondCharacterUnicode != 0) + { + uint glyphIndex = m_fontAsset.GetGlyphIndex(secondCharacterUnicode); + if (glyphIndex != 0) + m_EmptyGlyphPairAdjustmentRecord_prop.FindPropertyRelative("m_SecondAdjustmentRecord").FindPropertyRelative("m_GlyphIndex").intValue = (int)glyphIndex; + } + } + + private void UpdatePairAdjustmentRecordLookup(SerializedProperty property) + { + GlyphPairAdjustmentRecord pairAdjustmentRecord = GetGlyphPairAdjustmentRecord(property); + + uint firstGlyphIndex = pairAdjustmentRecord.firstAdjustmentRecord.glyphIndex; + uint secondGlyphIndex = pairAdjustmentRecord.secondAdjustmentRecord.glyphIndex; + + uint key = secondGlyphIndex << 16 | firstGlyphIndex; + + // Lookup dictionary entry and update it + if (m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookup.ContainsKey(key)) + m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookup[key] = pairAdjustmentRecord; + } + + GlyphPairAdjustmentRecord GetGlyphPairAdjustmentRecord(SerializedProperty property) + { + GlyphPairAdjustmentRecord pairAdjustmentRecord = new GlyphPairAdjustmentRecord(); + + SerializedProperty firstAdjustmentRecordProperty = property.FindPropertyRelative("m_FirstAdjustmentRecord"); + uint firstGlyphIndex = (uint)firstAdjustmentRecordProperty.FindPropertyRelative("m_GlyphIndex").intValue; + GlyphValueRecord firstValueRecord = GetValueRecord(firstAdjustmentRecordProperty.FindPropertyRelative("m_GlyphValueRecord")); + + pairAdjustmentRecord.firstAdjustmentRecord = new GlyphAdjustmentRecord(firstGlyphIndex, firstValueRecord); + + SerializedProperty secondAdjustmentRecordProperty = property.FindPropertyRelative("m_SecondAdjustmentRecord"); + uint secondGlyphIndex = (uint)secondAdjustmentRecordProperty.FindPropertyRelative("m_GlyphIndex").intValue; + GlyphValueRecord secondValueRecord = GetValueRecord(secondAdjustmentRecordProperty.FindPropertyRelative("m_GlyphValueRecord")); + + pairAdjustmentRecord.secondAdjustmentRecord = new GlyphAdjustmentRecord(secondGlyphIndex, secondValueRecord); + + // TODO : Need to revise how Everything is handled in the event more enum values are added. + int flagValue = property.FindPropertyRelative("m_FeatureLookupFlags").intValue; + //pairAdjustmentRecord.featureLookupFlags = flagValue == -1 ? FontFeatureLookupFlags.IgnoreLigatures | FontFeatureLookupFlags.IgnoreSpacingAdjustments : (FontFeatureLookupFlags) flagValue; + + return pairAdjustmentRecord; + } + + void SwapCharacterElements(SerializedProperty property, int selectedIndex, int newIndex) + { + property.MoveArrayElement(selectedIndex, newIndex); + } + + void RemoveRecord(SerializedProperty property, int index) + { + if (index > property.arraySize) + return; + + property.DeleteArrayElementAtIndex(index); + + serializedObject.ApplyModifiedProperties(); + + m_fontAsset.ReadFontAssetDefinition(); + } + + GlyphValueRecord GetValueRecord(SerializedProperty property) + { + GlyphValueRecord record = new GlyphValueRecord(); + record.xPlacement = property.FindPropertyRelative("m_XPlacement").floatValue; + record.yPlacement = property.FindPropertyRelative("m_YPlacement").floatValue; + record.xAdvance = property.FindPropertyRelative("m_XAdvance").floatValue; + record.yAdvance = property.FindPropertyRelative("m_YAdvance").floatValue; + + return record; + } + + private void UpdateMarkToBaseAdjustmentRecordLookup(SerializedProperty property) + { + MarkToBaseAdjustmentRecord adjustmentRecord = GetMarkToBaseAdjustmentRecord(property); + + uint firstGlyphIndex = adjustmentRecord.baseGlyphID; + uint secondGlyphIndex = adjustmentRecord.markGlyphID; + + uint key = secondGlyphIndex << 16 | firstGlyphIndex; + + // Lookup dictionary entry and update it + if (m_FontFeatureTable.m_MarkToBaseAdjustmentRecordLookup.ContainsKey(key)) + m_FontFeatureTable.m_MarkToBaseAdjustmentRecordLookup[key] = adjustmentRecord; + } + + MarkToBaseAdjustmentRecord GetMarkToBaseAdjustmentRecord(SerializedProperty property) + { + MarkToBaseAdjustmentRecord adjustmentRecord = new MarkToBaseAdjustmentRecord(); + + adjustmentRecord.baseGlyphID = (uint)property.FindPropertyRelative("m_BaseGlyphID").intValue; + SerializedProperty baseAnchorPointProperty = property.FindPropertyRelative("m_BaseGlyphAnchorPoint"); + + GlyphAnchorPoint baseAnchorPoint = new GlyphAnchorPoint(); + baseAnchorPoint.xCoordinate = baseAnchorPointProperty.FindPropertyRelative("m_XCoordinate").floatValue; + baseAnchorPoint.yCoordinate = baseAnchorPointProperty.FindPropertyRelative("m_YCoordinate").floatValue; + adjustmentRecord.baseGlyphAnchorPoint = baseAnchorPoint; + + adjustmentRecord.markGlyphID = (uint)property.FindPropertyRelative("m_MarkGlyphID").intValue; + SerializedProperty markAdjustmentRecordProperty = property.FindPropertyRelative("m_MarkPositionAdjustment"); + + MarkPositionAdjustment markAdjustmentRecord = new MarkPositionAdjustment(); + markAdjustmentRecord.xPositionAdjustment = markAdjustmentRecordProperty.FindPropertyRelative("m_XPositionAdjustment").floatValue; + markAdjustmentRecord.yPositionAdjustment = markAdjustmentRecordProperty.FindPropertyRelative("m_YPositionAdjustment").floatValue; + adjustmentRecord.markPositionAdjustment = markAdjustmentRecord; + + return adjustmentRecord; + } + + private void UpdateMarkToMarkAdjustmentRecordLookup(SerializedProperty property) + { + MarkToMarkAdjustmentRecord adjustmentRecord = GetMarkToMarkAdjustmentRecord(property); + + uint firstGlyphIndex = adjustmentRecord.baseMarkGlyphID; + uint secondGlyphIndex = adjustmentRecord.combiningMarkGlyphID; + + uint key = secondGlyphIndex << 16 | firstGlyphIndex; + + // Lookup dictionary entry and update it + if (m_FontFeatureTable.m_MarkToMarkAdjustmentRecordLookup.ContainsKey(key)) + m_FontFeatureTable.m_MarkToMarkAdjustmentRecordLookup[key] = adjustmentRecord; + } + + MarkToMarkAdjustmentRecord GetMarkToMarkAdjustmentRecord(SerializedProperty property) + { + MarkToMarkAdjustmentRecord adjustmentRecord = new MarkToMarkAdjustmentRecord(); + + adjustmentRecord.baseMarkGlyphID = (uint)property.FindPropertyRelative("m_BaseMarkGlyphID").intValue; + SerializedProperty baseAnchorPointProperty = property.FindPropertyRelative("m_BaseMarkGlyphAnchorPoint"); + + GlyphAnchorPoint baseAnchorPoint = new GlyphAnchorPoint(); + baseAnchorPoint.xCoordinate = baseAnchorPointProperty.FindPropertyRelative("m_XCoordinate").floatValue; + baseAnchorPoint.yCoordinate = baseAnchorPointProperty.FindPropertyRelative("m_YCoordinate").floatValue; + adjustmentRecord.baseMarkGlyphAnchorPoint = baseAnchorPoint; + + adjustmentRecord.combiningMarkGlyphID = (uint)property.FindPropertyRelative("m_CombiningMarkGlyphID").intValue; + SerializedProperty markAdjustmentRecordProperty = property.FindPropertyRelative("m_CombiningMarkPositionAdjustment"); + + MarkPositionAdjustment markAdjustment = new MarkPositionAdjustment(); + markAdjustment.xPositionAdjustment = markAdjustmentRecordProperty.FindPropertyRelative("m_XPositionAdjustment").floatValue; + markAdjustment.yPositionAdjustment = markAdjustmentRecordProperty.FindPropertyRelative("m_YPositionAdjustment").floatValue; + adjustmentRecord.combiningMarkPositionAdjustment = markAdjustment; + + return adjustmentRecord; + } + + /// + /// + /// + /// + /// + void CopyGlyphSerializedProperty(SerializedProperty srcGlyph, ref SerializedProperty dstGlyph) + { + // TODO : Should make a generic function which copies each of the properties. + dstGlyph.FindPropertyRelative("m_Index").intValue = srcGlyph.FindPropertyRelative("m_Index").intValue; + + // Glyph -> GlyphMetrics + SerializedProperty srcGlyphMetrics = srcGlyph.FindPropertyRelative("m_Metrics"); + SerializedProperty dstGlyphMetrics = dstGlyph.FindPropertyRelative("m_Metrics"); + + dstGlyphMetrics.FindPropertyRelative("m_Width").floatValue = srcGlyphMetrics.FindPropertyRelative("m_Width").floatValue; + dstGlyphMetrics.FindPropertyRelative("m_Height").floatValue = srcGlyphMetrics.FindPropertyRelative("m_Height").floatValue; + dstGlyphMetrics.FindPropertyRelative("m_HorizontalBearingX").floatValue = srcGlyphMetrics.FindPropertyRelative("m_HorizontalBearingX").floatValue; + dstGlyphMetrics.FindPropertyRelative("m_HorizontalBearingY").floatValue = srcGlyphMetrics.FindPropertyRelative("m_HorizontalBearingY").floatValue; + dstGlyphMetrics.FindPropertyRelative("m_HorizontalAdvance").floatValue = srcGlyphMetrics.FindPropertyRelative("m_HorizontalAdvance").floatValue; + + // Glyph -> GlyphRect + SerializedProperty srcGlyphRect = srcGlyph.FindPropertyRelative("m_GlyphRect"); + SerializedProperty dstGlyphRect = dstGlyph.FindPropertyRelative("m_GlyphRect"); + + dstGlyphRect.FindPropertyRelative("m_X").intValue = srcGlyphRect.FindPropertyRelative("m_X").intValue; + dstGlyphRect.FindPropertyRelative("m_Y").intValue = srcGlyphRect.FindPropertyRelative("m_Y").intValue; + dstGlyphRect.FindPropertyRelative("m_Width").intValue = srcGlyphRect.FindPropertyRelative("m_Width").intValue; + dstGlyphRect.FindPropertyRelative("m_Height").intValue = srcGlyphRect.FindPropertyRelative("m_Height").intValue; + + dstGlyph.FindPropertyRelative("m_Scale").floatValue = srcGlyph.FindPropertyRelative("m_Scale").floatValue; + dstGlyph.FindPropertyRelative("m_AtlasIndex").intValue = srcGlyph.FindPropertyRelative("m_AtlasIndex").intValue; + } + + + void CopyCharacterSerializedProperty(SerializedProperty source, ref SerializedProperty target) + { + // TODO : Should make a generic function which copies each of the properties. + int unicode = source.FindPropertyRelative("m_Unicode").intValue; + target.FindPropertyRelative("m_Unicode").intValue = unicode; + + int srcGlyphIndex = source.FindPropertyRelative("m_GlyphIndex").intValue; + target.FindPropertyRelative("m_GlyphIndex").intValue = srcGlyphIndex; + + target.FindPropertyRelative("m_Scale").floatValue = source.FindPropertyRelative("m_Scale").floatValue; + } + + + /// + /// + /// + /// + /// + void SearchGlyphTable(string searchPattern, ref List searchResults) + { + if (searchResults == null) searchResults = new List(); + + searchResults.Clear(); + + int arraySize = m_GlyphTable_prop.arraySize; + + for (int i = 0; i < arraySize; i++) + { + SerializedProperty sourceGlyph = m_GlyphTable_prop.GetArrayElementAtIndex(i); + + int id = sourceGlyph.FindPropertyRelative("m_Index").intValue; + + // Check for potential match against a character. + //if (searchPattern.Length == 1 && id == searchPattern[0]) + // searchResults.Add(i); + + // Check for potential match against decimal id + if (id.ToString().Contains(searchPattern)) + searchResults.Add(i); + + //if (id.ToString("x").Contains(searchPattern)) + // searchResults.Add(i); + + //if (id.ToString("X").Contains(searchPattern)) + // searchResults.Add(i); + } + } + + + void SearchCharacterTable(string searchPattern, ref List searchResults) + { + if (searchResults == null) searchResults = new List(); + + searchResults.Clear(); + + int arraySize = m_CharacterTable_prop.arraySize; + + for (int i = 0; i < arraySize; i++) + { + SerializedProperty sourceCharacter = m_CharacterTable_prop.GetArrayElementAtIndex(i); + + int id = sourceCharacter.FindPropertyRelative("m_Unicode").intValue; + + // Check for potential match against a character. + if (searchPattern.Length == 1 && id == searchPattern[0]) + searchResults.Add(i); + else if (id.ToString("x").Contains(searchPattern)) + searchResults.Add(i); + else if (id.ToString("X").Contains(searchPattern)) + searchResults.Add(i); + + // Check for potential match against decimal id + //if (id.ToString().Contains(searchPattern)) + // searchResults.Add(i); + } + } + + void SearchLigatureTable(string searchPattern, ref List searchResults) + { + if (searchResults == null) searchResults = new List(); + + searchResults.Clear(); + + // Lookup glyph index of potential characters contained in the search pattern. + uint firstGlyphIndex = 0; + TMP_Character firstCharacterSearch; + + if (searchPattern.Length > 0 && m_fontAsset.characterLookupTable.TryGetValue(searchPattern[0], out firstCharacterSearch)) + firstGlyphIndex = firstCharacterSearch.glyphIndex; + + uint secondGlyphIndex = 0; + TMP_Character secondCharacterSearch; + + if (searchPattern.Length > 1 && m_fontAsset.characterLookupTable.TryGetValue(searchPattern[1], out secondCharacterSearch)) + secondGlyphIndex = secondCharacterSearch.glyphIndex; + + int arraySize = m_MarkToBaseAdjustmentRecords_prop.arraySize; + + for (int i = 0; i < arraySize; i++) + { + SerializedProperty record = m_MarkToBaseAdjustmentRecords_prop.GetArrayElementAtIndex(i); + + int baseGlyphIndex = record.FindPropertyRelative("m_BaseGlyphID").intValue; + int markGlyphIndex = record.FindPropertyRelative("m_MarkGlyphID").intValue; + + if (firstGlyphIndex == baseGlyphIndex && secondGlyphIndex == markGlyphIndex) + searchResults.Add(i); + else if (searchPattern.Length == 1 && (firstGlyphIndex == baseGlyphIndex || firstGlyphIndex == markGlyphIndex)) + searchResults.Add(i); + else if (baseGlyphIndex.ToString().Contains(searchPattern)) + searchResults.Add(i); + else if (markGlyphIndex.ToString().Contains(searchPattern)) + searchResults.Add(i); + } + } + + void SearchKerningTable(string searchPattern, ref List searchResults) + { + if (searchResults == null) searchResults = new List(); + + searchResults.Clear(); + + // Lookup glyph index of potential characters contained in the search pattern. + uint firstGlyphIndex = 0; + TMP_Character firstCharacterSearch; + + if (searchPattern.Length > 0 && m_fontAsset.characterLookupTable.TryGetValue(searchPattern[0], out firstCharacterSearch)) + firstGlyphIndex = firstCharacterSearch.glyphIndex; + + uint secondGlyphIndex = 0; + TMP_Character secondCharacterSearch; + + if (searchPattern.Length > 1 && m_fontAsset.characterLookupTable.TryGetValue(searchPattern[1], out secondCharacterSearch)) + secondGlyphIndex = secondCharacterSearch.glyphIndex; + + int arraySize = m_GlyphPairAdjustmentRecords_prop.arraySize; + + for (int i = 0; i < arraySize; i++) + { + SerializedProperty record = m_GlyphPairAdjustmentRecords_prop.GetArrayElementAtIndex(i); + + SerializedProperty firstAdjustmentRecord = record.FindPropertyRelative("m_FirstAdjustmentRecord"); + SerializedProperty secondAdjustmentRecord = record.FindPropertyRelative("m_SecondAdjustmentRecord"); + + int firstGlyph = firstAdjustmentRecord.FindPropertyRelative("m_GlyphIndex").intValue; + int secondGlyph = secondAdjustmentRecord.FindPropertyRelative("m_GlyphIndex").intValue; + + if (firstGlyphIndex == firstGlyph && secondGlyphIndex == secondGlyph) + searchResults.Add(i); + else if (searchPattern.Length == 1 && (firstGlyphIndex == firstGlyph || firstGlyphIndex == secondGlyph)) + searchResults.Add(i); + else if (firstGlyph.ToString().Contains(searchPattern)) + searchResults.Add(i); + else if (secondGlyph.ToString().Contains(searchPattern)) + searchResults.Add(i); + } + } + + void SearchMarkToBaseTable(string searchPattern, ref List searchResults) + { + if (searchResults == null) searchResults = new List(); + + searchResults.Clear(); + + // Lookup glyph index of potential characters contained in the search pattern. + uint firstGlyphIndex = 0; + TMP_Character firstCharacterSearch; + + if (searchPattern.Length > 0 && m_fontAsset.characterLookupTable.TryGetValue(searchPattern[0], out firstCharacterSearch)) + firstGlyphIndex = firstCharacterSearch.glyphIndex; + + uint secondGlyphIndex = 0; + TMP_Character secondCharacterSearch; + + if (searchPattern.Length > 1 && m_fontAsset.characterLookupTable.TryGetValue(searchPattern[1], out secondCharacterSearch)) + secondGlyphIndex = secondCharacterSearch.glyphIndex; + + int arraySize = m_MarkToBaseAdjustmentRecords_prop.arraySize; + + for (int i = 0; i < arraySize; i++) + { + SerializedProperty record = m_MarkToBaseAdjustmentRecords_prop.GetArrayElementAtIndex(i); + + int baseGlyphIndex = record.FindPropertyRelative("m_BaseGlyphID").intValue; + int markGlyphIndex = record.FindPropertyRelative("m_MarkGlyphID").intValue; + + if (firstGlyphIndex == baseGlyphIndex && secondGlyphIndex == markGlyphIndex) + searchResults.Add(i); + else if (searchPattern.Length == 1 && (firstGlyphIndex == baseGlyphIndex || firstGlyphIndex == markGlyphIndex)) + searchResults.Add(i); + else if (baseGlyphIndex.ToString().Contains(searchPattern)) + searchResults.Add(i); + else if (markGlyphIndex.ToString().Contains(searchPattern)) + searchResults.Add(i); + } + } + + void SearchMarkToMarkTable(string searchPattern, ref List searchResults) + { + if (searchResults == null) searchResults = new List(); + + searchResults.Clear(); + + // Lookup glyph index of potential characters contained in the search pattern. + uint firstGlyphIndex = 0; + TMP_Character firstCharacterSearch; + + if (searchPattern.Length > 0 && m_fontAsset.characterLookupTable.TryGetValue(searchPattern[0], out firstCharacterSearch)) + firstGlyphIndex = firstCharacterSearch.glyphIndex; + + uint secondGlyphIndex = 0; + TMP_Character secondCharacterSearch; + + if (searchPattern.Length > 1 && m_fontAsset.characterLookupTable.TryGetValue(searchPattern[1], out secondCharacterSearch)) + secondGlyphIndex = secondCharacterSearch.glyphIndex; + + int arraySize = m_MarkToMarkAdjustmentRecords_prop.arraySize; + + for (int i = 0; i < arraySize; i++) + { + SerializedProperty record = m_MarkToMarkAdjustmentRecords_prop.GetArrayElementAtIndex(i); + + int baseGlyphIndex = record.FindPropertyRelative("m_BaseMarkGlyphID").intValue; + int markGlyphIndex = record.FindPropertyRelative("m_CombiningMarkGlyphID").intValue; + + if (firstGlyphIndex == baseGlyphIndex && secondGlyphIndex == markGlyphIndex) + searchResults.Add(i); + else if (searchPattern.Length == 1 && (firstGlyphIndex == baseGlyphIndex || firstGlyphIndex == markGlyphIndex)) + searchResults.Add(i); + else if (baseGlyphIndex.ToString().Contains(searchPattern)) + searchResults.Add(i); + else if (markGlyphIndex.ToString().Contains(searchPattern)) + searchResults.Add(i); + } + } + + void DrawMarkToBasePreview(int selectedRecord, Rect rect) + { + MarkToBaseAdjustmentRecord adjustmentRecord = m_fontAsset.fontFeatureTable.m_MarkToBaseAdjustmentRecords[selectedRecord]; + + uint baseGlyphIndex = adjustmentRecord.baseGlyphID; + uint markGlyphIndex = adjustmentRecord.markGlyphID; + + if (baseGlyphIndex == 0 || markGlyphIndex == 0) + return; + + float lineHeight = m_fontAsset.faceInfo.ascentLine - m_fontAsset.faceInfo.descentLine; + float scale = rect.width < rect.height ? rect.width / lineHeight : rect.height / lineHeight; + scale *= 0.9f; + + Glyph baseGlyph; + m_fontAsset.glyphLookupTable.TryGetValue(baseGlyphIndex, out baseGlyph); + + if (baseGlyph == null) + return; + + Rect center = new Rect(rect.x + rect.width / 2, rect.y + rect.height / 2, rect.width, rect.height); + + Vector2 origin = new Vector2(center.x, center.y); + origin.x = origin.x - (baseGlyph.metrics.horizontalBearingX + baseGlyph.metrics.width / 2) * scale; + origin.y = origin.y + (baseGlyph.metrics.horizontalBearingY - baseGlyph.metrics.height / 2) * scale; + + // Draw Baseline + DrawBaseline(origin, rect.width, Color.grey); + + // Draw Origin + DrawAnchorPoint(origin, Color.yellow); + + Rect baseGlyphPosition = new Rect(origin.x + baseGlyph.metrics.horizontalBearingX * scale, origin.y - baseGlyph.metrics.horizontalBearingY * scale , rect.width, rect.height); + + DrawGlyph(baseGlyph, baseGlyphPosition, scale); + + Vector2 baseAnchorPosition = new Vector2(origin.x + adjustmentRecord.baseGlyphAnchorPoint.xCoordinate * scale, origin.y - adjustmentRecord.baseGlyphAnchorPoint.yCoordinate * scale); + + DrawAnchorPoint(baseAnchorPosition, Color.green); + + // Draw Mark + if (m_fontAsset.glyphLookupTable.ContainsKey(markGlyphIndex)) + { + Glyph markGlyph = m_fontAsset.glyphLookupTable[markGlyphIndex]; + + Rect markGlyphPosition = new Rect(baseAnchorPosition.x + (markGlyph.metrics.horizontalBearingX - adjustmentRecord.markPositionAdjustment.xPositionAdjustment) * scale, baseAnchorPosition.y + (adjustmentRecord.markPositionAdjustment.yPositionAdjustment - markGlyph.metrics.horizontalBearingY) * scale, markGlyph.metrics.width, markGlyph.metrics.height); + + // Draw Mark Origin + DrawGlyph(markGlyph, markGlyphPosition, scale); + } + } + + void DrawMarkToMarkPreview(int selectedRecord, Rect rect) + { + MarkToMarkAdjustmentRecord adjustmentRecord = m_fontAsset.fontFeatureTable.m_MarkToMarkAdjustmentRecords[selectedRecord]; + + uint baseGlyphIndex = adjustmentRecord.baseMarkGlyphID; + uint markGlyphIndex = adjustmentRecord.combiningMarkGlyphID; + + if (baseGlyphIndex == 0 || markGlyphIndex == 0) + return; + + float lineHeight = m_fontAsset.faceInfo.ascentLine - m_fontAsset.faceInfo.descentLine; + float scale = rect.width < rect.height ? rect.width / lineHeight : rect.height / lineHeight; + scale *= 0.9f; + + Glyph baseGlyph; + m_fontAsset.glyphLookupTable.TryGetValue(baseGlyphIndex, out baseGlyph); + + if (baseGlyph == null) + return; + + Rect center = new Rect(rect.x + rect.width / 2, rect.y + rect.height / 2, rect.width, rect.height); + + Vector2 origin = new Vector2(center.x, center.y); + origin.x = origin.x - (baseGlyph.metrics.horizontalBearingX + baseGlyph.metrics.width / 2) * scale; + origin.y = origin.y + (baseGlyph.metrics.horizontalBearingY - baseGlyph.metrics.height / 2) * scale; + + // Draw Baseline + DrawBaseline(origin, rect.width, Color.grey); + + // Draw Origin + DrawAnchorPoint(origin, Color.yellow); + + Rect baseGlyphPosition = new Rect(origin.x + baseGlyph.metrics.horizontalBearingX * scale, origin.y - baseGlyph.metrics.horizontalBearingY * scale , rect.width, rect.height); + + DrawGlyph(baseGlyph, baseGlyphPosition, scale); + + Vector2 baseAnchorPosition = new Vector2(origin.x + adjustmentRecord.baseMarkGlyphAnchorPoint.xCoordinate * scale, origin.y - adjustmentRecord.baseMarkGlyphAnchorPoint.yCoordinate * scale); + + DrawAnchorPoint(baseAnchorPosition, Color.green); + + // Draw Mark Glyph + if (m_fontAsset.glyphLookupTable.ContainsKey(markGlyphIndex)) + { + Glyph markGlyph = m_fontAsset.glyphLookupTable[markGlyphIndex]; + + Rect markGlyphPosition = new Rect(baseAnchorPosition.x + (markGlyph.metrics.horizontalBearingX - adjustmentRecord.combiningMarkPositionAdjustment.xPositionAdjustment) * scale, baseAnchorPosition.y + (adjustmentRecord.combiningMarkPositionAdjustment.yPositionAdjustment - markGlyph.metrics.horizontalBearingY) * scale, markGlyph.metrics.width, markGlyph.metrics.height); + + DrawGlyph(markGlyph, markGlyphPosition, scale); + } + } + + void DrawBaseline(Vector2 position, float width, Color color) + { + Handles.color = color; + + // Horizontal line + Handles.DrawLine(new Vector2(0f, position.y), new Vector2(width, position.y)); + } + + void DrawAnchorPoint(Vector2 position, Color color) + { + Handles.color = color; + + // Horizontal line + Handles.DrawLine(new Vector2(position.x - 25, position.y), new Vector2(position.x + 25, position.y)); + + // Vertical line + Handles.DrawLine(new Vector2(position.x, position.y - 25), new Vector2(position.x, position.y + 25)); + } + + void DrawGlyph(Glyph glyph, Rect position, float scale) + { + // Get the atlas index of the glyph and lookup its atlas texture + int atlasIndex = glyph.atlasIndex; + Texture2D atlasTexture = m_fontAsset.atlasTextures.Length > atlasIndex ? m_fontAsset.atlasTextures[atlasIndex] : null; + + if (atlasTexture == null) + return; + + Material mat; + if (((GlyphRasterModes)m_fontAsset.atlasRenderMode & GlyphRasterModes.RASTER_MODE_BITMAP) == GlyphRasterModes.RASTER_MODE_BITMAP) + { + #if TEXTCORE_FONT_ENGINE_1_5_OR_NEWER + if (m_fontAsset.atlasRenderMode == GlyphRenderMode.COLOR || m_fontAsset.atlasRenderMode == GlyphRenderMode.COLOR_HINTED) + mat = internalRGBABitmapMaterial; + else + mat = internalBitmapMaterial; + #else + mat = internalBitmapMaterial; + #endif + + if (mat == null) + return; + + mat.mainTexture = atlasTexture; + } + else + { + mat = internalSDFMaterial; + + if (mat == null) + return; + + mat.mainTexture = atlasTexture; + mat.SetFloat(ShaderUtilities.ID_GradientScale, m_fontAsset.atlasPadding + 1); + } + + GlyphRect glyphRect = glyph.glyphRect; + + int padding = m_fontAsset.atlasPadding; + + int glyphOriginX = glyphRect.x - padding; + int glyphOriginY = glyphRect.y - padding; + int glyphWidth = glyphRect.width + padding * 2; + int glyphHeight = glyphRect.height + padding * 2; + + // Compute the normalized texture coordinates + Rect texCoords = new Rect((float)glyphOriginX / atlasTexture.width, (float)glyphOriginY / atlasTexture.height, (float)glyphWidth / atlasTexture.width, (float)glyphHeight / atlasTexture.height); + + if (Event.current.type == EventType.Repaint) + { + // Draw glyph from atlas texture. + Rect glyphDrawPosition = new Rect(position.x - padding * scale, position.y - padding * scale, position.width, position.height); + + //glyphDrawPosition.x += (glyphDrawPosition.width - glyphWidth * scale); // / 2; + //glyphDrawPosition.y += (glyphDrawPosition.height - glyphHeight * scale); // / 2; + glyphDrawPosition.width = glyphWidth * scale; + glyphDrawPosition.height = glyphHeight * scale; + + // Could switch to using the default material of the font asset which would require passing scale to the shader. + Graphics.DrawTexture(glyphDrawPosition, atlasTexture, texCoords, 0, 0, 0, 0, new Color(0.8f, 0.8f, 0.8f), mat); + } + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_FontAssetEditor.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_FontAssetEditor.cs.meta new file mode 100644 index 00000000..9b26bae5 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_FontAssetEditor.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 96b44f7d98314b139324a8a87eb66067 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_FontAsset_CreationMenu.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_FontAsset_CreationMenu.cs new file mode 100644 index 00000000..3c7db1c1 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_FontAsset_CreationMenu.cs @@ -0,0 +1,238 @@ +using System.IO; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.TextCore; +using UnityEngine.TextCore.LowLevel; +using UnityEditor; + +using Object = UnityEngine.Object; + + +namespace TMPro +{ + static class TMP_FontAsset_CreationMenu + { + [MenuItem("Assets/Create/TextMeshPro/Font Asset/Font Asset Variant", false, 200)] + static void CreateFontAssetVariant() + { + Object target = Selection.activeObject; + + // Make sure the selection is a font file + if (target == null || target.GetType() != typeof(TMP_FontAsset)) + { + Debug.LogWarning("A Font file must first be selected in order to create a Font Asset."); + return; + } + + // Make sure TMP Essential Resources have been imported in the user project. + if (TMP_Settings.instance == null) + { + Debug.Log("Unable to create font asset. Please import the TMP Essential Resources."); + return; + } + + TMP_FontAsset sourceFontAsset = (TMP_FontAsset)target; + + string sourceFontFilePath = AssetDatabase.GetAssetPath(target); + + string folderPath = Path.GetDirectoryName(sourceFontFilePath); + string assetName = Path.GetFileNameWithoutExtension(sourceFontFilePath); + + string newAssetFilePathWithName = AssetDatabase.GenerateUniqueAssetPath(folderPath + "/" + assetName + " - Variant.asset"); + + // Set Texture and Material reference to the source font asset. + TMP_FontAsset fontAsset = ScriptableObject.Instantiate(sourceFontAsset); + AssetDatabase.CreateAsset(fontAsset, newAssetFilePathWithName); + + fontAsset.atlasPopulationMode = AtlasPopulationMode.Static; + + // Initialize array for the font atlas textures. + fontAsset.atlasTextures = sourceFontAsset.atlasTextures; + fontAsset.material = sourceFontAsset.material; + + // Not sure if this is still necessary in newer versions of Unity. + EditorUtility.SetDirty(fontAsset); + + AssetDatabase.SaveAssets(); + } + + [MenuItem("Assets/Create/TextMeshPro/Font Asset/SDF #%F12", false, 100)] + //[MenuItem("Assets/Create/TextMeshPro/Font Asset", false, 100)] + static void CreateFontAssetSDF() + { + CreateFontAsset(GlyphRenderMode.SDFAA); + } + + [MenuItem("Assets/Create/TextMeshPro/Font Asset/Bitmap", false, 105)] + static void CreateFontAssetBitmap() + { + CreateFontAsset(GlyphRenderMode.SMOOTH); + } + + #if TEXTCORE_FONT_ENGINE_1_5_OR_NEWER + [MenuItem("Assets/Create/TextMeshPro/Font Asset/Color", false, 110)] + static void CreateFontAssetColor() + { + CreateFontAsset(GlyphRenderMode.COLOR); + } + #endif + + static void CreateFontAsset(GlyphRenderMode renderMode) + { + Object[] targets = Selection.objects; + + if (targets == null) + { + Debug.LogWarning("A Font file must first be selected in order to create a Font Asset."); + return; + } + + // Make sure TMP Essential Resources have been imported in the user project. + if (TMP_Settings.instance == null) + { + Debug.Log("Unable to create font asset. Please import the TMP Essential Resources."); + + // Show Window to Import TMP Essential Resources + return; + } + + for (int i = 0; i < targets.Length; i++) + { + Object target = targets[i]; + + // Make sure the selection is a font file + if (target == null || target.GetType() != typeof(Font)) + { + Debug.LogWarning("Selected Object [" + target.name + "] is not a Font file. A Font file must be selected in order to create a Font Asset.", target); + continue; + } + + CreateFontAssetFromSelectedObject(target, renderMode); + } + } + + static void CreateFontAssetFromSelectedObject(Object target, GlyphRenderMode renderMode) + { + Font font = (Font)target; + + string sourceFontFilePath = AssetDatabase.GetAssetPath(target); + + string folderPath = Path.GetDirectoryName(sourceFontFilePath); + string assetName = Path.GetFileNameWithoutExtension(sourceFontFilePath); + + string newAssetFilePathWithName; + ; + switch (renderMode) + { + case GlyphRenderMode.SMOOTH: + newAssetFilePathWithName = AssetDatabase.GenerateUniqueAssetPath(folderPath + "/" + assetName + " Bitmap.asset"); + break; + #if TEXTCORE_FONT_ENGINE_1_5_OR_NEWER + case GlyphRenderMode.COLOR: + newAssetFilePathWithName = AssetDatabase.GenerateUniqueAssetPath(folderPath + "/" + assetName + " Color.asset"); + break; + #endif + case GlyphRenderMode.SDFAA: + default: + newAssetFilePathWithName = AssetDatabase.GenerateUniqueAssetPath(folderPath + "/" + assetName + " SDF.asset"); + break; + } + + // Initialize FontEngine + FontEngine.InitializeFontEngine(); + + // Load Font Face + if (FontEngine.LoadFontFace(font, 90) != FontEngineError.Success) + { + Debug.LogWarning("Unable to load font face for [" + font.name + "]. Make sure \"Include Font Data\" is enabled in the Font Import Settings.", font); + return; + } + + // Create new Font Asset + TMP_FontAsset fontAsset = ScriptableObject.CreateInstance(); + AssetDatabase.CreateAsset(fontAsset, newAssetFilePathWithName); + + fontAsset.version = "1.1.0"; + fontAsset.faceInfo = FontEngine.GetFaceInfo(); + + // Set font reference and GUID + fontAsset.sourceFontFile = font; + fontAsset.m_SourceFontFileGUID = AssetDatabase.AssetPathToGUID(sourceFontFilePath); + fontAsset.m_SourceFontFile_EditorRef = font; + + fontAsset.atlasPopulationMode = AtlasPopulationMode.Dynamic; + fontAsset.clearDynamicDataOnBuild = TMP_Settings.clearDynamicDataOnBuild; + + // Get all font features + //fontAsset.ImportFontFeatures(); + + // Default atlas resolution is 1024 x 1024. + fontAsset.atlasTextures = new Texture2D[1]; + int atlasWidth = fontAsset.atlasWidth = 1024; + int atlasHeight = fontAsset.atlasHeight = 1024; + int atlasPadding = fontAsset.atlasPadding = 9; + + Texture2D texture; + Material mat; + Shader shader; + int packingModifier; + + switch (renderMode) + { + case GlyphRenderMode.SMOOTH: + fontAsset.atlasRenderMode = GlyphRenderMode.SMOOTH; + texture = new Texture2D(1, 1, TextureFormat.Alpha8, false); + shader = Shader.Find("TextMeshPro/Bitmap"); + packingModifier = 0; + mat = new Material(shader); + break; + #if TEXTCORE_FONT_ENGINE_1_5_OR_NEWER + case GlyphRenderMode.COLOR: + fontAsset.atlasRenderMode = GlyphRenderMode.COLOR; + texture = new Texture2D(1, 1, TextureFormat.RGBA32, false); + shader = Shader.Find("TextMeshPro/Sprite"); + packingModifier = 0; + mat = new Material(shader); + break; + #endif + case GlyphRenderMode.SDFAA: + default: + fontAsset.atlasRenderMode = GlyphRenderMode.SDFAA; + texture = new Texture2D(1, 1, TextureFormat.Alpha8, false); + shader = Shader.Find("TextMeshPro/Distance Field"); + packingModifier = 1; + mat = new Material(shader); + + mat.SetFloat(ShaderUtilities.ID_GradientScale, atlasPadding + packingModifier); + mat.SetFloat(ShaderUtilities.ID_WeightNormal, fontAsset.normalStyle); + mat.SetFloat(ShaderUtilities.ID_WeightBold, fontAsset.boldStyle); + + break; + } + + texture.name = assetName + " Atlas"; + mat.name = texture.name + " Material"; + + fontAsset.atlasTextures[0] = texture; + AssetDatabase.AddObjectToAsset(texture, fontAsset); + + fontAsset.freeGlyphRects = new List() { new GlyphRect(0, 0, atlasWidth - packingModifier, atlasHeight - packingModifier) }; + fontAsset.usedGlyphRects = new List(); + + mat.SetTexture(ShaderUtilities.ID_MainTex, texture); + mat.SetFloat(ShaderUtilities.ID_TextureWidth, atlasWidth); + mat.SetFloat(ShaderUtilities.ID_TextureHeight, atlasHeight); + + fontAsset.material = mat; + AssetDatabase.AddObjectToAsset(mat, fontAsset); + + // Add Font Asset Creation Settings + fontAsset.creationSettings = new FontAssetCreationSettings(fontAsset.m_SourceFontFileGUID, (int)fontAsset.faceInfo.pointSize, 0, atlasPadding, 0, 1024, 1024, 7, string.Empty, (int)renderMode); + + // Not sure if this is still necessary in newer versions of Unity. + //EditorUtility.SetDirty(fontAsset); + + AssetDatabase.SaveAssets(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_FontAsset_CreationMenu.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_FontAsset_CreationMenu.cs.meta new file mode 100644 index 00000000..57a3fcea --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_FontAsset_CreationMenu.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7496af95dfe67cf429ac65edaaf99106 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_InputFieldEditor.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_InputFieldEditor.cs new file mode 100644 index 00000000..6f572241 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_InputFieldEditor.cs @@ -0,0 +1,300 @@ +using UnityEngine; +using UnityEngine.UI; +using UnityEditor; +using UnityEditor.UI; +using UnityEditor.AnimatedValues; + + +namespace TMPro.EditorUtilities +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(TMP_InputField), true)] + public class TMP_InputFieldEditor : SelectableEditor + { + private struct m_foldout + { // Track Inspector foldout panel states, globally. + public static bool textInput = true; + public static bool fontSettings = true; + public static bool extraSettings = true; + //public static bool shadowSetting = false; + //public static bool materialEditor = true; + } + + SerializedProperty m_TextViewport; + SerializedProperty m_TextComponent; + SerializedProperty m_Text; + SerializedProperty m_ContentType; + SerializedProperty m_LineType; + SerializedProperty m_LineLimit; + SerializedProperty m_InputType; + SerializedProperty m_CharacterValidation; + SerializedProperty m_InputValidator; + SerializedProperty m_RegexValue; + SerializedProperty m_KeyboardType; + SerializedProperty m_CharacterLimit; + SerializedProperty m_CaretBlinkRate; + SerializedProperty m_CaretWidth; + SerializedProperty m_CaretColor; + SerializedProperty m_CustomCaretColor; + SerializedProperty m_SelectionColor; + SerializedProperty m_HideMobileKeyboard; + SerializedProperty m_HideMobileInput; + SerializedProperty m_Placeholder; + SerializedProperty m_VerticalScrollbar; + SerializedProperty m_ScrollbarScrollSensitivity; + SerializedProperty m_OnValueChanged; + SerializedProperty m_OnEndEdit; + SerializedProperty m_OnSelect; + SerializedProperty m_OnDeselect; + SerializedProperty m_ReadOnly; + SerializedProperty m_RichText; + SerializedProperty m_RichTextEditingAllowed; + SerializedProperty m_ResetOnDeActivation; + SerializedProperty m_KeepTextSelectionVisible; + SerializedProperty m_RestoreOriginalTextOnEscape; + SerializedProperty m_ShouldActivateOnSelect; + + SerializedProperty m_OnFocusSelectAll; + SerializedProperty m_GlobalPointSize; + SerializedProperty m_GlobalFontAsset; + + AnimBool m_CustomColor; + + //TMP_InputValidator m_ValidationScript; + + protected override void OnEnable() + { + base.OnEnable(); + + m_TextViewport = serializedObject.FindProperty("m_TextViewport"); + m_TextComponent = serializedObject.FindProperty("m_TextComponent"); + m_Text = serializedObject.FindProperty("m_Text"); + m_ContentType = serializedObject.FindProperty("m_ContentType"); + m_LineType = serializedObject.FindProperty("m_LineType"); + m_LineLimit = serializedObject.FindProperty("m_LineLimit"); + m_InputType = serializedObject.FindProperty("m_InputType"); + m_CharacterValidation = serializedObject.FindProperty("m_CharacterValidation"); + m_InputValidator = serializedObject.FindProperty("m_InputValidator"); + m_RegexValue = serializedObject.FindProperty("m_RegexValue"); + m_KeyboardType = serializedObject.FindProperty("m_KeyboardType"); + m_CharacterLimit = serializedObject.FindProperty("m_CharacterLimit"); + m_CaretBlinkRate = serializedObject.FindProperty("m_CaretBlinkRate"); + m_CaretWidth = serializedObject.FindProperty("m_CaretWidth"); + m_CaretColor = serializedObject.FindProperty("m_CaretColor"); + m_CustomCaretColor = serializedObject.FindProperty("m_CustomCaretColor"); + m_SelectionColor = serializedObject.FindProperty("m_SelectionColor"); + + m_HideMobileKeyboard = serializedObject.FindProperty("m_HideSoftKeyboard"); + m_HideMobileInput = serializedObject.FindProperty("m_HideMobileInput"); + + m_Placeholder = serializedObject.FindProperty("m_Placeholder"); + m_VerticalScrollbar = serializedObject.FindProperty("m_VerticalScrollbar"); + m_ScrollbarScrollSensitivity = serializedObject.FindProperty("m_ScrollSensitivity"); + + m_OnValueChanged = serializedObject.FindProperty("m_OnValueChanged"); + m_OnEndEdit = serializedObject.FindProperty("m_OnEndEdit"); + m_OnSelect = serializedObject.FindProperty("m_OnSelect"); + m_OnDeselect = serializedObject.FindProperty("m_OnDeselect"); + m_ReadOnly = serializedObject.FindProperty("m_ReadOnly"); + m_RichText = serializedObject.FindProperty("m_RichText"); + m_RichTextEditingAllowed = serializedObject.FindProperty("m_isRichTextEditingAllowed"); + m_ResetOnDeActivation = serializedObject.FindProperty("m_ResetOnDeActivation"); + m_KeepTextSelectionVisible = serializedObject.FindProperty("m_KeepTextSelectionVisible"); + m_RestoreOriginalTextOnEscape = serializedObject.FindProperty("m_RestoreOriginalTextOnEscape"); + + m_OnFocusSelectAll = serializedObject.FindProperty("m_OnFocusSelectAll"); + m_ShouldActivateOnSelect = serializedObject.FindProperty("m_ShouldActivateOnSelect"); + + m_GlobalPointSize = serializedObject.FindProperty("m_GlobalPointSize"); + m_GlobalFontAsset = serializedObject.FindProperty("m_GlobalFontAsset"); + + m_CustomColor = new AnimBool(m_CustomCaretColor.boolValue); + m_CustomColor.valueChanged.AddListener(Repaint); + } + + protected override void OnDisable() + { + base.OnDisable(); + m_CustomColor.valueChanged.RemoveListener(Repaint); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + base.OnInspectorGUI(); + + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(m_TextViewport); + + EditorGUILayout.PropertyField(m_TextComponent); + + TextMeshProUGUI text = null; + if (m_TextComponent != null && m_TextComponent.objectReferenceValue != null) + { + text = m_TextComponent.objectReferenceValue as TextMeshProUGUI; + //if (text.supportRichText) + //{ + // EditorGUILayout.HelpBox("Using Rich Text with input is unsupported.", MessageType.Warning); + //} + } + + EditorGUI.BeginDisabledGroup(m_TextComponent == null || m_TextComponent.objectReferenceValue == null); + + // TEXT INPUT BOX + EditorGUILayout.PropertyField(m_Text); + + // INPUT FIELD SETTINGS + #region INPUT FIELD SETTINGS + + m_foldout.fontSettings = EditorGUILayout.Foldout(m_foldout.fontSettings, "Input Field Settings", true, TMP_UIStyleManager.boldFoldout); + + if (m_foldout.fontSettings) + { + EditorGUI.indentLevel++; + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_GlobalFontAsset, new GUIContent("Font Asset", "Set the Font Asset for both Placeholder and Input Field text object.")); + if (EditorGUI.EndChangeCheck()) + { + TMP_InputField inputField = target as TMP_InputField; + inputField.SetGlobalFontAsset(m_GlobalFontAsset.objectReferenceValue as TMP_FontAsset); + } + + + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_GlobalPointSize, new GUIContent("Point Size", "Set the point size of both Placeholder and Input Field text object.")); + if (EditorGUI.EndChangeCheck()) + { + TMP_InputField inputField = target as TMP_InputField; + inputField.SetGlobalPointSize(m_GlobalPointSize.floatValue); + } + + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_CharacterLimit); + + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(m_ContentType); + if (!m_ContentType.hasMultipleDifferentValues) + { + EditorGUI.indentLevel++; + + if (m_ContentType.enumValueIndex == (int)TMP_InputField.ContentType.Standard || + m_ContentType.enumValueIndex == (int)TMP_InputField.ContentType.Autocorrected || + m_ContentType.enumValueIndex == (int)TMP_InputField.ContentType.Custom) + { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_LineType); + if (EditorGUI.EndChangeCheck()) + { + if (text != null) + { + if (m_LineType.enumValueIndex == (int)TMP_InputField.LineType.SingleLine) + text.textWrappingMode = TextWrappingModes.PreserveWhitespaceNoWrap; + else + { + text.textWrappingMode = TextWrappingModes.Normal; + } + } + } + + if (m_LineType.enumValueIndex != (int)TMP_InputField.LineType.SingleLine) + { + EditorGUILayout.PropertyField(m_LineLimit); + } + } + + if (m_ContentType.enumValueIndex == (int)TMP_InputField.ContentType.Custom) + { + EditorGUILayout.PropertyField(m_InputType); + EditorGUILayout.PropertyField(m_KeyboardType); + EditorGUILayout.PropertyField(m_CharacterValidation); + if (m_CharacterValidation.enumValueIndex == (int)TMP_InputField.CharacterValidation.Regex) + { + EditorGUILayout.PropertyField(m_RegexValue); + } + else if (m_CharacterValidation.enumValueIndex == (int)TMP_InputField.CharacterValidation.CustomValidator) + { + EditorGUILayout.PropertyField(m_InputValidator); + } + } + + EditorGUI.indentLevel--; + } + + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(m_Placeholder); + EditorGUILayout.PropertyField(m_VerticalScrollbar); + + if (m_VerticalScrollbar.objectReferenceValue != null) + EditorGUILayout.PropertyField(m_ScrollbarScrollSensitivity); + + EditorGUILayout.PropertyField(m_CaretBlinkRate); + EditorGUILayout.PropertyField(m_CaretWidth); + + EditorGUILayout.PropertyField(m_CustomCaretColor); + + m_CustomColor.target = m_CustomCaretColor.boolValue; + + if (EditorGUILayout.BeginFadeGroup(m_CustomColor.faded)) + { + EditorGUILayout.PropertyField(m_CaretColor); + } + EditorGUILayout.EndFadeGroup(); + + EditorGUILayout.PropertyField(m_SelectionColor); + + EditorGUI.indentLevel--; + } + #endregion + + + // CONTROL SETTINGS + #region CONTROL SETTINGS + m_foldout.extraSettings = EditorGUILayout.Foldout(m_foldout.extraSettings, "Control Settings", true, TMP_UIStyleManager.boldFoldout); + + if (m_foldout.extraSettings) + { + EditorGUI.indentLevel++; + + EditorGUILayout.PropertyField(m_OnFocusSelectAll, new GUIContent("OnFocus - Select All", "Should all the text be selected when the Input Field is selected?")); + EditorGUILayout.PropertyField(m_ResetOnDeActivation, new GUIContent("Reset On Deactivation", "Should the Text and Caret position be reset when Input Field looses focus and is Deactivated?")); + + EditorGUI.indentLevel++; + GUI.enabled = !m_ResetOnDeActivation.boolValue; + EditorGUILayout.PropertyField(m_KeepTextSelectionVisible, new GUIContent("Keep Text Selection Visible", "Should the text selection remain visible when the input field looses focus and is deactivated?")); + GUI.enabled = true; + EditorGUI.indentLevel--; + + EditorGUILayout.PropertyField(m_RestoreOriginalTextOnEscape, new GUIContent("Restore On ESC Key", "Should the original text be restored when pressing ESC? (Property not applicable for HoloLens)")); + EditorGUILayout.PropertyField(m_ShouldActivateOnSelect, new GUIContent("Should Activate On Select", "Determines if the Input Field will be activated when selected.")); + EditorGUILayout.PropertyField(m_HideMobileKeyboard, new GUIContent("Hide Soft Keyboard", "Controls the visibility of the mobile virtual keyboard.")); + + EditorGUI.BeginDisabledGroup(m_HideMobileKeyboard.boolValue); + EditorGUILayout.PropertyField(m_HideMobileInput, new GUIContent("Hide Mobile Input", "Controls the visibility of the editable text field above the mobile virtual keyboard.")); + EditorGUI.EndDisabledGroup(); + + EditorGUILayout.PropertyField(m_ReadOnly); + EditorGUILayout.PropertyField(m_RichText); + EditorGUILayout.PropertyField(m_RichTextEditingAllowed, new GUIContent("Allow Rich Text Editing")); + + EditorGUI.indentLevel--; + } + #endregion + + + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(m_OnValueChanged); + EditorGUILayout.PropertyField(m_OnEndEdit); + EditorGUILayout.PropertyField(m_OnSelect); + EditorGUILayout.PropertyField(m_OnDeselect); + + EditorGUI.EndDisabledGroup(); + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_InputFieldEditor.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_InputFieldEditor.cs.meta new file mode 100644 index 00000000..eeb62d8c --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_InputFieldEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: aa160f27c3fe4052a5850e21108811b6 +timeCreated: 1457861621 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_MarkupTagUpdateUtility.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_MarkupTagUpdateUtility.cs new file mode 100644 index 00000000..ffbff32b --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_MarkupTagUpdateUtility.cs @@ -0,0 +1,282 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + + +internal class TMP_MarkupTagUpdateUtility +{ + struct MarkupTagDescriptor + { + public string name; + public string tag; + public string description; + + public MarkupTagDescriptor(string name, string tag, string description) + { + this.name = name; + this.tag = tag; + this.description = description; + } + + public MarkupTagDescriptor(string name) + { + this.name = name; + this.tag = null; + this.description = null; + } + + public static MarkupTagDescriptor linefeed = new MarkupTagDescriptor("\n"); + } + + private static MarkupTagDescriptor[] m_MarkupTags = + { + new MarkupTagDescriptor("BOLD", "b", "// "), + new MarkupTagDescriptor("SLASH_BOLD", "/b", "// "), + new MarkupTagDescriptor("ITALIC", "i", "// "), + new MarkupTagDescriptor("SLASH_ITALIC", "/i", "// "), + new MarkupTagDescriptor("UNDERLINE", "u", "// "), + new MarkupTagDescriptor("SLASH_UNDERLINE", "/u", "// "), + new MarkupTagDescriptor("STRIKETHROUGH", "s", "// "), + new MarkupTagDescriptor("SLASH_STRIKETHROUGH", "/s", "// "), + new MarkupTagDescriptor("SUBSCRIPT", "sub", "// "), + new MarkupTagDescriptor("SLASH_SUBSCRIPT", "/sub", "// "), + new MarkupTagDescriptor("SUPERSCRIPT", "sup", "// "), + new MarkupTagDescriptor("SLASH_SUPERSCRIPT", "/sup", "// "), + new MarkupTagDescriptor("MARK", "mark", "// "), + new MarkupTagDescriptor("SLASH_MARK", "/mark", "// "), + MarkupTagDescriptor.linefeed, + + new MarkupTagDescriptor("COLOR", "color", "// "), + new MarkupTagDescriptor("SLASH_COLOR", "/color", "// "), + new MarkupTagDescriptor("ALPHA", "alpha", "// "), + new MarkupTagDescriptor("SLASH_ALPHA", "/alpha", "// "), + MarkupTagDescriptor.linefeed, + + new MarkupTagDescriptor("FONT", "font", "// or " ), + new MarkupTagDescriptor("SLASH_FONT", "/font", "// "), + new MarkupTagDescriptor("MATERIAL", "material", "// or as attribute "), + new MarkupTagDescriptor("SLASH_MATERIAL", "/material", "// "), + new MarkupTagDescriptor("SIZE", "size", "// "), + new MarkupTagDescriptor("SLASH_SIZE", "/size", "// "), + new MarkupTagDescriptor("FONT_WEIGHT", "font-weight", "// "), + new MarkupTagDescriptor("SLASH_FONT_WEIGHT", "/font-weight", "// "), + new MarkupTagDescriptor("SCALE", "scale", "// "), + new MarkupTagDescriptor("SLASH_SCALE", "/scale", "// "), + MarkupTagDescriptor.linefeed, + + new MarkupTagDescriptor("SPRITE", "sprite", "// "), + new MarkupTagDescriptor("STYLE", "style", "// "), + new MarkupTagDescriptor("GRADIENT", "gradient", "// "), + new MarkupTagDescriptor("SLASH_GRADIENT", "/gradient", "// "), + MarkupTagDescriptor.linefeed, + + new MarkupTagDescriptor("A", "a", "// "), + new MarkupTagDescriptor("SLASH_A", "/a", "// "), + new MarkupTagDescriptor("LINK", "link", "// "), + new MarkupTagDescriptor("SLASH_LINK", "/link", "// "), + MarkupTagDescriptor.linefeed, + + new MarkupTagDescriptor("POSITION", "pos", "// "), + new MarkupTagDescriptor("SLASH_POSITION", "/pos", "// "), + new MarkupTagDescriptor("VERTICAL_OFFSET", "voffset","// "), + new MarkupTagDescriptor("SLASH_VERTICAL_OFFSET", "/voffset", "// "), + new MarkupTagDescriptor("ROTATE", "rotate", "// "), + new MarkupTagDescriptor("SLASH_ROTATE", "/rotate", "// "), + new MarkupTagDescriptor("TRANSFORM", "transform","// "), + new MarkupTagDescriptor("SLASH_TRANSFORM", "/transform", "// "), + new MarkupTagDescriptor("SPACE", "space", "// "), + new MarkupTagDescriptor("SLASH_SPACE", "/space", "// "), + new MarkupTagDescriptor("CHARACTER_SPACE", "cspace", "// "), + new MarkupTagDescriptor("SLASH_CHARACTER_SPACE", "/cspace", "// "), + new MarkupTagDescriptor("MONOSPACE", "mspace", "// "), + new MarkupTagDescriptor("SLASH_MONOSPACE", "/mspace", "// "), + new MarkupTagDescriptor("CHARACTER_SPACING", "character-spacing", "// "), + new MarkupTagDescriptor("SLASH_CHARACTER_SPACING", "/character-spacing", "// "), + MarkupTagDescriptor.linefeed, + + new MarkupTagDescriptor("ALIGN", "align", "// "), + new MarkupTagDescriptor("SLASH_ALIGN", "/align", "// "), + new MarkupTagDescriptor("WIDTH", "width", "// "), + new MarkupTagDescriptor("SLASH_WIDTH", "/width", "// "), + new MarkupTagDescriptor("MARGIN", "margin", "// "), + new MarkupTagDescriptor("SLASH_MARGIN", "/margin", "// "), + new MarkupTagDescriptor("MARGIN_LEFT", "margin-left", "// "), + new MarkupTagDescriptor("MARGIN_RIGHT", "margin-right", "// "), + new MarkupTagDescriptor("INDENT", "indent", "// "), + new MarkupTagDescriptor("SLASH_INDENT", "/indent", "// "), + new MarkupTagDescriptor("LINE_INDENT", "line-indent", "// "), + new MarkupTagDescriptor("SLASH_LINE_INDENT", "/line-indent", "// "), + new MarkupTagDescriptor("LINE_HEIGHT", "line-height", "// "), + new MarkupTagDescriptor("SLASH_LINE_HEIGHT", "/line-height", "// "), + MarkupTagDescriptor.linefeed, + + new MarkupTagDescriptor("NO_BREAK", "nobr", "// "), + new MarkupTagDescriptor("SLASH_NO_BREAK", "/nobr", "// "), + new MarkupTagDescriptor("NO_PARSE", "noparse","// "), + new MarkupTagDescriptor("SLASH_NO_PARSE", "/noparse", "// "), + new MarkupTagDescriptor("PAGE", "page", "// "), + new MarkupTagDescriptor("SLASH_PAGE", "/page", "// "), + MarkupTagDescriptor.linefeed, + + new MarkupTagDescriptor("ACTION", "action", "// "), + new MarkupTagDescriptor("SLASH_ACTION", "/action", "// "), + MarkupTagDescriptor.linefeed, + + new MarkupTagDescriptor("CLASS", "class", "// "), + new MarkupTagDescriptor("TABLE", "table", "// "), + new MarkupTagDescriptor("SLASH_TABLE", "/table", "//
"), + new MarkupTagDescriptor("TH", "th", "// "), + new MarkupTagDescriptor("SLASH_TH", "/th", "// "), + new MarkupTagDescriptor("TR", "tr", "// "), + new MarkupTagDescriptor("SLASH_TR", "/tr", "// "), + new MarkupTagDescriptor("TD", "td", "// "), + new MarkupTagDescriptor("SLASH_TD", "/td", "// "), + MarkupTagDescriptor.linefeed, + + new MarkupTagDescriptor("// Text Styles"), + new MarkupTagDescriptor("LOWERCASE", "lowercase", "// "), + new MarkupTagDescriptor("SLASH_LOWERCASE", "/lowercase", "// "), + new MarkupTagDescriptor("ALLCAPS", "allcaps", "// "), + new MarkupTagDescriptor("SLASH_ALLCAPS", "/allcaps", "// "), + new MarkupTagDescriptor("UPPERCASE", "uppercase", "// "), + new MarkupTagDescriptor("SLASH_UPPERCASE", "/uppercase", "// "), + new MarkupTagDescriptor("SMALLCAPS", "smallcaps", "// "), + new MarkupTagDescriptor("SLASH_SMALLCAPS", "/smallcaps", "// "), + new MarkupTagDescriptor("CAPITALIZE", "capitalize", "// "), + new MarkupTagDescriptor("SLASH_CAPITALIZE", "/capitalize", "// "), + MarkupTagDescriptor.linefeed, + + new MarkupTagDescriptor("// Font Features"), + new MarkupTagDescriptor("LIGA", "liga", "// "), + new MarkupTagDescriptor("SLASH_LIGA", "/liga", "// "), + new MarkupTagDescriptor("FRAC", "frac", "// "), + new MarkupTagDescriptor("SLASH_FRAC", "/frac", "// "), + MarkupTagDescriptor.linefeed, + + new MarkupTagDescriptor("// Attributes"), + new MarkupTagDescriptor("NAME", "name", "// "), + new MarkupTagDescriptor("INDEX", "index", "// "), + new MarkupTagDescriptor("TINT", "tint", "// "), + new MarkupTagDescriptor("ANIM", "anim", "// "), + new MarkupTagDescriptor("HREF", "href", "// text to be displayed."), + new MarkupTagDescriptor("ANGLE", "angle", "// Italic Slant Angle"), + new MarkupTagDescriptor("FAMILY", "family", "// "), + MarkupTagDescriptor.linefeed, + + new MarkupTagDescriptor("// Named Colors"), + new MarkupTagDescriptor("RED", "red",""), + new MarkupTagDescriptor("GREEN", "green", ""), + new MarkupTagDescriptor("BLUE", "blue", ""), + new MarkupTagDescriptor("WHITE", "white", ""), + new MarkupTagDescriptor("BLACK", "black", ""), + new MarkupTagDescriptor("CYAN", "cyna", ""), + new MarkupTagDescriptor("MAGENTA", "magenta", ""), + new MarkupTagDescriptor("YELLOW", "yellow", ""), + new MarkupTagDescriptor("ORANGE", "orange", ""), + new MarkupTagDescriptor("PURPLE", "purple", ""), + MarkupTagDescriptor.linefeed, + + new MarkupTagDescriptor("// Unicode Characters"), + new MarkupTagDescriptor("BR", "br", "//
Line Feed (LF) \\u0A"), + new MarkupTagDescriptor("ZWSP", "zwsp", "// Zero Width Space \\u200B"), + new MarkupTagDescriptor("NBSP", "nbsp", "// Non Breaking Space \\u00A0"), + new MarkupTagDescriptor("SHY", "shy", "// Soft Hyphen \\u00AD"), + new MarkupTagDescriptor("ZWJ", "zwj", "// Zero Width Joiner \\u200D"), + new MarkupTagDescriptor("WJ", "wj", "// Word Joiner \\u2060"), + MarkupTagDescriptor.linefeed, + + new MarkupTagDescriptor("// Alignment"), + new MarkupTagDescriptor("LEFT", "left", "// "), + new MarkupTagDescriptor("RIGHT", "right", "// "), + new MarkupTagDescriptor("CENTER", "center", "// "), + new MarkupTagDescriptor("JUSTIFIED", "justified", "// "), + new MarkupTagDescriptor("FLUSH", "flush", "// "), + MarkupTagDescriptor.linefeed, + + new MarkupTagDescriptor("// Prefix and Unit suffix"), + new MarkupTagDescriptor("NONE", "none", ""), + new MarkupTagDescriptor("PLUS", "+", ""), + new MarkupTagDescriptor("MINUS", "-", ""), + new MarkupTagDescriptor("PX", "px", ""), + new MarkupTagDescriptor("PLUS_PX", "+px", ""), + new MarkupTagDescriptor("MINUS_PX", "-px", ""), + new MarkupTagDescriptor("EM", "em", ""), + new MarkupTagDescriptor("PLUS_EM", "+em", ""), + new MarkupTagDescriptor("MINUS_EM", "-em", ""), + new MarkupTagDescriptor("PCT", "pct", ""), + new MarkupTagDescriptor("PLUS_PCT", "+pct", ""), + new MarkupTagDescriptor("MINUS_PCT", "-pct", ""), + new MarkupTagDescriptor("PERCENTAGE", "%", ""), + new MarkupTagDescriptor("PLUS_PERCENTAGE", "+%", ""), + new MarkupTagDescriptor("MINUS_PERCENTAGE", "-%", ""), + new MarkupTagDescriptor("HASH", "#", "// #"), + MarkupTagDescriptor.linefeed, + + new MarkupTagDescriptor("TRUE", "true", ""), + new MarkupTagDescriptor("FALSE", "false", ""), + MarkupTagDescriptor.linefeed, + + new MarkupTagDescriptor("INVALID", "invalid", ""), + MarkupTagDescriptor.linefeed, + + new MarkupTagDescriptor("NORMAL", "normal", "// "), + new MarkupTagDescriptor("DEFAULT", "default", "// "), + }; + + + [MenuItem("Window/TextMeshPro/Internal/Update Markup Tag Hash Codes", false, 2200, true)] + static void UpdateMarkupTagHashCodes() + { + Dictionary markupHashCodes = new Dictionary(); + string output = string.Empty; + + for (int i = 0; i < m_MarkupTags.Length; i++) + { + MarkupTagDescriptor descriptor = m_MarkupTags[i]; + int hashCode = descriptor.tag == null ? 0 : GetHashCodeCaseInSensitive(descriptor.tag); + + if (descriptor.name == "\n") + output += "\n"; + else if (hashCode == 0) + output += descriptor.name + "\n"; + else + { + output += descriptor.name + " = " + hashCode + ",\t" + descriptor.description + "\n"; + + if (markupHashCodes.ContainsKey(hashCode) == false) + markupHashCodes.Add(hashCode, descriptor); + else + Debug.Log("[" + descriptor.name + "] with HashCode [" + hashCode + "] collides with [" + markupHashCodes[hashCode].name + "]."); + } + } + + Debug.Log(output); + } + + /// + /// Table used to convert character to uppercase. + /// + const string k_lookupStringU = "-------------------------------- !-#$%&-()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[-]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~-"; + + /// + /// Get uppercase version of this ASCII character. + /// + public static char ToUpperFast(char c) + { + if (c > k_lookupStringU.Length - 1) + return c; + + return k_lookupStringU[c]; + } + + public static int GetHashCodeCaseInSensitive(string s) + { + int hashCode = 5381; + + for (int i = 0; i < s.Length; i++) + hashCode = (hashCode << 5) + hashCode ^ ToUpperFast(s[i]); + + return hashCode; + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_MarkupTagUpdateUtility.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_MarkupTagUpdateUtility.cs.meta new file mode 100644 index 00000000..c7b8ae86 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_MarkupTagUpdateUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 225b67dcce9247b4c806e435b34695d2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_PackageUtilities.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_PackageUtilities.cs new file mode 100644 index 00000000..7bbfeceb --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_PackageUtilities.cs @@ -0,0 +1,1099 @@ +using UnityEngine; +using UnityEngine.SceneManagement; +using UnityEditor; +using System; +using System.IO; +using System.Linq; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Threading; +using TMPro.EditorUtilities; + +#if UNITY_2023_3_OR_NEWER +using PhysicsMaterialAsset = UnityEngine.PhysicsMaterial; +#else +using PhysicsMaterialAsset = UnityEngine.PhysicMaterial; +#endif + +namespace TMPro +{ + // Suppressing warnings related to the use of private structures which are confusing the compiler as these data structures are used by .json files. + #pragma warning disable 0649 + + /// + /// Data structure containing the target and replacement fileIDs and GUIDs which will require remapping from previous version of TextMesh Pro to the new TextMesh Pro UPM package. + /// + [System.Serializable] + struct AssetConversionRecord + { + public string referencedResource; + public string target; + public string replacement; + } + + + /// + /// Data structure containing a list of target and replacement fileID and GUID requiring remapping from previous versions of TextMesh Pro to the new TextMesh Pro UPM package. + /// This data structure is populated with the data contained in the PackageConversionData.json file included in the package. + /// + [System.Serializable] + class AssetConversionData + { + public List assetRecords; + } + + internal class TMP_ProjectTextSpacingConversionTool : EditorWindow + { + // Create Text Spacing Conversion Tool window + [MenuItem("Window/TextMeshPro/Project Text Spacing Conversion Tool", false, 2110)] + static void ShowConverterWindow() + { + var window = GetWindow(); + window.titleContent = new GUIContent("Conversion Tool"); + window.Focus(); + } + + /// + /// + /// + struct AssetModificationRecord + { + public string assetFilePath; + public string assetDataFile; + } + + struct AssetFileRecord + { + public string assetFilePath; + + public AssetFileRecord(string filePath, string metaFilePath) + { + this.assetFilePath = filePath; + } + } + + private static string m_ProjectPath; + [SerializeField] private string m_ProjectFolderToScan; + private static bool m_IsAlreadyScanningProject; + private static bool m_CancelScanProcess; + private static string k_ProjectScanReportDefaultText = "" + + " Character Word Line Paragraph\n" + + "Project Scan Results Spacing Spacing Spacing Spacing\n" + + "------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n"; + + [SerializeField] private GUIStyle m_OutputWindowStyle; + [SerializeField] private Font m_OutputWindowMonospacedFont; + private static string k_ProjectScanLabelPrefix = "Scanning: "; + private static string m_ProjectScanResults = string.Empty; + private static Vector2 m_ProjectScanResultScrollPosition; + private static float m_ProgressPercentage = 0; + + private static int m_ScanningTotalFiles; + private static int m_ScanningCurrentFileIndex; + private static string m_ScanningCurrentFileName; + + private static string k_TextMeshProScriptID = "m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3}"; + private static string k_TextMeshProUGUIScriptID = "m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}"; + //private static string k_FontAssetScriptID = "m_Script: {fileID: 11500000, guid: 71c1514a6bd24e1e882cebbe1904ce04, type: 3}"; + + private static string k_FontAssetProperty = "m_fontAsset: "; + private static string k_FontSizeProperty = "m_fontSize: "; + private static string k_LineSpacingProperty = "m_lineSpacing: "; + private static string k_CharacterSpacingProperty = "m_characterSpacing: "; + private static string k_WordSpacingProperty = "m_wordSpacing: "; + private static string k_ParagraphSpacingProperty = "m_paragraphSpacing: "; + + private static AssetConversionData m_ConversionData; + + private static readonly List m_ModifiedAssetList = new List(); + + void OnEnable() + { + // Set Editor Window Size + SetEditorWindowSize(); + + m_ProjectScanResults = k_ProjectScanReportDefaultText; + + // Define new style with monospaced font (if we have not already done so). + if (m_OutputWindowStyle == null || m_OutputWindowMonospacedFont == null) + { + if (m_OutputWindowMonospacedFont == null) + m_OutputWindowMonospacedFont = Font.CreateDynamicFontFromOSFont("Courier New", 13); + + if (m_OutputWindowStyle == null) + { + m_OutputWindowStyle = new GUIStyle() {font = m_OutputWindowMonospacedFont, richText = true}; + m_OutputWindowStyle.normal.textColor = new Color(0.95f, 0.95f, 0.95f, 1f); + } + else + { + m_OutputWindowStyle.font = m_OutputWindowMonospacedFont; + } + } + } + + void OnGUI() + { + // Define new style with monospaced font (if we have not already done so). + if (m_OutputWindowStyle == null || m_OutputWindowMonospacedFont == null) + { + if (m_OutputWindowMonospacedFont == null) + m_OutputWindowMonospacedFont = Font.CreateDynamicFontFromOSFont("Courier New", 13); + + if (m_OutputWindowStyle == null) + { + m_OutputWindowStyle = new GUIStyle() {font = m_OutputWindowMonospacedFont, richText = true}; + m_OutputWindowStyle.normal.textColor = new Color(0.95f, 0.95f, 0.95f, 1f); + } + else + { + m_OutputWindowStyle.font = m_OutputWindowMonospacedFont; + } + } + + GUILayout.BeginVertical(); + { + // Scan project files and resources + GUILayout.BeginVertical(EditorStyles.helpBox); + { + GUILayout.Label("Scan Project Files", EditorStyles.boldLabel); + GUILayout.Label("Press the Scan Project Files button to begin scanning your project for Scenes and Prefabs containing text objects whose line spacing values might need to be converted to the new (em) line spacing values.", TMP_UIStyleManager.label); + GUILayout.Space(10f); + GUILayout.Label("Project folder to be scanned. Example \"Assets/TextMesh Pro\""); + m_ProjectFolderToScan = EditorGUILayout.TextField("Folder Path: Assets/", m_ProjectFolderToScan); + GUILayout.Space(5f); + + GUI.enabled = m_IsAlreadyScanningProject == false ? true : false; + if (GUILayout.Button("Scan Project Files")) + { + m_CancelScanProcess = false; + + // Make sure Asset Serialization mode is set to ForceText and Version Control mode to Visible Meta Files. + if (CheckProjectSerializationAndSourceControlModes() == true) + { + m_ProjectPath = Path.GetFullPath("Assets/.."); + TMP_EditorCoroutine.StartCoroutine(ScanProjectFiles()); + } + else + { + EditorUtility.DisplayDialog("Project Settings Change Required", "In menu options \"Edit - Project Settings - Editor\", please change Asset Serialization Mode to ForceText and Source Control Mode to Visible Meta Files.", "OK", string.Empty); + } + } + GUI.enabled = true; + + // Display progress bar + Rect rect = GUILayoutUtility.GetRect(0f, 20f, GUILayout.ExpandWidth(true)); + EditorGUI.ProgressBar(rect, m_ProgressPercentage, "Scan Progress (" + m_ScanningCurrentFileIndex + "/" + m_ScanningTotalFiles + ")"); + + // Display cancel button and name of file currently being scanned. + if (m_IsAlreadyScanningProject) + { + Rect cancelRect = new Rect(rect.width - 20, rect.y + 2, 20, 16); + if (GUI.Button(cancelRect, "X")) + { + m_CancelScanProcess = true; + } + GUILayout.Label(k_ProjectScanLabelPrefix + m_ScanningCurrentFileName, TMP_UIStyleManager.label); + } + else + GUILayout.Label(string.Empty); + + GUILayout.Space(5); + + // Creation Feedback + GUILayout.BeginVertical(TMP_UIStyleManager.textAreaBoxWindow, GUILayout.ExpandHeight(true)); + { + m_ProjectScanResultScrollPosition = EditorGUILayout.BeginScrollView(m_ProjectScanResultScrollPosition, GUILayout.ExpandHeight(true)); + GUILayout.Label(m_ProjectScanResults, m_OutputWindowStyle); + EditorGUILayout.EndScrollView(); + } + GUILayout.EndVertical(); + GUILayout.Space(5f); + } + GUILayout.EndVertical(); + + // Scan project files and resources + GUILayout.BeginVertical(EditorStyles.helpBox); + { + GUILayout.Label("Save Modified Project Files", EditorStyles.boldLabel); + GUILayout.Label("Pressing the Save Modified Project Files button will update the files in the Project Scan Results listed above. Please make sure that you have created a backup of your project first as these file modifications are permanent and cannot be undone.", TMP_UIStyleManager.label); + GUILayout.Space(5f); + + GUI.enabled = m_IsAlreadyScanningProject == false && m_ModifiedAssetList.Count > 0 ? true : false; + if (GUILayout.Button("Save Modified Project Files")) + { + UpdateProjectFiles(); + } + GUILayout.Space(10f); + } + GUILayout.EndVertical(); + + } + GUILayout.EndVertical(); + GUILayout.Space(5f); + } + + void OnInspectorUpdate() + { + Repaint(); + } + + + /// + /// Limits the minimum size of the editor window. + /// + void SetEditorWindowSize() + { + EditorWindow editorWindow = this; + + Vector2 currentWindowSize = editorWindow.minSize; + + editorWindow.minSize = new Vector2(Mathf.Max(1024, currentWindowSize.x), Mathf.Max(420, currentWindowSize.y)); + } + + private IEnumerator ScanProjectFiles() + { + m_IsAlreadyScanningProject = true; + string packageFullPath = EditorUtilities.TMP_EditorUtility.packageFullPath; + + // List containing assets that have been modified. + m_ProjectScanResults = k_ProjectScanReportDefaultText; + m_ModifiedAssetList.Clear(); + m_ProgressPercentage = 0; + + // Get list of GUIDs for assets that might contain references to previous GUIDs that require updating. + string searchFolder = string.IsNullOrEmpty(m_ProjectFolderToScan) ? "Assets" : ("Assets/" + m_ProjectFolderToScan); + string[] guids = AssetDatabase.FindAssets("t:Object", new string[] { searchFolder }).Distinct().ToArray(); + + k_ProjectScanLabelPrefix = "Phase 1 - Filtering: "; + m_ScanningTotalFiles = guids.Length; + m_ScanningCurrentFileIndex = 0; + + List projectFilesToScan = new List(); + + foreach (var guid in guids) + { + if (m_CancelScanProcess) + break; + + string assetFilePath = AssetDatabase.GUIDToAssetPath(guid); + + m_ScanningCurrentFileIndex += 1; + m_ScanningCurrentFileName = assetFilePath; + m_ProgressPercentage = (float)m_ScanningCurrentFileIndex / m_ScanningTotalFiles; + + string fileExtension = Path.GetExtension(assetFilePath); + Type fileType = AssetDatabase.GetMainAssetTypeAtPath(assetFilePath); + + // Ignore all files other than Scenes and Prefabs. + if ((fileType == typeof(SceneAsset) || (fileType == typeof(GameObject) && fileExtension.ToLower() == ".prefab")) == false) + continue; + + string assetMetaFilePath = AssetDatabase.GetTextMetaFilePathFromAssetPath(assetFilePath); + + projectFilesToScan.Add(new AssetFileRecord(assetFilePath, assetMetaFilePath)); + + yield return null; + } + + m_ScanningTotalFiles = projectFilesToScan.Count; + + k_ProjectScanLabelPrefix = "Phase 2 - Scanning: "; + m_ScanningCurrentFileIndex = 0; + + for (int i = 0; i < m_ScanningTotalFiles; i++) + { + if (m_CancelScanProcess) + break; + + AssetFileRecord fileRecord = projectFilesToScan[i]; + + ScanProjectFile(fileRecord); + + m_ScanningCurrentFileName = fileRecord.assetFilePath; + + m_ScanningCurrentFileIndex += 1; + m_ProgressPercentage = (float)m_ScanningCurrentFileIndex / m_ScanningTotalFiles; + + yield return null; + } + + m_IsAlreadyScanningProject = false; + m_ScanningCurrentFileName = string.Empty; + } + + + static void ScanProjectFile(AssetFileRecord fileRecord) + { + if (m_CancelScanProcess) + return; + + // Read the asset data file + string assetDataFile; + bool hasDataFileChanged = false; + + try + { + assetDataFile = File.ReadAllText(m_ProjectPath + "/" + fileRecord.assetFilePath); + } + catch + { + // Continue to the next asset if we can't read the current one. + return; + } + + // Check if asset file references any text components. + if (assetDataFile.Contains(k_TextMeshProScriptID) || assetDataFile.Contains(k_TextMeshProUGUIScriptID)) + { + float characterSpacingValue = 0; + float newCharacterSpacingValue = 0; + float wordSpacingValue = 0; + float newWordSpacingValue = 0; + float lineSpacingValue = 0; + float newLineSpacingValue = 0; + float paragraphSpacingValue = 0; + float newParagraphSpacingValue = 0; + + float fontSize = 0; + float samplingPointSize = 0; + float faceScale = 1; + + List lines = assetDataFile.Split('\n').ToList(); + int serializedVersionInsertionIndex = 0; + + int readingFlag = 0; + + // Read through each lines of the asset file + for (int i = 0; i < lines.Count; i++) + { + string line = lines[i]; + + // Track potential line index to insert serializedVersion property + if (line.Contains("MonoBehaviour:")) + { + serializedVersionInsertionIndex = i + 1; + continue; + } + + // Read until we find the line that contains a reference to a text component + if (readingFlag == 0 && (line.Contains(k_TextMeshProScriptID) || line.Contains(k_TextMeshProUGUIScriptID))) + { + // Check if spacing values for this component have already been converted + if (lines[serializedVersionInsertionIndex].Contains(" m_SerializedVersion: 1")) + { + readingFlag = 0; + continue; + } + + lines.Insert(serializedVersionInsertionIndex, " m_SerializedVersion: 1"); + readingFlag = 1; + continue; + } + + // Keep reading until we find the font asset property field. + if (readingFlag == 1) + { + // Check for font asset property + if (line.Contains(k_FontAssetProperty)) + { + int guidIndex = line.IndexOf("guid: ", StringComparison.InvariantCulture); + if (guidIndex != -1) + { + string guid = line.Substring(guidIndex + 6, 32); + TMP_FontAsset fontAsset = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid)); + if (fontAsset != null) + { + samplingPointSize = fontAsset.faceInfo.pointSize; + faceScale = fontAsset.faceInfo.scale; + } + } + + readingFlag = 2; + continue; + } + } + + // Read font size property + if (readingFlag == 2) + { + if (line.Contains(k_FontSizeProperty)) + { + fontSize = float.Parse(line.Split(':')[1], NumberStyles.Float, CultureInfo.InvariantCulture); + readingFlag = 3; + continue; + } + } + + // Check for the spacing properties that need to be converted + if (readingFlag == 3) + { + // Read character spacing + if (line.Contains(k_CharacterSpacingProperty)) + { + characterSpacingValue = float.Parse(line.Split(':')[1], NumberStyles.Float, CultureInfo.InvariantCulture); + if (characterSpacingValue != 0) + { + // Convert character spacing value. + newCharacterSpacingValue = characterSpacingValue * faceScale / (samplingPointSize * 0.01f); + lines[i] = lines[i].Replace(k_CharacterSpacingProperty + characterSpacingValue, k_CharacterSpacingProperty + newCharacterSpacingValue); + + hasDataFileChanged = true; + } + continue; + } + + // Read word spacing + if (line.Contains(k_WordSpacingProperty)) + { + // Get the character spacing value + wordSpacingValue = float.Parse(line.Split(':')[1], NumberStyles.Float, CultureInfo.InvariantCulture); + if (wordSpacingValue != 0) + { + // Convert character spacing value. + newWordSpacingValue = wordSpacingValue * faceScale / (samplingPointSize * 0.01f); + lines[i] = lines[i].Replace(k_WordSpacingProperty + wordSpacingValue, k_WordSpacingProperty + newWordSpacingValue); + + hasDataFileChanged = true; + } + continue; + } + + // Read line spacing + if (line.Contains(k_LineSpacingProperty)) + { + // Get the value of line spacing value + lineSpacingValue = float.Parse(line.Split(':')[1], NumberStyles.Float, CultureInfo.InvariantCulture); + if (lineSpacingValue != 0) + { + // Convert line spacing value. + newLineSpacingValue = lineSpacingValue / (fontSize * 0.01f) * fontSize / samplingPointSize * faceScale; + lines[i] = lines[i].Replace(k_LineSpacingProperty + lineSpacingValue, k_LineSpacingProperty + newLineSpacingValue); + + hasDataFileChanged = true; + } + continue; + } + + // Read paragraph spacing + if (line.Contains(k_ParagraphSpacingProperty)) + { + // Get the value of line spacing value + paragraphSpacingValue = float.Parse(line.Split(':')[1], NumberStyles.Float, CultureInfo.InvariantCulture); + if (paragraphSpacingValue != 0) + { + // Convert line spacing value. + newParagraphSpacingValue = paragraphSpacingValue / (fontSize * 0.01f) * fontSize / samplingPointSize * faceScale; + lines[i] = lines[i].Replace(k_ParagraphSpacingProperty + paragraphSpacingValue, k_ParagraphSpacingProperty + newParagraphSpacingValue); + + hasDataFileChanged = true; + } + + readingFlag = 4; + continue; + } + } + + // Done reading text component serialized data. + if (readingFlag == 4 && line.Contains("---")) + { + readingFlag = 0; + + string characterSpacingFormat = $"{(characterSpacingValue == 0 ? " " : $"{characterSpacingValue,10:F}{newCharacterSpacingValue,10:F}")}"; + string wordSpacingFormat = $"{(wordSpacingValue == 0 ? " " : $"{wordSpacingValue,10:F}{newWordSpacingValue,10:F}")}"; + string lineSpacingFormat = $"{(lineSpacingValue == 0 ? " " : $"{lineSpacingValue,10:F}{newLineSpacingValue,10:F}")}"; + string paragraphSpacingFormat = $"{(paragraphSpacingValue == 0 ? " " : $"{paragraphSpacingValue,10:F}{newParagraphSpacingValue,10:F}")}"; + + if (characterSpacingValue != 0 || lineSpacingValue != 0) + m_ProjectScanResults += $"{fileRecord.assetFilePath,-100}" + characterSpacingFormat + wordSpacingFormat + lineSpacingFormat + paragraphSpacingFormat + "\n"; + + // Update asset data file + assetDataFile = string.Join("\n", lines); + + newCharacterSpacingValue = 0; + newWordSpacingValue = 0; + newLineSpacingValue = 0; + newParagraphSpacingValue = 0; + } + } + } + + // Check if asset file is a font asset + // if (assetDataFile.Contains(k_FontAssetScriptID)) + // { + // float samplingPointSize; + // float normalSpacing; + // float newNormalSpacing; + // float boldSpacing; + // float newBoldSpacing; + // } + + if (hasDataFileChanged) + { + AssetModificationRecord modifiedAsset; + modifiedAsset.assetFilePath = fileRecord.assetFilePath; + modifiedAsset.assetDataFile = assetDataFile; + + m_ModifiedAssetList.Add(modifiedAsset); + } + } + + /// + /// + /// + private static void ResetScanProcess() + { + m_IsAlreadyScanningProject = false; + m_ScanningCurrentFileName = string.Empty; + m_ProgressPercentage = 0; + m_ScanningCurrentFileIndex = 0; + m_ScanningTotalFiles = 0; + } + + + /// + /// + /// + private static void UpdateProjectFiles() + { + // Make sure Asset Serialization mode is set to ForceText with Visible Meta Files. + CheckProjectSerializationAndSourceControlModes(); + + string projectPath = Path.GetFullPath("Assets/.."); + + // Display dialogue to show user a list of project files that will be modified upon their consent. + if (EditorUtility.DisplayDialog("Save Modified Asset(s)?", "Are you sure you want to save all modified assets?", "YES", "NO")) + { + for (int i = 0; i < m_ModifiedAssetList.Count; i++) + { + // Make sure all file streams that might have been opened by Unity are closed. + //AssetDatabase.ReleaseCachedFileHandles(); + + //Debug.Log("Writing asset file [" + m_ModifiedAssetList[i].assetFilePath + "]."); + + File.WriteAllText(projectPath + "/" + m_ModifiedAssetList[i].assetFilePath, m_ModifiedAssetList[i].assetDataFile); + } + } + + AssetDatabase.Refresh(); + + m_ProgressPercentage = 0; + m_ProjectScanResults = k_ProjectScanReportDefaultText; + } + + + /// + /// Check project Asset Serialization and Source Control modes + /// + private static bool CheckProjectSerializationAndSourceControlModes() + { + // Check Project Asset Serialization and Visible Meta Files mode. + if (EditorSettings.serializationMode != SerializationMode.ForceText || VersionControlSettings.mode != "Visible Meta Files") + { + return false; + } + + return true; + } + } + + public class TMP_ProjectConversionUtility : EditorWindow + { + // Create Project Files GUID Remapping Tool window + [MenuItem("Window/TextMeshPro/Project Files GUID Remapping Tool", false, 2100)] + static void ShowConverterWindow() + { + var window = GetWindow(); + window.titleContent = new GUIContent("Conversion Tool"); + window.Focus(); + } + + private static HashSet m_IgnoreAssetTypes = new HashSet() + { + typeof(AnimatorOverrideController), + typeof(AudioClip), + typeof(AvatarMask), + typeof(ComputeShader), + typeof(Cubemap), + typeof(DefaultAsset), + typeof(Flare), + typeof(Font), + typeof(GUISkin), + typeof(HumanTemplate), + typeof(LightingDataAsset), + typeof(Mesh), + typeof(MonoScript), + typeof(PhysicsMaterialAsset), + typeof(PhysicsMaterial2D), + typeof(RenderTexture), + typeof(Shader), + typeof(TerrainData), + typeof(TextAsset), + typeof(Texture2D), + typeof(Texture2DArray), + typeof(Texture3D), + typeof(UnityEditorInternal.AssemblyDefinitionAsset), + typeof(UnityEngine.AI.NavMeshData), + typeof(UnityEngine.Tilemaps.Tile), + typeof(UnityEngine.U2D.SpriteAtlas), + typeof(UnityEngine.Video.VideoClip), + }; + + /// + /// + /// + struct AssetModificationRecord + { + public string assetFilePath; + public string assetDataFile; + } + + struct AssetFileRecord + { + public string assetFilePath; + public string assetMetaFilePath; + + public AssetFileRecord(string filePath, string metaFilePath) + { + this.assetFilePath = filePath; + this.assetMetaFilePath = metaFilePath; + } + } + + private static string m_ProjectPath; + private static string m_ProjectFolderToScan; + private static bool m_IsAlreadyScanningProject; + private static bool m_CancelScanProcess; + private static string k_ProjectScanReportDefaultText = "Project Scan Results\n"; + private static string k_ProjectScanLabelPrefix = "Scanning: "; + private static string m_ProjectScanResults = string.Empty; + private static Vector2 m_ProjectScanResultScrollPosition; + private static float m_ProgressPercentage = 0; + + private static int m_ScanningTotalFiles; + private static int m_RemainingFilesToScan; + private static int m_ScanningCurrentFileIndex; + private static string m_ScanningCurrentFileName; + + private static AssetConversionData m_ConversionData; + + private static List m_ModifiedAssetList = new List(); + + + void OnEnable() + { + // Set Editor Window Size + SetEditorWindowSize(); + + m_ProjectScanResults = k_ProjectScanReportDefaultText; + } + + + void OnGUI() + { + GUILayout.BeginVertical(); + { + // Scan project files and resources + GUILayout.BeginVertical(EditorStyles.helpBox); + { + GUILayout.Label("Scan Project Files", EditorStyles.boldLabel); + GUILayout.Label("Press the Scan Project Files button to begin scanning your project for files & resources that were created with a previous version of TextMesh Pro.", TMP_UIStyleManager.label); + GUILayout.Space(10f); + GUILayout.Label("Project folder to be scanned. Example \"Assets/TextMesh Pro\""); + m_ProjectFolderToScan = EditorGUILayout.TextField("Folder Path: Assets/", m_ProjectFolderToScan); + GUILayout.Space(5f); + + GUI.enabled = m_IsAlreadyScanningProject == false ? true : false; + if (GUILayout.Button("Scan Project Files")) + { + m_CancelScanProcess = false; + + // Make sure Asset Serialization mode is set to ForceText and Version Control mode to Visible Meta Files. + if (CheckProjectSerializationAndSourceControlModes() == true) + { + m_ProjectPath = Path.GetFullPath("Assets/.."); + TMP_EditorCoroutine.StartCoroutine(ScanProjectFiles()); + } + else + { + EditorUtility.DisplayDialog("Project Settings Change Required", "In menu options \"Edit - Project Settings - Editor\", please change Asset Serialization Mode to ForceText and Source Control Mode to Visible Meta Files.", "OK", string.Empty); + } + } + GUI.enabled = true; + + // Display progress bar + Rect rect = GUILayoutUtility.GetRect(0f, 20f, GUILayout.ExpandWidth(true)); + EditorGUI.ProgressBar(rect, m_ProgressPercentage, "Scan Progress (" + m_ScanningCurrentFileIndex + "/" + m_ScanningTotalFiles + ")"); + + // Display cancel button and name of file currently being scanned. + if (m_IsAlreadyScanningProject) + { + Rect cancelRect = new Rect(rect.width - 20, rect.y + 2, 20, 16); + if (GUI.Button(cancelRect, "X")) + { + m_CancelScanProcess = true; + } + GUILayout.Label(k_ProjectScanLabelPrefix + m_ScanningCurrentFileName, TMP_UIStyleManager.label); + } + else + GUILayout.Label(string.Empty); + + GUILayout.Space(5); + + // Creation Feedback + GUILayout.BeginVertical(TMP_UIStyleManager.textAreaBoxWindow, GUILayout.ExpandHeight(true)); + { + m_ProjectScanResultScrollPosition = EditorGUILayout.BeginScrollView(m_ProjectScanResultScrollPosition, GUILayout.ExpandHeight(true)); + GUILayout.Label(m_ProjectScanResults, TMP_UIStyleManager.label); + EditorGUILayout.EndScrollView(); + } + GUILayout.EndVertical(); + GUILayout.Space(5f); + } + GUILayout.EndVertical(); + + // Scan project files and resources + GUILayout.BeginVertical(EditorStyles.helpBox); + { + GUILayout.Label("Save Modified Project Files", EditorStyles.boldLabel); + GUILayout.Label("Pressing the Save Modified Project Files button will update the files in the Project Scan Results listed above. Please make sure that you have created a backup of your project first as these file modifications are permanent and cannot be undone.", TMP_UIStyleManager.label); + GUILayout.Space(5f); + + GUI.enabled = m_IsAlreadyScanningProject == false && m_ModifiedAssetList.Count > 0 ? true : false; + if (GUILayout.Button("Save Modified Project Files")) + { + UpdateProjectFiles(); + } + GUILayout.Space(10f); + } + GUILayout.EndVertical(); + + } + GUILayout.EndVertical(); + GUILayout.Space(5f); + } + + void OnInspectorUpdate() + { + Repaint(); + } + + + /// + /// Limits the minimum size of the editor window. + /// + void SetEditorWindowSize() + { + EditorWindow editorWindow = this; + + Vector2 currentWindowSize = editorWindow.minSize; + + editorWindow.minSize = new Vector2(Mathf.Max(640, currentWindowSize.x), Mathf.Max(420, currentWindowSize.y)); + } + + + /// + /// + /// + /// + /// + private static bool ShouldIgnoreFile(string filePath) + { + string fileExtension = Path.GetExtension(filePath); + Type fileType = AssetDatabase.GetMainAssetTypeAtPath(filePath); + + if (m_IgnoreAssetTypes.Contains(fileType)) + return true; + + // Exclude FBX + if (fileType == typeof(GameObject) && (fileExtension.ToLower() == ".fbx" || fileExtension.ToLower() == ".blend")) + return true; + + return false; + } + + + private IEnumerator ScanProjectFiles() + { + m_IsAlreadyScanningProject = true; + string packageFullPath = EditorUtilities.TMP_EditorUtility.packageFullPath; + + // List containing assets that have been modified. + m_ProjectScanResults = k_ProjectScanReportDefaultText; + m_ModifiedAssetList.Clear(); + m_ProgressPercentage = 0; + + // Read Conversion Data from Json file. + if (m_ConversionData == null) + m_ConversionData = JsonUtility.FromJson(File.ReadAllText(packageFullPath + "/PackageConversionData.json")); + + // Get list of GUIDs for assets that might contain references to previous GUIDs that require updating. + string searchFolder = string.IsNullOrEmpty(m_ProjectFolderToScan) ? "Assets" : ("Assets/" + m_ProjectFolderToScan); + string[] guids = AssetDatabase.FindAssets("t:Object", new string[] { searchFolder }).Distinct().ToArray(); + + k_ProjectScanLabelPrefix = "Phase 1 - Filtering: "; + m_ScanningTotalFiles = guids.Length; + m_ScanningCurrentFileIndex = 0; + + List projectFilesToScan = new List(); + + foreach (var guid in guids) + { + if (m_CancelScanProcess) + break; + + string assetFilePath = AssetDatabase.GUIDToAssetPath(guid); + + m_ScanningCurrentFileIndex += 1; + m_ScanningCurrentFileName = assetFilePath; + m_ProgressPercentage = (float)m_ScanningCurrentFileIndex / m_ScanningTotalFiles; + + // Filter out file types we have no interest in searching + if (ShouldIgnoreFile(assetFilePath)) + continue; + + string assetMetaFilePath = AssetDatabase.GetTextMetaFilePathFromAssetPath(assetFilePath); + + projectFilesToScan.Add(new AssetFileRecord(assetFilePath, assetMetaFilePath)); + + yield return null; + } + + m_RemainingFilesToScan = m_ScanningTotalFiles = projectFilesToScan.Count; + + k_ProjectScanLabelPrefix = "Phase 2 - Scanning: "; + + for (int i = 0; i < m_ScanningTotalFiles; i++) + { + if (m_CancelScanProcess) + break; + + AssetFileRecord fileRecord = projectFilesToScan[i]; + + ThreadPool.QueueUserWorkItem(Task => + { + ScanProjectFileAsync(fileRecord); + + m_ScanningCurrentFileName = fileRecord.assetFilePath; + + int completedScans = m_ScanningTotalFiles - Interlocked.Decrement(ref m_RemainingFilesToScan); + + m_ScanningCurrentFileIndex = completedScans; + m_ProgressPercentage = (float)completedScans / m_ScanningTotalFiles; + }); + + if (i % 64 == 0) + yield return new WaitForSeconds(2.0f); + + } + + while (m_RemainingFilesToScan > 0 && !m_CancelScanProcess) + yield return null; + + m_IsAlreadyScanningProject = false; + m_ScanningCurrentFileName = string.Empty; + } + + + static void ScanProjectFileAsync(AssetFileRecord fileRecord) + { + if (m_CancelScanProcess) + return; + + // Read the asset data file + string assetDataFile = string.Empty; + bool hasFileChanged = false; + + try + { + assetDataFile = File.ReadAllText(m_ProjectPath + "/" + fileRecord.assetFilePath); + } + catch + { + // Continue to the next asset if we can't read the current one. + return; + } + + // Read the asset meta data file + string assetMetaFile = File.ReadAllText(m_ProjectPath + "/" + fileRecord.assetMetaFilePath); + bool hasMetaFileChanges = false; + + foreach (AssetConversionRecord record in m_ConversionData.assetRecords) + { + if (assetDataFile.Contains(record.target)) + { + hasFileChanged = true; + + assetDataFile = assetDataFile.Replace(record.target, record.replacement); + } + + //// Check meta file + if (assetMetaFile.Contains(record.target)) + { + hasMetaFileChanges = true; + + assetMetaFile = assetMetaFile.Replace(record.target, record.replacement); + } + } + + if (hasFileChanged) + { + AssetModificationRecord modifiedAsset; + modifiedAsset.assetFilePath = fileRecord.assetFilePath; + modifiedAsset.assetDataFile = assetDataFile; + + m_ModifiedAssetList.Add(modifiedAsset); + + m_ProjectScanResults += fileRecord.assetFilePath + "\n"; + } + + if (hasMetaFileChanges) + { + AssetModificationRecord modifiedAsset; + modifiedAsset.assetFilePath = fileRecord.assetMetaFilePath; + modifiedAsset.assetDataFile = assetMetaFile; + + m_ModifiedAssetList.Add(modifiedAsset); + + m_ProjectScanResults += fileRecord.assetMetaFilePath + "\n"; + } + } + + + /// + /// + /// + private static void ResetScanProcess() + { + m_IsAlreadyScanningProject = false; + m_ScanningCurrentFileName = string.Empty; + m_ProgressPercentage = 0; + m_ScanningCurrentFileIndex = 0; + m_ScanningTotalFiles = 0; + } + + + /// + /// + /// + private static void UpdateProjectFiles() + { + // Make sure Asset Serialization mode is set to ForceText with Visible Meta Files. + CheckProjectSerializationAndSourceControlModes(); + + string projectPath = Path.GetFullPath("Assets/.."); + + // Display dialogue to show user a list of project files that will be modified upon their consent. + if (EditorUtility.DisplayDialog("Save Modified Asset(s)?", "Are you sure you want to save all modified assets?", "YES", "NO")) + { + for (int i = 0; i < m_ModifiedAssetList.Count; i++) + { + // Make sure all file streams that might have been opened by Unity are closed. + //AssetDatabase.ReleaseCachedFileHandles(); + + //Debug.Log("Writing asset file [" + m_ModifiedAssetList[i].assetFilePath + "]."); + + File.WriteAllText(projectPath + "/" + m_ModifiedAssetList[i].assetFilePath, m_ModifiedAssetList[i].assetDataFile); + } + } + + AssetDatabase.Refresh(); + + m_ProgressPercentage = 0; + m_ProjectScanResults = k_ProjectScanReportDefaultText; + } + + + /// + /// Check project Asset Serialization and Source Control modes + /// + private static bool CheckProjectSerializationAndSourceControlModes() + { + // Check Project Asset Serialization and Visible Meta Files mode. + if (EditorSettings.serializationMode != SerializationMode.ForceText || VersionControlSettings.mode != "Visible Meta Files") + { + return false; + } + + return true; + } + } + + public class TMP_PackageUtilities : Editor + { + /// + /// + /// + [MenuItem("Window/TextMeshPro/Import TMP Essential Resources", false, 2050)] + public static void ImportProjectResourcesMenu() + { + ImportEssentialResources(); + } + + + /// + /// + /// + [MenuItem("Window/TextMeshPro/Import TMP Examples and Extras", false, 2051)] + public static void ImportExamplesContentMenu() + { + ImportExamplesAndExtras(); + } + + /// + /// + /// + private static void ImportExamplesAndExtras() + { + string packageFullPath = TMP_EditorUtility.packageFullPath; + + AssetDatabase.ImportPackage(packageFullPath + "/Package Resources/TMP Examples & Extras.unitypackage", true); + } + + private static string k_SettingsFilePath; + private static byte[] k_SettingsBackup; + + /// + /// + /// + private static void ImportEssentialResources() + { + // Check if the TMP Settings asset is already present in the project. + string[] settings = AssetDatabase.FindAssets("t:TMP_Settings"); + + if (settings.Length > 0) + { + // Save assets just in case the TMP Setting were modified before import. + AssetDatabase.SaveAssets(); + + // Copy existing TMP Settings asset to a byte[] + k_SettingsFilePath = AssetDatabase.GUIDToAssetPath(settings[0]); + k_SettingsBackup = File.ReadAllBytes(k_SettingsFilePath); + + RegisterResourceImportCallback(); + } + + string packageFullPath = TMP_EditorUtility.packageFullPath; + + AssetDatabase.ImportPackage(packageFullPath + "/Package Resources/TMP Essential Resources.unitypackage", true); + } + + internal static void RegisterResourceImportCallback() + { + AssetDatabase.importPackageCompleted += ImportCallback; + } + + private static void ImportCallback(string packageName) + { + // Restore backup of TMP Settings from byte[] + File.WriteAllBytes(k_SettingsFilePath, k_SettingsBackup); + AssetDatabase.Refresh(); + + TMP_Settings.instance.SetAssetVersion(); + EditorUtility.SetDirty(TMP_Settings.instance); + AssetDatabase.SaveAssetIfDirty(TMP_Settings.instance); + + AssetDatabase.importPackageCompleted -= ImportCallback; + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_PackageUtilities.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_PackageUtilities.cs.meta new file mode 100644 index 00000000..e03778cc --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_PackageUtilities.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 68eedd4e5b33b37429c02c4add0036fe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_PostBuildProcessHandler.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_PostBuildProcessHandler.cs new file mode 100644 index 00000000..a397a550 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_PostBuildProcessHandler.cs @@ -0,0 +1,35 @@ +using UnityEngine; +using UnityEditor; +using UnityEditor.Callbacks; +using System.IO; + + +namespace TMPro +{ + public class TMP_PostBuildProcessHandler + { + [PostProcessBuildAttribute(10000)] + public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject) + { + if (target == BuildTarget.iOS) + { + // Try loading the TMP Settings + TMP_Settings settings = Resources.Load("TMP Settings"); + + if (settings == null || TMP_Settings.enableEmojiSupport == false) + return; + + string file = Path.Combine(pathToBuiltProject, "Trampoline", "Classes/UI/Keyboard.mm"); + + if (!File.Exists(file)) + { + file = Path.Combine(pathToBuiltProject, "Classes/UI/Keyboard.mm"); + } + + string content = File.ReadAllText(file); + content = content.Replace("FILTER_EMOJIS_IOS_KEYBOARD 1", "FILTER_EMOJIS_IOS_KEYBOARD 0"); + File.WriteAllText(file, content); + } + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_PostBuildProcessHandler.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_PostBuildProcessHandler.cs.meta new file mode 100644 index 00000000..af212b86 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_PostBuildProcessHandler.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6fdea2af3daa40fe8f88e5e9cfc17abb +timeCreated: 1479886230 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_PreBuildProcessor.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_PreBuildProcessor.cs new file mode 100644 index 00000000..dda2f9b1 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_PreBuildProcessor.cs @@ -0,0 +1,30 @@ +using UnityEngine; +using UnityEditor; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; + +namespace TMPro +{ + public class TMP_PreBuildProcessor : IPreprocessBuildWithReport + { + public int callbackOrder { get { return 0; } } + + public void OnPreprocessBuild(BuildReport report) + { + // Find all font assets in the project + string searchPattern = "t:TMP_FontAsset"; + string[] fontAssetGUIDs = AssetDatabase.FindAssets(searchPattern); + + for (int i = 0; i < fontAssetGUIDs.Length; i++) + { + string fontAssetPath = AssetDatabase.GUIDToAssetPath(fontAssetGUIDs[i]); + TMP_FontAsset fontAsset = AssetDatabase.LoadAssetAtPath(fontAssetPath); + + if (fontAsset != null && (fontAsset.atlasPopulationMode == AtlasPopulationMode.Dynamic || fontAsset.atlasPopulationMode == AtlasPopulationMode.DynamicOS) && fontAsset.clearDynamicDataOnBuild && fontAsset.atlasTexture.width != 0) + { + fontAsset.ClearCharacterAndGlyphTablesInternal(); + } + } + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_PreBuildProcessor.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_PreBuildProcessor.cs.meta new file mode 100644 index 00000000..ac8e8ac5 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_PreBuildProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bf8befe3c500aa84b9ce3860a226cf41 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_ProjectTextSettings.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_ProjectTextSettings.cs new file mode 100644 index 00000000..b8695be2 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_ProjectTextSettings.cs @@ -0,0 +1,43 @@ +#if !UNITY_2018_3_OR_NEWER +using UnityEditor; + +namespace TMPro +{ + + public static class TMP_ProjectTextSettings + { + // Open Project Text Settings + [MenuItem("Edit/Project Settings/TextMeshPro Settings", false, 309)] + public static void SelectProjectTextSettings() + { + TMP_Settings textSettings = TMP_Settings.instance; + + if (textSettings) + { + Selection.activeObject = textSettings; + + // TODO: Do we want to ping the Project Text Settings asset in the Project Inspector + EditorUtility.FocusProjectWindow(); + EditorGUIUtility.PingObject(textSettings); + } + else + TMPro_EventManager.RESOURCE_LOAD_EVENT.Add(ON_RESOURCES_LOADED); + } + + + // Event received when TMP resources have been loaded. + static void ON_RESOURCES_LOADED() + { + TMPro_EventManager.RESOURCE_LOAD_EVENT.Remove(ON_RESOURCES_LOADED); + + TMP_Settings textSettings = TMP_Settings.instance; + + Selection.activeObject = textSettings; + + // TODO: Do we want to ping the Project Text Settings asset in the Project Inspector + EditorUtility.FocusProjectWindow(); + EditorGUIUtility.PingObject(textSettings); + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_ProjectTextSettings.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_ProjectTextSettings.cs.meta new file mode 100644 index 00000000..6d194543 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_ProjectTextSettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0e751e877ed14d71a6b8e63ac54949cf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_ResourcesLoader.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_ResourcesLoader.cs new file mode 100644 index 00000000..5689b06f --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_ResourcesLoader.cs @@ -0,0 +1,112 @@ +using System.Collections; +using UnityEditor; +using UnityEngine; + + +namespace TMPro.EditorUtilities +{ + /* + [InitializeOnLoad] + class EssentialResourcesManager + { + private const string s_TMPShaderIncludeGUID = "407bc68d299748449bbf7f48ee690f8d"; + const string k_EssentialResourcesShaderVersionCheckKey = "TMP.EssentialResources.ShaderVersionCheck"; + + static EssentialResourcesManager() + { + bool shaderSearched = SessionState.GetBool(k_EssentialResourcesShaderVersionCheckKey, false); + + if (!EditorApplication.isPlayingOrWillChangePlaymode && !shaderSearched) + CheckShaderVersions(); + } + + static void CheckShaderVersions() + { + // Get path to TMP shader include file. + string assetPath = AssetDatabase.GUIDToAssetPath(s_TMPShaderIncludeGUID); + + if (string.IsNullOrEmpty(assetPath)) + return; + + AssetImporter importer = AssetImporter.GetAtPath(assetPath); + + if (importer != null && string.IsNullOrEmpty(importer.userData)) + { + // Show Shader Import Window + TMP_EditorCoroutine.StartCoroutine(ShowShaderPackageImporterWindow()); + } + + SessionState.SetBool(k_EssentialResourcesShaderVersionCheckKey, true); + } + + static IEnumerator ShowShaderPackageImporterWindow() + { + yield return new WaitForSeconds(5.0f); + + TMP_ShaderPackageImporterWindow.ShowPackageImporterWindow(); + } + } + */ + + /* + //[InitializeOnLoad] + class TMP_ResourcesLoader + { + + /// + /// Function to pre-load the TMP Resources + /// + public static void LoadTextMeshProResources() + { + //TMP_Settings.LoadDefaultSettings(); + //TMP_StyleSheet.LoadDefaultStyleSheet(); + } + + + static TMP_ResourcesLoader() + { + //Debug.Log("Loading TMP Resources..."); + + // Get current targetted platform + + + //string Settings = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone); + //TMPro.TMP_Settings.LoadDefaultSettings(); + //TMPro.TMP_StyleSheet.LoadDefaultStyleSheet(); + } + + + //[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + //static void OnBeforeSceneLoaded() + //{ + //Debug.Log("Before scene is loaded."); + + // //TMPro.TMP_Settings.LoadDefaultSettings(); + // //TMPro.TMP_StyleSheet.LoadDefaultStyleSheet(); + + // //ShaderVariantCollection collection = new ShaderVariantCollection(); + // //Shader s0 = Shader.Find("TextMeshPro/Mobile/Distance Field"); + // //ShaderVariantCollection.ShaderVariant tmp_Variant = new ShaderVariantCollection.ShaderVariant(s0, UnityEngine.Rendering.PassType.Normal, string.Empty); + + // //collection.Add(tmp_Variant); + // //collection.WarmUp(); + //} + + } + + //static class TMP_ProjectSettings + //{ + // [InitializeOnLoadMethod] + // static void SetProjectDefineSymbols() + // { + // string currentBuildSettings = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup); + + // //Check for and inject TMP_INSTALLED + // if (!currentBuildSettings.Contains("TMP_PRESENT")) + // { + // PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, currentBuildSettings + ";TMP_PRESENT"); + // } + // } + //} + */ +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_ResourcesLoader.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_ResourcesLoader.cs.meta new file mode 100644 index 00000000..8b322e2f --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_ResourcesLoader.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7241c7dc25374fc1a6ab3ef9da79c363 +timeCreated: 1465441092 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_SDFShaderGUI.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_SDFShaderGUI.cs new file mode 100644 index 00000000..dfd4cda8 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_SDFShaderGUI.cs @@ -0,0 +1,789 @@ +using UnityEngine; +using UnityEditor; + +namespace TMPro.EditorUtilities +{ + public class TMP_SDFShaderGUI : TMP_BaseShaderGUI + { + static ShaderFeature s_OutlineFeature, s_UnderlayFeature, s_BevelFeature, s_GlowFeature, s_MaskFeature; + + static bool s_Face = true, s_Outline = true, s_Outline2 = true, s_Outline3 = true, s_Underlay = true, s_Lighting = true, s_Glow, s_Bevel, s_Light, s_Bump, s_Env; + + static string[] + s_FaceUVSpeedName = { "_FaceUVSpeed" }, + s_FaceUvSpeedNames = { "_FaceUVSpeedX", "_FaceUVSpeedY" }, + s_OutlineUvSpeedNames = { "_OutlineUVSpeedX", "_OutlineUVSpeedY" }, + s_OutlineUvSpeedName = { "_OutlineUVSpeed" }; + + + static TMP_SDFShaderGUI() + { + s_OutlineFeature = new ShaderFeature() + { + undoLabel = "Outline", + keywords = new[] { "OUTLINE_ON" } + }; + + s_UnderlayFeature = new ShaderFeature() + { + undoLabel = "Underlay", + keywords = new[] { "UNDERLAY_ON", "UNDERLAY_INNER" }, + label = new GUIContent("Underlay Type"), + keywordLabels = new[] + { + new GUIContent("None"), new GUIContent("Normal"), new GUIContent("Inner") + } + }; + + s_BevelFeature = new ShaderFeature() + { + undoLabel = "Bevel", + keywords = new[] { "BEVEL_ON" } + }; + + s_GlowFeature = new ShaderFeature() + { + undoLabel = "Glow", + keywords = new[] { "GLOW_ON" } + }; + + s_MaskFeature = new ShaderFeature() + { + undoLabel = "Mask", + keywords = new[] { "MASK_HARD", "MASK_SOFT" }, + label = new GUIContent("Mask"), + keywordLabels = new[] + { + new GUIContent("Mask Off"), new GUIContent("Mask Hard"), new GUIContent("Mask Soft") + } + }; + } + + protected override void DoGUI() + { + bool isSRPMaterial = m_Material.HasProperty(ShaderUtilities.ID_IsoPerimeter); + + s_Face = BeginPanel("Face", s_Face); + if (s_Face) + { + DoFacePanel(); + } + + EndPanel(); + + // Outline panels + if (isSRPMaterial) + { + DoOutlinePanels(); + } + else + { + s_Outline = m_Material.HasProperty(ShaderUtilities.ID_OutlineTex) ? BeginPanel("Outline", s_Outline) : BeginPanel("Outline", s_OutlineFeature, s_Outline); + if (s_Outline) + { + DoOutlinePanel(); + } + + EndPanel(); + + if (m_Material.HasProperty(ShaderUtilities.ID_Outline2Color)) + { + s_Outline2 = BeginPanel("Outline 2", s_OutlineFeature, s_Outline2); + if (s_Outline2) + { + DoOutline2Panel(); + } + + EndPanel(); + } + } + + // Underlay panel + if (m_Material.HasProperty(ShaderUtilities.ID_UnderlayColor)) + { + if (isSRPMaterial) + { + s_Underlay = BeginPanel("Underlay", s_Underlay); + if (s_Underlay) + { + DoUnderlayPanel(); + } + + EndPanel(); + } + else + { + s_Underlay = BeginPanel("Underlay", s_UnderlayFeature, s_Underlay); + if (s_Underlay) + { + DoUnderlayPanel(); + } + + EndPanel(); + } + } + + // Lighting panel + if (m_Material.HasProperty("_SpecularColor")) + { + if (isSRPMaterial) + DrawLightingPanelSRP(); + else + DrawLightingPanelLegacy(); + } + + + else if (m_Material.HasProperty("_SpecColor")) + { + s_Bevel = BeginPanel("Bevel", s_Bevel); + if (s_Bevel) + { + DoBevelPanel(); + } + + EndPanel(); + + s_Light = BeginPanel("Surface Lighting", s_Light); + if (s_Light) + { + DoSurfaceLightingPanel(); + } + + EndPanel(); + + s_Bump = BeginPanel("Bump Map", s_Bump); + if (s_Bump) + { + DoBumpMapPanel(); + } + + EndPanel(); + + s_Env = BeginPanel("Environment Map", s_Env); + if (s_Env) + { + DoEnvMapPanel(); + } + + EndPanel(); + } + + + if (m_Material.HasProperty(ShaderUtilities.ID_GlowColor)) + { + s_Glow = BeginPanel("Glow", s_GlowFeature, s_Glow); + if (s_Glow) + { + DoGlowPanel(); + } + + EndPanel(); + } + + + s_DebugExtended = BeginPanel("Debug Settings", s_DebugExtended); + if (s_DebugExtended) + { + if (isSRPMaterial) + DoDebugPanelSRP(); + else + DoDebugPanel(); + } + EndPanel(); + + EditorGUILayout.Space(); + EditorGUILayout.Space(); + + if (isSRPMaterial) + { + m_Editor.RenderQueueField(); + m_Editor.EnableInstancingField(); + m_Editor.DoubleSidedGIField(); + m_Editor.EmissionEnabledProperty(); + } + } + + private void DrawLightingPanelSRP() + { + s_Lighting = BeginPanel("Lighting", s_Lighting); + if (s_Lighting) + { + s_Bevel = BeginPanel("Bevel", s_Bevel); + if (s_Bevel) + { + DoBevelPanelSRP(); + } + EndPanel(); + + s_Light = BeginPanel("Local Lighting", s_Light); + if (s_Light) + { + DoLocalLightingPanel(); + } + EndPanel(); + } + + EndPanel(); + } + + private void DrawLightingPanelLegacy() + { + s_Lighting = BeginPanel("Lighting", s_BevelFeature, s_Lighting); + if (s_Lighting) + { + s_Bevel = BeginPanel("Bevel", s_Bevel); + if (s_Bevel) + { + DoBevelPanel(); + } + + EndPanel(); + + s_Light = BeginPanel("Local Lighting", s_Light); + if (s_Light) + { + DoLocalLightingPanel(); + } + + EndPanel(); + + s_Bump = BeginPanel("Bump Map", s_Bump); + if (s_Bump) + { + DoBumpMapPanel(); + } + + EndPanel(); + + s_Env = BeginPanel("Environment Map", s_Env); + if (s_Env) + { + DoEnvMapPanel(); + } + + EndPanel(); + } + + EndPanel(); + } + + void DoFacePanel() + { + EditorGUI.indentLevel += 1; + + DoColor("_FaceColor", "Color"); + + if (m_Material.HasProperty(ShaderUtilities.ID_FaceTex)) + { + if (m_Material.HasProperty("_FaceUVSpeedX")) + { + DoTexture2D("_FaceTex", "Texture", true, s_FaceUvSpeedNames); + } + else if (m_Material.HasProperty("_FaceUVSpeed")) + { + DoTexture2D("_FaceTex", "Texture", true, s_FaceUVSpeedName); + } + else + { + DoTexture2D("_FaceTex", "Texture", true); + } + } + + if (m_Material.HasProperty("_Softness")) + { + DoSlider("_Softness", "X", new Vector2(0, 1), "Softness"); + } + + if (m_Material.HasProperty("_OutlineSoftness")) + { + DoSlider("_OutlineSoftness", "Softness"); + } + + if (m_Material.HasProperty(ShaderUtilities.ID_FaceDilate)) + { + DoSlider("_FaceDilate", "Dilate"); + if (m_Material.HasProperty(ShaderUtilities.ID_Shininess)) + { + DoSlider("_FaceShininess", "Gloss"); + } + } + + if (m_Material.HasProperty(ShaderUtilities.ID_IsoPerimeter)) + { + DoSlider("_IsoPerimeter", "X", new Vector2(-1, 1), "Dilate"); + } + + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoOutlinePanel() + { + EditorGUI.indentLevel += 1; + DoColor("_OutlineColor", "Color"); + if (m_Material.HasProperty(ShaderUtilities.ID_OutlineTex)) + { + if (m_Material.HasProperty("_OutlineUVSpeedX")) + { + DoTexture2D("_OutlineTex", "Texture", true, s_OutlineUvSpeedNames); + } + else if (m_Material.HasProperty("_OutlineUVSpeed")) + { + DoTexture2D("_OutlineTex", "Texture", true, s_OutlineUvSpeedName); + } + else + { + DoTexture2D("_OutlineTex", "Texture", true); + } + } + + DoSlider("_OutlineWidth", "Thickness"); + if (m_Material.HasProperty("_OutlineShininess")) + { + DoSlider("_OutlineShininess", "Gloss"); + } + + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoOutlinePanel(int outlineID, string propertyField, string label) + { + EditorGUI.indentLevel += 1; + DoColor("_OutlineColor" + outlineID, label); + + if (outlineID != 3) + DoOffset("_OutlineOffset" + outlineID, "Offset"); + else + { + if (m_Material.GetFloat(ShaderUtilities.ID_OutlineMode) == 0) + DoOffset("_OutlineOffset" + outlineID, "Offset"); + } + + DoSlider("_Softness", propertyField, new Vector2(0, 1), "Softness"); + DoSlider("_IsoPerimeter", propertyField, new Vector2(-1, 1), "Dilate"); + + if (outlineID == 3) + { + DoToggle("_OutlineMode", "Outline Mode"); + } + + if (m_Material.HasProperty("_OutlineShininess")) + { + //DoSlider("_OutlineShininess", "Gloss"); + } + + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoOutlinePanelWithTexture(int outlineID, string propertyField, string label) + { + EditorGUI.indentLevel += 1; + DoColor("_OutlineColor" + outlineID, label); + if (m_Material.HasProperty(ShaderUtilities.ID_OutlineTex)) + { + if (m_Material.HasProperty("_OutlineUVSpeedX")) + { + DoTexture2D("_OutlineTex", "Texture", true, s_OutlineUvSpeedNames); + } + else if (m_Material.HasProperty("_OutlineUVSpeed")) + { + DoTexture2D("_OutlineTex", "Texture", true, s_OutlineUvSpeedName); + } + else + { + DoTexture2D("_OutlineTex", "Texture", true); + } + } + + DoOffset("_OutlineOffset" + outlineID, "Offset"); + DoSlider("_Softness", propertyField, new Vector2(0, 1), "Softness"); + DoSlider("_IsoPerimeter", propertyField, new Vector2(-1, 1), "Dilate"); + + if (m_Material.HasProperty("_OutlineShininess")) + { + //DoSlider("_OutlineShininess", "Gloss"); + } + + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoOutline2Panel() + { + EditorGUI.indentLevel += 1; + DoColor("_Outline2Color", "Color"); + //if (m_Material.HasProperty(ShaderUtilities.ID_OutlineTex)) + //{ + // if (m_Material.HasProperty("_OutlineUVSpeedX")) + // { + // DoTexture2D("_OutlineTex", "Texture", true, s_OutlineUvSpeedNames); + // } + // else + // { + // DoTexture2D("_OutlineTex", "Texture", true); + // } + //} + + DoSlider("_Outline2Width", "Thickness"); + //if (m_Material.HasProperty("_OutlineShininess")) + //{ + // DoSlider("_OutlineShininess", "Gloss"); + //} + + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoOutlinePanels() + { + s_Outline = BeginPanel("Outline 1", s_Outline); + if (s_Outline) + DoOutlinePanelWithTexture(1, "Y", "Color"); + + EndPanel(); + + s_Outline2 = BeginPanel("Outline 2", s_Outline2); + if (s_Outline2) + DoOutlinePanel(2, "Z", "Color"); + + EndPanel(); + + s_Outline3 = BeginPanel("Outline 3", s_Outline3); + if (s_Outline3) + DoOutlinePanel(3, "W", "Color"); + + EndPanel(); + } + + void DoUnderlayPanel() + { + EditorGUI.indentLevel += 1; + + if (m_Material.HasProperty(ShaderUtilities.ID_IsoPerimeter)) + { + DoColor("_UnderlayColor", "Color"); + DoSlider("_UnderlayOffset", "X", new Vector2(-1, 1), "Offset X"); + DoSlider("_UnderlayOffset", "Y", new Vector2(-1, 1), "Offset Y"); + DoSlider("_UnderlayDilate", new Vector2(-1, 1), "Dilate"); + DoSlider("_UnderlaySoftness", new Vector2(0, 1), "Softness"); + } + else + { + s_UnderlayFeature.DoPopup(m_Editor, m_Material); + DoColor("_UnderlayColor", "Color"); + DoSlider("_UnderlayOffsetX", "Offset X"); + DoSlider("_UnderlayOffsetY", "Offset Y"); + DoSlider("_UnderlayDilate", "Dilate"); + DoSlider("_UnderlaySoftness", "Softness"); + } + + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + static GUIContent[] s_BevelTypeLabels = + { + new GUIContent("Outer Bevel"), + new GUIContent("Inner Bevel") + }; + + void DoBevelPanel() + { + EditorGUI.indentLevel += 1; + DoPopup("_ShaderFlags", "Type", s_BevelTypeLabels); + DoSlider("_Bevel", "Amount"); + DoSlider("_BevelOffset", "Offset"); + DoSlider("_BevelWidth", "Width"); + DoSlider("_BevelRoundness", "Roundness"); + DoSlider("_BevelClamp", "Clamp"); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoBevelPanelSRP() + { + EditorGUI.indentLevel += 1; + DoPopup("_BevelType", "Type", s_BevelTypeLabels); + DoSlider("_BevelAmount", "Amount"); + DoSlider("_BevelOffset", "Offset"); + DoSlider("_BevelWidth", "Width"); + DoSlider("_BevelRoundness", "Roundness"); + DoSlider("_BevelClamp", "Clamp"); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoLocalLightingPanel() + { + EditorGUI.indentLevel += 1; + DoSlider("_LightAngle", "Light Angle"); + DoColor("_SpecularColor", "Specular Color"); + DoSlider("_SpecularPower", "Specular Power"); + DoSlider("_Reflectivity", "Reflectivity Power"); + DoSlider("_Diffuse", "Diffuse Shadow"); + DoSlider("_Ambient", "Ambient Shadow"); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoSurfaceLightingPanel() + { + EditorGUI.indentLevel += 1; + DoColor("_SpecColor", "Specular Color"); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoBumpMapPanel() + { + EditorGUI.indentLevel += 1; + DoTexture2D("_BumpMap", "Texture"); + DoSlider("_BumpFace", "Face"); + DoSlider("_BumpOutline", "Outline"); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoEnvMapPanel() + { + EditorGUI.indentLevel += 1; + DoColor("_ReflectFaceColor", "Face Color"); + DoColor("_ReflectOutlineColor", "Outline Color"); + DoCubeMap("_Cube", "Texture"); + DoVector3("_EnvMatrixRotation", "Rotation"); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoGlowPanel() + { + EditorGUI.indentLevel += 1; + DoColor("_GlowColor", "Color"); + DoSlider("_GlowOffset", "Offset"); + DoSlider("_GlowInner", "Inner"); + DoSlider("_GlowOuter", "Outer"); + DoSlider("_GlowPower", "Power"); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoDebugPanel() + { + EditorGUI.indentLevel += 1; + DoTexture2D("_MainTex", "Font Atlas"); + DoFloat("_GradientScale", "Gradient Scale"); + DoFloat("_TextureWidth", "Texture Width"); + DoFloat("_TextureHeight", "Texture Height"); + EditorGUILayout.Space(); + DoFloat("_ScaleX", "Scale X"); + DoFloat("_ScaleY", "Scale Y"); + + if (m_Material.HasProperty(ShaderUtilities.ID_Sharpness)) + DoSlider("_Sharpness", "Sharpness"); + + DoSlider("_PerspectiveFilter", "Perspective Filter"); + EditorGUILayout.Space(); + DoFloat("_VertexOffsetX", "Offset X"); + DoFloat("_VertexOffsetY", "Offset Y"); + + if (m_Material.HasProperty(ShaderUtilities.ID_MaskCoord)) + { + EditorGUILayout.Space(); + s_MaskFeature.ReadState(m_Material); + s_MaskFeature.DoPopup(m_Editor, m_Material); + if (s_MaskFeature.Active) + { + DoMaskSubgroup(); + } + + EditorGUILayout.Space(); + DoVector("_ClipRect", "Clip Rect", s_LbrtVectorLabels); + } + else if (m_Material.HasProperty("_MaskTex")) + { + DoMaskTexSubgroup(); + } + else if (m_Material.HasProperty(ShaderUtilities.ID_MaskSoftnessX)) + { + EditorGUILayout.Space(); + DoFloat("_MaskSoftnessX", "Softness X"); + DoFloat("_MaskSoftnessY", "Softness Y"); + DoVector("_ClipRect", "Clip Rect", s_LbrtVectorLabels); + } + + if (m_Material.HasProperty(ShaderUtilities.ID_StencilID)) + { + EditorGUILayout.Space(); + DoFloat("_Stencil", "Stencil ID"); + DoFloat("_StencilComp", "Stencil Comp"); + } + + EditorGUILayout.Space(); + + EditorGUI.BeginChangeCheck(); + bool useRatios = EditorGUILayout.Toggle("Use Ratios", !m_Material.IsKeywordEnabled("RATIOS_OFF")); + if (EditorGUI.EndChangeCheck()) + { + m_Editor.RegisterPropertyChangeUndo("Use Ratios"); + if (useRatios) + { + m_Material.DisableKeyword("RATIOS_OFF"); + } + else + { + m_Material.EnableKeyword("RATIOS_OFF"); + } + } + + if (m_Material.HasProperty(ShaderUtilities.ShaderTag_CullMode)) + { + EditorGUILayout.Space(); + DoPopup("_CullMode", "Cull Mode", s_CullingTypeLabels); + } + + EditorGUILayout.Space(); + + EditorGUI.BeginDisabledGroup(true); + DoFloat("_ScaleRatioA", "Scale Ratio A"); + DoFloat("_ScaleRatioB", "Scale Ratio B"); + DoFloat("_ScaleRatioC", "Scale Ratio C"); + EditorGUI.EndDisabledGroup(); + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoDebugPanelSRP() + { + EditorGUI.indentLevel += 1; + DoTexture2D("_MainTex", "Font Atlas"); + DoFloat("_GradientScale", "Gradient Scale"); + //DoFloat("_TextureWidth", "Texture Width"); + //DoFloat("_TextureHeight", "Texture Height"); + EditorGUILayout.Space(); + + /* + DoFloat("_ScaleX", "Scale X"); + DoFloat("_ScaleY", "Scale Y"); + + if (m_Material.HasProperty(ShaderUtilities.ID_Sharpness)) + DoSlider("_Sharpness", "Sharpness"); + + DoSlider("_PerspectiveFilter", "Perspective Filter"); + EditorGUILayout.Space(); + DoFloat("_VertexOffsetX", "Offset X"); + DoFloat("_VertexOffsetY", "Offset Y"); + + if (m_Material.HasProperty(ShaderUtilities.ID_MaskCoord)) + { + EditorGUILayout.Space(); + s_MaskFeature.ReadState(m_Material); + s_MaskFeature.DoPopup(m_Editor, m_Material); + if (s_MaskFeature.Active) + { + DoMaskSubgroup(); + } + + EditorGUILayout.Space(); + DoVector("_ClipRect", "Clip Rect", s_LbrtVectorLabels); + } + else if (m_Material.HasProperty("_MaskTex")) + { + DoMaskTexSubgroup(); + } + else if (m_Material.HasProperty(ShaderUtilities.ID_MaskSoftnessX)) + { + EditorGUILayout.Space(); + DoFloat("_MaskSoftnessX", "Softness X"); + DoFloat("_MaskSoftnessY", "Softness Y"); + DoVector("_ClipRect", "Clip Rect", s_LbrtVectorLabels); + } + + if (m_Material.HasProperty(ShaderUtilities.ID_StencilID)) + { + EditorGUILayout.Space(); + DoFloat("_Stencil", "Stencil ID"); + DoFloat("_StencilComp", "Stencil Comp"); + } + + EditorGUILayout.Space(); + + EditorGUI.BeginChangeCheck(); + bool useRatios = EditorGUILayout.Toggle("Use Ratios", !m_Material.IsKeywordEnabled("RATIOS_OFF")); + if (EditorGUI.EndChangeCheck()) + { + m_Editor.RegisterPropertyChangeUndo("Use Ratios"); + if (useRatios) + { + m_Material.DisableKeyword("RATIOS_OFF"); + } + else + { + m_Material.EnableKeyword("RATIOS_OFF"); + } + } + */ + if (m_Material.HasProperty(ShaderUtilities.ShaderTag_CullMode)) + { + EditorGUILayout.Space(); + DoPopup("_CullMode", "Cull Mode", s_CullingTypeLabels); + } + + EditorGUILayout.Space(); + /* + EditorGUI.BeginDisabledGroup(true); + DoFloat("_ScaleRatioA", "Scale Ratio A"); + DoFloat("_ScaleRatioB", "Scale Ratio B"); + DoFloat("_ScaleRatioC", "Scale Ratio C"); + EditorGUI.EndDisabledGroup(); + */ + + EditorGUI.indentLevel -= 1; + EditorGUILayout.Space(); + } + + void DoMaskSubgroup() + { + DoVector("_MaskCoord", "Mask Bounds", s_XywhVectorLabels); + if (Selection.activeGameObject != null) + { + Renderer renderer = Selection.activeGameObject.GetComponent(); + if (renderer != null) + { + Rect rect = EditorGUILayout.GetControlRect(); + rect.x += EditorGUIUtility.labelWidth; + rect.width -= EditorGUIUtility.labelWidth; + if (GUI.Button(rect, "Match Renderer Bounds")) + { + FindProperty("_MaskCoord", m_Properties).vectorValue = new Vector4( + 0, + 0, + Mathf.Round(renderer.bounds.extents.x * 1000) / 1000, + Mathf.Round(renderer.bounds.extents.y * 1000) / 1000 + ); + } + } + } + + if (s_MaskFeature.State == 1) + { + DoFloat("_MaskSoftnessX", "Softness X"); + DoFloat("_MaskSoftnessY", "Softness Y"); + } + } + + void DoMaskTexSubgroup() + { + EditorGUILayout.Space(); + DoTexture2D("_MaskTex", "Mask Texture"); + DoToggle("_MaskInverse", "Inverse Mask"); + DoColor("_MaskEdgeColor", "Edge Color"); + DoSlider("_MaskEdgeSoftness", "Edge Softness"); + DoSlider("_MaskWipeControl", "Wipe Position"); + DoFloat("_MaskSoftnessX", "Softness X"); + DoFloat("_MaskSoftnessY", "Softness Y"); + DoVector("_ClipRect", "Clip Rect", s_LbrtVectorLabels); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_SDFShaderGUI.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_SDFShaderGUI.cs.meta new file mode 100644 index 00000000..c643afa1 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_SDFShaderGUI.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8413ca0e506d42a1a4bd9769f204ad16 +timeCreated: 1469844718 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_SerializedPropertyHolder.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_SerializedPropertyHolder.cs new file mode 100644 index 00000000..6c4dae30 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_SerializedPropertyHolder.cs @@ -0,0 +1,15 @@ +using UnityEngine; +using UnityEngine.TextCore.LowLevel; + + +namespace TMPro +{ + class TMP_SerializedPropertyHolder : ScriptableObject + { + public TMP_FontAsset fontAsset; + public uint firstCharacter; + public uint secondCharacter; + + public GlyphPairAdjustmentRecord glyphPairAdjustmentRecord = new GlyphPairAdjustmentRecord(new GlyphAdjustmentRecord(), new GlyphAdjustmentRecord()); + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_SerializedPropertyHolder.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_SerializedPropertyHolder.cs.meta new file mode 100644 index 00000000..cde31db9 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_SerializedPropertyHolder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9c4a050f089abb04ebd4125e419f4548 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_SettingsEditor.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_SettingsEditor.cs new file mode 100644 index 00000000..be1a0a1b --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_SettingsEditor.cs @@ -0,0 +1,491 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; +using UnityEditorInternal; + +#pragma warning disable 0414 // Disabled a few warnings for not yet implemented features. + +namespace TMPro.EditorUtilities +{ + [CustomEditor(typeof(TMP_Settings))] + public class TMP_SettingsEditor : Editor + { + internal class Styles + { + public static readonly GUIContent defaultFontAssetLabel = new GUIContent("Default Font Asset", "The Font Asset that will be assigned by default to newly created text objects when no Font Asset is specified."); + public static readonly GUIContent defaultFontAssetPathLabel = new GUIContent("Path: Resources/", "The relative path to a Resources folder where the Font Assets and Material Presets are located.\nExample \"Fonts & Materials/\""); + + public static readonly GUIContent fallbackFontAssetsLabel = new GUIContent("Fallback Font Assets", "The Font Assets that will be searched to locate and replace missing characters from a given Font Asset."); + public static readonly GUIContent fallbackFontAssetsListLabel = new GUIContent("Font Asset List", "The Font Assets that will be searched to locate and replace missing characters from a given Font Asset."); + + public static readonly GUIContent fallbackMaterialSettingsLabel = new GUIContent("Fallback Material Settings"); + public static readonly GUIContent matchMaterialPresetLabel = new GUIContent("Match Material Presets"); + public static readonly GUIContent hideSubTextObjectsPresetLabel = new GUIContent("Hide Sub Text Objects", "Determines if sub text objects will be hidden in the scene hierarchy. Property change will only take effect after entering or existing play mode."); + + public static readonly GUIContent containerDefaultSettingsLabel = new GUIContent("Text Container Default Settings"); + + public static readonly GUIContent textMeshProLabel = new GUIContent("TextMeshPro"); + public static readonly GUIContent textMeshProUiLabel = new GUIContent("TextMeshPro UI"); + public static readonly GUIContent enableRaycastTarget = new GUIContent("Enable Raycast Target"); + public static readonly GUIContent autoSizeContainerLabel = new GUIContent("Auto Size Text Container", "Set the size of the text container to match the text."); + public static readonly GUIContent isTextObjectScaleStaticLabel = new GUIContent("Is Object Scale Static", "Disables calling InternalUpdate() when enabled. This can improve performance when text object scale is static."); + + public static readonly GUIContent textComponentDefaultSettingsLabel = new GUIContent("Text Component Default Settings"); + public static readonly GUIContent defaultFontSize = new GUIContent("Default Font Size"); + public static readonly GUIContent autoSizeRatioLabel = new GUIContent("Text Auto Size Ratios"); + public static readonly GUIContent minLabel = new GUIContent("Min"); + public static readonly GUIContent maxLabel = new GUIContent("Max"); + + public static readonly GUIContent textWrappingModeLabel = new GUIContent("Text Wrapping Mode"); + public static readonly GUIContent kerningLabel = new GUIContent("Kerning"); + public static readonly GUIContent fontFeaturesLabel = new GUIContent("Font Features", "Font features that should be set by default on the text component."); + public static readonly GUIContent extraPaddingLabel = new GUIContent("Extra Padding"); + public static readonly GUIContent tintAllSpritesLabel = new GUIContent("Tint All Sprites"); + public static readonly GUIContent parseEscapeCharactersLabel = new GUIContent("Parse Escape Sequence"); + + public static readonly GUIContent dynamicFontSystemSettingsLabel = new GUIContent("Dynamic Font System Settings"); + public static readonly GUIContent getFontFeaturesAtRuntime = new GUIContent("Get Font Features at Runtime", "Determines if OpenType font features should be retrieved from source font files as new characters and glyphs are added to font assets."); + public static readonly GUIContent dynamicAtlasTextureGroup = new GUIContent("Dynamic Atlas Texture Group"); + + public static readonly GUIContent missingGlyphLabel = new GUIContent("Missing Character Unicode", "The character to be displayed when the requested character is not found in any font asset or fallbacks."); + public static readonly GUIContent clearDynamicDataOnBuildLabel = new GUIContent("Clear Dynamic Data On Build", "Determines if the \"Clear Dynamic Data on Build\" property will be set to true or false on newly created dynamic font assets."); + public static readonly GUIContent disableWarningsLabel = new GUIContent("Disable warnings", "Disable warning messages in the Console."); + + public static readonly GUIContent defaultSpriteAssetLabel = new GUIContent("Default Sprite Asset", "The Sprite Asset that will be assigned by default when using the tag when no Sprite Asset is specified."); + public static readonly GUIContent missingSpriteCharacterUnicodeLabel = new GUIContent("Missing Sprite Unicode", "The unicode value for the sprite character to be displayed when the requested sprite character is not found in any sprite assets or fallbacks."); + public static readonly GUIContent enableEmojiSupportLabel = new GUIContent("iOS Emoji Support", "Enables Emoji support for Touch Screen Keyboards on target devices."); + //public static readonly GUIContent spriteRelativeScale = new GUIContent("Relative Scaling", "Determines if the sprites will be scaled relative to the primary font asset assigned to the text object or relative to the current font asset."); + public static readonly GUIContent emojifallbackTextAssetsListLabel = new GUIContent("Fallback Emoji Text Assets", "The Text Assets that will be searched to display characters defined as Emojis in the Unicode."); + + public static readonly GUIContent spriteAssetsPathLabel = new GUIContent("Path: Resources/", "The relative path to a Resources folder where the Sprite Assets are located.\nExample \"Sprite Assets/\""); + + public static readonly GUIContent defaultStyleSheetLabel = new GUIContent("Default Style Sheet", "The Style Sheet that will be used for all text objects in this project."); + public static readonly GUIContent styleSheetResourcePathLabel = new GUIContent("Path: Resources/", "The relative path to a Resources folder where the Style Sheets are located.\nExample \"Style Sheets/\""); + + public static readonly GUIContent colorGradientPresetsLabel = new GUIContent("Color Gradient Presets", "The relative path to a Resources folder where the Color Gradient Presets are located.\nExample \"Color Gradient Presets/\""); + public static readonly GUIContent colorGradientsPathLabel = new GUIContent("Path: Resources/", "The relative path to a Resources folder where the Color Gradient Presets are located.\nExample \"Color Gradient Presets/\""); + + public static readonly GUIContent lineBreakingLabel = new GUIContent("Line Breaking for Asian languages", "The text assets that contain the Leading and Following characters which define the rules for line breaking with Asian languages."); + public static readonly GUIContent koreanSpecificRules = new GUIContent("Korean Language Options"); + } + + SerializedProperty m_PropFontAsset; + SerializedProperty m_PropDefaultFontAssetPath; + SerializedProperty m_PropDefaultFontSize; + SerializedProperty m_PropDefaultAutoSizeMinRatio; + SerializedProperty m_PropDefaultAutoSizeMaxRatio; + SerializedProperty m_PropDefaultTextMeshProTextContainerSize; + SerializedProperty m_PropDefaultTextMeshProUITextContainerSize; + SerializedProperty m_PropAutoSizeTextContainer; + SerializedProperty m_PropEnableRaycastTarget; + SerializedProperty m_PropIsTextObjectScaleStatic; + + SerializedProperty m_PropSpriteAsset; + SerializedProperty m_PropMissingSpriteCharacterUnicode; + //SerializedProperty m_PropSpriteRelativeScaling; + SerializedProperty m_PropEnableEmojiSupport; + SerializedProperty m_PropSpriteAssetPath; + + ReorderableList m_EmojiFallbackTextAssetList; + + SerializedProperty m_PropStyleSheet; + SerializedProperty m_PropStyleSheetsResourcePath; + ReorderableList m_GlobalFallbackFontAssetList; + + SerializedProperty m_PropColorGradientPresetsPath; + + SerializedProperty m_PropMatchMaterialPreset; + SerializedProperty m_PropHideSubTextObjects; + SerializedProperty m_PropTextWrappingMode; + SerializedProperty m_PropFontFeatures; + SerializedProperty m_PropExtraPadding; + SerializedProperty m_PropTintAllSprites; + SerializedProperty m_PropParseEscapeCharacters; + SerializedProperty m_PropMissingGlyphCharacter; + SerializedProperty m_PropClearDynamicDataOnBuild; + + //SerializedProperty m_DynamicAtlasTextureManager; + SerializedProperty m_GetFontFeaturesAtRuntime; + + SerializedProperty m_PropWarningsDisabled; + + SerializedProperty m_PropLeadingCharacters; + SerializedProperty m_PropFollowingCharacters; + SerializedProperty m_PropUseModernHangulLineBreakingRules; + + private const string k_UndoRedo = "UndoRedoPerformed"; + private bool m_IsFallbackGlyphCacheDirty; + + private static readonly string[] k_FontFeatures = new string[] { "kern", "liga", "mark", "mkmk" }; + + public void OnEnable() + { + if (target == null) + return; + + m_PropFontAsset = serializedObject.FindProperty("m_defaultFontAsset"); + m_PropDefaultFontAssetPath = serializedObject.FindProperty("m_defaultFontAssetPath"); + m_PropDefaultFontSize = serializedObject.FindProperty("m_defaultFontSize"); + m_PropDefaultAutoSizeMinRatio = serializedObject.FindProperty("m_defaultAutoSizeMinRatio"); + m_PropDefaultAutoSizeMaxRatio = serializedObject.FindProperty("m_defaultAutoSizeMaxRatio"); + m_PropDefaultTextMeshProTextContainerSize = serializedObject.FindProperty("m_defaultTextMeshProTextContainerSize"); + m_PropDefaultTextMeshProUITextContainerSize = serializedObject.FindProperty("m_defaultTextMeshProUITextContainerSize"); + m_PropAutoSizeTextContainer = serializedObject.FindProperty("m_autoSizeTextContainer"); + m_PropEnableRaycastTarget = serializedObject.FindProperty("m_EnableRaycastTarget"); + m_PropIsTextObjectScaleStatic = serializedObject.FindProperty("m_IsTextObjectScaleStatic"); + + m_PropSpriteAsset = serializedObject.FindProperty("m_defaultSpriteAsset"); + m_PropMissingSpriteCharacterUnicode = serializedObject.FindProperty("m_MissingCharacterSpriteUnicode"); + //m_PropSpriteRelativeScaling = serializedObject.FindProperty("m_SpriteRelativeScaling"); + m_PropEnableEmojiSupport = serializedObject.FindProperty("m_enableEmojiSupport"); + m_PropSpriteAssetPath = serializedObject.FindProperty("m_defaultSpriteAssetPath"); + + m_PropStyleSheet = serializedObject.FindProperty("m_defaultStyleSheet"); + m_PropStyleSheetsResourcePath = serializedObject.FindProperty("m_StyleSheetsResourcePath"); + + + m_PropColorGradientPresetsPath = serializedObject.FindProperty("m_defaultColorGradientPresetsPath"); + + // Global Fallback ReorderableList + m_GlobalFallbackFontAssetList = new ReorderableList(serializedObject, serializedObject.FindProperty("m_fallbackFontAssets"), true, true, true, true); + + m_GlobalFallbackFontAssetList.drawHeaderCallback = rect => + { + EditorGUI.LabelField(rect, Styles.fallbackFontAssetsListLabel); + }; + + m_GlobalFallbackFontAssetList.drawElementCallback = (rect, index, isActive, isFocused) => + { + var element = m_GlobalFallbackFontAssetList.serializedProperty.GetArrayElementAtIndex(index); + rect.y += 2; + EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), element, GUIContent.none); + }; + + m_GlobalFallbackFontAssetList.onChangedCallback = itemList => + { + m_IsFallbackGlyphCacheDirty = true; + }; + + // Emoji Fallback ReorderableList + m_EmojiFallbackTextAssetList = new ReorderableList(serializedObject, serializedObject.FindProperty("m_EmojiFallbackTextAssets"), true, true, true, true); + + m_EmojiFallbackTextAssetList.drawHeaderCallback = rect => + { + EditorGUI.LabelField(rect, "Text Asset List"); + }; + + m_EmojiFallbackTextAssetList.drawElementCallback = (rect, index, isActive, isFocused) => + { + var element = m_EmojiFallbackTextAssetList.serializedProperty.GetArrayElementAtIndex(index); + rect.y += 2; + EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), element, GUIContent.none); + }; + + m_EmojiFallbackTextAssetList.onChangedCallback = itemList => + { + m_IsFallbackGlyphCacheDirty = true; + }; + + m_PropMatchMaterialPreset = serializedObject.FindProperty("m_matchMaterialPreset"); + m_PropHideSubTextObjects = serializedObject.FindProperty("m_HideSubTextObjects"); + + m_PropTextWrappingMode = serializedObject.FindProperty("m_TextWrappingMode"); + + m_PropFontFeatures = serializedObject.FindProperty("m_ActiveFontFeatures"); + m_PropExtraPadding = serializedObject.FindProperty("m_enableExtraPadding"); + m_PropTintAllSprites = serializedObject.FindProperty("m_enableTintAllSprites"); + m_PropParseEscapeCharacters = serializedObject.FindProperty("m_enableParseEscapeCharacters"); + m_PropMissingGlyphCharacter = serializedObject.FindProperty("m_missingGlyphCharacter"); + m_PropClearDynamicDataOnBuild = serializedObject.FindProperty("m_ClearDynamicDataOnBuild"); + m_PropWarningsDisabled = serializedObject.FindProperty("m_warningsDisabled"); + + //m_DynamicAtlasTextureManager = serializedObject.FindProperty("m_DynamicAtlasTextureGroup"); + m_GetFontFeaturesAtRuntime = serializedObject.FindProperty("m_GetFontFeaturesAtRuntime"); + + m_PropLeadingCharacters = serializedObject.FindProperty("m_leadingCharacters"); + m_PropFollowingCharacters = serializedObject.FindProperty("m_followingCharacters"); + m_PropUseModernHangulLineBreakingRules = serializedObject.FindProperty("m_UseModernHangulLineBreakingRules"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + string evt_cmd = Event.current.commandName; + m_IsFallbackGlyphCacheDirty = false; + + float labelWidth = EditorGUIUtility.labelWidth; + float fieldWidth = EditorGUIUtility.fieldWidth; + + // TextMeshPro Font Info Panel + EditorGUI.indentLevel = 0; + + // FONT ASSET + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + GUILayout.Label(Styles.defaultFontAssetLabel, EditorStyles.boldLabel); + EditorGUI.indentLevel = 1; + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_PropFontAsset, Styles.defaultFontAssetLabel); + if (EditorGUI.EndChangeCheck()) + m_IsFallbackGlyphCacheDirty = true; + + EditorGUILayout.PropertyField(m_PropDefaultFontAssetPath, Styles.defaultFontAssetPathLabel); + EditorGUI.indentLevel = 0; + + EditorGUILayout.Space(); + EditorGUILayout.EndVertical(); + + // FALLBACK FONT ASSETs + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + GUILayout.Label(Styles.fallbackFontAssetsLabel, EditorStyles.boldLabel); + EditorGUI.BeginChangeCheck(); + m_GlobalFallbackFontAssetList.DoLayoutList(); + if (EditorGUI.EndChangeCheck()) + m_IsFallbackGlyphCacheDirty = true; + + GUILayout.Label(Styles.fallbackMaterialSettingsLabel, EditorStyles.boldLabel); + EditorGUI.indentLevel = 1; + EditorGUILayout.PropertyField(m_PropMatchMaterialPreset, Styles.matchMaterialPresetLabel); + EditorGUILayout.PropertyField(m_PropHideSubTextObjects, Styles.hideSubTextObjectsPresetLabel); + EditorGUI.indentLevel = 0; + + EditorGUILayout.Space(); + EditorGUILayout.EndVertical(); + + // MISSING GLYPHS + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + GUILayout.Label(Styles.dynamicFontSystemSettingsLabel, EditorStyles.boldLabel); + EditorGUI.indentLevel = 1; + EditorGUILayout.PropertyField(m_PropMissingGlyphCharacter, Styles.missingGlyphLabel); + EditorGUILayout.PropertyField(m_PropWarningsDisabled, Styles.disableWarningsLabel); + EditorGUILayout.Space(); + EditorGUILayout.PropertyField(m_GetFontFeaturesAtRuntime, Styles.getFontFeaturesAtRuntime); + EditorGUILayout.PropertyField(m_PropClearDynamicDataOnBuild, Styles.clearDynamicDataOnBuildLabel); + //EditorGUILayout.PropertyField(m_DynamicAtlasTextureManager, Styles.dynamicAtlasTextureManager); + EditorGUI.indentLevel = 0; + + EditorGUILayout.Space(); + EditorGUILayout.EndVertical(); + + // TEXT OBJECT DEFAULT PROPERTIES + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + GUILayout.Label(Styles.containerDefaultSettingsLabel, EditorStyles.boldLabel); + EditorGUI.indentLevel = 1; + + EditorGUILayout.PropertyField(m_PropDefaultTextMeshProTextContainerSize, Styles.textMeshProLabel); + EditorGUILayout.PropertyField(m_PropDefaultTextMeshProUITextContainerSize, Styles.textMeshProUiLabel); + EditorGUILayout.PropertyField(m_PropEnableRaycastTarget, Styles.enableRaycastTarget); + EditorGUILayout.PropertyField(m_PropAutoSizeTextContainer, Styles.autoSizeContainerLabel); + EditorGUILayout.PropertyField(m_PropIsTextObjectScaleStatic, Styles.isTextObjectScaleStaticLabel); + EditorGUI.indentLevel = 0; + + EditorGUILayout.Space(); + + GUILayout.Label(Styles.textComponentDefaultSettingsLabel, EditorStyles.boldLabel); + EditorGUI.indentLevel = 1; + EditorGUILayout.PropertyField(m_PropDefaultFontSize, Styles.defaultFontSize); + + EditorGUILayout.BeginHorizontal(); + { + EditorGUILayout.PrefixLabel(Styles.autoSizeRatioLabel); + EditorGUIUtility.labelWidth = 32; + EditorGUIUtility.fieldWidth = 10; + + EditorGUI.indentLevel = 0; + EditorGUILayout.PropertyField(m_PropDefaultAutoSizeMinRatio, Styles.minLabel); + EditorGUILayout.PropertyField(m_PropDefaultAutoSizeMaxRatio, Styles.maxLabel); + EditorGUI.indentLevel = 1; + } + EditorGUILayout.EndHorizontal(); + + EditorGUIUtility.labelWidth = labelWidth; + EditorGUIUtility.fieldWidth = fieldWidth; + + EditorGUILayout.PropertyField(m_PropTextWrappingMode, Styles.textWrappingModeLabel); + + DrawFontFeatures(); + + EditorGUILayout.PropertyField(m_PropExtraPadding, Styles.extraPaddingLabel); + EditorGUILayout.PropertyField(m_PropTintAllSprites, Styles.tintAllSpritesLabel); + + EditorGUILayout.PropertyField(m_PropParseEscapeCharacters, Styles.parseEscapeCharactersLabel); + + EditorGUI.indentLevel = 0; + + EditorGUILayout.Space(); + EditorGUILayout.EndVertical(); + + // SPRITE ASSET + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + GUILayout.Label(Styles.defaultSpriteAssetLabel, EditorStyles.boldLabel); + EditorGUI.indentLevel = 1; + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_PropSpriteAsset, Styles.defaultSpriteAssetLabel); + if (EditorGUI.EndChangeCheck()) + m_IsFallbackGlyphCacheDirty = true; + + EditorGUILayout.PropertyField(m_PropMissingSpriteCharacterUnicode, Styles.missingSpriteCharacterUnicodeLabel); + EditorGUILayout.PropertyField(m_PropEnableEmojiSupport, Styles.enableEmojiSupportLabel); + //EditorGUILayout.PropertyField(m_PropSpriteRelativeScaling, Styles.spriteRelativeScale); + EditorGUILayout.PropertyField(m_PropSpriteAssetPath, Styles.spriteAssetsPathLabel); + EditorGUI.indentLevel = 0; + + EditorGUILayout.Space(); + EditorGUILayout.EndVertical(); + + // EMOJI FALLBACK TEXT ASSETS + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + GUILayout.Label(Styles.emojifallbackTextAssetsListLabel, EditorStyles.boldLabel); + EditorGUI.BeginChangeCheck(); + m_EmojiFallbackTextAssetList.DoLayoutList(); + if (EditorGUI.EndChangeCheck()) + m_IsFallbackGlyphCacheDirty = true; + + EditorGUILayout.Space(); + EditorGUILayout.EndVertical(); + + // STYLE SHEET + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + GUILayout.Label(Styles.defaultStyleSheetLabel, EditorStyles.boldLabel); + EditorGUI.indentLevel = 1; + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_PropStyleSheet, Styles.defaultStyleSheetLabel); + if (EditorGUI.EndChangeCheck()) + { + serializedObject.ApplyModifiedProperties(); + + TMP_StyleSheet styleSheet = m_PropStyleSheet.objectReferenceValue as TMP_StyleSheet; + if (styleSheet != null) + styleSheet.RefreshStyles(); + } + EditorGUILayout.PropertyField(m_PropStyleSheetsResourcePath, Styles.styleSheetResourcePathLabel); + EditorGUI.indentLevel = 0; + + EditorGUILayout.Space(); + EditorGUILayout.EndVertical(); + + // COLOR GRADIENT PRESETS + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + GUILayout.Label(Styles.colorGradientPresetsLabel, EditorStyles.boldLabel); + EditorGUI.indentLevel = 1; + EditorGUILayout.PropertyField(m_PropColorGradientPresetsPath, Styles.colorGradientsPathLabel); + EditorGUI.indentLevel = 0; + + EditorGUILayout.Space(); + EditorGUILayout.EndVertical(); + + // LINE BREAKING RULE + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + GUILayout.Label(Styles.lineBreakingLabel, EditorStyles.boldLabel); + EditorGUI.indentLevel = 1; + EditorGUILayout.PropertyField(m_PropLeadingCharacters); + EditorGUILayout.PropertyField(m_PropFollowingCharacters); + + EditorGUILayout.Space(); + GUILayout.Label(Styles.koreanSpecificRules, EditorStyles.boldLabel); + EditorGUILayout.PropertyField(m_PropUseModernHangulLineBreakingRules, new GUIContent("Use Modern Line Breaking", "Determines if traditional or modern line breaking rules will be used to control line breaking. Traditional line breaking rules use the Leading and Following Character rules whereas Modern uses spaces for line breaking.")); + + EditorGUI.indentLevel = 0; + + EditorGUILayout.Space(); + EditorGUILayout.EndVertical(); + + if (m_IsFallbackGlyphCacheDirty || evt_cmd == k_UndoRedo) + TMP_ResourceManager.RebuildFontAssetCache(); + + if (serializedObject.ApplyModifiedProperties() || evt_cmd == k_UndoRedo) + { + EditorUtility.SetDirty(target); + TMPro_EventManager.ON_TMP_SETTINGS_CHANGED(); + } + } + + void DrawFontFeatures() + { + int srcMask = 0; + + int featureCount = m_PropFontFeatures.arraySize; + for (int i = 0; i < featureCount; i++) + { + SerializedProperty activeFeatureProperty = m_PropFontFeatures.GetArrayElementAtIndex(i); + + for (int j = 0; j < k_FontFeatures.Length; j++) + { + if (activeFeatureProperty.intValue == k_FontFeatures[j].TagToInt()) + { + srcMask |= 0x1 << j; + break; + } + } + } + + EditorGUI.BeginChangeCheck(); + + int mask = EditorGUILayout.MaskField(Styles.fontFeaturesLabel, srcMask, k_FontFeatures); + + if (EditorGUI.EndChangeCheck()) + { + m_PropFontFeatures.ClearArray(); + + int writeIndex = 0; + + for (int i = 0; i < k_FontFeatures.Length; i++) + { + int bit = 0x1 << i; + if ((mask & bit) == bit) + { + m_PropFontFeatures.InsertArrayElementAtIndex(writeIndex); + SerializedProperty newFeature = m_PropFontFeatures.GetArrayElementAtIndex(writeIndex); + newFeature.intValue = k_FontFeatures[i].TagToInt(); + + writeIndex += 1; + } + } + } + } + } + + class TMP_ResourceImporterProvider : SettingsProvider + { + TMP_PackageResourceImporter m_ResourceImporter; + + public TMP_ResourceImporterProvider() + : base("Project/TextMesh Pro", SettingsScope.Project) + { + } + + public override void OnGUI(string searchContext) + { + // Lazy creation that supports domain reload + if (m_ResourceImporter == null) + m_ResourceImporter = new TMP_PackageResourceImporter(logErrors: false); + + m_ResourceImporter.OnGUI(); + } + + public override void OnDeactivate() + { + if (m_ResourceImporter != null) + m_ResourceImporter.OnDestroy(); + } + + static UnityEngine.Object GetTMPSettings() + { + return Resources.Load("TMP Settings"); + } + + [SettingsProviderGroup] + static SettingsProvider[] CreateTMPSettingsProvider() + { + var providers = new List { new TMP_ResourceImporterProvider() }; + + if (GetTMPSettings() != null) + { + var provider = new AssetSettingsProvider("Project/TextMesh Pro/Settings", GetTMPSettings); + provider.PopulateSearchKeywordsFromGUIContentProperties(); + providers.Add(provider); + } + + return providers.ToArray(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_SettingsEditor.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_SettingsEditor.cs.meta new file mode 100644 index 00000000..a719ae77 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_SettingsEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0386b6eb838c47138cd51d1c1b879a35 +timeCreated: 1436658550 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_SpriteAssetEditor.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_SpriteAssetEditor.cs new file mode 100644 index 00000000..237810cd --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_SpriteAssetEditor.cs @@ -0,0 +1,978 @@ +using UnityEngine; +using UnityEngine.TextCore; +using UnityEditor; +using UnityEditorInternal; +using System.Collections.Generic; + + +namespace TMPro.EditorUtilities +{ + + [CustomEditor(typeof(TMP_SpriteAsset))] + public class TMP_SpriteAssetEditor : Editor + { + struct UI_PanelState + { + public static bool spriteAssetFaceInfoPanel = true; + public static bool spriteAtlasInfoPanel = true; + public static bool fallbackSpriteAssetPanel = true; + public static bool spriteCharacterTablePanel; + public static bool spriteGlyphTablePanel; + } + + private static string[] s_UiStateLabel = new string[] { "(Click to collapse) ", "(Click to expand) " }; + + int m_moveToIndex; + int m_selectedElement = -1; + bool m_isCharacterSelected = false; + bool m_isSpriteSelected = false; + int m_CurrentCharacterPage; + int m_CurrentGlyphPage; + + const string k_UndoRedo = "UndoRedoPerformed"; + + string m_CharacterSearchPattern; + List m_CharacterSearchList; + bool m_IsCharacterSearchDirty; + + string m_GlyphSearchPattern; + List m_GlyphSearchList; + bool m_IsGlyphSearchDirty; + + SerializedProperty m_FaceInfoProperty; + SerializedProperty m_PointSizeProperty; + SerializedProperty m_ScaleProperty; + SerializedProperty m_LineHeightProperty; + SerializedProperty m_AscentLineProperty; + SerializedProperty m_BaselineProperty; + SerializedProperty m_DescentLineProperty; + + SerializedProperty m_spriteAtlas_prop; + SerializedProperty m_material_prop; + SerializedProperty m_SpriteCharacterTableProperty; + SerializedProperty m_SpriteGlyphTableProperty; + ReorderableList m_fallbackSpriteAssetList; + + TMP_SpriteAsset m_SpriteAsset; + + bool isAssetDirty; + + float m_xOffset; + float m_yOffset; + float m_xAdvance; + float m_scale; + + public void OnEnable() + { + m_SpriteAsset = target as TMP_SpriteAsset; + + m_FaceInfoProperty = serializedObject.FindProperty("m_FaceInfo"); + m_PointSizeProperty = m_FaceInfoProperty.FindPropertyRelative("m_PointSize"); + m_ScaleProperty = m_FaceInfoProperty.FindPropertyRelative("m_Scale"); + m_LineHeightProperty = m_FaceInfoProperty.FindPropertyRelative("m_LineHeight"); + m_AscentLineProperty = m_FaceInfoProperty.FindPropertyRelative("m_AscentLine"); + m_BaselineProperty = m_FaceInfoProperty.FindPropertyRelative("m_Baseline"); + m_DescentLineProperty = m_FaceInfoProperty.FindPropertyRelative("m_DescentLine"); + + m_spriteAtlas_prop = serializedObject.FindProperty("spriteSheet"); + m_material_prop = serializedObject.FindProperty("m_Material"); + m_SpriteCharacterTableProperty = serializedObject.FindProperty("m_SpriteCharacterTable"); + m_SpriteGlyphTableProperty = serializedObject.FindProperty("m_GlyphTable"); + + // Fallback TMP Sprite Asset list + m_fallbackSpriteAssetList = new ReorderableList(serializedObject, serializedObject.FindProperty("fallbackSpriteAssets"), true, true, true, true); + + m_fallbackSpriteAssetList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => + { + var element = m_fallbackSpriteAssetList.serializedProperty.GetArrayElementAtIndex(index); + rect.y += 2; + EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), element, GUIContent.none); + }; + + m_fallbackSpriteAssetList.drawHeaderCallback = rect => + { + EditorGUI.LabelField(rect, new GUIContent("Fallback Sprite Asset List", "Select the Sprite Assets that will be searched and used as fallback when a given sprite is missing from this sprite asset.")); + }; + + // Clear glyph proxy lookups + TMP_PropertyDrawerUtilities.ClearGlyphProxyLookups(); + } + + + public override void OnInspectorGUI() + { + + //Debug.Log("OnInspectorGUI Called."); + Event currentEvent = Event.current; + string evt_cmd = currentEvent.commandName; // Get Current Event CommandName to check for Undo Events + + serializedObject.Update(); + + + // TEXTMESHPRO SPRITE INFO PANEL + #region Display Sprite Asset Face Info + Rect rect = EditorGUILayout.GetControlRect(false, 24); + + GUI.Label(rect, new GUIContent("Face Info - v" + m_SpriteAsset.version), TMP_UIStyleManager.sectionHeader); + + rect.x += rect.width - 132f; + rect.y += 2; + rect.width = 130f; + rect.height = 18f; + if (GUI.Button(rect, new GUIContent("Update Sprite Asset"))) + { + TMP_SpriteAssetMenu.UpdateSpriteAsset(m_SpriteAsset); + ResetSelectionNextFrame(); + } + EditorGUI.indentLevel = 1; + + EditorGUILayout.PropertyField(m_PointSizeProperty); + EditorGUILayout.PropertyField(m_ScaleProperty); + //EditorGUILayout.PropertyField(m_LineHeightProperty); + EditorGUILayout.PropertyField(m_AscentLineProperty); + EditorGUILayout.PropertyField(m_BaselineProperty); + EditorGUILayout.PropertyField(m_DescentLineProperty); + EditorGUILayout.Space(); + #endregion + + + // ATLAS TEXTURE & MATERIAL + #region Display Atlas Texture and Material + rect = EditorGUILayout.GetControlRect(false, 24); + + if (GUI.Button(rect, new GUIContent("Atlas & Material"), TMP_UIStyleManager.sectionHeader)) + UI_PanelState.spriteAtlasInfoPanel = !UI_PanelState.spriteAtlasInfoPanel; + + GUI.Label(rect, (UI_PanelState.spriteAtlasInfoPanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel); + + if (UI_PanelState.spriteAtlasInfoPanel) + { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_spriteAtlas_prop, new GUIContent("Sprite Atlas")); + if (EditorGUI.EndChangeCheck()) + { + // Assign the new sprite atlas texture to the current material + Texture2D tex = m_spriteAtlas_prop.objectReferenceValue as Texture2D; + if (tex != null) + { + Material mat = m_material_prop.objectReferenceValue as Material; + if (mat != null) + mat.mainTexture = tex; + } + } + + EditorGUILayout.PropertyField(m_material_prop, new GUIContent("Default Material")); + EditorGUILayout.Space(); + } + #endregion + + + // FALLBACK SPRITE ASSETS + #region Display Sprite Fallbacks + rect = EditorGUILayout.GetControlRect(false, 24); + EditorGUI.indentLevel = 0; + if (GUI.Button(rect, new GUIContent("Fallback Sprite Assets", "Select the Sprite Assets that will be searched and used as fallback when a given sprite is missing from this sprite asset."), TMP_UIStyleManager.sectionHeader)) + UI_PanelState.fallbackSpriteAssetPanel = !UI_PanelState.fallbackSpriteAssetPanel; + + GUI.Label(rect, (UI_PanelState.fallbackSpriteAssetPanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel); + + if (UI_PanelState.fallbackSpriteAssetPanel) + { + m_fallbackSpriteAssetList.DoLayoutList(); + EditorGUILayout.Space(); + } + #endregion + + + // SPRITE CHARACTER TABLE + #region Display Sprite Character Table + EditorGUI.indentLevel = 0; + rect = EditorGUILayout.GetControlRect(false, 24); + + if (GUI.Button(rect, new GUIContent("Sprite Character Table", "List of sprite characters contained in this sprite asset."), TMP_UIStyleManager.sectionHeader)) + UI_PanelState.spriteCharacterTablePanel = !UI_PanelState.spriteCharacterTablePanel; + + GUI.Label(rect, (UI_PanelState.spriteCharacterTablePanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel); + + if (UI_PanelState.spriteCharacterTablePanel) + { + int arraySize = m_SpriteCharacterTableProperty.arraySize; + int itemsPerPage = 10; + + // Display Glyph Management Tools + EditorGUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.ExpandWidth(true)); + { + // Search Bar implementation + #region DISPLAY SEARCH BAR + EditorGUILayout.BeginHorizontal(); + { + EditorGUIUtility.labelWidth = 110f; + EditorGUI.BeginChangeCheck(); + string searchPattern = EditorGUILayout.TextField("Sprite Search", m_CharacterSearchPattern, "SearchTextField"); + if (EditorGUI.EndChangeCheck() || m_IsCharacterSearchDirty) + { + if (string.IsNullOrEmpty(searchPattern) == false) + { + //GUIUtility.keyboardControl = 0; + m_CharacterSearchPattern = searchPattern.ToLower(System.Globalization.CultureInfo.InvariantCulture).Trim(); + + // Search Glyph Table for potential matches + SearchCharacterTable(m_CharacterSearchPattern, ref m_CharacterSearchList); + } + else + m_CharacterSearchPattern = null; + + m_IsCharacterSearchDirty = false; + } + + string styleName = string.IsNullOrEmpty(m_CharacterSearchPattern) ? "SearchCancelButtonEmpty" : "SearchCancelButton"; + if (GUILayout.Button(GUIContent.none, styleName)) + { + GUIUtility.keyboardControl = 0; + m_CharacterSearchPattern = string.Empty; + } + } + EditorGUILayout.EndHorizontal(); + #endregion + + // Display Page Navigation + if (!string.IsNullOrEmpty(m_CharacterSearchPattern)) + arraySize = m_CharacterSearchList.Count; + + // Display Page Navigation + DisplayPageNavigation(ref m_CurrentCharacterPage, arraySize, itemsPerPage); + } + EditorGUILayout.EndVertical(); + + if (arraySize > 0) + { + // Display each SpriteInfo entry using the SpriteInfo property drawer. + for (int i = itemsPerPage * m_CurrentCharacterPage; i < arraySize && i < itemsPerPage * (m_CurrentCharacterPage + 1); i++) + { + // Define the start of the selection region of the element. + Rect elementStartRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + + int elementIndex = i; + if (!string.IsNullOrEmpty(m_CharacterSearchPattern)) + elementIndex = m_CharacterSearchList[i]; + + SerializedProperty spriteCharacterProperty = m_SpriteCharacterTableProperty.GetArrayElementAtIndex(elementIndex); + + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + { + EditorGUI.BeginDisabledGroup(i != m_selectedElement || !m_isCharacterSelected); + { + EditorGUILayout.PropertyField(spriteCharacterProperty); + } + EditorGUI.EndDisabledGroup(); + } + EditorGUILayout.EndVertical(); + + // Define the end of the selection region of the element. + Rect elementEndRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + + // Check for Item selection + Rect selectionArea = new Rect(elementStartRegion.x, elementStartRegion.y, elementEndRegion.width, elementEndRegion.y - elementStartRegion.y); + if (DoSelectionCheck(selectionArea)) + { + if (m_selectedElement == i) + { + m_selectedElement = -1; + m_isCharacterSelected = false; + } + else + { + m_selectedElement = i; + m_isCharacterSelected = true; + m_isSpriteSelected = false; + GUIUtility.keyboardControl = 0; + } + } + + // Draw & Handle Section Area + if (m_selectedElement == i && m_isCharacterSelected) + { + // Draw selection highlight + TMP_EditorUtility.DrawBox(selectionArea, 2f, new Color32(40, 192, 255, 255)); + + // Draw options to MoveUp, MoveDown, Add or Remove Sprites + Rect controlRect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight * 1f); + controlRect.width /= 8; + + // Move sprite up. + bool guiEnabled = GUI.enabled; + if (i == 0) { GUI.enabled = false; } + if (GUI.Button(controlRect, "Up")) + { + SwapCharacterElements(i, i - 1); + } + GUI.enabled = guiEnabled; + + // Move sprite down. + controlRect.x += controlRect.width; + if (i == arraySize - 1) { GUI.enabled = false; } + if (GUI.Button(controlRect, "Down")) + { + SwapCharacterElements(i, i + 1); + } + GUI.enabled = guiEnabled; + + // Move sprite to new index + controlRect.x += controlRect.width * 2; + //if (i == arraySize - 1) { GUI.enabled = false; } + m_moveToIndex = EditorGUI.IntField(controlRect, m_moveToIndex); + controlRect.x -= controlRect.width; + if (GUI.Button(controlRect, "Goto")) + { + MoveCharacterToIndex(i, m_moveToIndex); + } + //controlRect.x += controlRect.width; + GUI.enabled = guiEnabled; + + // Add new Sprite + controlRect.x += controlRect.width * 4; + if (GUI.Button(controlRect, "+")) + { + m_SpriteCharacterTableProperty.arraySize += 1; + + int index = m_SpriteCharacterTableProperty.arraySize - 1; + + SerializedProperty spriteInfo_prop = m_SpriteCharacterTableProperty.GetArrayElementAtIndex(index); + + // Copy properties of the selected element + CopyCharacterSerializedProperty(m_SpriteCharacterTableProperty.GetArrayElementAtIndex(elementIndex), ref spriteInfo_prop); + + //spriteInfo_prop.FindPropertyRelative("m_Index").intValue = index; + serializedObject.ApplyModifiedProperties(); + + m_IsCharacterSearchDirty = true; + } + + // Delete selected Sprite + controlRect.x += controlRect.width; + if (m_selectedElement == -1) GUI.enabled = false; + if (GUI.Button(controlRect, "-")) + { + m_SpriteCharacterTableProperty.DeleteArrayElementAtIndex(elementIndex); + + m_selectedElement = -1; + serializedObject.ApplyModifiedProperties(); + + m_IsCharacterSearchDirty = true; + + return; + } + + + } + } + } + + DisplayPageNavigation(ref m_CurrentCharacterPage, arraySize, itemsPerPage); + + EditorGUIUtility.labelWidth = 40f; + EditorGUIUtility.fieldWidth = 20f; + + GUILayout.Space(5f); + + // GLOBAL TOOLS + #region Global Tools + /* + GUI.enabled = true; + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + rect = EditorGUILayout.GetControlRect(false, 40); + + float width = (rect.width - 75f) / 4; + EditorGUI.LabelField(rect, "Global Offsets & Scale", EditorStyles.boldLabel); + + + rect.x += 70; + bool old_ChangedState = GUI.changed; + + GUI.changed = false; + m_xOffset = EditorGUI.FloatField(new Rect(rect.x + 5f + width * 0, rect.y + 20, width - 5f, 18), new GUIContent("OX:"), m_xOffset); + if (GUI.changed) UpdateGlobalProperty("m_HorizontalBearingX", m_xOffset); + + m_yOffset = EditorGUI.FloatField(new Rect(rect.x + 5f + width * 1, rect.y + 20, width - 5f, 18), new GUIContent("OY:"), m_yOffset); + if (GUI.changed) UpdateGlobalProperty("m_HorizontalBearingY", m_yOffset); + + m_xAdvance = EditorGUI.FloatField(new Rect(rect.x + 5f + width * 2, rect.y + 20, width - 5f, 18), new GUIContent("ADV."), m_xAdvance); + if (GUI.changed) UpdateGlobalProperty("m_HorizontalAdvance", m_xAdvance); + + m_scale = EditorGUI.FloatField(new Rect(rect.x + 5f + width * 3, rect.y + 20, width - 5f, 18), new GUIContent("SF."), m_scale); + if (GUI.changed) UpdateGlobalProperty("m_Scale", m_scale); + + EditorGUILayout.EndVertical(); + + GUI.changed = old_ChangedState; + */ + #endregion + + } + #endregion + + + // SPRITE GLYPH TABLE + #region Display Sprite Glyph Table + EditorGUI.indentLevel = 0; + rect = EditorGUILayout.GetControlRect(false, 24); + + if (GUI.Button(rect, new GUIContent("Sprite Glyph Table", "A list of the SpriteGlyphs contained in this sprite asset."), TMP_UIStyleManager.sectionHeader)) + UI_PanelState.spriteGlyphTablePanel = !UI_PanelState.spriteGlyphTablePanel; + + GUI.Label(rect, (UI_PanelState.spriteGlyphTablePanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel); + + if (UI_PanelState.spriteGlyphTablePanel) + { + int arraySize = m_SpriteGlyphTableProperty.arraySize; + int itemsPerPage = 10; + + // Display Glyph Management Tools + EditorGUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.ExpandWidth(true)); + { + // Search Bar implementation + #region DISPLAY SEARCH BAR + EditorGUILayout.BeginHorizontal(); + { + EditorGUIUtility.labelWidth = 110f; + EditorGUI.BeginChangeCheck(); + string searchPattern = EditorGUILayout.TextField("Sprite Search", m_GlyphSearchPattern, "SearchTextField"); + if (EditorGUI.EndChangeCheck() || m_IsGlyphSearchDirty) + { + if (string.IsNullOrEmpty(searchPattern) == false) + { + //GUIUtility.keyboardControl = 0; + m_GlyphSearchPattern = searchPattern.ToLower(System.Globalization.CultureInfo.InvariantCulture).Trim(); + + // Search Glyph Table for potential matches + SearchCharacterTable(m_GlyphSearchPattern, ref m_GlyphSearchList); + } + else + m_GlyphSearchPattern = null; + + m_IsGlyphSearchDirty = false; + } + + string styleName = string.IsNullOrEmpty(m_GlyphSearchPattern) ? "SearchCancelButtonEmpty" : "SearchCancelButton"; + if (GUILayout.Button(GUIContent.none, styleName)) + { + GUIUtility.keyboardControl = 0; + m_GlyphSearchPattern = string.Empty; + } + } + EditorGUILayout.EndHorizontal(); + #endregion + + // Display Page Navigation + if (!string.IsNullOrEmpty(m_GlyphSearchPattern)) + arraySize = m_GlyphSearchList.Count; + + // Display Page Navigation + DisplayPageNavigation(ref m_CurrentGlyphPage, arraySize, itemsPerPage); + } + EditorGUILayout.EndVertical(); + + if (arraySize > 0) + { + // Display each SpriteInfo entry using the SpriteInfo property drawer. + for (int i = itemsPerPage * m_CurrentGlyphPage; i < arraySize && i < itemsPerPage * (m_CurrentGlyphPage + 1); i++) + { + // Define the start of the selection region of the element. + Rect elementStartRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + + int elementIndex = i; + if (!string.IsNullOrEmpty(m_GlyphSearchPattern)) + elementIndex = m_GlyphSearchList[i]; + + SerializedProperty spriteGlyphProperty = m_SpriteGlyphTableProperty.GetArrayElementAtIndex(elementIndex); + + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + { + EditorGUI.BeginDisabledGroup(i != m_selectedElement || !m_isSpriteSelected); + { + EditorGUILayout.PropertyField(spriteGlyphProperty); + } + EditorGUI.EndDisabledGroup(); + } + EditorGUILayout.EndVertical(); + + // Define the end of the selection region of the element. + Rect elementEndRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + + // Check for Item selection + Rect selectionArea = new Rect(elementStartRegion.x, elementStartRegion.y, elementEndRegion.width, elementEndRegion.y - elementStartRegion.y); + if (DoSelectionCheck(selectionArea)) + { + if (m_selectedElement == i) + { + m_selectedElement = -1; + m_isSpriteSelected = false; + } + else + { + m_selectedElement = i; + m_isCharacterSelected = false; + m_isSpriteSelected = true; + GUIUtility.keyboardControl = 0; + } + } + + // Draw & Handle Section Area + if (m_selectedElement == i && m_isSpriteSelected) + { + // Draw selection highlight + TMP_EditorUtility.DrawBox(selectionArea, 2f, new Color32(40, 192, 255, 255)); + + // Draw options to MoveUp, MoveDown, Add or Remove Sprites + Rect controlRect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight * 1f); + controlRect.width /= 8; + + // Move sprite up. + bool guiEnabled = GUI.enabled; + if (i == 0) { GUI.enabled = false; } + if (GUI.Button(controlRect, "Up")) + { + SwapGlyphElements(i, i - 1); + } + GUI.enabled = guiEnabled; + + // Move sprite down. + controlRect.x += controlRect.width; + if (i == arraySize - 1) { GUI.enabled = false; } + if (GUI.Button(controlRect, "Down")) + { + SwapGlyphElements(i, i + 1); + } + GUI.enabled = guiEnabled; + + // Move sprite to new index + controlRect.x += controlRect.width * 2; + //if (i == arraySize - 1) { GUI.enabled = false; } + m_moveToIndex = EditorGUI.IntField(controlRect, m_moveToIndex); + controlRect.x -= controlRect.width; + if (GUI.Button(controlRect, "Goto")) + { + MoveGlyphToIndex(i, m_moveToIndex); + } + //controlRect.x += controlRect.width; + GUI.enabled = guiEnabled; + + // Add new Sprite + controlRect.x += controlRect.width * 4; + if (GUI.Button(controlRect, "+")) + { + m_SpriteGlyphTableProperty.arraySize += 1; + + int index = m_SpriteGlyphTableProperty.arraySize - 1; + + SerializedProperty newSpriteGlyphProperty = m_SpriteGlyphTableProperty.GetArrayElementAtIndex(index); + + // Copy properties of the selected element + CopyGlyphSerializedProperty(m_SpriteGlyphTableProperty.GetArrayElementAtIndex(elementIndex), ref newSpriteGlyphProperty); + + newSpriteGlyphProperty.FindPropertyRelative("m_Index").intValue = index; + + serializedObject.ApplyModifiedProperties(); + + m_IsGlyphSearchDirty = true; + + //m_SpriteAsset.UpdateLookupTables(); + } + + // Delete selected Sprite + controlRect.x += controlRect.width; + if (m_selectedElement == -1) GUI.enabled = false; + if (GUI.Button(controlRect, "-")) + { + SerializedProperty selectedSpriteGlyphProperty = m_SpriteGlyphTableProperty.GetArrayElementAtIndex(elementIndex); + + int selectedGlyphIndex = selectedSpriteGlyphProperty.FindPropertyRelative("m_Index").intValue; + + m_SpriteGlyphTableProperty.DeleteArrayElementAtIndex(elementIndex); + + // Remove all Sprite Characters referencing this glyph. + for (int j = 0; j < m_SpriteCharacterTableProperty.arraySize; j++) + { + int glyphIndex = m_SpriteCharacterTableProperty.GetArrayElementAtIndex(j).FindPropertyRelative("m_GlyphIndex").intValue; + + if (glyphIndex == selectedGlyphIndex) + { + // Remove character + m_SpriteCharacterTableProperty.DeleteArrayElementAtIndex(j); + } + } + + m_selectedElement = -1; + serializedObject.ApplyModifiedProperties(); + + m_IsGlyphSearchDirty = true; + + //m_SpriteAsset.UpdateLookupTables(); + + return; + } + + + } + } + } + + DisplayPageNavigation(ref m_CurrentGlyphPage, arraySize, itemsPerPage); + + EditorGUIUtility.labelWidth = 40f; + EditorGUIUtility.fieldWidth = 20f; + + GUILayout.Space(5f); + + // GLOBAL TOOLS + #region Global Tools + GUI.enabled = true; + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + EditorGUILayout.LabelField("Global Offsets & Scale", EditorStyles.boldLabel); + + bool old_ChangedState = GUI.changed; + GUI.changed = false; + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(25f); + + m_xOffset = EditorGUILayout.FloatField(new GUIContent("OX:"), m_xOffset); + if (GUI.changed) UpdateGlobalProperty("m_HorizontalBearingX", m_xOffset); + + m_yOffset = EditorGUILayout.FloatField(new GUIContent("OY:"), m_yOffset); + if (GUI.changed) UpdateGlobalProperty("m_HorizontalBearingY", m_yOffset); + + m_xAdvance = EditorGUILayout.FloatField(new GUIContent("ADV."), m_xAdvance); + if (GUI.changed) UpdateGlobalProperty("m_HorizontalAdvance", m_xAdvance); + + m_scale = EditorGUILayout.FloatField(new GUIContent("SF."), m_scale); + if (GUI.changed) UpdateGlobalProperty("m_Scale", m_scale); + + EditorGUILayout.EndHorizontal(); + EditorGUILayout.EndVertical(); + #endregion + + GUI.changed = old_ChangedState; + + } + #endregion + + + if (serializedObject.ApplyModifiedProperties() || evt_cmd == k_UndoRedo || isAssetDirty) + { + if (m_SpriteAsset.m_IsSpriteAssetLookupTablesDirty || evt_cmd == k_UndoRedo) + { + m_SpriteAsset.UpdateLookupTables(); + TMP_ResourceManager.RebuildFontAssetCache(); + } + + TMPro_EventManager.ON_SPRITE_ASSET_PROPERTY_CHANGED(true, m_SpriteAsset); + + isAssetDirty = false; + EditorUtility.SetDirty(target); + } + + // Clear selection if mouse event was not consumed. + GUI.enabled = true; + if (currentEvent.type == EventType.MouseDown && currentEvent.button == 0) + m_selectedElement = -1; + + } + + private void ResetSelectionNextFrame() + { + var activeObject = Selection.activeObject; + EditorApplication.delayCall += () => + { + Selection.activeObject = null; + EditorApplication.delayCall += () => + { + Selection.activeObject = activeObject; + }; + }; + } + + + /// + /// + /// + /// + /// + void DisplayPageNavigation(ref int currentPage, int arraySize, int itemsPerPage) + { + Rect pagePos = EditorGUILayout.GetControlRect(false, 20); + pagePos.width /= 3; + + int shiftMultiplier = Event.current.shift ? 10 : 1; // Page + Shift goes 10 page forward + + // Previous Page + GUI.enabled = currentPage > 0; + + if (GUI.Button(pagePos, "Previous Page")) + { + currentPage -= 1 * shiftMultiplier; + //m_isNewPage = true; + } + + // Page Counter + GUI.enabled = true; + pagePos.x += pagePos.width; + int totalPages = (int)(arraySize / (float)itemsPerPage + 0.999f); + GUI.Label(pagePos, "Page " + (currentPage + 1) + " / " + totalPages, TMP_UIStyleManager.centeredLabel); + + // Next Page + pagePos.x += pagePos.width; + GUI.enabled = itemsPerPage * (currentPage + 1) < arraySize; + + if (GUI.Button(pagePos, "Next Page")) + { + currentPage += 1 * shiftMultiplier; + //m_isNewPage = true; + } + + // Clamp page range + currentPage = Mathf.Clamp(currentPage, 0, arraySize / itemsPerPage); + + GUI.enabled = true; + } + + + /// + /// Method to update the properties of all sprites + /// + /// + /// + void UpdateGlobalProperty(string property, float value) + { + int arraySize = m_SpriteGlyphTableProperty.arraySize; + + for (int i = 0; i < arraySize; i++) + { + // Get a reference to the sprite glyph. + SerializedProperty spriteGlyphProperty = m_SpriteGlyphTableProperty.GetArrayElementAtIndex(i); + + if (property == "m_Scale") + { + spriteGlyphProperty.FindPropertyRelative(property).floatValue = value; + } + else + { + SerializedProperty glyphMetricsProperty = spriteGlyphProperty.FindPropertyRelative("m_Metrics"); + glyphMetricsProperty.FindPropertyRelative(property).floatValue = value; + } + } + + GUI.changed = false; + } + + // Check if any of the Style elements were clicked on. + private bool DoSelectionCheck(Rect selectionArea) + { + Event currentEvent = Event.current; + + switch (currentEvent.type) + { + case EventType.MouseDown: + if (selectionArea.Contains(currentEvent.mousePosition) && currentEvent.button == 0) + { + currentEvent.Use(); + return true; + } + break; + } + + return false; + } + + + /// + /// Swap the sprite item at the currently selected array index to another index. + /// + /// Selected index. + /// New index. + void SwapCharacterElements(int selectedIndex, int newIndex) + { + m_SpriteCharacterTableProperty.MoveArrayElement(selectedIndex, newIndex); + m_selectedElement = newIndex; + m_IsCharacterSearchDirty = true; + m_SpriteAsset.m_IsSpriteAssetLookupTablesDirty = true; + } + + /// + /// Move Sprite Element at selected index to another index and reorder sprite list. + /// + /// + /// + void MoveCharacterToIndex(int selectedIndex, int newIndex) + { + int arraySize = m_SpriteCharacterTableProperty.arraySize; + + if (newIndex >= arraySize) + newIndex = arraySize - 1; + + m_SpriteCharacterTableProperty.MoveArrayElement(selectedIndex, newIndex); + + m_selectedElement = newIndex; + m_IsCharacterSearchDirty = true; + m_SpriteAsset.m_IsSpriteAssetLookupTablesDirty = true; + + // TODO: Need to handle switching pages if the character or glyph is moved to a different page. + } + + /// + /// + /// + /// + /// + void SwapGlyphElements(int selectedIndex, int newIndex) + { + m_SpriteGlyphTableProperty.MoveArrayElement(selectedIndex, newIndex); + m_selectedElement = newIndex; + m_IsGlyphSearchDirty = true; + m_SpriteAsset.m_IsSpriteAssetLookupTablesDirty = true; + } + + /// + /// Move Sprite Element at selected index to another index and reorder sprite list. + /// + /// + /// + void MoveGlyphToIndex(int selectedIndex, int newIndex) + { + int arraySize = m_SpriteGlyphTableProperty.arraySize; + + if (newIndex >= arraySize) + newIndex = arraySize - 1; + + m_SpriteGlyphTableProperty.MoveArrayElement(selectedIndex, newIndex); + + m_selectedElement = newIndex; + m_IsGlyphSearchDirty = true; + m_SpriteAsset.m_IsSpriteAssetLookupTablesDirty = true; + + // TODO: Need to handle switching pages if the character or glyph is moved to a different page. + } + + + /// + /// + /// + /// + /// + void CopyCharacterSerializedProperty(SerializedProperty source, ref SerializedProperty target) + { + target.FindPropertyRelative("m_Name").stringValue = source.FindPropertyRelative("m_Name").stringValue; + target.FindPropertyRelative("m_Unicode").intValue = source.FindPropertyRelative("m_Unicode").intValue; + target.FindPropertyRelative("m_GlyphIndex").intValue = source.FindPropertyRelative("m_GlyphIndex").intValue; + target.FindPropertyRelative("m_Scale").floatValue = source.FindPropertyRelative("m_Scale").floatValue; + } + + void CopyGlyphSerializedProperty(SerializedProperty srcGlyph, ref SerializedProperty dstGlyph) + { + // TODO : Should make a generic function which copies each of the properties. + + // Index + dstGlyph.FindPropertyRelative("m_Index").intValue = srcGlyph.FindPropertyRelative("m_Index").intValue; + + // GlyphMetrics + SerializedProperty srcGlyphMetrics = srcGlyph.FindPropertyRelative("m_Metrics"); + SerializedProperty dstGlyphMetrics = dstGlyph.FindPropertyRelative("m_Metrics"); + + dstGlyphMetrics.FindPropertyRelative("m_Width").floatValue = srcGlyphMetrics.FindPropertyRelative("m_Width").floatValue; + dstGlyphMetrics.FindPropertyRelative("m_Height").floatValue = srcGlyphMetrics.FindPropertyRelative("m_Height").floatValue; + dstGlyphMetrics.FindPropertyRelative("m_HorizontalBearingX").floatValue = srcGlyphMetrics.FindPropertyRelative("m_HorizontalBearingX").floatValue; + dstGlyphMetrics.FindPropertyRelative("m_HorizontalBearingY").floatValue = srcGlyphMetrics.FindPropertyRelative("m_HorizontalBearingY").floatValue; + dstGlyphMetrics.FindPropertyRelative("m_HorizontalAdvance").floatValue = srcGlyphMetrics.FindPropertyRelative("m_HorizontalAdvance").floatValue; + + // GlyphRect + SerializedProperty srcGlyphRect = srcGlyph.FindPropertyRelative("m_GlyphRect"); + SerializedProperty dstGlyphRect = dstGlyph.FindPropertyRelative("m_GlyphRect"); + + dstGlyphRect.FindPropertyRelative("m_X").intValue = srcGlyphRect.FindPropertyRelative("m_X").intValue; + dstGlyphRect.FindPropertyRelative("m_Y").intValue = srcGlyphRect.FindPropertyRelative("m_Y").intValue; + dstGlyphRect.FindPropertyRelative("m_Width").intValue = srcGlyphRect.FindPropertyRelative("m_Width").intValue; + dstGlyphRect.FindPropertyRelative("m_Height").intValue = srcGlyphRect.FindPropertyRelative("m_Height").intValue; + + dstGlyph.FindPropertyRelative("m_Scale").floatValue = srcGlyph.FindPropertyRelative("m_Scale").floatValue; + dstGlyph.FindPropertyRelative("m_AtlasIndex").intValue = srcGlyph.FindPropertyRelative("m_AtlasIndex").intValue; + } + + + /// + /// + /// + /// + /// + void SearchCharacterTable(string searchPattern, ref List searchResults) + { + if (searchResults == null) searchResults = new List(); + searchResults.Clear(); + + int arraySize = m_SpriteCharacterTableProperty.arraySize; + + for (int i = 0; i < arraySize; i++) + { + SerializedProperty sourceSprite = m_SpriteCharacterTableProperty.GetArrayElementAtIndex(i); + + // Check for potential match against array index + if (i.ToString().Contains(searchPattern)) + { + searchResults.Add(i); + continue; + } + + // Check for potential match against decimal id + int id = sourceSprite.FindPropertyRelative("m_GlyphIndex").intValue; + if (id.ToString().Contains(searchPattern)) + { + searchResults.Add(i); + continue; + } + + // Check for potential match against name + string name = sourceSprite.FindPropertyRelative("m_Name").stringValue.ToLower(System.Globalization.CultureInfo.InvariantCulture).Trim(); + if (name.Contains(searchPattern)) + { + searchResults.Add(i); + continue; + } + } + } + + void SearchGlyphTable(string searchPattern, ref List searchResults) + { + if (searchResults == null) searchResults = new List(); + searchResults.Clear(); + + int arraySize = m_SpriteGlyphTableProperty.arraySize; + + for (int i = 0; i < arraySize; i++) + { + SerializedProperty sourceSprite = m_SpriteGlyphTableProperty.GetArrayElementAtIndex(i); + + // Check for potential match against array index + if (i.ToString().Contains(searchPattern)) + { + searchResults.Add(i); + continue; + } + + // Check for potential match against decimal id + int id = sourceSprite.FindPropertyRelative("m_GlyphIndex").intValue; + if (id.ToString().Contains(searchPattern)) + { + searchResults.Add(i); + continue; + } + + // Check for potential match against name + string name = sourceSprite.FindPropertyRelative("m_Name").stringValue.ToLower(System.Globalization.CultureInfo.InvariantCulture).Trim(); + if (name.Contains(searchPattern)) + { + searchResults.Add(i); + continue; + } + } + } + + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_SpriteAssetEditor.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_SpriteAssetEditor.cs.meta new file mode 100644 index 00000000..9fcede33 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_SpriteAssetEditor.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: b09be1f217d34247af54863a2f5587e1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_SpriteAssetImporter.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_SpriteAssetImporter.cs new file mode 100644 index 00000000..fa5d9758 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_SpriteAssetImporter.cs @@ -0,0 +1,276 @@ +using System; +using UnityEngine; +using UnityEngine.TextCore; +using UnityEditor; +using System.IO; +using System.Collections.Generic; +using TMPro.EditorUtilities; +using TMPro.SpriteAssetUtilities; + +namespace TMPro +{ + public class TMP_SpriteAssetImporter : EditorWindow + { + // Create Sprite Asset Editor Window + [MenuItem("Window/TextMeshPro/Sprite Importer", false, 2026)] + public static void ShowFontAtlasCreatorWindow() + { + var window = GetWindow(); + window.titleContent = new GUIContent("Sprite Importer"); + window.Focus(); + } + + Texture2D m_SpriteAtlas; + SpriteAssetImportFormats m_SpriteDataFormat = SpriteAssetImportFormats.TexturePackerJsonArray; + TextAsset m_JsonFile; + + string m_CreationFeedback; + + TMP_SpriteAsset m_SpriteAsset; + + static readonly GUIContent k_ConvertSpriteNameToUnicodeLabel = new GUIContent("Use filenames as Unicodes", "Should sprite filenames be converted and assigned as Unicode code points for each sprite? This conversion assumes the sprite filenames represent valid Unicode code points."); + static bool k_SpriteNameIsUnicodeValue; + + /// + /// + /// + void OnEnable() + { + // Set Editor Window Size + SetEditorWindowSize(); + } + + /// + /// + /// + public void OnGUI() + { + DrawEditorPanel(); + } + + /// + /// + /// + private void OnDisable() + { + // Clean up sprite asset object that may have been created and not saved. + if (m_SpriteAsset != null && !EditorUtility.IsPersistent(m_SpriteAsset)) + DestroyImmediate(m_SpriteAsset); + } + + /// + /// + /// + void DrawEditorPanel() + { + // label + GUILayout.Label("Import Settings", EditorStyles.boldLabel); + + EditorGUI.BeginChangeCheck(); + + // Sprite Texture Selection + m_JsonFile = EditorGUILayout.ObjectField("Sprite Data Source", m_JsonFile, typeof(TextAsset), false) as TextAsset; + + m_SpriteDataFormat = (SpriteAssetImportFormats)EditorGUILayout.EnumPopup("Import Format", m_SpriteDataFormat); + + k_SpriteNameIsUnicodeValue = EditorGUILayout.Toggle(k_ConvertSpriteNameToUnicodeLabel, k_SpriteNameIsUnicodeValue); + + // Sprite Texture Selection + m_SpriteAtlas = EditorGUILayout.ObjectField("Sprite Texture Atlas", m_SpriteAtlas, typeof(Texture2D), false) as Texture2D; + + if (EditorGUI.EndChangeCheck()) + { + m_CreationFeedback = string.Empty; + } + + GUILayout.Space(10); + + GUI.enabled = m_JsonFile != null && m_SpriteAtlas != null && m_SpriteDataFormat != SpriteAssetImportFormats.None; + + // Create Sprite Asset + if (GUILayout.Button("Create Sprite Asset")) + { + m_CreationFeedback = string.Empty; + + // Clean up sprite asset object that may have been previously created. + if (m_SpriteAsset != null && !EditorUtility.IsPersistent(m_SpriteAsset)) + DestroyImmediate(m_SpriteAsset); + + // Read json data file + if (m_JsonFile != null) + { + switch (m_SpriteDataFormat) + { + case SpriteAssetImportFormats.TexturePackerJsonArray: + TexturePacker_JsonArray.SpriteDataObject jsonData = null; + try + { + jsonData = JsonUtility.FromJson(m_JsonFile.text); + } + catch + { + m_CreationFeedback = "The Sprite Data Source file [" + m_JsonFile.name + "] appears to be invalid or incorrectly formatted."; + } + + if (jsonData != null && jsonData.frames != null && jsonData.frames.Count > 0) + { + int spriteCount = jsonData.frames.Count; + + // Update import results + m_CreationFeedback = "Import Results\n--------------------\n"; + m_CreationFeedback += "" + spriteCount + " Sprites were imported from file."; + + // Create new Sprite Asset + m_SpriteAsset = CreateInstance(); + + // Assign sprite sheet / atlas texture to sprite asset + m_SpriteAsset.spriteSheet = m_SpriteAtlas; + + List spriteGlyphTable = new List(); + List spriteCharacterTable = new List(); + + PopulateSpriteTables(jsonData, spriteCharacterTable, spriteGlyphTable); + + m_SpriteAsset.spriteCharacterTable = spriteCharacterTable; + m_SpriteAsset.spriteGlyphTable = spriteGlyphTable; + } + break; + } + } + } + + GUI.enabled = true; + + // Creation Feedback + GUILayout.Space(5); + GUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.Height(60)); + { + EditorGUILayout.TextArea(m_CreationFeedback, TMP_UIStyleManager.label); + } + GUILayout.EndVertical(); + + GUILayout.Space(5); + GUI.enabled = m_JsonFile != null && m_SpriteAtlas && m_SpriteAsset != null; + if (GUILayout.Button("Save Sprite Asset") && m_JsonFile != null) + { + string filePath = EditorUtility.SaveFilePanel("Save Sprite Asset File", new FileInfo(AssetDatabase.GetAssetPath(m_JsonFile)).DirectoryName, m_JsonFile.name, "asset"); + + if (filePath.Length == 0) + return; + + SaveSpriteAsset(filePath); + } + GUI.enabled = true; + } + + /// + /// + /// + /// + /// + /// + private static void PopulateSpriteTables(TexturePacker_JsonArray.SpriteDataObject spriteDataObject, List spriteCharacterTable, List spriteGlyphTable) + { + List importedSprites = spriteDataObject.frames; + + float atlasHeight = spriteDataObject.meta.size.h; + + for (int i = 0; i < importedSprites.Count; i++) + { + TexturePacker_JsonArray.Frame spriteData = importedSprites[i]; + + TMP_SpriteGlyph spriteGlyph = new TMP_SpriteGlyph(); + spriteGlyph.index = (uint)i; + + spriteGlyph.metrics = new GlyphMetrics((int)spriteData.frame.w, (int)spriteData.frame.h, -spriteData.frame.w * spriteData.pivot.x, spriteData.frame.h * spriteData.pivot.y, (int)spriteData.frame.w); + spriteGlyph.glyphRect = new GlyphRect((int)spriteData.frame.x, (int)(atlasHeight - spriteData.frame.h - spriteData.frame.y), (int)spriteData.frame.w, (int)spriteData.frame.h); + spriteGlyph.scale = 1.0f; + + spriteGlyphTable.Add(spriteGlyph); + + TMP_SpriteCharacter spriteCharacter = new TMP_SpriteCharacter(0xFFFE, spriteGlyph); + + // Special handling for .notdef sprite name + string fileNameToLowerInvariant = spriteData.filename.ToLowerInvariant(); + if (fileNameToLowerInvariant == ".notdef" || fileNameToLowerInvariant == "notdef") + { + spriteCharacter.name = fileNameToLowerInvariant; + spriteCharacter.unicode = 0; + } + else + { + string spriteName = spriteData.filename.Split('.')[0]; + spriteCharacter.name = spriteName; + + if (k_SpriteNameIsUnicodeValue) + spriteCharacter.unicode = (uint)TMP_TextUtilities.StringHexToInt(spriteName); + } + + spriteCharacter.scale = 1.0f; + + spriteCharacterTable.Add(spriteCharacter); + } + } + + /// + /// + /// + /// + void SaveSpriteAsset(string filePath) + { + filePath = filePath.Substring(0, filePath.Length - 6); // Trim file extension from filePath. + + string dataPath = Application.dataPath; + + if (filePath.IndexOf(dataPath, System.StringComparison.InvariantCultureIgnoreCase) == -1) + { + Debug.LogError("You're saving the font asset in a directory outside of this project folder. This is not supported. Please select a directory under \"" + dataPath + "\""); + return; + } + + string relativeAssetPath = filePath.Substring(dataPath.Length - 6); + string dirName = Path.GetDirectoryName(relativeAssetPath); + string fileName = Path.GetFileNameWithoutExtension(relativeAssetPath); + string pathNoExt = dirName + "/" + fileName; + + // Save Sprite Asset + AssetDatabase.CreateAsset(m_SpriteAsset, pathNoExt + ".asset"); + + // Set version number + m_SpriteAsset.version = "1.1.0"; + + // Compute the hash code for the sprite asset. + m_SpriteAsset.hashCode = TMP_TextUtilities.GetSimpleHashCode(m_SpriteAsset.name); + + // Add new default material for sprite asset. + AddDefaultMaterial(m_SpriteAsset); + } + + /// + /// Create and add new default material to sprite asset. + /// + /// + static void AddDefaultMaterial(TMP_SpriteAsset spriteAsset) + { + Shader shader = Shader.Find("TextMeshPro/Sprite"); + Material material = new Material(shader); + material.SetTexture(ShaderUtilities.ID_MainTex, spriteAsset.spriteSheet); + + spriteAsset.material = material; + material.name = spriteAsset.name + " Material"; + AssetDatabase.AddObjectToAsset(material, spriteAsset); + } + + /// + /// Limits the minimum size of the editor window. + /// + void SetEditorWindowSize() + { + EditorWindow editorWindow = this; + + Vector2 currentWindowSize = editorWindow.minSize; + + editorWindow.minSize = new Vector2(Mathf.Max(230, currentWindowSize.x), Mathf.Max(300, currentWindowSize.y)); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_SpriteAssetImporter.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_SpriteAssetImporter.cs.meta new file mode 100644 index 00000000..d60763a5 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_SpriteAssetImporter.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f1ea944dcf8849ebab391e461b99ccb7 +timeCreated: 1480023525 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_SpriteAssetMenu.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_SpriteAssetMenu.cs new file mode 100644 index 00000000..4747a1d2 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_SpriteAssetMenu.cs @@ -0,0 +1,463 @@ +using UnityEngine; +using UnityEngine.TextCore; +using UnityEngine.U2D; +using UnityEditor; +using System.Linq; +using System.IO; +using System.Collections; +using System.Collections.Generic; + + +namespace TMPro.EditorUtilities +{ + public static class TMP_SpriteAssetMenu + { + // Add a Context Menu to the Sprite Asset Editor Panel to Create and Add a Default Material. + [MenuItem("CONTEXT/TMP_SpriteAsset/Add Default Material", true, 2200)] + static bool AddDefaultMaterialValidate(MenuCommand command) + { + return AssetDatabase.IsOpenForEdit(command.context); + } + + [MenuItem("CONTEXT/TMP_SpriteAsset/Add Default Material", false, 2200)] + static void AddDefaultMaterial(MenuCommand command) + { + TMP_SpriteAsset spriteAsset = (TMP_SpriteAsset)command.context; + + // Make sure the sprite asset already contains a default material + if (spriteAsset != null && spriteAsset.material == null) + { + // Add new default material for sprite asset. + AddDefaultMaterial(spriteAsset); + } + } + + // Add a Context Menu to the Sprite Asset Editor Panel to update existing sprite assets. + [MenuItem("CONTEXT/TMP_SpriteAsset/Update Sprite Asset", true, 2100)] + static bool UpdateSpriteAssetValidate(MenuCommand command) + { + return AssetDatabase.IsOpenForEdit(command.context); + } + + [MenuItem("CONTEXT/TMP_SpriteAsset/Update Sprite Asset", false, 2100)] + static void UpdateSpriteAsset(MenuCommand command) + { + TMP_SpriteAsset spriteAsset = (TMP_SpriteAsset)command.context; + + if (spriteAsset == null) + return; + + UpdateSpriteAsset(spriteAsset); + } + + + internal static void UpdateSpriteAsset(TMP_SpriteAsset spriteAsset) + { + // Get a list of all the sprites contained in the texture referenced by the sprite asset. + // This only works if the texture is set to sprite mode. + string filePath = AssetDatabase.GetAssetPath(spriteAsset.spriteSheet); + + if (string.IsNullOrEmpty(filePath)) + return; + + // Get all the sprites defined in the sprite sheet texture referenced by this sprite asset. + Sprite[] sprites = AssetDatabase.LoadAllAssetsAtPath(filePath).Select(x => x as Sprite).Where(x => x != null).ToArray(); + + // Return if sprite sheet texture does not have any sprites defined in it. + if (sprites.Length == 0) + { + Debug.Log("Sprite Asset [" + spriteAsset.name + "]'s atlas texture does not appear to have any sprites defined in it. Use the Unity Sprite Editor to define sprites for this texture.", spriteAsset.spriteSheet); + return; + } + + List spriteGlyphTable = spriteAsset.spriteGlyphTable; + + // Find available glpyh indexes + uint[] existingGlyphIndexes = spriteGlyphTable.Select(x => x.index).ToArray(); + List availableGlyphIndexes = new List(); + + uint lastGlyphIndex = existingGlyphIndexes.Length > 0 ? existingGlyphIndexes.Last() : 0; + int elementIndex = 0; + for (uint i = 0; i < lastGlyphIndex; i++) + { + uint existingGlyphIndex = existingGlyphIndexes[elementIndex]; + + if (i == existingGlyphIndex) + elementIndex += 1; + else + availableGlyphIndexes.Add(i); + } + + // Iterate over sprites contained in the updated sprite sheet to identify new and / or modified sprites. + for (int i = 0; i < sprites.Length; i++) + { + Sprite sprite = sprites[i]; + + // Check if current sprites is already contained in the sprite glyph table of the sprite asset. + TMP_SpriteGlyph spriteGlyph = spriteGlyphTable.FirstOrDefault(x => x.sprite == sprite); + + if (spriteGlyph != null) + { + // update existing sprite glyph + if (spriteGlyph.glyphRect.x != sprite.rect.x || spriteGlyph.glyphRect.y != sprite.rect.y || spriteGlyph.glyphRect.width != sprite.rect.width || spriteGlyph.glyphRect.height != sprite.rect.height) + spriteGlyph.glyphRect = new GlyphRect(sprite.rect); + } + else + { + TMP_SpriteCharacter spriteCharacter; + + // Check if this sprite potentially exists under the same name in the sprite character table. + if (spriteAsset.spriteCharacterTable != null && spriteAsset.spriteCharacterTable.Count > 0) + { + spriteCharacter = spriteAsset.spriteCharacterTable.FirstOrDefault(x => x.name == sprite.name); + spriteGlyph = spriteCharacter != null ? spriteGlyphTable[(int)spriteCharacter.glyphIndex] : null; + + if (spriteGlyph != null) + { + // Update sprite reference and data + spriteGlyph.sprite = sprite; + + if (spriteGlyph.glyphRect.x != sprite.rect.x || spriteGlyph.glyphRect.y != sprite.rect.y || spriteGlyph.glyphRect.width != sprite.rect.width || spriteGlyph.glyphRect.height != sprite.rect.height) + spriteGlyph.glyphRect = new GlyphRect(sprite.rect); + } + } + + // Add new Sprite Glyph to the table + spriteGlyph = new TMP_SpriteGlyph(); + + // Get available glyph index + if (availableGlyphIndexes.Count > 0) + { + spriteGlyph.index = availableGlyphIndexes[0]; + availableGlyphIndexes.RemoveAt(0); + } + else + spriteGlyph.index = (uint)spriteGlyphTable.Count; + + spriteGlyph.metrics = new GlyphMetrics(sprite.rect.width, sprite.rect.height, -sprite.pivot.x, sprite.rect.height - sprite.pivot.y, sprite.rect.width); + spriteGlyph.glyphRect = new GlyphRect(sprite.rect); + spriteGlyph.scale = 1.0f; + spriteGlyph.sprite = sprite; + + spriteGlyphTable.Add(spriteGlyph); + + spriteCharacter = new TMP_SpriteCharacter(0xFFFE, spriteGlyph); + + // Special handling for .notdef sprite name. + string fileNameToLowerInvariant = sprite.name.ToLowerInvariant(); + if (fileNameToLowerInvariant == ".notdef" || fileNameToLowerInvariant == "notdef") + { + spriteCharacter.name = fileNameToLowerInvariant; + spriteCharacter.unicode = 0; + } + else + { + spriteCharacter.unicode = 0xFFFE; + if (!string.IsNullOrEmpty(sprite.name) && sprite.name.Length > 2 && sprite.name[0] == '0' && (sprite.name[1] == 'x' || sprite.name[1] == 'X')) + { + spriteCharacter.unicode = (uint)TMP_TextUtilities.StringHexToInt(sprite.name.Remove(0, 2)); + } + spriteCharacter.name = sprite.name; + } + + spriteCharacter.scale = 1.0f; + + spriteAsset.spriteCharacterTable.Add(spriteCharacter); + } + } + + // Update Sprite Character Table to replace unicode 0x0 by 0xFFFE + for (int i = 0; i < spriteAsset.spriteCharacterTable.Count; i++) + { + TMP_SpriteCharacter spriteCharacter = spriteAsset.spriteCharacterTable[i]; + if (spriteCharacter.unicode == 0) + spriteCharacter.unicode = 0xFFFE; + } + + // Sort glyph table by glyph index + spriteAsset.SortGlyphTable(); + spriteAsset.UpdateLookupTables(); + TMPro_EventManager.ON_SPRITE_ASSET_PROPERTY_CHANGED(true, spriteAsset); + EditorUtility.SetDirty(spriteAsset); + + } + + + [MenuItem("Assets/Create/TextMeshPro/Sprite Asset", false, 200)] + static void CreateSpriteAsset() + { + Object[] targets = Selection.objects; + + if (targets == null) + { + Debug.LogWarning("A Sprite Texture must first be selected in order to create a Sprite Asset."); + return; + } + + // Make sure TMP Essential Resources have been imported in the user project. + if (TMP_Settings.instance == null) + { + Debug.Log("Unable to create sprite asset. Please import the TMP Essential Resources."); + + // Show Window to Import TMP Essential Resources + return; + } + + for (int i = 0; i < targets.Length; i++) + { + Object target = targets[i]; + + // Make sure the selection is a font file + if (target == null || target.GetType() != typeof(Texture2D)) + { + Debug.LogWarning("Selected Object [" + target.name + "] is not a Sprite Texture. A Sprite Texture must be selected in order to create a Sprite Asset.", target); + continue; + } + + CreateSpriteAssetFromSelectedObject(target); + } + } + + + static void CreateSpriteAssetFromSelectedObject(Object target) + { + // Get the path to the selected asset. + string filePathWithName = AssetDatabase.GetAssetPath(target); + string fileNameWithExtension = Path.GetFileName(filePathWithName); + string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePathWithName); + string filePath = filePathWithName.Replace(fileNameWithExtension, ""); + string uniquePath = AssetDatabase.GenerateUniqueAssetPath(filePath + fileNameWithoutExtension + ".asset"); + + // Create new Sprite Asset + TMP_SpriteAsset spriteAsset = ScriptableObject.CreateInstance(); + AssetDatabase.CreateAsset(spriteAsset, uniquePath); + + spriteAsset.version = "1.1.0"; + + // Compute the hash code for the sprite asset. + spriteAsset.hashCode = TMP_TextUtilities.GetSimpleHashCode(spriteAsset.name); + + List spriteGlyphTable = new List(); + List spriteCharacterTable = new List(); + + if (target.GetType() == typeof(Texture2D)) + { + Texture2D sourceTex = target as Texture2D; + + // Assign new Sprite Sheet texture to the Sprite Asset. + spriteAsset.spriteSheet = sourceTex; + + PopulateSpriteTables(sourceTex, ref spriteCharacterTable, ref spriteGlyphTable); + + spriteAsset.spriteCharacterTable = spriteCharacterTable; + spriteAsset.spriteGlyphTable = spriteGlyphTable; + + // Add new default material for sprite asset. + AddDefaultMaterial(spriteAsset); + } + else if (target.GetType() == typeof(SpriteAtlas)) + { + //SpriteAtlas spriteAtlas = target as SpriteAtlas; + + //PopulateSpriteTables(spriteAtlas, ref spriteCharacterTable, ref spriteGlyphTable); + + //spriteAsset.spriteCharacterTable = spriteCharacterTable; + //spriteAsset.spriteGlyphTable = spriteGlyphTable; + + //spriteAsset.spriteSheet = spriteGlyphTable[0].sprite.texture; + + //// Add new default material for sprite asset. + //AddDefaultMaterial(spriteAsset); + } + + // Update Lookup tables. + spriteAsset.UpdateLookupTables(); + + // Get the Sprites contained in the Sprite Sheet + EditorUtility.SetDirty(spriteAsset); + + //spriteAsset.sprites = sprites; + + // Set source texture back to Not Readable. + //texImporter.isReadable = false; + + AssetDatabase.SaveAssets(); + + AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(spriteAsset)); // Re-import font asset to get the new updated version. + + //AssetDatabase.Refresh(); + } + + + static void PopulateSpriteTables(Texture source, ref List spriteCharacterTable, ref List spriteGlyphTable) + { + //Debug.Log("Creating new Sprite Asset."); + + string filePath = AssetDatabase.GetAssetPath(source); + + // Get all the Sprites sorted by Index + Sprite[] sprites = AssetDatabase.LoadAllAssetsAtPath(filePath).Select(x => x as Sprite).Where(x => x != null).OrderByDescending(x => x.rect.y).ThenBy(x => x.rect.x).ToArray(); + + for (int i = 0; i < sprites.Length; i++) + { + Sprite sprite = sprites[i]; + + TMP_SpriteGlyph spriteGlyph = new TMP_SpriteGlyph(); + spriteGlyph.index = (uint)i; + spriteGlyph.metrics = new GlyphMetrics(sprite.rect.width, sprite.rect.height, -sprite.pivot.x, sprite.rect.height - sprite.pivot.y, sprite.rect.width); + spriteGlyph.glyphRect = new GlyphRect(sprite.rect); + spriteGlyph.scale = 1.0f; + spriteGlyph.sprite = sprite; + + spriteGlyphTable.Add(spriteGlyph); + + TMP_SpriteCharacter spriteCharacter = new TMP_SpriteCharacter(0xFFFE, spriteGlyph); + + // Special handling for .notdef sprite name. + string fileNameToLowerInvariant = sprite.name.ToLowerInvariant(); + if (fileNameToLowerInvariant == ".notdef" || fileNameToLowerInvariant == "notdef") + { + spriteCharacter.unicode = 0; + spriteCharacter.name = fileNameToLowerInvariant; + } + else + { + if (!string.IsNullOrEmpty(sprite.name) && sprite.name.Length > 2 && sprite.name[0] == '0' && (sprite.name[1] == 'x' || sprite.name[1] == 'X')) + { + spriteCharacter.unicode = (uint)TMP_TextUtilities.StringHexToInt(sprite.name.Remove(0, 2)); + } + spriteCharacter.name = sprite.name; + } + + spriteCharacter.scale = 1.0f; + + spriteCharacterTable.Add(spriteCharacter); + } + } + + + static void PopulateSpriteTables(SpriteAtlas spriteAtlas, ref List spriteCharacterTable, ref List spriteGlyphTable) + { + // Get number of sprites contained in the sprite atlas. + int spriteCount = spriteAtlas.spriteCount; + Sprite[] sprites = new Sprite[spriteCount]; + + // Get all the sprites + spriteAtlas.GetSprites(sprites); + + for (int i = 0; i < sprites.Length; i++) + { + Sprite sprite = sprites[i]; + + TMP_SpriteGlyph spriteGlyph = new TMP_SpriteGlyph(); + spriteGlyph.index = (uint)i; + spriteGlyph.metrics = new GlyphMetrics(sprite.textureRect.width, sprite.textureRect.height, -sprite.pivot.x, sprite.textureRect.height - sprite.pivot.y, sprite.textureRect.width); + spriteGlyph.glyphRect = new GlyphRect(sprite.textureRect); + spriteGlyph.scale = 1.0f; + spriteGlyph.sprite = sprite; + + spriteGlyphTable.Add(spriteGlyph); + + TMP_SpriteCharacter spriteCharacter = new TMP_SpriteCharacter(0xFFFE, spriteGlyph); + spriteCharacter.name = sprite.name; + spriteCharacter.scale = 1.0f; + + spriteCharacterTable.Add(spriteCharacter); + } + } + + + /// + /// Create and add new default material to sprite asset. + /// + /// + static void AddDefaultMaterial(TMP_SpriteAsset spriteAsset) + { + Shader shader = Shader.Find("TextMeshPro/Sprite"); + Material material = new Material(shader); + material.SetTexture(ShaderUtilities.ID_MainTex, spriteAsset.spriteSheet); + + spriteAsset.material = material; + material.name = spriteAsset.name + " Material"; + AssetDatabase.AddObjectToAsset(material, spriteAsset); + } + + + // Update existing SpriteInfo + static List UpdateSpriteInfo(TMP_SpriteAsset spriteAsset) + { + //Debug.Log("Updating Sprite Asset."); + + string filePath = AssetDatabase.GetAssetPath(spriteAsset.spriteSheet); + + // Get all the Sprites sorted Left to Right / Top to Bottom + Sprite[] sprites = AssetDatabase.LoadAllAssetsAtPath(filePath).Select(x => x as Sprite).Where(x => x != null).OrderByDescending(x => x.rect.y).ThenBy(x => x.rect.x).ToArray(); + + for (int i = 0; i < sprites.Length; i++) + { + Sprite sprite = sprites[i]; + + // Check if the sprite is already contained in the SpriteInfoList + int index = -1; + if (spriteAsset.spriteInfoList.Count > i && spriteAsset.spriteInfoList[i].sprite != null) + index = spriteAsset.spriteInfoList.FindIndex(item => item.sprite.GetInstanceID() == sprite.GetInstanceID()); + + // Use existing SpriteInfo if it already exists + TMP_Sprite spriteInfo = index == -1 ? new TMP_Sprite() : spriteAsset.spriteInfoList[index]; + + Rect spriteRect = sprite.rect; + spriteInfo.x = spriteRect.x; + spriteInfo.y = spriteRect.y; + spriteInfo.width = spriteRect.width; + spriteInfo.height = spriteRect.height; + + // Get Sprite Pivot + Vector2 pivot = new Vector2(0 - (sprite.bounds.min.x) / (sprite.bounds.extents.x * 2), 0 - (sprite.bounds.min.y) / (sprite.bounds.extents.y * 2)); + + // The position of the pivot influences the Offset position. + spriteInfo.pivot = new Vector2(0 - pivot.x * spriteRect.width, spriteRect.height - pivot.y * spriteRect.height); + + if (index == -1) + { + // Find the next available index for this Sprite + int[] ids = spriteAsset.spriteInfoList.Select(item => item.id).ToArray(); + + int id = 0; + for (int j = 0; j < ids.Length; j++ ) + { + if (ids[0] != 0) break; + + if (j > 0 && (ids[j] - ids[j - 1]) > 1) + { + id = ids[j - 1] + 1; + break; + } + + id = j + 1; + } + + spriteInfo.sprite = sprite; + spriteInfo.name = sprite.name; + spriteInfo.hashCode = TMP_TextUtilities.GetSimpleHashCode(spriteInfo.name); + spriteInfo.id = id; + spriteInfo.xAdvance = spriteRect.width; + spriteInfo.scale = 1.0f; + + spriteInfo.xOffset = spriteInfo.pivot.x; + spriteInfo.yOffset = spriteInfo.pivot.y; + + spriteAsset.spriteInfoList.Add(spriteInfo); + + // Sort the Sprites by ID + spriteAsset.spriteInfoList = spriteAsset.spriteInfoList.OrderBy(s => s.id).ToList(); + } + else + { + spriteAsset.spriteInfoList[index] = spriteInfo; + } + } + + return spriteAsset.spriteInfoList; + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_SpriteAssetMenu.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_SpriteAssetMenu.cs.meta new file mode 100644 index 00000000..850ab1f2 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_SpriteAssetMenu.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 1048a87135154606808bf2030da32d18 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_StyleAssetMenu.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_StyleAssetMenu.cs new file mode 100644 index 00000000..4c487a6a --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_StyleAssetMenu.cs @@ -0,0 +1,47 @@ +using UnityEngine; +using UnityEditor; +using System.IO; + + +namespace TMPro.EditorUtilities +{ + public static class TMP_StyleAssetMenu + { + [MenuItem("Assets/Create/TextMeshPro/Style Sheet", false, 210)] + internal static void CreateTextMeshProObjectPerform() + { + string filePath; + if (Selection.assetGUIDs.Length == 0) + { + // No asset selected. + filePath = "Assets"; + } + else + { + // Get the path of the selected folder or asset. + filePath = AssetDatabase.GUIDToAssetPath(Selection.assetGUIDs[0]); + + // Get the file extension of the selected asset as it might need to be removed. + string fileExtension = Path.GetExtension(filePath); + if (fileExtension != "") + { + filePath = Path.GetDirectoryName(filePath); + } + } + + string filePathWithName = AssetDatabase.GenerateUniqueAssetPath(filePath + "/Text StyleSheet.asset"); + + // Create new Style Sheet Asset. + TMP_StyleSheet styleSheet = ScriptableObject.CreateInstance(); + + AssetDatabase.CreateAsset(styleSheet, filePathWithName); + + EditorUtility.SetDirty(styleSheet); + + AssetDatabase.SaveAssets(); + + EditorUtility.FocusProjectWindow(); + EditorGUIUtility.PingObject(styleSheet); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_StyleAssetMenu.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_StyleAssetMenu.cs.meta new file mode 100644 index 00000000..cb44dc27 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_StyleAssetMenu.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 23a562f2cac6401f9f91251c68a1a794 +timeCreated: 1432690168 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_StyleSheetEditor.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_StyleSheetEditor.cs new file mode 100644 index 00000000..959ca7b5 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_StyleSheetEditor.cs @@ -0,0 +1,321 @@ +using System; +using UnityEngine; +using UnityEditor; + + +namespace TMPro.EditorUtilities +{ + + [CustomPropertyDrawer(typeof(TMP_Style))] + public class StyleDrawer : PropertyDrawer + { + public static readonly float height = 95f; + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return height; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + SerializedProperty nameProperty = property.FindPropertyRelative("m_Name"); + SerializedProperty hashCodeProperty = property.FindPropertyRelative("m_HashCode"); + SerializedProperty openingDefinitionProperty = property.FindPropertyRelative("m_OpeningDefinition"); + SerializedProperty closingDefinitionProperty = property.FindPropertyRelative("m_ClosingDefinition"); + SerializedProperty openingDefinitionArray = property.FindPropertyRelative("m_OpeningTagArray"); + SerializedProperty closingDefinitionArray = property.FindPropertyRelative("m_ClosingTagArray"); + + + EditorGUIUtility.labelWidth = 86; + position.height = EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + float labelHeight = position.height + 2f; + + EditorGUI.BeginChangeCheck(); + Rect rect0 = new Rect(position.x, position.y, (position.width) / 2 + 5, position.height); + EditorGUI.PropertyField(rect0, nameProperty); + if (EditorGUI.EndChangeCheck()) + { + // Recompute HashCode if name has changed. + hashCodeProperty.intValue = TMP_TextUtilities.GetSimpleHashCode(nameProperty.stringValue); + + property.serializedObject.ApplyModifiedProperties(); + + // Dictionary needs to be updated since HashCode has changed. + TMP_StyleSheet styleSheet = property.serializedObject.targetObject as TMP_StyleSheet; + styleSheet.RefreshStyles(); + } + + // HashCode + Rect rect1 = new Rect(rect0.x + rect0.width + 5, position.y, 65, position.height); + GUI.Label(rect1, "HashCode"); + GUI.enabled = false; + rect1.x += 65; + rect1.width = position.width / 2 - 75; + EditorGUI.PropertyField(rect1, hashCodeProperty, GUIContent.none); + + GUI.enabled = true; + + // Text Tags + EditorGUI.BeginChangeCheck(); + + // Opening Tags + position.y += labelHeight; + GUI.Label(position, "Opening Tags"); + Rect textRect1 = new Rect(110, position.y, position.width - 86, 35); + openingDefinitionProperty.stringValue = EditorGUI.TextArea(textRect1, openingDefinitionProperty.stringValue); + if (EditorGUI.EndChangeCheck()) + { + // If any properties have changed, we need to update the Opening and Closing Arrays. + int size = openingDefinitionProperty.stringValue.Length; + + // Adjust array size to match new string length. + if (openingDefinitionArray.arraySize != size) openingDefinitionArray.arraySize = size; + + for (int i = 0; i < size; i++) + { + SerializedProperty element = openingDefinitionArray.GetArrayElementAtIndex(i); + element.intValue = openingDefinitionProperty.stringValue[i]; + } + } + + EditorGUI.BeginChangeCheck(); + + // Closing Tags + position.y += 38; + GUI.Label(position, "Closing Tags"); + Rect textRect2 = new Rect(110, position.y, position.width - 86, 35); + closingDefinitionProperty.stringValue = EditorGUI.TextArea(textRect2, closingDefinitionProperty.stringValue); + + if (EditorGUI.EndChangeCheck()) + { + // If any properties have changed, we need to update the Opening and Closing Arrays. + int size = closingDefinitionProperty.stringValue.Length; + + // Adjust array size to match new string length. + if (closingDefinitionArray.arraySize != size) closingDefinitionArray.arraySize = size; + + for (int i = 0; i < size; i++) + { + SerializedProperty element = closingDefinitionArray.GetArrayElementAtIndex(i); + element.intValue = closingDefinitionProperty.stringValue[i]; + } + } + + } + } + + + + [CustomEditor(typeof(TMP_StyleSheet)), CanEditMultipleObjects] + public class TMP_StyleEditor : Editor + { + + TMP_StyleSheet m_StyleSheet; + SerializedProperty m_StyleListProp; + + int m_SelectedElement = -1; + int m_Page; + + bool m_IsStyleSheetDirty; + + + void OnEnable() + { + m_StyleSheet = target as TMP_StyleSheet; + m_StyleListProp = serializedObject.FindProperty("m_StyleList"); + } + + + public override void OnInspectorGUI() + { + Event currentEvent = Event.current; + + serializedObject.Update(); + + m_IsStyleSheetDirty = false; + int elementCount = m_StyleListProp.arraySize; + int itemsPerPage = (Screen.height - 100) / 110; + + if (elementCount > 0) + { + // Display each Style entry using the StyleDrawer PropertyDrawer. + for (int i = itemsPerPage * m_Page; i < elementCount && i < itemsPerPage * (m_Page + 1); i++) + { + // Define the start of the selection region of the element. + Rect elementStartRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + + SerializedProperty styleProperty = m_StyleListProp.GetArrayElementAtIndex(i); + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(styleProperty); + EditorGUILayout.EndVertical(); + if (EditorGUI.EndChangeCheck()) + { + // + } + + // Define the end of the selection region of the element. + Rect elementEndRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); + + // Check for Item selection + Rect selectionArea = new Rect(elementStartRegion.x, elementStartRegion.y, elementEndRegion.width, elementEndRegion.y - elementStartRegion.y); + if (DoSelectionCheck(selectionArea)) + { + if (m_SelectedElement == i) + { + m_SelectedElement = -1; + } + else + { + m_SelectedElement = i; + GUIUtility.keyboardControl = 0; + } + } + + // Handle Selection Highlighting + if (m_SelectedElement == i) + TMP_EditorUtility.DrawBox(selectionArea, 2f, new Color32(40, 192, 255, 255)); + } + } + + // STYLE LIST MANAGEMENT + Rect rect = EditorGUILayout.GetControlRect(false, 20); + float totalWidth = rect.width; + rect.width = totalWidth * 0.175f; + + // Move Style up. + bool guiEnabled = GUI.enabled; + if (m_SelectedElement == -1 || m_SelectedElement == 0) { GUI.enabled = false; } + if (GUI.Button(rect, "Up")) + { + SwapStyleElements(m_SelectedElement, m_SelectedElement - 1); + } + GUI.enabled = guiEnabled; + + // Move Style down. + rect.x += rect.width; + if (m_SelectedElement == elementCount - 1) { GUI.enabled = false; } + if (GUI.Button(rect, "Down")) + { + SwapStyleElements(m_SelectedElement, m_SelectedElement + 1); + } + GUI.enabled = guiEnabled; + + // Add Style + rect.x += rect.width + totalWidth * 0.3f; + if (GUI.Button(rect, "+")) + { + int index = m_SelectedElement == -1 ? elementCount : m_SelectedElement; + + if (index > elementCount) + index = elementCount; + + // Copy selected element + m_StyleListProp.InsertArrayElementAtIndex(index); + + // Select newly inserted element + m_SelectedElement = index + 1; + + serializedObject.ApplyModifiedProperties(); + m_StyleSheet.RefreshStyles(); + } + + // Delete style + rect.x += rect.width; + if (m_SelectedElement == -1 || m_SelectedElement >= elementCount) GUI.enabled = false; + if (GUI.Button(rect, "-")) + { + int index = m_SelectedElement == -1 ? 0 : m_SelectedElement; + + m_StyleListProp.DeleteArrayElementAtIndex(index); + + m_SelectedElement = -1; + serializedObject.ApplyModifiedProperties(); + m_StyleSheet.RefreshStyles(); + return; + } + + // Return if we can't display any items. + if (itemsPerPage == 0) return; + + // DISPLAY PAGE CONTROLS + int shiftMultiplier = currentEvent.shift ? 10 : 1; // Page + Shift goes 10 page forward + + Rect pagePos = EditorGUILayout.GetControlRect(false, 20); + pagePos.width = totalWidth * 0.35f; + + // Previous Page + if (m_Page > 0) GUI.enabled = true; + else GUI.enabled = false; + + if (GUI.Button(pagePos, "Previous")) + m_Page -= 1 * shiftMultiplier; + + // PAGE COUNTER + GUI.enabled = true; + pagePos.x += pagePos.width; + pagePos.width = totalWidth * 0.30f; + int totalPages = (int)(elementCount / (float)itemsPerPage + 0.999f); + GUI.Label(pagePos, "Page " + (m_Page + 1) + " / " + totalPages, TMP_UIStyleManager.centeredLabel); + + // Next Page + pagePos.x += pagePos.width; + pagePos.width = totalWidth * 0.35f; + if (itemsPerPage * (m_Page + 1) < elementCount) GUI.enabled = true; + else GUI.enabled = false; + + if (GUI.Button(pagePos, "Next")) + m_Page += 1 * shiftMultiplier; + + // Clamp page range + m_Page = Mathf.Clamp(m_Page, 0, elementCount / itemsPerPage); + + + if (serializedObject.ApplyModifiedProperties()) + { + TMPro_EventManager.ON_TEXT_STYLE_PROPERTY_CHANGED(true); + + if (m_IsStyleSheetDirty) + { + m_IsStyleSheetDirty = false; + m_StyleSheet.RefreshStyles(); + } + } + + // Clear selection if mouse event was not consumed. + GUI.enabled = true; + if (currentEvent.type == EventType.MouseDown && currentEvent.button == 0) + m_SelectedElement = -1; + + } + + + // Check if any of the Style elements were clicked on. + static bool DoSelectionCheck(Rect selectionArea) + { + Event currentEvent = Event.current; + + switch (currentEvent.type) + { + case EventType.MouseDown: + if (selectionArea.Contains(currentEvent.mousePosition) && currentEvent.button == 0) + { + currentEvent.Use(); + return true; + } + break; + } + + return false; + } + + void SwapStyleElements(int selectedIndex, int newIndex) + { + m_StyleListProp.MoveArrayElement(selectedIndex, newIndex); + m_SelectedElement = newIndex; + m_IsStyleSheetDirty = true; + } + + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_StyleSheetEditor.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_StyleSheetEditor.cs.meta new file mode 100644 index 00000000..a3bff26f --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_StyleSheetEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 34e2c9b9d9e44953933afe37461f44e6 +timeCreated: 1432683777 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_SubMeshUI_Editor.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_SubMeshUI_Editor.cs new file mode 100644 index 00000000..0681d0fd --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_SubMeshUI_Editor.cs @@ -0,0 +1,103 @@ +using UnityEngine; +using UnityEditor; +using System.Collections; + +namespace TMPro.EditorUtilities +{ + [CustomEditor(typeof(TMP_SubMeshUI)), CanEditMultipleObjects] + public class TMP_SubMeshUI_Editor : Editor + { + private struct m_foldout + { // Track Inspector foldout panel states, globally. + //public static bool textInput = true; + public static bool fontSettings = true; + //public static bool extraSettings = false; + //public static bool shadowSetting = false; + //public static bool materialEditor = true; + } + + private SerializedProperty fontAsset_prop; + private SerializedProperty spriteAsset_prop; + + //private TMP_SubMeshUI m_SubMeshComponent; + + //private CanvasRenderer m_canvasRenderer; + private Material m_targetMaterial; + + + public void OnEnable() + { + fontAsset_prop = serializedObject.FindProperty("m_fontAsset"); + spriteAsset_prop = serializedObject.FindProperty("m_spriteAsset"); + + //m_SubMeshComponent = target as TMP_SubMeshUI; + //m_rectTransform = m_SubMeshComponent.rectTransform; + //m_canvasRenderer = m_SubMeshComponent.canvasRenderer; + + + // Create new Material Editor if one does not exists + /* + if (m_canvasRenderer != null && m_canvasRenderer.GetMaterial() != null) + { + m_materialEditor = Editor.CreateEditor(m_canvasRenderer.GetMaterial()); + m_targetMaterial = m_canvasRenderer.GetMaterial(); + } + */ + } + + + public void OnDisable() + { + // Destroy material editor if one exists + /* + if (m_materialEditor != null) + { + //Debug.Log("Destroying Inline Material Editor."); + DestroyImmediate(m_materialEditor); + } + */ + } + + + + public override void OnInspectorGUI() + { + GUI.enabled = false; + EditorGUILayout.PropertyField(fontAsset_prop); + EditorGUILayout.PropertyField(spriteAsset_prop); + GUI.enabled = true; + + EditorGUILayout.Space(); + + // If a Custom Material Editor exists, we use it. + /* + if (m_canvasRenderer != null && m_canvasRenderer.GetMaterial() != null) + { + Material mat = m_canvasRenderer.GetMaterial(); + + //Debug.Log(mat + " " + m_targetMaterial); + + if (mat != m_targetMaterial) + { + // Destroy previous Material Instance + //Debug.Log("New Material has been assigned."); + m_targetMaterial = mat; + DestroyImmediate(m_materialEditor); + } + + + if (m_materialEditor == null) + { + m_materialEditor = Editor.CreateEditor(mat); + } + + m_materialEditor.DrawHeader(); + + + m_materialEditor.OnInspectorGUI(); + } + */ + } + + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_SubMeshUI_Editor.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_SubMeshUI_Editor.cs.meta new file mode 100644 index 00000000..b82410e5 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_SubMeshUI_Editor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6b01141ed8f74d198965c86f25eb7040 +timeCreated: 1452757501 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_SubMesh_Editor.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_SubMesh_Editor.cs new file mode 100644 index 00000000..f668af96 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_SubMesh_Editor.cs @@ -0,0 +1,71 @@ +using UnityEngine; +using UnityEditor; +using System.Collections; + +namespace TMPro.EditorUtilities +{ + [CustomEditor(typeof(TMP_SubMesh)), CanEditMultipleObjects] + public class TMP_SubMesh_Editor : Editor + { + private struct m_foldout + { // Track Inspector foldout panel states, globally. + //public static bool textInput = true; + public static bool fontSettings = true; + //public static bool extraSettings = false; + //public static bool shadowSetting = false; + //public static bool materialEditor = true; + } + + private SerializedProperty fontAsset_prop; + private SerializedProperty spriteAsset_prop; + + private TMP_SubMesh m_SubMeshComponent; + private Renderer m_Renderer; + + private string[] m_SortingLayerNames; + + public void OnEnable() + { + fontAsset_prop = serializedObject.FindProperty("m_fontAsset"); + spriteAsset_prop = serializedObject.FindProperty("m_spriteAsset"); + + m_SubMeshComponent = target as TMP_SubMesh; + + m_Renderer = m_SubMeshComponent.renderer; + + m_SortingLayerNames = SortingLayerHelper.sortingLayerNames; + } + + + public override void OnInspectorGUI() + { + EditorGUI.indentLevel = 0; + + GUI.enabled = false; + EditorGUILayout.PropertyField(fontAsset_prop); + EditorGUILayout.PropertyField(spriteAsset_prop); + GUI.enabled = true; + + EditorGUI.BeginChangeCheck(); + + // Look up the layer name using the current layer ID + string oldName = SortingLayer.IDToName(m_Renderer.sortingLayerID); + + // Use the name to look up our array index into the names list + int oldLayerIndex = System.Array.IndexOf(m_SortingLayerNames, oldName); + + // Show the pop-up for the names + int newLayerIndex = EditorGUILayout.Popup("Sorting Layer", oldLayerIndex, m_SortingLayerNames); + + // If the index changes, look up the ID for the new index to store as the new ID + if (newLayerIndex != oldLayerIndex) + m_Renderer.sortingLayerID = SortingLayer.NameToID(m_SortingLayerNames[newLayerIndex]); + + // Expose the manual sorting order + int newSortingLayerOrder = EditorGUILayout.IntField("Order in Layer", m_Renderer.sortingOrder); + if (newSortingLayerOrder != m_Renderer.sortingOrder) + m_Renderer.sortingOrder = newSortingLayerOrder; + + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_SubMesh_Editor.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_SubMesh_Editor.cs.meta new file mode 100644 index 00000000..fd4713b3 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_SubMesh_Editor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: dd2fe74169b54bf58fca17288513ef38 +timeCreated: 1456189048 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_UIStyleManager.cs b/Packages/com.unity.ugui/Editor/TMP/TMP_UIStyleManager.cs new file mode 100644 index 00000000..0a94a997 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_UIStyleManager.cs @@ -0,0 +1,134 @@ +using UnityEngine; +using UnityEditor; +using System.Collections; + + +namespace TMPro.EditorUtilities +{ + + public static class TMP_UIStyleManager + { + public static GUIStyle label; + public static GUIStyle textAreaBoxWindow; + public static GUIStyle boldFoldout; + public static GUIStyle panelTitle; + public static GUIStyle sectionHeader; + public static GUIStyle centeredLabel; + public static GUIStyle rightLabel; + public static GUIStyle wrappingTextArea; + + public static GUIStyle alignmentButtonLeft; + public static GUIStyle alignmentButtonMid; + public static GUIStyle alignmentButtonRight; + + // Alignment Button Textures + public static Texture2D alignLeft; + public static Texture2D alignCenter; + public static Texture2D alignRight; + public static Texture2D alignJustified; + public static Texture2D alignFlush; + public static Texture2D alignGeoCenter; + public static Texture2D alignTop; + public static Texture2D alignMiddle; + public static Texture2D alignBottom; + public static Texture2D alignBaseline; + public static Texture2D alignMidline; + public static Texture2D alignCapline; + public static Texture2D sectionHeaderTexture; + + public static GUIContent[] alignContentA; + public static GUIContent[] alignContentB; + + static TMP_UIStyleManager() + { + // Find to location of the TextMesh Pro Asset Folder (as users may have moved it) + var tmproAssetFolderPath = TMP_EditorUtility.packageRelativePath; + + if (EditorGUIUtility.isProSkin) + { + alignLeft = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignLeft.psd", typeof(Texture2D)) as Texture2D; + alignCenter = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignCenter.psd", typeof(Texture2D)) as Texture2D; + alignRight = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignRight.psd", typeof(Texture2D)) as Texture2D; + alignJustified = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignJustified.psd", typeof(Texture2D)) as Texture2D; + alignFlush = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignFlush.psd", typeof(Texture2D)) as Texture2D; + alignGeoCenter = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignCenterGeo.psd", typeof(Texture2D)) as Texture2D; + alignTop = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignTop.psd", typeof(Texture2D)) as Texture2D; + alignMiddle = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignMiddle.psd", typeof(Texture2D)) as Texture2D; + alignBottom = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignBottom.psd", typeof(Texture2D)) as Texture2D; + alignBaseline = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignBaseLine.psd", typeof(Texture2D)) as Texture2D; + alignMidline = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignMidLine.psd", typeof(Texture2D)) as Texture2D; + alignCapline = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignCapLine.psd", typeof(Texture2D)) as Texture2D; + sectionHeaderTexture = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/SectionHeader_Dark.psd", typeof(Texture2D)) as Texture2D; + } + else + { + alignLeft = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignLeft_Light.psd", typeof(Texture2D)) as Texture2D; + alignCenter = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignCenter_Light.psd", typeof(Texture2D)) as Texture2D; + alignRight = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignRight_Light.psd", typeof(Texture2D)) as Texture2D; + alignJustified = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignJustified_Light.psd", typeof(Texture2D)) as Texture2D; + alignFlush = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignFlush_Light.psd", typeof(Texture2D)) as Texture2D; + alignGeoCenter = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignCenterGeo_Light.psd", typeof(Texture2D)) as Texture2D; + alignTop = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignTop_Light.psd", typeof(Texture2D)) as Texture2D; + alignMiddle = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignMiddle_Light.psd", typeof(Texture2D)) as Texture2D; + alignBottom = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignBottom_Light.psd", typeof(Texture2D)) as Texture2D; + alignBaseline = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignBaseLine_Light.psd", typeof(Texture2D)) as Texture2D; + alignMidline = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignMidLine_Light.psd", typeof(Texture2D)) as Texture2D; + alignCapline = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/btn_AlignCapLine_Light.psd", typeof(Texture2D)) as Texture2D; + sectionHeaderTexture = AssetDatabase.LoadAssetAtPath(tmproAssetFolderPath + "/Editor Resources/Textures/SectionHeader_Light.psd", typeof(Texture2D)) as Texture2D; + } + + label = new GUIStyle(EditorStyles.label) { richText = true, wordWrap = true, stretchWidth = true }; + textAreaBoxWindow = new GUIStyle(EditorStyles.textArea) { richText = true }; + boldFoldout = new GUIStyle(EditorStyles.foldout) { fontStyle = FontStyle.Bold }; + panelTitle = new GUIStyle(EditorStyles.label) { fontStyle = FontStyle.Bold }; + + sectionHeader = new GUIStyle(EditorStyles.label) { fixedHeight = 22, richText = true, border = new RectOffset(9, 9, 0, 0), overflow = new RectOffset(9, 0, 0, 0), padding = new RectOffset(0, 0, 4, 0) }; + sectionHeader.normal.background = sectionHeaderTexture; + + centeredLabel = new GUIStyle(EditorStyles.label) { alignment = TextAnchor.MiddleCenter}; + rightLabel = new GUIStyle(EditorStyles.label) { alignment = TextAnchor.MiddleRight, richText = true }; + + + alignmentButtonLeft = new GUIStyle(EditorStyles.miniButtonLeft); + alignmentButtonLeft.padding.left = 4; + alignmentButtonLeft.padding.right = 4; + alignmentButtonLeft.padding.top = 2; + alignmentButtonLeft.padding.bottom = 2; + + alignmentButtonMid = new GUIStyle(EditorStyles.miniButtonMid); + alignmentButtonMid.padding.left = 4; + alignmentButtonMid.padding.right = 4; + alignmentButtonLeft.padding.top = 2; + alignmentButtonLeft.padding.bottom = 2; + + alignmentButtonRight = new GUIStyle(EditorStyles.miniButtonRight); + alignmentButtonRight.padding.left = 4; + alignmentButtonRight.padding.right = 4; + alignmentButtonLeft.padding.top = 2; + alignmentButtonLeft.padding.bottom = 2; + + wrappingTextArea = new GUIStyle(EditorStyles.textArea); + wrappingTextArea.wordWrap = true; + + alignContentA = new [] + { + new GUIContent(alignLeft, "Left"), + new GUIContent(alignCenter, "Center"), + new GUIContent(alignRight, "Right"), + new GUIContent(alignJustified, "Justified"), + new GUIContent(alignFlush, "Flush"), + new GUIContent(alignGeoCenter, "Geometry Center") + }; + + alignContentB = new [] + { + new GUIContent(alignTop, "Top"), + new GUIContent(alignMiddle, "Middle"), + new GUIContent(alignBottom, "Bottom"), + new GUIContent(alignBaseline, "Baseline"), + new GUIContent(alignMidline, "Midline"), + new GUIContent(alignCapline, "Capline") + }; + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMP_UIStyleManager.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMP_UIStyleManager.cs.meta new file mode 100644 index 00000000..9c09bfa3 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMP_UIStyleManager.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 30a939dce2fd4073955f2f20e659d506 +timeCreated: 1426454127 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMPro_ContextMenus.cs b/Packages/com.unity.ugui/Editor/TMP/TMPro_ContextMenus.cs new file mode 100644 index 00000000..0cee3dfc --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMPro_ContextMenus.cs @@ -0,0 +1,469 @@ +using UnityEngine; +using UnityEditor; +using System.IO; +using System.Collections; + + +namespace TMPro.EditorUtilities +{ + + public class TMP_ContextMenus : Editor + { + + private static Texture m_copiedTexture; + + private static Material m_copiedProperties; + private static Material m_copiedAtlasProperties; + + + // Add a Context Menu to the Texture Editor Panel to allow Copy / Paste of Texture. + #if !TEXTCORE_1_0_OR_NEWER + [MenuItem("CONTEXT/Texture/Copy", false, 2000)] + static void CopyTexture(MenuCommand command) + { + m_copiedTexture = command.context as Texture; + } + + + // Select the currently assigned material or material preset. + [MenuItem("CONTEXT/Material/Select Material", false, 500)] + static void SelectMaterial(MenuCommand command) + { + Material mat = command.context as Material; + + // Select current material + EditorUtility.FocusProjectWindow(); + EditorGUIUtility.PingObject(mat); + } + #endif + + + // Add a Context Menu to allow easy duplication of the Material. + [MenuItem("CONTEXT/Material/Create Material Preset", false)] + static void DuplicateMaterial(MenuCommand command) + { + // Get the type of text object + // If material is not a base material, we get material leaks... + + Material source_Mat = (Material)command.context; + if (!EditorUtility.IsPersistent(source_Mat)) + { + Debug.LogWarning("Material is an instance and cannot be converted into a persistent asset."); + return; + } + + string assetPath = AssetDatabase.GetAssetPath(source_Mat).Split('.')[0]; + + if (assetPath.IndexOf("Assets/", System.StringComparison.InvariantCultureIgnoreCase) == -1) + { + Debug.LogWarning("Material Preset cannot be created from a material that is located outside the project."); + return; + } + + Material duplicate = new Material(source_Mat); + + // Need to manually copy the shader keywords + duplicate.shaderKeywords = source_Mat.shaderKeywords; + + AssetDatabase.CreateAsset(duplicate, AssetDatabase.GenerateUniqueAssetPath(assetPath + ".mat")); + + GameObject[] selectedObjects = Selection.gameObjects; + + // Assign new Material Preset to selected text objects. + for (int i = 0; i < selectedObjects.Length; i++) + { + TMP_Text textObject = selectedObjects[i].GetComponent(); + + if (textObject != null) + { + textObject.fontSharedMaterial = duplicate; + } + else + { + TMP_SubMesh subMeshObject = selectedObjects[i].GetComponent(); + + if (subMeshObject != null) + subMeshObject.sharedMaterial = duplicate; + else + { + TMP_SubMeshUI subMeshUIObject = selectedObjects[i].GetComponent(); + + if (subMeshUIObject != null) + subMeshUIObject.sharedMaterial = duplicate; + } + } + } + + // Ping newly created Material Preset. + EditorUtility.FocusProjectWindow(); + EditorGUIUtility.PingObject(duplicate); + } + + + // COPY MATERIAL PROPERTIES + #if !TEXTCORE_1_0_OR_NEWER + [MenuItem("CONTEXT/Material/Copy Material Properties", false)] + static void CopyMaterialProperties(MenuCommand command) + { + Material mat = null; + if (command.context.GetType() == typeof(Material)) + mat = (Material)command.context; + else + { + mat = Selection.activeGameObject.GetComponent().GetMaterial(); + } + + m_copiedProperties = new Material(mat); + + m_copiedProperties.shaderKeywords = mat.shaderKeywords; + + m_copiedProperties.hideFlags = HideFlags.DontSave; + } + + + // PASTE MATERIAL PROPERTIES + [MenuItem("CONTEXT/Material/Paste Material Properties", true)] + static bool PasteMaterialPropertiesValidate(MenuCommand command) + { + if (m_copiedProperties == null) + return false; + + return AssetDatabase.IsOpenForEdit(command.context); + } + + [MenuItem("CONTEXT/Material/Paste Material Properties", false)] + static void PasteMaterialProperties(MenuCommand command) + { + if (m_copiedProperties == null) + { + Debug.LogWarning("No Material Properties to Paste. Use Copy Material Properties first."); + return; + } + + Material mat = null; + if (command.context.GetType() == typeof(Material)) + mat = (Material)command.context; + else + { + mat = Selection.activeGameObject.GetComponent().GetMaterial(); + } + + Undo.RecordObject(mat, "Paste Material"); + + ShaderUtilities.GetShaderPropertyIDs(); // Make sure we have valid Property IDs + if (mat.HasProperty(ShaderUtilities.ID_GradientScale)) + { + // Preserve unique SDF properties from destination material. + m_copiedProperties.SetTexture(ShaderUtilities.ID_MainTex, mat.GetTexture(ShaderUtilities.ID_MainTex)); + m_copiedProperties.SetFloat(ShaderUtilities.ID_GradientScale, mat.GetFloat(ShaderUtilities.ID_GradientScale)); + m_copiedProperties.SetFloat(ShaderUtilities.ID_TextureWidth, mat.GetFloat(ShaderUtilities.ID_TextureWidth)); + m_copiedProperties.SetFloat(ShaderUtilities.ID_TextureHeight, mat.GetFloat(ShaderUtilities.ID_TextureHeight)); + } + + EditorShaderUtilities.CopyMaterialProperties(m_copiedProperties, mat); + + // Copy ShaderKeywords from one material to the other. + mat.shaderKeywords = m_copiedProperties.shaderKeywords; + + // Let TextMeshPro Objects that this mat has changed. + TMPro_EventManager.ON_MATERIAL_PROPERTY_CHANGED(true, mat); + } + + + // Enable Resetting of Material properties without losing unique properties of the font atlas. + [MenuItem("CONTEXT/Material/Reset", true, 2100)] + static bool ResetSettingsValidate(MenuCommand command) + { + return AssetDatabase.IsOpenForEdit(command.context); + } + + [MenuItem("CONTEXT/Material/Reset", false, 2100)] + static void ResetSettings(MenuCommand command) + { + Material mat = null; + if (command.context.GetType() == typeof(Material)) + mat = (Material)command.context; + else + { + mat = Selection.activeGameObject.GetComponent().GetMaterial(); + } + + Undo.RecordObject(mat, "Reset Material"); + + ShaderUtilities.GetShaderPropertyIDs(); // Make sure we have valid Property IDs + if (mat.HasProperty(ShaderUtilities.ID_GradientScale)) + { + bool isSRPShader = mat.HasProperty(ShaderUtilities.ID_IsoPerimeter); + + // Copy unique properties of the SDF Material + var texture = mat.GetTexture(ShaderUtilities.ID_MainTex); + var gradientScale = mat.GetFloat(ShaderUtilities.ID_GradientScale); + + float texWidth = 0, texHeight = 0; + float normalWeight = 0, boldWeight = 0; + + if (!isSRPShader) + { + texWidth = mat.GetFloat(ShaderUtilities.ID_TextureWidth); + texHeight = mat.GetFloat(ShaderUtilities.ID_TextureHeight); + normalWeight = mat.GetFloat(ShaderUtilities.ID_WeightNormal); + boldWeight = mat.GetFloat(ShaderUtilities.ID_WeightBold); + } + + var stencilId = 0.0f; + var stencilComp = 0.0f; + + if (mat.HasProperty(ShaderUtilities.ID_StencilID)) + { + stencilId = mat.GetFloat(ShaderUtilities.ID_StencilID); + stencilComp = mat.GetFloat(ShaderUtilities.ID_StencilComp); + } + + // Reset the material + Unsupported.SmartReset(mat); + + // Reset ShaderKeywords + mat.shaderKeywords = new string[0]; // { "BEVEL_OFF", "GLOW_OFF", "UNDERLAY_OFF" }; + + // Copy unique material properties back to the material. + mat.SetTexture(ShaderUtilities.ID_MainTex, texture); + mat.SetFloat(ShaderUtilities.ID_GradientScale, gradientScale); + + if (!isSRPShader) + { + mat.SetFloat(ShaderUtilities.ID_TextureWidth, texWidth); + mat.SetFloat(ShaderUtilities.ID_TextureHeight, texHeight); + mat.SetFloat(ShaderUtilities.ID_WeightNormal, normalWeight); + mat.SetFloat(ShaderUtilities.ID_WeightBold, boldWeight); + } + + if (mat.HasProperty(ShaderUtilities.ID_StencilID)) + { + mat.SetFloat(ShaderUtilities.ID_StencilID, stencilId); + mat.SetFloat(ShaderUtilities.ID_StencilComp, stencilComp); + } + } + else + { + Unsupported.SmartReset(mat); + } + + TMPro_EventManager.ON_MATERIAL_PROPERTY_CHANGED(true, mat); + } + + + //This function is used for debugging and fixing potentially broken font atlas links. + [MenuItem("CONTEXT/Material/Copy Atlas", false, 2000)] + static void CopyAtlas(MenuCommand command) + { + Material mat = command.context as Material; + + m_copiedAtlasProperties = new Material(mat); + m_copiedAtlasProperties.hideFlags = HideFlags.DontSave; + } + + + // This function is used for debugging and fixing potentially broken font atlas links + [MenuItem("CONTEXT/Material/Paste Atlas", true, 2001)] + static bool PasteAtlasValidate(MenuCommand command) + { + if (m_copiedAtlasProperties == null && m_copiedTexture == null) + return false; + + return AssetDatabase.IsOpenForEdit(command.context); + } + + [MenuItem("CONTEXT/Material/Paste Atlas", false, 2001)] + static void PasteAtlas(MenuCommand command) + { + Material mat = command.context as Material; + + if (mat == null) + return; + + if (m_copiedAtlasProperties != null) + { + Undo.RecordObject(mat, "Paste Texture"); + + ShaderUtilities.GetShaderPropertyIDs(); // Make sure we have valid Property IDs + + if (m_copiedAtlasProperties.HasProperty(ShaderUtilities.ID_MainTex)) + mat.SetTexture(ShaderUtilities.ID_MainTex, m_copiedAtlasProperties.GetTexture(ShaderUtilities.ID_MainTex)); + + if (m_copiedAtlasProperties.HasProperty(ShaderUtilities.ID_GradientScale)) + { + mat.SetFloat(ShaderUtilities.ID_GradientScale, m_copiedAtlasProperties.GetFloat(ShaderUtilities.ID_GradientScale)); + mat.SetFloat(ShaderUtilities.ID_TextureWidth, m_copiedAtlasProperties.GetFloat(ShaderUtilities.ID_TextureWidth)); + mat.SetFloat(ShaderUtilities.ID_TextureHeight, m_copiedAtlasProperties.GetFloat(ShaderUtilities.ID_TextureHeight)); + } + } + else if (m_copiedTexture != null) + { + Undo.RecordObject(mat, "Paste Texture"); + + mat.SetTexture(ShaderUtilities.ID_MainTex, m_copiedTexture); + } + } + #endif + + + // Context Menus for TMPro Font Assets + //This function is used for debugging and fixing potentially broken font atlas links. + [MenuItem("CONTEXT/TMP_FontAsset/Extract Atlas", false, 2200)] + static void ExtractAtlas(MenuCommand command) + { + TMP_FontAsset font = command.context as TMP_FontAsset; + + string fontPath = AssetDatabase.GetAssetPath(font); + string texPath = Path.GetDirectoryName(fontPath) + "/" + Path.GetFileNameWithoutExtension(fontPath) + " Atlas.png"; + + // Create a Serialized Object of the texture to allow us to make it readable. + SerializedObject texprop = new SerializedObject(font.material.GetTexture(ShaderUtilities.ID_MainTex)); + texprop.FindProperty("m_IsReadable").boolValue = true; + texprop.ApplyModifiedProperties(); + + // Create a copy of the texture. + Texture2D tex = Instantiate(font.material.GetTexture(ShaderUtilities.ID_MainTex)) as Texture2D; + + // Set the texture to not readable again. + texprop.FindProperty("m_IsReadable").boolValue = false; + texprop.ApplyModifiedProperties(); + + Debug.Log(texPath); + // Saving File for Debug + var pngData = tex.EncodeToPNG(); + File.WriteAllBytes(texPath, pngData); + + AssetDatabase.Refresh(); + DestroyImmediate(tex); + } + + /// + /// + /// + /// + [MenuItem("CONTEXT/TMP_FontAsset/Update Atlas Texture...", false, 2000)] + static void RegenerateFontAsset(MenuCommand command) + { + TMP_FontAsset fontAsset = command.context as TMP_FontAsset; + + if (fontAsset != null) + { + TMPro_FontAssetCreatorWindow.ShowFontAtlasCreatorWindow(fontAsset); + } + } + + /*[MenuItem("CONTEXT/TMP_FontAsset/Force Upgrade To Version 1.1.0...", false, 2020)] + static void ForceFontAssetUpgrade(MenuCommand command) + { + TMP_FontAsset fontAsset = command.context as TMP_FontAsset; + + if (fontAsset != null) + { + fontAsset.UpgradeFontAsset(); + TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(true, fontAsset); + } + }*/ + + + /// + /// Clear Dynamic Font Asset data such as glyph, character and font features. + /// + /// + [MenuItem("CONTEXT/TMP_FontAsset/Reset", true, 100)] + static bool ClearFontAssetDataValidate(MenuCommand command) + { + return AssetDatabase.IsOpenForEdit(command.context); + } + + [MenuItem("CONTEXT/TMP_FontAsset/Reset", false, 100)] + static void ClearFontAssetData(MenuCommand command) + { + TMP_FontAsset fontAsset = command.context as TMP_FontAsset; + + if (fontAsset == null) + return; + + if (Selection.activeObject != fontAsset) + Selection.activeObject = fontAsset; + + fontAsset.ClearFontAssetData(true); + + TMP_ResourceManager.RebuildFontAssetCache(); + + TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(true, fontAsset); + } + + /// + /// Clear Character and Glyph data (only). + /// + /// + [MenuItem("CONTEXT/TMP_FontAsset/Clear Dynamic Data", true, 2100)] + static bool ClearFontCharacterDataValidate(MenuCommand command) + { + return AssetDatabase.IsOpenForEdit(command.context); + } + + [MenuItem("CONTEXT/TMP_FontAsset/Clear Dynamic Data", false, 2100)] + static void ClearFontCharacterData(MenuCommand command) + { + TMP_FontAsset fontAsset = command.context as TMP_FontAsset; + + if (fontAsset == null) + return; + + if (Selection.activeObject != fontAsset) + Selection.activeObject = fontAsset; + + fontAsset.ClearCharacterAndGlyphTablesInternal(); + + TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(true, fontAsset); + } + + /// + /// Import all font features + /// + /// + #if TEXTCORE_FONT_ENGINE_1_5_OR_NEWER + [MenuItem("CONTEXT/TMP_FontAsset/Import Font Features", true, 2110)] + static bool ReimportFontFeaturesValidate(MenuCommand command) + { + return AssetDatabase.IsOpenForEdit(command.context); + } + + [MenuItem("CONTEXT/TMP_FontAsset/Import Font Features", false, 2110)] + static void ReimportFontFeatures(MenuCommand command) + { + TMP_FontAsset fontAsset = command.context as TMP_FontAsset; + + if (fontAsset == null) + return; + + if (Selection.activeObject != fontAsset) + Selection.activeObject = fontAsset; + + fontAsset.ImportFontFeatures(); + + TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(true, fontAsset); + } + #endif + + /// + /// + /// + /// + [MenuItem("CONTEXT/TrueTypeFontImporter/Create TMP Font Asset...", false, 200)] + static void CreateFontAsset(MenuCommand command) + { + TrueTypeFontImporter importer = command.context as TrueTypeFontImporter; + + if (importer != null) + { + Font sourceFontFile = AssetDatabase.LoadAssetAtPath(importer.assetPath); + + if (sourceFontFile) + TMPro_FontAssetCreatorWindow.ShowFontAtlasCreatorWindow(sourceFontFile); + } + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMPro_ContextMenus.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMPro_ContextMenus.cs.meta new file mode 100644 index 00000000..f16753fe --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMPro_ContextMenus.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 44e1d646473a40178712cb2150f54cec +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMPro_CreateObjectMenu.cs b/Packages/com.unity.ugui/Editor/TMP/TMPro_CreateObjectMenu.cs new file mode 100644 index 00000000..a0d7d835 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMPro_CreateObjectMenu.cs @@ -0,0 +1,395 @@ +using UnityEngine; +using UnityEditor; +using UnityEditor.Presets; +using UnityEditor.SceneManagement; +using UnityEditor.Experimental.SceneManagement; +using UnityEditor.EventSystems; +using UnityEngine.SceneManagement; +using UnityEngine.UI; +using UnityEngine.EventSystems; + + +namespace TMPro.EditorUtilities +{ + public static class TMPro_CreateObjectMenu + { + + /// + /// Create a TextMeshPro object that works with the Mesh Renderer + /// + /// + [MenuItem("GameObject/3D Object/Text - TextMeshPro", false, 30)] + static void CreateTextMeshProObjectPerform(MenuCommand command) + { + GameObject go = ObjectFactory.CreateGameObject("Text (TMP)"); + + // Add support for new prefab mode + StageUtility.PlaceGameObjectInCurrentStage(go); + + TextMeshPro textComponent = ObjectFactory.AddComponent(go); + + if (textComponent.m_isWaitingOnResourceLoad == false) + { + // Get reference to potential Presets for component + Preset[] presets = Preset.GetDefaultPresetsForObject(textComponent); + + if (presets == null || presets.Length == 0) + { + textComponent.text = "Sample text"; + textComponent.alignment = TextAlignmentOptions.TopLeft; + } + else + { + textComponent.renderer.sortingLayerID = textComponent._SortingLayerID; + textComponent.renderer.sortingOrder = textComponent._SortingOrder; + } + + if (TMP_Settings.autoSizeTextContainer) + { + Vector2 size = textComponent.GetPreferredValues(TMP_Math.FLOAT_MAX, TMP_Math.FLOAT_MAX); + textComponent.rectTransform.sizeDelta = size; + } + else + { + textComponent.rectTransform.sizeDelta = TMP_Settings.defaultTextMeshProTextContainerSize; + } + } + else + { + textComponent.text = "Sample text"; + textComponent.alignment = TextAlignmentOptions.TopLeft; + } + + Undo.RegisterCreatedObjectUndo(go, "Create " + go.name); + + GameObject contextObject = command.context as GameObject; + if (contextObject != null) + { + GameObjectUtility.SetParentAndAlign(go, contextObject); + Undo.SetTransformParent(go.transform, contextObject.transform, "Parent " + go.name); + } + + Selection.activeGameObject = go; + } + + + /// + /// Create a TextMeshPro object that works with the CanvasRenderer + /// + /// + [MenuItem("GameObject/UI/Text - TextMeshPro", false, 2001)] + static void CreateTextMeshProGuiObjectPerform(MenuCommand menuCommand) + { + GameObject go = TMP_DefaultControls.CreateText(GetStandardResources()); + + // Override text color and font size + TextMeshProUGUI textComponent = go.GetComponent(); + + if (textComponent.m_isWaitingOnResourceLoad == false) + { + // Get reference to potential Presets for component + Preset[] presets = Preset.GetDefaultPresetsForObject(textComponent); + + if (presets == null || presets.Length == 0) + { + textComponent.fontSize = TMP_Settings.defaultFontSize; + textComponent.color = Color.white; + textComponent.text = "New Text"; + } + + if (TMP_Settings.autoSizeTextContainer) + { + Vector2 size = textComponent.GetPreferredValues(TMP_Math.FLOAT_MAX, TMP_Math.FLOAT_MAX); + textComponent.rectTransform.sizeDelta = size; + } + else + { + textComponent.rectTransform.sizeDelta = TMP_Settings.defaultTextMeshProUITextContainerSize; + } + } + else + { + textComponent.fontSize = -99; + textComponent.color = Color.white; + textComponent.text = "New Text"; + } + + PlaceUIElementRoot(go, menuCommand); + } + + [MenuItem("GameObject/UI/Button - TextMeshPro", false, 2031)] + public static void AddButton(MenuCommand menuCommand) + { + GameObject go = TMP_DefaultControls.CreateButton(GetStandardResources()); + + // Override font size + TMP_Text textComponent = go.GetComponentInChildren(); + textComponent.fontSize = 24; + + PlaceUIElementRoot(go, menuCommand); + } + + + [MenuItem("GameObject/UI/Input Field - TextMeshPro", false, 2037)] + static void AddTextMeshProInputField(MenuCommand menuCommand) + { + GameObject go = TMP_DefaultControls.CreateInputField(GetStandardResources()); + PlaceUIElementRoot(go, menuCommand); + } + + + [MenuItem("GameObject/UI/Dropdown - TextMeshPro", false, 2036)] + public static void AddDropdown(MenuCommand menuCommand) + { + GameObject go = TMP_DefaultControls.CreateDropdown(GetStandardResources()); + PlaceUIElementRoot(go, menuCommand); + } + + + private const string kUILayerName = "UI"; + + private const string kStandardSpritePath = "UI/Skin/UISprite.psd"; + private const string kBackgroundSpritePath = "UI/Skin/Background.psd"; + private const string kInputFieldBackgroundPath = "UI/Skin/InputFieldBackground.psd"; + private const string kKnobPath = "UI/Skin/Knob.psd"; + private const string kCheckmarkPath = "UI/Skin/Checkmark.psd"; + private const string kDropdownArrowPath = "UI/Skin/DropdownArrow.psd"; + private const string kMaskPath = "UI/Skin/UIMask.psd"; + + private static TMP_DefaultControls.Resources s_StandardResources; + + + private static TMP_DefaultControls.Resources GetStandardResources() + { + if (s_StandardResources.standard == null) + { + s_StandardResources.standard = AssetDatabase.GetBuiltinExtraResource(kStandardSpritePath); + s_StandardResources.background = AssetDatabase.GetBuiltinExtraResource(kBackgroundSpritePath); + s_StandardResources.inputField = AssetDatabase.GetBuiltinExtraResource(kInputFieldBackgroundPath); + s_StandardResources.knob = AssetDatabase.GetBuiltinExtraResource(kKnobPath); + s_StandardResources.checkmark = AssetDatabase.GetBuiltinExtraResource(kCheckmarkPath); + s_StandardResources.dropdown = AssetDatabase.GetBuiltinExtraResource(kDropdownArrowPath); + s_StandardResources.mask = AssetDatabase.GetBuiltinExtraResource(kMaskPath); + } + return s_StandardResources; + } + + + private static void SetPositionVisibleinSceneView(RectTransform canvasRTransform, RectTransform itemTransform) + { + // Find the best scene view + SceneView sceneView = SceneView.lastActiveSceneView; + + if (sceneView == null && SceneView.sceneViews.Count > 0) + sceneView = SceneView.sceneViews[0] as SceneView; + + // Couldn't find a SceneView. Don't set position. + if (sceneView == null || sceneView.camera == null) + return; + + // Create world space Plane from canvas position. + Camera camera = sceneView.camera; + Vector3 position = Vector3.zero; + Vector2 localPlanePosition; + + if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRTransform, new Vector2(camera.pixelWidth / 2, camera.pixelHeight / 2), camera, out localPlanePosition)) + { + // Adjust for canvas pivot + localPlanePosition.x = localPlanePosition.x + canvasRTransform.sizeDelta.x * canvasRTransform.pivot.x; + localPlanePosition.y = localPlanePosition.y + canvasRTransform.sizeDelta.y * canvasRTransform.pivot.y; + + localPlanePosition.x = Mathf.Clamp(localPlanePosition.x, 0, canvasRTransform.sizeDelta.x); + localPlanePosition.y = Mathf.Clamp(localPlanePosition.y, 0, canvasRTransform.sizeDelta.y); + + // Adjust for anchoring + position.x = localPlanePosition.x - canvasRTransform.sizeDelta.x * itemTransform.anchorMin.x; + position.y = localPlanePosition.y - canvasRTransform.sizeDelta.y * itemTransform.anchorMin.y; + + Vector3 minLocalPosition; + minLocalPosition.x = canvasRTransform.sizeDelta.x * (0 - canvasRTransform.pivot.x) + itemTransform.sizeDelta.x * itemTransform.pivot.x; + minLocalPosition.y = canvasRTransform.sizeDelta.y * (0 - canvasRTransform.pivot.y) + itemTransform.sizeDelta.y * itemTransform.pivot.y; + + Vector3 maxLocalPosition; + maxLocalPosition.x = canvasRTransform.sizeDelta.x * (1 - canvasRTransform.pivot.x) - itemTransform.sizeDelta.x * itemTransform.pivot.x; + maxLocalPosition.y = canvasRTransform.sizeDelta.y * (1 - canvasRTransform.pivot.y) - itemTransform.sizeDelta.y * itemTransform.pivot.y; + + position.x = Mathf.Clamp(position.x, minLocalPosition.x, maxLocalPosition.x); + position.y = Mathf.Clamp(position.y, minLocalPosition.y, maxLocalPosition.y); + } + + itemTransform.anchoredPosition = position; + itemTransform.localRotation = Quaternion.identity; + itemTransform.localScale = Vector3.one; + } + + + private static void PlaceUIElementRoot(GameObject element, MenuCommand menuCommand) + { + GameObject parent = menuCommand.context as GameObject; + bool explicitParentChoice = true; + if (parent == null) + { + parent = GetOrCreateCanvasGameObject(); + explicitParentChoice = false; + + // If in Prefab Mode, Canvas has to be part of Prefab contents, + // otherwise use Prefab root instead. + PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage(); + if (prefabStage != null && !prefabStage.IsPartOfPrefabContents(parent)) + parent = prefabStage.prefabContentsRoot; + } + + if (parent.GetComponentsInParent(true).Length == 0) + { + // Create canvas under context GameObject, + // and make that be the parent which UI element is added under. + GameObject canvas = CreateNewUI(); + Undo.SetTransformParent(canvas.transform, parent.transform, ""); + parent = canvas; + } + + GameObjectUtility.EnsureUniqueNameForSibling(element); + + SetParentAndAlign(element, parent); + if (!explicitParentChoice) // not a context click, so center in sceneview + SetPositionVisibleinSceneView(parent.GetComponent(), element.GetComponent()); + + // This call ensure any change made to created Objects after they where registered will be part of the Undo. + Undo.RegisterFullObjectHierarchyUndo(parent == null ? element : parent, ""); + + // We have to fix up the undo name since the name of the object was only known after reparenting it. + Undo.SetCurrentGroupName("Create " + element.name); + + Selection.activeGameObject = element; + } + + private static void SetParentAndAlign(GameObject child, GameObject parent) + { + if (parent == null) + return; + + Undo.SetTransformParent(child.transform, parent.transform, ""); + + RectTransform rectTransform = child.transform as RectTransform; + if (rectTransform) + { + rectTransform.anchoredPosition = Vector2.zero; + Vector3 localPosition = rectTransform.localPosition; + localPosition.z = 0; + rectTransform.localPosition = localPosition; + } + else + { + child.transform.localPosition = Vector3.zero; + } + child.transform.localRotation = Quaternion.identity; + child.transform.localScale = Vector3.one; + + SetLayerRecursively(child, parent.layer); + } + + private static void SetLayerRecursively(GameObject go, int layer) + { + go.layer = layer; + Transform t = go.transform; + for (int i = 0; i < t.childCount; i++) + SetLayerRecursively(t.GetChild(i).gameObject, layer); + } + + + public static GameObject CreateNewUI() + { + // Root for the UI + var root = new GameObject("Canvas"); + root.layer = LayerMask.NameToLayer(kUILayerName); + Canvas canvas = root.AddComponent(); + canvas.renderMode = RenderMode.ScreenSpaceOverlay; + root.AddComponent(); + root.AddComponent(); + + // Works for all stages. + StageUtility.PlaceGameObjectInCurrentStage(root); + bool customScene = false; + PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage(); + if (prefabStage != null) + { + root.transform.SetParent(prefabStage.prefabContentsRoot.transform, false); + customScene = true; + } + + Undo.RegisterCreatedObjectUndo(root, "Create " + root.name); + + // If there is no event system add one... + // No need to place event system in custom scene as these are temporary anyway. + // It can be argued for or against placing it in the user scenes, + // but let's not modify scene user is not currently looking at. + if (!customScene) + CreateEventSystem(false); + return root; + } + + + private static void CreateEventSystem(bool select) + { + CreateEventSystem(select, null); + } + + + private static void CreateEventSystem(bool select, GameObject parent) + { + var esys = Object.FindFirstObjectByType(); + if (esys == null) + { + var eventSystem = ObjectFactory.CreateGameObject("EventSystem"); + GameObjectUtility.SetParentAndAlign(eventSystem, parent); + esys = ObjectFactory.AddComponent(eventSystem); + InputModuleComponentFactory.AddInputModule(eventSystem); + + Undo.RegisterCreatedObjectUndo(eventSystem, "Create " + eventSystem.name); + } + + if (select && esys != null) + { + Selection.activeGameObject = esys.gameObject; + } + } + + + // Helper function that returns a Canvas GameObject; preferably a parent of the selection, or other existing Canvas. + public static GameObject GetOrCreateCanvasGameObject() + { + GameObject selectedGo = Selection.activeGameObject; + + // Try to find a gameobject that is the selected GO or one if its parents. + Canvas canvas = (selectedGo != null) ? selectedGo.GetComponentInParent() : null; + if (IsValidCanvas(canvas)) + return canvas.gameObject; + + // No canvas in selection or its parents? Then use any valid canvas. + // We have to find all loaded Canvases, not just the ones in main scenes. + Canvas[] canvasArray = StageUtility.GetCurrentStageHandle().FindComponentsOfType(); + for (int i = 0; i < canvasArray.Length; i++) + if (IsValidCanvas(canvasArray[i])) + return canvasArray[i].gameObject; + + // No canvas in the scene at all? Then create a new one. + return CreateNewUI(); + } + + static bool IsValidCanvas(Canvas canvas) + { + if (canvas == null || !canvas.gameObject.activeInHierarchy) + return false; + + // It's important that the non-editable canvas from a prefab scene won't be rejected, + // but canvases not visible in the Hierarchy at all do. Don't check for HideAndDontSave. + if (EditorUtility.IsPersistent(canvas) || (canvas.hideFlags & HideFlags.HideInHierarchy) != 0) + return false; + + if (StageUtility.GetStageHandle(canvas.gameObject) != StageUtility.GetCurrentStageHandle()) + return false; + + return true; + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMPro_CreateObjectMenu.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMPro_CreateObjectMenu.cs.meta new file mode 100644 index 00000000..be9643fd --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMPro_CreateObjectMenu.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 7065397ff8184621aa3ca4f854491259 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMPro_EditorShaderUtilities.cs b/Packages/com.unity.ugui/Editor/TMP/TMPro_EditorShaderUtilities.cs new file mode 100644 index 00000000..3d639005 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMPro_EditorShaderUtilities.cs @@ -0,0 +1,53 @@ +using UnityEngine; +using UnityEditor; +using System.Linq; +using System.Collections; + + +namespace TMPro.EditorUtilities +{ + + public static class EditorShaderUtilities + { + + /// + /// Copy Shader properties from source to destination material. + /// + /// + /// + public static void CopyMaterialProperties(Material source, Material destination) + { + MaterialProperty[] source_prop = MaterialEditor.GetMaterialProperties(new Material[] { source }); + + for (int i = 0; i < source_prop.Length; i++) + { + int property_ID = Shader.PropertyToID(source_prop[i].name); + if (destination.HasProperty(property_ID)) + { + //Debug.Log(source_prop[i].name + " Type:" + ShaderUtil.GetPropertyType(source.shader, i)); + switch (ShaderUtil.GetPropertyType(source.shader, i)) + { + case ShaderUtil.ShaderPropertyType.Color: + destination.SetColor(property_ID, source.GetColor(property_ID)); + break; + case ShaderUtil.ShaderPropertyType.Float: + destination.SetFloat(property_ID, source.GetFloat(property_ID)); + break; + case ShaderUtil.ShaderPropertyType.Range: + destination.SetFloat(property_ID, source.GetFloat(property_ID)); + break; + case ShaderUtil.ShaderPropertyType.TexEnv: + destination.SetTexture(property_ID, source.GetTexture(property_ID)); + break; + case ShaderUtil.ShaderPropertyType.Vector: + destination.SetVector(property_ID, source.GetVector(property_ID)); + break; + } + } + } + + } + + } + +} \ No newline at end of file diff --git a/Packages/com.unity.ugui/Editor/TMP/TMPro_EditorShaderUtilities.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMPro_EditorShaderUtilities.cs.meta new file mode 100644 index 00000000..89d25943 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMPro_EditorShaderUtilities.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: aa76955fe5bb44f7915d91db8c7043c4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMPro_FontAssetCreatorWindow.cs b/Packages/com.unity.ugui/Editor/TMP/TMPro_FontAssetCreatorWindow.cs new file mode 100644 index 00000000..65434777 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMPro_FontAssetCreatorWindow.cs @@ -0,0 +1,2134 @@ +using System; +using UnityEngine; +using UnityEditor; +using System.Collections.Generic; +using System.Globalization; +using System.Threading; +using System.IO; +using System.Text.RegularExpressions; +using UnityEngine.TextCore; +using UnityEngine.TextCore.LowLevel; +using UnityEditor.TextCore.LowLevel; +using Object = UnityEngine.Object; + +namespace TMPro.EditorUtilities +{ + public class TMPro_FontAssetCreatorWindow : EditorWindow + { + [MenuItem("Window/TextMeshPro/Font Asset Creator", false, 2025)] + public static void ShowFontAtlasCreatorWindow() + { + var window = GetWindow(); + window.titleContent = new GUIContent("Font Asset Creator"); + window.Focus(); + + // Make sure TMP Essential Resources have been imported. + window.CheckEssentialResources(); + } + + + public static void ShowFontAtlasCreatorWindow(Font font) + { + var window = GetWindow(); + + window.titleContent = new GUIContent("Font Asset Creator"); + window.Focus(); + + window.ClearGeneratedData(); + window.m_LegacyFontAsset = null; + window.m_SelectedFontAsset = null; + + // Override selected font asset + window.m_SourceFont = font; + + // Make sure TMP Essential Resources have been imported. + window.CheckEssentialResources(); + } + + + public static void ShowFontAtlasCreatorWindow(TMP_FontAsset fontAsset) + { + var window = GetWindow(); + + window.titleContent = new GUIContent("Font Asset Creator"); + window.Focus(); + + // Clear any previously generated data + window.ClearGeneratedData(); + window.m_LegacyFontAsset = null; + + // Load font asset creation settings if we have valid settings + if (string.IsNullOrEmpty(fontAsset.creationSettings.sourceFontFileGUID) == false) + { + window.LoadFontCreationSettings(fontAsset.creationSettings); + + // Override settings to inject character list from font asset + //window.m_CharacterSetSelectionMode = 6; + //window.m_CharacterSequence = TMP_EditorUtility.GetUnicodeCharacterSequence(TMP_FontAsset.GetCharactersArray(fontAsset)); + + window.m_ReferencedFontAsset = fontAsset; + window.m_SavedFontAtlas = fontAsset.atlasTexture; + } + else + { + window.m_WarningMessage = "Font Asset [" + fontAsset.name + "] does not contain any previous \"Font Asset Creation Settings\". This usually means [" + fontAsset.name + "] was created before this new functionality was added."; + window.m_SourceFont = null; + window.m_LegacyFontAsset = fontAsset; + } + + // Even if we don't have any saved generation settings, we still want to pre-select the source font file. + window.m_SelectedFontAsset = fontAsset; + + // Make sure TMP Essential Resources have been imported. + window.CheckEssentialResources(); + } + + [System.Serializable] + class FontAssetCreationSettingsContainer + { + public List fontAssetCreationSettings; + } + + FontAssetCreationSettingsContainer m_FontAssetCreationSettingsContainer; + + //static readonly string[] m_FontCreationPresets = new string[] { "Recent 1", "Recent 2", "Recent 3", "Recent 4" }; + int m_FontAssetCreationSettingsCurrentIndex = 0; + + const string k_FontAssetCreationSettingsContainerKey = "TextMeshPro.FontAssetCreator.RecentFontAssetCreationSettings.Container"; + const string k_FontAssetCreationSettingsCurrentIndexKey = "TextMeshPro.FontAssetCreator.RecentFontAssetCreationSettings.CurrentIndex"; + const float k_TwoColumnControlsWidth = 335f; + + // Diagnostics + System.Diagnostics.Stopwatch m_StopWatch; + double m_GlyphPackingGenerationTime; + double m_GlyphRenderingGenerationTime; + + string[] m_FontSizingOptions = { "Auto Sizing", "Custom Size" }; + int m_PointSizeSamplingMode; + string[] m_FontResolutionLabels = { "8", "16", "32", "64", "128", "256", "512", "1024", "2048", "4096", "8192" }; + int[] m_FontAtlasResolutions = { 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 }; + string[] m_FontCharacterSets = { "ASCII", "Extended ASCII", "ASCII Lowercase", "ASCII Uppercase", "Numbers + Symbols", "Custom Range", "Unicode Range (Hex)", "Custom Characters", "Characters from File" }; + enum FontPackingModes { Fast = 0, Optimum = 4 }; + FontPackingModes m_PackingMode = FontPackingModes.Fast; + + int m_CharacterSetSelectionMode; + + string m_CharacterSequence = ""; + string m_OutputFeedback = ""; + string m_WarningMessage; + int m_CharacterCount; + Vector2 m_ScrollPosition; + Vector2 m_OutputScrollPosition; + + bool m_IsRepaintNeeded; + + float m_AtlasGenerationProgress; + string m_AtlasGenerationProgressLabel = string.Empty; + bool m_IsGlyphPackingDone; + bool m_IsGlyphRenderingDone; + bool m_IsRenderingDone; + bool m_IsProcessing; + bool m_IsGenerationDisabled; + bool m_IsGenerationCancelled; + + bool m_IsFontAtlasInvalid; + Font m_SourceFont; + int m_SourceFontFaceIndex; + private string[] m_SourceFontFaces = new string[0]; + TMP_FontAsset m_SelectedFontAsset; + TMP_FontAsset m_LegacyFontAsset; + TMP_FontAsset m_ReferencedFontAsset; + + TextAsset m_CharactersFromFile; + int m_PointSize; + float m_PaddingFieldValue = 10; + int m_Padding; + + enum PaddingMode { Undefined = 0, Percentage = 1, Pixel = 2 }; + + string[] k_PaddingOptionLabels = { "%", "px" }; + private PaddingMode m_PaddingMode = PaddingMode.Percentage; + + GlyphRenderMode m_GlyphRenderMode = GlyphRenderMode.SDFAA; + int m_AtlasWidth = 512; + int m_AtlasHeight = 512; + byte[] m_AtlasTextureBuffer; + Texture2D m_FontAtlasTexture; + Texture2D m_GlyphRectPreviewTexture; + Texture2D m_SavedFontAtlas; + + // + List m_FontGlyphTable = new List(); + List m_FontCharacterTable = new List(); + + Dictionary m_CharacterLookupMap = new Dictionary(); + Dictionary> m_GlyphLookupMap = new Dictionary>(); + + List m_GlyphsToPack = new List(); + List m_GlyphsPacked = new List(); + List m_FreeGlyphRects = new List(); + List m_UsedGlyphRects = new List(); + List m_GlyphsToRender = new List(); + List m_AvailableGlyphsToAdd = new List(); + List m_MissingCharacters = new List(); + List m_ExcludedCharacters = new List(); + + private FaceInfo m_FaceInfo; + + bool m_IncludeFontFeatures; + + + public void OnEnable() + { + // Used for Diagnostics + m_StopWatch = new System.Diagnostics.Stopwatch(); + + // Set Editor window size. + minSize = new Vector2(315, minSize.y); + + // Initialize & Get shader property IDs. + ShaderUtilities.GetShaderPropertyIDs(); + + // Load last selected preset if we are not already in the process of regenerating an existing font asset (via the Context menu) + if (EditorPrefs.HasKey(k_FontAssetCreationSettingsContainerKey)) + { + if (m_FontAssetCreationSettingsContainer == null) + m_FontAssetCreationSettingsContainer = JsonUtility.FromJson(EditorPrefs.GetString(k_FontAssetCreationSettingsContainerKey)); + + if (m_FontAssetCreationSettingsContainer.fontAssetCreationSettings != null && m_FontAssetCreationSettingsContainer.fontAssetCreationSettings.Count > 0) + { + // Load Font Asset Creation Settings preset. + if (EditorPrefs.HasKey(k_FontAssetCreationSettingsCurrentIndexKey)) + m_FontAssetCreationSettingsCurrentIndex = EditorPrefs.GetInt(k_FontAssetCreationSettingsCurrentIndexKey); + + LoadFontCreationSettings(m_FontAssetCreationSettingsContainer.fontAssetCreationSettings[m_FontAssetCreationSettingsCurrentIndex]); + } + } + + // Get potential font face and styles for the current font. + m_SourceFontFaces = GetFontFaces(); + + ClearGeneratedData(); + } + + + public void OnDisable() + { + //Debug.Log("TextMeshPro Editor Window has been disabled."); + + // Destroy Engine only if it has been initialized already + FontEngine.DestroyFontEngine(); + + ClearGeneratedData(); + + // Remove Glyph Report if one was created. + if (File.Exists("Assets/TextMesh Pro/Glyph Report.txt")) + { + File.Delete("Assets/TextMesh Pro/Glyph Report.txt"); + File.Delete("Assets/TextMesh Pro/Glyph Report.txt.meta"); + + AssetDatabase.Refresh(); + } + + // Save Font Asset Creation Settings Index + SaveCreationSettingsToEditorPrefs(SaveFontCreationSettings()); + EditorPrefs.SetInt(k_FontAssetCreationSettingsCurrentIndexKey, m_FontAssetCreationSettingsCurrentIndex); + + // Unregister to event + TMPro_EventManager.RESOURCE_LOAD_EVENT.Remove(ON_RESOURCES_LOADED); + + Resources.UnloadUnusedAssets(); + } + + + // Event received when TMP resources have been loaded. + void ON_RESOURCES_LOADED() + { + TMPro_EventManager.RESOURCE_LOAD_EVENT.Remove(ON_RESOURCES_LOADED); + + m_IsGenerationDisabled = false; + } + + // Make sure TMP Essential Resources have been imported. + void CheckEssentialResources() + { + if (TMP_Settings.instance == null) + { + if (m_IsGenerationDisabled == false) + TMPro_EventManager.RESOURCE_LOAD_EVENT.Add(ON_RESOURCES_LOADED); + + m_IsGenerationDisabled = true; + } + } + + + public void OnGUI() + { + GUILayout.BeginHorizontal(); + + DrawControls(); + + if (position.width > position.height && position.width > k_TwoColumnControlsWidth) + DrawPreview(); + + GUILayout.EndHorizontal(); + } + + + public void Update() + { + if (m_IsRepaintNeeded) + { + //Debug.Log("Repainting..."); + m_IsRepaintNeeded = false; + Repaint(); + } + + // Update Progress bar is we are Rendering a Font. + if (m_IsProcessing) + { + m_AtlasGenerationProgress = FontEngine.generationProgress; + + m_IsRepaintNeeded = true; + } + + if (m_IsGlyphPackingDone) + { + UpdateRenderFeedbackWindow(); + + if (m_IsGenerationCancelled == false) + { + DrawGlyphRectPreviewTexture(); + Debug.Log("Glyph packing completed in: " + m_GlyphPackingGenerationTime.ToString("0.000 ms.")); + } + + m_IsGlyphPackingDone = false; + } + + if (m_IsGlyphRenderingDone) + { + Debug.Log("Font Atlas generation completed in: " + m_GlyphRenderingGenerationTime.ToString("0.000 ms.")); + m_IsGlyphRenderingDone = false; + } + + // Update Feedback Window & Create Font Texture once Rendering is done. + if (m_IsRenderingDone) + { + m_IsProcessing = false; + m_IsRenderingDone = false; + + if (m_IsGenerationCancelled == false) + { + m_AtlasGenerationProgress = FontEngine.generationProgress; + m_AtlasGenerationProgressLabel = "Generation completed in: " + (m_GlyphPackingGenerationTime + m_GlyphRenderingGenerationTime).ToString("0.00 ms."); + + UpdateRenderFeedbackWindow(); + CreateFontAtlasTexture(); + + // If dynamic make readable ... + m_FontAtlasTexture.Apply(false, false); + } + Repaint(); + } + } + + + /// + /// Method which returns the character corresponding to a decimal value. + /// + /// + /// + static uint[] ParseNumberSequence(string sequence) + { + List unicodeList = new List(); + string[] sequences = sequence.Split(','); + + foreach (string seq in sequences) + { + string[] s1 = seq.Split('-'); + + if (s1.Length == 1) + try + { + unicodeList.Add(uint.Parse(s1[0])); + } + catch + { + Debug.Log("No characters selected or invalid format."); + } + else + { + for (uint j = uint.Parse(s1[0]); j < uint.Parse(s1[1]) + 1; j++) + { + unicodeList.Add(j); + } + } + } + + return unicodeList.ToArray(); + } + + + /// + /// Method which returns the character (decimal value) from a hex sequence. + /// + /// + /// + static uint[] ParseHexNumberSequence(string sequence) + { + List unicodeList = new List(); + string[] sequences = sequence.Split(','); + + foreach (string seq in sequences) + { + string[] s1 = seq.Split('-'); + + if (s1.Length == 1) + try + { + unicodeList.Add(uint.Parse(s1[0], NumberStyles.AllowHexSpecifier)); + } + catch + { + Debug.Log("No characters selected or invalid format."); + } + else + { + for (uint j = uint.Parse(s1[0], NumberStyles.AllowHexSpecifier); j < uint.Parse(s1[1], NumberStyles.AllowHexSpecifier) + 1; j++) + { + unicodeList.Add(j); + } + } + } + + return unicodeList.ToArray(); + } + + + void DrawControls() + { + GUILayout.Space(5f); + + if (position.width > position.height && position.width > k_TwoColumnControlsWidth) + { + m_ScrollPosition = EditorGUILayout.BeginScrollView(m_ScrollPosition, GUILayout.Width(315)); + } + else + { + m_ScrollPosition = EditorGUILayout.BeginScrollView(m_ScrollPosition); + } + + GUILayout.Space(5f); + + GUILayout.Label(m_SelectedFontAsset != null ? string.Format("Font Settings [{0}]", m_SelectedFontAsset.name) : "Font Settings", EditorStyles.boldLabel); + + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + + EditorGUIUtility.labelWidth = 125f; + EditorGUIUtility.fieldWidth = 5f; + + // Disable Options if already generating a font atlas texture. + EditorGUI.BeginDisabledGroup(m_IsProcessing); + { + // FONT SELECTION + EditorGUI.BeginChangeCheck(); + m_SourceFont = EditorGUILayout.ObjectField("Source Font", m_SourceFont, typeof(Font), false) as Font; + if (EditorGUI.EndChangeCheck()) + { + m_SelectedFontAsset = null; + m_IsFontAtlasInvalid = true; + m_SourceFontFaces = GetFontFaces(); + m_SourceFontFaceIndex = 0; + } + + // FONT FACE AND STYLE SELECTION + EditorGUI.BeginChangeCheck(); + GUI.enabled = m_SourceFont != null; + m_SourceFontFaceIndex = EditorGUILayout.Popup("Font Face", m_SourceFontFaceIndex, m_SourceFontFaces); + if (EditorGUI.EndChangeCheck()) + { + m_SelectedFontAsset = null; + m_IsFontAtlasInvalid = true; + } + GUI.enabled = true; + + // FONT SIZING + EditorGUI.BeginChangeCheck(); + if (m_PointSizeSamplingMode == 0) + { + m_PointSizeSamplingMode = EditorGUILayout.Popup("Sampling Point Size", m_PointSizeSamplingMode, m_FontSizingOptions); + } + else + { + GUILayout.BeginHorizontal(); + m_PointSizeSamplingMode = EditorGUILayout.Popup("Sampling Point Size", m_PointSizeSamplingMode, m_FontSizingOptions, GUILayout.Width(225)); + m_PointSize = EditorGUILayout.IntField(m_PointSize); + GUILayout.EndHorizontal(); + } + if (EditorGUI.EndChangeCheck()) + { + m_IsFontAtlasInvalid = true; + } + + // FONT PADDING + GUILayout.BeginHorizontal(); + EditorGUI.BeginChangeCheck(); + + m_PaddingFieldValue = EditorGUILayout.FloatField("Padding", m_PaddingFieldValue); + + int selection = m_PaddingMode == PaddingMode.Undefined || m_PaddingMode == PaddingMode.Pixel ? 1 : 0; + selection = GUILayout.SelectionGrid(selection, k_PaddingOptionLabels, 2); + + if (m_PaddingMode == PaddingMode.Percentage) + m_PaddingFieldValue = (int)(m_PaddingFieldValue + 0.5f); + + if (EditorGUI.EndChangeCheck()) + { + m_PaddingMode = (PaddingMode)selection + 1; + m_IsFontAtlasInvalid = true; + } + GUILayout.EndHorizontal(); + + // FONT PACKING METHOD SELECTION + EditorGUI.BeginChangeCheck(); + m_PackingMode = (FontPackingModes)EditorGUILayout.EnumPopup("Packing Method", m_PackingMode); + if (EditorGUI.EndChangeCheck()) + { + m_IsFontAtlasInvalid = true; + } + + // FONT ATLAS RESOLUTION SELECTION + GUILayout.BeginHorizontal(); + GUI.changed = false; + + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PrefixLabel("Atlas Resolution"); + m_AtlasWidth = EditorGUILayout.IntPopup(m_AtlasWidth, m_FontResolutionLabels, m_FontAtlasResolutions); + m_AtlasHeight = EditorGUILayout.IntPopup(m_AtlasHeight, m_FontResolutionLabels, m_FontAtlasResolutions); + if (EditorGUI.EndChangeCheck()) + { + m_IsFontAtlasInvalid = true; + } + + GUILayout.EndHorizontal(); + + + // FONT CHARACTER SET SELECTION + EditorGUI.BeginChangeCheck(); + bool hasSelectionChanged = false; + m_CharacterSetSelectionMode = EditorGUILayout.Popup("Character Set", m_CharacterSetSelectionMode, m_FontCharacterSets); + if (EditorGUI.EndChangeCheck()) + { + m_CharacterSequence = ""; + hasSelectionChanged = true; + m_IsFontAtlasInvalid = true; + } + + switch (m_CharacterSetSelectionMode) + { + case 0: // ASCII + //characterSequence = "32 - 126, 130, 132 - 135, 139, 145 - 151, 153, 155, 161, 166 - 167, 169 - 174, 176, 181 - 183, 186 - 187, 191, 8210 - 8226, 8230, 8240, 8242 - 8244, 8249 - 8250, 8252 - 8254, 8260, 8286"; + m_CharacterSequence = "32 - 126, 160, 8203, 8230, 9633"; + break; + + case 1: // EXTENDED ASCII + m_CharacterSequence = "32 - 126, 160 - 255, 8192 - 8303, 8364, 8482, 9633"; + // Could add 9632 for missing glyph + break; + + case 2: // Lowercase + m_CharacterSequence = "32 - 64, 91 - 126, 160"; + break; + + case 3: // Uppercase + m_CharacterSequence = "32 - 96, 123 - 126, 160"; + break; + + case 4: // Numbers & Symbols + m_CharacterSequence = "32 - 64, 91 - 96, 123 - 126, 160"; + break; + + case 5: // Custom Range + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + GUILayout.Label("Enter a sequence of decimal values to define the characters to be included in the font asset or retrieve one from another font asset.", TMP_UIStyleManager.label); + GUILayout.Space(10f); + + EditorGUI.BeginChangeCheck(); + m_ReferencedFontAsset = EditorGUILayout.ObjectField("Select Font Asset", m_ReferencedFontAsset, typeof(TMP_FontAsset), false) as TMP_FontAsset; + if (EditorGUI.EndChangeCheck() || hasSelectionChanged) + { + if (m_ReferencedFontAsset != null) + m_CharacterSequence = TMP_EditorUtility.GetDecimalCharacterSequence(TMP_FontAsset.GetCharactersArray(m_ReferencedFontAsset)); + + m_IsFontAtlasInvalid = true; + } + + // Filter out unwanted characters. + char chr = Event.current.character; + if ((chr < '0' || chr > '9') && (chr < ',' || chr > '-')) + { + Event.current.character = '\0'; + } + GUILayout.Label("Character Sequence (Decimal)", EditorStyles.boldLabel); + EditorGUI.BeginChangeCheck(); + m_CharacterSequence = EditorGUILayout.TextArea(m_CharacterSequence, TMP_UIStyleManager.textAreaBoxWindow, GUILayout.Height(120), GUILayout.ExpandWidth(true)); + if (EditorGUI.EndChangeCheck()) + { + m_IsFontAtlasInvalid = true; + } + + EditorGUILayout.EndVertical(); + break; + + case 6: // Unicode HEX Range + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + GUILayout.Label("Enter a sequence of Unicode (hex) values to define the characters to be included in the font asset or retrieve one from another font asset.", TMP_UIStyleManager.label); + GUILayout.Space(10f); + + EditorGUI.BeginChangeCheck(); + m_ReferencedFontAsset = EditorGUILayout.ObjectField("Select Font Asset", m_ReferencedFontAsset, typeof(TMP_FontAsset), false) as TMP_FontAsset; + if (EditorGUI.EndChangeCheck() || hasSelectionChanged) + { + if (m_ReferencedFontAsset != null) + m_CharacterSequence = TMP_EditorUtility.GetUnicodeCharacterSequence(TMP_FontAsset.GetCharactersArray(m_ReferencedFontAsset)); + + m_IsFontAtlasInvalid = true; + } + + // Filter out unwanted characters. + chr = Event.current.character; + if ((chr < '0' || chr > '9') && (chr < 'a' || chr > 'f') && (chr < 'A' || chr > 'F') && (chr < ',' || chr > '-')) + { + Event.current.character = '\0'; + } + GUILayout.Label("Character Sequence (Hex)", EditorStyles.boldLabel); + EditorGUI.BeginChangeCheck(); + m_CharacterSequence = EditorGUILayout.TextArea(m_CharacterSequence, TMP_UIStyleManager.textAreaBoxWindow, GUILayout.Height(120), GUILayout.ExpandWidth(true)); + if (EditorGUI.EndChangeCheck()) + { + m_IsFontAtlasInvalid = true; + } + + EditorGUILayout.EndVertical(); + break; + + case 7: // Characters from Font Asset + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + GUILayout.Label("Type the characters to be included in the font asset or retrieve them from another font asset.", TMP_UIStyleManager.label); + GUILayout.Space(10f); + + EditorGUI.BeginChangeCheck(); + m_ReferencedFontAsset = EditorGUILayout.ObjectField("Select Font Asset", m_ReferencedFontAsset, typeof(TMP_FontAsset), false) as TMP_FontAsset; + if (EditorGUI.EndChangeCheck() || hasSelectionChanged) + { + if (m_ReferencedFontAsset != null) + m_CharacterSequence = TMP_FontAsset.GetCharacters(m_ReferencedFontAsset); + + m_IsFontAtlasInvalid = true; + } + + EditorGUI.indentLevel = 0; + + GUILayout.Label("Custom Character List", EditorStyles.boldLabel); + EditorGUI.BeginChangeCheck(); + m_CharacterSequence = EditorGUILayout.TextArea(m_CharacterSequence, TMP_UIStyleManager.textAreaBoxWindow, GUILayout.Height(120), GUILayout.ExpandWidth(true)); + if (EditorGUI.EndChangeCheck()) + { + m_IsFontAtlasInvalid = true; + } + EditorGUILayout.EndVertical(); + break; + + case 8: // Character List from File + EditorGUI.BeginChangeCheck(); + m_CharactersFromFile = EditorGUILayout.ObjectField("Character File", m_CharactersFromFile, typeof(TextAsset), false) as TextAsset; + if (EditorGUI.EndChangeCheck()) + { + m_IsFontAtlasInvalid = true; + } + + if (m_CharactersFromFile != null) + { + Regex rx = new Regex(@"(? + { + if (match.Value.StartsWith("\\U")) + return char.ConvertFromUtf32(int.Parse(match.Value.Replace("\\U", ""), NumberStyles.HexNumber)); + + return char.ConvertFromUtf32(int.Parse(match.Value.Replace("\\u", ""), NumberStyles.HexNumber)); + }); + } + break; + } + + // FONT STYLE SELECTION + //GUILayout.BeginHorizontal(); + //EditorGUI.BeginChangeCheck(); + ////m_FontStyle = (FaceStyles)EditorGUILayout.EnumPopup("Font Style", m_FontStyle, GUILayout.Width(225)); + ////m_FontStyleValue = EditorGUILayout.IntField((int)m_FontStyleValue); + //if (EditorGUI.EndChangeCheck()) + //{ + // m_IsFontAtlasInvalid = true; + //} + //GUILayout.EndHorizontal(); + + // Render Mode Selection + CheckForLegacyGlyphRenderMode(); + + EditorGUI.BeginChangeCheck(); + m_GlyphRenderMode = (GlyphRenderMode)EditorGUILayout.EnumPopup("Render Mode", m_GlyphRenderMode); + if (EditorGUI.EndChangeCheck()) + { + m_IsFontAtlasInvalid = true; + } + + m_IncludeFontFeatures = EditorGUILayout.Toggle("Get Font Features", m_IncludeFontFeatures); + + EditorGUILayout.Space(); + } + + EditorGUI.EndDisabledGroup(); + + if (!string.IsNullOrEmpty(m_WarningMessage)) + { + EditorGUILayout.HelpBox(m_WarningMessage, MessageType.Warning); + } + + GUI.enabled = m_SourceFont != null && !m_IsProcessing && !m_IsGenerationDisabled; // Enable Preview if we are not already rendering a font. + if (GUILayout.Button("Generate Font Atlas") && GUI.enabled) + { + if (!m_IsProcessing && m_SourceFont != null) + { + DestroyImmediate(m_FontAtlasTexture); + DestroyImmediate(m_GlyphRectPreviewTexture); + m_FontAtlasTexture = null; + m_SavedFontAtlas = null; + m_OutputFeedback = string.Empty; + + // Initialize font engine + FontEngineError errorCode = FontEngine.InitializeFontEngine(); + if (errorCode != FontEngineError.Success) + { + Debug.Log("Font Asset Creator - Error [" + errorCode + "] has occurred while Initializing the FreeType Library."); + } + + if (errorCode == FontEngineError.Success) + { + errorCode = FontEngine.LoadFontFace(m_SourceFont, 0, m_SourceFontFaceIndex); + + if (errorCode != FontEngineError.Success) + { + Debug.Log("Font Asset Creator - Error Code [" + errorCode + "] has occurred trying to load the [" + m_SourceFont.name + "] font file. This typically results from the use of an incompatible or corrupted font file.", m_SourceFont); + } + } + + + // Define an array containing the characters we will render. + if (errorCode == FontEngineError.Success) + { + uint[] characterSet = null; + + // Get list of characters that need to be packed and rendered to the atlas texture. + if (m_CharacterSetSelectionMode == 7 || m_CharacterSetSelectionMode == 8) + { + // Ensure these characters are always added + List char_List = new List() + { + 0x09, // Tab + 0x5F // Underline + }; + + for (int i = 0; i < m_CharacterSequence.Length; i++) + { + uint unicode = m_CharacterSequence[i]; + + // Handle surrogate pairs + if (i < m_CharacterSequence.Length - 1 && char.IsHighSurrogate((char)unicode) && char.IsLowSurrogate(m_CharacterSequence[i + 1])) + { + unicode = (uint)char.ConvertToUtf32(m_CharacterSequence[i], m_CharacterSequence[i + 1]); + i += 1; + } + + // Check to make sure we don't include duplicates + if (char_List.FindIndex(item => item == unicode) == -1) + char_List.Add(unicode); + } + + characterSet = char_List.ToArray(); + } + else if (m_CharacterSetSelectionMode == 6) + { + characterSet = ParseHexNumberSequence(m_CharacterSequence); + } + else + { + characterSet = ParseNumberSequence(m_CharacterSequence); + } + + m_CharacterCount = characterSet.Length; + + m_AtlasGenerationProgress = 0; + m_IsProcessing = true; + m_IsGenerationCancelled = false; + + GlyphLoadFlags glyphLoadFlags = ((GlyphRasterModes)m_GlyphRenderMode & GlyphRasterModes.RASTER_MODE_HINTED) == GlyphRasterModes.RASTER_MODE_HINTED + ? GlyphLoadFlags.LOAD_RENDER + : GlyphLoadFlags.LOAD_RENDER | GlyphLoadFlags.LOAD_NO_HINTING; + + glyphLoadFlags = ((GlyphRasterModes)m_GlyphRenderMode & GlyphRasterModes.RASTER_MODE_MONO) == GlyphRasterModes.RASTER_MODE_MONO + ? glyphLoadFlags | GlyphLoadFlags.LOAD_MONOCHROME + : glyphLoadFlags; + #if TEXTCORE_FONT_ENGINE_1_5_OR_NEWER + glyphLoadFlags = ((GlyphRasterModes)m_GlyphRenderMode & GlyphRasterModes.RASTER_MODE_COLOR) == GlyphRasterModes.RASTER_MODE_COLOR + ? glyphLoadFlags | GlyphLoadFlags.LOAD_COLOR + : glyphLoadFlags; + #endif + + // + AutoResetEvent autoEvent = new AutoResetEvent(false); + + // Worker thread to pack glyphs in the given texture space. + ThreadPool.QueueUserWorkItem(PackGlyphs => + { + // Start Stop Watch + m_StopWatch = System.Diagnostics.Stopwatch.StartNew(); + + // Clear the various lists used in the generation process. + m_AvailableGlyphsToAdd.Clear(); + m_MissingCharacters.Clear(); + m_ExcludedCharacters.Clear(); + m_CharacterLookupMap.Clear(); + m_GlyphLookupMap.Clear(); + m_GlyphsToPack.Clear(); + m_GlyphsPacked.Clear(); + + // Check if requested characters are available in the source font file. + for (int i = 0; i < characterSet.Length; i++) + { + uint unicode = characterSet[i]; + uint glyphIndex; + + if (FontEngine.TryGetGlyphIndex(unicode, out glyphIndex)) + { + // Skip over potential duplicate characters. + if (m_CharacterLookupMap.ContainsKey(unicode)) + continue; + + // Add character to character lookup map. + m_CharacterLookupMap.Add(unicode, glyphIndex); + + // Skip over potential duplicate glyph references. + if (m_GlyphLookupMap.ContainsKey(glyphIndex)) + { + // Add additional glyph reference for this character. + m_GlyphLookupMap[glyphIndex].Add(unicode); + continue; + } + + // Add glyph reference to glyph lookup map. + m_GlyphLookupMap.Add(glyphIndex, new List() { unicode }); + + // Add glyph index to list of glyphs to add to texture. + m_AvailableGlyphsToAdd.Add(glyphIndex); + } + else + { + // Add Unicode to list of missing characters. + m_MissingCharacters.Add(unicode); + } + } + + // Pack available glyphs in the provided texture space. + if (m_AvailableGlyphsToAdd.Count > 0) + { + int packingModifier = ((GlyphRasterModes)m_GlyphRenderMode & GlyphRasterModes.RASTER_MODE_BITMAP) == GlyphRasterModes.RASTER_MODE_BITMAP ? 0 : 1; + + if (m_PointSizeSamplingMode == 0) // Auto-Sizing Point Size Mode + { + // Estimate min / max range for auto sizing of point size. + int minPointSize = 0; + int maxPointSize = (int)Mathf.Sqrt((m_AtlasWidth * m_AtlasHeight) / m_AvailableGlyphsToAdd.Count) * 3; + + m_PointSize = (maxPointSize + minPointSize) / 2; + + bool optimumPointSizeFound = false; + for (int iteration = 0; iteration < 15 && optimumPointSizeFound == false && m_PointSize > 0; iteration++) + { + m_AtlasGenerationProgressLabel = "Packing glyphs - Pass (" + iteration + ")"; + + FontEngine.SetFaceSize(m_PointSize); + + m_Padding = (int)(m_PaddingMode == PaddingMode.Percentage ? m_PointSize * m_PaddingFieldValue / 100f : m_PaddingFieldValue); + + m_GlyphsToPack.Clear(); + m_GlyphsPacked.Clear(); + + m_FreeGlyphRects.Clear(); + m_FreeGlyphRects.Add(new GlyphRect(0, 0, m_AtlasWidth - packingModifier, m_AtlasHeight - packingModifier)); + m_UsedGlyphRects.Clear(); + + for (int i = 0; i < m_AvailableGlyphsToAdd.Count; i++) + { + uint glyphIndex = m_AvailableGlyphsToAdd[i]; + Glyph glyph; + + if (FontEngine.TryGetGlyphWithIndexValue(glyphIndex, glyphLoadFlags, out glyph)) + { + if (glyph.glyphRect.width > 0 && glyph.glyphRect.height > 0) + { + m_GlyphsToPack.Add(glyph); + } + else + { + m_GlyphsPacked.Add(glyph); + } + } + } + + FontEngine.TryPackGlyphsInAtlas(m_GlyphsToPack, m_GlyphsPacked, m_Padding, (GlyphPackingMode)m_PackingMode, m_GlyphRenderMode, m_AtlasWidth, m_AtlasHeight, m_FreeGlyphRects, m_UsedGlyphRects); + + if (m_IsGenerationCancelled) + { + DestroyImmediate(m_FontAtlasTexture); + m_FontAtlasTexture = null; + return; + } + + //Debug.Log("Glyphs remaining to add [" + m_GlyphsToAdd.Count + "]. Glyphs added [" + m_GlyphsAdded.Count + "]."); + + if (m_GlyphsToPack.Count > 0) + { + if (m_PointSize > minPointSize) + { + maxPointSize = m_PointSize; + m_PointSize = (m_PointSize + minPointSize) / 2; + + //Debug.Log("Decreasing point size from [" + maxPointSize + "] to [" + m_PointSize + "]."); + } + } + else + { + if (maxPointSize - minPointSize > 1 && m_PointSize < maxPointSize) + { + minPointSize = m_PointSize; + m_PointSize = (m_PointSize + maxPointSize) / 2; + + //Debug.Log("Increasing point size from [" + minPointSize + "] to [" + m_PointSize + "]."); + } + else + { + //Debug.Log("[" + iteration + "] iterations to find the optimum point size of : [" + m_PointSize + "]."); + optimumPointSizeFound = true; + } + } + } + } + else // Custom Point Size Mode + { + m_AtlasGenerationProgressLabel = "Packing glyphs..."; + + // Set point size + FontEngine.SetFaceSize(m_PointSize); + + m_Padding = (int)(m_PaddingMode == PaddingMode.Percentage ? m_PointSize * m_PaddingFieldValue / 100 : m_PaddingFieldValue); + + m_GlyphsToPack.Clear(); + m_GlyphsPacked.Clear(); + + m_FreeGlyphRects.Clear(); + m_FreeGlyphRects.Add(new GlyphRect(0, 0, m_AtlasWidth - packingModifier, m_AtlasHeight - packingModifier)); + m_UsedGlyphRects.Clear(); + + for (int i = 0; i < m_AvailableGlyphsToAdd.Count; i++) + { + uint glyphIndex = m_AvailableGlyphsToAdd[i]; + Glyph glyph; + + if (FontEngine.TryGetGlyphWithIndexValue(glyphIndex, glyphLoadFlags, out glyph)) + { + if (glyph.glyphRect.width > 0 && glyph.glyphRect.height > 0) + { + m_GlyphsToPack.Add(glyph); + } + else + { + m_GlyphsPacked.Add(glyph); + } + } + } + + FontEngine.TryPackGlyphsInAtlas(m_GlyphsToPack, m_GlyphsPacked, m_Padding, (GlyphPackingMode)m_PackingMode, m_GlyphRenderMode, m_AtlasWidth, m_AtlasHeight, m_FreeGlyphRects, m_UsedGlyphRects); + + if (m_IsGenerationCancelled) + { + DestroyImmediate(m_FontAtlasTexture); + m_FontAtlasTexture = null; + return; + } + //Debug.Log("Glyphs remaining to add [" + m_GlyphsToAdd.Count + "]. Glyphs added [" + m_GlyphsAdded.Count + "]."); + } + + } + else + { + int packingModifier = ((GlyphRasterModes)m_GlyphRenderMode & GlyphRasterModes.RASTER_MODE_BITMAP) == GlyphRasterModes.RASTER_MODE_BITMAP ? 0 : 1; + + FontEngine.SetFaceSize(m_PointSize); + + m_Padding = (int)(m_PaddingMode == PaddingMode.Percentage ? m_PointSize * m_PaddingFieldValue / 100 : m_PaddingFieldValue); + + m_GlyphsToPack.Clear(); + m_GlyphsPacked.Clear(); + + m_FreeGlyphRects.Clear(); + m_FreeGlyphRects.Add(new GlyphRect(0, 0, m_AtlasWidth - packingModifier, m_AtlasHeight - packingModifier)); + m_UsedGlyphRects.Clear(); + } + + //Stop StopWatch + m_StopWatch.Stop(); + m_GlyphPackingGenerationTime = m_StopWatch.Elapsed.TotalMilliseconds; + m_IsGlyphPackingDone = true; + m_StopWatch.Reset(); + + m_FontCharacterTable.Clear(); + m_FontGlyphTable.Clear(); + m_GlyphsToRender.Clear(); + + // Handle Results and potential cancellation of glyph rendering + if (m_GlyphRenderMode == GlyphRenderMode.SDF32 && m_PointSize > 512 || m_GlyphRenderMode == GlyphRenderMode.SDF16 && m_PointSize > 1024 || m_GlyphRenderMode == GlyphRenderMode.SDF8 && m_PointSize > 2048) + { + int upSampling = 1; + switch (m_GlyphRenderMode) + { + case GlyphRenderMode.SDF8: + upSampling = 8; + break; + case GlyphRenderMode.SDF16: + upSampling = 16; + break; + case GlyphRenderMode.SDF32: + upSampling = 32; + break; + } + + Debug.Log("Glyph rendering has been aborted due to sampling point size of [" + m_PointSize + "] x SDF [" + upSampling + "] up sampling exceeds 16,384 point size. Please revise your generation settings to make sure the sampling point size x SDF up sampling mode does not exceed 16,384."); + + m_IsRenderingDone = true; + m_AtlasGenerationProgress = 0; + m_IsGenerationCancelled = true; + } + + // Add glyphs and characters successfully added to texture to their respective font tables. + foreach (Glyph glyph in m_GlyphsPacked) + { + uint glyphIndex = glyph.index; + + m_FontGlyphTable.Add(glyph); + + // Add glyphs to list of glyphs that need to be rendered. + if (glyph.glyphRect.width > 0 && glyph.glyphRect.height > 0) + m_GlyphsToRender.Add(glyph); + + foreach (uint unicode in m_GlyphLookupMap[glyphIndex]) + { + // Create new Character + m_FontCharacterTable.Add(new TMP_Character(unicode, glyph)); + } + } + + // + foreach (Glyph glyph in m_GlyphsToPack) + { + foreach (uint unicode in m_GlyphLookupMap[glyph.index]) + { + m_ExcludedCharacters.Add(unicode); + } + } + + // Get the face info for the current sampling point size. + m_FaceInfo = FontEngine.GetFaceInfo(); + + autoEvent.Set(); + }); + + // Worker thread to render glyphs in texture buffer. + ThreadPool.QueueUserWorkItem(RenderGlyphs => + { + autoEvent.WaitOne(); + + if (m_IsGenerationCancelled == false) + { + // Start Stop Watch + m_StopWatch = System.Diagnostics.Stopwatch.StartNew(); + + m_IsRenderingDone = false; + + // Allocate texture data + #if TEXTCORE_FONT_ENGINE_1_5_OR_NEWER + if (m_GlyphRenderMode == GlyphRenderMode.COLOR || m_GlyphRenderMode == GlyphRenderMode.COLOR_HINTED) + m_AtlasTextureBuffer = new byte[m_AtlasWidth * m_AtlasHeight * 4]; + else + m_AtlasTextureBuffer = new byte[m_AtlasWidth * m_AtlasHeight]; + #else + m_AtlasTextureBuffer = new byte[m_AtlasWidth * m_AtlasHeight]; + #endif + + m_AtlasGenerationProgressLabel = "Rendering glyphs..."; + + // Render and add glyphs to the given atlas texture. + if (m_GlyphsToRender.Count > 0) + { + FontEngine.RenderGlyphsToTexture(m_GlyphsToRender, m_Padding, m_GlyphRenderMode, m_AtlasTextureBuffer, m_AtlasWidth, m_AtlasHeight); + } + + m_IsRenderingDone = true; + + // Stop StopWatch + m_StopWatch.Stop(); + m_GlyphRenderingGenerationTime = m_StopWatch.Elapsed.TotalMilliseconds; + m_IsGlyphRenderingDone = true; + m_StopWatch.Reset(); + } + }); + } + + SaveCreationSettingsToEditorPrefs(SaveFontCreationSettings()); + } + } + + // FONT RENDERING PROGRESS BAR + GUILayout.Space(1); + Rect progressRect = EditorGUILayout.GetControlRect(false, 20); + + GUI.enabled = true; + progressRect.width -= 22; + EditorGUI.ProgressBar(progressRect, Mathf.Max(0.01f, m_AtlasGenerationProgress), m_AtlasGenerationProgressLabel); + progressRect.x = progressRect.x + progressRect.width + 2; + progressRect.y -= 1; + progressRect.width = 20; + progressRect.height = 20; + + GUI.enabled = m_IsProcessing; + if (GUI.Button(progressRect, "X")) + { + FontEngine.SendCancellationRequest(); + m_AtlasGenerationProgress = 0; + m_IsProcessing = false; + m_IsGenerationCancelled = true; + } + GUILayout.Space(5); + + // FONT STATUS & INFORMATION + GUI.enabled = true; + + GUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.Height(200)); + m_OutputScrollPosition = EditorGUILayout.BeginScrollView(m_OutputScrollPosition); + EditorGUILayout.LabelField(m_OutputFeedback, TMP_UIStyleManager.label); + EditorGUILayout.EndScrollView(); + GUILayout.EndVertical(); + + // SAVE TEXTURE & CREATE and SAVE FONT XML FILE + GUI.enabled = m_FontAtlasTexture != null && !m_IsProcessing; // Enable Save Button if font_Atlas is not Null. + + EditorGUILayout.BeginHorizontal(); + + if (GUILayout.Button("Save") && GUI.enabled) + { + if (m_SelectedFontAsset == null) + { + if (m_LegacyFontAsset != null) + SaveNewFontAssetWithSameName(m_LegacyFontAsset); + else + SaveNewFontAsset(m_SourceFont); + } + else + { + // Save over exiting Font Asset + string filePath = Path.GetFullPath(AssetDatabase.GetAssetPath(m_SelectedFontAsset)).Replace('\\', '/'); + + if (((GlyphRasterModes)m_GlyphRenderMode & GlyphRasterModes.RASTER_MODE_BITMAP) == GlyphRasterModes.RASTER_MODE_BITMAP) + Save_Bitmap_FontAsset(filePath); + else + Save_SDF_FontAsset(filePath); + } + } + if (GUILayout.Button("Save as...") && GUI.enabled) + { + if (m_SelectedFontAsset == null) + { + SaveNewFontAsset(m_SourceFont); + } + else + { + SaveNewFontAssetWithSameName(m_SelectedFontAsset); + } + } + + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.Space(); + + EditorGUILayout.EndVertical(); + + GUI.enabled = true; // Re-enable GUI + + if (position.height > position.width || position.width < k_TwoColumnControlsWidth) + DrawPreview(); + + EditorGUILayout.EndScrollView(); + + if (m_IsFontAtlasInvalid) + ClearGeneratedData(); + } + + + /// + /// Clear the previously generated data. + /// + void ClearGeneratedData() + { + m_IsFontAtlasInvalid = false; + + if (m_FontAtlasTexture != null && !EditorUtility.IsPersistent(m_FontAtlasTexture)) + { + DestroyImmediate(m_FontAtlasTexture); + m_FontAtlasTexture = null; + } + + if (m_GlyphRectPreviewTexture != null) + { + DestroyImmediate(m_GlyphRectPreviewTexture); + m_GlyphRectPreviewTexture = null; + } + + m_AtlasGenerationProgressLabel = string.Empty; + m_AtlasGenerationProgress = 0; + m_SavedFontAtlas = null; + + m_OutputFeedback = string.Empty; + m_WarningMessage = string.Empty; + } + + /// + /// + /// + /// + string[] GetFontFaces() + { + if (FontEngine.LoadFontFace(m_SourceFont, 0, 0) != FontEngineError.Success) + return Array.Empty(); + return FontEngine.GetFontFaces(); + } + + + /// + /// Function to update the feedback window showing the results of the latest generation. + /// + void UpdateRenderFeedbackWindow() + { + m_PointSize = (int)m_FaceInfo.pointSize; + + string missingGlyphReport = string.Empty; + + //string colorTag = m_FontCharacterTable.Count == m_CharacterCount ? "" : ""; + string colorTag2 = ""; + + missingGlyphReport = "Font: " + colorTag2 + m_FaceInfo.familyName + " Style: " + colorTag2 + m_FaceInfo.styleName + ""; + + missingGlyphReport += "\nPoint Size: " + colorTag2 + m_FaceInfo.pointSize + " Padding: " + colorTag2 + m_Padding + " SP/PD Ratio: " + colorTag2 + ((float)m_Padding / m_FaceInfo.pointSize).ToString("0.0%" + ""); + + missingGlyphReport += "\n\nCharacters included: " + m_FontCharacterTable.Count + "/" + m_CharacterCount + ""; + missingGlyphReport += "\nMissing characters: " + m_MissingCharacters.Count + ""; + missingGlyphReport += "\nExcluded characters: " + m_ExcludedCharacters.Count + ""; + + // Report characters missing from font file + missingGlyphReport += "\n\nCharacters missing from font file:"; + missingGlyphReport += "\n----------------------------------------"; + + m_OutputFeedback = missingGlyphReport; + + for (int i = 0; i < m_MissingCharacters.Count; i++) + { + missingGlyphReport += "\nID: " + m_MissingCharacters[i] + "\tHex: " + m_MissingCharacters[i].ToString("X") + "\tChar [" + (char)m_MissingCharacters[i] + "]"; + + if (missingGlyphReport.Length < 16300) + m_OutputFeedback = missingGlyphReport; + } + + // Report characters that did not fit in the atlas texture + missingGlyphReport += "\n\nCharacters excluded from packing:"; + missingGlyphReport += "\n----------------------------------------"; + + for (int i = 0; i < m_ExcludedCharacters.Count; i++) + { + missingGlyphReport += "\nID: " + m_ExcludedCharacters[i] + "\tHex: " + m_ExcludedCharacters[i].ToString("X") + "\tChar [" + (char)m_ExcludedCharacters[i] + "]"; + + if (missingGlyphReport.Length < 16300) + m_OutputFeedback = missingGlyphReport; + } + + if (missingGlyphReport.Length > 16300) + m_OutputFeedback += "\n\nReport truncated.\nSee \"TextMesh Pro\\Glyph Report.txt\""; + + // Save Missing Glyph Report file + if (Directory.Exists("Assets/TextMesh Pro")) + { + missingGlyphReport = System.Text.RegularExpressions.Regex.Replace(missingGlyphReport, @"<[^>]*>", string.Empty); + File.WriteAllText("Assets/TextMesh Pro/Glyph Report.txt", missingGlyphReport); + AssetDatabase.Refresh(); + } + } + + void DrawGlyphRectPreviewTexture() + { + if (m_GlyphRectPreviewTexture != null) + DestroyImmediate(m_GlyphRectPreviewTexture); + + m_GlyphRectPreviewTexture = new Texture2D(m_AtlasWidth, m_AtlasHeight, TextureFormat.RGBA32, false, true); + + FontEngine.ResetAtlasTexture(m_GlyphRectPreviewTexture); + + foreach (Glyph glyph in m_GlyphsPacked) + { + GlyphRect glyphRect = glyph.glyphRect; + + Color c = UnityEngine.Random.ColorHSV(0f, 1f, 0.5f, 0.5f, 1.0f, 1.0f); + + int x0 = glyphRect.x; + int x1 = x0 + glyphRect.width; + + int y0 = glyphRect.y; + int y1 = y0 + glyphRect.height; + + // Draw glyph rectangle. + for (int x = x0; x < x1; x++) + { + for (int y = y0; y < y1; y++) + m_GlyphRectPreviewTexture.SetPixel(x, y, c); + } + } + + m_GlyphRectPreviewTexture.Apply(false); + } + + void CreateFontAtlasTexture() + { + if (m_FontAtlasTexture != null) + DestroyImmediate(m_FontAtlasTexture); + + Color32[] colors = new Color32[m_AtlasWidth * m_AtlasHeight]; + + #if TEXTCORE_FONT_ENGINE_1_5_OR_NEWER + switch (m_GlyphRenderMode) + { + case GlyphRenderMode.COLOR: + case GlyphRenderMode.COLOR_HINTED: + m_FontAtlasTexture = new Texture2D(m_AtlasWidth, m_AtlasHeight, TextureFormat.RGBA32, false, true); + + for (int i = 0; i < colors.Length; i++) + { + int readIndex = i * 4; + byte r = m_AtlasTextureBuffer[readIndex + 0]; + byte g = m_AtlasTextureBuffer[readIndex + 1]; + byte b = m_AtlasTextureBuffer[readIndex + 2]; + byte a = m_AtlasTextureBuffer[readIndex + 3]; + colors[i] = new Color32(r, g, b, a); + } + break; + default: + m_FontAtlasTexture = new Texture2D(m_AtlasWidth, m_AtlasHeight, TextureFormat.Alpha8, false, true); + + for (int i = 0; i < colors.Length; i++) + { + byte c = m_AtlasTextureBuffer[i]; + colors[i] = new Color32(c, c, c, c); + } + break; + } + #else + m_FontAtlasTexture = new Texture2D(m_AtlasWidth, m_AtlasHeight, TextureFormat.Alpha8, false, true); + + for (int i = 0; i < colors.Length; i++) + { + byte c = m_AtlasTextureBuffer[i]; + colors[i] = new Color32(c, c, c, c); + } + #endif + + // Clear allocation of + m_AtlasTextureBuffer = null; + + if ((m_GlyphRenderMode & GlyphRenderMode.RASTER) == GlyphRenderMode.RASTER || (m_GlyphRenderMode & GlyphRenderMode.RASTER_HINTED) == GlyphRenderMode.RASTER_HINTED) + m_FontAtlasTexture.filterMode = FilterMode.Point; + + m_FontAtlasTexture.SetPixels32(colors, 0); + m_FontAtlasTexture.Apply(false, false); + + // Saving File for Debug + //var pngData = m_FontAtlasTexture.EncodeToPNG(); + //File.WriteAllBytes("Assets/Textures/Debug Font Texture.png", pngData); + } + + + /// + /// Open Save Dialog to provide the option save the font asset using the name of the source font file. This also appends SDF to the name if using any of the SDF Font Asset creation modes. + /// + /// + void SaveNewFontAsset(Object sourceObject) + { + string filePath; + + // Save new Font Asset and open save file requester at Source Font File location. + string saveDirectory = new FileInfo(AssetDatabase.GetAssetPath(sourceObject)).DirectoryName; + + if (((GlyphRasterModes)m_GlyphRenderMode & GlyphRasterModes.RASTER_MODE_BITMAP) == GlyphRasterModes.RASTER_MODE_BITMAP) + { + filePath = EditorUtility.SaveFilePanel("Save TextMesh Pro! Font Asset File", saveDirectory, sourceObject.name, "asset"); + + if (filePath.Length == 0) + return; + + Save_Bitmap_FontAsset(filePath); + } + else + { + filePath = EditorUtility.SaveFilePanel("Save TextMesh Pro! Font Asset File", saveDirectory, sourceObject.name + " SDF", "asset"); + + if (filePath.Length == 0) + return; + + Save_SDF_FontAsset(filePath); + } + } + + + /// + /// Open Save Dialog to provide the option to save the font asset under the same name. + /// + /// + void SaveNewFontAssetWithSameName(Object sourceObject) + { + string filePath; + + // Save new Font Asset and open save file requester at Source Font File location. + string saveDirectory = new FileInfo(AssetDatabase.GetAssetPath(sourceObject)).DirectoryName; + + filePath = EditorUtility.SaveFilePanel("Save TextMesh Pro! Font Asset File", saveDirectory, sourceObject.name, "asset"); + + if (filePath.Length == 0) + return; + + if (((GlyphRasterModes)m_GlyphRenderMode & GlyphRasterModes.RASTER_MODE_BITMAP) == GlyphRasterModes.RASTER_MODE_BITMAP) + { + Save_Bitmap_FontAsset(filePath); + } + else + { + Save_SDF_FontAsset(filePath); + } + } + + + void Save_Bitmap_FontAsset(string filePath) + { + filePath = filePath.Substring(0, filePath.Length - 6); // Trim file extension from filePath. + + string dataPath = Application.dataPath; + + string relativeAssetPath = filePath.Substring(dataPath.Length - 6); + string tex_DirName = Path.GetDirectoryName(relativeAssetPath); + string tex_FileName = Path.GetFileNameWithoutExtension(relativeAssetPath); + string tex_Path_NoExt = tex_DirName + "/" + tex_FileName; + + // Check if TextMeshPro font asset already exists. If not, create a new one. Otherwise update the existing one. + TMP_FontAsset fontAsset = AssetDatabase.LoadAssetAtPath(tex_Path_NoExt + ".asset", typeof(TMP_FontAsset)) as TMP_FontAsset; + if (fontAsset == null) + { + //Debug.Log("Creating TextMeshPro font asset!"); + fontAsset = ScriptableObject.CreateInstance(); // Create new TextMeshPro Font Asset. + AssetDatabase.CreateAsset(fontAsset, tex_Path_NoExt + ".asset"); + + // Set version number of font asset + fontAsset.version = "1.1.0"; + + //Set Font Asset Type + fontAsset.atlasRenderMode = m_GlyphRenderMode; + + // Reference to the source font file GUID. + fontAsset.m_SourceFontFile_EditorRef = m_SourceFont; + fontAsset.m_SourceFontFileGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_SourceFont)); + + // Add FaceInfo to Font Asset + fontAsset.faceInfo = m_FaceInfo; + + // Add GlyphInfo[] to Font Asset + fontAsset.glyphTable = m_FontGlyphTable; + + // Add CharacterTable[] to font asset. + fontAsset.characterTable = m_FontCharacterTable; + + // Sort glyph and character tables. + fontAsset.SortAllTables(); + + // Get and Add Kerning Pairs to Font Asset + if (m_IncludeFontFeatures) + fontAsset.fontFeatureTable = GetAllFontFeatures(); + + + // Add Font Atlas as Sub-Asset + fontAsset.atlasTextures = new Texture2D[] { m_FontAtlasTexture }; + m_FontAtlasTexture.name = tex_FileName + " Atlas"; + fontAsset.atlasWidth = m_AtlasWidth; + fontAsset.atlasHeight = m_AtlasHeight; + fontAsset.atlasPadding = m_Padding; + + AssetDatabase.AddObjectToAsset(m_FontAtlasTexture, fontAsset); + + // Create new Material and Add it as Sub-Asset + Shader default_Shader = Shader.Find("TextMeshPro/Bitmap"); + Material tmp_material = new Material(default_Shader); + tmp_material.name = tex_FileName + " Material"; + tmp_material.SetTexture(ShaderUtilities.ID_MainTex, m_FontAtlasTexture); + fontAsset.material = tmp_material; + + AssetDatabase.AddObjectToAsset(tmp_material, fontAsset); + + } + else + { + // Find all Materials referencing this font atlas. + Material[] material_references = TMP_EditorUtility.FindMaterialReferences(fontAsset); + + // Set version number of font asset + fontAsset.version = "1.1.0"; + + // Special handling to remove legacy font asset data + if (fontAsset.m_glyphInfoList != null && fontAsset.m_glyphInfoList.Count > 0) + fontAsset.m_glyphInfoList = null; + + //Set Font Asset Type + fontAsset.atlasRenderMode = m_GlyphRenderMode; + + // Add FaceInfo to Font Asset + fontAsset.faceInfo = m_FaceInfo; + + // Add GlyphInfo[] to Font Asset + fontAsset.glyphTable = m_FontGlyphTable; + + // Add CharacterTable[] to font asset. + fontAsset.characterTable = m_FontCharacterTable; + + // Sort glyph and character tables. + fontAsset.SortAllTables(); + + // Get and Add Kerning Pairs to Font Asset + if (m_IncludeFontFeatures) + fontAsset.fontFeatureTable = GetAllFontFeatures(); + + // Destroy Assets that will be replaced. + if (fontAsset.atlasTextures != null && fontAsset.atlasTextures.Length > 0) + { + for (int i = 1; i < fontAsset.atlasTextures.Length; i++) + DestroyImmediate(fontAsset.atlasTextures[i], true); + } + + fontAsset.m_AtlasTextureIndex = 0; + fontAsset.atlasWidth = m_AtlasWidth; + fontAsset.atlasHeight = m_AtlasHeight; + fontAsset.atlasPadding = m_Padding; + + // Make sure remaining atlas texture is of the correct size + Texture2D tex = fontAsset.atlasTextures[0]; + tex.name = tex_FileName + " Atlas"; + + // Make texture readable to allow resizing + bool isReadableState = tex.isReadable; + if (isReadableState == false) + FontEngineEditorUtilities.SetAtlasTextureIsReadable(tex, true); + + if (tex.width != m_AtlasWidth || tex.height != m_AtlasHeight) + { + #if UNITY_2021_2_OR_NEWER + tex.Reinitialize(m_AtlasWidth, m_AtlasHeight); + #else + tex.Resize(m_AtlasWidth, m_AtlasHeight); + #endif + + tex.Apply(false); + } + + // Copy new texture data to existing texture + Graphics.CopyTexture(m_FontAtlasTexture, tex); + + // Apply changes to the texture. + tex.Apply(false); + + // Special handling due to a bug in earlier versions of Unity. + m_FontAtlasTexture.hideFlags = HideFlags.None; + fontAsset.material.hideFlags = HideFlags.None; + + // Update the Texture reference on the Material + //for (int i = 0; i < material_references.Length; i++) + //{ + // material_references[i].SetFloat(ShaderUtilities.ID_TextureWidth, tex.width); + // material_references[i].SetFloat(ShaderUtilities.ID_TextureHeight, tex.height); + + // int spread = m_Padding; + // material_references[i].SetFloat(ShaderUtilities.ID_GradientScale, spread); + + // material_references[i].SetFloat(ShaderUtilities.ID_WeightNormal, fontAsset.normalStyle); + // material_references[i].SetFloat(ShaderUtilities.ID_WeightBold, fontAsset.boldStyle); + //} + } + + // Set texture to non readable + if (fontAsset.atlasPopulationMode == AtlasPopulationMode.Static) + FontEngineEditorUtilities.SetAtlasTextureIsReadable(fontAsset.atlasTexture, false); + + // Add list of GlyphRects to font asset. + fontAsset.freeGlyphRects = m_FreeGlyphRects; + fontAsset.usedGlyphRects = m_UsedGlyphRects; + + // Save Font Asset creation settings + m_SelectedFontAsset = fontAsset; + m_LegacyFontAsset = null; + fontAsset.creationSettings = SaveFontCreationSettings(); + + AssetDatabase.SaveAssets(); + + AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(fontAsset)); // Re-import font asset to get the new updated version. + + //EditorUtility.SetDirty(font_asset); + fontAsset.ReadFontAssetDefinition(); + + AssetDatabase.Refresh(); + + m_FontAtlasTexture = null; + + // NEED TO GENERATE AN EVENT TO FORCE A REDRAW OF ANY TEXTMESHPRO INSTANCES THAT MIGHT BE USING THIS FONT ASSET + TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(true, fontAsset); + } + + + void Save_SDF_FontAsset(string filePath) + { + filePath = filePath.Substring(0, filePath.Length - 6); // Trim file extension from filePath. + + string dataPath = Application.dataPath; + + string relativeAssetPath = filePath.Substring(dataPath.Length - 6); + string tex_DirName = Path.GetDirectoryName(relativeAssetPath); + string tex_FileName = Path.GetFileNameWithoutExtension(relativeAssetPath); + string tex_Path_NoExt = tex_DirName + "/" + tex_FileName; + + + // Check if TextMeshPro font asset already exists. If not, create a new one. Otherwise update the existing one. + TMP_FontAsset fontAsset = AssetDatabase.LoadAssetAtPath(tex_Path_NoExt + ".asset"); + if (fontAsset == null) + { + //Debug.Log("Creating TextMeshPro font asset!"); + fontAsset = ScriptableObject.CreateInstance(); // Create new TextMeshPro Font Asset. + AssetDatabase.CreateAsset(fontAsset, tex_Path_NoExt + ".asset"); + + // Set version number of font asset + fontAsset.version = "1.1.0"; + + // Reference to source font file GUID. + fontAsset.m_SourceFontFile_EditorRef = m_SourceFont; + fontAsset.m_SourceFontFileGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_SourceFont)); + + //Set Font Asset Type + fontAsset.atlasRenderMode = m_GlyphRenderMode; + + // Add FaceInfo to Font Asset + fontAsset.faceInfo = m_FaceInfo; + + // Add GlyphInfo[] to Font Asset + fontAsset.glyphTable = m_FontGlyphTable; + + // Add CharacterTable[] to font asset. + fontAsset.characterTable = m_FontCharacterTable; + + // Sort glyph and character tables. + fontAsset.SortAllTables(); + + // Get and Add Kerning Pairs to Font Asset + if (m_IncludeFontFeatures) + fontAsset.fontFeatureTable = GetAllFontFeatures(); + + // Add Font Atlas as Sub-Asset + fontAsset.atlasTextures = new Texture2D[] { m_FontAtlasTexture }; + m_FontAtlasTexture.name = tex_FileName + " Atlas"; + fontAsset.atlasWidth = m_AtlasWidth; + fontAsset.atlasHeight = m_AtlasHeight; + fontAsset.atlasPadding = m_Padding; + + AssetDatabase.AddObjectToAsset(m_FontAtlasTexture, fontAsset); + + // Create new Material and Add it as Sub-Asset + Shader default_Shader = Shader.Find("TextMeshPro/Distance Field"); + Material tmp_material = new Material(default_Shader); + + tmp_material.name = tex_FileName + " Material"; + tmp_material.SetTexture(ShaderUtilities.ID_MainTex, m_FontAtlasTexture); + tmp_material.SetFloat(ShaderUtilities.ID_TextureWidth, m_FontAtlasTexture.width); + tmp_material.SetFloat(ShaderUtilities.ID_TextureHeight, m_FontAtlasTexture.height); + + int spread = m_Padding + 1; + tmp_material.SetFloat(ShaderUtilities.ID_GradientScale, spread); // Spread = Padding for Brute Force SDF. + + tmp_material.SetFloat(ShaderUtilities.ID_WeightNormal, fontAsset.normalStyle); + tmp_material.SetFloat(ShaderUtilities.ID_WeightBold, fontAsset.boldStyle); + + fontAsset.material = tmp_material; + + AssetDatabase.AddObjectToAsset(tmp_material, fontAsset); + } + else + { + // Find all Materials referencing this font atlas. + Material[] material_references = TMP_EditorUtility.FindMaterialReferences(fontAsset); + + // Set version number of font asset + fontAsset.version = "1.1.0"; + + // Special handling to remove legacy font asset data + if (fontAsset.m_glyphInfoList != null && fontAsset.m_glyphInfoList.Count > 0) + fontAsset.m_glyphInfoList = null; + + //Set Font Asset Type + fontAsset.atlasRenderMode = m_GlyphRenderMode; + + // Add FaceInfo to Font Asset + fontAsset.faceInfo = m_FaceInfo; + + // Add GlyphInfo[] to Font Asset + fontAsset.glyphTable = m_FontGlyphTable; + + // Add CharacterTable[] to font asset. + fontAsset.characterTable = m_FontCharacterTable; + + // Sort glyph and character tables. + fontAsset.SortAllTables(); + + // Get and Add Kerning Pairs to Font Asset + // TODO: Check and preserve existing adjustment pairs. + if (m_IncludeFontFeatures) + fontAsset.fontFeatureTable = GetAllFontFeatures(); + + // Destroy Assets that will be replaced. + if (fontAsset.atlasTextures != null && fontAsset.atlasTextures.Length > 0) + { + for (int i = 1; i < fontAsset.atlasTextures.Length; i++) + DestroyImmediate(fontAsset.atlasTextures[i], true); + } + + fontAsset.m_AtlasTextureIndex = 0; + fontAsset.atlasWidth = m_AtlasWidth; + fontAsset.atlasHeight = m_AtlasHeight; + fontAsset.atlasPadding = m_Padding; + + // Make sure remaining atlas texture is of the correct size + Texture2D tex = fontAsset.atlasTextures[0]; + tex.name = tex_FileName + " Atlas"; + + // Make texture readable to allow resizing + bool isReadableState = tex.isReadable; + if (isReadableState == false) + FontEngineEditorUtilities.SetAtlasTextureIsReadable(tex, true); + + if (tex.width != m_AtlasWidth || tex.height != m_AtlasHeight) + { + #if UNITY_2021_2_OR_NEWER + tex.Reinitialize(m_AtlasWidth, m_AtlasHeight); + #else + tex.Resize(m_AtlasWidth, m_AtlasHeight); + #endif + + tex.Apply(false); + } + + // Copy new texture data to existing texture + Graphics.CopyTexture(m_FontAtlasTexture, tex); + + // Apply changes to the texture. + tex.Apply(false); + + // Special handling due to a bug in earlier versions of Unity. + m_FontAtlasTexture.hideFlags = HideFlags.None; + fontAsset.material.hideFlags = HideFlags.None; + + // Update the Texture reference on the Material + for (int i = 0; i < material_references.Length; i++) + { + material_references[i].SetFloat(ShaderUtilities.ID_TextureWidth, tex.width); + material_references[i].SetFloat(ShaderUtilities.ID_TextureHeight, tex.height); + + int spread = m_Padding + 1; + material_references[i].SetFloat(ShaderUtilities.ID_GradientScale, spread); + + material_references[i].SetFloat(ShaderUtilities.ID_WeightNormal, fontAsset.normalStyle); + material_references[i].SetFloat(ShaderUtilities.ID_WeightBold, fontAsset.boldStyle); + } + } + + // Saving File for Debug + //var pngData = destination_Atlas.EncodeToPNG(); + //File.WriteAllBytes("Assets/Textures/Debug Distance Field.png", pngData); + + // Set texture to non readable + if (fontAsset.atlasPopulationMode == AtlasPopulationMode.Static) + FontEngineEditorUtilities.SetAtlasTextureIsReadable(fontAsset.atlasTexture, false); + + // Add list of GlyphRects to font asset. + fontAsset.freeGlyphRects = m_FreeGlyphRects; + fontAsset.usedGlyphRects = m_UsedGlyphRects; + + // Save Font Asset creation settings + m_SelectedFontAsset = fontAsset; + m_LegacyFontAsset = null; + fontAsset.creationSettings = SaveFontCreationSettings(); + + AssetDatabase.SaveAssets(); + + AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(fontAsset)); // Re-import font asset to get the new updated version. + + fontAsset.ReadFontAssetDefinition(); + + AssetDatabase.Refresh(); + + m_FontAtlasTexture = null; + + // NEED TO GENERATE AN EVENT TO FORCE A REDRAW OF ANY TEXTMESHPRO INSTANCES THAT MIGHT BE USING THIS FONT ASSET + TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(true, fontAsset); + } + + + /// + /// Internal method to save the Font Asset Creation Settings + /// + /// + FontAssetCreationSettings SaveFontCreationSettings() + { + FontAssetCreationSettings settings = new FontAssetCreationSettings(); + + //settings.sourceFontFileName = m_SourceFontFile.name; + settings.sourceFontFileGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_SourceFont)); + settings.faceIndex = m_SourceFontFaceIndex; + settings.pointSizeSamplingMode = m_PointSizeSamplingMode; + settings.pointSize = m_PointSize; + settings.padding = m_Padding; + settings.paddingMode = (int)m_PaddingMode; + settings.packingMode = (int)m_PackingMode; + settings.atlasWidth = m_AtlasWidth; + settings.atlasHeight = m_AtlasHeight; + settings.characterSetSelectionMode = m_CharacterSetSelectionMode; + settings.characterSequence = m_CharacterSequence; + settings.referencedFontAssetGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_ReferencedFontAsset)); + settings.referencedTextAssetGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_CharactersFromFile)); + settings.renderMode = (int)m_GlyphRenderMode; + settings.includeFontFeatures = m_IncludeFontFeatures; + + return settings; + } + + + /// + /// Internal method to load the Font Asset Creation Settings + /// + /// + void LoadFontCreationSettings(FontAssetCreationSettings settings) + { + m_SourceFont = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(settings.sourceFontFileGUID)); + m_SourceFontFaceIndex = settings.faceIndex; + m_SourceFontFaces = GetFontFaces(); + m_PointSizeSamplingMode = settings.pointSizeSamplingMode; + m_PointSize = settings.pointSize; + m_Padding = settings.padding; + m_PaddingMode = settings.paddingMode == 0 ? PaddingMode.Pixel : (PaddingMode)settings.paddingMode; + m_PaddingFieldValue = m_PaddingMode == PaddingMode.Percentage ? (float)m_Padding / m_PointSize * 100 : m_Padding; + m_PackingMode = (FontPackingModes)settings.packingMode; + m_AtlasWidth = settings.atlasWidth; + m_AtlasHeight = settings.atlasHeight; + m_CharacterSetSelectionMode = settings.characterSetSelectionMode; + m_CharacterSequence = settings.characterSequence; + m_ReferencedFontAsset = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(settings.referencedFontAssetGUID)); + m_CharactersFromFile = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(settings.referencedTextAssetGUID)); + m_GlyphRenderMode = (GlyphRenderMode)settings.renderMode; + m_IncludeFontFeatures = settings.includeFontFeatures; + } + + + /// + /// Save the latest font asset creation settings to EditorPrefs. + /// + /// + void SaveCreationSettingsToEditorPrefs(FontAssetCreationSettings settings) + { + // Create new list if one does not already exist + if (m_FontAssetCreationSettingsContainer == null) + { + m_FontAssetCreationSettingsContainer = new FontAssetCreationSettingsContainer(); + m_FontAssetCreationSettingsContainer.fontAssetCreationSettings = new List(); + } + + // Add new creation settings to the list + m_FontAssetCreationSettingsContainer.fontAssetCreationSettings.Add(settings); + + // Since list should only contain the most 4 recent settings, we remove the first element if list exceeds 4 elements. + if (m_FontAssetCreationSettingsContainer.fontAssetCreationSettings.Count > 4) + m_FontAssetCreationSettingsContainer.fontAssetCreationSettings.RemoveAt(0); + + m_FontAssetCreationSettingsCurrentIndex = m_FontAssetCreationSettingsContainer.fontAssetCreationSettings.Count - 1; + + // Serialize list to JSON + string serializedSettings = JsonUtility.ToJson(m_FontAssetCreationSettingsContainer, true); + + EditorPrefs.SetString(k_FontAssetCreationSettingsContainerKey, serializedSettings); + } + + + void DrawPreview() + { + Rect pixelRect; + + float ratioX = (position.width - k_TwoColumnControlsWidth) / m_AtlasWidth; + float ratioY = (position.height - 15) / m_AtlasHeight; + + if (position.width < position.height) + { + ratioX = (position.width - 15) / m_AtlasWidth; + ratioY = (position.height - 485) / m_AtlasHeight; + } + + if (ratioX < ratioY) + { + float width = m_AtlasWidth * ratioX; + float height = m_AtlasHeight * ratioX; + EditorGUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.MaxWidth(width), GUILayout.MaxHeight(height)); + + pixelRect = GUILayoutUtility.GetRect(width - 5, height, GUILayout.ExpandHeight(false), GUILayout.ExpandWidth(false)); + } + else + { + float width = m_AtlasWidth * ratioY; + float height = m_AtlasHeight * ratioY; + EditorGUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.MaxWidth(width), GUILayout.MaxHeight(height)); + + pixelRect = GUILayoutUtility.GetRect(width - 5, height, GUILayout.ExpandHeight(false), GUILayout.ExpandWidth(false)); + } + + if (m_FontAtlasTexture != null) + { + if (m_FontAtlasTexture.format == TextureFormat.Alpha8) + EditorGUI.DrawTextureAlpha(pixelRect, m_FontAtlasTexture, ScaleMode.StretchToFill); + else + EditorGUI.DrawPreviewTexture(pixelRect, m_FontAtlasTexture, null, ScaleMode.StretchToFill); + + // Destroy GlyphRect preview texture + if (m_GlyphRectPreviewTexture != null) + { + DestroyImmediate(m_GlyphRectPreviewTexture); + m_GlyphRectPreviewTexture = null; + } + } + else if (m_GlyphRectPreviewTexture != null) + { + EditorGUI.DrawPreviewTexture(pixelRect, m_GlyphRectPreviewTexture, null, ScaleMode.StretchToFill); + } + else if (m_SavedFontAtlas != null) + { + EditorGUI.DrawTextureAlpha(pixelRect, m_SavedFontAtlas, ScaleMode.StretchToFill); + } + + EditorGUILayout.EndVertical(); + } + + + void CheckForLegacyGlyphRenderMode() + { + // Special handling for legacy glyph render mode + if ((int)m_GlyphRenderMode < 0x100) + { + switch ((int)m_GlyphRenderMode) + { + case 0: + m_GlyphRenderMode = GlyphRenderMode.SMOOTH_HINTED; + break; + case 1: + m_GlyphRenderMode = GlyphRenderMode.SMOOTH; + break; + case 2: + m_GlyphRenderMode = GlyphRenderMode.RASTER_HINTED; + break; + case 3: + m_GlyphRenderMode = GlyphRenderMode.RASTER; + break; + case 6: + case 7: + m_GlyphRenderMode = GlyphRenderMode.SDFAA; + break; + } + } + } + + + /// + /// + /// + /// + TMP_FontFeatureTable GetAllFontFeatures() + { + TMP_FontFeatureTable fontFeatureTable = new TMP_FontFeatureTable(); + + PopulateGlyphAdjustmentTable(fontFeatureTable); + + #if TEXTCORE_FONT_ENGINE_1_5_OR_NEWER + PopulateLigatureTable(fontFeatureTable); + + PopulateDiacriticalMarkAdjustmentTables(fontFeatureTable); + #endif + + return fontFeatureTable; + } + + #if TEXTCORE_FONT_ENGINE_1_5_OR_NEWER + void PopulateGlyphAdjustmentTable(TMP_FontFeatureTable fontFeatureTable) + { + GlyphPairAdjustmentRecord[] adjustmentRecords = FontEngine.GetPairAdjustmentRecords(m_AvailableGlyphsToAdd); + + if (adjustmentRecords == null) + return; + + float emScale = (float)m_FaceInfo.pointSize / m_FaceInfo.unitsPerEM; + + for (int i = 0; i < adjustmentRecords.Length && adjustmentRecords[i].firstAdjustmentRecord.glyphIndex != 0; i++) + { + GlyphPairAdjustmentRecord record = adjustmentRecords[i]; + + // Adjust values currently in Units per EM to make them relative to Sampling Point Size. + GlyphValueRecord valueRecord = record.firstAdjustmentRecord.glyphValueRecord; + valueRecord.xAdvance *= emScale; + + GlyphPairAdjustmentRecord newRecord = new GlyphPairAdjustmentRecord { firstAdjustmentRecord = new GlyphAdjustmentRecord { glyphIndex = record.firstAdjustmentRecord.glyphIndex, glyphValueRecord = valueRecord }, secondAdjustmentRecord = record.secondAdjustmentRecord }; + + fontFeatureTable.glyphPairAdjustmentRecords.Add(newRecord); + } + + fontFeatureTable.SortGlyphPairAdjustmentRecords(); + } + + void PopulateLigatureTable(TMP_FontFeatureTable fontFeatureTable) + { + UnityEngine.TextCore.LowLevel.LigatureSubstitutionRecord[] ligatureRecords = FontEngine.GetLigatureSubstitutionRecords(m_AvailableGlyphsToAdd); + if (ligatureRecords != null) + AddLigatureRecords(fontFeatureTable, ligatureRecords); + } + + void AddLigatureRecords(TMP_FontFeatureTable fontFeatureTable, UnityEngine.TextCore.LowLevel.LigatureSubstitutionRecord[] records) + { + for (int i = 0; i < records.Length; i++) + { + UnityEngine.TextCore.LowLevel.LigatureSubstitutionRecord record = records[i]; + + if (records[i].componentGlyphIDs == null || records[i].ligatureGlyphID == 0) + return; + + uint firstComponentGlyphIndex = record.componentGlyphIDs[0]; + + LigatureSubstitutionRecord newRecord = new LigatureSubstitutionRecord() { componentGlyphIDs = record.componentGlyphIDs, ligatureGlyphID = record.ligatureGlyphID }; + + // Add new record to lookup + if (!fontFeatureTable.m_LigatureSubstitutionRecordLookup.ContainsKey(firstComponentGlyphIndex)) + { + fontFeatureTable.m_LigatureSubstitutionRecordLookup.Add(firstComponentGlyphIndex, new List { newRecord }); + } + else + { + fontFeatureTable.m_LigatureSubstitutionRecordLookup[firstComponentGlyphIndex].Add(newRecord); + } + + fontFeatureTable.m_LigatureSubstitutionRecords.Add(newRecord); + } + } + + void PopulateDiacriticalMarkAdjustmentTables(TMP_FontFeatureTable fontFeatureTable) + { + UnityEngine.TextCore.LowLevel.MarkToBaseAdjustmentRecord[] markToBaseRecords = FontEngine.GetMarkToBaseAdjustmentRecords(m_AvailableGlyphsToAdd); + if (markToBaseRecords != null) + AddMarkToBaseAdjustmentRecords(fontFeatureTable, markToBaseRecords); + + UnityEngine.TextCore.LowLevel.MarkToMarkAdjustmentRecord[] markToMarkRecords = FontEngine.GetMarkToMarkAdjustmentRecords(m_AvailableGlyphsToAdd); + if (markToMarkRecords != null) + AddMarkToMarkAdjustmentRecords(fontFeatureTable, markToMarkRecords); + + } + + void AddMarkToBaseAdjustmentRecords(TMP_FontFeatureTable fontFeatureTable, UnityEngine.TextCore.LowLevel.MarkToBaseAdjustmentRecord[] records) + { + float emScale = (float)m_FaceInfo.pointSize / m_FaceInfo.unitsPerEM; + + for (int i = 0; i < records.Length; i++) + { + UnityEngine.TextCore.LowLevel.MarkToBaseAdjustmentRecord record = records[i]; + + uint key = record.markGlyphID << 16 | record.baseGlyphID; + + if (fontFeatureTable.m_MarkToBaseAdjustmentRecordLookup.ContainsKey(key)) + continue; + + MarkToBaseAdjustmentRecord newRecord = new MarkToBaseAdjustmentRecord { + baseGlyphID = record.baseGlyphID, + baseGlyphAnchorPoint = new GlyphAnchorPoint { xCoordinate = record.baseGlyphAnchorPoint.xCoordinate * emScale, yCoordinate = record.baseGlyphAnchorPoint.yCoordinate * emScale }, + markGlyphID = record.markGlyphID, + markPositionAdjustment = new MarkPositionAdjustment { xPositionAdjustment = record.markPositionAdjustment.xPositionAdjustment * emScale, yPositionAdjustment = record.markPositionAdjustment.yPositionAdjustment * emScale } }; + + fontFeatureTable.MarkToBaseAdjustmentRecords.Add(newRecord); + fontFeatureTable.m_MarkToBaseAdjustmentRecordLookup.Add(key, newRecord); + } + } + + void AddMarkToMarkAdjustmentRecords(TMP_FontFeatureTable fontFeatureTable, UnityEngine.TextCore.LowLevel.MarkToMarkAdjustmentRecord[] records) + { + float emScale = (float)m_FaceInfo.pointSize / m_FaceInfo.unitsPerEM; + + for (int i = 0; i < records.Length; i++) + { + UnityEngine.TextCore.LowLevel.MarkToMarkAdjustmentRecord record = records[i]; + + uint key = record.combiningMarkGlyphID << 16 | record.baseMarkGlyphID; + + if (fontFeatureTable.m_MarkToMarkAdjustmentRecordLookup.ContainsKey(key)) + continue; + + MarkToMarkAdjustmentRecord newRecord = new MarkToMarkAdjustmentRecord { + baseMarkGlyphID = record.baseMarkGlyphID, + baseMarkGlyphAnchorPoint = new GlyphAnchorPoint { xCoordinate = record.baseMarkGlyphAnchorPoint.xCoordinate * emScale, yCoordinate = record.baseMarkGlyphAnchorPoint.yCoordinate * emScale}, + combiningMarkGlyphID = record.combiningMarkGlyphID, + combiningMarkPositionAdjustment = new MarkPositionAdjustment { xPositionAdjustment = record.combiningMarkPositionAdjustment.xPositionAdjustment * emScale, yPositionAdjustment = record.combiningMarkPositionAdjustment.yPositionAdjustment * emScale } }; + + fontFeatureTable.MarkToMarkAdjustmentRecords.Add(newRecord); + fontFeatureTable.m_MarkToMarkAdjustmentRecordLookup.Add(key, newRecord); + } + } + #else + void PopulateGlyphAdjustmentTable(TMP_FontFeatureTable fontFeatureTable) + { + GlyphPairAdjustmentRecord[] adjustmentRecords = FontEngine.GetGlyphPairAdjustmentTable(m_AvailableGlyphsToAdd.ToArray()); + + if (adjustmentRecords == null) + return; + + for (int i = 0; i < adjustmentRecords.Length && adjustmentRecords[i].firstAdjustmentRecord.glyphIndex != 0; i++) + { + fontFeatureTable.glyphPairAdjustmentRecords.Add(adjustmentRecords[i]); + } + + fontFeatureTable.SortGlyphPairAdjustmentRecords(); + } + #endif + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMPro_FontAssetCreatorWindow.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMPro_FontAssetCreatorWindow.cs.meta new file mode 100644 index 00000000..4648857f --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMPro_FontAssetCreatorWindow.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 383966e89d344865a36addd5d378ffd3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMPro_SortingLayerHelper.cs b/Packages/com.unity.ugui/Editor/TMP/TMPro_SortingLayerHelper.cs new file mode 100644 index 00000000..8ef1b2be --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMPro_SortingLayerHelper.cs @@ -0,0 +1,58 @@ +using UnityEngine; + + +namespace TMPro +{ + // Helpers used by the different sorting layer classes. + public static class SortingLayerHelper + { + // Gets an array of sorting layer names. + public static string[] sortingLayerNames + { + get + { + return GetSortingLayerNames(); + } + } + + static string[] GetSortingLayerNames() + { + int layerCount = SortingLayer.layers.Length; + + string[] layerNames = new string[layerCount]; + + for (int i = 0; i < layerCount; i++) + { + layerNames[i] = SortingLayer.layers[i].name; + } + + return layerNames; + } + + internal static int GetSortingLayerIndexFromValue(int value) + { + int layerCount = SortingLayer.layers.Length; + + for (int i = 0; i < layerCount; i++) + { + if (value == SortingLayer.layers[i].value) + return i; + } + + return -1; + } + + internal static int GetSortingLayerIndexFromSortingLayerID(int id) + { + int layerCount = SortingLayer.layers.Length; + + for (int i = 0; i < layerCount; i++) + { + if (id == SortingLayer.layers[i].id) + return i; + } + + return -1; + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMPro_SortingLayerHelper.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMPro_SortingLayerHelper.cs.meta new file mode 100644 index 00000000..9d902b90 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMPro_SortingLayerHelper.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 88ed537c17c34f339121fe9a7d6d7a0e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMPro_TextContainerEditor.cs b/Packages/com.unity.ugui/Editor/TMP/TMPro_TextContainerEditor.cs new file mode 100644 index 00000000..09fc6173 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMPro_TextContainerEditor.cs @@ -0,0 +1,235 @@ +using UnityEngine; +using UnityEditor; +using System.Collections; + + +namespace TMPro.EditorUtilities +{ + [CustomEditor(typeof(TextContainer)), CanEditMultipleObjects] + public class TMPro_TextContainerEditor : Editor + { + + // Serialized Properties + private SerializedProperty anchorPosition_prop; + private SerializedProperty pivot_prop; + private SerializedProperty rectangle_prop; + private SerializedProperty margins_prop; + + + private TextContainer m_textContainer; + //private Transform m_transform; + //private Vector3[] m_Rect_handlePoints = new Vector3[4]; + //private Vector3[] m_Margin_handlePoints = new Vector3[4]; + + //private Vector2 m_anchorPosition; + + //private Vector3 m_mousePreviousPOS; + //private Vector2 m_previousStartPOS; + //private int m_mouseDragFlag = 0; + + //private static Transform m_visualHelper; + + + void OnEnable() + { + + // Serialized Properties + anchorPosition_prop = serializedObject.FindProperty("m_anchorPosition"); + pivot_prop = serializedObject.FindProperty("m_pivot"); + rectangle_prop = serializedObject.FindProperty("m_rect"); + margins_prop = serializedObject.FindProperty("m_margins"); + + m_textContainer = (TextContainer)target; + //m_transform = m_textContainer.transform; + + + /* + if (m_visualHelper == null) + { + m_visualHelper = GameObject.CreatePrimitive(PrimitiveType.Sphere).transform; + m_visualHelper.localScale = new Vector3(0.25f, 0.25f, 0.25f); + } + */ + } + + void OnDisable() + { + /* + if (m_visualHelper != null) + DestroyImmediate (m_visualHelper.gameObject); + */ + } + + + + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(anchorPosition_prop); + if (anchorPosition_prop.enumValueIndex == 9) + { + EditorGUI.indentLevel += 1; + EditorGUILayout.PropertyField(pivot_prop, new GUIContent("Pivot Position")); + EditorGUI.indentLevel -= 1; + } + + + DrawDimensionProperty(rectangle_prop, "Dimensions"); + DrawMaginProperty(margins_prop, "Margins"); + if (EditorGUI.EndChangeCheck()) + { + // Re-compute pivot position when changes are made. + if (anchorPosition_prop.enumValueIndex != 9) + pivot_prop.vector2Value = GetAnchorPosition(anchorPosition_prop.enumValueIndex); + + m_textContainer.hasChanged = true; + } + + serializedObject.ApplyModifiedProperties(); + + EditorGUILayout.Space(); + } + + + private void DrawDimensionProperty(SerializedProperty property, string label) + { + float old_LabelWidth = EditorGUIUtility.labelWidth; + float old_FieldWidth = EditorGUIUtility.fieldWidth; + + Rect rect = EditorGUILayout.GetControlRect(false, 18); + Rect pos0 = new Rect(rect.x, rect.y + 2, rect.width, 18); + + float width = rect.width + 3; + pos0.width = old_LabelWidth; + GUI.Label(pos0, label); + + Rect rectangle = property.rectValue; + + float width_B = width - old_LabelWidth; + float fieldWidth = width_B / 4; + pos0.width = fieldWidth - 5; + + pos0.x = old_LabelWidth + 15; + GUI.Label(pos0, "Width"); + + pos0.x += fieldWidth; + rectangle.width = EditorGUI.FloatField(pos0, GUIContent.none, rectangle.width); + + pos0.x += fieldWidth; + GUI.Label(pos0, "Height"); + + pos0.x += fieldWidth; + rectangle.height = EditorGUI.FloatField(pos0, GUIContent.none, rectangle.height); + + property.rectValue = rectangle; + EditorGUIUtility.labelWidth = old_LabelWidth; + EditorGUIUtility.fieldWidth = old_FieldWidth; + } + + + private void DrawMaginProperty(SerializedProperty property, string label) + { + float old_LabelWidth = EditorGUIUtility.labelWidth; + float old_FieldWidth = EditorGUIUtility.fieldWidth; + + Rect rect = EditorGUILayout.GetControlRect(false, 2 * 18); + Rect pos0 = new Rect(rect.x, rect.y + 2, rect.width, 18); + + float width = rect.width + 3; + pos0.width = old_LabelWidth; + GUI.Label(pos0, label); + + //Vector4 vec = property.vector4Value; + Vector4 vec = Vector4.zero; + vec.x = property.FindPropertyRelative("x").floatValue; + vec.y = property.FindPropertyRelative("y").floatValue; + vec.z = property.FindPropertyRelative("z").floatValue; + vec.w = property.FindPropertyRelative("w").floatValue; + + + float widthB = width - old_LabelWidth; + float fieldWidth = widthB / 4; + pos0.width = fieldWidth - 5; + + // Labels + pos0.x = old_LabelWidth + 15; + GUI.Label(pos0, "Left"); + + pos0.x += fieldWidth; + GUI.Label(pos0, "Top"); + + pos0.x += fieldWidth; + GUI.Label(pos0, "Right"); + + pos0.x += fieldWidth; + GUI.Label(pos0, "Bottom"); + + pos0.y += 18; + + pos0.x = old_LabelWidth + 15; + vec.x = EditorGUI.FloatField(pos0, GUIContent.none, vec.x); + + pos0.x += fieldWidth; + vec.y = EditorGUI.FloatField(pos0, GUIContent.none, vec.y); + + pos0.x += fieldWidth; + vec.z = EditorGUI.FloatField(pos0, GUIContent.none, vec.z); + + pos0.x += fieldWidth; + vec.w = EditorGUI.FloatField(pos0, GUIContent.none, vec.w); + + //property.vector4Value = vec; + property.FindPropertyRelative("x").floatValue = vec.x; + property.FindPropertyRelative("y").floatValue = vec.y; + property.FindPropertyRelative("z").floatValue = vec.z; + property.FindPropertyRelative("w").floatValue = vec.w; + + EditorGUIUtility.labelWidth = old_LabelWidth; + EditorGUIUtility.fieldWidth = old_FieldWidth; + } + + + Vector2 GetAnchorPosition(int index) + { + Vector2 anchorPosition = Vector2.zero; + + switch (index) + { + case 0: // TOP LEFT + anchorPosition = new Vector2(0, 1); + break; + case 1: // TOP + anchorPosition = new Vector2(0.5f, 1); + break; + case 2: // TOP RIGHT + anchorPosition = new Vector2(1, 1); + break; + case 3: // LEFT + anchorPosition = new Vector2(0, 0.5f); + break; + case 4: // MIDDLE + anchorPosition = new Vector2(0.5f, 0.5f); + break; + case 5: // RIGHT + anchorPosition = new Vector2(1, 0.5f); + break; + case 6: // BOTTOM LEFT + anchorPosition = new Vector2(0, 0); + break; + case 7: // BOTTOM + anchorPosition = new Vector2(0.5f, 0); + break; + case 8: // BOTTOM RIGHT + anchorPosition = new Vector2(1, 0); + break; + } + + return anchorPosition; + } + + + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMPro_TextContainerEditor.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMPro_TextContainerEditor.cs.meta new file mode 100644 index 00000000..bad78812 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMPro_TextContainerEditor.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 02893ffb522b490a9fa28eedd2584309 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/TMPro_TexturePostProcessor.cs b/Packages/com.unity.ugui/Editor/TMP/TMPro_TexturePostProcessor.cs new file mode 100644 index 00000000..1c6664cf --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMPro_TexturePostProcessor.cs @@ -0,0 +1,61 @@ +using System; +using UnityEngine; +using UnityEditor; + + +namespace TMPro.EditorUtilities +{ + /// + /// Asset post processor used to handle text assets changes. + /// This includes tracking of changes to textures used by sprite assets as well as font assets potentially getting updated outside of the Unity editor. + /// + internal class TMPro_TexturePostProcessor : AssetPostprocessor + { + private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) + { + // Only run post processor after the Editor has been fully loaded. + if (Time.frameCount == 0) + return; + + bool textureImported = false; + + foreach (var asset in importedAssets) + { + // Return if imported asset path is outside of the project. + if (asset.StartsWith("Assets/", StringComparison.OrdinalIgnoreCase) == false) + continue; + + Type assetType = AssetDatabase.GetMainAssetTypeAtPath(asset); + + if (assetType == typeof(TMP_FontAsset)) + { + TMP_FontAsset fontAsset = AssetDatabase.LoadAssetAtPath(asset, typeof(TMP_FontAsset)) as TMP_FontAsset; + + // Only refresh font asset definition if font asset was previously initialized. + if (fontAsset != null && fontAsset.m_CharacterLookupDictionary != null) + TMP_EditorResourceManager.RegisterFontAssetForDefinitionRefresh(fontAsset); + + continue; + } + + if (assetType == typeof(Texture2D)) + textureImported = true; + } + + // If textures were imported, issue callback to any potential text objects that might require updating. + if (textureImported) + TMPro_EventManager.ON_SPRITE_ASSET_PROPERTY_CHANGED(true, null); + } + } + + internal class TMP_FontAssetPostProcessor : UnityEditor.AssetModificationProcessor + { + static AssetDeleteResult OnWillDeleteAsset(string path, RemoveAssetOptions opt) + { + if (AssetDatabase.GetMainAssetTypeAtPath(path) == typeof(TMP_FontAsset)) + TMP_ResourceManager.RebuildFontAssetCache(); + + return AssetDeleteResult.DidNotDelete; + } + } +} diff --git a/Packages/com.unity.ugui/Editor/TMP/TMPro_TexturePostProcessor.cs.meta b/Packages/com.unity.ugui/Editor/TMP/TMPro_TexturePostProcessor.cs.meta new file mode 100644 index 00000000..fb00b80f --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/TMPro_TexturePostProcessor.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: f4935fb862d54980b1bcbca942962642 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/TMP/Unity.TextMeshPro.Editor.asmdef b/Packages/com.unity.ugui/Editor/TMP/Unity.TextMeshPro.Editor.asmdef new file mode 100644 index 00000000..9f2e2561 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/Unity.TextMeshPro.Editor.asmdef @@ -0,0 +1,42 @@ +{ + "name": "Unity.TextMeshPro.Editor", + "rootNamespace": "", + "references": [ + "Unity.TextMeshPro", + "Unity.RenderPipelines.HighDefinition.Editor", + "Unity.RenderPipelines.Core.Runtime", + "Unity.RenderPipelines.HighDefinition.Runtime" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [ + { + "name": "com.unity.textcore", + "expression": "1.0.0-preview.0", + "define": "TEXTCORE_1_0_OR_NEWER" + }, + { + "name": "com.unity.render-pipelines.high-definition", + "expression": "10.7.0", + "define": "HDRP_10_7_OR_NEWER" + }, + { + "name": "com.unity.render-pipelines.high-definition", + "expression": "11.0.0", + "define": "HDRP_11_OR_NEWER" + }, + { + "name": "com.unity.render-pipelines.high-definition", + "expression": "12.0.0", + "define": "HDRP_12_OR_NEWER" + } + ], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Packages/com.unity.ugui/Editor/TMP/Unity.TextMeshPro.Editor.asmdef.meta b/Packages/com.unity.ugui/Editor/TMP/Unity.TextMeshPro.Editor.asmdef.meta new file mode 100644 index 00000000..6ed76ad6 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/TMP/Unity.TextMeshPro.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6546d7765b4165b40850b3667f981c26 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI.meta b/Packages/com.unity.ugui/Editor/UGUI.meta new file mode 100644 index 00000000..f00cab38 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 278b6073a5bdd4362acd72ca43ff9e0d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/EventSystem.meta b/Packages/com.unity.ugui/Editor/UGUI/EventSystem.meta new file mode 100644 index 00000000..f52f58c6 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/EventSystem.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f525580684527b147b70cf94aaa70dbc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/EventSystem/EventSystemEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/EventSystem/EventSystemEditor.cs new file mode 100644 index 00000000..c78c806d --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/EventSystem/EventSystemEditor.cs @@ -0,0 +1,71 @@ +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UnityEditor.EventSystems +{ + [CustomEditor(typeof(EventSystem), true)] + /// + /// Custom Editor for the EventSystem Component. + /// Extend this class to write a custom editor for a component derived from EventSystem. + /// + public class EventSystemEditor : Editor + { + public override void OnInspectorGUI() + { + DrawDefaultInspector(); + + var eventSystem = target as EventSystem; + if (eventSystem == null) + return; + + if (eventSystem.GetComponent() != null) + return; + + // no input modules :( + if (GUILayout.Button("Add Default Input Modules")) + { + InputModuleComponentFactory.AddInputModule(eventSystem.gameObject); + Undo.RegisterCreatedObjectUndo(eventSystem.gameObject, "Add Default Input Modules"); + } + } + + public override bool HasPreviewGUI() + { + return Application.isPlaying; + } + + private GUIStyle m_PreviewLabelStyle; + + protected GUIStyle previewLabelStyle + { + get + { + if (m_PreviewLabelStyle == null) + { + m_PreviewLabelStyle = new GUIStyle("PreOverlayLabel") + { + richText = true, + alignment = TextAnchor.UpperLeft, + fontStyle = FontStyle.Normal + }; + } + + return m_PreviewLabelStyle; + } + } + + public override bool RequiresConstantRepaint() + { + return Application.isPlaying; + } + + public override void OnPreviewGUI(Rect rect, GUIStyle background) + { + var system = target as EventSystem; + if (system == null) + return; + + GUI.Label(rect, system.ToString(), previewLabelStyle); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/EventSystem/EventSystemEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/EventSystem/EventSystemEditor.cs.meta new file mode 100644 index 00000000..a8da8e1b --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/EventSystem/EventSystemEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6f72aa6eab9392548b9e9d92eb6b2ef8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/EventSystem/EventTriggerEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/EventSystem/EventTriggerEditor.cs new file mode 100644 index 00000000..ddf06acc --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/EventSystem/EventTriggerEditor.cs @@ -0,0 +1,122 @@ +using System; +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UnityEditor.EventSystems +{ + [CustomEditor(typeof(EventTrigger), true)] + public class EventTriggerEditor : Editor + { + SerializedProperty m_DelegatesProperty; + + GUIContent m_IconToolbarMinus; + GUIContent m_EventIDName; + GUIContent[] m_EventTypes; + GUIContent m_AddButonContent; + + protected virtual void OnEnable() + { + m_DelegatesProperty = serializedObject.FindProperty("m_Delegates"); + m_AddButonContent = EditorGUIUtility.TrTextContent("Add New Event Type"); + m_EventIDName = new GUIContent(""); + // Have to create a copy since otherwise the tooltip will be overwritten. + m_IconToolbarMinus = new GUIContent(EditorGUIUtility.IconContent("Toolbar Minus")); + m_IconToolbarMinus.tooltip = "Remove all events in this list."; + + string[] eventNames = Enum.GetNames(typeof(EventTriggerType)); + m_EventTypes = new GUIContent[eventNames.Length]; + for (int i = 0; i < eventNames.Length; ++i) + { + m_EventTypes[i] = new GUIContent(eventNames[i]); + } + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + int toBeRemovedEntry = -1; + + EditorGUILayout.Space(); + + Vector2 removeButtonSize = GUIStyle.none.CalcSize(m_IconToolbarMinus); + + for (int i = 0; i < m_DelegatesProperty.arraySize; ++i) + { + SerializedProperty delegateProperty = m_DelegatesProperty.GetArrayElementAtIndex(i); + SerializedProperty eventProperty = delegateProperty.FindPropertyRelative("eventID"); + SerializedProperty callbacksProperty = delegateProperty.FindPropertyRelative("callback"); + m_EventIDName.text = eventProperty.enumDisplayNames[eventProperty.enumValueIndex]; + + EditorGUILayout.PropertyField(callbacksProperty, m_EventIDName); + Rect callbackRect = GUILayoutUtility.GetLastRect(); + + Rect removeButtonPos = new Rect(callbackRect.xMax - removeButtonSize.x - 8, callbackRect.y + 1, removeButtonSize.x, removeButtonSize.y); + if (GUI.Button(removeButtonPos, m_IconToolbarMinus, GUIStyle.none)) + { + toBeRemovedEntry = i; + } + + EditorGUILayout.Space(); + } + + if (toBeRemovedEntry > -1) + { + RemoveEntry(toBeRemovedEntry); + } + + Rect btPosition = GUILayoutUtility.GetRect(m_AddButonContent, GUI.skin.button); + const float addButonWidth = 200f; + btPosition.x = btPosition.x + (btPosition.width - addButonWidth) / 2; + btPosition.width = addButonWidth; + if (GUI.Button(btPosition, m_AddButonContent)) + { + ShowAddTriggermenu(); + } + + serializedObject.ApplyModifiedProperties(); + } + + private void RemoveEntry(int toBeRemovedEntry) + { + m_DelegatesProperty.DeleteArrayElementAtIndex(toBeRemovedEntry); + } + + void ShowAddTriggermenu() + { + // Now create the menu, add items and show it + GenericMenu menu = new GenericMenu(); + for (int i = 0; i < m_EventTypes.Length; ++i) + { + bool active = true; + + // Check if we already have a Entry for the current eventType, if so, disable it + for (int p = 0; p < m_DelegatesProperty.arraySize; ++p) + { + SerializedProperty delegateEntry = m_DelegatesProperty.GetArrayElementAtIndex(p); + SerializedProperty eventProperty = delegateEntry.FindPropertyRelative("eventID"); + if (eventProperty.enumValueIndex == i) + { + active = false; + } + } + if (active) + menu.AddItem(m_EventTypes[i], false, OnAddNewSelected, i); + else + menu.AddDisabledItem(m_EventTypes[i]); + } + menu.ShowAsContext(); + Event.current.Use(); + } + + private void OnAddNewSelected(object index) + { + int selected = (int)index; + + m_DelegatesProperty.arraySize += 1; + SerializedProperty delegateEntry = m_DelegatesProperty.GetArrayElementAtIndex(m_DelegatesProperty.arraySize - 1); + SerializedProperty eventProperty = delegateEntry.FindPropertyRelative("eventID"); + eventProperty.enumValueIndex = selected; + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/EventSystem/EventTriggerEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/EventSystem/EventTriggerEditor.cs.meta new file mode 100644 index 00000000..f037d7cb --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/EventSystem/EventTriggerEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37b164a494cd92a498526852ecceedef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/EventSystem/InputModuleComponentFactory.cs b/Packages/com.unity.ugui/Editor/UGUI/EventSystem/InputModuleComponentFactory.cs new file mode 100644 index 00000000..a84076b2 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/EventSystem/InputModuleComponentFactory.cs @@ -0,0 +1,29 @@ +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UnityEditor.EventSystems +{ + public static class InputModuleComponentFactory + { + public delegate BaseInputModule AddInputModuleComponentDelegate(GameObject gameObject); + + public static void SetInputModuleComponentOverride(AddInputModuleComponentDelegate addInputModuleComponentOverride) + { + m_AddInputModuleComponentOverride = addInputModuleComponentOverride; + } + + private static AddInputModuleComponentDelegate m_AddInputModuleComponentOverride = null; + + public static BaseInputModule AddInputModule(GameObject gameObject) + { + return m_AddInputModuleComponentOverride != null ? + m_AddInputModuleComponentOverride(gameObject) : + AddStandaloneInputModuleComponent(gameObject); + } + + private static BaseInputModule AddStandaloneInputModuleComponent(GameObject gameObject) + { + return ObjectFactory.AddComponent(gameObject); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/EventSystem/InputModuleComponentFactory.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/EventSystem/InputModuleComponentFactory.cs.meta new file mode 100644 index 00000000..c754c2a4 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/EventSystem/InputModuleComponentFactory.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 765f7aac6597fc444a90dac4294e929d \ No newline at end of file diff --git a/Packages/com.unity.ugui/Editor/UGUI/EventSystem/Physics2DRaycasterEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/EventSystem/Physics2DRaycasterEditor.cs new file mode 100644 index 00000000..73ecb449 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/EventSystem/Physics2DRaycasterEditor.cs @@ -0,0 +1,21 @@ +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UnityEditor.EventSystems +{ + [CustomEditor(typeof(Physics2DRaycaster), true)] + /// + /// Custom Editor for the EventSystem Component. + /// Extend this class to write a custom editor for a component derived from EventSystem. + /// + public class Physics2DRaycasterEditor : Editor + { + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); +#if !PACKAGE_PHYSICS2D + EditorGUILayout.HelpBox("Physics2D module is not present. This Raycaster will have no effect", MessageType.Warning); +#endif + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/EventSystem/Physics2DRaycasterEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/EventSystem/Physics2DRaycasterEditor.cs.meta new file mode 100644 index 00000000..4f103c18 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/EventSystem/Physics2DRaycasterEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1143ae6bb91836f4a8f8ebfaabb9396d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/EventSystem/PhysicsRaycasterEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/EventSystem/PhysicsRaycasterEditor.cs new file mode 100644 index 00000000..a13e9b6b --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/EventSystem/PhysicsRaycasterEditor.cs @@ -0,0 +1,20 @@ +using UnityEngine.EventSystems; + +namespace UnityEditor.EventSystems +{ + [CustomEditor(typeof(PhysicsRaycaster), true)] + /// + /// Custom Editor for the EventSystem Component. + /// Extend this class to write a custom editor for a component derived from EventSystem. + /// + public class PhysicsRaycasterEditor : Editor + { + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); +#if !PACKAGE_PHYSICS + EditorGUILayout.HelpBox("Physics module is not present. This Raycaster will have no effect", MessageType.Warning); +#endif + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/EventSystem/PhysicsRaycasterEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/EventSystem/PhysicsRaycasterEditor.cs.meta new file mode 100644 index 00000000..99f1db95 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/EventSystem/PhysicsRaycasterEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e976a5e755c7016418f66e15223c1b90 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/Properties.meta b/Packages/com.unity.ugui/Editor/UGUI/Properties.meta new file mode 100644 index 00000000..64369008 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/Properties.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cf97e54bcd5479a46bdbade48da047cc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/Properties/AssemblyInfo.cs b/Packages/com.unity.ugui/Editor/UGUI/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..81a20310 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/Properties/AssemblyInfo.cs @@ -0,0 +1,38 @@ +using System.Reflection; +using System.Runtime.InteropServices; +using UnityEngine; + + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("UnityEditor.UI")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Unity Technologies")] +[assembly: AssemblyProduct("com.unity.ugui")] +[assembly: AssemblyCopyright("Copyright © Unity Technologies 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: AssemblyIsEditorAssembly] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ad7418c3-5d25-4670-b468-8e7196596d42")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Packages/com.unity.ugui/Editor/UGUI/Properties/AssemblyInfo.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/Properties/AssemblyInfo.cs.meta new file mode 100644 index 00000000..fa5fb789 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/Properties/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d51458b261e0ecc4a98904e53924dc1c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI.meta b/Packages/com.unity.ugui/Editor/UGUI/UI.meta new file mode 100644 index 00000000..b1b7137a --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 853edc343b78a7c4c81cbb3851d48c0a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/AspectRatioFitterEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/AspectRatioFitterEditor.cs new file mode 100644 index 00000000..20c5f73a --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/AspectRatioFitterEditor.cs @@ -0,0 +1,74 @@ +using UnityEngine; +using UnityEditor.AnimatedValues; +using UnityEngine.UI; + +namespace UnityEditor.UI +{ + [CustomEditor(typeof(AspectRatioFitter), true)] + [CanEditMultipleObjects] + /// + /// Custom Editor for the AspectRatioFitter component. + /// Extend this class to write a custom editor for a component derived from AspectRatioFitter. + /// + public class AspectRatioFitterEditor : SelfControllerEditor + { + SerializedProperty m_AspectMode; + SerializedProperty m_AspectRatio; + + + AnimBool m_ModeBool; + private AspectRatioFitter aspectRatioFitter; + + protected virtual void OnEnable() + { + m_AspectMode = serializedObject.FindProperty("m_AspectMode"); + m_AspectRatio = serializedObject.FindProperty("m_AspectRatio"); + aspectRatioFitter = target as AspectRatioFitter; + + m_ModeBool = new AnimBool(m_AspectMode.intValue != 0); + m_ModeBool.valueChanged.AddListener(Repaint); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + EditorGUILayout.PropertyField(m_AspectMode); + + m_ModeBool.target = m_AspectMode.intValue != 0; + + if (EditorGUILayout.BeginFadeGroup(m_ModeBool.faded)) + EditorGUILayout.PropertyField(m_AspectRatio); + EditorGUILayout.EndFadeGroup(); + + serializedObject.ApplyModifiedProperties(); + + if (aspectRatioFitter) + { + if (!aspectRatioFitter.IsAspectModeValid()) + ShowNoParentWarning(); + if (!aspectRatioFitter.IsComponentValidOnObject()) + ShowCanvasRenderModeInvalidWarning(); + } + + base.OnInspectorGUI(); + } + + protected virtual void OnDisable() + { + aspectRatioFitter = null; + m_ModeBool.valueChanged.RemoveListener(Repaint); + } + + private static void ShowNoParentWarning() + { + var text = L10n.Tr("You cannot use this Aspect Mode because this Component's GameObject does not have a parent object."); + EditorGUILayout.HelpBox(text, MessageType.Warning, true); + } + + private static void ShowCanvasRenderModeInvalidWarning() + { + var text = L10n.Tr("You cannot use this Aspect Mode because this Component is attached to a Canvas with a fixed width and height."); + EditorGUILayout.HelpBox(text, MessageType.Warning, true); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/AspectRatioFitterEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/AspectRatioFitterEditor.cs.meta new file mode 100644 index 00000000..deb7906a --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/AspectRatioFitterEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b5f70efd2f7b286498ca6c00adbb4a13 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/ButtonEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/ButtonEditor.cs new file mode 100644 index 00000000..b8e48f67 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/ButtonEditor.cs @@ -0,0 +1,31 @@ +using UnityEngine.UI; + +namespace UnityEditor.UI +{ + [CustomEditor(typeof(Button), true)] + [CanEditMultipleObjects] + /// + /// Custom Editor for the Button Component. + /// Extend this class to write a custom editor for a component derived from Button. + /// + public class ButtonEditor : SelectableEditor + { + SerializedProperty m_OnClickProperty; + + protected override void OnEnable() + { + base.OnEnable(); + m_OnClickProperty = serializedObject.FindProperty("m_OnClick"); + } + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + EditorGUILayout.Space(); + + serializedObject.Update(); + EditorGUILayout.PropertyField(m_OnClickProperty); + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/ButtonEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/ButtonEditor.cs.meta new file mode 100644 index 00000000..e0213af3 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/ButtonEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 472a6f18dd2f97c41af72271d22db869 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/CanvasScalerEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/CanvasScalerEditor.cs new file mode 100644 index 00000000..a0f4ecfd --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/CanvasScalerEditor.cs @@ -0,0 +1,184 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace UnityEditor.UI +{ + [CustomEditor(typeof(CanvasScaler), true)] + [CanEditMultipleObjects] + /// + /// Custom Editor for the CanvasScaler component. + /// Extend this class to write a custom editor for a component derived from CanvasScaler. + /// + public class CanvasScalerEditor : Editor + { + SerializedProperty m_UiScaleMode; + SerializedProperty m_ScaleFactor; + SerializedProperty m_ReferenceResolution; + SerializedProperty m_ScreenMatchMode; + SerializedProperty m_MatchWidthOrHeight; + SerializedProperty m_PhysicalUnit; + SerializedProperty m_FallbackScreenDPI; + SerializedProperty m_DefaultSpriteDPI; + SerializedProperty m_DynamicPixelsPerUnit; + SerializedProperty m_ReferencePixelsPerUnit; + SerializedProperty m_PresetInfoIsWorld; + + const int kSliderEndpointLabelsHeight = 12; + + private class Styles + { + public GUIContent matchContent; + public GUIContent widthContent; + public GUIContent heightContent; + public GUIContent uiScaleModeContent; + public GUIStyle leftAlignedLabel; + public GUIStyle rightAlignedLabel; + + public Styles() + { + matchContent = EditorGUIUtility.TrTextContent("Match"); + widthContent = EditorGUIUtility.TrTextContent("Width"); + heightContent = EditorGUIUtility.TrTextContent("Height"); + uiScaleModeContent = EditorGUIUtility.TrTextContent("UI Scale Mode"); + + leftAlignedLabel = new GUIStyle(EditorStyles.label); + rightAlignedLabel = new GUIStyle(EditorStyles.label); + rightAlignedLabel.alignment = TextAnchor.MiddleRight; + } + } + private static Styles s_Styles; + private bool bIsPreset; + + protected virtual void OnEnable() + { + m_UiScaleMode = serializedObject.FindProperty("m_UiScaleMode"); + m_ScaleFactor = serializedObject.FindProperty("m_ScaleFactor"); + m_ReferenceResolution = serializedObject.FindProperty("m_ReferenceResolution"); + m_ScreenMatchMode = serializedObject.FindProperty("m_ScreenMatchMode"); + m_MatchWidthOrHeight = serializedObject.FindProperty("m_MatchWidthOrHeight"); + m_PhysicalUnit = serializedObject.FindProperty("m_PhysicalUnit"); + m_FallbackScreenDPI = serializedObject.FindProperty("m_FallbackScreenDPI"); + m_DefaultSpriteDPI = serializedObject.FindProperty("m_DefaultSpriteDPI"); + m_DynamicPixelsPerUnit = serializedObject.FindProperty("m_DynamicPixelsPerUnit"); + m_ReferencePixelsPerUnit = serializedObject.FindProperty("m_ReferencePixelsPerUnit"); + m_PresetInfoIsWorld = serializedObject.FindProperty("m_PresetInfoIsWorld"); + + if (m_SerializedObject == null || m_SerializedObject.targetObject == null) + bIsPreset = false; + else + bIsPreset = m_SerializedObject.targetObject is Component ? ((int)(m_SerializedObject.targetObject as Component).gameObject.hideFlags == 93) : !AssetDatabase.Contains(m_SerializedObject.targetObject); + } + + public override void OnInspectorGUI() + { + if (s_Styles == null) + s_Styles = new Styles(); + + bool allAreRoot = true; + bool showWorldDiffers = false; + bool showWorld = false; + + if (bIsPreset) + { + showWorld = m_PresetInfoIsWorld.boolValue; + } + else + { + showWorld = ((target as CanvasScaler).GetComponent().renderMode == RenderMode.WorldSpace); + + m_PresetInfoIsWorld.boolValue = showWorld; + serializedObject.ApplyModifiedProperties(); + + for (int i = 0; i < targets.Length; i++) + { + CanvasScaler scaler = targets[i] as CanvasScaler; + Canvas canvas = scaler.GetComponent(); + if (!canvas.isRootCanvas) + { + allAreRoot = false; + break; + } + if (showWorld && canvas.renderMode != RenderMode.WorldSpace || !showWorld && canvas.renderMode == RenderMode.WorldSpace) + { + showWorldDiffers = true; + break; + } + } + + if (!allAreRoot) + { + EditorGUILayout.HelpBox("Non-root Canvases will not be scaled.", MessageType.Warning); + return; + } + } + serializedObject.Update(); + + EditorGUI.showMixedValue = showWorldDiffers; + using (new EditorGUI.DisabledScope(showWorld || showWorldDiffers)) + { + if (showWorld || showWorldDiffers) + { + EditorGUILayout.Popup(s_Styles.uiScaleModeContent.text, 0, new[] { "World" }); + } + else + { + EditorGUILayout.PropertyField(m_UiScaleMode, s_Styles.uiScaleModeContent); + } + } + EditorGUI.showMixedValue = false; + + if (!showWorldDiffers && !(!showWorld && m_UiScaleMode.hasMultipleDifferentValues)) + { + EditorGUILayout.Space(); + + // World Canvas + if (showWorld) + { + EditorGUILayout.PropertyField(m_DynamicPixelsPerUnit); + } + // Constant pixel size + else if (m_UiScaleMode.enumValueIndex == (int)CanvasScaler.ScaleMode.ConstantPixelSize) + { + EditorGUILayout.PropertyField(m_ScaleFactor); + } + // Scale with screen size + else if (m_UiScaleMode.enumValueIndex == (int)CanvasScaler.ScaleMode.ScaleWithScreenSize) + { + EditorGUILayout.PropertyField(m_ReferenceResolution); + EditorGUILayout.PropertyField(m_ScreenMatchMode); + if (m_ScreenMatchMode.enumValueIndex == (int)CanvasScaler.ScreenMatchMode.MatchWidthOrHeight && !m_ScreenMatchMode.hasMultipleDifferentValues) + { + Rect r = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight + kSliderEndpointLabelsHeight); + DualLabeledSlider(r, m_MatchWidthOrHeight, s_Styles.matchContent, s_Styles.widthContent, s_Styles.heightContent); + } + } + // Constant physical size + else if (m_UiScaleMode.enumValueIndex == (int)CanvasScaler.ScaleMode.ConstantPhysicalSize) + { + EditorGUILayout.PropertyField(m_PhysicalUnit); + EditorGUILayout.PropertyField(m_FallbackScreenDPI); + EditorGUILayout.PropertyField(m_DefaultSpriteDPI); + } + + EditorGUILayout.PropertyField(m_ReferencePixelsPerUnit); + } + + serializedObject.ApplyModifiedProperties(); + } + + private static void DualLabeledSlider(Rect position, SerializedProperty property, GUIContent mainLabel, GUIContent labelLeft, GUIContent labelRight) + { + position.height = EditorGUIUtility.singleLineHeight; + Rect pos = position; + + position.y += 12; + position.xMin += EditorGUIUtility.labelWidth; + position.xMax -= EditorGUIUtility.fieldWidth; + + GUI.Label(position, labelLeft, s_Styles.leftAlignedLabel); + GUI.Label(position, labelRight, s_Styles.rightAlignedLabel); + + EditorGUI.PropertyField(pos, property, mainLabel); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/CanvasScalerEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/CanvasScalerEditor.cs.meta new file mode 100644 index 00000000..7b3c5586 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/CanvasScalerEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3bce033ee26244e419b3bb3bba95a37d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/ContentSizeFitterEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/ContentSizeFitterEditor.cs new file mode 100644 index 00000000..0f50b26d --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/ContentSizeFitterEditor.cs @@ -0,0 +1,33 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace UnityEditor.UI +{ + [CustomEditor(typeof(ContentSizeFitter), true)] + [CanEditMultipleObjects] + /// + /// Custom Editor for the ContentSizeFitter Component. + /// Extend this class to write a custom editor for a component derived from ContentSizeFitter. + /// + public class ContentSizeFitterEditor : SelfControllerEditor + { + SerializedProperty m_HorizontalFit; + SerializedProperty m_VerticalFit; + + protected virtual void OnEnable() + { + m_HorizontalFit = serializedObject.FindProperty("m_HorizontalFit"); + m_VerticalFit = serializedObject.FindProperty("m_VerticalFit"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + EditorGUILayout.PropertyField(m_HorizontalFit, true); + EditorGUILayout.PropertyField(m_VerticalFit, true); + serializedObject.ApplyModifiedProperties(); + + base.OnInspectorGUI(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/ContentSizeFitterEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/ContentSizeFitterEditor.cs.meta new file mode 100644 index 00000000..ef12da6d --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/ContentSizeFitterEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 35d143b352678294ab0f5feb97b67f88 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/DropdownEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/DropdownEditor.cs new file mode 100644 index 00000000..40e36f86 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/DropdownEditor.cs @@ -0,0 +1,55 @@ +using UnityEngine.UI; + +namespace UnityEditor.UI +{ + [CustomEditor(typeof(Dropdown), true)] + [CanEditMultipleObjects] + /// + /// Custom editor for the Dropdown component + /// Extend this class to write a custom editor for a component derived from Dropdown. + /// + public class DropdownEditor : SelectableEditor + { + SerializedProperty m_Template; + SerializedProperty m_CaptionText; + SerializedProperty m_CaptionImage; + SerializedProperty m_ItemText; + SerializedProperty m_ItemImage; + SerializedProperty m_OnSelectionChanged; + SerializedProperty m_Value; + SerializedProperty m_Options; + SerializedProperty m_AlphaFadeSpeed; + + protected override void OnEnable() + { + base.OnEnable(); + m_Template = serializedObject.FindProperty("m_Template"); + m_CaptionText = serializedObject.FindProperty("m_CaptionText"); + m_CaptionImage = serializedObject.FindProperty("m_CaptionImage"); + m_ItemText = serializedObject.FindProperty("m_ItemText"); + m_ItemImage = serializedObject.FindProperty("m_ItemImage"); + m_OnSelectionChanged = serializedObject.FindProperty("m_OnValueChanged"); + m_Value = serializedObject.FindProperty("m_Value"); + m_Options = serializedObject.FindProperty("m_Options"); + m_AlphaFadeSpeed = serializedObject.FindProperty("m_AlphaFadeSpeed"); + } + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + EditorGUILayout.Space(); + + serializedObject.Update(); + EditorGUILayout.PropertyField(m_Template); + EditorGUILayout.PropertyField(m_CaptionText); + EditorGUILayout.PropertyField(m_CaptionImage); + EditorGUILayout.PropertyField(m_ItemText); + EditorGUILayout.PropertyField(m_ItemImage); + EditorGUILayout.PropertyField(m_Value); + EditorGUILayout.PropertyField(m_AlphaFadeSpeed); + EditorGUILayout.PropertyField(m_Options); + EditorGUILayout.PropertyField(m_OnSelectionChanged); + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/DropdownEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/DropdownEditor.cs.meta new file mode 100644 index 00000000..e12a5a43 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/DropdownEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 05f582d4fbc8e0c40afccb76bbbe0935 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/GraphicEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/GraphicEditor.cs new file mode 100644 index 00000000..6126a5b8 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/GraphicEditor.cs @@ -0,0 +1,215 @@ +using System.Linq; +using UnityEditor.AnimatedValues; +using UnityEngine; +using UnityEngine.UI; + +namespace UnityEditor.UI +{ + /// + /// Editor class used to edit UI Graphics. + /// Extend this class to write your own graphic editor. + /// + + [CustomEditor(typeof(MaskableGraphic), false)] + [CanEditMultipleObjects] + public class GraphicEditor : Editor + { + protected SerializedProperty m_Script; + protected SerializedProperty m_Color; + protected SerializedProperty m_Material; + protected SerializedProperty m_RaycastTarget; + protected SerializedProperty m_RaycastPadding; + protected SerializedProperty m_Maskable; + + private GUIContent m_CorrectButtonContent; + protected AnimBool m_ShowNativeSize; + + GUIContent m_PaddingContent; + GUIContent m_LeftContent; + GUIContent m_RightContent; + GUIContent m_TopContent; + GUIContent m_BottomContent; + static private bool m_ShowPadding = false; + + protected virtual void OnDisable() + { + Tools.hidden = false; + m_ShowNativeSize.valueChanged.RemoveListener(Repaint); + SceneView.duringSceneGui -= DrawAnchorsOnSceneView; + } + + protected virtual void OnEnable() + { + m_CorrectButtonContent = EditorGUIUtility.TrTextContent("Set Native Size", "Sets the size to match the content."); + m_PaddingContent = EditorGUIUtility.TrTextContent("Raycast Padding"); + m_LeftContent = EditorGUIUtility.TrTextContent("Left"); + m_RightContent = EditorGUIUtility.TrTextContent("Right"); + m_TopContent = EditorGUIUtility.TrTextContent("Top"); + m_BottomContent = EditorGUIUtility.TrTextContent("Bottom"); + + m_Script = serializedObject.FindProperty("m_Script"); + m_Color = serializedObject.FindProperty("m_Color"); + m_Material = serializedObject.FindProperty("m_Material"); + m_RaycastTarget = serializedObject.FindProperty("m_RaycastTarget"); + m_RaycastPadding = serializedObject.FindProperty("m_RaycastPadding"); + m_Maskable = serializedObject.FindProperty("m_Maskable"); + + m_ShowNativeSize = new AnimBool(false); + m_ShowNativeSize.valueChanged.AddListener(Repaint); + + SceneView.duringSceneGui += DrawAnchorsOnSceneView; + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + EditorGUILayout.PropertyField(m_Script); + AppearanceControlsGUI(); + RaycastControlsGUI(); + MaskableControlsGUI(); + serializedObject.ApplyModifiedProperties(); + } + + void DrawAnchorsOnSceneView(SceneView sceneView) + { + if (!target || targets.Length > 1) + return; + + if (!sceneView.drawGizmos || !EditorGUIUtility.IsGizmosAllowedForObject(target)) + return; + + Graphic graphic = target as Graphic; + + RectTransform gui = graphic.rectTransform; + Transform ownSpace = gui.transform; + Rect rectInOwnSpace = gui.rect; + + Handles.color = Handles.UIColliderHandleColor; + DrawRect(rectInOwnSpace, ownSpace, graphic.raycastPadding); + } + + void DrawRect(Rect rect, Transform space, Vector4 offset) + { + Vector3 p0 = space.TransformPoint(new Vector2(rect.x + offset.x, rect.y + offset.y)); + Vector3 p1 = space.TransformPoint(new Vector2(rect.x + offset.x, rect.yMax - offset.w)); + Vector3 p2 = space.TransformPoint(new Vector2(rect.xMax - offset.z, rect.yMax - offset.w)); + Vector3 p3 = space.TransformPoint(new Vector2(rect.xMax - offset.z, rect.y + offset.y)); + + Handles.DrawLine(p0, p1); + Handles.DrawLine(p1, p2); + Handles.DrawLine(p2, p3); + Handles.DrawLine(p3, p0); + } + + /// + /// Set if the 'Set Native Size' button should be visible for this editor. + /// + /// Are we showing or hiding the AnimBool for the size. + /// Should the size AnimBool change instantly. + protected void SetShowNativeSize(bool show, bool instant) + { + if (instant) + m_ShowNativeSize.value = show; + else + m_ShowNativeSize.target = show; + } + + /// + /// GUI for showing a button that sets the size of the RectTransform to the native size for this Graphic. + /// + protected void NativeSizeButtonGUI() + { + if (EditorGUILayout.BeginFadeGroup(m_ShowNativeSize.faded)) + { + EditorGUILayout.BeginHorizontal(); + { + GUILayout.Space(EditorGUIUtility.labelWidth); + if (GUILayout.Button(m_CorrectButtonContent, EditorStyles.miniButton)) + { + foreach (Graphic graphic in targets.Select(obj => obj as Graphic)) + { + Undo.RecordObject(graphic.rectTransform, "Set Native Size"); + graphic.SetNativeSize(); + EditorUtility.SetDirty(graphic); + } + } + } + EditorGUILayout.EndHorizontal(); + } + EditorGUILayout.EndFadeGroup(); + } + + protected void MaskableControlsGUI() + { + EditorGUILayout.PropertyField(m_Maskable); + } + + /// + /// GUI related to the appearance of the Graphic. Color and Material properties appear here. + /// + protected void AppearanceControlsGUI() + { + EditorGUILayout.PropertyField(m_Color); + EditorGUILayout.PropertyField(m_Material); + } + + /// + /// GUI related to the Raycasting settings for the graphic. + /// + protected void RaycastControlsGUI() + { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_RaycastTarget); + if (EditorGUI.EndChangeCheck() && target is Graphic graphic) + { + graphic.SetRaycastDirty(); + } + + float height = EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + if (m_ShowPadding) + height += (EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing) * 4; + + var rect = EditorGUILayout.GetControlRect(true, height); + EditorGUI.BeginProperty(rect, m_PaddingContent, m_RaycastPadding); + rect.height = EditorGUIUtility.singleLineHeight; + + using (var check = new EditorGUI.ChangeCheckScope()) + { + m_ShowPadding = EditorGUI.Foldout(rect, m_ShowPadding, m_PaddingContent, true); + if (check.changed) + { + SceneView.RepaintAll(); + } + } + + if (m_ShowPadding) + { + using (var check = new EditorGUI.ChangeCheckScope()) + { + EditorGUI.indentLevel++; + Vector4 newPadding = m_RaycastPadding.vector4Value; + + rect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + newPadding.x = EditorGUI.FloatField(rect, m_LeftContent, newPadding.x); + + rect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + newPadding.y = EditorGUI.FloatField(rect, m_BottomContent, newPadding.y); + + rect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + newPadding.z = EditorGUI.FloatField(rect, m_RightContent, newPadding.z); + + rect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + newPadding.w = EditorGUI.FloatField(rect, m_TopContent, newPadding.w); + + if (check.changed) + { + m_RaycastPadding.vector4Value = newPadding; + } + EditorGUI.indentLevel--; + } + } + + EditorGUI.EndProperty(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/GraphicEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/GraphicEditor.cs.meta new file mode 100644 index 00000000..9bc6d513 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/GraphicEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c890977a36bfdc849872b9337ab89098 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/GridLayoutGroupEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/GridLayoutGroupEditor.cs new file mode 100644 index 00000000..59fa18a2 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/GridLayoutGroupEditor.cs @@ -0,0 +1,56 @@ +using UnityEngine; +using UnityEngine.UI; +using UnityEditorInternal; +using UnityEditor.AnimatedValues; + +namespace UnityEditor.UI +{ + [CustomEditor(typeof(GridLayoutGroup), true)] + [CanEditMultipleObjects] + /// + /// Custom Editor for the GridLayout Component. + /// Extend this class to write a custom editor for a component derived from GridLayout. + /// + public class GridLayoutGroupEditor : Editor + { + SerializedProperty m_Padding; + SerializedProperty m_CellSize; + SerializedProperty m_Spacing; + SerializedProperty m_StartCorner; + SerializedProperty m_StartAxis; + SerializedProperty m_ChildAlignment; + SerializedProperty m_Constraint; + SerializedProperty m_ConstraintCount; + + protected virtual void OnEnable() + { + m_Padding = serializedObject.FindProperty("m_Padding"); + m_CellSize = serializedObject.FindProperty("m_CellSize"); + m_Spacing = serializedObject.FindProperty("m_Spacing"); + m_StartCorner = serializedObject.FindProperty("m_StartCorner"); + m_StartAxis = serializedObject.FindProperty("m_StartAxis"); + m_ChildAlignment = serializedObject.FindProperty("m_ChildAlignment"); + m_Constraint = serializedObject.FindProperty("m_Constraint"); + m_ConstraintCount = serializedObject.FindProperty("m_ConstraintCount"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + EditorGUILayout.PropertyField(m_Padding, true); + EditorGUILayout.PropertyField(m_CellSize, true); + EditorGUILayout.PropertyField(m_Spacing, true); + EditorGUILayout.PropertyField(m_StartCorner, true); + EditorGUILayout.PropertyField(m_StartAxis, true); + EditorGUILayout.PropertyField(m_ChildAlignment, true); + EditorGUILayout.PropertyField(m_Constraint, true); + if (m_Constraint.enumValueIndex > 0) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_ConstraintCount, true); + EditorGUI.indentLevel--; + } + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/GridLayoutGroupEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/GridLayoutGroupEditor.cs.meta new file mode 100644 index 00000000..b18753cf --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/GridLayoutGroupEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6a981cd1456bec84b86e1c66773f57f5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/HorizontalOrVerticalLayoutGroupEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/HorizontalOrVerticalLayoutGroupEditor.cs new file mode 100644 index 00000000..0ec8a224 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/HorizontalOrVerticalLayoutGroupEditor.cs @@ -0,0 +1,95 @@ +using UnityEngine; +using UnityEngine.UI; +using UnityEditorInternal; +using UnityEditor.AnimatedValues; + +namespace UnityEditor.UI +{ + [CustomEditor(typeof(HorizontalOrVerticalLayoutGroup), true)] + [CanEditMultipleObjects] + /// + /// Custom Editor for the HorizontalOrVerticalLayoutGroupEditor Component. + /// Extend this class to write a custom editor for a component derived from HorizontalOrVerticalLayoutGroupEditor. + /// + public class HorizontalOrVerticalLayoutGroupEditor : Editor + { + SerializedProperty m_Padding; + SerializedProperty m_Spacing; + SerializedProperty m_ChildAlignment; + SerializedProperty m_ChildControlWidth; + SerializedProperty m_ChildControlHeight; + SerializedProperty m_ChildScaleWidth; + SerializedProperty m_ChildScaleHeight; + SerializedProperty m_ChildForceExpandWidth; + SerializedProperty m_ChildForceExpandHeight; + SerializedProperty m_ReverseArrangement; + + protected virtual void OnEnable() + { + m_Padding = serializedObject.FindProperty("m_Padding"); + m_Spacing = serializedObject.FindProperty("m_Spacing"); + m_ChildAlignment = serializedObject.FindProperty("m_ChildAlignment"); + m_ChildControlWidth = serializedObject.FindProperty("m_ChildControlWidth"); + m_ChildControlHeight = serializedObject.FindProperty("m_ChildControlHeight"); + m_ChildScaleWidth = serializedObject.FindProperty("m_ChildScaleWidth"); + m_ChildScaleHeight = serializedObject.FindProperty("m_ChildScaleHeight"); + m_ChildForceExpandWidth = serializedObject.FindProperty("m_ChildForceExpandWidth"); + m_ChildForceExpandHeight = serializedObject.FindProperty("m_ChildForceExpandHeight"); + m_ReverseArrangement = serializedObject.FindProperty("m_ReverseArrangement"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + EditorGUILayout.PropertyField(m_Padding, true); + EditorGUILayout.PropertyField(m_Spacing, true); + EditorGUILayout.PropertyField(m_ChildAlignment, true); + EditorGUILayout.PropertyField(m_ReverseArrangement, true); + + Rect rect = EditorGUILayout.GetControlRect(); + rect = EditorGUI.PrefixLabel(rect, -1, EditorGUIUtility.TrTextContent("Control Child Size")); + rect.width = Mathf.Max(50, (rect.width - 4) / 3); + EditorGUIUtility.labelWidth = 50; + ToggleLeft(rect, m_ChildControlWidth, EditorGUIUtility.TrTextContent("Width")); + rect.x += rect.width + 2; + ToggleLeft(rect, m_ChildControlHeight, EditorGUIUtility.TrTextContent("Height")); + EditorGUIUtility.labelWidth = 0; + + rect = EditorGUILayout.GetControlRect(); + rect = EditorGUI.PrefixLabel(rect, -1, EditorGUIUtility.TrTextContent("Use Child Scale")); + rect.width = Mathf.Max(50, (rect.width - 4) / 3); + EditorGUIUtility.labelWidth = 50; + ToggleLeft(rect, m_ChildScaleWidth, EditorGUIUtility.TrTextContent("Width")); + rect.x += rect.width + 2; + ToggleLeft(rect, m_ChildScaleHeight, EditorGUIUtility.TrTextContent("Height")); + EditorGUIUtility.labelWidth = 0; + + rect = EditorGUILayout.GetControlRect(); + rect = EditorGUI.PrefixLabel(rect, -1, EditorGUIUtility.TrTextContent("Child Force Expand")); + rect.width = Mathf.Max(50, (rect.width - 4) / 3); + EditorGUIUtility.labelWidth = 50; + ToggleLeft(rect, m_ChildForceExpandWidth, EditorGUIUtility.TrTextContent("Width")); + rect.x += rect.width + 2; + ToggleLeft(rect, m_ChildForceExpandHeight, EditorGUIUtility.TrTextContent("Height")); + EditorGUIUtility.labelWidth = 0; + + serializedObject.ApplyModifiedProperties(); + } + + void ToggleLeft(Rect position, SerializedProperty property, GUIContent label) + { + bool toggle = property.boolValue; + EditorGUI.BeginProperty(position, label, property); + EditorGUI.BeginChangeCheck(); + int oldIndent = EditorGUI.indentLevel; + EditorGUI.indentLevel = 0; + toggle = EditorGUI.ToggleLeft(position, label, toggle); + EditorGUI.indentLevel = oldIndent; + if (EditorGUI.EndChangeCheck()) + { + property.boolValue = property.hasMultipleDifferentValues ? true : !property.boolValue; + } + EditorGUI.EndProperty(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/HorizontalOrVerticalLayoutGroupEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/HorizontalOrVerticalLayoutGroupEditor.cs.meta new file mode 100644 index 00000000..5ba2269d --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/HorizontalOrVerticalLayoutGroupEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cb319974ad8ebd44aa1e1fbb02640b5b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/ImageEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/ImageEditor.cs new file mode 100644 index 00000000..2d8b5fe0 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/ImageEditor.cs @@ -0,0 +1,326 @@ +using System.Linq; +using UnityEngine; +using UnityEditor.AnimatedValues; +using UnityEngine.UI; + +namespace UnityEditor.UI +{ + /// + /// Editor class used to edit UI Sprites. + /// + + [CustomEditor(typeof(Image), true)] + [CanEditMultipleObjects] + /// + /// Custom Editor for the Image Component. + /// Extend this class to write a custom editor for a component derived from Image. + /// + public class ImageEditor : GraphicEditor + { + SerializedProperty m_FillMethod; + SerializedProperty m_FillOrigin; + SerializedProperty m_FillAmount; + SerializedProperty m_FillClockwise; + SerializedProperty m_Type; + SerializedProperty m_FillCenter; + SerializedProperty m_Sprite; + SerializedProperty m_PreserveAspect; + SerializedProperty m_UseSpriteMesh; + SerializedProperty m_PixelsPerUnitMultiplier; + GUIContent m_SpriteContent; + GUIContent m_SpriteTypeContent; + GUIContent m_ClockwiseContent; + AnimBool m_ShowSlicedOrTiled; + AnimBool m_ShowSliced; + AnimBool m_ShowTiled; + AnimBool m_ShowFilled; + AnimBool m_ShowType; + bool m_bIsDriven; + + private class Styles + { + public static GUIContent text = EditorGUIUtility.TrTextContent("Fill Origin"); + public static GUIContent[] OriginHorizontalStyle = + { + EditorGUIUtility.TrTextContent("Left"), + EditorGUIUtility.TrTextContent("Right") + }; + + public static GUIContent[] OriginVerticalStyle = + { + EditorGUIUtility.TrTextContent("Bottom"), + EditorGUIUtility.TrTextContent("Top") + }; + + public static GUIContent[] Origin90Style = + { + EditorGUIUtility.TrTextContent("BottomLeft"), + EditorGUIUtility.TrTextContent("TopLeft"), + EditorGUIUtility.TrTextContent("TopRight"), + EditorGUIUtility.TrTextContent("BottomRight") + }; + + public static GUIContent[] Origin180Style = + { + EditorGUIUtility.TrTextContent("Bottom"), + EditorGUIUtility.TrTextContent("Left"), + EditorGUIUtility.TrTextContent("Top"), + EditorGUIUtility.TrTextContent("Right") + }; + + public static GUIContent[] Origin360Style = + { + EditorGUIUtility.TrTextContent("Bottom"), + EditorGUIUtility.TrTextContent("Right"), + EditorGUIUtility.TrTextContent("Top"), + EditorGUIUtility.TrTextContent("Left") + }; + } + + protected override void OnEnable() + { + base.OnEnable(); + + m_SpriteContent = EditorGUIUtility.TrTextContent("Source Image"); + m_SpriteTypeContent = EditorGUIUtility.TrTextContent("Image Type"); + m_ClockwiseContent = EditorGUIUtility.TrTextContent("Clockwise"); + + m_Sprite = serializedObject.FindProperty("m_Sprite"); + m_Type = serializedObject.FindProperty("m_Type"); + m_FillCenter = serializedObject.FindProperty("m_FillCenter"); + m_FillMethod = serializedObject.FindProperty("m_FillMethod"); + m_FillOrigin = serializedObject.FindProperty("m_FillOrigin"); + m_FillClockwise = serializedObject.FindProperty("m_FillClockwise"); + m_FillAmount = serializedObject.FindProperty("m_FillAmount"); + m_PreserveAspect = serializedObject.FindProperty("m_PreserveAspect"); + m_UseSpriteMesh = serializedObject.FindProperty("m_UseSpriteMesh"); + m_PixelsPerUnitMultiplier = serializedObject.FindProperty("m_PixelsPerUnitMultiplier"); + + m_ShowType = new AnimBool(m_Sprite.objectReferenceValue != null); + m_ShowType.valueChanged.AddListener(Repaint); + + var typeEnum = (Image.Type)m_Type.enumValueIndex; + + m_ShowSlicedOrTiled = new AnimBool(!m_Type.hasMultipleDifferentValues && typeEnum == Image.Type.Sliced); + m_ShowSliced = new AnimBool(!m_Type.hasMultipleDifferentValues && typeEnum == Image.Type.Sliced); + m_ShowTiled = new AnimBool(!m_Type.hasMultipleDifferentValues && typeEnum == Image.Type.Tiled); + m_ShowFilled = new AnimBool(!m_Type.hasMultipleDifferentValues && typeEnum == Image.Type.Filled); + m_ShowSlicedOrTiled.valueChanged.AddListener(Repaint); + m_ShowSliced.valueChanged.AddListener(Repaint); + m_ShowTiled.valueChanged.AddListener(Repaint); + m_ShowFilled.valueChanged.AddListener(Repaint); + + SetShowNativeSize(true); + + m_bIsDriven = false; + } + + protected override void OnDisable() + { + base.OnDisable(); + + m_ShowType.valueChanged.RemoveListener(Repaint); + m_ShowSlicedOrTiled.valueChanged.RemoveListener(Repaint); + m_ShowSliced.valueChanged.RemoveListener(Repaint); + m_ShowTiled.valueChanged.RemoveListener(Repaint); + m_ShowFilled.valueChanged.RemoveListener(Repaint); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + Image image = target as Image; + RectTransform rect = image.GetComponent(); + m_bIsDriven = (rect.drivenByObject as Slider)?.fillRect == rect; + + SpriteGUI(); + AppearanceControlsGUI(); + RaycastControlsGUI(); + MaskableControlsGUI(); + + m_ShowType.target = m_Sprite.objectReferenceValue != null; + if (EditorGUILayout.BeginFadeGroup(m_ShowType.faded)) + TypeGUI(); + EditorGUILayout.EndFadeGroup(); + + SetShowNativeSize(false); + if (EditorGUILayout.BeginFadeGroup(m_ShowNativeSize.faded)) + { + EditorGUI.indentLevel++; + + if ((Image.Type)m_Type.enumValueIndex == Image.Type.Simple) + EditorGUILayout.PropertyField(m_UseSpriteMesh); + + EditorGUILayout.PropertyField(m_PreserveAspect); + EditorGUI.indentLevel--; + } + EditorGUILayout.EndFadeGroup(); + NativeSizeButtonGUI(); + + serializedObject.ApplyModifiedProperties(); + } + + void SetShowNativeSize(bool instant) + { + Image.Type type = (Image.Type)m_Type.enumValueIndex; + bool showNativeSize = (type == Image.Type.Simple || type == Image.Type.Filled) && m_Sprite.objectReferenceValue != null; + base.SetShowNativeSize(showNativeSize, instant); + } + + /// + /// Draw the atlas and Image selection fields. + /// + + protected void SpriteGUI() + { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_Sprite, m_SpriteContent); + if (EditorGUI.EndChangeCheck()) + { + var newSprite = m_Sprite.objectReferenceValue as Sprite; + if (newSprite) + { + Image.Type oldType = (Image.Type)m_Type.enumValueIndex; + if (newSprite.border.SqrMagnitude() > 0) + { + m_Type.enumValueIndex = (int)Image.Type.Sliced; + } + else if (oldType == Image.Type.Sliced) + { + m_Type.enumValueIndex = (int)Image.Type.Simple; + } + } + (serializedObject.targetObject as Image).DisableSpriteOptimizations(); + } + } + + /// + /// Sprites's custom properties based on the type. + /// + + protected void TypeGUI() + { + EditorGUILayout.PropertyField(m_Type, m_SpriteTypeContent); + + ++EditorGUI.indentLevel; + { + Image.Type typeEnum = (Image.Type)m_Type.enumValueIndex; + + bool showSlicedOrTiled = (!m_Type.hasMultipleDifferentValues && (typeEnum == Image.Type.Sliced || typeEnum == Image.Type.Tiled)); + if (showSlicedOrTiled && targets.Length > 1) + showSlicedOrTiled = targets.Select(obj => obj as Image).All(img => img.hasBorder); + + m_ShowSlicedOrTiled.target = showSlicedOrTiled; + m_ShowSliced.target = (showSlicedOrTiled && !m_Type.hasMultipleDifferentValues && typeEnum == Image.Type.Sliced); + m_ShowTiled.target = (showSlicedOrTiled && !m_Type.hasMultipleDifferentValues && typeEnum == Image.Type.Tiled); + m_ShowFilled.target = (!m_Type.hasMultipleDifferentValues && typeEnum == Image.Type.Filled); + + Image image = target as Image; + if (EditorGUILayout.BeginFadeGroup(m_ShowSlicedOrTiled.faded)) + { + if (image.hasBorder) + EditorGUILayout.PropertyField(m_FillCenter); + EditorGUILayout.PropertyField(m_PixelsPerUnitMultiplier); + } + EditorGUILayout.EndFadeGroup(); + + if (EditorGUILayout.BeginFadeGroup(m_ShowSliced.faded)) + { + if (image.sprite != null && !image.hasBorder) + EditorGUILayout.HelpBox("This Image doesn't have a border.", MessageType.Warning); + } + EditorGUILayout.EndFadeGroup(); + + if (EditorGUILayout.BeginFadeGroup(m_ShowTiled.faded)) + { + if (image.sprite != null && !image.hasBorder && (image.sprite.texture != null && image.sprite.texture.wrapMode != TextureWrapMode.Repeat || image.sprite.packed)) + EditorGUILayout.HelpBox("It looks like you want to tile a sprite with no border. It would be more efficient to modify the Sprite properties, clear the Packing tag and set the Wrap mode to Repeat.", MessageType.Warning); + } + EditorGUILayout.EndFadeGroup(); + + if (EditorGUILayout.BeginFadeGroup(m_ShowFilled.faded)) + { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_FillMethod); + if (EditorGUI.EndChangeCheck()) + { + m_FillOrigin.intValue = 0; + } + var shapeRect = EditorGUILayout.GetControlRect(true); + switch ((Image.FillMethod)m_FillMethod.enumValueIndex) + { + case Image.FillMethod.Horizontal: + EditorGUI.Popup(shapeRect, m_FillOrigin, Styles.OriginHorizontalStyle, Styles.text); + break; + case Image.FillMethod.Vertical: + EditorGUI.Popup(shapeRect, m_FillOrigin, Styles.OriginVerticalStyle, Styles.text); + break; + case Image.FillMethod.Radial90: + EditorGUI.Popup(shapeRect, m_FillOrigin, Styles.Origin90Style, Styles.text); + break; + case Image.FillMethod.Radial180: + EditorGUI.Popup(shapeRect, m_FillOrigin, Styles.Origin180Style, Styles.text); + break; + case Image.FillMethod.Radial360: + EditorGUI.Popup(shapeRect, m_FillOrigin, Styles.Origin360Style, Styles.text); + break; + } + + if (m_bIsDriven) + EditorGUILayout.HelpBox("The Fill amount property is driven by Slider.", MessageType.None); + using (new EditorGUI.DisabledScope(m_bIsDriven)) + { + EditorGUILayout.PropertyField(m_FillAmount); + } + + if ((Image.FillMethod)m_FillMethod.enumValueIndex > Image.FillMethod.Vertical) + { + EditorGUILayout.PropertyField(m_FillClockwise, m_ClockwiseContent); + } + } + EditorGUILayout.EndFadeGroup(); + } + --EditorGUI.indentLevel; + } + + /// + /// All graphics have a preview. + /// + + public override bool HasPreviewGUI() { return true; } + + /// + /// Draw the Image preview. + /// + + public override void OnPreviewGUI(Rect rect, GUIStyle background) + { + Image image = target as Image; + if (image == null) return; + + Sprite sf = image.sprite; + if (sf == null) return; + + SpriteDrawUtility.DrawSprite(sf, rect, image.canvasRenderer.GetColor()); + } + + /// + /// A string containing the Image details to be used as a overlay on the component Preview. + /// + /// + /// The Image details. + /// + + public override string GetInfoString() + { + Image image = target as Image; + Sprite sprite = image.sprite; + + int x = (sprite != null) ? Mathf.RoundToInt(sprite.rect.width) : 0; + int y = (sprite != null) ? Mathf.RoundToInt(sprite.rect.height) : 0; + + return string.Format("Image Size: {0}x{1}", x, y); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/ImageEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/ImageEditor.cs.meta new file mode 100644 index 00000000..a5511816 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/ImageEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b759d61544e231c41bc88530b1d94ee8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/InputFieldEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/InputFieldEditor.cs new file mode 100644 index 00000000..f146ea5a --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/InputFieldEditor.cs @@ -0,0 +1,151 @@ +using UnityEditor.AnimatedValues; +using UnityEngine; +using UnityEngine.UI; + +namespace UnityEditor.UI +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(InputField), true)] + /// + /// Custom Editor for the InputField Component. + /// Extend this class to write a custom editor for a component derived from InputField. + /// + public class InputFieldEditor : SelectableEditor + { + SerializedProperty m_TextComponent; + SerializedProperty m_Text; + SerializedProperty m_ContentType; + SerializedProperty m_LineType; + SerializedProperty m_InputType; + SerializedProperty m_CharacterValidation; + SerializedProperty m_KeyboardType; + SerializedProperty m_CharacterLimit; + SerializedProperty m_CaretBlinkRate; + SerializedProperty m_CaretWidth; + SerializedProperty m_CaretColor; + SerializedProperty m_CustomCaretColor; + SerializedProperty m_SelectionColor; + SerializedProperty m_HideMobileInput; + SerializedProperty m_Placeholder; + SerializedProperty m_OnValueChanged; + SerializedProperty m_OnSubmit; + SerializedProperty m_OnDidEndEdit; + SerializedProperty m_ReadOnly; + SerializedProperty m_ShouldActivateOnSelect; + + AnimBool m_CustomColor; + + GUIContent m_EndEditContent = new GUIContent("On End Edit"); + + protected override void OnEnable() + { + base.OnEnable(); + m_TextComponent = serializedObject.FindProperty("m_TextComponent"); + m_Text = serializedObject.FindProperty("m_Text"); + m_ContentType = serializedObject.FindProperty("m_ContentType"); + m_LineType = serializedObject.FindProperty("m_LineType"); + m_InputType = serializedObject.FindProperty("m_InputType"); + m_CharacterValidation = serializedObject.FindProperty("m_CharacterValidation"); + m_KeyboardType = serializedObject.FindProperty("m_KeyboardType"); + m_CharacterLimit = serializedObject.FindProperty("m_CharacterLimit"); + m_CaretBlinkRate = serializedObject.FindProperty("m_CaretBlinkRate"); + m_CaretWidth = serializedObject.FindProperty("m_CaretWidth"); + m_CaretColor = serializedObject.FindProperty("m_CaretColor"); + m_CustomCaretColor = serializedObject.FindProperty("m_CustomCaretColor"); + m_SelectionColor = serializedObject.FindProperty("m_SelectionColor"); + m_HideMobileInput = serializedObject.FindProperty("m_HideMobileInput"); + m_Placeholder = serializedObject.FindProperty("m_Placeholder"); + m_OnValueChanged = serializedObject.FindProperty("m_OnValueChanged"); + m_OnSubmit = serializedObject.FindProperty("m_OnSubmit"); + m_OnDidEndEdit = serializedObject.FindProperty("m_OnDidEndEdit"); + m_ReadOnly = serializedObject.FindProperty("m_ReadOnly"); + m_ShouldActivateOnSelect = serializedObject.FindProperty("m_ShouldActivateOnSelect"); + + m_CustomColor = new AnimBool(m_CustomCaretColor.boolValue); + m_CustomColor.valueChanged.AddListener(Repaint); + } + + protected override void OnDisable() + { + base.OnDisable(); + m_CustomColor.valueChanged.RemoveListener(Repaint); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + base.OnInspectorGUI(); + + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(m_TextComponent); + + if (m_TextComponent != null && m_TextComponent.objectReferenceValue != null) + { + Text text = m_TextComponent.objectReferenceValue as Text; + if (text.supportRichText) + { + EditorGUILayout.HelpBox("Using Rich Text with input is unsupported.", MessageType.Warning); + } + } + + using (new EditorGUI.DisabledScope(m_TextComponent == null || m_TextComponent.objectReferenceValue == null)) + { + EditorGUILayout.PropertyField(m_Text); + EditorGUILayout.PropertyField(m_CharacterLimit); + + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(m_ContentType); + if (!m_ContentType.hasMultipleDifferentValues) + { + EditorGUI.indentLevel++; + + if (m_ContentType.enumValueIndex == (int)InputField.ContentType.Standard || + m_ContentType.enumValueIndex == (int)InputField.ContentType.Autocorrected || + m_ContentType.enumValueIndex == (int)InputField.ContentType.Custom) + EditorGUILayout.PropertyField(m_LineType); + + if (m_ContentType.enumValueIndex == (int)InputField.ContentType.Custom) + { + EditorGUILayout.PropertyField(m_InputType); + EditorGUILayout.PropertyField(m_KeyboardType); + EditorGUILayout.PropertyField(m_CharacterValidation); + } + + EditorGUI.indentLevel--; + } + + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(m_Placeholder); + EditorGUILayout.PropertyField(m_CaretBlinkRate); + EditorGUILayout.PropertyField(m_CaretWidth); + + EditorGUILayout.PropertyField(m_CustomCaretColor); + + m_CustomColor.target = m_CustomCaretColor.boolValue; + + if (EditorGUILayout.BeginFadeGroup(m_CustomColor.faded)) + { + EditorGUILayout.PropertyField(m_CaretColor); + } + EditorGUILayout.EndFadeGroup(); + + EditorGUILayout.PropertyField(m_SelectionColor); + EditorGUILayout.PropertyField(m_HideMobileInput); + EditorGUILayout.PropertyField(m_ReadOnly); + EditorGUILayout.PropertyField(m_ShouldActivateOnSelect); + + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(m_OnValueChanged); + EditorGUILayout.PropertyField(m_OnSubmit); + EditorGUILayout.PropertyField(m_OnDidEndEdit, m_EndEditContent); + } + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/InputFieldEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/InputFieldEditor.cs.meta new file mode 100644 index 00000000..06e88195 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/InputFieldEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 21d2d5d6901f2ca43a8015c60ada4e2c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/InterceptedEventsPreview.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/InterceptedEventsPreview.cs new file mode 100644 index 00000000..4ea4eef7 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/InterceptedEventsPreview.cs @@ -0,0 +1,270 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEngine; +using UnityEngine.Profiling; +using UnityEngine.EventSystems; + +namespace UnityEditor.Events +{ + [CustomPreview(typeof(GameObject))] + /// + /// Custom preview drawing that will draw the intercepted events of a given object. + /// + class InterceptedEventsPreview : ObjectPreview + { + protected class ComponentInterceptedEvents + { + public GUIContent componentName; + public int[] interceptedEvents; + } + + class Styles + { + public GUIStyle labelStyle = new GUIStyle(EditorStyles.label); + public GUIStyle componentName = new GUIStyle(EditorStyles.boldLabel); + + public Styles() + { + Color fontColor = new Color(0.7f, 0.7f, 0.7f); + labelStyle.padding.right += 20; + labelStyle.normal.textColor = fontColor; + labelStyle.active.textColor = fontColor; + labelStyle.focused.textColor = fontColor; + labelStyle.hover.textColor = fontColor; + labelStyle.onNormal.textColor = fontColor; + labelStyle.onActive.textColor = fontColor; + labelStyle.onFocused.textColor = fontColor; + labelStyle.onHover.textColor = fontColor; + + componentName.normal.textColor = fontColor; + componentName.active.textColor = fontColor; + componentName.focused.textColor = fontColor; + componentName.hover.textColor = fontColor; + componentName.onNormal.textColor = fontColor; + componentName.onActive.textColor = fontColor; + componentName.onFocused.textColor = fontColor; + componentName.onHover.textColor = fontColor; + } + } + + private Dictionary> m_TargetEvents; + private bool m_InterceptsAnyEvent = false; + private GUIContent m_Title; + private Styles m_Styles; + + public override void Initialize(UnityEngine.Object[] targets) + { + Profiler.BeginSample("ComponentInterceptedEvents.Initialize"); + + base.Initialize(targets); + m_TargetEvents = new Dictionary>(targets.Length); + m_InterceptsAnyEvent = false; + for (int i = 0; i < targets.Length; ++i) + { + GameObject go = targets[i] as GameObject; + List interceptedEvents = GetEventsInfo(go); + m_TargetEvents.Add(go, interceptedEvents); + if (interceptedEvents.Any()) + m_InterceptsAnyEvent = true; + } + Profiler.EndSample(); + } + + public override GUIContent GetPreviewTitle() + { + if (m_Title == null) + { + m_Title = EditorGUIUtility.TrTextContent("Intercepted Events"); + } + return m_Title; + } + + public override bool HasPreviewGUI() + { + return m_TargetEvents != null && m_InterceptsAnyEvent; + } + + public override void OnPreviewGUI(Rect r, GUIStyle background) + { + if (Event.current.type != EventType.Repaint) + return; + Profiler.BeginSample("InterceptedEventsPreview.OnPreviewGUI"); + + + if (m_Styles == null) + m_Styles = new Styles(); + + Vector2 maxEventLabelSize = Vector2.zero; + int totalInterceptedEvents = 0; + + List componentIncerceptedEvents = m_TargetEvents[target as GameObject]; + + // Find out the maximum size needed for any given label. + foreach (ComponentInterceptedEvents componentInterceptedEvents in componentIncerceptedEvents) + { + foreach (int eventIndex in componentInterceptedEvents.interceptedEvents) + { + GUIContent eventContent = s_PossibleEvents[eventIndex]; + ++totalInterceptedEvents; + Vector2 labelSize = m_Styles.labelStyle.CalcSize(eventContent); + if (maxEventLabelSize.x < labelSize.x) + { + maxEventLabelSize.x = labelSize.x; + } + if (maxEventLabelSize.y < labelSize.y) + { + maxEventLabelSize.y = labelSize.y; + } + } + } + + // Apply padding + RectOffset previewPadding = new RectOffset(-5, -5, -5, -5); + r = previewPadding.Add(r); + + // Figure out how many rows and columns we can/should have + int columns = Mathf.Max(Mathf.FloorToInt(r.width / maxEventLabelSize.x), 1); + int rows = Mathf.Max(totalInterceptedEvents / columns, 1) + componentIncerceptedEvents.Count; + + // Centering + float initialX = r.x + Mathf.Max(0, (r.width - (maxEventLabelSize.x * columns)) / 2); + float initialY = r.y + Mathf.Max(0, (r.height - (maxEventLabelSize.y * rows)) / 2); + + Rect labelRect = new Rect(initialX, initialY, maxEventLabelSize.x, maxEventLabelSize.y); + int currentColumn = 0; + foreach (ComponentInterceptedEvents componentInterceptedEvents in componentIncerceptedEvents) + { + GUI.Label(labelRect, componentInterceptedEvents.componentName, m_Styles.componentName); + labelRect.y += labelRect.height; + labelRect.x = initialX; + foreach (int eventIndex in componentInterceptedEvents.interceptedEvents) + { + GUIContent eventContent = s_PossibleEvents[eventIndex]; + GUI.Label(labelRect, eventContent, m_Styles.labelStyle); + if (currentColumn < columns - 1) + { + labelRect.x += labelRect.width; + } + else + { + labelRect.y += labelRect.height; + labelRect.x = initialX; + } + + currentColumn = (currentColumn + 1) % columns; + } + + if (labelRect.x != initialX) + { + labelRect.y += labelRect.height; + labelRect.x = initialX; + } + } + Profiler.EndSample(); + } + + //Lookup cache to avoid recalculating which types uses which events: + //Caches all interfaces that inherit from IEventSystemHandler + static List s_EventSystemInterfaces = null; + //Caches all GUIContents in a single list to avoid creating too much GUIContent and strings. + private static List s_PossibleEvents = null; + //Caches all events used by each interface + static Dictionary> s_InterfaceEventSystemEvents = null; + //Caches each concrete type and it's events + static readonly Dictionary s_ComponentEvents2 = new Dictionary(); + + + protected static List GetEventsInfo(GameObject gameObject) + { + InitializeEvetnsInterfaceCacheIfNeeded(); + + List componentEvents = new List(); + + MonoBehaviour[] mbs = gameObject.GetComponents(); + + for (int i = 0, imax = mbs.Length; i < imax; ++i) + { + ComponentInterceptedEvents componentEvent = null; + + MonoBehaviour mb = mbs[i]; + if (mb == null) + continue; + + Type type = mb.GetType(); + + if (!s_ComponentEvents2.ContainsKey(type)) + { + List events = null; + Profiler.BeginSample("ComponentInterceptedEvents.GetEventsInfo.NewType"); + if (typeof(IEventSystemHandler).IsAssignableFrom(type)) + { + for (int index = 0; index < s_EventSystemInterfaces.Count; index++) + { + var eventInterface = s_EventSystemInterfaces[index]; + if (!eventInterface.IsAssignableFrom(type)) + continue; + + if (events == null) + events = new List(); + + events.AddRange(s_InterfaceEventSystemEvents[eventInterface]); + } + } + + if (events != null) + { + componentEvent = new ComponentInterceptedEvents(); + componentEvent.componentName = new GUIContent(type.Name); + componentEvent.interceptedEvents = events.OrderBy(index => s_PossibleEvents[index].text).ToArray(); + } + s_ComponentEvents2.Add(type, componentEvent); + + Profiler.EndSample(); + } + else + { + componentEvent = s_ComponentEvents2[type]; + } + + + if (componentEvent != null) + { + componentEvents.Add(componentEvent); + } + } + + return componentEvents; + } + + private static void InitializeEvetnsInterfaceCacheIfNeeded() + { + if (s_EventSystemInterfaces != null) + return; + + s_EventSystemInterfaces = new List(); + s_PossibleEvents = new List(); + s_InterfaceEventSystemEvents = new Dictionary>(); + + TypeCache.TypeCollection types = TypeCache.GetTypesDerivedFrom(); + foreach (var type in types) + { + if (!type.IsInterface) + continue; + + s_EventSystemInterfaces.Add(type); + List eventIndexList = new List(); + + MethodInfo[] methodInfos = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + for (int mi = 0; mi < methodInfos.Length; mi++) + { + MethodInfo methodInfo = methodInfos[mi]; + eventIndexList.Add(s_PossibleEvents.Count); + s_PossibleEvents.Add(new GUIContent(methodInfo.Name)); + } + s_InterfaceEventSystemEvents.Add(type, eventIndexList); + } + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/InterceptedEventsPreview.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/InterceptedEventsPreview.cs.meta new file mode 100644 index 00000000..615b3454 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/InterceptedEventsPreview.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 127023922adddf744b59fa7b0b0c3030 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/LayoutElementEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/LayoutElementEditor.cs new file mode 100644 index 00000000..8675f7ea --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/LayoutElementEditor.cs @@ -0,0 +1,106 @@ +using UnityEngine; +using UnityEngine.UI; +using UnityEditorInternal; +using UnityEditor.AnimatedValues; + +namespace UnityEditor.UI +{ + [CustomEditor(typeof(LayoutElement), true)] + [CanEditMultipleObjects] + /// + /// Custom editor for the LayoutElement component + /// Extend this class to write a custom editor for a component derived from LayoutElement. + /// + public class LayoutElementEditor : Editor + { + SerializedProperty m_IgnoreLayout; + SerializedProperty m_MinWidth; + SerializedProperty m_MinHeight; + SerializedProperty m_PreferredWidth; + SerializedProperty m_PreferredHeight; + SerializedProperty m_FlexibleWidth; + SerializedProperty m_FlexibleHeight; + SerializedProperty m_LayoutPriority; + + protected virtual void OnEnable() + { + m_IgnoreLayout = serializedObject.FindProperty("m_IgnoreLayout"); + m_MinWidth = serializedObject.FindProperty("m_MinWidth"); + m_MinHeight = serializedObject.FindProperty("m_MinHeight"); + m_PreferredWidth = serializedObject.FindProperty("m_PreferredWidth"); + m_PreferredHeight = serializedObject.FindProperty("m_PreferredHeight"); + m_FlexibleWidth = serializedObject.FindProperty("m_FlexibleWidth"); + m_FlexibleHeight = serializedObject.FindProperty("m_FlexibleHeight"); + m_LayoutPriority = serializedObject.FindProperty("m_LayoutPriority"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.PropertyField(m_IgnoreLayout); + + if (!m_IgnoreLayout.boolValue) + { + EditorGUILayout.Space(); + + LayoutElementField(m_MinWidth, 0); + LayoutElementField(m_MinHeight, 0); + LayoutElementField(m_PreferredWidth, t => t.rect.width); + LayoutElementField(m_PreferredHeight, t => t.rect.height); + LayoutElementField(m_FlexibleWidth, 1); + LayoutElementField(m_FlexibleHeight, 1); + } + + EditorGUILayout.PropertyField(m_LayoutPriority); + + serializedObject.ApplyModifiedProperties(); + } + + void LayoutElementField(SerializedProperty property, float defaultValue) + { + LayoutElementField(property, _ => defaultValue); + } + + void LayoutElementField(SerializedProperty property, System.Func defaultValue) + { + Rect position = EditorGUILayout.GetControlRect(); + + // Label + GUIContent label = EditorGUI.BeginProperty(position, null, property); + + // Rects + Rect fieldPosition = EditorGUI.PrefixLabel(position, label); + + Rect toggleRect = fieldPosition; + toggleRect.width = 16; + + Rect floatFieldRect = fieldPosition; + floatFieldRect.xMin += 16; + + // Checkbox + EditorGUI.BeginChangeCheck(); + bool enabled = EditorGUI.ToggleLeft(toggleRect, GUIContent.none, property.floatValue >= 0); + if (EditorGUI.EndChangeCheck()) + { + // This could be made better to set all of the targets to their initial width, but mimizing code change for now + property.floatValue = (enabled ? defaultValue((target as LayoutElement).transform as RectTransform) : -1); + } + + if (!property.hasMultipleDifferentValues && property.floatValue >= 0) + { + // Float field + EditorGUIUtility.labelWidth = 4; // Small invisible label area for drag zone functionality + EditorGUI.BeginChangeCheck(); + float newValue = EditorGUI.FloatField(floatFieldRect, new GUIContent(" "), property.floatValue); + if (EditorGUI.EndChangeCheck()) + { + property.floatValue = Mathf.Max(0, newValue); + } + EditorGUIUtility.labelWidth = 0; + } + + EditorGUI.EndProperty(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/LayoutElementEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/LayoutElementEditor.cs.meta new file mode 100644 index 00000000..5a1dd266 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/LayoutElementEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7693972390a4ed841a986c0c452c1058 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/LayoutPropertiesPreview.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/LayoutPropertiesPreview.cs new file mode 100644 index 00000000..de984835 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/LayoutPropertiesPreview.cs @@ -0,0 +1,127 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; +using System.Globalization; + +namespace UnityEditor.Events +{ + [CustomPreview(typeof(GameObject))] + /// + /// Custom preview drawing that will draw the layout properties of a given object. + /// + class LayoutPropertiesPreview : ObjectPreview + { + private const float kLabelWidth = 110; + private const float kValueWidth = 100; + + class Styles + { + public GUIStyle labelStyle = new GUIStyle(EditorStyles.label); + public GUIStyle headerStyle = new GUIStyle(EditorStyles.boldLabel); + + public Styles() + { + labelStyle.padding.right += 4; + headerStyle.padding.right += 4; + } + } + + private GUIContent m_Title; + private Styles m_Styles; + + public override void Initialize(UnityEngine.Object[] targets) + { + base.Initialize(targets); + } + + public override GUIContent GetPreviewTitle() + { + if (m_Title == null) + { + m_Title = EditorGUIUtility.TrTextContent("Layout Properties"); + } + return m_Title; + } + + public override bool HasPreviewGUI() + { + GameObject go = target as GameObject; + if (!go) + return false; + + // Prevent allocations in the editor by using TryGetComponent + ILayoutElement layoutElement; + return go.TryGetComponent(out layoutElement); + } + + public override void OnPreviewGUI(Rect r, GUIStyle background) + { + if (Event.current.type != EventType.Repaint) + return; + + if (m_Styles == null) + m_Styles = new Styles(); + + GameObject go = target as GameObject; + RectTransform rect = go.transform as RectTransform; + if (rect == null) + return; + + // Apply padding + RectOffset previewPadding = new RectOffset(-5, -5, -5, -5); + r = previewPadding.Add(r); + + // Prepare rects for columns + r.height = EditorGUIUtility.singleLineHeight; + Rect labelRect = r; + Rect valueRect = r; + Rect sourceRect = r; + labelRect.width = kLabelWidth; + valueRect.xMin += kLabelWidth; + valueRect.width = kValueWidth; + sourceRect.xMin += kLabelWidth + kValueWidth; + + // Headers + GUI.Label(labelRect, "Property", m_Styles.headerStyle); + GUI.Label(valueRect, "Value", m_Styles.headerStyle); + GUI.Label(sourceRect, "Source", m_Styles.headerStyle); + labelRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + valueRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + sourceRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + + // Prepare reusable variable for out argument + ILayoutElement source = null; + + // Show properties + + ShowProp(ref labelRect, ref valueRect, ref sourceRect, "Min Width", LayoutUtility.GetLayoutProperty(rect, e => e.minWidth, 0, out source).ToString(CultureInfo.InvariantCulture.NumberFormat), source); + ShowProp(ref labelRect, ref valueRect, ref sourceRect, "Min Height", LayoutUtility.GetLayoutProperty(rect, e => e.minHeight, 0, out source).ToString(CultureInfo.InvariantCulture.NumberFormat), source); + ShowProp(ref labelRect, ref valueRect, ref sourceRect, "Preferred Width", LayoutUtility.GetLayoutProperty(rect, e => e.preferredWidth, 0, out source).ToString(CultureInfo.InvariantCulture.NumberFormat), source); + ShowProp(ref labelRect, ref valueRect, ref sourceRect, "Preferred Height", LayoutUtility.GetLayoutProperty(rect, e => e.preferredHeight, 0, out source).ToString(CultureInfo.InvariantCulture.NumberFormat), source); + + float flexible = 0; + + flexible = LayoutUtility.GetLayoutProperty(rect, e => e.flexibleWidth, 0, out source); + ShowProp(ref labelRect, ref valueRect, ref sourceRect, "Flexible Width", flexible > 0 ? ("enabled (" + flexible.ToString(CultureInfo.InvariantCulture.NumberFormat) + ")") : "disabled", source); + flexible = LayoutUtility.GetLayoutProperty(rect, e => e.flexibleHeight, 0, out source); + ShowProp(ref labelRect, ref valueRect, ref sourceRect, "Flexible Height", flexible > 0 ? ("enabled (" + flexible.ToString(CultureInfo.InvariantCulture.NumberFormat) + ")") : "disabled", source); + + if (!rect.GetComponent()) + { + Rect noteRect = new Rect(labelRect.x, labelRect.y + 10, r.width, EditorGUIUtility.singleLineHeight); + GUI.Label(noteRect, "Add a LayoutElement to override values.", m_Styles.labelStyle); + } + } + + private void ShowProp(ref Rect labelRect, ref Rect valueRect, ref Rect sourceRect, string label, string value, ILayoutElement source) + { + GUI.Label(labelRect, label, m_Styles.labelStyle); + GUI.Label(valueRect, value, m_Styles.labelStyle); + GUI.Label(sourceRect, source == null ? "none" : source.GetType().Name, m_Styles.labelStyle); + labelRect.y += EditorGUIUtility.singleLineHeight; + valueRect.y += EditorGUIUtility.singleLineHeight; + sourceRect.y += EditorGUIUtility.singleLineHeight; + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/LayoutPropertiesPreview.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/LayoutPropertiesPreview.cs.meta new file mode 100644 index 00000000..9df54b81 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/LayoutPropertiesPreview.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 794f3951c48395848920fdb593a2ae38 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/MaskEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/MaskEditor.cs new file mode 100644 index 00000000..e4e1c84c --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/MaskEditor.cs @@ -0,0 +1,32 @@ +using UnityEngine.UI; + +namespace UnityEditor.UI +{ + [CustomEditor(typeof(Mask), true)] + [CanEditMultipleObjects] + /// + /// Custom Editor for the Mask component. + /// Extend this class to write a custom editor for a component derived from Mask. + /// + public class MaskEditor : Editor + { + SerializedProperty m_ShowMaskGraphic; + + protected virtual void OnEnable() + { + m_ShowMaskGraphic = serializedObject.FindProperty("m_ShowMaskGraphic"); + } + + public override void OnInspectorGUI() + { + var graphic = (target as Mask).GetComponent(); + + if (graphic && !graphic.IsActive()) + EditorGUILayout.HelpBox("Masking disabled due to Graphic component being disabled.", MessageType.Warning); + + serializedObject.Update(); + EditorGUILayout.PropertyField(m_ShowMaskGraphic); + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/MaskEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/MaskEditor.cs.meta new file mode 100644 index 00000000..f04bd096 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/MaskEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b10cb8fee5b39014d8a417bf413f5e5c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/MenuOptions.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/MenuOptions.cs new file mode 100644 index 00000000..491d1f2e --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/MenuOptions.cs @@ -0,0 +1,435 @@ +using System; +using UnityEditor.SceneManagement; +using UnityEditor.EventSystems; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace UnityEditor.UI +{ + /// + /// This script adds the UI menu options to the Unity Editor. + /// + + static internal class MenuOptions + { + enum MenuOptionsPriorityOrder { + // 2000 - Text (TMP) + Image = 2001, + RawImage = 2002, + Panel = 2003, + // 2020 - Button (TMP) + Toggle = 2021, + // 2022 - Dropdown (TMP) + // 2023 - Input Field (TMP) + Slider = 2024, + Scrollbar = 2025, + ScrollView = 2026, + Canvas = 2060, + EventSystem = 2061, + Text = 2080, + Button = 2081, + Dropdown = 2082, + InputField = 2083, + }; + + private const string kUILayerName = "UI"; + + private const string kStandardSpritePath = "UI/Skin/UISprite.psd"; + private const string kBackgroundSpritePath = "UI/Skin/Background.psd"; + private const string kInputFieldBackgroundPath = "UI/Skin/InputFieldBackground.psd"; + private const string kKnobPath = "UI/Skin/Knob.psd"; + private const string kCheckmarkPath = "UI/Skin/Checkmark.psd"; + private const string kDropdownArrowPath = "UI/Skin/DropdownArrow.psd"; + private const string kMaskPath = "UI/Skin/UIMask.psd"; + + static private DefaultControls.Resources s_StandardResources; + + static private DefaultControls.Resources GetStandardResources() + { + if (s_StandardResources.standard == null) + { + s_StandardResources.standard = AssetDatabase.GetBuiltinExtraResource(kStandardSpritePath); + s_StandardResources.background = AssetDatabase.GetBuiltinExtraResource(kBackgroundSpritePath); + s_StandardResources.inputField = AssetDatabase.GetBuiltinExtraResource(kInputFieldBackgroundPath); + s_StandardResources.knob = AssetDatabase.GetBuiltinExtraResource(kKnobPath); + s_StandardResources.checkmark = AssetDatabase.GetBuiltinExtraResource(kCheckmarkPath); + s_StandardResources.dropdown = AssetDatabase.GetBuiltinExtraResource(kDropdownArrowPath); + s_StandardResources.mask = AssetDatabase.GetBuiltinExtraResource(kMaskPath); + } + return s_StandardResources; + } + + private class DefaultEditorFactory : DefaultControls.IFactoryControls + { + public static DefaultEditorFactory Default = new DefaultEditorFactory(); + + public GameObject CreateGameObject(string name, params Type[] components) + { + return ObjectFactory.CreateGameObject(name, components); + } + } + + private class FactorySwapToEditor : IDisposable + { + DefaultControls.IFactoryControls factory; + + public FactorySwapToEditor() + { + factory = DefaultControls.factory; + DefaultControls.factory = DefaultEditorFactory.Default; + } + + public void Dispose() + { + DefaultControls.factory = factory; + } + } + + private static void SetPositionVisibleinSceneView(RectTransform canvasRTransform, RectTransform itemTransform) + { + SceneView sceneView = SceneView.lastActiveSceneView; + + // Couldn't find a SceneView. Don't set position. + if (sceneView == null || sceneView.camera == null) + return; + + // Create world space Plane from canvas position. + Vector2 localPlanePosition; + Camera camera = sceneView.camera; + Vector3 position = Vector3.zero; + if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRTransform, new Vector2(camera.pixelWidth / 2, camera.pixelHeight / 2), camera, out localPlanePosition)) + { + // Adjust for canvas pivot + localPlanePosition.x = localPlanePosition.x + canvasRTransform.sizeDelta.x * canvasRTransform.pivot.x; + localPlanePosition.y = localPlanePosition.y + canvasRTransform.sizeDelta.y * canvasRTransform.pivot.y; + + localPlanePosition.x = Mathf.Clamp(localPlanePosition.x, 0, canvasRTransform.sizeDelta.x); + localPlanePosition.y = Mathf.Clamp(localPlanePosition.y, 0, canvasRTransform.sizeDelta.y); + + // Adjust for anchoring + position.x = localPlanePosition.x - canvasRTransform.sizeDelta.x * itemTransform.anchorMin.x; + position.y = localPlanePosition.y - canvasRTransform.sizeDelta.y * itemTransform.anchorMin.y; + + Vector3 minLocalPosition; + minLocalPosition.x = canvasRTransform.sizeDelta.x * (0 - canvasRTransform.pivot.x) + itemTransform.sizeDelta.x * itemTransform.pivot.x; + minLocalPosition.y = canvasRTransform.sizeDelta.y * (0 - canvasRTransform.pivot.y) + itemTransform.sizeDelta.y * itemTransform.pivot.y; + + Vector3 maxLocalPosition; + maxLocalPosition.x = canvasRTransform.sizeDelta.x * (1 - canvasRTransform.pivot.x) - itemTransform.sizeDelta.x * itemTransform.pivot.x; + maxLocalPosition.y = canvasRTransform.sizeDelta.y * (1 - canvasRTransform.pivot.y) - itemTransform.sizeDelta.y * itemTransform.pivot.y; + + position.x = Mathf.Clamp(position.x, minLocalPosition.x, maxLocalPosition.x); + position.y = Mathf.Clamp(position.y, minLocalPosition.y, maxLocalPosition.y); + } + + itemTransform.anchoredPosition = position; + itemTransform.localRotation = Quaternion.identity; + itemTransform.localScale = Vector3.one; + } + + private static void PlaceUIElementRoot(GameObject element, MenuCommand menuCommand) + { + GameObject parent = menuCommand.context as GameObject; + bool explicitParentChoice = true; + if (parent == null) + { + parent = GetOrCreateCanvasGameObject(); + explicitParentChoice = false; + + // If in Prefab Mode, Canvas has to be part of Prefab contents, + // otherwise use Prefab root instead. + PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage(); + if (prefabStage != null && !prefabStage.IsPartOfPrefabContents(parent)) + parent = prefabStage.prefabContentsRoot; + } + if (parent.GetComponentsInParent(true).Length == 0) + { + // Create canvas under context GameObject, + // and make that be the parent which UI element is added under. + GameObject canvas = MenuOptions.CreateNewUI(); + Undo.SetTransformParent(canvas.transform, parent.transform, ""); + parent = canvas; + } + + GameObjectUtility.EnsureUniqueNameForSibling(element); + + SetParentAndAlign(element, parent); + if (!explicitParentChoice) // not a context click, so center in sceneview + SetPositionVisibleinSceneView(parent.GetComponent(), element.GetComponent()); + + // This call ensure any change made to created Objects after they where registered will be part of the Undo. + Undo.RegisterFullObjectHierarchyUndo(parent == null ? element : parent, ""); + + // We have to fix up the undo name since the name of the object was only known after reparenting it. + Undo.SetCurrentGroupName("Create " + element.name); + + Selection.activeGameObject = element; + } + + private static void SetParentAndAlign(GameObject child, GameObject parent) + { + if (parent == null) + return; + + Undo.SetTransformParent(child.transform, parent.transform, ""); + + RectTransform rectTransform = child.transform as RectTransform; + if (rectTransform) + { + rectTransform.anchoredPosition = Vector2.zero; + Vector3 localPosition = rectTransform.localPosition; + localPosition.z = 0; + rectTransform.localPosition = localPosition; + } + else + { + child.transform.localPosition = Vector3.zero; + } + child.transform.localRotation = Quaternion.identity; + child.transform.localScale = Vector3.one; + + SetLayerRecursively(child, parent.layer); + } + + private static void SetLayerRecursively(GameObject go, int layer) + { + go.layer = layer; + Transform t = go.transform; + for (int i = 0; i < t.childCount; i++) + SetLayerRecursively(t.GetChild(i).gameObject, layer); + } + + // Graphic elements + + [MenuItem("GameObject/UI/Image", false, (int)MenuOptionsPriorityOrder.Image)] + static public void AddImage(MenuCommand menuCommand) + { + GameObject go; + using (new FactorySwapToEditor()) + go = DefaultControls.CreateImage(GetStandardResources()); + PlaceUIElementRoot(go, menuCommand); + } + + [MenuItem("GameObject/UI/Raw Image", false, (int)MenuOptionsPriorityOrder.RawImage)] + static public void AddRawImage(MenuCommand menuCommand) + { + GameObject go; + using (new FactorySwapToEditor()) + go = DefaultControls.CreateRawImage(GetStandardResources()); + PlaceUIElementRoot(go, menuCommand); + } + + [MenuItem("GameObject/UI/Panel", false, (int)MenuOptionsPriorityOrder.Panel)] + static public void AddPanel(MenuCommand menuCommand) + { + GameObject go; + using (new FactorySwapToEditor()) + go = DefaultControls.CreatePanel(GetStandardResources()); + PlaceUIElementRoot(go, menuCommand); + + // Panel is special, we need to ensure there's no padding after repositioning. + RectTransform rect = go.GetComponent(); + rect.anchoredPosition = Vector2.zero; + rect.sizeDelta = Vector2.zero; + } + + // Controls + + // Toggle is a control you just click on. + + [MenuItem("GameObject/UI/Toggle", false, (int)MenuOptionsPriorityOrder.Toggle)] + static public void AddToggle(MenuCommand menuCommand) + { + GameObject go; + using (new FactorySwapToEditor()) + go = DefaultControls.CreateToggle(GetStandardResources()); + PlaceUIElementRoot(go, menuCommand); + } + + // Slider and Scrollbar modify a number + + [MenuItem("GameObject/UI/Slider", false, (int)MenuOptionsPriorityOrder.Slider)] + static public void AddSlider(MenuCommand menuCommand) + { + GameObject go; + using (new FactorySwapToEditor()) + go = DefaultControls.CreateSlider(GetStandardResources()); + PlaceUIElementRoot(go, menuCommand); + } + + [MenuItem("GameObject/UI/Scrollbar", false, (int)MenuOptionsPriorityOrder.Scrollbar)] + static public void AddScrollbar(MenuCommand menuCommand) + { + GameObject go; + using (new FactorySwapToEditor()) + go = DefaultControls.CreateScrollbar(GetStandardResources()); + PlaceUIElementRoot(go, menuCommand); + } + + [MenuItem("GameObject/UI/Scroll View", false, (int)MenuOptionsPriorityOrder.ScrollView)] + static public void AddScrollView(MenuCommand menuCommand) + { + GameObject go; + using (new FactorySwapToEditor()) + go = DefaultControls.CreateScrollView(GetStandardResources()); + PlaceUIElementRoot(go, menuCommand); + } + + // Containers + + [MenuItem("GameObject/UI/Canvas", false, (int)MenuOptionsPriorityOrder.Canvas)] + static public void AddCanvas(MenuCommand menuCommand) + { + var go = CreateNewUI(); + SetParentAndAlign(go, menuCommand.context as GameObject); + if (go.transform.parent as RectTransform) + { + RectTransform rect = go.transform as RectTransform; + rect.anchorMin = Vector2.zero; + rect.anchorMax = Vector2.one; + rect.anchoredPosition = Vector2.zero; + rect.sizeDelta = Vector2.zero; + } + Selection.activeGameObject = go; + } + + // Legacy Elements + + [MenuItem("GameObject/UI/Legacy/Text", false, (int)MenuOptionsPriorityOrder.Text)] + static public void AddText(MenuCommand menuCommand) + { + GameObject go; + using (new FactorySwapToEditor()) + go = DefaultControls.CreateText(GetStandardResources()); + PlaceUIElementRoot(go, menuCommand); + } + + [MenuItem("GameObject/UI/Legacy/Button", false, (int)MenuOptionsPriorityOrder.Button)] + static public void AddButton(MenuCommand menuCommand) + { + GameObject go; + using (new FactorySwapToEditor()) + go = DefaultControls.CreateButton(GetStandardResources()); + PlaceUIElementRoot(go, menuCommand); + } + + [MenuItem("GameObject/UI/Legacy/Dropdown", false, (int)MenuOptionsPriorityOrder.Dropdown)] + static public void AddDropdown(MenuCommand menuCommand) + { + GameObject go; + using (new FactorySwapToEditor()) + go = DefaultControls.CreateDropdown(GetStandardResources()); + PlaceUIElementRoot(go, menuCommand); + } + + [MenuItem("GameObject/UI/Legacy/Input Field", false, (int)MenuOptionsPriorityOrder.InputField)] + public static void AddInputField(MenuCommand menuCommand) + { + GameObject go; + using (new FactorySwapToEditor()) + go = DefaultControls.CreateInputField(GetStandardResources()); + PlaceUIElementRoot(go, menuCommand); + } + + // Helper methods + + static public GameObject CreateNewUI() + { + // Root for the UI + var root = ObjectFactory.CreateGameObject("Canvas", typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster)); + root.layer = LayerMask.NameToLayer(kUILayerName); + Canvas canvas = root.GetComponent(); + canvas.renderMode = RenderMode.ScreenSpaceOverlay; + + // Works for all stages. + StageUtility.PlaceGameObjectInCurrentStage(root); + bool customScene = false; + PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage(); + if (prefabStage != null) + { + Undo.SetTransformParent(root.transform, prefabStage.prefabContentsRoot.transform, ""); + customScene = true; + } + + Undo.SetCurrentGroupName("Create " + root.name); + + // If there is no event system add one... + // No need to place event system in custom scene as these are temporary anyway. + // It can be argued for or against placing it in the user scenes, + // but let's not modify scene user is not currently looking at. + if (!customScene) + CreateEventSystem(false); + return root; + } + + [MenuItem("GameObject/UI/Event System", false, (int)MenuOptionsPriorityOrder.EventSystem)] + public static void CreateEventSystem(MenuCommand menuCommand) + { + GameObject parent = menuCommand.context as GameObject; + CreateEventSystem(true, parent); + } + + private static void CreateEventSystem(bool select) + { + CreateEventSystem(select, null); + } + + private static void CreateEventSystem(bool select, GameObject parent) + { + StageHandle stage = parent == null ? StageUtility.GetCurrentStageHandle() : StageUtility.GetStageHandle(parent); + var esys = stage.FindComponentOfType(); + if (esys == null) + { + var eventSystem = ObjectFactory.CreateGameObject("EventSystem"); + if (parent == null) + StageUtility.PlaceGameObjectInCurrentStage(eventSystem); + else + SetParentAndAlign(eventSystem, parent); + esys = ObjectFactory.AddComponent(eventSystem); + InputModuleComponentFactory.AddInputModule(eventSystem); + + Undo.RegisterCreatedObjectUndo(eventSystem, "Create " + eventSystem.name); + } + + if (select && esys != null) + { + Selection.activeGameObject = esys.gameObject; + } + } + + // Helper function that returns a Canvas GameObject; preferably a parent of the selection, or other existing Canvas. + static public GameObject GetOrCreateCanvasGameObject() + { + GameObject selectedGo = Selection.activeGameObject; + + // Try to find a gameobject that is the selected GO or one if its parents. + Canvas canvas = (selectedGo != null) ? selectedGo.GetComponentInParent() : null; + if (IsValidCanvas(canvas)) + return canvas.gameObject; + + // No canvas in selection or its parents? Then use any valid canvas. + // We have to find all loaded Canvases, not just the ones in main scenes. + Canvas[] canvasArray = StageUtility.GetCurrentStageHandle().FindComponentsOfType(); + for (int i = 0; i < canvasArray.Length; i++) + if (IsValidCanvas(canvasArray[i])) + return canvasArray[i].gameObject; + + // No canvas in the scene at all? Then create a new one. + return MenuOptions.CreateNewUI(); + } + + static bool IsValidCanvas(Canvas canvas) + { + if (canvas == null || !canvas.gameObject.activeInHierarchy) + return false; + + // It's important that the non-editable canvas from a prefab scene won't be rejected, + // but canvases not visible in the Hierarchy at all do. Don't check for HideAndDontSave. + if (EditorUtility.IsPersistent(canvas) || (canvas.hideFlags & HideFlags.HideInHierarchy) != 0) + return false; + + return StageUtility.GetStageHandle(canvas.gameObject) == StageUtility.GetCurrentStageHandle(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/MenuOptions.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/MenuOptions.cs.meta new file mode 100644 index 00000000..c66a09f5 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/MenuOptions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f867743975592a743a3581ff042bcc25 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/PrefabLayoutRebuilder.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/PrefabLayoutRebuilder.cs new file mode 100644 index 00000000..0f933dad --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/PrefabLayoutRebuilder.cs @@ -0,0 +1,24 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace UnityEditor.UI +{ + [InitializeOnLoad] + internal class PrefabLayoutRebuilder + { + static PrefabLayoutRebuilder() + { + PrefabUtility.prefabInstanceUpdated += OnPrefabInstanceUpdates; + } + + static void OnPrefabInstanceUpdates(GameObject instance) + { + if (instance) + { + RectTransform rect = instance.transform as RectTransform; + if (rect) + LayoutRebuilder.MarkLayoutForRebuild(rect); + } + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/PrefabLayoutRebuilder.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/PrefabLayoutRebuilder.cs.meta new file mode 100644 index 00000000..35e0b75c --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/PrefabLayoutRebuilder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a62706dc421fc9b4fa368a8050a930f7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers.meta new file mode 100644 index 00000000..7b2dc62e --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bc9aa6d5a7945f34882c442e9e201537 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/AnimationTriggersDrawer.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/AnimationTriggersDrawer.cs new file mode 100644 index 00000000..a0fd9e35 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/AnimationTriggersDrawer.cs @@ -0,0 +1,69 @@ +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UI; +using UnityEngine.UIElements; + +namespace UnityEditor.UI +{ + [CustomPropertyDrawer(typeof(AnimationTriggers), true)] + /// + /// This is a PropertyDrawer for AnimationTriggers. It is implemented using the standard Unity PropertyDrawer framework. + /// + public class AnimationTriggersDrawer : PropertyDrawer + { + const string kNormalTrigger = "m_NormalTrigger"; + const string kHighlightedTrigger = "m_HighlightedTrigger"; + const string kPressedTrigger = "m_PressedTrigger"; + const string kSelectedTrigger = "m_SelectedTrigger"; + const string kDisabledTrigger = "m_DisabledTrigger"; + + public override void OnGUI(Rect rect, SerializedProperty prop, GUIContent label) + { + Rect drawRect = rect; + drawRect.height = EditorGUIUtility.singleLineHeight; + + SerializedProperty normalTrigger = prop.FindPropertyRelative(kNormalTrigger); + SerializedProperty higlightedTrigger = prop.FindPropertyRelative(kHighlightedTrigger); + SerializedProperty pressedTrigger = prop.FindPropertyRelative(kPressedTrigger); + SerializedProperty selectedTrigger = prop.FindPropertyRelative(kSelectedTrigger); + SerializedProperty disabledTrigger = prop.FindPropertyRelative(kDisabledTrigger); + + EditorGUI.PropertyField(drawRect, normalTrigger); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(drawRect, higlightedTrigger); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(drawRect, pressedTrigger); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(drawRect, selectedTrigger); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(drawRect, disabledTrigger); + } + + public override float GetPropertyHeight(SerializedProperty prop, GUIContent label) + { + return 5 * EditorGUIUtility.singleLineHeight + 4 * EditorGUIUtility.standardVerticalSpacing; + } + + public override VisualElement CreatePropertyGUI(SerializedProperty property) + { + var container = new VisualElement(); + + var properties = new[] + { + property.FindPropertyRelative(kNormalTrigger), + property.FindPropertyRelative(kHighlightedTrigger), + property.FindPropertyRelative(kPressedTrigger), + property.FindPropertyRelative(kSelectedTrigger), + property.FindPropertyRelative(kDisabledTrigger), + }; + + foreach (var prop in properties) + { + var field = new PropertyField(prop); + container.Add(field); + } + + return container; + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/AnimationTriggersDrawer.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/AnimationTriggersDrawer.cs.meta new file mode 100644 index 00000000..530938b0 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/AnimationTriggersDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c18288a8d31fc9043a807ee8a9f1ae64 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/ColorBlockDrawer.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/ColorBlockDrawer.cs new file mode 100644 index 00000000..15349c85 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/ColorBlockDrawer.cs @@ -0,0 +1,79 @@ +using UnityEngine; +using UnityEngine.UI; +using UnityEditor.UIElements; +using UnityEngine.UIElements; + +namespace UnityEditor.UI +{ + [CustomPropertyDrawer(typeof(ColorBlock), true)] + /// + /// This is a PropertyDrawer for ColorBlock. It is implemented using the standard Unity PropertyDrawer framework.. + /// + public class ColorBlockDrawer : PropertyDrawer + { + const string kNormalColor = "m_NormalColor"; + const string kHighlightedColor = "m_HighlightedColor"; + const string kPressedColor = "m_PressedColor"; + const string kSelectedColor = "m_SelectedColor"; + const string kDisabledColor = "m_DisabledColor"; + const string kColorMultiplier = "m_ColorMultiplier"; + const string kFadeDuration = "m_FadeDuration"; + + public override void OnGUI(Rect rect, SerializedProperty prop, GUIContent label) + { + Rect drawRect = rect; + drawRect.height = EditorGUIUtility.singleLineHeight; + + SerializedProperty normalColor = prop.FindPropertyRelative(kNormalColor); + SerializedProperty highlighted = prop.FindPropertyRelative(kHighlightedColor); + SerializedProperty pressedColor = prop.FindPropertyRelative(kPressedColor); + SerializedProperty selectedColor = prop.FindPropertyRelative(kSelectedColor); + SerializedProperty disabledColor = prop.FindPropertyRelative(kDisabledColor); + SerializedProperty colorMultiplier = prop.FindPropertyRelative(kColorMultiplier); + SerializedProperty fadeDuration = prop.FindPropertyRelative(kFadeDuration); + + EditorGUI.PropertyField(drawRect, normalColor); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(drawRect, highlighted); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(drawRect, pressedColor); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(drawRect, selectedColor); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(drawRect, disabledColor); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(drawRect, colorMultiplier); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(drawRect, fadeDuration); + } + + public override float GetPropertyHeight(SerializedProperty prop, GUIContent label) + { + return 7 * EditorGUIUtility.singleLineHeight + 6 * EditorGUIUtility.standardVerticalSpacing; + } + + public override VisualElement CreatePropertyGUI(SerializedProperty property) + { + VisualElement container = new VisualElement(); + + var properties = new[] + { + property.FindPropertyRelative(kNormalColor), + property.FindPropertyRelative(kHighlightedColor), + property.FindPropertyRelative(kPressedColor), + property.FindPropertyRelative(kSelectedColor), + property.FindPropertyRelative(kDisabledColor), + property.FindPropertyRelative(kColorMultiplier), + property.FindPropertyRelative(kFadeDuration) + }; + + foreach (var prop in properties) + { + var field = new PropertyField(prop); + container.Add(field); + } + + return container; + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/ColorBlockDrawer.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/ColorBlockDrawer.cs.meta new file mode 100644 index 00000000..55519627 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/ColorBlockDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b825fd5f27403b84f97726dd9c5a5e6f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/DropdownOptionListDrawer.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/DropdownOptionListDrawer.cs new file mode 100644 index 00000000..6cd916ec --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/DropdownOptionListDrawer.cs @@ -0,0 +1,121 @@ +using System; +using UnityEditorInternal; +using UnityEngine; +using UnityEngine.UI; +using UnityEngine.UIElements; +using UnityEditor; +using UnityEditor.UIElements; + +namespace UnityEditor.UI +{ + [CustomPropertyDrawer(typeof(Dropdown.OptionDataList), true)] + /// + /// This is a PropertyDrawer for Dropdown.OptionDataList. It is implemented using the standard Unity PropertyDrawer framework. + /// + class DropdownOptionListDrawer : PropertyDrawer + { + const string kOptionsPath = "m_Options"; + const string kTextPath = "m_Text"; + const string kImagePath = "m_Image"; + const string kHeader = "Options"; + const string kListViewUssName = "unity-list-view__header"; + const string kVisualElementName = "DropdownOptionDataList"; + + // Offset for fixed size list items, so it wouldn't look tight or overlap each other + const float itemOffset = 4; + + private ReorderableList m_ReorderableList; + + private void Init(SerializedProperty property) + { + if (m_ReorderableList != null && m_ReorderableList.serializedProperty.serializedObject.m_NativeObjectPtr != IntPtr.Zero) + { + return; + } + + SerializedProperty array = property.FindPropertyRelative(kOptionsPath); + + m_ReorderableList = new ReorderableList(property.serializedObject, array); + m_ReorderableList.drawElementCallback = DrawOptionData; + m_ReorderableList.drawHeaderCallback = DrawHeader; + m_ReorderableList.elementHeight += 16; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + Init(property); + + m_ReorderableList.DoList(position); + } + + private void DrawHeader(Rect rect) + { + GUI.Label(rect, kHeader); + } + + private void DrawOptionData(Rect rect, int index, bool isActive, bool isFocused) + { + SerializedProperty itemData = m_ReorderableList.serializedProperty.GetArrayElementAtIndex(index); + SerializedProperty itemText = itemData.FindPropertyRelative(kTextPath); + SerializedProperty itemImage = itemData.FindPropertyRelative(kImagePath); + + RectOffset offset = new RectOffset(0, 0, -1, -3); + rect = offset.Add(rect); + rect.height = EditorGUIUtility.singleLineHeight; + + EditorGUI.PropertyField(rect, itemText, GUIContent.none); + rect.y += EditorGUIUtility.singleLineHeight; + EditorGUI.PropertyField(rect, itemImage, GUIContent.none); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + Init(property); + + return m_ReorderableList.GetHeight(); + } + + public override VisualElement CreatePropertyGUI(SerializedProperty property) + { + var root = new VisualElement(); + root.name = kVisualElementName; + + Init(property); + + var headerElement = new VisualElement(); + headerElement.AddToClassList(kListViewUssName); + var header = new Label(kHeader); + headerElement.Add(header); + root.Add(headerElement); + + var listView = CreateListView(property); + root.Add(listView); + + return root; + } + + ListView CreateListView(SerializedProperty property) + { + var listView = new ListView + { + showAddRemoveFooter = true, + reorderMode = ListViewReorderMode.Animated, + showBorder = true, + showFoldoutHeader = false, + showBoundCollectionSize = false, + showAlternatingRowBackgrounds = AlternatingRowBackground.None, + fixedItemHeight = m_ReorderableList.elementHeight + itemOffset, + horizontalScrollingEnabled = false, + name = kHeader + }; + + + var propertyRelative = property.FindPropertyRelative(kOptionsPath); + listView.bindingPath = propertyRelative.propertyPath; + + listView.makeItem += () => new DropdownOptionListItem(kTextPath, kImagePath); + + return listView; + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/DropdownOptionListDrawer.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/DropdownOptionListDrawer.cs.meta new file mode 100644 index 00000000..9e8ada52 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/DropdownOptionListDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1385bc74f3945c943be16ecbb1381063 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/FontDataDrawer.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/FontDataDrawer.cs new file mode 100644 index 00000000..23eb7370 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/FontDataDrawer.cs @@ -0,0 +1,514 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace UnityEditor.UI +{ + [CustomPropertyDrawer(typeof(FontData), true)] + /// + /// This is a PropertyDrawer for FontData. It is implemented using the standard Unity PropertyDrawer framework + /// + public class FontDataDrawer : PropertyDrawer + { + static private class Styles + { + public static GUIStyle alignmentButtonLeft = new GUIStyle(EditorStyles.miniButtonLeft); + public static GUIStyle alignmentButtonMid = new GUIStyle(EditorStyles.miniButtonMid); + public static GUIStyle alignmentButtonRight = new GUIStyle(EditorStyles.miniButtonRight); + + public static GUIContent m_EncodingContent; + + public static GUIContent m_LeftAlignText; + public static GUIContent m_CenterAlignText; + public static GUIContent m_RightAlignText; + public static GUIContent m_TopAlignText; + public static GUIContent m_MiddleAlignText; + public static GUIContent m_BottomAlignText; + + public static GUIContent m_LeftAlignTextActive; + public static GUIContent m_CenterAlignTextActive; + public static GUIContent m_RightAlignTextActive; + public static GUIContent m_TopAlignTextActive; + public static GUIContent m_MiddleAlignTextActive; + public static GUIContent m_BottomAlignTextActive; + + static Styles() + { + m_EncodingContent = EditorGUIUtility.TrTextContent("Rich Text", "Use emoticons and colors"); + + // Horizontal Alignment Icons + m_LeftAlignText = EditorGUIUtility.IconContent(@"GUISystem/align_horizontally_left", "Left Align"); + m_CenterAlignText = EditorGUIUtility.IconContent(@"GUISystem/align_horizontally_center", "Center Align"); + m_RightAlignText = EditorGUIUtility.IconContent(@"GUISystem/align_horizontally_right", "Right Align"); + m_LeftAlignTextActive = EditorGUIUtility.IconContent(@"GUISystem/align_horizontally_left_active", "Left Align"); + m_CenterAlignTextActive = EditorGUIUtility.IconContent(@"GUISystem/align_horizontally_center_active", "Center Align"); + m_RightAlignTextActive = EditorGUIUtility.IconContent(@"GUISystem/align_horizontally_right_active", "Right Align"); + + // Vertical Alignment Icons + m_TopAlignText = EditorGUIUtility.IconContent(@"GUISystem/align_vertically_top", "Top Align"); + m_MiddleAlignText = EditorGUIUtility.IconContent(@"GUISystem/align_vertically_center", "Middle Align"); + m_BottomAlignText = EditorGUIUtility.IconContent(@"GUISystem/align_vertically_bottom", "Bottom Align"); + m_TopAlignTextActive = EditorGUIUtility.IconContent(@"GUISystem/align_vertically_top_active", "Top Align"); + m_MiddleAlignTextActive = EditorGUIUtility.IconContent(@"GUISystem/align_vertically_center_active", "Middle Align"); + m_BottomAlignTextActive = EditorGUIUtility.IconContent(@"GUISystem/align_vertically_bottom_active", "Bottom Align"); + + FixAlignmentButtonStyles(alignmentButtonLeft, alignmentButtonMid, alignmentButtonRight); + } + + static void FixAlignmentButtonStyles(params GUIStyle[] styles) + { + foreach (GUIStyle style in styles) + { + style.padding.left = 2; + style.padding.right = 2; + } + } + } + + private enum VerticalTextAligment + { + Top, + Middle, + Bottom + } + + private enum HorizontalTextAligment + { + Left, + Center, + Right + } + + private const int kAlignmentButtonWidth = 20; + + static int s_TextAlignmentHash = "DoTextAligmentControl".GetHashCode(); + + private SerializedProperty m_SupportEncoding; + private SerializedProperty m_Font; + private SerializedProperty m_FontSize; + private SerializedProperty m_LineSpacing; + private SerializedProperty m_FontStyle; + private SerializedProperty m_ResizeTextForBestFit; + private SerializedProperty m_ResizeTextMinSize; + private SerializedProperty m_ResizeTextMaxSize; + private SerializedProperty m_HorizontalOverflow; + private SerializedProperty m_VerticalOverflow; + private SerializedProperty m_Alignment; + private SerializedProperty m_AlignByGeometry; + + private float m_FontFieldfHeight = 0f; + private float m_FontStyleHeight = 0f; + private float m_FontSizeHeight = 0f; + private float m_LineSpacingHeight = 0f; + private float m_EncodingHeight = 0f; + private float m_ResizeTextForBestFitHeight = 0f; + private float m_ResizeTextMinSizeHeight = 0f; + private float m_ResizeTextMaxSizeHeight = 0f; + private float m_HorizontalOverflowHeight = 0f; + private float m_VerticalOverflowHeight = 0f; + private float m_AlignByGeometryHeight = 0f; + + protected void Init(SerializedProperty property) + { + m_SupportEncoding = property.FindPropertyRelative("m_RichText"); + m_Font = property.FindPropertyRelative("m_Font"); + m_FontSize = property.FindPropertyRelative("m_FontSize"); + m_LineSpacing = property.FindPropertyRelative("m_LineSpacing"); + m_FontStyle = property.FindPropertyRelative("m_FontStyle"); + m_ResizeTextForBestFit = property.FindPropertyRelative("m_BestFit"); + m_ResizeTextMinSize = property.FindPropertyRelative("m_MinSize"); + m_ResizeTextMaxSize = property.FindPropertyRelative("m_MaxSize"); + m_HorizontalOverflow = property.FindPropertyRelative("m_HorizontalOverflow"); + m_VerticalOverflow = property.FindPropertyRelative("m_VerticalOverflow"); + m_Alignment = property.FindPropertyRelative("m_Alignment"); + m_AlignByGeometry = property.FindPropertyRelative("m_AlignByGeometry"); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + Init(property); + m_FontFieldfHeight = EditorGUI.GetPropertyHeight(m_Font); + m_FontStyleHeight = EditorGUI.GetPropertyHeight(m_FontStyle); + m_FontSizeHeight = EditorGUI.GetPropertyHeight(m_FontSize); + m_LineSpacingHeight = EditorGUI.GetPropertyHeight(m_LineSpacing); + m_EncodingHeight = EditorGUI.GetPropertyHeight(m_SupportEncoding); + m_ResizeTextForBestFitHeight = EditorGUI.GetPropertyHeight(m_ResizeTextForBestFit); + m_ResizeTextMinSizeHeight = EditorGUI.GetPropertyHeight(m_ResizeTextMinSize); + m_ResizeTextMaxSizeHeight = EditorGUI.GetPropertyHeight(m_ResizeTextMaxSize); + m_HorizontalOverflowHeight = EditorGUI.GetPropertyHeight(m_HorizontalOverflow); + m_VerticalOverflowHeight = EditorGUI.GetPropertyHeight(m_VerticalOverflow); + m_AlignByGeometryHeight = EditorGUI.GetPropertyHeight(m_AlignByGeometry); + + var height = m_FontFieldfHeight + + m_FontStyleHeight + + m_FontSizeHeight + + m_LineSpacingHeight + + m_EncodingHeight + + m_ResizeTextForBestFitHeight + + m_HorizontalOverflowHeight + + m_VerticalOverflowHeight + + EditorGUIUtility.singleLineHeight * 3 + + EditorGUIUtility.standardVerticalSpacing * 10 + + m_AlignByGeometryHeight; + + if (m_ResizeTextForBestFit.boolValue) + { + height += m_ResizeTextMinSizeHeight + + m_ResizeTextMaxSizeHeight + + EditorGUIUtility.standardVerticalSpacing * 2; + } + return height; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + Init(property); + + Rect rect = position; + rect.height = EditorGUIUtility.singleLineHeight; + + EditorGUI.LabelField(rect, "Character", EditorStyles.boldLabel); + rect.y += rect.height + EditorGUIUtility.standardVerticalSpacing; + ++EditorGUI.indentLevel; + { + Font font = m_Font.objectReferenceValue as Font; + rect.height = m_FontFieldfHeight; + EditorGUI.BeginChangeCheck(); + EditorGUI.PropertyField(rect, m_Font); + if (EditorGUI.EndChangeCheck()) + { + font = m_Font.objectReferenceValue as Font; + if (font != null && !font.dynamic) + m_FontSize.intValue = font.fontSize; + } + + rect.y += rect.height + EditorGUIUtility.standardVerticalSpacing; + rect.height = m_FontStyleHeight; + using (new EditorGUI.DisabledScope(!m_Font.hasMultipleDifferentValues && font != null && !font.dynamic)) + { + EditorGUI.PropertyField(rect, m_FontStyle); + } + + rect.y += rect.height + EditorGUIUtility.standardVerticalSpacing; + rect.height = m_FontSizeHeight; + EditorGUI.PropertyField(rect, m_FontSize); + + rect.y += rect.height + EditorGUIUtility.standardVerticalSpacing; + rect.height = m_LineSpacingHeight; + EditorGUI.PropertyField(rect, m_LineSpacing); + + rect.y += rect.height + EditorGUIUtility.standardVerticalSpacing; + rect.height = m_EncodingHeight; + EditorGUI.PropertyField(rect, m_SupportEncoding, Styles.m_EncodingContent); + } + --EditorGUI.indentLevel; + + rect.y += rect.height + EditorGUIUtility.standardVerticalSpacing; + rect.height = EditorGUIUtility.singleLineHeight; + EditorGUI.LabelField(rect, "Paragraph", EditorStyles.boldLabel); + rect.y += rect.height + EditorGUIUtility.standardVerticalSpacing; + ++EditorGUI.indentLevel; + { + rect.height = EditorGUIUtility.singleLineHeight; + DoTextAligmentControl(rect, m_Alignment); + + rect.y += rect.height + EditorGUIUtility.standardVerticalSpacing; + rect.height = m_HorizontalOverflowHeight; + EditorGUI.PropertyField(rect, m_AlignByGeometry); + + rect.y += rect.height + EditorGUIUtility.standardVerticalSpacing; + rect.height = m_HorizontalOverflowHeight; + EditorGUI.PropertyField(rect, m_HorizontalOverflow); + + rect.y += rect.height + EditorGUIUtility.standardVerticalSpacing; + rect.height = m_VerticalOverflowHeight; + EditorGUI.PropertyField(rect, m_VerticalOverflow); + + rect.y += rect.height + EditorGUIUtility.standardVerticalSpacing; + rect.height = m_ResizeTextMaxSizeHeight; + EditorGUI.PropertyField(rect, m_ResizeTextForBestFit); + + if (m_ResizeTextForBestFit.boolValue) + { + rect.y += rect.height + EditorGUIUtility.standardVerticalSpacing; + rect.height = m_ResizeTextMinSizeHeight; + EditorGUI.PropertyField(rect, m_ResizeTextMinSize); + + rect.y += rect.height + EditorGUIUtility.standardVerticalSpacing; + rect.height = m_ResizeTextMaxSizeHeight; + EditorGUI.PropertyField(rect, m_ResizeTextMaxSize); + } + } + --EditorGUI.indentLevel; + } + + private void DoTextAligmentControl(Rect position, SerializedProperty alignment) + { + GUIContent alingmentContent = EditorGUIUtility.TrTextContent("Alignment"); + + int id = EditorGUIUtility.GetControlID(s_TextAlignmentHash, FocusType.Keyboard, position); + + EditorGUIUtility.SetIconSize(new Vector2(15, 15)); + EditorGUI.BeginProperty(position, alingmentContent, alignment); + { + Rect controlArea = EditorGUI.PrefixLabel(position, id, alingmentContent); + + float width = kAlignmentButtonWidth * 3; + float spacing = Mathf.Clamp(controlArea.width - width * 2, 2, 10); + + Rect horizontalAligment = new Rect(controlArea.x, controlArea.y, width, controlArea.height); + Rect verticalAligment = new Rect(horizontalAligment.xMax + spacing, controlArea.y, width, controlArea.height); + + DoHorizontalAligmentControl(horizontalAligment, alignment); + DoVerticalAligmentControl(verticalAligment, alignment); + } + EditorGUI.EndProperty(); + EditorGUIUtility.SetIconSize(Vector2.zero); + } + + private static void DoHorizontalAligmentControl(Rect position, SerializedProperty alignment) + { + TextAnchor ta = (TextAnchor)alignment.intValue; + HorizontalTextAligment horizontalAlignment = GetHorizontalAlignment(ta); + + bool leftAlign = (horizontalAlignment == HorizontalTextAligment.Left); + bool centerAlign = (horizontalAlignment == HorizontalTextAligment.Center); + bool rightAlign = (horizontalAlignment == HorizontalTextAligment.Right); + + if (alignment.hasMultipleDifferentValues) + { + foreach (var obj in alignment.serializedObject.targetObjects) + { + Text text = obj as Text; + horizontalAlignment = GetHorizontalAlignment(text.alignment); + leftAlign = leftAlign || (horizontalAlignment == HorizontalTextAligment.Left); + centerAlign = centerAlign || (horizontalAlignment == HorizontalTextAligment.Center); + rightAlign = rightAlign || (horizontalAlignment == HorizontalTextAligment.Right); + } + } + + position.width = kAlignmentButtonWidth; + + EditorGUI.BeginChangeCheck(); + EditorToggle(position, leftAlign, leftAlign ? Styles.m_LeftAlignTextActive : Styles.m_LeftAlignText, Styles.alignmentButtonLeft); + if (EditorGUI.EndChangeCheck()) + { + SetHorizontalAlignment(alignment, HorizontalTextAligment.Left); + } + + position.x += position.width; + EditorGUI.BeginChangeCheck(); + EditorToggle(position, centerAlign, centerAlign ? Styles.m_CenterAlignTextActive : Styles.m_CenterAlignText, Styles.alignmentButtonMid); + if (EditorGUI.EndChangeCheck()) + { + SetHorizontalAlignment(alignment, HorizontalTextAligment.Center); + } + + position.x += position.width; + EditorGUI.BeginChangeCheck(); + EditorToggle(position, rightAlign, rightAlign ? Styles.m_RightAlignTextActive : Styles.m_RightAlignText, Styles.alignmentButtonRight); + if (EditorGUI.EndChangeCheck()) + { + SetHorizontalAlignment(alignment, HorizontalTextAligment.Right); + } + } + + private static void DoVerticalAligmentControl(Rect position, SerializedProperty alignment) + { + TextAnchor ta = (TextAnchor)alignment.intValue; + VerticalTextAligment verticalTextAligment = GetVerticalAlignment(ta); + + bool topAlign = (verticalTextAligment == VerticalTextAligment.Top); + bool middleAlign = (verticalTextAligment == VerticalTextAligment.Middle); + bool bottomAlign = (verticalTextAligment == VerticalTextAligment.Bottom); + + if (alignment.hasMultipleDifferentValues) + { + foreach (var obj in alignment.serializedObject.targetObjects) + { + Text text = obj as Text; + TextAnchor textAlignment = text.alignment; + verticalTextAligment = GetVerticalAlignment(textAlignment); + topAlign = topAlign || (verticalTextAligment == VerticalTextAligment.Top); + middleAlign = middleAlign || (verticalTextAligment == VerticalTextAligment.Middle); + bottomAlign = bottomAlign || (verticalTextAligment == VerticalTextAligment.Bottom); + } + } + + + position.width = kAlignmentButtonWidth; + + // position.x += position.width; + EditorGUI.BeginChangeCheck(); + EditorToggle(position, topAlign, topAlign ? Styles.m_TopAlignTextActive : Styles.m_TopAlignText, Styles.alignmentButtonLeft); + if (EditorGUI.EndChangeCheck()) + { + SetVerticalAlignment(alignment, VerticalTextAligment.Top); + } + + position.x += position.width; + EditorGUI.BeginChangeCheck(); + EditorToggle(position, middleAlign, middleAlign ? Styles.m_MiddleAlignTextActive : Styles.m_MiddleAlignText, Styles.alignmentButtonMid); + if (EditorGUI.EndChangeCheck()) + { + SetVerticalAlignment(alignment, VerticalTextAligment.Middle); + } + + position.x += position.width; + EditorGUI.BeginChangeCheck(); + EditorToggle(position, bottomAlign, bottomAlign ? Styles.m_BottomAlignTextActive : Styles.m_BottomAlignText, Styles.alignmentButtonRight); + if (EditorGUI.EndChangeCheck()) + { + SetVerticalAlignment(alignment, VerticalTextAligment.Bottom); + } + } + + private static bool EditorToggle(Rect position, bool value, GUIContent content, GUIStyle style) + { + int hashCode = "AlignToggle".GetHashCode(); + int id = EditorGUIUtility.GetControlID(hashCode, FocusType.Keyboard, position); + Event evt = Event.current; + + // Toggle selected toggle on space or return key + if (EditorGUIUtility.keyboardControl == id && evt.type == EventType.KeyDown && (evt.keyCode == KeyCode.Space || evt.keyCode == KeyCode.Return || evt.keyCode == KeyCode.KeypadEnter)) + { + value = !value; + evt.Use(); + GUI.changed = true; + } + + if (evt.type == EventType.KeyDown && Event.current.button == 0 && position.Contains(Event.current.mousePosition)) + { + GUIUtility.keyboardControl = id; + EditorGUIUtility.editingTextField = false; + HandleUtility.Repaint(); + } + + bool returnValue = GUI.Toggle(position, id, value, content, style); + + return returnValue; + } + + private static HorizontalTextAligment GetHorizontalAlignment(TextAnchor ta) + { + switch (ta) + { + case TextAnchor.MiddleCenter: + case TextAnchor.UpperCenter: + case TextAnchor.LowerCenter: + return HorizontalTextAligment.Center; + + case TextAnchor.UpperRight: + case TextAnchor.MiddleRight: + case TextAnchor.LowerRight: + return HorizontalTextAligment.Right; + + case TextAnchor.UpperLeft: + case TextAnchor.MiddleLeft: + case TextAnchor.LowerLeft: + return HorizontalTextAligment.Left; + } + + return HorizontalTextAligment.Left; + } + + private static VerticalTextAligment GetVerticalAlignment(TextAnchor ta) + { + switch (ta) + { + case TextAnchor.UpperLeft: + case TextAnchor.UpperCenter: + case TextAnchor.UpperRight: + return VerticalTextAligment.Top; + + case TextAnchor.MiddleLeft: + case TextAnchor.MiddleCenter: + case TextAnchor.MiddleRight: + return VerticalTextAligment.Middle; + + case TextAnchor.LowerLeft: + case TextAnchor.LowerCenter: + case TextAnchor.LowerRight: + return VerticalTextAligment.Bottom; + } + + return VerticalTextAligment.Top; + } + + // We can't go through serialized properties here since we're showing two controls for a single SerializzedProperty. + private static void SetHorizontalAlignment(SerializedProperty alignment, HorizontalTextAligment horizontalAlignment) + { + foreach (var obj in alignment.serializedObject.targetObjects) + { + Text text = obj as Text; + VerticalTextAligment currentVerticalAligment = GetVerticalAlignment(text.alignment); + Undo.RecordObject(text, "Horizontal Alignment"); + text.alignment = GetAnchor(currentVerticalAligment, horizontalAlignment); + EditorUtility.SetDirty(obj); + } + } + + private static void SetVerticalAlignment(SerializedProperty alignment, VerticalTextAligment verticalAlignment) + { + foreach (var obj in alignment.serializedObject.targetObjects) + { + Text text = obj as Text; + HorizontalTextAligment currentHorizontalAligment = GetHorizontalAlignment(text.alignment); + Undo.RecordObject(text, "Vertical Alignment"); + text.alignment = GetAnchor(verticalAlignment, currentHorizontalAligment); + EditorUtility.SetDirty(obj); + } + } + + private static TextAnchor GetAnchor(VerticalTextAligment verticalTextAligment, HorizontalTextAligment horizontalTextAligment) + { + TextAnchor ac = TextAnchor.UpperLeft; + + switch (horizontalTextAligment) + { + case HorizontalTextAligment.Left: + switch (verticalTextAligment) + { + case VerticalTextAligment.Bottom: + ac = TextAnchor.LowerLeft; + break; + case VerticalTextAligment.Middle: + ac = TextAnchor.MiddleLeft; + break; + default: + ac = TextAnchor.UpperLeft; + break; + } + break; + case HorizontalTextAligment.Center: + switch (verticalTextAligment) + { + case VerticalTextAligment.Bottom: + ac = TextAnchor.LowerCenter; + break; + case VerticalTextAligment.Middle: + ac = TextAnchor.MiddleCenter; + break; + default: + ac = TextAnchor.UpperCenter; + break; + } + break; + default: + switch (verticalTextAligment) + { + case VerticalTextAligment.Bottom: + ac = TextAnchor.LowerRight; + break; + case VerticalTextAligment.Middle: + ac = TextAnchor.MiddleRight; + break; + default: + ac = TextAnchor.UpperRight; + break; + } + break; + } + return ac; + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/FontDataDrawer.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/FontDataDrawer.cs.meta new file mode 100644 index 00000000..c238f8fe --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/FontDataDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fea12beeeb5a7a448b5e60f50e40975d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/NavigationDrawer.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/NavigationDrawer.cs new file mode 100644 index 00000000..ef243360 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/NavigationDrawer.cs @@ -0,0 +1,152 @@ +using System; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UI; +using UnityEngine.UIElements; + +namespace UnityEditor.UI +{ + [CustomPropertyDrawer(typeof(Navigation), true)] + /// + /// This is a PropertyDrawer for Navigation. It is implemented using the standard Unity PropertyDrawer framework. + /// + public class NavigationDrawer : PropertyDrawer + { + const string kNavigation = "Navigation"; + + const string kModeProp = "m_Mode"; + const string kWrapAroundProp = "m_WrapAround"; + const string kSelectOnUpProp = "m_SelectOnUp"; + const string kSelectOnDownProp = "m_SelectOnDown"; + const string kSelectOnLeftProp = "m_SelectOnLeft"; + const string kSelectOnRightProp = "m_SelectOnRight"; + + const string kHiddenClass = "unity-ui-navigation-hidden"; + + private class Styles + { + readonly public GUIContent navigationContent; + + public Styles() + { + navigationContent = EditorGUIUtility.TrTextContent(kNavigation); + } + } + + private static Styles s_Styles = null; + + public override void OnGUI(Rect pos, SerializedProperty prop, GUIContent label) + { + if (s_Styles == null) + s_Styles = new Styles(); + + Rect drawRect = pos; + drawRect.height = EditorGUIUtility.singleLineHeight; + + SerializedProperty navigation = prop.FindPropertyRelative(kModeProp); + SerializedProperty wrapAround = prop.FindPropertyRelative(kWrapAroundProp); + Navigation.Mode navMode = GetNavigationMode(navigation); + + EditorGUI.PropertyField(drawRect, navigation, s_Styles.navigationContent); + + ++EditorGUI.indentLevel; + + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + + switch (navMode) + { + case Navigation.Mode.Horizontal: + case Navigation.Mode.Vertical: + { + EditorGUI.PropertyField(drawRect, wrapAround); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + } + break; + case Navigation.Mode.Explicit: + { + SerializedProperty selectOnUp = prop.FindPropertyRelative(kSelectOnUpProp); + SerializedProperty selectOnDown = prop.FindPropertyRelative(kSelectOnDownProp); + SerializedProperty selectOnLeft = prop.FindPropertyRelative(kSelectOnLeftProp); + SerializedProperty selectOnRight = prop.FindPropertyRelative(kSelectOnRightProp); + + EditorGUI.PropertyField(drawRect, selectOnUp); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(drawRect, selectOnDown); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(drawRect, selectOnLeft); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(drawRect, selectOnRight); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + } + break; + } + + --EditorGUI.indentLevel; + } + + static Navigation.Mode GetNavigationMode(SerializedProperty navigation) + { + return (Navigation.Mode)navigation.enumValueIndex; + } + + public override float GetPropertyHeight(SerializedProperty prop, GUIContent label) + { + SerializedProperty navigation = prop.FindPropertyRelative(kModeProp); + if (navigation == null) + return EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + + Navigation.Mode navMode = GetNavigationMode(navigation); + + switch (navMode) + { + case Navigation.Mode.None: + return EditorGUIUtility.singleLineHeight; + case Navigation.Mode.Horizontal: + case Navigation.Mode.Vertical: + return 2 * EditorGUIUtility.singleLineHeight + 2 * EditorGUIUtility.standardVerticalSpacing; + case Navigation.Mode.Explicit: + return 5 * EditorGUIUtility.singleLineHeight + 5 * EditorGUIUtility.standardVerticalSpacing; + default: + return EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + } + } + + PropertyField PrepareField(VisualElement parent, string propertyPath, bool hideable = true, string label = null) + { + var field = new PropertyField(null, label) { bindingPath = propertyPath }; + if (hideable) field.AddToClassList(kHiddenClass); + parent.Add(field); + return field; + } + + public override VisualElement CreatePropertyGUI(SerializedProperty property) + { + var container = new VisualElement() { name = kNavigation }; + var indented = new VisualElement() { name = "Indent" }; + + indented.AddToClassList("unity-ui-navigation-indent"); + + var navigation = PrepareField(container, kModeProp, false, kNavigation); + var wrapAround = PrepareField(indented, kWrapAroundProp); + var selectOnUp = PrepareField(indented, kSelectOnUpProp); + var selectOnDown = PrepareField(indented, kSelectOnDownProp); + var selectOnLeft = PrepareField(indented, kSelectOnLeftProp); + var selectOnRight = PrepareField(indented, kSelectOnRightProp); + + Action callback = (value) => + { + wrapAround.EnableInClassList(kHiddenClass, value != Navigation.Mode.Vertical && value != Navigation.Mode.Horizontal); + selectOnUp.EnableInClassList(kHiddenClass, value != Navigation.Mode.Explicit); + selectOnDown.EnableInClassList(kHiddenClass, value != Navigation.Mode.Explicit); + selectOnLeft.EnableInClassList(kHiddenClass, value != Navigation.Mode.Explicit); + selectOnRight.EnableInClassList(kHiddenClass, value != Navigation.Mode.Explicit); + }; + + navigation.RegisterValueChangeCallback((e) => callback.Invoke((Navigation.Mode)e.changedProperty.enumValueIndex)); + callback.Invoke((Navigation.Mode)property.FindPropertyRelative(kModeProp).enumValueFlag); + + container.Add(indented); + return container; + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/NavigationDrawer.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/NavigationDrawer.cs.meta new file mode 100644 index 00000000..b08ad697 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/NavigationDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fb27f3049fe06c246803a4a4c5b7fda3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/SpriteStateDrawer.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/SpriteStateDrawer.cs new file mode 100644 index 00000000..7c02e176 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/SpriteStateDrawer.cs @@ -0,0 +1,65 @@ +using UnityEngine; +using UnityEngine.UI; +using UnityEditor.UIElements; +using UnityEngine.UIElements; + +namespace UnityEditor.UI +{ + [CustomPropertyDrawer(typeof(SpriteState), true)] + /// + /// This is a PropertyDrawer for SpriteState. It is implemented using the standard Unity PropertyDrawer framework. + /// + public class SpriteStateDrawer : PropertyDrawer + { + const string kHighlightedSprite = "m_HighlightedSprite"; + const string kPressedSprite = "m_PressedSprite"; + const string kSelectedSprite = "m_SelectedSprite"; + const string kDisabledSprite = "m_DisabledSprite"; + const string kVisualElementName = "SpriteState"; + + public override void OnGUI(Rect rect, SerializedProperty prop, GUIContent label) + { + Rect drawRect = rect; + drawRect.height = EditorGUIUtility.singleLineHeight; + SerializedProperty highlightedSprite = prop.FindPropertyRelative(kHighlightedSprite); + SerializedProperty pressedSprite = prop.FindPropertyRelative(kPressedSprite); + SerializedProperty selectedSprite = prop.FindPropertyRelative(kSelectedSprite); + SerializedProperty disabledSprite = prop.FindPropertyRelative(kDisabledSprite); + + EditorGUI.PropertyField(drawRect, highlightedSprite); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(drawRect, pressedSprite); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(drawRect, selectedSprite); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(drawRect, disabledSprite); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + } + + public override float GetPropertyHeight(SerializedProperty prop, GUIContent label) + { + return 4 * EditorGUIUtility.singleLineHeight + 3 * EditorGUIUtility.standardVerticalSpacing; + } + + public override VisualElement CreatePropertyGUI(SerializedProperty property) + { + var container = new VisualElement(); + container.name = kVisualElementName; + + var properties = new[] + { + property.FindPropertyRelative(kHighlightedSprite), + property.FindPropertyRelative(kPressedSprite), + property.FindPropertyRelative(kSelectedSprite), + property.FindPropertyRelative(kDisabledSprite) + }; + + foreach (var prop in properties) + { + container.Add(new PropertyField(prop)); + } + + return container; + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/SpriteStateDrawer.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/SpriteStateDrawer.cs.meta new file mode 100644 index 00000000..adf278db --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/PropertyDrawers/SpriteStateDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 728d2c19676ea3743aaa087aa28c4a16 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/RawImageEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/RawImageEditor.cs new file mode 100644 index 00000000..e5ba9f0b --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/RawImageEditor.cs @@ -0,0 +1,110 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace UnityEditor.UI +{ + [CustomEditor(typeof(RawImage), true)] + [CanEditMultipleObjects] + /// + /// Custom editor for RawImage. + /// Extend this class to write a custom editor for a component derived from RawImage. + /// + public class RawImageEditor : GraphicEditor + { + SerializedProperty m_Texture; + SerializedProperty m_UVRect; + GUIContent m_UVRectContent; + + protected override void OnEnable() + { + base.OnEnable(); + + // Note we have precedence for calling rectangle for just rect, even in the Inspector. + // For example in the Camera component's Viewport Rect. + // Hence sticking with Rect here to be consistent with corresponding property in the API. + m_UVRectContent = EditorGUIUtility.TrTextContent("UV Rect"); + + m_Texture = serializedObject.FindProperty("m_Texture"); + m_UVRect = serializedObject.FindProperty("m_UVRect"); + + SetShowNativeSize(true); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.PropertyField(m_Texture); + + AppearanceControlsGUI(); + RaycastControlsGUI(); + MaskableControlsGUI(); + EditorGUILayout.PropertyField(m_UVRect, m_UVRectContent); + SetShowNativeSize(false); + NativeSizeButtonGUI(); + + serializedObject.ApplyModifiedProperties(); + } + + void SetShowNativeSize(bool instant) + { + base.SetShowNativeSize(m_Texture.objectReferenceValue != null, instant); + } + + private static Rect Outer(RawImage rawImage) + { + Rect outer = rawImage.uvRect; + outer.xMin *= rawImage.rectTransform.rect.width; + outer.xMax *= rawImage.rectTransform.rect.width; + outer.yMin *= rawImage.rectTransform.rect.height; + outer.yMax *= rawImage.rectTransform.rect.height; + return outer; + } + + /// + /// Allow the texture to be previewed. + /// + + public override bool HasPreviewGUI() + { + RawImage rawImage = target as RawImage; + if (rawImage == null) + return false; + + var outer = Outer(rawImage); + return outer.width > 0 && outer.height > 0; + } + + /// + /// Draw the Image preview. + /// + + public override void OnPreviewGUI(Rect rect, GUIStyle background) + { + RawImage rawImage = target as RawImage; + Texture tex = rawImage.mainTexture; + + if (tex == null) + return; + + var outer = Outer(rawImage); + SpriteDrawUtility.DrawSprite(tex, rect, outer, rawImage.uvRect, rawImage.canvasRenderer.GetColor()); + } + + /// + /// Info String drawn at the bottom of the Preview + /// + + public override string GetInfoString() + { + RawImage rawImage = target as RawImage; + + // Image size Text + string text = string.Format("RawImage Size: {0}x{1}", + Mathf.RoundToInt(Mathf.Abs(rawImage.rectTransform.rect.width)), + Mathf.RoundToInt(Mathf.Abs(rawImage.rectTransform.rect.height))); + + return text; + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/RawImageEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/RawImageEditor.cs.meta new file mode 100644 index 00000000..d7d31a2d --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/RawImageEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e6413f4090046814d802ddbff9890878 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/RectMask2DEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/RectMask2DEditor.cs new file mode 100644 index 00000000..4148ff2c --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/RectMask2DEditor.cs @@ -0,0 +1,67 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace UnityEditor.UI +{ + [CustomEditor(typeof(RectMask2D), true)] + [CanEditMultipleObjects] + /// + /// Custom editor for the RectMask2d component. + /// Extend this class to write a custom editor for a component derived from Mask. + /// + public class RectMask2DEditor : Editor + { + SerializedProperty m_Padding; + SerializedProperty m_Softness; + GUIContent m_PaddingContent; + GUIContent m_LeftContent; + GUIContent m_RightContent; + GUIContent m_TopContent; + GUIContent m_BottomContent; + + static private bool m_ShowOffsets = false; + + protected virtual void OnEnable() + { + m_PaddingContent = EditorGUIUtility.TrTextContent("Padding"); + m_LeftContent = EditorGUIUtility.TrTextContent("Left"); + m_RightContent = EditorGUIUtility.TrTextContent("Right"); + m_TopContent = EditorGUIUtility.TrTextContent("Top"); + m_BottomContent = EditorGUIUtility.TrTextContent("Bottom"); + m_Padding = serializedObject.FindProperty("m_Padding"); + m_Softness = serializedObject.FindProperty("m_Softness"); + } + + public override void OnInspectorGUI() + { + m_ShowOffsets = EditorGUILayout.Foldout(m_ShowOffsets, m_PaddingContent, true); + + if (m_ShowOffsets) + OffsetGUI(); + + EditorGUILayout.PropertyField(m_Softness); + + serializedObject.ApplyModifiedProperties(); + } + + void OffsetGUI() + { + using (var check = new EditorGUI.ChangeCheckScope()) + { + EditorGUI.indentLevel++; + Vector4 newPadding = m_Padding.vector4Value; + + newPadding.x = EditorGUILayout.FloatField(m_LeftContent, newPadding.x); + newPadding.z = EditorGUILayout.FloatField(m_RightContent, newPadding.z); + newPadding.w = EditorGUILayout.FloatField(m_TopContent, newPadding.w); + newPadding.y = EditorGUILayout.FloatField(m_BottomContent, newPadding.y); + + if (check.changed) + { + m_Padding.vector4Value = newPadding; + } + EditorGUI.indentLevel--; + } + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/RectMask2DEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/RectMask2DEditor.cs.meta new file mode 100644 index 00000000..aec7a261 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/RectMask2DEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 58e7d991249847640b1534192721c5ea +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/ScrollRectEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/ScrollRectEditor.cs new file mode 100644 index 00000000..56d415ba --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/ScrollRectEditor.cs @@ -0,0 +1,176 @@ +using UnityEngine; +using UnityEngine.UI; +using UnityEditor.AnimatedValues; + +namespace UnityEditor.UI +{ + [CustomEditor(typeof(ScrollRect), true)] + [CanEditMultipleObjects] + /// + /// Custom Editor for the ScrollRect Component. + /// Extend this class to write a custom editor for a component derived from ScrollRect. + /// + public class ScrollRectEditor : Editor + { + SerializedProperty m_Content; + SerializedProperty m_Horizontal; + SerializedProperty m_Vertical; + SerializedProperty m_MovementType; + SerializedProperty m_Elasticity; + SerializedProperty m_Inertia; + SerializedProperty m_DecelerationRate; + SerializedProperty m_ScrollSensitivity; + SerializedProperty m_Viewport; + SerializedProperty m_HorizontalScrollbar; + SerializedProperty m_VerticalScrollbar; + SerializedProperty m_HorizontalScrollbarVisibility; + SerializedProperty m_VerticalScrollbarVisibility; + SerializedProperty m_HorizontalScrollbarSpacing; + SerializedProperty m_VerticalScrollbarSpacing; + SerializedProperty m_OnValueChanged; + AnimBool m_ShowElasticity; + AnimBool m_ShowDecelerationRate; + bool m_ViewportIsNotChild, m_HScrollbarIsNotChild, m_VScrollbarIsNotChild; + static string s_HError = "For this visibility mode, the Viewport property and the Horizontal Scrollbar property both needs to be set to a Rect Transform that is a child to the Scroll Rect."; + static string s_VError = "For this visibility mode, the Viewport property and the Vertical Scrollbar property both needs to be set to a Rect Transform that is a child to the Scroll Rect."; + + protected virtual void OnEnable() + { + m_Content = serializedObject.FindProperty("m_Content"); + m_Horizontal = serializedObject.FindProperty("m_Horizontal"); + m_Vertical = serializedObject.FindProperty("m_Vertical"); + m_MovementType = serializedObject.FindProperty("m_MovementType"); + m_Elasticity = serializedObject.FindProperty("m_Elasticity"); + m_Inertia = serializedObject.FindProperty("m_Inertia"); + m_DecelerationRate = serializedObject.FindProperty("m_DecelerationRate"); + m_ScrollSensitivity = serializedObject.FindProperty("m_ScrollSensitivity"); + m_Viewport = serializedObject.FindProperty("m_Viewport"); + m_HorizontalScrollbar = serializedObject.FindProperty("m_HorizontalScrollbar"); + m_VerticalScrollbar = serializedObject.FindProperty("m_VerticalScrollbar"); + m_HorizontalScrollbarVisibility = serializedObject.FindProperty("m_HorizontalScrollbarVisibility"); + m_VerticalScrollbarVisibility = serializedObject.FindProperty("m_VerticalScrollbarVisibility"); + m_HorizontalScrollbarSpacing = serializedObject.FindProperty("m_HorizontalScrollbarSpacing"); + m_VerticalScrollbarSpacing = serializedObject.FindProperty("m_VerticalScrollbarSpacing"); + m_OnValueChanged = serializedObject.FindProperty("m_OnValueChanged"); + + m_ShowElasticity = new AnimBool(Repaint); + m_ShowDecelerationRate = new AnimBool(Repaint); + SetAnimBools(true); + } + + protected virtual void OnDisable() + { + m_ShowElasticity.valueChanged.RemoveListener(Repaint); + m_ShowDecelerationRate.valueChanged.RemoveListener(Repaint); + } + + void SetAnimBools(bool instant) + { + SetAnimBool(m_ShowElasticity, !m_MovementType.hasMultipleDifferentValues && m_MovementType.enumValueIndex == (int)ScrollRect.MovementType.Elastic, instant); + SetAnimBool(m_ShowDecelerationRate, !m_Inertia.hasMultipleDifferentValues && m_Inertia.boolValue == true, instant); + } + + void SetAnimBool(AnimBool a, bool value, bool instant) + { + if (instant) + a.value = value; + else + a.target = value; + } + + void CalculateCachedValues() + { + m_ViewportIsNotChild = false; + m_HScrollbarIsNotChild = false; + m_VScrollbarIsNotChild = false; + if (targets.Length == 1) + { + Transform transform = ((ScrollRect)target).transform; + if (m_Viewport.objectReferenceValue == null || ((RectTransform)m_Viewport.objectReferenceValue).transform.parent != transform) + m_ViewportIsNotChild = true; + if (m_HorizontalScrollbar.objectReferenceValue == null || ((Scrollbar)m_HorizontalScrollbar.objectReferenceValue).transform.parent != transform) + m_HScrollbarIsNotChild = true; + if (m_VerticalScrollbar.objectReferenceValue == null || ((Scrollbar)m_VerticalScrollbar.objectReferenceValue).transform.parent != transform) + m_VScrollbarIsNotChild = true; + } + } + + public override void OnInspectorGUI() + { + SetAnimBools(false); + + serializedObject.Update(); + // Once we have a reliable way to know if the object changed, only re-cache in that case. + CalculateCachedValues(); + + EditorGUILayout.PropertyField(m_Content); + + EditorGUILayout.PropertyField(m_Horizontal); + EditorGUILayout.PropertyField(m_Vertical); + + EditorGUILayout.PropertyField(m_MovementType); + if (EditorGUILayout.BeginFadeGroup(m_ShowElasticity.faded)) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_Elasticity); + EditorGUI.indentLevel--; + } + EditorGUILayout.EndFadeGroup(); + + EditorGUILayout.PropertyField(m_Inertia); + if (EditorGUILayout.BeginFadeGroup(m_ShowDecelerationRate.faded)) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_DecelerationRate); + EditorGUI.indentLevel--; + } + EditorGUILayout.EndFadeGroup(); + + EditorGUILayout.PropertyField(m_ScrollSensitivity); + + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(m_Viewport); + + EditorGUILayout.PropertyField(m_HorizontalScrollbar); + if (m_HorizontalScrollbar.objectReferenceValue && !m_HorizontalScrollbar.hasMultipleDifferentValues) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_HorizontalScrollbarVisibility, EditorGUIUtility.TrTextContent("Visibility")); + + if ((ScrollRect.ScrollbarVisibility)m_HorizontalScrollbarVisibility.enumValueIndex == ScrollRect.ScrollbarVisibility.AutoHideAndExpandViewport + && !m_HorizontalScrollbarVisibility.hasMultipleDifferentValues) + { + if (m_ViewportIsNotChild || m_HScrollbarIsNotChild) + EditorGUILayout.HelpBox(s_HError, MessageType.Error); + EditorGUILayout.PropertyField(m_HorizontalScrollbarSpacing, EditorGUIUtility.TrTextContent("Spacing")); + } + + EditorGUI.indentLevel--; + } + + EditorGUILayout.PropertyField(m_VerticalScrollbar); + if (m_VerticalScrollbar.objectReferenceValue && !m_VerticalScrollbar.hasMultipleDifferentValues) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_VerticalScrollbarVisibility, EditorGUIUtility.TrTextContent("Visibility")); + + if ((ScrollRect.ScrollbarVisibility)m_VerticalScrollbarVisibility.enumValueIndex == ScrollRect.ScrollbarVisibility.AutoHideAndExpandViewport + && !m_VerticalScrollbarVisibility.hasMultipleDifferentValues) + { + if (m_ViewportIsNotChild || m_VScrollbarIsNotChild) + EditorGUILayout.HelpBox(s_VError, MessageType.Error); + EditorGUILayout.PropertyField(m_VerticalScrollbarSpacing, EditorGUIUtility.TrTextContent("Spacing")); + } + + EditorGUI.indentLevel--; + } + + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(m_OnValueChanged); + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/ScrollRectEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/ScrollRectEditor.cs.meta new file mode 100644 index 00000000..1ad9cfbd --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/ScrollRectEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 56ba6cb160ebfc042b48224bd1a35614 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/ScrollbarEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/ScrollbarEditor.cs new file mode 100644 index 00000000..79c1cf7b --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/ScrollbarEditor.cs @@ -0,0 +1,108 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +namespace UnityEditor.UI +{ + [CustomEditor(typeof(Scrollbar), true)] + [CanEditMultipleObjects] + /// + /// Custom Editor for the Scrollbar Component. + /// Extend this class to write a custom editor for a component derived from Scrollbar. + /// + public class ScrollbarEditor : SelectableEditor + { + SerializedProperty m_HandleRect; + SerializedProperty m_Direction; + SerializedProperty m_Value; + SerializedProperty m_Size; + SerializedProperty m_NumberOfSteps; + SerializedProperty m_OnValueChanged; + + protected override void OnEnable() + { + base.OnEnable(); + + m_HandleRect = serializedObject.FindProperty("m_HandleRect"); + m_Direction = serializedObject.FindProperty("m_Direction"); + m_Value = serializedObject.FindProperty("m_Value"); + m_Size = serializedObject.FindProperty("m_Size"); + m_NumberOfSteps = serializedObject.FindProperty("m_NumberOfSteps"); + m_OnValueChanged = serializedObject.FindProperty("m_OnValueChanged"); + } + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + EditorGUILayout.Space(); + + serializedObject.Update(); + + // EditorGUILayout.PropertyField(m_HandleRect); + EditorGUI.BeginChangeCheck(); + RectTransform newRectTransform = EditorGUILayout.ObjectField("Handle Rect", m_HandleRect.objectReferenceValue, typeof(RectTransform), true) as RectTransform; + if (EditorGUI.EndChangeCheck()) + { + // Handle Rect will modify its GameObject RectTransform drivenBy, so we need to Record the old and new RectTransform. + List modifiedObjects = new List(); + modifiedObjects.Add(newRectTransform); + foreach (var target in m_HandleRect.serializedObject.targetObjects) + { + MonoBehaviour mb = target as MonoBehaviour; + if (mb == null) + continue; + + modifiedObjects.Add(mb); + modifiedObjects.Add(mb.GetComponent()); + } + Undo.RecordObjects(modifiedObjects.ToArray(), "Change Handle Rect"); + m_HandleRect.objectReferenceValue = newRectTransform; + } + + if (m_HandleRect.objectReferenceValue != null) + { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_Direction); + if (EditorGUI.EndChangeCheck()) + { + Undo.RecordObjects(serializedObject.targetObjects, "Change Scrollbar Direction"); + + Scrollbar.Direction direction = (Scrollbar.Direction)m_Direction.enumValueIndex; + foreach (var obj in serializedObject.targetObjects) + { + Scrollbar scrollbar = obj as Scrollbar; + scrollbar.SetDirection(direction, true); + } + } + + EditorGUILayout.PropertyField(m_Value); + EditorGUILayout.PropertyField(m_Size); + EditorGUILayout.PropertyField(m_NumberOfSteps); + + bool warning = false; + foreach (var obj in serializedObject.targetObjects) + { + Scrollbar scrollbar = obj as Scrollbar; + Scrollbar.Direction dir = scrollbar.direction; + if (dir == Scrollbar.Direction.LeftToRight || dir == Scrollbar.Direction.RightToLeft) + warning = (scrollbar.navigation.mode != Navigation.Mode.Automatic && scrollbar.navigation.mode != Navigation.Mode.Horizontal && (scrollbar.FindSelectableOnLeft() != null || scrollbar.FindSelectableOnRight() != null)); + else + warning = (scrollbar.navigation.mode != Navigation.Mode.Automatic && scrollbar.navigation.mode != Navigation.Mode.Vertical && (scrollbar.FindSelectableOnDown() != null || scrollbar.FindSelectableOnUp() != null)); + } + + if (warning) + EditorGUILayout.HelpBox("The selected scrollbar direction conflicts with navigation. Not all navigation options may work.", MessageType.Warning); + + EditorGUILayout.Space(); + // Draw the event notification options + EditorGUILayout.PropertyField(m_OnValueChanged); + } + else + { + EditorGUILayout.HelpBox("Specify a RectTransform for the scrollbar handle. It must have a parent RectTransform that the handle can slide within.", MessageType.Info); + } + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/ScrollbarEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/ScrollbarEditor.cs.meta new file mode 100644 index 00000000..3ea1629d --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/ScrollbarEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f700f31b2e40d7f4bb69753fdbbbc2b5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/SelectableEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/SelectableEditor.cs new file mode 100644 index 00000000..7626b2f3 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/SelectableEditor.cs @@ -0,0 +1,383 @@ +using System.Collections.Generic; +using System.Text; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; +using UnityEditor.AnimatedValues; + +namespace UnityEditor.UI +{ + [CustomEditor(typeof(Selectable), true)] + /// + /// Custom Editor for the Selectable Component. + /// Extend this class to write a custom editor for a component derived from Selectable. + /// + public class SelectableEditor : Editor + { + SerializedProperty m_Script; + SerializedProperty m_InteractableProperty; + SerializedProperty m_TargetGraphicProperty; + SerializedProperty m_TransitionProperty; + SerializedProperty m_ColorBlockProperty; + SerializedProperty m_SpriteStateProperty; + SerializedProperty m_AnimTriggerProperty; + SerializedProperty m_NavigationProperty; + + GUIContent m_VisualizeNavigation = EditorGUIUtility.TrTextContent("Visualize", "Show navigation flows between selectable UI elements."); + + AnimBool m_ShowColorTint = new AnimBool(); + AnimBool m_ShowSpriteTrasition = new AnimBool(); + AnimBool m_ShowAnimTransition = new AnimBool(); + + private static List s_Editors = new List(); + private static bool s_ShowNavigation = false; + private static string s_ShowNavigationKey = "SelectableEditor.ShowNavigation"; + + // Whenever adding new SerializedProperties to the Selectable and SelectableEditor + // Also update this guy in OnEnable. This makes the inherited classes from Selectable not require a CustomEditor. + private string[] m_PropertyPathToExcludeForChildClasses; + + protected virtual void OnEnable() + { + m_Script = serializedObject.FindProperty("m_Script"); + m_InteractableProperty = serializedObject.FindProperty("m_Interactable"); + m_TargetGraphicProperty = serializedObject.FindProperty("m_TargetGraphic"); + m_TransitionProperty = serializedObject.FindProperty("m_Transition"); + m_ColorBlockProperty = serializedObject.FindProperty("m_Colors"); + m_SpriteStateProperty = serializedObject.FindProperty("m_SpriteState"); + m_AnimTriggerProperty = serializedObject.FindProperty("m_AnimationTriggers"); + m_NavigationProperty = serializedObject.FindProperty("m_Navigation"); + + m_PropertyPathToExcludeForChildClasses = new[] + { + m_Script.propertyPath, + m_NavigationProperty.propertyPath, + m_TransitionProperty.propertyPath, + m_ColorBlockProperty.propertyPath, + m_SpriteStateProperty.propertyPath, + m_AnimTriggerProperty.propertyPath, + m_InteractableProperty.propertyPath, + m_TargetGraphicProperty.propertyPath, + }; + + var trans = GetTransition(m_TransitionProperty); + m_ShowColorTint.value = (trans == Selectable.Transition.ColorTint); + m_ShowSpriteTrasition.value = (trans == Selectable.Transition.SpriteSwap); + m_ShowAnimTransition.value = (trans == Selectable.Transition.Animation); + + m_ShowColorTint.valueChanged.AddListener(Repaint); + m_ShowSpriteTrasition.valueChanged.AddListener(Repaint); + + s_Editors.Add(this); + RegisterStaticOnSceneGUI(); + + s_ShowNavigation = EditorPrefs.GetBool(s_ShowNavigationKey); + } + + protected virtual void OnDisable() + { + m_ShowColorTint.valueChanged.RemoveListener(Repaint); + m_ShowSpriteTrasition.valueChanged.RemoveListener(Repaint); + + s_Editors.Remove(this); + RegisterStaticOnSceneGUI(); + } + + private void RegisterStaticOnSceneGUI() + { + SceneView.duringSceneGui -= StaticOnSceneGUI; + if (s_Editors.Count > 0) + SceneView.duringSceneGui += StaticOnSceneGUI; + } + + static Selectable.Transition GetTransition(SerializedProperty transition) + { + return (Selectable.Transition)transition.enumValueIndex; + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.PropertyField(m_InteractableProperty); + + var trans = GetTransition(m_TransitionProperty); + + var graphic = m_TargetGraphicProperty.objectReferenceValue as Graphic; + if (graphic == null) + graphic = (target as Selectable).GetComponent(); + + var animator = (target as Selectable).GetComponent(); + m_ShowColorTint.target = (!m_TransitionProperty.hasMultipleDifferentValues && trans == Button.Transition.ColorTint); + m_ShowSpriteTrasition.target = (!m_TransitionProperty.hasMultipleDifferentValues && trans == Button.Transition.SpriteSwap); + m_ShowAnimTransition.target = (!m_TransitionProperty.hasMultipleDifferentValues && trans == Button.Transition.Animation); + + EditorGUILayout.PropertyField(m_TransitionProperty); + + ++EditorGUI.indentLevel; + { + if (trans == Selectable.Transition.ColorTint || trans == Selectable.Transition.SpriteSwap) + { + EditorGUILayout.PropertyField(m_TargetGraphicProperty); + } + + switch (trans) + { + case Selectable.Transition.ColorTint: + if (graphic == null) + EditorGUILayout.HelpBox("You must have a Graphic target in order to use a color transition.", MessageType.Warning); + break; + + case Selectable.Transition.SpriteSwap: + if (graphic as Image == null) + EditorGUILayout.HelpBox("You must have a Image target in order to use a sprite swap transition.", MessageType.Warning); + break; + } + + if (EditorGUILayout.BeginFadeGroup(m_ShowColorTint.faded)) + { + EditorGUILayout.PropertyField(m_ColorBlockProperty); + } + EditorGUILayout.EndFadeGroup(); + + if (EditorGUILayout.BeginFadeGroup(m_ShowSpriteTrasition.faded)) + { + EditorGUILayout.PropertyField(m_SpriteStateProperty); + } + EditorGUILayout.EndFadeGroup(); + + if (EditorGUILayout.BeginFadeGroup(m_ShowAnimTransition.faded)) + { + EditorGUILayout.PropertyField(m_AnimTriggerProperty); + + if (animator == null || animator.runtimeAnimatorController == null) + { + Rect buttonRect = EditorGUILayout.GetControlRect(); + buttonRect.xMin += EditorGUIUtility.labelWidth; + if (GUI.Button(buttonRect, "Auto Generate Animation", EditorStyles.miniButton)) + { + var controller = GenerateSelectableAnimatorContoller((target as Selectable).animationTriggers, target as Selectable); + if (controller != null) + { + if (animator == null) + animator = (target as Selectable).gameObject.AddComponent(); + + Animations.AnimatorController.SetAnimatorController(animator, controller); + } + } + } + } + EditorGUILayout.EndFadeGroup(); + } + --EditorGUI.indentLevel; + + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(m_NavigationProperty); + + EditorGUI.BeginChangeCheck(); + Rect toggleRect = EditorGUILayout.GetControlRect(); + toggleRect.xMin += EditorGUIUtility.labelWidth; + s_ShowNavigation = GUI.Toggle(toggleRect, s_ShowNavigation, m_VisualizeNavigation, EditorStyles.miniButton); + if (EditorGUI.EndChangeCheck()) + { + EditorPrefs.SetBool(s_ShowNavigationKey, s_ShowNavigation); + SceneView.RepaintAll(); + } + + // We do this here to avoid requiring the user to also write a Editor for their Selectable-derived classes. + // This way if we are on a derived class we dont draw anything else, otherwise draw the remaining properties. + ChildClassPropertiesGUI(); + + serializedObject.ApplyModifiedProperties(); + } + + // Draw the extra SerializedProperties of the child class. + // We need to make sure that m_PropertyPathToExcludeForChildClasses has all the Selectable properties and in the correct order. + // TODO: find a nicer way of doing this. (creating a InheritedEditor class that automagically does this) + private void ChildClassPropertiesGUI() + { + if (IsDerivedSelectableEditor()) + return; + + DrawPropertiesExcluding(serializedObject, m_PropertyPathToExcludeForChildClasses); + } + + private bool IsDerivedSelectableEditor() + { + return GetType() != typeof(SelectableEditor); + } + + private static Animations.AnimatorController GenerateSelectableAnimatorContoller(AnimationTriggers animationTriggers, Selectable target) + { + if (target == null) + return null; + + // Where should we create the controller? + var path = GetSaveControllerPath(target); + if (string.IsNullOrEmpty(path)) + return null; + + // figure out clip names + var normalName = string.IsNullOrEmpty(animationTriggers.normalTrigger) ? "Normal" : animationTriggers.normalTrigger; + var highlightedName = string.IsNullOrEmpty(animationTriggers.highlightedTrigger) ? "Highlighted" : animationTriggers.highlightedTrigger; + var pressedName = string.IsNullOrEmpty(animationTriggers.pressedTrigger) ? "Pressed" : animationTriggers.pressedTrigger; + var selectedName = string.IsNullOrEmpty(animationTriggers.selectedTrigger) ? "Selected" : animationTriggers.selectedTrigger; + var disabledName = string.IsNullOrEmpty(animationTriggers.disabledTrigger) ? "Disabled" : animationTriggers.disabledTrigger; + + // Create controller and hook up transitions. + var controller = Animations.AnimatorController.CreateAnimatorControllerAtPath(path); + GenerateTriggerableTransition(normalName, controller); + GenerateTriggerableTransition(highlightedName, controller); + GenerateTriggerableTransition(pressedName, controller); + GenerateTriggerableTransition(selectedName, controller); + GenerateTriggerableTransition(disabledName, controller); + + AssetDatabase.ImportAsset(path); + + return controller; + } + + private static string GetSaveControllerPath(Selectable target) + { + var defaultName = target.gameObject.name; + var message = string.Format("Create a new animator for the game object '{0}':", defaultName); + return EditorUtility.SaveFilePanelInProject("New Animation Contoller", defaultName, "controller", message); + } + + private static void SetUpCurves(AnimationClip highlightedClip, AnimationClip pressedClip, string animationPath) + { + string[] channels = { "m_LocalScale.x", "m_LocalScale.y", "m_LocalScale.z" }; + + var highlightedKeys = new[] { new Keyframe(0f, 1f), new Keyframe(0.5f, 1.1f), new Keyframe(1f, 1f) }; + var highlightedCurve = new AnimationCurve(highlightedKeys); + foreach (var channel in channels) + AnimationUtility.SetEditorCurve(highlightedClip, EditorCurveBinding.FloatCurve(animationPath, typeof(Transform), channel), highlightedCurve); + + var pressedKeys = new[] { new Keyframe(0f, 1.15f) }; + var pressedCurve = new AnimationCurve(pressedKeys); + foreach (var channel in channels) + AnimationUtility.SetEditorCurve(pressedClip, EditorCurveBinding.FloatCurve(animationPath, typeof(Transform), channel), pressedCurve); + } + + private static string BuildAnimationPath(Selectable target) + { + // if no target don't hook up any curves. + var highlight = target.targetGraphic; + if (highlight == null) + return string.Empty; + + var startGo = highlight.gameObject; + var toFindGo = target.gameObject; + + var pathComponents = new Stack(); + while (toFindGo != startGo) + { + pathComponents.Push(startGo.name); + + // didn't exist in hierarchy! + if (startGo.transform.parent == null) + return string.Empty; + + startGo = startGo.transform.parent.gameObject; + } + + // calculate path + var animPath = new StringBuilder(); + if (pathComponents.Count > 0) + animPath.Append(pathComponents.Pop()); + + while (pathComponents.Count > 0) + animPath.Append("/").Append(pathComponents.Pop()); + + return animPath.ToString(); + } + + private static AnimationClip GenerateTriggerableTransition(string name, Animations.AnimatorController controller) + { + // Create the clip + var clip = Animations.AnimatorController.AllocateAnimatorClip(name); + AssetDatabase.AddObjectToAsset(clip, controller); + + // Create a state in the animatior controller for this clip + var state = controller.AddMotion(clip); + + // Add a transition property + controller.AddParameter(name, AnimatorControllerParameterType.Trigger); + + // Add an any state transition + var stateMachine = controller.layers[0].stateMachine; + var transition = stateMachine.AddAnyStateTransition(state); + transition.AddCondition(Animations.AnimatorConditionMode.If, 0, name); + return clip; + } + + private static void StaticOnSceneGUI(SceneView view) + { + if (!s_ShowNavigation) + return; + + Selectable[] selectables = Selectable.allSelectablesArray; + + for (int i = 0; i < selectables.Length; i++) + { + Selectable s = selectables[i]; + if (SceneManagement.StageUtility.IsGameObjectRenderedByCamera(s.gameObject, Camera.current)) + DrawNavigationForSelectable(s); + } + } + + private static void DrawNavigationForSelectable(Selectable sel) + { + if (sel == null) + return; + + Transform transform = sel.transform; + bool active = Selection.transforms.Any(e => e == transform); + + Handles.color = new Color(1.0f, 0.6f, 0.2f, active ? 1.0f : 0.4f); + DrawNavigationArrow(-Vector2.right, sel, sel.FindSelectableOnLeft()); + DrawNavigationArrow(Vector2.up, sel, sel.FindSelectableOnUp()); + + Handles.color = new Color(1.0f, 0.9f, 0.1f, active ? 1.0f : 0.4f); + DrawNavigationArrow(Vector2.right, sel, sel.FindSelectableOnRight()); + DrawNavigationArrow(-Vector2.up, sel, sel.FindSelectableOnDown()); + } + + const float kArrowThickness = 2.5f; + const float kArrowHeadSize = 1.2f; + + private static void DrawNavigationArrow(Vector2 direction, Selectable fromObj, Selectable toObj) + { + if (fromObj == null || toObj == null) + return; + Transform fromTransform = fromObj.transform; + Transform toTransform = toObj.transform; + + Vector2 sideDir = new Vector2(direction.y, -direction.x); + Vector3 fromPoint = fromTransform.TransformPoint(GetPointOnRectEdge(fromTransform as RectTransform, direction)); + Vector3 toPoint = toTransform.TransformPoint(GetPointOnRectEdge(toTransform as RectTransform, -direction)); + float fromSize = HandleUtility.GetHandleSize(fromPoint) * 0.05f; + float toSize = HandleUtility.GetHandleSize(toPoint) * 0.05f; + fromPoint += fromTransform.TransformDirection(sideDir) * fromSize; + toPoint += toTransform.TransformDirection(sideDir) * toSize; + float length = Vector3.Distance(fromPoint, toPoint); + Vector3 fromTangent = fromTransform.rotation * direction * length * 0.3f; + Vector3 toTangent = toTransform.rotation * -direction * length * 0.3f; + + Handles.DrawBezier(fromPoint, toPoint, fromPoint + fromTangent, toPoint + toTangent, Handles.color, null, kArrowThickness); + Handles.DrawAAPolyLine(kArrowThickness, toPoint, toPoint + toTransform.rotation * (-direction - sideDir) * toSize * kArrowHeadSize); + Handles.DrawAAPolyLine(kArrowThickness, toPoint, toPoint + toTransform.rotation * (-direction + sideDir) * toSize * kArrowHeadSize); + } + + private static Vector3 GetPointOnRectEdge(RectTransform rect, Vector2 dir) + { + if (rect == null) + return Vector3.zero; + if (dir != Vector2.zero) + dir /= Mathf.Max(Mathf.Abs(dir.x), Mathf.Abs(dir.y)); + dir = rect.rect.center + Vector2.Scale(rect.rect.size, dir * 0.5f); + return dir; + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/SelectableEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/SelectableEditor.cs.meta new file mode 100644 index 00000000..b5abe1e4 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/SelectableEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e9253e696cd45794d9aec6d4de366b6e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/SelfControllerEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/SelfControllerEditor.cs new file mode 100644 index 00000000..b7eba217 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/SelfControllerEditor.cs @@ -0,0 +1,38 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace UnityEditor.UI +{ + /// + /// Base class for custom editors that are for components that implement the SelfControllerEditor interface. + /// + public class SelfControllerEditor : Editor + { + static string s_Warning = "Parent has a type of layout group component. A child of a layout group should not have a {0} component, since it should be driven by the layout group."; + + public override void OnInspectorGUI() + { + bool anyHaveLayoutParent = false; + for (int i = 0; i < targets.Length; i++) + { + Component comp = (targets[i] as Component); + ILayoutIgnorer ignorer = comp.GetComponent(typeof(ILayoutIgnorer)) as ILayoutIgnorer; + if (ignorer != null && ignorer.ignoreLayout) + continue; + + RectTransform parent = comp.transform.parent as RectTransform; + if (parent != null) + { + Behaviour layoutGroup = parent.GetComponent(typeof(ILayoutGroup)) as Behaviour; + if (layoutGroup != null && layoutGroup.enabled) + { + anyHaveLayoutParent = true; + break; + } + } + } + if (anyHaveLayoutParent) + EditorGUILayout.HelpBox(string.Format(s_Warning, ObjectNames.NicifyVariableName(target.GetType().Name)), MessageType.Warning); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/SelfControllerEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/SelfControllerEditor.cs.meta new file mode 100644 index 00000000..883cc990 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/SelfControllerEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dcf00682bef4d264d84a5c92c8f5a40f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/SliderEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/SliderEditor.cs new file mode 100644 index 00000000..b95a58f7 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/SliderEditor.cs @@ -0,0 +1,141 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +namespace UnityEditor.UI +{ + [CustomEditor(typeof(Slider), true)] + [CanEditMultipleObjects] + /// + /// Custom Editor for the Slider Component. + /// Extend this class to write a custom editor for a component derived from Slider. + /// + public class SliderEditor : SelectableEditor + { + SerializedProperty m_Direction; + SerializedProperty m_FillRect; + SerializedProperty m_HandleRect; + SerializedProperty m_MinValue; + SerializedProperty m_MaxValue; + SerializedProperty m_WholeNumbers; + SerializedProperty m_Value; + SerializedProperty m_OnValueChanged; + + protected override void OnEnable() + { + base.OnEnable(); + m_FillRect = serializedObject.FindProperty("m_FillRect"); + m_HandleRect = serializedObject.FindProperty("m_HandleRect"); + m_Direction = serializedObject.FindProperty("m_Direction"); + m_MinValue = serializedObject.FindProperty("m_MinValue"); + m_MaxValue = serializedObject.FindProperty("m_MaxValue"); + m_WholeNumbers = serializedObject.FindProperty("m_WholeNumbers"); + m_Value = serializedObject.FindProperty("m_Value"); + m_OnValueChanged = serializedObject.FindProperty("m_OnValueChanged"); + } + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + EditorGUILayout.Space(); + + serializedObject.Update(); + + EditorGUILayout.PropertyField(m_FillRect); + EditorGUILayout.PropertyField(m_HandleRect); + + if (m_FillRect.objectReferenceValue != null || m_HandleRect.objectReferenceValue != null) + { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_Direction); + if (EditorGUI.EndChangeCheck()) + { + Undo.RecordObjects(serializedObject.targetObjects, "Change Slider Direction"); + + Slider.Direction direction = (Slider.Direction)m_Direction.enumValueIndex; + foreach (var obj in serializedObject.targetObjects) + { + Slider slider = obj as Slider; + slider.SetDirection(direction, true); + } + } + + EditorGUI.BeginChangeCheck(); + float newMin = EditorGUILayout.FloatField("Min Value", m_MinValue.floatValue); + if (EditorGUI.EndChangeCheck()) + { + if (m_WholeNumbers.boolValue ? Mathf.Round(newMin) < m_MaxValue.floatValue : newMin < m_MaxValue.floatValue) + { + m_MinValue.floatValue = newMin; + if (m_Value.floatValue < newMin) + m_Value.floatValue = newMin; + } + } + + EditorGUI.BeginChangeCheck(); + float newMax = EditorGUILayout.FloatField("Max Value", m_MaxValue.floatValue); + if (EditorGUI.EndChangeCheck()) + { + if (m_WholeNumbers.boolValue ? Mathf.Round(newMax) > m_MinValue.floatValue : newMax > m_MinValue.floatValue) + { + m_MaxValue.floatValue = newMax; + if (m_Value.floatValue > newMax) + m_Value.floatValue = newMax; + } + } + + EditorGUILayout.PropertyField(m_WholeNumbers); + + bool areMinMaxEqual = (m_MinValue.floatValue == m_MaxValue.floatValue); + + if (areMinMaxEqual) + EditorGUILayout.HelpBox("Min Value and Max Value cannot be equal.", MessageType.Warning); + + if (m_WholeNumbers.boolValue) + m_Value.floatValue = Mathf.Round(m_Value.floatValue); + + EditorGUI.BeginDisabledGroup(areMinMaxEqual); + EditorGUI.BeginChangeCheck(); + EditorGUILayout.Slider(m_Value, m_MinValue.floatValue, m_MaxValue.floatValue); + if (EditorGUI.EndChangeCheck()) + { + // Apply the change before sending the event + serializedObject.ApplyModifiedProperties(); + + foreach (var t in targets) + { + if (t is Slider slider) + { + slider.onValueChanged?.Invoke(slider.value); + } + } + } + EditorGUI.EndDisabledGroup(); + + bool warning = false; + foreach (var obj in serializedObject.targetObjects) + { + Slider slider = obj as Slider; + Slider.Direction dir = slider.direction; + if (dir == Slider.Direction.LeftToRight || dir == Slider.Direction.RightToLeft) + warning = (slider.navigation.mode != Navigation.Mode.Automatic && (slider.FindSelectableOnLeft() != null || slider.FindSelectableOnRight() != null)); + else + warning = (slider.navigation.mode != Navigation.Mode.Automatic && (slider.FindSelectableOnDown() != null || slider.FindSelectableOnUp() != null)); + } + + if (warning) + EditorGUILayout.HelpBox("The selected slider direction conflicts with navigation. Not all navigation options may work.", MessageType.Warning); + + // Draw the event notification options + EditorGUILayout.Space(); + EditorGUILayout.PropertyField(m_OnValueChanged); + } + else + { + EditorGUILayout.HelpBox("Specify a RectTransform for the slider fill or the slider handle or both. Each must have a parent RectTransform that it can slide within.", MessageType.Info); + } + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/SliderEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/SliderEditor.cs.meta new file mode 100644 index 00000000..ba3ba436 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/SliderEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bc98484caab3b6d4facbcff38be93380 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/SpriteDrawUtility.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/SpriteDrawUtility.cs new file mode 100644 index 00000000..a06dc071 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/SpriteDrawUtility.cs @@ -0,0 +1,201 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace UnityEditor.UI +{ + /// + /// PropertyDrawer for [[SpriteState]]. + /// This is a PropertyDrawer for SpriteState it is implemented using the standard unity PropertyDrawer framework. + /// + internal class SpriteDrawUtility + { + static Texture2D s_ContrastTex; + + // Returns a usable texture that looks like a high-contrast checker board. + static Texture2D contrastTexture + { + get + { + if (s_ContrastTex == null) + s_ContrastTex = CreateCheckerTex( + new Color(0f, 0.0f, 0f, 0.5f), + new Color(1f, 1f, 1f, 0.5f)); + return s_ContrastTex; + } + } + + // Create a checker-background texture. + static Texture2D CreateCheckerTex(Color c0, Color c1) + { + Texture2D tex = new Texture2D(16, 16); + tex.name = "[Generated] Checker Texture"; + tex.hideFlags = HideFlags.DontSave; + + for (int y = 0; y < 8; ++y) for (int x = 0; x < 8; ++x) tex.SetPixel(x, y, c1); + for (int y = 8; y < 16; ++y) for (int x = 0; x < 8; ++x) tex.SetPixel(x, y, c0); + for (int y = 0; y < 8; ++y) for (int x = 8; x < 16; ++x) tex.SetPixel(x, y, c0); + for (int y = 8; y < 16; ++y) for (int x = 8; x < 16; ++x) tex.SetPixel(x, y, c1); + + tex.Apply(); + tex.filterMode = FilterMode.Point; + return tex; + } + + // Create a gradient texture. + static Texture2D CreateGradientTex() + { + Texture2D tex = new Texture2D(1, 16); + tex.name = "[Generated] Gradient Texture"; + tex.hideFlags = HideFlags.DontSave; + + Color c0 = new Color(1f, 1f, 1f, 0f); + Color c1 = new Color(1f, 1f, 1f, 0.4f); + + for (int i = 0; i < 16; ++i) + { + float f = Mathf.Abs((i / 15f) * 2f - 1f); + f *= f; + tex.SetPixel(0, i, Color.Lerp(c0, c1, f)); + } + + tex.Apply(); + tex.filterMode = FilterMode.Bilinear; + return tex; + } + + // Draws the tiled texture. Like GUI.DrawTexture() but tiled instead of stretched. + static void DrawTiledTexture(Rect rect, Texture tex) + { + float u = rect.width / tex.width; + float v = rect.height / tex.height; + + Rect texCoords = new Rect(0, 0, u, v); + TextureWrapMode originalMode = tex.wrapMode; + tex.wrapMode = TextureWrapMode.Repeat; + GUI.DrawTextureWithTexCoords(rect, tex, texCoords); + tex.wrapMode = originalMode; + } + + // Draw the specified Image. + public static void DrawSprite(Sprite sprite, Rect drawArea, Color color) + { + if (sprite == null) + return; + + Texture2D tex = sprite.texture; + if (tex == null) + return; + + Rect outer = sprite.rect; + Rect inner = outer; + inner.xMin += sprite.border.x; + inner.yMin += sprite.border.y; + inner.xMax -= sprite.border.z; + inner.yMax -= sprite.border.w; + + Vector4 uv4 = UnityEngine.Sprites.DataUtility.GetOuterUV(sprite); + Rect uv = new Rect(uv4.x, uv4.y, uv4.z - uv4.x, uv4.w - uv4.y); + Vector4 padding = UnityEngine.Sprites.DataUtility.GetPadding(sprite); + padding.x /= outer.width; + padding.y /= outer.height; + padding.z /= outer.width; + padding.w /= outer.height; + + DrawSprite(tex, drawArea, padding, outer, inner, uv, color, null); + } + + // Draw the specified Image. + public static void DrawSprite(Texture tex, Rect drawArea, Rect outer, Rect uv, Color color) + { + DrawSprite(tex, drawArea, Vector4.zero, outer, outer, uv, color, null); + } + + // Draw the specified Image. + private static void DrawSprite(Texture tex, Rect drawArea, Vector4 padding, Rect outer, Rect inner, Rect uv, Color color, Material mat) + { + // Create the texture rectangle that is centered inside rect. + Rect outerRect = drawArea; + outerRect.width = Mathf.Abs(outer.width); + outerRect.height = Mathf.Abs(outer.height); + + if (outerRect.width > 0f) + { + float f = drawArea.width / outerRect.width; + outerRect.width *= f; + outerRect.height *= f; + } + + if (drawArea.height > outerRect.height) + { + outerRect.y += (drawArea.height - outerRect.height) * 0.5f; + } + else if (outerRect.height > drawArea.height) + { + float f = drawArea.height / outerRect.height; + outerRect.width *= f; + outerRect.height *= f; + } + + if (drawArea.width > outerRect.width) + outerRect.x += (drawArea.width - outerRect.width) * 0.5f; + + // Draw the background + EditorGUI.DrawTextureTransparent(outerRect, null, ScaleMode.ScaleToFit, outer.width / outer.height); + + // Draw the Image + GUI.color = color; + + Rect paddedTexArea = new Rect( + outerRect.x + outerRect.width * padding.x, + outerRect.y + outerRect.height * padding.w, + outerRect.width - (outerRect.width * (padding.z + padding.x)), + outerRect.height - (outerRect.height * (padding.w + padding.y)) + ); + + if (mat == null) + { + GUI.DrawTextureWithTexCoords(paddedTexArea, tex, uv, true); + } + else + { + // NOTE: There is an issue in Unity that prevents it from clipping the drawn preview + // using BeginGroup/EndGroup, and there is no way to specify a UV rect... + EditorGUI.DrawPreviewTexture(paddedTexArea, tex, mat); + } + + // Draw the border indicator lines + GUI.BeginGroup(outerRect); + { + tex = contrastTexture; + GUI.color = Color.white; + + if (inner.xMin != outer.xMin) + { + float x = (inner.xMin - outer.xMin) / outer.width * outerRect.width - 1; + DrawTiledTexture(new Rect(x, 0f, 1f, outerRect.height), tex); + } + + if (inner.xMax != outer.xMax) + { + float x = (inner.xMax - outer.xMin) / outer.width * outerRect.width - 1; + DrawTiledTexture(new Rect(x, 0f, 1f, outerRect.height), tex); + } + + if (inner.yMin != outer.yMin) + { + // GUI.DrawTexture is top-left based rather than bottom-left + float y = (inner.yMin - outer.yMin) / outer.height * outerRect.height - 1; + DrawTiledTexture(new Rect(0f, outerRect.height - y, outerRect.width, 1f), tex); + } + + if (inner.yMax != outer.yMax) + { + float y = (inner.yMax - outer.yMin) / outer.height * outerRect.height - 1; + DrawTiledTexture(new Rect(0f, outerRect.height - y, outerRect.width, 1f), tex); + } + } + + GUI.EndGroup(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/SpriteDrawUtility.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/SpriteDrawUtility.cs.meta new file mode 100644 index 00000000..66071751 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/SpriteDrawUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 260b531edc40677429c0198d6961e448 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/TextEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/TextEditor.cs new file mode 100644 index 00000000..c3dd509e --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/TextEditor.cs @@ -0,0 +1,37 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace UnityEditor.UI +{ + [CustomEditor(typeof(Text), true)] + [CanEditMultipleObjects] + /// + /// Custom Editor for the Text Component. + /// Extend this class to write a custom editor for a component derived from Text. + /// + public class TextEditor : GraphicEditor + { + SerializedProperty m_Text; + SerializedProperty m_FontData; + + protected override void OnEnable() + { + base.OnEnable(); + m_Text = serializedObject.FindProperty("m_Text"); + m_FontData = serializedObject.FindProperty("m_FontData"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.PropertyField(m_Text); + EditorGUILayout.PropertyField(m_FontData); + + AppearanceControlsGUI(); + RaycastControlsGUI(); + MaskableControlsGUI(); + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/TextEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/TextEditor.cs.meta new file mode 100644 index 00000000..109cf771 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/TextEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1336690ece4db2740b4ba38873e00dfb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/ToggleEditor.cs b/Packages/com.unity.ugui/Editor/UGUI/UI/ToggleEditor.cs new file mode 100644 index 00000000..2c0bab3d --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/ToggleEditor.cs @@ -0,0 +1,80 @@ +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.UI; + +namespace UnityEditor.UI +{ + [CustomEditor(typeof(Toggle), true)] + [CanEditMultipleObjects] + /// + /// Custom Editor for the Toggle Component. + /// Extend this class to write a custom editor for a component derived from Toggle. + /// + public class ToggleEditor : SelectableEditor + { + SerializedProperty m_OnValueChangedProperty; + SerializedProperty m_TransitionProperty; + SerializedProperty m_GraphicProperty; + SerializedProperty m_GroupProperty; + SerializedProperty m_IsOnProperty; + + protected override void OnEnable() + { + base.OnEnable(); + + m_TransitionProperty = serializedObject.FindProperty("toggleTransition"); + m_GraphicProperty = serializedObject.FindProperty("graphic"); + m_GroupProperty = serializedObject.FindProperty("m_Group"); + m_IsOnProperty = serializedObject.FindProperty("m_IsOn"); + m_OnValueChangedProperty = serializedObject.FindProperty("onValueChanged"); + } + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + EditorGUILayout.Space(); + + serializedObject.Update(); + Toggle toggle = serializedObject.targetObject as Toggle; + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_IsOnProperty); + if (EditorGUI.EndChangeCheck()) + { + if (!Application.isPlaying) + EditorSceneManager.MarkSceneDirty(toggle.gameObject.scene); + + ToggleGroup group = m_GroupProperty.objectReferenceValue as ToggleGroup; + + toggle.isOn = m_IsOnProperty.boolValue; + + if (group != null && group.isActiveAndEnabled && toggle.IsActive()) + { + if (toggle.isOn || (!group.AnyTogglesOn() && !group.allowSwitchOff)) + { + toggle.isOn = true; + group.NotifyToggleOn(toggle); + } + } + } + EditorGUILayout.PropertyField(m_TransitionProperty); + EditorGUILayout.PropertyField(m_GraphicProperty); + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_GroupProperty); + if (EditorGUI.EndChangeCheck()) + { + if (!Application.isPlaying) + EditorSceneManager.MarkSceneDirty(toggle.gameObject.scene); + + ToggleGroup group = m_GroupProperty.objectReferenceValue as ToggleGroup; + toggle.group = group; + } + + EditorGUILayout.Space(); + + // Draw the event notification options + EditorGUILayout.PropertyField(m_OnValueChangedProperty); + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Packages/com.unity.ugui/Editor/UGUI/UI/ToggleEditor.cs.meta b/Packages/com.unity.ugui/Editor/UGUI/UI/ToggleEditor.cs.meta new file mode 100644 index 00000000..cac46ed1 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UI/ToggleEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d36a7c7a1ed377c4b8008e53032d7dcf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Editor/UGUI/UnityEditor.UI.asmdef b/Packages/com.unity.ugui/Editor/UGUI/UnityEditor.UI.asmdef new file mode 100644 index 00000000..1c34715b --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UnityEditor.UI.asmdef @@ -0,0 +1,28 @@ +{ + "name": "UnityEditor.UI", + + "references": [ + "UnityEngine.UI" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "versionDefines": [ + { + "name": "com.unity.modules.physics", + "expression": "1.0.0", + "define": "PACKAGE_PHYSICS" + }, + { + "name": "com.unity.modules.physics2d", + "expression": "1.0.0", + "define": "PACKAGE_PHYSICS2D" + }, + { + "name": "com.unity.modules.animation", + "expression": "1.0.0", + "define": "PACKAGE_ANIMATION" + } + ] +} \ No newline at end of file diff --git a/Packages/com.unity.ugui/Editor/UGUI/UnityEditor.UI.asmdef.meta b/Packages/com.unity.ugui/Editor/UGUI/UnityEditor.UI.asmdef.meta new file mode 100644 index 00000000..15592b37 --- /dev/null +++ b/Packages/com.unity.ugui/Editor/UGUI/UnityEditor.UI.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 343deaaf83e0cee4ca978e7df0b80d21 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/LICENSE.md b/Packages/com.unity.ugui/LICENSE.md new file mode 100644 index 00000000..3af9c291 --- /dev/null +++ b/Packages/com.unity.ugui/LICENSE.md @@ -0,0 +1,5 @@ +Unity UI Copyright © 2015-2020 Unity Technologies ApS ("**_Unity_**") + +Licensed under the Unity Companion License for Unity-dependent projects (see https://unity3d.com/legal/licenses/unity_companion_license). + +_Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. Please review the license for details on these and other terms and conditions. diff --git a/Packages/com.unity.ugui/LICENSE.md.meta b/Packages/com.unity.ugui/LICENSE.md.meta new file mode 100644 index 00000000..7596d848 --- /dev/null +++ b/Packages/com.unity.ugui/LICENSE.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4d3d51749e989f747b2674e0b4d9b3d7 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Package Resources.meta b/Packages/com.unity.ugui/Package Resources.meta new file mode 100644 index 00000000..e8a96b82 --- /dev/null +++ b/Packages/com.unity.ugui/Package Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5ec95f4d5b2d1f14e9ff8682562553f9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Package Resources/TMP Essential Resources.unitypackage b/Packages/com.unity.ugui/Package Resources/TMP Essential Resources.unitypackage new file mode 100644 index 00000000..30871545 --- /dev/null +++ b/Packages/com.unity.ugui/Package Resources/TMP Essential Resources.unitypackage @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5a258f71e21757d380416b238e099772e09dbead695889add09268d88f4b16a6 +size 888625 diff --git a/Packages/com.unity.ugui/Package Resources/TMP Essential Resources.unitypackage.meta b/Packages/com.unity.ugui/Package Resources/TMP Essential Resources.unitypackage.meta new file mode 100644 index 00000000..bc49ab30 --- /dev/null +++ b/Packages/com.unity.ugui/Package Resources/TMP Essential Resources.unitypackage.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ce4ff17ca867d2b48b5c8a4181611901 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Package Resources/TMP Examples & Extras.unitypackage b/Packages/com.unity.ugui/Package Resources/TMP Examples & Extras.unitypackage new file mode 100644 index 00000000..b7ba6e33 --- /dev/null +++ b/Packages/com.unity.ugui/Package Resources/TMP Examples & Extras.unitypackage @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c0201ed3d2a50c80af8eb10cea7e65393191a08dbff54ecd455672fc141832d2 +size 2104106 diff --git a/Packages/com.unity.ugui/Package Resources/TMP Examples & Extras.unitypackage.meta b/Packages/com.unity.ugui/Package Resources/TMP Examples & Extras.unitypackage.meta new file mode 100644 index 00000000..aaf21f78 --- /dev/null +++ b/Packages/com.unity.ugui/Package Resources/TMP Examples & Extras.unitypackage.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: bc00e25696e4132499f56528d3fed2e3 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/PackageConversionData.json b/Packages/com.unity.ugui/PackageConversionData.json new file mode 100644 index 00000000..05c193e2 --- /dev/null +++ b/Packages/com.unity.ugui/PackageConversionData.json @@ -0,0 +1,654 @@ +{ + "assetRecords": [ + { + "referencedResource": "Blue to Purple - Vertical.asset", + "target": "guid: 1e643bbd7e13d46418da3774e72bef60", + "replacement": "guid: 479a66fa4b094512a62b0a8e553ad95a" + }, + { + "referencedResource": "Dark to Light Green - Vertical.asset", + "target": "guid: 90c9133b254e2184b8084dea4f392337", + "replacement": "guid: 4c86a3366cd840348ebe8dc438570ee4" + }, + { + "referencedResource": "Light to Dark Green - Vertical.asset", + "target": "guid: 33c745f0979f3984182a138bcc6e57ec", + "replacement": "guid: 5cf8ae092ca54931b443bec5148f3c59" + }, + { + "referencedResource": "Yellow to Orange - Vertical.asset", + "target": "guid: e002cb2a36d9e4a439a062867fa24e1e", + "replacement": "guid: 69a525efa7e6472eab268f6ea605f06e" + }, + { + "referencedResource": "Crate - Surface Shader Scene.mat", + "target": "guid: e177c46c2a091564d88df2c2ca9dcf97", + "replacement": "guid: e6b9b44320f4448d9d5e0ee634259966" + }, + { + "referencedResource": "Ground - Logo Scene.mat", + "target": "guid: 504ae362e57fc464b847f1e9fd0e4035", + "replacement": "guid: c719e38f25a9480abd2480ab621a2949" + }, + { + "referencedResource": "Ground - Surface Shader Scene.mat", + "target": "guid: 9ed9aa864ec2d7f4dad266b9534c6d85", + "replacement": "guid: aadd5a709a48466c887296bb5b1b8110" + }, + { + "referencedResource": "Small Crate_diffuse.mat", + "target": "guid: 92f161029a6d3c54a92d9d283352a135", + "replacement": "guid: 22262639920f43d6be32430e4e58350d" + }, + { + "referencedResource": "Text Popup.prefab", + "target": "guid: c879e892866c8db4f8930b25672233ac", + "replacement": "guid: b06f0e6c1dfa4356ac918da1bb32c603" + }, + { + "referencedResource": "TextMeshPro - Prefab 1.prefab", + "target": "guid: a6a60659abb4d9d4b934feebd3dcc952", + "replacement": "guid: a6e39ced0ea046bcb636c3f0b2e2a745" + }, + { + "referencedResource": "TextMeshPro - Prefab 2.prefab", + "target": "guid: 1b190e3e0ab4c8e4881656b9160c59c2", + "replacement": "guid: fdad9d952ae84cafb74c63f2e694d042" + }, + { + "referencedResource": "Anton SDF.asset", + "target": "guid: f76ef802b8b940c46a31f9027f2b0158", + "replacement": "guid: 8a89fa14b10d46a99122fd4f73fca9a2" + }, + { + "referencedResource": "Anton SDF - Drop Shadow.mat", + "target": "guid: 250a1a103b3b4914c9707e6a423446d6", + "replacement": "guid: 749b9069dc4742c5bfa5c74644049926" + }, + { + "referencedResource": "Anton SDF - Outline.mat", + "target": "guid: e077dc203e948b740859c1c0ca8b9691", + "replacement": "guid: a00013af81304728b2be1f4309ee2433" + }, + { + "referencedResource": "Bangers SDF.asset", + "target": "guid: 808aa8f1ab804104aa7d0c337a6c1481", + "replacement": "guid: 125cb55b44b24c4393181402bc6200e6" + }, + { + "referencedResource": "Bangers SDF - Drop Shadow.mat", + "target": "guid: c26f698d4eee19e4a8b8f42cd299bab5", + "replacement": "guid: f2dcf029949142e28b974630369c8b4e" + }, + { + "referencedResource": "Bangers SDF - Outline.mat", + "target": "guid: db7f2cfbf23d6d54ca4e74a9abd55326", + "replacement": "guid: f629c6e43dba4bf38cb74d8860150664" + }, + { + "referencedResource": "Bangers SDF Glow.mat", + "target": "guid: 7dd7006c58d8a3148a73aa211d8c13d0", + "replacement": "guid: d75b8f41e959450c84ac6e967084d3e1" + }, + { + "referencedResource": "Bangers SDF Logo.mat", + "target": "guid: 4fb51aa7001a2244395ddf6a15d37389", + "replacement": "guid: f4e195ac1e204eff960149d1cb34e18c" + }, + { + "referencedResource": "Electronic Highway Sign SDF.asset", + "target": "guid: 163292f6f226d954593d45b079f8aae0", + "replacement": "guid: dc36b3fdc14f47ebb36fd484a67e268a" + }, + { + "referencedResource": "LiberationSans SDF - Drop Shadow.mat", + "target": "guid: 33db60c37b63f08448ded4b385e74e38", + "replacement": "guid: e73a58f6e2794ae7b1b7e50b7fb811b0" + }, + { + "referencedResource": "LiberationSans SDF - Metalic Green.mat", + "target": "guid: 4f9843c79516ed1468b9b5a4f32e67e3", + "replacement": "guid: 8b29aaa3eec7468097ff07adfcf29ac9" + }, + { + "referencedResource": "LiberationSans SDF - Outline.mat", + "target": "guid: 83a1b0fe6c3dbac44b66f09c82e1d509", + "replacement": "guid: 79459efec17a4d00a321bdcc27bbc385" + }, + { + "referencedResource": "LiberationSans SDF - Overlay.mat", + "target": "guid: 55eb086ae18c76e4bb6cc7106d0dd6e2", + "replacement": "guid: 9ad269c99dcf42b7aedefd83dd5a7b9d" + }, + { + "referencedResource": "LiberationSans SDF - Soft Mask.mat", + "target": "guid: 74e06d99c1657fc4abd33f20685ea9ff", + "replacement": "guid: 42df1c7856584b6b8db9a509b6b10074" + }, + { + "referencedResource": "Oswald Bold SDF.asset", + "target": "guid: 09641b029dfa78843902b548a9de7553", + "replacement": "guid: 0161d805a3764c089bef00bfe00793f5" + }, + { + "referencedResource": "Roboto-Bold SDF.asset", + "target": "guid: d62a573c923f5cb47b8ff65261033b90", + "replacement": "guid: 5302535af1044152a457ed104f1f4b91" + }, + { + "referencedResource": "Roboto-Bold SDF - Drop Shadow.mat", + "target": "guid: 102e7c5c5e3b1f3468518cb166967d77", + "replacement": "guid: b246c4190f4e46ec9352fe15a7b09ce0" + }, + { + "referencedResource": "Roboto-Bold SDF - Surface.mat", + "target": "guid: e2da38ead8f8238449c54a1ef49e080f", + "replacement": "guid: e6b276ec991f467aa14ef1f3cc665993" + }, + { + "referencedResource": "DropCap Numbers.asset", + "target": "guid: c4fd2a959a50b584b92dedfefec1ffda", + "replacement": "guid: 14aa93acbb234d16aaef0e8b46814db6" + }, + { + "referencedResource": "Benchmark01.cs", + "target": "guid: c5fb1b5c24460f745be29cc0eb06a58c", + "replacement": "guid: f970ea55f9f84bf79b05dab180b8c125" + }, + { + "referencedResource": "Benchmark01_UGUI.cs", + "target": "guid: 5e6abf300e36c0a4eb43969c3f2172f8", + "replacement": "guid: 8ef7be1c625941f7ba8ed7cc71718c0d" + }, + { + "referencedResource": "Benchmark02.cs", + "target": "guid: 3467f4170568a484d8b57e2051a27363", + "replacement": "guid: e8538afcddc14efbb5d9e94b7ae50197" + }, + { + "referencedResource": "Benchmark03.cs", + "target": "guid: e6e9d20624a23da4c8b2b6fb7608bb9a", + "replacement": "guid: a73109742c8d47ac822895a473300c29" + }, + { + "referencedResource": "Benchmark04.cs", + "target": "guid: 481dd67bdedc3104ea2156ed49f3acd5", + "replacement": "guid: dc20866c0d5e413ab7559440e15333ae" + }, + { + "referencedResource": "CameraController.cs", + "target": "guid: a9f0e07aefca0cc459134ff9df622278", + "replacement": "guid: 2d687537154440a3913a9a3c7977978c" + }, + { + "referencedResource": "ChatController.cs", + "target": "guid: eba5a4db2591a5844aea5f6f3ad8548e", + "replacement": "guid: 53d91f98a2664f5cb9af11de72ac54ec" + }, + { + "referencedResource": "EnvMapAnimator.cs", + "target": "guid: 7e69f3f28c520ce4d9ab9964b2895b1a", + "replacement": "guid: a4b6f99e8bc54541bbd149b014ff441c" + }, + { + "referencedResource": "ObjectSpin.cs", + "target": "guid: 5e7872ff51989434dabf7807265ada3c", + "replacement": "guid: 4f19c7f94c794c5097d8bd11e39c750d" + }, + { + "referencedResource": "ShaderPropAnimator.cs", + "target": "guid: c56cf968fb6a5b6488e709242718845d", + "replacement": "guid: 2787a46a4dc848c1b4b7b9307b614bfd" + }, + { + "referencedResource": "SimpleScript.cs", + "target": "guid: c64808ff5137c9044a583750e5b0468a", + "replacement": "guid: 9eff140b25d64601aabc6ba32245d099" + }, + { + "referencedResource": "SkewTextExample.cs", + "target": "guid: 48d40dfeb33b717488f55ddbf676643a", + "replacement": "guid: d412675cfb3441efa3bf8dcd9b7624dc" + }, + { + "referencedResource": "TeleType.cs", + "target": "guid: 9094c5c777af3f14489e8947748e86e6", + "replacement": "guid: e32c266ee6204b21a427753cb0694c81" + }, + { + "referencedResource": "TextConsoleSimulator.cs", + "target": "guid: 45757dcc8f119454dac6365e8fd15e8b", + "replacement": "guid: 43bcd35a1c0c40ccb6d472893fe2093f" + }, + { + "referencedResource": "TextMeshProFloatingText.cs", + "target": "guid: dd0e4b969aa70504382a89d2f208ae6c", + "replacement": "guid: a4d4c76e63944cba8c7d00f56334b98c" + }, + { + "referencedResource": "TextMeshSpawner.cs", + "target": "guid: 385939aed18e82d41894437798c30ed8", + "replacement": "guid: 76c11bbcfddf44e0ba17d6c2751c8d84" + }, + { + "referencedResource": "TMP_ExampleScript_01.cs", + "target": "guid: 36bafabb5572c6347923b971425ab3be", + "replacement": "guid: 6f2c5b59b6874405865e2616e4ec276a" + }, + { + "referencedResource": "TMP_FrameRateCounter.cs", + "target": "guid: c0357609254b68d4881cab18f04dd4dc", + "replacement": "guid: 686ec78b56aa445795335fbadafcfaa4" + }, + { + "referencedResource": "TMP_TextEventCheck.cs", + "target": "guid: ba181bda76b7f6047ba2188e94bf0894", + "replacement": "guid: d736ce056cf444ca96e424f4d9c42b76" + }, + { + "referencedResource": "TMP_TextEventHandler.cs", + "target": "guid: 48a2fdbd95acd794caf78a85a0b6926a", + "replacement": "guid: 1312ae25639a4bae8e25ae223209cc50" + }, + { + "referencedResource": "TMP_TextInfoDebugTool.cs", + "target": "guid: 5eeee4467ee5b6a4884a1ec94812d93e", + "replacement": "guid: 21256c5b62f346f18640dad779911e20" + }, + { + "referencedResource": "TMP_TextSelector_A.cs", + "target": "guid: 68baf2864c88f4a43a50f16709de8717", + "replacement": "guid: 103e0a6a1d404693b9fb1a5173e0e979" + }, + { + "referencedResource": "TMP_TextSelector_B.cs", + "target": "guid: f499ff45b9a3d0840a0df48d01b2877b", + "replacement": "guid: a05dcd8be7ec4ccbb35c26219884aa37" + }, + { + "referencedResource": "TMP_UiFrameRateCounter.cs", + "target": "guid: dc33b7a34d20d5e4e8d54b6867ce81e3", + "replacement": "guid: 24b0dc2d1d494adbbec1f4db26b4cf83" + }, + { + "referencedResource": "TMPro_InstructionOverlay.cs", + "target": "guid: 53b866620ba77504eaf52cab7dbd95c9", + "replacement": "guid: c3c1afeda5e545e0b19add5373896d2e" + }, + { + "referencedResource": "VertexColorCycler.cs", + "target": "guid: c8d54cdd5913d4e4bb7b655d7d16835b", + "replacement": "guid: 91b8ba3d52e041fab2d0e0f169855539" + }, + { + "referencedResource": "VertexJitter.cs", + "target": "guid: e4769cb37968ea948a763a9a89f9e583", + "replacement": "guid: 2ed57967c52645d390a89dcf8f61ba73" + }, + { + "referencedResource": "VertexShakeA.cs", + "target": "guid: eaa12d191e718c945ac55da73fa469db", + "replacement": "guid: f7cfa58e417a46ea8889989684c2522e" + }, + { + "referencedResource": "VertexShakeB.cs", + "target": "guid: 32c83a5d3ba42b84aa26386eac47566b", + "replacement": "guid: e4e0d9ccee5f4950be8979268c9014e0" + }, + { + "referencedResource": "VertexZoom.cs", + "target": "guid: 5305493000edc7d4ea4302757dc19a99", + "replacement": "guid: 52ec835d14bd486f900952b77698b7eb" + }, + { + "referencedResource": "WarpTextExample.cs", + "target": "guid: f3eef864a10f51045a7530e2afe7c179", + "replacement": "guid: 790744c462254b7ba8038e6ed28b3db2" + }, + { + "referencedResource": "DropCap Numbers.psd", + "target": "guid: 28b41fef228d6814f90e541deaf9f262", + "replacement": "guid: fd09957580ac4326916010f1f260975b" + }, + { + "referencedResource": "Brushed Metal 3.jpg", + "target": "guid: c30270e41dccf9441ab56d94261bdcfa", + "replacement": "guid: f88677df267a41d6be1e7a6133e7d227" + }, + { + "referencedResource": "Engraved Wall.jpg", + "target": "guid: 93d6f74f2ef358e41989d4152b195f88", + "replacement": "guid: e0f91e6569da4934a48d85bf8d3063f0" + }, + { + "referencedResource": "Engraved Wall Normal.jpg", + "target": "guid: 1edd0950293e8664094053a041548c23", + "replacement": "guid: 20f91c93e7fb490f9496609c52ef3904" + }, + { + "referencedResource": "Floor Cement.jpg", + "target": "guid: ac5a0a5373b36e049bb7f98f88dbc244", + "replacement": "guid: 283f897e4925411ebbaa758b4cb13fc2" + }, + { + "referencedResource": "Floor Tiles 1 - diffuse.jpg", + "target": "guid: 7bbfb8818476e4641ba3e75f5225eb69", + "replacement": "guid: 85ac55597b97403c82fc6601a93cf241" + }, + { + "referencedResource": "Floor Tiles 1 - normal.jpg", + "target": "guid: e00d5a9a0944134448432ccacf221b95", + "replacement": "guid: c45cd05946364f32aba704f0853a975b" + }, + { + "referencedResource": "Fruit Jelly (B&W).jpg", + "target": "guid: 74d8c208a0193e14ca6916bea88a2c52", + "replacement": "guid: 1cdc5b506b1a4a33a53c30669ced1f51" + }, + { + "referencedResource": "Gradient Diagonal (Color).jpg", + "target": "guid: 2421a4955e71725448211e6bfbc7d7fb", + "replacement": "guid: 2ce5c55e85304b819a1826ecbc839aa5" + }, + { + "referencedResource": "Gradient Horizontal (Color).jpg", + "target": "guid: 0bbb43aff4f7811419ffceb1b16cf3d6", + "replacement": "guid: 6eb184de103d4b3f812b38561065192f" + }, + { + "referencedResource": "Gradient Vertical (Color).jpg", + "target": "guid: 3359915af07779e4e9a966df9eed764f", + "replacement": "guid: 03d0538de6e24c0f819bfc9ce084dfa9" + }, + { + "referencedResource": "Mask Zig-n-Zag.psd", + "target": "guid: 04eb87e72b3c1c648ba47a869ee00505", + "replacement": "guid: bb8dfcd263ad4eb383a33d74a720be6f" + }, + { + "referencedResource": "Sand Normal Map.jpg", + "target": "guid: 89e1b1c005d29cf4598ea861deb35a80", + "replacement": "guid: 8b8c8a10edf94ddc8cc4cc4fcd5696a9" + }, + { + "referencedResource": "Small Crate_diffuse.jpg", + "target": "guid: 64734c9bc6df32149a0c9cb0b18693e1", + "replacement": "guid: 602cb87b6a29443b8636370ea0751574" + }, + { + "referencedResource": "Small Crate_normal.jpg", + "target": "guid: 81b50d9cb6f3104448ec54c00a80101a", + "replacement": "guid: 8878a782f4334ecbbcf683b3ac780966" + }, + { + "referencedResource": "Stainless 03.png", + "target": "guid: 40d7f27f614cc1043a1f7e19074f461c", + "replacement": "guid: 83cb272f9ee046f6ab6636ca38af8db4" + }, + { + "referencedResource": "Text Overflow - Linked Text Image 1.png", + "target": "guid: 1fd8c568b1fcdbe43be65c1619cf3293", + "replacement": "guid: 4ccf43d26c4748c792174516f4a8fcef" + }, + { + "referencedResource": "Text Overflow - Linked Text UI Screenshot.png", + "target": "guid: 7983d2ec0427c114a916ae3c4769dc10", + "replacement": "guid: c76d18757a194d618355f05f815cb0a1" + }, + { + "referencedResource": "Wipe Pattern - Circle.psd", + "target": "guid: 6f5e9497d22a7a84193ec825e2eb41ac", + "replacement": "guid: 10c49fcd9c64421db7c0133e61e55f97" + }, + { + "referencedResource": "Wipe Pattern - Diagonal.psd", + "target": "guid: 8ee4d366b96418044aa9f94b3e2de645", + "replacement": "guid: ed5290d8df18488780e2996b9b882f01" + }, + { + "referencedResource": "Wipe Pattern - Radial Double.psd", + "target": "guid: 3e0e22da7c9570b498205179ef58ef38", + "replacement": "guid: 7631f4eff8f74ed38eb3eb9db17134e1" + }, + { + "referencedResource": "Wipe Pattern - Radial Quad.psd", + "target": "guid: 05ffd580f33f74644a6025ec196860af", + "replacement": "guid: 2b5e9ae96c5644d8bae932f8b4ca68a2" + }, + { + "referencedResource": "LiberationSans SDF.asset", + "target": "guid: 715b80e429c437e40867928a4e1fc975", + "replacement": "guid: 8f586378b4e144a9851e7b34d9b748ee" + }, + { + "referencedResource": "LineBreaking Following Characters.txt", + "target": "guid: 312ba5b9e90627940866e19549a788cf", + "replacement": "guid: fade42e8bc714b018fac513c043d323b" + }, + { + "referencedResource": "LineBreaking Leading Characters.txt", + "target": "guid: 8d713940fcbede142ae4a33ea0062b33", + "replacement": "guid: d82c1b31c7e74239bff1220585707d2b" + }, + { + "referencedResource": "TMP_Bitmap.shader", + "target": "guid: edfcf888cd11d9245b91d2883049a57e", + "replacement": "guid: 128e987d567d4e2c824d754223b3f3b0" + }, + { + "referencedResource": "TMP_Bitmap-Mobile.shader", + "target": "guid: d1cf17907700cb647aa3ea423ba38f2e", + "replacement": "guid: 1e3b057af24249748ff873be7fafee47" + }, + { + "referencedResource": "TMP_SDF.shader", + "target": "guid: dca26082f9cb439469295791d9f76fe5", + "replacement": "guid: 68e6db2ebdc24f95958faec2be5558d6" + }, + { + "referencedResource": "TMP_SDF Overlay.shader", + "target": "guid: 4a7755d6b5b67874f89c85f56f95fe97", + "replacement": "guid: dd89cf5b9246416f84610a006f916af7" + }, + { + "referencedResource": "TMP_SDF-Mobile.shader", + "target": "guid: cafd18099dfc0114896e0a8b277b81b6", + "replacement": "guid: fe393ace9b354375a9cb14cdbbc28be4" + }, + { + "referencedResource": "TMP_SDF-Mobile Masking.shader", + "target": "guid: afc255f7c2be52e41973a3d10a2e632d", + "replacement": "guid: bc1ede39bf3643ee8e493720e4259791" + }, + { + "referencedResource": "TMP_SDF-Mobile Overlay.shader", + "target": "guid: 9ecb3fe313cb5f7478141eba4a2d54ed", + "replacement": "guid: a02a7d8c237544f1962732b55a9aebf1" + }, + { + "referencedResource": "TMP_SDF-Surface.shader", + "target": "guid: 8e6b9842dbb1a5a4887378afab854e63", + "replacement": "guid: f7ada0af4f174f0694ca6a487b8f543d" + }, + { + "referencedResource": "TMP_SDF-Surface-Mobile.shader", + "target": "guid: 3c2ea7753c1425145a74d106ec1cd852", + "replacement": "guid: 85187c2149c549c5b33f0cdb02836b17" + }, + { + "referencedResource": "TMP_Sprite.shader", + "target": "guid: 3a1c68c8292caf046bd21158886c5e40", + "replacement": "guid: cf81c85f95fe47e1a27f6ae460cf182c" + }, + { + "referencedResource": "Default Sprite Asset.asset", + "target": "guid: 273ca6c80b4b5d746b5e548f532bffd8", + "replacement": "guid: fbef3c704dce48f08a44612d6c856c8d" + }, + { + "referencedResource": "EmojiOne.asset", + "target": "guid: 9a952e2781ef26940ae089f1053ef4ef", + "replacement": "guid: c41005c129ba4d66911b75229fd70b45" + }, + { + "referencedResource": "TMP Default Style Sheet.asset", + "target": "guid: 54d1085f9a2fdea4587fcfc7dddcd4bc", + "replacement": "guid: f952c082cb03451daed3ee968ac6c63e" + }, + { + "referencedResource": "TMP Settings.asset", + "target": "guid: 69ed5bac41eebaa4c97e9d2a4168c54f", + "replacement": "guid: 3f5b5dff67a942289a9defa416b206f3" + }, + { + "referencedResource": "TextContainer.cs", + "target": "guid: 3b34fc186f40e8043b977d4fa70db8c5", + "replacement": "guid: 32d40088a6124c578ad6b428df586e2e" + }, + { + "referencedResource": "TextContainer.cs", + "target": "fileID: 311004786, guid: 89f0137620f6af44b9ba852b4190e64e", + "replacement": "fileID: 11500000, guid: 32d40088a6124c578ad6b428df586e2e" + }, + { + "referencedResource": "TextMeshPro.cs", + "target": "guid: 1a1578b9753d2604f98d608cb4239e2f", + "replacement": "guid: 9541d86e2fd84c1d9990edf0852d74ab" + }, + { + "referencedResource": "TextMeshPro.cs", + "target": "fileID: -806885394, guid: 89f0137620f6af44b9ba852b4190e64e", + "replacement": "fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab" + }, + { + "referencedResource": "TextMeshProUGUI.cs", + "target": "guid: 496f2e385b0c62542b5c739ccfafd8da", + "replacement": "guid: f4688fdb7df04437aeb418b961361dc5" + }, + { + "referencedResource": "TextMeshProUGUI.cs", + "target": "fileID: 1453722849, guid: 89f0137620f6af44b9ba852b4190e64e", + "replacement": "fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5" + }, + { + "referencedResource": "TMP_Asset.cs", + "target": "guid: e2c4405608b405a4680436e183e53c45", + "replacement": "guid: 3bda1886f58f4e0ab1139400b160c3ee" + }, + { + "referencedResource": "TMP_Asset.cs", + "target": "fileID: -659140726, guid: 89f0137620f6af44b9ba852b4190e64e", + "replacement": "fileID: 11500000, guid: 3bda1886f58f4e0ab1139400b160c3ee" + }, + { + "referencedResource": "TMP_ColorGradient.cs", + "target": "guid: e90e18dd4a044ff4394833216e6bf4d2", + "replacement": "guid: 54d21f6ece3b46479f0c328f8c6007e0" + }, + { + "referencedResource": "TMP_ColorGradient.cs", + "target": "fileID: 2108210716, guid: 89f0137620f6af44b9ba852b4190e64e", + "replacement": "fileID: 11500000, guid: 54d21f6ece3b46479f0c328f8c6007e0" + }, + { + "referencedResource": "TMP_Dropdown.cs", + "target": "guid: 44cb1d34ddab9d449a05fc3747876be1", + "replacement": "guid: 7b743370ac3e4ec2a1668f5455a8ef8a" + }, + { + "referencedResource": "TMP_Dropdown.cs", + "target": "fileID: 1148083418, guid: 89f0137620f6af44b9ba852b4190e64e", + "replacement": "fileID: 11500000, guid: 7b743370ac3e4ec2a1668f5455a8ef8a" + }, + { + "referencedResource": "TMP_FontAsset.cs", + "target": "guid: 74dfce233ddb29b4294c3e23c1d3650d", + "replacement": "guid: 71c1514a6bd24e1e882cebbe1904ce04" + }, + { + "referencedResource": "TMP_FontAsset.cs", + "target": "fileID: -667331979, guid: 89f0137620f6af44b9ba852b4190e64e", + "replacement": "fileID: 11500000, guid: 71c1514a6bd24e1e882cebbe1904ce04" + }, + { + "referencedResource": "TMP_InputField.cs", + "target": "guid: 7b85855a3deaa2e44ac6741a6bbc85f6", + "replacement": "guid: 2da0c512f12947e489f739169773d7ca" + }, + { + "referencedResource": "TMP_InputField.cs", + "target": "fileID: -1620774994, guid: 89f0137620f6af44b9ba852b4190e64e", + "replacement": "fileID: 11500000, guid: 2da0c512f12947e489f739169773d7ca" + }, + { + "referencedResource": "TMP_Settings.cs", + "target": "guid: aafc3c7b9e915d64e8ec3d2c88b3a231", + "replacement": "guid: 2705215ac5b84b70bacc50632be6e391" + }, + { + "referencedResource": "TMP_Settings.cs", + "target": "fileID: -395462249, guid: 89f0137620f6af44b9ba852b4190e64e", + "replacement": "fileID: 11500000, guid: 2705215ac5b84b70bacc50632be6e391" + }, + { + "referencedResource": "TMP_SpriteAsset.cs", + "target": "guid: 90940d439ca0ef746af0b48419b92d2e", + "replacement": "guid: 84a92b25f83d49b9bc132d206b370281" + }, + { + "referencedResource": "TMP_SpriteAsset.cs", + "target": "fileID: 2019389346, guid: 89f0137620f6af44b9ba852b4190e64e", + "replacement": "fileID: 11500000, guid: 84a92b25f83d49b9bc132d206b370281" + }, + { + "referencedResource": "TMP_StyleSheet.cs", + "target": "guid: 13259b4ce497b194eb52a33d8eda0bdc", + "replacement": "guid: ab2114bdc8544297b417dfefe9f1e410" + }, + { + "referencedResource": "TMP_StyleSheet.cs", + "target": "fileID: -1936749209, guid: 89f0137620f6af44b9ba852b4190e64e", + "replacement": "fileID: 11500000, guid: ab2114bdc8544297b417dfefe9f1e410" + }, + { + "referencedResource": "TMP_SubMesh.cs", + "target": "guid: bd950677b2d06c74494b1c1118584fff", + "replacement": "guid: 07994bfe8b0e4adb97d706de5dea48d5" + }, + { + "referencedResource": "TMP_SubMesh.cs", + "target": "fileID: 1330537494, guid: 89f0137620f6af44b9ba852b4190e64e", + "replacement": "fileID: 11500000, guid: 07994bfe8b0e4adb97d706de5dea48d5" + }, + { + "referencedResource": "TMP_SubMeshUI.cs", + "target": "guid: a5378e1f14d974d419f811d6b0861f20", + "replacement": "guid: 058cba836c1846c3aa1c5fd2e28aea77" + }, + { + "referencedResource": "TMP_SubMeshUI.cs", + "target": "fileID: 1908110080, guid: 89f0137620f6af44b9ba852b4190e64e", + "replacement": "fileID: 11500000, guid: 058cba836c1846c3aa1c5fd2e28aea77" + }, + { + "referencedResource": "TMP_Text.cs", + "target": "guid: 9ec8dc9c3fa2e5d41b939b5888d2f1e8", + "replacement": "guid: 5143f58107604835ab1a5efa2d8818fd" + }, + { + "referencedResource": "TMP_Text.cs", + "target": "fileID: -1385168320, guid: 89f0137620f6af44b9ba852b4190e64e", + "replacement": "fileID: 11500000, guid: 5143f58107604835ab1a5efa2d8818fd" + }, + { + "referencedResource": "Default Sprite Asset.png", + "target": "guid: 5b32c2d36abe44540bed74c1f787033b", + "replacement": "guid: a0fc465d6cf04254a2938578735e2383" + }, + { + "referencedResource": "EmojiOne.png", + "target": "guid: 6ec706981a919c3489f0b061a40054e2", + "replacement": "guid: dffef66376be4fa480fb02b19edbe903" + } + ] +} \ No newline at end of file diff --git a/Packages/com.unity.ugui/PackageConversionData.json.meta b/Packages/com.unity.ugui/PackageConversionData.json.meta new file mode 100644 index 00000000..a7a2790c --- /dev/null +++ b/Packages/com.unity.ugui/PackageConversionData.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 05f5bfd584002f948982a1498890f9a9 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/PackageConversionData_Assets.json b/Packages/com.unity.ugui/PackageConversionData_Assets.json new file mode 100644 index 00000000..f07aa23f --- /dev/null +++ b/Packages/com.unity.ugui/PackageConversionData_Assets.json @@ -0,0 +1,184 @@ +{ + "assetRecords": [ + { + "referencedResource": "TMP_FontAsset.cs", + "target": "guid: 74dfce233ddb29b4294c3e23c1d3650d", + "replacement": "guid: 71c1514a6bd24e1e882cebbe1904ce04" + }, + { + "referencedResource": "TMP_FontAsset.cs", + "target": "fileID: -667331979, guid: 89f0137620f6af44b9ba852b4190e64e", + "replacement": "fileID: 11500000, guid: 71c1514a6bd24e1e882cebbe1904ce04" + }, + { + "referencedResource": "Anton SDF.asset", + "target": "guid: f76ef802b8b940c46a31f9027f2b0158", + "replacement": "guid: 8a89fa14b10d46a99122fd4f73fca9a2" + }, + { + "referencedResource": "Bangers SDF.asset", + "target": "guid: 808aa8f1ab804104aa7d0c337a6c1481", + "replacement": "guid: 125cb55b44b24c4393181402bc6200e6" + }, + { + "referencedResource": "Electronic Highway Sign SDF.asset", + "target": "guid: 163292f6f226d954593d45b079f8aae0", + "replacement": "guid: dc36b3fdc14f47ebb36fd484a67e268a" + }, + { + "referencedResource": "Oswald Bold SDF.asset", + "target": "guid: 09641b029dfa78843902b548a9de7553", + "replacement": "guid: 0161d805a3764c089bef00bfe00793f5" + }, + { + "referencedResource": "Roboto-Bold SDF.asset", + "target": "guid: d62a573c923f5cb47b8ff65261033b90", + "replacement": "guid: 5302535af1044152a457ed104f1f4b91" + }, + { + "referencedResource": "LiberationSans SDF.asset", + "target": "guid: 715b80e429c437e40867928a4e1fc975", + "replacement": "guid: 8f586378b4e144a9851e7b34d9b748ee" + }, + { + "referencedResource": "TMP_Bitmap.shader", + "target": "guid: edfcf888cd11d9245b91d2883049a57e", + "replacement": "guid: 128e987d567d4e2c824d754223b3f3b0" + }, + { + "referencedResource": "TMP_Bitmap-Mobile.shader", + "target": "guid: d1cf17907700cb647aa3ea423ba38f2e", + "replacement": "guid: 1e3b057af24249748ff873be7fafee47" + }, + { + "referencedResource": "TMP_SDF.shader", + "target": "guid: dca26082f9cb439469295791d9f76fe5", + "replacement": "guid: 68e6db2ebdc24f95958faec2be5558d6" + }, + { + "referencedResource": "TMP_SDF Overlay.shader", + "target": "guid: 4a7755d6b5b67874f89c85f56f95fe97", + "replacement": "guid: dd89cf5b9246416f84610a006f916af7" + }, + { + "referencedResource": "TMP_SDF-Mobile.shader", + "target": "guid: cafd18099dfc0114896e0a8b277b81b6", + "replacement": "guid: fe393ace9b354375a9cb14cdbbc28be4" + }, + { + "referencedResource": "TMP_SDF-Mobile Masking.shader", + "target": "guid: afc255f7c2be52e41973a3d10a2e632d", + "replacement": "guid: bc1ede39bf3643ee8e493720e4259791" + }, + { + "referencedResource": "TMP_SDF-Mobile Overlay.shader", + "target": "guid: 9ecb3fe313cb5f7478141eba4a2d54ed", + "replacement": "guid: a02a7d8c237544f1962732b55a9aebf1" + }, + { + "referencedResource": "TMP_SDF-Surface.shader", + "target": "guid: 8e6b9842dbb1a5a4887378afab854e63", + "replacement": "guid: f7ada0af4f174f0694ca6a487b8f543d" + }, + { + "referencedResource": "TMP_SDF-Surface-Mobile.shader", + "target": "guid: 3c2ea7753c1425145a74d106ec1cd852", + "replacement": "guid: 85187c2149c549c5b33f0cdb02836b17" + }, + { + "referencedResource": "TMP_Sprite.shader", + "target": "guid: 3a1c68c8292caf046bd21158886c5e40", + "replacement": "guid: cf81c85f95fe47e1a27f6ae460cf182c" + }, + { + "referencedResource": "TMP_ColorGradient.cs", + "target": "guid: e90e18dd4a044ff4394833216e6bf4d2", + "replacement": "guid: 54d21f6ece3b46479f0c328f8c6007e0" + }, + { + "referencedResource": "TMP_ColorGradient.cs", + "target": "fileID: 2108210716, guid: 89f0137620f6af44b9ba852b4190e64e", + "replacement": "fileID: 11500000, guid: 54d21f6ece3b46479f0c328f8c6007e0" + }, + { + "referencedResource": "TMP_Settings.cs", + "target": "guid: aafc3c7b9e915d64e8ec3d2c88b3a231", + "replacement": "guid: 2705215ac5b84b70bacc50632be6e391" + }, + { + "referencedResource": "TMP_Settings.cs", + "target": "fileID: -395462249, guid: 89f0137620f6af44b9ba852b4190e64e", + "replacement": "fileID: 11500000, guid: 2705215ac5b84b70bacc50632be6e391" + }, + { + "referencedResource": "TMP Settings.asset", + "target": "guid: 69ed5bac41eebaa4c97e9d2a4168c54f", + "replacement": "guid: 3f5b5dff67a942289a9defa416b206f3" + }, + { + "referencedResource": "LineBreaking Following Characters.txt", + "target": "guid: 312ba5b9e90627940866e19549a788cf", + "replacement": "guid: fade42e8bc714b018fac513c043d323b" + }, + { + "referencedResource": "LineBreaking Leading Characters.txt", + "target": "guid: 8d713940fcbede142ae4a33ea0062b33", + "replacement": "guid: d82c1b31c7e74239bff1220585707d2b" + }, + { + "referencedResource": "TMP_StyleSheet.cs", + "target": "guid: 13259b4ce497b194eb52a33d8eda0bdc", + "replacement": "guid: ab2114bdc8544297b417dfefe9f1e410" + }, + { + "referencedResource": "TMP_StyleSheet.cs", + "target": "fileID: -1936749209, guid: 89f0137620f6af44b9ba852b4190e64e", + "replacement": "fileID: 11500000, guid: ab2114bdc8544297b417dfefe9f1e410" + }, + { + "referencedResource": "TMP Default Style Sheet.asset", + "target": "guid: 54d1085f9a2fdea4587fcfc7dddcd4bc", + "replacement": "guid: f952c082cb03451daed3ee968ac6c63e" + }, + { + "referencedResource": "TMP_SpriteAsset.cs", + "target": "guid: 90940d439ca0ef746af0b48419b92d2e", + "replacement": "guid: 84a92b25f83d49b9bc132d206b370281" + }, + { + "referencedResource": "TMP_SpriteAsset.cs", + "target": "fileID: 2019389346, guid: 89f0137620f6af44b9ba852b4190e64e", + "replacement": "fileID: 11500000, guid: 84a92b25f83d49b9bc132d206b370281" + }, + { + "referencedResource": "Default Sprite Asset.asset", + "target": "guid: 273ca6c80b4b5d746b5e548f532bffd8", + "replacement": "guid: fbef3c704dce48f08a44612d6c856c8d" + }, + { + "referencedResource": "Default Sprite Asset.png", + "target": "guid: 5b32c2d36abe44540bed74c1f787033b", + "replacement": "guid: a0fc465d6cf04254a2938578735e2383" + }, + { + "referencedResource": "EmojiOne.asset", + "target": "guid: 9a952e2781ef26940ae089f1053ef4ef", + "replacement": "guid: c41005c129ba4d66911b75229fd70b45" + }, + { + "referencedResource": "EmojiOne.png", + "target": "guid: 6ec706981a919c3489f0b061a40054e2", + "replacement": "guid: dffef66376be4fa480fb02b19edbe903" + }, + { + "referencedResource": "DropCap Numbers.asset", + "target": "guid: c4fd2a959a50b584b92dedfefec1ffda", + "replacement": "guid: 14aa93acbb234d16aaef0e8b46814db6" + }, + { + "referencedResource": "DropCap Numbers.psd", + "target": "guid: 28b41fef228d6814f90e541deaf9f262", + "replacement": "guid: fd09957580ac4326916010f1f260975b" + } + ] +} \ No newline at end of file diff --git a/Packages/com.unity.ugui/PackageConversionData_Assets.json.meta b/Packages/com.unity.ugui/PackageConversionData_Assets.json.meta new file mode 100644 index 00000000..f534ac14 --- /dev/null +++ b/Packages/com.unity.ugui/PackageConversionData_Assets.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0e0afa652c0031c48896a97b424d027b +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/README.md b/Packages/com.unity.ugui/README.md new file mode 100644 index 00000000..730b6d50 --- /dev/null +++ b/Packages/com.unity.ugui/README.md @@ -0,0 +1,9 @@ +# Unity UI +The Unity UI package allows you to create in-game user interfaces fast and intuitively. + +## Prerequisites +### Unity 2019.2 +This package is in development, and requires Unity 2019.2. + +## Getting Started +The Unity UI user manual can be found [here](https://docs.unity3d.com/Manual/UISystem.html). diff --git a/Packages/com.unity.ugui/README.md.meta b/Packages/com.unity.ugui/README.md.meta new file mode 100644 index 00000000..5fea44cf --- /dev/null +++ b/Packages/com.unity.ugui/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e0ae6629cc70b514889df37fccb76832 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Runtime.meta b/Packages/com.unity.ugui/Runtime.meta new file mode 100644 index 00000000..112da530 --- /dev/null +++ b/Packages/com.unity.ugui/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: aa14b70e6a58c5b4fa6663623e3dca91 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Runtime/TMP.meta b/Packages/com.unity.ugui/Runtime/TMP.meta new file mode 100644 index 00000000..5dd2b028 --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 619aadd8f276341ca84d7ad5a9c6db21 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Runtime/TMP/AssemblyInfo.cs b/Packages/com.unity.ugui/Runtime/TMP/AssemblyInfo.cs new file mode 100644 index 00000000..80e1b85e --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/AssemblyInfo.cs @@ -0,0 +1,9 @@ +using System.Runtime.CompilerServices; + +// Allow internal visibility for testing purposes. +[assembly: InternalsVisibleTo("Unity.TextCore")] +[assembly: InternalsVisibleTo("Unity.TextCore.FontEngine.Tools")] + +[assembly: InternalsVisibleTo("Unity.FontEngine.Tests")] +[assembly: InternalsVisibleTo("Unity.TextCore.Editor")] +[assembly: InternalsVisibleTo("Unity.TextMeshPro.Editor")] diff --git a/Packages/com.unity.ugui/Runtime/TMP/AssemblyInfo.cs.meta b/Packages/com.unity.ugui/Runtime/TMP/AssemblyInfo.cs.meta new file mode 100644 index 00000000..cd527067 --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1c147d10db452eb4b854a35f84472017 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Runtime/TMP/FastAction.cs b/Packages/com.unity.ugui/Runtime/TMP/FastAction.cs new file mode 100644 index 00000000..5eabdfee --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/FastAction.cs @@ -0,0 +1,161 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + + +namespace TMPro +{ + /// + /// Alternative Action delegate with increased performance when adding or removing delegates. + /// + public class FastAction + { + LinkedList delegates = new LinkedList(); + + Dictionary> lookup = new Dictionary>(); + + public void Add(System.Action rhs) + { + if (lookup.ContainsKey(rhs)) return; + + lookup[rhs] = delegates.AddLast(rhs); + } + + public void Remove(System.Action rhs) + { + LinkedListNode node; + if (lookup.TryGetValue(rhs, out node)) + { + lookup.Remove(rhs); + delegates.Remove(node); + } + } + + public void Call() + { + var node = delegates.First; + while (node != null) + { + node.Value(); + node = node.Next; + } + } + } + + /// + /// Alternative Action delegate with increased performance when adding or removing delegates. + /// + /// The parameter of the method that this delegate encapsulates. + public class FastAction + { + LinkedList> delegates = new LinkedList>(); + + Dictionary, LinkedListNode>> lookup = new Dictionary, LinkedListNode>>(); + + public void Add(System.Action rhs) + { + if (lookup.ContainsKey(rhs)) return; + + lookup[rhs] = delegates.AddLast(rhs); + } + + public void Remove(System.Action rhs) + { + LinkedListNode> node; + if (lookup.TryGetValue(rhs, out node)) + { + lookup.Remove(rhs); + delegates.Remove(node); + } + } + + public void Call(A a) + { + var node = delegates.First; + while (node != null) + { + node.Value(a); + node = node.Next; + } + } + } + + /// + /// Alternative Action delegate with increased performance when adding or removing delegates. + /// + /// The first parameter of the method that this delegate encapsulates. + /// The second parameter of the method that this delegate encapsulates. + public class FastAction + { + LinkedList> delegates = new LinkedList>(); + + Dictionary, LinkedListNode>> lookup = new Dictionary, LinkedListNode>>(); + + public void Add(System.Action rhs) + { + if (lookup.ContainsKey(rhs)) return; + + lookup[rhs] = delegates.AddLast(rhs); + } + + public void Remove(System.Action rhs) + { + LinkedListNode> node; + if (lookup.TryGetValue(rhs, out node)) + { + lookup.Remove(rhs); + delegates.Remove(node); + } + } + + public void Call(A a, B b) + { + var node = delegates.First; + while (node != null) + { + node.Value(a, b); + node = node.Next; + } + } + } + + /// + /// Alternative Action delegate with increased performance when adding or removing delegates. + /// + /// The first parameter of the method that this delegate encapsulates. + /// The second parameter of the method that this delegate encapsulates. + /// The third parameter of the method that this delegate encapsulates. + public class FastAction + { + LinkedList> delegates = new LinkedList>(); + + Dictionary, LinkedListNode>> lookup = new Dictionary, LinkedListNode>>(); + + public void Add(System.Action rhs) + { + if (lookup.ContainsKey(rhs)) return; + + lookup[rhs] = delegates.AddLast(rhs); + } + + public void Remove(System.Action rhs) + { + LinkedListNode> node; + if (lookup.TryGetValue(rhs, out node)) + { + lookup.Remove(rhs); + delegates.Remove(node); + } + } + + public void Call(A a, B b, C c) + { + var node = delegates.First; + while (node != null) + { + node.Value(a, b, c); + node = node.Next; + } + } + } +} \ No newline at end of file diff --git a/Packages/com.unity.ugui/Runtime/TMP/FastAction.cs.meta b/Packages/com.unity.ugui/Runtime/TMP/FastAction.cs.meta new file mode 100644 index 00000000..fcd991e5 --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/FastAction.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 871f8edd56e84b8fb295b10cc3c78f36 +timeCreated: 1435956061 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Runtime/TMP/FontFeatureCommon.cs b/Packages/com.unity.ugui/Runtime/TMP/FontFeatureCommon.cs new file mode 100644 index 00000000..810e06f2 --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/FontFeatureCommon.cs @@ -0,0 +1,15 @@ + + +namespace UnityEngine.TextCore +{ + /// + /// Enumeration of currently supported OpenType Layout features. + /// + public enum OTL_FeatureTag : uint + { + kern = 'k' << 24 | 'e' << 16 | 'r' << 8 | 'n', + liga = 'l' << 24 | 'i' << 16 | 'g' << 8 | 'a', + mark = 'm' << 24 | 'a' << 16 | 'r' << 8 | 'k', + mkmk = 'm' << 24 | 'k' << 16 | 'm' << 8 | 'k', + } +} diff --git a/Packages/com.unity.ugui/Runtime/TMP/FontFeatureCommon.cs.meta b/Packages/com.unity.ugui/Runtime/TMP/FontFeatureCommon.cs.meta new file mode 100644 index 00000000..7ce018bb --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/FontFeatureCommon.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 326e2b1b31fc06d4fa884c803b27b46a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Runtime/TMP/FontFeatureCommonGPOS.cs b/Packages/com.unity.ugui/Runtime/TMP/FontFeatureCommonGPOS.cs new file mode 100644 index 00000000..cd19357a --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/FontFeatureCommonGPOS.cs @@ -0,0 +1,159 @@ +using System; +using UnityEngine; + + +namespace TMPro +{ + /// + /// A GlyphAnchorPoint defines the position of an anchor point relative to the origin of a glyph. + /// This data structure is used by the Mark-to-Base, Mark-to-Mark and Mark-to-Ligature OpenType font features. + /// + [Serializable] + public struct GlyphAnchorPoint + { + /// + /// The x coordinate of the anchor point relative to the glyph. + /// + public float xCoordinate { get { return m_XCoordinate; } set { m_XCoordinate = value; } } + + /// + /// The y coordinate of the anchor point relative to the glyph. + /// + public float yCoordinate { get { return m_YCoordinate; } set { m_YCoordinate = value; } } + + // ============================================= + // Private backing fields for public properties. + // ============================================= + + [SerializeField] + private float m_XCoordinate; + + [SerializeField] + private float m_YCoordinate; + } + + /// + /// A MarkPositionAdjustment defines the positional adjustment of a glyph relative to the anchor point of base glyph. + /// This data structure is used by the Mark-to-Base, Mark-to-Mark and Mark-to-Ligature OpenType font features. + /// + [Serializable] + public struct MarkPositionAdjustment + { + /// + /// The horizontal positional adjustment of the glyph relative to the anchor point of its parent base glyph. + /// + public float xPositionAdjustment { get { return m_XPositionAdjustment; } set { m_XPositionAdjustment = value; } } + + /// + /// The vertical positional adjustment of the glyph relative to the anchor point of its parent base glyph. + /// + public float yPositionAdjustment { get { return m_YPositionAdjustment; } set { m_YPositionAdjustment = value; } } + + /// + /// Initializes and returns an instance of MarkPositionAdjustment + /// + /// The horizontal positional adjustment. + /// The vertical positional adjustment. + public MarkPositionAdjustment(float x, float y) + { + m_XPositionAdjustment = x; + m_YPositionAdjustment = y; + } + + // ============================================= + // Private backing fields for public properties. + // ============================================= + + [SerializeField] + private float m_XPositionAdjustment; + + [SerializeField] + private float m_YPositionAdjustment; + }; + + /// + /// A MarkToBaseAdjustmentRecord defines the positional adjustment between a base glyph and mark glyph. + /// + [Serializable] + public struct MarkToBaseAdjustmentRecord + { + /// + /// The index of the base glyph. + /// + public uint baseGlyphID { get { return m_BaseGlyphID; } set { m_BaseGlyphID = value; } } + + /// + /// The position of the anchor point of the base glyph. + /// + public GlyphAnchorPoint baseGlyphAnchorPoint { get { return m_BaseGlyphAnchorPoint; } set { m_BaseGlyphAnchorPoint = value; } } + + /// + /// The index of the mark glyph. + /// + public uint markGlyphID { get { return m_MarkGlyphID; } set { m_MarkGlyphID = value; } } + + /// + /// The positional adjustment of the mark glyph relative to the anchor point of the base glyph. + /// + public MarkPositionAdjustment markPositionAdjustment { get { return m_MarkPositionAdjustment; } set { m_MarkPositionAdjustment = value; } } + + // ============================================= + // Private backing fields for public properties. + // ============================================= + + [SerializeField] + private uint m_BaseGlyphID; + + [SerializeField] + private GlyphAnchorPoint m_BaseGlyphAnchorPoint; + + [SerializeField] + private uint m_MarkGlyphID; + + [SerializeField] + private MarkPositionAdjustment m_MarkPositionAdjustment; + } + + /// + /// A MarkToMarkAdjustmentRecord defines the positional adjustment between two mark glyphs. + /// + [Serializable] + public struct MarkToMarkAdjustmentRecord + { + /// + /// The index of the base glyph. + /// + public uint baseMarkGlyphID { get { return m_BaseMarkGlyphID; } set { m_BaseMarkGlyphID = value; } } + + /// + /// The position of the anchor point of the base mark glyph. + /// + public GlyphAnchorPoint baseMarkGlyphAnchorPoint { get { return m_BaseMarkGlyphAnchorPoint; } set { m_BaseMarkGlyphAnchorPoint = value; } } + + /// + /// The index of the mark glyph. + /// + public uint combiningMarkGlyphID { get { return m_CombiningMarkGlyphID; } set { m_CombiningMarkGlyphID = value; } } + + /// + /// The positional adjustment of the combining mark glyph relative to the anchor point of the base mark glyph. + /// + public MarkPositionAdjustment combiningMarkPositionAdjustment { get { return m_CombiningMarkPositionAdjustment; } set { m_CombiningMarkPositionAdjustment = value; } } + + // ============================================= + // Private backing fields for public properties. + // ============================================= + + [SerializeField] + private uint m_BaseMarkGlyphID; + + [SerializeField] + private GlyphAnchorPoint m_BaseMarkGlyphAnchorPoint; + + [SerializeField] + private uint m_CombiningMarkGlyphID; + + [SerializeField] + private MarkPositionAdjustment m_CombiningMarkPositionAdjustment; + } +} diff --git a/Packages/com.unity.ugui/Runtime/TMP/FontFeatureCommonGPOS.cs.meta b/Packages/com.unity.ugui/Runtime/TMP/FontFeatureCommonGPOS.cs.meta new file mode 100644 index 00000000..c64f0ec4 --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/FontFeatureCommonGPOS.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a4bbbb1fed4e2b7448af9313d6d00536 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Runtime/TMP/FontFeatureCommonGSUB.cs b/Packages/com.unity.ugui/Runtime/TMP/FontFeatureCommonGSUB.cs new file mode 100644 index 00000000..a7618cf6 --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/FontFeatureCommonGSUB.cs @@ -0,0 +1,107 @@ +using System; +using UnityEngine; + +#pragma warning disable CS0660, CS0661 + +namespace TMPro +{ + /// + /// The SingleSubstitutionRecord defines the substitution of a single glyph by another. + /// + [Serializable] + public struct SingleSubstitutionRecord + { + // + } + + /// + /// The MultipleSubstitutionRecord defines the substitution of a single glyph by multiple glyphs. + /// + [Serializable] + public struct MultipleSubstitutionRecord + { + /// + /// The index of the target glyph being substituted. + /// + public uint targetGlyphID { get { return m_TargetGlyphID; } set { m_TargetGlyphID = value; } } + + /// + /// Array that contains the index of the glyphs replacing the single target glyph. + /// + public uint[] substituteGlyphIDs { get { return m_SubstituteGlyphIDs; } set { m_SubstituteGlyphIDs = value; } } + + // ============================================= + // Private backing fields for public properties. + // ============================================= + + [SerializeField] + private uint m_TargetGlyphID; + + [SerializeField] + private uint[] m_SubstituteGlyphIDs; + } + + /// + /// The AlternateSubstitutionRecord defines the substitution of a single glyph by several potential alternative glyphs. + /// + [Serializable] + public struct AlternateSubstitutionRecord + { + + } + + /// + /// The LigatureSubstitutionRecord defines the substitution of multiple glyphs by a single glyph. + /// + [Serializable] + public struct LigatureSubstitutionRecord + { + /// + /// Array that contains the index of the glyphs being substituted. + /// + public uint[] componentGlyphIDs { get { return m_ComponentGlyphIDs; } set { m_ComponentGlyphIDs = value; } } + + /// + /// The index of the replacement glyph. + /// + public uint ligatureGlyphID { get { return m_LigatureGlyphID; } set { m_LigatureGlyphID = value; } } + + // ============================================= + // Private backing fields for public properties. + // ============================================= + + [SerializeField] + private uint[] m_ComponentGlyphIDs; + + [SerializeField] + private uint m_LigatureGlyphID; + + // ============================================= + // Operator overrides + // ============================================= + + public static bool operator==(LigatureSubstitutionRecord lhs, LigatureSubstitutionRecord rhs) + { + if (lhs.ligatureGlyphID != rhs.m_LigatureGlyphID) + return false; + + int lhsComponentCount = lhs.m_ComponentGlyphIDs.Length; + + if (lhsComponentCount != rhs.m_ComponentGlyphIDs.Length) + return false; + + for (int i = 0; i < lhsComponentCount; i++) + { + if (lhs.m_ComponentGlyphIDs[i] != rhs.m_ComponentGlyphIDs[i]) + return false; + } + + return true; + } + + public static bool operator!=(LigatureSubstitutionRecord lhs, LigatureSubstitutionRecord rhs) + { + return !(lhs == rhs); + } + } +} diff --git a/Packages/com.unity.ugui/Runtime/TMP/FontFeatureCommonGSUB.cs.meta b/Packages/com.unity.ugui/Runtime/TMP/FontFeatureCommonGSUB.cs.meta new file mode 100644 index 00000000..adbd686e --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/FontFeatureCommonGSUB.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 77b2d47bca9376f4a8ae69084a485957 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Runtime/TMP/ITextPreProcessor.cs b/Packages/com.unity.ugui/Runtime/TMP/ITextPreProcessor.cs new file mode 100644 index 00000000..5d3f57a2 --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/ITextPreProcessor.cs @@ -0,0 +1,17 @@ + + +namespace TMPro +{ + /// + /// Interface used for preprocessing and shaping of text. + /// + public interface ITextPreprocessor + { + /// + /// Function used for preprocessing of text + /// + /// Source text to be processed + /// Processed text + string PreprocessText(string text); + } +} diff --git a/Packages/com.unity.ugui/Runtime/TMP/ITextPreProcessor.cs.meta b/Packages/com.unity.ugui/Runtime/TMP/ITextPreProcessor.cs.meta new file mode 100644 index 00000000..8dd70834 --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/ITextPreProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: afc31ad767318c9488de260c166cd21d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Runtime/TMP/MaterialReferenceManager.cs b/Packages/com.unity.ugui/Runtime/TMP/MaterialReferenceManager.cs new file mode 100644 index 00000000..f1ebd5f4 --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/MaterialReferenceManager.cs @@ -0,0 +1,622 @@ +using System.Collections.Generic; +using UnityEngine; + + +namespace TMPro +{ + + public class MaterialReferenceManager + { + private static MaterialReferenceManager s_Instance; + + // Dictionaries used to track Asset references. + private Dictionary m_FontMaterialReferenceLookup = new Dictionary(); + private Dictionary m_FontAssetReferenceLookup = new Dictionary(); + private Dictionary m_SpriteAssetReferenceLookup = new Dictionary(); + private Dictionary m_ColorGradientReferenceLookup = new Dictionary(); + + + /// + /// Get a singleton instance of the registry + /// + public static MaterialReferenceManager instance + { + get + { + if (MaterialReferenceManager.s_Instance == null) + MaterialReferenceManager.s_Instance = new MaterialReferenceManager(); + return MaterialReferenceManager.s_Instance; + } + } + + + + /// + /// Add new font asset reference to dictionary. + /// + /// + public static void AddFontAsset(TMP_FontAsset fontAsset) + { + MaterialReferenceManager.instance.AddFontAssetInternal(fontAsset); + } + + /// + /// Add new Font Asset reference to dictionary. + /// + /// + private void AddFontAssetInternal(TMP_FontAsset fontAsset) + { + if (m_FontAssetReferenceLookup.ContainsKey(fontAsset.hashCode)) return; + + // Add reference to the font asset. + m_FontAssetReferenceLookup.Add(fontAsset.hashCode, fontAsset); + + // Add reference to the font material. + m_FontMaterialReferenceLookup.Add(fontAsset.materialHashCode, fontAsset.material); + } + + + + /// + /// Add new Sprite Asset to dictionary. + /// + /// + /// + public static void AddSpriteAsset(TMP_SpriteAsset spriteAsset) + { + MaterialReferenceManager.instance.AddSpriteAssetInternal(spriteAsset); + } + + /// + /// Internal method to add a new sprite asset to the dictionary. + /// + /// + /// + private void AddSpriteAssetInternal(TMP_SpriteAsset spriteAsset) + { + if (m_SpriteAssetReferenceLookup.ContainsKey(spriteAsset.hashCode)) return; + + // Add reference to sprite asset. + m_SpriteAssetReferenceLookup.Add(spriteAsset.hashCode, spriteAsset); + + // Adding reference to the sprite asset material as well + m_FontMaterialReferenceLookup.Add(spriteAsset.hashCode, spriteAsset.material); + } + + /// + /// Add new Sprite Asset to dictionary. + /// + /// + /// + public static void AddSpriteAsset(int hashCode, TMP_SpriteAsset spriteAsset) + { + MaterialReferenceManager.instance.AddSpriteAssetInternal(hashCode, spriteAsset); + } + + /// + /// Internal method to add a new sprite asset to the dictionary. + /// + /// + /// + private void AddSpriteAssetInternal(int hashCode, TMP_SpriteAsset spriteAsset) + { + if (m_SpriteAssetReferenceLookup.ContainsKey(hashCode)) return; + + // Add reference to Sprite Asset. + m_SpriteAssetReferenceLookup.Add(hashCode, spriteAsset); + + // Add reference to Sprite Asset using the asset hashcode. + m_FontMaterialReferenceLookup.Add(hashCode, spriteAsset.material); + + // Compatibility check + if (spriteAsset.hashCode == 0) + spriteAsset.hashCode = hashCode; + } + + + /// + /// Add new Material reference to dictionary. + /// + /// + /// + public static void AddFontMaterial(int hashCode, Material material) + { + MaterialReferenceManager.instance.AddFontMaterialInternal(hashCode, material); + } + + /// + /// Add new material reference to dictionary. + /// + /// + /// + private void AddFontMaterialInternal(int hashCode, Material material) + { + // Since this function is called after checking if the material is + // contained in the dictionary, there is no need to check again. + m_FontMaterialReferenceLookup.Add(hashCode, material); + } + + + /// + /// Add new Color Gradient Preset to dictionary. + /// + /// + /// + public static void AddColorGradientPreset(int hashCode, TMP_ColorGradient spriteAsset) + { + MaterialReferenceManager.instance.AddColorGradientPreset_Internal(hashCode, spriteAsset); + } + + /// + /// Internal method to add a new Color Gradient Preset to the dictionary. + /// + /// + /// + private void AddColorGradientPreset_Internal(int hashCode, TMP_ColorGradient spriteAsset) + { + if (m_ColorGradientReferenceLookup.ContainsKey(hashCode)) return; + + // Add reference to Color Gradient Preset Asset. + m_ColorGradientReferenceLookup.Add(hashCode, spriteAsset); + } + + + + /// + /// Add new material reference and return the index of this new reference in the materialReferences array. + /// + /// + /// + /// + //public int AddMaterial(Material material, int materialHashCode, TMP_FontAsset fontAsset) + //{ + // if (!m_MaterialReferenceLookup.ContainsKey(materialHashCode)) + // { + // int index = m_MaterialReferenceLookup.Count; + + // materialReferences[index].fontAsset = fontAsset; + // materialReferences[index].material = material; + // materialReferences[index].isDefaultMaterial = material.GetInstanceID() == fontAsset.material.GetInstanceID() ? true : false; + // materialReferences[index].index = index; + // materialReferences[index].referenceCount = 0; + + // m_MaterialReferenceLookup[materialHashCode] = index; + + // // Compute Padding value and store it + // // TODO + + // int fontAssetHashCode = fontAsset.hashCode; + + // if (!m_FontAssetReferenceLookup.ContainsKey(fontAssetHashCode)) + // m_FontAssetReferenceLookup.Add(fontAssetHashCode, fontAsset); + + // m_countInternal += 1; + + // return index; + // } + // else + // { + // return m_MaterialReferenceLookup[materialHashCode]; + // } + //} + + + /// + /// Add new material reference and return the index of this new reference in the materialReferences array. + /// + /// + /// + /// + /// + //public int AddMaterial(Material material, int materialHashCode, TMP_SpriteAsset spriteAsset) + //{ + // if (!m_MaterialReferenceLookup.ContainsKey(materialHashCode)) + // { + // int index = m_MaterialReferenceLookup.Count; + + // materialReferences[index].fontAsset = materialReferences[0].fontAsset; + // materialReferences[index].spriteAsset = spriteAsset; + // materialReferences[index].material = material; + // materialReferences[index].isDefaultMaterial = true; + // materialReferences[index].index = index; + // materialReferences[index].referenceCount = 0; + + // m_MaterialReferenceLookup[materialHashCode] = index; + + // int spriteAssetHashCode = spriteAsset.hashCode; + + // if (!m_SpriteAssetReferenceLookup.ContainsKey(spriteAssetHashCode)) + // m_SpriteAssetReferenceLookup.Add(spriteAssetHashCode, spriteAsset); + + // m_countInternal += 1; + + // return index; + // } + // else + // { + // return m_MaterialReferenceLookup[materialHashCode]; + // } + //} + + + /// + /// Function to check if the font asset is already referenced. + /// + /// + /// + public bool Contains(TMP_FontAsset font) + { + return m_FontAssetReferenceLookup.ContainsKey(font.hashCode); + } + + + /// + /// Function to check if the sprite asset is already referenced. + /// + /// + /// + public bool Contains(TMP_SpriteAsset sprite) + { + return m_FontAssetReferenceLookup.ContainsKey(sprite.hashCode); + } + + + + /// + /// Function returning the Font Asset corresponding to the provided hash code. + /// + /// + /// + /// + public static bool TryGetFontAsset(int hashCode, out TMP_FontAsset fontAsset) + { + return MaterialReferenceManager.instance.TryGetFontAssetInternal(hashCode, out fontAsset); + } + + /// + /// Internal Function returning the Font Asset corresponding to the provided hash code. + /// + /// + /// + /// + private bool TryGetFontAssetInternal(int hashCode, out TMP_FontAsset fontAsset) + { + fontAsset = null; + + return m_FontAssetReferenceLookup.TryGetValue(hashCode, out fontAsset); + } + + + + /// + /// Function returning the Sprite Asset corresponding to the provided hash code. + /// + /// + /// + /// + public static bool TryGetSpriteAsset(int hashCode, out TMP_SpriteAsset spriteAsset) + { + return MaterialReferenceManager.instance.TryGetSpriteAssetInternal(hashCode, out spriteAsset); + } + + /// + /// Internal function returning the Sprite Asset corresponding to the provided hash code. + /// + /// + /// + /// + private bool TryGetSpriteAssetInternal(int hashCode, out TMP_SpriteAsset spriteAsset) + { + spriteAsset = null; + + return m_SpriteAssetReferenceLookup.TryGetValue(hashCode, out spriteAsset); + } + + + /// + /// Function returning the Color Gradient Preset corresponding to the provided hash code. + /// + /// + /// + /// + public static bool TryGetColorGradientPreset(int hashCode, out TMP_ColorGradient gradientPreset) + { + return MaterialReferenceManager.instance.TryGetColorGradientPresetInternal(hashCode, out gradientPreset); + } + + /// + /// Internal function returning the Color Gradient Preset corresponding to the provided hash code. + /// + /// + /// + /// + private bool TryGetColorGradientPresetInternal(int hashCode, out TMP_ColorGradient gradientPreset) + { + gradientPreset = null; + + return m_ColorGradientReferenceLookup.TryGetValue(hashCode, out gradientPreset); + } + + + /// + /// Function returning the Font Material corresponding to the provided hash code. + /// + /// + /// + /// + public static bool TryGetMaterial(int hashCode, out Material material) + { + return MaterialReferenceManager.instance.TryGetMaterialInternal(hashCode, out material); + } + + /// + /// Internal function returning the Font Material corresponding to the provided hash code. + /// + /// + /// + /// + private bool TryGetMaterialInternal(int hashCode, out Material material) + { + material = null; + + return m_FontMaterialReferenceLookup.TryGetValue(hashCode, out material); + } + + + /// + /// Function to lookup a material based on hash code and returning the MaterialReference containing this material. + /// + /// + /// + /// + //public bool TryGetMaterial(int hashCode, out MaterialReference materialReference) + //{ + // int materialIndex = -1; + + // if (m_MaterialReferenceLookup.TryGetValue(hashCode, out materialIndex)) + // { + // materialReference = materialReferences[materialIndex]; + + // return true; + // } + + // materialReference = new MaterialReference(); + + // return false; + //} + + + + /// + /// + /// + /// + /// + //public int GetMaterialIndex(TMP_FontAsset fontAsset) + //{ + // if (m_MaterialReferenceLookup.ContainsKey(fontAsset.materialHashCode)) + // return m_MaterialReferenceLookup[fontAsset.materialHashCode]; + + // return -1; + //} + + + /// + /// + /// + /// + /// + //public TMP_FontAsset GetFontAsset(int index) + //{ + // if (index >= 0 && index < materialReferences.Length) + // return materialReferences[index].fontAsset; + + // return null; + //} + + + /// + /// + /// + /// + /// + /// + //public void SetDefaultMaterial(Material material, int materialHashCode, TMP_FontAsset fontAsset) + //{ + // if (!m_MaterialReferenceLookup.ContainsKey(materialHashCode)) + // { + // materialReferences[0].fontAsset = fontAsset; + // materialReferences[0].material = material; + // materialReferences[0].index = 0; + // materialReferences[0].isDefaultMaterial = material.GetInstanceID() == fontAsset.material.GetInstanceID() ? true : false; + // materialReferences[0].referenceCount = 0; + // m_MaterialReferenceLookup[materialHashCode] = 0; + + // // Compute Padding value and store it + // // TODO + + // int fontHashCode = fontAsset.hashCode; + + // if (!m_FontAssetReferenceLookup.ContainsKey(fontHashCode)) + // m_FontAssetReferenceLookup.Add(fontHashCode, fontAsset); + // } + // else + // { + // materialReferences[0].fontAsset = fontAsset; + // materialReferences[0].material = material; + // materialReferences[0].index = 0; + // materialReferences[0].referenceCount = 0; + // m_MaterialReferenceLookup[materialHashCode] = 0; + // } + // // Compute padding + // // TODO + + // m_countInternal = 1; + //} + + + + /// + /// + /// + //public void Clear() + //{ + // //m_currentIndex = 0; + // m_MaterialReferenceLookup.Clear(); + // m_SpriteAssetReferenceLookup.Clear(); + // m_FontAssetReferenceLookup.Clear(); + //} + + + /// + /// Function to clear the reference count for each of the material references. + /// + //public void ClearReferenceCount() + //{ + // m_countInternal = 0; + + // for (int i = 0; i < materialReferences.Length; i++) + // { + // if (materialReferences[i].fontAsset == null) + // return; + + // materialReferences[i].referenceCount = 0; + // } + //} + + } + + + public struct TMP_MaterialReference + { + public Material material; + public int referenceCount; + } + + + public struct MaterialReference + { + + public int index; + public TMP_FontAsset fontAsset; + public TMP_SpriteAsset spriteAsset; + public Material material; + public bool isDefaultMaterial; + public bool isFallbackMaterial; + public Material fallbackMaterial; + public float padding; + public int referenceCount; + + + /// + /// Constructor for new Material Reference. + /// + /// + /// + /// + /// + /// + public MaterialReference(int index, TMP_FontAsset fontAsset, TMP_SpriteAsset spriteAsset, Material material, float padding) + { + this.index = index; + this.fontAsset = fontAsset; + this.spriteAsset = spriteAsset; + this.material = material; + this.isDefaultMaterial = material.GetInstanceID() == fontAsset.material.GetInstanceID(); + this.isFallbackMaterial = false; + this.fallbackMaterial = null; + this.padding = padding; + this.referenceCount = 0; + } + + + /// + /// Function to check if a certain font asset is contained in the material reference array. + /// + /// + /// + /// + public static bool Contains(MaterialReference[] materialReferences, TMP_FontAsset fontAsset) + { + int id = fontAsset.GetInstanceID(); + + for (int i = 0; i < materialReferences.Length && materialReferences[i].fontAsset != null; i++) + { + if (materialReferences[i].fontAsset.GetInstanceID() == id) + return true; + } + + return false; + } + + + /// + /// Function to add a new material reference and returning its index in the material reference array. + /// + /// + /// + /// + /// + /// + public static int AddMaterialReference(Material material, TMP_FontAsset fontAsset, ref MaterialReference[] materialReferences, Dictionary materialReferenceIndexLookup) + { + int materialID = material.GetInstanceID(); + int index; + + if (materialReferenceIndexLookup.TryGetValue(materialID, out index)) + return index; + + index = materialReferenceIndexLookup.Count; + + // Add new reference index + materialReferenceIndexLookup[materialID] = index; + + if (index >= materialReferences.Length) + System.Array.Resize(ref materialReferences, Mathf.NextPowerOfTwo(index + 1)); + + materialReferences[index].index = index; + materialReferences[index].fontAsset = fontAsset; + materialReferences[index].spriteAsset = null; + materialReferences[index].material = material; + materialReferences[index].isDefaultMaterial = materialID == fontAsset.material.GetInstanceID(); + materialReferences[index].referenceCount = 0; + + return index; + } + + + /// + /// + /// + /// + /// + /// + /// + /// + public static int AddMaterialReference(Material material, TMP_SpriteAsset spriteAsset, ref MaterialReference[] materialReferences, Dictionary materialReferenceIndexLookup) + { + int materialID = material.GetInstanceID(); + int index; + + if (materialReferenceIndexLookup.TryGetValue(materialID, out index)) + return index; + + index = materialReferenceIndexLookup.Count; + + // Add new reference index + materialReferenceIndexLookup[materialID] = index; + + if (index >= materialReferences.Length) + System.Array.Resize(ref materialReferences, Mathf.NextPowerOfTwo(index + 1)); + + materialReferences[index].index = index; + materialReferences[index].fontAsset = materialReferences[0].fontAsset; + materialReferences[index].spriteAsset = spriteAsset; + materialReferences[index].material = material; + materialReferences[index].isDefaultMaterial = true; + materialReferences[index].referenceCount = 0; + + return index; + } + } +} diff --git a/Packages/com.unity.ugui/Runtime/TMP/MaterialReferenceManager.cs.meta b/Packages/com.unity.ugui/Runtime/TMP/MaterialReferenceManager.cs.meta new file mode 100644 index 00000000..17ad5664 --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/MaterialReferenceManager.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 11a6a034ab84493cbed6af5ae7aae78b +timeCreated: 1449743129 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Runtime/TMP/TMP_Asset.cs b/Packages/com.unity.ugui/Runtime/TMP/TMP_Asset.cs new file mode 100644 index 00000000..21f60866 --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/TMP_Asset.cs @@ -0,0 +1,108 @@ +using System; +using UnityEngine; +using UnityEngine.Serialization; +using UnityEngine.TextCore; + +namespace TMPro +{ + // Base class inherited by the various TextMeshPro Assets. + [Serializable] + public abstract class TMP_Asset : ScriptableObject + { + /// + /// The version of the text asset class. + /// Version 1.1.0 introduces new data structure to be compatible with new font asset structure. + /// + public string version + { + get { return m_Version; } + internal set { m_Version = value; } + } + + /// + /// Instance ID of the TMP Asset + /// + public int instanceID + { + get + { + if (m_InstanceID == 0) + m_InstanceID = GetInstanceID(); + + return m_InstanceID; + } + } + + /// + /// HashCode based on the name of the asset. + /// + public int hashCode + { + get + { + if (m_HashCode == 0) + m_HashCode = TMP_TextUtilities.GetHashCode(name); + + return m_HashCode; + } + set => m_HashCode = value; + } + + /// + /// Information about the face of the asset. + /// + public FaceInfo faceInfo + { + get { return m_FaceInfo; } + set { m_FaceInfo = value; } + } + + /// + /// The material used by this asset. + /// + public Material material + { + get => m_Material; + set => m_Material = value; + } + + /// + /// HashCode based on the name of the material assigned to this asset. + /// + public int materialHashCode + { + get + { + if (m_MaterialHashCode == 0) + { + if (m_Material == null) + return 0; + + m_MaterialHashCode = TMP_TextUtilities.GetSimpleHashCode(m_Material.name); + } + + return m_MaterialHashCode; + } + set => m_MaterialHashCode = value; + } + + // ============================================= + // Private backing fields for public properties. + // ============================================= + + [SerializeField] + internal string m_Version; + + internal int m_InstanceID; + + internal int m_HashCode; + + [SerializeField] + internal FaceInfo m_FaceInfo; + + [SerializeField][FormerlySerializedAs("material")] + internal Material m_Material; + + internal int m_MaterialHashCode; + } +} diff --git a/Packages/com.unity.ugui/Runtime/TMP/TMP_Asset.cs.meta b/Packages/com.unity.ugui/Runtime/TMP/TMP_Asset.cs.meta new file mode 100644 index 00000000..62e9ee7a --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/TMP_Asset.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3bda1886f58f4e0ab1139400b160c3ee +timeCreated: 1459318952 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Runtime/TMP/TMP_Character.cs b/Packages/com.unity.ugui/Runtime/TMP/TMP_Character.cs new file mode 100644 index 00000000..6b4cc834 --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/TMP_Character.cs @@ -0,0 +1,70 @@ +using System; +using UnityEngine.TextCore; + +namespace TMPro +{ + /// + /// A basic element of text. + /// + [Serializable] + public class TMP_Character : TMP_TextElement + { + /// + /// Default constructor. + /// + public TMP_Character() + { + m_ElementType = TextElementType.Character; + this.scale = 1.0f; + } + + /// + /// Constructor for new character + /// + /// Unicode value. + /// Glyph + public TMP_Character(uint unicode, Glyph glyph) + { + m_ElementType = TextElementType.Character; + + this.unicode = unicode; + this.textAsset = null; + this.glyph = glyph; + this.glyphIndex = glyph.index; + this.scale = 1.0f; + } + + /// + /// Constructor for new character + /// + /// Unicode value. + /// The font asset to which this character belongs. + /// Glyph + public TMP_Character(uint unicode, TMP_FontAsset fontAsset, Glyph glyph) + { + m_ElementType = TextElementType.Character; + + this.unicode = unicode; + this.textAsset = fontAsset; + this.glyph = glyph; + this.glyphIndex = glyph.index; + this.scale = 1.0f; + } + + /// + /// Constructor for new character + /// + /// Unicode value. + /// Glyph index. + internal TMP_Character(uint unicode, uint glyphIndex) + { + m_ElementType = TextElementType.Character; + + this.unicode = unicode; + this.textAsset = null; + this.glyph = null; + this.glyphIndex = glyphIndex; + this.scale = 1.0f; + } + } +} diff --git a/Packages/com.unity.ugui/Runtime/TMP/TMP_Character.cs.meta b/Packages/com.unity.ugui/Runtime/TMP/TMP_Character.cs.meta new file mode 100644 index 00000000..55aea1b6 --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/TMP_Character.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4ac5b6a65aaeb59478e3b78660e9f134 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Runtime/TMP/TMP_CharacterInfo.cs b/Packages/com.unity.ugui/Runtime/TMP/TMP_CharacterInfo.cs new file mode 100644 index 00000000..cecb1eb3 --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/TMP_CharacterInfo.cs @@ -0,0 +1,223 @@ +using System.Diagnostics; +using UnityEngine; +using UnityEngine.TextCore; + + +namespace TMPro +{ + public struct TMP_Vertex + { + public Vector3 position; + public Vector4 uv; + public Vector2 uv2; + //public Vector2 uv4; + public Color32 color; + + public static TMP_Vertex zero { get { return k_Zero; } } + + //public Vector3 normal; + //public Vector4 tangent; + + static readonly TMP_Vertex k_Zero = new TMP_Vertex(); + } + + /// + /// + /// + public struct TMP_Offset + { + public float left { get { return m_Left; } set { m_Left = value; } } + + public float right { get { return m_Right; } set { m_Right = value; } } + + public float top { get { return m_Top; } set { m_Top = value; } } + + public float bottom { get { return m_Bottom; } set { m_Bottom = value; } } + + public float horizontal { get { return m_Left; } set { m_Left = value; m_Right = value; } } + + public float vertical { get { return m_Top; } set { m_Top = value; m_Bottom = value; } } + + /// + /// + /// + public static TMP_Offset zero { get { return k_ZeroOffset; } } + + // ============================================= + // Private backing fields for public properties. + // ============================================= + + float m_Left; + float m_Right; + float m_Top; + float m_Bottom; + + static readonly TMP_Offset k_ZeroOffset = new TMP_Offset(0F, 0F, 0F, 0F); + + /// + /// + /// + /// + /// + /// + /// + public TMP_Offset(float left, float right, float top, float bottom) + { + m_Left = left; + m_Right = right; + m_Top = top; + m_Bottom = bottom; + } + + /// + /// + /// + /// + /// + public TMP_Offset(float horizontal, float vertical) + { + m_Left = horizontal; + m_Right = horizontal; + m_Top = vertical; + m_Bottom = vertical; + } + + public static bool operator ==(TMP_Offset lhs, TMP_Offset rhs) + { + return lhs.m_Left == rhs.m_Left && + lhs.m_Right == rhs.m_Right && + lhs.m_Top == rhs.m_Top && + lhs.m_Bottom == rhs.m_Bottom; + } + + public static bool operator !=(TMP_Offset lhs, TMP_Offset rhs) + { + return !(lhs == rhs); + } + + public static TMP_Offset operator *(TMP_Offset a, float b) + { + return new TMP_Offset(a.m_Left * b, a.m_Right * b, a.m_Top * b, a.m_Bottom * b); + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public override bool Equals(object obj) + { + return base.Equals(obj); + } + + public bool Equals(TMP_Offset other) + { + return base.Equals(other); + } + } + + + /// + /// + /// + public struct HighlightState + { + public Color32 color; + public TMP_Offset padding; + + public HighlightState(Color32 color, TMP_Offset padding) + { + this.color = color; + this.padding = padding; + } + + public static bool operator ==(HighlightState lhs, HighlightState rhs) + { + return lhs.color.Compare(rhs.color) && lhs.padding == rhs.padding; + } + + public static bool operator !=(HighlightState lhs, HighlightState rhs) + { + return !(lhs == rhs); + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public override bool Equals(object obj) + { + return base.Equals(obj); + } + + public bool Equals(HighlightState other) + { + return base.Equals(other); + } + } + /// + /// Structure containing information about individual text elements (character or sprites). + /// + [DebuggerDisplay("Unicode '{character}' ({((uint)character).ToString(\"X\")})")] + public struct TMP_CharacterInfo + { + public TMP_TextElementType elementType; + + public char character; // Should be changed to an uint to handle UTF32 + + /// + /// Index of the character in the source text. + /// + public int index; + public int stringLength; + + public TMP_TextElement textElement; + public Glyph alternativeGlyph; + public TMP_FontAsset fontAsset; + public Material material; + public int materialReferenceIndex; + public bool isUsingAlternateTypeface; + + public float pointSize; + + //public short wordNumber; + public int lineNumber; + //public short charNumber; + public int pageNumber; + + + public int vertexIndex; + public TMP_Vertex vertex_BL; + public TMP_Vertex vertex_TL; + public TMP_Vertex vertex_TR; + public TMP_Vertex vertex_BR; + + public Vector3 topLeft; + public Vector3 bottomLeft; + public Vector3 topRight; + public Vector3 bottomRight; + + public float origin; + public float xAdvance; + public float ascender; + public float baseLine; + public float descender; + internal float adjustedAscender; + internal float adjustedDescender; + internal float adjustedHorizontalAdvance; + + public float aspectRatio; + public float scale; + public Color32 color; + public Color32 underlineColor; + public int underlineVertexIndex; + public Color32 strikethroughColor; + public int strikethroughVertexIndex; + public Color32 highlightColor; + public HighlightState highlightState; + public FontStyles style; + public bool isVisible; + //public bool isIgnoringAlignment; + } +} diff --git a/Packages/com.unity.ugui/Runtime/TMP/TMP_CharacterInfo.cs.meta b/Packages/com.unity.ugui/Runtime/TMP/TMP_CharacterInfo.cs.meta new file mode 100644 index 00000000..9367a16e --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/TMP_CharacterInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 90fe1c65e6bb3bc4e90862df7297719e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Runtime/TMP/TMP_ColorGradient.cs b/Packages/com.unity.ugui/Runtime/TMP/TMP_ColorGradient.cs new file mode 100644 index 00000000..8e8e38a8 --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/TMP_ColorGradient.cs @@ -0,0 +1,68 @@ +using UnityEngine; +using System.Collections; + +namespace TMPro +{ + public enum ColorMode + { + Single, + HorizontalGradient, + VerticalGradient, + FourCornersGradient + } + + [System.Serializable][ExcludeFromPresetAttribute] + public class TMP_ColorGradient : ScriptableObject + { + public ColorMode colorMode = ColorMode.FourCornersGradient; + + public Color topLeft; + public Color topRight; + public Color bottomLeft; + public Color bottomRight; + + const ColorMode k_DefaultColorMode = ColorMode.FourCornersGradient; + static readonly Color k_DefaultColor = Color.white; + + /// + /// Default Constructor which sets each of the colors as white. + /// + public TMP_ColorGradient() + { + colorMode = k_DefaultColorMode; + topLeft = k_DefaultColor; + topRight = k_DefaultColor; + bottomLeft = k_DefaultColor; + bottomRight = k_DefaultColor; + } + + /// + /// Constructor allowing to set the default color of the Color Gradient. + /// + /// + public TMP_ColorGradient(Color color) + { + colorMode = k_DefaultColorMode; + topLeft = color; + topRight = color; + bottomLeft = color; + bottomRight = color; + } + + /// + /// The vertex colors at the corners of the characters. + /// + /// Top left color. + /// Top right color. + /// Bottom left color. + /// Bottom right color. + public TMP_ColorGradient(Color color0, Color color1, Color color2, Color color3) + { + colorMode = k_DefaultColorMode; + this.topLeft = color0; + this.topRight = color1; + this.bottomLeft = color2; + this.bottomRight = color3; + } + } +} diff --git a/Packages/com.unity.ugui/Runtime/TMP/TMP_ColorGradient.cs.meta b/Packages/com.unity.ugui/Runtime/TMP/TMP_ColorGradient.cs.meta new file mode 100644 index 00000000..1d79d010 --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/TMP_ColorGradient.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 54d21f6ece3b46479f0c328f8c6007e0 +timeCreated: 1468187202 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Runtime/TMP/TMP_Compatibility.cs b/Packages/com.unity.ugui/Runtime/TMP/TMP_Compatibility.cs new file mode 100644 index 00000000..8484a5c3 --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/TMP_Compatibility.cs @@ -0,0 +1,74 @@ +using UnityEngine; +using System.Collections; + + +namespace TMPro +{ + // Class used to convert scenes and objects saved in version 0.1.44 to the new Text Container + public static class TMP_Compatibility + { + public enum AnchorPositions { TopLeft, Top, TopRight, Left, Center, Right, BottomLeft, Bottom, BottomRight, BaseLine, None }; + + /// + /// Function used to convert text alignment option enumeration format. + /// + /// + /// + public static TextAlignmentOptions ConvertTextAlignmentEnumValues(TextAlignmentOptions oldValue) + { + switch ((int)oldValue) + { + case 0: + return TextAlignmentOptions.TopLeft; + case 1: + return TextAlignmentOptions.Top; + case 2: + return TextAlignmentOptions.TopRight; + case 3: + return TextAlignmentOptions.TopJustified; + case 4: + return TextAlignmentOptions.Left; + case 5: + return TextAlignmentOptions.Center; + case 6: + return TextAlignmentOptions.Right; + case 7: + return TextAlignmentOptions.Justified; + case 8: + return TextAlignmentOptions.BottomLeft; + case 9: + return TextAlignmentOptions.Bottom; + case 10: + return TextAlignmentOptions.BottomRight; + case 11: + return TextAlignmentOptions.BottomJustified; + case 12: + return TextAlignmentOptions.BaselineLeft; + case 13: + return TextAlignmentOptions.Baseline; + case 14: + return TextAlignmentOptions.BaselineRight; + case 15: + return TextAlignmentOptions.BaselineJustified; + case 16: + return TextAlignmentOptions.MidlineLeft; + case 17: + return TextAlignmentOptions.Midline; + case 18: + return TextAlignmentOptions.MidlineRight; + case 19: + return TextAlignmentOptions.MidlineJustified; + case 20: + return TextAlignmentOptions.CaplineLeft; + case 21: + return TextAlignmentOptions.Capline; + case 22: + return TextAlignmentOptions.CaplineRight; + case 23: + return TextAlignmentOptions.CaplineJustified; + } + + return TextAlignmentOptions.TopLeft; + } + } +} diff --git a/Packages/com.unity.ugui/Runtime/TMP/TMP_Compatibility.cs.meta b/Packages/com.unity.ugui/Runtime/TMP/TMP_Compatibility.cs.meta new file mode 100644 index 00000000..e0c9caba --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/TMP_Compatibility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 21364f754cf9b9b47a60742332d4af56 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Runtime/TMP/TMP_CoroutineTween.cs b/Packages/com.unity.ugui/Runtime/TMP/TMP_CoroutineTween.cs new file mode 100644 index 00000000..bec1f54e --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/TMP_CoroutineTween.cs @@ -0,0 +1,246 @@ +using UnityEngine; +using UnityEngine.Events; +using System.Collections; + + +namespace TMPro +{ + // Base interface for tweeners, + // using an interface instead of + // an abstract class as we want the + // tweens to be structs. + internal interface ITweenValue + { + void TweenValue(float floatPercentage); + bool ignoreTimeScale { get; } + float duration { get; } + bool ValidTarget(); + } + + // Color tween class, receives the + // TweenValue callback and then sets + // the value on the target. + internal struct ColorTween : ITweenValue + { + public enum ColorTweenMode + { + All, + RGB, + Alpha + } + + public class ColorTweenCallback : UnityEvent { } + + private ColorTweenCallback m_Target; + private Color m_StartColor; + private Color m_TargetColor; + private ColorTweenMode m_TweenMode; + + private float m_Duration; + private bool m_IgnoreTimeScale; + + public Color startColor + { + get { return m_StartColor; } + set { m_StartColor = value; } + } + + public Color targetColor + { + get { return m_TargetColor; } + set { m_TargetColor = value; } + } + + public ColorTweenMode tweenMode + { + get { return m_TweenMode; } + set { m_TweenMode = value; } + } + + public float duration + { + get { return m_Duration; } + set { m_Duration = value; } + } + + public bool ignoreTimeScale + { + get { return m_IgnoreTimeScale; } + set { m_IgnoreTimeScale = value; } + } + + public void TweenValue(float floatPercentage) + { + if (!ValidTarget()) + return; + + var newColor = Color.Lerp(m_StartColor, m_TargetColor, floatPercentage); + + if (m_TweenMode == ColorTweenMode.Alpha) + { + newColor.r = m_StartColor.r; + newColor.g = m_StartColor.g; + newColor.b = m_StartColor.b; + } + else if (m_TweenMode == ColorTweenMode.RGB) + { + newColor.a = m_StartColor.a; + } + m_Target.Invoke(newColor); + } + + public void AddOnChangedCallback(UnityAction callback) + { + if (m_Target == null) + m_Target = new ColorTweenCallback(); + + m_Target.AddListener(callback); + } + + public bool GetIgnoreTimescale() + { + return m_IgnoreTimeScale; + } + + public float GetDuration() + { + return m_Duration; + } + + public bool ValidTarget() + { + return m_Target != null; + } + } + + // Float tween class, receives the + // TweenValue callback and then sets + // the value on the target. + internal struct FloatTween : ITweenValue + { + public class FloatTweenCallback : UnityEvent { } + + private FloatTweenCallback m_Target; + private float m_StartValue; + private float m_TargetValue; + + private float m_Duration; + private bool m_IgnoreTimeScale; + + public float startValue + { + get { return m_StartValue; } + set { m_StartValue = value; } + } + + public float targetValue + { + get { return m_TargetValue; } + set { m_TargetValue = value; } + } + + public float duration + { + get { return m_Duration; } + set { m_Duration = value; } + } + + public bool ignoreTimeScale + { + get { return m_IgnoreTimeScale; } + set { m_IgnoreTimeScale = value; } + } + + public void TweenValue(float floatPercentage) + { + if (!ValidTarget()) + return; + + var newValue = Mathf.Lerp(m_StartValue, m_TargetValue, floatPercentage); + m_Target.Invoke(newValue); + } + + public void AddOnChangedCallback(UnityAction callback) + { + if (m_Target == null) + m_Target = new FloatTweenCallback(); + + m_Target.AddListener(callback); + } + + public bool GetIgnoreTimescale() + { + return m_IgnoreTimeScale; + } + + public float GetDuration() + { + return m_Duration; + } + + public bool ValidTarget() + { + return m_Target != null; + } + } + + // Tween runner, executes the given tween. + // The coroutine will live within the given + // behaviour container. + internal class TweenRunner where T : struct, ITweenValue + { + protected MonoBehaviour m_CoroutineContainer; + protected IEnumerator m_Tween; + + // utility function for starting the tween + private static IEnumerator Start(T tweenInfo) + { + if (!tweenInfo.ValidTarget()) + yield break; + + var elapsedTime = 0.0f; + while (elapsedTime < tweenInfo.duration) + { + elapsedTime += tweenInfo.ignoreTimeScale ? Time.unscaledDeltaTime : Time.deltaTime; + var percentage = Mathf.Clamp01(elapsedTime / tweenInfo.duration); + tweenInfo.TweenValue(percentage); + yield return null; + } + tweenInfo.TweenValue(1.0f); + } + + public void Init(MonoBehaviour coroutineContainer) + { + m_CoroutineContainer = coroutineContainer; + } + + public void StartTween(T info) + { + if (m_CoroutineContainer == null) + { + Debug.LogWarning("Coroutine container not configured... did you forget to call Init?"); + return; + } + + StopTween(); + + if (!m_CoroutineContainer.gameObject.activeInHierarchy) + { + info.TweenValue(1.0f); + return; + } + + m_Tween = Start(info); + m_CoroutineContainer.StartCoroutine(m_Tween); + } + + public void StopTween() + { + if (m_Tween != null) + { + m_CoroutineContainer.StopCoroutine(m_Tween); + m_Tween = null; + } + } + } +} \ No newline at end of file diff --git a/Packages/com.unity.ugui/Runtime/TMP/TMP_CoroutineTween.cs.meta b/Packages/com.unity.ugui/Runtime/TMP/TMP_CoroutineTween.cs.meta new file mode 100644 index 00000000..01cf5eb3 --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/TMP_CoroutineTween.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 658c1fb149e7498aa072b0c0f3bf13f0 +timeCreated: 1464850953 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.ugui/Runtime/TMP/TMP_DefaultControls.cs b/Packages/com.unity.ugui/Runtime/TMP/TMP_DefaultControls.cs new file mode 100644 index 00000000..c2793ad0 --- /dev/null +++ b/Packages/com.unity.ugui/Runtime/TMP/TMP_DefaultControls.cs @@ -0,0 +1,424 @@ +using UnityEngine; +using System.Collections; +using UnityEngine.UI; + +#if UNITY_EDITOR +using UnityEditor; +#endif + + +namespace TMPro +{ + + public static class TMP_DefaultControls + { + public struct Resources + { + public Sprite standard; + public Sprite background; + public Sprite inputField; + public Sprite knob; + public Sprite checkmark; + public Sprite dropdown; + public Sprite mask; + } + + private const float kWidth = 160f; + private const float kThickHeight = 30f; + private const float kThinHeight = 20f; + private static Vector2 s_TextElementSize = new Vector2(100f, 100f); + private static Vector2 s_ThickElementSize = new Vector2(kWidth, kThickHeight); + private static Vector2 s_ThinElementSize = new Vector2(kWidth, kThinHeight); + //private static Vector2 s_ImageElementSize = new Vector2(100f, 100f); + private static Color s_DefaultSelectableColor = new Color(1f, 1f, 1f, 1f); + //private static Color s_PanelColor = new Color(1f, 1f, 1f, 0.392f); + private static Color s_TextColor = new Color(50f / 255f, 50f / 255f, 50f / 255f, 1f); + + + private static GameObject CreateUIElementRoot(string name, Vector2 size) + { + GameObject root; + + #if UNITY_EDITOR + root = ObjectFactory.CreateGameObject(name, typeof(RectTransform)); + var rt = root.GetComponent(); + rt.sizeDelta = size; + #else + root = new GameObject(name); + RectTransform rectTransform = root.AddComponent(); + rectTransform.sizeDelta = size; + #endif + + return root; + } + + static GameObject CreateUIObject(string name, GameObject parent) + { + GameObject go; + #if UNITY_EDITOR + go = ObjectFactory.CreateGameObject(name, typeof(RectTransform)); + #else + go = new GameObject(name); + go.AddComponent(); + #endif + SetParentAndAlign(go, parent); + return go; + } + + private static void SetDefaultTextValues(TMP_Text lbl) + { + // Set text values we want across UI elements in default controls. + // Don't set values which are the same as the default values for the Text component, + // since there's no point in that, and it's good to keep them as consistent as possible. + lbl.color = s_TextColor; + lbl.fontSize = 14; + } + + private static void SetDefaultColorTransitionValues(Selectable slider) + { + ColorBlock colors = slider.colors; + colors.highlightedColor = new Color(0.882f, 0.882f, 0.882f); + colors.pressedColor = new Color(0.698f, 0.698f, 0.698f); + colors.disabledColor = new Color(0.521f, 0.521f, 0.521f); + } + + private static void SetParentAndAlign(GameObject child, GameObject parent) + { + if (parent == null) + return; + + child.transform.SetParent(parent.transform, false); + SetLayerRecursively(child, parent.layer); + } + + private static void SetLayerRecursively(GameObject go, int layer) + { + go.layer = layer; + Transform t = go.transform; + for (int i = 0; i < t.childCount; i++) + SetLayerRecursively(t.GetChild(i).gameObject, layer); + } + + // Actual controls + + public static GameObject CreateScrollbar(Resources resources) + { + // Create GOs Hierarchy + GameObject scrollbarRoot = CreateUIElementRoot("Scrollbar", s_ThinElementSize); + + GameObject sliderArea = CreateUIObject("Sliding Area", scrollbarRoot); + GameObject handle = CreateUIObject("Handle", sliderArea); + + Image bgImage = AddComponent(scrollbarRoot); + bgImage.sprite = resources.background; + bgImage.type = Image.Type.Sliced; + bgImage.color = s_DefaultSelectableColor; + + Image handleImage = AddComponent(handle); + handleImage.sprite = resources.standard; + handleImage.type = Image.Type.Sliced; + handleImage.color = s_DefaultSelectableColor; + + RectTransform sliderAreaRect = sliderArea.GetComponent(); + sliderAreaRect.sizeDelta = new Vector2(-20, -20); + sliderAreaRect.anchorMin = Vector2.zero; + sliderAreaRect.anchorMax = Vector2.one; + + RectTransform handleRect = handle.GetComponent(); + handleRect.sizeDelta = new Vector2(20, 20); + + Scrollbar scrollbar = AddComponent(scrollbarRoot); + scrollbar.handleRect = handleRect; + scrollbar.targetGraphic = handleImage; + SetDefaultColorTransitionValues(scrollbar); + + return scrollbarRoot; + } + + public static GameObject CreateButton(Resources resources) + { + GameObject buttonRoot = CreateUIElementRoot("Button", s_ThickElementSize); + + GameObject childText; +#if UNITY_EDITOR + childText = ObjectFactory.CreateGameObject("Text (TMP)", typeof(RectTransform)); +#else + childText = new GameObject("Text (TMP)"); + childText.AddComponent(); +#endif + + SetParentAndAlign(childText, buttonRoot); + + Image image = AddComponent(buttonRoot); + image.sprite = resources.standard; + image.type = Image.Type.Sliced; + image.color = s_DefaultSelectableColor; + + Button bt = AddComponent