Files
ewsdr/ChannelsForm.pas
T
ew8bakandClaude Sonnet 4.6 1175e42516 Add channel memory: CH button, dropdown, editor form, smart CTCSS/RPT auto-clear
- New ChannelStore.pas: TChannel record + JSON persistence (channels.json)
- New ChannelsForm.pas: full channel editor (list + fields, pre-fills from current radio state)
- CH button in RX block: left-click opens dropdown, right-click opens editor
- Active channel: button highlights with channel name, deactivates on VFO move
- ApplyChannel: auto-switches XVTR/HF band based on channel frequency; saves old
  band state before switching to prevent cache corruption
- SaveCurrentBand: skip save when VFO > 61 MHz (prevents HF cache corruption
  from VHF channel application without XVTR)
- DeactivateXvtr: save full XVTR state (was only saving LastFreq)
- CTCSS/RPT from channel marked as auto: cleared automatically when tuning away
  from channel frequency; survives band switches via FXvtrSettings auto-flags
- TXvtrEntry: add LastCTCSSAutoActive, LastFMRptAutoActive fields

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 15:39:37 +03:00

621 lines
19 KiB
ObjectPascal
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
unit ChannelsForm;
{ TChannelsForm — редактор списка каналов (channel memory).
Открывается по правой кнопке мыши на кнопке CH в блоке RX левой панели.
Список каналов слева (FlatListBox), поля редактирования справа.
Все изменения сохраняются немедленно в TChannelStore и на диск. }
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Math,
Forms, Controls, Graphics, StdCtrls, ExtCtrls,
FlatButton, FlatCheckBox, FlatComboBox, FlatEdit,
FlatSpinEdit, FlatFloatSpinEdit, FlatListBox,
AppTheme, ChannelStore;
const
// Копии из MainForm: нужны для выпадающих списков
CH_MODE_COUNT = 8;
CH_MODE_NAMES: array[0..CH_MODE_COUNT-1] of string =
('LSB','USB','DSB','CWL','CWU','FM','AM','SAM');
CH_CTCSS_COUNT = 38;
CH_CTCSS_NAMES: array[0..CH_CTCSS_COUNT-1] of string = (
'67.0', '71.9', '74.4', '77.0', '79.7', '82.5', '85.4', '88.5',
'91.5', '94.8', '97.4', '100.0', '103.5', '107.2', '110.9', '114.8',
'118.8', '123.0', '127.3', '131.8', '136.5', '141.3', '146.2', '151.4',
'156.7', '162.2', '167.9', '173.8', '179.9', '186.2', '192.8', '203.5',
'210.7', '218.1', '225.7', '233.6', '241.8', '250.3');
type
TChannelsForm = class(TForm)
private
// --- Левая панель ---
FPanelLeft: TPanel;
FBtnAdd: TFlatButton;
FBtnDelete: TFlatButton;
FBtnUp: TFlatButton;
FBtnDown: TFlatButton;
FList: TFlatListBox;
// --- Правая панель (поля редактирования) ---
FPanelRight: TPanel;
// Labels (для перекраски темой)
FLbls: array of TLabel;
// Поля
FEdGroup: TFlatEdit;
FEdName: TFlatEdit;
FSpinRXFreq: TFlatFloatSpinEdit;
FSpinTXFreq: TFlatFloatSpinEdit;
FCmbMode: TFlatComboBox;
FBtnRptNone: TFlatButton;
FBtnRptMinus: TFlatButton;
FBtnRptPlus: TFlatButton;
FSpinRptOffset: TFlatFloatSpinEdit;
FChkCTCSS: TFlatCheckBox;
FCmbCTCSS: TFlatComboBox;
FSpinPower: TFlatSpinEdit;
// Данные
FStore: TChannelStore;
FUpdating: Boolean;
FOnChanged: TNotifyEvent;
FCurrentDefaults: TChannel; // значения по умолчанию для новых каналов
procedure BuildUI;
procedure StyleBtn(B: TFlatButton; AActive: Boolean = False);
function MakeLabel(AParent: TWinControl; const Cap: string;
X, Y, W, H: Integer): TLabel;
procedure LoadChannelToFields(Idx: Integer);
procedure SaveFieldsToChannel;
procedure RefreshList(KeepIdx: Integer = -1);
function SelectedIdx: Integer;
// Handlers — список
procedure OnListClick(Sender: TObject);
procedure OnListDblClick(Sender: TObject);
// Handlers — тулбар
procedure OnAddClick(Sender: TObject);
procedure OnDeleteClick(Sender: TObject);
procedure OnUpClick(Sender: TObject);
procedure OnDownClick(Sender: TObject);
// Handlers — поля
procedure OnFieldChange(Sender: TObject);
procedure OnRptBtnClick(Sender: TObject);
procedure OnCTCSSChkChange(Sender: TObject);
procedure OnCTCSSCmbChange(Sender: TObject);
// Handlers — форма
procedure OnFormClose(Sender: TObject; var CloseAction: TCloseAction);
public
constructor Create(AOwner: TComponent; AStore: TChannelStore;
AOnChanged: TNotifyEvent); reintroduce;
procedure ApplyTheme(const T: TAppTheme);
procedure SetCurrentDefaults(const Ch: TChannel);
property OnChannelsChanged: TNotifyEvent read FOnChanged write FOnChanged;
end;
implementation
const
// Геометрия
LPANEL_W = 185; // ширина левой панели
TOOLBAR_H = 32; // высота тулбара с кнопками Add/Del/Up/Down
BTN_H = 24;
// Правая панель
LBL_X = 8;
LBL_W = 95;
CTRL_X = 106;
ROW_H = 30; // высота строки
CTRL_H = 24; // высота контрола
constructor TChannelsForm.Create(AOwner: TComponent; AStore: TChannelStore;
AOnChanged: TNotifyEvent);
begin
inherited CreateNew(AOwner);
FStore := AStore;
FOnChanged := AOnChanged;
FUpdating := False;
TChannelStore.DefaultChannel(FCurrentDefaults);
Caption := 'Channels';
BorderStyle := bsSizeable;
Width := 720;
Height := 480;
Position := poScreenCenter;
KeyPreview := True;
OnClose := @OnFormClose;
BuildUI;
ApplyTheme(DarkTheme);
RefreshList(0);
end;
procedure TChannelsForm.BuildUI;
var
i: Integer;
BtnW: Integer;
RW: Integer; // ширина правой панели
Y: Integer;
begin
// ----- Левая панель -----
FPanelLeft := TPanel.Create(Self);
FPanelLeft.Parent := Self;
FPanelLeft.Align := alLeft;
FPanelLeft.Width := LPANEL_W;
FPanelLeft.BevelOuter := bvNone;
BtnW := (LPANEL_W - 4 - 3 * 2) div 4; // 4 кнопки с зазорами
FBtnAdd := TFlatButton.Create(Self);
FBtnAdd.Parent := FPanelLeft;
FBtnAdd.SetBounds(2, 4, BtnW, BTN_H);
FBtnAdd.Caption := 'ADD';
FBtnAdd.OnClick := @OnAddClick;
FBtnDelete := TFlatButton.Create(Self);
FBtnDelete.Parent := FPanelLeft;
FBtnDelete.SetBounds(2 + (BtnW + 2), 4, BtnW, BTN_H);
FBtnDelete.Caption := 'DEL';
FBtnDelete.OnClick := @OnDeleteClick;
FBtnUp := TFlatButton.Create(Self);
FBtnUp.Parent := FPanelLeft;
FBtnUp.SetBounds(2 + 2 * (BtnW + 2), 4, BtnW, BTN_H);
FBtnUp.Caption := '↑';
FBtnUp.OnClick := @OnUpClick;
FBtnDown := TFlatButton.Create(Self);
FBtnDown.Parent := FPanelLeft;
FBtnDown.SetBounds(2 + 3 * (BtnW + 2), 4, BtnW, BTN_H);
FBtnDown.Caption := '↓';
FBtnDown.OnClick := @OnDownClick;
FList := TFlatListBox.Create(Self);
FList.Parent := FPanelLeft;
FList.SetBounds(0, TOOLBAR_H, LPANEL_W, FPanelLeft.Height - TOOLBAR_H);
FList.Anchors := [akLeft, akTop, akRight, akBottom];
FList.OnClick := @OnListClick;
FList.OnDblClick := @OnListDblClick;
// ----- Правая панель -----
FPanelRight := TPanel.Create(Self);
FPanelRight.Parent := Self;
FPanelRight.Align := alClient;
FPanelRight.BevelOuter := bvNone;
SetLength(FLbls, 0);
RW := Width - LPANEL_W;
Y := 8;
// Group
MakeLabel(FPanelRight, 'Group', LBL_X, Y + 1, LBL_W, CTRL_H);
FEdGroup := TFlatEdit.Create(Self);
FEdGroup.Parent := FPanelRight;
FEdGroup.SetBounds(CTRL_X, Y, RW - CTRL_X - 8, CTRL_H);
FEdGroup.Anchors := [akLeft, akTop, akRight];
FEdGroup.OnChange := @OnFieldChange;
Inc(Y, ROW_H);
// Name
MakeLabel(FPanelRight, 'Name', LBL_X, Y + 1, LBL_W, CTRL_H);
FEdName := TFlatEdit.Create(Self);
FEdName.Parent := FPanelRight;
FEdName.SetBounds(CTRL_X, Y, RW - CTRL_X - 8, CTRL_H);
FEdName.Anchors := [akLeft, akTop, akRight];
FEdName.OnChange := @OnFieldChange;
Inc(Y, ROW_H);
// RX Freq
MakeLabel(FPanelRight, 'RX Freq', LBL_X, Y + 1, LBL_W, CTRL_H);
FSpinRXFreq := TFlatFloatSpinEdit.Create(Self);
FSpinRXFreq.Parent := FPanelRight;
FSpinRXFreq.SetBounds(CTRL_X, Y, RW - CTRL_X - 50, CTRL_H);
FSpinRXFreq.Anchors := [akLeft, akTop, akRight];
FSpinRXFreq.MinValue := 0.001;
FSpinRXFreq.MaxValue := 2000.0;
FSpinRXFreq.Increment := 0.001;
FSpinRXFreq.DecimalPlaces := 6;
FSpinRXFreq.Value := 145.5;
FSpinRXFreq.OnChange := @OnFieldChange;
MakeLabel(FPanelRight, 'MHz', RW - 46, Y + 1, 40, CTRL_H);
Inc(Y, ROW_H);
// TX Freq
MakeLabel(FPanelRight, 'TX Freq', LBL_X, Y + 1, LBL_W, CTRL_H);
FSpinTXFreq := TFlatFloatSpinEdit.Create(Self);
FSpinTXFreq.Parent := FPanelRight;
FSpinTXFreq.SetBounds(CTRL_X, Y, RW - CTRL_X - 50, CTRL_H);
FSpinTXFreq.Anchors := [akLeft, akTop, akRight];
FSpinTXFreq.MinValue := 0.001;
FSpinTXFreq.MaxValue := 2000.0;
FSpinTXFreq.Increment := 0.001;
FSpinTXFreq.DecimalPlaces := 6;
FSpinTXFreq.Value := 145.5;
FSpinTXFreq.OnChange := @OnFieldChange;
MakeLabel(FPanelRight, 'MHz', RW - 46, Y + 1, 40, CTRL_H);
Inc(Y, ROW_H);
// Mode
MakeLabel(FPanelRight, 'Mode', LBL_X, Y + 1, LBL_W, CTRL_H);
FCmbMode := TFlatComboBox.Create(Self);
FCmbMode.Parent := FPanelRight;
FCmbMode.SetBounds(CTRL_X, Y, 160, CTRL_H);
for i := 0 to CH_MODE_COUNT - 1 do FCmbMode.Items.Add(CH_MODE_NAMES[i]);
FCmbMode.ItemIndex := 5; // FM default
FCmbMode.OnChange := @OnFieldChange;
Inc(Y, ROW_H);
// RPTR direction
MakeLabel(FPanelRight, 'RPTR', LBL_X, Y + 1, LBL_W, CTRL_H);
FBtnRptNone := TFlatButton.Create(Self);
FBtnRptNone.Parent := FPanelRight;
FBtnRptNone.SetBounds(CTRL_X, Y, 55, CTRL_H);
FBtnRptNone.Caption := 'NONE';
FBtnRptNone.Tag := 0;
FBtnRptNone.OnClick := @OnRptBtnClick;
FBtnRptMinus := TFlatButton.Create(Self);
FBtnRptMinus.Parent := FPanelRight;
FBtnRptMinus.SetBounds(CTRL_X + 58, Y, 38, CTRL_H);
FBtnRptMinus.Caption := '';
FBtnRptMinus.Tag := 1;
FBtnRptMinus.OnClick := @OnRptBtnClick;
FBtnRptPlus := TFlatButton.Create(Self);
FBtnRptPlus.Parent := FPanelRight;
FBtnRptPlus.SetBounds(CTRL_X + 99, Y, 38, CTRL_H);
FBtnRptPlus.Caption := '+';
FBtnRptPlus.Tag := 2;
FBtnRptPlus.OnClick := @OnRptBtnClick;
Inc(Y, ROW_H);
// RPTR Offset
MakeLabel(FPanelRight, 'RPT Offset', LBL_X, Y + 1, LBL_W, CTRL_H);
FSpinRptOffset := TFlatFloatSpinEdit.Create(Self);
FSpinRptOffset.Parent := FPanelRight;
FSpinRptOffset.SetBounds(CTRL_X, Y, RW - CTRL_X - 50, CTRL_H);
FSpinRptOffset.Anchors := [akLeft, akTop, akRight];
FSpinRptOffset.MinValue := 0.0;
FSpinRptOffset.MaxValue := 100.0;
FSpinRptOffset.Increment := 0.025;
FSpinRptOffset.DecimalPlaces := 3;
FSpinRptOffset.Value := 0.6;
FSpinRptOffset.OnChange := @OnFieldChange;
MakeLabel(FPanelRight, 'MHz', RW - 46, Y + 1, 40, CTRL_H);
Inc(Y, ROW_H);
// CTCSS
MakeLabel(FPanelRight, 'CTCSS', LBL_X, Y + 1, LBL_W, CTRL_H);
FChkCTCSS := TFlatCheckBox.Create(Self);
FChkCTCSS.Parent := FPanelRight;
FChkCTCSS.SetBounds(CTRL_X, Y, 26, CTRL_H);
FChkCTCSS.Caption := '';
FChkCTCSS.Checked := False;
FChkCTCSS.OnChange := @OnCTCSSChkChange;
FCmbCTCSS := TFlatComboBox.Create(Self);
FCmbCTCSS.Parent := FPanelRight;
FCmbCTCSS.SetBounds(CTRL_X + 30, Y, RW - CTRL_X - 38, CTRL_H);
FCmbCTCSS.Anchors := [akLeft, akTop, akRight];
for i := 0 to CH_CTCSS_COUNT - 1 do FCmbCTCSS.Items.Add(CH_CTCSS_NAMES[i]);
FCmbCTCSS.ItemIndex := 0;
FCmbCTCSS.OnChange := @OnCTCSSCmbChange;
Inc(Y, ROW_H);
// Power
MakeLabel(FPanelRight, 'Power', LBL_X, Y + 1, LBL_W, CTRL_H);
FSpinPower := TFlatSpinEdit.Create(Self);
FSpinPower.Parent := FPanelRight;
FSpinPower.SetBounds(CTRL_X, Y, 80, CTRL_H);
FSpinPower.MinValue := 0;
FSpinPower.MaxValue := 100;
FSpinPower.Value := 100;
FSpinPower.OnChange := @OnFieldChange;
MakeLabel(FPanelRight, '%', CTRL_X + 84, Y + 1, 20, CTRL_H);
end;
function TChannelsForm.MakeLabel(AParent: TWinControl; const Cap: string;
X, Y, W, H: Integer): TLabel;
var L: TLabel;
begin
L := TLabel.Create(Self);
L.Parent := AParent;
L.Caption := Cap;
L.SetBounds(X, Y, W, H);
L.Font.Name := 'Courier New';
L.Font.Size := 8;
L.Font.Color := DarkTheme.TextDim;
// Сохраняем для последующей перекраски темой
SetLength(FLbls, Length(FLbls) + 1);
FLbls[High(FLbls)] := L;
Result := L;
end;
procedure TChannelsForm.StyleBtn(B: TFlatButton; AActive: Boolean);
var T: TAppTheme;
begin
T := DarkTheme;
B.Active := AActive;
B.ClrNorm := T.BtnNorm;
B.ClrActive := T.BtnActive;
B.ClrHot := T.BtnHot;
B.ClrBorder := IfThen(AActive, T.BtnBorderActive, T.BtnBorderNorm);
B.ClrText := T.BtnText;
B.ClrTextAct := T.BtnTextActive;
end;
procedure TChannelsForm.ApplyTheme(const T: TAppTheme);
var
i: Integer;
Ch: TChannel;
begin
Color := T.Panel;
FPanelLeft.Color := T.Panel;
FPanelRight.Color := T.Panel;
FList.SetAppTheme(T);
StyleBtn(FBtnAdd);
StyleBtn(FBtnDelete);
StyleBtn(FBtnUp);
StyleBtn(FBtnDown);
// RPT buttons — пересчитываем Active из текущего состояния
if SelectedIdx >= 0 then
begin
Ch := FStore.GetChannel(SelectedIdx);
StyleBtn(FBtnRptNone, Ch.RptDir = 0);
StyleBtn(FBtnRptMinus, Ch.RptDir = 1);
StyleBtn(FBtnRptPlus, Ch.RptDir = 2);
end
else
begin
StyleBtn(FBtnRptNone, True);
StyleBtn(FBtnRptMinus, False);
StyleBtn(FBtnRptPlus, False);
end;
FEdGroup.SetAppTheme(T);
FEdName.SetAppTheme(T);
FSpinRXFreq.SetAppTheme(T);
FSpinTXFreq.SetAppTheme(T);
FCmbMode.SetAppTheme(T);
FSpinRptOffset.SetAppTheme(T);
FChkCTCSS.SetAppTheme(T);
FCmbCTCSS.SetAppTheme(T);
FSpinPower.SetAppTheme(T);
for i := 0 to High(FLbls) do
begin
FLbls[i].Font.Color := T.TextDim;
FLbls[i].Color := T.Panel;
FLbls[i].ParentColor := False;
end;
end;
// ---------------------------------------------------------------------------
// Список каналов
// ---------------------------------------------------------------------------
function TChannelsForm.SelectedIdx: Integer;
begin
Result := FList.ItemIndex;
end;
procedure TChannelsForm.RefreshList(KeepIdx: Integer);
var
i, NewIdx: Integer;
Ch: TChannel;
begin
FList.Items.Clear;
for i := 0 to FStore.Count - 1 do
begin
Ch := FStore.GetChannel(i);
if Ch.Group <> '' then
FList.Items.Add(Ch.Group + ': ' + Ch.Name)
else
FList.Items.Add(Ch.Name);
end;
if FStore.Count = 0 then
begin
LoadChannelToFields(-1);
Exit;
end;
NewIdx := EnsureRange(KeepIdx, 0, FStore.Count - 1);
FList.ItemIndex := NewIdx;
LoadChannelToFields(NewIdx);
end;
procedure TChannelsForm.LoadChannelToFields(Idx: Integer);
var Ch: TChannel;
HasSel: Boolean;
begin
FUpdating := True;
try
HasSel := (Idx >= 0) and (Idx < FStore.Count);
FEdGroup.Enabled := HasSel;
FEdName.Enabled := HasSel;
FSpinRXFreq.Enabled := HasSel;
FSpinTXFreq.Enabled := HasSel;
FCmbMode.Enabled := HasSel;
FBtnRptNone.Enabled := HasSel;
FBtnRptMinus.Enabled := HasSel;
FBtnRptPlus.Enabled := HasSel;
FSpinRptOffset.Enabled := HasSel;
FChkCTCSS.Enabled := HasSel;
FCmbCTCSS.Enabled := HasSel;
FSpinPower.Enabled := HasSel;
if not HasSel then Exit;
Ch := FStore.GetChannel(Idx);
FEdGroup.Text := Ch.Group;
FEdName.Text := Ch.Name;
FSpinRXFreq.Value := Ch.RXFreq / 1000000.0;
FSpinTXFreq.Value := Ch.TXFreq / 1000000.0;
FCmbMode.ItemIndex := EnsureRange(Ch.Mode, 0, CH_MODE_COUNT - 1);
StyleBtn(FBtnRptNone, Ch.RptDir = 0);
StyleBtn(FBtnRptMinus, Ch.RptDir = 1);
StyleBtn(FBtnRptPlus, Ch.RptDir = 2);
FSpinRptOffset.Value := Ch.RptOffsetHz / 1000000.0;
FChkCTCSS.Checked := Ch.CTCSSOn;
FCmbCTCSS.ItemIndex := EnsureRange(Ch.CTCSSToneIdx, 0, CH_CTCSS_COUNT - 1);
FSpinPower.Value := Ch.Power;
finally
FUpdating := False;
end;
end;
procedure TChannelsForm.SaveFieldsToChannel;
var
Idx: Integer;
Ch: TChannel;
i: Integer;
begin
if FUpdating then Exit;
Idx := SelectedIdx;
if (Idx < 0) or (Idx >= FStore.Count) then Exit;
Ch := FStore.GetChannel(Idx);
Ch.Group := FEdGroup.Text;
Ch.Name := FEdName.Text;
Ch.RXFreq := FSpinRXFreq.Value * 1000000.0;
Ch.TXFreq := FSpinTXFreq.Value * 1000000.0;
Ch.Mode := EnsureRange(FCmbMode.ItemIndex, 0, CH_MODE_COUNT - 1);
// RptDir берётся из кнопок (Active)
if FBtnRptMinus.Active then Ch.RptDir := 1
else if FBtnRptPlus.Active then Ch.RptDir := 2
else Ch.RptDir := 0;
Ch.RptOffsetHz := FSpinRptOffset.Value * 1000000.0;
Ch.CTCSSOn := FChkCTCSS.Checked;
Ch.CTCSSToneIdx := EnsureRange(FCmbCTCSS.ItemIndex, 0, CH_CTCSS_COUNT - 1);
Ch.Power := FSpinPower.Value;
FStore.UpdateChannel(Idx, Ch);
FStore.Save;
// Обновляем имя в списке
FUpdating := True;
try
if Ch.Group <> '' then
FList.Items[Idx] := Ch.Group + ': ' + Ch.Name
else
FList.Items[Idx] := Ch.Name;
finally
FUpdating := False;
end;
if Assigned(FOnChanged) then FOnChanged(Self);
end;
// ---------------------------------------------------------------------------
// Обработчики кнопок тулбара
// ---------------------------------------------------------------------------
procedure TChannelsForm.OnListClick(Sender: TObject);
begin
if FUpdating then Exit;
LoadChannelToFields(FList.ItemIndex);
end;
procedure TChannelsForm.OnListDblClick(Sender: TObject);
begin
LoadChannelToFields(FList.ItemIndex);
end;
procedure TChannelsForm.OnAddClick(Sender: TObject);
var
Ch: TChannel;
NewIdx: Integer;
begin
Ch := FCurrentDefaults; // берём значения текущего состояния радио
FStore.AddChannel(Ch);
FStore.Save;
NewIdx := FStore.Count - 1;
RefreshList(NewIdx);
if Assigned(FOnChanged) then FOnChanged(Self);
// Фокус на имя для быстрого переименования
if FEdName.Enabled then FEdName.SetFocus;
FEdName.SelectAll;
end;
procedure TChannelsForm.OnDeleteClick(Sender: TObject);
var Idx: Integer;
begin
Idx := SelectedIdx;
if (Idx < 0) or (Idx >= FStore.Count) then Exit;
FStore.DeleteChannel(Idx);
FStore.Save;
RefreshList(EnsureRange(Idx, 0, FStore.Count - 1));
if Assigned(FOnChanged) then FOnChanged(Self);
end;
procedure TChannelsForm.OnUpClick(Sender: TObject);
var Idx: Integer;
begin
Idx := SelectedIdx;
if Idx < 1 then Exit;
FStore.MoveUp(Idx);
FStore.Save;
RefreshList(Idx - 1);
if Assigned(FOnChanged) then FOnChanged(Self);
end;
procedure TChannelsForm.OnDownClick(Sender: TObject);
var Idx: Integer;
begin
Idx := SelectedIdx;
if (Idx < 0) or (Idx >= FStore.Count - 1) then Exit;
FStore.MoveDown(Idx);
FStore.Save;
RefreshList(Idx + 1);
if Assigned(FOnChanged) then FOnChanged(Self);
end;
// ---------------------------------------------------------------------------
// Обработчики полей редактирования
// ---------------------------------------------------------------------------
procedure TChannelsForm.OnFieldChange(Sender: TObject);
begin
SaveFieldsToChannel;
end;
procedure TChannelsForm.OnRptBtnClick(Sender: TObject);
var Dir: Integer;
begin
Dir := (Sender as TFlatButton).Tag;
StyleBtn(FBtnRptNone, Dir = 0);
StyleBtn(FBtnRptMinus, Dir = 1);
StyleBtn(FBtnRptPlus, Dir = 2);
SaveFieldsToChannel;
end;
procedure TChannelsForm.OnCTCSSChkChange(Sender: TObject);
begin
SaveFieldsToChannel;
end;
procedure TChannelsForm.OnCTCSSCmbChange(Sender: TObject);
begin
SaveFieldsToChannel;
end;
procedure TChannelsForm.OnFormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
CloseAction := caHide; // скрываем, не уничтожаем — указатель в MainForm остаётся валидным
end;
procedure TChannelsForm.SetCurrentDefaults(const Ch: TChannel);
begin
FCurrentDefaults := Ch;
end;
end.