using System; using System.Windows.Forms; using System.Collections; using System.Collections.Specialized; using System.Diagnostics; namespace AyaNova { class TabOrderManager { /// /// Case 152 tab order on forms /// Compare two controls in the selected tab scheme. /// private class TabSchemeComparer : IComparer { private TabScheme comparisonScheme; #region IComparer Members public int Compare(object x, object y) { Control control1 = x as Control; Control control2 = y as Control; if (control1 == control2) return 0; if (control1 == null || control2 == null) { Debug.Assert(false, "Attempting to compare a non-control"); return 0; } if (comparisonScheme == TabScheme.None) { // Nothing to do. return 0; } if (comparisonScheme == TabScheme.AcrossFirst) { // The primary direction to sort is the y direction (using the Top property). // If two controls have the same y coordination, then we sort them by their x's. if (control1.Top < control2.Top) { return -1; } else if (control1.Top > control2.Top) { return 1; } else { return (control1.Left.CompareTo(control2.Left)); } } else // comparisonScheme = TabScheme.DownFirst { // The primary direction to sort is the x direction (using the Left property). // If two controls have the same x coordination, then we sort them by their y's. if (control1.Left < control2.Left) { return -1; } else if (control1.Left > control2.Left) { return 1; } else { return (control1.Top.CompareTo(control2.Top)); } } } #endregion /// /// Create a tab scheme comparer that compares using the given scheme. /// /// public TabSchemeComparer(TabScheme scheme) { comparisonScheme = scheme; } } /// /// The container whose tab order we manage. /// private Control container; /// /// Hash of controls to schemes so that individual containers can have different ordering /// strategies than their parents. /// private Hashtable schemeOverrides; /// /// The tab index we start numbering from when the tab order is applied. /// private int curTabIndex = 0; /// /// The general tab-ordering strategy (i.e. whether we tab across rows first, or down columns). /// public enum TabScheme { None, AcrossFirst, DownFirst } /// /// Constructor /// /// The container whose tab order we manage. public TabOrderManager(Control container) { this.container = container; this.curTabIndex = 0; this.schemeOverrides = new Hashtable(); } /// /// Construct a tab order manager that starts numbering at the given tab index. /// /// The container whose tab order we manage. /// Where to start numbering. /// List of controls with explicitly defined schemes. private TabOrderManager(Control container, int curTabIndex, Hashtable schemeOverrides) { this.container = container; this.curTabIndex = curTabIndex; this.schemeOverrides = schemeOverrides; } /// /// Explicitly set a tab order scheme for a given (presumably container) control. /// /// The control to set the scheme for. /// The requested scheme. public void SetSchemeForControl(Control c, TabScheme scheme) { schemeOverrides[c] = scheme; } /// /// Recursively set the tab order on this container and all of its children. /// /// The tab ordering strategy to apply. /// The next tab index to be used. public int SetTabOrder(TabScheme scheme) { // Tab order isn't important enough to ever cause a crash, so replace any exceptions // with assertions. try { ArrayList controlArraySorted = new ArrayList(); controlArraySorted.AddRange(container.Controls); controlArraySorted.Sort(new TabSchemeComparer(scheme)); foreach (Control c in controlArraySorted) { // Debug.WriteLine("TabOrderManager: Changing tab index for " + c.Name); c.TabIndex = curTabIndex++; if (c.Controls.Count > 0) { // Control has children -- recurse. TabScheme childScheme = scheme; if (schemeOverrides.Contains(c)) { childScheme = (TabScheme)schemeOverrides[c]; } curTabIndex = (new TabOrderManager(c, curTabIndex, schemeOverrides)).SetTabOrder(childScheme); } } return curTabIndex; } catch (Exception e) { Debug.Assert(false, "Exception in TabOrderManager.SetTabOrder: " + e.Message); return 0; } } } }