From 94ed756c477520a07a3f25d7209e4e4806d7c71e Mon Sep 17 00:00:00 2001 From: "James N. V. Cash" Date: Mon, 26 Jan 2026 22:02:33 -0500 Subject: [PATCH 1/3] WIP: draw lines on target frequencies --- friture/Plot.qml | 2 ++ friture/PlotArea.qml | 19 +++++++++++++++++++ friture/spectrogram_data.py | 16 ++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/friture/Plot.qml b/friture/Plot.qml index ac4ef74e..adc3977d 100644 --- a/friture/Plot.qml +++ b/friture/Plot.qml @@ -65,6 +65,8 @@ Rectangle { vertical_axis: scopedata.vertical_axis horizontal_axis: scopedata.horizontal_axis + annotations: (scopedata.target_frequencies !== undefined) ? scopedata.target_frequencies : [] + Item { id: plotItemPlaceholder anchors.fill: parent diff --git a/friture/PlotArea.qml b/friture/PlotArea.qml index f49e6870..c83d3a4a 100644 --- a/friture/PlotArea.qml +++ b/friture/PlotArea.qml @@ -11,6 +11,8 @@ Item { required property Axis vertical_axis required property Axis horizontal_axis + property var annotations: [] + default property alias content: plotItemPlaceholder.children PlotBackground { @@ -31,6 +33,23 @@ Item { anchors.fill: parent } + Repeater { + id: annotationRepeater + anchors.fill: parent + + model: scopePlotArea.annotations + + Rectangle { + width: parent.width + height: 1 + color: "red" + y: (1.0 - scopePlotArea.vertical_axis.coordinate_transform.toScreen(modelData)) * parent.height + + visible: modelData >= scopePlotArea.vertical_axis.min && modelData <= scopePlotArea.vertical_axis.max + } + + } + Rectangle { id: plotBorder anchors.fill: parent diff --git a/friture/spectrogram_data.py b/friture/spectrogram_data.py index eaa83917..ee9e2d1c 100644 --- a/friture/spectrogram_data.py +++ b/friture/spectrogram_data.py @@ -17,9 +17,25 @@ # You should have received a copy of the GNU General Public License # along with Friture. If not, see . +from PyQt5 import QtCore +from PyQt5.QtCore import pyqtProperty + from friture.scope_data import Scope_Data class Spectrogram_Data(Scope_Data): + target_frequencies_changed = QtCore.pyqtSignal() def __init__(self, parent=None): super().__init__(parent) + self._target_frequencies = [100., 165., 185.] + + + @pyqtProperty('QVariantList', notify=target_frequencies_changed) # type: ignore + def target_frequencies(self): + return self._target_frequencies + + @target_frequencies.setter + def target_frequencies(self, freqs): + if self._target_frequencies != freqs: + self._target_frequencies = freqs + self.target_frequencies_changed.emit() From e5b5bdfc25c5a5461eb86e21aaf1148ddb22a3d6 Mon Sep 17 00:00:00 2001 From: "James N. V. Cash" Date: Mon, 26 Jan 2026 22:36:47 -0500 Subject: [PATCH 2/3] WIP: fix drawing annotation lines --- friture/PlotArea.qml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/friture/PlotArea.qml b/friture/PlotArea.qml index c83d3a4a..256a0c51 100644 --- a/friture/PlotArea.qml +++ b/friture/PlotArea.qml @@ -40,12 +40,11 @@ Item { model: scopePlotArea.annotations Rectangle { + x: 0 + y: parent.height * (1. - scopePlotArea.vertical_axis.coordinate_transform.toScreen(modelData) ) width: parent.width height: 1 - color: "red" - y: (1.0 - scopePlotArea.vertical_axis.coordinate_transform.toScreen(modelData)) * parent.height - - visible: modelData >= scopePlotArea.vertical_axis.min && modelData <= scopePlotArea.vertical_axis.max + color: "magenta" } } From 0f0bd7752e571224e948677648b87be14e6093e0 Mon Sep 17 00:00:00 2001 From: "James N. V. Cash" Date: Tue, 27 Jan 2026 11:55:19 -0500 Subject: [PATCH 3/3] Make target lines addable & removable by right-clicking --- friture/Plot.qml | 4 ++-- friture/PlotArea.qml | 21 +++++++++++++++++---- friture/spectrogram_data.py | 14 ++++++++++++-- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/friture/Plot.qml b/friture/Plot.qml index adc3977d..88e39daa 100644 --- a/friture/Plot.qml +++ b/friture/Plot.qml @@ -62,11 +62,11 @@ Rectangle { Layout.fillHeight: true Layout.fillWidth: true + scopedata: plot.scopedata + vertical_axis: scopedata.vertical_axis horizontal_axis: scopedata.horizontal_axis - annotations: (scopedata.target_frequencies !== undefined) ? scopedata.target_frequencies : [] - Item { id: plotItemPlaceholder anchors.fill: parent diff --git a/friture/PlotArea.qml b/friture/PlotArea.qml index 256a0c51..5ed1831f 100644 --- a/friture/PlotArea.qml +++ b/friture/PlotArea.qml @@ -8,11 +8,10 @@ Item { SystemPalette { id: systemPalette; colorGroup: SystemPalette.Active } + required property var scopedata required property Axis vertical_axis required property Axis horizontal_axis - property var annotations: [] - default property alias content: plotItemPlaceholder.children PlotBackground { @@ -37,14 +36,14 @@ Item { id: annotationRepeater anchors.fill: parent - model: scopePlotArea.annotations + model: scopePlotArea.scopedata.target_frequencies Rectangle { x: 0 y: parent.height * (1. - scopePlotArea.vertical_axis.coordinate_transform.toScreen(modelData) ) width: parent.width height: 1 - color: "magenta" + color: "lime" } } @@ -105,5 +104,19 @@ Item { id: plotMouseArea anchors.fill: parent cursorShape: Qt.CrossCursor + acceptedButtons: Qt.LeftButton | Qt.RightButton + + onClicked: { + if (mouse.button !== Qt.RightButton) { return; } + var freq = vertical_axis.coordinate_transform.toPlot((parent.height - mouse.y) / parent.height); + for (var existingFreq of scopedata.target_frequencies) { + var existingCoord = parent.height * (1 - scopePlotArea.vertical_axis.coordinate_transform.toScreen(existingFreq)); + if (Math.abs(existingCoord - mouse.y) < 5) { + scopedata.remove_target_frequency(existingFreq); + return; + } + } + scopedata.add_target_frequency(freq); + } } } diff --git a/friture/spectrogram_data.py b/friture/spectrogram_data.py index ee9e2d1c..994f7e52 100644 --- a/friture/spectrogram_data.py +++ b/friture/spectrogram_data.py @@ -18,7 +18,7 @@ # along with Friture. If not, see . from PyQt5 import QtCore -from PyQt5.QtCore import pyqtProperty +from PyQt5.QtCore import pyqtProperty, pyqtSlot from friture.scope_data import Scope_Data @@ -27,7 +27,7 @@ class Spectrogram_Data(Scope_Data): def __init__(self, parent=None): super().__init__(parent) - self._target_frequencies = [100., 165., 185.] + self._target_frequencies = [] @pyqtProperty('QVariantList', notify=target_frequencies_changed) # type: ignore @@ -39,3 +39,13 @@ def target_frequencies(self, freqs): if self._target_frequencies != freqs: self._target_frequencies = freqs self.target_frequencies_changed.emit() + + @pyqtSlot(float) + def add_target_frequency(self, frequency): + if frequency not in self._target_frequencies: + self._target_frequencies.append(frequency) + self.target_frequencies_changed.emit() + + @pyqtSlot(float) + def remove_target_frequency(self, frequency): + self.target_frequencies = [f for f in self._target_frequencies if f != frequency]