# Unity 101 Tip #97 – Rectangle intersection extension methods

Published 4/4/2016 by createdbyx in Code Snippets | Programming | Unity
Tags: , ,

Provided below are two extension methods for determining if two unity Rect types intersect one another.

```/// <summary>
/// Returns a third Rect structure that represents the intersection of two other Rect structures.
/// If there is no intersection, an empty Rect is returned.
/// </summary>
/// <param name="a">
/// A rectangle to intersect.
/// </param>
/// <param name="b">
/// B rectangle to intersect.
/// </param>
/// <returns>
/// A Rect that represents the intersection of a and b.
/// </returns>
public static Rect Intersect(this Rect a, Rect b)
{
float x = Math.Max((sbyte)a.x, (sbyte)b.x);
var num2 = Math.Min(a.x + a.width, b.x + b.width);
float y = Math.Max((sbyte)a.y, (sbyte)b.y);
var num4 = Math.Min(a.y + a.height, b.y + b.height);
if ((num2 >= x) && (num4 >= y))
{
return new Rect(x, y, num2 - x, num4 - y);
}

return new Rect();
}

/// <summary>
/// Determines if this rectangle intersects with rect.
/// </summary>
/// <param name="source">The source rectangle from which the intersection will be tested.</param>
/// <param name="rect">
/// The rectangle to test.
/// </param>
/// <returns>
/// This method returns true if there is any intersection, otherwise false.
/// </returns>
public static bool Intersects(this Rect source, Rect rect)
{
return !((source.x > rect.xMax) || (source.xMax< rect.x) || (source.y > rect.yMax) || (source.yMax < rect.y));
}```

# Unity 101 Tip #96 – DrawRectangle & DrawLine gui helper methods

Published 3/28/2016 by createdbyx in Unity | Programming | Code Snippets
Tags: , ,

The DrawRectangle & DrawLine helper methods allow you to draw a lines and rectangles inside OnGUI methods.

```/// <summary>
/// Draws a rectangle.
/// </summary>
/// <param name="rect">A <see cref="Rect"/> type that defines the bounds of the rectangle to draw.</param>
public static void DrawRectangle(Rect rect)
{
DrawRectangle(rect, GUI.contentColor, 1f);
}

/// <summary>
/// Draws a rectangle.
/// </summary>
/// <param name="rect">
/// A <see cref="Rect"/> type that defines the bounds of the rectangle to draw.
/// </param>
/// <param name="color">
/// The color of the rectangle.
/// </param>
public static void DrawRectangle(Rect rect, Color color)
{
DrawRectangle(rect, color, 1);
}

/// <summary>
/// Draws a rectangle.
/// </summary>
/// <param name="rect">
/// A <see cref="Rect"/> type that defines the bounds of the rectangle to draw.
/// </param>
/// <param name="thickness">
/// The line thickness of the rectangle.
/// </param>
public static void DrawRectangle(Rect rect, float thickness)
{
DrawRectangle(rect, GUI.contentColor, thickness);
}

/// <summary>
/// Draws a rectangle.
/// </summary>
/// <param name="rect">
/// A <see cref="Rect"/> type that defines the bounds of the rectangle to draw.
/// </param>
/// <param name="color">
/// The color of the rectangle.
/// </param>
/// <param name="thickness">
/// The line thickness of the rectangle.
/// </param>
public static void DrawRectangle(Rect rect, Color color, float thickness)
{
DrawHLine(new Vector2(rect.x, rect.y), rect.width, color, thickness);
DrawHLine(new Vector2(rect.x, rect.y + rect.height - 1), rect.width, color, thickness);
DrawVLine(new Vector2(rect.x, rect.y), rect.height, color, thickness);
DrawVLine(new Vector2(rect.x + rect.width - 1, rect.y), rect.height, color, thickness);
}

/// <summary>
/// Draws a line.
/// </summary>
/// <param name="pointA">The start point of the line.</param>
/// <param name="pointB">The end point of the line.</param>
public static void DrawLine(Vector2 pointA, Vector2 pointB)
{
DrawLine(pointA, pointB, GUI.contentColor, 1.0f);
}

/// <summary>
/// Draws a line.
/// </summary>
/// <param name="pointA">The start point of the line.</param>
/// <param name="pointB">The end point of the line.</param>
/// <param name="color">The color to use.</param>
public static void DrawLine(Vector2 pointA, Vector2 pointB, Color color)
{
DrawLine(pointA, pointB, color, 1.0f);
}

/// <summary>
/// Draws a line.
/// </summary>
/// <param name="pointA">The start point of the line.</param>
/// <param name="pointB">The end point of the line.</param>
/// <param name="thickness">THe thickness of the line.</param>
public static void DrawLine(Vector2 pointA, Vector2 pointB, float thickness)
{
DrawLine(pointA, pointB, GUI.contentColor, thickness);
}

/// <summary>
/// Draws a line.
/// </summary>
/// <param name="pointA">The start point of the line.</param>
/// <param name="pointB">The end point of the line.</param>
/// <param name="color">The color to use.</param>
/// <param name="thickness">THe thickness of the line.</param>
public static void DrawLine(Vector2 pointA, Vector2 pointB, Color color, float thickness)
{
// Save the current GUI matrix, since we're going to make changes to it.
var matrix = GUI.matrix;

// Store current GUI color, so we can switch it back later,
// and set the GUI color to the color parameter
var savedColor = GUI.color;
GUI.color = color;

// Determine the angle of the line.
var angle = Vector2.Angle(pointB - pointA, Vector2.right);

// Vector3.Angle always returns a positive number.
// If pointB is above pointA, then angle needs to be negative.
if (pointA.y > pointB.y)
{
angle = -angle;
}

// Use ScaleAroundPivot to adjust the size of the line.
// We could do this when we draw the texture, but by scaling it here we can use
//  non-integer values for the thickness and length (such as sub 1 pixel widths).
// Note that the pivot point is at +.5 from pointA.y, this is so that the thickness of the line
//  is centered on the origin at pointA.
GUIUtility.ScaleAroundPivot(new Vector2((pointB - pointA).magnitude, thickness), new Vector2(pointA.x, pointA.y + 0.5f));

// Set the rotation for the line.
//  The angle was calculated with pointA as the origin.
GUIUtility.RotateAroundPivot(angle, pointA);

// Finally, draw the actual line.
// We're really only drawing a 1x1 texture from pointA.
// The matrix operations done with ScaleAroundPivot and RotateAroundPivot will make this
//  render with the proper thickness, length, and angle.
GUI.DrawTexture(new Rect(pointA.x, pointA.y, 1, 1), Texture2D.whiteTexture);

// We're done.  Restore the GUI matrix and GUI color to whatever they were before.
GUI.matrix = matrix;
GUI.color = savedColor;
}

/// <summary>
/// Draws a horizontal line.
/// </summary>
/// <param name="pointA">
/// The start point of the line.
/// </param>
/// <param name="length">
/// The length of the line.
/// </param>
/// <param name="color">
/// The color to use.
/// </param>
/// <param name="thickness">
/// THe thickness of the line.
/// </param>
/// <remarks>
/// The line will be drawn from <see cref="pointA"/> moving to the right. To draw to the left use a negative <see cref="length"/> value.
/// </remarks>
public static void DrawHLine(Vector2 pointA, float length, Color color, float thickness)
{
// Store current GUI color, so we can switch it back later,
// and set the GUI color to the color parameter
var savedColor = GUI.color;
GUI.color = color;

// Finally, draw the actual line.
// We're really only drawing a 1x1 texture from pointA.
// The matrix operations done with ScaleAroundPivot and RotateAroundPivot will make this
//  render with the proper thickness, length, and angle.
GUI.DrawTexture(new Rect(pointA.x, pointA.y, length - 1, thickness), Texture2D.whiteTexture, ScaleMode.StretchToFill);

// We're done.  Restore the GUI matrix and GUI color to whatever they were before.
GUI.color = savedColor;
}

/// <summary>
/// Draws a vertical line.
/// </summary>
/// <param name="pointA">
/// The start point of the line.
/// </param>
/// <param name="length">
/// The length of the line.
/// </param>
/// <param name="color">
/// The color to use.
/// </param>
/// <param name="thickness">
/// THe thickness of the line.
/// </param>
/// <remarks>
/// The line will be drawn from <see cref="pointA"/> moving up. To draw down use a negative <see cref="length"/> value.
/// </remarks>
public static void DrawVLine(Vector2 pointA, float length, Color color, float thickness)
{
// Store current GUI color, so we can switch it back later,
// and set the GUI color to the color parameter
var savedColor = GUI.color;
GUI.color = color;

// Finally, draw the actual line.
// We're really only drawing a 1x1 texture from pointA.
// The matrix operations done with ScaleAroundPivot and RotateAroundPivot will make this
//  render with the proper thickness, length, and angle.
GUI.DrawTexture(new Rect(pointA.x, pointA.y, thickness, length - 1), Texture2D.whiteTexture, ScaleMode.StretchToFill);

// We're done.  Restore the GUI matrix and GUI color to whatever they were before.
GUI.color = savedColor;
}```

# Unity 101 Tip #95 – FillRectangle gui helper methods

Published 3/21/2016 by createdbyx in Code Snippets | Unity | Programming
Tags: , ,

The FillRectangle helper methods allow you to draw a filled rectangles inside OnGUI methods.

```        /// <summary>
/// Draws a filled rectangle.
/// </summary>
/// <param name="rect">
/// A <see cref="Rect"/> type that defines the bounds of the rectangle to draw.
/// </param>
public static void FillRectangle(Rect rect)
{
FillRectangle(rect, GUI.color);
}

/// <summary>
/// Draws a filled rectangle.
/// </summary>
/// <param name="rect">
/// A <see cref="Rect"/> type that defines the bounds of the rectangle to draw.
/// </param>
/// <param name="color">
/// The color of the rectangle.
/// </param>
public static void FillRectangle(Rect rect, Color color)
{
// Store current GUI color, so we can switch it back later,
// and set the GUI color to the color parameter
var savedColor = GUI.color;
GUI.color = color;

// Finally, draw the actual rectangle.
GUI.DrawTexture(rect, Texture2D.whiteTexture, ScaleMode.StretchToFill);

// We're done.  Restore the GUI matrix and GUI color to whatever they were before.
GUI.color = savedColor;
}```

# Unity 101 Tip #94 – GetOrAddComponent extension method

Published 3/18/2016 by createdbyx in Unity | Programming
Tags: , ,

Some times you need to make sure a component has been set on a game object and if it does not exist add it.

```        /// <summary>
/// Tries to get a component and if it does not exist adds the component and returns a reference to it.
/// </summary>
/// <remarks>
/// <example>
/// Usage example:
/// <code>
/// </code>
/// </example>
/// </remarks>
public static T GetOrAddComponent<T>(this Component child) where T : Component
{
var result = child.GetComponent<T>();
if (result == null)
{
}

return result;
}```

# Unity 101 Tip #93 – In Game Translation Gizmo

Published 2/17/2016 by createdbyx in Unity
Tags: ,

The code snippet below allows you to attach a translation gizmo to a object to allow the user to move that object while the game is running. Works just like the unity translation gizmo.

```    using System;
using UnityEngine;

/// <summary>
/// The translation gizmo.
/// </summary>
public class TranslationGizmo : MonoBehaviour
{
#region Fields

/// <summary>
/// The camera reference used to determin distance to translation gizmo.
/// </summary>
public UnityEngine.Camera cameraReference;

/// <summary>
/// Used to determine how thick the envelope is around a axis line when attempting to click and drag it with the mouse.
/// </summary>
public float axisEnvelope = 0.04f;

/// <summary>
/// Determines the length of the cone.
/// </summary>
public float coneLength = 0.85f;

/// <summary>
/// Specifies how many segments the cone is made up of.
/// </summary>
public int coneSegments = 30;

/// <summary>
/// Determines the diameter of the cone.
/// </summary>
public float coneSize = 0.075f;

/// <summary>
/// Determines the length of the axis lines.
/// </summary>
public float lineLength = 0.13f;

/// <summary>
/// The line material used to render the lines.
/// </summary>
public Material lineMaterial;

/// <summary>
/// Determines the size of the square panning gizmos.
/// </summary>
public float panScale = 0.3f;

/// <summary>
/// Determines the transparency level of the axis plane quads.
/// </summary>
public float planeTransparency = 0.3f;

/// <summary>
/// The color that will be used for the X axis.
/// </summary>
public Color xAxisColor = Color.red;

/// <summary>
/// The color that will be used for the Y axis.
/// </summary>
public Color yAxisColor = Color.green;

/// <summary>
/// The color that will be used for the Z axis.
/// </summary>
public Color zAxisColor = Color.blue;

/// <summary>
/// Holds the button state used to determine if dragging has started.
/// </summary>
protected bool inputButtonState;

/// <summary>
/// Holds the relative mouse X position.
/// </summary>
protected float mouseAxisX;

/// <summary>
/// Holds the relative mouse Y position.
/// </summary>
protected float mouseAxisY;

/// <summary>
/// Holds the pre-calculated distance value from the camera to the game object.
/// </summary>

/// <summary>
/// The hit mouse down.
/// </summary>
private Vector3 hitMouseDown;

/// <summary>
/// The hit mouse move.
/// </summary>
private Vector3 hitMouseMove;

/// <summary>
/// Holds wheather or not the input axis has changed.
/// </summary>
private bool inputAxisChanged;

/// <summary>
/// Holds wheather or not the mouse if being dragged.
/// </summary>
private bool isDragging;

/// <summary>
/// Holds XY plane information.
/// </summary>
private Plane planeXY;

/// <summary>
/// Holds XZ plane information.
/// </summary>
private Plane planeXZ;

/// <summary>
/// Holds YZ plane information.
/// </summary>
private Plane planeYZ;

/// <summary>
/// Holds the previous input button state.
/// </summary>
private bool previousInputButtonState;

/// <summary>
/// Holds the rotation matrix used to determine at what rotation the gizmo will be drawn at.
/// </summary>
private Matrix4x4 rotationMatrix;

/// <summary>
/// Holds the value for the <see cref="WorldTranslation"/> property.
/// </summary>
[SerializeField]
private bool worldTranslation;

/// <summary>
/// Gets or sets a value indicating whether world translation is enabled.
/// </summary>
/// <value>
///   <c>true</c> if world translation is active; otherwise, <c>false</c> for local translation.
/// </value>
public bool WorldTranslation
{
get
{
return this.worldTranslation;
}

set
{
this.worldTranslation = value;
}
}

/// <summary>
/// Holds the type of axis movement is currently being made.
/// </summary>

#endregion

#region Public Events

/// <summary>
/// Occurs when position changed.
/// </summary>
public event EventHandler<Vector3EventArgs> PositionChanged;

#endregion

#region Enums

/// <summary>
/// Enum defining the types of axis movement.
/// </summary>
private enum TypeOfMove
{
/// <summary>
/// No axis movement.
/// </summary>
None,

/// <summary>
/// Movement along the X axis.
/// </summary>
XAxis,

/// <summary>
/// Movement along the
/// </summary>
X2Axis,

/// <summary>
/// Movement along the Y axis.
/// </summary>
YAxis,

/// <summary>
/// The y 2 axis.
/// </summary>
Y2Axis,

/// <summary>
/// Movement along the Z axis.
/// </summary>
ZAxis,

/// <summary>
/// The z 2 axis.
/// </summary>
Z2Axis,

/// <summary>
/// Movement along the XZ axis.
/// </summary>
XZAxis,

/// <summary>
/// Movement along the YZ axis.
/// </summary>
YZAxis,

/// <summary>
/// Movement along the XY axis.
/// </summary>
XYAxis,
};

#endregion

#region Public Methods and Operators

/// <summary>
/// Awake is called when the script instance is being loaded.
/// </summary>
public void Awake()
{
// if no material assigned setup a default material
if (this.lineMaterial == null)
{
#if !UNITY_5
this.lineMaterial =
new Material(
"Shader \"Lines/Colored Blended\" {" + "SubShader { Pass { " + "    Blend SrcAlpha OneMinusSrcAlpha "
+ "    ZWrite Off Cull Off Fog { Mode Off } ZTest Always" + "    BindChannels {"
+ "      Bind \"vertex\", vertex Bind \"color\", color }" + "} } }");
#else
// Unity has a built-in shader that is useful for drawing
// simple colored things.
this.lineMaterial.hideFlags = HideFlags.HideAndDontSave;
// Turn on alpha blending
this.lineMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
this.lineMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
// Turn backface culling off
this.lineMaterial.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Off);
// Turn off depth writes
this.lineMaterial.SetInt("_ZWrite", 0);
#endif
}
}

/// <summary>
/// Update is called every frame, if the MonoBehaviour is enabled.
/// </summary>
public void Update()
{
if (cameraReference == null)
{
return;
}

// calculate distance once between the camera and the game objects position
var transformReference = this.transform;
var position = transformReference.position;
this.cameraDistance = Vector3.Distance(this.cameraReference.transform.position, position) * this.lineLength;

this.previousInputButtonState = this.inputButtonState;
this.GetInputButtonState();

// if the input button is released stop moving
if (!this.inputButtonState)
{
this.isDragging = false;
return;
}

// only handle dragging is already dragging or if input button state was pressed
if (this.isDragging || (!this.previousInputButtonState && this.inputButtonState))
{
// get mouse/input values
this.GetInputValues();
this.inputAxisChanged = Math.Abs(this.mouseAxisX) > float.Epsilon || Math.Abs(this.mouseAxisY) > float.Epsilon;

// update planes based on world or local translation
if (this.worldTranslation)
{
// update planes
this.planeXZ.SetNormalAndPosition(Vector3.up, position);
this.planeXY.SetNormalAndPosition(Vector3.forward, position);
this.planeYZ.SetNormalAndPosition(Vector3.right, position);
}
else
{
// update planes
this.planeXZ.SetNormalAndPosition(transformReference.up, position);
this.planeXY.SetNormalAndPosition(transformReference.forward, position);
this.planeYZ.SetNormalAndPosition(transformReference.right, position);
}

// cast a ray once
var ray = this.cameraReference.ScreenPointToRay(Input.mousePosition);

// handle axis translations
this.HandleXZ(ray);
this.HandleXY(ray);
this.HandleYZ(ray);
}
}

#endregion

#region Methods

/// <summary>
/// Get the state of the input button used to determine if dragging has occurred.
/// </summary>
protected virtual void GetInputButtonState()
{
this.inputButtonState = Input.GetMouseButton(0);
}

/// <summary>
/// Gets the X/Y input values
/// </summary>
protected virtual void GetInputValues()
{
this.mouseAxisX = Input.GetAxis("Mouse X");
this.mouseAxisY = Input.GetAxis("Mouse Y");
}

/// <summary>
/// Raises the <see cref="PositionChanged"/> event.
/// </summary>
/// <param name="previousPosition">
/// The previous Position.
/// </param>
/// <param name="position">
/// The position.
/// </param>
protected virtual void OnPositionChanged(Vector3 previousPosition, Vector3 position)
{
var handler = this.PositionChanged;
if (handler != null)
{
handler(this, new Vector3EventArgs(previousPosition, position));
}
}

/// <summary>
/// Uses OpenGL to draw a line for the axis.
/// </summary>
/// <param name="color">
/// The color to use when drawing the cone.
/// </param>
/// <param name="axis">
/// Defines axis that the cone will be drawn against.
/// </param>
/// <param name="axisU">
/// Represents the "X" axis to draw the base of the cone against.
/// </param>
/// <param name="axisV">
/// Represents the "Y" axis to draw the base of the cone against.
/// </param>
private void DrawAxis(Color color, Vector3 axis, Vector3 axisU, Vector3 axisV)
{
// scale the axis by the camera distance

// start drawing lines
GL.Begin(GL.LINES);
GL.Color(color);
GL.Vertex3(0, 0, 0);
GL.Vertex3(axis.x, axis.y, axis.z);
GL.End();

// draw the cone for the axis
this.DrawCone(axis, axisU, axisV, this.cameraDistance * this.coneSize, this.coneLength, color);
}

/// <summary>
/// Uses OpenGL to draw a cone for the axis.
/// </summary>
/// <param name="axis">
/// Defines axis that the cone will be drawn against.
/// </param>
/// <param name="axisU">
/// Represents the "X" axis to draw the base of the cone against.
/// </param>
/// <param name="axisV">
/// Represents the "Y" axis to draw the base of the cone against.
/// </param>
/// Specifies the radius for the base of the cone.
/// </param>
/// <param name="length">
/// Specifies how tall the cone is.
/// </param>
/// <param name="color">
/// The color to use when drawing the cone.
/// </param>
private void DrawCone(Vector3 axis, Vector3 axisU, Vector3 axisV, float radius, float length, Color color)
{
GL.Begin(GL.TRIANGLES);
GL.Color(color);

// pre-calculate the angle step for each cone segment
var angle = (2 * Mathf.PI) / this.coneSegments;

for (var i = 0; i <= this.coneSegments; i++)
{
var pt = axisU * Mathf.Cos(angle * i) * radius;
pt += axisV * Mathf.Sin(angle * i) * radius;
pt += axis * length;
GL.Vertex(pt);

pt = axisU * Mathf.Cos(angle * (i + 1)) * radius;
pt += axisV * Mathf.Sin(angle * (i + 1)) * radius;
pt += axis * length;
GL.Vertex(pt);

GL.Vertex(axis);
}

GL.End();
}

/// <summary>
/// Uses OpenGL to draw a square plane for the axis.
/// </summary>
/// <param name="size">
/// Defines size of the plane that will be drawn for the axis.
/// </param>
/// <param name="axisU">
/// Represents the "X" axis to draw the plane against.
/// </param>
/// <param name="axisV">
/// Represents the "Y" axis to draw the plane against.
/// </param>
/// <param name="color">
/// The color to use when drawing the plane.
/// </param>
private void DrawQuad(float size, Vector3 axisU, Vector3 axisV, Color color)
{
color.a = this.planeTransparency;
var pts = new Vector3[4];
pts[0] = Vector3.zero;
pts[1] = axisU * size;
pts[2] = (axisU + axisV) * size;
pts[3] = axisV * size;

GL.Color(color);
GL.Vertex(pts[0]);
GL.Vertex(pts[1]);
GL.Vertex(pts[2]);
GL.Vertex(pts[3]);
GL.End();
color.a = 1f;

GL.Begin(GL.LINES);
GL.Color(color);
GL.Vertex(pts[0]);
GL.Vertex(pts[1]);
GL.Vertex(pts[1]);
GL.Vertex(pts[2]);
GL.Vertex(pts[2]);
GL.Vertex(pts[3]);
GL.Vertex(pts[3]);
GL.Vertex(pts[0]);
GL.End();
}

/// <summary>
/// Start is called just before any of the Update methods is called the first time.
/// </summary>
public void Start()
{
if (this.cameraReference == null)
{
this.cameraReference = UnityEngine.Camera.main;
}
}

/// <summary>
/// Handles dragging along the XU plane.
/// </summary>
/// <param name="ray">
/// The reay used to determine if the XY plane was being interacted with.
/// </param>
private void HandleXY(Ray ray)
{
float enter;
this.planeXY.Raycast(ray, out enter);
var hit = ray.GetPoint(enter);
hit = this.rotationMatrix.inverse.MultiplyPoint(hit);

if (this.typeMovementBeingMade == TypeOfMove.None && hit.x > 0f && hit.x <= this.panScale * this.cameraDistance && hit.y > 0
&& hit.y <= this.panScale * this.cameraDistance)
{
this.hitMouseDown = hit;
this.isDragging = true;
}

{
this.hitMouseMove = hit - this.hitMouseDown;
this.hitMouseMove.z = 0;
this.UpdatePosition(this.worldTranslation ? this.hitMouseMove : this.transform.localRotation * this.hitMouseMove);
}

if (this.typeMovementBeingMade == TypeOfMove.None && hit.x > 0f && hit.x <= this.cameraDistance
&& Mathf.Abs(hit.y) < this.axisEnvelope * this.cameraDistance)
{
// case x
this.hitMouseDown = hit;
this.isDragging = true;
}

if (this.typeMovementBeingMade == TypeOfMove.X2Axis && this.inputAxisChanged)
{
this.hitMouseMove = hit - this.hitMouseDown;
this.hitMouseMove.y = 0;
this.hitMouseMove.z = 0;
this.UpdatePosition(this.worldTranslation ? this.hitMouseMove : this.transform.localRotation * this.hitMouseMove);
}

if (this.typeMovementBeingMade == TypeOfMove.None && hit.y > 0f && hit.y <= this.cameraDistance
&& Mathf.Abs(hit.x) < this.axisEnvelope * this.cameraDistance)
{
// case y
this.hitMouseDown = hit;
this.isDragging = true;
}

if (this.typeMovementBeingMade == TypeOfMove.YAxis && this.inputAxisChanged)
{
this.hitMouseMove = hit - this.hitMouseDown;
this.hitMouseMove.z = 0;
this.hitMouseMove.x = 0;
this.UpdatePosition(this.worldTranslation ? this.hitMouseMove : this.transform.localRotation * this.hitMouseMove);
}
}

/// <summary>
/// Handles dragging along the XZ plane.
/// </summary>
/// <param name="ray">
/// The reay used to determine if the XZ plane was being interacted with.
/// </param>
private void HandleXZ(Ray ray)
{
float enter;
this.planeXZ.Raycast(ray, out enter);
var hit = ray.GetPoint(enter);
hit = this.rotationMatrix.inverse.MultiplyPoint(hit);

if (this.typeMovementBeingMade == TypeOfMove.None && hit.x > 0f && hit.x <= this.panScale * this.cameraDistance && hit.z > 0
&& hit.z <= this.panScale * this.cameraDistance)
{
this.hitMouseDown = hit;
this.isDragging = true;
}

if (this.typeMovementBeingMade == TypeOfMove.XZAxis && this.inputAxisChanged)
{
this.hitMouseMove = hit - this.hitMouseDown;
this.hitMouseMove.y = 0;
this.UpdatePosition(this.worldTranslation ? this.hitMouseMove : this.transform.localRotation * this.hitMouseMove);
}

if (this.typeMovementBeingMade == TypeOfMove.None && hit.x > 0f && hit.x <= this.cameraDistance
&& Mathf.Abs(hit.z) < this.axisEnvelope * this.cameraDistance)
{
// case x
this.hitMouseDown = hit;
this.isDragging = true;
}

if (this.typeMovementBeingMade == TypeOfMove.XAxis && this.inputAxisChanged)
{
this.hitMouseMove = hit - this.hitMouseDown;
this.hitMouseMove.y = 0;
this.hitMouseMove.z = 0;
this.UpdatePosition(this.worldTranslation ? this.hitMouseMove : this.transform.localRotation * this.hitMouseMove);
}

if (this.typeMovementBeingMade == TypeOfMove.None && hit.z > 0f && hit.z <= this.cameraDistance
&& Mathf.Abs(hit.x) < this.axisEnvelope * this.cameraDistance)
{
// case  z
this.hitMouseDown = hit;
this.isDragging = true;
}

if (this.typeMovementBeingMade == TypeOfMove.ZAxis && this.inputAxisChanged)
{
this.hitMouseMove = hit - this.hitMouseDown;
this.hitMouseMove.y = 0;
this.hitMouseMove.x = 0;
this.UpdatePosition(this.worldTranslation ? this.hitMouseMove : this.transform.localRotation * this.hitMouseMove);
}
}

/// <summary>
/// Handles dragging along the YZ plane.
/// </summary>
/// <param name="ray">
/// The reay used to determine if the YZ plane was being interacted with.
/// </param>
private void HandleYZ(Ray ray)
{
float enter;
this.planeYZ.Raycast(ray, out enter);
var hit = ray.GetPoint(enter);
hit = this.rotationMatrix.inverse.MultiplyPoint(hit);

if (this.typeMovementBeingMade == TypeOfMove.None && hit.z > 0 && hit.z <= this.panScale * this.cameraDistance && hit.y > 0
&& hit.y <= this.panScale * this.cameraDistance)
{
this.hitMouseDown = hit;
this.isDragging = true;
}

{
this.hitMouseMove = hit - this.hitMouseDown;
this.hitMouseMove.x = 0;
this.UpdatePosition(this.worldTranslation ? this.hitMouseMove : this.transform.localRotation * this.hitMouseMove);
}

if (this.typeMovementBeingMade == TypeOfMove.None && hit.z > 0f && hit.z <= this.cameraDistance
&& Mathf.Abs(hit.y) < this.axisEnvelope * this.cameraDistance)
{
// case  z
this.hitMouseDown = hit;
this.isDragging = true;
}

if (this.typeMovementBeingMade == TypeOfMove.Z2Axis && this.inputAxisChanged)
{
this.hitMouseMove = hit - this.hitMouseDown;
this.hitMouseMove.y = 0;
this.hitMouseMove.x = 0;
this.UpdatePosition(this.worldTranslation ? this.hitMouseMove : this.transform.localRotation * this.hitMouseMove);
}

if (this.typeMovementBeingMade == TypeOfMove.None && hit.y > 0f && hit.y <= this.cameraDistance
&& Mathf.Abs(hit.z) < this.axisEnvelope * this.cameraDistance)
{
// case y
this.hitMouseDown = hit;
this.isDragging = true;
}

if (this.typeMovementBeingMade == TypeOfMove.Y2Axis && this.inputAxisChanged)
{
this.hitMouseMove = hit - this.hitMouseDown;
this.hitMouseMove.z = 0;
this.hitMouseMove.x = 0;
this.UpdatePosition(this.worldTranslation ? this.hitMouseMove : this.transform.localRotation * this.hitMouseMove);
}
}

/// <summary>
/// Called by unity when after camera has rendered the scene.
/// </summary>
private void OnRenderObject()
{
// set the material pass is a material has been specified
var material = this.lineMaterial;
if (material != null)
{
material.SetPass(0);
}

// push a matrix on to the stack
GL.PushMatrix();
this.rotationMatrix = this.transform.localToWorldMatrix;

// setup rotation matrix
if (this.worldTranslation)
{
this.rotationMatrix = Matrix4x4.TRS(this.transform.position, Quaternion.identity, Vector3.one);
}
else
{
this.rotationMatrix = Matrix4x4.TRS(this.transform.position, this.transform.localRotation, Vector3.one);
}

GL.MultMatrix(this.rotationMatrix);

// draw each axis
this.DrawAxis(this.xAxisColor, Vector3.right, Vector3.up, Vector3.forward);
this.DrawAxis(this.yAxisColor, Vector3.up, Vector3.right, Vector3.forward);
this.DrawAxis(this.zAxisColor, Vector3.forward, Vector3.right, Vector3.up);

GL.PopMatrix();
}

/// <summary>
/// Updates the transform position and raises the <see cref="PositionChanged"/> event.
/// </summary>
/// <param name="value">
/// The value to add on to the existing transform position.
/// </param>
private void UpdatePosition(Vector3 value)
{
var position = this.transform.position;
var previousPosition = position;
position += value;
this.transform.position = position;
this.OnPositionChanged(previousPosition, position);
}

#endregion
}

///
/// Provides event arguments for the  type.
///
public class Vector3EventArgs : EventArgs
{
#region Constructors and Destructors

///
/// Initializes a new instance of the  class.
///
///
/// The previous value.
///
///
/// The current value.
///
public Vector3EventArgs(Vector3 previousValue, Vector3 value)
{
this.Value = value;
this.PreviousValue = previousValue;
}

///
/// Initializes a new instance of the  class.
///
public Vector3EventArgs()
{
}

#endregion

#region Public Properties

///
/// Gets or sets a previous  value.
///
public Vector3 PreviousValue { get; set; }

///
/// Gets or sets a  value.
///
public Vector3 Value { get; set; }

#endregion
}```

# Unity 101 Tip #92 – Adding Tab and Shift-Tab support to TextArea and TextField

Published 2/8/2016 by createdbyx in Code Snippets | Example | Programming | Unity
Tags: , , ,

I needed to add tab key support to a GUI.TextArea and soon discovered it was not quite as easy as I had originally thought. I have provided two code examples below. The first example is simplified and the second example is more complex that wraps TextArea controls inside of parent control.

With these examples you can type text in a TextArea/TextField and press the tab key to insert 4 spaces, or press Shift+Tab to move the line 4 spaces to the left if the area is clear.

I have also provided a third advanced example from my UIControls library to give an example of a real word usage scenario. This third example synchronizes my TextBox control with the unity’s TextEditor. My TextBox control has similar properties as Winforms TextBox.

Simplified example

```using System;
using UnityEditor;
using UnityEngine;

public class TextAreaTabSupport : EditorWindow
{
private int lastKBFocus = -1;
private string textA = string.Empty;
private string textB = string.Empty;
private string textC = string.Empty;

public static void ShowWindow()
{
GetWindow<TextAreaTabSupport>().Show();
}

public void OnGUI()
{
var current = Event.current;
GUI.SetNextControlName("testa");

if (GUI.GetNameOfFocusedControl() == "testa" && this.lastKBFocus == GUIUtility.keyboardControl)
{
if (current.type == EventType.KeyDown || current.type == EventType.KeyUp)
{
if (current.isKey && (current.keyCode == KeyCode.Tab || current.character == '\t'))
{
if (current.type == EventType.KeyUp)
{
var te = (TextEditor)GUIUtility.GetStateObject(typeof(TextEditor), GUIUtility.keyboardControl);

if (!current.shift)
{
for (var i = 0; i < 4; i++)
{
te.Insert(' ');
}
}
else
{
var min = Math.Min(te.cursorIndex, te.selectIndex);
var index = min;
var temp = te.text;
for (var i = 1; i < 5; i++)
{
if ((min - i) < 0 || temp[min - i] != ' ')
{
break;
}

index = min - i;
}

if (index < min)
{
te.selectIndex = index;
te.cursorIndex = min;
te.ReplaceSelection(string.Empty);
}
}

this.textA = te.text;
}

current.Use();
}
}
}

this.textA = GUI.TextArea(new Rect(0, 40, 100, 100), this.textA);

if (GUI.GetNameOfFocusedControl() == "testa" && current.type == EventType.KeyDown || current.type == EventType.KeyUp)
{
this.lastKBFocus = GUIUtility.keyboardControl;
}

GUI.SetNextControlName("testb");
this.textB = GUI.TextArea(new Rect(110, 40, 100, 100), this.textB);

GUI.SetNextControlName("testc");
this.textC = GUI.TextField(new Rect(220, 40, 100, 30), this.textC);

if (GUI.Button(new Rect(10, 110, 50, 25), "Click"))
{

}
}
}```

And a more complex example

```using System;
using UnityEditor;
using UnityEngine;

public class TextAreaTabSupport : EditorWindow
{
private Vector2 scroll;
private int lastKBFocus = -1;
private string textA = string.Empty;
private string textB = string.Empty;
private string textC = string.Empty;

public static void ShowWindow()
{
GetWindow<TextAreaTabSupport>().Show();
}

public void OnGUI()
{
var current = Event.current;

GUI.SetNextControlName("scroller");
using (var scroll = new GUI.ScrollViewScope(new Rect(Vector2.zero, new Vector2(330, 150)), this.scroll, new Rect(Vector2.zero, new Vector2(330, 150))))
{
this.scroll = scroll.scrollPosition;

if (GUI.GetNameOfFocusedControl() == "testa" && this.lastKBFocus == GUIUtility.keyboardControl)
{
if (current.type == EventType.KeyDown || current.type == EventType.KeyUp)
{
if (current.isKey && (current.keyCode == KeyCode.Tab || current.character == '\t'))
{
if (current.type == EventType.KeyUp)
{
var te = (TextEditor)GUIUtility.GetStateObject(typeof(TextEditor), GUIUtility.keyboardControl);

if (!current.shift)
{
for (var i = 0; i < 4; i++)
{
te.Insert(' ');
}
}
else
{
var min = Math.Min(te.cursorIndex, te.selectIndex);
var index = min;
var temp = te.text;
for (var i = 1; i < 5; i++)
{
if ((min - i) < 0 || temp[min - i] != ' ')
{
break;
}

index = min - i;
}

if (index < min)
{
te.selectIndex = index;
te.cursorIndex = min;
te.ReplaceSelection(string.Empty);
}
}

this.textA = te.text;
}

current.Use();
}
}
}

using (new GUI.GroupScope(new Rect(0, 0, 110, 110)))
{
GUI.SetNextControlName("testa");
this.textA = GUI.TextArea(new Rect(0, 4, 100, 100), this.textA);
}

if (this.lastKBFocus != GUIUtility.keyboardControl && (current.type == EventType.KeyDown || current.type == EventType.KeyUp))
{
this.lastKBFocus = GUIUtility.keyboardControl;
}

GUI.SetNextControlName("testb");
this.textB = GUI.TextArea(new Rect(110, 40, 100, 100), this.textB);

GUI.SetNextControlName("testc");
this.textC = GUI.TextField(new Rect(220, 40, 100, 30), this.textC);

if (GUI.Button(new Rect(10, 110, 50, 25), "Click"))
{

}
}
}
}```

```namespace Codefarts.UIControls.Renderers
{
#if UNITY_5
using System;

using UnityEngine;

/// <summary>
/// Provides a renderer implementation for the <see cref="TextBox"/> control.
/// </summary>
[ControlRenderer(typeof(TextBox))]
public class TextBoxRenderer : BaseRenderer
{
/// <summary>
/// Implemented by inheritors to draw the actual control.
/// </summary>
/// <param name="args">The rendering argument information.</param>
/// <exception cref="System.ArgumentNullException">control</exception>
public override void DrawControl(ControlRenderingArgs args)
{
var textBox = (TextBox)args.Control;

// unity gui does not like null strings
var text = textBox.Text == null ? string.Empty : textBox.Text;

var maxLength = textBox.MaxLength == 0 ? int.MaxValue : textBox.MaxLength;

var rect = new Rect(textBox.Location + args.Offset, textBox.Size);
var hsbVisibility = textBox.HorizontalScrollBarVisibility;
var vsbVisibility = textBox.VerticalScrollBarVisibility;
var alwaysShowHorizontal = hsbVisibility == ScrollBarVisibility.Visible;
var alwaysShowVertical = vsbVisibility == ScrollBarVisibility.Visible;

KeyCode keyCode;
bool isDown;
bool isUp;
string controlName;
this.GetKeyInfoAndSetControlName(textBox, out keyCode, out isDown, out isUp, out controlName, false);

// get style and sync it up
var style = textBox.GetStyle(Control.ControlStyle, true, GUI.skin.textArea);
if (textBox.Font != null)
{
style.SetFontStyle(textBox.Font);
}

var current = Event.current;
int lastKBFocus;
textBox.Properties.TryGetValueCast(ControlDrawingHelpers.LastKeyboardControlID, out lastKBFocus, -1);
var selectionStart = textBox.SelectionStart;
var selectionLength = textBox.SelectionLength;

if (GUI.GetNameOfFocusedControl() == controlName && lastKBFocus == GUIUtility.keyboardControl)
{
var te = (TextEditor)GUIUtility.GetStateObject(typeof(TextEditor), GUIUtility.keyboardControl);

// sync textbox & texteditor selections
this.SyncTextBoxSelection(TextBox.TextBoxSelectionStartChanged, te, textBox);
this.SyncTextBoxSelection(TextBox.TextBoxSelectionLengthChanged, te, textBox);

// process tab key if nessary
text = this.HandleTabKeyPress(ref selectionStart, te, current, textBox, text);

selectionLength = Math.Abs(te.cursorIndex - te.selectIndex);
}

// draw the text area/field control
textBox.Text = this.DrawActualTextControl(textBox, text, rect, alwaysShowHorizontal, alwaysShowVertical, style, maxLength, controlName);

// check if we need to record last keyboard control id
if (GUI.GetNameOfFocusedControl() == controlName && lastKBFocus != GUIUtility.keyboardControl)
{
textBox.Properties[ControlDrawingHelpers.LastKeyboardControlID] = GUIUtility.keyboardControl;
}

// check is text selection changed and sync if nessary
if (textBox.SelectionStart != selectionStart)
{
textBox.SelectionStart = selectionStart;
}
if (textBox.SelectionLength != selectionLength)
{
textBox.SelectionLength = selectionLength;
}

// Handle key events
this.HandleKeyEventsAfterControlDrawn(controlName, keyCode, isDown, textBox, isUp);

// handle mouse enter & leave events
this.HandleMouseEvents(textBox);
}

private string HandleTabKeyPress(ref int selectionStart, TextEditor te, Event current, TextBox textBox, string text)
{
selectionStart = Math.Min(te.cursorIndex, te.selectIndex);
if (current.type == EventType.KeyDown || current.type == EventType.KeyUp)
{
if (current.isKey && (current.keyCode == KeyCode.Tab || current.character == '\t'))
{
// consume the tab key event before drawing the control
if (current.type == EventType.KeyUp && textBox.AcceptsTab)
{
if (!current.shift)
{
for (var i = 0; i < 4; i++)
{
te.Insert(' ');
}
}
else
{
var min = selectionStart;
var index = min;
var temp = te.text;
for (var i = 1; i < 5; i++)
{
if ((min - i) < 0 || temp[min - i] != ' ')
{
break;
}

index = min - i;
}

if (index < min)
{
te.selectIndex = index;
te.cursorIndex = min;
te.ReplaceSelection(string.Empty);
}
}

selectionStart = Math.Min(te.cursorIndex, te.selectIndex);

text = te.text;
}

current.Use();
}
}

return text;
}

private void SyncTextBoxSelection(string name, TextEditor editor, TextBox tb)
{
var props = tb.Properties;
if (props != null)
{
bool changed;
if (props.TryGetValueCast(name, out changed, false) && changed)
{
props[name] = false;
this.SetTextEditorSelection(editor, tb.SelectionStart, tb.SelectionLength);
}
}
}

private void SetTextEditorSelection(TextEditor editor, int start, int length)
{
if (editor.cursorIndex < editor.selectIndex)
{
editor.cursorIndex = start;
editor.selectIndex = start + length;
}
else
{
editor.selectIndex = start;
editor.cursorIndex = start + length;
}
}

protected virtual string DrawActualTextControl(TextBox textBox, string text, Rect rect, bool alwaysShowHorizontal, bool alwaysShowVertical,
GUIStyle style, int maxLength, string controlName)
{
var scrollPosition = new Vector2(-textBox.HorizontalOffset, -textBox.VerticalOffset);
if (textBox.AcceptsReturn)
{
var textSize = GUI.skin.textArea.CalcSize(new GUIContent(text));
var viewRect = new Rect(Vector2.zero, textSize);
viewRect.width = Math.Max(textSize.x, rect.width);
viewRect.height = Math.Max(textSize.y, rect.height);

var drawHorizScroll = viewRect.width > rect.width || alwaysShowHorizontal;
var drawVertScroll = viewRect.height > rect.height || alwaysShowVertical;

var horizRect = new Rect(
0,
rect.height - GUI.skin.horizontalScrollbar.fixedHeight,
rect.width - (drawVertScroll ? GUI.skin.verticalScrollbar.fixedWidth : 0),
GUI.skin.horizontalScrollbar.fixedHeight);
var vertRect = new Rect(
rect.width - GUI.skin.verticalScrollbar.fixedWidth,
0,
GUI.skin.verticalScrollbar.fixedWidth,
rect.height - (drawHorizScroll ? GUI.skin.horizontalScrollbar.fixedHeight : 0));
horizRect.position += rect.position;
vertRect.position += rect.position;

scrollPosition.x = drawHorizScroll ? scrollPosition.x : 0;
scrollPosition.y = drawVertScroll ? scrollPosition.y : 0;

viewRect.position = scrollPosition;
var grpRect = new Rect(
rect.x,
rect.y,
rect.width - (drawVertScroll ? GUI.skin.verticalScrollbar.fixedWidth : 0),
rect.height - (drawHorizScroll ? GUI.skin.horizontalScrollbar.fixedHeight : 0));

using (new GUI.GroupScope(grpRect))
{
// draw background
var brush = textBox.Background;
if (brush != null)
{
BrushExtensions.Draw(brush, new Rect(Vector2.zero, grpRect.size));
}

GUI.SetNextControlName(controlName);
// as of unity v5.3 there is a bug that prevent me from specifying a maxlength
//BUG: see details here -> https://fogbugz.unity3d.com/default.asp?768436_vikdrmh7ernh03ls
text = GUI.TextArea(viewRect, text, style);
}

if (drawHorizScroll)
{
textBox.HorizontalOffset = GUI.HorizontalScrollbar(
horizRect,
textBox.HorizontalOffset,
Math.Min(viewRect.width, rect.width),
0,
viewRect.width + (drawVertScroll ? GUI.skin.verticalScrollbar.fixedWidth : 0));
}

if (drawVertScroll)
{
textBox.VerticalOffset = GUI.VerticalScrollbar(
vertRect,
textBox.VerticalOffset,
Math.Min(viewRect.height, rect.height),
0,
viewRect.height + (drawHorizScroll ? GUI.skin.horizontalScrollbar.fixedHeight : 0));
}
}
else
{
// draw background
var brush = textBox.Background;
if (brush != null)
{
BrushExtensions.Draw(brush, rect);
}
GUI.SetNextControlName(controlName);
text = GUI.TextField(rect, text, maxLength, style);
}

return text;
}
}
#endif
}```

# Unity 101 Tip #91 – Draw GUI Texture helper method

Published 2/1/2016 by createdbyx in Code Snippets | Programming | Unity
Tags: , , , ,

The code below provides a handy helper method for drawing GUI textures via GUI.DrawTextureWithTexCoords.

```///
/// Draws a image image.
///
/// The destination image.
/// The x position in the destination image.
/// The y position in the destination image.
/// The destination width of the drawn image.
/// The destination height of the drawn image.
/// If set to true the image will be drawn fliped horizontally.
/// If set to true the image will be drawen flipped vertically.
/// If set to true the image will be tiled across the destination area.
/// image
/// If width, height, sourceWidth or sourceHeight are less then 1.
public static void Draw(Texture2D image, float x, float y, float width, float height, bool flipHorizontally, bool flipVertically, bool tile)
{
Draw(image, x, y, width, height, 0, 0, image.width, image.height, false, false, false);
}

///
/// Draws a image image.
///
/// The destination image.
/// The x position in the destination image.
/// The y position in the destination image.
/// The destination width of the drawn image.
/// The destination height of the drawn image.
/// The x position in the source image.
/// The y position in the source image.
/// The source width.
/// The source height.
/// image
/// If width, height, sourceWidth or sourceHeight are less then 1.
public static void Draw(Texture2D image, float x, float y, float width, float height, float sourceX, float sourceY, float sourceWidth, float sourceHeight)
{
Draw(image, x, y, width, height, sourceX, sourceY, sourceWidth, sourceHeight, false, false, false);
}

///
/// Draws a image image.
///
/// The destination image.
/// The x position in the destination image.
/// The y position in the destination image.
/// The destination width of the drawn image.
/// The destination height of the drawn image.
/// The x position in the source image.
/// The y position in the source image.
/// The source width.
/// The source height.
/// If set to true the image will be drawn fliped horizontally.
/// If set to true the image will be drawen flipped vertically.
/// If set to true the image will be tiled across the destination area.
/// image
/// If width, height, sourceWidth or sourceHeight are less then 1.
/// This method has issues with Clamped textures.
public static void Draw(Texture2D image, float x, float y, float width, float height, float sourceX, float sourceY, float sourceWidth, float sourceHeight,
bool flipHorizontally, bool flipVertically, bool tile)
{
// perform input validation
if (image == null)
{
throw new ArgumentNullException("image");
}

if (sourceWidth < float.Epsilon)
{
throw new ArgumentOutOfRangeException("sourceWidth");
}

if (sourceHeight < float.Epsilon)
{
throw new ArgumentOutOfRangeException("sourceHeight");
}

if (width < float.Epsilon)
{
return;
}

if (height < float.Epsilon)
{
return;
}

var imgWidth = (float)image.width;
var imgHeight = (float)image.height;
var srcWidth = sourceWidth / imgWidth;
var srcHeight = sourceHeight / imgHeight;
var position = new Rect(x, y + height, width, -height);
if (tile)
{
srcWidth = width / imgWidth;
srcHeight = height / imgHeight;
}

srcWidth = flipHorizontally ? -srcWidth : srcWidth;
srcHeight = !flipVertically ? -srcHeight : srcHeight;

var texCoords = new Rect(sourceX / imgWidth, imgHeight - (sourceY / imgHeight), srcWidth, srcHeight);

GUI.DrawTextureWithTexCoords(position, image, texCoords, true);
}```

# Unity 101 Tip #90 – Renderer.IsVisibleFrom extension method

Published 1/25/2016 by createdbyx in Code Snippets | Unity
Tags: , , , ,
```/// <summary>
/// Determines whether the renderer is visible from the specified camera.
/// </summary>
/// <param name="renderer">The renderer to check for visibility.</param>
/// <param name="camera">The camera to check against.</param>
/// <returns>true if the renderer is visible to the camera; otherwise false.</returns>
public static bool IsVisibleFrom(this Renderer renderer, Camera camera)
{
var planes = GeometryUtility.CalculateFrustumPlanes(camera);
return GeometryUtility.TestPlanesAABB(planes, renderer.bounds);
}```

# Unity 101 Tip #89 – using block / GuiEnabled

Published 1/18/2016 by createdbyx in Unity
Tags: , , ,

The code below allows you to set and automatically restore the GUI.enabled state when used with a using block similar to GUILayout.HorizontialScope.

```/// <summary>
/// Provides  a class for setting and restoring GUI.enabled.
/// </summary>
public class GuiEnabled : IDisposable
{
/// <summary>
/// Gets or sets a value indicating the state that is to be restored.
/// </summary>
public bool StateToBeRestored { get; set; }

/// <summary>
/// Initializes a new instance of the <see cref="GuiEnabled"/> class.
/// </summary>
/// <param name="stateToBeRestored">Value indicating the state that is to be restored.</param>
public GuiEnabled(bool stateToBeRestored)
{
this.StateToBeRestored = stateToBeRestored;
}

/// <summary>
/// Initializes a new instance of the <see cref="GuiEnabled"/> class.
/// </summary>
/// <param name="stateToBeRestored">If set to <c>true</c> the GUI.enabled state will be restored to this value.</param>
/// <param name="setState">Immediatley sets the value of GUI.enabled to this state.</param>
public GuiEnabled(bool stateToBeRestored, bool setState) : this(stateToBeRestored)
{
GUI.enabled = setState;
}

/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
GUI.enabled = this.StateToBeRestored;
}
}```

Here is an simple use case

```GUILayout.Button("Enabled button");
using (var enabled = new GuiEnabled(GUI.enabled, false))
{
GUILayout.Button("Disabled button");
//if (someCondition)
//{
// setting to false means after we exit the using block GUI.enabled will be set to false.
//    enabled.StateToBeRestored = false;
//}
}
GUILayout.Button("Enabled button");```

# Unity 101 Tip #88 – Show In Explorer

Published 11/6/2015 by createdbyx in Unity
Tags: , ,

If you need your editor scripts to have the same functionality as “Assets->Show In Explorer” check out the cross platform method EditorUtility.RevealInFinder. This method is currently undocumented in Unity 5.2.1.

# Created by: X

## Just another personal website in this crazy online world

 Dean Lunz (aka Created by: X) Computer programming nerd, and tech geek. About Me -- Resume