/// <summary> /// Returns whether the specified widget is visible by the panel. /// </summary> public bool IsVisible(NGUIWidget w) { if (mAlpha < 0.001f) { return(false); } if (!w.enabled || !NGUITools.GetActive(w.gameObject) || w.alpha < 0.001f) { return(false); } // No clipping? No point in checking. if (mClipping == NGUIDrawCall.Clipping.None) { return(true); } Vector2 size = w.relativeSize; Vector2 a = Vector2.Scale(w.pivotOffset, size); Vector2 b = a; a.x += size.x; a.y -= size.y; // Transform coordinates into world space Transform wt = w.cachedTransform; Vector3 v0 = wt.TransformPoint(a); Vector3 v1 = wt.TransformPoint(new Vector2(a.x, b.y)); Vector3 v2 = wt.TransformPoint(new Vector2(b.x, a.y)); Vector3 v3 = wt.TransformPoint(b); return(IsVisible(v0, v1, v2, v3)); }
/// <summary> /// Helper function that causes the widget to smoothly fade in. /// </summary> void AnimateColor(NGUIWidget widget) { Color c = widget.color; widget.color = new Color(c.r, c.g, c.b, 0f); TweenColor.Begin(widget.gameObject, animSpeed, c).method = NGUITweener.Method.EaseOut; }
/// <summary> /// Initialize the cached values. /// </summary> void Init() { mInitDone = true; if (foreground != null) { mFGWidget = foreground.GetComponent <NGUIWidget>(); mFGFilled = (mFGWidget != null) ? mFGWidget as NGUISprite : null; mFGTrans = foreground.transform; if (mSize == Vector2.zero) { mSize = foreground.localScale; } if (mCenter == Vector2.zero) { mCenter = foreground.localPosition + foreground.localScale * 0.5f; } } else if (mCol != null) { if (mSize == Vector2.zero) { mSize = mCol.size; } if (mCenter == Vector2.zero) { mCenter = mCol.center; } } else { Debug.LogWarning("NGUISlider expected to find a foreground object or a box collider to work with", this); } }
/// <summary> /// Add the specified widget to the managed list. /// </summary> public void AddWidget(NGUIWidget w) { if (w != null) { #if UNITY_EDITOR if (w.cachedTransform.parent != null) { NGUIWidget parentWidget = NGUITools.FindInParents <NGUIWidget>(w.cachedTransform.parent.gameObject); if (parentWidget != null) { w.cachedTransform.parent = parentWidget.cachedTransform.parent; Debug.LogError("You should never nest widgets! Parent them to a common game object instead. Forcefully changing the parent.", w); // If the error above gets triggered, it means that you parented one widget to another. // If left unchecked, this may lead to odd behavior in the UI. Consider restructuring your UI. // For example, if you were trying to do this: // Widget #1 // | // +- Widget #2 // You can do this instead, fixing the problem: // GameObject (scale 1, 1, 1) // | // +- Widget #1 // | // +- Widget #2 } } #endif NGUINode node = AddTransform(w.cachedTransform); if (node != null) { node.widget = w; w.visibleFlag = 1; if (!mWidgets.Contains(w)) { mWidgets.Add(w); if (!mChanged.Contains(w.material)) { mChanged.Add(w.material); mChangedLastFrame = true; } mDepthChanged = true; mWidgetsAdded = true; } } else { Debug.LogError("Unable to find an appropriate root for " + NGUITools.GetHierarchy(w.gameObject) + "\nPlease make sure that there is at least one game object above this widget!", w.gameObject); } } }
/// <summary> /// Raycast into the screen, returning an array of widgets. /// </summary> static NGUIWidget[] Raycast(NGUIWidget widget, Vector2 mousePos) { GameObject root = widget.gameObject; NGUIPanel panel = NGUITools.FindInParents <NGUIPanel>(root); return((panel != null) ? NGUIEditorTools.Raycast(panel, mousePos) : new NGUIWidget[] {}); }
/// <summary> /// Find all needed components. /// </summary> void Awake() { mPanel = GetComponent <NGUIPanel>(); if (mPanel == null) { mWidget = GetComponentInChildren <NGUIWidget>(); } }
/// <summary> /// Set the alpha of all widgets. /// </summary> void SetAlpha(float val) { for (int i = 0, imax = mWidgets.Length; i < imax; ++i) { NGUIWidget w = mWidgets[i]; Color c = w.color; c.a = val; w.color = c; } }
/// <summary> /// Helper function that causes the widget to smoothly move into position. /// </summary> void AnimatePosition(NGUIWidget widget, bool placeAbove, float bottom) { Vector3 target = widget.cachedTransform.localPosition; Vector3 start = placeAbove ? new Vector3(target.x, bottom, target.z) : new Vector3(target.x, 0f, target.z); widget.cachedTransform.localPosition = start; GameObject go = widget.gameObject; TweenPosition.Begin(go, animSpeed, target).method = NGUITweener.Method.EaseOut; }
/// <summary> /// Find all needed components. /// </summary> void Awake() { mWidget = GetComponentInChildren <NGUIWidget>(); Renderer ren = renderer; if (ren != null) { mMat = ren.material; } mLight = light; }
/// <summary> /// Static widget comparison function used for Z-sorting. /// </summary> static public int CompareFunc(NGUIWidget left, NGUIWidget right) { if (left.mDepth > right.mDepth) { return(1); } if (left.mDepth < right.mDepth) { return(-1); } return(0); }
/// <summary> /// Get a list of widgets managed by the specified transform's children. /// </summary> static void GetWidgets(Transform t, List <NGUIWidget> widgets) { for (int i = 0; i < t.childCount; ++i) { Transform child = t.GetChild(i); NGUIWidget w = child.GetComponent <NGUIWidget>(); if (w != null) { widgets.Add(w); } else if (child.GetComponent <NGUIPanel>() == null) { GetWidgets(child, widgets); } } }
/// <summary> /// Calculate the combined bounds of all widgets attached to the specified game object or its children (in world space). /// </summary> static public Bounds CalculateAbsoluteWidgetBounds(Transform trans) { NGUIWidget[] widgets = trans.GetComponentsInChildren <NGUIWidget>() as NGUIWidget[]; if (widgets.Length == 0) { return(new Bounds(trans.position, Vector3.zero)); } Vector3 vMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); Vector3 vMax = new Vector3(float.MinValue, float.MinValue, float.MinValue); Vector3 v; for (int i = 0, imax = widgets.Length; i < imax; ++i) { NGUIWidget w = widgets[i]; Vector2 size = w.relativeSize; Vector2 offset = w.pivotOffset; float x = (offset.x + 0.5f) * size.x; float y = (offset.y - 0.5f) * size.y; size *= 0.5f; Transform wt = w.cachedTransform; v = wt.TransformPoint(new Vector3(x - size.x, y - size.y, 0f)); vMax = Vector3.Max(v, vMax); vMin = Vector3.Min(v, vMin); v = wt.TransformPoint(new Vector3(x - size.x, y + size.y, 0f)); vMax = Vector3.Max(v, vMax); vMin = Vector3.Min(v, vMin); v = wt.TransformPoint(new Vector3(x + size.x, y - size.y, 0f)); vMax = Vector3.Max(v, vMax); vMin = Vector3.Min(v, vMin); v = wt.TransformPoint(new Vector3(x + size.x, y + size.y, 0f)); vMax = Vector3.Max(v, vMax); vMin = Vector3.Min(v, vMin); } Bounds b = new Bounds(vMin, Vector3.zero); b.Encapsulate(vMax); return(b); }
/// <summary> /// Helper function that causes the widget to smoothly grow until it reaches its original size. /// </summary> void AnimateScale(NGUIWidget widget, bool placeAbove, float bottom) { GameObject go = widget.gameObject; Transform t = widget.cachedTransform; float minSize = font.size * textScale + mBgBorder * 2f; Vector3 scale = t.localScale; t.localScale = new Vector3(scale.x, minSize, scale.z); TweenScale.Begin(go, animSpeed, scale).method = NGUITweener.Method.EaseOut; if (placeAbove) { Vector3 pos = t.localPosition; t.localPosition = new Vector3(pos.x, pos.y - scale.y + minSize, pos.z); TweenPosition.Begin(go, animSpeed, pos).method = NGUITweener.Method.EaseOut; } }
/// <summary> /// Make the specified selection pixel-perfect. /// </summary> static public void MakePixelPerfect(Transform t) { NGUIWidget w = t.GetComponent <NGUIWidget>(); if (w != null) { w.MakePixelPerfect(); } else { t.localPosition = Round(t.localPosition); t.localScale = Round(t.localScale); for (int i = 0, imax = t.childCount; i < imax; ++i) { MakePixelPerfect(t.GetChild(i)); } } }
protected void Init() { if (tweenTarget == null) { tweenTarget = gameObject; } NGUIWidget widget = tweenTarget.GetComponent <NGUIWidget>(); if (widget != null) { mColor = widget.color; } else { Renderer ren = tweenTarget.renderer; if (ren != null) { mColor = ren.material.color; } else { Light lt = tweenTarget.light; if (lt != null) { mColor = lt.color; } else { Debug.LogWarning(NGUITools.GetHierarchy(gameObject) + " has nothing for NGUIButtonColor to color", this); enabled = false; } } } OnEnable(); mDefaultColor = mColor; duration = Mathf.Clamp(duration, 0.001f, duration); }
/// <summary> /// Draw the inspector widget. /// </summary> public override void OnInspectorGUI() { EditorGUIUtility.LookLikeControls(80f); mWidget = target as NGUIWidget; if (!mInitialized) { mInitialized = true; OnInit(); } //NGUIEditorTools.DrawSeparator(); EditorGUILayout.Space(); // Check to see if we can draw the widget's default properties to begin with if (DrawProperties()) { // Draw all common properties next DrawCommonProperties(); DrawExtraProperties(); } }
/// <summary> /// Calculate the 4 corners of a widget taking padding into consideration. /// </summary> static public Vector3[] CalculateWidgetCorners(NGUIWidget w) { Vector2 size = w.relativeSize; Vector2 offset = w.pivotOffset; Vector4 padding = w.relativePadding; float x0 = offset.x * size.x - padding.x; float y0 = offset.y * size.y + padding.y; float x1 = x0 + size.x + padding.x + padding.z; float y1 = y0 - size.y - padding.y - padding.w; Transform wt = w.cachedTransform; return(new Vector3[] { wt.TransformPoint(x0, y0, 0f), wt.TransformPoint(x0, y1, 0f), wt.TransformPoint(x1, y1, 0f), wt.TransformPoint(x1, y0, 0f) }); }
/// <summary> /// Remove the specified widget from the managed list. /// </summary> public void RemoveWidget(NGUIWidget w) { if (w != null) { // Do we have this node? Mark the widget's material as having been changed NGUINode pc = GetNode(w.cachedTransform); if (pc != null) { // Mark the material as having been changed if (pc.visibleFlag == 1 && !mChanged.Contains(w.material)) { mChanged.Add(w.material); mChangedLastFrame = true; } // Remove this transform RemoveTransform(w.cachedTransform); } mWidgets.Remove(w); } }
/// <summary> /// Raycast into the specified panel, returning a list of widgets. /// </summary> static public NGUIWidget[] Raycast(NGUIPanel panel, Vector2 mousePos) { List <NGUIWidget> list = new List <NGUIWidget>(); NGUIWidget[] widgets = panel.gameObject.GetComponentsInChildren <NGUIWidget>(); for (int i = 0; i < widgets.Length; ++i) { NGUIWidget w = widgets[i]; if (w.panel == panel) { Vector3[] corners = NGUIMath.CalculateWidgetCorners(w); if (DistanceToRectangle(corners, mousePos) == 0f) { list.Add(w); } } } list.Sort(delegate(NGUIWidget w1, NGUIWidget w2) { return(w2.depth.CompareTo(w1.depth)); }); return(list.ToArray()); }
/// <summary> /// Get rid of the popup dialog when the selection gets lost. /// </summary> void OnSelect(bool isSelected) { if (!isSelected && mChild != null) { mLabelList.Clear(); handleEvents = false; if (isAnimated) { NGUIWidget[] widgets = mChild.GetComponentsInChildren <NGUIWidget>(); for (int i = 0, imax = widgets.Length; i < imax; ++i) { NGUIWidget w = widgets[i]; Color c = w.color; c.a = 0f; TweenColor.Begin(w.gameObject, animSpeed, c).method = NGUITweener.Method.EaseOut; } Collider[] cols = mChild.GetComponentsInChildren <Collider>(); for (int i = 0, imax = cols.Length; i < imax; ++i) { cols[i].enabled = false; } UpdateManager.AddDestroy(mChild, animSpeed); } else { Destroy(mChild); } mBackground = null; mHighlight = null; mChild = null; } }
/// <summary> /// Force-localize the widget. /// </summary> public void Localize() { Localization loc = Localization.instance; NGUIWidget w = GetComponent <NGUIWidget>(); NGUILabel lbl = w as NGUILabel; NGUISprite sp = w as NGUISprite; // If no localization key has been specified, use the label's text as the key if (string.IsNullOrEmpty(mLanguage) && string.IsNullOrEmpty(key) && lbl != null) { key = lbl.text; } // If we still don't have a key, leave the value as blank string val = string.IsNullOrEmpty(key) ? "" : loc.Get(key); if (lbl != null) { // If this is a label used by input, we should localize its default value instead NGUIInput input = NGUITools.FindInParents <NGUIInput>(lbl.gameObject); if (input != null && input.label == lbl) { input.defaultText = val; } else { lbl.text = val; } } else if (sp != null) { sp.spriteName = val; sp.MakePixelPerfect(); } mLanguage = loc.currentLanguage; }
/// <summary> /// Convenience function that figures out the panel's correct change flag by searching the parents. /// </summary> int GetChangeFlag(NGUINode start) { int flag = start.changeFlag; if (flag == -1) { Transform trans = start.trans.parent; NGUINode sub; // Keep going until we find a set flag for (;;) { // Check the parent's flag #if USE_SIMPLE_DICTIONARY if (trans != null && mChildren.TryGetValue(trans, out sub)) { #else if (trans != null && mChildren.Contains(trans)) { sub = (NGUINode)mChildren[trans]; #endif flag = sub.changeFlag; trans = trans.parent; // If the flag hasn't been set either, add this child to the hierarchy if (flag == -1) { mHierarchy.Add(sub); } else { break; } } else { flag = 0; break; } } // Update the parent flags for (int i = 0, imax = mHierarchy.size; i < imax; ++i) { NGUINode pc = mHierarchy.buffer[i]; pc.changeFlag = flag; } mHierarchy.Clear(); } return(flag); } /// <summary> /// Update the world-to-local transform matrix as well as clipping bounds. /// </summary> void UpdateTransformMatrix() { if (mUpdateTime == 0f || mMatrixTime != mUpdateTime) { mMatrixTime = mUpdateTime; mWorldToLocal = cachedTransform.worldToLocalMatrix; if (mClipping != NGUIDrawCall.Clipping.None) { Vector2 size = new Vector2(mClipRange.z, mClipRange.w); if (size.x == 0f) { size.x = (mCam == null) ? Screen.width : mCam.pixelWidth; } if (size.y == 0f) { size.y = (mCam == null) ? Screen.height : mCam.pixelHeight; } size *= 0.5f; mMin.x = mClipRange.x - size.x; mMin.y = mClipRange.y - size.y; mMax.x = mClipRange.x + size.x; mMax.y = mClipRange.y + size.y; } } } /// <summary> /// Run through all managed transforms and see if they've changed. /// </summary> void UpdateTransforms() { mChangedLastFrame = false; bool transformsChanged = false; bool shouldCull = false; #if UNITY_EDITOR shouldCull = (clipping != NGUIDrawCall.Clipping.None) && (!Application.isPlaying || mUpdateTime > mCullTime); if (!Application.isPlaying || !widgetsAreStatic || mWidgetsAdded || shouldCull != mCulled) #else shouldCull = (clipping != NGUIDrawCall.Clipping.None) && (mUpdateTime > mCullTime); if (!widgetsAreStatic || mWidgetsAdded || shouldCull != mCulled) #endif { #if USE_SIMPLE_DICTIONARY foreach (KeyValuePair <Transform, NGUINode> child in mChildren) { NGUINode node = child.Value; #else for (int i = 0, imax = mChildren.Count; i < imax; ++i) { NGUINode node = (NGUINode)mChildren[i]; #endif if (node.trans == null) { mRemoved.Add(node.trans); continue; } if (node.HasChanged()) { node.changeFlag = 1; transformsChanged = true; #if UNITY_EDITOR Vector3 s = node.trans.lossyScale; float min = Mathf.Abs(Mathf.Min(s.x, s.y)); if (min == 0f) { Debug.LogError("Scale of 0 is invalid! Zero cannot be divided by, which causes problems. Use a small value instead, such as 0.01\n" + node.trans.lossyScale, node.trans); } #endif } else { node.changeFlag = -1; } } // Clean up the deleted transforms for (int i = 0, imax = mRemoved.Count; i < imax; ++i) { mChildren.Remove(mRemoved[i]); } mRemoved.Clear(); } // If the children weren't culled but should be, check their visibility if (!mCulled && shouldCull) { mCheckVisibility = true; } // If something has changed, propagate the changes *down* the tree hierarchy (to children). // An alternative (but slower) approach would be to do a pc.trans.GetComponentsInChildren<NGUIWidget>() // in the loop above, and mark each one as dirty. if (mCheckVisibility || transformsChanged || mRebuildAll) { #if USE_SIMPLE_DICTIONARY foreach (KeyValuePair <Transform, NGUINode> child in mChildren) { NGUINode pc = child.Value; #else for (int i = 0, imax = mChildren.Count; i < imax; ++i) { NGUINode pc = (NGUINode)mChildren[i]; #endif if (pc.widget != null) { int visibleFlag = 1; // No sense in checking the visibility if we're not culling anything (as the visibility is always 'true') if (shouldCull || transformsChanged) { // If the change flag has not yet been determined... if (pc.changeFlag == -1) { pc.changeFlag = GetChangeFlag(pc); } // Is the widget visible? if (shouldCull) { visibleFlag = (mCheckVisibility || pc.changeFlag == 1) ? (IsVisible(pc.widget) ? 1 : 0) : pc.visibleFlag; } } // If visibility changed, mark the node as changed as well if (pc.visibleFlag != visibleFlag) { pc.changeFlag = 1; } // If the node has changed and the widget is visible (or was visible before) if (pc.changeFlag == 1 && (visibleFlag == 1 || pc.visibleFlag != 0)) { // Update the visibility flag pc.visibleFlag = visibleFlag; Material mat = pc.widget.material; // Add this material to the list of changed materials if (!mChanged.Contains(mat)) { mChanged.Add(mat); mChangedLastFrame = true; } } } } } mCulled = shouldCull; mCheckVisibility = false; mWidgetsAdded = false; } /// <summary> /// Update all widgets and rebuild their geometry if necessary. /// </summary> void UpdateWidgets() { #if USE_SIMPLE_DICTIONARY foreach (KeyValuePair <Transform, NGUINode> c in mChildren) { NGUINode pc = c.Value; #else for (int i = 0, imax = mChildren.Count; i < imax; ++i) { NGUINode pc = (NGUINode)mChildren[i]; #endif NGUIWidget w = pc.widget; // If the widget is visible, update it if (pc.visibleFlag == 1 && w != null && w.UpdateGeometry(this, ref mWorldToLocal, (pc.changeFlag == 1), generateNormals)) { // We will need to refill this buffer if (!mChanged.Contains(w.material)) { mChanged.Add(w.material); mChangedLastFrame = true; } } pc.changeFlag = 0; } } /// <summary> /// Update the clipping rect in the shaders and draw calls' positions. /// </summary> public void UpdateDrawcalls() { Vector4 range = Vector4.zero; if (mClipping != NGUIDrawCall.Clipping.None) { range = new Vector4(mClipRange.x, mClipRange.y, mClipRange.z * 0.5f, mClipRange.w * 0.5f); } if (range.z == 0f) { range.z = Screen.width * 0.5f; } if (range.w == 0f) { range.w = Screen.height * 0.5f; } RuntimePlatform platform = Application.platform; if (platform == RuntimePlatform.WindowsPlayer || platform == RuntimePlatform.WindowsWebPlayer || platform == RuntimePlatform.WindowsEditor) { range.x -= 0.5f; range.y += 0.5f; } Transform t = cachedTransform; for (int i = 0, imax = mDrawCalls.size; i < imax; ++i) { NGUIDrawCall dc = mDrawCalls.buffer[i]; dc.clipping = mClipping; dc.clipRange = range; dc.clipSoftness = mClipSoftness; dc.depthPass = depthPass && mClipping == NGUIDrawCall.Clipping.None; // Set the draw call's transform to match the panel's. // Note that parenting directly to the panel causes unity to crash as soon as you hit Play. Transform dt = dc.transform; dt.position = t.position; dt.rotation = t.rotation; dt.localScale = t.lossyScale; } } /// <summary> /// Set the draw call's geometry responsible for the specified material. /// </summary> void Fill(Material mat) { // Cleanup deleted widgets for (int i = mWidgets.size; i > 0;) { if (mWidgets[--i] == null) { mWidgets.RemoveAt(i); } } // Fill the buffers for the specified material for (int i = 0, imax = mWidgets.size; i < imax; ++i) { NGUIWidget w = mWidgets.buffer[i]; if (w.visibleFlag == 1 && w.material == mat) { NGUINode node = GetNode(w.cachedTransform); if (node != null) { if (generateNormals) { w.WriteToBuffers(mVerts, mUvs, mCols, mNorms, mTans); } else { w.WriteToBuffers(mVerts, mUvs, mCols, null, null); } } else { Debug.LogError("No transform found for " + NGUITools.GetHierarchy(w.gameObject), this); } } } if (mVerts.size > 0) { // Rebuild the draw call's mesh NGUIDrawCall dc = GetDrawCall(mat, true); dc.depthPass = depthPass && mClipping == NGUIDrawCall.Clipping.None; dc.Set(mVerts, generateNormals ? mNorms : null, generateNormals ? mTans : null, mUvs, mCols); } else { // There is nothing to draw for this material -- eliminate the draw call NGUIDrawCall dc = GetDrawCall(mat, false); if (dc != null) { mDrawCalls.Remove(dc); NGUITools.DestroyImmediate(dc.gameObject); } } // Cleanup mVerts.Clear(); mNorms.Clear(); mTans.Clear(); mUvs.Clear(); mCols.Clear(); } /// <summary> /// Main update function /// </summary> void LateUpdate() { mUpdateTime = Time.realtimeSinceStartup; UpdateTransformMatrix(); UpdateTransforms(); // Always move widgets to the panel's layer if (mLayer != gameObject.layer) { mLayer = gameObject.layer; NGUICamera uic = NGUICamera.FindCameraForLayer(mLayer); mCam = (uic != null) ? uic.cachedCamera : NGUITools.FindCameraForLayer(mLayer); SetChildLayer(cachedTransform, mLayer); var cache = drawCalls; for (int i = 0, imax = cache.size; i < imax; ++i) { mDrawCalls.buffer[i].gameObject.layer = mLayer; } } UpdateWidgets(); // If the depth has changed, we need to re-sort the widgets if (mDepthChanged) { mDepthChanged = false; mWidgets.Sort(NGUIWidget.CompareFunc); } var dcInit = drawCalls; // Fill the draw calls for all of the changed materials for (int i = 0, imax = mChanged.size; i < imax; ++i) { Fill(mChanged.buffer[i]); } // Update the clipping rects UpdateDrawcalls(); mChanged.Clear(); mRebuildAll = false; #if UNITY_EDITOR mScreenSize = new Vector2(Screen.width, Screen.height); #endif }
static bool IsLeft(NGUIWidget.Pivot pivot) { return pivot == NGUIWidget.Pivot.Left || pivot == NGUIWidget.Pivot.TopLeft || pivot == NGUIWidget.Pivot.BottomLeft; }
/// <summary> /// Find all needed components. /// </summary> void Awake() { mPanel = GetComponent<NGUIPanel>(); if (mPanel == null) mWidget = GetComponentInChildren<NGUIWidget>(); }
/// <summary> /// Draw a toggle button for the pivot point. /// </summary> void Toggle(string text, string style, NGUIWidget.Pivot pivot, bool isHorizontal) { bool isActive = false; switch (pivot) { case NGUIWidget.Pivot.Left: isActive = IsLeft(mWidget.pivot); break; case NGUIWidget.Pivot.Right: isActive = IsRight(mWidget.pivot); break; case NGUIWidget.Pivot.Top: isActive = IsTop(mWidget.pivot); break; case NGUIWidget.Pivot.Bottom: isActive = IsBottom(mWidget.pivot); break; case NGUIWidget.Pivot.Center: isActive = isHorizontal ? pivot == GetHorizontal(mWidget.pivot) : pivot == GetVertical(mWidget.pivot); break; } if (GUILayout.Toggle(isActive, text, style) != isActive) SetPivot(pivot, isHorizontal); }
void Awake() { mWidget = GetComponent<NGUIWidget>(); mPanel = GetComponent<NGUIPanel>(); Update(); }
/// <summary> /// Adjust the transform's position and scale. /// </summary> static void AdjustPosAndScale(NGUIWidget w, Vector3 startLocalPos, Vector3 startLocalScale, Vector3 worldDelta, NGUIWidget.Pivot dragPivot) { Transform t = w.cachedTransform; Transform parent = t.parent; Matrix4x4 parentToLocal = (parent != null) ? t.parent.worldToLocalMatrix : Matrix4x4.identity; Matrix4x4 worldToLocal = parentToLocal; Quaternion invRot = Quaternion.Inverse(t.localRotation); worldToLocal = worldToLocal * Matrix4x4.TRS(Vector3.zero, invRot, Vector3.one); Vector3 localDelta = worldToLocal.MultiplyVector(worldDelta); bool canBeSquare = false; float left = 0f; float right = 0f; float top = 0f; float bottom = 0f; switch (dragPivot) { case NGUIWidget.Pivot.TopLeft: canBeSquare = (w.pivot == NGUIWidget.Pivot.BottomRight); left = localDelta.x; top = localDelta.y; break; case NGUIWidget.Pivot.Left: left = localDelta.x; break; case NGUIWidget.Pivot.BottomLeft: canBeSquare = (w.pivot == NGUIWidget.Pivot.TopRight); left = localDelta.x; bottom = localDelta.y; break; case NGUIWidget.Pivot.Top: top = localDelta.y; break; case NGUIWidget.Pivot.Bottom: bottom = localDelta.y; break; case NGUIWidget.Pivot.TopRight: canBeSquare = (w.pivot == NGUIWidget.Pivot.BottomLeft); right = localDelta.x; top = localDelta.y; break; case NGUIWidget.Pivot.Right: right = localDelta.x; break; case NGUIWidget.Pivot.BottomRight: canBeSquare = (w.pivot == NGUIWidget.Pivot.TopLeft); right = localDelta.x; bottom = localDelta.y; break; } AdjustWidget(w, startLocalPos, startLocalScale, left, top, right, bottom, canBeSquare && Event.current.modifiers == EventModifiers.Shift); }
/// <summary> /// Raycast into the screen, returning an array of widgets. /// </summary> static NGUIWidget[] Raycast(NGUIWidget widget, Vector2 mousePos) { GameObject root = widget.gameObject; NGUIPanel panel = NGUITools.FindInParents<NGUIPanel>(root); return (panel != null) ? NGUIEditorTools.Raycast(panel, mousePos) : new NGUIWidget[] {}; }
/// <summary> /// Draw the on-screen selection, knobs, and handle all interaction logic. /// </summary> public void OnSceneGUI() { if (!EditorPrefs.GetBool("New GUI", true)) return; if (Tools.current != Tool.View) return; mWidget = target as NGUIWidget; Handles.color = mOutlineColor; Transform t = mWidget.cachedTransform; Event e = Event.current; int id = GUIUtility.GetControlID(s_Hash, FocusType.Passive); EventType type = e.GetTypeForControl(id); Vector3[] corners = NGUIMath.CalculateWidgetCorners(mWidget); Handles.DrawLine(corners[0], corners[1]); Handles.DrawLine(corners[1], corners[2]); Handles.DrawLine(corners[2], corners[3]); Handles.DrawLine(corners[0], corners[3]); Vector3[] worldPos = new Vector3[8]; worldPos[0] = corners[0]; worldPos[1] = corners[1]; worldPos[2] = corners[2]; worldPos[3] = corners[3]; worldPos[4] = (corners[0] + corners[1]) * 0.5f; worldPos[5] = (corners[1] + corners[2]) * 0.5f; worldPos[6] = (corners[2] + corners[3]) * 0.5f; worldPos[7] = (corners[0] + corners[3]) * 0.5f; Vector2[] screenPos = new Vector2[8]; for (int i = 0; i < 8; ++i) screenPos[i] = HandleUtility.WorldToGUIPoint(worldPos[i]); Bounds b = new Bounds(screenPos[0], Vector3.zero); for (int i = 1; i < 8; ++i) b.Encapsulate(screenPos[i]); // Time to figure out what kind of action is underneath the mouse Action actionUnderMouse = mAction; NGUIWidget.Pivot pivotUnderMouse = NGUIWidget.Pivot.Center; if (actionUnderMouse == Action.None) { int index = 0; float dist = GetScreenDistance(worldPos, e.mousePosition, out index); if (dist < 10f) { pivotUnderMouse = mPivots[index]; actionUnderMouse = Action.Scale; } else if (e.modifiers == 0 && NGUIEditorTools.DistanceToRectangle(corners, e.mousePosition) == 0f) { actionUnderMouse = Action.Move; } else if (dist < 30f) { actionUnderMouse = Action.Rotate; } } // Change the mouse cursor to a more appropriate one #if !UNITY_3_5 { Vector2 min = b.min; Vector2 max = b.max; min.x -= 30f; max.x += 30f; min.y -= 30f; max.y += 30f; Rect rect = new Rect(min.x, min.y, max.x - min.x, max.y - min.y); if (actionUnderMouse == Action.Rotate) { SetCursorRect(rect, MouseCursor.RotateArrow); } else if (actionUnderMouse == Action.Move) { SetCursorRect(rect, MouseCursor.MoveArrow); } else if (actionUnderMouse == Action.Scale) { SetCursorRect(rect, MouseCursor.ScaleArrow); } else SetCursorRect(rect, MouseCursor.Arrow); } #endif switch (type) { case EventType.Repaint: { Handles.BeginGUI(); { for (int i = 0; i < 8; ++i) { DrawKnob(worldPos[i], mWidget.pivot == mPivots[i], id); } } Handles.EndGUI(); } break; case EventType.MouseDown: { mStartMouse = e.mousePosition; mAllowSelection = true; if (e.button == 1) { if (e.modifiers == 0) { GUIUtility.hotControl = GUIUtility.keyboardControl = id; e.Use(); } } else if (e.button == 0 && actionUnderMouse != Action.None && Raycast(corners, out mStartDrag)) { mStartPos = t.position; mStartRot = t.localRotation.eulerAngles; mStartDir = mStartDrag - t.position; mStartScale = t.localScale; mDragPivot = pivotUnderMouse; mActionUnderMouse = actionUnderMouse; GUIUtility.hotControl = GUIUtility.keyboardControl = id; e.Use(); } } break; case EventType.MouseDrag: { // Prevent selection once the drag operation begins bool dragStarted = (e.mousePosition - mStartMouse).magnitude > 3f; if (dragStarted) mAllowSelection = false; if (GUIUtility.hotControl == id) { e.Use(); if (mAction != Action.None || mActionUnderMouse != Action.None) { Vector3 pos; if (Raycast(corners, out pos)) { if (mAction == Action.None && mActionUnderMouse != Action.None) { // Wait until the mouse moves by more than a few pixels if (dragStarted) { if (mActionUnderMouse == Action.Move) { mStartPos = t.position; NGUIEditorTools.RegisterUndo("Move widget", t); } else if (mActionUnderMouse == Action.Rotate) { mStartRot = t.localRotation.eulerAngles; mStartDir = mStartDrag - t.position; NGUIEditorTools.RegisterUndo("Rotate widget", t); } else if (mActionUnderMouse == Action.Scale) { mStartPos = t.localPosition; mStartScale = t.localScale; mDragPivot = pivotUnderMouse; NGUIEditorTools.RegisterUndo("Scale widget", t); } mAction = actionUnderMouse; } } if (mAction != Action.None) { if (mAction == Action.Move) { t.position = mStartPos + (pos - mStartDrag); pos = t.localPosition; pos.x = Mathf.RoundToInt(pos.x); pos.y = Mathf.RoundToInt(pos.y); t.localPosition = pos; } else if (mAction == Action.Rotate) { Vector3 dir = pos - t.position; float angle = Vector3.Angle(mStartDir, dir); if (angle > 0f) { float dot = Vector3.Dot(Vector3.Cross(mStartDir, dir), t.forward); if (dot < 0f) angle = -angle; angle = mStartRot.z + angle; if (e.modifiers != EventModifiers.Shift) angle = Mathf.Round(angle / 15f) * 15f; else angle = Mathf.Round(angle); t.localRotation = Quaternion.Euler(mStartRot.x, mStartRot.y, angle); } } else if (mAction == Action.Scale) { // World-space delta since the drag started Vector3 delta = pos - mStartDrag; // Adjust the widget's position and scale based on the delta, restricted by the pivot AdjustPosAndScale(mWidget, mStartPos, mStartScale, delta, mDragPivot); } } } } } } break; case EventType.MouseUp: { if (GUIUtility.hotControl == id) { GUIUtility.hotControl = 0; GUIUtility.keyboardControl = 0; if (e.button < 2) { bool handled = false; if (e.button == 1) { // Right-click: Select the widget below NGUIWidget last = null; NGUIWidget[] widgets = Raycast(mWidget, e.mousePosition); for (int i = widgets.Length; i > 0; ) { NGUIWidget w = widgets[--i]; if (w == mWidget) break; last = w; } if (last != null) { Selection.activeGameObject = last.gameObject; handled = true; } } else if (mAction == Action.None) { if (mAllowSelection) { // Left-click: Select the widget above NGUIWidget last = null; NGUIWidget[] widgets = Raycast(mWidget, e.mousePosition); if (widgets.Length > 0) { for (int i = 0; i < widgets.Length; ++i) { NGUIWidget w = widgets[i]; if (w == mWidget) { if (last != null) Selection.activeGameObject = last.gameObject; handled = true; break; } last = w; } if (!handled) { Selection.activeGameObject = widgets[0].gameObject; handled = true; } } } } else { // Finished dragging something mAction = Action.None; mActionUnderMouse = Action.None; Vector3 pos = t.localPosition; Vector3 scale = t.localScale; if (mWidget.pixelPerfectAfterResize) { t.localPosition = pos; t.localScale = scale; mWidget.MakePixelPerfect(); } else { pos.x = Mathf.Round(pos.x); pos.y = Mathf.Round(pos.y); scale.x = Mathf.Round(scale.x); scale.y = Mathf.Round(scale.y); t.localPosition = pos; t.localScale = scale; } handled = true; } if (handled) { mActionUnderMouse = Action.None; mAction = Action.None; e.Use(); } } } else if (mAllowSelection) { NGUIWidget[] widgets = Raycast(mWidget, e.mousePosition); if (widgets.Length > 0) Selection.activeGameObject = widgets[0].gameObject; } mAllowSelection = true; } break; case EventType.KeyDown: { if (e.keyCode == KeyCode.UpArrow) { Vector3 pos = t.localPosition; pos.y += 1f; t.localPosition = pos; e.Use(); } else if (e.keyCode == KeyCode.DownArrow) { Vector3 pos = t.localPosition; pos.y -= 1f; t.localPosition = pos; e.Use(); } else if (e.keyCode == KeyCode.LeftArrow) { Vector3 pos = t.localPosition; pos.x -= 1f; t.localPosition = pos; e.Use(); } else if (e.keyCode == KeyCode.RightArrow) { Vector3 pos = t.localPosition; pos.x += 1f; t.localPosition = pos; e.Use(); } else if (e.keyCode == KeyCode.Escape) { if (GUIUtility.hotControl == id) { if (mAction != Action.None) { if (mAction == Action.Move) { t.position = mStartPos; } else if (mAction == Action.Rotate) { t.localRotation = Quaternion.Euler(mStartRot); } else if (mAction == Action.Scale) { t.position = mStartPos; t.localScale = mStartScale; } } GUIUtility.hotControl = 0; GUIUtility.keyboardControl = 0; mActionUnderMouse = Action.None; mAction = Action.None; e.Use(); } else { Selection.activeGameObject = null; Tools.current = Tool.Move; } } } break; } }
/// <summary> /// Helper function used to animate widgets. /// </summary> void Animate(NGUIWidget widget, bool placeAbove, float bottom) { AnimateColor(widget); AnimatePosition(widget, placeAbove, bottom); }
private void Update() { _spriteDict.Clear(); _labelDict.Clear(); _textureDict.Clear(); var widgets = _prefab.GetComponentsInChildren <UIWidget>(true); foreach (var widget in widgets) { var nw = new NGUIWidget(widget); switch (GetUIWidgetType(widget)) { case WidgetType.Sprite: { if (nw.IsUISpriteEmpty()) { continue; } if (!_spriteDict.ContainsKey(nw.Sprite.atlas)) { _spriteDict[nw.Sprite.atlas] = new List <UISprite>(); } _spriteDict[nw.Sprite.atlas].Add(nw.Sprite); break; } case WidgetType.Label: { if (nw.IsUILabelEmpty()) { continue; } if (!_labelDict.ContainsKey(nw.Label.bitmapFont)) { _labelDict[nw.Label.bitmapFont] = new List <UILabel>(); } _labelDict[nw.Label.bitmapFont].Add(nw.Label); break; } case WidgetType.Texture: { if (nw.IsUITextureEmpty()) { continue; } if (!_textureDict.ContainsKey(nw.Texture.mainTexture)) { _textureDict[nw.Texture.mainTexture] = new List <UITexture>(); } _textureDict[nw.Texture.mainTexture].Add(nw.Texture); break; } } } }
/// <summary> /// Calculate the 4 corners of a widget taking padding into consideration. /// </summary> public static Vector3[] CalculateWidgetCorners(NGUIWidget w) { Vector2 size = w.relativeSize; Vector2 offset = w.pivotOffset; Vector4 padding = w.relativePadding; float x0 = offset.x * size.x - padding.x; float y0 = offset.y * size.y + padding.y; float x1 = x0 + size.x + padding.x + padding.z; float y1 = y0 - size.y - padding.y - padding.w; Transform wt = w.cachedTransform; return new Vector3[] { wt.TransformPoint(x0, y0, 0f), wt.TransformPoint(x0, y1, 0f), wt.TransformPoint(x1, y1, 0f), wt.TransformPoint(x1, y0, 0f) }; }
static bool IsRight(NGUIWidget.Pivot pivot) { return pivot == NGUIWidget.Pivot.Right || pivot == NGUIWidget.Pivot.TopRight || pivot == NGUIWidget.Pivot.BottomRight; }
/// <summary> /// Adjust the widget's rectangle based on the specified modifier values. /// </summary> static void AdjustWidget(NGUIWidget w, Vector3 pos, Vector3 scale, float left, float top, float right, float bottom, bool makeSquare) { Vector2 offset = w.pivotOffset; Vector4 padding = w.relativePadding; Vector2 size = w.relativeSize; offset.x -= padding.x; offset.y -= padding.y; size.x += padding.x + padding.z; size.y += padding.y + padding.w; scale.Scale(size); offset.y = -offset.y; Transform t = w.cachedTransform; Quaternion rot = t.localRotation; NGUIWidget.Pivot pivot = w.pivot; Vector2 rotatedTL = new Vector2(left, top); Vector2 rotatedTR = new Vector2(right, top); Vector2 rotatedBL = new Vector2(left, bottom); Vector2 rotatedBR = new Vector2(right, bottom); Vector2 rotatedL = new Vector2(left, 0f); Vector2 rotatedR = new Vector2(right, 0f); Vector2 rotatedT = new Vector2(0f, top); Vector2 rotatedB = new Vector2(0f, bottom); rotatedTL = rot * rotatedTL; rotatedTR = rot * rotatedTR; rotatedBL = rot * rotatedBL; rotatedBR = rot * rotatedBR; rotatedL = rot * rotatedL; rotatedR = rot * rotatedR; rotatedT = rot * rotatedT; rotatedB = rot * rotatedB; switch (pivot) { case NGUIWidget.Pivot.TopLeft: pos.x += rotatedTL.x; pos.y += rotatedTL.y; break; case NGUIWidget.Pivot.BottomRight: pos.x += rotatedBR.x; pos.y += rotatedBR.y; break; case NGUIWidget.Pivot.BottomLeft: pos.x += rotatedBL.x; pos.y += rotatedBL.y; break; case NGUIWidget.Pivot.TopRight: pos.x += rotatedTR.x; pos.y += rotatedTR.y; break; case NGUIWidget.Pivot.Left: pos.x += rotatedL.x + (rotatedT.x + rotatedB.x) * 0.5f; pos.y += rotatedL.y + (rotatedT.y + rotatedB.y) * 0.5f; break; case NGUIWidget.Pivot.Right: pos.x += rotatedR.x + (rotatedT.x + rotatedB.x) * 0.5f; pos.y += rotatedR.y + (rotatedT.y + rotatedB.y) * 0.5f; break; case NGUIWidget.Pivot.Top: pos.x += rotatedT.x + (rotatedL.x + rotatedR.x) * 0.5f; pos.y += rotatedT.y + (rotatedL.y + rotatedR.y) * 0.5f; break; case NGUIWidget.Pivot.Bottom: pos.x += rotatedB.x + (rotatedL.x + rotatedR.x) * 0.5f; pos.y += rotatedB.y + (rotatedL.y + rotatedR.y) * 0.5f; break; case NGUIWidget.Pivot.Center: pos.x += (rotatedL.x + rotatedR.x + rotatedT.x + rotatedB.x) * 0.5f; pos.y += (rotatedT.y + rotatedB.y + rotatedL.y + rotatedR.y) * 0.5f; break; } scale.x -= left - right; scale.y += top - bottom; scale.x /= size.x; scale.y /= size.y; Vector4 border = w.border; float minx = Mathf.Max(2f, padding.x + padding.z + border.x + border.z); float miny = Mathf.Max(2f, padding.y + padding.w + border.y + border.w); if (scale.x < minx) scale.x = minx; if (scale.y < miny) scale.y = miny; // NOTE: This will only work correctly when dragging the corner opposite of the pivot point if (makeSquare) { scale.x = Mathf.Min(scale.x, scale.y); scale.y = scale.x; } t.localPosition = pos; t.localScale = scale; }
static bool IsTop(NGUIWidget.Pivot pivot) { return pivot == NGUIWidget.Pivot.Top || pivot == NGUIWidget.Pivot.TopLeft || pivot == NGUIWidget.Pivot.TopRight; }
void SetPivot(NGUIWidget.Pivot pivot, bool isHorizontal) { NGUIWidget.Pivot horizontal = GetHorizontal(mWidget.pivot); NGUIWidget.Pivot vertical = GetVertical(mWidget.pivot); pivot = isHorizontal ? Combine(pivot, vertical) : Combine(horizontal, pivot); if (mWidget.pivot != pivot) { NGUIEditorTools.RegisterUndo("Pivot change", mWidget); mWidget.pivot = pivot; } }
/// <summary> /// Calculate the combined bounds of all widgets attached to the specified game object or its children (in relative-to-object space). /// </summary> static public Bounds CalculateRelativeWidgetBounds(Transform root, Transform child) { NGUIWidget[] widgets = child.GetComponentsInChildren <NGUIWidget>() as NGUIWidget[]; if (widgets.Length == 0) { return(new Bounds(Vector3.zero, Vector3.zero)); } Vector3 vMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); Vector3 vMax = new Vector3(float.MinValue, float.MinValue, float.MinValue); Matrix4x4 toLocal = root.worldToLocalMatrix; for (int i = 0, imax = widgets.Length; i < imax; ++i) { NGUIWidget w = widgets[i]; Vector2 size = w.relativeSize; Vector2 offset = w.pivotOffset; Transform toWorld = w.cachedTransform; float x = (offset.x + 0.5f) * size.x; float y = (offset.y - 0.5f) * size.y; size *= 0.5f; // Start with the corner of the widget Vector3 v = new Vector3(x - size.x, y - size.y, 0f); // Transform the coordinate from relative-to-widget to world space v = toWorld.TransformPoint(v); // Now transform from world space to relative-to-parent space v = toLocal.MultiplyPoint3x4(v); vMax = Vector3.Max(v, vMax); vMin = Vector3.Min(v, vMin); // Repeat for the other 3 corners v = new Vector3(x - size.x, y + size.y, 0f); v = toWorld.TransformPoint(v); v = toLocal.MultiplyPoint3x4(v); vMax = Vector3.Max(v, vMax); vMin = Vector3.Min(v, vMin); v = new Vector3(x + size.x, y - size.y, 0f); v = toWorld.TransformPoint(v); v = toLocal.MultiplyPoint3x4(v); vMax = Vector3.Max(v, vMax); vMin = Vector3.Min(v, vMin); v = new Vector3(x + size.x, y + size.y, 0f); v = toWorld.TransformPoint(v); v = toLocal.MultiplyPoint3x4(v); vMax = Vector3.Max(v, vMax); vMin = Vector3.Min(v, vMin); } Bounds b = new Bounds(vMin, Vector3.zero); b.Encapsulate(vMax); return(b); }
static NGUIWidget.Pivot GetHorizontal(NGUIWidget.Pivot pivot) { if (IsLeft(pivot)) return NGUIWidget.Pivot.Left; if (IsRight(pivot)) return NGUIWidget.Pivot.Right; return NGUIWidget.Pivot.Center; }
void Awake() { mWidget = GetComponent <NGUIWidget>(); mPanel = GetComponent <NGUIPanel>(); Update(); }
static NGUIWidget.Pivot GetVertical(NGUIWidget.Pivot pivot) { if (IsTop(pivot)) return NGUIWidget.Pivot.Top; if (IsBottom(pivot)) return NGUIWidget.Pivot.Bottom; return NGUIWidget.Pivot.Center; }
void UpdateAlpha() { // Update the widget alpha for (int i = 0, imax = mWidgets.Length; i < imax; ++i) { NGUIWidget w = mWidgets[i]; if (w != null) { w.alpha = mAlpha[i] * alpha; } } if (mLevel == 0) { // Fade in started -- enable all game objects Transform trans = transform; for (int i = 0, imax = trans.childCount; i < imax; ++i) { NGUITools.SetActive(trans.GetChild(i).gameObject, true); } for (int i = 0, imax = mColliders.Length; i < imax; ++i) { mColliders[i].enabled = false; } mLevel = 1; } else if (mLevel == 2 && alpha < 0.99f) { // Fade out started -- disable tweens and colliders TweenColor[] tweens = GetComponentsInChildren <TweenColor>(); for (int i = 0, imax = tweens.Length; i < imax; ++i) { tweens[i].enabled = false; } for (int i = 0, imax = mColliders.Length; i < imax; ++i) { mColliders[i].enabled = false; } mLevel = 1; } if (mLevel == 1) { if (alpha < 0.01f) { // Fade out finished -- disable all game objects Transform trans = transform; for (int i = 0, imax = trans.childCount; i < imax; ++i) { NGUITools.SetActive(trans.GetChild(i).gameObject, false); } mLevel = 0; } else if (alpha > 0.99f) { // Fade in finished -- enable all colliders for (int i = 0, imax = mColliders.Length; i < imax; ++i) { mColliders[i].enabled = true; } mLevel = 2; } } }
static bool IsBottom(NGUIWidget.Pivot pivot) { return pivot == NGUIWidget.Pivot.Bottom || pivot == NGUIWidget.Pivot.BottomLeft || pivot == NGUIWidget.Pivot.BottomRight; }
/// <summary> /// Draw the on-screen selection, knobs, and handle all interaction logic. /// </summary> public void OnSceneGUI() { if (!EditorPrefs.GetBool("New GUI", true)) { return; } if (Tools.current != Tool.View) { return; } mWidget = target as NGUIWidget; Handles.color = mOutlineColor; Transform t = mWidget.cachedTransform; Event e = Event.current; int id = GUIUtility.GetControlID(s_Hash, FocusType.Passive); EventType type = e.GetTypeForControl(id); Vector3[] corners = NGUIMath.CalculateWidgetCorners(mWidget); Handles.DrawLine(corners[0], corners[1]); Handles.DrawLine(corners[1], corners[2]); Handles.DrawLine(corners[2], corners[3]); Handles.DrawLine(corners[0], corners[3]); Vector3[] worldPos = new Vector3[8]; worldPos[0] = corners[0]; worldPos[1] = corners[1]; worldPos[2] = corners[2]; worldPos[3] = corners[3]; worldPos[4] = (corners[0] + corners[1]) * 0.5f; worldPos[5] = (corners[1] + corners[2]) * 0.5f; worldPos[6] = (corners[2] + corners[3]) * 0.5f; worldPos[7] = (corners[0] + corners[3]) * 0.5f; Vector2[] screenPos = new Vector2[8]; for (int i = 0; i < 8; ++i) { screenPos[i] = HandleUtility.WorldToGUIPoint(worldPos[i]); } Bounds b = new Bounds(screenPos[0], Vector3.zero); for (int i = 1; i < 8; ++i) { b.Encapsulate(screenPos[i]); } // Time to figure out what kind of action is underneath the mouse Action actionUnderMouse = mAction; NGUIWidget.Pivot pivotUnderMouse = NGUIWidget.Pivot.Center; if (actionUnderMouse == Action.None) { int index = 0; float dist = GetScreenDistance(worldPos, e.mousePosition, out index); if (dist < 10f) { pivotUnderMouse = mPivots[index]; actionUnderMouse = Action.Scale; } else if (e.modifiers == 0 && NGUIEditorTools.DistanceToRectangle(corners, e.mousePosition) == 0f) { actionUnderMouse = Action.Move; } else if (dist < 30f) { actionUnderMouse = Action.Rotate; } } // Change the mouse cursor to a more appropriate one #if !UNITY_3_5 { Vector2 min = b.min; Vector2 max = b.max; min.x -= 30f; max.x += 30f; min.y -= 30f; max.y += 30f; Rect rect = new Rect(min.x, min.y, max.x - min.x, max.y - min.y); if (actionUnderMouse == Action.Rotate) { SetCursorRect(rect, MouseCursor.RotateArrow); } else if (actionUnderMouse == Action.Move) { SetCursorRect(rect, MouseCursor.MoveArrow); } else if (actionUnderMouse == Action.Scale) { SetCursorRect(rect, MouseCursor.ScaleArrow); } else { SetCursorRect(rect, MouseCursor.Arrow); } } #endif switch (type) { case EventType.Repaint: { Handles.BeginGUI(); { for (int i = 0; i < 8; ++i) { DrawKnob(worldPos[i], mWidget.pivot == mPivots[i], id); } } Handles.EndGUI(); } break; case EventType.MouseDown: { mStartMouse = e.mousePosition; mAllowSelection = true; if (e.button == 1) { if (e.modifiers == 0) { GUIUtility.hotControl = GUIUtility.keyboardControl = id; e.Use(); } } else if (e.button == 0 && actionUnderMouse != Action.None && Raycast(corners, out mStartDrag)) { mStartPos = t.position; mStartRot = t.localRotation.eulerAngles; mStartDir = mStartDrag - t.position; mStartScale = t.localScale; mDragPivot = pivotUnderMouse; mActionUnderMouse = actionUnderMouse; GUIUtility.hotControl = GUIUtility.keyboardControl = id; e.Use(); } } break; case EventType.MouseDrag: { // Prevent selection once the drag operation begins bool dragStarted = (e.mousePosition - mStartMouse).magnitude > 3f; if (dragStarted) { mAllowSelection = false; } if (GUIUtility.hotControl == id) { e.Use(); if (mAction != Action.None || mActionUnderMouse != Action.None) { Vector3 pos; if (Raycast(corners, out pos)) { if (mAction == Action.None && mActionUnderMouse != Action.None) { // Wait until the mouse moves by more than a few pixels if (dragStarted) { if (mActionUnderMouse == Action.Move) { mStartPos = t.position; NGUIEditorTools.RegisterUndo("Move widget", t); } else if (mActionUnderMouse == Action.Rotate) { mStartRot = t.localRotation.eulerAngles; mStartDir = mStartDrag - t.position; NGUIEditorTools.RegisterUndo("Rotate widget", t); } else if (mActionUnderMouse == Action.Scale) { mStartPos = t.localPosition; mStartScale = t.localScale; mDragPivot = pivotUnderMouse; NGUIEditorTools.RegisterUndo("Scale widget", t); } mAction = actionUnderMouse; } } if (mAction != Action.None) { if (mAction == Action.Move) { t.position = mStartPos + (pos - mStartDrag); pos = t.localPosition; pos.x = Mathf.RoundToInt(pos.x); pos.y = Mathf.RoundToInt(pos.y); t.localPosition = pos; } else if (mAction == Action.Rotate) { Vector3 dir = pos - t.position; float angle = Vector3.Angle(mStartDir, dir); if (angle > 0f) { float dot = Vector3.Dot(Vector3.Cross(mStartDir, dir), t.forward); if (dot < 0f) { angle = -angle; } angle = mStartRot.z + angle; if (e.modifiers != EventModifiers.Shift) { angle = Mathf.Round(angle / 15f) * 15f; } else { angle = Mathf.Round(angle); } t.localRotation = Quaternion.Euler(mStartRot.x, mStartRot.y, angle); } } else if (mAction == Action.Scale) { // World-space delta since the drag started Vector3 delta = pos - mStartDrag; // Adjust the widget's position and scale based on the delta, restricted by the pivot AdjustPosAndScale(mWidget, mStartPos, mStartScale, delta, mDragPivot); } } } } } } break; case EventType.MouseUp: { if (GUIUtility.hotControl == id) { GUIUtility.hotControl = 0; GUIUtility.keyboardControl = 0; if (e.button < 2) { bool handled = false; if (e.button == 1) { // Right-click: Select the widget below NGUIWidget last = null; NGUIWidget[] widgets = Raycast(mWidget, e.mousePosition); for (int i = widgets.Length; i > 0;) { NGUIWidget w = widgets[--i]; if (w == mWidget) { break; } last = w; } if (last != null) { Selection.activeGameObject = last.gameObject; handled = true; } } else if (mAction == Action.None) { if (mAllowSelection) { // Left-click: Select the widget above NGUIWidget last = null; NGUIWidget[] widgets = Raycast(mWidget, e.mousePosition); if (widgets.Length > 0) { for (int i = 0; i < widgets.Length; ++i) { NGUIWidget w = widgets[i]; if (w == mWidget) { if (last != null) { Selection.activeGameObject = last.gameObject; } handled = true; break; } last = w; } if (!handled) { Selection.activeGameObject = widgets[0].gameObject; handled = true; } } } } else { // Finished dragging something mAction = Action.None; mActionUnderMouse = Action.None; Vector3 pos = t.localPosition; Vector3 scale = t.localScale; if (mWidget.pixelPerfectAfterResize) { t.localPosition = pos; t.localScale = scale; mWidget.MakePixelPerfect(); } else { pos.x = Mathf.Round(pos.x); pos.y = Mathf.Round(pos.y); scale.x = Mathf.Round(scale.x); scale.y = Mathf.Round(scale.y); t.localPosition = pos; t.localScale = scale; } handled = true; } if (handled) { mActionUnderMouse = Action.None; mAction = Action.None; e.Use(); } } } else if (mAllowSelection) { NGUIWidget[] widgets = Raycast(mWidget, e.mousePosition); if (widgets.Length > 0) { Selection.activeGameObject = widgets[0].gameObject; } } mAllowSelection = true; } break; case EventType.KeyDown: { if (e.keyCode == KeyCode.UpArrow) { Vector3 pos = t.localPosition; pos.y += 1f; t.localPosition = pos; e.Use(); } else if (e.keyCode == KeyCode.DownArrow) { Vector3 pos = t.localPosition; pos.y -= 1f; t.localPosition = pos; e.Use(); } else if (e.keyCode == KeyCode.LeftArrow) { Vector3 pos = t.localPosition; pos.x -= 1f; t.localPosition = pos; e.Use(); } else if (e.keyCode == KeyCode.RightArrow) { Vector3 pos = t.localPosition; pos.x += 1f; t.localPosition = pos; e.Use(); } else if (e.keyCode == KeyCode.Escape) { if (GUIUtility.hotControl == id) { if (mAction != Action.None) { if (mAction == Action.Move) { t.position = mStartPos; } else if (mAction == Action.Rotate) { t.localRotation = Quaternion.Euler(mStartRot); } else if (mAction == Action.Scale) { t.position = mStartPos; t.localScale = mStartScale; } } GUIUtility.hotControl = 0; GUIUtility.keyboardControl = 0; mActionUnderMouse = Action.None; mAction = Action.None; e.Use(); } else { Selection.activeGameObject = null; Tools.current = Tool.Move; } } } break; } }
/// <summary> /// Initialize the cached values. /// </summary> void Init() { mInitDone = true; if (foreground != null) { mFGWidget = foreground.GetComponent<NGUIWidget>(); mFGFilled = (mFGWidget != null) ? mFGWidget as NGUISprite : null; mFGTrans = foreground.transform; if (mSize == Vector2.zero) mSize = foreground.localScale; if (mCenter == Vector2.zero) mCenter = foreground.localPosition + foreground.localScale * 0.5f; } else if (mCol != null) { if (mSize == Vector2.zero) mSize = mCol.size; if (mCenter == Vector2.zero) mCenter = mCol.center; } else { Debug.LogWarning("NGUISlider expected to find a foreground object or a box collider to work with", this); } }
/// <summary> /// Adjust the widget's rectangle based on the specified modifier values. /// </summary> static void AdjustWidget(NGUIWidget w, Vector3 pos, Vector3 scale, float left, float top, float right, float bottom, bool makeSquare) { Vector2 offset = w.pivotOffset; Vector4 padding = w.relativePadding; Vector2 size = w.relativeSize; offset.x -= padding.x; offset.y -= padding.y; size.x += padding.x + padding.z; size.y += padding.y + padding.w; scale.Scale(size); offset.y = -offset.y; Transform t = w.cachedTransform; Quaternion rot = t.localRotation; NGUIWidget.Pivot pivot = w.pivot; Vector2 rotatedTL = new Vector2(left, top); Vector2 rotatedTR = new Vector2(right, top); Vector2 rotatedBL = new Vector2(left, bottom); Vector2 rotatedBR = new Vector2(right, bottom); Vector2 rotatedL = new Vector2(left, 0f); Vector2 rotatedR = new Vector2(right, 0f); Vector2 rotatedT = new Vector2(0f, top); Vector2 rotatedB = new Vector2(0f, bottom); rotatedTL = rot * rotatedTL; rotatedTR = rot * rotatedTR; rotatedBL = rot * rotatedBL; rotatedBR = rot * rotatedBR; rotatedL = rot * rotatedL; rotatedR = rot * rotatedR; rotatedT = rot * rotatedT; rotatedB = rot * rotatedB; switch (pivot) { case NGUIWidget.Pivot.TopLeft: pos.x += rotatedTL.x; pos.y += rotatedTL.y; break; case NGUIWidget.Pivot.BottomRight: pos.x += rotatedBR.x; pos.y += rotatedBR.y; break; case NGUIWidget.Pivot.BottomLeft: pos.x += rotatedBL.x; pos.y += rotatedBL.y; break; case NGUIWidget.Pivot.TopRight: pos.x += rotatedTR.x; pos.y += rotatedTR.y; break; case NGUIWidget.Pivot.Left: pos.x += rotatedL.x + (rotatedT.x + rotatedB.x) * 0.5f; pos.y += rotatedL.y + (rotatedT.y + rotatedB.y) * 0.5f; break; case NGUIWidget.Pivot.Right: pos.x += rotatedR.x + (rotatedT.x + rotatedB.x) * 0.5f; pos.y += rotatedR.y + (rotatedT.y + rotatedB.y) * 0.5f; break; case NGUIWidget.Pivot.Top: pos.x += rotatedT.x + (rotatedL.x + rotatedR.x) * 0.5f; pos.y += rotatedT.y + (rotatedL.y + rotatedR.y) * 0.5f; break; case NGUIWidget.Pivot.Bottom: pos.x += rotatedB.x + (rotatedL.x + rotatedR.x) * 0.5f; pos.y += rotatedB.y + (rotatedL.y + rotatedR.y) * 0.5f; break; case NGUIWidget.Pivot.Center: pos.x += (rotatedL.x + rotatedR.x + rotatedT.x + rotatedB.x) * 0.5f; pos.y += (rotatedT.y + rotatedB.y + rotatedL.y + rotatedR.y) * 0.5f; break; } scale.x -= left - right; scale.y += top - bottom; scale.x /= size.x; scale.y /= size.y; Vector4 border = w.border; float minx = Mathf.Max(2f, padding.x + padding.z + border.x + border.z); float miny = Mathf.Max(2f, padding.y + padding.w + border.y + border.w); if (scale.x < minx) { scale.x = minx; } if (scale.y < miny) { scale.y = miny; } // NOTE: This will only work correctly when dragging the corner opposite of the pivot point if (makeSquare) { scale.x = Mathf.Min(scale.x, scale.y); scale.y = scale.x; } t.localPosition = pos; t.localScale = scale; }
static NGUIWidget.Pivot Combine(NGUIWidget.Pivot horizontal, NGUIWidget.Pivot vertical) { if (horizontal == NGUIWidget.Pivot.Left) { if (vertical == NGUIWidget.Pivot.Top) return NGUIWidget.Pivot.TopLeft; if (vertical == NGUIWidget.Pivot.Bottom) return NGUIWidget.Pivot.BottomLeft; return NGUIWidget.Pivot.Left; } if (horizontal == NGUIWidget.Pivot.Right) { if (vertical == NGUIWidget.Pivot.Top) return NGUIWidget.Pivot.TopRight; if (vertical == NGUIWidget.Pivot.Bottom) return NGUIWidget.Pivot.BottomRight; return NGUIWidget.Pivot.Right; } return vertical; }
/// <summary> /// All widgets have depth, color and make pixel-perfect options /// </summary> protected void DrawCommonProperties() { #if UNITY_3_4 PrefabType type = EditorUtility.GetPrefabType(mWidget.gameObject); #else PrefabType type = PrefabUtility.GetPrefabType(mWidget.gameObject); #endif NGUIEditorTools.DrawSeparator(); #if UNITY_3_5 // Pivot point -- old school drop-down style NGUIWidget.Pivot pivot = (NGUIWidget.Pivot)EditorGUILayout.EnumPopup("Pivot", mWidget.pivot); if (mWidget.pivot != pivot) { NGUIEditorTools.RegisterUndo("Pivot Change", mWidget); mWidget.pivot = pivot; } #else // Pivot point -- the new, more visual style GUILayout.BeginHorizontal(); GUILayout.Label("Pivot", GUILayout.Width(76f)); Toggle("◄", "ButtonLeft", NGUIWidget.Pivot.Left, true); Toggle("▬", "ButtonMid", NGUIWidget.Pivot.Center, true); Toggle("►", "ButtonRight", NGUIWidget.Pivot.Right, true); Toggle("▲", "ButtonLeft", NGUIWidget.Pivot.Top, false); Toggle("▌", "ButtonMid", NGUIWidget.Pivot.Center, false); Toggle("▼", "ButtonRight", NGUIWidget.Pivot.Bottom, false); GUILayout.EndHorizontal(); #endif // Depth navigation if (type != PrefabType.Prefab) { GUILayout.Space(2f); GUILayout.BeginHorizontal(); { EditorGUILayout.PrefixLabel("Depth"); int depth = mWidget.depth; if (GUILayout.Button("Back", GUILayout.Width(60f))) { --depth; } depth = EditorGUILayout.IntField(depth); if (GUILayout.Button("Forward", GUILayout.Width(60f))) { ++depth; } if (mWidget.depth != depth) { NGUIEditorTools.RegisterUndo("Depth Change", mWidget); mWidget.depth = depth; mDepthCheck = true; } } GUILayout.EndHorizontal(); NGUIPanel panel = mWidget.panel; if (panel != null) { int count = 0; for (int i = 0; i < panel.widgets.size; ++i) { NGUIWidget w = panel.widgets[i]; if (w != null && w.depth == mWidget.depth && w.material == mWidget.material) { ++count; } } if (count > 1) { EditorGUILayout.HelpBox(count + " widgets are using the depth value of " + mWidget.depth + ". It may not be clear what should be in front of what.", MessageType.Warning); } if (mDepthCheck) { if (panel.drawCalls.size > 1) { EditorGUILayout.HelpBox("The widgets underneath this panel are using more than one atlas. You may need to adjust transform position's Z value instead. When adjusting the Z, lower value means closer to the camera.", MessageType.Warning); } } } } // Pixel-correctness if (type != PrefabType.Prefab) { GUILayout.BeginHorizontal(); { EditorGUILayout.PrefixLabel("Correction"); if (GUILayout.Button("Make Pixel-Perfect")) { NGUIEditorTools.RegisterUndo("Make Pixel-Perfect", mWidget.transform); mWidget.MakePixelPerfect(); } } GUILayout.EndHorizontal(); } //NGUIEditorTools.DrawSeparator(); EditorGUILayout.Space(); // Color tint GUILayout.BeginHorizontal(); Color color = EditorGUILayout.ColorField("Color Tint", mWidget.color); if (GUILayout.Button("Copy", GUILayout.Width(50f))) { NGUISettings.color = color; } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); NGUISettings.color = EditorGUILayout.ColorField("Clipboard", NGUISettings.color); if (GUILayout.Button("Paste", GUILayout.Width(50f))) { color = NGUISettings.color; } GUILayout.EndHorizontal(); if (mWidget.color != color) { NGUIEditorTools.RegisterUndo("Color Change", mWidget); mWidget.color = color; } }
/// <summary> /// Find all needed components. /// </summary> void Awake() { mWidget = GetComponentInChildren<NGUIWidget>(); Renderer ren = renderer; if (ren != null) mMat = ren.material; mLight = light; }