diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eb83a8f --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +/[Ll]ibrary/ +/[Tt]emp/ +/[Oo]bj/ +/[Bb]uild/ +/[Bb]uilds/ +/Assets/AssetStoreTools* + +# Visual Studio 2015 cache directory +/.vs/ + +# Autogenerated VS/MD/Consulo solution and project files +ExportedObj/ +.consulo/ +*.csproj +*.unityproj +*.sln +*.suo +*.tmp +*.user +*.userprefs +*.pidb +*.booproj +*.svd +*.pdb + +# Unity3D generated meta files +*.pidb.meta + +# Unity3D Generated File On Crash Reports +sysinfo.txt + +# Builds +*.apk +*.unitypackage diff --git a/Assets/UIEditor.meta b/Assets/UIEditor.meta new file mode 100644 index 0000000..401820f --- /dev/null +++ b/Assets/UIEditor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f65238b2c6a3138469c80da6e66bbb9b +folderAsset: yes +timeCreated: 1521279303 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UIEditor/Common.meta b/Assets/UIEditor/Common.meta new file mode 100644 index 0000000..3bad570 --- /dev/null +++ b/Assets/UIEditor/Common.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 167aa88946f53d54ba354a933fdd9735 +folderAsset: yes +timeCreated: 1520392679 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UIEditor/Common/BetterList.cs b/Assets/UIEditor/Common/BetterList.cs new file mode 100644 index 0000000..e844e78 --- /dev/null +++ b/Assets/UIEditor/Common/BetterList.cs @@ -0,0 +1,387 @@ +//------------------------------------------------- +// NGUI: Next-Gen UI kit +// Copyright © 2011-2017 Tasharen Entertainment Inc +//------------------------------------------------- + +using UnityEngine; +using System.Collections.Generic; +using System.Diagnostics; + +/// +/// This improved version of the System.Collections.Generic.List that doesn't release the buffer on Clear(), +/// resulting in better performance and less garbage collection. +/// PRO: BetterList performs faster than List when you Add and Remove items (although slower if you remove from the beginning). +/// CON: BetterList performs worse when sorting the list. If your operations involve sorting, use the standard List instead. +/// + +public class BetterList +{ +#if UNITY_FLASH + + List mList = new List(); + + /// + /// Direct access to the buffer. Note that you should not use its 'Length' parameter, but instead use BetterList.size. + /// + + public T this[int i] + { + get { return mList[i]; } + set { mList[i] = value; } + } + + /// + /// Compatibility with the non-flash syntax. + /// + + public List buffer { get { return mList; } } + + /// + /// Direct access to the buffer's size. Note that it's only public for speed and efficiency. You shouldn't modify it. + /// + + public int size { get { return mList.Count; } } + + /// + /// For 'foreach' functionality. + /// + + public IEnumerator GetEnumerator () { return mList.GetEnumerator(); } + + /// + /// Clear the array by resetting its size to zero. Note that the memory is not actually released. + /// + + public void Clear () { mList.Clear(); } + + /// + /// Clear the array and release the used memory. + /// + + public void Release () { mList.Clear(); } + + /// + /// Add the specified item to the end of the list. + /// + + public void Add (T item) { mList.Add(item); } + + /// + /// Insert an item at the specified index, pushing the entries back. + /// + + public void Insert (int index, T item) + { + if (index > -1 && index < mList.Count) mList.Insert(index, item); + else mList.Add(item); + } + + /// + /// Returns 'true' if the specified item is within the list. + /// + + public bool Contains (T item) { return mList.Contains(item); } + + /// + /// Return the index of the specified item. + /// + + public int IndexOf (T item) { return mList.IndexOf(item); } + + /// + /// Remove the specified item from the list. Note that RemoveAt() is faster and is advisable if you already know the index. + /// + + public bool Remove (T item) { return mList.Remove(item); } + + /// + /// Remove an item at the specified index. + /// + + public void RemoveAt (int index) { mList.RemoveAt(index); } + + /// + /// Remove an item from the end. + /// + + public T Pop () + { + if (buffer != null && size != 0) + { + T val = buffer[mList.Count - 1]; + mList.RemoveAt(mList.Count - 1); + return val; + } + return default(T); + } + + /// + /// Mimic List's ToArray() functionality, except that in this case the list is resized to match the current size. + /// + + public T[] ToArray () { return mList.ToArray(); } + + /// + /// List.Sort equivalent. + /// + + public void Sort (System.Comparison comparer) { mList.Sort(comparer); } + +#else + + /// + /// Direct access to the buffer. Note that you should not use its 'Length' parameter, but instead use BetterList.size. + /// + + public T[] buffer; + + /// + /// Direct access to the buffer's size. Note that it's only public for speed and efficiency. You shouldn't modify it. + /// + + public int size = 0; + + /// + /// For 'foreach' functionality. + /// + + [DebuggerHidden] + [DebuggerStepThrough] + public IEnumerator GetEnumerator () + { + if (buffer != null) + { + for (int i = 0; i < size; ++i) + { + yield return buffer[i]; + } + } + } + + /// + /// Convenience function. I recommend using .buffer instead. + /// + + [DebuggerHidden] + public T this[int i] + { + get { return buffer[i]; } + set { buffer[i] = value; } + } + + /// + /// Helper function that expands the size of the array, maintaining the content. + /// + + void AllocateMore () + { + T[] newList = (buffer != null) ? new T[Mathf.Max(buffer.Length << 1, 32)] : new T[32]; + if (buffer != null && size > 0) buffer.CopyTo(newList, 0); + buffer = newList; + } + + /// + /// Trim the unnecessary memory, resizing the buffer to be of 'Length' size. + /// Call this function only if you are sure that the buffer won't need to resize anytime soon. + /// + + void Trim () + { + if (size > 0) + { + if (size < buffer.Length) + { + T[] newList = new T[size]; + for (int i = 0; i < size; ++i) newList[i] = buffer[i]; + buffer = newList; + } + } + else buffer = null; + } + + /// + /// Clear the array by resetting its size to zero. Note that the memory is not actually released. + /// + + public void Clear () { size = 0; } + + /// + /// Clear the array and release the used memory. + /// + + public void Release () { size = 0; buffer = null; } + + /// + /// Add the specified item to the end of the list. + /// + + public void Add (T item) + { + if (buffer == null || size == buffer.Length) AllocateMore(); + buffer[size++] = item; + } + + /// + /// Insert an item at the specified index, pushing the entries back. + /// + + public void Insert (int index, T item) + { + if (buffer == null || size == buffer.Length) AllocateMore(); + + if (index > -1 && index < size) + { + for (int i = size; i > index; --i) buffer[i] = buffer[i - 1]; + buffer[index] = item; + ++size; + } + else Add(item); + } + + /// + /// Returns 'true' if the specified item is within the list. + /// + + public bool Contains (T item) + { + if (buffer == null) return false; + for (int i = 0; i < size; ++i) if (buffer[i].Equals(item)) return true; + return false; + } + + /// + /// Return the index of the specified item. + /// + + public int IndexOf (T item) + { + if (buffer == null) return -1; + for (int i = 0; i < size; ++i) if (buffer[i].Equals(item)) return i; + return -1; + } + + /// + /// Remove the specified item from the list. Note that RemoveAt() is faster and is advisable if you already know the index. + /// + + public bool Remove (T item) + { + if (buffer != null) + { + EqualityComparer comp = EqualityComparer.Default; + + for (int i = 0; i < size; ++i) + { + if (comp.Equals(buffer[i], item)) + { + --size; + buffer[i] = default(T); + for (int b = i; b < size; ++b) buffer[b] = buffer[b + 1]; + buffer[size] = default(T); + return true; + } + } + } + return false; + } + + /// + /// Remove an item at the specified index. + /// + + public void RemoveAt (int index) + { + if (buffer != null && index > -1 && index < size) + { + --size; + buffer[index] = default(T); + for (int b = index; b < size; ++b) buffer[b] = buffer[b + 1]; + buffer[size] = default(T); + } + } + + /// + /// Remove an item from the end. + /// + + public T Pop () + { + if (buffer != null && size != 0) + { + T val = buffer[--size]; + buffer[size] = default(T); + return val; + } + return default(T); + } + + /// + /// Mimic List's ToArray() functionality, except that in this case the list is resized to match the current size. + /// + + public T[] ToArray () { Trim(); return buffer; } + + //class Comparer : System.Collections.IComparer + //{ + // public System.Comparison func; + // public int Compare (object x, object y) { return func((T)x, (T)y); } + //} + + //Comparer mComp = new Comparer(); + + /// + /// List.Sort equivalent. Doing Array.Sort causes GC allocations. + /// + + //public void Sort (System.Comparison comparer) + //{ + // if (size > 0) + // { + // mComp.func = comparer; + // System.Array.Sort(buffer, 0, size, mComp); + // } + //} + + /// + /// List.Sort equivalent. Manual sorting causes no GC allocations. + /// + + [DebuggerHidden] + [DebuggerStepThrough] + public void Sort (CompareFunc comparer) + { + int start = 0; + int max = size - 1; + bool changed = true; + + while (changed) + { + changed = false; + + for (int i = start; i < max; ++i) + { + // Compare the two values + if (comparer(buffer[i], buffer[i + 1]) > 0) + { + // Swap the values + T temp = buffer[i]; + buffer[i] = buffer[i + 1]; + buffer[i + 1] = temp; + changed = true; + } + else if (!changed) + { + // Nothing has changed -- we can start here next time + start = (i == 0) ? 0 : i - 1; + } + } + } + } + + /// + /// Comparison function should return -1 if left is less than right, 1 if left is greater than right, and 0 if they match. + /// + + public delegate int CompareFunc (T left, T right); +#endif +} diff --git a/Assets/UIEditor/Common/BetterList.cs.meta b/Assets/UIEditor/Common/BetterList.cs.meta new file mode 100644 index 0000000..21241c4 --- /dev/null +++ b/Assets/UIEditor/Common/BetterList.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7c80989c78df03344839803db8983eb9 +timeCreated: 1520392679 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UIEditor/Common/CommonHelper.cs b/Assets/UIEditor/Common/CommonHelper.cs new file mode 100644 index 0000000..685f15f --- /dev/null +++ b/Assets/UIEditor/Common/CommonHelper.cs @@ -0,0 +1,135 @@ +#if UNITY_EDITOR +using UnityEngine; +using System.Diagnostics; +using System; + +namespace U3DExtends { + public class CommonHelper { + //生成parent下的唯一控件名 + public static string GenerateUniqueName(GameObject parent, string type) + { + var widgets = parent.GetComponentsInChildren(); + int test_num = 1; + string test_name = type+"_"+test_num; + RectTransform uiBase = null; + int prevent_death_count = 0;//防止死循环 + do { + test_name = type+"_"+test_num; + uiBase = System.Array.Find(widgets, p => p.gameObject.name==test_name); + test_num = test_num + UnityEngine.Random.Range(1, (prevent_death_count+1)*2); + if (prevent_death_count++ >= 100) + break; + } while (uiBase != null); + + return test_name; + } + + static public bool IsPointInRect(Vector3 mouse_abs_pos, RectTransform trans) + { + if (trans != null) + { + float l_t_x = trans.position.x; + float l_t_y = trans.position.y; + float r_b_x = l_t_x + trans.sizeDelta.x; + float r_b_y = l_t_y - trans.sizeDelta.y; + if (mouse_abs_pos.x >= l_t_x && mouse_abs_pos.y <= l_t_y && mouse_abs_pos.x <= r_b_x && mouse_abs_pos.y >= r_b_y) + { + return true; + } + } + return false; + } + + public static Color StringToColor(string hexString) + { + int start_index = 2; + if (hexString.Length == 8) + start_index = 2; + else if (hexString.Length == 6) + start_index = 0; + byte r = byte.Parse(hexString.Substring(start_index, 2), System.Globalization.NumberStyles.HexNumber); + byte g = byte.Parse(hexString.Substring(start_index+2, 2), System.Globalization.NumberStyles.HexNumber); + byte b = byte.Parse(hexString.Substring(start_index+4, 2), System.Globalization.NumberStyles.HexNumber); + return new Color(r / 255.0f, g / 255.0f, b / 255.0f); + } + + public static string ColorToString(Color color) + { + string hexString = ""; + string color_hex = "00"; + color_hex = String.Format("{0:x}", (int)Mathf.Floor(color.r * 255)); + if (color_hex.Length < 2) + color_hex = "0" + color_hex; + hexString = hexString + color_hex; + color_hex = String.Format("{0:x}", (int)Mathf.Floor(color.g * 255)); + if (color_hex.Length < 2) + color_hex = "0" + color_hex; + hexString = hexString + color_hex; + color_hex = String.Format("{0:x}", (int)Mathf.Floor(color.b * 255)); + if (color_hex.Length < 2) + color_hex = "0" + color_hex; + hexString = hexString + color_hex; + //UnityEngine.Debug.Log("hexString :" + hexString); + return hexString; + } + + public static Process ProcessCommand(string command, string argument) + { + UnityEngine.Debug.Log(string.Format("command : {0} argument{1}", command, argument)); + ProcessStartInfo start = new ProcessStartInfo(command); + start.Arguments = argument; + start.CreateNoWindow = true; + start.ErrorDialog = true; + start.UseShellExecute = false; + + if (start.UseShellExecute) + { + start.RedirectStandardOutput = false; + start.RedirectStandardError = false; + start.RedirectStandardInput = false; + } + else + { + start.RedirectStandardOutput = true; + start.RedirectStandardError = true; + start.RedirectStandardInput = true; + start.StandardOutputEncoding = System.Text.UTF8Encoding.UTF8; + start.StandardErrorEncoding = System.Text.UTF8Encoding.UTF8; + } + + Process p = Process.Start(start); + //string output = p.StandardOutput.ReadToEnd(); + //p.WaitForExit(); + return p; + } + + //获取文件名 + public static string GetFileNameByPath(string path) + { + path = path.Replace("\\", "/"); + int last_gang_index = path.LastIndexOf("/"); + if (last_gang_index == -1) + return ""; + last_gang_index++; + string name = path.Substring(last_gang_index, path.Length - last_gang_index); + int last_dot_index = name.LastIndexOf('.'); + if (last_dot_index == -1) + return ""; + name = name.Substring(0, last_dot_index); + return name; + } + + //获取文件类型后缀 + public static string GetFileTypeSuffixByPath(string path) + { + path = path.Replace("\\", "/"); + int last_dot_index = path.LastIndexOf('.'); + if (last_dot_index == -1) + return ""; + last_dot_index++; + string type_str = path.Substring(last_dot_index, path.Length - last_dot_index); + return type_str; + } + } +} +#endif \ No newline at end of file diff --git a/Assets/UIEditor/Common/CommonHelper.cs.meta b/Assets/UIEditor/Common/CommonHelper.cs.meta new file mode 100644 index 0000000..720eb6a --- /dev/null +++ b/Assets/UIEditor/Common/CommonHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c451c114c4e790f4ebc16668e49140c1 +timeCreated: 1520392679 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UIEditor/Common/ContextMenu.cs b/Assets/UIEditor/Common/ContextMenu.cs new file mode 100644 index 0000000..6fbd81e --- /dev/null +++ b/Assets/UIEditor/Common/ContextMenu.cs @@ -0,0 +1,149 @@ +#if UNITY_EDITOR +using UnityEngine; +using UnityEditor; +using System.Collections.Generic; + +namespace U3DExtends { +static public class ContextMenu +{ + static List mEntries = new List(); + static GenericMenu mMenu; + + static public void AddItem(string item, bool isChecked, GenericMenu.MenuFunction2 callback, object param) + { + if (callback != null) + { + if (mMenu == null) mMenu = new GenericMenu(); + int count = 0; + + for (int i = 0; i < mEntries.Count; ++i) + { + string str = mEntries[i]; + if (str == item) ++count; + } + mEntries.Add(item); + + if (count > 0) item += " [" + count + "]"; + mMenu.AddItem(new GUIContent(item), isChecked, callback, param); + } + else AddDisabledItem(item); + } + + static public void Show() + { + if (mMenu != null) + { + mMenu.ShowAsContext(); + mMenu = null; + mEntries.Clear(); + } + } + + //增加几种对齐菜单 + static public void AddAlignMenu() + { + AddItem("对齐/左对齐 ←", false, AlignTool.AlignInHorziontalLeft, null); + AddItem("对齐/右对齐 →", false, AlignTool.AlignInHorziontalRight, null); + AddItem("对齐/上对齐 ↑", false, AlignTool.AlignInVerticalUp, null); + AddItem("对齐/下对齐 ↓", false, AlignTool.AlignInVerticalDown, null); + AddItem("对齐/水平均匀 |||", false, AlignTool.UniformDistributionInHorziontal, null); + AddItem("对齐/垂直均匀 ☰", false, AlignTool.UniformDistributionInVertical, null); + AddItem("对齐/一样大 ■", false, AlignTool.ResizeMax, null); + AddItem("对齐/一样小 ●", false, AlignTool.ResizeMin, null); + } + + //增加层次菜单 + static public void AddPriorityMenu() + { + AddItem("层次/最里层 ↑↑↑", false, PriorityTool.MoveToTopWidget, null); + AddItem("层次/最外层 ↓↓↓", false, PriorityTool.MoveToBottomWidget, null); + AddItem("层次/往里挤 ↑", false, PriorityTool.MoveUpWidget, null); + AddItem("层次/往外挤 ↓", false, PriorityTool.MoveDownWidget, null); + } + + //增加显示隐藏菜单 + static public void AddShowOrHideMenu() + { + bool hasHideWidget = false; + foreach (var item in Selection.gameObjects) + { + if (!item.activeSelf) + { + hasHideWidget = true; + break; + } + } + if (hasHideWidget) + AddItem("显示", false, UILayoutTool.ShowAllSelectedWidgets, null); + else + AddItem("隐藏", false, UILayoutTool.HideAllSelectedWidgets, null); + } + + static public void AddCommonItems(GameObject[] targets) + { + if (targets == null || targets.Length <= 0) + { + AddItem("新建", false, UIEditorHelper.CreatNewLayoutForMenu, null); + AddItem("打开界面", false, UIEditorHelper.LoadLayout, null); + } + if (targets != null && targets.Length > 0) + { + AddItem("保存", false, UIEditorHelper.SaveLayout, null); + + AddSeparator("///"); + AddItem("复制选中控件名", false, UIEditorHelper.CopySelectWidgetName, null); + + //如果选中超过1个节点的话 + if (targets.Length > 1) + { + AddAlignMenu(); + AddItem("同流合污", false, UILayoutTool.MakeGroup, null); + } + AddSeparator("///"); + if (targets.Length == 1) + { + AddPriorityMenu(); + + if (UIEditorHelper.IsNodeCanDivide(targets[0])) + AddItem("分道扬镖", false, UILayoutTool.UnGroup, null); + Decorate uiBase = targets[0].GetComponent(); + if (uiBase != null) + { + if (uiBase.gameObject.hideFlags == HideFlags.NotEditable) + { + AddItem("解锁", false, UIEditorHelper.UnLockWidget, null); + } + else + { + AddItem("锁定", false, UIEditorHelper.LockWidget, null); + } + } + } + + AddShowOrHideMenu(); + + AddSeparator("///"); + + AddItem("添加参考图", false, UIEditorHelper.CreateDecorate, null); + + } + AddItem("排序所有界面", false, UILayoutTool.ResortAllLayout, null); + AddItem("清空界面", false, UIEditorHelper.ClearAllCanvas, null); + } + + static public void AddSeparator(string path) + { + if (mMenu == null) mMenu = new GenericMenu(); + + if (Application.platform != RuntimePlatform.OSXEditor) + mMenu.AddSeparator(path); + } + + static public void AddDisabledItem(string item) + { + if (mMenu == null) mMenu = new GenericMenu(); + mMenu.AddDisabledItem(new GUIContent(item)); + } +} +} +#endif \ No newline at end of file diff --git a/Assets/UIEditor/Common/ContextMenu.cs.meta b/Assets/UIEditor/Common/ContextMenu.cs.meta new file mode 100644 index 0000000..a392195 --- /dev/null +++ b/Assets/UIEditor/Common/ContextMenu.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6fe4cd445ce309344932a7f21c4e0e4e +timeCreated: 1520818956 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UIEditor/Common/Decorate.cs b/Assets/UIEditor/Common/Decorate.cs new file mode 100644 index 0000000..bd65e57 --- /dev/null +++ b/Assets/UIEditor/Common/Decorate.cs @@ -0,0 +1,53 @@ +#if UNITY_EDITOR +using UnityEngine; +using UnityEngine.UI; + +namespace U3DExtends +{ + [RequireComponent(typeof(RectTransform))] + [ExecuteInEditMode] + public class Decorate : MonoBehaviour + { + string spr_path = ""; + [SerializeField] + [HideInInspector] + private Image _image; + + public string SprPath + { + get { return spr_path; } + set + { + LoadSpr(value); + } + } + + public void LoadSpr(string path) + { + InitComponent(); + //Debug.Log("path : " + path); + if (spr_path != path) + { + spr_path = path; + _image.sprite = UIEditorHelper.LoadSpriteInLocal(path); + _image.SetNativeSize(); + gameObject.name = CommonHelper.GetFileNameByPath(path); + //Debug.Log("_image.sprite :" + (_image.sprite != null).ToString()); + } + } + + protected void Start() + { + InitComponent(); + } + + protected void InitComponent() + { + if (_image == null) + _image = GetComponent(); + } + + + } +} +#endif \ No newline at end of file diff --git a/Assets/UIEditor/Common/Decorate.cs.meta b/Assets/UIEditor/Common/Decorate.cs.meta new file mode 100644 index 0000000..cfdaaf1 --- /dev/null +++ b/Assets/UIEditor/Common/Decorate.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 533a76e193efebc48ab9061535a0b110 +timeCreated: 1521105297 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UIEditor/Common/PathSaver.cs b/Assets/UIEditor/Common/PathSaver.cs new file mode 100644 index 0000000..f1d3a7b --- /dev/null +++ b/Assets/UIEditor/Common/PathSaver.cs @@ -0,0 +1,50 @@ +#if UNITY_EDITOR +using UnityEditor; + +//路径保存器,记录上次打开的路径,不同项目的不同用处路径都分开保存 +namespace U3DExtends +{ + public enum PathType { + //OpenLayout,//打开布局时默认打开的文件夹路径//和Save用同个会方便点 + SaveLayout,//保存布局时默认打开的文件夹路径 + OpenDecorate,//选择参考图时默认打开的文件夹路径 + PrefabTool,//Prefab界面用的 + } + public class PathSaver { + private volatile static PathSaver _instance = null; + private static readonly object lockHelper = new object(); + private PathSaver() { } + public static PathSaver GetInstance() + { + if(_instance == null) + { + lock(lockHelper) + { + if(_instance == null) + _instance = new PathSaver(); + } + } + return _instance; + } + + public string GeDefaultPath(PathType type) + { + return ""; + } + + public string GetLastPath(PathType type) + { + return EditorPrefs.GetString("PathSaver_" + type.ToString(), GeDefaultPath(type)); + } + + public void SetLastPath(PathType type, string path) + { + if (path == "") + return; + path = System.IO.Path.GetDirectoryName(path); + EditorPrefs.SetString("PathSaver_" + type.ToString(), path); + } + + } +} +#endif \ No newline at end of file diff --git a/Assets/UIEditor/Common/PathSaver.cs.meta b/Assets/UIEditor/Common/PathSaver.cs.meta new file mode 100644 index 0000000..5d023ac --- /dev/null +++ b/Assets/UIEditor/Common/PathSaver.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5a399f9e8d9b3ec48ae81f9a2c031840 +timeCreated: 1520819465 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UIEditor/Common/UIEditorHelper.cs b/Assets/UIEditor/Common/UIEditorHelper.cs new file mode 100644 index 0000000..022b096 --- /dev/null +++ b/Assets/UIEditor/Common/UIEditorHelper.cs @@ -0,0 +1,589 @@ +#if UNITY_EDITOR +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using UnityEditor; +using UnityEngine; +using UnityEngine.UI; + +namespace U3DExtends +{ + public static class UIEditorHelper + { + public static void SetImageByPath(string assetPath, Image image, bool isNativeSize = true) + { + Object newImg = UnityEditor.AssetDatabase.LoadAssetAtPath(assetPath, typeof(Sprite)); + Undo.RecordObject(image, "Change Image"); + image.sprite = newImg as Sprite; + if (isNativeSize) + image.SetNativeSize(); + EditorUtility.SetDirty(image); + } + + [MenuItem("UIEditor/复制节点名 " + Configure.ShortCut.CopyNodesName)] + public static void CopySelectWidgetName(object o) + { + string result = ""; + foreach (var item in Selection.gameObjects) + { + string item_name = item.name; + Transform root_trans = item.transform.parent; + while (root_trans != null && root_trans.GetComponent() == null) + { + if (root_trans.parent != null && root_trans.parent.GetComponent() == null) + item_name = root_trans.name + "/" + item_name; + else + break; + root_trans = root_trans.parent; + } + result = result + "\"" + item_name + "\","; + } + + //复制到系统全局的粘贴板上 + GUIUtility.systemCopyBuffer = result; + Debug.Log("Copy Nodes Name Succeed!"); + } + + public static Transform GetRootLayout(Transform trans) + { + Transform result = null; + Canvas canvas = trans.GetComponentInParent(); + if (canvas != null) + { + foreach (var item in canvas.transform.GetComponentsInChildren()) + { + if (item.GetComponent() == null && canvas.transform != item) + { + result = item; + break; + } + } + } + return result; + } + + static public Transform GetContainerUnderMouse(Vector3 mouse_abs_pos, GameObject ignore_obj = null) + { + GameObject testUI = GameObject.Find(Configure.UITestNodeName); + if (!testUI) + { + testUI = new GameObject(Configure.UITestNodeName, typeof(RectTransform)); + } + List list = new List(); + Canvas[] containers = Transform.FindObjectsOfType(); + foreach (var item in containers) + { + if (ignore_obj == item.gameObject || item.transform.parent != testUI.transform) + continue; + RectTransform trans = item.transform as RectTransform; + if (trans != null) + { + double halfWidth = trans.sizeDelta.x / 2.0; + double halfHeight = trans.sizeDelta.y / 2.0; + double l_t_x = trans.position.x - halfWidth; + double l_t_y = trans.position.y + halfHeight; + double r_b_x = trans.position.x + halfWidth; + double r_b_y = trans.position.y - halfHeight; + //UnityEngine.Debug.Log("item name : " + item.gameObject.name + " pos:" + trans.position.ToString() + " l_t_x:" + l_t_x + " l_t_y:" + l_t_y + " r_b_x:" + r_b_x + " r_b_y:" + r_b_y); + if (mouse_abs_pos.x >= l_t_x && mouse_abs_pos.y <= l_t_y && mouse_abs_pos.x <= r_b_x && mouse_abs_pos.y >= r_b_y) + { + list.Add(item); + break; + } + } + } + if (list.Count <= 0) + return null; + return GetRootLayout(list[0].transform); + } + + public static GameObject CreatNewLayout(bool isNeedLayout = true) + { + GameObject testUI = GameObject.Find(Configure.UITestNodeName); + if (!testUI) + { + testUI = new GameObject(Configure.UITestNodeName, typeof(RectTransform)); + } + const string file_path = Configure.ResAssetsPath + "Canvas.prefab"; + GameObject layout_prefab = UnityEditor.AssetDatabase.LoadAssetAtPath(file_path, typeof(UnityEngine.Object)) as GameObject; + GameObject layout = GameObject.Instantiate(layout_prefab) as GameObject; + layout.transform.parent = testUI.transform; + if (!isNeedLayout) + { + Transform child = layout.transform.GetChild(0); + layout.transform.DetachChildren(); + GameObject.DestroyImmediate(child.gameObject); + } + + Selection.activeGameObject = layout; + RectTransform trans = layout.transform as RectTransform; + SceneView.lastActiveSceneView.MoveToView(trans); + return layout; + } + + public static void SelectPicForDecorate(Decorate decorate) + { + if (decorate != null) + { + string default_path = PathSaver.GetInstance().GetLastPath(PathType.OpenDecorate); + string spr_path = EditorUtility.OpenFilePanel("加载外部图片", default_path, ""); + if (spr_path.Length > 0) + { + decorate.SprPath = spr_path; + PathSaver.GetInstance().SetLastPath(PathType.OpenDecorate, spr_path); + } + } + } + + public static void CreateDecorate(object o) + { + if (Selection.activeTransform != null) + { + Canvas canvas = Selection.activeTransform.GetComponentInParent(); + if (canvas != null) + { + const string file_path = Configure.ResAssetsPath + "Decorate.prefab"; + GameObject decorate_prefab = UnityEditor.AssetDatabase.LoadAssetAtPath(file_path, typeof(UnityEngine.Object)) as GameObject; + GameObject decorate = GameObject.Instantiate(decorate_prefab) as GameObject; + decorate.transform.parent = canvas.transform; + RectTransform rectTrans = decorate.transform as RectTransform; + rectTrans.SetAsFirstSibling(); + rectTrans.localPosition = Vector3.zero; + Selection.activeTransform = rectTrans; + + if (Configure.OpenSelectPicDialogWhenAddDecorate) + { + Decorate decor = rectTrans.GetComponent(); + UIEditorHelper.SelectPicForDecorate(decor); + } + } + } + } + + public static void CreatNewLayoutForMenu(object o) + { + CreatNewLayout(); + } + + [MenuItem("UIEditor/清空界面 " + Configure.ShortCut.ClearAllCanvas)] + public static void ClearAllCanvas(object o) + { + bool isDeleteAll = EditorUtility.DisplayDialog("警告", "是否清空掉所有界面?", "干!", "不了"); + if (isDeleteAll) + { + GameObject test = GameObject.Find(Configure.UITestNodeName); + if (test != null) + { + Canvas[] allLayouts = test.transform.GetComponentsInChildren(true); + foreach (var item in allLayouts) + { + //Undo.DestroyObjectImmediate(item.gameObject); + GameObject.DestroyImmediate(item.gameObject); + } + } + } + } + + [MenuItem("UIEditor/加载界面 " + Configure.ShortCut.LoadUIPrefab, false, 1)] + public static void LoadLayout(object o) + { + string default_path = PathSaver.GetInstance().GetLastPath(PathType.SaveLayout); + string select_path = EditorUtility.OpenFilePanel("Open Layout", default_path, "prefab"); + PathSaver.GetInstance().SetLastPath(PathType.SaveLayout, select_path); + //Debug.Log(string.Format("select_path : {0}", select_path)); + if (select_path.Length > 0) + { + //Cat!TODO:检查是否已打开同名界面 + + GameObject new_layout = CreatNewLayout(false); + new_layout.transform.localPosition = new Vector3(new_layout.transform.localPosition.x, new_layout.transform.localPosition.y, 0); + + select_path = FileUtil.GetProjectRelativePath(select_path); + + Object prefab = AssetDatabase.LoadAssetAtPath(select_path, typeof(Object)); + GameObject new_view = PrefabUtility.InstantiateAttachedAsset(prefab) as GameObject; + PrefabUtility.ReconnectToLastPrefab(new_view); + new_view.transform.parent = new_layout.transform; + new_view.transform.localPosition = Vector3.zero; + string just_name = System.IO.Path.GetFileNameWithoutExtension(select_path); + new_view.name = just_name; + new_layout.gameObject.name = just_name + "_Canvas"; + } + } + + //[MenuItem("UIEditor/Operate/锁定")] + public static void LockWidget(object o) + { + if (Selection.gameObjects.Length > 0) + { + Selection.gameObjects[0].hideFlags = HideFlags.NotEditable; + } + } + + //[MenuItem("UIEditor/Operate/解锁")] + public static void UnLockWidget(object o) + { + if (Selection.gameObjects.Length > 0) + { + Selection.gameObjects[0].hideFlags = HideFlags.None; + } + } + + public static bool SaveTextureToPNG(Texture inputTex, string save_file_name) + { + RenderTexture temp = RenderTexture.GetTemporary(inputTex.width, inputTex.height, 0, RenderTextureFormat.ARGB32); + Graphics.Blit(inputTex, temp); + bool ret = SaveRenderTextureToPNG(temp, save_file_name); + RenderTexture.ReleaseTemporary(temp); + return ret; + + } + + //是否支持解体 + public static bool IsNodeCanDivide(GameObject obj) + { + if (obj == null) + return false; + return obj.transform.childCount > 0 && obj.GetComponent() == null && obj.transform.parent.GetComponent() == null; + } + + //将RenderTexture保存成一张png图片 + public static bool SaveRenderTextureToPNG(RenderTexture rt, string save_file_name) + { + RenderTexture prev = RenderTexture.active; + RenderTexture.active = rt; + Texture2D png = new Texture2D(rt.width, rt.height, TextureFormat.ARGB32, false); + png.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0); + byte[] bytes = png.EncodeToPNG(); + string directory = Path.GetDirectoryName(save_file_name); + if (!Directory.Exists(directory)) + Directory.CreateDirectory(directory); + FileStream file = File.Open(save_file_name, FileMode.Create); + BinaryWriter writer = new BinaryWriter(file); + writer.Write(bytes); + file.Close(); + Texture2D.DestroyImmediate(png); + png = null; + RenderTexture.active = prev; + return true; + + } + + public static Texture2D LoadTextureInLocal(string file_path) + { + //创建文件读取流 + FileStream fileStream = new FileStream(file_path, FileMode.Open, FileAccess.Read); + fileStream.Seek(0, SeekOrigin.Begin); + //创建文件长度缓冲区 + byte[] bytes = new byte[fileStream.Length]; + //读取文件 + fileStream.Read(bytes, 0, (int)fileStream.Length); + //释放文件读取流 + fileStream.Close(); + fileStream.Dispose(); + fileStream = null; + + //创建Texture + int width = 300; + int height = 372; + Texture2D texture = new Texture2D(width, height); + texture.LoadImage(bytes); + return texture; + } + + private static Vector2 HalfVec = new Vector2(0.5f, 0.5f); + public static Sprite LoadSpriteInLocal(string file_path) + { + Texture2D texture = LoadTextureInLocal(file_path); + //创建Sprite + Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), UIEditorHelper.HalfVec); + return sprite; + } + + public static Texture GetAssetPreview(GameObject obj) + { + GameObject canvas_obj = null; + GameObject clone = GameObject.Instantiate(obj); + Transform cloneTransform = clone.transform; + bool isUINode = false; + if (cloneTransform is RectTransform) + { + canvas_obj = new GameObject("render canvas", typeof(Canvas)); + Canvas canvas = canvas_obj.GetComponent(); + cloneTransform.parent = canvas_obj.transform; + cloneTransform.localPosition = Vector3.zero; + + canvas_obj.transform.position = new Vector3(-1000, -1000, -1000); + canvas_obj.layer = 21; + isUINode = true; + } + else + cloneTransform.position = new Vector3(-1000, -1000, -1000); + + Transform[] all = clone.GetComponentsInChildren(); + foreach (Transform trans in all) + { + trans.gameObject.layer = 21; + } + + Bounds bounds = GetBounds(clone); + Vector3 Min = bounds.min; + Vector3 Max = bounds.max; + GameObject cameraObj = new GameObject("render camera"); + + Camera renderCamera = cameraObj.AddComponent(); + renderCamera.backgroundColor = new Color(0.8f, 0.8f, 0.8f, 1f); + renderCamera.clearFlags = CameraClearFlags.Color; + renderCamera.cameraType = CameraType.Preview; + renderCamera.cullingMask = 1 << 21; + if (isUINode) + { + cameraObj.transform.position = new Vector3((Max.x + Min.x) / 2f, (Max.y + Min.y) / 2f, cloneTransform.position.z-100); + Vector3 center = new Vector3(cloneTransform.position.x, (Max.y + Min.y) / 2f, cloneTransform.position.z); + cameraObj.transform.LookAt(center); + + renderCamera.orthographic = true; + float width = Max.x - Min.x; + float height = Max.y - Min.y; + float max_camera_size = width > height ? width : height; + renderCamera.orthographicSize = max_camera_size / 2; + } + else + { + cameraObj.transform.position = new Vector3((Max.x + Min.x) / 2f, (Max.y + Min.y) / 2f, Max.z + (Max.z - Min.z)); + Vector3 center = new Vector3(cloneTransform.position.x, (Max.y + Min.y) / 2f, cloneTransform.position.z); + cameraObj.transform.LookAt(center); + + int angle = (int)(Mathf.Atan2((Max.y - Min.y) / 2, (Max.z - Min.z)) * 180 / 3.1415f * 2); + renderCamera.fieldOfView = angle; + } + RenderTexture texture = new RenderTexture(128, 128, 0, RenderTextureFormat.Default); + renderCamera.targetTexture = texture; + + Undo.DestroyObjectImmediate(cameraObj); + Undo.PerformUndo();//不知道为什么要删掉再Undo回来后才Render得出来UI的节点,3D节点是没这个问题的,估计是Canvas创建后没那么快有效? + renderCamera.RenderDontRestore(); + RenderTexture tex = new RenderTexture(128, 128, 0, RenderTextureFormat.Default); + Graphics.Blit(texture, tex); + + Object.DestroyImmediate(canvas_obj); + Object.DestroyImmediate(cameraObj); + return tex; + } + + public static Bounds GetBounds(GameObject obj) + { + Vector3 Min = new Vector3(99999, 99999, 99999); + Vector3 Max = new Vector3(-99999, -99999, -99999); + MeshRenderer[] renders = obj.GetComponentsInChildren(); + if (renders.Length > 0) + { + for (int i = 0; i < renders.Length; i++) + { + if (renders[i].bounds.min.x < Min.x) + Min.x = renders[i].bounds.min.x; + if (renders[i].bounds.min.y < Min.y) + Min.y = renders[i].bounds.min.y; + if (renders[i].bounds.min.z < Min.z) + Min.z = renders[i].bounds.min.z; + + if (renders[i].bounds.max.x > Max.x) + Max.x = renders[i].bounds.max.x; + if (renders[i].bounds.max.y > Max.y) + Max.y = renders[i].bounds.max.y; + if (renders[i].bounds.max.z > Max.z) + Max.z = renders[i].bounds.max.z; + } + } + else + { + RectTransform[] rectTrans = obj.GetComponentsInChildren(); + Vector3[] corner = new Vector3[4]; + for (int i = 0; i < rectTrans.Length; i++) + { + //获取节点的四个角的世界坐标,分别按顺序为左下左上,右上右下 + rectTrans[i].GetWorldCorners(corner); + if (corner[0].x < Min.x) + Min.x = corner[0].x; + if (corner[0].y < Min.y) + Min.y = corner[0].y; + if (corner[0].z < Min.z) + Min.z = corner[0].z; + + if (corner[2].x > Max.x) + Max.x = corner[2].x; + if (corner[2].y > Max.y) + Max.y = corner[2].y; + if (corner[2].z > Max.z) + Max.z = corner[2].z; + } + } + + Vector3 center = (Min + Max) / 2; + Vector3 size = new Vector3(Max.x - Min.x, Max.y - Min.y, Max.z - Min.z); + return new Bounds(center, size); + } + + [MenuItem("UIEditor/保存界面 " + Configure.ShortCut.SaveUIPrefab, false, 2)] + public static void SaveLayout(object o) + { + if (Selection.activeGameObject == null) + { + EditorUtility.DisplayDialog("Warning", "I don't know which prefab you want to save", "Ok"); + return; + } + Canvas layout = Selection.activeGameObject.GetComponentInParent(); + for (int i = 0; i < layout.transform.childCount; i++) + { + Transform child = layout.transform.GetChild(i); + if (child.GetComponent() != null) + continue; + GameObject child_obj = child.gameObject; + //Debug.Log("child type :" + PrefabUtility.GetPrefabType(child_obj)); + + //判断选择的物体,是否为预设 + PrefabType cur_prefab_type = PrefabUtility.GetPrefabType(child_obj); + if (cur_prefab_type == PrefabType.DisconnectedPrefabInstance) + { + PrefabUtility.ReconnectToLastPrefab(child_obj); + } + if (PrefabUtility.GetPrefabType(child_obj) == PrefabType.PrefabInstance) + { + UnityEngine.Object parentObject = PrefabUtility.GetPrefabParent(child_obj); + //替换预设 + PrefabUtility.ReplacePrefab(child_obj, parentObject, ReplacePrefabOptions.ConnectToPrefab); + //刷新 + AssetDatabase.Refresh(); + if (Configure.IsShowDialogWhenSaveLayout) + EditorUtility.DisplayDialog("Tip", "Save Succeed!", "Ok"); + Debug.Log("Save Succeed!"); + } + else + { + //不是预设的话说明还没保存过的,弹出保存框 + string default_path = PathSaver.GetInstance().GetLastPath(PathType.SaveLayout); + string save_path = EditorUtility.SaveFilePanel("Save Layout", default_path, "prefab_name", "prefab"); + if (save_path == "") + continue; + PathSaver.GetInstance().SetLastPath(PathType.SaveLayout, save_path); + save_path = FileUtil.GetProjectRelativePath(save_path); + + Object new_prefab = PrefabUtility.CreateEmptyPrefab(save_path); + PrefabUtility.ReplacePrefab(child_obj, new_prefab, ReplacePrefabOptions.ConnectToPrefab); + + string just_name = System.IO.Path.GetFileNameWithoutExtension(save_path); + child_obj.name = just_name; + layout.gameObject.name = just_name + "_Canvas"; + //刷新 + AssetDatabase.Refresh(); + if (Configure.IsShowDialogWhenSaveLayout) + EditorUtility.DisplayDialog("Tip", "Save Succeed!", "Ok"); + Debug.Log("Save Succeed!"); + } + } + } + + static public string ObjectToGUID(UnityEngine.Object obj) + { + string path = AssetDatabase.GetAssetPath(obj); + return (!string.IsNullOrEmpty(path)) ? AssetDatabase.AssetPathToGUID(path) : null; + } + + static MethodInfo s_GetInstanceIDFromGUID; + static public UnityEngine.Object GUIDToObject(string guid) + { + if (string.IsNullOrEmpty(guid)) return null; + + if (s_GetInstanceIDFromGUID == null) + s_GetInstanceIDFromGUID = typeof(AssetDatabase).GetMethod("GetInstanceIDFromGUID", BindingFlags.Static | BindingFlags.NonPublic); + + int id = (int)s_GetInstanceIDFromGUID.Invoke(null, new object[] { guid }); + if (id != 0) return EditorUtility.InstanceIDToObject(id); + string path = AssetDatabase.GUIDToAssetPath(guid); + if (string.IsNullOrEmpty(path)) return null; + return AssetDatabase.LoadAssetAtPath(path, typeof(UnityEngine.Object)); + } + + static public T GUIDToObject(string guid) where T : UnityEngine.Object + { + UnityEngine.Object obj = GUIDToObject(guid); + if (obj == null) return null; + + System.Type objType = obj.GetType(); + if (objType == typeof(T) || objType.IsSubclassOf(typeof(T))) return obj as T; + + if (objType == typeof(GameObject) && typeof(T).IsSubclassOf(typeof(Component))) + { + GameObject go = obj as GameObject; + return go.GetComponent(typeof(T)) as T; + } + return null; + } + + static public void SetEnum(string name, System.Enum val) + { + EditorPrefs.SetString(name, val.ToString()); + } + + static public T GetEnum(string name, T defaultValue) + { + string val = EditorPrefs.GetString(name, defaultValue.ToString()); + string[] names = System.Enum.GetNames(typeof(T)); + System.Array values = System.Enum.GetValues(typeof(T)); + + for (int i = 0; i < names.Length; ++i) + { + if (names[i] == val) + return (T)values.GetValue(i); + } + return defaultValue; + } + + static public void DrawTiledTexture(Rect rect, Texture tex) + { + GUI.BeginGroup(rect); + { + int width = Mathf.RoundToInt(rect.width); + int height = Mathf.RoundToInt(rect.height); + + for (int y = 0; y < height; y += tex.height) + { + for (int x = 0; x < width; x += tex.width) + { + GUI.DrawTexture(new Rect(x, y, tex.width, tex.height), tex); + } + } + } + GUI.EndGroup(); + } + + 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; + } + + static Texture2D mBackdropTex; + static public Texture2D backdropTexture + { + get + { + if (mBackdropTex == null) mBackdropTex = CreateCheckerTex( + new Color(0.1f, 0.1f, 0.1f, 0.5f), + new Color(0.2f, 0.2f, 0.2f, 0.5f)); + return mBackdropTex; + } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/UIEditor/Common/UIEditorHelper.cs.meta b/Assets/UIEditor/Common/UIEditorHelper.cs.meta new file mode 100644 index 0000000..2f97e23 --- /dev/null +++ b/Assets/UIEditor/Common/UIEditorHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 2d6a19623cd7ca14db511d4087d6c174 +timeCreated: 1521079536 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UIEditor/Common/UILayoutTool.cs b/Assets/UIEditor/Common/UILayoutTool.cs new file mode 100644 index 0000000..4bfe46b --- /dev/null +++ b/Assets/UIEditor/Common/UILayoutTool.cs @@ -0,0 +1,306 @@ +#if UNITY_EDITOR +using UnityEngine; +using UnityEditor; +using System.Linq; + +namespace U3DExtends +{ + public class UILayoutTool : MonoBehaviour + { + [MenuItem("UIEditor/排序所有界面 " + Configure.ShortCut.SortAllCanvas)] + public static void ResortAllLayout(object o) + { + GameObject testUI = GameObject.Find(Configure.UITestNodeName); + if (testUI != null) + { + Canvas[] layouts = testUI.GetComponentsInChildren(); + if (layouts[0] != null) + { + SceneView.lastActiveSceneView.MoveToView(layouts[0].transform); + } + Vector2 startPos = new Vector2(layouts[0].transform.position.x - 1280 * 1, layouts[0].transform.position.y + 720 * 1); + int index = 0; + foreach (var item in layouts) + { + int row = index / 5; + int col = index % 5; + Vector2 pos = new Vector2(1280 * col + startPos.x, -720 * row + startPos.y); + item.transform.position = pos; + index++; + } + } + } + + //[MenuItem("UIEditor/显示 " + Configure.ShortCut.SortAllCanvas)] + public static void ShowAllSelectedWidgets(object o) + { + foreach (var item in Selection.gameObjects) + { + item.SetActive(true); + } + } + //[MenuItem("UIEditor/隐藏 " + Configure.ShortCut.SortAllCanvas)] + public static void HideAllSelectedWidgets(object o) + { + foreach (var item in Selection.gameObjects) + { + item.SetActive(false); + } + } + + //[MenuItem("UIEditor/Operate/解除")] + public static void UnGroup(object o) + { + if (Selection.gameObjects == null || Selection.gameObjects.Length <= 0) + { + EditorUtility.DisplayDialog("Error", "当前没有选中节点", "Ok"); + return; + } + if (Selection.gameObjects.Length > 1) + { + EditorUtility.DisplayDialog("Error", "只能同时解除一个Box", "Ok"); + return; + } + GameObject target = Selection.activeGameObject; + Transform new_parent = target.transform.parent; + if (target.transform.childCount > 0) + { + Transform[] child_ui = target.transform.GetComponentsInChildren(true); + foreach (var item in child_ui) + { + //不是自己的子节点或是自己的话就跳过 + if (item.transform.parent != target.transform || item.transform == target.transform) + continue; + + item.transform.SetParent(new_parent, true); + } + Undo.DestroyObjectImmediate(target); + //GameObject.DestroyImmediate(target); + } + else + { + EditorUtility.DisplayDialog("Error", "选择对象容器控件", "Ok"); + } + } + + //[MenuItem("UIEditor/Operate/组合")] + public static void MakeGroup(object o) + { + if (Selection.gameObjects == null || Selection.gameObjects.Length <= 0) + { + EditorUtility.DisplayDialog("Error", "当前没有选中节点", "Ok"); + return; + } + + //先判断选中的节点是不是挂在同个父节点上的 + Transform parent = Selection.gameObjects[0].transform.parent; + foreach (var item in Selection.gameObjects) + { + Debug.Log("item name :" + item.name); + if (item.transform.parent != parent) + { + EditorUtility.DisplayDialog("Error", "不能跨容器组合", "Ok"); + return; + } + } + GameObject box = new GameObject("group", typeof(RectTransform)); + RectTransform rectTrans = box.GetComponent(); + if (rectTrans != null) + { + Vector2 left_top_pos = new Vector2(99999, -99999); + Vector2 right_bottom_pos = new Vector2(-99999, 99999); + foreach (var item in Selection.gameObjects) + { + RectTransform itemRectTrans = item.GetComponent(); + //Debug.Log("item name : " + item.name + " itemRectTrans:" + (itemRectTrans!=null).ToString()); + if (itemRectTrans != null) + { + float item_x = itemRectTrans.localPosition.x; + float item_y = itemRectTrans.localPosition.y; + float item_left_top_x = item_x - itemRectTrans.sizeDelta.x / 2; + float item_left_top_y = item_y + itemRectTrans.sizeDelta.y / 2; + if (item_left_top_x < left_top_pos.x) + left_top_pos.x = item_left_top_x; + if (item_left_top_y > left_top_pos.y) + left_top_pos.y = item_left_top_y; + float item_bottom_right_x = item_x + itemRectTrans.sizeDelta.x/2; + float item_bottom_right_y = item_y - itemRectTrans.sizeDelta.y/2; + //Debug.Log(" item_bottom_right_y" + item_bottom_right_y + " item_y:" + item_y); + if (item_bottom_right_x > right_bottom_pos.x) + right_bottom_pos.x = item_bottom_right_x; + if (item_bottom_right_y < right_bottom_pos.y) + right_bottom_pos.y = item_bottom_right_y; + //Debug.Log("right_bottom_pos : " + right_bottom_pos.ToString()); + } + } + rectTrans.SetParent(parent); + rectTrans.sizeDelta = new Vector2(right_bottom_pos.x - left_top_pos.x, left_top_pos.y - right_bottom_pos.y); + left_top_pos.x += rectTrans.sizeDelta.x/2; + left_top_pos.y -= rectTrans.sizeDelta.y/2; + rectTrans.localPosition = left_top_pos; + + //需要先生成好Box和设置好它的坐标和大小才可以把选中的节点挂进来,注意要先排好序,不然层次就乱了 + GameObject[] sorted_objs = Selection.gameObjects.OrderBy(x => x.transform.GetSiblingIndex()).ToArray(); + for (int i = 0; i < sorted_objs.Length; i++) + { + sorted_objs[i].transform.SetParent(rectTrans, true); + } + } + Selection.activeGameObject = box; + } + + + } + + + public class PriorityTool + { + [MenuItem("UIEditor/层次/最里层 " + Configure.ShortCut.MoveNodeTop)] + public static void MoveToTopWidget(object o) + { + Transform curSelect = Selection.activeTransform; + if (curSelect != null) + { + curSelect.SetAsFirstSibling(); + } + } + [MenuItem("UIEditor/层次/最外层 " + Configure.ShortCut.MoveNodeBottom)] + public static void MoveToBottomWidget(object o) + { + Transform curSelect = Selection.activeTransform; + if (curSelect != null) + { + curSelect.SetAsLastSibling(); + } + } + + [MenuItem("UIEditor/层次/往里挤 " + Configure.ShortCut.MoveNodeUp)] + public static void MoveUpWidget(object o) + { + Transform curSelect = Selection.activeTransform; + if (curSelect != null) + { + int curIndex = curSelect.GetSiblingIndex(); + if (curIndex > 0) + curSelect.SetSiblingIndex(curIndex - 1); + } + } + + [MenuItem("UIEditor/层次/往外挤 " + Configure.ShortCut.MoveNodeDown)] + public static void MoveDownWidget(object o) + { + Transform curSelect = Selection.activeTransform; + if (curSelect != null) + { + int curIndex = curSelect.GetSiblingIndex(); + int child_num = curSelect.parent.childCount; + if (curIndex < child_num - 1) + curSelect.SetSiblingIndex(curIndex + 1); + } + } + } + + public class AlignTool + { + [MenuItem("UIEditor/对齐/左对齐 ←")] + internal static void AlignInHorziontalLeft(object o) + { + float x = Mathf.Min(Selection.gameObjects.Select(obj => obj.transform.localPosition.x).ToArray()); + + foreach (GameObject gameObject in Selection.gameObjects) + { + gameObject.transform.localPosition = new Vector2(x, + gameObject.transform.localPosition.y); + } + } + + [MenuItem("UIEditor/对齐/右对齐 →")] + public static void AlignInHorziontalRight(object o) + { + float x = Mathf.Max(Selection.gameObjects.Select(obj => obj.transform.localPosition.x + + ((RectTransform)obj.transform).sizeDelta.x).ToArray()); + foreach (GameObject gameObject in Selection.gameObjects) + { + gameObject.transform.localPosition = new Vector3(x - + ((RectTransform)gameObject.transform).sizeDelta.x, gameObject.transform.localPosition.y); + } + } + + [MenuItem("UIEditor/对齐/上对齐 ↑")] + public static void AlignInVerticalUp(object o) + { + float y = Mathf.Max(Selection.gameObjects.Select(obj => obj.transform.localPosition.y).ToArray()); + foreach (GameObject gameObject in Selection.gameObjects) + { + gameObject.transform.localPosition = new Vector3(gameObject.transform.localPosition.x, y); + } + } + + [MenuItem("UIEditor/对齐/下对齐 ↓")] + public static void AlignInVerticalDown(object o) + { + float y = Mathf.Min(Selection.gameObjects.Select(obj => obj.transform.localPosition.y - + ((RectTransform)obj.transform).sizeDelta.y).ToArray()); + + foreach (GameObject gameObject in Selection.gameObjects) + { + gameObject.transform.localPosition = new Vector3(gameObject.transform.localPosition.x, y + ((RectTransform)gameObject.transform).sizeDelta.y); + } + } + + + [MenuItem("UIEditor/对齐/水平均匀 |||")] + public static void UniformDistributionInHorziontal(object o) + { + int count = Selection.gameObjects.Length; + float firstX = Mathf.Min(Selection.gameObjects.Select(obj => obj.transform.localPosition.x).ToArray()); + float lastX = Mathf.Max(Selection.gameObjects.Select(obj => obj.transform.localPosition.x).ToArray()); + float distance = (lastX - firstX) / (count - 1); + var objects = Selection.gameObjects.ToList(); + objects.Sort((x, y) => (int)(x.transform.localPosition.x - y.transform.localPosition.x)); + for (int i = 0; i < count; i++) + { + objects[i].transform.localPosition = new Vector3(firstX + i * distance, objects[i].transform.localPosition.y); + } + } + + [MenuItem("UIEditor/对齐/垂直均匀 ☰")] + public static void UniformDistributionInVertical(object o) + { + int count = Selection.gameObjects.Length; + float firstY = Mathf.Min(Selection.gameObjects.Select(obj => obj.transform.localPosition.y).ToArray()); + float lastY = Mathf.Max(Selection.gameObjects.Select(obj => obj.transform.localPosition.y).ToArray()); + float distance = (lastY - firstY) / (count - 1); + var objects = Selection.gameObjects.ToList(); + objects.Sort((x, y) => (int)(x.transform.localPosition.y - y.transform.localPosition.y)); + for (int i = 0; i < count; i++) + { + objects[i].transform.localPosition = new Vector3(objects[i].transform.localPosition.x, firstY + i * distance); + } + } + + [MenuItem("UIEditor/对齐/一样大 ■")] + public static void ResizeMax(object o) + { + var height = Mathf.Max(Selection.gameObjects.Select(obj => ((RectTransform)obj.transform).sizeDelta.y).ToArray()); + var width = Mathf.Max(Selection.gameObjects.Select(obj => ((RectTransform)obj.transform).sizeDelta.x).ToArray()); + foreach (GameObject gameObject in Selection.gameObjects) + { + ((RectTransform)gameObject.transform).sizeDelta = new Vector2(width, height); + } + } + + [MenuItem("UIEditor/对齐/一样小 ●")] + public static void ResizeMin(object o) + { + var height = Mathf.Min(Selection.gameObjects.Select(obj => ((RectTransform)obj.transform).sizeDelta.y).ToArray()); + var width = Mathf.Min(Selection.gameObjects.Select(obj => ((RectTransform)obj.transform).sizeDelta.x).ToArray()); + foreach (GameObject gameObject in Selection.gameObjects) + { + ((RectTransform)gameObject.transform).sizeDelta = new Vector2(width, height); + } + } + + } +} +#endif \ No newline at end of file diff --git a/Assets/UIEditor/Common/UILayoutTool.cs.meta b/Assets/UIEditor/Common/UILayoutTool.cs.meta new file mode 100644 index 0000000..073a287 --- /dev/null +++ b/Assets/UIEditor/Common/UILayoutTool.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5997bec4b8584554e81988d7100d4e25 +timeCreated: 1520819106 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UIEditor/Common/UISnapshotPoint.cs b/Assets/UIEditor/Common/UISnapshotPoint.cs new file mode 100644 index 0000000..790fe0f --- /dev/null +++ b/Assets/UIEditor/Common/UISnapshotPoint.cs @@ -0,0 +1,22 @@ +//------------------------------------------------- +// NGUI: Next-Gen UI kit +// Copyright © 2011-2017 Tasharen Entertainment Inc +//------------------------------------------------- + +using UnityEngine; + +[ExecuteInEditMode] +public class UISnapshotPoint : MonoBehaviour +{ + public bool isOrthographic = true; + public float nearClip = -100f; + public float farClip = 100f; + + [Range(10, 80)] + public int fieldOfView = 35; + public float orthoSize = 30f; + + public Texture2D thumbnail; + + void Start () { if (tag != "EditorOnly") tag = "EditorOnly"; } +} diff --git a/Assets/UIEditor/Common/UISnapshotPoint.cs.meta b/Assets/UIEditor/Common/UISnapshotPoint.cs.meta new file mode 100644 index 0000000..51acb4b --- /dev/null +++ b/Assets/UIEditor/Common/UISnapshotPoint.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c94da426e8ec5bc45868222603cd1e68 +timeCreated: 1520392679 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UIEditor/Configure.cs b/Assets/UIEditor/Configure.cs new file mode 100644 index 0000000..bab066a --- /dev/null +++ b/Assets/UIEditor/Configure.cs @@ -0,0 +1,59 @@ +namespace U3DExtends +{ + //ܺͿݼ + public static class Configure + { + //ǷеҼ˵ + public static bool IsShowSceneMenu = true; + + //ѡͼƬڵѡͼƬʱڵ㸳ϸͼ + public static bool IsEnableFastSelectImage = true; + + //UI prefabͼƬsceneʱҵµCanvasϣûлʹһ + public static bool IsEnableDragUIToScene = true; + + //ǷüͷƶUIڵ + public static bool IsMoveNodeByArrowKey = true; + + //ʱǷҪʾɹʾ + public static bool IsShowDialogWhenSaveLayout = true; + + //ϷʱصUITestNodeNameڵ + public static bool HideAllUIWhenRunGame = true; + + //һӲοͼʹѡͼƬ + public static bool OpenSelectPicDialogWhenAddDecorate = true; + + //·Ϊգú״ε뱾ʱͻظĿ¼µprefab + //public const string PrefabWinFirstSearchPath = "Assets/LuaFramework/AssetBundleRes/ui/uiComponent/prefab"; + public const string PrefabWinFirstSearchPath = ""; + + //ݼ ˵ݼ%#&1 ľǣCtrl + Shift + Alt + 1 + public static class ShortCut + { + //ѡнڵȫַϵͳа + public const string CopyNodesName = "%#c"; + + //ʾεĿݼ + public const string MoveNodeUp = "%UP"; + public const string MoveNodeTop = "%#UP"; + public const string MoveNodeDown = "%DOWN"; + public const string MoveNodeBottom = "%#DOWN"; + + //н + public const string SortAllCanvas = ""; + //ɾUITestNodeNameڵµн + public const string ClearAllCanvas = ""; + + //ؽ + public const string LoadUIPrefab = "%#l"; + // + public const string SaveUIPrefab = "%#s";//Cat!TODO:κsؿݼЧֻSceneView.onSceneGUIDelegateﴦ + } + + //б༭Canvasŵ˽ڵϣɶƽڵ + public static string UITestNodeName = "UITestNode"; + public const string ResPath = "UIEditor/Res/"; + public const string ResAssetsPath = "Assets/" + ResPath; + } +} diff --git a/Assets/UIEditor/Configure.cs.meta b/Assets/UIEditor/Configure.cs.meta new file mode 100644 index 0000000..b68d3e5 --- /dev/null +++ b/Assets/UIEditor/Configure.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 48da7126a66a4e44092e053194dbc732 +timeCreated: 1520924403 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UIEditor/Editor.meta b/Assets/UIEditor/Editor.meta new file mode 100644 index 0000000..e112574 --- /dev/null +++ b/Assets/UIEditor/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f6f07031ebb323642ae8923693c4e90d +folderAsset: yes +timeCreated: 1520392679 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UIEditor/Editor/CustomInspectors.cs b/Assets/UIEditor/Editor/CustomInspectors.cs new file mode 100644 index 0000000..985bbee --- /dev/null +++ b/Assets/UIEditor/Editor/CustomInspectors.cs @@ -0,0 +1,20 @@ +using UnityEngine; +using UnityEditor; + +namespace U3DExtends +{ + [CustomEditor(typeof(Decorate))] + public class DecorateEditor : Editor + { + public override void OnInspectorGUI() + { + Decorate widget = target as Decorate; + if (GUILayout.Button("加载外部图片", GUILayout.Height(30))) + { + UIEditorHelper.SelectPicForDecorate(widget); + } + } + } + + //Cat!TODO:给按钮文本等控件增加切换样式的功能 +} \ No newline at end of file diff --git a/Assets/UIEditor/Editor/CustomInspectors.cs.meta b/Assets/UIEditor/Editor/CustomInspectors.cs.meta new file mode 100644 index 0000000..b87b2e7 --- /dev/null +++ b/Assets/UIEditor/Editor/CustomInspectors.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 34c41c274d88c8043b41a532d64206e4 +timeCreated: 1521105540 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UIEditor/Editor/PrefabWin.cs b/Assets/UIEditor/Editor/PrefabWin.cs new file mode 100644 index 0000000..217e408 --- /dev/null +++ b/Assets/UIEditor/Editor/PrefabWin.cs @@ -0,0 +1,681 @@ +using UnityEditor; +using UnityEngine; +using System.Collections.Generic; +using System.Text; +using System.IO; +using System.Text.RegularExpressions; + +namespace U3DExtends { +public class PrefabWin : EditorWindow +{ + [MenuItem("Window/PrefabWin", false, 9)] + static public void OpenPrefabTool() + { + EditorWindow.GetWindow(false, "Prefab Win", true).Show(); + } + + static public PrefabWin instance; + + class Item + { + public GameObject prefab; + public string guid; + public Texture tex; + public bool dynamicTex = false; + } + + enum Mode + { + CompactMode, + IconMode, + DetailedMode, + } + + const int cellPadding = 4; + float mSizePercent = 0.5f; + + public float SizePercent + { + get { return mSizePercent; } + set + { + if (mSizePercent != value) + { + mReset = true; + mSizePercent = value; + mCellSize = Mathf.FloorToInt(80 * SizePercent + 10); + EditorPrefs.SetFloat("PrefabWin_SizePercent", mSizePercent); + } + } + } + int mCellSize=50; + int cellSize { get { return mCellSize; } } + + int mTab = 0; + Mode mMode = Mode.CompactMode; + Vector2 mPos = Vector2.zero; + bool mMouseIsInside = false; + GUIContent mContent; + GUIStyle mStyle; + + BetterList mItems = new BetterList(); + + GameObject draggedObject + { + get + { + if (DragAndDrop.objectReferences == null) return null; + if (DragAndDrop.objectReferences.Length == 1) return DragAndDrop.objectReferences[0] as GameObject; + return null; + } + set + { + if (value != null) + { + DragAndDrop.PrepareStartDrag(); + DragAndDrop.objectReferences = new Object[1] { value }; + draggedObjectIsOurs = true; + } + else DragAndDrop.AcceptDrag(); + } + } + + bool draggedObjectIsOurs + { + get + { + object obj = DragAndDrop.GetGenericData("Prefab Tool"); + if (obj == null) return false; + return (bool)obj; + } + set + { + DragAndDrop.SetGenericData("Prefab Tool", value); + } + } + + void OnEnable () + { + instance = this; + + Load(); + + mContent = new GUIContent(); + mStyle = new GUIStyle(); + mStyle.alignment = TextAnchor.MiddleCenter; + mStyle.padding = new RectOffset(2, 2, 2, 2); + mStyle.clipping = TextClipping.Clip; + mStyle.wordWrap = true; + mStyle.stretchWidth = false; + mStyle.stretchHeight = false; + mStyle.normal.textColor = UnityEditor.EditorGUIUtility.isProSkin ? new Color(1f, 1f, 1f, 0.5f) : new Color(0f, 0f, 0f, 0.5f); + mStyle.normal.background = null; + } + + void OnDisable () + { + instance = null; + foreach (Item item in mItems) DestroyTexture(item); + Save(); + } + + void OnSelectionChange () { Repaint(); } + + public void Reset () + { + foreach (Item item in mItems) DestroyTexture(item); + mItems.Clear(); + + if (mTab == 0 && Configure.PrefabWinFirstSearchPath!="") + { + List filtered = new List(); + string[] allAssets = AssetDatabase.GetAllAssetPaths(); + + foreach (string s in allAssets) + { + //search prefab files in folder:Assets/Resources/Prefab + bool isComeFromPrefab = Regex.IsMatch(s, Configure.PrefabWinFirstSearchPath+@"/((?!/).)*\.prefab"); + if (isComeFromPrefab) + filtered.Add(s); + } + + filtered.Sort(string.Compare); + foreach (string s in filtered) AddGUID(AssetDatabase.AssetPathToGUID(s), -1); + RectivateLights(); + } + } + + void AddItem (GameObject go, int index) + { + string guid = U3DExtends.UIEditorHelper.ObjectToGUID(go); + + if (string.IsNullOrEmpty(guid)) + { + string path = EditorUtility.SaveFilePanelInProject("Save a prefab", + go.name + ".prefab", "prefab", "Save prefab as...", ""); + + if (string.IsNullOrEmpty(path)) return; + + go = PrefabUtility.CreatePrefab(path, go); + if (go == null) return; + + guid = U3DExtends.UIEditorHelper.ObjectToGUID(go); + if (string.IsNullOrEmpty(guid)) return; + } + + Item ent = new Item(); + ent.prefab = go; + ent.guid = guid; + GeneratePreview(ent, null); + RectivateLights(); + + if (index < mItems.size) mItems.Insert(index, ent); + else mItems.Add(ent); + Save(); + } + + Item AddGUID (string guid, int index) + { + GameObject go = U3DExtends.UIEditorHelper.GUIDToObject(guid); + + if (go != null) + { + Item ent = new Item(); + ent.prefab = go; + ent.guid = guid; + GeneratePreview(ent, null); + if (index < mItems.size) mItems.Insert(index, ent); + else mItems.Add(ent); + return ent; + } + return null; + } + + void RemoveItem (object obj) + { + if (this == null) return; + int index = (int)obj; + if (index < mItems.size && index > -1) + { + Item item = mItems[index]; + DestroyTexture(item); + mItems.RemoveAt(index); + } + Save(); + } + + Item FindItem (GameObject go) + { + for (int i = 0; i < mItems.size; ++i) + if (mItems[i].prefab == go) + return mItems[i]; + return null; + } + + string saveKey { get { return "PrefabWin " + Application.dataPath + " " + mTab; } } + + void Save () + { + string data = ""; + + if (mItems.size > 0) + { + string guid = mItems[0].guid; + StringBuilder sb = new StringBuilder(); + sb.Append(guid); + + for (int i = 1; i < mItems.size; ++i) + { + guid = mItems[i].guid; + + if (string.IsNullOrEmpty(guid)) + { + Debug.LogWarning("Unable to save " + mItems[i].prefab.name); + } + else + { + sb.Append('|'); + sb.Append(mItems[i].guid); + } + } + data = sb.ToString(); + } + EditorPrefs.SetString(saveKey, data); + } + + void Load () + { + mTab = EditorPrefs.GetInt("PrefabWin Prefab Tab", 0); + SizePercent = EditorPrefs.GetFloat("PrefabWin_SizePercent", 0.5f); + + foreach (Item item in mItems) DestroyTexture(item); + mItems.Clear(); + + string data = EditorPrefs.GetString(saveKey, ""); + //data = "";//For test + if (string.IsNullOrEmpty(data)) + { + Reset(); + } + else + { + if (string.IsNullOrEmpty(data)) return; + string[] guids = data.Split('|'); + foreach (string s in guids) AddGUID(s, -1); + RectivateLights(); + } + } + + void DestroyTexture (Item item) + { + if (item != null && item.dynamicTex && item.tex != null) + { + DestroyImmediate(item.tex); + item.dynamicTex = false; + item.tex = null; + } + } + + public void RegenerateTexture (GameObject prefab, UISnapshotPoint point) + { + for (int i = 0; i < mItems.size; ++i) + { + Item item = mItems[i]; + + if (item.prefab == prefab) + { + GeneratePreview(item, point); + RectivateLights(); + break; + } + } + } + + void UpdateVisual () + { + if (draggedObject == null) DragAndDrop.visualMode = DragAndDropVisualMode.Rejected; + else if (draggedObjectIsOurs) DragAndDrop.visualMode = DragAndDropVisualMode.Move; + else DragAndDrop.visualMode = DragAndDropVisualMode.Copy; + } + + Item CreateItemByPath (string path) + { + if (!string.IsNullOrEmpty(path)) + { + path = FileUtil.GetProjectRelativePath(path); + string guid = AssetDatabase.AssetPathToGUID(path); + + if (!string.IsNullOrEmpty(guid)) + { + GameObject go = AssetDatabase.LoadAssetAtPath(path, typeof(GameObject)) as GameObject; + Item ent = new Item(); + ent.prefab = go; + ent.guid = guid; + GeneratePreview(ent, null); + return ent; + } + else Debug.Log("No GUID"); + } + return null; + } + + static UISnapshotPoint GetSnapshotPoint (Transform t) + { + UISnapshotPoint point = t.GetComponent(); + if (point != null) return point; + + for (int i = 0, imax = t.childCount; i < imax; ++i) + { + Transform c = t.GetChild(i); + point = GetSnapshotPoint(c); + if (point != null) return point; + } + return null; + } + + void GeneratePreview (Item item, UISnapshotPoint point) + { + if (item == null || item.prefab == null) return; + { + string preview_path = Application.dataPath + "/" + Configure.ResPath + "Preview/" + item.prefab.name + ".png"; + if (File.Exists(preview_path)) + { + Texture texture = UIEditorHelper.LoadTextureInLocal(preview_path); + item.tex = texture; + } + else + { + Texture Tex = UIEditorHelper.GetAssetPreview(item.prefab); + if (Tex != null) + { + DestroyTexture(item); + item.tex = Tex; + UIEditorHelper.SaveTextureToPNG(Tex, preview_path); + } + } + + item.dynamicTex = false; + return; + } + } + + static Transform FindChild (Transform t, string startsWith) + { + if (t.name.StartsWith(startsWith)) return t; + + for (int i = 0, imax = t.childCount; i < imax; ++i) + { + Transform ch = FindChild(t.GetChild(i), startsWith); + if (ch != null) return ch; + } + return null; + } + + static BetterList mLights; + + static void RectivateLights () + { + if (mLights != null) + { + for (int i = 0; i < mLights.size; ++i) + mLights[i].enabled = true; + mLights = null; + } + } + + int GetCellUnderMouse (int spacingX, int spacingY) + { + Vector2 pos = Event.current.mousePosition + mPos; + + int topPadding = 24; + int x = cellPadding, y = cellPadding + topPadding; + if (pos.y < y) return -1; + + float width = Screen.width - cellPadding + mPos.x; + float height = Screen.height - cellPadding + mPos.y; + int index = 0; + + for (; ; ++index) + { + Rect rect = new Rect(x, y, spacingX, spacingY); + if (rect.Contains(pos)) break; + + x += spacingX; + + if (x + spacingX > width) + { + if (pos.x > x) return -1; + y += spacingY; + x = cellPadding; + if (y + spacingY > height) return -1; + } + } + return index; + } + + bool mReset = false; + + void OnGUI () + { + Event currentEvent = Event.current; + EventType type = currentEvent.type; + + int x = cellPadding, y = cellPadding; + int width = Screen.width - cellPadding; + int spacingX = cellSize + cellPadding; + int spacingY = spacingX; + if (mMode == Mode.DetailedMode) spacingY += 32; + + GameObject dragged = draggedObject; + bool isDragging = (dragged != null); + int indexUnderMouse = GetCellUnderMouse(spacingX, spacingY); + Item selection = isDragging ? FindItem(dragged) : null; + string searchFilter = EditorPrefs.GetString("PrefabWin_SearchFilter", null); + + int newTab = mTab; + + GUILayout.BeginHorizontal(); + if (GUILayout.Toggle(newTab == 0, "通用控件", "ButtonLeft")) newTab = 0; + if (GUILayout.Toggle(newTab == 1, "其它模板", "ButtonRight")) newTab = 1; + GUILayout.EndHorizontal(); + + if (mTab != newTab) + { + Save(); + mTab = newTab; + mReset = true; + EditorPrefs.SetInt("PrefabWin Prefab Tab", mTab); + Load(); + } + + if (mReset && type == EventType.Repaint) + { + mReset = false; + foreach (Item item in mItems) GeneratePreview(item, null); + RectivateLights(); + } + + bool eligibleToDrag = (currentEvent.mousePosition.y < Screen.height - 40); + + if (type == EventType.MouseDown) + { + mMouseIsInside = true; + } + else if (type == EventType.MouseDrag) + { + mMouseIsInside = true; + + if (indexUnderMouse != -1 && eligibleToDrag) + { + if (draggedObjectIsOurs) DragAndDrop.StartDrag("Prefab Tool"); + currentEvent.Use(); + } + } + else if (type == EventType.MouseUp) + { + DragAndDrop.PrepareStartDrag(); + mMouseIsInside = false; + Repaint(); + } + else if (type == EventType.DragUpdated) + { + mMouseIsInside = true; + UpdateVisual(); + currentEvent.Use(); + } + else if (type == EventType.DragPerform) + { + if (dragged != null) + { + if (selection != null) + { + DestroyTexture(selection); + mItems.Remove(selection); + } + + AddItem(dragged, indexUnderMouse); + draggedObject = null; + } + mMouseIsInside = false; + currentEvent.Use(); + } + else if (type == EventType.DragExited || type == EventType.Ignore) + { + mMouseIsInside = false; + } + + if (!mMouseIsInside) + { + selection = null; + dragged = null; + } + + BetterList indices = new BetterList(); + + for (int i = 0; i < mItems.size; ) + { + if (dragged != null && indices.size == indexUnderMouse) + indices.Add(-1); + + if (mItems[i] != selection) + { + if (string.IsNullOrEmpty(searchFilter) || + mItems[i].prefab.name.IndexOf(searchFilter, System.StringComparison.CurrentCultureIgnoreCase) != -1) + indices.Add(i); + } + ++i; + } + + if (!indices.Contains(-1)) indices.Add(-1); + + if (eligibleToDrag && type == EventType.MouseDown && indexUnderMouse > -1) + { + GUIUtility.keyboardControl = 0; + + if (currentEvent.button == 0 && indexUnderMouse < indices.size) + { + int index = indices[indexUnderMouse]; + + if (index != -1 && index < mItems.size) + { + selection = mItems[index]; + draggedObject = selection.prefab; + dragged = selection.prefab; + currentEvent.Use(); + } + } + } + + mPos = EditorGUILayout.BeginScrollView(mPos); + { + Color normal = new Color(1f, 1f, 1f, 0.5f); + for (int i = 0; i < indices.size; ++i) + { + int index = indices[i]; + Item ent = (index != -1) ? mItems[index] : selection; + + if (ent != null && ent.prefab == null) + { + mItems.RemoveAt(index); + continue; + } + + Rect rect = new Rect(x, y, cellSize, cellSize); + Rect inner = rect; + inner.xMin += 2f; + inner.xMax -= 2f; + inner.yMin += 2f; + inner.yMax -= 2f; + rect.yMax -= 1f; + + if (!isDragging && (mMode == Mode.CompactMode || (ent == null || ent.tex != null))) + mContent.tooltip = (ent != null) ? ent.prefab.name : "Click to add"; + else mContent.tooltip = ""; + + //if (ent == selection) + { + GUI.color = normal; + U3DExtends.UIEditorHelper.DrawTiledTexture(inner, U3DExtends.UIEditorHelper.backdropTexture); + } + + GUI.color = Color.white; + GUI.backgroundColor = normal; + + if (GUI.Button(rect, mContent, "Button")) + { + if (ent == null || currentEvent.button == 0) + { + string path = EditorUtility.OpenFilePanel("Add a prefab", "", "prefab"); + + if (!string.IsNullOrEmpty(path)) + { + Item newEnt = CreateItemByPath(path); + + if (newEnt != null) + { + mItems.Add(newEnt); + Save(); + } + } + } + else if (currentEvent.button == 1) + { + //ContextMenu.AddItem("Update Preview", false, UpdatePreView, index); + ContextMenu.AddItem("Delete", false, RemoveItem, index); + ContextMenu.Show(); + } + } + + string caption = (ent == null) ? "" : ent.prefab.name.Replace("Control - ", ""); + + if (ent != null) + { + if (ent.tex != null) + { + GUI.DrawTexture(inner, ent.tex); + } + else if (mMode != Mode.DetailedMode) + { + GUI.Label(inner, caption, mStyle); + caption = ""; + } + } + else GUI.Label(inner, "Add", mStyle); + + if (mMode == Mode.DetailedMode) + { + GUI.backgroundColor = new Color(1f, 1f, 1f, 0.5f); + GUI.contentColor = new Color(1f, 1f, 1f, 0.7f); + GUI.Label(new Rect(rect.x, rect.y + rect.height, rect.width, 32f), caption, "ProgressBarBack"); + GUI.contentColor = Color.white; + GUI.backgroundColor = Color.white; + } + + x += spacingX; + + if (x + spacingX > width) + { + y += spacingY; + x = cellPadding; + } + } + GUILayout.Space(y + spacingY); + } + EditorGUILayout.EndScrollView(); + //if (mTab == 0) + { + //EditorGUILayout.BeginHorizontal(); + //bool isCreateBackground = GUILayout.Button("背景"); + //if (isCreateBackground) + // EditorApplication.ExecuteMenuItem("UIEditor/创建/Background"); + + //bool isCreateDecorate = GUILayout.Button("参考图"); + //if (isCreateDecorate) + // EditorApplication.ExecuteMenuItem("UIEditor/创建/Decorate"); + //EditorGUILayout.EndHorizontal(); + } + //else if (mTab != 0) + { + GUILayout.BeginHorizontal(); + { + string after = EditorGUILayout.TextField("", searchFilter, "SearchTextField", GUILayout.Width(Screen.width - 20f)); + + if (GUILayout.Button("", "SearchCancelButton", GUILayout.Width(18f))) + { + after = ""; + GUIUtility.keyboardControl = 0; + } + + if (searchFilter != after) + { + EditorPrefs.SetString("PrefabWin_SearchFilter", after); + searchFilter = after; + } + } + GUILayout.EndHorizontal(); + } + + SizePercent = EditorGUILayout.Slider(SizePercent, 0, 1); + } +} +} \ No newline at end of file diff --git a/Assets/UIEditor/Editor/PrefabWin.cs.meta b/Assets/UIEditor/Editor/PrefabWin.cs.meta new file mode 100644 index 0000000..b8e3d08 --- /dev/null +++ b/Assets/UIEditor/Editor/PrefabWin.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e66c7da2d12bfc542bd704e5eadb7679 +timeCreated: 1520497408 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UIEditor/Editor/SceneEditor.cs b/Assets/UIEditor/Editor/SceneEditor.cs new file mode 100644 index 0000000..c187f28 --- /dev/null +++ b/Assets/UIEditor/Editor/SceneEditor.cs @@ -0,0 +1,220 @@ +using UnityEngine; +using UnityEditor; +using UnityEngine.UI; + +namespace U3DExtends { +public class SceneEditor { + + static Object LastSelectObj = null; + static Object CurSelectObj = null; + [InitializeOnLoadMethod] + static void Init() + { + SceneView.onSceneGUIDelegate += OnSceneGUI; + + //选中Image节点并点击图片后即帮它赋上图片 + if (Configure.IsEnableFastSelectImage) + Selection.selectionChanged += OnSelectChange; + } + + static void OnSelectChange() + { + LastSelectObj = CurSelectObj; + CurSelectObj = Selection.activeObject; + //如果要遍历目录,修改为SelectionMode.DeepAssets + UnityEngine.Object[] arr = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.TopLevel); + if (arr != null && arr.Length > 0) + { + GameObject selectObj = LastSelectObj as GameObject; + if (selectObj != null && (arr[0] is Sprite || arr[0] is Texture2D)) + { + string assetPath = AssetDatabase.GetAssetPath(arr[0]); + Image image = selectObj.GetComponent(); + Button btn = selectObj.GetComponent