Download TextBoxTabStops.zip, last updated 25/05/2019 (56.09 KB)

Download
  • md5: c19ff63a08cba2440f23c149be49025d
  • sha1: e41fa65000e766cd66ed012744340b6fe53df4b4
  • sha256: d3b220e4c5e4753d7b761ee0eb978600bdc14f6a9bbee50117e66a1a052d642c
using System;
using System.Collections.Generic;
using System.Windows.Forms;

// Setting tab stops in a Windows Forms TextBox control
// https://www.cyotek.com/blog/setting-tab-stops-in-a-windows-forms-textbox-control

// This work is licensed under the Creative Commons Attribution 4.0 International License.
// To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/.

// Found this example useful?
// https://www.paypal.me/cyotek

namespace Cyotek.Demo.TextBoxTabStops
{
  internal static class TextBoxExtensions
  {
    #region Private Fields

    private readonly static char[] _cellSeparators = { '\t' };

    private readonly static char[] _lineSeparators = { '\r', '\n' };

    #endregion Private Fields

    #region Public Methods

    public static int[] AutoDetectTabStops(string text)
    {
      int[] result;

      if (!string.IsNullOrEmpty(text) && text.IndexOf('\t') != -1)
      {
        List<int> tabStops;
        string[] lines;

        tabStops = new List<int>();

        lines = text.Split(_lineSeparators, StringSplitOptions.RemoveEmptyEntries);

        for (int i = 0; i < lines.Length; i++)
        {
          string[] cells;

          cells = lines[i].Split(_cellSeparators);

          for (int j = 0; j < cells.Length; j++)
          {
            int estimatedDialogUnits;

            estimatedDialogUnits = cells[j].Length * 4;

            if (tabStops.Count <= j)
            {
              tabStops.Add(estimatedDialogUnits);
            }
            else if (estimatedDialogUnits > tabStops[j])
            {
              tabStops[j] = estimatedDialogUnits;
            }
          }
        }

        for (int i = 1; i < tabStops.Count; i++)
        {
          tabStops[i] += tabStops[i - 1];
        }

        result = tabStops.ToArray();
      }
      else
      {
        result = new[] { 32 };
      }

      return result;
    }

    public static bool AutoDetectTabStops(this TextBoxBase textBox, string text)
    {
      if (textBox == null)
      {
        throw new ArgumentNullException(nameof(textBox));
      }

      return textBox.SetTabStops(AutoDetectTabStops(text));
    }

    public static bool AutoDetectTabStops(this TextBoxBase textBox)
    {
      return textBox.AutoDetectTabStops(textBox.Text);
    }

    public static bool ResetTabStops(this TextBoxBase textBox)
    {
      bool result;

      if (textBox == null)
      {
        throw new ArgumentNullException(nameof(textBox));
      }

      result = NativeMethods.SendMessage(textBox.Handle, NativeMethods.EM_SETTABSTOPS, 0, 0) != 0;
      textBox.Invalidate();

      return result;
    }

    public static bool SetTabStops(this TextBoxBase textBox, int tabSize)
    {
      bool result;

      if (textBox == null)
      {
        throw new ArgumentNullException(nameof(textBox));
      }

      result = NativeMethods.SendMessage(textBox.Handle, NativeMethods.EM_SETTABSTOPS, 1, tabSize) != 0;
      textBox.Invalidate();

      return result;
    }

    public static bool SetTabStops(this TextBoxBase textBox, int[] tabStops)
    {
      bool result;

      if (textBox == null)
      {
        throw new ArgumentNullException(nameof(textBox));
      }

      if (tabStops == null || tabStops.Length == 0)
      {
        throw new ArgumentException(nameof(tabStops));
      }

      result = NativeMethods.SendMessage(textBox.Handle, NativeMethods.EM_SETTABSTOPS, tabStops.Length, tabStops) != 0;
      textBox.Invalidate();

      return result;
    }

    #endregion Public Methods
  }
}

Donate

Donate