/* Copyright (C) 2019-2021 Doug McLain Modified Copyright (C) 2024 Rohith Namboothiri This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ import QtQuick import QtQuick.Controls import org.dudetronics.droidstar Page { id: mainTab padding: 0 // Let the parent (SwipeView) size this page so it scales on all screens. background: Rectangle { color: "#121212" } //property int rows: USE_FLITE ? 20 : 18 //property bool tts: USE_FLITE property int rows: { if(USE_FLITE){ rows = 20; } else{ rows = 18; } } property bool tts: { if(USE_FLITE){ tts = true; } else{ tts = false; } } // Properties to hold first row data property string firstRowSerialNumber: "N/A" property string firstRowCallsign: "N/A" property string firstRowHandle: "N/A" property string firstRowCountry: "N/A" // Properties to hold second row data property string secondRowSerialNumber: "N/A" property string secondRowCallsign: "N/A" property string secondRowHandle: "N/A" property string secondRowCountry: "N/A" // Slot to update the first row data when the signal is received from QsoTab function updateFirstRowData(serialNumber, callsign, handle, country) { firstRowSerialNumber = serialNumber; firstRowCallsign = callsign; firstRowHandle = handle; firstRowCountry = country; } // Slot to update the second row data when the signal is received from QsoTab function updateSecondRowData(serialNumber, callsign, handle, country) { secondRowSerialNumber = serialNumber; secondRowCallsign = callsign; secondRowHandle = handle; secondRowCountry = country; } // Connections to handle signals from QsoTab.qml Connections { target: qsoTab // Assuming qsoTab is an instance of QsoTab somewhere higher in the hierarchy onFirstRowDataChanged: updateFirstRowData(serialNumber, callsign, handle, country) onSecondRowDataChanged: updateSecondRowData(serialNumber, callsign, handle, country) } // Define the ListModel within the scope of the Item ListModel { id: recentTgidsModel } function updateRecentTgids(newTgid) { droidstar.addRecentTGID(newTgid); updateRecentTgidsModel(); } function updateRecentTgidsModel() { recentTgidsModel.clear(); var tgids = droidstar.loadRecentTGIDs(); for (var i = 0; i < tgids.length; i++) { recentTgidsModel.append({"modelData": tgids[i]}); } } function clearRecentTgids() { recentTgidsModel.clear(); droidstar.clearRecentTGIDs(); // Call the C++ function to clear persistent storage } Connections { target: droidstar onRecentTgidsUpdated: updateRecentTgidsModel() } Component.onCompleted: updateRecentTgidsModel() /* function fetchFirstName() { console.log("Fetching first name based on data1 change"); var fetchedName = vuidUpdater.mfirstName; // Fetch the first name using the property vuidUpdater.msetFirstName(fetchedName); // Update the first name } function updateFirstNameText(name) { firstNameText.text = name; console.log("Text changed to:", name); } // Connections for VUIDUpdater Connections { target: vuidUpdater function onMfirstNameChanged(name) { console.log("QML First name updated to:", name); updateFirstNameText(name); } } */ // Function to update the full name with country function updateFullNameText() { if (vuidUpdater.fetchedFirstName && vuidUpdater.fetchedCountry) { firstNameText1.text = vuidUpdater.fetchedFirstName + " (" + vuidUpdater.fetchedCountry + ")"; } else if (vuidUpdater.fetchedFirstName) { firstNameText1.text = vuidUpdater.fetchedFirstName; } else { firstNameText1.text = ""; } } Timer { id: data2CheckTimer interval: 500 // 500m seconds repeat: false // Run once when started onTriggered: { if (_data2.text === "") { console.log("Data2 has been empty for 500s, clearing first name display"); firstNameText1.text = ""; // Clear the displayed name } } } onWidthChanged: { if (_comboMode.currentText === "DMR") { _comboMode.width = (mainTab.width / 5) - 5; _connectbutton.width = (mainTab.width * 2 / 5) - 5; _connectbutton.x = (mainTab.width * 3 / 5); } else { _comboMode.width = (mainTab.width / 2) - 5; _connectbutton.width = (mainTab.width / 2) - 5; _connectbutton.x = mainTab.width / 2; } } Keys.onPressed: { console.log("Key pressed: " + event.key); } property alias element3: _element3 property alias label1: _label1 property alias label2: _label2 property alias label3: _label3 property alias label4: _label4 property alias label5: _label5 property alias label6: _label6 //property alias ambestatus: _ambestatus //property alias mmdvmstatus: _mmdvmstatus property alias netstatus: _netstatus property alias levelMeter: _levelMeter property alias uitimer: _uitimer property alias comboMode: _comboMode property alias comboHost: _comboHost property alias dtmflabel: _dtmflabel property alias editIAXDTMF: _editIAXDTMF property alias dtmfsendbutton: _dtmfsendbutton property alias comboModule: _comboModule property alias comboSlot: _comboSlot property alias comboCC: _comboCC property alias dmrtgidEdit: _dmrtgidEdit property alias comboM17CAN: _comboM17CAN property alias privateBox: _privateBox property alias connectbutton: _connectbutton property alias sliderMicGain: _slidermicGain property alias data1: _data1 property alias data2: _data2 property alias data3: _data3 property alias data4: _data4 property alias data5: _data5 property alias data6: _data6 property alias txtimer: _txtimer property alias buttonTX: _buttonTX property alias btntxt: _btntxt property alias swtxBox: _swtxBox property alias swrxBox: _swrxBox property alias agcBox: _agcBox property alias recentTgLabel: recentTgLabel property alias recentTgidsComboBox: recentTgidsComboBox property alias lastHeard: lastHeard property alias firstRowData: firstRowData property alias secondRowData: secondRowData // UI Components Text { id: recentTgLabel text: qsTr("Recent TG") color: "white" font.pixelSize: parent.height / 40 x: 10 y: (parent.height / rows + 1) * 3 // Adjust y position to fit layout width: parent.width / 4 // Adjust width to fit next to the ComboBox height: parent.height / rows verticalAlignment: Text.AlignVCenter visible: true } ComboBox { id: recentTgidsComboBox x: recentTgLabel.x + recentTgLabel.width + 5 // Position next to recentTgLabel y: recentTgLabel.y // Align vertically with recentTgLabel width: (parent.width * 3 / 4) - 15 - 10 // Adjust width to fit in the remaining space height: parent.height / rows font.pixelSize: parent.height / 35 visible: true model: recentTgidsModel textRole: "modelData" contentItem: Text { text: recentTgidsComboBox.currentText color: "white" verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } // Override the popup for the ComboBox popup: Popup { width: parent.width //height: 50 // Adjust height as needed Column { width: parent.width spacing: 5 Repeater { model: recentTgidsModel delegate: Item { width: parent.width height: 30 Text { text: modelData width: parent.width height: parent.height verticalAlignment: Text.AlignVCenter color: "white" // Set the text color to white // Add a MouseArea to make the Text item clickable MouseArea { anchors.fill: parent onClicked: { _dmrtgidEdit.text = modelData; // Set the selected TGID to the TextField recentTgidsComboBox.currentIndex = index; // Update ComboBox to show selected item recentTgidsComboBox.popup.close(); // Close the popup after selection console.log("droidstar.tgid_text_changed called from onClicked with TGID:", modelData); // Log event droidstar.tgid_text_changed(dmrtgidEdit.text); // Notify backend of TGID change } } } } } // Clear button inside the ComboBox popup Button { text: qsTr("Clear") width: parent.width onClicked: clearRecentTgids() } } } onActivated: { _dmrtgidEdit.text = currentText; // Set the selected TGID to the TextField //console.log("droidstar.tgid_text_changed called from onActivated with TGID:", currentText); // Log event //droidstar.tgid_text_changed(currentText); // Notify backend of TGID change } } Timer { id: _uitimer interval: 20 running: true repeat: true property int cnt: 0 property int rxcnt: 0 property int last_rxcnt: 0 onTriggered: update_level() function update_level() { if (cnt >= 20) { if (rxcnt === last_rxcnt) { droidstar.set_output_level(0); rxcnt = 0; // console.log("TIMEOUT"); } else { last_rxcnt = rxcnt; } cnt = 0; } else { ++cnt; } var l = (parent.width - 20) * droidstar.get_output_level() / 32767.0; if (l > _levelMeter.width) { _levelMeter.width = l; } else { if (_levelMeter.width > 0) _levelMeter.width -= 8; else _levelMeter.width = 0; } } } ComboBox { id: _comboMode property bool loaded: false x: 5 y: 0 width: (parent.width / 2) - 5 height: parent.height / rows font.pixelSize: parent.height / 40 currentIndex: -1 displayText: currentIndex === -1 ? "Mode..." : currentText model: ["M17", "YSF", "FCS", "DMR", "P25", "NXDN", "REF", "XRF", "DCS", "IAX"] contentItem: Text { text: _comboMode.displayText font: _comboMode.font leftPadding: 10 verticalAlignment: Text.AlignVCenter color: _comboMode.enabled ? "white" : "darkgrey" } onCurrentTextChanged: { if (_comboMode.loaded) { droidstar.process_mode_change(_comboMode.currentText); } if (_comboMode.currentText === "DMR") { _comboMode.width = (mainTab.width / 5) - 5; _connectbutton.width = (mainTab.width * 2 / 5) - 5; _connectbutton.x = (mainTab.width * 3 / 5); } else { _comboMode.width = (mainTab.width / 2) - 5; _connectbutton.width = (mainTab.width / 2) - 5; _connectbutton.x = mainTab.width / 2; } } } ComboBox { id: _comboSlot x: (parent.width / 5) y: 0 width: (parent.width / 5) height: parent.height / rows font.pixelSize: parent.height / 35 model: ["S1", "S2"] currentIndex: 1 contentItem: Text { text: _comboSlot.displayText font: _comboSlot.font leftPadding: 10 verticalAlignment: Text.AlignVCenter color: _comboSlot.enabled ? "white" : "darkgrey" } onCurrentTextChanged: { droidstar.set_slot(_comboSlot.currentIndex); } visible: false } ComboBox { id: _comboCC x: (parent.width * 2 / 5) y: 0 width: (parent.width / 5) height: parent.height / rows font.pixelSize: parent.height / 35 model: [ "CC0", "CC1", "CC2", "CC3", "CC4", "CC5", "CC6", "CC7", "CC8", "CC9", "CC10", "CC11", "CC12", "CC13", "CC14", "CC15" ] currentIndex: 1 contentItem: Text { text: _comboCC.displayText font: _comboCC.font leftPadding: 10 verticalAlignment: Text.AlignVCenter color: _comboCC.enabled ? "white" : "darkgrey" } onCurrentTextChanged: { droidstar.set_cc(_comboCC.currentIndex); } visible: false } Button { id: _connectbutton objectName: "connectbutton" x: parent.width / 2 y: 0 width: parent.width / 2 height: parent.height / rows text: qsTr("Connect") font.pixelSize: parent.height / 30 onClicked: { // settingsTab.callsignEdit.text = settingsTab.callsignEdit.text.toUpperCase(); droidstar.set_callsign(settingsTab.callsignEdit.text.toUpperCase()); // droidstar.set_host(comboHost.currentText); droidstar.set_module(comboModule.currentText); droidstar.set_protocol(comboMode.currentText); droidstar.set_dmrtgid(dmrtgidEdit.text); droidstar.set_dmrid(settingsTab.dmridEdit.text); droidstar.set_essid(settingsTab.comboEssid.currentText); droidstar.set_bm_password(settingsTab.bmpwEdit.text); droidstar.set_tgif_password(settingsTab.tgifpwEdit.text); droidstar.set_latitude(settingsTab.latEdit.text); droidstar.set_longitude(settingsTab.lonEdit.text); droidstar.set_location(settingsTab.locEdit.text); droidstar.set_description(settingsTab.descEdit.text); droidstar.set_url(settingsTab.urlEdit.text); droidstar.set_swid(settingsTab.swidEdit.text); droidstar.set_pkgid(settingsTab.pkgidEdit.text); droidstar.set_dmr_options(settingsTab.dmroptsEdit.text); droidstar.set_dmr_pc(mainTab.privateBox.checked); droidstar.set_txtimeout(settingsTab.txtimerEdit.text); // droidstar.set_toggletx(toggleTX.checked); droidstar.set_xrf2ref(settingsTab.xrf2ref.checked); droidstar.set_ipv6(settingsTab.ipv6.checked); droidstar.set_vocoder(settingsTab.comboVocoder.currentText); droidstar.set_modem(settingsTab.comboModem.currentText); droidstar.set_playback(settingsTab.comboPlayback.currentText); droidstar.set_capture(settingsTab.comboCapture.currentText); droidstar.set_modemRxFreq(settingsTab.modemRXFreqEdit.text); droidstar.set_modemTxFreq(settingsTab.modemTXFreqEdit.text); droidstar.set_modemRxOffset(settingsTab.modemRXOffsetEdit.text); droidstar.set_modemTxOffset(settingsTab.modemTXOffsetEdit.text); droidstar.set_modemRxDCOffset(settingsTab.modemRXDCOffsetEdit.text); droidstar.set_modemTxDCOffset(settingsTab.modemTXDCOffsetEdit.text); droidstar.set_modemRxLevel(settingsTab.modemRXLevelEdit.text); droidstar.set_modemTxLevel(settingsTab.modemRXLevelEdit.text); droidstar.set_modemRFLevel(settingsTab.modemRFLevelEdit.text); droidstar.set_modemTxDelay(settingsTab.modemTXDelayEdit.text); droidstar.set_modemCWIdTxLevel(settingsTab.modemCWIdTXLevelEdit.text); droidstar.set_modemDstarTxLevel(settingsTab.modemDStarTXLevelEdit.text); droidstar.set_modemDMRTxLevel(settingsTab.modemDMRTXLevelEdit.text); droidstar.set_modemYSFTxLevel(settingsTab.modemYSFTXLevelEdit.text); droidstar.set_modemP25TxLevel(settingsTab.modemYSFTXLevelEdit.text); droidstar.set_modemNXDNTxLevel(settingsTab.modemNXDNTXLevelEdit.text); droidstar.set_modemBaud(settingsTab.modemBaudEdit.text); // droidstar.set_mmdvm_direct(settingsTab.mmdvmBox.checked) droidstar.process_connect(); } } ComboBox { id: _comboHost x: 5 y: (parent.height / rows + 1) * 1 width: (parent.width * 3) / 4 - 5 height: parent.height / rows font.pixelSize: parent.height / 35 currentIndex: -1 displayText: currentIndex === -1 ? "Host..." : currentText contentItem: Text { text: _comboHost.displayText font: _comboHost.font leftPadding: 10 verticalAlignment: Text.AlignVCenter color: _comboHost.enabled ? "white" : "darkgrey" } onCurrentTextChanged: { if (settingsTab.mmdvmBox.checked) { droidstar.set_dst(_comboHost.currentText); } if (!droidstar.get_modelchange()) { droidstar.process_host_change(_comboHost.currentText); } } } ComboBox { id: _comboModule x: (parent.width * 3) / 4 y: (parent.height / rows + 1) * 1 width: (parent.width / 4) - 5 height: parent.height / rows font.pixelSize: parent.height / 35 currentIndex: -1 displayText: currentIndex === -1 ? "Mod..." : currentText model: [ " ", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" ] contentItem: Text { text: _comboModule.displayText font: _comboModule.font leftPadding: 10 verticalAlignment: Text.AlignVCenter color: _comboModule.enabled ? "white" : "darkgrey" } onCurrentTextChanged: { if (_comboMode.loaded) { droidstar.set_module(_comboModule.currentText); } } } CheckBox { id: _privateBox x: (parent.width * 3) / 4 y: (parent.height / rows + 1) * 1 width: (parent.width / 4) - 5 height: parent.height / rows text: qsTr("Private") onClicked: { droidstar.set_dmr_pc(privateBox.checked); // console.log("screen size ", parent.width, " x ", parent.height); } visible: false } Text { id: _dtmflabel x: 5 y: (parent.height / rows + 1) * 3 width: parent.width / 5 height: parent.height / rows text: qsTr("DTMF") color: "white" font.pixelSize: parent.height / 30 verticalAlignment: Text.AlignVCenter visible: false } TextField { id: _editIAXDTMF x: parent.width / 4 y: (parent.height / rows + 1) * 3 width: (parent.width * 3 / 8) - 4 height: parent.height / rows font.pixelSize: parent.height / 35 // inputMethodHints: "ImhPreferNumbers" visible: false } Button { id: _dtmfsendbutton x: (parent.width * 5 / 8) y: (parent.height / rows + 1) * 3 width: (parent.width * 3 / 8) - 5 height: parent.height / rows text: qsTr("Send") font.pixelSize: parent.height / 30 onClicked: { droidstar.dtmf_send_clicked(editIAXDTMF.text); } visible: false } Text { id: _element3 x: 5 y: (parent.height / rows + 1) * 2 width: parent.width / 5 height: parent.height / rows text: qsTr("TGID") color: "white" font.pixelSize: parent.height / 30 verticalAlignment: Text.AlignVCenter visible: false } TextField { visible: false id: _dmrtgidEdit x: parent.width / 5 y: (parent.height / rows + 1) * 2 width: parent.width / 5 height: parent.height / rows font.pixelSize: parent.height / 35 selectByMouse: true inputMethodHints: "ImhPreferNumbers" text: qsTr("") onEditingFinished: { droidstar.tgid_text_changed(dmrtgidEdit.text); console.log("droidstar.tgid_text_changed called from onEditingFinished with TGID:", dmrtgidEdit.text); // Log event updateRecentTgids(dmrtgidEdit.text); //tgidsModel = droidstar.loadRecentTGIDs(); updateRecentTgidsModel(); // Refresh the ListModel correctly } } ComboBox { visible: false id: _comboM17CAN x: parent.width / 5 y: (parent.height / rows + 1) * 2 width: parent.width / 5 height: parent.height / rows font.pixelSize: parent.height / 35 currentIndex: 0 model: ["0", "1", "2", "3", "4", "5", "6", "7"] contentItem: Text { text: _comboM17CAN.displayText font: _comboM17CAN.font leftPadding: 10 verticalAlignment: Text.AlignVCenter color: _comboM17CAN.enabled ? "white" : "darkgrey" } onCurrentTextChanged: { droidstar.set_modemM17CAN(_comboM17CAN.currentText); } } CheckBox { id: _swtxBox x: (parent.width * 2 / 5) + 5 y: (parent.height / rows + 1) * 2 width: parent.width / 4 height: parent.height / rows font.pixelSize: parent.height / 40 text: qsTr("SWTX") onClicked: { droidstar.set_swtx(_swtxBox.checked); } } CheckBox { id: _swrxBox x: (parent.width * 3 / 5) + 5 y: (parent.height / rows + 1) * 2 width: parent.width / 4 height: parent.height / rows font.pixelSize: parent.height / 40 text: qsTr("SWRX") onClicked: { droidstar.set_swrx(_swrxBox.checked); } } CheckBox { id: _agcBox x: (parent.width * 4 / 5) + 5 y: (parent.height / rows + 1) * 2 width: parent.width / 4 height: parent.height / rows font.pixelSize: parent.height / 40 text: qsTr("AGC") onClicked: { droidstar.set_agc(_agcBox.checked); } } Text { id: micgain_label x: 10 y: (parent.height / rows + 1) * 4 width: parent.width / 4 height: parent.height / rows text: qsTr("Mic") color: "white" font.pixelSize: parent.height / 40 verticalAlignment: Text.AlignVCenter } Slider { property double v visible: true id: _slidermicGain x: (parent.width / 4) + 10 y: (parent.height / rows + 1) * 4 width: (parent.width * 3 / 4) - 20 height: parent.height / rows value: 0.1 onValueChanged: { v = value * 100 droidstar.set_input_volume(value) micgain_label.text = "Mic " + v.toFixed(1) } } Text { id: _label1 x: 10 y: (parent.height / rows + 1) * 5 width: parent.width / 3 height: parent.height / rows text: qsTr("MYCALL") color: "white" font.pixelSize: parent.height / 40 } // Static label for "Handle" Text { id: fnameLabel x: 10 y: (parent.height / rows + 1) * 6 // Position below the mic gain slider width: parent.width / 3 height: parent.height / rows text: qsTr("Handle") color: "white" font.pixelSize: parent.height / 40 } Text { id: firstNameText1 x: parent.width / 3 y: (parent.height / rows + 1) * 6 width: (parent.width * 2) / 3 height: parent.height / rows color: "white" //text: vuidUpdater.fetchedFirstName text: vuidUpdater.fetchedFirstName + (vuidUpdater.fetchedCountry !== "" ? " (" + vuidUpdater.fetchedCountry + ")" : "") wrapMode: Text.WordWrap // This enables word wrapping font.pixelSize: parent.height / 40 } Text { id: _label2 x: 10 y: (parent.height / rows + 1) * 7.2 width: parent.width / 3 height: parent.height / rows text: qsTr("URCALL") color: "white" font.pixelSize: parent.height / 40 } Text { id: _label3 x: 10 y: (parent.height / rows + 1) * 8.2 width: parent.width / 3 height: parent.height / rows text: qsTr("RPTR1") color: "white" font.pixelSize: parent.height / 40 } Text { id: _label4 x: 10 y: (parent.height / rows + 1) * 9.2 width: parent.width / 3 height: parent.height / rows text: qsTr("RPTR2") color: "white" font.pixelSize: parent.height / 40 } Text { id: _label5 x: 10 y: (parent.height / rows + 1) * 10.2 width: parent.width / 3 height: parent.height / rows text: qsTr("StrmID") color: "white" font.pixelSize: parent.height / 40 } Text { id: _label6 x: 10 y: (parent.height / rows + 1) * 11.2 width: parent.width / 3 height: parent.height / rows text: qsTr("Text") color: "white" font.pixelSize: parent.height / 40 } Text { id: _label7 x: 10 y: (parent.height / rows + 1) * 12.2 width: parent.width / 3 height: parent.height / rows text: qsTr("") color: "white" font.pixelSize: parent.height / 40 } Text { id: _data1 x: parent.width / 3 y: (parent.height / rows + 1) * 5 width: (parent.width * 2) / 3 height: parent.height / rows text: qsTr("") color: "white" font.pixelSize: parent.height / 40 } Text { id: _data2 x: parent.width / 3 y: (parent.height / rows + 1) * 7.2 width: (parent.width * 2) / 3 height: parent.height / rows text: qsTr("") color: "white" font.pixelSize: parent.height / 40 Timer { id: stabilityTimer interval: 200 // 200 milliseconds to verify text stability repeat: false onTriggered: { if (_data2.text !== "") { data2CheckTimer.stop(); // Stop the main timer as data is stable and non-empty let dataInt = parseInt(_data2.text); if (!isNaN(dataInt)) { vuidUpdater.fetchFirstNameFromAPI(dataInt); emitDataUpdated(); } else { } } else { } } } onTextChanged: { if (text === "") { data2CheckTimer.start(); // Start the timer if data2 is empty return; // Exit after starting the timer for empty input } // Reset and start the stability timer whenever text changes stabilityTimer.restart(); } } Connections { target: vuidUpdater function onFetchedFirstNameChanged(name) { updateFullNameText(); // Function to update the full text } function onFetchedCountryChanged(country) { updateFullNameText(); // Function to update the full text } } /* // Function to update the full name with country function updateFullNameText() { firstNameText1.text = vuidUpdater.fetchedFirstName + " (" + vuidUpdater.fetchedCountry + ")"; } */ /* Connections { target: vuidUpdater function onFetchedFirstNameChanged(name) { console.log("Fetched first name updated to:", name); firstNameText1.text = name; // Explicitly set the text } } */ Text { id: _data3 x: parent.width / 3 y: (parent.height / rows + 1) * 8.2 width: (parent.width * 2) / 3 height: parent.height / rows text: qsTr("") color: "white" font.pixelSize: parent.height / 40 } Text { id: _data4 x: parent.width / 3 y: (parent.height / rows + 1) * 9.2 width: (parent.width * 2) / 3 height: parent.height / rows text: qsTr("") color: "white" font.pixelSize: parent.height / 40 } Text { id: _data5 x: parent.width / 3 y: (parent.height / rows + 1) * 10.2 width: (parent.width * 2) / 3 height: parent.height / rows text: qsTr("") color: "white" font.pixelSize: parent.height / 40 } Text { id: _data6 x: parent.width / 3 y: (parent.height / rows + 1) * 11.2 width: (parent.width * 2) / 3 height: parent.height / rows text: qsTr("") color: "white" font.pixelSize: parent.height / 40 } Text { id: _data7 x: parent.width / 3 y: (parent.height / rows + 1) * 12.2 width: (parent.width * 2) / 3 height: parent.height / rows text: qsTr("") color: "white" font.pixelSize: parent.height / 40 } /* Text { id: _ambestatus x: 10 y: _data7.y + _data7.height - 40 width: parent.width - 30 height: parent.height / rows text: qsTr("No AMBE hardware connected") color: "white" font.pixelSize: parent.height / 45 } Text { id: _mmdvmstatus x: 10 y: _ambestatus.y + _ambestatus.height width: parent.width - 40 height: parent.height / rows text: qsTr("No MMDVM connected") color: "white" font.pixelSize: parent.height / 35 }*/ // Text elements to display the last heard data Text { id: lastHeard x: 10 y: _data7.y + _data7.height - 80 width: parent.width - 40 height: parent.height / rows text: qsTr("Last Heard") color: "white" font.pixelSize: parent.height / 35 } // Text element to display first row data Text { id: firstRowData x: 10 y: lastHeard.y + lastHeard.height width: parent.width - 40 height: parent.height / rows text: (firstRowSerialNumber !== "N/A" ? firstRowSerialNumber + ". " : "") + (firstRowCallsign !== "N/A" ? firstRowCallsign : "") + (firstRowHandle !== "N/A" && firstRowCallsign !== "N/A" ? " - " : "") + (firstRowHandle !== "N/A" ? firstRowHandle : "") + (firstRowCountry !== "N/A" && (firstRowCallsign !== "N/A" || firstRowHandle !== "N/A") ? " - " : "") + (firstRowCountry !== "N/A" ? firstRowCountry : "") color: "white" font.pixelSize: parent.height / 45 wrapMode: Text.WordWrap } // Text element to display second row data Text { id: secondRowData x: 10 y: firstRowData.y + firstRowData.height width: parent.width - 40 height: parent.height / rows text: (secondRowSerialNumber !== "N/A" ? secondRowSerialNumber + ". " : "") + (secondRowCallsign !== "N/A" ? secondRowCallsign : "") + (secondRowHandle !== "N/A" && secondRowCallsign !== "N/A" ? " - " : "") + (secondRowHandle !== "N/A" ? secondRowHandle : "") + (secondRowCountry !== "N/A" && (secondRowCallsign !== "N/A" || secondRowHandle !== "N/A") ? " - " : "") + (secondRowCountry !== "N/A" ? secondRowCountry : "") color: "white" font.pixelSize: parent.height / 45 wrapMode: Text.WordWrap } /* Text { id: _netstatus x: 10 y: (parent.height / rows + 1) * 15 width: parent.width - 20 height: parent.height / rows text: qsTr("Not Connected to network") color: "white" font.pixelSize: parent.height / 35 }*/ Rectangle { x: 10 y: (parent.height / rows + 1.1) * 14.2 width: parent.width - 20 height: parent.height / 30 color: "black" border.color: "black" border.width: 1 radius: 5 } Rectangle { id: _levelMeter x: 10 y: (parent.height / rows + 1.1) * 14.2 width: 0 height: parent.height / 30 color: "#80C342" border.color: "black" border.width: 1 radius: 5 } ButtonGroup { id: ttsvoicegroup onClicked: { droidstar.tts_changed(button.text); } } CheckBox { id: mic visible: tts ? true : false x: 5 y: (parent.height / rows + 1) * 17 height: 25 spacing: 1 text: qsTr("Mic") checked: true ButtonGroup.group: ttsvoicegroup } CheckBox { id: tts1 visible: tts ? true : false x: parent.width / 4 y: (parent.height / rows + 1) * 17 height: 25 spacing: 1 text: qsTr("TTS1") ButtonGroup.group: ttsvoicegroup } CheckBox { id: tts2 visible: tts ? true : false x: parent.width * 2 / 4 y: (parent.height / rows + 1) * 17 height: 25 spacing: 1 text: qsTr("TTS2") checked: true ButtonGroup.group: ttsvoicegroup } CheckBox { id: tts3 visible: tts ? true : false x: parent.width * 3 / 4 y: (parent.height / rows + 1) * 17 height: 25 spacing: 1 text: qsTr("TTS3") ButtonGroup.group: ttsvoicegroup } TextField { id: _ttstxtedit visible: tts ? true : false x: 5 y: (parent.height / rows + 1) * 18 width: parent.width - 10 height: parent.height / rows font.pixelSize: parent.height / 35 selectByMouse: true inputMethodHints: "ImhPreferNumbers" text: qsTr("") onEditingFinished: { droidstar.tts_text_changed(_ttstxtedit.text); } } property string dmrID: _data2.text property string tgid: _data3.text // Assuming _data3 contains the TGID signal dataUpdated(var receivedDmrID, var receivedTGID) Timer { id: updateTimer interval: 500 // Delay in ms, adjust as needed for your case repeat: false onTriggered: { if (dmrID && tgid) { dataUpdated(dmrID, parseInt(tgid)); // Emit both dmrID and tgid as integers } else { } } } function emitDataUpdated() { updateTimer.restart(); // Start or restart the timer whenever dmrID changes } onDmrIDChanged: { emitDataUpdated(); // Trigger the timer only when dmrID changes } Button { Timer { id: _txtimer repeat: true onTriggered: { ++buttonTX.cnt; btntxt.text = "TX: " + buttonTX.cnt; if (buttonTX.cnt >= parseInt(settingsTab.txtimerEdit.text)) { buttonTX.tx = false; droidstar.click_tx(buttonTX.tx); _txtimer.running = false; _btntxt.text = "TX"; } } } property bool tx: false property int cnt: 0 visible: true enabled: false id: _buttonTX background: Rectangle { color: _buttonTX.tx ? "#800000" : "steelblue" radius: 10 Column { anchors.centerIn: parent spacing: 5 width: parent.width Text { id: _btntxt font.pointSize: 20 text: qsTr("TX") color: "white" horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter anchors.horizontalCenter: parent.horizontalCenter } Text { id: _netstatus text: qsTr("Not Connected to network") color: "white" font.pixelSize: 16 // Adjust font size for better readability horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter anchors.horizontalCenter: parent.horizontalCenter } } } x: 10 y: (parent.height / rows + 1) * (tts ? 17 : 15) width: parent.width - 20 height: parent.height - y - 10 font.pointSize: 24 onClicked: { if (settingsTab.toggleTX.checked) { tx = !tx; droidstar.click_tx(tx); if (tx) { cnt = 0; _txtimer.running = true; _btntxt.color = "white"; } else { _txtimer.running = false; btntxt.color = "black"; _btntxt.text = "TX"; } } } onPressed: { if (!settingsTab.toggleTX.checked) { tx = true; droidstar.press_tx(); } } onReleased: { if (!settingsTab.toggleTX.checked) { tx = false; droidstar.release_tx(); } } onCanceled: { if (!settingsTab.toggleTX.checked) { tx = false; droidstar.release_tx(); } } } }