scroll freq

This commit is contained in:
2026-03-11 22:06:37 +03:00
parent 8d64bba6fc
commit 4407511d56
3 changed files with 83 additions and 4 deletions
+27
View File
@@ -478,6 +478,7 @@ type
procedure WebOnANF(On_: Boolean);
procedure WebOnFreqB(Hz: Double);
procedure WebOnActiveVfo(Idx: Integer);
procedure WebOnCenter(Hz: Double);
// Synchronize-обёртки (выполняются в UI-потоке)
procedure SyncWebFreq;
procedure SyncWebMode;
@@ -498,6 +499,7 @@ type
procedure SyncWebANF;
procedure SyncWebFreqB;
procedure SyncWebActiveVfo;
procedure SyncWebCenter;
procedure BtnWfAGCClick(Sender: TObject);
procedure BtnWfNFClick(Sender: TObject);
procedure BtnHidePanelClick(Sender: TObject);
@@ -828,6 +830,7 @@ begin
FWebServer.OnANF := WebOnANF;
FWebServer.OnFreqB := WebOnFreqB;
FWebServer.OnActiveVfo := WebOnActiveVfo;
FWebServer.OnCenter := WebOnCenter;
FWebServer.Start;
FSMeterPeak := -130;
FSMeterMin := -130;
@@ -4755,6 +4758,30 @@ begin
ActivateVfo(FWebSyncInt);
end;
// ── CTUN drag center scroll (из веба) ────────────────────────────────────
procedure TMainForm.WebOnCenter(Hz: Double);
begin
FWebSyncFreq := Hz;
FWebSyncM := SyncWebCenter;
TThread.Synchronize(nil, FWebSyncM);
end;
procedure TMainForm.SyncWebCenter;
begin
// Сдвигаем DDC-центр без смены VFO (аналог CTUN-drag в десктопе)
FCenterFreq := FWebSyncFreq;
if FWDSPReady then
begin
if FActiveVfo = 0 then FDSPEngine.SetShift(FVfoA - FCenterFreq)
else FDSPEngine.SetShift(FVfoB - FCenterFreq);
end;
if FNetwork.Connected and FNetwork.Running then
FNetwork.UpdateState(FCenterFreq, FCenterFreq, FDriveLevel, FTransmitting, True, True);
FRulerLastFreq := -1.0; FRulerLastVfo := -1.0;
FSpectrumDirty := True;
end;
procedure TMainForm.TrkDriveChange(Sender: TObject);
begin
FDriveLevel := Round(TrkDrive.Position / 100.0 * 255);
+47 -4
View File
@@ -449,10 +449,53 @@ begin
'cv.addEventListener("contextmenu",e=>e.preventDefault());' +
'cv.addEventListener("mouseenter",()=>{wTarget=cv.id;});' +
'cv.addEventListener("wheel",wh,{passive:false,capture:true});' +
'cv.addEventListener("mousedown",e=>{audioKick();wTarget=cv.id;if(e.button===2){markerOn=Math.abs(markerX-e.offsetX)>=8||!markerOn;markerX=e.offsetX;return;}if(e.button!==0)return;dragging=true;dragX0=e.offsetX;dragCen0=cur.center_hz||0;dragVfo0=activeVfoHz();dragMs=0;});' +
'cv.addEventListener("mousemove",e=>{wTarget=cv.id;hoverX=e.offsetX;if(markerOn)markerX=e.offsetX;if(!dragging)return;const n=Date.now();if(n-dragMs<35)return;dragMs=n;const dHz=(e.offsetX-dragX0)/Math.max(1,cv.clientWidth)*(cur.span_hz||0);if(cur.ctun)ws2({cmd:"freq",hz:Math.round(dragCen0-dHz)});else{const nf=cl(Math.round(dragVfo0-dHz),30000,60000000);setActiveVfoHz(nf);if(activeVfo==="A")cur.vfo_a_hz=nf;else cur.vfo_b_hz=nf;renderVfos();pend("freq");ws2({cmd:"freq",hz:nf});}});' +
'cv.addEventListener("mouseup",e=>{if(e.button===2)return;if(Math.abs(e.offsetX-dragX0)<4){const nf=cl(Math.round(xToHz(e.offsetX,cv.clientWidth)/100)*100,30000,60000000);setActiveVfoHz(nf);if(activeVfo==="A")cur.vfo_a_hz=nf;else cur.vfo_b_hz=nf;renderVfos();pend("freq");ws2({cmd:"freq",hz:nf});}dragging=false;});' +
'cv.addEventListener("mouseleave",()=>{if(!markerOn)hoverX=-1;wTarget="";dragging=false;});}' +
'cv.addEventListener("mousedown",e=>{' +
'audioKick();wTarget=cv.id;' +
'if(e.button===2){markerOn=Math.abs(markerX-e.offsetX)>=8||!markerOn;markerX=e.offsetX;return;}' +
'if(e.button!==0)return;' +
'dragging=true;dragX0=e.offsetX;' +
// CTUN ON: drag scrolls the spectrum window (center moves, VFO stays)
// CTUN OFF: drag moves active VFO (and center follows it)
'dragCen0=cur.center_hz||activeVfoHz();' +
'dragVfo0=activeVfoHz();' +
'dragMs=0;' +
'cv.style.cursor="ew-resize";' +
'});' +
'cv.addEventListener("mousemove",e=>{' +
'wTarget=cv.id;hoverX=e.offsetX;' +
'if(markerOn&&!dragging)markerX=e.offsetX;' +
'if(!dragging)return;' +
'const n=Date.now();if(n-dragMs<16)return;dragMs=n;' +
'const span=cur.span_hz||192000;' +
'const dHz=(e.offsetX-dragX0)/Math.max(1,cv.clientWidth)*span;' +
'if(cur.ctun){' +
// CTUN ON: move DDC center window, VFO marker moves on screen
'const newCen=Math.round(dragCen0-dHz);' +
'cur.center_hz=newCen;' +
'ws2({cmd:"set_center",hz:newCen});'
+ '} else {' +
// CTUN OFF: move active VFO, center follows → update center_hz locally
'const nf=cl(Math.round(dragVfo0-dHz),30000,60000000);' +
'setActiveVfoHz(nf);' +
// Optimistically update center so ruler/filter band stay in sync while dragging
'cur.center_hz=nf;' +
'if(activeVfo==="A"){cur.vfo_a_hz=nf;}else{cur.vfo_b_hz=nf;}' +
'renderVfos();pend("freq");ws2({cmd:"freq",hz:nf});' +
'}' +
'});' +
'cv.addEventListener("mouseup",e=>{' +
'cv.style.cursor="";' +
'if(e.button===2)return;' +
'if(dragging&&Math.abs(e.offsetX-dragX0)<4){' +
// Click (no drag): tune active VFO to clicked frequency
'const nf=cl(Math.round(xToHz(e.offsetX,cv.clientWidth)/100)*100,30000,60000000);' +
'setActiveVfoHz(nf);cur.center_hz=nf;' +
'if(activeVfo==="A")cur.vfo_a_hz=nf;else cur.vfo_b_hz=nf;' +
'renderVfos();pend("freq");ws2({cmd:"freq",hz:nf});' +
'}' +
'dragging=false;' +
'});' +
'cv.addEventListener("mouseleave",()=>{cv.style.cursor="";if(!markerOn)hoverX=-1;wTarget="";dragging=false;});}' +
'bindCv(specCv);bindCv(wfCv);' +
'window.addEventListener("wheel",e=>{if(e.target?.closest?.(".vfo-ro"))return;if(!wTarget){if(e.target===specCv)wTarget="spec";else if(e.target===wfCv)wTarget="wf";}if(wTarget)doWheel(e);},{passive:false,capture:true});' +
+9
View File
@@ -123,6 +123,7 @@ type
TWebCmdANF = procedure(On_: Boolean) of object;
TWebCmdFreqB = procedure(Hz: Double) of object;
TWebCmdActiveVfo = procedure(Idx: Integer) of object;
TWebCmdCenter = procedure(Hz: Double) of object;
// ── Главный класс сервера ─────────────────────────────────────────────────
TWebServer = class
@@ -202,6 +203,7 @@ type
FOnANF: TWebCmdANF;
FOnFreqB: TWebCmdFreqB;
FOnActiveVfo: TWebCmdActiveVfo;
FOnCenter: TWebCmdCenter;
FWebClientActive: Boolean;
@@ -267,6 +269,7 @@ type
property OnANF: TWebCmdANF read FOnANF write FOnANF;
property OnFreqB: TWebCmdFreqB read FOnFreqB write FOnFreqB;
property OnActiveVfo: TWebCmdActiveVfo read FOnActiveVfo write FOnActiveVfo;
property OnCenter: TWebCmdCenter read FOnCenter write FOnCenter;
end;
implementation
@@ -972,6 +975,12 @@ begin
if ModeValue > 1 then ModeValue := 1;
FStateLock.Enter; FActiveVfo := ModeValue; FStateLock.Leave;
if Assigned(FOnActiveVfo) then FOnActiveVfo(ModeValue);
end
else if Cmd = 'set_center' then
begin
HzF := JsonGetFloat(Json, 'hz', FCenterHz);
FStateLock.Enter; FCenterHz := HzF; FStateLock.Leave;
if Assigned(FOnCenter) then FOnCenter(HzF);
end;
end;