QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
LogViewerParametersTab.qml
Go to the documentation of this file.
1import QtQuick
2import QtQuick.Controls
3import QtQuick.Layouts
4
5import QGroundControl
6import QGroundControl.Controls
7
8/// Parameters tab for the Log Viewer.
9/// Owns all filter state; call applyFilter() after a log loads or clears.
10ColumnLayout {
11 id: control
12
13 required property var logParser
14
15 spacing: ScreenTools.defaultFontPixelHeight * 0.5
16
17 // -------------------------------------------------------------------------
18 // Internal state
19 // -------------------------------------------------------------------------
20 property string _parameterSearchText: ""
21 property bool _showOnlyChangedParameters: true
22 property var _filteredParameters: []
23
24 QGCPalette { id: qgcPal }
25
26 // -------------------------------------------------------------------------
27 // Public API
28 // -------------------------------------------------------------------------
29
30 /// Recompute the filtered parameter list. Call after log load or clear.
31 function applyFilter() {
32 const query = String(_parameterSearchText).trim().toLowerCase()
33 const onlyChanged = _showOnlyChangedParameters
34
35 const output = []
36 for (let i = 0; i < logParser.parameters.length; i++) {
37 const item = logParser.parameters[i]
38 // "Show only changed" filter: skip parameters that equal their system default
39 if (onlyChanged && item.hasDefault && item.isDefault) {
40 continue
41 }
42 if (query.length > 0) {
43 const name = String(item.name)
44 const desc = item.shortDescription ? String(item.shortDescription) : ""
45 const value = String(item.value)
46 if ((name + " " + value + " " + desc).toLowerCase().indexOf(query) === -1) {
47 continue
48 }
49 }
50 output.push(item)
51 }
52 _filteredParameters = output
53 }
54
55 // -------------------------------------------------------------------------
56 // UI
57 // -------------------------------------------------------------------------
58
59 RowLayout {
60 Layout.fillWidth: true
61 spacing: ScreenTools.defaultFontPixelWidth
62
63 QGCTextField {
64 id: _parameterSearchField
65 Layout.fillWidth: true
66 textColor: qgcPal.textFieldText
67 placeholderTextColor: Qt.rgba(qgcPal.textFieldText.r, qgcPal.textFieldText.g, qgcPal.textFieldText.b, 0.7)
68 placeholderText: qsTr("Search parameters")
69
70 onTextChanged: {
71 control._parameterSearchText = text
72 if (text.trim().length === 0) {
73 _parameterSearchTimer.stop()
74 control.applyFilter()
75 } else {
76 _parameterSearchTimer.restart()
77 }
78 }
79
80 onAccepted: {
81 control._parameterSearchText = text
82 _parameterSearchTimer.stop()
83 control.applyFilter()
84 }
85 }
86
87 QGCCheckBoxSlider {
88 text: qsTr("Changed only")
89 checked: _showOnlyChangedParameters
90 onToggled: {
91 control._showOnlyChangedParameters = checked
92 control.applyFilter()
93 }
94 }
95 }
96
97 ScrollView {
98 Layout.fillWidth: true
99 Layout.fillHeight: true
100 clip: true
101
102 ListView {
103 anchors.fill: parent
104 model: _filteredParameters
105 spacing: ScreenTools.defaultFontPixelHeight * 0.1
106 clip: true
107 ScrollBar.vertical: ScrollBar { }
108
109 delegate: Rectangle {
110 width: ListView.view.width
111 height: _paramRow.implicitHeight + ScreenTools.defaultFontPixelHeight * 0.4
112 color: index % 2 === 0 ? qgcPal.windowShade : qgcPal.windowShadeDark
113 radius: 2
114
115 // Format value: use metadata decimalPlaces when available,
116 // fall back to isFloat heuristic. Show enum label when applicable.
117 readonly property string _formattedValue: {
118 const v = modelData.value
119 if (v === undefined || v === null) return qsTr("N/A")
120 const numV = Number(v)
121 // Enum: find matching label
122 const eStrs = modelData.enumStrings
123 const eVals = modelData.enumValues
124 if (eStrs && eVals && eStrs.length > 0 && eVals.length === eStrs.length) {
125 for (let ei = 0; ei < eVals.length; ei++) {
126 if (Number(eVals[ei]) === numV) {
127 return eStrs[ei] + " (" + Math.round(numV) + ")"
128 }
129 }
130 }
131 // Numeric: metadata decimalPlaces wins
132 const dp = (modelData.decimalPlaces !== undefined) ? modelData.decimalPlaces : -1
133 let formatted
134 if (dp >= 0) {
135 formatted = numV.toFixed(dp)
136 } else if (modelData.isFloat) {
137 formatted = numV.toFixed(6)
138 } else {
139 formatted = String(Math.round(numV))
140 }
141 const units = (modelData.units && modelData.units.length > 0) ? (" " + modelData.units) : ""
142 return formatted + units
143 }
144
145 readonly property string _defaultText: {
146 if (!modelData.hasDefault) return ""
147 const d = modelData.defaultValue
148 if (d === undefined || d === null) return ""
149 const numD = Number(d)
150 const dp = (modelData.decimalPlaces !== undefined) ? modelData.decimalPlaces : -1
151 let formatted
152 if (dp >= 0) {
153 formatted = numD.toFixed(dp)
154 } else if (modelData.isFloat) {
155 formatted = numD.toFixed(6)
156 } else {
157 formatted = String(Math.round(numD))
158 }
159 return qsTr(" (default: %1)").arg(formatted)
160 }
161
162 RowLayout {
163 id: _paramRow
164 anchors.verticalCenter: parent.verticalCenter
165 anchors.left: parent.left
166 anchors.right: parent.right
167 anchors.margins: ScreenTools.defaultFontPixelWidth * 0.5
168 spacing: ScreenTools.defaultFontPixelWidth * 0.5
169
170 // Changed-from-default indicator dot
171 Rectangle {
172 visible: modelData.hasDefault && !modelData.isDefault
173 width: ScreenTools.defaultFontPixelHeight * 0.5
174 height: width
175 radius: width / 2
176 color: qgcPal.colorOrange
177 Layout.alignment: Qt.AlignVCenter
178 }
179
180 // Spacer to keep alignment when dot is hidden
181 Item {
182 visible: !(modelData.hasDefault && !modelData.isDefault)
183 width: ScreenTools.defaultFontPixelHeight * 0.5
184 height: width
185 }
186
187 QGCLabel {
188 text: modelData.name
189 font.bold: modelData.hasDefault && !modelData.isDefault
190 Layout.preferredWidth: ScreenTools.defaultFontPixelWidth * 22
191 elide: Text.ElideRight
192 }
193
194 QGCLabel {
195 text: _formattedValue
196 Layout.preferredWidth: ScreenTools.defaultFontPixelWidth * 14
197 horizontalAlignment: Text.AlignRight
198 }
199
200 QGCLabel {
201 text: _defaultText
202 color: Qt.rgba(qgcPal.text.r, qgcPal.text.g, qgcPal.text.b, 0.6)
203 Layout.preferredWidth: ScreenTools.defaultFontPixelWidth * 16
204 elide: Text.ElideRight
205 }
206
207 QGCLabel {
208 text: modelData.shortDescription ? String(modelData.shortDescription) : ""
209 color: Qt.rgba(qgcPal.text.r, qgcPal.text.g, qgcPal.text.b, 0.6)
210 Layout.fillWidth: true
211 elide: Text.ElideRight
212 }
213 }
214 }
215 }
216 }
217
218 Timer {
219 id: _parameterSearchTimer
220 interval: 250
221 repeat: false
222 onTriggered: control.applyFilter()
223 }
224}