Website may be up and down over next few months. I'm currently doing a complete overhaul of everything. Going back to simple individual .htm pages, new overall site theme, sanitizing and cleaning up html of all pages and blog posts, attempting to implement a new tooling and publishing system etc etc.

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;

    [MenuItem("Test/Text Area Tab Support")]
    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;

    [MenuItem("Test/Text Area Tab Support")]
    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"))
            {

            }
        }
    }
}

Advanced example

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      
}

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);
}

Provides a helper method for determining weather two value ranges intersect.

LINQPad v4 C# sample RangeIntersection.linq (5.18 kb)

/// <summary>
/// Check for the intersection between two sets of ranges.
/// </summary>
/// <param name="range1Start">The start of the first range.</param>
/// <param name="range1End">The end of the first reage.</param>
/// <param name="range2Start">The start of the second range.</param>
/// <param name="range2End">The end of the second range.</param>
/// <returns>true if the two ranges intersect with each other; otherwise false.</returns>
public static bool RangeIntersection(int range1Start, int range1End, int range2Start, int range2End)
{
    var r1Start = range1Start;
    var r1End = range1End;
    var r2Start = range2Start;
    var r2End = range2End;

    if (range1Start > range1End)
    {
        r1Start = range1End;
        r1End = range1Start;
    }

    if (range2Start > range2End)
    {
        r2Start = range2End;
        r2End = range2Start;
    }

    var greatestStart = r1Start > r2Start ? r1Start : r2Start;
    var smallestEnd = r1End < r2End ? r1End : r2End;
    return !(greatestStart > smallestEnd);
}

RangeChecking


        /// <summary>Retrieves and removes an item from the list.</summary>
        /// <typeparam name="T">The type that the generic list contains.</typeparam>
        /// <param name="list">The list.</param>
        /// <param name="index">The index of the item to be pulled out of the list.</param>
        public static T PullItemAt<T>(this IList<T> list, int index)
        {
            var item = list[index];
            list.RemoveAt(index);
            return item;
        }

/// <summary>
/// Adds items to a <see cref="ObservableCollection{T}"/>.
/// </summary>
/// <typeparam name="T">The generic type that the generic observable collection stores.</typeparam>
/// <param name="list">The list where items will be added to.</param>
/// <param name="items">The items to be added.</param>
public static void AddRange<T>(this ObservableCollection<T> list, IEnumerable<T> items)
{
    foreach (var item in items)
    {
        list.Add(item);
    }
}

/// <summary>
/// Tries to get a value from the generic list.
/// </summary>
/// <typeparam name="T">The type that the generic list contains.</typeparam>
/// <param name="list">The generic list reference.</param>
/// <param name="predicate">The predicate used to find the desired element.</param>
/// <param name="item">The item to be returned if the <see cref="predicate"/> argument finds a match.</param>
/// <returns>true if a item was found; otherwise false.</returns>
public static bool TryGet<T>(this IList<T> list, Func<T, bool> predicate, out T item)
{
    var result = list.Where(predicate).ToArray();
    item = result.FirstOrDefault();
    return result.Length != 0;
}

/// <summary>
/// Tries to get a value from the generic list.
/// </summary>
/// <typeparam name="T">The type that the generic list contains.</typeparam>
/// <typeparam name="S">The type that the selector function will return.</typeparam>
/// <param name="list">The generic list reference.</param>
/// <param name="predicate">The predicate used to find the desired element.</param>
/// <param name="selector">The selector function used to retrieve a value from the matched item. determined by the <see cref="predicate"/> argument.</param>
/// <param name="item">The item to be returned if the <see cref="predicate"/> argument finds a match.</param>
/// <returns>true if a item was found; otherwise false.</returns>
public static bool TryGet<T, S>(this IList<T> list, Func<T, bool> predicate, Func<T, S> selector, out S item)
{
    var result = list.Where(predicate).ToArray();
    item = selector(result.FirstOrDefault());
    return result.Length != 0;
}

public static string GetMD5HashFromFile(string fileName)
{
    byte[] retVal;
    using (var file = new FileStream(fileName, FileMode.Open))
    {
        var md5 = new MD5CryptoServiceProvider();
        retVal = md5.ComputeHash(file);
    }

    var sb = new StringBuilder();
    for (var i = 0; i < retVal.Length; i++)
    {
        sb.Append(retVal[i].ToString("x2"));
    }

    return sb.ToString();
}

A simple performance test for comparing direct file property access or creating a FileInfo object.

The results show that if you are accessing more then one file property FileInfo is the way to go otherwise File.GetCreationTime and related methods have the same performance hit.

100 iterations of c:\windows
directValues –> 00:00:00.2900065
infoValues –> 00:00:00.1611554

void Main()
{
    var folder = "c:\\windows";
    var files = Directory.GetFiles(folder, "*.*", SearchOption.TopDirectoryOnly);

    var stopwatch = new Stopwatch();
    var directValues = 0l;
    var infoValues = 0l;
    for (int i = 0; i < 100; i++)
    {
        stopwatch.Restart();
        stopwatch.Start();
        foreach (var file in files)
        {
            var lastWriteTime = File.GetLastWriteTime(file);
            var creationTime = File.GetCreationTime(file);
        }

        stopwatch.Stop();
        directValues += stopwatch.ElapsedTicks;

        stopwatch.Restart();
        stopwatch.Start();
        foreach (var file in files)
        {
            var info = new FileInfo(file);
            var lastWriteTime = info.LastWriteTime;
            var creationTime = info.CreationTime;
        }

        stopwatch.Stop();
        infoValues += stopwatch.ElapsedTicks;

    }

    "100 iterations of c:\\windows".Dump();
    TimeSpan.FromTicks(directValues).Dump("directValues");
    TimeSpan.FromTicks(infoValues).Dump("infoValues");
}

Full repo available at https://bitbucket.org/createdbyx/codefarts.utilities-extension-methods-only

/// <summary>Determines whether a value in within a certain range.</summary>
/// <param name="value">The value.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
/// <returns>True if the value is in range.</returns>
public static bool IsInRange(this BaseType value, BaseType min, BaseType max)
{
    return value >= min && value <= max;
}

/// <summary>Determines whether a value in within a certain range.</summary>
/// <param name="value">The value.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
/// <param name="throwException">if set to <c>true</c> will throw a <see cref="IndexOutOfRangeException"/> if the value is out of range.</param>
/// <returns>True if the value is in range.</returns>
/// <exception cref="System.IndexOutOfRangeException">Is thrown if the value is out of range.</exception>
public static bool IsInRange(this BaseType value, BaseType min, BaseType max, bool throwException)
{
    if (!(value >= min && value <= max) && throwException)
    {
        throw new IndexOutOfRangeException();
    }

    return true;
}

/// <summary>Determines whether a value in within a certain range.</summary>
/// <param name="value">The value.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
/// <param name="throwException">if set to <c>true</c> will throw a <see cref="IndexOutOfRangeException"/> if the value is out of range.</param>
/// <param name="message">The message for the <see cref="IndexOutOfRangeException"/> if it is thrown.</param>
/// <returns>True if the value is in range.</returns>
/// <exception cref="System.IndexOutOfRangeException">Is thrown if the value is out of range.</exception>
public static bool IsInRange(this BaseType value, BaseType min, BaseType max, bool throwException, string message)
{
    if (!(value >= min && value <= max) && throwException)
    {
        throw new IndexOutOfRangeException(message);
    }

    return true;
}

Full repo available at https://bitbucket.org/createdbyx/codefarts.utilities-extension-methods-only

/// <summary>
/// Clamps the specified value.
/// </summary>
/// <param name="value">The value to be clamped.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
/// <returns>The clamped value.</returns>
public static BaseType Clamp(this BaseType value, BaseType min, BaseType max)
{
    if (value < min)
    {
        return min;
    }

    if (value > max)
    {
        return max;
    }

    return value;
}

Created by: X

Just another personal website in this crazy online world

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