{
  Copyright (C)
  2026 - Uladzimir Karpenka, EW8BAK

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
}

unit CWMessagesForm;

{ TCWMessagesForm — память телеграфных сообщений (CW_MSG_COUNT ячеек).

  Зачем отдельным окном. Передача текста нужна ПОСРЕДИ связи, поэтому кнопки
  «отправить» обязаны быть под рукой, а не в настройках. В блоке TX левой
  панели свободных ячеек нет (MOX/TUN/PS/2TON + DUP/RX MUTE/профиль + DRV),
  поэтому окно располагается рядом. Используются те же ячейки
  привязаны к F1..F8 в главном окне.

  Правки текста пишутся в TCWSettings сразу (идиома EWSDR: кнопки «сохранить»
  нет), через тот же OnChanged, что и вкладка настроек. }

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Math,
  Forms, Controls, Graphics, StdCtrls, ExtCtrls,
  FlatButton, FlatEdit, AppTheme, Settings, DpiUtils;

type
  TCWSendEvent   = procedure(const Text: string) of object;
  TCWMsgsChanged = procedure(const C: TCWSettings) of object;

  TCWMessagesForm = class(TForm)
  private
    FCW:        TCWSettings;
    FTheme:     TAppTheme;
    FUpdating:  Boolean;
    FLbls:      array[0..CW_MSG_COUNT-1] of TLabel;
    FEdits:     array[0..CW_MSG_COUNT-1] of TFlatEdit;
    FSendBtns:  array[0..CW_MSG_COUNT-1] of TFlatButton;
    FBtnStop:   TFlatButton;
    FBtnClose:  TFlatButton;
    FHint:      TLabel;
    FOnSend:    TCWSendEvent;
    FOnAbort:   TNotifyEvent;
    FOnChanged: TCWMsgsChanged;
    procedure BuildUI;
    procedure EditChange(Sender: TObject);
    procedure SendClick(Sender: TObject);
    procedure StopClick(Sender: TObject);
    procedure CloseClick(Sender: TObject);
    procedure StyleBtn(B: TFlatButton);
  public
    constructor Create(AOwner: TComponent); override;
    procedure LoadFrom(const C: TCWSettings);
    procedure ApplyTheme(const T: TAppTheme);
    // Отправить ячейку по индексу (F1..F8 из главного окна).
    procedure SendSlot(Idx: Integer);
    property OnSend:    TCWSendEvent   read FOnSend    write FOnSend;
    property OnAbort:   TNotifyEvent   read FOnAbort   write FOnAbort;
    property OnChanged: TCWMsgsChanged read FOnChanged write FOnChanged;
  end;

implementation

const
{$IFDEF WINDOWS}
  UI_FONT = 'Segoe UI';
{$ELSE}
  UI_FONT = 'Sans';
{$ENDIF}
  FORM_W  = 470;
  PAD     = 14;
  ROW_H   = 26;
  ROW_GAP = 6;
  LBL_W   = 30;
  BTN_W   = 66;

constructor TCWMessagesForm.Create(AOwner: TComponent);
begin
  inherited CreateNew(AOwner);
  FTheme    := DarkTheme;
  FUpdating := False;
  TSettingsManager.DefaultCW(FCW);

  Scaled      := False;
  Caption     := 'CW Messages';
  BorderStyle := bsSingle;
  if AOwner is TCustomForm then Position := poOwnerFormCenter
  else                          Position := poScreenCenter;
  Width  := DpiScale(FORM_W);
  // Ряды + строка кнопок + подсказка в ДВЕ строки под ними (в один ряд с
  // кнопками она налезала на Close).
  Height := DpiScale(2 * PAD + CW_MSG_COUNT * (ROW_H + ROW_GAP)
                     + ROW_H + 8 + 34);
  BuildUI;
  ApplyTheme(DarkTheme);
end;

procedure TCWMessagesForm.BuildUI;
var
  i, Y: Integer;
begin
  Y := PAD;
  for i := 0 to CW_MSG_COUNT - 1 do
  begin
    FLbls[i] := TLabel.Create(Self);
    FLbls[i].Parent    := Self;
    FLbls[i].Caption   := 'F' + IntToStr(i + 1);
    FLbls[i].Font.Name := UI_FONT;
    FLbls[i].Font.Size := 9;
    FLbls[i].SetBounds(DpiScale(PAD), DpiScale(Y + 5),
                       DpiScale(LBL_W), DpiScale(18));

    FEdits[i] := TFlatEdit.Create(Self);
    FEdits[i].Parent    := Self;
    FEdits[i].Font.Name := UI_FONT;
    FEdits[i].Font.Size := 9;
    FEdits[i].MaxLength := 63;
    FEdits[i].Tag       := i;
    FEdits[i].OnChange  := @EditChange;
    FEdits[i].SetBounds(DpiScale(PAD + LBL_W), DpiScale(Y),
                        DpiScale(FORM_W - 2 * PAD - LBL_W - BTN_W - 8),
                        DpiScale(ROW_H - 2));

    FSendBtns[i] := TFlatButton.Create(Self);
    FSendBtns[i].Parent  := Self;
    FSendBtns[i].Caption := 'Send';
    FSendBtns[i].Tag     := i;
    FSendBtns[i].OnClick := @SendClick;
    FSendBtns[i].SetBounds(DpiScale(FORM_W - PAD - BTN_W), DpiScale(Y),
                           DpiScale(BTN_W), DpiScale(ROW_H - 2));
    Inc(Y, ROW_H + ROW_GAP);
  end;

  FBtnStop := TFlatButton.Create(Self);
  FBtnStop.Parent  := Self;
  FBtnStop.Caption := 'Stop';
  FBtnStop.OnClick := @StopClick;
  FBtnStop.SetBounds(DpiScale(PAD), DpiScale(Y), DpiScale(BTN_W), DpiScale(ROW_H));

  FBtnClose := TFlatButton.Create(Self);
  FBtnClose.Parent  := Self;
  FBtnClose.Caption := 'Close';
  FBtnClose.OnClick := @CloseClick;
  FBtnClose.SetBounds(DpiScale(FORM_W - PAD - BTN_W), DpiScale(Y),
                      DpiScale(BTN_W), DpiScale(ROW_H));

  FHint := TLabel.Create(Self);
  FHint.Parent     := Self;
  FHint.Font.Name  := UI_FONT;
  FHint.Font.Size  := 8;
  FHint.AutoSize   := False;
  FHint.WordWrap   := True;
  FHint.Caption    := 'F1..F8 in the main window send the same slots. '
                    + 'Touching the paddle or dropping MOX stops sending.';
  FHint.SetBounds(DpiScale(PAD), DpiScale(Y + ROW_H + 8),
                  DpiScale(FORM_W - 2 * PAD), DpiScale(34));
end;

procedure TCWMessagesForm.StyleBtn(B: TFlatButton);
begin
  if B = nil then Exit;
  B.ClrNorm    := FTheme.BtnNorm;
  B.ClrBorder  := FTheme.BtnBorderNorm;
  B.ClrHot     := FTheme.BtnHot;
  B.ClrActive  := FTheme.BtnActive;
  B.ClrText    := FTheme.BtnText;
  B.ClrTextAct := FTheme.BtnTextActive;
  B.Font.Name  := UI_FONT;
  B.Font.Size  := 9;
  B.Invalidate;
end;

procedure TCWMessagesForm.ApplyTheme(const T: TAppTheme);
var i: Integer;
begin
  FTheme := T;
  Color  := T.BG;
  for i := 0 to CW_MSG_COUNT - 1 do
  begin
    FLbls[i].Font.Color := T.TextDim;
    FEdits[i].SetAppTheme(T);
    StyleBtn(FSendBtns[i]);
  end;
  StyleBtn(FBtnStop);
  StyleBtn(FBtnClose);
  FHint.Font.Color := T.TextDim;
  Invalidate;
end;

procedure TCWMessagesForm.LoadFrom(const C: TCWSettings);
var i: Integer;
begin
  FUpdating := True;
  try
    FCW := C;
    for i := 0 to CW_MSG_COUNT - 1 do
      FEdits[i].Text := C.Messages[i];
  finally
    FUpdating := False;
  end;
end;

procedure TCWMessagesForm.EditChange(Sender: TObject);
var i: Integer;
begin
  if FUpdating then Exit;
  i := TFlatEdit(Sender).Tag;
  if (i < 0) or (i >= CW_MSG_COUNT) then Exit;
  FCW.Messages[i] := Copy(TFlatEdit(Sender).Text, 1, 63);
  if Assigned(FOnChanged) then FOnChanged(FCW);
end;

procedure TCWMessagesForm.SendSlot(Idx: Integer);
begin
  if (Idx < 0) or (Idx >= CW_MSG_COUNT) then Exit;
  if FCW.Messages[Idx] = '' then Exit;
  if Assigned(FOnSend) then FOnSend(FCW.Messages[Idx]);
end;

procedure TCWMessagesForm.SendClick(Sender: TObject);
begin
  SendSlot(TFlatButton(Sender).Tag);
end;

procedure TCWMessagesForm.StopClick(Sender: TObject);
begin
  if Assigned(FOnAbort) then FOnAbort(Self);
end;

procedure TCWMessagesForm.CloseClick(Sender: TObject);
begin
  Hide;
end;

end.
