{*******************************************************}
{                                                       }
{       Pascal Script Source File                       }
{       Run by RemObjects Pascal Script in CnWizards    }
{                                                       }
{       Generated by CnPack IDE Wizards                 }
{                                                       }
{*******************************************************}

program LabelFocusCtrl;

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

const
  EDIT_AT_RIGHT = True; // False means Down.
  ALIGN_MARGIN = 10;    // 对齐阈值 10 像素内

var
  Count: Integer;
  List: TList;
  Root: TComponent;
  ProcSelect: Boolean;

procedure ProcessContainer(Parent: TWinControl);
var
  I, J: Integer;
  ALabel: TLabel;
  AEdit, TheEdit: TWinControl;
  LabelList: TList;
  EditList: TList;
  ControlList: TList;
begin
  if Parent = nil then
    Exit;

  LabelList := TList.Create;
  EditList := TList.Create;
  ControlList := TList.Create;

  try
    for I := 0 to Parent.ControlCount - 1 do
    begin
      if Parent.Controls[I] is TLabel then
        LabelList.Add(CnObjectToInt(Parent.Controls[I]))
      else if (Parent.Controls[I] is TCustomEdit) or
        (Parent.Controls[I] is TCustomComboBox) or
        (Parent.Controls[I] is TCustomMemo) then
        EditList.Add(CnObjectToInt(Parent.Controls[I]))
      else if Parent.Controls[I] is TWinControl then
      begin
        if TWinControl(Parent.Controls[I]).ControlCount > 1 then
          ControlList.Add(CnObjectToInt(Parent.Controls[I]));
      end;
    end;

    // 仨 List 均已赋值完毕。对每个 Label 找其右或下一定距离内的 Edit
    for I := LabelList.Count - 1 downto 0 do
    begin
      ALabel := TLabel(CnIntToObject(LabelList[I]));

//      if ALabel.FocusControl <> nil then // 已经设置好的就不动了
//        Continue;

      if EDIT_AT_RIGHT then // 找右面
      begin
        // 找 Edit，其左上角的纵坐标离 Label 左上角的纵坐标小于 ALIGN_MARGIN，并且 Edit 在 Label 右边
        // 如果有多个，以最左边的为准
        TheEdit := nil;
        for J := 0 to EditList.Count - 1 do
        begin                   
          AEdit := TWinControl(CnIntToObject(EditList[J]));

          if (Abs(AEdit.Top - ALabel.Top) <= ALIGN_MARGIN) and (AEdit.Left > ALabel.Left) then
          begin
            if TheEdit = nil then
              TheEdit := AEdit
            else if AEdit.Left < TheEdit.Left then
              TheEdit := AEdit;
          end;
        end;

        if TheEdit <> nil then
        begin
          ALabel.FocusControl := TheEdit;
          Inc(Count);
        end;
      end
      else // 找下面
      begin
        // 找 Edit，其左上角的横坐标离 Label 左上角的横坐标小于 ALIGN_MARGIN，并且 Edit 在 Label 下边
        // 如果有多个，以最上边的为准
        TheEdit := nil;
        for J := 0 to EditList.Count - 1 do
        begin
          AEdit := TWinControl(CnIntToObject(EditList[J]));

          if (Abs(AEdit.Left - ALabel.Left) <= ALIGN_MARGIN) and (AEdit.Top > ALabel.Top) then
          begin
            if (TheEdit = nil) or (AEdit.Top < TheEdit.Top) then
              TheEdit := AEdit;
          end;
        end;

        if TheEdit <> nil then
        begin
          ALabel.FocusControl := TheEdit;
          Inc(Count);
        end;
      end;
    end;

    // 递归处理子容器
    for I := 0 to ControlList.Count - 1 do
      ProcessContainer(TWinControl(ControlList[I]));
  finally
    LabelList.Free;
    EditList.Free;
    ControlList.Free;
  end;
end;

begin
  List := TList.Create;
  Count := 0;
  try
    ProcSelect := False;

    if not CnOtaGetSelectedControlFromCurrentForm(List) then
      ProcSelect := False;

    if List.Count = 1 then
      if (CnIntToObject(List[0]) is TWinControl) then
        if (TWinControl(CnIntToObject(List[0])).ControlCount > 1) then
          ProcSelect := True;

    if not ProcSelect then
    begin
      InfoDlg('Will Process the Label/Edit Pairs in Current Form.');
      Root := CnOtaGetRootComponentFromEditor(CnOtaGetCurrentFormEditor);
      if (Root <> nil) and (Root is TWinControl) then
      begin
        ProcessContainer(TWinControl(Root));
        InfoDlg(IntToStr(Count) + ' Label FocusControl Set.');
      end
      else
        ErrorDlg('No Designer Found. Nothing to Process.');
    end
    else
    begin
      InfoDlg('Will Process the Label Label/Edit Pairs in ' + TWinControl(CnIntToObject(List[0])).Name);
      ProcessContainer(TWinControl(CnIntToObject(List[0])));
      InfoDlg(IntToStr(Count) + ' Label FocusControl Set.');
    end;
  finally
    List.Free;
  end;
end.
 
