Save/restore CTun, AGC, FM step per XVTR slot; add FM step to web

- Add LastCTun, LastAGCMode, LastAGCTop to TXvtrEntry; SaveCurrentBand
  now captures all three in the XVTR branch; ActivateXvtrBand restores
  them on slot switch/startup (previously CTun was always reset to False
  and AGC was never saved/restored for XVTR)
- WebServer: expose fmstep_idx in state JSON so web clients sync the
  FM step from desktop state
- WebPageHtml: swap stepSel options to FM steps (6.25k/12.5k/20k/25k)
  when mode=FM, restore HF steps when leaving FM; syncs fmstep_idx
  from server on connect and mode change

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-18 22:27:14 +03:00
co-authored by Claude Sonnet 4.6
parent c4cd8afb06
commit a59501f2c4
4 changed files with 53 additions and 13 deletions
+12 -1
View File
@@ -216,6 +216,9 @@ begin
'const stEl=document.getElementById("stEl"),latEl=document.getElementById("latEl");' +
'let cur={},vfoA=14200000,vfoB=14200000,activeVfo="A";' +
'const FM_STEP_HZ=[6250,12500,20000,25000];' +
'const FM_STEP_LBL=["6.25k","12.5k","20k","25k"];' +
'let fmStepIdx=3,lastHFStep=100,inFMStep=false;' +
'let localCenter=14200000,localSpan=192000;' + // локальные копии — обновляются мгновенно при действии пользователя
'let dragging=false,dragX0=0,dragCen0=0,dragVfo0=0,dragMs=0,wheelActiveTs=0;' +
'let hoverX=-1,wTarget="",markerOn=false,markerX=0;' +
@@ -566,6 +569,7 @@ begin
'if(!isPending("freq")){vfoA=cur.vfo_a_hz||vfoA;}' +
'if(msg.vfo_b_hz!=null)vfoB=msg.vfo_b_hz;' +
'if(msg.freq_mhz_digits!=null){freqMhzDigits=Math.max(3,Math.min(5,msg.freq_mhz_digits|0));freqMaxHz=Math.pow(10,freqMhzDigits+6)-1;}' +
'if(msg.fmstep_idx!=null){fmStepIdx=Math.max(0,Math.min(3,msg.fmstep_idx|0));if(inFMStep)syncStepSel();}' +
'if(msg.active_vfo!=null&&!isPending("freq")){' +
'const sv=msg.active_vfo===0?"A":"B";' +
'if(sv!==activeVfo){activeVfo=sv;' +
@@ -583,7 +587,7 @@ begin
'if(!isPending("mox"))updMoxBtn(!!cur.transmitting);' +
'if(!isPending("tun"))updToneBtn(!!cur.tuning);' +
'if(!isPending("drive")){const ts=q("txSl");if(ts&&!ts.matches(":active")){ts.value=cur.drive||0;var tv=q("txVal");if(tv)tv.textContent=cur.drive||0;}}' +
'if(!isPending("mode")){syncModGrp(cur.mode||0);}' +
'if(!isPending("mode")){syncModGrp(cur.mode||0);syncStepSel();}' +
'if(!isPending("attn")){const at=q("attSel");if(at)at.value=cur.attn_idx||0;}' +
'updBand(activeVfo==="A"?(cur.vfo_a_hz||0):(vfoB||0));updSpan(cur.span_hz||192000);' +
'paintSM(Number(cur.smeter_dbm||-130));' +
@@ -642,6 +646,13 @@ begin
'if(smCv.width!==(sw*dpr|0)||smCv.height!==(sh*dpr|0)){smCv.width=sw*dpr|0;smCv.height=sh*dpr|0;mctx.setTransform(dpr,0,0,dpr,0,0);}' +
'if(wfBuf.width!==wfCv.clientWidth||wfBuf.height!==wfCv.clientHeight){wfBuf.width=wfCv.clientWidth;wfBuf.height=wfCv.clientHeight;wfBCtx.fillStyle="#000";wfBCtx.fillRect(0,0,wfBuf.width,wfBuf.height);}}' +
'function syncStepSel(){const isFM=(cur.mode===5);const sel=q("stepSel");if(!sel)return;' +
'if(isFM&&!inFMStep){lastHFStep=+sel.value||100;sel.innerHTML="";' +
'FM_STEP_LBL.forEach((l,i)=>{const o=document.createElement("option");o.value=FM_STEP_HZ[i];o.textContent=l;sel.appendChild(o);});' +
'sel.value=FM_STEP_HZ[fmStepIdx];inFMStep=true;}' +
'else if(!isFM&&inFMStep){sel.innerHTML=["10 Hz","100 Hz","1 kHz","10 kHz"].map((l,i)=>`<option value="${[10,100,1000,10000][i]}">${l}</option>`).join("");' +
'sel.value=lastHFStep;inFMStep=false;}' +
'else if(isFM){sel.value=FM_STEP_HZ[fmStepIdx];}}' +
'function tuneStep(e){const s=+q("stepSel").value||100;if(e.ctrlKey&&e.shiftKey)return 1000000;if(e.ctrlKey)return 1000;if(e.shiftKey)return 10;return s;}' +
'function activeVfoHz(){return activeVfo==="A"?vfoA:vfoB;}' +
'function setActiveVfoHz(f){if(activeVfo==="A")vfoA=f;else vfoB=f;}' +