mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
scroll freq
This commit is contained in:
@@ -478,6 +478,7 @@ type
|
|||||||
procedure WebOnANF(On_: Boolean);
|
procedure WebOnANF(On_: Boolean);
|
||||||
procedure WebOnFreqB(Hz: Double);
|
procedure WebOnFreqB(Hz: Double);
|
||||||
procedure WebOnActiveVfo(Idx: Integer);
|
procedure WebOnActiveVfo(Idx: Integer);
|
||||||
|
procedure WebOnCenter(Hz: Double);
|
||||||
// Synchronize-обёртки (выполняются в UI-потоке)
|
// Synchronize-обёртки (выполняются в UI-потоке)
|
||||||
procedure SyncWebFreq;
|
procedure SyncWebFreq;
|
||||||
procedure SyncWebMode;
|
procedure SyncWebMode;
|
||||||
@@ -498,6 +499,7 @@ type
|
|||||||
procedure SyncWebANF;
|
procedure SyncWebANF;
|
||||||
procedure SyncWebFreqB;
|
procedure SyncWebFreqB;
|
||||||
procedure SyncWebActiveVfo;
|
procedure SyncWebActiveVfo;
|
||||||
|
procedure SyncWebCenter;
|
||||||
procedure BtnWfAGCClick(Sender: TObject);
|
procedure BtnWfAGCClick(Sender: TObject);
|
||||||
procedure BtnWfNFClick(Sender: TObject);
|
procedure BtnWfNFClick(Sender: TObject);
|
||||||
procedure BtnHidePanelClick(Sender: TObject);
|
procedure BtnHidePanelClick(Sender: TObject);
|
||||||
@@ -828,6 +830,7 @@ begin
|
|||||||
FWebServer.OnANF := WebOnANF;
|
FWebServer.OnANF := WebOnANF;
|
||||||
FWebServer.OnFreqB := WebOnFreqB;
|
FWebServer.OnFreqB := WebOnFreqB;
|
||||||
FWebServer.OnActiveVfo := WebOnActiveVfo;
|
FWebServer.OnActiveVfo := WebOnActiveVfo;
|
||||||
|
FWebServer.OnCenter := WebOnCenter;
|
||||||
FWebServer.Start;
|
FWebServer.Start;
|
||||||
FSMeterPeak := -130;
|
FSMeterPeak := -130;
|
||||||
FSMeterMin := -130;
|
FSMeterMin := -130;
|
||||||
@@ -4755,6 +4758,30 @@ begin
|
|||||||
ActivateVfo(FWebSyncInt);
|
ActivateVfo(FWebSyncInt);
|
||||||
end;
|
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);
|
procedure TMainForm.TrkDriveChange(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
FDriveLevel := Round(TrkDrive.Position / 100.0 * 255);
|
FDriveLevel := Round(TrkDrive.Position / 100.0 * 255);
|
||||||
|
|||||||
+47
-4
@@ -449,10 +449,53 @@ begin
|
|||||||
'cv.addEventListener("contextmenu",e=>e.preventDefault());' +
|
'cv.addEventListener("contextmenu",e=>e.preventDefault());' +
|
||||||
'cv.addEventListener("mouseenter",()=>{wTarget=cv.id;});' +
|
'cv.addEventListener("mouseenter",()=>{wTarget=cv.id;});' +
|
||||||
'cv.addEventListener("wheel",wh,{passive:false,capture:true});' +
|
'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("mousedown",e=>{' +
|
||||||
'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});}});' +
|
'audioKick();wTarget=cv.id;' +
|
||||||
'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;});' +
|
'if(e.button===2){markerOn=Math.abs(markerX-e.offsetX)>=8||!markerOn;markerX=e.offsetX;return;}' +
|
||||||
'cv.addEventListener("mouseleave",()=>{if(!markerOn)hoverX=-1;wTarget="";dragging=false;});}' +
|
'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);' +
|
'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});' +
|
'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});' +
|
||||||
|
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ type
|
|||||||
TWebCmdANF = procedure(On_: Boolean) of object;
|
TWebCmdANF = procedure(On_: Boolean) of object;
|
||||||
TWebCmdFreqB = procedure(Hz: Double) of object;
|
TWebCmdFreqB = procedure(Hz: Double) of object;
|
||||||
TWebCmdActiveVfo = procedure(Idx: Integer) of object;
|
TWebCmdActiveVfo = procedure(Idx: Integer) of object;
|
||||||
|
TWebCmdCenter = procedure(Hz: Double) of object;
|
||||||
|
|
||||||
// ── Главный класс сервера ─────────────────────────────────────────────────
|
// ── Главный класс сервера ─────────────────────────────────────────────────
|
||||||
TWebServer = class
|
TWebServer = class
|
||||||
@@ -202,6 +203,7 @@ type
|
|||||||
FOnANF: TWebCmdANF;
|
FOnANF: TWebCmdANF;
|
||||||
FOnFreqB: TWebCmdFreqB;
|
FOnFreqB: TWebCmdFreqB;
|
||||||
FOnActiveVfo: TWebCmdActiveVfo;
|
FOnActiveVfo: TWebCmdActiveVfo;
|
||||||
|
FOnCenter: TWebCmdCenter;
|
||||||
|
|
||||||
FWebClientActive: Boolean;
|
FWebClientActive: Boolean;
|
||||||
|
|
||||||
@@ -267,6 +269,7 @@ type
|
|||||||
property OnANF: TWebCmdANF read FOnANF write FOnANF;
|
property OnANF: TWebCmdANF read FOnANF write FOnANF;
|
||||||
property OnFreqB: TWebCmdFreqB read FOnFreqB write FOnFreqB;
|
property OnFreqB: TWebCmdFreqB read FOnFreqB write FOnFreqB;
|
||||||
property OnActiveVfo: TWebCmdActiveVfo read FOnActiveVfo write FOnActiveVfo;
|
property OnActiveVfo: TWebCmdActiveVfo read FOnActiveVfo write FOnActiveVfo;
|
||||||
|
property OnCenter: TWebCmdCenter read FOnCenter write FOnCenter;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@@ -972,6 +975,12 @@ begin
|
|||||||
if ModeValue > 1 then ModeValue := 1;
|
if ModeValue > 1 then ModeValue := 1;
|
||||||
FStateLock.Enter; FActiveVfo := ModeValue; FStateLock.Leave;
|
FStateLock.Enter; FActiveVfo := ModeValue; FStateLock.Leave;
|
||||||
if Assigned(FOnActiveVfo) then FOnActiveVfo(ModeValue);
|
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;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user