NGUI Version 3.9.0

  1. //----------------------------------------------
  2. // NGUI: Next-Gen UI kit
  3. // Copyright © 2011-2015 Tasharen Entertainment
  4. //----------------------------------------------
  5. using UnityEngine;
  6. using UnityEditor;
  7. using System.Collections.Generic;
  8. /// <summary>
  9. /// Inspector class used to edit UIWidgets.
  10. /// </summary>
  11. [CanEditMultipleObjects]
  12. [CustomEditor(typeof(UIWidget), true)]
  13. public class UIWidgetInspector : UIRectEditor
  14. {
  15. static public new UIWidgetInspector instance; //
  16. public enum Action // YUTODO这个什么作用?
  17. {
  18. None,
  19. Move, // 移动
  20. Scale,// 缩放
  21. Rotate,
  22. }
  23. Action mAction = Action.None;
  24. Action mActionUnderMouse = Action.None;
  25. bool mAllowSelection = true;
  26. protected UIWidget mWidget; // 保存一个widget
  27. static protected bool mUseShader = false;// 默认不使用shader
  28. // GUIStyle 是什么鬼?
  29. // 各种颜色的点
  30. static GUIStyle mBlueDot = null; // 蓝点?
  31. static GUIStyle mYellowDot = null;
  32. static GUIStyle mRedDot = null;
  33. static GUIStyle mOrangeDot = null;
  34. static GUIStyle mGreenDot = null;
  35. static GUIStyle mGreyDot = null;
  36. static MouseCursor mCursor = MouseCursor.Arrow; // 还能控制鼠标光标?666
  37. // 枢轴点
  38. static public UIWidget.Pivot[] pivotPoints =
  39. {
  40. UIWidget.Pivot.BottomLeft,
  41. UIWidget.Pivot.TopLeft,
  42. UIWidget.Pivot.TopRight,
  43. UIWidget.Pivot.BottomRight,
  44. UIWidget.Pivot.Left,
  45. UIWidget.Pivot.Top,
  46. UIWidget.Pivot.Right,
  47. UIWidget.Pivot.Bottom,
  48. };
  49. //
  50. static int s_Hash = "WidgetHash".GetHashCode();
  51. // 坐标
  52. Vector3 mLocalPos = Vector3.zero;
  53. Vector3 mWorldPos = Vector3.zero;
  54. // 起始宽高
  55. int mStartWidth = 0;
  56. int mStartHeight = 0;
  57. // 起始拖动和鼠标?
  58. Vector3 mStartDrag = Vector3.zero;
  59. Vector2 mStartMouse = Vector2.zero;
  60. // 起始方向和旋转角度
  61. Vector3 mStartRot = Vector3.zero;
  62. Vector3 mStartDir = Vector3.right;
  63. // 起始的上下左右?
  64. Vector2 mStartLeft = Vector2.zero;
  65. Vector2 mStartRight = Vector2.zero;
  66. Vector2 mStartBottom = Vector2.zero;
  67. Vector2 mStartTop = Vector2.zero;
  68. // 拖动枢轴点 默认为中心
  69. UIWidget.Pivot mDragPivot = UIWidget.Pivot.Center;
  70. /// <summary>
  71. /// Raycast into the screen.
  72. /// 判断当前鼠标是否射中传入的平面
  73. /// </summary>
  74. /// <param name="corners">传入待检测平面的三个点</param>
  75. /// <param name="hit">射到的点的坐标</param>
  76. /// <returns>射到返回true</returns>
  77. static public bool Raycast (Vector3[] corners, out Vector3 hit)
  78. {
  79. Plane plane = new Plane(corners[0], corners[1], corners[2]); // 三点确定一个平面
  80. Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); // 转换2D GUI位置到世界空间的ray
  81. float dist = 0f;
  82. bool isHit = plane.Raycast(ray, out dist); // 检查射线有没有射中平面
  83. hit = isHit ? ray.GetPoint(dist) : Vector3.zero; // GetPoint 返回离射线距离为 dist 的那个点的位置。
  84. return isHit;
  85. }
  86. /// <summary>
  87. /// Color used by the handles based on the current color scheme.
  88. /// 根据当前颜色主题返回颜色
  89. /// </summary>
  90. static public Color handlesColor
  91. {
  92. get
  93. {
  94. if (NGUISettings.colorMode == NGUISettings.ColorMode.Orange)
  95. {
  96. return new Color(1f, 0.5f, 0f);
  97. }
  98. else if (NGUISettings.colorMode == NGUISettings.ColorMode.Green)
  99. {
  100. return Color.green;
  101. }
  102. return Color.white;
  103. }
  104. }
  105. /// <summary>
  106. /// Draw a control dot at the specified world position.
  107. /// 在世界坐标绘制控制点
  108. /// </summary>
  109. static public void DrawKnob (Vector3 point, bool selected, bool canResize, int id)
  110. {
  111. // TODO 这是一种什么赋值方法?
  112. if (mGreyDot == null) mGreyDot = "sv_label_0"; // 一种内置的编辑器风格
  113. if (mBlueDot == null) mBlueDot = "sv_label_1";
  114. if (mGreenDot == null) mGreenDot = "sv_label_3";
  115. if (mYellowDot == null) mYellowDot = "sv_label_4";
  116. if (mOrangeDot == null) mOrangeDot = "sv_label_5";
  117. if (mRedDot == null) mRedDot = "sv_label_6";
  118. //
  119. Vector2 screenPoint = HandleUtility.WorldToGUIPoint(point);
  120. // 矩阵
  121. #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6
  122. Rect rect = new Rect(screenPoint.x - 7f, screenPoint.y - 7f, 14f, 14f);
  123. #else
  124. Rect rect = new Rect(screenPoint.x - 5f, screenPoint.y - 9f, 14f, 14f);
  125. #endif
  126. // 根据传入的状态判断显示的颜色
  127. if (selected)
  128. {
  129. if (NGUISettings.colorMode == NGUISettings.ColorMode.Orange)
  130. {
  131. mRedDot.Draw(rect, GUIContent.none, id);
  132. }
  133. else
  134. {
  135. mOrangeDot.Draw(rect, GUIContent.none, id);
  136. }
  137. }
  138. else if (canResize)
  139. {
  140. if (NGUISettings.colorMode == NGUISettings.ColorMode.Orange)
  141. {
  142. mOrangeDot.Draw(rect, GUIContent.none, id);
  143. }
  144. else if (NGUISettings.colorMode == NGUISettings.ColorMode.Green)
  145. {
  146. mGreenDot.Draw(rect, GUIContent.none, id);
  147. }
  148. else
  149. {
  150. mBlueDot.Draw(rect, GUIContent.none, id);
  151. }
  152. }
  153. else mGreyDot.Draw(rect, GUIContent.none, id); //
  154. }
  155. /// <summary>
  156. /// Screen-space distance from the mouse position to the specified world position.
  157. /// 屏幕空间下 鼠标到某点的距离
  158. /// </summary>
  159. static public float GetScreenDistance (Vector3 worldPos, Vector2 mousePos)
  160. {
  161. Vector2 screenPos = HandleUtility.WorldToGUIPoint(worldPos);
  162. return Vector2.Distance(mousePos, screenPos);
  163. }
  164. /// <summary>
  165. /// Closest screen-space distance from the mouse position to one of the specified world points.
  166. /// 屏幕空间下 在鼠标到各点的距离中取最小距离
  167. /// </summary>
  168. static public float GetScreenDistance (Vector3[] worldPoints, Vector2 mousePos, out int index)
  169. {
  170. float min = float.MaxValue;
  171. index = 0;
  172. for (int i = 0; i < worldPoints.Length; ++i)
  173. {
  174. float distance = GetScreenDistance(worldPoints[i], mousePos);
  175. if (distance < min)
  176. {
  177. index = i;
  178. min = distance;
  179. }
  180. }
  181. return min;
  182. }
  183. /// <summary>
  184. /// Set the mouse cursor rectangle, refreshing the screen when it gets changed.
  185. /// 鼠标光标类型发生改变时重新设置它的矩形区域
  186. /// </summary>
  187. static public void SetCursorRect (Rect rect, MouseCursor cursor)
  188. {
  189. EditorGUIUtility.AddCursorRect(rect, cursor);
  190. if (Event.current.type == EventType.MouseMove)
  191. {
  192. if (mCursor != cursor)
  193. {
  194. mCursor = cursor;
  195. Event.current.Use();
  196. }
  197. }
  198. }
  199. /// <summary>
  200. ///
  201. /// </summary>
  202. protected override void OnDisable ()
  203. {
  204. base.OnDisable();
  205. NGUIEditorTools.HideMoveTool(false);
  206. instance = null;
  207. }
  208. /// <summary>
  209. /// Convert the specified 4 corners into 8 pivot points (adding left, top, right, bottom -- in that order).
  210. /// 把四个角落的坐标数组扩展为八个点的坐标数组
  211. /// </summary>
  212. static public Vector3[] GetHandles (Vector3[] corners)
  213. {
  214. Vector3[] v = new Vector3[8];
  215. v[0] = corners[0];
  216. v[1] = corners[1];
  217. v[2] = corners[2];
  218. v[3] = corners[3];
  219. v[4] = (corners[0] + corners[1]) * 0.5f;
  220. v[5] = (corners[1] + corners[2]) * 0.5f;
  221. v[6] = (corners[2] + corners[3]) * 0.5f;
  222. v[7] = (corners[0] + corners[3]) * 0.5f;
  223. return v;
  224. }
  225. /// <summary>
  226. /// Determine what kind of pivot point is under the mouse and update the cursor accordingly.
  227. /// 通过鼠标的位置判断应当进行什么样的操作。
  228. /// 默认返回 center 锚点,能够缩放时返回 目标锚点
  229. /// </summary>
  230. static public UIWidget.Pivot GetPivotUnderMouse (Vector3[] worldPos, Event e, bool[] resizable, bool movable, ref Action action)
  231. {
  232. // Time to figure out what kind of action is underneath the mouse
  233. UIWidget.Pivot pivotUnderMouse = UIWidget.Pivot.Center;// 初始化为 锚点中心
  234. //
  235. if (action == Action.None)
  236. {
  237. int index = 0;
  238. float dist = GetScreenDistance(worldPos, e.mousePosition, out index); // 获取最小的距离,并记录最小距离对应点的下标
  239. bool alt = (e.modifiers & EventModifiers.Alt) != 0; // 判断是不是按了组合键
  240. //
  241. if (resizable[index] && dist < 10f) // 如果这个位置能动,并且距离小于10f
  242. {
  243. pivotUnderMouse = pivotPoints[index]; //鼠标点到的枢轴点是index标示出的index
  244. action = Action.Scale;// 进行缩放动作
  245. }
  246. else if (!alt && NGUIEditorTools.SceneViewDistanceToRectangle(worldPos, e.mousePosition) == 0f) // 没有按组合键并且鼠标点在矩形框里面
  247. {
  248. action = movable ? Action.Move : Action.Rotate; // 能移动仅进行移动,不能移动就进行旋转
  249. }
  250. else if (dist < 30f)
  251. {
  252. action = Action.Rotate; // 其他情况就进行旋转
  253. }
  254. }
  255. // Change the mouse cursor to a more appropriate one
  256. //
  257. Vector2[] screenPos = new Vector2[8];
  258. for (int i = 0; i < 8; ++i) screenPos[i] = HandleUtility.WorldToGUIPoint(worldPos[i]);
  259. Bounds b = new Bounds(screenPos[0], Vector3.zero); // 给定中心点和大小。,后面那个大小代表(width,height,depth)
  260. for (int i = 1; i < 8; ++i) b.Encapsulate(screenPos[i]);// 包含八个点的最小矩形框,在这里八个点都恰好在矩形框的边上。
  261. Vector2 min = b.min;// min = center - extents; extents 是 size 的一半。例如中心点为(0,0,0),extents(2,3,5),那么min(-2,-3,-5)
  262. Vector2 max = b.max;
  263. // 在原来的基础上扩展 30f。depth 没用到所以这里没处理
  264. min.x -= 30f;
  265. max.x += 30f;
  266. min.y -= 30f;
  267. max.y += 30f;
  268. Rect rect = new Rect(min.x, min.y, max.x - min.x, max.y - min.y); // 获取矩形框
  269. // 根据动作的状态 显示鼠标光标的形状
  270. if (action == Action.Rotate)
  271. {
  272. SetCursorRect(rect, MouseCursor.RotateArrow);
  273. }
  274. else if (action == Action.Move)
  275. {
  276. SetCursorRect(rect, MouseCursor.MoveArrow);
  277. }
  278. else if (action == Action.Scale)
  279. {
  280. SetCursorRect(rect, MouseCursor.ScaleArrow);
  281. }
  282. else SetCursorRect(rect, MouseCursor.Arrow);
  283. return pivotUnderMouse;
  284. }
  285. /// <summary>
  286. /// Draw the specified anchor point.
  287. /// 绘制黄色的锚点以及连接线、距离标签
  288. /// </summary>
  289. static public void DrawAnchorHandle (UIRect.AnchorPoint anchor, Transform myTrans, Vector3[] myCorners, int side, int id)
  290. {
  291. if (!anchor.target) return; // 没有定锚点就不用画了
  292. int i0, i1;
  293. //矩形四个点在数组中的序列与相对位置的关系如下
  294. //12
  295. //03
  296. //根据是哪边的锚点来选出决定那条边的两个顶点
  297. if (side == 0)
  298. {
  299. // Left
  300. i0 = 0;
  301. i1 = 1;
  302. }
  303. else if (side == 1)
  304. {
  305. // Top
  306. i0 = 1;
  307. i1 = 2;
  308. }
  309. else if (side == 2)
  310. {
  311. // Right
  312. i0 = 3;
  313. i1 = 2;
  314. }
  315. else
  316. {
  317. // Bottom
  318. i0 = 0;
  319. i1 = 3;
  320. }
  321. //
  322. Vector3 myPos = (myCorners[i0] + myCorners[i1]) * 0.5f; // 锚点相关位置是对应边的中点
  323. Vector3[] sides = null; // 目标对象矩形的四个节点
  324. if (anchor.rect != null)
  325. {
  326. sides = anchor.rect.worldCorners;
  327. }
  328. else
  329. {
  330. #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6
  331. Camera cam = anchor.target.camera; // 获取锚点目标的 camera
  332. #else
  333. Camera cam = anchor.target.GetComponent<Camera>();
  334. #endif
  335. if (cam != null) sides = cam.GetWorldCorners(); // 获取相机的边界
  336. }
  337. Vector3 theirPos; // 黄点位置,必然在目标矩形上面
  338. if (sides != null)
  339. {
  340. Vector3 v0, v1;
  341. if (side == 0 || side == 2)
  342. {
  343. // Left or right
  344. v0 = Vector3.Lerp(sides[0], sides[3], anchor.relative); // 在两个向量V0、V1间做线性插值,根据第三个参数t决定返回某个插值。例如 t=0 返回V0,t=0.5 返回V0、V1的中间插值。
  345. v1 = Vector3.Lerp(sides[1], sides[2], anchor.relative); //
  346. }
  347. else
  348. {
  349. // Top or bottom
  350. v0 = Vector3.Lerp(sides[0], sides[1], anchor.relative);
  351. v1 = Vector3.Lerp(sides[3], sides[2], anchor.relative);
  352. }
  353. // 黄点是 myPos 在 v0 和 v1 连接线上的投影点,如果超过v0v1线段,则黄点设置为v0或v1。
  354. theirPos = HandleUtility.ProjectPointLine(myPos, v0, v1);
  355. }
  356. else
  357. {
  358. theirPos = anchor.target.position;
  359. }
  360. // 画连接线
  361. NGUIHandles.DrawShadowedLine(myCorners, myPos, theirPos, Color.yellow);
  362. // 位置偏离的时候在一定条件下绘制一个标记负值距离的标签
  363. if (Event.current.GetTypeForControl(id) == EventType.Repaint) // 控制ID id 当前事件类型如果是重绘
  364. {
  365. Vector2 screenPoint = HandleUtility.WorldToGUIPoint(theirPos);
  366. #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6
  367. Rect rect = new Rect(screenPoint.x - 7f, screenPoint.y - 7f, 14f, 14f);
  368. #else
  369. Rect rect = new Rect(screenPoint.x - 5f, screenPoint.y - 9f, 14f, 14f);
  370. #endif
  371. if (mYellowDot == null) mYellowDot = "sv_label_4";
  372. Vector3 v0 = HandleUtility.WorldToGUIPoint(myPos);
  373. Vector3 v1 = HandleUtility.WorldToGUIPoint(theirPos);
  374. Handles.BeginGUI(); // 开始一个 2D 绘制块
  375. mYellowDot.Draw(rect, GUIContent.none, id); // 绘制黄点
  376. Vector3 diff = v1 - v0;
  377. bool isHorizontal = Mathf.Abs(diff.x) > Mathf.Abs(diff.y);// 判断是否为水平线
  378. float mag = diff.magnitude; // 获取线的长度
  379. if ((isHorizontal && mag > 60f) || (!isHorizontal && mag > 30f)) // 长度超过 60 的水平线或者长度大于 30 的竖直线
  380. {
  381. Vector3 pos = (myPos + theirPos) * 0.5f; //
  382. string text = anchor.absolute.ToString();//
  383. GUI.color = Color.yellow;
  384. if (side == 0)
  385. {
  386. if (theirPos.x < myPos.x) //如果目标点的位置比出发点的位置还要靠左,那么显示一个标记距离的label
  387. NGUIHandles.DrawCenteredLabel(pos, text);
  388. }
  389. else if (side == 1)
  390. {
  391. if (theirPos.y > myPos.y)
  392. NGUIHandles.DrawCenteredLabel(pos, text);
  393. }
  394. else if (side == 2)
  395. {
  396. if (theirPos.x > myPos.x)
  397. NGUIHandles.DrawCenteredLabel(pos, text);
  398. }
  399. else if (side == 3)
  400. {
  401. if (theirPos.y < myPos.y)
  402. NGUIHandles.DrawCenteredLabel(pos, text);
  403. }
  404. GUI.color = Color.white;
  405. }
  406. Handles.EndGUI();
  407. }
  408. }
  409. /// <summary>
  410. /// Draw the on-screen selection, knobs, and handle all interaction logic.
  411. ///
  412. /// </summary>
  413. public void OnSceneGUI ()
  414. {
  415. if (Selection.objects.Length > 1) return; // 选中了多个对象,返回
  416. NGUIEditorTools.HideMoveTool(true); // 隐藏移动工具
  417. if (!UIWidget.showHandles) return; // 没有需要显示的 handles,返回
  418. mWidget = target as UIWidget; // 把选中对象作为一个 UIWidget 组件处理
  419. Transform t = mWidget.cachedTransform; // 获取对象的 transform
  420. Event e = Event.current; //
  421. int id = GUIUtility.GetControlID(s_Hash, FocusType.Passive); // 获取一个控制ID,这个控制不能获取键盘焦点
  422. EventType type = e.GetTypeForControl(id); // 获取控制ID的事件类型
  423. Action actionUnderMouse = mAction; // 移动、缩放或是旋转
  424. Vector3[] handles = GetHandles(mWidget.worldCorners); // 获取组件的八个枢轴点点
  425. // 绘制矩形框
  426. NGUIHandles.DrawShadowedLine(handles, handles[0], handles[1], handlesColor);
  427. NGUIHandles.DrawShadowedLine(handles, handles[1], handles[2], handlesColor);
  428. NGUIHandles.DrawShadowedLine(handles, handles[2], handles[3], handlesColor);
  429. NGUIHandles.DrawShadowedLine(handles, handles[0], handles[3], handlesColor);
  430. // If the widget is anchored, draw the anchors
  431. // 组件有锚点的话就绘制锚点
  432. if (mWidget.isAnchored)
  433. {
  434. DrawAnchorHandle(mWidget.leftAnchor, mWidget.cachedTransform, handles, 0, id);
  435. DrawAnchorHandle(mWidget.topAnchor, mWidget.cachedTransform, handles, 1, id);
  436. DrawAnchorHandle(mWidget.rightAnchor, mWidget.cachedTransform, handles, 2, id);
  437. DrawAnchorHandle(mWidget.bottomAnchor, mWidget.cachedTransform, handles, 3, id);
  438. }
  439. // 需要时显示细节
  440. if (type == EventType.Repaint)
  441. {
  442. bool showDetails = (mAction == UIWidgetInspector.Action.Scale) || NGUISettings.drawGuides; // 进行缩放时显示细节
  443. if (mAction == UIWidgetInspector.Action.None && e.modifiers == EventModifiers.Control) showDetails = true;
  444. if (NGUITools.GetActive(mWidget) && mWidget.parent == null) showDetails = true;
  445. if (showDetails) NGUIHandles.DrawSize(handles, mWidget.width, mWidget.height);
  446. }
  447. // Presence of the legacy stretch component prevents resizing
  448. // TODO 显示原来的轨迹组件放置重绘 ??
  449. bool canResize = (mWidget.GetComponent<UIStretch>() == null); // 没有这个组件说明是可以自由缩放的
  450. bool[] resizable = new bool[8]; //
  451. resizable[4] = canResize; // left
  452. resizable[5] = canResize; // top
  453. resizable[6] = canResize; // right
  454. resizable[7] = canResize; // bottom
  455. UILabel lbl = mWidget as UILabel; // 如果这个 widget 组件实际上是个一个 Label 组件
  456. if (lbl != null)
  457. {
  458. if (lbl.overflowMethod == UILabel.Overflow.ResizeFreely) // 如果 label 设置为可以随意缩放,那么其锚点都定住
  459. {
  460. resizable[4] = false; // left
  461. resizable[5] = false; // top
  462. resizable[6] = false; // right
  463. resizable[7] = false; // bottom
  464. }
  465. else if (lbl.overflowMethod == UILabel.Overflow.ResizeHeight) // 如果是高度可以自由缩放,那么上下两个锚点也定住
  466. {
  467. resizable[5] = false; // top
  468. resizable[7] = false; // bottom
  469. }
  470. }
  471. if (mWidget.keepAspectRatio == UIWidget.AspectRatioSource.BasedOnHeight) // 基于高度变换,那么左右锚点就不需要设置了
  472. {
  473. resizable[4] = false;
  474. resizable[6] = false;
  475. }
  476. else if (mWidget.keepAspectRatio == UIWidget.AspectRatioSource.BasedOnWidth)
  477. {
  478. resizable[5] = false;
  479. resizable[7] = false;
  480. }
  481. // 角落的锚点情况根据上下左右的可用情况设置
  482. resizable[0] = resizable[7] && resizable[4]; // bottom-left
  483. resizable[1] = resizable[5] && resizable[4]; // top-left
  484. resizable[2] = resizable[5] && resizable[6]; // top-right
  485. resizable[3] = resizable[7] && resizable[6]; // bottom-right
  486. // 获取锚点,没有的话返回 center
  487. UIWidget.Pivot pivotUnderMouse = GetPivotUnderMouse(handles, e, resizable, true, ref actionUnderMouse);
  488. switch (type)
  489. {
  490. case EventType.Repaint: // 绘制控制点
  491. {
  492. Vector3 v0 = HandleUtility.WorldToGUIPoint(handles[0]);
  493. Vector3 v2 = HandleUtility.WorldToGUIPoint(handles[2]);
  494. if ((v2 - v0).magnitude > 60f) // 斜边 长度大于 60 才绘制控制点
  495. {
  496. Vector3 v1 = HandleUtility.WorldToGUIPoint(handles[1]);
  497. Vector3 v3 = HandleUtility.WorldToGUIPoint(handles[3]);
  498. Handles.BeginGUI();
  499. {
  500. for (int i = 0; i < 4; ++i)
  501. DrawKnob(handles[i], mWidget.pivot == pivotPoints[i], resizable[i], id);
  502. if ((v1 - v0).magnitude > 80f)
  503. {
  504. if (mWidget.leftAnchor.target == null || mWidget.leftAnchor.absolute != 0)
  505. DrawKnob(handles[4], mWidget.pivot == pivotPoints[4], resizable[4], id);
  506. if (mWidget.rightAnchor.target == null || mWidget.rightAnchor.absolute != 0)
  507. DrawKnob(handles[6], mWidget.pivot == pivotPoints[6], resizable[6], id);
  508. }
  509. if ((v3 - v0).magnitude > 80f)
  510. {
  511. if (mWidget.topAnchor.target == null || mWidget.topAnchor.absolute != 0)
  512. DrawKnob(handles[5], mWidget.pivot == pivotPoints[5], resizable[5], id);
  513. if (mWidget.bottomAnchor.target == null || mWidget.bottomAnchor.absolute != 0)
  514. DrawKnob(handles[7], mWidget.pivot == pivotPoints[7], resizable[7], id);
  515. }
  516. }
  517. Handles.EndGUI();
  518. }
  519. }
  520. break;
  521. case EventType.MouseDown:
  522. {
  523. if (actionUnderMouse != Action.None)
  524. {
  525. mStartMouse = e.mousePosition; // 记录鼠标起始位置
  526. mAllowSelection = true; // 标记拖动的开始,拖动过程中无法再次选中
  527. if (e.button == 1) //
  528. {
  529. if (e.modifiers == 0) // 没有用组合键
  530. {
  531. GUIUtility.hotControl = GUIUtility.keyboardControl = id;
  532. e.Use(); // 使用该事件,用于表示这个事件已经处理过了
  533. }
  534. }
  535. else if (e.button == 0 && actionUnderMouse != Action.None && Raycast(handles, out mStartDrag)) // 鼠标左键&&能够操作&&点到了这个平面 // TODO 不知道为什么需要这么多判断
  536. {
  537. mWorldPos = t.position;
  538. mLocalPos = t.localPosition;
  539. mStartRot = t.localRotation.eulerAngles;
  540. mStartDir = mStartDrag - t.position; // 用向量来表示角度,鼠标与中点连线的夹角
  541. mStartWidth = mWidget.width;
  542. mStartHeight = mWidget.height;
  543. // TODO 上下左右,
  544. mStartLeft.x = mWidget.leftAnchor.relative;
  545. mStartLeft.y = mWidget.leftAnchor.absolute;
  546. mStartRight.x = mWidget.rightAnchor.relative;
  547. mStartRight.y = mWidget.rightAnchor.absolute;
  548. mStartBottom.x = mWidget.bottomAnchor.relative;
  549. mStartBottom.y = mWidget.bottomAnchor.absolute;
  550. mStartTop.x = mWidget.topAnchor.relative;
  551. mStartTop.y = mWidget.topAnchor.absolute;
  552. //
  553. mDragPivot = pivotUnderMouse;
  554. mActionUnderMouse = actionUnderMouse;
  555. //
  556. GUIUtility.hotControl = GUIUtility.keyboardControl = id;
  557. e.Use();
  558. }
  559. }
  560. }
  561. break;
  562. case EventType.MouseDrag:
  563. {
  564. // Prevent selection once the drag operation begins
  565. // 如果已经进行了拖动操作,那么无法再进行选中了
  566. bool dragStarted = (e.mousePosition - mStartMouse).magnitude > 3f;
  567. if (dragStarted) mAllowSelection = false;
  568. if (GUIUtility.hotControl == id) // 如果热键控制 与 id 一致
  569. {
  570. e.Use(); // TODO 这个为什么设置在前面?
  571. if (mAction != Action.None || mActionUnderMouse != Action.None) //
  572. {
  573. Vector3 pos;
  574. if (Raycast(handles, out pos))
  575. {
  576. // 拖动开始时进行数据记录
  577. if (mAction == Action.None && mActionUnderMouse != Action.None) // 前面的 mAction 用于标记是否是拖动刚开始
  578. {
  579. // Wait until the mouse moves by more than a few pixels
  580. if (dragStarted)
  581. {
  582. if (mActionUnderMouse == Action.Move) //
  583. {
  584. NGUISnap.Recalculate(mWidget); // 重新计算
  585. }
  586. else if (mActionUnderMouse == Action.Rotate) //
  587. {
  588. mStartRot = t.localRotation.eulerAngles; // 返回欧垃角
  589. mStartDir = mStartDrag - t.position; // 旋转的角度
  590. }
  591. else if (mActionUnderMouse == Action.Scale)
  592. {
  593. mStartWidth = mWidget.width;
  594. mStartHeight = mWidget.height;
  595. mDragPivot = pivotUnderMouse;
  596. }
  597. mAction = actionUnderMouse;
  598. }
  599. }
  600. //
  601. if (mAction != Action.None)
  602. {
  603. // 设置撤销点
  604. NGUIEditorTools.RegisterUndo("Change Rect", t);
  605. NGUIEditorTools.RegisterUndo("Change Rect", mWidget);
  606. // Reset the widget before adjusting anything
  607. // 在进行任何调整前先进行重置
  608. t.position = mWorldPos;
  609. mWidget.width = mStartWidth;
  610. mWidget.height = mStartHeight;
  611. // widget 的上下左右锚点都重置为初始值
  612. mWidget.leftAnchor.Set(mStartLeft.x, mStartLeft.y);
  613. mWidget.rightAnchor.Set(mStartRight.x, mStartRight.y);
  614. mWidget.bottomAnchor.Set(mStartBottom.x, mStartBottom.y);
  615. mWidget.topAnchor.Set(mStartTop.x, mStartTop.y);
  616. // 移动操作
  617. if (mAction == Action.Move)
  618. {
  619. // Move the widget
  620. t.position = mWorldPos + (pos - mStartDrag); // t.position = t.positon + (pos - mStartDrag);//mWorldPos 和 mStartDrag 应该是同一个值,不知道为什么要分开来
  621. Vector3 after = t.localPosition; //
  622. bool snapped = false; //
  623. Transform parent = t.parent;
  624. if (parent != null)
  625. {
  626. UIGrid grid = parent.GetComponent<UIGrid>(); //
  627. // 如果说这个widget的父节点具有 Grid 组件,并且按照 CellSnap 的布局方式进行布局
  628. // 那么根据grid的cell大小进行对齐操作。
  629. if (grid != null && grid.arrangement == UIGrid.Arrangement.CellSnap)
  630. {
  631. snapped = true;
  632. if (grid.cellWidth > 0) after.x = Mathf.Round(after.x / grid.cellWidth) * grid.cellWidth;
  633. if (grid.cellHeight > 0) after.y = Mathf.Round(after.y / grid.cellHeight) * grid.cellHeight;
  634. }
  635. }
  636. // 如果还没对齐过,进行对齐
  637. if (!snapped)
  638. {
  639. // Snap the widget
  640. after = NGUISnap.Snap(after, mWidget.localCorners, e.modifiers != EventModifiers.Control);
  641. }
  642. // Calculate the final delta
  643. // 本地坐标的变化量
  644. Vector3 localDelta = (after - mLocalPos);
  645. // Restore the position
  646. t.position = mWorldPos; // 恢复坐标位置
  647. // Adjust the widget by the delta
  648. // 根据 delta 来移动 Widget 。 // TODO 这跟直接移动 postion 有什么区别?
  649. NGUIMath.MoveRect(mWidget, localDelta.x, localDelta.y);
  650. }
  651. else if (mAction == Action.Rotate)
  652. {
  653. // 这部分代码不是太懂呢。。
  654. Vector3 dir = pos - t.position;
  655. float angle = Vector3.Angle(mStartDir, dir);
  656. if (angle > 0f)
  657. {
  658. float dot = Vector3.Dot(Vector3.Cross(mStartDir, dir), t.forward);
  659. if (dot < 0f) angle = -angle;
  660. angle = mStartRot.z + angle; // 为什么要加 z 值
  661. angle = (NGUISnap.allow && e.modifiers != EventModifiers.Control) ?
  662. Mathf.Round(angle / 15f) * 15f : Mathf.Round(angle);
  663. // 计算欧拉角
  664. t.localRotation = Quaternion.Euler(mStartRot.x, mStartRot.y, angle);
  665. }
  666. }
  667. else if (mAction == Action.Scale)
  668. {
  669. // Move the widget
  670. //
  671. t.position = mWorldPos + (pos - mStartDrag);
  672. // Calculate the final delta
  673. Vector3 localDelta = (t.localPosition - mLocalPos);
  674. // Restore the position
  675. t.position = mWorldPos;
  676. // Adjust the widget's position and scale based on the delta, restricted by the pivot
  677. // 以枢轴点为中心进行缩放
  678. NGUIMath.ResizeWidget(mWidget, mDragPivot, localDelta.x, localDelta.y, 2, 2);
  679. ReEvaluateAnchorType();
  680. }
  681. }
  682. }
  683. }
  684. }
  685. }
  686. break;
  687. // 释放鼠标
  688. case EventType.MouseUp:
  689. {
  690. if (e.button == 2) break; // 中键不处理
  691. if (GUIUtility.hotControl == id)
  692. {
  693. // 收尾处理
  694. GUIUtility.hotControl = 0;
  695. GUIUtility.keyboardControl = 0;
  696. //
  697. if (e.button < 2)
  698. {
  699. bool handled = false;
  700. //
  701. if (e.button == 1)
  702. {
  703. // Right-click: Open a context menu listing all widgets underneath
  704. NGUIEditorTools.ShowSpriteSelectionMenu(e.mousePosition);
  705. handled = true;
  706. }
  707. else if (mAction == Action.None)
  708. {
  709. // 选择对象
  710. if (mAllowSelection)
  711. {
  712. // Left-click: Select the topmost widget
  713. NGUIEditorTools.SelectWidget(e.mousePosition);
  714. handled = true;
  715. }
  716. }
  717. else
  718. {
  719. // Finished dragging something
  720. Vector3 pos = t.localPosition;
  721. pos.x = Mathf.Round(pos.x);
  722. pos.y = Mathf.Round(pos.y);
  723. pos.z = Mathf.Round(pos.z);
  724. t.localPosition = pos; //对相对位置进行圆整
  725. handled = true;
  726. }
  727. if (handled) e.Use(); // 如果处理过了,那么该事件结束
  728. }
  729. // Clear the actions
  730. mActionUnderMouse = Action.None;
  731. mAction = Action.None;
  732. }
  733. else if (mAllowSelection) // 没控制但是允许选中,那么选择第一个 widget
  734. {
  735. List<UIWidget> widgets = NGUIEditorTools.SceneViewRaycast(e.mousePosition);
  736. if (widgets.Count > 0) Selection.activeGameObject = widgets[0].gameObject;
  737. }
  738. mAllowSelection = true;
  739. }
  740. break;
  741. // 上下左右键对矩形框进行移动
  742. case EventType.KeyDown:
  743. {
  744. if (e.keyCode == KeyCode.UpArrow)
  745. {
  746. NGUIEditorTools.RegisterUndo("Nudge Rect", t);
  747. NGUIEditorTools.RegisterUndo("Nudge Rect", mWidget);
  748. NGUIMath.MoveRect(mWidget, 0f, 1f);
  749. e.Use();
  750. }
  751. else if (e.keyCode == KeyCode.DownArrow)
  752. {
  753. NGUIEditorTools.RegisterUndo("Nudge Rect", t);
  754. NGUIEditorTools.RegisterUndo("Nudge Rect", mWidget);
  755. NGUIMath.MoveRect(mWidget, 0f, -1f);
  756. e.Use();
  757. }
  758. else if (e.keyCode == KeyCode.LeftArrow)
  759. {
  760. NGUIEditorTools.RegisterUndo("Nudge Rect", t);
  761. NGUIEditorTools.RegisterUndo("Nudge Rect", mWidget);
  762. NGUIMath.MoveRect(mWidget, -1f, 0f);
  763. e.Use();
  764. }
  765. else if (e.keyCode == KeyCode.RightArrow)
  766. {
  767. NGUIEditorTools.RegisterUndo("Nudge Rect", t);
  768. NGUIEditorTools.RegisterUndo("Nudge Rect", mWidget);
  769. NGUIMath.MoveRect(mWidget, 1f, 0f);
  770. e.Use();
  771. }
  772. else if (e.keyCode == KeyCode.Escape)
  773. {
  774. if (GUIUtility.hotControl == id)
  775. {
  776. if (mAction != Action.None)
  777. Undo.PerformUndo();
  778. GUIUtility.hotControl = 0;
  779. GUIUtility.keyboardControl = 0;
  780. mActionUnderMouse = Action.None;
  781. mAction = Action.None;
  782. e.Use();
  783. }
  784. else Selection.activeGameObject = null;
  785. }
  786. }
  787. break;
  788. }
  789. }
  790. /// <summary>
  791. /// Cache the reference.
  792. /// 记录引用
  793. /// </summary>
  794. protected override void OnEnable ()
  795. {
  796. base.OnEnable();
  797. instance = this;
  798. mWidget = target as UIWidget; // 在对 mWidget 进行操作时为什么不需要判空?
  799. }
  800. /// <summary>
  801. /// All widgets have depth, color and make pixel-perfect options
  802. /// 所有组件都有 depth,color和 pixel-perfect 选项
  803. /// </summary>
  804. protected override void DrawCustomProperties ()
  805. {
  806. if (NGUISettings.unifiedTransform) // 这个不知道是哪里设置的。。如果是统一的transform,某些部分就不需要显示了。
  807. {
  808. DrawColor(serializedObject, mWidget);
  809. }
  810. else DrawInspectorProperties(serializedObject, mWidget, true); // 在检视器中显示Widget组件的操作面板
  811. }
  812. /// <summary>
  813. /// Draw common widget properties that can be shown as a part of the Transform Inspector.
  814. /// 在检视器中显示通用的 widget 属性,不显示颜色部分
  815. /// </summary>
  816. public void DrawWidgetTransform () { DrawInspectorProperties(serializedObject, mWidget, false); }
  817. /// <summary>
  818. /// Draw the widget's color.
  819. /// 在检视器中显示,设置 widget 的颜色和透明度
  820. /// </summary>
  821. static public void DrawColor (SerializedObject so, UIWidget w)
  822. {
  823. if ((w.GetType() != typeof(UIWidget)))
  824. {
  825. NGUIEditorTools.DrawProperty("Color Tint", so, "mColor", GUILayout.MinWidth(20f));
  826. }
  827. else if (so.isEditingMultipleObjects)
  828. {
  829. NGUIEditorTools.DrawProperty("Alpha", so, "mColor.a", GUILayout.Width(120f));
  830. }
  831. else
  832. {
  833. GUI.changed = false;
  834. float alpha = EditorGUILayout.Slider("Alpha", w.alpha, 0f, 1f);
  835. if (GUI.changed)
  836. {
  837. NGUIEditorTools.RegisterUndo("Alpha change", w);
  838. w.alpha = alpha;
  839. }
  840. }
  841. }
  842. /// <summary>
  843. /// Draw common widget properties.
  844. /// 在检视器中显示通用 widget 属性
  845. /// </summary>
  846. static public void DrawInspectorProperties (SerializedObject so, UIWidget w, bool drawColor)
  847. {
  848. if (drawColor)
  849. {
  850. DrawColor(so, w);
  851. GUILayout.Space(3f);
  852. }
  853. PrefabType type = PrefabUtility.GetPrefabType(w.gameObject); // TODO 为什么要辨别出 prefab 的类型?有些情况不需要显示?
  854. if (NGUIEditorTools.DrawHeader("Widget")) // 包裹起来
  855. {
  856. NGUIEditorTools.BeginContents();
  857. if (NGUISettings.minimalisticLook) NGUIEditorTools.SetLabelWidth(70f);
  858. DrawPivot(so, w); //枢轴点
  859. DrawDepth(so, w, type == PrefabType.Prefab);// 深度
  860. DrawDimensions(so, w, type == PrefabType.Prefab);// 大小
  861. if (NGUISettings.minimalisticLook) NGUIEditorTools.SetLabelWidth(70f);
  862. SerializedProperty ratio = so.FindProperty("aspectRatio");
  863. SerializedProperty aspect = so.FindProperty("keepAspectRatio");
  864. GUILayout.BeginHorizontal();
  865. {
  866. if (!aspect.hasMultipleDifferentValues && aspect.intValue == 0) // 单个或多个对象选中时 aspect 都是第一种情况
  867. {
  868. EditorGUI.BeginDisabledGroup(true); // 设置为禁用
  869. NGUIEditorTools.DrawProperty("Aspect", ratio, false, GUILayout.Width(130f));
  870. EditorGUI.EndDisabledGroup();
  871. }
  872. else NGUIEditorTools.DrawProperty("Aspect", ratio, false, GUILayout.Width(130f));
  873. NGUIEditorTools.DrawProperty("", aspect, false, GUILayout.MinWidth(20f));
  874. }
  875. GUILayout.EndHorizontal();
  876. // 编辑多个对象或者对象存在 碰撞盒的时候显示
  877. if (so.isEditingMultipleObjects || w.hasBoxCollider)
  878. {
  879. GUILayout.BeginHorizontal();
  880. {
  881. NGUIEditorTools.DrawProperty("Collider", so, "autoResizeBoxCollider", GUILayout.Width(100f));
  882. GUILayout.Label("auto-adjust to match");
  883. }
  884. GUILayout.EndHorizontal();
  885. }
  886. NGUIEditorTools.EndContents();
  887. }
  888. }
  889. /// <summary>
  890. /// Draw widget's dimensions.
  891. /// </summary>
  892. static void DrawDimensions (SerializedObject so, UIWidget w, bool isPrefab)
  893. {
  894. GUILayout.BeginHorizontal();
  895. {
  896. bool freezeSize = so.isEditingMultipleObjects;
  897. UILabel lbl = w as UILabel;
  898. if (!freezeSize && lbl) freezeSize = (lbl.overflowMethod == UILabel.Overflow.ResizeFreely);
  899. if (freezeSize)
  900. {
  901. EditorGUI.BeginDisabledGroup(true);
  902. NGUIEditorTools.DrawProperty("Size", so, "mWidth", GUILayout.MinWidth(100f));
  903. EditorGUI.EndDisabledGroup();
  904. }
  905. else
  906. {
  907. GUI.changed = false;
  908. int val = EditorGUILayout.IntField("Size", w.width, GUILayout.MinWidth(100f));
  909. if (GUI.changed)
  910. {
  911. NGUIEditorTools.RegisterUndo("Dimensions Change", w);
  912. w.width = val;
  913. }
  914. }
  915. if (!freezeSize && lbl)
  916. {
  917. UILabel.Overflow ov = lbl.overflowMethod;
  918. freezeSize = (ov == UILabel.Overflow.ResizeFreely || ov == UILabel.Overflow.ResizeHeight);
  919. }
  920. NGUIEditorTools.SetLabelWidth(12f);
  921. if (freezeSize)
  922. {
  923. EditorGUI.BeginDisabledGroup(true);
  924. NGUIEditorTools.DrawProperty("x", so, "mHeight", GUILayout.MinWidth(30f));
  925. EditorGUI.EndDisabledGroup();
  926. }
  927. else
  928. {
  929. GUI.changed = false;
  930. int val = EditorGUILayout.IntField("x", w.height, GUILayout.MinWidth(30f));
  931. if (GUI.changed)
  932. {
  933. NGUIEditorTools.RegisterUndo("Dimensions Change", w);
  934. w.height = val;
  935. }
  936. }
  937. NGUIEditorTools.SetLabelWidth(80f);
  938. if (isPrefab)
  939. {
  940. GUILayout.Space(70f);
  941. }
  942. else
  943. {
  944. EditorGUI.BeginDisabledGroup(so.isEditingMultipleObjects);
  945. if (GUILayout.Button("Snap", GUILayout.Width(60f)))
  946. {
  947. foreach (GameObject go in Selection.gameObjects)
  948. {
  949. UIWidget pw = go.GetComponent<UIWidget>();
  950. if (pw != null)
  951. {
  952. NGUIEditorTools.RegisterUndo("Snap Dimensions", pw);
  953. NGUIEditorTools.RegisterUndo("Snap Dimensions", pw.transform);
  954. pw.MakePixelPerfect();
  955. }
  956. }
  957. }
  958. EditorGUI.EndDisabledGroup();
  959. }
  960. }
  961. GUILayout.EndHorizontal();
  962. }
  963. /// <summary>
  964. /// Draw widget's depth.
  965. /// </summary>
  966. static void DrawDepth (SerializedObject so, UIWidget w, bool isPrefab)
  967. {
  968. if (isPrefab) return;
  969. GUILayout.Space(2f);
  970. GUILayout.BeginHorizontal();
  971. {
  972. EditorGUILayout.PrefixLabel("Depth");
  973. if (GUILayout.Button("Back", GUILayout.MinWidth(46f)))
  974. {
  975. foreach (GameObject go in Selection.gameObjects)
  976. {
  977. UIWidget pw = go.GetComponent<UIWidget>();
  978. if (pw != null) pw.depth = w.depth - 1;
  979. }
  980. }
  981. NGUIEditorTools.DrawProperty("", so, "mDepth", GUILayout.MinWidth(20f));
  982. if (GUILayout.Button("Forward", GUILayout.MinWidth(60f)))
  983. {
  984. foreach (GameObject go in Selection.gameObjects)
  985. {
  986. UIWidget pw = go.GetComponent<UIWidget>();
  987. if (pw != null) pw.depth = w.depth + 1;
  988. }
  989. }
  990. }
  991. GUILayout.EndHorizontal();
  992. int matchingDepths = 1;
  993. UIPanel p = w.panel;
  994. if (p != null)
  995. {
  996. for (int i = 0, imax = p.widgets.Count; i < imax; ++i)
  997. {
  998. UIWidget pw = p.widgets[i];
  999. if (pw != w && pw.depth == w.depth)
  1000. ++matchingDepths;
  1001. }
  1002. }
  1003. if (matchingDepths > 1)
  1004. {
  1005. EditorGUILayout.HelpBox(matchingDepths + " widgets are sharing the depth value of " + w.depth, MessageType.Info);
  1006. }
  1007. }
  1008. /// <summary>
  1009. /// Draw the widget's pivot.
  1010. /// </summary>
  1011. static void DrawPivot (SerializedObject so, UIWidget w)
  1012. {
  1013. SerializedProperty pv = so.FindProperty("mPivot");
  1014. if (pv.hasMultipleDifferentValues)
  1015. {
  1016. // TODO: Doing this doesn't keep the widget's position where it was. Another approach is needed.
  1017. NGUIEditorTools.DrawProperty("Pivot", so, "mPivot");
  1018. }
  1019. else
  1020. {
  1021. // Pivot point -- the new, more visual style
  1022. GUILayout.BeginHorizontal();
  1023. GUILayout.Label("Pivot", GUILayout.Width(NGUISettings.minimalisticLook ? 66f : 76f));
  1024. Toggle(w, "\u25C4", "ButtonLeft", UIWidget.Pivot.Left, true);
  1025. Toggle(w, "\u25AC", "ButtonMid", UIWidget.Pivot.Center, true);
  1026. Toggle(w, "\u25BA", "ButtonRight", UIWidget.Pivot.Right, true);
  1027. Toggle(w, "\u25B2", "ButtonLeft", UIWidget.Pivot.Top, false);
  1028. Toggle(w, "\u258C", "ButtonMid", UIWidget.Pivot.Center, false);
  1029. Toggle(w, "\u25BC", "ButtonRight", UIWidget.Pivot.Bottom, false);
  1030. GUILayout.EndHorizontal();
  1031. pv.enumValueIndex = (int)w.pivot;
  1032. }
  1033. }
  1034. /// <summary>
  1035. /// Draw a toggle button for the pivot point.
  1036. /// </summary>
  1037. static void Toggle (UIWidget w, string text, string style, UIWidget.Pivot pivot, bool isHorizontal)
  1038. {
  1039. bool isActive = false;
  1040. switch (pivot)
  1041. {
  1042. case UIWidget.Pivot.Left:
  1043. isActive = IsLeft(w.pivot);
  1044. break;
  1045. case UIWidget.Pivot.Right:
  1046. isActive = IsRight(w.pivot);
  1047. break;
  1048. case UIWidget.Pivot.Top:
  1049. isActive = IsTop(w.pivot);
  1050. break;
  1051. case UIWidget.Pivot.Bottom:
  1052. isActive = IsBottom(w.pivot);
  1053. break;
  1054. case UIWidget.Pivot.Center:
  1055. isActive = isHorizontal ? pivot == GetHorizontal(w.pivot) : pivot == GetVertical(w.pivot);
  1056. break;
  1057. }
  1058. if (GUILayout.Toggle(isActive, text, style) != isActive)
  1059. SetPivot(w, pivot, isHorizontal);
  1060. }
  1061. static bool IsLeft (UIWidget.Pivot pivot)
  1062. {
  1063. return pivot == UIWidget.Pivot.Left ||
  1064. pivot == UIWidget.Pivot.TopLeft ||
  1065. pivot == UIWidget.Pivot.BottomLeft;
  1066. }
  1067. static bool IsRight (UIWidget.Pivot pivot)
  1068. {
  1069. return pivot == UIWidget.Pivot.Right ||
  1070. pivot == UIWidget.Pivot.TopRight ||
  1071. pivot == UIWidget.Pivot.BottomRight;
  1072. }
  1073. static bool IsTop (UIWidget.Pivot pivot)
  1074. {
  1075. return pivot == UIWidget.Pivot.Top ||
  1076. pivot == UIWidget.Pivot.TopLeft ||
  1077. pivot == UIWidget.Pivot.TopRight;
  1078. }
  1079. static bool IsBottom (UIWidget.Pivot pivot)
  1080. {
  1081. return pivot == UIWidget.Pivot.Bottom ||
  1082. pivot == UIWidget.Pivot.BottomLeft ||
  1083. pivot == UIWidget.Pivot.BottomRight;
  1084. }
  1085. static UIWidget.Pivot GetHorizontal (UIWidget.Pivot pivot)
  1086. {
  1087. if (IsLeft(pivot)) return UIWidget.Pivot.Left;
  1088. if (IsRight(pivot)) return UIWidget.Pivot.Right;
  1089. return UIWidget.Pivot.Center;
  1090. }
  1091. static UIWidget.Pivot GetVertical (UIWidget.Pivot pivot)
  1092. {
  1093. if (IsTop(pivot)) return UIWidget.Pivot.Top;
  1094. if (IsBottom(pivot)) return UIWidget.Pivot.Bottom;
  1095. return UIWidget.Pivot.Center;
  1096. }
  1097. static UIWidget.Pivot Combine (UIWidget.Pivot horizontal, UIWidget.Pivot vertical)
  1098. {
  1099. if (horizontal == UIWidget.Pivot.Left)
  1100. {
  1101. if (vertical == UIWidget.Pivot.Top) return UIWidget.Pivot.TopLeft;
  1102. if (vertical == UIWidget.Pivot.Bottom) return UIWidget.Pivot.BottomLeft;
  1103. return UIWidget.Pivot.Left;
  1104. }
  1105. if (horizontal == UIWidget.Pivot.Right)
  1106. {
  1107. if (vertical == UIWidget.Pivot.Top) return UIWidget.Pivot.TopRight;
  1108. if (vertical == UIWidget.Pivot.Bottom) return UIWidget.Pivot.BottomRight;
  1109. return UIWidget.Pivot.Right;
  1110. }
  1111. return vertical;
  1112. }
  1113. static void SetPivot (UIWidget w, UIWidget.Pivot pivot, bool isHorizontal)
  1114. {
  1115. UIWidget.Pivot horizontal = GetHorizontal(w.pivot);
  1116. UIWidget.Pivot vertical = GetVertical(w.pivot);
  1117. pivot = isHorizontal ? Combine(pivot, vertical) : Combine(horizontal, pivot);
  1118. if (w.pivot != pivot)
  1119. {
  1120. NGUIEditorTools.RegisterUndo("Pivot change", w);
  1121. w.pivot = pivot;
  1122. }
  1123. }
  1124. protected override void OnDrawFinalProperties ()
  1125. {
  1126. if (mAnchorType == AnchorType.Advanced || !mWidget.isAnchored) return;
  1127. SerializedProperty sp = serializedObject.FindProperty("leftAnchor.target");
  1128. if (!IsRect(sp))
  1129. {
  1130. GUILayout.Space(3f);
  1131. GUILayout.BeginHorizontal();
  1132. GUILayout.Space(6f);
  1133. NGUIEditorTools.DrawProperty("", serializedObject, "hideIfOffScreen", GUILayout.Width(18f));
  1134. GUILayout.Label("Hide if off-screen", GUILayout.MinWidth(20f));
  1135. GUILayout.EndHorizontal();
  1136. }
  1137. }
  1138. }

NGUI 源码分析- UIWidgetInspector的更多相关文章

  1. NGUI 源码分析- AnchorPoint

    AnchorPoint 是 UIRect 的一个内部类,此处规定作为基准的那个对象称为锚点对象,基准对象对应的矩形框称为目标框,当前对象对应的矩形框称为源框. public class AnchorP ...

  2. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  3. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  4. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  5. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  6. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  7. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  8. java使用websocket,并且获取HttpSession,源码分析

    转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...

  9. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

随机推荐

  1. [ch04-01] 用最小二乘法解决线性回归问题

    系列博客,原文在笔者所维护的github上:https://aka.ms/beginnerAI, 点击star加星不要吝啬,星越多笔者越努力. 4.1 最小二乘法 4.1.1 历史 最小二乘法,也叫做 ...

  2. Caused by: java.util.zip.ZipException: zip file is empty

    1.问题描述:mybranch分支代码和master分支的代码一模一样,mybranch代码部署到服务器上没有任何问题,而master代码部署到服务器上运行不起来. 2.解决办法: (1)登陆服务器启 ...

  3. Linux进阶文档丨阿里架构师十年Linux心得,全在这份文档里面

    Linux是什么 Linux就是个操作系统: 它和Windows XP.Windows 7.Windows 10什么的一样就是一个操作系统而已! Linux能干什么: 它能当服务器,服务器上安装者各种 ...

  4. SpringBoot源码学习系列之嵌入式Servlet容器

    目录 1.博客前言简单介绍 2.定制servlet容器 3.变换servlet容器 4.servlet容器启动原理 SpringBoot源码学习系列之嵌入式Servlet容器启动原理 @ 1.博客前言 ...

  5. 十一次作业——LL(1)文法的判断,递归下降分析程序

    1. 文法 G(S): (1)S -> AB (2)A ->Da|ε (3)B -> cC (4)C -> aADC |ε (5)D -> b|ε 验证文法 G(S)是不 ...

  6. css重置样式

    <style> html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, ...

  7. Dict.setdefault()

    """ setdefault方法参数输入已有键,返回对应值,找不到已有键,创建新键,值为None """ >>> dict ...

  8. windows下利用iis建立网站网站并实现局域共享

    博客园 首页 新随笔 联系 管理 订阅 随笔- 54  文章- 9  评论- 0  Windows下利用IIS建立网站并实现局域网共享 https://blog.csdn.net/qq_4148541 ...

  9. luogu P1044 栈

    题目背景 栈是计算机中经典的数据结构,简单的说,栈就是限制在一端进行插入删除操作的线性表. 栈有两种最重要的操作,即poppop(从栈顶弹出一个元素)和pushpush(将一个元素进栈). 栈的重要性 ...

  10. [TimLinux] JavaScript 元素动态显示

    1. css的opacity属性 这个属性用于:设置元素的不透明级别,取值范围:从 0.0 (完全透明)到 1.0(完全不透明),元素所在的文本流还在.这个属性的动态变化可以用来设置元素的淡入淡出效果 ...