From 87ae33644391e02105bb98f4d0c666269125e670 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Mon, 24 Jul 2017 19:27:23 +0000 Subject: [PATCH] Add the option to ALT+click a decoded CQ or QRZ message which only moves the Rx frequency to theirs, this facilitates calling a station who is busy and may have many callers on their frequency. Updated the corresponding mouse shortcuts help text. Allow for times with seconds when parsing fast mode and FT8 decodes. Exclude the RR73 grid square from and grid validation or matching, it is not a grid square any more as far as WSJT-X is concerned, it is an RRR substitute. Add a simple state machine for QSO progress such that replies and auto-sequencing can be better controlled. Get compound callsign edge cases working again and allow QSOs from and to compound callsign holders working in as many situations as possible including auto-sequencing and FT8 auto-reply mode. This does mean that a "DE W6/K1ABC DM93" type message close to a callers Tx or Rx frequency will be taken as a reply to a CQ call despite it not being explicitly addressed back to the CQ caller. Compound callsigns should work in MSK144 contest mode also as well as in short code modes with some minor restrictions (short codes will not be used where configuration demands that a message be used to send a full compound callsign). Auto sequencing has been made generic such that it can be used for more than one mode if desired. Allow the use of free text messages to sign off in auto sequenced QSOs without the message being overwritten by the sequencer. Double click actions have been added to the Tx5 radio and push buttons to revert back to the default standard 73 message. Make DisplayText class interface more idiomatic C++ and simplify a bit. Fixed some displayed widget arrangements for different modes and sub-modes so that they are consistent when starting up and when switching mode or sub-mode. This is a big change which has been extensively tested but no doubt there will also be some new defects introduced. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@7939 ab8295b8-cf94-4d9e-aec4-7959e3be5d79 --- decodedtext.cpp | 19 +- decodedtext.h | 105 ++++--- displaytext.cpp | 49 ++-- displaytext.h | 4 +- mainwindow.cpp | 690 ++++++++++++++++++++++++++------------------- mainwindow.h | 19 +- mainwindow.ui | 18 +- mouse_commands.txt | 5 +- 8 files changed, 533 insertions(+), 376 deletions(-) diff --git a/decodedtext.cpp b/decodedtext.cpp index e71ace45b..a44f697f4 100644 --- a/decodedtext.cpp +++ b/decodedtext.cpp @@ -3,6 +3,11 @@ #include #include + +extern "C" { + bool stdmsg_(const char* msg, int len); +} + QString DecodedText::CQersCall() { // extract the CQer's call TODO: does this work with all call formats? @@ -37,12 +42,12 @@ QString DecodedText::CQersCall() bool DecodedText::isJT65() { - return _string.indexOf("#") == column_mode; + return _string.indexOf("#") == column_mode + padding_; } bool DecodedText::isJT9() { - return _string.indexOf("@") == column_mode; + return _string.indexOf("@") == column_mode + padding_; } bool DecodedText::isTX() @@ -53,7 +58,7 @@ bool DecodedText::isTX() int DecodedText::frequencyOffset() { - return _string.mid(column_freq,4).toInt(); + return _string.mid(column_freq + padding_,4).toInt(); } int DecodedText::snr() @@ -64,7 +69,7 @@ int DecodedText::snr() float DecodedText::dt() { - return _string.mid(column_dt,5).toFloat(); + return _string.mid(column_dt + padding_,5).toFloat(); } /* @@ -79,7 +84,7 @@ float DecodedText::dt() // find and extract any report. Returns true if this is a standard message bool DecodedText::report(QString const& myBaseCall, QString const& dxBaseCall, /*mod*/QString& report) { - QString msg=_string.mid(column_qsoText).trimmed(); + QString msg=_string.mid(column_qsoText + padding_).trimmed(); if(msg.length() < 1) return false; msg = msg.left (22).remove (QRegularExpression {"[<>]"}); int i1=msg.indexOf('\r'); @@ -124,7 +129,7 @@ bool DecodedText::report(QString const& myBaseCall, QString const& dxBaseCall, / QString DecodedText::call() { auto call = _string; - call = call.replace (QRegularExpression {" CQ ([A-Z]{2,2}|[0-9]{3,3}) "}, " CQ_\\1 ").mid (column_qsoText); + call = call.replace (QRegularExpression {" CQ ([A-Z]{2,2}|[0-9]{3,3}) "}, " CQ_\\1 ").mid (column_qsoText + padding_); int i = call.indexOf(" "); return call.mid(0,i); } @@ -134,7 +139,7 @@ void DecodedText::deCallAndGrid(/*out*/QString& call, QString& grid) { auto msg = _string; if(msg.mid(4,1)!=" ") msg=msg.mid(0,4)+msg.mid(6,-1); //Remove seconds from UTC - msg = msg.replace (QRegularExpression {" CQ ([A-Z]{2,2}|[0-9]{3,3}) "}, " CQ_\\1 ").mid (column_qsoText); + msg = msg.replace (QRegularExpression {" CQ ([A-Z]{2,2}|[0-9]{3,3}) "}, " CQ_\\1 ").mid (column_qsoText + padding_); int i1 = msg.indexOf (" "); call = msg.mid (i1 + 1); int i2 = call.indexOf (" "); diff --git a/decodedtext.h b/decodedtext.h index bdc8c8862..06fd28c9b 100644 --- a/decodedtext.h +++ b/decodedtext.h @@ -15,79 +15,78 @@ /* 0123456789012345678901234567890123456789 -^ ^ ^ ^ ^ ^ -2343 -11 0.8 1259 # YV6BFE F6GUU R-08 -2343 -19 0.3 718 # VE6WQ SQ2NIJ -14 -2343 -7 0.3 815 # KK4DSD W7VP -16 -2343 -13 0.1 3627 @ CT1FBK IK5YZT R+02 +^ ^ ^ ^ ^ ^ +2343 -11 0.8 1259 # YV6BFE F6GUU R-08 +2343 -19 0.3 718 # VE6WQ SQ2NIJ -14 +2343 -7 0.3 815 # KK4DSD W7VP -16 +2343 -13 0.1 3627 @ CT1FBK IK5YZT R+02 -0605 Tx 1259 # CQ VK3ACF QF22 +0605 Tx 1259 # CQ VK3ACF QF22 */ class DecodedText { public: - // These define the columns in the decoded text where fields are to be found. - // We rely on these columns being the same in the fortran code (lib/decoder.f90) that formats the decoded text - enum Columns { column_time = 0, - column_snr = 5, - column_dt = 9, - column_freq = 14, - column_mode = 19, - column_qsoText = 22 }; + void operator=(const QString &rhs) + { + _string = rhs; + padding_ = _string.indexOf (" ") > 4 ? 2 : 0; // allow for seconds + }; + void operator=(const QByteArray &rhs) + { + _string = rhs; + padding_ = _string.indexOf (" ") > 4 ? 2 : 0; // allow for seconds + }; - void operator=(const QString &rhs) - { - _string = rhs; - }; - void operator=(const QByteArray &rhs) - { - _string = rhs; - }; + void operator+=(const QString &rhs) + { + _string += rhs; + }; - void operator+=(const QString &rhs) - { - _string += rhs; - }; + QString string() { return _string; }; - QString string() { return _string; }; + int indexOf(QString s) { return _string.indexOf(s); }; + int indexOf(QString s, int i) { return _string.indexOf(s,i); }; + QString mid(int f, int t) { return _string.mid(f,t); }; + QString left(int i) { return _string.left(i); }; - int indexOf(QString s) { return _string.indexOf(s); }; - int indexOf(QString s, int i) { return _string.indexOf(s,i); }; - QString mid(int f, int t) { return _string.mid(f,t); }; - QString left(int i) { return _string.left(i); }; + void clear() { _string.clear(); }; - void clear() { _string.clear(); }; + QString CQersCall(); - QString CQersCall(); + bool isJT65(); + bool isJT9(); + bool isTX(); + int frequencyOffset(); // hertz offset from the tuned dial or rx frequency, aka audio frequency + int snr(); + float dt(); - bool isJT65(); - bool isJT9(); - bool isTX(); - int frequencyOffset(); // hertz offset from the tuned dial or rx frequency, aka audio frequency - int snr(); - float dt(); - - // find and extract any report. Returns true if this is a standard message + // find and extract any report. Returns true if this is a standard message bool report(QString const& myBaseCall, QString const& dxBaseCall, /*mod*/QString& report); - // get the first text word, usually the call - QString call(); + // get the first message text word, usually the call + QString call(); - // get the second word, most likely the de call and the third word, most likely grid - void deCallAndGrid(/*out*/QString& call, QString& grid); + // get the second word, most likely the de call and the third word, most likely grid + void deCallAndGrid(/*out*/QString& call, QString& grid); - int timeInSeconds(); + int timeInSeconds(); - // returns a string of the SNR field with a leading + or - followed by two digits - QString report(); + // returns a string of the SNR field with a leading + or - followed by two digits + QString report(); private: - QString _string; - + // These define the columns in the decoded text where fields are to be found. + // We rely on these columns being the same in the fortran code (lib/decoder.f90) that formats the decoded text + enum Columns {column_time = 0, + column_snr = 5, + column_dt = 9, + column_freq = 14, + column_mode = 19, + column_qsoText = 22 }; + + QString _string; + int padding_; }; - -extern "C" { bool stdmsg_(const char* msg, int len); } - #endif // DECODEDTEXT_H diff --git a/displaytext.cpp b/displaytext.cpp index 3b8154f31..18845f7bc 100644 --- a/displaytext.cpp +++ b/displaytext.cpp @@ -40,8 +40,8 @@ void DisplayText::setContentFont(QFont const& font) void DisplayText::mouseDoubleClickEvent(QMouseEvent *e) { bool ctrl = (e->modifiers() & Qt::ControlModifier); - bool shift = (e->modifiers() & Qt::ShiftModifier); - emit(selectCallsign(shift,ctrl)); + bool alt = (e->modifiers() & Qt::AltModifier); + emit(selectCallsign(alt,ctrl)); QTextEdit::mouseDoubleClickEvent(e); } @@ -72,24 +72,24 @@ void DisplayText::appendText(QString const& text, QString const& bg) } -void DisplayText::_appendDXCCWorkedB4(DecodedText& t1, QString& bg, +QString DisplayText::_appendDXCCWorkedB4(QString message, QString const& callsign, QString * bg, LogBook logBook, QColor color_CQ, QColor color_DXCC, QColor color_NewCall) { - QString call = t1.CQersCall (); + QString call = callsign; QString countryName; bool callWorkedBefore; bool countryWorkedBefore; if(call.length()==2) { - int i0=t1.indexOf("CQ "+call); - call=t1.mid(i0+6,-1); + int i0=message.indexOf("CQ "+call); + call=message.mid(i0+6,-1); i0=call.indexOf(" "); call=call.mid(0,i0); } - if(call.length()<3) return; - if(!call.contains(QRegExp("[0-9]")) or !call.contains(QRegExp("[A-Z]"))) return; + if(call.length()<3) return message; + if(!call.contains(QRegExp("[0-9]")) or !call.contains(QRegExp("[A-Z]"))) return message; logBook.match(/*in*/call,/*out*/countryName,callWorkedBefore,countryWorkedBefore); int charsAvail = 48; @@ -97,31 +97,31 @@ void DisplayText::_appendDXCCWorkedB4(DecodedText& t1, QString& bg, // the decoder (seems) to always generate 41 chars. For a normal CQ call, the last five are spaces // TODO this magic 37 characters is also referenced in MainWindow::doubleClickOnCall() int nmin=37; - int i=t1.indexOf(" CQ "); - int k=t1.string().mid(i+4,3).toInt(); + int i=message.indexOf(" CQ "); + int k=message.mid(i+4,3).toInt(); if(k>0 and k<999) nmin += 4; - int s3 = t1.indexOf(" ",nmin); + int s3 = message.indexOf(" ",nmin); if (s3 < nmin) s3 = nmin; // always want at least the characters to position 35 s3 += 1; // convert the index into a character count - t1 = t1.left(s3); // reduce trailing white space + message = message.left(s3); // reduce trailing white space charsAvail -= s3; if (charsAvail > 4) { if (!countryWorkedBefore) // therefore not worked call either { - t1 += "!"; - bg=color_DXCC.name(); + message += "!"; + *bg = color_DXCC.name(); } else if (!callWorkedBefore) // but have worked the country { - t1 += "~"; - bg=color_NewCall.name(); + message += "~"; + *bg = color_NewCall.name(); } else { - t1 += " "; // have worked this call before - bg=color_CQ.name(); + message += " "; // have worked this call before + *bg = color_CQ.name(); } charsAvail -= 1; @@ -144,8 +144,9 @@ void DisplayText::_appendDXCCWorkedB4(DecodedText& t1, QString& bg, countryName.replace ("Asiatic", "AS"); countryName.replace ("European", "EU"); countryName.replace ("African", "AF"); - t1 += countryName; + message += countryName; } + return message; } void DisplayText::displayDecodedText(DecodedText decodedText, QString myCall, @@ -170,11 +171,13 @@ void DisplayText::displayDecodedText(DecodedText decodedText, QString myCall, or decodedText.indexOf (" " + myCall + ">") >= 0)) { bg=color_MyCall.name(); } - // if enabled add the DXCC entity and B4 status to the end of the preformated text line t1 + // if enabled add the DXCC entity and B4 status to the end of the + // preformated text line t1 + auto message = decodedText.string (); if (displayDXCCEntity && CQcall) - _appendDXCCWorkedB4(/*mod*/decodedText,bg,logBook,color_CQ, - color_DXCC,color_NewCall); - appendText(decodedText.string(),bg); + _appendDXCCWorkedB4 (message, decodedText.CQersCall (), &bg, logBook, color_CQ, + color_DXCC, color_NewCall); + appendText (message, bg); } diff --git a/displaytext.h b/displaytext.h index dc8764541..65e8bfbb5 100644 --- a/displaytext.h +++ b/displaytext.h @@ -23,7 +23,7 @@ public: void displayQSY(QString text); signals: - void selectCallsign(bool shift, bool ctrl); + void selectCallsign(bool alt, bool ctrl); public slots: void appendText(QString const& text, QString const& bg = "white"); @@ -32,7 +32,7 @@ protected: void mouseDoubleClickEvent(QMouseEvent *e); private: - void _appendDXCCWorkedB4(/*mod*/DecodedText& t1, QString &bg, LogBook logBook, + QString _appendDXCCWorkedB4(QString message, QString const& callsign, QString * bg, LogBook logBook, QColor color_CQ, QColor color_DXCC, QColor color_NewCall); QTextCharFormat m_charFormat; diff --git a/mainwindow.cpp b/mainwindow.cpp index f7f50b933..efe625537 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -154,16 +154,15 @@ namespace { Radio::Frequency constexpr default_frequency {14076000}; QRegExp message_alphabet {"[- @A-Za-z0-9+./?#<>]*"}; - QRegExp grid_regexp {QRegExp {"[A-Ra-r]{2}[0-9]{2}([A-Xa-x]{2}){0,1}"}}; + // grid exact match excluding RR73 + QRegularExpression grid_regexp {"\\A(?![Rr]{2}73)[A-Ra-r]{2}[0-9]{2}([A-Xa-x]{2}){0,1}\\z"}; bool message_is_73 (int type, QStringList const& msg_parts) { - bool b; - b = type >= 0 - && (((type < 6 || 7 == type) - && (msg_parts.contains ("73") or msg_parts.contains ("RR73"))) - || (type == 6 && !msg_parts.filter ("73").isEmpty ())); - return b; + return type >= 0 + && (((type < 6 || 7 == type) + && (msg_parts.contains ("73") || msg_parts.contains ("RR73"))) + || (type == 6 && !msg_parts.filter ("73").isEmpty ())); } int ms_minute_error () @@ -270,6 +269,8 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, m_bRefSpec {false}, m_bClearRefSpec {false}, m_bTrain {false}, + m_bAutoReply {false}, + m_QSOProgress {CALLING}, m_ihsym {0}, m_nzap {0}, m_px {0.0}, @@ -779,7 +780,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, QByteArray cfname=fname.toLocal8Bit(); fftwf_import_wisdom_from_filename(cfname); - genStdMsgs(m_rpt); + //genStdMsgs(m_rpt); m_ntx = 6; ui->txrb6->setChecked(true); @@ -1396,12 +1397,12 @@ void MainWindow::fastSink(qint64 frames) int RxFreq=ui->RxFreqSpinBox->value (); int nTRpDepth=m_TRperiod + 1000*(m_ndepth & 3); qint64 ms0 = QDateTime::currentMSecsSinceEpoch(); - strncpy(dec_data.params.mycall, (m_config.my_callsign()+" ").toLatin1(),12); + strncpy(dec_data.params.mycall, (m_baseCall+" ").toLatin1(),12); QString hisCall {ui->dxCallEntry->text ()}; bool bshmsg=ui->cbShMsgs->isChecked(); bool bcontest=m_config.contestMode(); bool bswl=ui->cbSWL->isChecked(); - strncpy(dec_data.params.hiscall,(hisCall + " ").toLatin1 ().constData (), 12); + strncpy(dec_data.params.hiscall,(Radio::base_callsign (hisCall) + " ").toLatin1 ().constData (), 12); strncpy(dec_data.params.mygrid, (m_config.my_grid()+" ").toLatin1(),6); QString dataDir; dataDir = m_config.writeable_data_dir ().absolutePath (); @@ -1430,14 +1431,7 @@ void MainWindow::fastSink(qint64 frames) m_logBook,m_config.color_CQ(),m_config.color_MyCall(),m_config.color_DXCC(), m_config.color_NewCall()); m_bDecoded=true; - int i1=message.indexOf(m_baseCall); - int i2=message.indexOf(m_hisCall); - if(i1>10 and i2>i1+3) { - if (ui->cbAutoSeq->isVisible () && ui->cbAutoSeq->isChecked () - && (message.indexOf (" 73") < 0 || m_ntx != 6)) { - if(!m_sentFirst73) processMessage (message,43,false); - } - } + auto_sequence (message, ui->sbFtol->value ()); if (m_mode != "ISCAT") postDecode (true, decodedtext.string ()); writeAllTxt(message); bool stdMsg = decodedtext.report(m_baseCall, @@ -1517,8 +1511,8 @@ void MainWindow::on_actionSettings_triggered() //Setup Dialog { // things that might change that we need know about auto callsign = m_config.my_callsign (); - bool bvhf0=m_config.enable_VHF_features(); - bool bcontest0=m_config.contestMode(); + //bool bvhf0=m_config.enable_VHF_features(); + //bool bcontest0=m_config.contestMode(); if (QDialog::Accepted == m_config.exec ()) { if (m_config.my_callsign () != callsign) { m_baseCall = Radio::base_callsign (m_config.my_callsign ()); @@ -1558,14 +1552,14 @@ void MainWindow::on_actionSettings_triggered() //Setup Dialog if(m_mode=="JT9+JT65") on_actionJT9_JT65_triggered(); if(m_mode=="JT65") { on_actionJT65_triggered(); - if(m_config.enable_VHF_features() != bvhf0) genStdMsgs(m_rpt); + //if(m_config.enable_VHF_features() != bvhf0) genStdMsgs(m_rpt); } if(m_mode=="QRA64") on_actionQRA64_triggered(); if(m_mode=="FreqCal") on_actionFreqCal_triggered(); if(m_mode=="ISCAT") on_actionISCAT_triggered(); if(m_mode=="MSK144") { on_actionMSK144_triggered(); - if(m_config.contestMode() != bcontest0) genStdMsgs(m_rpt); + //if(m_config.contestMode() != bcontest0) genStdMsgs(m_rpt); } if(m_mode=="WSPR") on_actionWSPR_triggered(); if(m_mode=="WSPR-LF") on_actionWSPR_LF_triggered(); @@ -1640,6 +1634,7 @@ void MainWindow::on_actionAbout_triggered() //Display "About" void MainWindow::on_autoButton_clicked (bool checked) { m_auto = checked; + if (!checked) m_bCallingCQ = false; statusUpdate (); m_bEchoTxOK=false; if(m_auto and (m_mode=="Echo")) { @@ -1762,7 +1757,7 @@ void MainWindow::keyPressEvent (QKeyEvent * e) break; case Qt::Key_G: if(e->modifiers() & Qt::AltModifier) { - genStdMsgs(m_rpt); + genStdMsgs (m_rpt, true); return; } break; @@ -2558,15 +2553,7 @@ void::MainWindow::fast_decode_done() dec_data.params.ndiskdat=false; // if(m_msg[0][0]==0) m_bDecoded=false; for(int i=0; i<100; i++) { - int i1=msg0.indexOf(m_baseCall); - int i2=msg0.indexOf(m_hisCall); - if ((m_mode == "MSK144" || m_bFast9) - && ui->cbAutoSeq->isVisible () && ui->cbAutoSeq->isChecked () - && tmax >= 0.0 && i1 > 10 && i2 > i1 + 3) { - if (msg0.indexOf (" 73") < 0 || m_ntx != 6) { - if(!m_sentFirst73) processMessage(msg0,43,false); - } - } + if (tmax >= 0.0) auto_sequence (msg0, ui->sbFtol->value ()); if(m_msg[i][0]==0) break; QString message=QString::fromLatin1(m_msg[i]); m_msg[i][0]=0; @@ -2739,16 +2726,20 @@ void MainWindow::readFromStdout() //readFromStdout int audioFreq=decodedtext.frequencyOffset(); if(m_mode=="FT8") { - int i1=decodedtext.string().indexOf(" "+m_baseCall+" "); - if(m_bCallingCQ and i1>0 and ui->cbFirst->isChecked()) { -// int snr=decodedtext.string().mid(6,4).toInt(); - m_bDoubleClicked=true; - processMessage(decodedtext.string(),43,false); - m_bCallingCQ=false; - ui->cbFirst->setStyleSheet(""); - } else { - audioFreq=decodedtext.string().mid(16,4).toInt(); - if(i1>0 or (abs(audioFreq - m_wideGraph->rxFreq()) <= 10)) bDisplayRight=true; + auto const& parts = decodedtext.string ().split (' ', QString::SkipEmptyParts); + if (parts.size () > 6) { + auto for_us = parts[5].contains (m_baseCall) + || ("DE" == parts[5] && qAbs (ui->RxFreqSpinBox->value () - audioFreq) <= 10); + if(m_bCallingCQ && !m_bAutoReply && for_us && ui->cbFirst->isChecked()) { + // int snr=decodedtext.string().mid(6,4).toInt(); + m_bDoubleClicked=true; + m_bAutoReply = true; + processMessage (decodedtext.string (), decodedtext.string ().size ()); + // m_bCallingCQ=false; + ui->cbFirst->setStyleSheet(""); + } else { + if (for_us or (abs(audioFreq - m_wideGraph->rxFreq()) <= 10)) bDisplayRight=true; + } } } else { if(abs(audioFreq - m_wideGraph->rxFreq()) <= 10) bDisplayRight=true; @@ -2767,7 +2758,7 @@ void MainWindow::readFromStdout() //readFromStdout } m_QSOText=decodedtext; } - if(m_mode=="FT8") FT8_AutoSeq(decodedtext.string()); + if(m_mode=="FT8") auto_sequence (decodedtext.string(), 10); postDecode (true, decodedtext.string ()); @@ -2795,14 +2786,32 @@ void MainWindow::readFromStdout() //readFromStdout } } -void MainWindow::FT8_AutoSeq(QString message) +void MainWindow::auto_sequence (QString const& message, unsigned tolerance) { - int i1=message.indexOf(m_baseCall); - int i2=message.indexOf(Radio::base_callsign(m_hisCall)); - if(i1>10 and i2>i1+3) { - if ((message.indexOf (" 73") < 0 || m_ntx != 6)) { - if(ui->cbAutoSeq->isChecked() and !m_sentFirst73) processMessage (message,43,false); - } + auto const& parts = message.split (' ', QString::SkipEmptyParts); + if (parts.size () > 6) { + bool ok; + auto df = parts[3].toInt (&ok); + auto in_tolerance = ok + && (qAbs (ui->RxFreqSpinBox->value () - df) <= int (tolerance) + || qAbs (ui->TxFreqSpinBox->value () - df) <= int (tolerance)); + if (m_auto // transmit allowed + && ui->cbAutoSeq->isVisible () && ui->cbAutoSeq->isChecked() // auto-sequencing allowed + && ((!m_bCallingCQ // not calling CQ/QRZ + && !m_sentFirst73 // finished QSO + && ((parts[5].contains (m_baseCall) + // being called and not already in a QSO + && parts[6].contains (Radio::base_callsign (ui->dxCallEntry-> text ()))) + // type 2 compound replies + || (in_tolerance + && ((m_QSOProgress >= ROGER_REPORT && message_is_73 (0, parts)) + || ("DE" == parts[5] && parts[6].contains (Radio::base_callsign (m_hisCall))))))) + || (m_bCallingCQ && m_bAutoReply + && ((in_tolerance && "DE" == parts[5]) // look for type 2 compound call replies on our Tx and Rx offsets + || parts[5].contains (m_baseCall))))) + { + processMessage (message, message.size ()); + } } } @@ -2823,7 +2832,7 @@ void MainWindow::pskPost(DecodedText decodedtext) int snr = decodedtext.snr(); Frequency frequency = m_freqNominal + audioFrequency; pskSetLocal (); - if(grid_regexp.exactMatch (grid)) { + if(grid.contains (grid_regexp)) { // qDebug() << "To PSKreporter:" << deCall << grid << frequency << msgmode << snr; psk_Reporter->addRemoteStation(deCall,grid,QString::number(frequency),msgmode, QString::number(snr),QString::number(QDateTime::currentDateTime().toTime_t())); @@ -3098,8 +3107,8 @@ void MainWindow::guiUpdate() } m_currentMessage = QString::fromLatin1(msgsent); + m_bCallingCQ = m_currentMessage.contains (QRegularExpression {"^(CQ|QRZ) "}); if(m_mode=="FT8") { - m_bCallingCQ=m_currentMessage.mid(0,3)=="CQ "; if(m_bCallingCQ) { ui->cbFirst->setStyleSheet("QCheckBox{color:red}"); } else { @@ -3128,7 +3137,8 @@ void MainWindow::guiUpdate() msg_parts[0].remove (QChar {'<'}); msg_parts[1].remove (QChar {'>'}); } - auto is_73 = message_is_73 (m_currentMessageType, msg_parts); + auto is_73 = m_QSOProgress >= ROGER_REPORT + && message_is_73 (m_currentMessageType, msg_parts); m_sentFirst73 = is_73 && !message_is_73 (m_lastMessageType, m_lastMessageSent.split (' ', QString::SkipEmptyParts)); if (m_sentFirst73) { @@ -3146,6 +3156,7 @@ void MainWindow::guiUpdate() if(b) { m_ntx=6; ui->txrb6->setChecked(true); + m_QSOProgress = CALLING; } } @@ -3192,6 +3203,7 @@ void MainWindow::guiUpdate() { ui->genMsg->setText(ui->tx6->text()); m_ntx=7; + m_QSOProgress = CALLING; m_gen_message_is_cq = true; ui->rbGenMsg->setChecked(true); } else { @@ -3219,6 +3231,16 @@ void MainWindow::guiUpdate() ui->TxFreqSpinBox->value(),m_config.color_TxMsg(),m_bFastMode); } + switch (m_ntx) + { + case 1: m_QSOProgress = REPLYING; break; + case 2: m_QSOProgress = REPORT; break; + case 3: m_QSOProgress = ROGER_REPORT; break; + case 4: m_QSOProgress = ROGERS; break; + case 5: m_QSOProgress = SIGNOFF; break; + case 6: m_QSOProgress = CALLING; break; + default: break; // determined elsewhere + } m_transmitting = true; transmitDisplay (true); statusUpdate (); @@ -3460,17 +3482,23 @@ void MainWindow::on_txrb5_toggled(bool status) } } +void MainWindow::on_txrb5_doubleClicked() +{ + genStdMsgs (m_rpt, true); +} + void MainWindow::on_txrb6_toggled(bool status) { if (status) { m_ntx=6; - if (ui->txrb6->text().contains("CQ ")) set_dateTimeQSO(-1); + if (ui->txrb6->text().contains (QRegularExpression {"^(CQ|QRZ) "})) set_dateTimeQSO(-1); } } void MainWindow::on_txb1_clicked() { m_ntx=1; + m_QSOProgress = REPLYING; ui->txrb1->setChecked(true); if (m_transmitting) m_restart=true; } @@ -3478,6 +3506,7 @@ void MainWindow::on_txb1_clicked() void MainWindow::on_txb2_clicked() { m_ntx=2; + m_QSOProgress = REPORT; ui->txrb2->setChecked(true); if (m_transmitting) m_restart=true; } @@ -3485,6 +3514,7 @@ void MainWindow::on_txb2_clicked() void MainWindow::on_txb3_clicked() { m_ntx=3; + m_QSOProgress = ROGER_REPORT; ui->txrb3->setChecked(true); if (m_transmitting) m_restart=true; } @@ -3492,6 +3522,7 @@ void MainWindow::on_txb3_clicked() void MainWindow::on_txb4_clicked() { m_ntx=4; + m_QSOProgress = ROGERS; ui->txrb4->setChecked(true); if (m_transmitting) m_restart=true; } @@ -3499,59 +3530,61 @@ void MainWindow::on_txb4_clicked() void MainWindow::on_txb5_clicked() { m_ntx=5; + m_QSOProgress = SIGNOFF; ui->txrb5->setChecked(true); if (m_transmitting) m_restart=true; } +void MainWindow::on_txb5_doubleClicked() +{ + genStdMsgs (m_rpt, true); +} + void MainWindow::on_txb6_clicked() { m_ntx=6; + m_QSOProgress = CALLING; set_dateTimeQSO(-1); ui->txrb6->setChecked(true); if (m_transmitting) m_restart=true; } -void MainWindow::doubleClickOnCall2(bool shift, bool ctrl) +void MainWindow::doubleClickOnCall2(bool alt, bool ctrl) { set_dateTimeQSO(-1); // reset our QSO start time m_decodedText2=true; - doubleClickOnCall(shift,ctrl); + doubleClickOnCall(alt,ctrl); m_decodedText2=false; } -void MainWindow::doubleClickOnCall(bool shift, bool ctrl) +void MainWindow::doubleClickOnCall(bool alt, bool ctrl) { QTextCursor cursor; - QString t; //Full contents if(m_mode=="ISCAT") { MessageBox::information_message (this, "Double-click not presently implemented for ISCAT mode"); } - if(shift) t=""; //Silence compiler warning if(m_decodedText2) { cursor=ui->decodedTextBrowser->textCursor(); - t= ui->decodedTextBrowser->toPlainText(); } else { cursor=ui->decodedTextBrowser2->textCursor(); - t= ui->decodedTextBrowser2->toPlainText(); } cursor.select(QTextCursor::LineUnderCursor); int position {cursor.position()}; - if(shift && position==-9999) return; //Silence compiler warning QString messages; if(!m_decodedText2) messages= ui->decodedTextBrowser2->toPlainText(); if(m_decodedText2) messages= ui->decodedTextBrowser->toPlainText(); if(ui->cbCQTx->isEnabled() && ui->cbCQTx->isChecked()) m_bDoubleClickAfterCQnnn=true; m_bDoubleClicked=true; - processMessage(messages, position, ctrl); + processMessage(messages, position, ctrl, alt); } -void MainWindow::processMessage(QString const& messages, int position, bool ctrl) +void MainWindow::processMessage(QString const& messages, int position, bool ctrl, bool alt) { - QString t1 = messages.mid(0,position); //contents up to \n on selected line + QString t1 = messages.left(position); //contents up to \n on selected line int i1=t1.lastIndexOf(QChar::LineFeed) + 1; //points to first char of line DecodedText decodedtext; QString t2 = messages.mid(i1,position-i1); //selected line @@ -3572,10 +3605,11 @@ void MainWindow::processMessage(QString const& messages, int position, bool ctrl int ntsec=3600*t2.mid(0,2).toInt() + 60*t2.mid(2,2).toInt(); if(m_bFastMode or m_mode=="FT8") { ntsec = ntsec + t2.mid(4,2).toInt(); - t2a=t2.mid(0,4) + t2.mid(6,-1); //Change hhmmss to hhmm for the message parser - } else { - t2a=t2.left (44); // strip and quality info trailing the decoded message + t2a = t2.left (4) + t2.mid (6); //Change hhmmss to hhmm for the message parser } + t2a = t2.left (45); // strip any quality info trailing the + // decoded message + if(m_bFastMode or m_mode=="FT8") { i1=t2a.indexOf(" CQ "); if(i1>10) { @@ -3610,8 +3644,8 @@ void MainWindow::processMessage(QString const& messages, int position, bool ctrl ui->RxFreqSpinBox->setValue (frequency); //Set Rx freq } - if(decodedtext.isTX() and !m_config.enable_VHF_features()) { - if (ctrl && ui->TxFreqSpinBox->isEnabled()) { + if (decodedtext.isTX()) { + if (!m_config.enable_VHF_features() && ctrl && ui->TxFreqSpinBox->isEnabled()) { ui->TxFreqSpinBox->setValue(frequency); //Set Tx freq } return; @@ -3629,7 +3663,8 @@ void MainWindow::processMessage(QString const& messages, int position, bool ctrl && (t4.at (5) == m_baseCall // " 73" || t4.at (5).startsWith (m_baseCall + '/') || t4.at (5).endsWith ('/' + m_baseCall)) - && t4.at (6) == "73")) + && t4.at (6) == "73") + && !(m_QSOProgress >= ROGER_REPORT && message_is_73 (0, t4))) { qDebug () << "Not processing message - hiscall:" << hiscall << "hisgrid:" << hisgrid; return; @@ -3657,10 +3692,10 @@ void MainWindow::processMessage(QString const& messages, int position, bool ctrl if(!m_bFastMode and (!m_config.enable_VHF_features() or m_mode=="FT8")) { // Don't change Tx freq if in a fast mode, or VHF features enabled; also not if a // station is calling me, unless m_lockTxFreq is true or CTRL is held down. - if ((firstcall!=m_config.my_callsign () and firstcall != m_baseCall) or - m_lockTxFreq or ctrl) { + if ((firstcall != m_config.my_callsign () && firstcall != m_baseCall && firstcall != "DE") + || m_lockTxFreq || ctrl) { if (ui->TxFreqSpinBox->isEnabled ()) { - if(!m_bFastMode) ui->TxFreqSpinBox->setValue(frequency); + if(!m_bFastMode && !alt) ui->TxFreqSpinBox->setValue(frequency); } else if(m_mode != "JT4" && m_mode != "JT65" && !m_mode.startsWith ("JT9") && m_mode != "QRA64") { return; @@ -3668,6 +3703,160 @@ void MainWindow::processMessage(QString const& messages, int position, bool ctrl } } + // prior DX call (possible QSO partner) + auto qso_partner_base_call = Radio::base_callsign (ui->dxCallEntry-> text ()); + auto base_call = Radio::base_callsign (hiscall); + +// Determine appropriate response to received message + auto dtext = " " + decodedtext.string () + " "; + int gen_msg {0}; + if(dtext.contains (" " + m_baseCall + " ") + || dtext.contains ("<" + m_baseCall + " ") + || dtext.contains ("/" + m_baseCall + " ") + || dtext.contains (" " + m_baseCall + "/") + || (firstcall == "DE" /*&& ((t4.size () > 7 && t4.at(7) != "73") || t4.size () <= 7)*/)) + { + if (t4.size () > 7 // enough fields for a normal msg + && (t4.at (5).contains (m_baseCall) || "DE" == t4.at (5)) + && t4.at (6).contains (qso_partner_base_call) + && !t4.at (7).contains (grid_regexp)) // but no grid on end of msg + { + QString r=t4.at (7); + if(m_QSOProgress >= ROGER_REPORT && (r.mid(0,3)=="RRR" || r.toInt()==73 || "RR73" == r)) { + if(ui->tabWidget->currentIndex()==1) { + gen_msg = 5; + if (ui->rbGenMsg->isChecked ()) m_ntx=7; + m_gen_message_is_cq = false; + } + else { + m_ntx=5; + ui->txrb5->setChecked(true); + } + m_QSOProgress = SIGNOFF; + } else if((m_QSOProgress >= REPORT + || (m_QSOProgress >= REPLYING && "MSK144" == m_mode && m_config.contestMode ())) + && r.mid(0,1)=="R") { + m_ntx=4; + m_QSOProgress = ROGERS; + ui->txrb4->setChecked(true); + if(ui->tabWidget->currentIndex()==1) { + gen_msg = 4; + m_ntx=7; + m_gen_message_is_cq = false; + } + } else if(m_QSOProgress >= CALLING && r.toInt()>=-50 && r.toInt()<=49) { + m_ntx=3; + m_QSOProgress = ROGER_REPORT; + ui->txrb3->setChecked(true); + if(ui->tabWidget->currentIndex()==1) { + gen_msg = 3; + m_ntx=7; + m_gen_message_is_cq = false; + } + } + else { // nothing for us + return; + } + } + else if (m_QSOProgress >= ROGERS + && t4.size () >= 7 && t4.at (5).contains (m_baseCall) && t4.at (6) == "73") { + // 73 back to compound call holder + if(ui->tabWidget->currentIndex()==1) { + gen_msg = 5; + if (ui->rbGenMsg->isChecked ()) m_ntx=7; + m_gen_message_is_cq = false; + } + else { + m_ntx=5; + ui->txrb5->setChecked(true); + } + m_QSOProgress = SIGNOFF; + } + else if (CALLING == m_QSOProgress) { + if ((t4.size () >= 9 && t4.at (5).contains (m_baseCall) && t4.at (8) == "OOO") + || (m_mode=="MSK144" && m_config.contestMode())) { + // EME short code report or MSK144 contest mode reply, send back Tx3 + m_ntx = 3; + m_QSOProgress = ROGER_REPORT; + ui->txrb3->setChecked (true); + if (ui->tabWidget->currentIndex () == 1) { + gen_msg = 3; + m_ntx = 7; + m_gen_message_is_cq = false; + } + } else { + m_ntx=2; + m_QSOProgress = REPORT; + ui->txrb2->setChecked(true); + if(ui->tabWidget->currentIndex()==1) { + gen_msg = 2; + m_ntx=7; + m_gen_message_is_cq = false; + } + + if (m_bDoubleClickAfterCQnnn and m_transmitting) { + on_stopTxButton_clicked(); + TxAgainTimer.start(1500); + } + m_bDoubleClickAfterCQnnn=false; + } + } + else { // nothing for us + return; + } + } + else if (firstcall == "DE" && t4.size () >= 8 && t4.at (7) == "73") { + if (m_QSOProgress >= ROGERS && base_call == qso_partner_base_call && m_currentMessageType) { + // 73 back to compound call holder + if(ui->tabWidget->currentIndex()==1) { + gen_msg = 5; + m_ntx=7; + m_gen_message_is_cq = false; + } + else { + m_ntx=5; + ui->txrb5->setChecked(true); + } + m_QSOProgress = SIGNOFF; + } + else { + // treat like a CQ/QRZ + m_ntx=1; + m_QSOProgress = REPLYING; + ui->txrb1->setChecked(true); + if(ui->tabWidget->currentIndex()==1) { + gen_msg = 1; + m_ntx=7; + m_gen_message_is_cq = false; + } + } + } + else if (m_QSOProgress >= ROGERS && message_is_73 (0, t4)) { + if(ui->tabWidget->currentIndex()==1) { + gen_msg = 5; + if (ui->rbGenMsg->isChecked ()) m_ntx=7; + m_gen_message_is_cq = false; + } + else { + m_ntx=5; + ui->txrb5->setChecked(true); + } + m_QSOProgress = SIGNOFF; + } + else // just work them + { + m_ntx=1; + m_QSOProgress = REPLYING; + ui->txrb1->setChecked(true); + if(ui->tabWidget->currentIndex()==1) { + gen_msg = 1; + m_ntx=7; + m_gen_message_is_cq = false; + } + } + + // if we get here then we are reacting to the message + QString s1=m_QSOText.string().trimmed(); QString s2=t2.trimmed(); if (s1!=s2 and !decodedtext.isTX()) { @@ -3678,13 +3867,10 @@ void MainWindow::processMessage(QString const& messages, int position, bool ctrl m_QSOText=decodedtext; } - // prior DX call (possible QSO partner) - auto qso_partner_base_call = Radio::base_callsign (ui->dxCallEntry-> text ()); - - auto base_call = Radio::base_callsign (hiscall); - if (base_call != Radio::base_callsign (ui->dxCallEntry-> text ()) || base_call != hiscall) + if (hiscall != "73" + && (base_call != qso_partner_base_call || base_call != hiscall)) { - if (Radio::base_callsign (ui->dxCallEntry->text ()) != base_call) { + if (qso_partner_base_call != base_call) { // clear the DX grid if the base call of his call is different // from the current DX call ui->dxGridEntry->clear (); @@ -3693,7 +3879,7 @@ void MainWindow::processMessage(QString const& messages, int position, bool ctrl // i.e. compound version of same base call ui->dxCallEntry->setText (hiscall); } - if (grid_regexp.exactMatch (hisgrid)) { + if (hisgrid.contains (grid_regexp)) { if(ui->dxGridEntry->text().mid(0,4) != hisgrid) ui->dxGridEntry->setText(hisgrid); } if (!ui->dxGridEntry->text ().size ()) @@ -3715,117 +3901,22 @@ void MainWindow::processMessage(QString const& messages, int position, bool ctrl } ui->rptSpinBox->setValue(n); - if(m_nTx73==0) genStdMsgs(rpt); //Don't genStdMsgs if we're already sending 73. - -// Determine appropriate response to received message - auto dtext = " " + decodedtext.string () + " "; - if(dtext.contains (" " + m_baseCall + " ") - || dtext.contains ("<" + m_baseCall + " ") - || dtext.contains ("/" + m_baseCall + " ") - || dtext.contains (" " + m_baseCall + "/") - || (firstcall == "DE" && ((t4.size () > 7 && t4.at(7) != "73") || t4.size () <= 7))) - { - - if (t4.size () > 7 // enough fields for a normal msg - and !grid_regexp.exactMatch (t4.at (7))) // but no grid on end of msg - { - QString r=t4.at (7); - if(r.mid(0,3)=="RRR" || (r.toInt()==73)) { - m_ntx=5; - ui->txrb5->setChecked(true); - if(ui->tabWidget->currentIndex()==1) { - ui->genMsg->setText(ui->tx5->currentText()); - m_ntx=7; - m_gen_message_is_cq = false; - ui->rbGenMsg->setChecked(true); - } - } else if(r.mid(0,1)=="R") { - m_ntx=4; - ui->txrb4->setChecked(true); - if(ui->tabWidget->currentIndex()==1) { - ui->genMsg->setText(ui->tx4->text()); - m_ntx=7; - m_gen_message_is_cq = false; - ui->rbGenMsg->setChecked(true); - } - } else if(r.toInt()>=-50 and r.toInt()<=49) { - m_ntx=3; - ui->txrb3->setChecked(true); - if(ui->tabWidget->currentIndex()==1) { - ui->genMsg->setText(ui->tx3->text()); - m_ntx=7; - m_gen_message_is_cq = false; - ui->rbGenMsg->setChecked(true); - } - } - } - else if (t4.size () == 7 && t4.at (6) == "73") { - // 73 back to compound call holder - m_ntx=5; - ui->txrb5->setChecked(true); - if(ui->tabWidget->currentIndex()==1) { - ui->genMsg->setText(ui->tx5->currentText()); - m_ntx=7; - m_gen_message_is_cq = false; - ui->rbGenMsg->setChecked(true); - } - } else { - if(m_mode=="MSK144" and m_config.contestMode()) { - m_ntx=3; - ui->txrb3->setChecked(true); - } else { - m_ntx=2; - ui->txrb2->setChecked(true); - } - if(ui->tabWidget->currentIndex()==1) { - ui->genMsg->setText(ui->tx2->text()); - m_ntx=7; - m_gen_message_is_cq = false; - ui->rbGenMsg->setChecked(true); - } - - if(m_bDoubleClickAfterCQnnn and m_transmitting) { - on_stopTxButton_clicked(); - TxAgainTimer.start(1500); - } - m_bDoubleClickAfterCQnnn=false; + if (!m_nTx73) { // Don't genStdMsgs if we're already sending 73. + genStdMsgs(rpt); + if (gen_msg) { + switch (gen_msg) { + case 1: ui->genMsg->setText (ui->tx1->text ()); break; + case 2: ui->genMsg->setText (ui->tx2->text ()); break; + case 3: ui->genMsg->setText (ui->tx3->text ()); break; + case 4: ui->genMsg->setText (ui->tx4->text ()); break; + case 5: ui->genMsg->setText (ui->tx5->currentText ()); break; } - } - else if (firstcall == "DE" && t4.size () == 8 && t4.at (7) == "73") { - if (base_call == qso_partner_base_call) { - // 73 back to compound call holder - m_ntx=5; - ui->txrb5->setChecked(true); - if(ui->tabWidget->currentIndex()==1) { - ui->genMsg->setText(ui->tx5->currentText()); - m_ntx=7; - m_gen_message_is_cq = false; - ui->rbGenMsg->setChecked(true); - } - } - else { - // treat like a CQ/QRZ - m_ntx=1; - ui->txrb1->setChecked(true); - if(ui->tabWidget->currentIndex()==1) { - ui->genMsg->setText(ui->tx1->text()); - m_ntx=7; - m_gen_message_is_cq = false; - ui->rbGenMsg->setChecked(true); + if (gen_msg != 5) { // allow user to pre-select a free message + ui->rbGenMsg->setChecked (true); } } } - else // myCall not in msg - { - m_ntx=1; - ui->txrb1->setChecked(true); - if(ui->tabWidget->currentIndex()==1) { - ui->genMsg->setText(ui->tx1->text()); - m_ntx=7; - m_gen_message_is_cq = false; - ui->rbGenMsg->setChecked(true); - } - } + if(m_transmitting) m_restart=true; if (ui->cbAutoSeq->isVisible () && ui->cbAutoSeq->isChecked () && !m_bDoubleClicked) return; if(m_config.quick_call()) auto_tx_mode(true); @@ -3836,19 +3927,27 @@ void MainWindow::genCQMsg () { if(m_config.my_callsign().size () && m_config.my_grid().size ()) { + auto const& grid = m_config.my_callsign () != m_baseCall && shortList (m_config.my_callsign ()) ? QString {} : m_config.my_grid (); if (ui->cbCQTx->isEnabled () && ui->cbCQTx->isVisible () && ui->cbCQTx->isChecked ()) { msgtype (QString {"CQ %1 %2 %3"} .arg (m_freqNominal / 1000 - m_freqNominal / 1000000 * 1000, 3, 10, QChar {'0'}) .arg (m_config.my_callsign()) - .arg (m_config.my_grid ().left (4)), + .arg (grid.left (4)), ui->tx6); } else { - msgtype (QString {"CQ %1 %2"}.arg (m_config.my_callsign ()).arg (m_config.my_grid ().left (4)), ui->tx6); + msgtype (QString {"CQ %1 %2"}.arg (m_config.my_callsign ()).arg (grid.left (4)), ui->tx6); } - if ((m_mode=="JT4" or m_mode=="QRA64") and ui->cbShMsgs->isChecked()) msgtype ("@1000 (TUNE)", ui->tx6); + if ((m_mode=="JT4" or m_mode=="QRA64") and ui->cbShMsgs->isChecked()) { + if (ui->cbTx6->isChecked ()) { + msgtype ("@1250 (SEND MSGS)", ui->tx6); + } + else { + msgtype ("@1000 (TUNE)", ui->tx6); + } + } } else { @@ -3856,10 +3955,10 @@ void MainWindow::genCQMsg () } } -void MainWindow::genStdMsgs(QString rpt) +void MainWindow::genStdMsgs(QString rpt, bool unconditional) { genCQMsg (); - QString hisCall=ui->dxCallEntry->text(); + auto const& hisCall=ui->dxCallEntry->text(); if(!hisCall.size ()) { ui->labAz->clear (); // ui->labDist->clear (); @@ -3867,18 +3966,25 @@ void MainWindow::genStdMsgs(QString rpt) ui->tx2->clear (); ui->tx3->clear (); ui->tx4->clear (); - ui->tx5->lineEdit ()->clear (); + if (unconditional) { // leave in place in case it needs + // sending again + ui->tx5->lineEdit ()->clear (); + } ui->genMsg->clear (); m_gen_message_is_cq = false; return; } - QString hisBase = Radio::base_callsign (hisCall); - + auto const& my_callsign = m_config.my_callsign (); + auto is_compound = my_callsign != m_baseCall; + auto is_type_one = is_compound && shortList (my_callsign); + auto const& my_grid = m_config.my_grid ().left (4); + auto const& hisBase = Radio::base_callsign (hisCall); + auto eme_short_codes = m_config.enable_VHF_features () && ui->cbShMsgs->isChecked () && m_mode == "JT65"; QString t0=hisBase + " " + m_baseCall + " "; QString t00=t0; - QString t {t0 + m_config.my_grid ().left (4)}; + QString t {t0 + my_grid}; msgtype(t, ui->tx1); - if(m_config.enable_VHF_features() and ui->cbShMsgs->isChecked() and m_mode=="JT65") { + if (eme_short_codes) { t=t+" OOO"; msgtype(t, ui->tx2); msgtype("RO", ui->tx3); @@ -3890,9 +3996,9 @@ void MainWindow::genStdMsgs(QString rpt) if(m_mode=="MSK144") { if(m_config.contestMode()) { - t=t0 + m_config.my_grid().mid(0,4); + t=t0 + my_grid; msgtype(t, ui->tx2); - t=t0 + "R " + m_config.my_grid().mid(0,4); + t=t0 + "R " + my_grid; msgtype(t, ui->tx3); } if(m_bShMsgs) { @@ -3917,76 +4023,84 @@ void MainWindow::genStdMsgs(QString rpt) msgtype(t, ui->tx3); } t=t0 + "RRR"; - if((m_mode=="JT4" or m_mode=="QRA64") and m_bShMsgs) t="@1500 (RRR)"; + if ((m_mode=="JT4" || m_mode=="QRA64") && m_bShMsgs) t="@1500 (RRR)"; msgtype(t, ui->tx4); t=t0 + "73"; - if(m_mode=="JT4" or m_mode=="QRA64") { - if (m_bShMsgs) t="@1750 (73)"; - msgtype(t, ui->tx5->lineEdit ()); + if (m_mode=="JT4" || m_mode=="QRA64") { + if (m_bShMsgs) t="@1750 (73)"; + msgtype(t, ui->tx5->lineEdit ()); } - else if (hisBase != m_lastCallsign) { // only update tx5 when callsign changes - + else if ("MSK144" == m_mode && m_bShMsgs) { + msgtype(t, ui->tx5->lineEdit ()); + } + else if (unconditional || hisBase != m_lastCallsign) { + // only update tx5 when forced or callsign changes msgtype(t, ui->tx5->lineEdit ()); m_lastCallsign = hisBase; } - } + } - if(m_config.my_callsign () != m_baseCall) { - if(shortList(m_config.my_callsign ())) { - t=hisBase + " " + m_config.my_callsign (); + if (is_compound) { + if (is_type_one) { + t=hisBase + " " + my_callsign; msgtype(t, ui->tx1); - t="CQ " + m_config.my_callsign (); - if(ui->cbCQTx->isEnabled () && ui->cbCQTx->isVisible () && ui->cbCQTx->isChecked()) { - msgtype ( - QString {"CQ %1 %2"} - .arg (m_freqNominal / 1000 - m_freqNominal / 1000000 * 1000, 3, 10, QChar {'0'}) - .arg (m_config.my_callsign()), - ui->tx6); - } - else msgtype(t, ui->tx6); } else { switch (m_config.type_2_msg_gen ()) { case Configuration::type_2_msg_1_full: - t="DE " + m_config.my_callsign () + " " + m_config.my_grid ().mid(0,4); + t="DE " + my_callsign + " " + my_grid; msgtype(t, ui->tx1); - t=t0 + "R" + rpt; - msgtype(t, ui->tx3); + if (!eme_short_codes) { + t=t0 + "R" + rpt; + msgtype(t, ui->tx3); + if ((m_mode != "JT4" && m_mode != "QRA64") || !m_bShMsgs) { + t="DE " + my_callsign + " 73"; + msgtype(t, ui->tx5->lineEdit ()); + } + } break; case Configuration::type_2_msg_3_full: - t = t0 + m_config.my_grid ().mid(0,4); + t = t00 + my_grid; msgtype(t, ui->tx1); - t="DE " + m_config.my_callsign () + " R" + rpt; + t="DE " + my_callsign + " R" + rpt; msgtype(t, ui->tx3); + if (!eme_short_codes && ((m_mode != "JT4" && m_mode != "QRA64") || !m_bShMsgs)) { + t="DE " + my_callsign + " 73"; + msgtype(t, ui->tx5->lineEdit ()); + } break; case Configuration::type_2_msg_5_only: - t = t0 + m_config.my_grid ().mid(0,4); + t = t00 + my_grid; msgtype(t, ui->tx1); - t=t0 + "R" + rpt; - msgtype(t, ui->tx3); + if (!eme_short_codes) { + t=t0 + "R" + rpt; + msgtype(t, ui->tx3); + } + t="DE " + my_callsign + " 73"; + msgtype(t, ui->tx5->lineEdit ()); break; } - t="DE " + m_config.my_callsign () + " 73"; - msgtype(t, ui->tx5->lineEdit ()); } if (hisCall != hisBase - && m_config.type_2_msg_gen () != Configuration::type_2_msg_5_only) { + && m_config.type_2_msg_gen () != Configuration::type_2_msg_5_only + && !eme_short_codes) { // cfm we have his full call copied as we could not do this earlier t = hisCall + " 73"; msgtype(t, ui->tx5->lineEdit ()); } } else { - if(hisCall!=hisBase) { - if(shortList(hisCall)) { + if (hisCall != hisBase) { + if (shortList(hisCall)) { // cfm we know his full call with a type 1 tx1 message - t=hisCall + " " + m_config.my_callsign (); + t = hisCall + " " + my_callsign; msgtype(t, ui->tx1); } - else { + else if (!eme_short_codes + && ("MSK144" != m_mode || !m_bShMsgs)) { t=hisCall + " 73"; - msgtype(t, ui->tx5->lineEdit()); + msgtype(t, ui->tx5->lineEdit ()); } } } @@ -4002,6 +4116,7 @@ void MainWindow::clearDX () { ui->dxCallEntry->clear (); ui->dxGridEntry->clear (); + m_lastCallsign.clear (); m_rptSent.clear (); m_rptRcvd.clear (); m_qsoStart.clear (); @@ -4019,6 +4134,7 @@ void MainWindow::clearDX () m_ntx=6; ui->txrb6->setChecked(true); } + m_QSOProgress = CALLING; } void MainWindow::lookup() //lookup() @@ -4362,6 +4478,8 @@ void MainWindow::displayWidgets(int n) b=m_mode=="FT8"; ui->cbFirst->setVisible(b); ui->cbWeak->setVisible(false); + m_lastCallsign.clear (); // ensures Tx5 is updated for new modes + genStdMsgs (m_rpt, true); } void MainWindow::on_actionFT8_triggered() @@ -4377,7 +4495,6 @@ void MainWindow::on_actionFT8_triggered() */ m_mode="FT8"; bool bVHF=false; - displayWidgets(nWidgets("111010000000111000010000")); m_bFast9=false; m_bFastMode=false; WSPR_config(false); @@ -4393,7 +4510,6 @@ void MainWindow::on_actionFT8_triggered() m_wideGraph->setMode(m_mode); m_wideGraph->setModeTx(m_modeTx); VHF_features_enabled(bVHF); - ui->cbAutoSeq->setVisible(true); ui->cbAutoSeq->setChecked(true); m_TRperiod=15; m_fastGraph->hide(); @@ -4405,6 +4521,7 @@ void MainWindow::on_actionFT8_triggered() m_detector->setPeriod(m_TRperiod); // TODO - not thread safe ui->label_6->setText("Band Activity"); ui->label_7->setText("Rx Frequency"); + displayWidgets(nWidgets("111010000100111000010000")); statusChanged(); } @@ -4412,11 +4529,6 @@ void MainWindow::on_actionJT4_triggered() { m_mode="JT4"; bool bVHF=m_config.enable_VHF_features(); - if(bVHF) { - displayWidgets(nWidgets("111110010010111110110000")); - } else { - displayWidgets(nWidgets("111010000000111000111100")); - } WSPR_config(false); switch_mode (Modes::JT4); m_modeTx="JT4"; @@ -4437,7 +4549,6 @@ void MainWindow::on_actionJT4_triggered() m_bFastMode=false; m_bFast9=false; setup_status_bar (bVHF); - fast_config(false); ui->sbSubmode->setMaximum(6); ui->label_6->setText("Single-Period Decodes"); ui->label_7->setText("Average Decodes"); @@ -4448,6 +4559,12 @@ void MainWindow::on_actionJT4_triggered() } else { ui->sbSubmode->setValue(0); } + if(bVHF) { + displayWidgets(nWidgets("111110010010111110110000")); + } else { + displayWidgets(nWidgets("111010000000111000111100")); + } + fast_config(false); statusChanged(); } @@ -4455,11 +4572,6 @@ void MainWindow::on_actionJT9_triggered() { m_mode="JT9"; bool bVHF=m_config.enable_VHF_features(); - if(bVHF) { - displayWidgets(nWidgets("111110101100111110010000")); - } else { - displayWidgets(nWidgets("111010000000111000010000")); - } m_bFast9=ui->cbFast9->isChecked(); m_bFastMode=m_bFast9; WSPR_config(false); @@ -4482,9 +4594,7 @@ void MainWindow::on_actionJT9_triggered() ui->cbFast9->setEnabled(false); ui->cbFast9->setChecked(false); } - ui->cbAutoSeq->setVisible(m_bFast9); ui->sbSubmode->setMaximum(7); - fast_config(m_bFastMode); if(m_bFast9) { m_TRperiod = ui->sbTR->value (); m_wideGraph->hide(); @@ -4504,13 +4614,19 @@ void MainWindow::on_actionJT9_triggered() m_detector->setPeriod(m_TRperiod); // TODO - not thread safe ui->label_6->setText("Band Activity"); ui->label_7->setText("Rx Frequency"); + if(bVHF) { + displayWidgets(nWidgets("111110101000111110010000")); + } else { + displayWidgets(nWidgets("111010000000111000010000")); + } + fast_config(m_bFastMode); + ui->cbAutoSeq->setVisible(m_bFast9); statusChanged(); } void MainWindow::on_actionJT9_JT65_triggered() { m_mode="JT9+JT65"; - displayWidgets(nWidgets("111010000001111000010000")); WSPR_config(false); switch_mode (Modes::JT65); if(m_modeTx != "JT65") { @@ -4535,12 +4651,13 @@ void MainWindow::on_actionJT9_JT65_triggered() m_wideGraph->setModeTx(m_modeTx); m_bFastMode=false; m_bFast9=false; - fast_config(false); ui->sbSubmode->setValue(0); ui->label_6->setText("Band Activity"); ui->label_7->setText("Rx Frequency"); ui->decodedTextLabel->setText("UTC dB DT Freq Message"); ui->decodedTextLabel2->setText("UTC dB DT Freq Message"); + displayWidgets(nWidgets("111010000001111000010000")); + fast_config(false); statusChanged(); } @@ -4555,11 +4672,6 @@ void MainWindow::on_actionJT65_triggered() on_actionJT9_triggered(); m_mode="JT65"; bool bVHF=m_config.enable_VHF_features(); - if(bVHF) { - displayWidgets(nWidgets("111110010000111110110000")); - } else { - displayWidgets(nWidgets("111010000000111000011100")); - } WSPR_config(false); switch_mode (Modes::JT65); if(m_modeTx!="JT65") on_pbTxMode_clicked(); @@ -4580,7 +4692,6 @@ void MainWindow::on_actionJT65_triggered() setup_status_bar (bVHF); m_bFastMode=false; m_bFast9=false; - fast_config(false); ui->sbSubmode->setMaximum(2); if(bVHF) { ui->sbSubmode->setValue(m_nSubMode); @@ -4591,6 +4702,12 @@ void MainWindow::on_actionJT65_triggered() ui->label_6->setText("Band Activity"); ui->label_7->setText("Rx Frequency"); } + if(bVHF) { + displayWidgets(nWidgets("111110010000111110110000")); + } else { + displayWidgets(nWidgets("111010000000111000011100")); + } + fast_config(false); statusChanged(); } @@ -4600,11 +4717,9 @@ void MainWindow::on_actionQRA64_triggered() on_actionJT65_triggered(); m_nSubMode=n; m_mode="QRA64"; - displayWidgets(nWidgets("111110010010111110000000")); m_modeTx="QRA64"; ui->actionQRA64->setChecked(true); switch_mode (Modes::QRA64); - statusChanged(); setup_status_bar (true); m_hsymStop=180; if(m_config.decode_at_52s()) m_hsymStop=188; @@ -4622,12 +4737,13 @@ void MainWindow::on_actionQRA64_triggered() "Using old QRA64 sync pattern."); m_bQRAsyncWarned=true; } + displayWidgets(nWidgets("111110010010111110000000")); + statusChanged(); } void MainWindow::on_actionISCAT_triggered() { m_mode="ISCAT"; - displayWidgets(nWidgets("100111000000000110000000")); m_modeTx="ISCAT"; ui->actionISCAT->setChecked(true); m_TRperiod = ui->sbTR->value (); @@ -4647,7 +4763,6 @@ void MainWindow::on_actionISCAT_triggered() if(!m_fastGraph->isVisible()) m_fastGraph->show(); if(m_wideGraph->isVisible()) m_wideGraph->hide(); setup_status_bar (true); - fast_config(true); ui->cbShMsgs->setChecked(false); ui->label_7->setText(""); ui->decodedTextBrowser2->setVisible(false); @@ -4658,14 +4773,14 @@ void MainWindow::on_actionISCAT_triggered() ui->sbSubmode->setMaximum(1); if(m_nSubMode==0) ui->TxFreqSpinBox->setValue(1012); if(m_nSubMode==1) ui->TxFreqSpinBox->setValue(560); + displayWidgets(nWidgets("100111000000000110000000")); + fast_config(true); statusChanged (); } void MainWindow::on_actionMSK144_triggered() { m_mode="MSK144"; - displayWidgets(nWidgets("101111110100000000010001")); -// displayWidgets(nWidgets("101111111100000000010001")); m_modeTx="MSK144"; ui->actionMSK144->setChecked(true); switch_mode (Modes::MSK144); @@ -4678,7 +4793,6 @@ void MainWindow::on_actionMSK144_triggered() VHF_features_enabled(true); m_bFastMode=true; m_bFast9=false; - fast_config(m_bFastMode); m_TRperiod = ui->sbTR->value (); m_wideGraph->hide(); m_fastGraph->show(); @@ -4700,13 +4814,15 @@ void MainWindow::on_actionMSK144_triggered() ui->rptSpinBox->setValue(0); ui->rptSpinBox->setSingleStep(1); ui->sbFtol->values ({20, 50, 100, 200}); + displayWidgets(nWidgets("101111110100000000010001")); +// displayWidgets(nWidgets("101111111100000000010001")); + fast_config(m_bFastMode); statusChanged(); } void MainWindow::on_actionWSPR_triggered() { m_mode="WSPR"; - displayWidgets(nWidgets("000000000000000001010000")); WSPR_config(true); switch_mode (Modes::WSPR); m_modeTx="WSPR"; @@ -4726,8 +4842,9 @@ void MainWindow::on_actionWSPR_triggered() m_wideGraph->setModeTx(m_modeTx); m_bFastMode=false; m_bFast9=false; - fast_config(false); ui->TxFreqSpinBox->setValue(ui->WSPRfreqSpinBox->value()); + displayWidgets(nWidgets("000000000000000001010000")); + fast_config(false); statusChanged(); } @@ -4752,7 +4869,6 @@ void MainWindow::on_actionEcho_triggered() { on_actionJT4_triggered(); m_mode="Echo"; - displayWidgets(nWidgets("000000000000000000000010")); ui->actionEcho->setChecked(true); m_TRperiod=3; m_modulator->setPeriod(m_TRperiod); // TODO - not thread safe @@ -4775,9 +4891,10 @@ void MainWindow::on_actionEcho_triggered() } m_bFastMode=false; m_bFast9=false; - fast_config(false); WSPR_config(true); ui->decodedTextLabel->setText(" UTC N Level Sig DF Width Q"); + displayWidgets(nWidgets("000000000000000000000010")); + fast_config(false); statusChanged(); } @@ -4785,11 +4902,9 @@ void MainWindow::on_actionFreqCal_triggered() { on_actionJT9_triggered(); m_mode="FreqCal"; - displayWidgets(nWidgets("001101000000000000000000")); ui->actionFreqCal->setChecked(true); switch_mode(Modes::FreqCal); m_wideGraph->setMode(m_mode); - statusChanged(); m_TRperiod = ui->sbTR->value (); m_modulator->setPeriod(m_TRperiod); // TODO - not thread safe m_detector->setPeriod(m_TRperiod); // TODO - not thread safe @@ -4802,6 +4917,8 @@ void MainWindow::on_actionFreqCal_triggered() setup_status_bar (true); // 18:15:47 0 1 1500 1550.349 0.100 3.5 10.2 ui->decodedTextLabel->setText(" UTC Freq CAL Offset fMeas DF Level S/N"); + displayWidgets(nWidgets("001101000000000000000000")); + statusChanged(); } void MainWindow::switch_mode (Mode mode) @@ -4870,7 +4987,7 @@ void MainWindow::fast_config(bool b) { m_bFastMode=b; ui->TxFreqSpinBox->setEnabled(!b); -// ui->sbTR->setVisible(b); + ui->sbTR->setVisible(b); if(b and (m_bFast9 or m_mode=="MSK144" or m_mode=="ISCAT")) { m_wideGraph->hide(); m_fastGraph->show(); @@ -5073,6 +5190,7 @@ void MainWindow::on_pbCallCQ_clicked() genStdMsgs(m_rpt); ui->genMsg->setText(ui->tx6->text()); m_ntx=7; + m_QSOProgress = CALLING; m_gen_message_is_cq = true; ui->rbGenMsg->setChecked(true); if(m_transmitting) m_restart=true; @@ -5088,6 +5206,7 @@ void MainWindow::on_pbAnswerCaller_clicked() t=t.mid(0,i0+1)+t.mid(i0+2,3); ui->genMsg->setText(t); m_ntx=7; + m_QSOProgress = REPORT; m_gen_message_is_cq = false; ui->rbGenMsg->setChecked(true); if(m_transmitting) m_restart=true; @@ -5099,6 +5218,7 @@ void MainWindow::on_pbSendRRR_clicked() genStdMsgs(m_rpt); ui->genMsg->setText(ui->tx4->text()); m_ntx=7; + m_QSOProgress = ROGERS; m_gen_message_is_cq = false; ui->rbGenMsg->setChecked(true); if(m_transmitting) m_restart=true; @@ -5113,6 +5233,7 @@ void MainWindow::on_pbAnswerCQ_clicked() int i1=t.indexOf(" "); if(i0>0 and i0genMsg->setText(t); m_ntx=7; + m_QSOProgress = REPLYING; m_gen_message_is_cq = false; ui->rbGenMsg->setChecked(true); if(m_transmitting) m_restart=true; @@ -5123,6 +5244,7 @@ void MainWindow::on_pbSendReport_clicked() genStdMsgs(m_rpt); ui->genMsg->setText(ui->tx3->text()); m_ntx=7; + m_QSOProgress = ROGER_REPORT; m_gen_message_is_cq = false; ui->rbGenMsg->setChecked(true); if(m_transmitting) m_restart=true; @@ -5134,6 +5256,7 @@ void MainWindow::on_pbSend73_clicked() genStdMsgs(m_rpt); ui->genMsg->setText(ui->tx5->currentText()); m_ntx=7; + m_QSOProgress = SIGNOFF; m_gen_message_is_cq = false; ui->rbGenMsg->setChecked(true); if(m_transmitting) m_restart=true; @@ -5145,6 +5268,8 @@ void MainWindow::on_rbGenMsg_clicked(bool checked) if(!m_freeText) { if(m_ntx != 7 && m_transmitting) m_restart=true; m_ntx=7; + // would like to set m_QSOProgress but what to? So leave alone and + // assume it is correct } } @@ -5153,6 +5278,9 @@ void MainWindow::on_rbFreeText_clicked(bool checked) m_freeText=checked; if(m_freeText) { m_ntx=8; + // would like to set m_QSOProgress but what to? So leave alone and + // assume it is correct. Perhaps should store old value to be + // restored above in on_rbGenMsg_clicked if (m_transmitting) m_restart=true; } } @@ -5171,9 +5299,7 @@ void MainWindow::on_rptSpinBox_valueChanged(int n) } m_rpt=QString::number(n); int ntx0=m_ntx; - QString t=ui->tx5->currentText(); genStdMsgs(m_rpt); - if(!m_bDoubleClicked) ui->tx5->setCurrentText(t); m_ntx=ntx0; if(m_ntx==1) ui->txrb1->setChecked(true); if(m_ntx==2) ui->txrb2->setChecked(true); @@ -5238,6 +5364,8 @@ void MainWindow::on_stopTxButton_clicked() //Stop Tx if (m_tune) stop_tuning (); if (m_auto and !m_tuneup) auto_tx_mode (false); m_btxok=false; + m_bCallingCQ = false; + m_bAutoReply = false; // ready for next } void MainWindow::rigOpen () @@ -5838,6 +5966,7 @@ void MainWindow::on_cbShMsgs_toggled(bool b) if(m_bShMsgs and (m_mode=="MSK144")) ui->rptSpinBox->setValue(1); int itone0=itone[0]; int ntx=m_ntx; + m_lastCallsign.clear (); // ensure Tx5 gets updated genStdMsgs(m_rpt); itone[0]=itone0; if(ntx==1) ui->txrb1->setChecked(true); @@ -5853,15 +5982,9 @@ void MainWindow::on_cbSWL_toggled(bool b) if(b) ui->cbShMsgs->setChecked(false); } -void MainWindow::on_cbTx6_toggled(bool b) +void MainWindow::on_cbTx6_toggled(bool) { - QString t; - if(b) { - t="@1250 (SEND MSGS)"; - } else { - t="@1000 (TUNE)"; - } - ui->tx6->setText(t); + genCQMsg (); } // Takes a decoded CQ line and sets it up for reply @@ -5913,7 +6036,7 @@ void MainWindow::replyToCQ (QTime time, qint32 snr, float delta_time, quint32 de // find the linefeed at the end of the line position = ui->decodedTextBrowser->toPlainText().indexOf(QChar::LineFeed,position); m_bDoubleClicked = true; - processMessage (messages, position, false); + processMessage (messages, position); tx_watchdog (false); QApplication::alert (this); } @@ -6402,6 +6525,7 @@ void MainWindow::on_cbCQTx_toggled(bool b) if(b) { ui->txrb6->setChecked(true); m_ntx=6; + m_QSOProgress = CALLING; } setRig (); setXIT (ui->TxFreqSpinBox->value ()); diff --git a/mainwindow.h b/mainwindow.h index 4ef245318..fc519c490 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -160,12 +160,14 @@ private slots: void on_txrb3_toggled(bool status); void on_txrb4_toggled(bool status); void on_txrb5_toggled(bool status); + void on_txrb5_doubleClicked (); void on_txrb6_toggled(bool status); void on_txb1_clicked(); void on_txb2_clicked(); void on_txb3_clicked(); void on_txb4_clicked(); void on_txb5_clicked(); + void on_txb5_doubleClicked (); void on_txb6_clicked(); void on_lookupButton_clicked(); void on_addButton_clicked(); @@ -299,7 +301,7 @@ private: private: void astroUpdate (); void writeAllTxt(QString message); - void FT8_AutoSeq(QString message); + void auto_sequence (QString const& message, unsigned tolerance); void hideMenus(bool b); NetworkAccessManager m_network_manager; @@ -446,6 +448,17 @@ private: bool m_bQRAsyncWarned; bool m_bDoubleClicked; bool m_bCallingCQ; + bool m_bAutoReply; + enum + { + CALLING, + REPLYING, + REPORT, + ROGER_REPORT, + ROGERS, + SIGNOFF + } + m_QSOProgress; int m_ihsym; int m_nzap; @@ -557,7 +570,7 @@ private: void writeSettings(); void createStatusBar(); void updateStatusBar(); - void genStdMsgs(QString rpt); + void genStdMsgs(QString rpt, bool unconditional = false); void genCQMsg(); void clearDX (); void lookup(); @@ -573,7 +586,7 @@ private: void pskPost(DecodedText decodedtext); void displayDialFrequency (); void transmitDisplay (bool); - void processMessage(QString const& messages, qint32 position, bool ctrl); + void processMessage(QString const& messages, qint32 position, bool ctrl = false, bool alt = false); void replyToCQ (QTime, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode, QString const& message_text); void replayDecodes (); void postDecode (bool is_new, QString const& message); diff --git a/mainwindow.ui b/mainwindow.ui index 9e604eeca..66a2d7cf5 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -1292,9 +1292,9 @@ list. The list can be maintained in Settings (F2). - + - Send this message in next Tx interval + <html><head/><body><p>Send this message in next Tx interval</p><p>Double-click to reset to the standard 73 message</p></body></html> @@ -1308,7 +1308,7 @@ list. The list can be maintained in Settings (F2). - + 30 @@ -1316,7 +1316,7 @@ list. The list can be maintained in Settings (F2). - Switch to this Tx message NOW + <html><head/><body><p>Switch to this Tx message NOW</p><p>Double-click to reset to the standard 73 message</p></body></html> Tx &5 @@ -3018,6 +3018,16 @@ QPushButton[state="ok"] { QSpinBox
RestrictedSpinBox.hpp
+ + DoubleClickableRadioButton + QRadioButton +
DoubleClickableRadioButton.hpp
+
+ + DoubleClickablePushButton + QPushButton +
DoubleClickablePushButton.hpp
+
logQSOButton diff --git a/mouse_commands.txt b/mouse_commands.txt index b087d573c..9e4cddf2c 100644 --- a/mouse_commands.txt +++ b/mouse_commands.txt @@ -18,7 +18,10 @@ locator to Dx Grid; change Rx and Tx frequencies to
decoded signal's frequency; generate standard messages.
If first callsign is your own, Tx frequency is not
- changed unless Ctrl is held down when double-clicking. + changed unless Ctrl is held down when double-clicking.
+
+ Hold down Alt to only move the Rx frequency when
+ when double-clicking to reply to a CQ or QRZ caller.