View Issue Details

IDProjectCategoryView StatusLast Update
0031270LazarusPatchpublic2017-01-25 08:54
ReporterZoran VučenovićAssigned ToJuha Manninen 
PrioritynormalSeverityminorReproducibilityN/A
Status closedResolutionfixed 
Product Version1.7 (SVN)Product Build 
Target Version1.8Fixed in Version1.7 (SVN) 
Summary0031270: TabOrder dialog - add possibility to sort tab orders for all child controls recursively.
DescriptionOn Tab Order Dialog (IDE main menu->View->Tab Order), there is a very nice button which calculates tab order of controls according to their position on form, but it does it only in one level (it does not calculate tab positions for child controls).

I often use it, but also I need it to do it recursively to child controls (I often have many panels and sub-panels on my forms).

So, I created a patch which adds a check box on TabOrder dialog, and when checked, calculating of tab order is also done recursively for child controls.
Steps To ReproducePlease test and apply the patch :)
TagsNo tags attached.
Fixed in Revisionr53999
LazTarget-
Widgetset
Attached Files
  • TabOrderRecursively.diff (7,516 bytes)
    Index: designer/taborderdlg.lfm
    ===================================================================
    --- designer/taborderdlg.lfm	(revision 53989)
    +++ designer/taborderdlg.lfm	(working copy)
    @@ -1,22 +1,22 @@
     object TabOrderDialog: TTabOrderDialog
       Left = 349
    -  Height = 374
    +  Height = 419
       Top = 112
    -  Width = 310
    +  Width = 440
       ActiveControl = ItemTreeview
       Caption = 'TabOrderDialog'
    -  ClientHeight = 374
    -  ClientWidth = 310
    +  ClientHeight = 419
    +  ClientWidth = 440
       OnCreate = TabOrderDialogCREATE
       OnShow = FormShow
       LCLVersion = '1.7'
       Visible = True
       object ArrowUp: TSpeedButton
    -    AnchorSideRight.Control = Owner
    -    AnchorSideRight.Side = asrBottom
    -    Left = 279
    +    AnchorSideRight.Control = PanelSortByPosition
    +    AnchorSideRight.Side = asrCenter
    +    Left = 375
         Height = 25
    -    Top = 120
    +    Top = 91
         Width = 25
         Anchors = [akTop, akRight]
         BorderSpacing.Around = 6
    @@ -25,11 +25,11 @@
         ParentShowHint = False
       end
       object ArrowDown: TSpeedButton
    -    AnchorSideRight.Control = Owner
    -    AnchorSideRight.Side = asrBottom
    -    Left = 279
    +    AnchorSideRight.Control = PanelSortByPosition
    +    AnchorSideRight.Side = asrCenter
    +    Left = 375
         Height = 25
    -    Top = 176
    +    Top = 147
         Width = 25
         Anchors = [akTop, akRight]
         BorderSpacing.Around = 6
    @@ -40,12 +40,14 @@
       object ItemTreeview: TTreeView
         AnchorSideLeft.Control = Owner
         AnchorSideTop.Control = Owner
    +    AnchorSideRight.Control = PanelSortByPosition
         Left = 6
    -    Height = 357
    +    Height = 402
         Top = 6
    -    Width = 267
    +    Width = 330
         Anchors = [akTop, akLeft, akRight, akBottom]
         BorderSpacing.Around = 6
    +    ExpandSignSize = 11
         HideSelection = False
         ReadOnly = True
         RightClickSelect = True
    @@ -54,19 +56,49 @@
         OnSelectionChanged = ItemTreeviewSelectionChanged
         Options = [tvoAutoItemHeight, tvoKeepCollapsedNodes, tvoReadOnly, tvoRightClickSelect, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips]
       end
    -  object SortByPositionButton: TBitBtn
    +  object PanelSortByPosition: TPanel
    +    AnchorSideTop.Side = asrBottom
         AnchorSideRight.Control = Owner
         AnchorSideRight.Side = asrBottom
    -    Left = 279
    -    Height = 25
    -    Top = 232
    -    Width = 25
    +    Left = 342
    +    Height = 58
    +    Top = 192
    +    Width = 93
         Anchors = [akTop, akRight]
    -    BorderSpacing.Around = 6
    -    GlyphShowMode = gsmAlways
    -    OnClick = SortByPositionButtonClick
    -    ParentShowHint = False
    -    ShowHint = True
    +    AutoSize = True
    +    BorderSpacing.Around = 5
    +    BevelOuter = bvLowered
    +    ClientHeight = 58
    +    ClientWidth = 93
         TabOrder = 1
    +    object SortByPositionButton: TBitBtn
    +      AnchorSideLeft.Control = PanelSortByPosition
    +      AnchorSideLeft.Side = asrCenter
    +      AnchorSideTop.Control = PanelSortByPosition
    +      Left = 34
    +      Height = 25
    +      Top = 4
    +      Width = 25
    +      BorderSpacing.Around = 3
    +      GlyphShowMode = gsmAlways
    +      OnClick = SortByPositionButtonClick
    +      ParentShowHint = False
    +      ShowHint = True
    +      TabOrder = 0
    +    end
    +    object CheckBoxSortRecursivly: TCheckBox
    +      AnchorSideLeft.Control = PanelSortByPosition
    +      AnchorSideTop.Control = SortByPositionButton
    +      AnchorSideTop.Side = asrBottom
    +      Left = 4
    +      Height = 22
    +      Top = 32
    +      Width = 85
    +      BorderSpacing.Around = 3
    +      Caption = 'recursively'
    +      ParentShowHint = False
    +      ShowHint = True
    +      TabOrder = 1
    +    end
       end
     end
    Index: designer/taborderdlg.pas
    ===================================================================
    --- designer/taborderdlg.pas	(revision 53989)
    +++ designer/taborderdlg.pas	(working copy)
    @@ -33,7 +33,8 @@
     
     uses
       Classes, SysUtils, Forms, Controls, Dialogs, Buttons, ComCtrls, IDEOptionDefs,
    -  LCLType, LCLProc, PropEdits, IDEDialogs, LazarusIDEStrConsts, AvgLvlTree;
    +  LCLType, LCLProc, ExtCtrls, StdCtrls, PropEdits, IDEDialogs,
    +  LazarusIDEStrConsts, AvgLvlTree;
     
     type
     
    @@ -42,6 +43,8 @@
       TTabOrderDialog = class(TForm)
         ArrowDown: TSpeedButton;
         ArrowUp: TSpeedButton;
    +    CheckBoxSortRecursivly: TCheckBox;
    +    PanelSortByPosition: TPanel;
         ItemTreeview: TTreeView;
         SortByPositionButton: TBitBtn;
         procedure ItemTreeviewSelectionChanged(Sender: TObject);
    @@ -139,6 +142,7 @@
       ArrowDown.Hint:=lisTabOrderDownHint;
       ArrowUp.Hint:=lisTabOrderUpHint;
       SortByPositionButton.Hint:=lisTabOrderSortHint;
    +  CheckBoxSortRecursivly.Hint := lisTabOrderRecursionHint;
     end;
     
     procedure TTabOrderDialog.FormShow(Sender: TObject);
    @@ -157,15 +161,48 @@
     end;
     
     procedure TTabOrderDialog.SortByPositionButtonClick(Sender: TObject);
    +
    +  procedure SortControls(FirstItem: TTreeNode);
    +  var
    +    SortedNodes: TFPList;
    +    I: Integer;
    +    CurrItem: TTreeNode;
    +  begin
    +    if Assigned(FirstItem) then begin
    +      SortedNodes := TFPList.Create;
    +      try
    +        CurrItem := FirstItem;
    +        repeat
    +          if CheckBoxSortRecursivly.Checked then
    +            SortControls(CurrItem.GetFirstChild);
    +
    +          SortedNodes.Add(CurrItem);
    +          CurrItem := CurrItem.GetNextSibling;
    +        until CurrItem = nil;
    +
    +        SortedNodes.Sort(@SortNodeByControlPos);
    +
    +        for I := SortedNodes.Count - 1 downto 0 do
    +        begin
    +          CurrItem := TTreeNode(SortedNodes[I]);
    +          CurrItem.MoveTo(FirstItem, naAddFirst);
    +          TWinControl(CurrItem.Data).TabOrder := I;
    +          CurrItem.Text := TWinControl(CurrItem.Data).Name + '   (' + IntToStr(I) + ')';
    +        end;
    +      finally
    +        SortedNodes.Free;
    +      end;
    +    end;
    +  end;
    +
     var
    -  FirstItem, CurrItem: TTreeNode;
    -  SortedNodes: TFPList;
    -  i: Integer;
    +  FirstItem: TTreeNode;
     begin
       if (ItemTreeview.Selected <> nil) and (ItemTreeview.Selected.Parent <> nil) then
         FirstItem := ItemTreeview.Selected.Parent.GetFirstChild
       else
         FirstItem := ItemTreeview.Items.GetFirstNode;
    +
       if IDEMessageDialog('', Format(lisTabOrderConfirmSort, [TControl(FirstItem.Data).Parent.Name]),
         mtConfirmation, mbOKCancel) <> mrOK then
       begin
    @@ -173,25 +210,9 @@
       end;
     
       ItemTreeview.BeginUpdate;
    -  SortedNodes := TFPList.Create;
       try
    -    CurrItem := FirstItem;
    -    repeat
    -      SortedNodes.Add(CurrItem);
    -      CurrItem := CurrItem.GetNextSibling;
    -    until CurrItem = nil;
    -
    -    SortedNodes.Sort(@SortNodeByControlPos);
    -
    -    for i := SortedNodes.Count - 1 downto 0 do
    -    begin
    -      CurrItem := TTreeNode(SortedNodes[i]);
    -      CurrItem.MoveTo(FirstItem, naAddFirst);
    -      TWinControl(CurrItem.Data).TabOrder := i;
    -      CurrItem.Text := TWinControl(CurrItem.Data).Name + '   (' + IntToStr(i) + ')';
    -    end;
    +    SortControls(FirstItem);
       finally
    -    SortedNodes.Free;
         ItemTreeview.EndUpdate;
       end;
       GlobalDesignHook.Modified(Self);
    Index: ide/lazarusidestrconsts.pas
    ===================================================================
    --- ide/lazarusidestrconsts.pas	(revision 53989)
    +++ ide/lazarusidestrconsts.pas	(working copy)
    @@ -5053,6 +5053,7 @@
       lisTabOrderUpHint = 'Move the selected control up in tab order';
       lisTabOrderDownHint = 'Move the selected control down in tab order';
       lisTabOrderSortHint = 'Calculate tab order for controls by their X- and Y- positions';
    +  lisTabOrderRecursionHint = 'Calculate tab order recursively for child controls';
       lisTabOrderConfirmSort = 'Sort tab orders of all child controls of "%s" by their positions?';
     
       lisCustomProgram = 'Custom Program';
    
    TabOrderRecursively.diff (7,516 bytes)

Activities

Zoran Vučenović

2017-01-24 15:30

developer  

TabOrderRecursively.diff (7,516 bytes)
Index: designer/taborderdlg.lfm
===================================================================
--- designer/taborderdlg.lfm	(revision 53989)
+++ designer/taborderdlg.lfm	(working copy)
@@ -1,22 +1,22 @@
 object TabOrderDialog: TTabOrderDialog
   Left = 349
-  Height = 374
+  Height = 419
   Top = 112
-  Width = 310
+  Width = 440
   ActiveControl = ItemTreeview
   Caption = 'TabOrderDialog'
-  ClientHeight = 374
-  ClientWidth = 310
+  ClientHeight = 419
+  ClientWidth = 440
   OnCreate = TabOrderDialogCREATE
   OnShow = FormShow
   LCLVersion = '1.7'
   Visible = True
   object ArrowUp: TSpeedButton
-    AnchorSideRight.Control = Owner
-    AnchorSideRight.Side = asrBottom
-    Left = 279
+    AnchorSideRight.Control = PanelSortByPosition
+    AnchorSideRight.Side = asrCenter
+    Left = 375
     Height = 25
-    Top = 120
+    Top = 91
     Width = 25
     Anchors = [akTop, akRight]
     BorderSpacing.Around = 6
@@ -25,11 +25,11 @@
     ParentShowHint = False
   end
   object ArrowDown: TSpeedButton
-    AnchorSideRight.Control = Owner
-    AnchorSideRight.Side = asrBottom
-    Left = 279
+    AnchorSideRight.Control = PanelSortByPosition
+    AnchorSideRight.Side = asrCenter
+    Left = 375
     Height = 25
-    Top = 176
+    Top = 147
     Width = 25
     Anchors = [akTop, akRight]
     BorderSpacing.Around = 6
@@ -40,12 +40,14 @@
   object ItemTreeview: TTreeView
     AnchorSideLeft.Control = Owner
     AnchorSideTop.Control = Owner
+    AnchorSideRight.Control = PanelSortByPosition
     Left = 6
-    Height = 357
+    Height = 402
     Top = 6
-    Width = 267
+    Width = 330
     Anchors = [akTop, akLeft, akRight, akBottom]
     BorderSpacing.Around = 6
+    ExpandSignSize = 11
     HideSelection = False
     ReadOnly = True
     RightClickSelect = True
@@ -54,19 +56,49 @@
     OnSelectionChanged = ItemTreeviewSelectionChanged
     Options = [tvoAutoItemHeight, tvoKeepCollapsedNodes, tvoReadOnly, tvoRightClickSelect, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips]
   end
-  object SortByPositionButton: TBitBtn
+  object PanelSortByPosition: TPanel
+    AnchorSideTop.Side = asrBottom
     AnchorSideRight.Control = Owner
     AnchorSideRight.Side = asrBottom
-    Left = 279
-    Height = 25
-    Top = 232
-    Width = 25
+    Left = 342
+    Height = 58
+    Top = 192
+    Width = 93
     Anchors = [akTop, akRight]
-    BorderSpacing.Around = 6
-    GlyphShowMode = gsmAlways
-    OnClick = SortByPositionButtonClick
-    ParentShowHint = False
-    ShowHint = True
+    AutoSize = True
+    BorderSpacing.Around = 5
+    BevelOuter = bvLowered
+    ClientHeight = 58
+    ClientWidth = 93
     TabOrder = 1
+    object SortByPositionButton: TBitBtn
+      AnchorSideLeft.Control = PanelSortByPosition
+      AnchorSideLeft.Side = asrCenter
+      AnchorSideTop.Control = PanelSortByPosition
+      Left = 34
+      Height = 25
+      Top = 4
+      Width = 25
+      BorderSpacing.Around = 3
+      GlyphShowMode = gsmAlways
+      OnClick = SortByPositionButtonClick
+      ParentShowHint = False
+      ShowHint = True
+      TabOrder = 0
+    end
+    object CheckBoxSortRecursivly: TCheckBox
+      AnchorSideLeft.Control = PanelSortByPosition
+      AnchorSideTop.Control = SortByPositionButton
+      AnchorSideTop.Side = asrBottom
+      Left = 4
+      Height = 22
+      Top = 32
+      Width = 85
+      BorderSpacing.Around = 3
+      Caption = 'recursively'
+      ParentShowHint = False
+      ShowHint = True
+      TabOrder = 1
+    end
   end
 end
Index: designer/taborderdlg.pas
===================================================================
--- designer/taborderdlg.pas	(revision 53989)
+++ designer/taborderdlg.pas	(working copy)
@@ -33,7 +33,8 @@
 
 uses
   Classes, SysUtils, Forms, Controls, Dialogs, Buttons, ComCtrls, IDEOptionDefs,
-  LCLType, LCLProc, PropEdits, IDEDialogs, LazarusIDEStrConsts, AvgLvlTree;
+  LCLType, LCLProc, ExtCtrls, StdCtrls, PropEdits, IDEDialogs,
+  LazarusIDEStrConsts, AvgLvlTree;
 
 type
 
@@ -42,6 +43,8 @@
   TTabOrderDialog = class(TForm)
     ArrowDown: TSpeedButton;
     ArrowUp: TSpeedButton;
+    CheckBoxSortRecursivly: TCheckBox;
+    PanelSortByPosition: TPanel;
     ItemTreeview: TTreeView;
     SortByPositionButton: TBitBtn;
     procedure ItemTreeviewSelectionChanged(Sender: TObject);
@@ -139,6 +142,7 @@
   ArrowDown.Hint:=lisTabOrderDownHint;
   ArrowUp.Hint:=lisTabOrderUpHint;
   SortByPositionButton.Hint:=lisTabOrderSortHint;
+  CheckBoxSortRecursivly.Hint := lisTabOrderRecursionHint;
 end;
 
 procedure TTabOrderDialog.FormShow(Sender: TObject);
@@ -157,15 +161,48 @@
 end;
 
 procedure TTabOrderDialog.SortByPositionButtonClick(Sender: TObject);
+
+  procedure SortControls(FirstItem: TTreeNode);
+  var
+    SortedNodes: TFPList;
+    I: Integer;
+    CurrItem: TTreeNode;
+  begin
+    if Assigned(FirstItem) then begin
+      SortedNodes := TFPList.Create;
+      try
+        CurrItem := FirstItem;
+        repeat
+          if CheckBoxSortRecursivly.Checked then
+            SortControls(CurrItem.GetFirstChild);
+
+          SortedNodes.Add(CurrItem);
+          CurrItem := CurrItem.GetNextSibling;
+        until CurrItem = nil;
+
+        SortedNodes.Sort(@SortNodeByControlPos);
+
+        for I := SortedNodes.Count - 1 downto 0 do
+        begin
+          CurrItem := TTreeNode(SortedNodes[I]);
+          CurrItem.MoveTo(FirstItem, naAddFirst);
+          TWinControl(CurrItem.Data).TabOrder := I;
+          CurrItem.Text := TWinControl(CurrItem.Data).Name + '   (' + IntToStr(I) + ')';
+        end;
+      finally
+        SortedNodes.Free;
+      end;
+    end;
+  end;
+
 var
-  FirstItem, CurrItem: TTreeNode;
-  SortedNodes: TFPList;
-  i: Integer;
+  FirstItem: TTreeNode;
 begin
   if (ItemTreeview.Selected <> nil) and (ItemTreeview.Selected.Parent <> nil) then
     FirstItem := ItemTreeview.Selected.Parent.GetFirstChild
   else
     FirstItem := ItemTreeview.Items.GetFirstNode;
+
   if IDEMessageDialog('', Format(lisTabOrderConfirmSort, [TControl(FirstItem.Data).Parent.Name]),
     mtConfirmation, mbOKCancel) <> mrOK then
   begin
@@ -173,25 +210,9 @@
   end;
 
   ItemTreeview.BeginUpdate;
-  SortedNodes := TFPList.Create;
   try
-    CurrItem := FirstItem;
-    repeat
-      SortedNodes.Add(CurrItem);
-      CurrItem := CurrItem.GetNextSibling;
-    until CurrItem = nil;
-
-    SortedNodes.Sort(@SortNodeByControlPos);
-
-    for i := SortedNodes.Count - 1 downto 0 do
-    begin
-      CurrItem := TTreeNode(SortedNodes[i]);
-      CurrItem.MoveTo(FirstItem, naAddFirst);
-      TWinControl(CurrItem.Data).TabOrder := i;
-      CurrItem.Text := TWinControl(CurrItem.Data).Name + '   (' + IntToStr(i) + ')';
-    end;
+    SortControls(FirstItem);
   finally
-    SortedNodes.Free;
     ItemTreeview.EndUpdate;
   end;
   GlobalDesignHook.Modified(Self);
Index: ide/lazarusidestrconsts.pas
===================================================================
--- ide/lazarusidestrconsts.pas	(revision 53989)
+++ ide/lazarusidestrconsts.pas	(working copy)
@@ -5053,6 +5053,7 @@
   lisTabOrderUpHint = 'Move the selected control up in tab order';
   lisTabOrderDownHint = 'Move the selected control down in tab order';
   lisTabOrderSortHint = 'Calculate tab order for controls by their X- and Y- positions';
+  lisTabOrderRecursionHint = 'Calculate tab order recursively for child controls';
   lisTabOrderConfirmSort = 'Sort tab orders of all child controls of "%s" by their positions?';
 
   lisCustomProgram = 'Custom Program';
TabOrderRecursively.diff (7,516 bytes)

Zeljan Rikalo

2017-01-24 17:54

developer   ~0097671

Nice feature.

Juha Manninen

2017-01-24 23:55

developer   ~0097682

Applied, thanks.

Zoran Vučenović

2017-01-25 08:54

developer   ~0097684

Thank you.

Issue History

Date Modified Username Field Change
2017-01-24 15:30 Zoran Vučenović New Issue
2017-01-24 15:30 Zoran Vučenović File Added: TabOrderRecursively.diff
2017-01-24 17:54 Zeljan Rikalo Note Added: 0097671
2017-01-24 23:26 Juha Manninen Assigned To => Juha Manninen
2017-01-24 23:26 Juha Manninen Status new => assigned
2017-01-24 23:55 Juha Manninen Fixed in Revision => r53999
2017-01-24 23:55 Juha Manninen Note Added: 0097682
2017-01-24 23:55 Juha Manninen Status assigned => resolved
2017-01-24 23:55 Juha Manninen Resolution open => fixed
2017-01-25 08:54 Zoran Vučenović Note Added: 0097684
2017-01-25 08:54 Zoran Vučenović Status resolved => closed
2017-01-25 08:54 Zoran Vučenović Fixed in Version => 1.7 (SVN)
2017-01-25 08:54 Zoran Vučenović Target Version => 1.8