Calendar
Mo | Tu | We | Th | Fr | Sa | Su |
---|
25 | 26 | 27 | 28 | 29 | 30 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 1 | 2 | 3 | 4 | 5 |
Archive
- 2002
- 2003
- 2004
- 2005
- 2006
- 2007
- 2008
- 2009
- 2010
- 2011
- 2012
- 2013
- 2014
- 2015
- 2016
- 2019
- 2020
|
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.
The XAML. Use null to define a separator.
<Menu Name="MainMenu" Grid.Row="0" IsMainMenu="True" ItemsSource="{Binding Model}">
<Menu.Resources>
<ControlTemplate x:Key="MenuSeparatorTemplate">
<Separator />
</ControlTemplate>
</Menu.Resources>
<Menu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding Command}" />
<Setter Property="CommandParameter" Value="{Binding CommandParameter}" />
<Setter Property="Header" Value="{Binding Header}" />
<Setter Property="ItemsSource" Value="{Binding Children}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding }" Value="{x:Null}">
<Setter Property="Template" Value="{StaticResource MenuSeparatorTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Menu.ItemContainerStyle>
</Menu>
1904ebec-5d8f-42d8-926b-b4ae27f98984|0|.0
/// <summary>
/// Determines whether an enum has been marked Obsolete.
/// </summary>
/// <param name="value">The enum value to check against.</param>
/// <returns>
/// <c>true</c> if marked obsolete; otherwise, <c>false</c>.
/// </returns>
public static bool IsEnumObsolete(this Enum value)
{
var fi = value.GetType().GetField(value.ToString());
var attributes = (ObsoleteAttribute[])fi.GetCustomAttributes(typeof(ObsoleteAttribute), false);
return attributes.Length > 0;
}
be7a966d-9156-44a5-9022-2764949e4101|0|.0
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
}
7e8e00a5-cad7-4eca-8192-9fb6363764d9|1|1.0
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");
}
f166ac5a-7acc-43a8-9cf9-3076c5e1dfb1|1|5.0
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;
}
4f516f2a-bf73-42fd-b45b-ecb8ae75995d|0|.0
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;
}
c9e15e0d-15b9-4029-8e20-43d032c50e38|0|.0
Full repo available at https://bitbucket.org/createdbyx/codefarts.utilities-extension-methods-only /// <summary>
/// Determines weather or not all the characters in a string are all the same.
/// </summary>
/// <param name="value">The value to check for.</param>
/// <returns>true is all characters are the same, otherwise false.</returns>
public static bool AllTheSame(this string value)
{
#if UNITY3D
if (!StringExtensionMethods.IsNullOrWhiteSpace(value))
#else
if (!string.IsNullOrWhiteSpace(value))
#endif
{
var clone = new string(value[0], value.Length);
return clone == value;
}
return false;
}
#if UNITY3D
public static bool IsNullOrWhiteSpace(this string value)
{
if (value == null)
{
return true;
}
for (var i = 0; i < value.Length; i++)
{
if (!char.IsWhiteSpace(value[i]))
{
return false;
}
}
return true;
}
#endif
}
921b6831-b717-421d-ba8f-8ad18fd0f56d|0|.0
Full repo available at https://bitbucket.org/createdbyx/codefarts.utilities-extension-methods-only namespace System.Collections
{
/// <summary>
/// Provides extension methods for the IList interface.
/// </summary>
public static class IListExtensionMethods
{
/// <summary>Swaps the specified items in a list.</summary>
/// <param name="list">The list.</param>
/// <param name="indexA">The index of item A.</param>
/// <param name="indexB">The index of item B.</param>
/// <param name="remove">If set to <c>true</c> items will be removed and re-inserted.</param>
public static void Swap(this IList list, int indexA, int indexB, bool remove)
{
if (indexA == indexB)
{
return;
}
indexA.IsInRange(0, list.Count - 1, true, "indexA is out of range.");
indexB.IsInRange(0, list.Count - 1, true, "indexB is out of range.");
if (remove)
{
var first = Math.Min(indexA, indexB);
var second = Math.Max(indexA, indexB);
var tempA = list[first];
var tempB = list[second];
list.RemoveAt(second);
list.RemoveAt(first);
list.Insert(first, tempB);
list.Insert(second, tempA);
}
else
{
var temp = list[indexA];
list[indexA] = list[indexB];
list[indexB] = temp;
}
}
/// <summary>Swaps the specified items in a list.</summary>
/// <param name="list">The list.</param>
/// <param name="indexA">The index of item A.</param>
/// <param name="indexB">The index of item B.</param>
/// <remarks>Items are swapped and not removed or inserted.</remarks>
public static void Swap(this IList list, int indexA, int indexB)
{
Swap(list, indexA, indexB, false);
}
/// <summary>Swaps the specified items in a list and return true if successful.</summary>
/// <param name="list">The list.</param>
/// <param name="indexA">The index of item A.</param>
/// <param name="indexB">The index of item B.</param>
/// <remarks>Items are swapped and not removed or inserted.</remarks>
/// <returns>true if successful.</returns>
public static bool TrySwap(this IList list, int indexA, int indexB)
{
try
{
Swap(list, indexA, indexB);
}
catch
{
return false;
}
return true;
}
/// <summary>Swaps the specified items in a list and return true if successful.</summary>
/// <param name="list">The list.</param>
/// <param name="indexA">The index of item A.</param>
/// <param name="indexB">The index of item B.</param>
/// <param name="remove">If set to <c>true</c> items will be removes and re-inserted.</param>
/// <returns>true if successful.</returns>
public static bool TrySwap(this IList list, int indexA, int indexB, bool remove)
{
try
{
Swap(list, indexA, indexB, remove);
}
catch
{
return false;
}
return true;
}
}
}
fba1eb61-9978-4f0f-b9cd-34b808c00e42|0|.0
Full repo available at https://bitbucket.org/createdbyx/codefarts.utilities-extension-methods-only /// <summary>
/// Removes a range of entries inside an array.
/// </summary>
/// <typeparam name="T">Specifies the generic type of the array.</typeparam>
/// <param name="array">The destination array.</param>
/// <param name="index">The start index where entries will be removed from.</param>
/// <param name="length">The number of entries to be removed.</param>
/// <returns>
/// Returns the resized and updated destination array.
/// </returns>
/// <exception cref="ArgumentOutOfRangeException">index</exception>
public static T[] RemoveRange<T>(this T[] array, int index, int length)
{
if (length < 1)
{
return array;
}
if (index < 0 || index > array.Length - 1)
{
throw new ArgumentOutOfRangeException("index");
}
if (index + length > array.Length - 1)
{
Array.Resize(ref array, index);
return array;
}
var endLength = Math.Max(0, Math.Min(array.Length - index, array.Length - (index + length)));
var tempArray = new T[endLength];
Array.Copy(array, index + length, tempArray, 0, endLength);
Array.Resize(ref array, array.Length - length);
tempArray.CopyTo(array, array.Length - endLength);
return array;
}
f468b7a3-87f8-4dd1-9ff8-ab01d10053ca|0|.0
Full repo available at https://bitbucket.org/createdbyx/codefarts.utilities-extension-methods-only /// <summary>
/// Moves the specified entries in the array by a set ammount.
/// </summary>
/// <typeparam name="T">Specifies the generic type of the array.</typeparam>
/// <param name="array">The destination array.</param>
/// <param name="index">The start index where entries will be moved from.</param>
/// <param name="length">The number of entries to be moved.</param>
/// <param name="shift">The ammount and direction to move the specified entries.</param>
/// <returns>
/// Returns the resized and updated destination array.
/// </returns>
/// <exception cref="ArgumentOutOfRangeException">length;'length' argument must be greater then 0.</exception>
/// <remarks><p>To move entries to the left (towards 0) specify a negative shift value and a positive shift value to move entries to the right.</p>
/// <example>
/// <code>
/// var items = new[] { 0, 1, 2, 3, 4 };
/// items = items.Move(3, 2, -1);
/// </code>
/// Result should be { 0, 1, 3, 4, 4 }
/// </example></remarks>
public static T[] Move<T>(this T[] array, int index, int length, int shift)
{
if (length <= 0)
{
throw new ArgumentOutOfRangeException("length", "'length' argument must be greater then 0.");
}
if (shift > 0 && index + length + shift > array.Length - 1)
{
Array.Resize(ref array, array.Length + (index + length + shift - array.Length));
}
if (index + shift < 0)
{
length += index + shift;
index = -(index + shift);
}
length = Math.Min(array.Length - index, length);
if (length > 0)
{
Array.Copy(array, index, array, index + shift, length);
}
return array;
}
e86270ef-5f08-434f-b3bd-39dc58677b56|0|.0
|
|