unit UMSetup;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, CheckLst, ExtCtrls, ComCtrls, Buttons, AppEvnts,
  Menus, Grids, Inifiles;

type
  TFMSetup = class(TForm)
    ApplicationEvents1: TApplicationEvents;
    GroupBox1: TGroupBox;
    Label1: TLabel;
    Label2: TLabel;
    ChLBMenu: TCheckListBox;
    StaticText1: TStaticText;
    Edit1: TEdit;
    GroupBox2: TGroupBox;
    SBUp: TSpeedButton;
    SBDown: TSpeedButton;
    Label3: TLabel;
    Label4: TLabel;
    LBRazd: TListBox;
    StaticText2: TStaticText;
    Edit2: TEdit;
    GroupBox3: TGroupBox;
    Label5: TLabel;
    LBComand: TListBox;
    StaticText3: TStaticText;
    BAdd: TButton;
    Panel1: TPanel;
    BClose: TButton;
    Button3: TButton;
    HotKey1: THotKey;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure ApplicationEvents1ShowHint(var HintStr: String;
      var CanShow: Boolean; var HintInfo: THintInfo);
    procedure SBUpClick(Sender: TObject);
    procedure SBDownClick(Sender: TObject);
    procedure LBRazdKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure ChLBMenuClick(Sender: TObject);
    procedure LBRazdClick(Sender: TObject);
    procedure LBComandClick(Sender: TObject);
    procedure BCloseClick(Sender: TObject);
    procedure BAddClick(Sender: TObject);
    procedure Edit1Exit(Sender: TObject);
    procedure Edit2Exit(Sender: TObject);
    procedure HotKey1Exit(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
    function FindComandTag(Ind: integer): integer;
  public
    { Public declarations }
  end;
procedure ToIni(Always: boolean);

var
  FMSetup: TFMSetup;
  TmpMenu: TMenuItem;
  SFileIni: string;
implementation

uses UMenu, ActnList, StdActns, UOptions, UPSetup;

{$R *.DFM}

procedure ToIni(Always: boolean);
var i, j, NCount: integer;
begin
 Ini.WriteInteger('Файл','NFilesMax', NFiles);
 // Занесение списка файлов
 for i:=NFileMen to Form1.MainMenu1.Items[0].Count - 1 do
    Ini.WriteString('Файл','Файл'+IntToStr(i-NFileMen+1), Form1.MainMenu1.Items[0].Items[i].Caption);
 // занесение шрифта
 Ini.WriteString('Параметры','Шрифт', FOptions.ComboBox1.Text);
 Ini.WriteInteger('Параметры','Размер', FOptions.SpinEdit1.Value);
 // Занесение настроек
 Ini.WriteBool('Параметры','Меню', FOptions.CBMenu.Checked);
 Ini.WriteBool('Параметры','Панели', FOptions.CBPanels.Checked);
 Ini.WriteBool('Параметры','Файл', FOptions.CBFile.Checked);

 if Always or FOptions.CBMenu.Checked then
  // Цикл по меню
  for i:=0 to Form1.MainMenu1.Items.Count - 1 do begin
   with Form1.MainMenu1.Items[i] do begin
    // Удаление секции
    Ini.EraseSection(Name);
    // Занесение Caption, Visible, ShortCut, числа разделов
    Ini.WriteString(Name,'Caption',Caption);
    Ini.WriteBool(Name,'Visible',Visible);
    Ini.WriteString(Name,'ShortCut',ShortCutToText(ShortCut));
    if i > 0 then NCount := Count
    else NCount := NFileMen;
    Ini.WriteInteger(Name,'Count',NCount);
    for j:=0 to NCount-1 do begin
     // Занесение номера в Form1.Components, Caption, ShortCut
     Ini.WriteInteger(Name,Name+IntToStr(j)+'Number',Items[j].ComponentIndex);
     Ini.WriteString(Name,Name+IntToStr(j)+'Caption',Items[j].Caption);
     Ini.WriteString(Name,Name+IntToStr(j)+'ShortCut',
                ShortCutToText(Items[j].ShortCut));
    end;
   end;
  end;

 // Занесение информации о панелях TToolBar
 // Считается, что они размещены на Form1.ControlBar1
 if Always or FOptions.CBPanels.Checked then
  for i:=0 to Form1.ControlBar1.ControlCount - 1 do
   if Form1.ControlBar1.Controls[i].ClassName = 'TToolBar'
   then with Form1.ControlBar1.Controls[i] as TToolBar
    do begin
    Ini.WriteInteger(Name,'Count',ButtonCount);
    Ini.WriteBool(Name,'Visible',Visible);
    // Занесение кнопок
     for j:=0 to ButtonCount-1 do
      Ini.WriteInteger(Name,'Button'+IntToStr(j),Buttons[j].ComponentIndex);
    end;
 Ini.UpdateFile;
end;

function CopyMenuItem(Item:TMenuItem): TMenuItem;
begin
 Result := TMenuItem.Create(FMSetup);
 Result.Action := Item.Action;
 Result.Name := Item.Name;
 Result.Caption := Item.Caption;
 Result.Checked := Item.Checked;
 Result.Default := Item.Default;
 Result.Enabled := Item.Enabled;
 Result.GroupIndex := Item.GroupIndex;
 Result.HelpContext := Item.HelpContext;
 Result.Hint := Item.Hint;
 Result.RadioItem := Item.RadioItem;
 Result.ShortCut := Item.ShortCut;
 Result.Visible := Item.Visible;
 Result.Tag := Item.ComponentIndex;
end;

function TFMSetup.FindComandTag(Ind: integer): integer;
begin
 for Result:=0 to LBComand.Items.Count - 1 do
  if((LBComand.Items.Objects[Result] as TComponent).Tag = Ind)
   then exit;
 Result := -1;
end;

procedure TFMSetup.FormCreate(Sender: TObject);
var i, j, NRasd, NCount, Ind, Ind2: integer;
    F:File;
    s:string;
    TmpItem: TFileOld;
    TmpMenu2: TMenuItem;
    APchar:array[0..254] of char;

begin
 for i := 0 to Screen.Fonts.Count - 1 do
    Form1.ComboBox1.Items.Add(Screen.Fonts[i]);
 Form1.ComboBox1.ItemIndex := Form1.ComboBox1.Items.IndexOf(
                        Form1.RichEdit1.Font.Name);
 FOptions.ComboBox1.Items.Assign(Form1.ComboBox1.Items);
 FOptions.ComboBox1.ItemIndex := Form1.ComboBox1.ItemIndex;
 
// Создание и занесение в список LBComand объектов TMenuItem -
// дублей разделов меню
 NRasd := 1;
 for i:=0 to Form1.ComponentCount - 1 do
   if Form1.Components[i].ClassNameIs('TMenuItem')
   then if (Form1.Components[i] as TMenuItem).Parent <> Form1.MainMenu1.Items then
   with Form1.Components[i] as TMenuItem do begin
    TmpMenu := TMenuItem.Create(FMSetup);
    TmpMenu := CopyMenuItem(Form1.Components[i] as TMenuItem);
    if IsLine//(Caption = '-')
     then begin
      // Задание различных надписей в разделах-разделителях,
      // чтобы их можно было далее различать по надписям
      TmpMenu.Caption := 'Разделитель'+IntToStr(NRasd);
      Inc(NRasd);
     end;
    LBComand.Items.AddObject(StrAmp(TmpMenu.Caption), TmpMenu)
   end;
// Создание на форме Form1 объектов TMenuItem,
// соответствующих действиям, отсутствующим в меню,
// и занесение в список LBComand их дублей

 for i:=0 to Form1.ComponentCount - 1 do
   if (Form1.Components[i].InheritsFrom(TAction))
      and (LBComand.Items.IndexOf(StrAmp((Form1.Components[i] as TAction).Caption)) < 0)
   then begin
    TmpMenu := TMenuItem.Create(Form1);
    TmpMenu.Name := 'New_'+Form1.Components[i].Name;
    TmpMenu.Action := Form1.Components[i] as TAction;
    TmpMenu2 := TMenuItem.Create(FMSetup);
    TmpMenu2.Action := Form1.Components[i] as TAction;
    TmpMenu2.Tag := TmpMenu.ComponentIndex;
    LBComand.Items.AddObject(StrAmp(TmpMenu.Caption), TmpMenu2);
   end;

//-------------------------------------------
// РАБОТА С ФАЙЛОМ INI
 // Формирование имени ффйла .ini в каталоге Windows
 GetWindowsDirectory(APchar,255);
 SFileIni := string(APchar) + '\' +
             ExtractFileName(Application.ExeName);
 SFileIni := ChangeFileExt(SFileIni, '.INI');
 // Проверка существования файла .ini
 if not FileExists(SFileIni) then begin
  // Создание файла .ini
  AssignFile(F, SFileIni);
  Rewrite(f);
  CloseFile(F);
  Ini:=TIniFile.Create(SFileIni);
  // Создание раздела "Файлы"
  // и ключей "NFileMen", "NFilesMax" и "Файлi"
  Ini.WriteInteger('Файл','NFileMen', NFileMen);
  Ini.WriteInteger('Файл','NFilesMax', NFiles);
  for i:=1 to 10 do
   Ini.WriteString('Файл','Файл'+IntToStr(i), '');
  // Запись информации по умолчанию в файл
  ToIni(true);
 end

 // Если файл .ini имеется, то чтение информации
 else begin
  Ini:=TIniFile.Create(SFileIni);
  // Чтение настроек
  FOptions.CBMenu.Checked := Ini.ReadBool('Параметры','Меню', false);
  FOptions.CBPanels.Checked := Ini.ReadBool('Параметры','Панели', false);
  FOptions.CBFile.Checked := Ini.ReadBool('Параметры','Файл', true);

  // Цикл по меню
  for i:=0 to Form1.MainMenu1.Items.Count - 1 do begin
   with Form1.MainMenu1.Items[i] do begin
    // Чтение Caption, Visible, ShortCut
    Caption := Ini.ReadString(Name,'Caption', Caption);
    Visible := Ini.ReadBool(Name,'Visible',Visible);
    ShortCut := TextToShortCut(Ini.ReadString(Name,'ShortCut',ShortCutToText(ShortCut)));
    // Очистка содержимого Items[i]
    for j:=0 to Count-1 do
     Delete(0);
    // Чтение нового числа разделов меню
    NCount := Ini.ReadInteger(Name,'Count',Count);
    for j:=0 to NCount-1 do begin
     Ind := Ini.ReadInteger(Name,Name+IntToStr(j)+'Number',-1);
     if(Ind >= 0)
      then begin
       (Form1.Components[Ind] as TMenuItem).Caption := Ini.ReadString(Name,Name+IntToStr(j)+'Caption','');
       (Form1.Components[Ind] as TMenuItem).ShortCut := TextToShortCut(Ini.ReadString(Name,Name+IntToStr(j)+'ShortCut',''));
       Add(Form1.Components[Ind] as TMenuItem);
       if not (Form1.Components[Ind] as TMenuItem).IsLine
       then begin
        Ind2 := FindComandTag(Ind);
        if Ind2 > 0
         then begin
          (LBComand.Items.Objects[Ind2] as TMenuItem).Caption := Ini.ReadString(Name,Name+IntToStr(j)+'Caption','');
          (LBComand.Items.Objects[Ind2] as TMenuItem).ShortCut := TextToShortCut(Ini.ReadString(Name,Name+IntToStr(j)+'ShortCut',''));
         end;
       end;
      end;
    end;
   end;
  end;
  // Чтение запомненных файлов
  NFileMen := Ini.ReadInteger(Form1.MainMenu1.Items[0].Name,'Count', NFileMen);
  NFiles := Ini.ReadInteger('Файл','NFilesMax', NFiles);
  for i:=1 to NFiles do begin
   s := Ini.ReadString('Файл','Файл'+IntToStr(i), '');
   if s <> ''
   then begin
    TmpItem := TFileOld.Create(Form1);
    TmpItem.Caption := s;
    Form1.MainMenu1.Items[0].Add(TmpItem);
   end
   else break;
  end;
  if FOptions.CBFile.Checked and (Form1.MainMenu1.Items[0].Count > NFileMen)
  then Form1.MainMenu1.Items[0].Items[NFileMen].Click;
 // Чтение информации о шрифте
 Form1.RichEdit1.Font.Name := Ini.ReadString('Параметры','Шрифт', Form1.RichEdit1.Font.Name);
 Form1.ComboBox1.ItemIndex := Form1.ComboBox1.Items.IndexOf(
                                  Form1.RichEdit1.Font.Name);
 FOptions.ComboBox1.ItemIndex := Form1.ComboBox1.ItemIndex;
 FOptions.SpinEdit1.Value := Ini.ReadInteger('Параметры','Размер', Form1.RichEdit1.DefAttributes.Size);
 Form1.RichEdit1.Font.Size := FOptions.SpinEdit1.Value;

 // Чтение информации о панелях
 for i:=0 to Form1.ControlBar1.ControlCount - 1 do
   if Form1.ControlBar1.Controls[i].ClassName = 'TToolBar'
   then with Form1.ControlBar1.Controls[i] as TToolBar
    do begin
     if Name <> 'TBHide'
      then FPSetup.CheckListBox1.Checked[i] := Ini.ReadBool(Name,'Visible',true);
     // Очистка списка кнопок
     for j:=0 to ButtonCount-1 do
      Buttons[0].Parent := Form1.TBHide;
     NCount := Ini.ReadInteger(Name,'Count',0);
     for j:=NCount-1 downto 0 do begin
      Ind := Ini.ReadInteger(Name,'Button'+IntToStr(j),-1);
     if Ind >= 0
      then (Form1.Components[Ind] as TControl).Parent :=
            Form1.ControlBar1.Controls[i] as TToolBar;
     end;
     Visible :=  Ini.ReadBool(Name,'Visible',true);
    end;

 end;

// Формирование в ChLBMenu списка меню
 ChLBMenu.Items.Clear;
 for i:=0 to Form1.MainMenu1.Items.Count - 1 do begin
  TmpMenu := TMenuItem.Create(FMSetup);
  TmpMenu := CopyMenuItem(Form1.MainMenu1.Items[i]as TMenuItem);
  ChLBMenu.Checked[ChLBMenu.Items.AddObject(StrAmp(TmpMenu.Caption), TmpMenu)] :=
             Form1.MainMenu1.Items[i].Visible;
 end;
 LBComand.ItemIndex := 0;
 LBComandClick(Sender);
end;

procedure TFMSetup.FormDestroy(Sender: TObject);
begin
 ChLBMenu.Items.Clear;
 LBComand.Items.Clear;
end;

procedure TFMSetup.ApplicationEvents1ShowHint(var HintStr: String;
  var CanShow: Boolean; var HintInfo: THintInfo);
begin
if (HintInfo.HintControl.ClassName = 'TEdit') and
   (Label2.Canvas.TextWidth((HintInfo.HintControl as TEdit).Text) >
    (HintInfo.HintControl as TEdit).ClientWidth)
 then begin
  HintStr := (HintInfo.HintControl as TEdit).Text;
  ApplicationEvents1.CancelDispatch;
 end
 else if (HintInfo.HintControl.ClassName = 'TListBox')
  then if ((HintInfo.HintControl as TListBox).ItemIndex >= 0) and
      ((HintInfo.HintControl as TListBox).Canvas.TextWidth(
        (HintInfo.HintControl as TListBox).Items[
        (HintInfo.HintControl as TListBox).ItemIndex]) >
      (HintInfo.HintControl as TListBox).ClientWidth)
  then begin
    HintStr:=(HintInfo.HintControl as TListBox).Items[(HintInfo.HintControl as TListBox).ItemIndex];
    ApplicationEvents1.CancelDispatch;
  end

end;

procedure TFMSetup.SBUpClick(Sender: TObject);
begin
 if LBRazd.ItemIndex > 0
 then
  with ChLBMenu.Items.Objects[ChLBMenu.ItemIndex] as TMenuItem
  do begin
   TmpMenu := Items[LBRazd.ItemIndex];
   Delete(LBRazd.ItemIndex);
   Insert(LBRazd.ItemIndex -1,TmpMenu);
   LBRazd.Items.Exchange(LBRazd.ItemIndex - 1, LBRazd.ItemIndex);
  end;
end;

procedure TFMSetup.SBDownClick(Sender: TObject);
begin
 if LBRazd.ItemIndex < LBRazd.Items.Count - 1
 then
  with ChLBMenu.Items.Objects[ChLBMenu.ItemIndex] as TMenuItem
  do begin
   TmpMenu := Items[LBRazd.ItemIndex];
   Delete(LBRazd.ItemIndex);
   Insert(LBRazd.ItemIndex +1,TmpMenu);
   LBRazd.Items.Exchange(LBRazd.ItemIndex + 1, LBRazd.ItemIndex);
  end;
end;

procedure TFMSetup.LBRazdKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
 if(Key = VK_Delete) and (LBRazd.ItemIndex >= 0) and
  (Pos('Разделитель', LBRazd.Items[LBRazd.ItemIndex]) = 0)
 then begin
  (ChLBMenu.Items.Objects[ChLBMenu.ItemIndex] as TMenuItem).Delete(LBRazd.ItemIndex);
  LBRazd.Items.Delete(LBRazd.ItemIndex);
 end;
end;

procedure TFMSetup.ChLBMenuClick(Sender: TObject);
var i: integer;
begin
 with ChLBMenu.Items.Objects[ChLBMenu.ItemIndex] as TMenuItem do begin
  StaticText1.Caption := GetLongHint(Hint);
  Edit1.Text := Caption;
  LBRazd.Clear;
  if Count > 0
  then for i:=0 to Count - 1 do
    LBRazd.Items.AddObject(StrAmp(Items[i].Caption), Items[i])
 end;
 LBRazd.ItemIndex := 0;
 LBRazdClick(Sender);
end;

procedure TFMSetup.LBRazdClick(Sender: TObject);
begin
 StaticText2.Caption := GetLongHint((LBRazd.Items.Objects[LBRazd.ItemIndex] as TMenuItem).Hint);
 Edit2.Text := (LBRazd.Items.Objects[LBRazd.ItemIndex] as TMenuItem).Caption;
 HotKey1.HotKey := (LBRazd.Items.Objects[LBRazd.ItemIndex] as TMenuItem).ShortCut;
end;

procedure TFMSetup.LBComandClick(Sender: TObject);
begin
 StaticText3.Caption := GetLongHint((LBComand.Items.Objects[LBComand.ItemIndex] as TMenuItem).Hint);
end;

procedure TFMSetup.BCloseClick(Sender: TObject);
var i, j: integer;
    Obj: TMenuItem;
begin
 NFileMen := (ChLBMenu.Items.Objects[0] as TMenuItem).Count;
 for i:=0 to ChLBMenu.Items.Count - 1 do
 with ChLBMenu.Items.Objects[i] as TMenuItem do begin
  Form1.MainMenu1.Items[i].Visible := ChLBMenu.Checked[i];
  Form1.MainMenu1.Items[i].Caption := Caption;
  for j:=0 to Form1.MainMenu1.Items[i].Count - 1 do
   Form1.MainMenu1.Items[i].Delete(0);
  for j:=0 to Count - 1 do begin
   Obj := (Form1.Components[Items[j].Tag] as TMenuItem);
   if not Obj.IsLine
    then Obj.Caption := Items[j].Caption;
   Obj.ShortCut := Items[j].ShortCut;
   Form1.MainMenu1.Items[i].Add(Obj);
  end;
 end;
end;

procedure TFMSetup.BAddClick(Sender: TObject);
var Obj: TMenuItem;
begin
 try
  Obj := ChLBMenu.Items.Objects[ChLBMenu.ItemIndex] as TMenuItem;
  Obj.Insert(LBRazd.ItemIndex, LBComand.Items.Objects[LBComand.ItemIndex] as TMenuItem);
  ChLBMenuClick(Sender);
 except
  ShowMessage('Раздел уже имеется в меню ' +
              StrAmp((LBComand.Items.Objects[LBComand.ItemIndex] as TMenuItem).
              Parent.Caption) +
              '.'#13'Сначала его надо оттуда удалить.')
 end;
end;

procedure TFMSetup.Edit1Exit(Sender: TObject);
begin
 if(Edit1.Modified)
  then begin
   (ChLBMenu.Items.Objects[ChLBMenu.ItemIndex] as TMenuItem).Caption := Edit1.Text;
   Edit1.Modified := false;
  end;
end;

procedure TFMSetup.Edit2Exit(Sender: TObject);
begin
 if(Edit2.Modified)
  then begin
   (LBRazd.Items.Objects[LBRazd.ItemIndex] as TMenuItem).Caption := Edit2.Text;
   Edit2.Modified := false;
  end;
end;

procedure TFMSetup.HotKey1Exit(Sender: TObject);
begin
  (LBRazd.Items.Objects[LBRazd.ItemIndex] as TMenuItem).ShortCut := HotKey1.HotKey;
end;

procedure TFMSetup.FormShow(Sender: TObject);
var i, j, NRasd: integer;
begin
// Формирование в ChLBMenu списка меню,
// и занесение в эти объекты списков разделов
 NRasd := 1;
 for i:=0 to Form1.MainMenu1.Items.Count - 1 do begin
  ChLBMenu.Checked[i] := Form1.MainMenu1.Items[i].Visible;
  TmpMenu := ChLBMenu.Items.Objects[i] as TMenuItem;
  for j:=0 to TmpMenu.Count - 1 do
   TmpMenu.Delete(0);
  if Form1.MainMenu1.Items[i].Count > 0 then
   for j:=0 to Form1.MainMenu1.Items[i].Count-1 do
    if not Form1.MainMenu1.Items[i].Items[j].ClassNameIs('TFileOld')
    then begin
    if not Form1.MainMenu1.Items[i].Items[j].IsLine //Caption <> '-')
     then TmpMenu.Add((LBComand.Items.Objects[FindComandTag(Form1.MainMenu1.Items[i].Items[j].ComponentIndex)]) as TMenuItem)
     else begin
      TmpMenu.Add((LBComand.Items.Objects[LBComand.Items.IndexOf('Разделитель' + IntToStr(NRasd))]) as TMenuItem);
      Inc(NRasd);
     end
    end;
 end;
 ChLBMenu.ItemIndex := 0;
 ChLBMenuClick(Sender);
end;

end.
