diff --git a/.github/workflows/dockerimage.yml b/.github/workflows/dockerimage.yml index b10a0bfb65..70f0d00889 100644 --- a/.github/workflows/dockerimage.yml +++ b/.github/workflows/dockerimage.yml @@ -21,3 +21,12 @@ jobs: with: name: Scopy.flatpak path: ${{ github.workspace }}/Scopy.flatpak + - name: Upload master flatpak build to continous prerelease + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} + run: | + wget https://github.com/tcnksm/ghr/releases/download/v0.13.0/ghr_v0.13.0_linux_amd64.tar.gz + tar xvf ghr_v0.13.0_linux_amd64.tar.gz + ghr_v0.13.0_linux_amd64/ghr -u ${{ github.repository_owner }} -r scopy -name "Continuous build" -b "Latest succesful master build " -prerelease -debug -replace continous ${{ github.workspace }}/Scopy.flatpak + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + diff --git a/CI/appveyor/build_appveyor_macos.sh b/CI/appveyor/build_appveyor_macos.sh index 32bf443188..09f7a3c71f 100755 --- a/CI/appveyor/build_appveyor_macos.sh +++ b/CI/appveyor/build_appveyor_macos.sh @@ -21,8 +21,13 @@ mkdir -p build cd build if [ "$APPVEYOR" == "true" ] ; then + MACOS_VERSION=$(/usr/libexec/PlistBuddy -c "Print:ProductVersion" /System/Library/CoreServices/SystemVersion.plist) + if [[ "$MACOS_VERSION" == "10.14."* ]] ; then + export MACOSX_DEPLOYMENT_TARGET=10.13 + fi cmake .. make -j${NUM_JOBS} + otool -l ./Scopy.app/Contents/MacOS/Scopy # for debugging else cmake -DCMAKE_PREFIX_PATH="$STAGINGDIR;${QT_PATH}/lib/cmake" -DCMAKE_INSTALL_PREFIX="$STAGINGDIR" \ -DCMAKE_EXE_LINKER_FLAGS="-L${STAGINGDIR}/lib" .. diff --git a/CI/appveyor/build_appveyor_mingw.sh b/CI/appveyor/build_appveyor_mingw.sh index e3617fc66e..c5fa0efa8e 100755 --- a/CI/appveyor/build_appveyor_mingw.sh +++ b/CI/appveyor/build_appveyor_mingw.sh @@ -11,17 +11,25 @@ WORKDIR=${PWD} echo BUILD_NO $BUILD_NO JOBS=$(nproc) + wget http://swdownloads.analog.com/cse/m1k/drivers/dpinst.zip wget http://swdownloads.analog.com/cse/m1k/drivers/dfu-util.zip 7z x -y "dpinst.zip" -o"/c/dpinst" 7z x -y "dfu-util.zip" -o"/c/dfu-util" +# github release upload tool install +wget https://github.com/tcnksm/ghr/releases/download/v0.13.0/ghr_v0.13.0_windows_amd64.zip +7z x -y ghr_v0.13.0_windows_amd64.zip -o"/c/ghr" +UPLOAD_TOOL=/c/ghr/ghr_v0.13.0_windows_amd64/ghr.exe + + CC=/${MINGW_VERSION}/bin/${ARCH}-w64-mingw32-gcc.exe CXX=/${MINGW_VERSION}/bin/${ARCH}-w64-mingw32-g++.exe CMAKE_OPTS="\ -DCMAKE_C_COMPILER:FILEPATH=${CC} \ -DCMAKE_CXX_COMPILER:FILEPATH=${CXX} \ -DPKG_CONFIG_EXECUTABLE=/$MINGW_VERSION/bin/pkg-config.exe \ + -DCMAKE_CXX_FLAGS="-fno-omit-frame-pointer" \ -DCMAKE_PREFIX_PATH=/c/msys64/$MINGW_VERSION/lib/cmake \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ " @@ -33,8 +41,9 @@ SCOPY_CMAKE_OPTS="\ -DPYTHON_EXECUTABLE=/$MINGW_VERSION/bin/python3.exe \ " -PYTHON_LOCATION=/$MINGW_VERSION/lib/python3.8 -PYTHON_FILES="${PYTHON_LOCATION}/*.py ${PYTHON_LOCATION}/asyncio ${PYTHON_LOCATION}/collections ${PYTHON_LOCATION}/concurrent ${PYTHON_LOCATION}/config-3.* ${PYTHON_LOCATION}/ctypes ${PYTHON_LOCATION}/distutils ${PYTHON_LOCATION}/encodings ${PYTHON_LOCATION}/lib-dynload ${PYTHON_LOCATION}/site-packages" +#PYTHON_LOCATION=/$MINGW_VERSION/lib/python3.8 +#PYTHON_FILES="${PYTHON_LOCATION}/*.py ${PYTHON_LOCATION}/asyncio ${PYTHON_LOCATION}/collections ${PYTHON_LOCATION}/concurrent ${PYTHON_LOCATION}/config-3.* ${PYTHON_LOCATION}/ctypes ${PYTHON_LOCATION}/distutils ${PYTHON_LOCATION}/encodings ${PYTHON_LOCATION}/lib-dynload ${PYTHON_LOCATION}/site-packages" +PYTHON_FILES=/$MINGW_VERSION/lib/python3.* DLL_DEPS=$(cat ${WORKDIR}/CI/appveyor/mingw_dll_deps) DLL_DEPS="$DLL_DEPS $PYTHON_FILES" @@ -106,6 +115,13 @@ dump_syms -r /c/$DEST_FOLDER/Scopy.exe > /c/$DEST_FOLDER/Scopy.exe.sym mkdir /c/$DEBUG_FOLDER mv /c/$DEST_FOLDER/Scopy.exe.sym /c/$DEBUG_FOLDER mv /c/$DEST_FOLDER/.debug /c/$DEBUG_FOLDER +/c/cv2pdb/cv2pdb /c/$DEST_FOLDER/Scopy.exe +/c/cv2pdb/cv2pdb /c/$DEST_FOLDER/libm2k.dll +/c/cv2pdb/cv2pdb /c/$DEST_FOLDER/libiio.dll +/c/cv2pdb/cv2pdb /c/$DEST_FOLDER/libgnuradio-m2k.dll +/c/cv2pdb/cv2pdb /c/$DEST_FOLDER/libgnuradio-scopy.dll +cp -R /c/projects/scopy /c/$DEBUG_FOLDER/scopy +mv /c/$DEST_FOLDER/*.pdb /c/$DEBUG_FOLDER cp -r /c/projects/scopy/drivers /c/$DEST_FOLDER if [[ $ARCH_BIT == "64" ]]; then @@ -128,3 +144,16 @@ appveyor AddMessage "11. Creating installer" iscc //Qp /c/$BUILD_FOLDER/scopy-$ARCH_BIT.iss appveyor PushArtifact $DEPLOY_FILE appveyor AddMessage "12. Job complete" + +if [ "$APPVEYOR_REPO_BRANCH" = "master" ]; then + echo Identified master branch + if [ -z "$APPVEYOR_PULL_REQUEST_NUMBER" ]; then + echo Not a pull request + mkdir /c/to_deploy + cp /c/scopy-${ARCH_BIT}bit.zip /c/to_deploy + cp /c/debug-${ARCH_BIT}bit.zip /c/to_deploy + cp $DEPLOY_FILE /c/to_deploy + $UPLOAD_TOOL -u $APPVEYOR_ACCOUNT_NAME -r $APPVEYOR_PROJECT_NAME -name "Continuous build" -b "Latest succesful master build " -prerelease -debug -replace continous /c/to_deploy + fi +fi + diff --git a/CI/appveyor/data b/CI/appveyor/data new file mode 100644 index 0000000000..2c37c2a94b --- /dev/null +++ b/CI/appveyor/data @@ -0,0 +1 @@ +vineri 26 martie 2021, 13:48:33 +0200 diff --git a/CI/appveyor/install_macos_deps.sh b/CI/appveyor/install_macos_deps.sh index 2b28d6e834..fa7ccc56e3 100755 --- a/CI/appveyor/install_macos_deps.sh +++ b/CI/appveyor/install_macos_deps.sh @@ -1,6 +1,6 @@ #!/bin/bash -LIBIIO_BRANCH=master +LIBIIO_VERSION=v0.21 LIBAD9361_BRANCH=master LIBM2K_BRANCH=master GRIIO_BRANCH=upgrade-3.8 @@ -11,20 +11,22 @@ GRM2K_BRANCH=master QWT_BRANCH=qwt-6.1-multiaxes QWTPOLAR_BRANCH=master # not used LIBSIGROK_BRANCH=master -LIBSIGROKDECODE_BRANCH=master #not used +LIBSIGROKDECODE_BRANCH=master BOOST_VERSION_FILE=1_73_0 BOOST_VERSION=1.73.0 LIBTINYIIOD_BRANCH=master PYTHON="python3" PACKAGES=" ${QT_FORMULAE} pkg-config cmake fftw bison gettext autoconf automake libtool libzip glib libusb glog $PYTHON" -PACKAGES="$PACKAGES doxygen wget gnu-sed libmatio dylibbundler libxml2" +PACKAGES="$PACKAGES doxygen wget gnu-sed libmatio dylibbundler libxml2 ghr" set -e cd ~ WORKDIR=${PWD} NUM_JOBS=4 +brew update +brew search ${QT_FORMULAE} brew_install_or_upgrade() { brew install $1 || \ brew upgrade $1 || \ @@ -63,10 +65,12 @@ QMAKE="$(command -v qmake)" CMAKE_OPTS="-DCMAKE_PREFIX_PATH=$STAGINGDIR -DCMAKE_INSTALL_PREFIX=$STAGINGDIR" build_libiio() { - echo "### Building libiio - branch $LIBIIO_BRANCH" + echo "### Building libiio - version $LIBIIO_VERSION" cd ~ - git clone --depth 1 https://github.com/analogdevicesinc/libiio.git -b $LIBIIO_BRANCH ${WORKDIR}/libiio + git clone https://github.com/analogdevicesinc/libiio.git ${WORKDIR}/libiio + cd ${WORKDIR}/libiio + git checkout $LIBIIO_VERSION mkdir ${WORKDIR}/libiio/build-${ARCH} cd ${WORKDIR}/libiio/build-${ARCH} @@ -137,7 +141,7 @@ build_boost() { echo "### Building boost - version $BOOST_VERSION_FILE" cd ~ - wget https://dl.bintray.com/boostorg/release/$BOOST_VERSION/source/boost_$BOOST_VERSION_FILE.tar.gz + wget https://boostorg.jfrog.io/artifactory/main/release/$BOOST_VERSION/source/boost_$BOOST_VERSION_FILE.tar.gz tar -xzf boost_$BOOST_VERSION_FILE.tar.gz cd boost_$BOOST_VERSION_FILE patch -p1 < ${WORKDIR}/projects/scopy/CI/appveyor/patches/boost-darwin.patch @@ -240,11 +244,11 @@ build_libsigrokdecode() { echo "### Building libsigrokdecode - branch $LIBSIGROKDECODE_BRANCH" git clone --depth 1 https://github.com/sigrokproject/libsigrokdecode.git -b $LIBSIGROKDECODE_BRANCH ${WORKDIR}/libsigrokdecode - mkdir -p ${WORKDIR}/libsigrokdecode/build-${ARCH} cd ${WORKDIR}/libsigrokdecode ./autogen.sh ./configure + sudo make $JOBS install } @@ -257,14 +261,14 @@ patch_qwtpolar_mac() { +++ b/qwtpolarconfig.pri @@ -16,7 +16,9 @@ QWT_POLAR_VER_PAT = 1 QWT_POLAR_VERSION = \$\${QWT_POLAR_VER_MAJ}.\$\${QWT_POLAR_VER_MIN}.\$\${QWT_POLAR_VER_PAT} - + unix { - QWT_POLAR_INSTALL_PREFIX = /usr/local/qwtpolar-\$\$QWT_POLAR_VERSION + QWT_POLAR_INSTALL_PREFIX = $STAGINGDIR + QMAKE_CXXFLAGS = -I${STAGINGDIR}/include + QMAKE_LFLAGS = ${STAGINGDIR}/lib/libqwt*dylib } - + win32 { EOF } diff --git a/CI/appveyor/install_msys_deps.sh b/CI/appveyor/install_msys_deps.sh index 2154fd9102..a7c66f6450 100644 --- a/CI/appveyor/install_msys_deps.sh +++ b/CI/appveyor/install_msys_deps.sh @@ -7,7 +7,15 @@ echo "Download and install pre-compiled libraries ... " wget "https://ci.appveyor.com/api/projects/$SCOPY_MINGW_BUILD_DEPS_FORK/scopy-mingw-build-deps/artifacts/scopy-$MINGW_VERSION-build-deps-pacman.txt?branch=$SCOPY_MINGW_BUILD_DEPS_BRANCH&job=Environment: MINGW_VERSION=$MINGW_VERSION, ARCH=$ARCH" -O /tmp/scopy-$MINGW_VERSION-build-deps-pacman.txt wget "https://ci.appveyor.com/api/projects/$SCOPY_MINGW_BUILD_DEPS_FORK/scopy-mingw-build-deps/artifacts/scopy-$MINGW_VERSION-build-deps.tar.xz?branch=$SCOPY_MINGW_BUILD_DEPS_BRANCH&job=Environment: MINGW_VERSION=$MINGW_VERSION, ARCH=$ARCH" -O /tmp/scopy-$MINGW_VERSION-build-deps.tar.xz wget "https://ci.appveyor.com/api/projects/$SCOPY_MINGW_BUILD_DEPS_FORK/scopy-mingw-build-deps/artifacts/scopy-mingw-build-status?branch=$SCOPY_MINGW_BUILD_DEPS_BRANCH&job=Environment: MINGW_VERSION=$MINGW_VERSION, ARCH=$ARCH" -O /tmp/scopy-mingw-build-status + + cd /c + +pacman -S --noconfirm unzip +wget https://swdownloads.analog.com/cse/scopydeps/cv2pdb.zip +unzip cv2pdb.zip +#/c/cv2pdb/cv2pdb.exe + tar xJf /tmp/scopy-$MINGW_VERSION-build-deps.tar.xz cat /tmp/scopy-mingw-build-status @@ -16,6 +24,7 @@ SCOPY_MINGW_BUILD_DEPS_PACMAN=$( Qt -License +License Homepage @@ -51,7 +51,7 @@ table, th, td { PulseView -License +License Homepage diff --git a/resources/scopy.html b/resources/scopy.html index 43bce635a5..517d3737ba 100644 --- a/resources/scopy.html +++ b/resources/scopy.html @@ -11,7 +11,7 @@

Welcome to Scopy!



Scopy is a powerful toolbox for signal analysis and generation.

Please visit our wiki for more information about Scopy.
-If you need help, drop a message on our Engineer Zone.
+If you need help, drop a message on our Engineer Zone.
diff --git a/resources/stylesheets/light.qss b/resources/stylesheets/light.qss index 4aa40cb6d8..77a251b5f9 100644 --- a/resources/stylesheets/light.qss +++ b/resources/stylesheets/light.qss @@ -139,15 +139,14 @@ QComboBox QAbstractItemView { border: none; background-color: white; text-align: left; - color: #bebebe; + color: black; outline: none; border-bottom: 1px solid #bebebe; border-top: 1px solid #bebebe; -} -/* This only works on Windows */ -QComboBox QAbstractItemView { + /* This only works on Windows */ + selection-color: black; selection-background-color: #EDEDED; } diff --git a/scopy-32.iss.cmakein b/scopy-32.iss.cmakein index 828f614a06..39e573b98c 100644 --- a/scopy-32.iss.cmakein +++ b/scopy-32.iss.cmakein @@ -21,7 +21,7 @@ AllowNoIcons=yes Compression=lzma SolidCompression=yes ArchitecturesInstallIn64BitMode=x64 -DefaultDirName={#AppDev}\{#AppName} +DefaultDirName={pf}\{#AppDev}\{#AppName} DefaultGroupName={#AppName} AlwaysRestart=yes DisableDirPage=no @@ -59,10 +59,192 @@ begin end; end; +var + UninstallPage: TNewNotebookPage; + UninstallButton: TNewButton; + UninstallDriverCheckBox: TNewCheckBox; + +procedure UpdateUninstallWizard; +begin + if UninstallProgressForm.InnerNotebook.ActivePage = UninstallPage then + begin + UninstallProgressForm.PageNameLabel.Caption := 'Uninstall Scopy'; + UninstallProgressForm.PageDescriptionLabel.Caption := ''; + end; + UninstallButton.Caption := 'Uninstall'; + UninstallButton.ModalResult := mrOK; +end; + +procedure UninstallButtonClick(Sender: TObject); +begin + UninstallButton.Visible := False; +end; + +procedure InitializeUninstallProgressForm(); +var + PageNameLabel: string; + PageDescriptionLabel: string; + CancelButtonEnabled: Boolean; + CancelButtonModalResult: Integer; + ResultCode : Integer; + PageCaption: TNewStaticText; +begin + if not UninstallSilent then + begin + { Create the first page and make it active } + UninstallPage := TNewNotebookPage.Create(UninstallProgressForm); + UninstallPage.Notebook := UninstallProgressForm.InnerNotebook; + UninstallPage.Parent := UninstallProgressForm.InnerNotebook; + UninstallPage.Align := alClient; + + PageCaption := TNewStaticText.Create(UninstallProgressForm); + PageCaption.Parent := UninstallPage; + PageCaption.Top := UninstallProgressForm.StatusLabel.Top; + PageCaption.Left := UninstallProgressForm.StatusLabel.Left; + PageCaption.Width := UninstallProgressForm.StatusLabel.Width; + PageCaption.Height := UninstallProgressForm.StatusLabel.Height; + PageCaption.AutoSize := False; + PageCaption.ShowAccelChar := False; + PageCaption.Caption := 'Press Uninstall to proceeed with uninstallation.'; + + UninstallDriverCheckBox := TNewCheckBox.Create(UninstallProgressForm); + UninstallDriverCheckBox.Parent := UninstallPage; + UninstallDriverCheckBox.Top := PageCaption.Top; + UninstallDriverCheckBox.Left := PageCaption.Left; + UninstallDriverCheckBox.Width := PageCaption.Width; + UninstallDriverCheckBox.Height := PageCaption.Height; + UninstallDriverCheckBox.Caption := 'Uninstall ADALM2000/ADALM-PLUTO drivers.'; + UninstallProgressForm.InnerNotebook.ActivePage := UninstallPage; + + PageNameLabel := UninstallProgressForm.PageNameLabel.Caption; + PageDescriptionLabel := UninstallProgressForm.PageDescriptionLabel.Caption; + + + UninstallButton := TNewButton.Create(UninstallProgressForm); + UninstallButton.Parent := UninstallProgressForm; + UninstallButton.Left := + UninstallProgressForm.CancelButton.Left - + UninstallProgressForm.CancelButton.Width - + ScaleX(10); + UninstallButton.Top := UninstallProgressForm.CancelButton.Top; + UninstallButton.Width := UninstallProgressForm.CancelButton.Width; + UninstallButton.Height := UninstallProgressForm.CancelButton.Height; + UninstallButton.OnClick := @UninstallButtonClick; + UninstallProgressForm.CancelButton.TabOrder := UninstallButton.TabOrder + 1; + + { Run the wizard } + UpdateUninstallWizard; + CancelButtonEnabled := UninstallProgressForm.CancelButton.Enabled + UninstallProgressForm.CancelButton.Enabled := True; + CancelButtonModalResult := UninstallProgressForm.CancelButton.ModalResult; + UninstallProgressForm.CancelButton.ModalResult := mrCancel; + + { Display the First uninstaller page } + if UninstallProgressForm.ShowModal = mrCancel then Abort; + + if UninstallDriverCheckBox.Checked = True then + begin + if not Exec(ExpandConstant('{app}\drivers\dpinst.exe'), '/s /U pluto-cdc-acm.inf', ExpandConstant('{app}\drivers'), SW_SHOW, ewWaitUntilTerminated, ResultCode) then + begin + MsgBox('Failed to uninstall drivers: ' + SysErrorMessage(ResultCode) + '.', mbInformation, MB_OK); + end; + + if not Exec(ExpandConstant('{app}\drivers\dpinst.exe'), '/s /U pluto-rndis.inf', ExpandConstant('{app}\drivers'), SW_SHOW, ewWaitUntilTerminated, ResultCode) then + begin + MsgBox('Failed to uninstall drivers: ' + SysErrorMessage(ResultCode) + '.', mbInformation, MB_OK); + end; + + if not Exec(ExpandConstant('{app}\drivers\dpinst.exe'), '/s /U pluto-usbd.inf', ExpandConstant('{app}\drivers'), SW_SHOW, ewWaitUntilTerminated, ResultCode) then + begin + MsgBox('Failed to uninstall drivers: ' + SysErrorMessage(ResultCode) + '.', mbInformation, MB_OK); + end; + + if not Exec(ExpandConstant('{app}\drivers\dpinst.exe'), '/s /U pluto-dfu.inf', ExpandConstant('{app}\drivers'), SW_SHOW, ewWaitUntilTerminated, ResultCode) then + begin + MsgBox('Failed to uninstall drivers: ' + SysErrorMessage(ResultCode) + '.', mbInformation, MB_OK); + end; + + if not RegDeleteKeyIncludingSubkeys(HKEY_LOCAL_MACHINE, 'Software\Analog Devices\Scopy') then + begin + MsgBox('Failed to remove registry key: Scopy.', mbInformation, MB_OK); + end; + end; + UninstallProgressForm.CancelButton.Enabled := CancelButtonEnabled; + UninstallProgressForm.CancelButton.ModalResult := CancelButtonModalResult; + UninstallProgressForm.PageNameLabel.Caption := PageNameLabel; + UninstallProgressForm.PageDescriptionLabel.Caption := PageDescriptionLabel; + UninstallProgressForm.InnerNotebook.ActivePage := UninstallProgressForm.InstallingPage; + end; +end; + +function GetInstallLocation(): String; +var + regPath: String; + installLocationString: String; +begin + regPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#SetupSetting("AppId")}_is1'); + installLocationString := ''; + if not RegQueryStringValue(HKLM, regPath, 'InstallLocation', installLocationString) then + RegQueryStringValue(HKCU, regPath, 'InstallLocation', installLocationString); + Result := installLocationString; +end; + +function GetUninstallerString(): String; +var + regPath: String; + uninstallerString: String; +begin + regPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#SetupSetting("AppId")}_is1'); + uninstallerString := ''; + if not RegQueryStringValue(HKLM, regPath, 'UninstallString', uninstallerString) then + RegQueryStringValue(HKCU, regPath, 'UninstallString', uninstallerString); + Result := uninstallerString; +end; + + +function IsUpgrade(): Boolean; +begin + Result := (GetInstallLocation() = ExpandConstant('{app}\')); +end; + + +procedure RemoveOldVersion(); +var + installLocationString: String; + uninstallerString: String; + resultCode: Integer; +begin + installLocationString := GetInstallLocation(); + uninstallerString := GetUninstallerString(); + if installLocationString <> '' then begin + uninstallerString := RemoveQuotes(uninstallerString); + if not Exec(uninstallerString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, resultCode) then + begin + MsgBox('Failed to uninstall previous version!', mbInformation, MB_OK); + end; + end; +end; + +procedure CurStepChanged(CurStep: TSetupStep); +begin + if (CurStep=ssInstall) then + begin + if (isUpgrade()) then + begin + if MsgBox('A different Scopy version was found at this location. Remove before installing?', mbConfirmation, MB_YESNO or MB_DEFBUTTON2) = IDYES then + begin + RemoveOldVersion(); + end; + end; + end; +end; + [Tasks] Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}" Name: "deleteini"; Description: Delete previous settings (Scopy.ini) +Name: "deletepreferences"; Description: Delete previous application preferences (Preferences.ini) Name: "drivers"; Description: Install drivers for ADALM2000; Check: not isDriverInstalled; +Name: "drivers_overwrite"; Description: Install drivers for ADALM2000; Check: isDriverInstalled; Flags: unchecked [Files] Source: "c:\scopy_32\*"; DestDir: "{app}"; Check: not Is64BitInstallMode; Flags: ignoreversion recursesubdirs createallsubdirs @@ -74,18 +256,13 @@ Name: "{commondesktop}\{#AppName}"; Filename: "{app}\{#AppExeName}"; Tasks: desk [InstallDelete] Type: files; Name: "{userappdata}\ADI\Scopy.ini"; Tasks: deleteini +Type: files; Name: "{userappdata}\ADI\Preferences.ini"; Tasks: deletepreferences [Run] -Filename: "{app}\drivers\dpinst.exe"; Parameters: "/PATH ""{app}\drivers"" {param:dpinstflags|/F}" ; Flags: waituntilterminated; Tasks: drivers - -[UninstallRun] -Filename: "{app}\drivers\dpinst.exe"; Parameters: "/s /U pluto-cdc-acm.inf"; WorkingDir: "{app}\drivers"; Flags: waituntilterminated; -Filename: "{app}\drivers\dpinst.exe"; Parameters: "/s /U pluto-rndis.inf"; WorkingDir: "{app}\drivers"; Flags: waituntilterminated; -Filename: "{app}\drivers\dpinst.exe"; Parameters: "/s /U pluto-usbd.inf"; WorkingDir: "{app}\drivers"; Flags: waituntilterminated; -Filename: "{app}\drivers\dpinst.exe"; Parameters: "/s /U pluto-dfu.inf"; WorkingDir: "{app}\drivers"; Flags: waituntilterminated; +Filename: "{app}\drivers\dpinst.exe"; Parameters: "/PATH ""{app}\drivers"" {param:dpinstflags|/F}" ; Flags: waituntilterminated; Tasks: drivers drivers_overwrite [Registry] -Root: HKLM; Subkey: "Software\Analog Devices"; Flags: uninsdeletekeyifempty -Root: HKLM; Subkey: "Software\Analog Devices\{#AppName}"; Flags: uninsdeletekey +Root: HKLM; Subkey: "Software\Analog Devices" +Root: HKLM; Subkey: "Software\Analog Devices\{#AppName}" Root: HKLM; Subkey: "Software\Analog Devices\{#AppName}\Settings"; ValueType: string; ValueName: "InstallPath"; ValueData: "{app}" Root: HKLM; Subkey: "Software\Analog Devices\{#AppName}\Settings"; ValueType: string; ValueName: "InstallVersion"; ValueData: {#DriverVersion} diff --git a/scopy-64.iss.cmakein b/scopy-64.iss.cmakein index 500d281a36..ddaf9f0de1 100644 --- a/scopy-64.iss.cmakein +++ b/scopy-64.iss.cmakein @@ -21,7 +21,7 @@ AllowNoIcons=yes Compression=lzma SolidCompression=yes ArchitecturesInstallIn64BitMode=x64 -DefaultDirName={#AppDev}\{#AppName} +DefaultDirName={pf}\{#AppDev}\{#AppName} DefaultGroupName={#AppName} AlwaysRestart=yes DisableDirPage=no @@ -59,10 +59,194 @@ begin end; end; +var + UninstallPage: TNewNotebookPage; + UninstallButton: TNewButton; + UninstallDriverCheckBox: TNewCheckBox; + +procedure UpdateUninstallWizard; +begin + if UninstallProgressForm.InnerNotebook.ActivePage = UninstallPage then + begin + UninstallProgressForm.PageNameLabel.Caption := 'Uninstall Scopy'; + UninstallProgressForm.PageDescriptionLabel.Caption := ''; + end; + UninstallButton.Caption := 'Uninstall'; + UninstallButton.ModalResult := mrOK; +end; + +procedure UninstallButtonClick(Sender: TObject); +begin + UninstallButton.Visible := False; +end; + +procedure InitializeUninstallProgressForm(); +var + PageNameLabel: string; + PageDescriptionLabel: string; + CancelButtonEnabled: Boolean; + CancelButtonModalResult: Integer; + ResultCode : Integer; + PageCaption: TNewStaticText; +begin + if not UninstallSilent then + begin + { Create the first page and make it active } + UninstallPage := TNewNotebookPage.Create(UninstallProgressForm); + UninstallPage.Notebook := UninstallProgressForm.InnerNotebook; + UninstallPage.Parent := UninstallProgressForm.InnerNotebook; + UninstallPage.Align := alClient; + + PageCaption := TNewStaticText.Create(UninstallProgressForm); + PageCaption.Parent := UninstallPage; + PageCaption.Top := UninstallProgressForm.StatusLabel.Top; + PageCaption.Left := UninstallProgressForm.StatusLabel.Left; + PageCaption.Width := UninstallProgressForm.StatusLabel.Width; + PageCaption.Height := UninstallProgressForm.StatusLabel.Height; + PageCaption.AutoSize := False; + PageCaption.ShowAccelChar := False; + PageCaption.Caption := 'Press Uninstall to proceeed with uninstallation.'; + + UninstallDriverCheckBox := TNewCheckBox.Create(UninstallProgressForm); + UninstallDriverCheckBox.Parent := UninstallPage; + UninstallDriverCheckBox.Top := PageCaption.Top; + UninstallDriverCheckBox.Left := PageCaption.Left; + UninstallDriverCheckBox.Width := PageCaption.Width; + UninstallDriverCheckBox.Height := PageCaption.Height; + UninstallDriverCheckBox.Caption := 'Uninstall ADALM2000/ADALM-PLUTO drivers.'; + UninstallProgressForm.InnerNotebook.ActivePage := UninstallPage; + + PageNameLabel := UninstallProgressForm.PageNameLabel.Caption; + PageDescriptionLabel := UninstallProgressForm.PageDescriptionLabel.Caption; + + + UninstallButton := TNewButton.Create(UninstallProgressForm); + UninstallButton.Parent := UninstallProgressForm; + UninstallButton.Left := + UninstallProgressForm.CancelButton.Left - + UninstallProgressForm.CancelButton.Width - + ScaleX(10); + UninstallButton.Top := UninstallProgressForm.CancelButton.Top; + UninstallButton.Width := UninstallProgressForm.CancelButton.Width; + UninstallButton.Height := UninstallProgressForm.CancelButton.Height; + UninstallButton.OnClick := @UninstallButtonClick; + UninstallProgressForm.CancelButton.TabOrder := UninstallButton.TabOrder + 1; + + { Run the wizard } + UpdateUninstallWizard; + CancelButtonEnabled := UninstallProgressForm.CancelButton.Enabled + UninstallProgressForm.CancelButton.Enabled := True; + CancelButtonModalResult := UninstallProgressForm.CancelButton.ModalResult; + UninstallProgressForm.CancelButton.ModalResult := mrCancel; + + { Display the First uninstaller page } + if UninstallProgressForm.ShowModal = mrCancel then Abort; + + if UninstallDriverCheckBox.Checked = True then + begin + if not Exec(ExpandConstant('{app}\drivers\dpinst.exe'), '/s /U pluto-cdc-acm.inf', ExpandConstant('{app}\drivers'), SW_SHOW, ewWaitUntilTerminated, ResultCode) then + begin + MsgBox('Failed to uninstall drivers: ' + SysErrorMessage(ResultCode) + '.', mbInformation, MB_OK); + end; + + if not Exec(ExpandConstant('{app}\drivers\dpinst.exe'), '/s /U pluto-rndis.inf', ExpandConstant('{app}\drivers'), SW_SHOW, ewWaitUntilTerminated, ResultCode) then + begin + MsgBox('Failed to uninstall drivers: ' + SysErrorMessage(ResultCode) + '.', mbInformation, MB_OK); + end; + + if not Exec(ExpandConstant('{app}\drivers\dpinst.exe'), '/s /U pluto-usbd.inf', ExpandConstant('{app}\drivers'), SW_SHOW, ewWaitUntilTerminated, ResultCode) then + begin + MsgBox('Failed to uninstall drivers: ' + SysErrorMessage(ResultCode) + '.', mbInformation, MB_OK); + end; + + if not Exec(ExpandConstant('{app}\drivers\dpinst.exe'), '/s /U pluto-dfu.inf', ExpandConstant('{app}\drivers'), SW_SHOW, ewWaitUntilTerminated, ResultCode) then + begin + MsgBox('Failed to uninstall drivers: ' + SysErrorMessage(ResultCode) + '.', mbInformation, MB_OK); + end; + + if not RegDeleteKeyIncludingSubkeys(HKEY_LOCAL_MACHINE, 'Software\Analog Devices\Scopy') then + begin + MsgBox('Failed to remove registry key: Scopy.', mbInformation, MB_OK); + end; + end; + UninstallProgressForm.CancelButton.Enabled := CancelButtonEnabled; + UninstallProgressForm.CancelButton.ModalResult := CancelButtonModalResult; + UninstallProgressForm.PageNameLabel.Caption := PageNameLabel; + UninstallProgressForm.PageDescriptionLabel.Caption := PageDescriptionLabel; + UninstallProgressForm.InnerNotebook.ActivePage := UninstallProgressForm.InstallingPage; + end; +end; + + +function GetInstallLocation(): String; +var + regPath: String; + installLocationString: String; +begin + regPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#SetupSetting("AppId")}_is1'); + installLocationString := ''; + if not RegQueryStringValue(HKLM, regPath, 'InstallLocation', installLocationString) then + RegQueryStringValue(HKCU, regPath, 'InstallLocation', installLocationString); + Result := installLocationString; +end; + +function GetUninstallerString(): String; +var + regPath: String; + uninstallerString: String; +begin + regPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#SetupSetting("AppId")}_is1'); + uninstallerString := ''; + if not RegQueryStringValue(HKLM, regPath, 'UninstallString', uninstallerString) then + RegQueryStringValue(HKCU, regPath, 'UninstallString', uninstallerString); + Result := uninstallerString; +end; + + +function IsUpgrade(): Boolean; +begin + Result := (GetInstallLocation() = ExpandConstant('{app}\')); +end; + + +procedure RemoveOldVersion(); +var + installLocationString: String; + uninstallerString: String; + resultCode: Integer; +begin + installLocationString := GetInstallLocation(); + uninstallerString := GetUninstallerString(); + if installLocationString <> '' then begin + uninstallerString := RemoveQuotes(uninstallerString); + if not Exec(uninstallerString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, resultCode) then + begin + MsgBox('Failed to uninstall previous version!', mbInformation, MB_OK); + end; + end; +end; + +procedure CurStepChanged(CurStep: TSetupStep); +begin + if (CurStep=ssInstall) then + begin + if (isUpgrade()) then + begin + if MsgBox('A different Scopy version was found at this location. Remove before installing?', mbConfirmation, MB_YESNO or MB_DEFBUTTON2) = IDYES then + begin + RemoveOldVersion(); + end; + end; + end; +end; + + [Tasks] Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}" Name: "deleteini"; Description: Delete previous settings (Scopy.ini) +Name: "deletepreferences"; Description: Delete previous application preferences (Preferences.ini) Name: "drivers"; Description: Install drivers for ADALM2000; Check: not isDriverInstalled; +Name: "drivers_overwrite"; Description: Install drivers for ADALM2000; Check: isDriverInstalled; Flags: unchecked [Files] Source: "c:\scopy_64\*"; DestDir: "{app}"; Check: Is64BitInstallMode; Flags: ignoreversion recursesubdirs createallsubdirs @@ -74,18 +258,13 @@ Name: "{commondesktop}\{#AppName}"; Filename: "{app}\{#AppExeName}"; Tasks: desk [InstallDelete] Type: files; Name: "{userappdata}\ADI\Scopy.ini"; Tasks: deleteini +Type: files; Name: "{userappdata}\ADI\Preferences.ini"; Tasks: deletepreferences [Run] -Filename: "{app}\drivers\dpinst.exe"; Parameters: "/PATH ""{app}\drivers"" {param:dpinstflags|/F}" ; Flags: waituntilterminated; Tasks: drivers - -[UninstallRun] -Filename: "{app}\drivers\dpinst.exe"; Parameters: "/s /U pluto-cdc-acm.inf"; WorkingDir: "{app}\drivers"; Flags: waituntilterminated; -Filename: "{app}\drivers\dpinst.exe"; Parameters: "/s /U pluto-rndis.inf"; WorkingDir: "{app}\drivers"; Flags: waituntilterminated; -Filename: "{app}\drivers\dpinst.exe"; Parameters: "/s /U pluto-usbd.inf"; WorkingDir: "{app}\drivers"; Flags: waituntilterminated; -Filename: "{app}\drivers\dpinst.exe"; Parameters: "/s /U pluto-dfu.inf"; WorkingDir: "{app}\drivers"; Flags: waituntilterminated; +Filename: "{app}\drivers\dpinst.exe"; Parameters: "/PATH ""{app}\drivers"" {param:dpinstflags|/F}" ; Flags: waituntilterminated; Tasks: drivers drivers_overwrite [Registry] -Root: HKLM; Subkey: "Software\Analog Devices"; Flags: uninsdeletekeyifempty -Root: HKLM; Subkey: "Software\Analog Devices\{#AppName}"; Flags: uninsdeletekey +Root: HKLM; Subkey: "Software\Analog Devices" +Root: HKLM; Subkey: "Software\Analog Devices\{#AppName}" Root: HKLM; Subkey: "Software\Analog Devices\{#AppName}\Settings"; ValueType: string; ValueName: "InstallPath"; ValueData: "{app}" Root: HKLM; Subkey: "Software\Analog Devices\{#AppName}\Settings"; ValueType: string; ValueName: "InstallVersion"; ValueData: {#DriverVersion} diff --git a/scopy.iss.cmakein b/scopy.iss.cmakein index eaa38ba170..c37ae5a061 100644 --- a/scopy.iss.cmakein +++ b/scopy.iss.cmakein @@ -21,7 +21,7 @@ AllowNoIcons=yes Compression=lzma SolidCompression=yes ArchitecturesInstallIn64BitMode=x64 -DefaultDirName={#AppDev}\{#AppName} +DefaultDirName={pf}\{#AppDev}\{#AppName} DefaultGroupName={#AppName} AlwaysRestart=yes DisableDirPage=no @@ -59,10 +59,192 @@ begin end; end; +var + UninstallPage: TNewNotebookPage; + UninstallButton: TNewButton; + UninstallDriverCheckBox: TNewCheckBox; + +procedure UpdateUninstallWizard; +begin + if UninstallProgressForm.InnerNotebook.ActivePage = UninstallPage then + begin + UninstallProgressForm.PageNameLabel.Caption := 'Uninstall Scopy'; + UninstallProgressForm.PageDescriptionLabel.Caption := ''; + end; + UninstallButton.Caption := 'Uninstall'; + UninstallButton.ModalResult := mrOK; +end; + +procedure UninstallButtonClick(Sender: TObject); +begin + UninstallButton.Visible := False; +end; + +procedure InitializeUninstallProgressForm(); +var + PageNameLabel: string; + PageDescriptionLabel: string; + CancelButtonEnabled: Boolean; + CancelButtonModalResult: Integer; + ResultCode : Integer; + PageCaption: TNewStaticText; +begin + if not UninstallSilent then + begin + { Create the first page and make it active } + UninstallPage := TNewNotebookPage.Create(UninstallProgressForm); + UninstallPage.Notebook := UninstallProgressForm.InnerNotebook; + UninstallPage.Parent := UninstallProgressForm.InnerNotebook; + UninstallPage.Align := alClient; + + PageCaption := TNewStaticText.Create(UninstallProgressForm); + PageCaption.Parent := UninstallPage; + PageCaption.Top := UninstallProgressForm.StatusLabel.Top; + PageCaption.Left := UninstallProgressForm.StatusLabel.Left; + PageCaption.Width := UninstallProgressForm.StatusLabel.Width; + PageCaption.Height := UninstallProgressForm.StatusLabel.Height; + PageCaption.AutoSize := False; + PageCaption.ShowAccelChar := False; + PageCaption.Caption := 'Press Uninstall to proceeed with uninstallation.'; + + UninstallDriverCheckBox := TNewCheckBox.Create(UninstallProgressForm); + UninstallDriverCheckBox.Parent := UninstallPage; + UninstallDriverCheckBox.Top := PageCaption.Top; + UninstallDriverCheckBox.Left := PageCaption.Left; + UninstallDriverCheckBox.Width := PageCaption.Width; + UninstallDriverCheckBox.Height := PageCaption.Height; + UninstallDriverCheckBox.Caption := 'Uninstall ADALM2000/ADALM-PLUTO drivers.'; + UninstallProgressForm.InnerNotebook.ActivePage := UninstallPage; + + PageNameLabel := UninstallProgressForm.PageNameLabel.Caption; + PageDescriptionLabel := UninstallProgressForm.PageDescriptionLabel.Caption; + + + UninstallButton := TNewButton.Create(UninstallProgressForm); + UninstallButton.Parent := UninstallProgressForm; + UninstallButton.Left := + UninstallProgressForm.CancelButton.Left - + UninstallProgressForm.CancelButton.Width - + ScaleX(10); + UninstallButton.Top := UninstallProgressForm.CancelButton.Top; + UninstallButton.Width := UninstallProgressForm.CancelButton.Width; + UninstallButton.Height := UninstallProgressForm.CancelButton.Height; + UninstallButton.OnClick := @UninstallButtonClick; + UninstallProgressForm.CancelButton.TabOrder := UninstallButton.TabOrder + 1; + + { Run the wizard } + UpdateUninstallWizard; + CancelButtonEnabled := UninstallProgressForm.CancelButton.Enabled + UninstallProgressForm.CancelButton.Enabled := True; + CancelButtonModalResult := UninstallProgressForm.CancelButton.ModalResult; + UninstallProgressForm.CancelButton.ModalResult := mrCancel; + + { Display the First uninstaller page } + if UninstallProgressForm.ShowModal = mrCancel then Abort; + + if UninstallDriverCheckBox.Checked = True then + begin + if not Exec(ExpandConstant('{app}\drivers\dpinst.exe'), '/s /U pluto-cdc-acm.inf', ExpandConstant('{app}\drivers'), SW_SHOW, ewWaitUntilTerminated, ResultCode) then + begin + MsgBox('Failed to uninstall drivers: ' + SysErrorMessage(ResultCode) + '.', mbInformation, MB_OK); + end; + + if not Exec(ExpandConstant('{app}\drivers\dpinst.exe'), '/s /U pluto-rndis.inf', ExpandConstant('{app}\drivers'), SW_SHOW, ewWaitUntilTerminated, ResultCode) then + begin + MsgBox('Failed to uninstall drivers: ' + SysErrorMessage(ResultCode) + '.', mbInformation, MB_OK); + end; + + if not Exec(ExpandConstant('{app}\drivers\dpinst.exe'), '/s /U pluto-usbd.inf', ExpandConstant('{app}\drivers'), SW_SHOW, ewWaitUntilTerminated, ResultCode) then + begin + MsgBox('Failed to uninstall drivers: ' + SysErrorMessage(ResultCode) + '.', mbInformation, MB_OK); + end; + + if not Exec(ExpandConstant('{app}\drivers\dpinst.exe'), '/s /U pluto-dfu.inf', ExpandConstant('{app}\drivers'), SW_SHOW, ewWaitUntilTerminated, ResultCode) then + begin + MsgBox('Failed to uninstall drivers: ' + SysErrorMessage(ResultCode) + '.', mbInformation, MB_OK); + end; + + if not RegDeleteKeyIncludingSubkeys(HKEY_LOCAL_MACHINE, 'Software\Analog Devices\Scopy') then + begin + MsgBox('Failed to remove registry key: Scopy.', mbInformation, MB_OK); + end; + end; + UninstallProgressForm.CancelButton.Enabled := CancelButtonEnabled; + UninstallProgressForm.CancelButton.ModalResult := CancelButtonModalResult; + UninstallProgressForm.PageNameLabel.Caption := PageNameLabel; + UninstallProgressForm.PageDescriptionLabel.Caption := PageDescriptionLabel; + UninstallProgressForm.InnerNotebook.ActivePage := UninstallProgressForm.InstallingPage; + end; +end; + +function GetInstallLocation(): String; +var + regPath: String; + installLocationString: String; +begin + regPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#SetupSetting("AppId")}_is1'); + installLocationString := ''; + if not RegQueryStringValue(HKLM, regPath, 'InstallLocation', installLocationString) then + RegQueryStringValue(HKCU, regPath, 'InstallLocation', installLocationString); + Result := installLocationString; +end; + +function GetUninstallerString(): String; +var + regPath: String; + uninstallerString: String; +begin + regPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#SetupSetting("AppId")}_is1'); + uninstallerString := ''; + if not RegQueryStringValue(HKLM, regPath, 'UninstallString', uninstallerString) then + RegQueryStringValue(HKCU, regPath, 'UninstallString', uninstallerString); + Result := uninstallerString; +end; + + +function IsUpgrade(): Boolean; +begin + Result := (GetInstallLocation() = ExpandConstant('{app}\')); +end; + + +procedure RemoveOldVersion(); +var + installLocationString: String; + uninstallerString: String; + resultCode: Integer; +begin + installLocationString := GetInstallLocation(); + uninstallerString := GetUninstallerString(); + if installLocationString <> '' then begin + uninstallerString := RemoveQuotes(uninstallerString); + if not Exec(uninstallerString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, resultCode) then + begin + MsgBox('Failed to uninstall previous version!', mbInformation, MB_OK); + end; + end; +end; + +procedure CurStepChanged(CurStep: TSetupStep); +begin + if (CurStep=ssInstall) then + begin + if (isUpgrade()) then + begin + if MsgBox('A different Scopy version was found at this location. Remove before installing?', mbConfirmation, MB_YESNO or MB_DEFBUTTON2) = IDYES then + begin + RemoveOldVersion(); + end; + end; + end; +end; + [Tasks] Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}" Name: "deleteini"; Description: Delete previous settings (Scopy.ini) +Name: "deletepreferences"; Description: Delete previous application preferences (Preferences.ini) Name: "drivers"; Description: Install drivers for ADALM2000; Check: not isDriverInstalled; +Name: "drivers_overwrite"; Description: Install drivers for ADALM2000; Check: isDriverInstalled; Flags: unchecked [Files] Source: "c:\scopy_64\*"; DestDir: "{app}"; Check: Is64BitInstallMode; Flags: ignoreversion recursesubdirs createallsubdirs @@ -76,18 +258,13 @@ Name: "{commondesktop}\{#AppName}"; Filename: "{app}\{#AppExeName}"; Tasks: desk [InstallDelete] Type: files; Name: "{userappdata}\ADI\Scopy.ini"; Tasks: deleteini +Type: files; Name: "{userappdata}\ADI\Preferences.ini"; Tasks: deletepreferences [Run] -Filename: "{app}\drivers\dpinst.exe"; Parameters: "/PATH ""{app}\drivers"" {param:dpinstflags|/F}" ; Flags: waituntilterminated; Tasks: drivers - -[UninstallRun] -Filename: "{app}\drivers\dpinst.exe"; Parameters: "/s /U pluto-cdc-acm.inf"; WorkingDir: "{app}\drivers"; Flags: waituntilterminated; -Filename: "{app}\drivers\dpinst.exe"; Parameters: "/s /U pluto-rndis.inf"; WorkingDir: "{app}\drivers"; Flags: waituntilterminated; -Filename: "{app}\drivers\dpinst.exe"; Parameters: "/s /U pluto-usbd.inf"; WorkingDir: "{app}\drivers"; Flags: waituntilterminated; -Filename: "{app}\drivers\dpinst.exe"; Parameters: "/s /U pluto-dfu.inf"; WorkingDir: "{app}\drivers"; Flags: waituntilterminated; +Filename: "{app}\drivers\dpinst.exe"; Parameters: "/PATH ""{app}\drivers"" {param:dpinstflags|/F}" ; Flags: waituntilterminated; Tasks: drivers drivers_overwrite [Registry] -Root: HKLM; Subkey: "Software\Analog Devices"; Flags: uninsdeletekeyifempty -Root: HKLM; Subkey: "Software\Analog Devices\{#AppName}"; Flags: uninsdeletekey +Root: HKLM; Subkey: "Software\Analog Devices" +Root: HKLM; Subkey: "Software\Analog Devices\{#AppName}" Root: HKLM; Subkey: "Software\Analog Devices\{#AppName}\Settings"; ValueType: string; ValueName: "InstallPath"; ValueData: "{app}" Root: HKLM; Subkey: "Software\Analog Devices\{#AppName}\Settings"; ValueType: string; ValueName: "InstallVersion"; ValueData: {#DriverVersion} diff --git a/src/DisplayPlot.cc b/src/DisplayPlot.cc index a6da863954..7157c9d374 100644 --- a/src/DisplayPlot.cc +++ b/src/DisplayPlot.cc @@ -57,6 +57,7 @@ #include #include #include +#include using namespace adiscope; @@ -207,7 +208,7 @@ void OscScaleDraw::draw(QPainter *painter, const QPalette &) const drawLabel(painter, delta); } - for (const auto &tick : ticks) { + for (const auto &tick : qAsConst(ticks)) { if (tick != delta) { drawLabel(painter, tick); } @@ -508,77 +509,73 @@ void PlotAxisConfiguration::setMouseGesturesEnabled(bool en) * DisplayPlot class */ -DisplayPlot::DisplayPlot(int nplots, QWidget* parent, +DisplayPlot::DisplayPlot(int nplots, QWidget* parent, bool isdBgraph, unsigned int xNumDivs, unsigned int yNumDivs) - : PrintablePlot(parent), d_nplots(nplots), d_stop(false), - d_coloredLabels(false), d_mouseGesturesEnabled(false), - d_displayScale(1), d_xAxisNumDiv(1), - d_yAxisNumDiv(1) + : PrintablePlot(parent), d_nplots(nplots), d_stop(false), + d_coloredLabels(false), d_mouseGesturesEnabled(false), + d_displayScale(1), d_xAxisNumDiv(1), d_trackMode(false), + d_cursorsEnabled(false), d_isLogaritmicPlot(false), + d_isLogaritmicYPlot(false), + d_yAxisNumDiv(1) { - d_CurveColors << QColor("#ff7200") << QColor("#9013fe") << QColor(Qt::green) - << QColor(Qt::cyan) << QColor(Qt::magenta) - << QColor(Qt::yellow) << QColor(Qt::gray) << QColor(Qt::darkRed) - << QColor(Qt::darkGreen) << QColor(Qt::darkBlue) << QColor(Qt::darkGray) - << QColor(Qt::black); - d_printColors << QColor("#ff7200") << QColor("#9013fe") << QColor(Qt::darkGreen) - << QColor(Qt::blue) << QColor(Qt::magenta) - << QColor(Qt::darkRed); + d_CurveColors << QColor("#ff7200") << QColor("#9013fe") << QColor(Qt::green) + << QColor(Qt::cyan) << QColor(Qt::magenta) + << QColor(Qt::yellow) << QColor(Qt::gray) << QColor(Qt::darkRed) + << QColor(Qt::darkGreen) << QColor(Qt::darkBlue) << QColor(Qt::darkGray) + << QColor(Qt::black); - qRegisterMetaType("QColorList"); - resize(parent->width(), parent->height()); + d_printColors << QColor("#ff7200") << QColor("#9013fe") << QColor(Qt::darkGreen) + << QColor(Qt::blue) << QColor(Qt::magenta) + << QColor(Qt::darkRed); - d_autoscale_state = false; + qRegisterMetaType("QColorList"); + resize(parent->width(), parent->height()); - d_yAxisUnit = ""; - d_xAxisUnit = ""; + d_autoscale_state = false; - setXaxisNumDiv(xNumDivs); - setYaxisNumDiv(yNumDivs); + d_yAxisUnit = ""; + d_xAxisUnit = ""; - d_usingLeftAxisScales = true; + setXaxisNumDiv(xNumDivs); + setYaxisNumDiv(yNumDivs); - // Disable polygon clipping + d_usingLeftAxisScales = true; + + // Disable polygon clipping #if QWT_VERSION < 0x060000 - QwtPainter::setDeviceClipping(false); + QwtPainter::setDeviceClipping(false); #else - QwtPainter::setPolylineSplitting(false); + QwtPainter::setPolylineSplitting(false); #endif #if QWT_VERSION < 0x060000 - // We don't need the cache here - canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, false); - canvas()->setPaintAttribute(QwtPlotCanvas::PaintPacked, false); + // We don't need the cache here + canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, false); + canvas()->setPaintAttribute(QwtPlotCanvas::PaintPacked, false); #endif - QColor default_palette_color = QColor("white"); - setPaletteColor(default_palette_color); + QColor default_palette_color = QColor("white"); + setPaletteColor(default_palette_color); - d_panner = new QwtPlotPanner(canvas()); - d_panner->setAxisEnabled(QwtPlot::yRight, false); - d_panner->setMouseButton(Qt::MidButton, Qt::ControlModifier); + d_panner = new QwtPlotPanner(canvas()); + d_panner->setAxisEnabled(QwtPlot::yRight, false); + d_panner->setMouseButton(Qt::MidButton, Qt::ControlModifier); - // emit the position of clicks on widget - d_picker = new QwtDblClickPlotPicker(canvas()); + // emit the position of clicks on widget + d_picker = new QwtDblClickPlotPicker(canvas()); #if QWT_VERSION < 0x060000 - connect(d_picker, SIGNAL(selected(const QPointF &)), - this, SLOT(onPickerPointSelected(const QPointF &))); + connect(d_picker, SIGNAL(selected(const QPointF &)), + this, SLOT(onPickerPointSelected(const QPointF &))); #else - d_picker->setStateMachine(new QwtPickerDblClickPointMachine()); - connect(d_picker, SIGNAL(selected(const QPointF &)), - this, SLOT(onPickerPointSelected6(const QPointF &))); + d_picker->setStateMachine(new QwtPickerDblClickPointMachine()); + connect(d_picker, SIGNAL(selected(const QPointF &)), + this, SLOT(onPickerPointSelected6(const QPointF &))); #endif - // Configure horizontal axis - bottomHorizAxisInit(); - - // One vertical axis by default - setLeftVertAxesCount(1); - - setActiveVertAxis(0); - - plotLayout()->setAlignCanvasToScales(true); + // Configure horizontal axis + bottomHorizAxisInit(); QColor plotColor; if (QIcon::themeName() == "scopy-default") { @@ -587,82 +584,685 @@ DisplayPlot::DisplayPlot(int nplots, QWidget* parent, plotColor = QColor("#D3D3D3"); } - for (unsigned int i = 0; i < 4; i++) { - QwtScaleDraw::Alignment scale = - static_cast(i); - auto scaleItem = new EdgelessPlotScaleItem(scale); - - scaleItem->scaleDraw()->setAlignment(scale); - scaleItem->scaleDraw()->enableComponent(QwtAbstractScaleDraw::Backbone, false); - scaleItem->scaleDraw()->enableComponent(QwtAbstractScaleDraw::Labels, false); - scaleItem->setFont(this->axisWidget(QwtPlot::yLeft)->font()); - - QPalette palette = scaleItem->palette(); - - palette.setBrush(QPalette::Foreground, plotColor); - palette.setBrush(QPalette::Text, plotColor); - scaleItem->setPalette(palette); - scaleItem->setBorderDistance(0); - scaleItem->attach(this); - scaleItems.push_back(scaleItem); - scaleItem->setZ(200); - } + // One vertical axis by default + setLeftVertAxesCount(1); + + setActiveVertAxis(0); + + plotLayout()->setAlignCanvasToScales(true); + - this->plotLayout()->setCanvasMargin(0, QwtPlot::yLeft); - this->plotLayout()->setCanvasMargin(0, QwtPlot::yRight); - this->plotLayout()->setCanvasMargin(0, QwtPlot::xTop); - this->plotLayout()->setCanvasMargin(0, QwtPlot::xBottom); + this->plotLayout()->setCanvasMargin(0, QwtPlot::yLeft); + this->plotLayout()->setCanvasMargin(0, QwtPlot::yRight); + this->plotLayout()->setCanvasMargin(0, QwtPlot::xTop); + this->plotLayout()->setCanvasMargin(0, QwtPlot::xBottom); - ((QFrame*) canvas())->setLineWidth(0); + ((QFrame*) canvas())->setLineWidth(0); - // Avoid jumping when labels with more/less digits - // appear/disappear when scrolling vertically + //Set up the grid and the legend for all displayplots, but dBgraph + setupDisplayPlotDiv(isdBgraph); - QwtLegend* legendDisplay = new QwtLegend(this); + d_symbolCtrl = new SymbolController(this); + + /* Adjacent areas */ + d_bottomHandlesArea = new HorizHandlesArea(this->canvas()); + d_rightHandlesArea = new VertHandlesArea(this->canvas()); + d_topHandlesArea = new HorizHandlesArea(this->canvas()); + d_leftHandlesArea = new VertHandlesArea(this->canvas()); + + d_bottomHandlesArea->setMinimumHeight(50); + d_rightHandlesArea->setMinimumWidth(50); + d_bottomHandlesArea->setLargestChildWidth(60); + d_rightHandlesArea->setLargestChildHeight(60); + d_rightHandlesArea->setMinimumHeight(this->minimumHeight()); + + d_formatter = static_cast(new MetricPrefixFormatter); + + markerIntersection1 = new QwtPlotMarker(); + markerIntersection2 = new QwtPlotMarker(); + markerIntersection1->setSymbol(new QwtSymbol( + QwtSymbol::Ellipse, QColor(237, 28, 36), + QPen(QColor(255, 255 ,255, 140), 2, Qt::SolidLine), + QSize(5, 5))); + markerIntersection2->setSymbol(new QwtSymbol( + QwtSymbol::Ellipse, QColor(237, 28, 36), + QPen(QColor(255, 255 ,255, 140), 2, Qt::SolidLine), + QSize(5, 5))); + + d_selected_channel = -1; + + setupCursors(); + setupReadouts(); +} + + +void DisplayPlot::setupDisplayPlotDiv(bool isdBgraph) { + if(!isdBgraph) + { + + // Avoid jumping when labels with more/less digits + // appear/disappear when scrolling vertically + QwtLegend* legendDisplay = new QwtLegend(this); #if QWT_VERSION < 0x060100 - legendDisplay->setItemMode(QwtLegend::CheckableItem); - insertLegend(legendDisplay); - connect(this, SIGNAL(legendChecked(QwtPlotItem *, bool)), - this, SLOT(legendEntryChecked(QwtPlotItem *, bool))); + legendDisplay->setItemMode(QwtLegend::CheckableItem); + insertLegend(legendDisplay); + connect(this, SIGNAL(legendChecked(QwtPlotItem *, bool)), + this, SLOT(legendEntryChecked(QwtPlotItem *, bool))); #else /* QWT_VERSION < 0x060100 */ - legendDisplay->setDefaultItemMode(QwtLegendData::Checkable); - insertLegend(legendDisplay); - connect(legendDisplay, SIGNAL(checked(const QVariant&, bool, int)), - this, SLOT(legendEntryChecked(const QVariant&, bool, int))); + legendDisplay->setDefaultItemMode(QwtLegendData::Checkable); + insertLegend(legendDisplay); + connect(legendDisplay, SIGNAL(checked(const QVariant&, bool, int)), + this, SLOT(legendEntryChecked(const QVariant&, bool, int))); #endif /* QWT_VERSION < 0x060100 */ - // Plot needs a grid - d_grid = new EdgelessPlotGrid(); - QColor majorPenColor(plotColor); - d_grid->setMajorPen(majorPenColor, 1.0, Qt::DashLine); - d_grid->attach(this); + for (unsigned int i = 0; i < 4; i++) { + QwtScaleDraw::Alignment scale = + static_cast(i); + auto scaleItem = new EdgelessPlotScaleItem(scale); + + scaleItem->scaleDraw()->setAlignment(scale); + scaleItem->scaleDraw()->enableComponent(QwtAbstractScaleDraw::Backbone, false); + scaleItem->scaleDraw()->enableComponent(QwtAbstractScaleDraw::Labels, false); + scaleItem->setFont(this->axisWidget(QwtPlot::yLeft)->font()); + + QPalette palette = scaleItem->palette(); + palette.setBrush(QPalette::Foreground, QColor("#6E6E6F")); + palette.setBrush(QPalette::Text, QColor("#6E6E6F")); + scaleItem->setPalette(palette); + scaleItem->setBorderDistance(0); + scaleItem->attach(this); + scaleItems.push_back(scaleItem); + scaleItem->setZ(200); + } + + // Plot needs a grid + d_grid = new EdgelessPlotGrid(); + QColor majorPenColor("#353537"); + d_grid->setMajorPen(majorPenColor, 1.0, Qt::DashLine); + d_grid->attach(this); + } } + DisplayPlot::~DisplayPlot() { - // d_zoomer and d_panner deleted when parent deleted + markerIntersection1->detach(); + markerIntersection2->detach(); + // d_zoomer and d_panner deleted when parent deleted + // Since some curves may not be attached to the plot they won't get deleted + for (auto it = d_plot_curve.begin(); it != d_plot_curve.end() ; ++it) { + QwtPlotCurve * qpc = (*it); + qpc->detach(); + delete qpc; + } + + // delete vertAxes + for (auto it = vertAxes.begin(); it != vertAxes.end(); ++it) { + delete *it; + } + + for (auto it = scaleItems.begin(); it != scaleItems.end(); ++it) { + delete *it; + } + + delete markerIntersection1; + delete markerIntersection2; + delete horizAxis; +} - // Since some curves may not be attached to the plot they won't get deleted - for (auto it = d_plot_curve.begin(); it != d_plot_curve.end() ; ++it) { - QwtPlotCurve * qpc = (*it); - qpc->detach(); - delete qpc; +QWidget* DisplayPlot::getPlotwithElements() +{ + QWidget* widget = new QWidget(); + QGridLayout *gridplot = new QGridLayout(); + + gridplot->addWidget(topHandlesArea(), 0, 0, 1, 3); + gridplot->addWidget(leftHandlesArea(), 0, 0, 3, 1); + gridplot->addWidget(this, 1, 1, 1, 1); + gridplot->addWidget(rightHandlesArea(), 0, 2, 3, 1); + gridplot->addWidget(bottomHandlesArea(), 2, 0, 1, 3); + + gridplot->setVerticalSpacing(0); + gridplot->setHorizontalSpacing(0); + gridplot->setContentsMargins(0, 0, 0, 0); + widget->setLayout(gridplot); + + return widget; +} + + +void DisplayPlot::setupCursors() { + + d_vBar1 = new VertBar(this, true); + d_vBar2 = new VertBar(this, true); + d_hBar1 = new HorizBar(this, true); + d_hBar2 = new HorizBar(this, true); + + d_vCursorHandle1 = new PlotLineHandleV( + QPixmap(":/icons/v_cursor_handle.svg"), + d_rightHandlesArea); + d_vCursorHandle2 = new PlotLineHandleV( + QPixmap(":/icons/v_cursor_handle.svg"), + d_rightHandlesArea); + d_hCursorHandle1 = new PlotLineHandleH( + QPixmap(":/icons/h_cursor_handle.svg"), + d_bottomHandlesArea); + d_hCursorHandle2 = new PlotLineHandleH( + QPixmap(":/icons/h_cursor_handle.svg"), + d_bottomHandlesArea); + + d_vertCursorsHandleEnabled = true; + + d_symbolCtrl->attachSymbol(d_vBar1); + d_symbolCtrl->attachSymbol(d_vBar2); + d_symbolCtrl->attachSymbol(d_hBar1); + d_symbolCtrl->attachSymbol(d_hBar2); + + QPen cursorsLinePen = QPen(QColor(155, 155, 155), 1, Qt::DashLine); + d_hBar1->setPen(cursorsLinePen); + d_hBar2->setPen(cursorsLinePen); + d_vBar1->setPen(cursorsLinePen); + d_vBar2->setPen(cursorsLinePen); + + d_vCursorHandle1->setPen(cursorsLinePen); + d_vCursorHandle2->setPen(cursorsLinePen); + d_hCursorHandle1->setPen(cursorsLinePen); + d_hCursorHandle2->setPen(cursorsLinePen); + + d_vBar1->setVisible(false); + d_vBar2->setVisible(false); + d_hBar1->setVisible(false); + d_hBar2->setVisible(false); + + d_vCursorHandle1->hide(); + d_vCursorHandle2->hide(); + d_hCursorHandle1->hide(); + d_hCursorHandle2->hide(); + + vertCursorsLocked = false; + horizCursorsLocked = false; + + /* When a handle position changes the bar follows */ + connect(d_vCursorHandle1, SIGNAL(positionChanged(int)), + SLOT(onVertCursorHandle1Changed(int))); + connect(d_vCursorHandle2, SIGNAL(positionChanged(int)), + SLOT(onVertCursorHandle2Changed(int))); + connect(d_hCursorHandle1, SIGNAL(positionChanged(int)), + SLOT(onHorizCursorHandle1Changed(int))); + connect(d_hCursorHandle2, SIGNAL(positionChanged(int)), + SLOT(onHorizCursorHandle2Changed(int))); + + /* When bar position changes due to plot resizes update the handle */ + connect(d_hBar1, SIGNAL(pixelPositionChanged(int)), + SLOT(onHbar1PixelPosChanged(int))); + connect(d_hBar2, SIGNAL(pixelPositionChanged(int)), + SLOT(onHbar2PixelPosChanged(int))); + connect(d_vBar1, SIGNAL(pixelPositionChanged(int)), + SLOT(onVbar1PixelPosChanged(int))); + connect(d_vBar2, SIGNAL(pixelPositionChanged(int)), + SLOT(onVbar2PixelPosChanged(int))); +} + +void DisplayPlot::setupReadouts() { + d_cursorReadoutsVisible = false; + + d_cursorReadouts = new CursorReadouts(this); + d_cursorReadouts->setAxis(QwtPlot::xTop,QwtPlot::yLeft); + d_cursorReadouts->setTopLeftStartingPoint(QPoint(8, 8)); + d_cursorReadouts->setTimeReadoutVisible(false); + d_cursorReadouts->setVoltageReadoutVisible(false); + + /* Update Cursor Readouts */ + connect(d_hBar1, SIGNAL(positionChanged(double)), + SLOT(onHCursor1Moved(double))); + connect(d_hBar2, SIGNAL(positionChanged(double)), + SLOT(onHCursor2Moved(double))); + connect(d_vBar1, SIGNAL(positionChanged(double)), + SLOT(onVCursor1Moved(double))); + connect(d_vBar2, SIGNAL(positionChanged(double)), + SLOT(onVCursor2Moved(double))); +} + +void DisplayPlot::onVertCursorHandle1Changed(int value) +{ + if (vertCursorsLocked) { + int position2 = value - (pixelPosHandleVert1 - pixelPosHandleVert2); + pixelPosHandleVert2 = position2; + d_hBar2->setPixelPosition(position2); } + pixelPosHandleVert1 = value; + + d_hBar1->setPixelPosition(value); +} - // delete vertAxes - for (auto it = vertAxes.begin(); it != vertAxes.end(); ++it) { - delete *it; +void DisplayPlot::onVertCursorHandle2Changed(int value) +{ + if (vertCursorsLocked) { + int position1 = value + (pixelPosHandleVert1 - pixelPosHandleVert2); + pixelPosHandleVert1 = position1; + d_hBar1->setPixelPosition(position1); } + pixelPosHandleVert2 = value; + d_hBar2->setPixelPosition(value); +} + - for (auto it = scaleItems.begin(); it != scaleItems.end(); ++it) { - delete *it; +void DisplayPlot::onHorizCursorHandle1Changed(int value) +{ + if (horizCursorsLocked) { + int position2 = value - (pixelPosHandleHoriz1 - pixelPosHandleHoriz2); + pixelPosHandleHoriz2 = position2; + d_vBar2->setPixelPosition(position2); } + pixelPosHandleHoriz1 = value; + d_vBar1->setPixelPosition(value); +} - delete d_grid; +void DisplayPlot::onHorizCursorHandle2Changed(int value) +{ + if (horizCursorsLocked) { + int position1 = value + (pixelPosHandleHoriz1 - pixelPosHandleHoriz2); + pixelPosHandleHoriz1 = position1; + d_vBar1->setPixelPosition(position1); + } + pixelPosHandleHoriz2 = value; + d_vBar2->setPixelPosition(value); +} - //delete horizAxis - delete horizAxis; +VertBar* DisplayPlot::vBar1() +{ + return d_vBar1; +} + +VertBar* DisplayPlot::vBar2() +{ + return d_vBar2; +} + +HorizHandlesArea* DisplayPlot::bottomHandlesArea() +{ + return d_bottomHandlesArea; +} + +QWidget * DisplayPlot::rightHandlesArea() +{ + return d_rightHandlesArea; +} + +QWidget * DisplayPlot::leftHandlesArea() +{ + return d_leftHandlesArea; +} + +QWidget * DisplayPlot::topHandlesArea() +{ + return d_topHandlesArea; +} + +QString DisplayPlot::formatXValue(double value, int precision) const +{ + return d_formatter->format(value, d_xAxisUnit, precision); +} + +QString DisplayPlot::formatYValue(double value, int precision) const +{ + return d_formatter->format(value, d_yAxisUnit, precision); +} + +void DisplayPlot::onHbar1PixelPosChanged(int pos) +{ + d_vCursorHandle1->setPositionSilenty(pos); +} + +void DisplayPlot::onHbar2PixelPosChanged(int pos) +{ + d_vCursorHandle2->setPositionSilenty(pos); +} + +void DisplayPlot::onVbar1PixelPosChanged(int pos) +{ + d_hCursorHandle1->setPositionSilenty(pos); + displayIntersection(); +} + +void DisplayPlot::onVbar2PixelPosChanged(int pos) +{ + d_hCursorHandle2->setPositionSilenty(pos); + displayIntersection(); +} + +struct cursorReadoutsText DisplayPlot::allCursorReadouts() const +{ + return d_cursorReadoutsText; +} + +void DisplayPlot::onVCursor1Moved(double value) +{ + QString text; + + text = d_formatter->format(value, "", 3); + d_cursorReadouts->setTimeCursor1Text(text); + d_cursorReadoutsText.t1 = text; + + double diff = value - d_vBar2->plotCoord().y(); + text = d_formatter->format(diff, "", 3); + d_cursorReadouts->setTimeDeltaText(text); + d_cursorReadoutsText.tDelta = text; + + Q_EMIT cursorReadoutsChanged(d_cursorReadoutsText); +} + +void DisplayPlot::onVCursor2Moved(double value) +{ + QString text; + + text = d_formatter->format(value, "", 3); + d_cursorReadouts->setTimeCursor2Text(text); + d_cursorReadoutsText.t2 = text; + + double diff = d_vBar1->plotCoord().y() - value; + text = d_formatter->format(diff, "", 3); + d_cursorReadouts->setTimeDeltaText(text); + d_cursorReadoutsText.tDelta = text; + + Q_EMIT cursorReadoutsChanged(d_cursorReadoutsText); +} + + +void DisplayPlot::onHCursor1Moved(double value) +{ + QString text; + bool error = false; + + value *= d_displayScale; + text = d_formatter->format(value, "", 3); + d_cursorReadouts->setVoltageCursor1Text(error ? "-" : text); + d_cursorReadoutsText.v1 = error ? "-" : text; + + double valueCursor2 = d_hBar2->plotCoord().x(); + + double diff = value - (valueCursor2 * d_displayScale) ; + text = d_formatter->format(diff, "", 3); + d_cursorReadouts->setVoltageDeltaText(error ? "-" : text); + d_cursorReadoutsText.vDelta = error ? "-" : text; + + Q_EMIT cursorReadoutsChanged(d_cursorReadoutsText); +} + +void DisplayPlot::onHCursor2Moved(double value) +{ + QString text; + bool error = false; + + value *= d_displayScale; + text = d_formatter->format(value, "", 3); + d_cursorReadouts->setVoltageCursor2Text(error ? "-" : text); + d_cursorReadoutsText.v2 = error ? "-" : text; + + double valueCursor1 = d_hBar1->plotCoord().x(); + + double diff = (valueCursor1 * d_displayScale) - value; + text = d_formatter->format(diff, "", 3); + d_cursorReadouts->setVoltageDeltaText(error ? "-" : text); + d_cursorReadoutsText.vDelta = error ? "-" : text; + + Q_EMIT cursorReadoutsChanged(d_cursorReadoutsText); +} + +void DisplayPlot::setVertCursorsEnabled(bool en) +{ + if (d_vertCursorsEnabled != en) { + d_vertCursorsEnabled = en; + d_vBar1->setVisible(en); + d_vBar2->setVisible(en); + d_hCursorHandle1->setVisible(en); + d_hCursorHandle2->setVisible(en); + d_cursorReadouts->setTimeReadoutVisible(en && + d_cursorReadoutsVisible); + } +} + +void DisplayPlot::toggleCursors(bool en) +{ + if (d_cursorsEnabled != en) { + d_cursorsEnabled = en; + d_vBar1->setVisible(en); + d_vBar2->setVisible(en); + + if(d_vertCursorsHandleEnabled) + { + d_hCursorHandle1->setVisible(en); + d_hCursorHandle2->setVisible(en); + } + + d_cursorReadouts->setTimeReadoutVisible(en); + d_cursorReadouts->setVoltageReadoutVisible(en); + + if (en) { + onVCursor1Moved(d_vBar1->plotCoord().x()); + onVCursor2Moved(d_vBar2->plotCoord().x()); + } else { + markerIntersection1->detach(); + markerIntersection2->detach(); + replot(); + } + } +} + +bool DisplayPlot::isLogaritmicPlot() const +{ + return d_isLogaritmicPlot; +} + +void DisplayPlot::setPlotLogaritmic(bool value) +{ + d_isLogaritmicPlot = value; +} + +bool DisplayPlot::isLogaritmicYPlot() const +{ + return d_isLogaritmicYPlot; +} + +void DisplayPlot::setPlotYLogaritmic(bool value) +{ + d_isLogaritmicYPlot = value; +} + +void DisplayPlot::setVertCursorsHandleEnabled(bool en) +{ + d_vertCursorsHandleEnabled = en; +} + +bool DisplayPlot::vertCursorsEnabled() +{ + return d_vertCursorsEnabled; +} + +void DisplayPlot::setHorizCursorsEnabled(bool en) +{ + if (d_horizCursorsEnabled != en) { + d_horizCursorsEnabled = en; + d_hBar1->setVisible(en); + d_hBar2->setVisible(en); + d_vCursorHandle1->setVisible(en); + d_vCursorHandle2->setVisible(en); + d_cursorReadouts->setVoltageReadoutVisible(en && + d_cursorReadoutsVisible); + } +} + +bool DisplayPlot::horizCursorsEnabled() +{ + return d_horizCursorsEnabled; +} + +void DisplayPlot::setCursorReadoutsVisible(bool en) +{ + if (d_cursorReadoutsVisible != en) { + d_cursorReadoutsVisible = en; + d_cursorReadouts->setVoltageReadoutVisible(en && + d_vertCursorsEnabled ); + d_cursorReadouts->setTimeReadoutVisible(en && + d_horizCursorsEnabled ); + } +} + +void DisplayPlot::setHorizCursorsLocked(bool value) +{ + horizCursorsLocked = value; +} + +void DisplayPlot::setVertCursorsLocked(bool value) +{ + vertCursorsLocked = value; +} + +void DisplayPlot::setCursorReadoutsTransparency(int value) +{ + d_cursorReadouts->setTransparency(value); +} + +void DisplayPlot::moveCursorReadouts(CustomPlotPositionButton::ReadoutsPosition position) +{ + d_cursorReadouts->moveToPosition(position); +} + +void DisplayPlot::trackModeEnabled(bool enabled) +{ + d_trackMode = !enabled; + if (d_horizCursorsEnabled) { + d_hBar1->setVisible(enabled); + d_hBar2->setVisible(enabled); + d_vCursorHandle1->setVisible(enabled); + d_vCursorHandle2->setVisible(enabled); + } + if (d_trackMode) { + onVCursor1Moved(d_vBar1->plotCoord().x()); + onVCursor2Moved(d_vBar2->plotCoord().x()); + displayIntersection(); + } else { + onHCursor1Moved(d_hBar1->plotCoord().y()); + onHCursor2Moved(d_hBar2->plotCoord().y()); + markerIntersection1->detach(); + markerIntersection2->detach(); + replot(); + } +} + +void DisplayPlot::displayIntersection() +{ + if (!d_trackMode) { + return; + } + + double intersectionCursor1, intersectionCursor2; + bool attachmk1 = true; + bool attachmk2 = true; + + + intersectionCursor1 = getHorizontalCursorIntersection(d_vBar1->plotCoord().x()); + intersectionCursor2 = getHorizontalCursorIntersection(d_vBar2->plotCoord().x()); + + if (intersectionCursor1 == -1000000){ + attachmk1 = false; + } + if (intersectionCursor2 == -1000000) { + attachmk2 = false; + } + + bool value = isAxisValid(QwtAxisId(QwtPlot::yLeft, d_selected_channel)); + + if(value) + { + markerIntersection1->setAxes(QwtPlot::xBottom, QwtAxisId(QwtPlot::yLeft, d_selected_channel)); + markerIntersection2->setAxes(QwtPlot::xBottom, QwtAxisId(QwtPlot::yLeft, d_selected_channel)); + } + else + { + markerIntersection1->setAxes(QwtPlot::xBottom, QwtAxisId(QwtPlot::yLeft, 0)); + markerIntersection2->setAxes(QwtPlot::xBottom, QwtAxisId(QwtPlot::yLeft, 0)); + } + + markerIntersection1->setValue(d_vBar1->plotCoord().x(), intersectionCursor1); + markerIntersection2->setValue(d_vBar2->plotCoord().x(), intersectionCursor2); + + if (attachmk1) { + markerIntersection1->attach(this); + } else { + markerIntersection1->detach(); + } + if (attachmk2) { + markerIntersection2->attach(this); + } else { + markerIntersection2->detach(); + } + + replot(); +} + +double DisplayPlot::getHorizontalCursorIntersection(double time) +{ + int n = Curve(d_selected_channel)->data()->size(); + + if (n == 0) { + return -1; + } else { + double leftTime, rightTime, leftCustom, rightCustom; + int rightIndex = -1; + int leftIndex = -1; + + int left = 0; + int right = n - 1; + + if (Curve(d_selected_channel)->data()->sample(right).x() < time || + Curve(d_selected_channel)->data()->sample(left).x() > time) { + return -1; + } + + while (left <= right) { + int mid = (left + right) / 2; + double xData = Curve(d_selected_channel)->data()->sample(mid).x(); + if (xData == time) { + if (mid > 0) { + leftIndex = mid - 1; + rightIndex = mid; + } + break; + } else if (xData < time) { + left = mid + 1; + } else { + right = mid - 1; + } + } + + if ((leftIndex == -1 || rightIndex == -1) && left > 0) { + leftIndex = left - 1; + rightIndex = left; + } + + if (leftIndex == -1 || rightIndex == -1) { + return -1; + } + + leftTime = Curve(d_selected_channel)->data()->sample(leftIndex).x(); + rightTime = Curve(d_selected_channel)->data()->sample(rightIndex).x(); + + leftCustom = Curve(d_selected_channel)->data()->sample(leftIndex).y(); + rightCustom = Curve(d_selected_channel)->data()->sample(rightIndex).y(); + + double value = (rightCustom - leftCustom) / (rightTime - leftTime) * + (time - leftTime) + leftCustom; + + return value; + } +} + +void DisplayPlot::repositionCursors() +{ + onVCursor1Moved(d_vBar1->plotCoord().x()); + onVCursor2Moved(d_vBar2->plotCoord().x()); + displayIntersection(); } void @@ -1222,6 +1822,7 @@ void DisplayPlot::bringCurveToFront(unsigned int curveIdx) { DetachCurve(curveIdx); AttachCurve(curveIdx); + displayIntersection(); replot(); } @@ -1555,6 +2156,26 @@ static QwtScaleDiv getEdgelessScaleDiv(const QwtScaleDiv& from_scaleDiv) return QwtScaleDiv(lowerBound, upperBound, minorTicks, mediumTicks, majorTicks); } +void DisplayPlot::setXaxisMajorTicksPos(QList ticks) +{ + d_majorTicks = ticks; +} + +QList DisplayPlot::getXaxisMajorTicksPos() const +{ + return d_majorTicks; +} + +void DisplayPlot::setYaxisMajorTicksPos(QList ticks) +{ + d_majorTicksY = ticks; +} + +QList DisplayPlot::getYaxisMajorTicksPos() const +{ + return d_majorTicksY; +} + unsigned int DisplayPlot::xAxisNumDiv() const { return d_xAxisNumDiv; diff --git a/src/DisplayPlot.h b/src/DisplayPlot.h index 9ad53a588a..91469c15c4 100644 --- a/src/DisplayPlot.h +++ b/src/DisplayPlot.h @@ -65,6 +65,12 @@ #include "plot_utils.hpp" #include "extendingplotzoomer.h" #include "printableplot.h" +#include "symbol_controller.h" +#include "plot_line_handle.h" +#include "cursor_readouts.h" +#include "handles_area.hpp" +#include "plotpickerwrapper.h" +#include typedef QList QColorList; Q_DECLARE_METATYPE ( QColorList ) @@ -215,6 +221,16 @@ public Q_SLOTS: } }; +struct cursorReadoutsText { + QString t1; + QString t2; + QString tDelta; + QString freq; + QString v1; + QString v2; + QString vDelta; +}; + /*! * \brief QWidget base plot to build QTGUI plotting tools. * \ingroup qtgui_blk @@ -284,8 +300,10 @@ class DisplayPlot:public PrintablePlot public: - DisplayPlot(int nplots, QWidget*, unsigned int xNumDivs = 10, - unsigned int yNumDivs = 10); + DisplayPlot(int nplots, QWidget*, + bool isdBgraph = false, + unsigned int xNumDivs = 10, + unsigned int yNumDivs = 10); virtual ~DisplayPlot(); virtual void replot() = 0; @@ -377,16 +395,39 @@ class DisplayPlot:public PrintablePlot QwtPlotZoomer *getZoomer() const; void setZoomerParams(bool bounded, int maxStackDepth); - - void bringCurveToFront(unsigned int curveIdx); void enableColoredLabels(bool colored); void enableMouseGesturesOnScales(bool enable); void setDisplayScale(double value); - void setAllYAxis(double min, double max); + + HorizHandlesArea* bottomHandlesArea(); + QWidget *rightHandlesArea(); + QWidget *leftHandlesArea(); + virtual QWidget *topHandlesArea(); + VertBar* vBar1(); + VertBar* vBar2(); + bool isLogaritmicPlot() const; + void setPlotLogaritmic(bool ); + bool isLogaritmicYPlot() const; + void setPlotYLogaritmic(bool value); + void setXaxisMajorTicksPos(QList); + QList getXaxisMajorTicksPos() const; + void setYaxisMajorTicksPos(QList); + QList getYaxisMajorTicksPos() const; + QWidget* getPlotwithElements(); + + bool vertCursorsEnabled(); + bool horizCursorsEnabled(); + struct cursorReadoutsText allCursorReadouts() const; + void trackModeEnabled(bool enabled); + void repositionCursors(); + void toggleCursors(bool en); + virtual QString formatXValue(double value, int precision) const; + virtual QString formatYValue(double value, int precision) const; + public Q_SLOTS: virtual void disableLegend(); virtual void setYaxis(double min, double max); @@ -498,6 +539,16 @@ public Q_SLOTS: unsigned int xAxisNumDiv() const; unsigned int yAxisNumDiv() const; + void setVertCursorsEnabled(bool en); + void setHorizCursorsEnabled(bool en); + void setVertCursorsHandleEnabled(bool en); + void setCursorReadoutsVisible(bool en); + void setHorizCursorsLocked(bool value); + void setVertCursorsLocked(bool value); + + void setCursorReadoutsTransparency(int value); + void moveCursorReadouts(CustomPlotPositionButton::ReadoutsPosition position); + Q_SIGNALS: void horizScaleDivisionChanged(double); void vertScaleDivisionChanged(double); @@ -509,6 +560,19 @@ public Q_SLOTS: // signals that the plot size changed void plotSizeChanged(); + void cursorReadoutsChanged(struct cursorReadoutsText); + +private Q_SLOTS: + void onHbar1PixelPosChanged(int); + void onHbar2PixelPosChanged(int); + void onVbar1PixelPosChanged(int); + void onVbar2PixelPosChanged(int); + + void onHorizCursorHandle1Changed(int value); + void onVertCursorHandle1Changed(int value); + void onVertCursorHandle2Changed(int value); + void onHorizCursorHandle2Changed(int value); + protected Q_SLOTS: virtual void legendEntryChecked(QwtPlotItem *plotItem, bool on); virtual void legendEntryChecked(const QVariant &plotItem, bool on, int index); @@ -518,6 +582,11 @@ protected Q_SLOTS: void onVertAxisOffsetDecrease(); void onVertAxisOffsetIncrease(); + virtual void onHCursor1Moved(double); + virtual void onHCursor2Moved(double); + virtual void onVCursor1Moved(double); + virtual void onVCursor2Moved(double); + void _onXbottomAxisWidgetScaleDivChanged(); void _onYleftAxisWidgetScaleDivChanged(); @@ -578,11 +647,62 @@ protected Q_SLOTS: void resizeEvent(QResizeEvent *event); + HorizHandlesArea *d_bottomHandlesArea; + VertHandlesArea *d_rightHandlesArea; + VertHandlesArea *d_leftHandlesArea; + HorizHandlesArea *d_topHandlesArea; + + VertBar *d_vBar1; + VertBar *d_vBar2; + HorizBar *d_hBar1; + HorizBar *d_hBar2; + SymbolController *d_symbolCtrl; + + PlotLineHandleV *d_vCursorHandle1; + PlotLineHandleV *d_vCursorHandle2; + PlotLineHandleH *d_hCursorHandle1; + PlotLineHandleH *d_hCursorHandle2; + + struct cursorReadoutsText d_cursorReadoutsText; + CursorReadouts *d_cursorReadouts; + + bool d_trackMode; + int d_selected_channel; + bool d_cursorsEnabled; + + QwtPlotMarker *markerIntersection1; + QwtPlotMarker *markerIntersection2; + + double getHorizontalCursorIntersection(double time); + private: void AddAxisOffset(int axisPos, int axisIdx, double offset); bool d_coloredLabels; bool d_mouseGesturesEnabled; + bool d_vertCursorsHandleEnabled; + bool d_vertCursorsEnabled; + bool d_horizCursorsEnabled; + bool horizCursorsLocked; + bool vertCursorsLocked; + + int pixelPosHandleHoriz1; + int pixelPosHandleHoriz2; + int pixelPosHandleVert1; + int pixelPosHandleVert2; + + bool d_isLogaritmicPlot; + bool d_isLogaritmicYPlot; + QList d_majorTicks; + QList d_majorTicksY; + bool d_cursorReadoutsVisible; + PrefixFormatter * d_formatter; + + void setupCursors(); + void setupReadouts(); + void displayIntersection(); + void setupDisplayPlotDiv(bool isdBgraph); + }; /* diff --git a/src/FftDisplayPlot.cc b/src/FftDisplayPlot.cc index 26497f9ef3..3efe221bf8 100644 --- a/src/FftDisplayPlot.cc +++ b/src/FftDisplayPlot.cc @@ -31,6 +31,8 @@ #include #include +#define ERROR_VALUE -10000000 + using namespace adiscope; class FftDisplayZoomer: public LimitedPlotZoomer @@ -129,6 +131,9 @@ FftDisplayPlot::FftDisplayPlot(int nplots, QWidget *parent) : setAxisScaleDraw(QwtPlot::xBottom, xScaleDraw); xScaleDraw->setFloatPrecision(2); + d_yAxisUnit = "dB"; + d_xAxisUnit = "Hz"; + _resetXAxisPoints(); d_mrkCtrl = new MarkerController(this); @@ -156,6 +161,26 @@ FftDisplayPlot::FftDisplayPlot(int nplots, QWidget *parent) : setMaxYaxisDivision(100); // A maximum division of 100 dB setVertUnitsPerDiv(20); setVertOffset(-VertUnitsPerDiv() * 5); + + setYaxisNumDiv(11); + + d_selected_channel = 0; + + d_topHandlesArea->setMinimumHeight(50); + d_topHandlesArea->setLargestChildWidth(50); + + d_leftHandlesArea->setMinimumWidth(50); + d_leftHandlesArea->setTopPadding(50); + d_leftHandlesArea->setBottomPadding(55); + d_leftHandlesArea->setMinimumHeight(this->minimumHeight()); + + enableAxis(QwtPlot::xBottom, false); + enableAxis(QwtPlot::yLeft, false); + d_formatter = static_cast(new MetricPrefixFormatter); + + setupReadouts(); + + installEventFilter(this); } FftDisplayPlot::~FftDisplayPlot() @@ -182,15 +207,208 @@ FftDisplayPlot::~FftDisplayPlot() } d_refXdata.clear(); d_refYdata.clear(); + removeEventFilter(this); + canvas()->removeEventFilter(d_cursorReadouts); + canvas()->removeEventFilter(d_symbolCtrl); } void FftDisplayPlot::replot() { + if (!d_leftHandlesArea || !d_bottomHandlesArea) { + return; + } + + d_leftHandlesArea->repaint(); + d_bottomHandlesArea->repaint(); + QwtPlot::replot(); } +QString FftDisplayPlot::formatXValue(double value, int precision) const +{ + return d_formatter->format(value, "Hz", precision); +} + +QString FftDisplayPlot::formatYValue(double value, int precision) const +{ + return d_formatter->format(value, "dB", precision); +} + +void FftDisplayPlot::setupReadouts() +{ + d_cursorReadouts->setTimeReadoutVisible(false); + d_cursorReadouts->setVoltageReadoutVisible(false); + + d_cursorReadouts->setTimeCursor1LabelText("F1 = "); + d_cursorReadouts->setTimeCursor2LabelText("F2 = "); + d_cursorReadouts->setTimeDeltaLabelText("ΔF = "); + d_cursorReadouts->setVoltageCursor1LabelText("Mag1 = "); + d_cursorReadouts->setVoltageCursor2LabelText("Mag2 = "); + d_cursorReadouts->setDeltaVoltageLabelText("ΔMag = "); + + d_cursorReadouts->setFrequencyDeltaVisible(false); + d_cursorReadouts->setTransparency(0); +} + +void FftDisplayPlot::updateHandleAreaPadding() +{ + d_leftHandlesArea->repaint(); + d_bottomHandlesArea->setLeftPadding(d_leftHandlesArea->width()); + d_bottomHandlesArea->setRightPadding(50); + + d_rightHandlesArea->setTopPadding(50); + d_rightHandlesArea->setBottomPadding(50); + + //update handle position to avoid cursors getting out of the plot bounds when changing the padding; + d_hCursorHandle1->updatePosition(); + d_hCursorHandle2->updatePosition(); + d_vCursorHandle1->updatePosition(); + d_vCursorHandle2->updatePosition(); +} + +void FftDisplayPlot::onHCursor1Moved(double value) +{ + QString text; + bool error = false; + if (d_trackMode) { + if (value == ERROR_VALUE) { + error = true; + } + } + + value *= d_displayScale; + text = d_formatter->format(value, "dB", 3); + d_cursorReadouts->setVoltageCursor1Text(error ? "-" : text); + d_cursorReadoutsText.t1 = error ? "-" : text; + + double valueCursor2; + if (d_trackMode) { + valueCursor2 = getHorizontalCursorIntersection(d_vBar2->plotCoord().x()); + } else { + valueCursor2 = d_hBar2->plotCoord().y(); + } + + double diff = value - (valueCursor2 * d_displayScale); + text = d_formatter->format(diff, "dB", 3); + d_cursorReadouts->setVoltageDeltaText(error ? "-" : text); + d_cursorReadoutsText.tDelta = error ? "-" : text; + + Q_EMIT cursorReadoutsChanged(d_cursorReadoutsText); +} + +void FftDisplayPlot::onHCursor2Moved(double value) +{ + QString text; + bool error = false; + if (d_trackMode) { + if (value == ERROR_VALUE) { + error = true; + } + } + + value *= d_displayScale; + text = d_formatter->format(value, "dB", 3); + d_cursorReadouts->setVoltageCursor2Text(error ? "-" : text); + d_cursorReadoutsText.t2 = error ? "-" : text; + + double valueCursor1; + if (d_trackMode) { + valueCursor1 = getHorizontalCursorIntersection(d_vBar1->plotCoord().x()); + } else { + valueCursor1 = d_hBar1->plotCoord().y(); + } + + double diff = (valueCursor1 * d_displayScale) - value; + text = d_formatter->format(diff, "dB", 3); + d_cursorReadouts->setVoltageDeltaText(error ? "-" : text); + d_cursorReadoutsText.tDelta = error ? "-" : text; + + Q_EMIT cursorReadoutsChanged(d_cursorReadoutsText); +} + +void FftDisplayPlot::onVCursor1Moved(double value) +{ + QString text; + text = d_formatter->format(value, "Hz", 3); + d_cursorReadouts->setTimeCursor1Text(text); + d_cursorReadoutsText.v1 = text; + + double diff = value - d_vBar2->plotCoord().x(); + text = d_formatter->format(diff, "Hz", 3); + d_cursorReadouts->setTimeDeltaText(text); + d_cursorReadoutsText.vDelta = text; + + if (d_trackMode) { + onHCursor1Moved(getHorizontalCursorIntersection(d_vBar1->plotCoord().x())); + } + + Q_EMIT cursorReadoutsChanged(d_cursorReadoutsText); +} + +void FftDisplayPlot::onVCursor2Moved(double value) +{ + QString text; + text = d_formatter->format(value, "Hz", 3); + d_cursorReadouts->setTimeCursor2Text(text); + d_cursorReadoutsText.v2 = text; + + double diff = d_vBar1->plotCoord().x() - value; + text = d_formatter->format(diff, "Hz", 3); + d_cursorReadouts->setTimeDeltaText(text); + d_cursorReadoutsText.vDelta = text; + + if (d_trackMode) { + onHCursor2Moved(getHorizontalCursorIntersection(d_vBar2->plotCoord().x())); + } + + Q_EMIT cursorReadoutsChanged(d_cursorReadoutsText); +} + +void FftDisplayPlot::enableXaxisLabels() +{ + d_bottomHandlesArea->installExtension(std::unique_ptr(new XBottomRuller(this))); +} + +void FftDisplayPlot::enableYaxisLabels() +{ + d_leftHandlesArea->installExtension(std::unique_ptr(new YLeftRuller(this))); +} + +bool FftDisplayPlot::eventFilter(QObject *object, QEvent *event) +{ + if (object == canvas() && event->type() == QEvent::Resize) { + updateHandleAreaPadding(); + + //force cursor handles to emit position changed + //when the plot canvas is being resized + d_hCursorHandle1->triggerMove(); + d_hCursorHandle2->triggerMove(); + d_vCursorHandle1->triggerMove(); + d_vCursorHandle2->triggerMove(); + + } + return QObject::eventFilter(object, event); +} + +void FftDisplayPlot::showEvent(QShowEvent *event) +{ + d_vCursorHandle1->triggerMove(); + d_vCursorHandle2->triggerMove(); + d_hCursorHandle1->triggerMove(); + d_hCursorHandle2->triggerMove(); +} + +void FftDisplayPlot::setSelectedChannel(int id) +{ + if (d_selected_channel != id) { + d_selected_channel = id; + } +} + void FftDisplayPlot::setZoomerEnabled() { + enableAxis(QwtPlot::xBottom, true); + enableAxis(QwtPlot::yLeft, true); if(!d_zoomer[0]) { d_zoomer[0] = new FftDisplayZoomer(canvas()); @@ -323,37 +541,47 @@ void FftDisplayPlot::setWindowCoefficientSum(unsigned int ch, float sum, float s void FftDisplayPlot::useLogScaleY(bool log_scale) { if (log_scale) { + setPlotYLogaritmic(true); QwtLogScaleEngine *scaleEngine = new QwtLogScaleEngine(); setAxisScaleEngine(QwtPlot::yLeft, (QwtScaleEngine *)scaleEngine); - OscScaleDraw *yScaleDraw = new OscScaleDraw(&dBFormatter, "V/√Hz"); - yScaleDraw->enableComponent(QwtAbstractScaleDraw::Ticks, true); - yScaleDraw->setFloatPrecision(2); - setAxisScaleDraw(QwtPlot::yLeft, yScaleDraw); +// OscScaleDraw *yScaleDraw = new OscScaleDraw(&dBFormatter, "V/√Hz"); +// yScaleDraw->enableComponent(QwtAbstractScaleDraw::Ticks, true); +// yScaleDraw->setFloatPrecision(2); +// setAxisScaleDraw(QwtPlot::yLeft, yScaleDraw); + replot(); + auto div = axisScaleDiv(QwtPlot::yLeft); + setYaxisMajorTicksPos(div.ticks(2)); } else { + setPlotYLogaritmic(false); OscScaleEngine *scaleEngine = new OscScaleEngine(); this->setAxisScaleEngine(QwtPlot::yLeft, (QwtScaleEngine *)scaleEngine); - OscScaleDraw *yScaleDraw = new OscScaleDraw(&dBFormatter, ""); - yScaleDraw->setFloatPrecision(2); - setAxisScaleDraw(QwtPlot::yLeft, yScaleDraw); +// OscScaleDraw *yScaleDraw = new OscScaleDraw(&dBFormatter, ""); +// yScaleDraw->setFloatPrecision(2); +// setAxisScaleDraw(QwtPlot::yLeft, yScaleDraw); + replot(); + auto div = axisScaleDiv(QwtPlot::yLeft); + setYaxisNumDiv((div.ticks(2)).size()); } + replot(); } void FftDisplayPlot::useLogFreq(bool use_log_freq) { if (use_log_freq) { + setPlotLogaritmic(true); setAxisScaleEngine(QwtPlot::xBottom, new QwtLogScaleEngine); - OscScaleDraw *xScaleDraw = new OscScaleDraw(&freqFormatter, "Hz"); - setAxisScaleDraw(QwtPlot::xBottom, xScaleDraw); - xScaleDraw->setFloatPrecision(2); + replot(); + auto div = axisScaleDiv(QwtPlot::xBottom); + setXaxisMajorTicksPos(div.ticks(2)); } else { + setPlotLogaritmic(false); OscScaleEngine *scaleEngine = new OscScaleEngine(); this->setAxisScaleEngine(QwtPlot::xBottom, (QwtScaleEngine *)scaleEngine); - OscScaleDraw *xScaleDraw = new OscScaleDraw(&freqFormatter, "Hz"); - setAxisScaleDraw(QwtPlot::xBottom, xScaleDraw); - xScaleDraw->setFloatPrecision(2); + replot(); + auto div = axisScaleDiv(QwtPlot::xBottom); + setXaxisNumDiv((div.ticks(2)).size() - 1); } - d_logScaleEnabled = use_log_freq; replot(); } @@ -1257,6 +1485,9 @@ void FftDisplayPlot::setStartStop(double start, double stop) { m_sweepStart = start; m_sweepStop = stop; + auto div = axisScaleDiv(QwtPlot::xBottom); + setXaxisNumDiv((div.ticks(2)).size() - 1); + setXaxisMajorTicksPos(div.ticks(2)); } void FftDisplayPlot::setVisiblePeakSearch(bool enabled) diff --git a/src/FftDisplayPlot.h b/src/FftDisplayPlot.h index 8a1326a906..ce22535760 100644 --- a/src/FftDisplayPlot.h +++ b/src/FftDisplayPlot.h @@ -23,6 +23,10 @@ #include "DisplayPlot.h" #include "spectrum_marker.hpp" +#include "symbol_controller.h" +#include "plot_line_handle.h" +#include "handles_area.hpp" +#include "cursor_readouts.h" #include namespace adiscope { @@ -50,6 +54,7 @@ namespace adiscope { class FftDisplayPlot : public DisplayPlot { + friend class SpectrumAnalyzer_API; Q_OBJECT public: @@ -82,6 +87,7 @@ namespace adiscope { }; typedef boost::shared_ptr average_sptr; + private: QList> d_markers; double* x_data; @@ -104,6 +110,7 @@ namespace adiscope { MetricPrefixFormatter dBFormatter; MetricPrefixFormatter freqFormatter; + PrefixFormatter *d_formatter; std::vector d_ch_average_type; std::vector d_ch_avg_obj; @@ -132,6 +139,8 @@ namespace adiscope { unsigned int d_nb_overlapping_avg; std::vector> d_ps_avg; + void setupReadouts(); + void updateHandleAreaPadding(); void plotData(const std::vector &pts, uint64_t num_points); @@ -162,6 +171,10 @@ namespace adiscope { void onMrkCtrlMarkerPosChanged(std::shared_ptr &); void onMrkCtrlMarkerReleased(std::shared_ptr &); + void onHCursor1Moved(double); + void onHCursor2Moved(double); + void onVCursor1Moved(double); + void onVCursor2Moved(double); public: explicit FftDisplayPlot(int nplots, QWidget *parent = nullptr); ~FftDisplayPlot(); @@ -228,6 +241,13 @@ namespace adiscope { void setWindowCoefficientSum(unsigned int ch, float sum, float sqr_sum); void setNbOverlappingAverages(unsigned int nb_avg); void useLogScaleY(bool log_scale); + + bool eventFilter(QObject *, QEvent *); + void enableXaxisLabels(); + void enableYaxisLabels(); + QString formatXValue(double value, int precision) const; + QString formatYValue(double value, int precision) const; + Q_SIGNALS: void newData(); void sampleRateUpdated(double); @@ -242,7 +262,9 @@ namespace adiscope { void presetSampleRate(double sr); void useLogFreq(bool use_log_freq); void customEvent(QEvent *e); + void showEvent(QShowEvent *event); bool getLogScale() const; + void setSelectedChannel(int id); }; } diff --git a/src/HistogramDisplayPlot.cc b/src/HistogramDisplayPlot.cc index eac659c061..4b5024f5aa 100644 --- a/src/HistogramDisplayPlot.cc +++ b/src/HistogramDisplayPlot.cc @@ -332,7 +332,7 @@ HistogramDisplayPlot::HistogramDisplayPlot(int nplots, QWidget* parent) insertLegend(nullptr); d_grid->detach(); - for(QwtPlotScaleItem* scale : scaleItems){ + for(QwtPlotScaleItem* scale : qAsConst(scaleItems)){ scale->detach(); } } @@ -353,12 +353,12 @@ void HistogramDisplayPlot::setOrientation(Qt::Orientation orientation) if (orientation == Qt::Vertical) { d_grid->attach(this); - for(QwtPlotScaleItem* scale : scaleItems){ + for(QwtPlotScaleItem* scale : qAsConst(scaleItems)){ scale->attach(this); } } else { d_grid->detach(); - for(QwtPlotScaleItem* scale : scaleItems){ + for(QwtPlotScaleItem* scale : qAsConst(scaleItems)){ scale->detach(); } } diff --git a/src/TimeDomainDisplayPlot.cc b/src/TimeDomainDisplayPlot.cc index f2212fb63d..0f030cdfe8 100644 --- a/src/TimeDomainDisplayPlot.cc +++ b/src/TimeDomainDisplayPlot.cc @@ -171,8 +171,8 @@ int SinkManager::sinkFirstChannelPos(const std::string& name) /*********************************************************************** * Main Time domain plotter widget **********************************************************************/ -TimeDomainDisplayPlot::TimeDomainDisplayPlot(QWidget* parent, unsigned int xNumDivs, unsigned int yNumDivs) - : DisplayPlot(0, parent, xNumDivs, yNumDivs) +TimeDomainDisplayPlot::TimeDomainDisplayPlot(QWidget* parent, bool isdBgraph, unsigned int xNumDivs, unsigned int yNumDivs) + : DisplayPlot(0, parent, isdBgraph, xNumDivs, yNumDivs) { d_tag_text_color = Qt::black; d_tag_background_color = Qt::white; diff --git a/src/TimeDomainDisplayPlot.h b/src/TimeDomainDisplayPlot.h index d8549efbaf..02eb47c228 100644 --- a/src/TimeDomainDisplayPlot.h +++ b/src/TimeDomainDisplayPlot.h @@ -100,7 +100,7 @@ class TimeDomainDisplayPlot: public DisplayPlot Q_PROPERTY ( Qt::BrushStyle tag_background_style READ getTagBackgroundStyle WRITE setTagBackgroundStyle ) public: - TimeDomainDisplayPlot(QWidget*, unsigned int xNumDivs = 10, unsigned int yNumDivs = 10); + TimeDomainDisplayPlot(QWidget*, bool isdBgraph = false, unsigned int xNumDivs = 10, unsigned int yNumDivs = 10); virtual ~TimeDomainDisplayPlot(); void plotNewData(const std::string &sender, diff --git a/src/connectDialog.cpp b/src/connectDialog.cpp index 973ba45d71..bf811760cb 100644 --- a/src/connectDialog.cpp +++ b/src/connectDialog.cpp @@ -71,7 +71,7 @@ QString ConnectDialog::URIstringParser(QString uri) }; bool prependIP = true; - for( auto pre:prefixes) + for( const auto &pre:prefixes) { if(uri.startsWith(pre) == true) prependIP = false; diff --git a/src/cursor_readouts.cpp b/src/cursor_readouts.cpp index 2a18d65ba9..e9945679b7 100644 --- a/src/cursor_readouts.cpp +++ b/src/cursor_readouts.cpp @@ -36,6 +36,7 @@ CursorReadouts::CursorReadouts(QwtPlot *plot): ui(new Ui::CursorReadouts), d_voltage_rd_visible(true), d_time_rd_visible(true), + freq_delta_visible(true), d_topLeft(QPoint(0, 0)), currentPosition(CustomPlotPositionButton::topLeft), hAxis(QwtPlot::xBottom), @@ -247,6 +248,7 @@ void CursorReadouts::setTimeDeltaVisible(bool visible){ void CursorReadouts::setFrequencyDeltaVisible(bool visible){ ui->frequencyDeltaLabel->setVisible(visible); ui->frequencyDelta->setVisible(visible); + freq_delta_visible = visible; } void CursorReadouts::setTimeCursor1LabelText(const QString &text){ @@ -265,6 +267,10 @@ QString CursorReadouts::timeCursor2LabelText(){ return ui->cursorT2label->text(); } +void CursorReadouts::setTimeDeltaLabelText(const QString &text){ + ui->timeDeltaLabel->setText(text); +} + void CursorReadouts::setVoltageCursor1LabelText(const QString &text){ ui->cursorV1label->setText(text); } @@ -391,11 +397,11 @@ void CursorReadouts::moveTopRight(bool resize) QRect timeRect, voltageRect; if (d_time_rd_visible && !d_voltage_rd_visible) { - voltageRect = QRect(0,0,0,0); - timeRect = QRect(d_topLeft.x() - ui->TimeCursors->width(),d_topLeft.y(),d_topLeft.x(),d_topLeft.y()+ui->TimeCursors->height()); + voltageRect = QRect(0,0,0,0); + timeRect = QRect(d_topLeft.x() - ui->TimeCursors->width(),d_topLeft.y(),d_topLeft.x(),d_topLeft.y()+ui->TimeCursors->height()); } else { - voltageRect = QRect(d_topLeft.x() - ui->VoltageCursors->width(),d_topLeft.y(),d_topLeft.x(),d_topLeft.y()+ui->VoltageCursors->height()); - timeRect = QRect(voltageRect.x()-ui->TimeCursors->width(),d_topLeft.y(),voltageRect.x(),d_topLeft.y()+ui->VoltageCursors->height()); + voltageRect = QRect(d_topLeft.x() - ui->VoltageCursors->width(),d_topLeft.y(),d_topLeft.x(),d_topLeft.y()+ui->VoltageCursors->height()); + timeRect = QRect(voltageRect.x()-ui->TimeCursors->width(),d_topLeft.y(),voltageRect.x(),d_topLeft.y()+ui->VoltageCursors->height()); } @@ -426,16 +432,26 @@ void CursorReadouts::moveBottomLeft(bool resize) QRect timeRect, voltageRect; - d_topLeft.setY(plot()->height()-8); - d_topLeft.setX(8); + int value = plot()->canvas()->height()-8; + d_topLeft.setY(value); + d_topLeft.setX(8); + + if(freq_delta_visible) + { + if (!d_time_rd_visible && d_voltage_rd_visible) { + voltageRect = QRect(QPoint(d_topLeft.x(),d_topLeft.y()-ui->VoltageCursors->height()-20), QPoint(d_topLeft.x()+ui->VoltageCursors->width(),d_topLeft.y())); + timeRect = QRect(0,0,0,0); + } else { + timeRect = QRect(QPoint(d_topLeft.x(),d_topLeft.y()-ui->TimeCursors->height()-20), QPoint(ui->TimeCursors->width()+d_topLeft.x(),d_topLeft.y())); + voltageRect = QRect(QPoint(d_topLeft.x()+timeRect.width(),d_topLeft.y()-ui->VoltageCursors->height()-20), QPoint(d_topLeft.x()+timeRect.width()+ui->VoltageCursors->width(),d_topLeft.y())); + } + } + else + { + timeRect = QRect(QPoint(d_topLeft.x(),d_topLeft.y()-ui->TimeCursors->height()+5), QPoint(ui->TimeCursors->width()+d_topLeft.x(),d_topLeft.y())); + voltageRect = QRect(QPoint(d_topLeft.x()+timeRect.width(),d_topLeft.y()-ui->VoltageCursors->height()+5), QPoint(d_topLeft.x()+timeRect.width()+ui->VoltageCursors->width(),d_topLeft.y())); + } - if (!d_time_rd_visible && d_voltage_rd_visible) { - voltageRect = QRect(QPoint(d_topLeft.x(),d_topLeft.y()-ui->VoltageCursors->height()-20), QPoint(d_topLeft.x()+ui->VoltageCursors->width(),d_topLeft.y())); - timeRect = QRect(0,0,0,0); - } else { - timeRect = QRect(QPoint(d_topLeft.x(),d_topLeft.y()-ui->TimeCursors->height()-20), QPoint(ui->TimeCursors->width()+d_topLeft.x(),d_topLeft.y())); - voltageRect = QRect(QPoint(d_topLeft.x()+timeRect.width(),d_topLeft.y()-ui->VoltageCursors->height()-20), QPoint(d_topLeft.x()+timeRect.width()+ui->VoltageCursors->width(),d_topLeft.y())); - } int diff = voltageRect.x() - lastVoltageRect.x(); if (diff < 10 && diff > -10) diff = voltageRect.y() - lastVoltageRect.y(); @@ -464,17 +480,24 @@ void CursorReadouts::moveBottomRight(bool resize) QRect timeRect, voltageRect; - d_topLeft.setY(plot()->height()-8); - d_topLeft.setX(plot()->canvas()->width()-8); - - if (d_time_rd_visible && !d_voltage_rd_visible) { - voltageRect = QRect(0,0,0,0); - timeRect = QRect(d_topLeft.x() - ui->TimeCursors->width(),d_topLeft.y()-ui->TimeCursors->height()-20,d_topLeft.x(),d_topLeft.y()); - } else { - voltageRect = QRect(d_topLeft.x() - ui->VoltageCursors->width(),d_topLeft.y()-ui->VoltageCursors->height()-20,d_topLeft.x(),d_topLeft.y()); - timeRect = QRect(voltageRect.x()-ui->TimeCursors->width(),voltageRect.y(),voltageRect.x(),voltageRect.y()+ui->TimeCursors->height()); - - } + d_topLeft.setY(plot()->canvas()->height()-8); + d_topLeft.setX(plot()->canvas()->width()-8); + + if(freq_delta_visible) + { + if (d_time_rd_visible && !d_voltage_rd_visible) { + voltageRect = QRect(0,0,0,0); + timeRect = QRect(d_topLeft.x() - ui->TimeCursors->width(),d_topLeft.y()-ui->TimeCursors->height()-20,d_topLeft.x(),d_topLeft.y()); + } else { + voltageRect = QRect(d_topLeft.x() - ui->VoltageCursors->width(),d_topLeft.y()-ui->VoltageCursors->height()-20,d_topLeft.x(),d_topLeft.y()); + timeRect = QRect(voltageRect.x()-ui->TimeCursors->width(),voltageRect.y(),voltageRect.x(),voltageRect.y()+ui->TimeCursors->height()); + } + } + else + { + voltageRect = QRect(d_topLeft.x() - ui->VoltageCursors->width(),d_topLeft.y()-ui->VoltageCursors->height()+5,d_topLeft.x(),d_topLeft.y()); + timeRect = QRect(voltageRect.x()-ui->TimeCursors->width(),voltageRect.y(),voltageRect.x(),voltageRect.y()+ui->TimeCursors->height()+5); + } int diff = timeRect.x() - lastTimeRect.x(); if (diff < 10 && diff > -10) diff = timeRect.y() - lastTimeRect.y(); diff --git a/src/cursor_readouts.h b/src/cursor_readouts.h index 21d76b77b2..c462a2ca52 100644 --- a/src/cursor_readouts.h +++ b/src/cursor_readouts.h @@ -66,19 +66,20 @@ namespace adiscope { QString voltageCursor2Text(); void setVoltageDeltaText(const QString &); QString voltageDeltaText(); - void setTimeDeltaVisible(bool); - void setFrequencyDeltaVisible(bool); - void setTimeCursor1LabelText(const QString &); - QString timeCursor1LabelText(); - void setTimeCursor2LabelText(const QString &); - QString timeCursor2LabelText(); - void setVoltageCursor1LabelText(const QString &); - QString voltageCursor1LabelText(); - void setVoltageCursor2LabelText(const QString &); - QString voltageCursor2LabelText(); - void setDeltaVoltageLabelText(const QString &); - QString deltaVoltageLabelText(); - void setAxis(QwtAxisId hAxis,QwtAxisId vAxis); + void setTimeDeltaVisible(bool); + void setFrequencyDeltaVisible(bool); + void setTimeCursor1LabelText(const QString &); + QString timeCursor1LabelText(); + void setTimeCursor2LabelText(const QString &); + QString timeCursor2LabelText(); + void setTimeDeltaLabelText(const QString &text); + void setVoltageCursor1LabelText(const QString &); + QString voltageCursor1LabelText(); + void setVoltageCursor2LabelText(const QString &); + QString voltageCursor2LabelText(); + void setDeltaVoltageLabelText(const QString &); + QString deltaVoltageLabelText(); + void setAxis(QwtAxisId hAxis,QwtAxisId vAxis); virtual bool eventFilter(QObject *, QEvent *); void setTransparency(int value); @@ -94,6 +95,7 @@ namespace adiscope { Ui::CursorReadouts *ui; bool d_voltage_rd_visible; bool d_time_rd_visible; + bool freq_delta_visible; QPoint d_topLeft; void moveTopLeft(bool resize = false); void moveTopRight(bool resize = false); @@ -102,7 +104,7 @@ namespace adiscope { CustomPlotPositionButton::ReadoutsPosition currentPosition; CustomAnimation *anim, *anim2; QRect lastTimeRect, lastVoltageRect; - QwtAxisId hAxis,vAxis; + QwtAxisId hAxis,vAxis; }; } diff --git a/src/db_click_buttons.cpp b/src/db_click_buttons.cpp index cedbfbe610..1064723ba7 100644 --- a/src/db_click_buttons.cpp +++ b/src/db_click_buttons.cpp @@ -47,7 +47,7 @@ DbClickButtons::DbClickButtons(QWidget *parent, int maxRowBtnCount) : btn_list = findChildren(); int n = 0; - for (const auto& i : btn_list) { + for (const auto& i : qAsConst(btn_list)) { btn_states.push_back(false); i->setProperty("id", QVariant(n++)); connect(i, SIGNAL(clicked()), diff --git a/src/dbgraph.cpp b/src/dbgraph.cpp index 0a9f6d06d6..fed6611956 100644 --- a/src/dbgraph.cpp +++ b/src/dbgraph.cpp @@ -29,27 +29,16 @@ using namespace adiscope; -void dBgraph::setupCursors() +void dBgraph::setupVerticalBars() { - d_symbolCtrl = new SymbolController(this); - - d_vBar1 = new VertBar(this,true); - d_vBar2 = new VertBar(this,true); d_plotBar = new VertBar(this, true); d_frequencyBar = new VertBar(this, true); - d_symbolCtrl->attachSymbol(d_vBar1); - d_symbolCtrl->attachSymbol(d_vBar2); d_symbolCtrl->attachSymbol(d_plotBar); d_symbolCtrl->attachSymbol(d_frequencyBar); - QPen cursorsLinePen = QPen(QColor(155,155,155),1,Qt::DashLine); QPen plotLinePen = QPen(QColor(211, 211, 211, 50), 5, Qt::SolidLine); QPen frequencyLinePen = QPen(QColor(74, 100, 255, 150), 2, Qt::DashLine); - d_vBar1->setPen(cursorsLinePen); - d_vBar2->setPen(cursorsLinePen); - d_vBar1->setVisible(false); - d_vBar2->setVisible(false); d_plotBar->setVisible(false); d_frequencyBar->setPen(frequencyLinePen); @@ -60,55 +49,33 @@ void dBgraph::setupCursors() d_plotBar->setPen(plotLinePen); d_plotBar->setMobileAxis(QwtPlot::xTop); - connect(d_vBar1, SIGNAL(pixelPositionChanged(int)), - SLOT(onVbar1PixelPosChanged(int))); - connect(d_vBar1, SIGNAL(pixelPositionChanged(int)), - SLOT(onCursor1Moved(int))); - - connect(d_vBar2, SIGNAL(pixelPositionChanged(int)), - SLOT(onVbar2PixelPosChanged(int))); - connect(d_vBar2, SIGNAL(pixelPositionChanged(int)), - SLOT(onCursor2Moved(int))); - connect(d_frequencyBar, &VertBar::pixelPositionChanged, this, &dBgraph::frequencyBarPositionChanged); -} -void dBgraph::parametersOverrange(bool enable) -{ - if (enable) { - d_plotBar->setPen(QPen(QColor(250, 0, 0, 50), 5, Qt::SolidLine)); - } else { - d_plotBar->setPen(QPen(QColor(211, 211, 211, 50), 5, Qt::SolidLine)); - } + d_vBar1->setMobileAxis(QwtPlot::xTop); + d_vBar2->setMobileAxis(QwtPlot::xTop); } void dBgraph::setupReadouts() { - d_cursorReadouts = new CursorReadouts(this); - d_cursorReadouts->setAxis(QwtPlot::xTop,QwtPlot::yLeft); - d_cursorReadouts->setTopLeftStartingPoint(QPoint(8, 8)); - d_cursorReadouts->moveToPosition(CustomPlotPositionButton::topLeft); - d_cursorReadouts->setTimeReadoutVisible(false); d_cursorReadouts->setVoltageReadoutVisible(false); - d_cursorReadouts->setTimeCursor1LabelText("F1= "); - d_cursorReadouts->setTimeCursor2LabelText("F2= "); - d_cursorReadouts->setVoltageCursor1LabelText("Mag1= "); - d_cursorReadouts->setVoltageCursor2LabelText("Mag2= "); - d_cursorReadouts->setDeltaVoltageLabelText("ΔMag= "); + d_cursorReadouts->setTimeCursor1LabelText("F1 = "); + d_cursorReadouts->setTimeCursor2LabelText("F2 = "); + d_cursorReadouts->setVoltageCursor1LabelText("Mag1 = "); + d_cursorReadouts->setVoltageCursor2LabelText("Mag2 = "); + d_cursorReadouts->setDeltaVoltageLabelText("ΔMag = "); d_cursorReadouts->setFrequencyDeltaVisible(false); d_cursorReadouts->setTimeDeltaVisible(false); d_cursorReadouts->setTransparency(0); } -dBgraph::dBgraph(QWidget *parent) : QwtPlot(parent), +dBgraph::dBgraph(QWidget *parent, bool isdBgraph) + : DisplayPlot(0, parent, isdBgraph), curve("data"), reference("reference"), - d_cursorsCentered(false), - d_cursorsEnabled(false), xmin(10), xmax(10), ymin(10), @@ -133,6 +100,7 @@ dBgraph::dBgraph(QWidget *parent) : QwtPlot(parent), EdgelessPlotGrid *grid = new EdgelessPlotGrid; grid->setMajorPen(plotColor, 1.0, Qt::DashLine); + grid->setXAxis(QwtPlot::xTop); grid->attach(this); @@ -150,14 +118,16 @@ dBgraph::dBgraph(QWidget *parent) : QwtPlot(parent), thickness = 1; + d_formatter = static_cast(new MetricPrefixFormatter); + OscScaleEngine *scaleLeft = new OscScaleEngine; + setYaxisNumDiv(7); scaleLeft->setMajorTicksCount(7); this->setAxisScaleEngine(QwtPlot::yLeft, static_cast(scaleLeft)); - /* draw_x / draw_y: Outmost X / Y scales. Only draw the labels */ - formatter = static_cast(new MetricPrefixFormatter); - draw_x = new OscScaleDraw(formatter, "Hz"); + + draw_x = new OscScaleDraw(d_formatter, "Hz"); draw_x->setFloatPrecision(2); draw_x->enableComponent(QwtAbstractScaleDraw::Ticks, false); draw_x->enableComponent(QwtAbstractScaleDraw::Backbone, false); @@ -170,15 +140,27 @@ dBgraph::dBgraph(QWidget *parent) : QwtPlot(parent), draw_y->setMinimumExtent(50); setAxisScaleDraw(QwtPlot::yLeft, draw_y); + d_leftHandlesArea->setMinimumWidth(60); + d_leftHandlesArea->setTopPadding(10); + d_leftHandlesArea->setBottomPadding(0); + d_leftHandlesArea->setMinimumHeight(this->minimumHeight()); + + d_rightHandlesArea->setMinimumWidth(40); + d_rightHandlesArea->setMinimumHeight(this->minimumHeight()); + + + d_topHandlesArea->setMinimumHeight(20); + d_topHandlesArea->setLargestChildWidth(60); + useLogFreq(false); /* Create 4 scales within the plot itself. Only draw the ticks */ for (unsigned int i = 0; i < 4; i++) { EdgelessPlotScaleItem *scaleItem = new EdgelessPlotScaleItem( - static_cast(i)); + static_cast(i)); /* Top/bottom scales must be sync'd to xTop; left/right scales - * must be sync'd to yLeft */ + * must be sync'd to yLeft */ if (i < 2) { scaleItem->setXAxis(QwtPlot::xTop); } else { @@ -186,13 +168,13 @@ dBgraph::dBgraph(QWidget *parent) : QwtPlot(parent), } scaleItem->scaleDraw()->enableComponent( - QwtAbstractScaleDraw::Backbone, false); + QwtAbstractScaleDraw::Backbone, false); scaleItem->scaleDraw()->enableComponent( - QwtAbstractScaleDraw::Labels, false); + QwtAbstractScaleDraw::Labels, false); QPalette palette = scaleItem->palette(); - palette.setBrush(QPalette::Foreground, plotColor); - palette.setBrush(QPalette::Text, plotColor); + palette.setBrush(QPalette::Foreground, QColor(plotColor)); + palette.setBrush(QPalette::Text, QColor(plotColor)); scaleItem->setPalette(palette); scaleItem->setBorderDistance(0); scaleItem->attach(this); @@ -204,49 +186,65 @@ dBgraph::dBgraph(QWidget *parent) : QwtPlot(parent), zoomer->setMousePattern(QwtEventPattern::MouseSelect2, Qt::RightButton, Qt::ControlModifier); + installEventFilter(this); + static_cast(canvas())->setLineWidth(0); setContentsMargins(10, 10, 24, 20); - - picker = new PlotPickerWrapper(QwtPlot::xTop,QwtPlot::yLeft,this->canvas()); - QMargins margins = contentsMargins(); margins.setBottom(0); setContentsMargins(margins); + enableAxis(QwtPlot::yLeft, false); + enableAxis(QwtPlot::xTop, false); + QwtScaleWidget *scaleWidget = axisWidget(QwtPlot::xTop); - const int fmw = QFontMetrics(scaleWidget->font()).width("XXXX.XX XX"); + const int fmw = QFontMetrics(scaleWidget->font()).width("-XXXX.XX XX"); scaleWidget->setMinBorderDist(fmw / 2, fmw / 2); - markerIntersection1 = new QwtPlotMarker(); - markerIntersection2 = new QwtPlotMarker(); - markerIntersection1->setSymbol(new QwtSymbol( - QwtSymbol::Ellipse, QColor(237, 28, 36), - QPen(QColor(255, 255,255, 140), 2, Qt::SolidLine), - QSize(5, 5))); - markerIntersection2->setSymbol(new QwtSymbol( - QwtSymbol::Ellipse, QColor(237, 28, 36), - QPen(QColor(255, 255,255, 140), 2, Qt::SolidLine), - QSize(5, 5))); + setupVerticalBars(); + setupReadouts(); markerIntersection1->setAxes(QwtPlot::xTop, QwtPlot::yLeft); markerIntersection2->setAxes(QwtPlot::xTop, QwtPlot::yLeft); - - setupCursors(); - - setupReadouts(); - } dBgraph::~dBgraph() { - markerIntersection1->detach(); - markerIntersection2->detach(); canvas()->removeEventFilter(d_cursorReadouts); canvas()->removeEventFilter(d_symbolCtrl); - delete markerIntersection1; - delete markerIntersection2; - delete formatter; - delete picker; + delete d_formatter; +} + +void dBgraph::replot() +{ + if (!d_leftHandlesArea || !d_topHandlesArea) { + return; + } + + d_leftHandlesArea->repaint(); + d_topHandlesArea->repaint(); + + QwtPlot::replot(); +} + +void dBgraph::enableXaxisLabels() +{ + d_topHandlesArea->installExtension(std::unique_ptr(new XTopRuller(this))); +} + + +void dBgraph::enableYaxisLabels() +{ + d_leftHandlesArea->installExtension(std::unique_ptr(new YLeftRuller(this))); +} + +void dBgraph::parametersOverrange(bool enable) +{ + if (enable) { + d_plotBar->setPen(QPen(QColor(250, 0, 0, 50), 5, Qt::SolidLine)); + } else { + d_plotBar->setPen(QPen(QColor(211, 211, 211, 50), 5, Qt::SolidLine)); + } } void dBgraph::setAxesScales(double xmin, double xmax, double ymin, double ymax) @@ -298,13 +296,25 @@ void dBgraph::plot(double x, double y) curve.setRawSamples(xdata.data(), ydata.data(), xdata.size()); if (d_cursorsEnabled) { - onCursor1Moved(d_vBar1->transform(d_vBar1->plotCoord()).x()); - onCursor2Moved(d_vBar2->transform(d_vBar2->plotCoord()).x()); + onVCursor1Moved(d_vBar1->plotCoord().x()); + onVCursor2Moved(d_vBar2->plotCoord().x()); } - replot(); } +bool dBgraph::eventFilter(QObject *object, QEvent *event) +{ + if (object == canvas() && event->type() == QEvent::Resize) + { + + d_leftHandlesArea->repaint(); + d_bottomHandlesArea->setLeftPadding(d_leftHandlesArea->width() + 10); + d_bottomHandlesArea->setRightPadding(d_rightHandlesArea->width() + 24); + + } + return QObject::eventFilter(object, event); +} + int dBgraph::getNumSamples() const { return numSamples; @@ -313,22 +323,22 @@ int dBgraph::getNumSamples() const QString dBgraph::getScaleValueFormat(double value, QwtAxisId scale) const { auto *scaleDraw = static_cast( - axisScaleDraw(scale)); + axisScaleDraw(scale)); - return formatter->format(value, - scaleDraw->getUnitType(), - scaleDraw->getFloatPrecison()); + return d_formatter->format(value, + scaleDraw->getUnitType(), + scaleDraw->getFloatPrecison()); } QString dBgraph::getScaleValueFormat(double value, QwtAxisId scale, int precision) const { auto *scaleDraw = static_cast( - axisScaleDraw(scale)); + axisScaleDraw(scale)); - return formatter->format(value, - scaleDraw->getUnitType(), - precision); + return d_formatter->format(value, + scaleDraw->getUnitType(), + precision); } void dBgraph::setShowZero(bool en) @@ -365,8 +375,6 @@ void dBgraph::reset() { xdata.clear(); ydata.clear(); - markerIntersection1->detach(); - markerIntersection2->detach(); d_plotPosition = 0; } @@ -422,9 +430,9 @@ void dBgraph::setYTitle(const QString& title) yTitle.setFont(font); setAxisTitle(QwtPlot::yLeft, yTitle); - d_cursorReadouts->setVoltageCursor1LabelText(title.mid(0,3)+"1= "); - d_cursorReadouts->setVoltageCursor2LabelText(title.mid(0,3)+"2= "); - d_cursorReadouts->setDeltaVoltageLabelText("Δ"+title.mid(0,3)+"= "); + d_cursorReadouts->setVoltageCursor1LabelText(title.mid(0,3)+"1 = "); + d_cursorReadouts->setVoltageCursor2LabelText(title.mid(0,3)+"2 = "); + d_cursorReadouts->setDeltaVoltageLabelText("Δ"+title.mid(0,3)+" = "); } void dBgraph::setXMin(double val) @@ -436,6 +444,9 @@ void dBgraph::setXMin(double val) zoomer->setZoomBase(); replot(); + auto div = axisScaleDiv(QwtPlot::xTop); + setXaxisNumDiv((div.ticks(2)).size() - 1); + setXaxisMajorTicksPos(div.ticks(2)); } void dBgraph::setXMax(double val) @@ -447,6 +458,9 @@ void dBgraph::setXMax(double val) zoomer->setZoomBase(); replot(); + auto div = axisScaleDiv(QwtPlot::xTop); + setXaxisNumDiv((div.ticks(2)).size() - 1); + setXaxisMajorTicksPos(div.ticks(2)); } void dBgraph::setYMin(double val) @@ -454,6 +468,8 @@ void dBgraph::setYMin(double val) setAxisScale(QwtPlot::yLeft, val, ymax); ymin = val; replot(); + d_leftHandlesArea->repaint(); + d_topHandlesArea->repaint(); double width = xmax - xmin; double height = ymax - ymin; @@ -473,16 +489,16 @@ void dBgraph::setYMax(double val) QString dBgraph::xUnit() const { - return draw_x->getUnitType(); + return draw_x->getUnitType();; } QString dBgraph::yUnit() const { - return draw_y->getUnitType(); + return draw_y->getUnitType();; } void dBgraph::setXUnit(const QString& unit) -{ +{ draw_x->setUnitType(unit); } @@ -494,18 +510,25 @@ void dBgraph::setYUnit(const QString& unit) void dBgraph::useLogFreq(bool use_log_freq) { if (use_log_freq) { + setPlotLogaritmic(true); this->setAxisScaleEngine(QwtPlot::xTop, new QwtLogScaleEngine); + replot(); + auto div = axisScaleDiv(QwtPlot::xTop); + setXaxisNumDiv((div.ticks(2)).size() - 1); + setXaxisMajorTicksPos(div.ticks(2)); } else { + setPlotLogaritmic(false); auto scaleTop = new OscScaleEngine; scaleTop->setMajorTicksCount(9); + setXaxisNumDiv(8); this->setAxisScaleEngine(QwtPlot::xTop, scaleTop); } this->log_freq = use_log_freq; if (d_cursorsEnabled && isVisible()) { - onCursor1Moved(d_vBar1->transform(d_vBar1->plotCoord()).x()); - onCursor2Moved(d_vBar2->transform(d_vBar2->plotCoord()).x()); + onVCursor1Moved(d_vBar1->plotCoord().x()); + onVCursor2Moved(d_vBar2->plotCoord().x()); } // Use delta only when log scale is disabled and delta @@ -576,73 +599,23 @@ bool dBgraph::addReferenceWaveformFromPlot() return true; } -void dBgraph::onCursor1PositionChanged(int pos) -{ - pos = std::min(pos,QwtPlot::canvas()->width()-1); - d_vBar1->setPixelPosition(pos); - onCursor1Moved(pos); -} - -void dBgraph::onCursor2PositionChanged(int pos) +QString dBgraph::formatXValue(double value, int precision) const { - pos = std::min(pos,QwtPlot::canvas()->width()-1); - d_vBar2->setPixelPosition(pos); - onCursor2Moved(pos); + return d_formatter->format(value, "Hz", precision); } -void dBgraph::onVbar1PixelPosChanged(int pos) +QString dBgraph::formatYValue(double value, int precision) const { - Q_EMIT VBar1PixelPosChanged(pos); + return d_formatter->format(value, draw_y->getUnitType(), precision); } -void dBgraph::onVbar2PixelPosChanged(int pos) -{ - Q_EMIT VBar2PixelPosChanged(pos); -} - -void dBgraph::toggleCursors(bool en) -{ - d_frequencyBar->setPixelPosition(0); - if (d_cursorsEnabled != en) { - if (!d_cursorsCentered) { - d_cursorsCentered=true; - d_vBar1->setPixelPosition(canvas()->width()/2-30); - d_vBar2->setPixelPosition(canvas()->width()/2+30); - } - - d_cursorsEnabled = en; - d_vBar1->setVisible(en); - d_vBar2->setVisible(en); - - d_cursorReadouts->setTimeReadoutVisible(en); - d_cursorReadouts->setVoltageReadoutVisible(en); - - if (en) { - onCursor1Moved(d_vBar1->transform(d_vBar1->plotCoord()).x()); - onCursor2Moved(d_vBar2->transform(d_vBar2->plotCoord()).x()); - } else { - markerIntersection1->detach(); - markerIntersection2->detach(); - replot(); - } - } -} - -CustomPlotPositionButton::ReadoutsPosition -dBgraph::getCursorReadoutCurrentPosition() -{ - return d_cursorReadouts->getCurrentPosition(); -} - -void dBgraph::onCursor1Moved(int value) +void dBgraph::onVCursor1Moved(double value) { QString text; - - auto point = picker->pointCoordinates(QPoint(value,0)); - text = formatter->format(point.x(),"Hz",2); + text = d_formatter->format(value, "Hz", 2); d_cursorReadouts->setTimeCursor1Text(text); - text = cursorIntersection(point.x()); + text = cursorIntersection(value); d_cursorReadouts->setVoltageCursor1Text(text); double d1 = d_cursorReadouts->voltageCursor1Text().split(" ")[0].toDouble(); @@ -653,25 +626,22 @@ void dBgraph::onCursor1Moved(int value) } else { if (d_cursorsEnabled) { markerIntersection1->attach(this); - markerIntersection1->setValue(point.x(), d1); + markerIntersection1->setValue(value, d1); } } - replot(); d_cursorReadouts->setVoltageDeltaText(QString::number(d2-d1)+" "+ draw_y->getUnitType()); } -void dBgraph::onCursor2Moved(int value) +void dBgraph::onVCursor2Moved(double value) { QString text; - - auto point = picker->pointCoordinates(QPoint(value,0)); - text = formatter->format(point.x(),"Hz",2); + text = d_formatter->format(value, "Hz", 2); d_cursorReadouts->setTimeCursor2Text(text); - text = cursorIntersection(point.x()); + text = cursorIntersection(value); d_cursorReadouts->setVoltageCursor2Text(text); double d1 = d_cursorReadouts->voltageCursor1Text().split(" ")[0].toDouble(); @@ -682,10 +652,9 @@ void dBgraph::onCursor2Moved(int value) } else { if (d_cursorsEnabled) { markerIntersection2->attach(this); - markerIntersection2->setValue(point.x(), d2); + markerIntersection2->setValue(value, d2); } } - replot(); d_cursorReadouts->setVoltageDeltaText(QString::number(d2-d1)+" "+ @@ -725,23 +694,12 @@ QString dBgraph::cursorIntersection(qreal freq) rightCustom = ydata.data()[rightIndex]; double val = (rightCustom - leftCustom)/(rightFreq - leftFreq)* - (freq-leftFreq)+leftCustom; + (freq-leftFreq)+leftCustom; return QString::number(val,'f',2) +" "+ draw_y->getUnitType(); } } -void dBgraph::setCursorReadoutsTransparency(int value) -{ - d_cursorReadouts->setTransparency(value); -} - -void dBgraph::moveCursorReadouts(CustomPlotPositionButton::ReadoutsPosition - position) -{ - d_cursorReadouts->moveToPosition(position); -} - QVector dBgraph::getXAxisData() { QVector data; @@ -798,8 +756,8 @@ void dBgraph::scaleDivChanged() this->setAxisScale(QwtPlot::xTop, intv.minValue(), intv.maxValue()); this->replot(); - onCursor1Moved(d_vBar1->transform(d_vBar1->plotCoord()).x()); - onCursor2Moved(d_vBar2->transform(d_vBar2->plotCoord()).x()); + onVCursor1Moved(d_vBar1->plotCoord().x()); + onVCursor2Moved(d_vBar2->plotCoord().x()); } void dBgraph::mousePressEvent(QMouseEvent *event) @@ -816,6 +774,8 @@ void dBgraph::onResetZoom() void dBgraph::showEvent(QShowEvent *event) { + d_hCursorHandle1->updatePosition(); + d_hCursorHandle2->updatePosition(); auto sw = axisWidget(QwtPlot::xTop); sw->scaleDraw()->invalidateCache(); sw->repaint(); diff --git a/src/dbgraph.hpp b/src/dbgraph.hpp index fab94bd78e..42a5a8602c 100644 --- a/src/dbgraph.hpp +++ b/src/dbgraph.hpp @@ -29,15 +29,16 @@ #include "symbol_controller.h" #include "plot_line_handle.h" #include "cursor_readouts.h" -#include "plotpickerwrapper.h" +#include "DisplayPlot.h" namespace adiscope { class OscScaleDraw; class PrefixFormatter; class OscScaleZoomer; -class dBgraph : public QwtPlot +class dBgraph : public DisplayPlot { + friend class NetworkAnalyzer_API; Q_OBJECT Q_PROPERTY(int numSamples @@ -64,7 +65,8 @@ class dBgraph : public QwtPlot Q_PROPERTY(bool log_freq MEMBER log_freq WRITE useLogFreq); public: - explicit dBgraph(QWidget *parent = nullptr); + explicit dBgraph(QWidget *parent = nullptr, bool isdBgraph = true); + ~dBgraph(); void setAxesScales(double xmin, double xmax, @@ -73,6 +75,8 @@ class dBgraph : public QwtPlot int getNumSamples() const; + bool eventFilter(QObject *, QEvent *); + QString getScaleValueFormat(double value, QwtAxisId scale) const; QString getScaleValueFormat(double value, QwtAxisId scale, int precision) const; @@ -84,9 +88,6 @@ class dBgraph : public QwtPlot QString xTitle() const; QString yTitle() const; - void toggleCursors(bool); - CustomPlotPositionButton::ReadoutsPosition getCursorReadoutCurrentPosition(); - QString cursorIntersection(qreal text); QVector getXAxisData(); QVector getYAxisData(); @@ -96,9 +97,14 @@ class dBgraph : public QwtPlot void setPlotBarEnabled(bool enabled); void parametersOverrange(bool enable); + + void enableXaxisLabels(); + void enableYaxisLabels(); + QString formatXValue(double value, int precision) const; + QString formatYValue(double value, int precision) const; + + void replot(); Q_SIGNALS: - void VBar1PixelPosChanged(int); - void VBar2PixelPosChanged(int); void resetZoom(); void frequencySelected(double); @@ -127,18 +133,6 @@ public Q_SLOTS: void useDeltaLabel(bool use_delta); void sweepDone(); - void onVbar1PixelPosChanged(int pos); - void onVbar2PixelPosChanged(int pos); - - void onCursor1PositionChanged(int pos); - void onCursor2PositionChanged(int pos); - - void onCursor1Moved(int); - void onCursor2Moved(int); - - void setCursorReadoutsTransparency(int value); - void moveCursorReadouts(CustomPlotPositionButton::ReadoutsPosition position); - void scaleDivChanged(); void mousePressEvent(QMouseEvent *event); void onResetZoom(); @@ -150,15 +144,15 @@ public Q_SLOTS: void removeReferenceWaveform(); bool addReferenceWaveformFromPlot(); - +private Q_SLOTS: + void onVCursor1Moved(double); + void onVCursor2Moved(double); protected Q_SLOTS: void showEvent(QShowEvent *event); private: QwtPlotCurve curve; QwtPlotCurve reference; - QwtPlotMarker *markerIntersection1; - QwtPlotMarker *markerIntersection2; unsigned int numSamples; double xmin, xmax, ymin, ymax; QColor color; @@ -167,25 +161,18 @@ protected Q_SLOTS: bool delta_label; bool d_plotBarEnabled; - bool d_cursorsEnabled; - bool d_cursorsCentered; OscScaleDraw *draw_x, *draw_y; - PrefixFormatter *formatter; + OscScaleZoomer *zoomer; QVector xdata, ydata; unsigned int d_plotPosition; - SymbolController *d_symbolCtrl; - VertBar *d_vBar1; - VertBar *d_vBar2; VertBar *d_plotBar; VertBar *d_frequencyBar; + PrefixFormatter *d_formatter; - PlotPickerWrapper *picker; - - CursorReadouts *d_cursorReadouts; - void setupCursors(); + void setupVerticalBars(); void setupReadouts(); }; } diff --git a/src/debugger.cpp b/src/debugger.cpp index bbd109f529..afc6647149 100644 --- a/src/debugger.cpp +++ b/src/debugger.cpp @@ -156,7 +156,7 @@ void Debugger::updateValueWidget(QString attribute) QVector availableValues = debug.getAttributeVector(); ui->valueStackedWidget->setEnabled(true); - for (QString t : availableValues) { + for (const QString &t : qAsConst(availableValues)) { if (!QString::compare(t, attribute, Qt::CaseInsensitive)) { available = true; diff --git a/src/detachedwindowsmanager.cpp b/src/detachedwindowsmanager.cpp index 4f46754490..5071517ccb 100644 --- a/src/detachedwindowsmanager.cpp +++ b/src/detachedwindowsmanager.cpp @@ -65,7 +65,7 @@ DetachedWindowsManager::DetachedWindowsManager() DetachedWindowsManager::~DetachedWindowsManager() { - for (auto iterator : pool) { + for (auto iterator : qAsConst(pool)) { delete iterator; } diff --git a/src/digitalio.cpp b/src/digitalio.cpp index cc40bb947a..42985394a0 100644 --- a/src/digitalio.cpp +++ b/src/digitalio.cpp @@ -213,7 +213,7 @@ QPair *DigitalIO::findIndividualUi(int ch) for (auto &&group : groups) { auto i=0; - for (auto wid : group->chui) { + for (auto wid : qAsConst(group->chui)) { if (wid->first->property("dio")==ch) { return group->chui[i]; } @@ -274,7 +274,7 @@ void adiscope::DigitalIoGroup::changeDirection() auto val = 0; auto i=0; - for (auto ch:chui) { + for (auto ch:qAsConst(chui)) { ch->second->inout->setChecked(!chk); auto channel = ch->first->property("dio").toInt(); dio->setDirection(channel,!chk); diff --git a/src/dmm.cpp b/src/dmm.cpp index 570608ef1f..442fe01039 100644 --- a/src/dmm.cpp +++ b/src/dmm.cpp @@ -75,8 +75,7 @@ DMM::DMM(struct iio_context *ctx, Filter *filt, ToolMenuItem *toolMenuItem, logging_refresh_rate(0), wheelEventGuard(nullptr), m_autoGainEnabled({true, true}), - m_historyForGain({0, 0}), - m_gainHistorySize(10) + m_gainHistorySize(25) { ui->setupUi(this); @@ -212,6 +211,11 @@ DMM::DMM(struct iio_context *ctx, Filter *filt, ToolMenuItem *toolMenuItem, readPreferences(); ui->btnHelp->setUrl("https://wiki.analog.com/university/tools/m2k/scopy/voltmeter"); + + for(unsigned int i=0;i < m_adc_nb_channels;i++) + { + m_gainHistory.push_back(boost::circular_buffer(m_gainHistorySize)); + } } void DMM::readPreferences() @@ -249,11 +253,11 @@ void DMM::gainModeChanged(int idx) if (idx == 0) { // auto m_autoGainEnabled[channelIdx] = true; } else if (idx == 1) { // low - gainLabel->setText("Low Gain"); + gainLabel->setText("±25V"); m_m2k_analogin->setRange(static_cast(channelIdx), libm2k::analog::PLUS_MINUS_25V); } else if (idx == 2) { // high - gainLabel->setText("High Gain"); + gainLabel->setText("±2.5V"); m_m2k_analogin->setRange(static_cast(channelIdx), libm2k::analog::PLUS_MINUS_2_5V); } @@ -314,8 +318,8 @@ void DMM::updateValuesList(std::vector values) checkAndUpdateGainMode({m_m2k_analogin->convertRawToVolts(0, static_cast(values[2])), m_m2k_analogin->convertRawToVolts(0, static_cast(values[3])), - m_m2k_analogin->convertRawToVolts(0, static_cast(values[4])), - m_m2k_analogin->convertRawToVolts(0, static_cast(values[5]))}); + m_m2k_analogin->convertRawToVolts(1, static_cast(values[4])), + m_m2k_analogin->convertRawToVolts(1, static_cast(values[5]))}); if(!use_timer) data_cond.notify_all(); @@ -342,14 +346,8 @@ bool DMM::isIioManagerStarted() const return manager->started() && ui->run_button->isChecked(); } -void DMM::checkAndUpdateGainMode(const std::vector &volts) +libm2k::analog::M2K_RANGE DMM::suggestRange(double volt_max, double volt_min) { - if (volts.size() < m_adc_nb_channels * 2) { - return; - } - - std::vector gainLabels {ui->currentGainCh1Label, ui->currentGainCh2Label}; - std::vector errorLabels {ui->ch1ErrorLabel, ui->ch2ErrorLabel}; double hi = 0.0; double lo = 0.0; @@ -364,80 +362,112 @@ void DMM::checkAndUpdateGainMode(const std::vector &volts) const double lo_hi = lo + half_hist_interval; const double lo_lo = lo - half_hist_interval; - for (int i = 0; i < m_adc_nb_channels; ++i) { - libm2k::analog::M2K_RANGE gain = libm2k::analog::PLUS_MINUS_25V; + libm2k::analog::M2K_RANGE gain = libm2k::analog::PLUS_MINUS_25V; - bool changed = false; - if (volts[m_adc_nb_channels * i] > 0.0) { - changed = true; - if (volts[m_adc_nb_channels * i] >= hi_hi) { - gain = libm2k::analog::PLUS_MINUS_25V; - } else if (volts[m_adc_nb_channels * i] <= hi_lo) { - gain = libm2k::analog::PLUS_MINUS_2_5V; - } else { - changed = false; - } + if (volt_max > 0.0) { + if (volt_max >= hi_hi) { + gain = libm2k::analog::PLUS_MINUS_25V; + } else if (volt_max <= hi_lo) { + gain = libm2k::analog::PLUS_MINUS_2_5V; } - if (volts[m_adc_nb_channels * i + 1] <= 0.0) { - changed = true; - if (volts[m_adc_nb_channels * i + 1] <= lo_lo ) { - gain = libm2k::analog::PLUS_MINUS_25V; - } else if (volts[m_adc_nb_channels * i + 1] >= lo_hi) { + if (volt_min <= 0.0) { + if (volt_min >= lo_hi ) { gain = libm2k::analog::PLUS_MINUS_2_5V; - } else { - changed = false; + } else if (volt_min <= lo_lo) { + gain = libm2k::analog::PLUS_MINUS_25V; } } + } + return gain; +} - if (!changed) { - continue; - } +void DMM::checkAndUpdateGainMode(const std::vector &volts) +{ + if (volts.size() < m_adc_nb_channels * 2) { + return; + } - if (gain == libm2k::analog::PLUS_MINUS_2_5V && m_m2k_analogin->getRange(static_cast(i)) != gain - && m_historyForGain[i] < m_gainHistorySize) { - m_historyForGain[i]++; - continue; // we don't wanna change the gain now; - } + std::vector gainLabels {ui->currentGainCh1Label, ui->currentGainCh2Label}; + std::vector errorLabels {ui->ch1ErrorLabel, ui->ch2ErrorLabel}; - if (gain == libm2k::analog::PLUS_MINUS_25V) { - m_historyForGain[i] = 0; - } - errorLabels[i]->setText(""); - if (m_m2k_analogin->getRange(static_cast(i)) != gain) { - if (m_autoGainEnabled[i]) { - const bool started = isIioManagerStarted(); - if (started) { - manager->lock(); - } + libm2k::analog::M2K_RANGE gain[m_adc_nb_channels]; + libm2k::analog::M2K_RANGE currentChannelGain[m_adc_nb_channels]; + bool recreateFlowGraph = false; - // rebuild the flowgraph - // there might be data on in the gnuradio flowgraph that - // was captured using one gain mode and plotted and converted - // with another gain mode. This will ensure this situation doesn't - // happen - manager->disconnect(id_ch1); - manager->disconnect(id_ch2); + for (unsigned int i = 0; i < m_adc_nb_channels; ++i) { + gain[i]=libm2k::analog::PLUS_MINUS_25V; + currentChannelGain[i] = m_m2k_analogin->getRange(static_cast(i)); + //gain[i] = currentChannelGain[i];//libm2k::analog::PLUS_MINUS_25V; - configureModes(); + // add all gains to circular buffer + auto suggested_range = suggestRange (volts[m_adc_nb_channels * i], volts[(m_adc_nb_channels * i) + 1]); + m_gainHistory[i].push_back(suggested_range); - m_m2k_analogin->setRange(static_cast(i), gain); - gainLabels[i]->setText(gain == libm2k::analog::PLUS_MINUS_25V ? "Low Gain" : "High Gain"); + // define m2k_range sum computation operation as lambda + auto range_sum = [](double a, libm2k::analog::M2K_RANGE b) { + return (a) + static_cast(b); + }; + + + + // compute average of circular buffer - moving average + double sum = std::accumulate(m_gainHistory[i].begin(),m_gainHistory[i].end(), 0.0, range_sum); + double avg = sum / m_gainHistory[i].size(); + // only change to high gain if ALL values in circular buffer == HIGH_GAIN + // this means as soon as we find a value out of HIGH range we switch immediately - but wait m_gainHistorySize to change back to HIGH + if(avg == libm2k::analog::PLUS_MINUS_2_5V) { + gain[i] = libm2k::analog::PLUS_MINUS_2_5V; + } + + if(gain[i] != currentChannelGain[i] ) { + if(m_autoGainEnabled[i]) { + errorLabels[i]->setText(""); + m_m2k_analogin->setRange(static_cast(i), gain[i]); + gainLabels[i]->setText(gain[i] == libm2k::analog::PLUS_MINUS_25V ? "±25V" : "±2.5V"); + recreateFlowGraph = true; - if (started) { - manager->start(id_ch1); - manager->start(id_ch2); - manager->unlock(); - } } else { - errorLabels[i]->setText("Out of range!"); + if(currentChannelGain[i] == libm2k::analog::PLUS_MINUS_2_5V) { // only show out of range for +/- 2.5 + errorLabels[i]->setText("Out of range"); + } else { + errorLabels[i]->setText(""); + } } + } else { + errorLabels[i]->setText(""); + } + + + } + + if(recreateFlowGraph) { + const bool started = isIioManagerStarted(); + if (started) { + manager->lock(); + } + + // rebuild the flowgraph + // there might be data on in the gnuradio flowgraph that + // was captured using one gain mode and plotted and converted + // with another gain mode. This will ensure this situation doesn't + // happen + manager->disconnect(id_ch1); + manager->disconnect(id_ch2); + + configureModes(); + + if (started) { + manager->start(id_ch1); + manager->start(id_ch2); + manager->unlock(); } } } + void DMM::collapseDataLog(bool checked) { if(checked) diff --git a/src/dmm.hpp b/src/dmm.hpp index a2bc5748a4..4b0375dae5 100644 --- a/src/dmm.hpp +++ b/src/dmm.hpp @@ -35,6 +35,7 @@ #include "spinbox_a.hpp" #include #include +#include /* libm2k includes */ #include @@ -87,13 +88,14 @@ namespace adiscope { std::vector m_min, m_max; std::vector m_autoGainEnabled; - std::vector m_historyForGain; + std::vector> m_gainHistory; int m_gainHistorySize; void disconnectAll(); gr::basic_block_sptr configureGraph(gr::basic_block_sptr s2f, bool is_ac); void configureModes(); + libm2k::analog::M2K_RANGE suggestRange(double volt_max, double volt_min); int numSamplesFromIdx(int idx); void writeAllSettingsToHardware(); void checkPeakValues(int, double); diff --git a/src/fft_block.cpp b/src/fft_block.cpp index 164dadc377..9351fb5737 100644 --- a/src/fft_block.cpp +++ b/src/fft_block.cpp @@ -37,9 +37,6 @@ fft_block::fft_block(bool use_complex, size_t fft_size, unsigned int nbthreads) io_signature::make(1, 1, sizeof(gr_complex))), d_complex(use_complex) { - auto s2v = blocks::stream_to_vector::make( - use_complex ? sizeof(gr_complex) : sizeof(float), - fft_size); auto v2s = blocks::vector_to_stream::make(sizeof(gr_complex), fft_size); d_s2v_overlap = adiscope::stream_to_vector_overlap::make( diff --git a/src/filemanager.cpp b/src/filemanager.cpp index 63ce39bad7..89aeae3493 100644 --- a/src/filemanager.cpp +++ b/src/filemanager.cpp @@ -88,7 +88,7 @@ void FileManager::open(QString fileName, QVector line_data; QString line = in.readLine(); QStringList list = line.split(separator, QString::SkipEmptyParts); - for (QString list_item : list) { + for (const QString &list_item : qAsConst(list)) { line_data.push_back(list_item); } if (line_data.size() > 0) { @@ -289,7 +289,7 @@ void FileManager::performWrite() //column names row exportStream << "Sample" << separator; bool skipFirstSeparator=true; - for (QString columnName : columnNames) { + for (const QString &columnName : qAsConst(columnNames)) { if(!skipFirstSeparator) exportStream << separator; exportStream << columnName; diff --git a/src/filter.cpp b/src/filter.cpp index b2572a022c..1a3fe03d27 100644 --- a/src/filter.cpp +++ b/src/filter.cpp @@ -55,7 +55,8 @@ Filter::Filter(const struct iio_context *ctx) auto doc = QJsonDocument::fromJson(file.readAll()); auto obj = doc.object(); - for (const auto &key : obj.keys()) { + auto obj_keys = obj.keys(); + for (const auto &key : qAsConst(obj_keys)) { const auto child = obj[key].toObject(); if (!child.contains("compatible-devices")) @@ -67,7 +68,8 @@ Filter::Filter(const struct iio_context *ctx) bool compatible = true; - for (const auto &value : compatible_devices.toArray()) { + auto comp_dev = compatible_devices.toArray(); + for (const auto &value : qAsConst(comp_dev)) { if (!value.isString()) { compatible = false; break; diff --git a/src/handlesareaextension.cpp b/src/handlesareaextension.cpp index f471c8c9f1..29797112cb 100644 --- a/src/handlesareaextension.cpp +++ b/src/handlesareaextension.cpp @@ -1,177 +1,612 @@ -#include "handlesareaextension.h" - -#include - -#include - -#include "handles_area.hpp" -#include "oscilloscope_plot.hpp" -#include "paintersaverestore.h" - -using namespace adiscope; - -HandlesAreaExtension::HandlesAreaExtension(QwtPlot* plot) - : m_plot(plot) {} - -XBottomRuller::XBottomRuller(QwtPlot *plot) - : HandlesAreaExtension(plot) {} - -bool XBottomRuller::draw(QPainter *painter, QWidget *owner) -{ - HorizHandlesArea *area = qobject_cast(owner); - if (!area) { - return false; - } - - const CapturePlot *plot = qobject_cast(m_plot); - if (!plot) { - return false; - } - - // Some extensions might alter the state of the painter - // such as its brush or pen. Consider saving its state - // then restore it when done using it so other extensions - // won't be affected - - // PainterSaveRestore psr(painter); - - const QwtInterval interval = plot->axisInterval(QwtPlot::xBottom); - - const double leftP = area->leftPadding(); - const double rightP = area->rightPadding(); - - const int labels = plot->xAxisNumDiv() + 1; - - const double totalWidth = owner->width() - (leftP + rightP); - const double distBetween2Labels = totalWidth / (labels - 1); - const double timeBetween2Labels = (interval.maxValue() - interval.minValue()) / (labels - 1); - - // compute rectangles of labels and - // corresponding text - QVector labelRectangles; - QStringList labelTexts; - double midPoint = leftP; - double currentTime = interval.minValue(); - for (int i = 0; i < labels; ++i) { - const QString text = plot->timeScaleValueFormat(currentTime, 2); - - const QSizeF textSize = QwtText(text).textSize(painter->font()); - QRectF textRect(QPointF(0.0, 0.0), textSize); - - textRect.moveCenter(QPointF(midPoint, textSize.height() / 2.0)); - - labelRectangles.push_back(textRect); - labelTexts.push_back(text); - - midPoint += distBetween2Labels; - currentTime += timeBetween2Labels; - } - - bool allLabelsTheSame = true; - for (int i = 1; i < labelTexts.size(); ++i) { - if (labelTexts[i] != labelTexts[i - 1]) { - allLabelsTheSame = false; - break; - } - } - - // get nr of major ticks - const int nrMajorTicks = plot->axisScaleDiv(QwtPlot::xBottom).ticks(QwtScaleDiv::MajorTick).size(); - const int midLabelTick = nrMajorTicks / 2; - - if (allLabelsTheSame) { - // draw delta as middle label - labelRectangles.clear(); - labelTexts.clear(); - midPoint = leftP; - currentTime = interval.minValue(); - for (int i = 0; i < labels; ++i) { - QString text; - if (i == midLabelTick) { - text = plot->timeScaleValueFormat(currentTime, 6); - } else { - text = plot->timeScaleValueFormat(currentTime - (interval.minValue() + midLabelTick * timeBetween2Labels), 2); - if (i > midLabelTick) { - text = "+" + text; - } - } - - const QSizeF textSize = QwtText(text).textSize(painter->font()); - QRectF textRect(QPointF(0.0, 0.0), textSize); - - textRect.moveCenter(QPointF(midPoint, textSize.height() / 2.0)); - - labelRectangles.push_back(textRect); - labelTexts.push_back(text); - - midPoint += distBetween2Labels; - currentTime += timeBetween2Labels; - } - - } - - // adjust labels to fit visible area of the handle area - // mainly the first and last label - if (labelRectangles.first().topLeft().x() < owner->mask().boundingRect().bottomLeft().x()) { - int offset = owner->mask().boundingRect().bottomLeft().x() - labelRectangles.first().topLeft().x(); - labelRectangles.first().adjust(offset, 0, offset, 0); - } - - if (labelRectangles.last().bottomRight().x() > owner->mask().boundingRect().bottomRight().x()) { - int offset = labelRectangles.last().bottomRight().x() - owner->mask().boundingRect().bottomRight().x(); - labelRectangles.last().adjust(-offset, 0, -offset, 0); - } - - // filter out overlaping labels, but always drawing - // the first and last label - bool overlaping = false; - do { - // consider none overlaping - overlaping = false; - - // find overlaping - int i = 0; - for (; i < labelRectangles.size() - 1; ++i) { - if (labelRectangles[i].intersects(labelRectangles[i + 1])) { - overlaping = true; - break; - } - } - - // done - if (!overlaping) { - break; - } - if (allLabelsTheSame) { - int center = midLabelTick; - for (int i = center - 1; i >= 0; i -= 2) { - // Remove the tick and make sure to update the center - // label position - labelRectangles.removeAt(i); - labelTexts.removeAt(i); - --center; - } - for (int j = center + 1; j < labelRectangles.size(); j += 1) { - labelRectangles.removeAt(j); - labelTexts.removeAt(j); - } - - } else { - // remove overlaping - if (i + 1 == labelRectangles.size() - 1) { - labelRectangles.removeAt(i); - labelTexts.removeAt(i); - } else { - labelRectangles.removeAt(i + 1); - labelTexts.removeAt(i + 1); - } - } - } while(overlaping); - - // draw the labels - for (int i = 0; i < labelRectangles.size(); ++i) { - painter->drawText(labelRectangles[i], labelTexts[i]); - } - - return false; -} +#include "handlesareaextension.h" + +#include + +#include + +#include "handles_area.hpp" +#include "DisplayPlot.h" +#include "paintersaverestore.h" + +using namespace adiscope; + +HandlesAreaExtension::HandlesAreaExtension(QwtPlot* plot) + : m_plot(plot) {} + +XBottomRuller::XBottomRuller(QwtPlot *plot) + : HandlesAreaExtension(plot) {} + +bool XBottomRuller::draw(QPainter *painter, QWidget *owner) +{ + HorizHandlesArea *area = qobject_cast(owner); + if (!area) { + return false; + } + + const DisplayPlot *plot = qobject_cast(m_plot); + if (!plot) { + return false; + } + + const double leftP = area->leftPadding(); + const double rightP = area->rightPadding(); + + QVector labelRectangles; + QStringList labelTexts; + + if(plot->isLogaritmicPlot()) + { + QList majorTicks = plot->getXaxisMajorTicksPos(); + double pointVal, currentValue; + + for (int i = 0; i < majorTicks.size(); ++i) { + currentValue = majorTicks.at(i); + pointVal = plot->transform(QwtPlot::xBottom, currentValue) + leftP; + + const QString text = plot->formatXValue(currentValue, 2); + + const QSizeF textSize = QwtText(text).textSize(painter->font()); + QRectF textRect(QPointF(0.0, 0.0), textSize); + + textRect.moveCenter(QPointF(pointVal, textSize.height() / 2.0)); + + labelRectangles.push_back(textRect); + labelTexts.push_back(text); + } + + // adjust labels to fit visible area of the handle area + // mainly the first and last label + if (labelRectangles.first().topLeft().x() < owner->mask().boundingRect().bottomLeft().x()) { + int offset = owner->mask().boundingRect().bottomLeft().x() - labelRectangles.first().topLeft().x(); + labelRectangles.first().adjust(offset, 0, offset, 0); + } + + if (labelRectangles.last().bottomRight().x() > owner->mask().boundingRect().bottomRight().x()) { + int offset = labelRectangles.last().bottomRight().x() - owner->mask().boundingRect().bottomRight().x(); + labelRectangles.last().adjust(-offset, 0, -offset, 0); + } + } + else + { + // Some extensions might alter the state of the painter + // such as its brush or pen. Consider saving its state + // then restore it when done using it so other extensions + // won't be affected + + // PainterSaveRestore psr(painter); + + const QwtInterval interval = plot->axisInterval(QwtPlot::xBottom); + + const int labels = plot->xAxisNumDiv() + 1; + + const double totalWidth = owner->width() - (leftP + rightP); + const double distBetween2Labels = totalWidth / (labels - 1); + const double valueBetween2Labels = (interval.maxValue() - interval.minValue()) / (labels - 1); + + double midPoint = leftP; + double currentValue = interval.minValue(); + for (int i = 0; i < labels; ++i) { + + const QString text = plot->formatXValue(currentValue, 2); + + const QSizeF textSize = QwtText(text).textSize(painter->font()); + QRectF textRect(QPointF(0.0, 0.0), textSize); + + textRect.moveCenter(QPointF(midPoint, textSize.height() / 2.0)); + + labelRectangles.push_back(textRect); + labelTexts.push_back(text); + + midPoint += distBetween2Labels; + currentValue += valueBetween2Labels; + } + + bool allLabelsTheSame = true; + for (int i = 1; i < labelTexts.size(); ++i) { + if (labelTexts[i] != labelTexts[i - 1]) { + allLabelsTheSame = false; + break; + } + } + + // get nr of major ticks + const int nrMajorTicks = plot->axisScaleDiv(QwtPlot::xBottom).ticks(QwtScaleDiv::MajorTick).size(); + const int midLabelTick = nrMajorTicks / 2; + + if (allLabelsTheSame) { + // draw delta as middle label + labelRectangles.clear(); + labelTexts.clear(); + midPoint = leftP; + currentValue = interval.minValue(); + for (int i = 0; i < labels; ++i) { + QString text; + if (i == midLabelTick) { + text = plot->formatXValue(currentValue, 6); + } else { + text = plot->formatXValue(currentValue - (interval.minValue() + midLabelTick * valueBetween2Labels), 2); + + if (i > midLabelTick) { + text = "+" + text; + } + } + + const QSizeF textSize = QwtText(text).textSize(painter->font()); + QRectF textRect(QPointF(0.0, 0.0), textSize); + + textRect.moveCenter(QPointF(midPoint, textSize.height() / 2.0)); + + labelRectangles.push_back(textRect); + labelTexts.push_back(text); + + midPoint += distBetween2Labels; + currentValue += valueBetween2Labels; + } + + } + + // adjust labels to fit visible area of the handle area + // mainly the first and last label + if (labelRectangles.first().topLeft().x() < owner->mask().boundingRect().bottomLeft().x()) { + int offset = owner->mask().boundingRect().bottomLeft().x() - labelRectangles.first().topLeft().x(); + labelRectangles.first().adjust(offset, 0, offset, 0); + } + + if (labelRectangles.last().bottomRight().x() > owner->mask().boundingRect().bottomRight().x()) { + int offset = labelRectangles.last().bottomRight().x() - owner->mask().boundingRect().bottomRight().x(); + labelRectangles.last().adjust(-offset, 0, -offset, 0); + } + + // filter out overlaping labels, but always drawing + // the first and last label + bool overlaping = false; + do { + // consider none overlaping + overlaping = false; + + // find overlaping + int i = 0; + for (; i < labelRectangles.size() - 1; ++i) { + if (labelRectangles[i].intersects(labelRectangles[i + 1])) { + overlaping = true; + break; + } + } + + // done + if (!overlaping) { + break; + } + if (allLabelsTheSame) { + int center = midLabelTick; + for (int i = center - 1; i >= 0; i -= 2) { + // Remove the tick and make sure to update the center + // label position + labelRectangles.removeAt(i); + labelTexts.removeAt(i); + --center; + } + for (int j = center + 1; j < labelRectangles.size(); j += 1) { + labelRectangles.removeAt(j); + labelTexts.removeAt(j); + } + + } else { + // remove overlaping + if (i + 1 == labelRectangles.size() - 1) { + labelRectangles.removeAt(i); + labelTexts.removeAt(i); + } else { + labelRectangles.removeAt(i + 1); + labelTexts.removeAt(i + 1); + } + } + } while(overlaping); + + } + // draw the labels + for (int i = 0; i < labelRectangles.size(); ++i) { + painter->drawText(labelRectangles[i], labelTexts[i]); + } + + return false; +} + +XTopRuller::XTopRuller(QwtPlot *plot) + : HandlesAreaExtension(plot) {} + +bool XTopRuller::draw(QPainter *painter, QWidget *owner) +{ + HorizHandlesArea *area = qobject_cast(owner); + if (!area) { + return false; + } + + const DisplayPlot *plot = qobject_cast(m_plot); + if (!plot) { + return false; + } + + const double leftP = area->leftPadding(); + const double rightP = area->rightPadding(); + + QVector labelRectangles; + QStringList labelTexts; + + if(plot->isLogaritmicPlot()) + { + QList majorTicks = plot->getXaxisMajorTicksPos(); + double pointVal, currentValue; + + for (int i = 0; i < majorTicks.size(); ++i) { + currentValue = majorTicks.at(i); + pointVal = plot->transform(QwtPlot::xTop, currentValue) + leftP; + + const QString text = plot->formatXValue(currentValue, 2); + + const QSizeF textSize = QwtText(text).textSize(painter->font()); + QRectF textRect(QPointF(0.0, 0.0), textSize); + + textRect.moveCenter(QPointF(pointVal + textSize.width() / 2.0, textSize.height() / 2.0)); + + labelRectangles.push_back(textRect); + labelTexts.push_back(text); + } + + // adjust labels to fit visible area of the handle area + // mainly the first and last label + if (labelRectangles.first().topLeft().x() < owner->mask().boundingRect().bottomLeft().x()) { + int offset = owner->mask().boundingRect().bottomLeft().x() - labelRectangles.first().topLeft().x(); + labelRectangles.first().adjust(offset, 0, offset, 0); + } + + if (labelRectangles.last().bottomRight().x() > owner->mask().boundingRect().bottomRight().x()) { + int offset = labelRectangles.last().bottomRight().x() - owner->mask().boundingRect().bottomRight().x(); + labelRectangles.last().adjust(-offset, 0, -offset, 0); + } + + + } + else + { + // Some extensions might alter the state of the painter + // such as its brush or pen. Consider saving its state + // then restore it when done using it so other extensions + // won't be affected + + // PainterSaveRestore psr(painter); + + const QwtInterval interval = plot->axisInterval(QwtPlot::xTop); + + const int labels = plot->xAxisNumDiv() + 1; + + const double totalWidth = owner->width() - (leftP + rightP); + const double distBetween2Labels = totalWidth / (labels - 1); + const double valueBetween2Labels = (interval.maxValue() - interval.minValue()) / (labels - 1); + double midPoint = leftP; + double currentValue = interval.minValue(); + + for (int i = 0; i < labels; ++i) { + const QString text = plot->formatXValue(currentValue, 2); + + const QSizeF textSize = QwtText(text).textSize(painter->font()); + QRectF textRect(QPointF(0.0, 0.0), textSize); + + textRect.moveCenter(QPointF(midPoint, textSize.height() / 2.0)); + + labelRectangles.push_back(textRect); + labelTexts.push_back(text); + + midPoint += distBetween2Labels; + currentValue += valueBetween2Labels; + } + + bool allLabelsTheSame = true; + for (int i = 1; i < labelTexts.size(); ++i) { + if (labelTexts[i] != labelTexts[i - 1]) { + allLabelsTheSame = false; + break; + } + } + + // get nr of major ticks + const int nrMajorTicks = plot->axisScaleDiv(QwtPlot::xTop).ticks(QwtScaleDiv::MajorTick).size(); + const int midLabelTick = nrMajorTicks / 2; + + if (allLabelsTheSame) { + // draw delta as middle label + labelRectangles.clear(); + labelTexts.clear(); + midPoint = leftP; + currentValue = interval.minValue(); + for (int i = 0; i < labels; ++i) { + QString text; + if (i == midLabelTick) { + text = plot->formatXValue(currentValue, 2); + } else { + text= plot->formatXValue(currentValue - (interval.minValue() + midLabelTick * valueBetween2Labels), 2); + if (i > midLabelTick) { + text = "+" + text; + } + } + + const QSizeF textSize = QwtText(text).textSize(painter->font()); + QRectF textRect(QPointF(0.0, 0.0), textSize); + + textRect.moveCenter(QPointF(midPoint, textSize.height() / 2.0)); + + labelRectangles.push_back(textRect); + labelTexts.push_back(text); + + midPoint += distBetween2Labels; + currentValue += valueBetween2Labels; + } + + } + + // adjust labels to fit visible area of the handle area + // mainly the first and last label + if (labelRectangles.first().topLeft().x() < owner->mask().boundingRect().bottomLeft().x()) { + int offset = owner->mask().boundingRect().bottomLeft().x() - labelRectangles.first().topLeft().x(); + labelRectangles.first().adjust(offset, 0, offset, 0); + } + + if (labelRectangles.last().bottomRight().x() > owner->mask().boundingRect().bottomRight().x()) { + int offset = labelRectangles.last().bottomRight().x() - owner->mask().boundingRect().bottomRight().x(); + labelRectangles.last().adjust(-offset, 0, -offset, 0); + } + + // filter out overlaping labels, but always drawing + // the first and last label + bool overlaping = false; + do { + // consider none overlaping + overlaping = false; + + // find overlaping + int i = 0; + for (; i < labelRectangles.size() - 1; ++i) { + if (labelRectangles[i].intersects(labelRectangles[i + 1])) { + overlaping = true; + break; + } + } + + // done + if (!overlaping) { + break; + } + if (allLabelsTheSame) { + int center = midLabelTick; + for (int i = center - 1; i >= 0; i -= 2) { + // Remove the tick and make sure to update the center + // label position + labelRectangles.removeAt(i); + labelTexts.removeAt(i); + --center; + } + for (int j = center + 1; j < labelRectangles.size(); j += 1) { + labelRectangles.removeAt(j); + labelTexts.removeAt(j); + } + + } else { + // remove overlaping + if (i + 1 == labelRectangles.size() - 1) { + labelRectangles.removeAt(i); + labelTexts.removeAt(i); + } else { + labelRectangles.removeAt(i + 1); + labelTexts.removeAt(i + 1); + } + } + } while(overlaping); + } + + // draw the labels + for (int i = 0; i < labelRectangles.size(); ++i) { + painter->drawText(labelRectangles[i], labelTexts[i]); + } + + return false; +} + +YLeftRuller::YLeftRuller(QwtPlot *plot) + : HandlesAreaExtension(plot) {} + +bool YLeftRuller::draw(QPainter *painter, QWidget *owner) +{ + VertHandlesArea *area = qobject_cast(owner); + if (!area) { + return false; + } + + auto width_text = QFontMetrics(painter->font()).horizontalAdvance("-XXX.XX XX"); + if(area->width() != width_text) + area->setMinimumWidth(width_text); + + const DisplayPlot *plot = qobject_cast(m_plot); + if (!plot) { + return false; + } + + + const double topP = area->topPadding(); + const double bottomP = area->bottomPadding(); + + QVector labelRectangles; + QStringList labelTexts; + + if(plot->isLogaritmicYPlot()) + { + QList majorTicks = plot->getYaxisMajorTicksPos(); + double pointVal, currentValue; + + for (int i = 0; i < majorTicks.size(); ++i) { + currentValue = majorTicks.at(i); + pointVal = plot->transform(QwtPlot::yLeft, currentValue) + topP; + + const QString text = plot->formatYValue(currentValue, 2); + + const QSizeF textSize = QwtText(text).textSize(painter->font()); + QRectF textRect(QPointF(0.0, 0.0), textSize); + + textRect.moveCenter(QPointF(textSize.width() / 2.0, pointVal)); + + labelRectangles.push_back(textRect); + labelTexts.push_back(text); + } + + // adjust labels to fit visible area of the handle area + // mainly the first and last label + if(!labelRectangles.empty()) + { + if (labelRectangles.first().topRight().y() < owner->mask().boundingRect().topLeft().y()) { + int offset = owner->mask().boundingRect().topLeft().y() - labelRectangles.first().topRight().y(); + labelRectangles.first().adjust(0, offset, 0, offset); + } + + if (labelRectangles.last().bottomRight().y() > owner->mask().boundingRect().bottomLeft().y()) { + int offset = labelRectangles.last().bottomRight().y() - owner->mask().boundingRect().bottomLeft().y(); + labelRectangles.last().adjust(0, -offset, 0, -offset); + } + } + } + else + { + + const QwtInterval interval = plot->axisInterval(QwtPlot::yLeft); + + const int labels = plot->yAxisNumDiv(); + + const double totalHeight = owner->height() - (topP + bottomP); + const double distBetween2Labels = totalHeight / (labels - 1); + const double valueBetween2Labels = (interval.maxValue() - interval.minValue()) / (labels - 1); + + double midPoint = topP; + double currentValue = interval.maxValue(); + + for (int i = 0; i < labels; ++i) { + const QString text = plot->formatYValue(currentValue, 2); + QSizeF textSize = QwtText(text).textSize(painter->font()); + textSize.setWidth(textSize.width() + 20); + + QRectF textRect(QPointF(0.0, 0.0), textSize); + + textRect.moveCenter(QPointF(textSize.width() / 2.0, midPoint)); + + labelRectangles.push_back(textRect); + labelTexts.push_back(text); + + midPoint += distBetween2Labels; + currentValue -= valueBetween2Labels; + } + + bool allLabelsTheSame = true; + for (int i = 1; i < labelTexts.size(); ++i) { + if (labelTexts[i] != labelTexts[i - 1]) { + allLabelsTheSame = false; + break; + } + } + + // get nr of major ticks + const int nrMajorTicks = plot->axisScaleDiv(QwtPlot::yLeft).ticks(QwtScaleDiv::MajorTick).size(); + const int midLabelTick = nrMajorTicks / 2; + + if (allLabelsTheSame) { + // draw delta as middle label + labelRectangles.clear(); + labelTexts.clear(); + midPoint = topP; + currentValue = interval.maxValue(); + for (int i = 0; i < labels; ++i) { + QString text; + if (i == midLabelTick) { + text = plot->formatYValue(currentValue, 2); + } else { + text = plot->formatYValue(currentValue - (interval.maxValue() + midLabelTick * valueBetween2Labels), 2); + if (i > midLabelTick) { + text = "+" + text; + } + } + + QSizeF textSize = QwtText(text).textSize(painter->font()); + textSize.setWidth(textSize.width() + 20); + QRectF textRect(QPointF(0.0, 0.0), textSize); + textRect.moveCenter(QPointF(textSize.width() / 2.0, midPoint)); + + labelRectangles.push_back(textRect); + labelTexts.push_back(text); + + midPoint += distBetween2Labels; + currentValue -= valueBetween2Labels; + } + } + + // adjust labels to fit visible area of the handle area + // mainly the first and last label + if (labelRectangles.first().topRight().y() < owner->mask().boundingRect().topLeft().y()) { + int offset = owner->mask().boundingRect().topLeft().y() - labelRectangles.first().topRight().y(); + labelRectangles.first().adjust(0, offset, 0, offset); + } + + if (labelRectangles.last().bottomRight().y() > owner->mask().boundingRect().bottomLeft().y()) { + int offset = labelRectangles.last().bottomRight().y() - owner->mask().boundingRect().bottomLeft().y(); + labelRectangles.last().adjust(0, -offset, 0, -offset); + } + + // filter out overlaping labels, but always drawing + // the first and last label + bool overlaping = false; + do { + // consider none overlaping + overlaping = false; + + // find overlaping + int i = 0; + for (; i < labelRectangles.size() - 1; ++i) { + if (labelRectangles[i].intersects(labelRectangles[i + 1])) { + overlaping = true; + break; + } + } + + // done + if (!overlaping) { + break; + } + if (allLabelsTheSame) { + int center = midLabelTick; + for (int i = center - 1; i >= 0; i -= 2) { + // Remove the tick and make sure to update the center + // label position + labelRectangles.removeAt(i); + labelTexts.removeAt(i); + --center; + } + for (int j = center + 1; j < labelRectangles.size(); j += 1) { + labelRectangles.removeAt(j); + labelTexts.removeAt(j); + } + + }else { + // remove overlaping + if (i + 1 == labelRectangles.size() - 1) { + labelRectangles.removeAt(i); + labelTexts.removeAt(i); + } else { + labelRectangles.removeAt(i + 1); + labelTexts.removeAt(i + 1); + } + } + }while(overlaping); + } + + // draw the labels + for (int i = 0; i < labelRectangles.size(); ++i) { + painter->drawText(labelRectangles[i], labelTexts[i]); + } + + return false; +} diff --git a/src/handlesareaextension.h b/src/handlesareaextension.h index 70fd6a9879..2c67f18556 100644 --- a/src/handlesareaextension.h +++ b/src/handlesareaextension.h @@ -28,5 +28,20 @@ class XBottomRuller: public HandlesAreaExtension { virtual bool draw(QPainter *painter, QWidget *owner) Q_DECL_OVERRIDE; }; +class YLeftRuller: public HandlesAreaExtension { +public: + YLeftRuller(QwtPlot *plot); + virtual ~YLeftRuller() = default; + + virtual bool draw(QPainter *painter, QWidget *owner) Q_DECL_OVERRIDE; +}; + +class XTopRuller: public HandlesAreaExtension { +public: + XTopRuller(QwtPlot *plot); + virtual ~XTopRuller() = default; + + virtual bool draw(QPainter *painter, QWidget *owner) Q_DECL_OVERRIDE; +}; #endif // HANDLESAREAEXTENSION_H diff --git a/src/info_page.cpp b/src/info_page.cpp index 2bd36d901a..23d6e5511d 100644 --- a/src/info_page.cpp +++ b/src/info_page.cpp @@ -253,7 +253,8 @@ void InfoPage::refreshInfoWidget() int pos = 0; ui->paramLayout->setRowMinimumHeight(pos, 20); - for (auto key : m_info_params.keys()) { + auto info_param_keys = m_info_params.keys(); + for (const auto &key : qAsConst(info_param_keys)) { QLabel *valueLbl = new QLabel(this); QLabel *keyLbl = new QLabel(this); valueLbl->setText(m_info_params.value(key)); @@ -272,7 +273,8 @@ void InfoPage::refreshInfoWidget() pos++; ui->paramLayout->addWidget(new QLabel("Advanced"), pos, 0, 1, 1); pos++; - for (auto key : m_info_params_advanced.keys()) { + auto info_params_advanced = m_info_params_advanced.keys(); + for (const auto &key : qAsConst(info_params_advanced)) { QLabel *valueLbl = new QLabel(this); QLabel *keyLbl = new QLabel(this); @@ -503,7 +505,7 @@ void M2kInfoPage::refreshTemperature() libm2k::context::contextClose(temp_m2k, false); } - refreshInfoWidget(); + QMetaObject::invokeMethod(this,"refreshInfoWidget",Qt::QueuedConnection); } void M2kInfoPage::setCtx(iio_context *ctx) diff --git a/src/info_page.hpp b/src/info_page.hpp index b79b44d05b..19deef669d 100644 --- a/src/info_page.hpp +++ b/src/info_page.hpp @@ -68,8 +68,6 @@ class InfoPage : public QWidget QPushButton *calibrateButton(); virtual void getDeviceInfo(); - void refreshInfoWidget(); - void setConnectionStatus(bool); bool supportsIdentification(); bool supportsCalibration(); @@ -81,7 +79,7 @@ public Q_SLOTS: void readPreferences(); void identifyDevice(bool clicked = true); void setStatusLabel(QLabel *lbl, QString str = "", QString color="white"); - + void refreshInfoWidget(); void setCalibrationStatusLabel(QString str = "", QString color = "white"); void setCalibrationInfoLabel(QString str = "", QString color = "white"); diff --git a/src/logicanalyzer/annotationdecoder.cpp b/src/logicanalyzer/annotationdecoder.cpp index 8e9e7e77c9..ffcdf47df6 100644 --- a/src/logicanalyzer/annotationdecoder.cpp +++ b/src/logicanalyzer/annotationdecoder.cpp @@ -29,6 +29,8 @@ using namespace adiscope; constexpr uint64_t MAX_CHUNK_SIZE = 256 * 1024; +std::mutex AnnotationDecoder::g_sessionMutex; + void AnnotationDecoder::initDecoderChannels() { uint16_t id = 0; @@ -243,6 +245,8 @@ void AnnotationDecoder::stopDecode() m_decodeThread = nullptr; } + std::lock_guard srd_lock(g_sessionMutex); + if (m_srdSession) { srd_session_destroy(m_srdSession); m_srdSession = nullptr; @@ -371,6 +375,8 @@ void AnnotationDecoder::stackChanged() { stopDecode(); + std::lock_guard srd_lock(g_sessionMutex); + if (srd_session_new(&m_srdSession) != SRD_OK) { qDebug() << "srd_session_new returned error!"; } else { @@ -495,6 +501,7 @@ void AnnotationDecoder::decodeProc() memcpy(chunk.get(), data + start, chunkSize * sizeof(uint16_t)); // qDebug() << "send data!"; + std::lock_guard srd_lock(g_sessionMutex); if (srd_session_send(m_srdSession, start, stop, reinterpret_cast( chunk.get()), chunkSize, sizeof(uint16_t)) != SRD_OK) { diff --git a/src/logicanalyzer/annotationdecoder.h b/src/logicanalyzer/annotationdecoder.h index f016089035..e136d2fe2f 100644 --- a/src/logicanalyzer/annotationdecoder.h +++ b/src/logicanalyzer/annotationdecoder.h @@ -85,6 +85,7 @@ class AnnotationDecoder std::atomic m_decodeCanceled; std::mutex m_newDataMutex; std::condition_variable m_newDataCv; + static std::mutex g_sessionMutex; std::queue> m_newDataQueue; void initDecoderChannels(); }; diff --git a/src/logicanalyzer/logic_analyzer.cpp b/src/logicanalyzer/logic_analyzer.cpp index 0607bc298c..0a820e86f2 100644 --- a/src/logicanalyzer/logic_analyzer.cpp +++ b/src/logicanalyzer/logic_analyzer.cpp @@ -80,7 +80,7 @@ LogicAnalyzer::LogicAnalyzer(struct iio_context *ctx, adiscope::Filter *filt, bool offline_mode_): LogicTool(nullptr, toolMenuItem, new LogicAnalyzer_API(this), "Logic Analyzer", parent), ui(new Ui::LogicAnalyzer), - m_plot(this, 16, 10), + m_plot(this, false, 16, 10), m_bufferPreviewer(new DigitalBufferPreviewer(40, this)), m_m2k_context(m2kOpen(ctx, "")), m_m2kDigital(m_m2k_context->getDigital()), @@ -1348,7 +1348,7 @@ void LogicAnalyzer::setupUi() setDynamicProperty(cr_ui->btnLockHorizontal, "use_icon", true); - auto cursorsPositionButton = new CustomPlotPositionButton(cr_ui->posSelect); + cursorsPositionButton = new CustomPlotPositionButton(cr_ui->posSelect); connect(cursorsPositionButton, &CustomPlotPositionButton::positionChanged, [=](CustomPlotPositionButton::ReadoutsPosition position){ m_plot.moveCursorReadouts(position); @@ -1357,11 +1357,9 @@ void LogicAnalyzer::setupUi() cursorsPositionButton->setPosition(CustomPlotPositionButton::ReadoutsPosition::bottomRight); // Disable some options we don't need for this cursor settings panel - cr_ui->btnNormalTrack->setVisible(false); - cr_ui->label_3->setVisible(false); - cr_ui->line_3->setVisible(false); - cr_ui->vCursorsEnable->setVisible(false); - cr_ui->btnLockVertical->setVisible(false); + cr_ui->widgteBtnNormalTrack->setVisible(false); + cr_ui->widgetVertical->setVisible(false); + cr_ui->widgetVerticalBtns->setVisible(false); cr_ui->horizontalSlider->setMaximum(100); cr_ui->horizontalSlider->setMinimum(0); @@ -2330,11 +2328,12 @@ void LogicAnalyzer::setupTriggerMenu() connect(ui->btnEnableExternalTrigger, &CustomSwitch::toggled, [=](bool on){ if (on) { - int source = ui->externalTriggerSourceComboBox->currentIndex(); - int condition = ui->externalTriggerConditionComboBox->currentIndex(); + const int source = ui->externalTriggerSourceComboBox->currentIndex(); + const int condition = ui->externalTriggerConditionComboBox->currentIndex(); m_m2kDigital->getTrigger()->setDigitalSource(static_cast(source)); m_m2kDigital->getTrigger()->setDigitalExternalCondition( static_cast((condition + 5) % 6)); + ui->externalTriggerConditionComboBox->setDisabled(source); } else { m_m2kDigital->getTrigger()->setDigitalSource(M2K_TRIGGER_SOURCE_DIGITAL::SRC_NONE); } @@ -2408,7 +2407,7 @@ void LogicAnalyzer::restoreTriggerState() void LogicAnalyzer::readPreferences() { qDebug() << "reading preferences!!!!"; - for (GenericLogicPlotCurve *curve : m_plotCurves) { + for (GenericLogicPlotCurve *curve : qAsConst(m_plotCurves)) { if (curve->getType() == LogicPlotCurveType::Data) { LogicDataCurve *ldc = dynamic_cast(curve); if (!ldc) { @@ -2433,7 +2432,8 @@ void LogicAnalyzer::exportData() bool noChannelEnabled = true; m_exportConfig = m_exportSettings->getExportConfig(); - for (auto x : m_exportConfig.keys()) { + auto keys = m_exportConfig.keys(); + for (auto x : qAsConst(keys)) { if(m_exportConfig[x]) { noChannelEnabled = false; break; @@ -2460,20 +2460,24 @@ void LogicAnalyzer::exportData() // Check the selected file type if (selectedFilter != "") { if(selectedFilter.contains("comma", Qt::CaseInsensitive)) { - fileName += ".csv"; separator = ","; } if(selectedFilter.contains("tab", Qt::CaseInsensitive)) { - fileName += ".txt"; separator = "\t"; } if(selectedFilter.contains("Change Dump", Qt::CaseInsensitive)) { endRow = " $end\n"; startRow = "$"; - fileName += ".vcd"; } } + if (fileName.split(".").size() <= 1) { + // file name w/o extension. Let's append it + QString ext = selectedFilter.split(".")[1].split(")")[0]; + fileName += "." + ext; + } + + if (separator != "") { done = exportTabCsv(separator, fileName); diff --git a/src/logicanalyzer/logic_analyzer.h b/src/logicanalyzer/logic_analyzer.h index 2f9ac9722b..13cb0e4b41 100644 --- a/src/logicanalyzer/logic_analyzer.h +++ b/src/logicanalyzer/logic_analyzer.h @@ -149,6 +149,7 @@ private Q_SLOTS: // TODO: consisten naming (m_ui, m_crUi) Ui::LogicAnalyzer *ui; Ui::CursorsSettings *cr_ui; + CustomPlotPositionButton *cursorsPositionButton; QList m_menuOrder; QQueue> m_menuButtonActions; diff --git a/src/logicanalyzer/logicanalyzer_api.cpp b/src/logicanalyzer/logicanalyzer_api.cpp index 3629448e62..b3ef6a67af 100644 --- a/src/logicanalyzer/logicanalyzer_api.cpp +++ b/src/logicanalyzer/logicanalyzer_api.cpp @@ -24,6 +24,7 @@ #include "annotationcurve.h" #include "annotationdecoder.h" +#include "ui_cursors_settings.h" #include #include @@ -176,7 +177,7 @@ QList>> LogicAnalyzer_API::getAssignedDecoderChannels() co } auto stack = annCurve->getDecoderStack(); QList> assignedChannels; - for (std::shared_ptr decoder : stack) { + for (const std::shared_ptr &decoder : stack) { for (const auto &ch : decoder->channels()) { if (ch->assigned_signal) { assignedChannels.push_back({ch->id, ch->bit_id}); @@ -261,7 +262,7 @@ QList LogicAnalyzer_API::getDecoderSettings() const QJsonObject obj; QJsonArray propArray; - for(auto p : bindings[i]->properties()) { + for(const auto &p : bindings[i]->properties()) { QJsonObject propObj; QString prop_name(p->name()); @@ -344,7 +345,7 @@ void LogicAnalyzer_API::setDecoderSettings(const QList &decoderSett } QJsonArray propArray = obj["properties"].toArray(); - for (auto propRef : propArray) { + for (const auto &propRef : qAsConst(propArray)) { auto prop = propRef.toObject(); for(auto p : binding->properties()) { @@ -403,7 +404,69 @@ QString LogicAnalyzer_API::getNotes() { return m_logic->ui->instrumentNotes->getNotes(); } + void LogicAnalyzer_API::setNotes(QString str) { m_logic->ui->instrumentNotes->setNotes(str); } + +bool LogicAnalyzer_API::hasCursors() const +{ + return m_logic->ui->cursorsBox->isChecked(); +} + +void LogicAnalyzer_API::setCursors(bool en) +{ + m_logic->ui->cursorsBox->setChecked(en); +} + +int LogicAnalyzer_API::getCursorsPosition() const +{ + if (!hasCursors()) { + return 0; + } + auto currentPos = m_logic->m_plot.getCursorReadouts()->getCurrentPosition(); + switch (currentPos) { + case CustomPlotPositionButton::ReadoutsPosition::topLeft: + default: + return 0; + case CustomPlotPositionButton::ReadoutsPosition::topRight: + return 1; + case CustomPlotPositionButton::ReadoutsPosition::bottomLeft: + return 2; + case CustomPlotPositionButton::ReadoutsPosition::bottomRight: + return 3; + } + return 2; +} + +void LogicAnalyzer_API::setCursorsPosition(int val) +{ + if (!hasCursors()) { + return; + } + enum CustomPlotPositionButton::ReadoutsPosition types[] = { + CustomPlotPositionButton::ReadoutsPosition::topLeft, + CustomPlotPositionButton::ReadoutsPosition::topRight, + CustomPlotPositionButton::ReadoutsPosition::bottomLeft, + CustomPlotPositionButton::ReadoutsPosition::bottomRight + }; + m_logic->cursorsPositionButton->setPosition(types[val]); + m_logic->m_plot.replot(); +} + +int LogicAnalyzer_API::getCursorsTransparency() const +{ + if (!hasCursors()) { + return 0; + } + return m_logic->cr_ui->horizontalSlider->value(); +} + +void LogicAnalyzer_API::setCursorsTransparency(int val) +{ + if (!hasCursors()) { + return; + } + m_logic->cr_ui->horizontalSlider->setValue(val); +} diff --git a/src/logicanalyzer/logicanalyzer_api.h b/src/logicanalyzer/logicanalyzer_api.h index fcef82e67c..25f76ba047 100644 --- a/src/logicanalyzer/logicanalyzer_api.h +++ b/src/logicanalyzer/logicanalyzer_api.h @@ -31,6 +31,13 @@ class LogicAnalyzer_API : public ApiObject { Q_OBJECT + /*cursor settings*/ + Q_PROPERTY(bool cursors READ hasCursors WRITE setCursors); + Q_PROPERTY(int cursors_position READ getCursorsPosition + WRITE setCursorsPosition) + Q_PROPERTY(int cursors_transparency READ getCursorsTransparency + WRITE setCursorsTransparency) + /* sweep settings */ Q_PROPERTY(bool streamOneShot READ getStreamOrOneShot WRITE setStreamOrOneShot) Q_PROPERTY(double sampleRate READ getSampleRate WRITE setSampleRate) @@ -124,6 +131,15 @@ class LogicAnalyzer_API : public ApiObject private: logic::LogicAnalyzer *m_logic; + + bool hasCursors() const; + void setCursors(bool en); + + int getCursorsPosition() const; + void setCursorsPosition(int val); + + int getCursorsTransparency() const; + void setCursorsTransparency(int val); }; } } diff --git a/src/main.cpp b/src/main.cpp index 977452b3f0..2518826167 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -147,8 +147,6 @@ int main(int argc, char **argv) myappTranslator.load(languageFileName); app.installTranslator(&myappTranslator); - ToolLauncher launcher(prevCrashDump); - ScopyColorEditor *colorEditor = new ScopyColorEditor(&app); colorEditor->setVisible(false); @@ -161,6 +159,7 @@ int main(int argc, char **argv) app.setStyleSheet(colorEditor->getStyleSheet()); } + ToolLauncher launcher(prevCrashDump); launcher.getPrefPanel()->setColorEditor(colorEditor); bool nogui = parser.isSet("nogui"); diff --git a/src/network_analyzer.cpp b/src/network_analyzer.cpp index 933aa00390..bb223ed04c 100644 --- a/src/network_analyzer.cpp +++ b/src/network_analyzer.cpp @@ -181,6 +181,8 @@ NetworkAnalyzer::NetworkAnalyzer(struct iio_context *ctx, Filter *filt, m_dac_nb_channels(0), d_cursorsEnabled(false), m_stop(true), + m_dBgraph(this, true), + m_phaseGraph(this, true), wheelEventGuard(nullptr), wasChecked(false), justStarted(false), iterationsThreadCanceled(false), iterationsThreadReady(false), @@ -418,14 +420,52 @@ NetworkAnalyzer::NetworkAnalyzer(struct iio_context *ctx, Filter *filt, connect(ui->cbLineThickness,SIGNAL(currentIndexChanged(int)),ui->xygraph, SLOT(setThickness(int))); - d_bottomHandlesArea = new HorizHandlesArea(this); - d_bottomHandlesArea->setMinimumHeight(50); + m_phaseGraph.setVertCursorsHandleEnabled(false); + + ui->gridLayout_plots->addWidget(bufferPreviewer, 0, 1, 1, 1); + ui->gridLayout_plots->addWidget(ui->statusWidget, 1, 1, 1, 1); + ui->gridLayout_plots->addWidget(m_dBgraph.rightHandlesArea(), 0, 2, 6, 1); + ui->gridLayout_plots->addWidget(m_dBgraph.topHandlesArea(), 2, 0, 1, 2); + ui->gridLayout_plots->addWidget(m_dBgraph.leftHandlesArea(), 3, 0, 1, 1); + ui->gridLayout_plots->addWidget(&m_dBgraph, 3, 1, 1, 1); + + ui->gridLayout_plots->addWidget(m_phaseGraph.topHandlesArea(), 4, 0, 1, 2); + ui->gridLayout_plots->addWidget(m_phaseGraph.leftHandlesArea(), 5, 0, 1, 1); + ui->gridLayout_plots->addWidget(&m_phaseGraph, 5, 1, 1, 1); + + ui->gridLayout_plots->addWidget(m_dBgraph.bottomHandlesArea(), 6, 0, 1, 3); + + m_phaseGraph.enableXaxisLabels(); + m_dBgraph.enableXaxisLabels(); + + m_phaseGraph.enableYaxisLabels(); + m_dBgraph.enableYaxisLabels(); + + connect(m_dBgraph.vBar1(), static_cast(&HorizDebugSymbol::positionChanged), + [=](double x) + { + m_phaseGraph.vBar1()->setPosition(x); + }); + + connect(m_dBgraph.vBar2(), static_cast(&HorizDebugSymbol::positionChanged), + [=](double x) + { + m_phaseGraph.vBar2()->setPosition(x); + }); + + //The inverse connection is neccesary for the change of the boundaries for sweep + connect(m_phaseGraph.vBar1(), static_cast(&HorizDebugSymbol::positionChanged), + [=](double x) + { + m_dBgraph.vBar1()->setPosition(x); + }); + + connect(m_phaseGraph.vBar2(), static_cast(&HorizDebugSymbol::positionChanged), + [=](double x) + { + m_dBgraph.vBar2()->setPosition(x); + }); - ui->gridLayout_plots->addWidget(bufferPreviewer, 0, 0, 1, 1); - ui->gridLayout_plots->addWidget(ui->statusWidget, 1, 0, 1, 1); - ui->gridLayout_plots->addWidget(&m_dBgraph, 2, 0, 1, 1); - ui->gridLayout_plots->addWidget(&m_phaseGraph, 3, 0, 1, 1); - ui->gridLayout_plots->addWidget(d_bottomHandlesArea, 4, 0, 1, 1); ui->currentFrequencyLabel->setVisible(false); ui->currentSampleLabel->setVisible(false); @@ -435,16 +475,10 @@ NetworkAnalyzer::NetworkAnalyzer(struct iio_context *ctx, Filter *filt, QPixmap(":/icons/time_trigger_handle.svg"), QPixmap(":/icons/time_trigger_left.svg"), QPixmap(":/icons/time_trigger_right.svg"), - d_bottomHandlesArea); + m_dBgraph.bottomHandlesArea()); d_frequencyHandle->setPen(QPen(QColor(74, 100, 255), 2, Qt::SolidLine)); d_frequencyHandle->setVisible(true); - - d_hCursorHandle1 = new PlotLineHandleH( - QPixmap(":/icons/h_cursor_handle.svg"), - d_bottomHandlesArea); - d_hCursorHandle2 = new PlotLineHandleH( - QPixmap(":/icons/h_cursor_handle.svg"), - d_bottomHandlesArea); + d_frequencyHandle->triggerMove(); ui->nicholsgraph->enableFrequencyBar(false); @@ -493,26 +527,6 @@ NetworkAnalyzer::NetworkAnalyzer(struct iio_context *ctx, Filter *filt, connect(&m_dBgraph, &dBgraph::frequencySelected, bufferPreviewer, &NetworkAnalyzerBufferViewer::selectBuffers); - QPen cursorsLinePen = QPen(QColor(155,155,155),1,Qt::DashLine); - d_hCursorHandle1->setPen(cursorsLinePen); - d_hCursorHandle2->setPen(cursorsLinePen); - d_hCursorHandle1->setVisible(false); - d_hCursorHandle2->setVisible(false); - - connect(&m_dBgraph,SIGNAL(VBar1PixelPosChanged(int)), - SLOT(onVbar1PixelPosChanged(int))); - connect(&m_dBgraph,SIGNAL(VBar2PixelPosChanged(int)), - SLOT(onVbar2PixelPosChanged(int))); - - connect(d_hCursorHandle1, SIGNAL(positionChanged(int)),&m_dBgraph, - SLOT(onCursor1PositionChanged(int))); - connect(d_hCursorHandle2, SIGNAL(positionChanged(int)),&m_dBgraph, - SLOT(onCursor2PositionChanged(int))); - connect(d_hCursorHandle1, SIGNAL(positionChanged(int)),&m_phaseGraph, - SLOT(onCursor1PositionChanged(int))); - connect(d_hCursorHandle2, SIGNAL(positionChanged(int)),&m_phaseGraph, - SLOT(onCursor2PositionChanged(int))); - startStopRange->setStopValue((double) max_samplerate / 3.0 - 1.0); connect(samplesCount, SIGNAL(valueChanged(double)), @@ -573,6 +587,20 @@ NetworkAnalyzer::NetworkAnalyzer(struct iio_context *ctx, Filter *filt, m_phaseGraph.setCursorReadoutsTransparency(value); }); + setDynamicProperty(ui->btnLockHorizontal, "use_icon", true); + + connect(ui->btnLockHorizontal, &QPushButton::toggled, + &m_dBgraph, &dBgraph::setHorizCursorsLocked); + + connect(ui->btnLockHorizontal, &QPushButton::toggled, + &m_phaseGraph, &dBgraph::setHorizCursorsLocked); + + connect(ui->hCursorsEnable, &QPushButton::toggled, + &m_dBgraph, &dBgraph::toggleCursors); + + connect(ui->hCursorsEnable, &QPushButton::toggled, + &m_phaseGraph, &dBgraph::toggleCursors); + connect(ui->posSelect, &CustomPlotPositionButton::positionChanged, [=](CustomPlotPositionButton::ReadoutsPosition position) { m_dBgraph.moveCursorReadouts(position); @@ -787,7 +815,7 @@ void NetworkAnalyzer::computeIterations() // it is safe to modify without using a lock iterationsThreadCanceled = false; iterationsThreadReady = false; - iterationsThread = new boost::thread(boost::bind(&NetworkAnalyzer::computeFrequencyArray, this)); + iterationsThread = new std::thread(boost::bind(&NetworkAnalyzer::computeFrequencyArray, this)); } void NetworkAnalyzer::setMinimumDistanceBetween(SpinBoxA *min, SpinBoxA *max, @@ -838,17 +866,6 @@ void NetworkAnalyzer::rightMenuFinished(bool opened) void NetworkAnalyzer::showEvent(QShowEvent *event) { - d_bottomHandlesArea->setLeftPadding(m_dBgraph.axisWidget(QwtAxisId( - QwtPlot::yLeft, 0))->width() - + ui->gridLayout_plots->margin() - + ui->widgetPlotContainer->layout()->margin() + 1); - int rightPadding = 0; - rightPadding = rightPadding + m_dBgraph.width() - - m_dBgraph.axisWidget(QwtPlot::yLeft)->width() - m_dBgraph.canvas()->width() - - ui->widgetPlotContainer->layout()->margin() ; - d_bottomHandlesArea->setRightPadding(rightPadding); - d_hCursorHandle1->setPosition(d_hCursorHandle1->pos().x()); - d_hCursorHandle2->setPosition(d_hCursorHandle2->pos().x()); Tool::showEvent(event); } @@ -1744,16 +1761,6 @@ void NetworkAnalyzer::configHwForNetworkAnalyzing() } } -void NetworkAnalyzer::onVbar1PixelPosChanged(int pos) -{ - d_hCursorHandle1->setPositionSilenty(pos); -} - -void NetworkAnalyzer::onVbar2PixelPosChanged(int pos) -{ - d_hCursorHandle2->setPositionSilenty(pos); -} - void NetworkAnalyzer::toggleCursors(bool en) { if (!en) { @@ -1764,11 +1771,8 @@ void NetworkAnalyzer::toggleCursors(bool en) d_cursorsEnabled = en; m_dBgraph.toggleCursors(en); m_phaseGraph.toggleCursors(en); - d_hCursorHandle1->setVisible(en); - d_hCursorHandle2->setVisible(en); ui->btnCursors->setEnabled(en); } - } void NetworkAnalyzer::readPreferences() diff --git a/src/network_analyzer.hpp b/src/network_analyzer.hpp index 854ee1d7f2..26a699645d 100644 --- a/src/network_analyzer.hpp +++ b/src/network_analyzer.hpp @@ -148,7 +148,7 @@ class NetworkAnalyzer : public Tool QVector iterations; QVector iterationStats; - boost::thread *iterationsThread; + std::thread *iterationsThread; bool iterationsThreadCanceled; bool iterationsThreadReady; @@ -197,8 +197,6 @@ class NetworkAnalyzer : public Tool bool justStarted; bool autoAdjustGain; - PlotLineHandleH *d_hCursorHandle1; - PlotLineHandleH *d_hCursorHandle2; FreePlotLineHandleH *d_frequencyHandle; bool d_cursorsEnabled; @@ -217,8 +215,6 @@ class NetworkAnalyzer : public Tool void setMinimumDistanceBetween(SpinBoxA *min, SpinBoxA *max, double distance); - HorizHandlesArea *d_bottomHandlesArea; - QQueue> menuButtonActions; MouseWheelWidgetGuard *wheelEventGuard; @@ -271,8 +267,6 @@ private Q_SLOTS: void _saveChannelBuffers(double frequency, double sample_rate, std::vector data1, std::vector data2); void toggleCursors(bool en); - void onVbar1PixelPosChanged(int pos); - void onVbar2PixelPosChanged(int pos); void readPreferences(); void onGraphIndexChanged(int); void on_btnExport_clicked(); diff --git a/src/network_analyzer_api.cpp b/src/network_analyzer_api.cpp index 97e8bc6c13..1b953f96fb 100644 --- a/src/network_analyzer_api.cpp +++ b/src/network_analyzer_api.cpp @@ -163,7 +163,7 @@ bool NetworkAnalyzer_API::getCursors() const void NetworkAnalyzer_API::setCursors(bool enabled) { - net->ui->boxCursors->setChecked(enabled); + net->ui->boxCursors->setChecked(enabled); } bool NetworkAnalyzer_API::running() const @@ -178,58 +178,59 @@ void NetworkAnalyzer_API::run(bool enabled) int NetworkAnalyzer_API::getCursorsPosition() const { - if (!net->ui->boxCursors->isChecked()) { - return 0; - } - auto currentPos = net->m_dBgraph.getCursorReadoutCurrentPosition(); - switch (currentPos) { - case CustomPlotPositionButton::ReadoutsPosition::topLeft: - default: - return 0; - case CustomPlotPositionButton::ReadoutsPosition::topRight: - return 1; - case CustomPlotPositionButton::ReadoutsPosition::bottomLeft: - return 2; - case CustomPlotPositionButton::ReadoutsPosition::bottomRight: - return 3; - } + if (!net->ui->boxCursors->isChecked()) { + return 0; + } + auto currentPos = net->m_dBgraph.d_cursorReadouts->getCurrentPosition(); + switch (currentPos) { + case CustomPlotPositionButton::ReadoutsPosition::topLeft: + default: + return 0; + case CustomPlotPositionButton::ReadoutsPosition::topRight: + return 1; + case CustomPlotPositionButton::ReadoutsPosition::bottomLeft: + return 2; + case CustomPlotPositionButton::ReadoutsPosition::bottomRight: + return 3; + } + return 2; } void NetworkAnalyzer_API::setCursorsPosition(int val) { - if (!net->ui->boxCursors->isChecked()) { - return; - } - enum CustomPlotPositionButton::ReadoutsPosition types[] = { - CustomPlotPositionButton::ReadoutsPosition::topLeft, - CustomPlotPositionButton::ReadoutsPosition::topRight, - CustomPlotPositionButton::ReadoutsPosition::bottomLeft, - CustomPlotPositionButton::ReadoutsPosition::bottomRight - }; - net->ui->posSelect->setPosition(types[val]); - net->m_dBgraph.moveCursorReadouts(types[val]); - net->m_dBgraph.replot(); - net->m_phaseGraph.moveCursorReadouts(types[val]); - net->m_phaseGraph.replot(); + if (!net->ui->boxCursors->isChecked()) { + return; + } + enum CustomPlotPositionButton::ReadoutsPosition types[] = { + CustomPlotPositionButton::ReadoutsPosition::topLeft, + CustomPlotPositionButton::ReadoutsPosition::topRight, + CustomPlotPositionButton::ReadoutsPosition::bottomLeft, + CustomPlotPositionButton::ReadoutsPosition::bottomRight + }; + net->ui->posSelect->setPosition(types[val]); + net->m_dBgraph.moveCursorReadouts(types[val]); + net->m_dBgraph.replot(); + net->m_phaseGraph.moveCursorReadouts(types[val]); + net->m_phaseGraph.replot(); } int NetworkAnalyzer_API::getCursorsTransparency() const { - if (!net->ui->boxCursors->isChecked()) { - return 0; - } - return net->ui->horizontalSlider->value(); + if (!net->ui->boxCursors->isChecked()) { + return 0; + } + return net->ui->horizontalSlider->value(); } void NetworkAnalyzer_API::setCursorsTransparency(int val) { - if (!net->ui->boxCursors->isChecked()) { - return; - } - net->ui->horizontalSlider->setValue(val); - net->ui->transLabel->setText(tr("Transparency ") + QString::number(val) + "%"); - net->m_dBgraph.setCursorReadoutsTransparency(val); - net->m_phaseGraph.setCursorReadoutsTransparency(val); + if (!net->ui->boxCursors->isChecked()) { + return; + } + net->ui->horizontalSlider->setValue(val); + net->ui->transLabel->setText(tr("Transparency ") + QString::number(val) + "%"); + net->m_dBgraph.setCursorReadoutsTransparency(val); + net->m_phaseGraph.setCursorReadoutsTransparency(val); } diff --git a/src/network_analyzer_api.hpp b/src/network_analyzer_api.hpp index 5451f4fda2..5d927549ae 100644 --- a/src/network_analyzer_api.hpp +++ b/src/network_analyzer_api.hpp @@ -103,6 +103,7 @@ class NetworkAnalyzer_API : public ApiObject int getLineThickness() const; void setLineThickness(int index); + int getCursorsPosition() const; void setCursorsPosition(int val); diff --git a/src/osc_export_settings.cpp b/src/osc_export_settings.cpp index 2d4198ac94..e56eeee2eb 100644 --- a/src/osc_export_settings.cpp +++ b/src/osc_export_settings.cpp @@ -134,7 +134,9 @@ void ExportSettings::setExportConfig(QMap config) { QStandardItemModel *model = static_cast(exportChannels->model()); - for (int key : config.keys()) { + + auto keys = config.keys(); + for (int key : qAsConst(keys)) { model->item(key, 1)->setData(QVariant((int) config[key]), Qt::EditRole); } diff --git a/src/oscilloscope.cpp b/src/oscilloscope.cpp index 53e7708b97..b7be9c4057 100644 --- a/src/oscilloscope.cpp +++ b/src/oscilloscope.cpp @@ -107,7 +107,7 @@ Oscilloscope::Oscilloscope(struct iio_context *ctx, Filter *filt, ui(new Ui::Oscilloscope), trigger_settings(m_m2k_analogin), measure_settings(nullptr), - plot(this, 16, 10), + plot(this, false, 16, 10), fft_plot(nb_channels, this), xy_plot(nb_channels / 2, this), hist_plot(nb_channels, this), @@ -720,7 +720,9 @@ Oscilloscope::Oscilloscope(struct iio_context *ctx, Filter *filt, } auto max_elem = max_element(probe_attenuation.begin(), probe_attenuation.begin() + nb_channels); - for (auto rail : math_rails.values()) { + + auto const values = math_rails.values(); + for (auto rail : values) { rail->set_lo(MIN_MATH_RANGE); rail->set_hi(MAX_MATH_RANGE); } @@ -1936,7 +1938,9 @@ void Oscilloscope::btnExport_clicked(){ fileName += "." + ext; } bool atleastOneChannelEnabled = false; - for (auto x : exportConfig.keys()) + + auto keys = exportConfig.keys(); + for (auto x : qAsConst(keys)) if (exportConfig[x]){ atleastOneChannelEnabled = true; break; @@ -2193,7 +2197,8 @@ void Oscilloscope::create_add_channel_panel() if (tabWidget->currentIndex() != 0) { QMap import_map = importSettings->getExportConfig(); - for (int key : import_map.keys()) { + auto keys = import_map.keys(); + for (int key : qAsConst(keys)) { if (import_map[key]) { add_ref_waveform(key); } @@ -2979,7 +2984,7 @@ void Oscilloscope::onXY_view_toggled(bool visible) adc_samp_conv_block, i)); } } - for(auto p : math_sinks) { + for(const auto &p : qAsConst(math_sinks)) { auto math = p.first; xy_channels.push_back(QPair( math, 0)); diff --git a/src/oscilloscope_api.cpp b/src/oscilloscope_api.cpp index f59e483b27..a5323e4323 100644 --- a/src/oscilloscope_api.cpp +++ b/src/oscilloscope_api.cpp @@ -115,42 +115,42 @@ void Oscilloscope_API::setVerticalCursors(bool en) double Oscilloscope_API::cursorV1() const { - return osc->plot.value_v1; + return osc->plot.value_v1; } double Oscilloscope_API::cursorV2() const { - return osc->plot.value_v2; + return osc->plot.value_v2; } double Oscilloscope_API::cursorH1() const { - return osc->plot.value_h1; + return osc->plot.value_h1; } double Oscilloscope_API::cursorH2() const { - return osc->plot.value_h2; + return osc->plot.value_h2; } void Oscilloscope_API::setCursorV1(double val) { - osc->plot.d_vBar1->setPosition(val); + osc->plot.d_vBar1->setPosition(val); } void Oscilloscope_API::setCursorV2(double val) { - osc->plot.d_vBar2->setPosition(val); + osc->plot.d_vBar2->setPosition(val); } void Oscilloscope_API::setCursorH1(double val) { - osc->plot.d_hBar1->setPosition(val); + osc->plot.d_hBar1->setPosition(val); } void Oscilloscope_API::setCursorH2(double val) { - osc->plot.d_hBar2->setPosition(val); + osc->plot.d_hBar2->setPosition(val); } bool Oscilloscope_API::autoTrigger() const @@ -585,6 +585,7 @@ int Oscilloscope_API::getCursorsPosition() const case CustomPlotPositionButton::ReadoutsPosition::bottomRight: return 3; } + return 3; } void Oscilloscope_API::setCursorsPosition(int val) @@ -652,7 +653,7 @@ QVariantList Oscilloscope_API::getChannels() { QVariantList list; - for (Channel_API *each : osc->channels_api) { + for (Channel_API *each : qAsConst(osc->channels_api)) { list.append(QVariant::fromValue(each)); } return list; diff --git a/src/oscilloscope_plot.cpp b/src/oscilloscope_plot.cpp index abce26dc2b..7276a6f85d 100644 --- a/src/oscilloscope_plot.cpp +++ b/src/oscilloscope_plot.cpp @@ -40,9 +40,9 @@ using namespace adiscope; /* * OscilloscopePlot class */ -OscilloscopePlot::OscilloscopePlot(QWidget *parent, - unsigned int xNumDivs, unsigned int yNumDivs): - TimeDomainDisplayPlot(parent, xNumDivs, yNumDivs) +OscilloscopePlot::OscilloscopePlot(QWidget *parent, bool isdBgraph, + unsigned int xNumDivs, unsigned int yNumDivs): + TimeDomainDisplayPlot(parent, isdBgraph, xNumDivs, yNumDivs) { setYaxisUnit("V"); @@ -59,29 +59,21 @@ OscilloscopePlot::~OscilloscopePlot() /* * CapturePlot class */ -CapturePlot::CapturePlot(QWidget *parent, +CapturePlot::CapturePlot(QWidget *parent, bool isdBgraph, unsigned int xNumDivs, unsigned int yNumDivs): - OscilloscopePlot(parent, xNumDivs, yNumDivs), + OscilloscopePlot(parent, isdBgraph, xNumDivs, yNumDivs), d_triggerAEnabled(false), d_triggerBEnabled(false), - d_selected_channel(-1), d_measurementsEnabled(false), - d_cursorReadoutsVisible(false), d_bufferSizeLabelVal(0), d_sampleRateLabelVal(1.0), d_labelsEnabled(false), d_timeTriggerMinValue(-1), d_timeTriggerMaxValue(1), - d_trackMode(false), - horizCursorsLocked(false), - vertCursorsLocked(false), - d_horizCursorsEnabled(false), - d_vertCursorsEnabled(false), d_bonusWidth(0), d_gatingEnabled(false), m_conversion_function(nullptr), d_startedGrouping(false), - d_bottomHandlesArea(nullptr), d_xAxisInterval{0.0, 0.0}, d_currentHandleInitPx(30), d_maxBufferError(nullptr) @@ -98,42 +90,21 @@ CapturePlot::CapturePlot(QWidget *parent, d_timeTriggerActiveLinePen = QPen(QColor(74, 100, 255), 2, Qt::SolidLine); /* End of: Initial colors scheme */ - markerIntersection1 = new QwtPlotMarker(); - markerIntersection2 = new QwtPlotMarker(); - markerIntersection1->setSymbol(new QwtSymbol( - QwtSymbol::Ellipse, QColor(237, 28, 36), - QPen(QColor(255, 255 ,255, 140), 2, Qt::SolidLine), - QSize(5, 5))); - markerIntersection2->setSymbol(new QwtSymbol( - QwtSymbol::Ellipse, QColor(237, 28, 36), - QPen(QColor(255, 255 ,255, 140), 2, Qt::SolidLine), - QSize(5, 5))); - - d_symbolCtrl = new SymbolController(this); - setHorizUnitsPerDiv(1E-6); zoomBaseUpdate(); - /* Adjacent areas (top/bottom/left/right) */ + /* Adjacent areas */ d_topWidget = new QWidget(this); - d_topHandlesArea = new GateHandlesArea(this->canvas()); - d_bottomHandlesArea = new HorizHandlesArea(this->canvas()); - d_leftHandlesArea = new VertHandlesArea(this->canvas()); - d_rightHandlesArea = new VertHandlesArea(this->canvas()); + d_topGateHandlesArea = new GateHandlesArea(this->canvas()); d_topWidget->setStyleSheet("QWidget {background-color: transparent}"); d_topWidget->setMinimumHeight(50); - d_topHandlesArea->setMinimumHeight(20); - d_topHandlesArea->setLargestChildWidth(80); - d_bottomHandlesArea->setMinimumHeight(50); + d_topGateHandlesArea->setMinimumHeight(20); + d_topGateHandlesArea->setLargestChildWidth(80); d_leftHandlesArea->setMinimumWidth(50); - d_rightHandlesArea->setMinimumWidth(50); - d_bottomHandlesArea->setLargestChildWidth(60); - d_rightHandlesArea->setLargestChildHeight(60); d_leftHandlesArea->setMinimumHeight(this->minimumHeight()); - d_rightHandlesArea->setMinimumHeight(this->minimumHeight()); - d_topHandlesArea->hide(); + d_topGateHandlesArea->hide(); /* Add content to the top area of the plot */ // Time Base d_timeBaseLabel = new QLabel(this); @@ -207,9 +178,9 @@ CapturePlot::CapturePlot(QWidget *parent, /* When bar position changes due to plot resizes update the handle */ connect(d_timeTriggerBar, &VertBar::pixelPositionChanged, [=](int pos) { - updateHandleAreaPadding(d_labelsEnabled); - d_timeTriggerHandle->setPositionSilenty(pos); - }); + updateHandleAreaPadding(d_labelsEnabled); + d_timeTriggerHandle->setPositionSilenty(pos); + }); connect(d_timeTriggerHandle, &FreePlotLineHandleH::positionChanged, d_timeTriggerBar, &VertBar::setPixelPosition); @@ -292,35 +263,16 @@ CapturePlot::CapturePlot(QWidget *parent, connect(d_levelTriggerBHandle, SIGNAL(grabbedChanged(bool)), SLOT(onTriggerBHandleGrabbed(bool))); - - /* Measurement Cursors */ - d_vCursorHandle1 = new PlotLineHandleV( - QPixmap(":/icons/v_cursor_handle.svg"), - d_rightHandlesArea); - d_vCursorHandle2 = new PlotLineHandleV( - QPixmap(":/icons/v_cursor_handle.svg"), - d_rightHandlesArea); - d_hCursorHandle1 = new PlotLineHandleH( - QPixmap(":/icons/h_cursor_handle.svg"), - d_bottomHandlesArea); - d_hCursorHandle2 = new PlotLineHandleH( - QPixmap(":/icons/h_cursor_handle.svg"), - d_bottomHandlesArea); - /* Measurement gate cursors */ d_hGatingHandle1 = new PlotGateHandle( QPixmap(":/icons/gate_handle.svg"), - d_topHandlesArea); + d_topGateHandlesArea); d_hGatingHandle2 = new PlotGateHandle( QPixmap(":/icons/gate_handle.svg"), - d_topHandlesArea); + d_topGateHandlesArea); d_hGatingHandle1->setCenterLeft(false); - d_vBar1 = new VertBar(this, true); - d_vBar2 = new VertBar(this, true); - d_hBar1 = new HorizBar(this, true); - d_hBar2 = new HorizBar(this, true); d_gateBar1 = new VertBar(this,true); d_gateBar2 = new VertBar(this,true); @@ -328,26 +280,9 @@ CapturePlot::CapturePlot(QWidget *parent, d_gateBar1->setVisible(false); d_gateBar2->setVisible(false); - d_symbolCtrl->attachSymbol(d_vBar1); - d_symbolCtrl->attachSymbol(d_vBar2); - d_symbolCtrl->attachSymbol(d_hBar1); - d_symbolCtrl->attachSymbol(d_hBar2); - d_symbolCtrl->attachSymbol(d_gateBar1); d_symbolCtrl->attachSymbol(d_gateBar2); - QPen cursorsLinePen = QPen(QColor(155, 155, 155), 1, Qt::DashLine); - d_hBar1->setPen(cursorsLinePen); - d_hBar2->setPen(cursorsLinePen); - d_vBar1->setPen(cursorsLinePen); - d_vBar2->setPen(cursorsLinePen); - - d_vCursorHandle1->setPen(cursorsLinePen); - d_vCursorHandle2->setPen(cursorsLinePen); - d_hCursorHandle1->setPen(cursorsLinePen); - d_hCursorHandle2->setPen(cursorsLinePen); - - /* gate bars */ QPen gatePen = QPen(QColor(255,255,255),1,Qt::SolidLine); d_gateBar1->setPen(gatePen); @@ -359,81 +294,9 @@ CapturePlot::CapturePlot(QWidget *parent, d_hGatingHandle1->hide(); d_hGatingHandle2->hide(); - d_vCursorHandle1->hide(); - d_vCursorHandle2->hide(); - d_hCursorHandle1->hide(); - d_hCursorHandle2->hide(); - - d_vBar1->setVisible(false); - d_vBar2->setVisible(false); - d_hBar1->setVisible(false); - d_hBar2->setVisible(false); - - d_cursorReadouts = new CursorReadouts(this); - d_cursorReadouts->setTopLeftStartingPoint(QPoint(8, 8)); - d_cursorReadouts->setTimeReadoutVisible(false); - d_cursorReadouts->setVoltageReadoutVisible(false); - - /* Set initial values for cursors */ - double voltsPerDiv = VertUnitsPerDiv(activeVertAxis()); - double secPerDiv = HorizUnitsPerDiv(); - - /* Update Cursor Readouts */ - onVoltageCursor1Moved(d_hBar1->plotCoord().y()); - onVoltageCursor2Moved(d_hBar2->plotCoord().y()); - onTimeCursor1Moved(d_vBar1->plotCoord().x()); - onTimeCursor2Moved(d_vBar2->plotCoord().x()); - d_cursorMetricFormatter.setTwoDecimalMode(false); d_cursorTimeFormatter.setTwoDecimalMode(false); - /* When a handle position changes the bar follows */ - connect(d_vCursorHandle1, &PlotLineHandleV::positionChanged, - [=](int value) { - - if (vertCursorsLocked) { - int position2 = value - (pixelPosHandleVert1 - pixelPosHandleVert2); - pixelPosHandleVert2 = position2; - d_hBar2->setPixelPosition(position2); - } - - pixelPosHandleVert1 = value; - d_hBar1->setPixelPosition(value); - }); - connect(d_vCursorHandle2, &PlotLineHandleV::positionChanged, - [=](int value) { - - if (vertCursorsLocked) { - int position1 = value + (pixelPosHandleVert1 - pixelPosHandleVert2); - pixelPosHandleVert1 = position1; - d_hBar1->setPixelPosition(position1); - } - - pixelPosHandleVert2 = value; - d_hBar2->setPixelPosition(value); - }); - - connect(d_hCursorHandle1, &PlotLineHandleH::positionChanged, - [=](int value) { - if (horizCursorsLocked) { - int position2 = value - (pixelPosHandleHoriz1 - pixelPosHandleHoriz2); - pixelPosHandleHoriz2 = position2; - d_vBar2->setPixelPosition(position2); - } - pixelPosHandleHoriz1 = value; - d_vBar1->setPixelPosition(value); - }); - connect(d_hCursorHandle2, &PlotLineHandleH::positionChanged, - [=](int value) { - if (horizCursorsLocked) { - int position1 = value + (pixelPosHandleHoriz1 - pixelPosHandleHoriz2); - pixelPosHandleHoriz1 = position1; - d_vBar1->setPixelPosition(position1); - } - pixelPosHandleHoriz2 = value; - d_vBar2->setPixelPosition(value); - }); - connect(d_hGatingHandle1, &PlotLineHandleH::positionChanged,[=](int value){ d_hGatingHandle2->setOtherCursorPosition(d_hGatingHandle1->position()); /* make sure that the gate handles don't cross each other */ @@ -460,11 +323,7 @@ CapturePlot::CapturePlot(QWidget *parent, } }); - d_hBar1->setPosition(0 + voltsPerDiv); - d_hBar2->setPosition(0 - voltsPerDiv); - d_vBar1->setPosition(0 + secPerDiv); - d_vBar2->setPosition(0 - secPerDiv); - + double secPerDiv = HorizUnitsPerDiv(); d_gateBar1->setPosition(0 - 4 * secPerDiv); d_gateBar2->setPosition(0 + 4 * secPerDiv); @@ -472,25 +331,6 @@ CapturePlot::CapturePlot(QWidget *parent, d_hGatingHandle1->setOtherCursorPosition(d_hGatingHandle2->position()); d_hGatingHandle2->setOtherCursorPosition(d_hGatingHandle1->position()); - /* When bar position changes due to plot resizes update the handle */ - connect(d_hBar1, SIGNAL(pixelPositionChanged(int)), - SLOT(onHbar1PixelPosChanged(int))); - connect(d_hBar2, SIGNAL(pixelPositionChanged(int)), - SLOT(onHbar2PixelPosChanged(int))); - connect(d_vBar1, SIGNAL(pixelPositionChanged(int)), - SLOT(onVbar1PixelPosChanged(int))); - connect(d_vBar2, SIGNAL(pixelPositionChanged(int)), - SLOT(onVbar2PixelPosChanged(int))); - - connect(d_vBar1, SIGNAL(positionChanged(double)), - SLOT(onTimeCursor1Moved(double))); - connect(d_vBar2, SIGNAL(positionChanged(double)), - SLOT(onTimeCursor2Moved(double))); - connect(d_hBar1, SIGNAL(positionChanged(double)), - SLOT(onVoltageCursor1Moved(double))); - connect(d_hBar2, SIGNAL(positionChanged(double)), - SLOT(onVoltageCursor2Moved(double))); - connect(d_timeTriggerHandle, &FreePlotLineHandleH::reset, [=](){ Q_EMIT timeTriggerValueChanged(0); }); @@ -509,7 +349,6 @@ CapturePlot::CapturePlot(QWidget *parent, connect(d_gateBar2,SIGNAL(positionChanged(double)), SLOT(onGateBar2Moved(double))); - /* Apply measurements for every new batch of data */ connect(this, SIGNAL(newData()), SLOT(onNewDataReceived())); @@ -523,8 +362,8 @@ CapturePlot::CapturePlot(QWidget *parent, installEventFilter(this); QwtScaleWidget *scaleWidget = axisWidget(QwtPlot::xBottom); - const int fmw = QFontMetrics(scaleWidget->font()).width("-XXX.XXX XX"); - scaleWidget->setMinBorderDist(fmw / 2 + 30, fmw / 2 + 30); + const int fmw = QFontMetrics(scaleWidget->font()).width("-XXX.XXX XX"); + scaleWidget->setMinBorderDist(fmw / 2 + 30, fmw / 2 + 30); displayGraticule = false; @@ -552,17 +391,14 @@ CapturePlot::CapturePlot(QWidget *parent, rightGateRect.setRight(axisScaleDiv(xBottom).upperBound()); rightGate->setRect(rightGateRect); rightGate->setBrush(gateBrush); + } CapturePlot::~CapturePlot() { - markerIntersection1->detach(); - markerIntersection2->detach(); - removeEventFilter(this); canvas()->removeEventFilter(d_cursorReadouts); + removeEventFilter(this); canvas()->removeEventFilter(d_symbolCtrl); - delete markerIntersection1; - delete markerIntersection2; for (auto it = d_measureObjs.begin(); it != d_measureObjs.end(); ++it) { delete *it; } @@ -571,6 +407,21 @@ CapturePlot::~CapturePlot() delete rightGate; } +QString CapturePlot::formatXValue(double value, int precision) const +{ + return d_cursorTimeFormatter.format(value, "", precision); +} + +QString CapturePlot::formatYValue(double value, int precision) const +{ + return d_cursorMetricFormatter.format(value, "", precision); +} + +CursorReadouts * CapturePlot::getCursorReadouts() const +{ + return d_cursorReadouts; +} + void CapturePlot::replot() { @@ -607,32 +458,9 @@ void CapturePlot::enableTimeTrigger(bool enable) d_timeTriggerHandle->setVisible(enable); } -void CapturePlot::onHbar1PixelPosChanged(int pos) -{ - d_vCursorHandle1->setPositionSilenty(pos); -} - -void CapturePlot::onHbar2PixelPosChanged(int pos) -{ - d_vCursorHandle2->setPositionSilenty(pos); -} - -void CapturePlot::onVbar1PixelPosChanged(int pos) -{ - d_hCursorHandle1->setPositionSilenty(pos); - displayIntersection(); -} - -void CapturePlot::onVbar2PixelPosChanged(int pos) -{ - displayIntersection(); - d_hCursorHandle2->setPositionSilenty(pos); -} - -void CapturePlot::onTimeCursor1Moved(double value) +void CapturePlot::onVCursor1Moved(double value) { QString text; - text = d_cursorTimeFormatter.format(value, "", 3); d_cursorReadouts->setTimeCursor1Text(text); d_cursorReadoutsText.t1 = text; @@ -648,19 +476,17 @@ void CapturePlot::onTimeCursor1Moved(double value) text = "Infinity"; d_cursorReadouts->setFreqDeltaText(text); d_cursorReadoutsText.freq = text; - if (d_trackMode) { - onVoltageCursor1Moved(getHorizontalCursorIntersection(d_vBar1->plotCoord().x())); + onHCursor1Moved(getHorizontalCursorIntersection(d_vBar1->plotCoord().x())); } value_v1 = value; Q_EMIT cursorReadoutsChanged(d_cursorReadoutsText); } -void CapturePlot::onTimeCursor2Moved(double value) +void CapturePlot::onVCursor2Moved(double value) { QString text; - text = d_cursorTimeFormatter.format(value, "", 3); d_cursorReadouts->setTimeCursor2Text(text); d_cursorReadoutsText.t2 = text; @@ -676,16 +502,15 @@ void CapturePlot::onTimeCursor2Moved(double value) text = "Infinity"; d_cursorReadouts->setFreqDeltaText(text); d_cursorReadoutsText.freq = text; - if (d_trackMode) { - onVoltageCursor2Moved(getHorizontalCursorIntersection(d_vBar2->plotCoord().x())); + onHCursor2Moved(getHorizontalCursorIntersection(d_vBar2->plotCoord().x())); } value_v2 = value; Q_EMIT cursorReadoutsChanged(d_cursorReadoutsText); } -void CapturePlot::onVoltageCursor1Moved(double value) +void CapturePlot::onHCursor1Moved(double value) { QString text; @@ -717,7 +542,7 @@ void CapturePlot::onVoltageCursor1Moved(double value) Q_EMIT cursorReadoutsChanged(d_cursorReadoutsText); } -void CapturePlot::onVoltageCursor2Moved(double value) +void CapturePlot::onHCursor2Moved(double value) { QString text; @@ -855,23 +680,9 @@ QWidget * CapturePlot::topArea() } QWidget * CapturePlot::topHandlesArea() -{/* handle area for gate cursors */ - return d_topHandlesArea; -} - -QWidget * CapturePlot::bottomHandlesArea() -{ - return d_bottomHandlesArea; -} - -QWidget * CapturePlot::leftHandlesArea() -{ - return d_leftHandlesArea; -} - -QWidget * CapturePlot::rightHandlesArea() { - return d_rightHandlesArea; + /* handle area for gate cursors */ + return d_topGateHandlesArea; } void CapturePlot::setBonusWidthForHistogram(int width) @@ -907,64 +718,11 @@ bool CapturePlot::triggerBEnabled() return d_triggerBEnabled; } -void CapturePlot::setVertCursorsEnabled(bool en) -{ - if (d_vertCursorsEnabled != en) { - d_vertCursorsEnabled = en; - d_vBar1->setVisible(en); - d_vBar2->setVisible(en); - d_hCursorHandle1->setVisible(en); - d_hCursorHandle2->setVisible(en); - d_cursorReadouts->setTimeReadoutVisible(en && - d_cursorReadoutsVisible); - } -} - -bool CapturePlot::vertCursorsEnabled() -{ - return d_vertCursorsEnabled; -} - -void CapturePlot::setHorizCursorsEnabled(bool en) -{ - if (d_horizCursorsEnabled != en) { - d_horizCursorsEnabled = en; - d_hBar1->setVisible(en); - d_hBar2->setVisible(en); - d_vCursorHandle1->setVisible(en); - d_vCursorHandle2->setVisible(en); - d_cursorReadouts->setVoltageReadoutVisible(en && - d_cursorReadoutsVisible); - } -} - -bool CapturePlot::horizCursorsEnabled() -{ - return d_horizCursorsEnabled; -} - -void CapturePlot::setCursorReadoutsVisible(bool en) -{ - if (d_cursorReadoutsVisible != en) { - d_cursorReadoutsVisible = en; - d_cursorReadouts->setVoltageReadoutVisible(en && - d_vertCursorsEnabled); - d_cursorReadouts->setTimeReadoutVisible(en && - d_horizCursorsEnabled); - } -} - void CapturePlot::setSelectedChannel(int id) { if (d_selected_channel != id) { d_selected_channel = id; - - if (id > -1) { - d_hBar1->setMobileAxis(QwtAxisId(QwtPlot::yLeft, id)); - d_hBar2->setMobileAxis(QwtAxisId(QwtPlot::yLeft, id)); - } } - // } int CapturePlot::selectedChannel() @@ -1019,11 +777,6 @@ void CapturePlot::onTriggerBHandleGrabbed(bool grabbed) d_symbolCtrl->updateOverlay(); } -void CapturePlot::setVertCursorsLocked(bool value) -{ - vertCursorsLocked = value; -} - void CapturePlot::showEvent(QShowEvent *event) { d_vCursorHandle1->triggerMove(); @@ -1056,11 +809,6 @@ int CapturePlot::getAnalogChannels() const return d_ydata.size() + d_ref_ydata.size(); } -void CapturePlot::setHorizCursorsLocked(bool value) -{ - horizCursorsLocked = value; -} - Measure* CapturePlot::measureOfChannel(int chnIdx) const { Measure *measure = nullptr; @@ -1109,8 +857,8 @@ void CapturePlot::enableAxisLabels(bool enabled) void CapturePlot::setDisplayScale(double value) { DisplayPlot::setDisplayScale(value); - onVoltageCursor1Moved(d_hBar1->plotCoord().y()); - onVoltageCursor2Moved(d_hBar2->plotCoord().y()); + onHCursor1Moved(d_hBar1->plotCoord().y()); + onHCursor2Moved(d_hBar2->plotCoord().y()); } void CapturePlot::setTimeTriggerInterval(double min, double max) @@ -1128,13 +876,13 @@ void CapturePlot::setGraticuleEnabled(bool enabled){ displayGraticule = enabled; if(!displayGraticule){ - for(QwtPlotScaleItem* scale : scaleItems){ + for(QwtPlotScaleItem* scale : qAsConst(scaleItems)){ scale->attach(this); } graticule->enableGraticule(displayGraticule); } else{ - for(QwtPlotScaleItem* scale : scaleItems){ + for(QwtPlotScaleItem* scale : qAsConst(scaleItems)){ scale->detach(); } graticule->enableGraticule(displayGraticule); @@ -1155,7 +903,7 @@ void CapturePlot::setGatingEnabled(bool enabled){ if(enabled){ leftGate->attach(this); rightGate->attach(this); - d_topHandlesArea->show(); + d_topGateHandlesArea->show(); //update handle onGateBar1Moved(leftGateRect.right()); onGateBar2Moved(rightGateRect.left()); @@ -1163,7 +911,7 @@ void CapturePlot::setGatingEnabled(bool enabled){ else{ leftGate->detach(); rightGate->detach(); - d_topHandlesArea->hide(); + d_topGateHandlesArea->hide(); } for (int i = 0; i < d_measureObjs.size(); i++) { Measure *measure = d_measureObjs[i]; @@ -1177,35 +925,6 @@ void CapturePlot::setGatingEnabled(bool enabled){ } } -void CapturePlot::trackModeEnabled(bool enabled) -{ - d_trackMode = !enabled; - if (d_horizCursorsEnabled) { - d_hBar1->setVisible(enabled); - d_hBar2->setVisible(enabled); - d_vCursorHandle1->setVisible(enabled); - d_vCursorHandle2->setVisible(enabled); - } - if (d_trackMode) { - onTimeCursor1Moved(d_vBar1->plotCoord().x()); - onTimeCursor2Moved(d_vBar2->plotCoord().x()); - displayIntersection(); - } else { - onVoltageCursor1Moved(d_hBar1->plotCoord().y()); - onVoltageCursor2Moved(d_hBar2->plotCoord().y()); - markerIntersection1->detach(); - markerIntersection2->detach(); - replot(); - } -} - -void CapturePlot::repositionCursors() -{ - onTimeCursor1Moved(d_vBar1->plotCoord().x()); - onTimeCursor2Moved(d_vBar2->plotCoord().x()); - displayIntersection(); -} - void CapturePlot::setActiveVertAxis(unsigned int axisIdx, bool selected) { DisplayPlot::setActiveVertAxis(axisIdx, selected); @@ -1250,22 +969,22 @@ void CapturePlot::updateHandleAreaPadding(bool enabled) if (enabled) { d_bottomHandlesArea->setLeftPadding(50 + axisWidget(QwtAxisId(QwtPlot::yLeft, d_activeVertAxis))->width()); - d_topHandlesArea->setLeftPadding(90 + axisWidget(QwtAxisId(QwtPlot::yLeft, d_activeVertAxis))->width()); + d_topGateHandlesArea->setLeftPadding(90 + axisWidget(QwtAxisId(QwtPlot::yLeft, d_activeVertAxis))->width()); QwtScaleWidget *scaleWidget = axisWidget(QwtPlot::xBottom); const int fmw = QFontMetrics(scaleWidget->font()).width("-XX.XX XX"); const int fmh = QFontMetrics(scaleWidget->font()).height(); d_bottomHandlesArea->setRightPadding(50 + fmw/2 + d_bonusWidth); - d_topHandlesArea->setRightPadding(50 + fmw/2 + d_bonusWidth); + d_topGateHandlesArea->setRightPadding(50 + fmw/2 + d_bonusWidth); d_rightHandlesArea->setTopPadding(50 + 6); d_rightHandlesArea->setBottomPadding(50 + fmh); QMargins margins = d_topWidget->layout()->contentsMargins(); margins.setLeft(d_leftHandlesArea->minimumWidth()+100); d_topWidget->layout()->setContentsMargins(margins); } else { - if(d_topHandlesArea->leftPadding() != 90) - d_topHandlesArea->setLeftPadding(90); - if(d_topHandlesArea->rightPadding() != 90) - d_topHandlesArea->setRightPadding(90); + if(d_topGateHandlesArea->leftPadding() != 90) + d_topGateHandlesArea->setLeftPadding(90); + if(d_topGateHandlesArea->rightPadding() != 90) + d_topGateHandlesArea->setRightPadding(90); if (d_bottomHandlesArea->leftPadding() != 50 + xAxisBonusWidth) d_bottomHandlesArea->setLeftPadding(50 + xAxisBonusWidth); if (d_bottomHandlesArea->rightPadding() != 50 + d_bonusWidth + xAxisBonusWidth) @@ -1275,7 +994,7 @@ void CapturePlot::updateHandleAreaPadding(bool enabled) if (d_rightHandlesArea->bottomPadding() != 50) d_rightHandlesArea->setBottomPadding(50); - int topPadding = d_gatingEnabled ? d_topHandlesArea->height() : 0; + int topPadding = d_gatingEnabled ? d_topGateHandlesArea->height() : 0; d_leftHandlesArea->setTopPadding(50 + topPadding); d_rightHandlesArea->setTopPadding(50 + topPadding); @@ -1292,104 +1011,6 @@ void CapturePlot::updateHandleAreaPadding(bool enabled) d_vCursorHandle2->updatePosition(); } -double CapturePlot::getHorizontalCursorIntersection(double time) -{ - int n = Curve(d_selected_channel)->data()->size(); - - if (n == 0) { - return ERROR_VALUE; - } else { - double leftTime, rightTime, leftCustom, rightCustom; - int rightIndex = -1; - int leftIndex = -1; - - int left = 0; - int right = n - 1; - - if (Curve(d_selected_channel)->data()->sample(right).x() < time || - Curve(d_selected_channel)->data()->sample(left).x() > time) { - return ERROR_VALUE; - } - - while (left <= right) { - int mid = (left + right) / 2; - double xData = Curve(d_selected_channel)->data()->sample(mid).x(); - if (xData == time) { - if (mid > 0) { - leftIndex = mid - 1; - rightIndex = mid; - } - break; - } else if (xData < time) { - left = mid + 1; - } else { - right = mid - 1; - } - } - - if ((leftIndex == -1 || rightIndex == -1) && left > 0) { - leftIndex = left - 1; - rightIndex = left; - } - - if (leftIndex == -1 || rightIndex == -1) { - return ERROR_VALUE; - } - - leftTime = Curve(d_selected_channel)->data()->sample(leftIndex).x(); - rightTime = Curve(d_selected_channel)->data()->sample(rightIndex).x(); - - leftCustom = Curve(d_selected_channel)->data()->sample(leftIndex).y(); - rightCustom = Curve(d_selected_channel)->data()->sample(rightIndex).y(); - - double value = (rightCustom - leftCustom) / (rightTime - leftTime) * - (time - leftTime) + leftCustom; - - return value; - } -} - -void CapturePlot::displayIntersection() -{ - if (!d_trackMode) { - return; - } - - double intersectionCursor1, intersectionCursor2; - bool attachmk1 = true; - bool attachmk2 = true; - - - intersectionCursor1 = getHorizontalCursorIntersection(d_vBar1->plotCoord().x()); - intersectionCursor2 = getHorizontalCursorIntersection(d_vBar2->plotCoord().x()); - - if (intersectionCursor1 == -1000000){ - attachmk1 = false; - } - if (intersectionCursor2 == -1000000) { - attachmk2 = false; - } - - markerIntersection1->setAxes(QwtPlot::xBottom, QwtAxisId(QwtPlot::yLeft, d_selected_channel)); - markerIntersection2->setAxes(QwtPlot::xBottom, QwtAxisId(QwtPlot::yLeft, d_selected_channel)); - - markerIntersection1->setValue(d_vBar1->plotCoord().x(), intersectionCursor1); - markerIntersection2->setValue(d_vBar2->plotCoord().x(), intersectionCursor2); - - if (attachmk1) { - markerIntersection1->attach(this); - } else { - markerIntersection1->detach(); - } - if (attachmk2) { - markerIntersection2->attach(this); - } else { - markerIntersection2->detach(); - } - - replot(); -} - void CapturePlot::updateGateMargins(){ /* update the size of the gates */ leftGateRect.setTop(axisScaleDiv(yRight).upperBound()); @@ -1414,6 +1035,9 @@ bool CapturePlot::eventFilter(QObject *object, QEvent *event) d_hCursorHandle2->triggerMove(); d_vCursorHandle1->triggerMove(); d_vCursorHandle2->triggerMove(); + d_timeTriggerHandle->triggerMove(); + d_levelTriggerAHandle->triggerMove(); + d_levelTriggerBHandle->triggerMove(); /* update the size of the gates when the plot canvas is resized */ updateGateMargins(); @@ -1645,7 +1269,7 @@ bool CapturePlot::endGroupSelection(bool moveAnnotationCurvesLast) // merge new group if selected channels already have a group QList group = d_groupHandles.takeLast(); QList updatedGroup; - for (RoundedHandleV *hdl : group) { + for (RoundedHandleV *hdl : qAsConst(group)) { auto hdlGroup = std::find_if(d_groupHandles.begin(), d_groupHandles.end(), [&hdl](const QList &group){ return group.contains(hdl); @@ -1658,7 +1282,9 @@ bool CapturePlot::endGroupSelection(bool moveAnnotationCurvesLast) continue; } - for (const auto &grpHdl : *hdlGroup) { + + auto hdlGroupContainer = *hdlGroup; + for (const auto &grpHdl : qAsConst(hdlGroupContainer)) { if (!updatedGroup.contains(grpHdl)) { updatedGroup.push_back(grpHdl); } @@ -1718,14 +1344,14 @@ bool CapturePlot::endGroupSelection(bool moveAnnotationCurvesLast) group.first()->setSelected(true); group.first()->selected(true); - for (QwtPlotZoneItem *groupMarker : d_groupMarkers) { + for (QwtPlotZoneItem *groupMarker : qAsConst(d_groupMarkers)) { groupMarker->detach(); delete groupMarker; } d_groupMarkers.clear(); - for (const auto &group : d_groupHandles) { + for (const auto &group : qAsConst(d_groupHandles)) { // Add group marker QwtScaleMap yMap = this->canvasMap(QwtAxisId(QwtPlot::yLeft, 0)); const QwtInterval y = axisInterval(QwtAxisId(QwtPlot::yLeft, 0)); @@ -1749,7 +1375,7 @@ bool CapturePlot::endGroupSelection(bool moveAnnotationCurvesLast) } if (!newGroup) { - for (const auto &group : d_groupHandles) { + for (const auto &group : qAsConst(d_groupHandles)) { group.first()->triggerMove(); } } @@ -1775,7 +1401,8 @@ QVector CapturePlot::getGroupOfChannel(int chnIdx) return groupIdxList; } - for (const auto &hdl : *hdlGroup) { + auto hdlGroupContainer = *hdlGroup; + for (const auto &hdl : qAsConst(hdlGroupContainer)) { groupIdxList.push_back(d_offsetHandles.indexOf(hdl)); } @@ -2011,7 +1638,7 @@ void CapturePlot::handleInGroupChangedPosition(int position) void adiscope::CapturePlot::pushBackNewOffsetWidgets(RoundedHandleV *chOffsetHdl, HorizBar *chOffsetBar) { - int indexOfNewChannel = d_ydata.size() - 1; + const int indexOfNewChannel = (d_ydata.size() + d_ref_ydata.size()) - 1; d_offsetBars.insert(indexOfNewChannel, chOffsetBar); d_offsetHandles.insert(indexOfNewChannel, chOffsetHdl); @@ -2171,7 +1798,9 @@ void CapturePlot::setOffsetWidgetVisible(int chnIdx, bool visible) } int count = 0; - for (const auto &handle : *hdlGroup) { + + auto hdlGroupContainer = *hdlGroup; + for (const auto &handle : qAsConst(hdlGroupContainer)) { if (handle->isVisible()) { count++; } @@ -2303,11 +1932,6 @@ void CapturePlot::setPeriodDetectHyst(int chnIdx, double hyst) measure->setHysteresisSpan(hyst); } -struct cursorReadoutsText CapturePlot::allCursorReadouts() const -{ - return d_cursorReadoutsText; -} - void CapturePlot::setTimeBaseLabelValue(double value) { QString text = d_cursorTimeFormatter.format(value, "", 3); @@ -2376,16 +2000,6 @@ void CapturePlot::setMaxBufferSizeErrorLabel(bool reached, const QString &custom d_maxBufferError->setText(reached ? errorMessage : ""); } -void CapturePlot::setCursorReadoutsTransparency(int value) -{ - d_cursorReadouts->setTransparency(value); -} - -void CapturePlot::moveCursorReadouts(CustomPlotPositionButton::ReadoutsPosition position) -{ - d_cursorReadouts->moveToPosition(position); -} - void CapturePlot::updateBufferSizeSampleRateLabel(int nsamples, double sr) { QString txtSampleRate = d_cursorMetricFormatter.format(sr, "sps", 0); diff --git a/src/oscilloscope_plot.hpp b/src/oscilloscope_plot.hpp index 38ca368614..8d58e9ede4 100644 --- a/src/oscilloscope_plot.hpp +++ b/src/oscilloscope_plot.hpp @@ -22,10 +22,6 @@ #define M2K_OSCILLOSCOPE_PLOT_H #include "TimeDomainDisplayPlot.h" -#include "symbol_controller.h" -#include "handles_area.hpp" -#include "plot_line_handle.h" -#include "cursor_readouts.h" #include "measure.h" #include "customplotpositionbutton.h" #include "graticule.h" @@ -45,24 +41,15 @@ namespace adiscope { Q_OBJECT public: - OscilloscopePlot(QWidget *parent, unsigned int xNumDivs = 10, + OscilloscopePlot(QWidget *parent, bool isdBgraph = false, unsigned int xNumDivs = 10, unsigned int yNumDiv = 10); ~OscilloscopePlot(); }; - struct cursorReadoutsText { - QString t1; - QString t2; - QString tDelta; - QString freq; - QString v1; - QString v2; - QString vDelta; - }; - class CapturePlot: public OscilloscopePlot { friend class Oscilloscope_API; + friend class LogicAnalyzer_API; friend class Channel_API; Q_OBJECT @@ -76,7 +63,7 @@ namespace adiscope { }; public: - CapturePlot(QWidget *parent, unsigned int xNumDivs = 10, + CapturePlot(QWidget *parent, bool isdBgraph = false, unsigned int xNumDivs = 10, unsigned int yNumDivs = 10); ~CapturePlot(); @@ -87,19 +74,13 @@ namespace adiscope { QWidget *topArea(); QWidget *topHandlesArea(); - QWidget *bottomHandlesArea(); - QWidget *leftHandlesArea(); - QWidget *rightHandlesArea(); void setBonusWidthForHistogram(int width); bool triggerAEnabled(); bool triggerBEnabled(); - bool vertCursorsEnabled(); - bool horizCursorsEnabled(); int selectedChannel(); bool measurementsEnabled(); - struct cursorReadoutsText allCursorReadouts() const; void setOffsetWidgetVisible(int chnIdx, bool visible); void removeOffsetWidgets(int chnIdx); @@ -129,8 +110,6 @@ namespace adiscope { void setTimeTriggerInterval(double min, double max); bool labelsEnabled(); - void trackModeEnabled(bool enabled); - void repositionCursors(); void setGraticuleEnabled(bool enabled); void setGatingEnabled(bool enabled); @@ -144,11 +123,15 @@ namespace adiscope { QString getChannelName(int chIdx) const; void setChannelName(const QString &name, int chIdx); + QString formatXValue(double value, int precision) const; + QString formatYValue(double value, int precision) const; + + CursorReadouts * getCursorReadouts() const; + Q_SIGNALS: void timeTriggerValueChanged(double); void channelOffsetChanged(unsigned int, double); void measurementsAvailable(); - void cursorReadoutsChanged(struct cursorReadoutsText); void canvasSizeChanged(); void leftGateChanged(double); void rightGateChanged(double); @@ -157,22 +140,16 @@ namespace adiscope { public Q_SLOTS: void setTriggerAEnabled(bool en); void setTriggerBEnabled(bool en); - void setVertCursorsEnabled(bool en); - void setHorizCursorsEnabled(bool en); void setSelectedChannel(int id); void setMeasuremensEnabled(bool en); void setPeriodDetectLevel(int chnIdx, double lvl); void setPeriodDetectHyst(int chnIdx, double hyst); - void setCursorReadoutsVisible(bool en); void setTimeBaseLabelValue(double timebase); void setBufferSizeLabelValue(int numSamples); void setSampleRatelabelValue(double sampleRate); void setTriggerState(int triggerState); void setMaxBufferSizeErrorLabel(bool reached, const QString &customWarning = ""); - void setCursorReadoutsTransparency(int value); - void moveCursorReadouts(CustomPlotPositionButton::ReadoutsPosition position); - void setHorizCursorsLocked(bool value); - void setVertCursorsLocked(bool value); + void showEvent(QShowEvent *event); void printWithNoBackground(const QString& toolName = "", bool editScaleDraw = true); @@ -201,25 +178,12 @@ namespace adiscope { Measure* measureOfChannel(int chnIdx) const; void updateBufferSizeSampleRateLabel(int nsamples, double sr); void updateHandleAreaPadding(bool); - double getHorizontalCursorIntersection(double time); - void displayIntersection(); void updateGateMargins(); private Q_SLOTS: void onChannelAdded(int); void onNewDataReceived(); - - void onHbar1PixelPosChanged(int); - void onHbar2PixelPosChanged(int); - void onVbar1PixelPosChanged(int); - void onVbar2PixelPosChanged(int); - - void onTimeCursor1Moved(double); - void onTimeCursor2Moved(double); - void onVoltageCursor1Moved(double); - void onVoltageCursor2Moved(double); - void onGateBar1PixelPosChanged(int); void onGateBar2PixelPosChanged(int); @@ -233,24 +197,22 @@ namespace adiscope { void onTriggerBHandleGrabbed(bool); void handleInGroupChangedPosition(int position); + + void onHCursor1Moved(double); + void onHCursor2Moved(double); + void onVCursor1Moved(double); + void onVCursor2Moved(double); + private: std::function m_conversion_function; - SymbolController *d_symbolCtrl; bool d_triggerAEnabled; bool d_triggerBEnabled; - bool d_vertCursorsEnabled; - bool d_horizCursorsEnabled; bool d_measurementsEnabled; bool d_labelsEnabled; - int d_selected_channel; - QWidget *d_topWidget; - GateHandlesArea *d_topHandlesArea; - HorizHandlesArea *d_bottomHandlesArea; - VertHandlesArea *d_leftHandlesArea; - VertHandlesArea *d_rightHandlesArea; + GateHandlesArea *d_topGateHandlesArea; int d_bonusWidth; QLabel *d_timeBaseLabel; @@ -269,19 +231,9 @@ namespace adiscope { bool d_startedGrouping; QVector d_groupMarkers; - PlotLineHandleV *d_vCursorHandle1; - PlotLineHandleV *d_vCursorHandle2; - PlotLineHandleH *d_hCursorHandle1; - PlotLineHandleH *d_hCursorHandle2; - PlotGateHandle *d_hGatingHandle1; PlotGateHandle *d_hGatingHandle2; - VertBar *d_vBar1; - VertBar *d_vBar2; - HorizBar *d_hBar1; - HorizBar *d_hBar2; - VertBar *d_gateBar1; VertBar *d_gateBar2; @@ -292,13 +244,8 @@ namespace adiscope { FreePlotLineHandleV *d_levelTriggerAHandle; FreePlotLineHandleV *d_levelTriggerBHandle; - - - CursorReadouts *d_cursorReadouts; MetricPrefixFormatter d_cursorMetricFormatter; - TimePrefixFormatter d_cursorTimeFormatter; - struct cursorReadoutsText d_cursorReadoutsText; - bool d_cursorReadoutsVisible; + TimePrefixFormatter d_cursorTimeFormatter; QPen d_trigAactiveLinePen; QPen d_trigAinactiveLinePen; @@ -317,16 +264,6 @@ namespace adiscope { bool displayGraticule; Graticule *graticule; - bool d_trackMode; - QwtPlotMarker *markerIntersection1; - QwtPlotMarker *markerIntersection2; - bool horizCursorsLocked; - bool vertCursorsLocked; - int pixelPosHandleHoriz1; - int pixelPosHandleHoriz2; - int pixelPosHandleVert1; - int pixelPosHandleVert2; - QwtPlotShapeItem *leftGate, *rightGate; QRectF leftGateRect, rightGateRect; bool d_gatingEnabled; diff --git a/src/patterngenerator/pattern_generator.cpp b/src/patterngenerator/pattern_generator.cpp index 90260e32ef..8efe5252ad 100644 --- a/src/patterngenerator/pattern_generator.cpp +++ b/src/patterngenerator/pattern_generator.cpp @@ -69,7 +69,7 @@ PatternGenerator::PatternGenerator(struct iio_context *ctx, Filter *filt, DIOManager *diom, ToolLauncher *parent) : LogicTool(nullptr, toolMenuItem, new PatternGenerator_API(this), "Pattern Generator", parent) , m_ui(new Ui::PatternGenerator) - , m_plot(this, 16, 10) + , m_plot(this, false, 16, 10) , m_plotScrollBar(new QScrollBar(Qt::Vertical, this)) , m_selectedChannel(-1) , m_nbChannels(DIGITAL_NR_CHANNELS) @@ -334,6 +334,13 @@ void PatternGenerator::channelSelectedChanged(int chIdx, bool selected) m_ui->patternComboBox->setEnabled(true); m_ui->btnOutputMode->setEnabled(true); + if (m_selectedChannel < m_nbChannels) { + const DIO_MODE outputMode = m_m2kDigital->getOutputMode(m_selectedChannel); + const bool btnOutputModeSelected = (outputMode == DIO_MODE::DIO_OPENDRAIN ? true + :false); + m_ui->btnOutputMode->setChecked(btnOutputModeSelected); + } + updateChannelGroupWidget(true); updateChannelGroupPattern(true); @@ -909,12 +916,6 @@ void PatternGenerator::connectSignalsAndSlots() connect(m_ui->nameLineEdit, &QLineEdit::textChanged, [=](const QString &text){ m_plot.setChannelName(text, m_selectedChannel); m_plotCurves[m_selectedChannel]->setName(text); - if (m_selectedChannel < m_nbChannels) { - QWidget *widgetInLayout = m_ui->channelEnumeratorLayout->itemAtPosition(m_selectedChannel % 8, - m_selectedChannel / 8)->widget(); - auto channelBox = dynamic_cast(widgetInLayout); - channelBox->setText(text); - } }); connect(m_ui->printBtn, &QPushButton::clicked, [=](){ @@ -1022,7 +1023,7 @@ void PatternGenerator::updateChannelGroupPattern(bool visible) qDebug() << "Enabled patterns: " << m_enabledPatterns; qDebug() << "################################################################"; - for (const auto &ep : m_enabledPatterns) { + for (const auto &ep : qAsConst(m_enabledPatterns)) { if (ep.first.contains(m_selectedChannel)) { pattern = QString::fromStdString(ep.second->get_pattern()->get_name()); ep.second->setVisible(visible); diff --git a/src/patterngenerator/pattern_generator_api.cpp b/src/patterngenerator/pattern_generator_api.cpp index 9ba3bd50f1..3c24fc6e37 100644 --- a/src/patterngenerator/pattern_generator_api.cpp +++ b/src/patterngenerator/pattern_generator_api.cpp @@ -125,7 +125,7 @@ void logic::PatternGenerator_API::setCurrentGroups(const QVector > QVector, QString> > logic::PatternGenerator_API::getEnabledPatterns() const { QVector, QString> > enabledPatterns; - for (const QPair, PatternUI *> &pattern : m_pattern->m_enabledPatterns) { + for (const QPair, PatternUI *> &pattern : qAsConst(m_pattern->m_enabledPatterns)) { enabledPatterns.push_back({pattern.first, Pattern_API::toString(pattern.second->get_pattern())}); } diff --git a/src/patterngenerator/patterns/patterns.cpp b/src/patterngenerator/patterns/patterns.cpp index 471d9a2578..c64c7d905f 100644 --- a/src/patterngenerator/patterns/patterns.cpp +++ b/src/patterngenerator/patterns/patterns.cpp @@ -350,7 +350,8 @@ Pattern *Pattern_API::fromJson(QJsonObject obj) sp->setCSPol(params["CS"].toBool()); sp->setMsbFirst(params["MSB"].toBool()); - for (auto val : params["v"].toArray()) { + auto paramsContainer = params["v"].toArray(); + for (auto val : qAsConst(paramsContainer)) { sp->v.push_back(val.toInt()); } } else if (ip) { @@ -361,7 +362,8 @@ Pattern *Pattern_API::fromJson(QJsonObject obj) ip->setMsbFirst(params["MSB"].toBool()); ip->setWrite(params["write"].toBool()); - for (auto val : params["v"].toArray()) { + auto paramsContainer = params["v"].toArray(); + for (auto val : qAsConst(paramsContainer)) { ip->v.push_back(val.toInt()); } } else if (imp) { @@ -2010,7 +2012,7 @@ void I2CPatternUI::parse_ui() std::vector b; std::reverse(strList.begin(),strList.end()); - for (QString str: strList) { + for (const QString &str: qAsConst(strList)) { uint64_t val; bool ok; b.clear(); @@ -2412,7 +2414,7 @@ void SPIPatternUI::parse_ui() std::vector b; std::reverse(strList.begin(),strList.end()); - for (QString str: strList) { + for (const QString &str: qAsConst(strList)) { uint64_t val; bool ok; b.clear(); @@ -3680,7 +3682,8 @@ void ImportPatternUI::parse_ui() } unsigned short mask = 0; - for (int key : import_settings->getExportConfig().keys()) { + auto keys = import_settings->getExportConfig().keys(); + for (int key : qAsConst(keys)) { mask = mask | (import_settings->getExportConfig()[key] << key); } @@ -3799,7 +3802,7 @@ Pattern *PatternFactory::create(QString name) { int i=0; - for (auto str : ui_list) { + for (const auto &str : qAsConst(ui_list)) { if (name==str) { return create(i); } @@ -3878,7 +3881,7 @@ PatternUI *PatternFactory::create_ui(Pattern *pattern, QWidget *parent) int i=0; QString name = QString::fromStdString(pattern->get_name()); - for (auto str : ui_list) { + for (const auto &str : qAsConst(ui_list)) { if (name==str) { return create_ui(pattern,i,parent); } diff --git a/src/phonehome.cpp b/src/phonehome.cpp index d7668eee6d..0349d538db 100644 --- a/src/phonehome.cpp +++ b/src/phonehome.cpp @@ -30,16 +30,18 @@ bool PhoneHome::getDone() const return done; } -PhoneHome::PhoneHome(QSettings *settings, Preferences *pref) : +PhoneHome::PhoneHome(QSettings *settings, Preferences *pref, QNetworkAccessManager* manager) : ApiObject(), m_timestamp(0), m_versionsJson(""), preferences(pref), settings(settings), done(false) { setObjectName("phonehome"); + this->manager = manager; load(*settings); } PhoneHome::~PhoneHome() { save(*settings); + delete manager; } void PhoneHome::setPreferences(Preferences* preferences) @@ -55,9 +57,7 @@ void PhoneHome::versionsRequest(bool force) if(m_timestamp + timeout < now || force) { // from swdownloads - QNetworkAccessManager* manager = new QNetworkAccessManager(this); connect(manager, &QNetworkAccessManager::finished, this, &PhoneHome::onVersionsRequestFinished); - connect(manager, &QNetworkAccessManager::finished, manager, &QNetworkAccessManager::deleteLater); manager->get(QNetworkRequest(QUrl(preferences->getCheck_updates_url()))); Q_EMIT scopyVersionCheckRequested(); diff --git a/src/phonehome.h b/src/phonehome.h index 909b9da1f5..d1c9d0a5b6 100644 --- a/src/phonehome.h +++ b/src/phonehome.h @@ -40,6 +40,7 @@ class PhoneHome : public ApiObject QString m_m2kLink; qint64 m_timestamp; QString m_versionsJson; + QNetworkAccessManager* manager; PhoneHome* instance; Preferences* preferences; QSettings *settings; @@ -50,7 +51,7 @@ class PhoneHome : public ApiObject Q_PROPERTY(QString versionsJson READ getVersionsJson WRITE setVersionsJson) public: - PhoneHome(QSettings *settings, Preferences *preferences); + PhoneHome(QSettings *settings, Preferences *preferences, QNetworkAccessManager* manager); ~PhoneHome(); void versionsRequest(bool force = false); void extractVersionStringsFromJson(const QJsonDocument &doc); diff --git a/src/preferences.cpp b/src/preferences.cpp index c94e1f0f94..5c3008c6b1 100644 --- a/src/preferences.cpp +++ b/src/preferences.cpp @@ -74,6 +74,11 @@ Preferences::Preferences(QWidget *parent) : { ui->setupUi(this); + /** Will still be available to use for development purposes. + * For now, no longer exposed to the users.**/ + ui->debugMessagesCheckbox->setVisible(false); + ui->debugMessagesLbl->setVisible(false); + connect(ui->doubleClickCheckBox, &QCheckBox::stateChanged, [=](int state){ double_click_to_detach = (!state ? false : true); Q_EMIT notify(); diff --git a/src/scopyExceptionHandler.h b/src/scopyExceptionHandler.h index 67a4f404d1..cd72f943ff 100644 --- a/src/scopyExceptionHandler.h +++ b/src/scopyExceptionHandler.h @@ -1,38 +1,34 @@ #ifndef SCOPYEXCEPTIONHANDLER_H #define SCOPYEXCEPTIONHANDLER_H -#include #include #include #include #include #include +#include using namespace adiscope; +// Debug messages are currently disabled for users, can be used for development. +// The message box was removed because exceptions might occur both from the control flow +// and for signaling problems. Until those are handled separately, we can't use +// QMessageBox to show the exception, since those can be thrown from different threads. + #define HANDLE_EXCEPTION(e) \ if (GetScopyApplicationInstance()->getDebugMode()) { \ auto me = dynamic_cast(&e); \ - auto handleLambda = [me, e](){ \ - QMessageBox msg; \ - QString str; \ - if (me) { \ - str = QString("Exception %1\ne.type() - %2\ne.what() - %3\ne.iioCode() - %4\nthrown from %5:%6\ncaught in %7:%8\nScopy git tag %9\n") \ - .arg("m2k_exception").arg(me->type()).arg(me->what()).arg(me->iioCode()).arg(QString::fromStdString(me->file())).arg(QString::number(me->line())).arg(__FILE__).arg(__LINE__).arg(SCOPY_VERSION_GIT); \ - } else { \ - str = QString("Exception %1\ncaught in %2:%3\nScopy git tag %4\n").arg(e.what()).arg(__FILE__).arg(__LINE__).arg(SCOPY_VERSION_GIT); \ - } \ - if (WriteScopyMinidump()) { \ - str = str + "Created minidump."; \ - } \ - msg.setText(str); \ - msg.exec(); \ - }; \ - if (GetScopyApplicationInstance()->thread() != QThread::currentThread()) { \ - QMetaObject::invokeMethod(GetScopyApplicationInstance(), handleLambda, Qt::BlockingQueuedConnection); \ + QString str; \ + if (me) { \ + str = QString("Exception %1\ne.type() - %2\ne.what() - %3\ne.iioCode() - %4\nthrown from %5:%6\ncaught in %7:%8\nScopy git tag %9\n") \ + .arg("m2k_exception").arg(me->type()).arg(me->what()).arg(me->iioCode()).arg(QString::fromStdString(me->file())).arg(QString::number(me->line())).arg(__FILE__).arg(__LINE__).arg(SCOPY_VERSION_GIT); \ } else { \ - handleLambda(); \ + str = QString("Exception %1\ncaught in %2:%3\nScopy git tag %4\n").arg(e.what()).arg(__FILE__).arg(__LINE__).arg(SCOPY_VERSION_GIT); \ + } \ + if (WriteScopyMinidump()) { \ + str = str + "Created minidump."; \ } \ + qDebug() << str << "\n"; \ } \ #endif // SCOPYEXCEPTIONHANDLER_H diff --git a/src/scopy_color_editor.cpp b/src/scopy_color_editor.cpp index c642d41e91..09636bcd65 100644 --- a/src/scopy_color_editor.cpp +++ b/src/scopy_color_editor.cpp @@ -37,12 +37,12 @@ void ScopyColorEditor::parseAndBuildMap(QString toParse) QString textEditText = ""; - for (auto token : print) { + for (const auto &token : qAsConst(print)) { // TODO: skip empty parts is only available in qt >= 5.14 // QStringList ttoken = token.split("\n", Qt::SkipEmptyParts); QStringList ttoken; if (ttoken.size()) { - for (auto t : ttoken) { + for (const auto &t : ttoken) { if (t.startsWith("/*")) continue; //ignore comments textEditText += t; textEditText += '\n'; @@ -86,7 +86,7 @@ ScopyColorEditor::ScopyColorEditor(QApplication *app, QWidget *parent) QDir themes(":/stylesheets/themes/"); QStringList stylesheets = themes.entryList(); - for (const QString &entry : stylesheets) { + for (const QString &entry : qAsConst(stylesheets)) { m_ui->stylesheetsCmbBox->addItem(entry); } @@ -198,7 +198,8 @@ void ScopyColorEditor::buildMenuForMap() bool toAdd = false; - for (auto line : it.value()) { + auto itContainer = it.value(); + for (auto line : qAsConst(itContainer)) { std::vector controls; int index = 0; while ((index = line.indexOf("rgba(", index)) != -1) { @@ -361,7 +362,8 @@ void ScopyColorEditor::rebuildAndApplyStylesheet() for (auto it = m_entityStylesheetMap.begin(); it != m_entityStylesheetMap.end(); ++it) { stylesheet += it.key() + " {\n"; - for (auto line : it.value()) { + auto itContainer = it.value(); + for (const auto &line : qAsConst(itContainer)) { stylesheet += line + "\n"; } @@ -448,7 +450,7 @@ QString ScopyColorEditor::clearAndRebuildEditor(const QString &stylesheet) { m_entityStylesheetMap.clear(); auto layout = m_ui->scrollArea->widget()->layout(); - for (QWidget *widget : m_colorEditors) { + for (QWidget *widget : qAsConst(m_colorEditors)) { layout->removeWidget(widget); widget->deleteLater(); } @@ -491,7 +493,7 @@ void ScopyColorEditor::stylesheetSelected(const QString &stylesheet) void ScopyColorEditor::search(const QString &searchText) { - for (QWidget *w : m_colorEditors) { + for (QWidget *w : qAsConst(m_colorEditors)) { QLabel *label = qobject_cast(w->layout()->itemAt(0)->widget()); bool hasSearchedWords = label->text().contains(searchText); w->setVisible(hasSearchedWords); diff --git a/src/scroll_filter.cpp b/src/scroll_filter.cpp index a3100ded50..9fa0d76d8b 100644 --- a/src/scroll_filter.cpp +++ b/src/scroll_filter.cpp @@ -51,28 +51,28 @@ void MouseWheelWidgetGuard::installEventRecursively(QWidget *parentWidget) } QList comboBoxes = parentWidget-> findChildren(); - for(auto ch : comboBoxes) { + for(auto ch : qAsConst(comboBoxes)) { ch->installEventFilter(new MouseWheelWidgetGuard(ch)); ch->setFocusPolicy(Qt::StrongFocus); } QList doubleSpinBoxes = parentWidget-> findChildren(); - for(auto ch : doubleSpinBoxes) { + for(auto ch : qAsConst(doubleSpinBoxes)) { ch->installEventFilter(new MouseWheelWidgetGuard(ch)); ch->setFocusPolicy(Qt::StrongFocus); } QList spinBoxes = parentWidget-> findChildren(); - for(auto ch : spinBoxes) { + for(auto ch : qAsConst(spinBoxes)) { ch->installEventFilter(new MouseWheelWidgetGuard(ch)); ch->setFocusPolicy(Qt::StrongFocus); } QList lineEdits = parentWidget-> findChildren(); - for(auto ch : lineEdits) { + for(auto ch : qAsConst(lineEdits)) { ch->installEventFilter(new MouseWheelWidgetGuard(ch)); ch->setFocusPolicy(Qt::StrongFocus); } diff --git a/src/signal_generator.cpp b/src/signal_generator.cpp index 87d01cb479..9acfa5c148 100644 --- a/src/signal_generator.cpp +++ b/src/signal_generator.cpp @@ -143,7 +143,7 @@ SignalGenerator::SignalGenerator(struct iio_context *_ctx, Filter *filt, ui->run_button->enableSingleButton(false); this->setAttribute(Qt::WA_DeleteOnClose, true); - this->plot = new OscilloscopePlot(this); + this->m_plot = new CapturePlot(this); QVector iio_channels; @@ -460,40 +460,40 @@ SignalGenerator::SignalGenerator(struct iio_context *_ctx, Filter *filt, time_block_data->time_block = scope_sink_f::make( nb_points, sample_rate, "Signal Generator", nb_channels, - static_cast(plot)); + static_cast(m_plot)); /* Attach all curves by default */ - plot->registerSink(time_block_data->time_block->name(), + m_plot->registerSink(time_block_data->time_block->name(), nb_channels, nb_points); for(auto i = 0; i < nb_channels; i++) { - plot->Curve(i)->setPaintAttribute(QwtPlotCurve::ClipPolygons, false); - plot->Curve(i)->setPaintAttribute(QwtPlotCurve::FilterPointsAggressive, true); + m_plot->Curve(i)->setPaintAttribute(QwtPlotCurve::ClipPolygons, false); + m_plot->Curve(i)->setPaintAttribute(QwtPlotCurve::FilterPointsAggressive, true); } /* This must be done after attaching the curves; otherwise * plot->getLineColor(i) returns black. */ for (unsigned int i = 0; i < nb_channels; i++) { - channels[i]->setColor(plot->getLineColor(i)); + channels[i]->setColor(m_plot->getLineColor(i)); } - plot->disableLegend(); - plot->setPaletteColor(QColor("black")); + m_plot->disableLegend(); + m_plot->setPaletteColor(QColor("black")); - plot->setVertUnitsPerDiv(AMPLITUDE_VOLTS * 2.0 / 10.0); + m_plot->setVertUnitsPerDiv(AMPLITUDE_VOLTS * 2.0 / 10.0); - plot->setHorizUnitsPerDiv((double) nb_points / + m_plot->setHorizUnitsPerDiv((double) nb_points / ((double) sample_rate * 10.0)); - plot->setHorizOffset((double) nb_points / + m_plot->setHorizOffset((double) nb_points / ((double) sample_rate * 2.0)); - plot->zoomBaseUpdate(); - ui->plot->insertWidget(0,plot, 0, 0); + m_plot->zoomBaseUpdate(); + //ui->plot->insertWidget(0,m_plot, 0, 0); connect(ui->btnAppearanceCollapse, SIGNAL(toggled(bool)),ui->wAppearance, SLOT(setVisible(bool))); connect(ui->btnSigGenAutoscale, &QPushButton::toggled, [=](bool checked){ - plot->setAutoScale(checked); + m_plot->setAutoScale(checked); }); fileManager = new FileManager("Signal Generator"); @@ -585,7 +585,7 @@ SignalGenerator::SignalGenerator(struct iio_context *_ctx, Filter *filt, time_block_data->time_block->set_update_time(0.001); - plot->addZoomer(0); + m_plot->addZoomer(0); resetZoom(); auto ptr = getCurrentData(); @@ -593,10 +593,20 @@ SignalGenerator::SignalGenerator(struct iio_context *_ctx, Filter *filt, readPreferences(); - // Reduce the extent of the yLeft axis because it is not needed - plot->axisWidget(QwtPlot::yLeft)->scaleDraw()->setMinimumExtent(65); - ui->btnHelp->setUrl("https://wiki.analog.com/university/tools/m2k/scopy/siggen"); + + m_plot->setOffsetHandleVisible(0,false); + m_plot->setOffsetHandleVisible(1,false); + m_plot->enableAxis(QwtPlot::yLeft, false); + m_plot->setActiveVertAxis(0); + + m_plot->enableTimeTrigger(false); + + ui->plot->addWidget(m_plot->topArea(), 0, 0, 1, 4); + ui->plot->addWidget(m_plot->topHandlesArea(), 1, 0, 1, 4); + ui->plot->removeWidget(ui->instrumentNotes); + ui->plot->addWidget(ui->instrumentNotes,3,0,1,4); + ui->plot->addWidget(m_plot, 2, 1, 1, 1); } SignalGenerator::~SignalGenerator() @@ -611,7 +621,7 @@ SignalGenerator::~SignalGenerator() delete fileManager; - delete plot; + delete m_plot; delete ui; delete time_block_data; } @@ -634,7 +644,7 @@ void SignalGenerator::readPreferences() void SignalGenerator::resetZoom() { - disconnect(plot->getZoomer(),SIGNAL(zoomed(QRectF)),this,SLOT(rescale())); + disconnect(m_plot->getZoomer(),SIGNAL(zoomed(QRectF)),this,SLOT(rescale())); bool disable_zoom=false; for (auto it = channels.begin(); it != channels.end(); ++it) { @@ -647,11 +657,11 @@ void SignalGenerator::resetZoom() } if (!disable_zoom) { - connect(plot->getZoomer(),SIGNAL(zoomed(QRectF)),this,SLOT(rescale())); + connect(m_plot->getZoomer(),SIGNAL(zoomed(QRectF)),this,SLOT(rescale())); } double period = 0.0; - unsigned int slowSignalId = 0; + int slowSignalId = -1; for (auto it = channels.begin(); it != channels.end(); ++it) { if ((*it)->enableButton()->isChecked()) { @@ -704,21 +714,23 @@ void SignalGenerator::resetZoom() period=0.1; } - plot->setVertUnitsPerDiv(1); - plot->setVertOffset(0); - plot->setHorizUnitsPerDiv(period/10); - plot->setHorizOffset(period/2); - plot->zoomBaseUpdate(); + m_plot->setVertUnitsPerDiv(1); + m_plot->setVertOffset(0); + m_plot->setHorizUnitsPerDiv(period/10); + m_plot->setHorizOffset(period/2); + m_plot->zoomBaseUpdate(); rescale(); - plot->DetachCurve(slowSignalId); - plot->AttachCurve(slowSignalId); + if(slowSignalId != -1) { + m_plot->DetachCurve(slowSignalId); + m_plot->AttachCurve(slowSignalId); + } } void SignalGenerator::rescale() { - auto hOffset=plot->HorizOffset(); - auto hUnitsPerDiv=plot->HorizUnitsPerDiv(); + auto hOffset=m_plot->HorizOffset(); + auto hUnitsPerDiv=m_plot->HorizUnitsPerDiv(); auto xDivisions=10; @@ -741,15 +753,15 @@ void SignalGenerator::rescale() } long startSample=sample_rate*zoomT1; - plot->setDataStartingPoint(startSample); - plot->setSampleRate(sample_rate,1,"Hz"); + m_plot->setDataStartingPoint(startSample); + m_plot->setSampleRate(sample_rate,1,"Hz"); if (nb_points < 16) { nb_points = 16; } time_block_data->time_block->set_nsamps(nb_points); time_block_data->time_block->set_samp_rate(sample_rate); updatePreview(); - plot->replot(); + m_plot->replot(); } void SignalGenerator::constantValueChanged(double value) @@ -900,8 +912,8 @@ void SignalGenerator::lineThicknessChanged(int index) int lineThickness = (int)(ptr->lineThickness / 0.5) - 1; if (lineThickness != index) { ptr->lineThickness = 0.5 * (index + 1); - plot->setLineWidth(ptr->id, ptr->lineThickness); - plot->replot(); + m_plot->setLineWidth(ptr->id, ptr->lineThickness); + m_plot->replot(); } } @@ -1458,8 +1470,10 @@ void SignalGenerator::start() m_m2k_analogout->setOversamplingRatio(i, oversampling); m_m2k_analogout->setSampleRate(i, final_rate); + } + qDebug(CAT_SIGNAL_GENERATOR) << "Pushed cyclic buffer"; m_m2k_analogout->setCyclic(true); @@ -1616,7 +1630,8 @@ void SignalGenerator::loadFileChannelData(int chIdx) return; } - for (auto x : fileManager->read(ptr->file_channel)) { + auto fileChannels = fileManager->read(ptr->file_channel); + for (auto x : qAsConst(fileChannels)) { ptr->file_data.push_back(x); } } @@ -1895,13 +1910,13 @@ void adiscope::SignalGenerator::channelWidgetEnabled(bool en) m_m2k_analogout->enableChannel(id, en); if (en) { - plot->AttachCurve(id); + m_plot->AttachCurve(id); } else { - plot->DetachCurve(id); + m_plot->DetachCurve(id); } resetZoom(); - plot->replot(); + m_plot->replot(); bool enable_run = en; @@ -1937,8 +1952,6 @@ void adiscope::SignalGenerator::channelWidgetMenuToggled(bool checked) { ChannelWidget *cw = static_cast(QObject::sender()); - plot->setActiveVertAxis(cw->id()); - triggerRightMenuToggle(cw->id(), checked); } @@ -2045,6 +2058,9 @@ void SignalGenerator::updateRightMenuForChn(int chIdx) waveformUpdateUi(ptr->waveform); ui->tabWidget->setCurrentIndex((int) ptr->type); resizeTabWidget((int)ptr->type); + + ui->tabWidget->setStyleSheet(QString("QTabBar::tab:selected { border-bottom: 2px solid %1; }") + .arg(m_plot->getLineColor(chIdx).name())); } void SignalGenerator::updateAndToggleMenu(int chIdx, bool open) diff --git a/src/signal_generator.hpp b/src/signal_generator.hpp index fff07a6ebd..16e28a2857 100644 --- a/src/signal_generator.hpp +++ b/src/signal_generator.hpp @@ -148,7 +148,7 @@ class SignalGenerator : public Tool libm2k::analog::M2kAnalogOut* m_m2k_analogout; Ui::SignalGenerator *ui; - OscilloscopePlot *plot; + CapturePlot *m_plot; gr::top_block_sptr top_block; struct time_block_data *time_block_data; diff --git a/src/signal_generator_api.cpp b/src/signal_generator_api.cpp index 7a8b403681..a339ee4c0c 100644 --- a/src/signal_generator_api.cpp +++ b/src/signal_generator_api.cpp @@ -833,8 +833,8 @@ void SignalGenerator_API::setLineThickness(const QList& list) if(i == gen->currentChannel){ gen->updateRightMenuForChn(i); - gen->plot->setLineWidth(i, ptr->lineThickness); - gen->plot->replot(); + gen->m_plot->setLineWidth(i, ptr->lineThickness); + gen->m_plot->replot(); } } int index = (int)(gen->getCurrentData()->lineThickness / 0.5) - 1; diff --git a/src/spectrum_analyzer.cpp b/src/spectrum_analyzer.cpp index 0b699b110e..20b5f84bd9 100644 --- a/src/spectrum_analyzer.cpp +++ b/src/spectrum_analyzer.cpp @@ -50,6 +50,8 @@ /* Generated UI */ #include "ui_spectrum_analyzer.h" +#include "ui_cursors_settings.h" +#include "ui_cursor_readouts.h" #include #include @@ -129,6 +131,8 @@ SpectrumAnalyzer::SpectrumAnalyzer(struct iio_context *ctx, Filter *filt, crt_peak(0), max_peak_count(10), fft_size(32768), + hCursorsEnabled(true), + vCursorsEnabled(true), searchVisiblePeaks(true), m_max_sample_rate(100e6), sample_rate_divider(1), @@ -203,10 +207,12 @@ SpectrumAnalyzer::SpectrumAnalyzer(struct iio_context *ctx, Filter *filt, settings_group->addButton(ui->btnSweep); settings_group->addButton(ui->btnMarkers); settings_group->addButton(ui->btnAddRef); + settings_group->addButton(ui->btnCursors); settings_group->setExclusive(true); fft_plot = new FftDisplayPlot(m_adc_nb_channels, this); fft_plot->disableLegend(); + // Disable mouse interactions with the axes until they are in a working state fft_plot->setXaxisMouseGesturesEnabled(false); @@ -214,9 +220,10 @@ SpectrumAnalyzer::SpectrumAnalyzer(struct iio_context *ctx, Filter *filt, fft_plot->setYaxisMouseGesturesEnabled(i, false); } - QGridLayout *gLayout = static_cast - (ui->widgetPlotContainer->layout()); - gLayout->addWidget(fft_plot, 1, 0, 1, 1); + ui->gridLayout_plot->addWidget(fft_plot->getPlotwithElements(), 1, 0, 1, 1); + + fft_plot->enableXaxisLabels(); + fft_plot->enableYaxisLabels(); // Initialize spectrum channels for (int i = 0 ; i < m_adc_nb_channels; i++) { @@ -293,6 +300,7 @@ SpectrumAnalyzer::SpectrumAnalyzer(struct iio_context *ctx, Filter *filt, fft_plot->setStartStop(start, stop); fft_plot->setAxisScale(QwtPlot::xBottom, start, stop); fft_plot->replot(); + fft_plot->bottomHandlesArea()->repaint(); setSampleRate(2 * stop); @@ -399,6 +407,10 @@ SpectrumAnalyzer::SpectrumAnalyzer(struct iio_context *ctx, Filter *filt, connect(fft_plot, SIGNAL(sampleCountUpdated(uint)), this, SLOT(onPlotSampleCountUpdated(uint))); + + connect(this, SIGNAL(selectedChannelChanged(int)), + fft_plot, SLOT(setSelectedChannel(int))); + if (ctx) { build_gnuradio_block_chain(); } else { @@ -438,6 +450,12 @@ SpectrumAnalyzer::SpectrumAnalyzer(struct iio_context *ctx, Filter *filt, connect(bottom_scale, SIGNAL(valueChanged(double)), SLOT(onBottomValueChanged(double))); + cursor_panel_init(); + + connect(fft_plot, + SIGNAL(cursorReadoutsChanged(struct cursorReadoutsText)), + SLOT(onCursorReadoutsChanged(struct cursorReadoutsText))); + // UI default ui->comboBox_window->setCurrentText("Hamming"); ui->comboBox_line_thickness->setCurrentText("1"); @@ -458,7 +476,7 @@ SpectrumAnalyzer::SpectrumAnalyzer(struct iio_context *ctx, Filter *filt, ui->lblMagUnit->setText(ui->cmb_units->currentText()); ui->markerTable->hide(); - for (auto ch: channels) { + for (auto ch: qAsConst(channels)) { ch->setFftWindow(FftWinType::HAMMING, fft_size); } @@ -788,6 +806,8 @@ void SpectrumAnalyzer::toggleRightMenu(CustomPushButton *btn, bool checked) index = 3; } else if (btn == ui->btnAddRef) { index = 4; + } else if (btn == ui->btnCursors) { + index = 5; } } @@ -820,6 +840,25 @@ void SpectrumAnalyzer::rightMenuFinished(bool opened) } } +void SpectrumAnalyzer::on_boxCursors_toggled(bool on) +{ + fft_plot->setHorizCursorsEnabled( + on ? cr_ui->vCursorsEnable->isChecked() : false); + fft_plot->setVertCursorsEnabled( + on ? cr_ui->hCursorsEnable->isChecked() : false); + + fft_plot->trackModeEnabled(on ? cr_ui->btnNormalTrack->isChecked() : true); + + if (on) { + fft_plot->setCursorReadoutsVisible(on); + } else { + if (ui->btnCursors->isChecked()) + ui->btnCursors->setChecked(false); + + menuOrder.removeOne(ui->btnCursors); + } +} + void SpectrumAnalyzer::on_btnToolSettings_toggled(bool checked) { triggerRightMenuToggle( @@ -844,6 +883,12 @@ void SpectrumAnalyzer::on_btnSettings_clicked(bool checked) } } +void SpectrumAnalyzer::on_btnCursors_toggled(bool checked) +{ + triggerRightMenuToggle( + static_cast(QObject::sender()), checked); +} + void SpectrumAnalyzer::on_btnSweep_toggled(bool checked) { triggerRightMenuToggle( @@ -919,13 +964,93 @@ void SpectrumAnalyzer::on_btnImport_clicked() { QMap import_map = ui->importSettings->getExportConfig(); - for (int key : import_map.keys()) { + auto keys = import_map.keys(); + for (int key : qAsConst(keys)) { if (import_map[key]) { add_ref_waveform(key); } } } +void SpectrumAnalyzer::cursor_panel_init() +{ + cr_ui = new Ui::CursorsSettings; + cr_ui->setupUi(ui->cursorsSettings); + setDynamicProperty(cr_ui->btnLockHorizontal, "use_icon", true); + setDynamicProperty(cr_ui->btnLockVertical, "use_icon", true); + + connect(cr_ui->btnLockHorizontal, &QPushButton::toggled, + fft_plot, &FftDisplayPlot::setHorizCursorsLocked); + connect(cr_ui->btnLockVertical, &QPushButton::toggled, + fft_plot, &FftDisplayPlot::setVertCursorsLocked); + + cursorsPositionButton = new CustomPlotPositionButton(cr_ui->posSelect); + + connect(cr_ui->hCursorsEnable, SIGNAL(toggled(bool)), + fft_plot, SLOT(setVertCursorsEnabled(bool))); + connect(cr_ui->vCursorsEnable, SIGNAL(toggled(bool)), + fft_plot, SLOT(setHorizCursorsEnabled(bool))); + connect(cr_ui->btnNormalTrack, &QPushButton::toggled, + this, &SpectrumAnalyzer::toggleCursorsMode); + + cr_ui->horizontalSlider->setMaximum(100); + cr_ui->horizontalSlider->setMinimum(0); + cr_ui->horizontalSlider->setSingleStep(1); + + connect(cr_ui->horizontalSlider, &QSlider::valueChanged, [=](int value){ + cr_ui->transLabel->setText(tr("Transparency ") + QString::number(value) + "%"); + fft_plot->setCursorReadoutsTransparency(value); + }); + cr_ui->horizontalSlider->setSliderPosition(0); + + connect(cursorsPositionButton, &CustomPlotPositionButton::positionChanged, + [=](CustomPlotPositionButton::ReadoutsPosition position){ + fft_plot->moveCursorReadouts(position); + }); + +} + + +void SpectrumAnalyzer::toggleCursorsMode(bool toggled) +{ + cr_ui->hCursorsEnable->setEnabled(toggled); + cr_ui->vCursorsEnable->setEnabled(toggled); + + if (toggled) { + fft_plot->setVertCursorsEnabled(hCursorsEnabled); + fft_plot->setHorizCursorsEnabled(vCursorsEnabled); +// cursor_readouts_ui->TimeCursors->setVisible(vCursorsEnabled); +// cursor_readouts_ui->VoltageCursors->setVisible(hCursorsEnabled); + } else { + hCursorsEnabled = cr_ui->hCursorsEnable->isChecked(); + vCursorsEnabled = cr_ui->vCursorsEnable->isChecked(); + fft_plot->setVertCursorsEnabled(true); + fft_plot->setHorizCursorsEnabled(true); +// cursor_readouts_ui->TimeCursors->setVisible(true); +// cursor_readouts_ui->VoltageCursors->setVisible(true); + } + + cr_ui->btnLockVertical->setEnabled(toggled); + fft_plot->trackModeEnabled(toggled); +} + +void SpectrumAnalyzer::onCursorReadoutsChanged(struct cursorReadoutsText data) +{ + fillCursorReadouts(data); +} + +void SpectrumAnalyzer::fillCursorReadouts(const struct cursorReadoutsText& data) +{ + //needs to be filled when measure ui is added + // cursor_readouts_ui->cursorT1->setText(data.t1); + // cursor_readouts_ui->cursorT2->setText(data.t2); + // cursor_readouts_ui->timeDelta->setText(data.tDelta); + // cursor_readouts_ui->frequencyDelta->setText(data.freq); + // cursor_readouts_ui->cursorV1->setText(data.v1); + // cursor_readouts_ui->cursorV2->setText(data.v2); + // cursor_readouts_ui->voltageDelta->setText(data.vDelta); +} + QString SpectrumAnalyzer::getReferenceChannelName() const { int current = 1; @@ -933,7 +1058,7 @@ QString SpectrumAnalyzer::getReferenceChannelName() const bool isOk = true; for (const auto &ref_channel : referenceChannels) { QString shortName = ref_channel->shortName(); - int channel_counter = shortName.mid(shortName.size() - 1).toInt(); + int channel_counter = shortName.midRef(shortName.size() - 1).toInt(); if (current == channel_counter) { isOk = false; break; @@ -1038,6 +1163,7 @@ void SpectrumAnalyzer::onReferenceChannelDeleted() if (channelWidget->id() < crt_channel_id) { crt_channel_id--; + Q_EMIT selectedChannelChanged(crt_channel_id); } else if (channelWidget->id() == crt_channel_id) { for (int i = 0; i < m_adc_nb_channels + nb_ref_channels; ++i) { auto cw = getChannelWidgetAt(i); @@ -1046,6 +1172,7 @@ void SpectrumAnalyzer::onReferenceChannelDeleted() } if (cw->enableButton()->isChecked()) { channelsEnabled = true; + Q_EMIT selectedChannelChanged(0); cw->nameButton()->setChecked(true); break; } @@ -1468,7 +1595,11 @@ void SpectrumAnalyzer::onChannelSelected(bool en) ChannelWidget *cw = static_cast(QObject::sender()); int chIdx = cw->id(); - crt_channel_id = chIdx; + if(crt_channel_id != chIdx) + { + crt_channel_id = chIdx; + Q_EMIT selectedChannelChanged(chIdx); + } if (!cw->isReferenceChannel()) { const bool visible = (channels[crt_channel_id]->averageType() != FftDisplayPlot::AverageType::SAMPLE); @@ -2113,6 +2244,7 @@ void SpectrumAnalyzer::on_cmb_units_currentIndexChanged(const QString& unit) fft_plot->recalculateMagnitudes(); fft_plot->replot(); + fft_plot->leftHandlesArea()->repaint(); ui->lblMagUnit->setText(unit); @@ -2170,11 +2302,11 @@ void SpectrumAnalyzer::on_btnMarkerTable_toggled(bool checked) // Set the Plot 3 times taller than the Marker Table (when visible) QGridLayout *layout = static_cast( - ui->widgetPlotContainer->layout()); + ui->widgetPlotContainer->layout()); int row1 = getGridLayoutPosFromIndex(layout, - layout->indexOf(ui->markerTable)).first; + layout->indexOf(ui->markerTable)).first; int row2 = getGridLayoutPosFromIndex(layout, - layout->indexOf(fft_plot)).first; + layout->indexOf(ui->gridLayout_plot)).first; if (checked) { layout->setRowStretch(row1, 1); @@ -2215,6 +2347,9 @@ void SpectrumAnalyzer::onTopValueChanged(double top_value) fft_plot->setAxisScale(QwtPlot::yLeft, bottom_scale->value(), top_value); } fft_plot->replot(); + auto div = fft_plot->axisScaleDiv(QwtPlot::yLeft); + fft_plot->setYaxisMajorTicksPos(div.ticks(2)); + fft_plot->leftHandlesArea()->repaint(); } void SpectrumAnalyzer::onScalePerDivValueChanged(double perDiv) @@ -2257,6 +2392,9 @@ void SpectrumAnalyzer::onBottomValueChanged(double bottom_value) fft_plot->setAxisScale(QwtPlot::yLeft, bottom_value, top_scale->value()); } fft_plot->replot(); + auto div = fft_plot->axisScaleDiv(QwtPlot::yLeft); + fft_plot->setYaxisMajorTicksPos(div.ticks(2)); + fft_plot->leftHandlesArea()->repaint(); } void SpectrumAnalyzer::onCurrentAverageIndexChanged(uint chnIdx, uint avgIdx) diff --git a/src/spectrum_analyzer.hpp b/src/spectrum_analyzer.hpp index 0af38fe868..938e39bf05 100644 --- a/src/spectrum_analyzer.hpp +++ b/src/spectrum_analyzer.hpp @@ -54,6 +54,8 @@ extern "C" { namespace Ui { class SpectrumAnalyzer; +class CursorReadouts; +class CursorsSettings; } namespace adiscope { @@ -111,6 +113,7 @@ public Q_SLOTS: Q_SIGNALS: void started(bool); void showTool(); + void selectedChannelChanged(int); private Q_SLOTS: void on_btnHistory_toggled(bool checked); @@ -119,6 +122,12 @@ private Q_SLOTS: void on_btnSettings_clicked(bool checked); void on_btnSweep_toggled(bool checked); void on_btnMarkers_toggled(bool checked); + + void on_boxCursors_toggled(bool on); + void on_btnCursors_toggled(bool); + void onCursorReadoutsChanged(struct cursorReadoutsText); + void toggleCursorsMode(bool toggled); + void on_comboBox_type_currentIndexChanged(const QString&); void on_comboBox_window_currentIndexChanged(const QString&); void on_comboBox_line_thickness_currentIndexChanged(int index); @@ -197,6 +206,15 @@ private Q_SLOTS: libm2k::context::Generic* m_generic_context; libm2k::analog::GenericAnalogIn* m_generic_analogin; Ui::SpectrumAnalyzer *ui; + + + Ui::CursorReadouts *cursor_readouts_ui; + QWidget *cursorReadouts; + Ui::CursorsSettings *cr_ui; + CustomPlotPositionButton *cursorsPositionButton; + bool hCursorsEnabled; + bool vCursorsEnabled; + adiscope::DbClickButtons *marker_selector; unsigned int m_nb_overlapping_avg; @@ -254,6 +272,9 @@ private Q_SLOTS: bool isIioManagerStarted() const; void setCurrentSampleLabel(double); + void cursor_panel_init(); + void fillCursorReadouts(const struct cursorReadoutsText &); + bool canSwitchAverageHistory(FftDisplayPlot::AverageType avg_type); }; diff --git a/src/spectrum_analyzer_api.cpp b/src/spectrum_analyzer_api.cpp index bdd9214e46..fc15c2612e 100644 --- a/src/spectrum_analyzer_api.cpp +++ b/src/spectrum_analyzer_api.cpp @@ -19,6 +19,7 @@ */ #include "spectrum_analyzer_api.hpp" #include "ui_spectrum_analyzer.h" +#include "ui_cursors_settings.h" #include "channel_widget.hpp" #include "db_click_buttons.hpp" @@ -218,7 +219,7 @@ QVariantList SpectrumAnalyzer_API::getMarkers() { QVariantList list; - for (SpectrumMarker_API *each : sp->marker_api) { + for (SpectrumMarker_API *each : qAsConst(sp->marker_api)) { list.append(QVariant::fromValue(each)); } @@ -226,6 +227,16 @@ QVariantList SpectrumAnalyzer_API::getMarkers() } +bool SpectrumAnalyzer_API::hasCursors() const +{ + return sp->ui->boxCursors->isChecked(); +} + +void SpectrumAnalyzer_API::setCursors(bool en) +{ + sp->ui->boxCursors->setChecked(en); +} + bool SpectrumAnalyzer_API::running() { return sp->runButton()->isChecked(); @@ -249,7 +260,7 @@ QVariantList SpectrumAnalyzer_API::getChannels() { QVariantList list; - for (SpectrumChannel_API *each : sp->ch_api) { + for (SpectrumChannel_API *each : qAsConst(sp->ch_api)) { list.append(QVariant::fromValue(each)); } @@ -364,11 +375,82 @@ void SpectrumAnalyzer_API::setMarkerTableVisible(bool en) sp->ui->btnMarkerTable->setChecked(en); } +bool SpectrumAnalyzer_API::horizontalCursors() const +{ + return sp->cr_ui->hCursorsEnable->isChecked(); +} + +void SpectrumAnalyzer_API::setHorizontalCursors(bool en) +{ + sp->cr_ui->hCursorsEnable->setChecked(en); +} + +bool SpectrumAnalyzer_API::verticalCursors() const +{ + return sp->cr_ui->vCursorsEnable->isChecked(); +} + +void SpectrumAnalyzer_API::setVerticalCursors(bool en) +{ + sp->cr_ui->vCursorsEnable->setChecked(en); +} + bool SpectrumAnalyzer_API::getLogScale() const { return sp->fft_plot->getLogScale(); } +int SpectrumAnalyzer_API::getCursorsPosition() const +{ + if (!hasCursors()) { + return 0; + } + auto currentPos = sp->fft_plot->d_cursorReadouts->getCurrentPosition(); + switch (currentPos) { + case CustomPlotPositionButton::ReadoutsPosition::topLeft: + default: + return 0; + case CustomPlotPositionButton::ReadoutsPosition::topRight: + return 1; + case CustomPlotPositionButton::ReadoutsPosition::bottomLeft: + return 2; + case CustomPlotPositionButton::ReadoutsPosition::bottomRight: + return 3; + } + return 3; +} + +void SpectrumAnalyzer_API::setCursorsPosition(int val) +{ + if (!hasCursors()) { + return; + } + enum CustomPlotPositionButton::ReadoutsPosition types[] = { + CustomPlotPositionButton::ReadoutsPosition::topLeft, + CustomPlotPositionButton::ReadoutsPosition::topRight, + CustomPlotPositionButton::ReadoutsPosition::bottomLeft, + CustomPlotPositionButton::ReadoutsPosition::bottomRight + }; + sp->cursorsPositionButton->setPosition(types[val]); + sp->fft_plot->replot(); +} + +int SpectrumAnalyzer_API::getCursorsTransparency() const +{ + if (!hasCursors()) { + return 0; + } + return sp->cr_ui->horizontalSlider->value(); +} + +void SpectrumAnalyzer_API::setCursorsTransparency(int val) +{ + if (!hasCursors()) { + return; + } + sp->cr_ui->horizontalSlider->setValue(val); +} + void SpectrumAnalyzer_API::setLogScale(bool useLogScale) { sp->ui->logBtn->setChecked(useLogScale); diff --git a/src/spectrum_analyzer_api.hpp b/src/spectrum_analyzer_api.hpp index 8439efef25..ddc6371507 100644 --- a/src/spectrum_analyzer_api.hpp +++ b/src/spectrum_analyzer_api.hpp @@ -27,6 +27,7 @@ namespace adiscope { class SpectrumAnalyzer_API : public ApiObject { Q_OBJECT + Q_PROPERTY(bool cursors READ hasCursors WRITE setCursors); Q_PROPERTY(bool running READ running WRITE run STORED false); Q_PROPERTY(bool single READ isSingle WRITE single STORED false); Q_PROPERTY(double startFreq READ startFreq WRITE setStartFreq); @@ -42,6 +43,15 @@ class SpectrumAnalyzer_API : public ApiObject setMarkerTableVisible); Q_PROPERTY(QVariantList markers READ getMarkers); + Q_PROPERTY(bool horizontal_cursors READ horizontalCursors + WRITE setHorizontalCursors) + Q_PROPERTY(bool vertical_cursors READ verticalCursors + WRITE setVerticalCursors) + Q_PROPERTY(int cursors_position READ getCursorsPosition + WRITE setCursorsPosition) + Q_PROPERTY(int cursors_transparency READ getCursorsTransparency + WRITE setCursorsTransparency) + Q_PROPERTY(bool logScale READ getLogScale WRITE setLogScale) Q_PROPERTY(QString notes READ getNotes WRITE setNotes) @@ -53,6 +63,10 @@ class SpectrumAnalyzer_API : public ApiObject private: SpectrumAnalyzer *sp; + + bool hasCursors() const; + void setCursors(bool en); + bool running(); void run(bool); @@ -89,6 +103,18 @@ class SpectrumAnalyzer_API : public ApiObject bool markerTableVisible(); void setMarkerTableVisible(bool); + bool horizontalCursors() const; + void setHorizontalCursors(bool en); + + bool verticalCursors() const; + void setVerticalCursors(bool en); + + int getCursorsPosition() const; + void setCursorsPosition(int val); + + int getCursorsTransparency() const; + void setCursorsTransparency(int val); + bool getLogScale() const; void setLogScale(bool useLogScale); diff --git a/src/spinbox_a.cpp b/src/spinbox_a.cpp index cc3c709780..307f6324e4 100644 --- a/src/spinbox_a.cpp +++ b/src/spinbox_a.cpp @@ -86,7 +86,7 @@ SpinBoxA::SpinBoxA(vector >units, const QString& name, /* Compat */ QStringList list; - for (auto unit : units) { + for (const auto &unit : units) { list.append(QString("%1=%2").arg(unit.first).arg(unit.second)); } @@ -670,6 +670,13 @@ int ScaleSpinButton::getIntegerDivider() void ScaleSpinButton::setValue(double newVal) { + if(newVal > m_max_value) { + newVal = m_max_value; + } + if(newVal < m_min_value) { + newVal = m_min_value; + } + if(integer_divider) { integer_step = round(integer_divider / newVal); diff --git a/src/stream_to_vector_overlap_impl.cc b/src/stream_to_vector_overlap_impl.cc index 4534a8f421..65b82b956a 100644 --- a/src/stream_to_vector_overlap_impl.cc +++ b/src/stream_to_vector_overlap_impl.cc @@ -64,10 +64,10 @@ stream_to_vector_overlap_impl::stream_to_vector_overlap_impl(size_t itemsize, io_signature::make(1, 1, itemsize * nitems_per_block), nitems_per_block), m_overlap_factor(overlap_factor), - m_nitems_per_block(nitems_per_block), - m_itemsize(itemsize) + m_itemsize(itemsize), + m_nitems_per_block(nitems_per_block) { - m_nb_overlapped_items = nitems_per_block * m_overlap_factor; + m_nb_overlapped_items = (size_t)(nitems_per_block * m_overlap_factor); } int stream_to_vector_overlap_impl::work(int noutput_items, @@ -81,8 +81,8 @@ int stream_to_vector_overlap_impl::work(int noutput_items, const char* in = (const char*)input_items[0]; char* out = (char*)output_items[0]; - unsigned int src_index = 0; - while (src_index + block_size < nb_input_items) { + size_t src_index = 0; + while (src_index + block_size <= nb_input_items) { memcpy(out + nb_total_copied_items, in + src_index, block_size); nb_total_copied_items += block_size; src_index = src_index + block_size - overlap_size; diff --git a/src/stream_to_vector_overlap_impl.h b/src/stream_to_vector_overlap_impl.h index 1e4e7e4cbc..74478a7e77 100644 --- a/src/stream_to_vector_overlap_impl.h +++ b/src/stream_to_vector_overlap_impl.h @@ -60,7 +60,7 @@ class stream_to_vector_overlap_impl : public stream_to_vector_overlap private: double m_overlap_factor; - unsigned int m_nb_overlapped_items; + size_t m_nb_overlapped_items; size_t m_itemsize; size_t m_nitems_per_block; }; diff --git a/src/tool_launcher.cpp b/src/tool_launcher.cpp index b1222a8dd1..373d4f050e 100644 --- a/src/tool_launcher.cpp +++ b/src/tool_launcher.cpp @@ -223,8 +223,8 @@ ToolLauncher::ToolLauncher(QString prevCrashDump, QWidget *parent) : connect(ui->stackedWidget, SIGNAL(moved(int)), this, SLOT(pageMoved(int))); - - m_phoneHome = new PhoneHome(settings, prefPanel); + networkAccessManager = new QNetworkAccessManager(this); + m_phoneHome = new PhoneHome(settings, prefPanel, networkAccessManager); if (prefPanel->getFirst_application_run()) { QMessageBox* msgBox = new QMessageBox(this); @@ -274,7 +274,10 @@ ToolLauncher::ToolLauncher(QString prevCrashDump, QWidget *parent) : menu->getToolMenuItemFor(TOOL_NETWORK_ANALYZER)->setCalibrating(false); if (!okc.second && okc.first) { - selectedDev->infoPage()->setCalibrationStatusLabel(tr("Calibrated")); + QMetaObject::invokeMethod(selectedDev->infoPage(), + "setCalibrationStatusLabel", + Qt::QueuedConnection, + Q_ARG(QString, tr("Calibrated"))); } }); @@ -1122,6 +1125,8 @@ void adiscope::ToolLauncher::disconnect() infoPg->setCalibrationStatusLabel(""); } search_timer->start(TIMER_TIMEOUT_MS); + selectedDev->infoPage()->setConnectionStatusLabel("Not connected"); + selectedDev->infoPage()->setCalibrationStatusLabel(""); } /* Update the list of devices now */ @@ -1198,7 +1203,6 @@ void adiscope::ToolLauncher::connectBtn_clicked(bool pressed) bool success = switchContext(uri); if (success) { selectedDev->setConnected(true, false, ctx); - selectedDev->connectButton()->setText(tr("Calibrating...")); selectedDev->setName(filter->hw_name()); selectedDev->infoPage()->identifyDevice(true); setDynamicProperty(ui->btnConnect, "connected", true); @@ -1364,7 +1368,7 @@ void adiscope::ToolLauncher::saveRunningToolsBeforeCalibration() void adiscope::ToolLauncher::stopToolsBeforeCalibration() { - for(Tool* tool : calibration_saved_tools) + for(Tool* tool : qAsConst(calibration_saved_tools)) tool->stop(); } void adiscope::ToolLauncher::restartToolsAfterCalibration() @@ -1439,10 +1443,12 @@ QPair adiscope::ToolLauncher::calibrate() bool skipCalib = false; + QString statusLabel; if (calib->isInitialized()) { if (prefPanel->getAttemptTempLutCalib() && calib->hasContextCalibration()) { float calibTemperature = calib->calibrateFromContext(); - selectedDev->infoPage()->setCalibrationStatusLabel(tr("Calibrated from look-up table @ ") + QString::number(calibTemperature) + " deg. Celsius" ); + + statusLabel = tr("Calibrated from look-up table @ ") + QString::number(calibTemperature) + " deg. Celsius"; skipCalib = true; ok = true; @@ -1450,14 +1456,20 @@ QPair adiscope::ToolLauncher::calibrate() // always calibrate if initial flag is set // if it's calibrated and skip_calibration_if_calibrated - do not calibrate if (!(initialCalibrationFlag && skip_calibration_if_already_calibrated && calib->isCalibrated() )) { + statusLabel = tr("Calibrating ... "); ok = calib->calibrateAll(); } else { - selectedDev->infoPage()->setCalibrationStatusLabel(tr("Calibration skipped because already calibrated.")); + statusLabel = tr("Calibration skipped because already calibrated."); skipCalib = true; ok = true; } } + ok = calib->calibrateAll(); } + QMetaObject::invokeMethod(selectedDev->infoPage(), + "setCalibrationStatusLabel", + Qt::QueuedConnection, + Q_ARG(QString, statusLabel)); calibrating = false; @@ -1574,9 +1586,6 @@ void adiscope::ToolLauncher::enableDacBasedTools() if (m_adc_tools_failed || m_dac_tools_failed) { disconnect(); - } else { - m_sessionInfo.setLastConnectedFirmware(selectedDev->infoPage()->getFirmwareVersion()); - m_sessionInfo.setLastConnectedSerialNumber(selectedDev->infoPage()->getSerialNumber()); } } @@ -1666,7 +1675,6 @@ bool adiscope::ToolLauncher::switchContext(const QString& uri) }); } - if (filter->compatible((TOOL_PATTERN_GENERATOR))) { pattern_generator = new logic::PatternGenerator(ctx, filter, menu->getToolMenuItemFor(TOOL_PATTERN_GENERATOR), &js_engine, dioManager, this); @@ -1676,6 +1684,7 @@ bool adiscope::ToolLauncher::switchContext(const QString& uri) }); } } + catch (libm2k::m2k_exception &e) { return false; } @@ -1826,12 +1835,12 @@ void ToolLauncher::closeEvent(QCloseEvent *event) // Close all detached windows QApplication::closeAllWindows(); - for (auto iterator : debugInstances) { + for (auto iterator : qAsConst(debugInstances)) { delete iterator; } debugInstances.clear(); - for (auto iterator : debugWindows) { + for (auto iterator : qAsConst(debugWindows)) { iterator->close(); delete iterator; } diff --git a/src/tool_launcher.hpp b/src/tool_launcher.hpp index 6e98b7f65f..865c94621c 100644 --- a/src/tool_launcher.hpp +++ b/src/tool_launcher.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -272,6 +273,7 @@ private Q_SLOTS: void saveRunningToolsBeforeCalibration(); void stopToolsBeforeCalibration(); + QNetworkAccessManager* networkAccessManager; PhoneHome* m_phoneHome; SessionInfo m_sessionInfo; diff --git a/src/tool_launcher_api.cpp b/src/tool_launcher_api.cpp index 1917f980f7..adaade2851 100644 --- a/src/tool_launcher_api.cpp +++ b/src/tool_launcher_api.cpp @@ -197,7 +197,7 @@ void ToolLauncher_API::load(const QString& file) ApiObjectManager::getInstance().load(settings); - for (auto tool : tl->toolList) + for (auto tool : qAsConst(tl->toolList)) tool->settingsLoaded(); } diff --git a/src/user_notes_api.cpp b/src/user_notes_api.cpp index 47a3808ca6..decd532802 100644 --- a/src/user_notes_api.cpp +++ b/src/user_notes_api.cpp @@ -68,7 +68,7 @@ QVariantList UserNotes_API::getNotes() QVariantList list; refreshApi(); - for (auto *each : notes_list_api) { + for (auto *each : qAsConst(notes_list_api)) { list.append(QVariant::fromValue(each)); } return list; diff --git a/ui/cursor_readouts.ui b/ui/cursor_readouts.ui index 3e713fbb3e..ef1a1381b3 100644 --- a/ui/cursor_readouts.ui +++ b/ui/cursor_readouts.ui @@ -314,23 +314,7 @@ - CurV2 - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - ΔV + CurV2 = Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -346,14 +330,14 @@ - CurV1 + CurV1 = Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - + @@ -366,7 +350,23 @@ - + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 0 + 0 + + + + + false @@ -382,7 +382,23 @@ - + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 0 + 0 + + + + + @@ -395,21 +411,24 @@ - - - - Qt::Vertical + + + + + 0 + 0 + - - QSizePolicy::Fixed + + color: rgba(255, 255, 255, 153); - - - 0 - 0 - + + ΔV = - + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + @@ -427,24 +446,8 @@ - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 0 - 0 - - - - - - + + Qt::Vertical @@ -459,7 +462,7 @@ - + @@ -472,27 +475,6 @@ - - - - = - - - - - - - = - - - - - - - = - - - diff --git a/ui/cursors_settings.ui b/ui/cursors_settings.ui index d2a8d845d6..f831c36fba 100644 --- a/ui/cursors_settings.ui +++ b/ui/cursors_settings.ui @@ -21,7 +21,7 @@ 18 - 0 + 5 18 @@ -37,6 +37,9 @@ 0 + + QFrame::NoFrame + Qt::ScrollBarAsNeeded @@ -51,8 +54,8 @@ 0 0 - 276 - 601 + 278 + 598 @@ -82,7 +85,7 @@ - 240 + 280 2 @@ -119,45 +122,58 @@ QLayout::SetDefaultConstraint - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 10 - 25 - - - - - - - - 0 - - - - - true - - - - 0 - 0 - - - - - 238 - 30 - - - - QPushButton { + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 10 + 25 + + + + + + + + true + + + + 0 + 0 + + + + + 238 + 30 + + + + QPushButton { min-height: 30px; max-height: 30px; min-width: 238px; @@ -219,47 +235,48 @@ QLabel#off:disabled { color: rgba(255,255,255,51); } - - - - - - true - - - true - - - false - - - Normal - - - Track - - - 0 - - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 15 - - - + + + + + + true + + + true + + + false + + + Normal + + + Track + + + 0 + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 15 + + + + + + @@ -375,131 +392,156 @@ color: rgba(255,255,255,51); - - - 0 - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 0 - 25 - - - - - - - - - 0 - 1 - - - - - 16777215 - 1 - - - - Qt::Horizontal - - - true - - - - - - - - 0 - 0 - - - - VERTICAL - - - true - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 0 - 15 - - - - - + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 0 + 25 + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + Qt::Horizontal + + + true + + + + + + + + 0 + 0 + + + + VERTICAL + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 0 + 15 + + + + + + - - - 10 - - - - - 0 - - - - - true - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - QPushButton[use_icon=true] - - - - - - true - - - - - - + + + + 10 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + true + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + QPushButton[use_icon=true] + + + + + + true + + + + + + + diff --git a/ui/digitalIoElement.ui b/ui/digitalIoElement.ui index 12ff028793..1120a30827 100644 --- a/ui/digitalIoElement.ui +++ b/ui/digitalIoElement.ui @@ -145,7 +145,7 @@ width: 1310px; } - 1 + 0 diff --git a/ui/dmm.ui b/ui/dmm.ui index fba8128fc3..2b568c2960 100644 --- a/ui/dmm.ui +++ b/ui/dmm.ui @@ -7,7 +7,7 @@ 0 0 900 - 830 + 890 @@ -227,23 +227,41 @@ QPushButton:disabled { 0 - + + + Qt::Horizontal + + + + 40 + 20 + + + + + + - font-size: 13px; + font-size: 13px; +color: red; +text-align:right; - Low Gain + + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - + font-size: 13px; -color: red; +text-align:center; - + ±25V @@ -542,23 +560,44 @@ QLabel[ac=true] { qproperty-text: "VRMS"; } 0 - + + + Qt::Horizontal + + + + 40 + 20 + + + + + + - font-size: 13px; + font-size: 13px; +color: red; +text-align:right; - Low Gain + + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - + font-size: 13px; -color: red; +text-align:center; - + ±25V + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft @@ -987,7 +1026,7 @@ QLabel[ac=true] { qproperty-text: "VRMS"; } - Gain + Range @@ -1000,12 +1039,12 @@ QLabel[ac=true] { qproperty-text: "VRMS"; } - Low + ± 25V - High + ± 2.5V @@ -1265,7 +1304,7 @@ QLabel[ac=true] { qproperty-text: "VRMS"; } - Gain + Range @@ -1278,12 +1317,12 @@ QLabel[ac=true] { qproperty-text: "VRMS"; } - Low + ± 25V - High + ± 2.5V @@ -1981,6 +2020,9 @@ line-height: 14px; + + + @@ -2017,7 +2059,7 @@ line-height: 14px; - + diff --git a/ui/logic_analyzer.ui b/ui/logic_analyzer.ui index efb8871aa0..1579a8795e 100644 --- a/ui/logic_analyzer.ui +++ b/ui/logic_analyzer.ui @@ -2047,7 +2047,7 @@ QPushButton:checked { border-image: url(:/icons/setup_btn_checked.svg); } cursorsBox - clicked(bool) + toggled(bool) btnCursors setEnabled(bool) diff --git a/ui/network_analyzer.ui b/ui/network_analyzer.ui index 7a5249ff5a..8e04fbbf07 100644 --- a/ui/network_analyzer.ui +++ b/ui/network_analyzer.ui @@ -796,7 +796,7 @@ border: 5px solid white; - 0 + 2 @@ -839,7 +839,7 @@ border: 5px solid white; 0 - -465 + 0 340 1036 @@ -2041,6 +2041,9 @@ padding-left: 20px; + + QFrame::NoFrame + Qt::ScrollBarAlwaysOff @@ -2052,8 +2055,8 @@ padding-left: 20px; 0 0 - 298 - 529 + 300 + 531 @@ -2741,8 +2744,141 @@ padding-left: 20px; + + + + 0 + + + + + + 0 + 0 + + + + QLabel { + font-size: 12px; + color: rgba(255, 255, 255, 70); + } + + + HORIZONTAL + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + border: 1px solid rgba(255, 255, 255, 70); + + + Qt::Horizontal + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 0 + 15 + + + + + + + + 0 + + + + + 0 + + + + + + + + true + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + true + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 0 + 15 + + + + + + 0 + 0 @@ -2797,7 +2933,7 @@ padding-left: 20px; 20 - 25 + 10 @@ -2987,6 +3123,11 @@ QLabel { + + adiscope::CustomSwitch + QPushButton +
customSwitch.hpp
+
adiscope::DetachDragZone QWidget @@ -3004,11 +3145,6 @@ QLabel { QPushButton
linked_button.hpp
- - adiscope::CustomSwitch - QPushButton -
customSwitch.hpp
-
adiscope::MenuAnim QWidget @@ -3044,6 +3180,11 @@ QLabel {
customplotpositionbutton.h
1
+ + adiscope::SmallOnOffSwitch + QPushButton +
smallOnOffSwitch.hpp
+
diff --git a/ui/osc_general_settings.ui b/ui/osc_general_settings.ui index c3daf86530..ffec3aff2b 100644 --- a/ui/osc_general_settings.ui +++ b/ui/osc_general_settings.ui @@ -46,6 +46,9 @@ 0 + + QFrame::NoFrame + Qt::ScrollBarAsNeeded @@ -63,8 +66,8 @@ 0 0 - 265 - 473 + 267 + 475 diff --git a/ui/pattern_generator.ui b/ui/pattern_generator.ui index c616a8acd6..f5fd868151 100644 --- a/ui/pattern_generator.ui +++ b/ui/pattern_generator.ui @@ -1606,25 +1606,7 @@ QPushButton:checked { border-image: url(:/icons/setup_btn_checked.svg); } - QCheckBox { - spacing: 8px; - background-color: transparent; - font-size: 14px; - font-weight: bold; - -color: rgba(255, 255, 255, 153); -} - -QCheckBox::indicator { -width: 14px; - height: 14px; - border: 2px solid rgb(74,100,255); - border-radius: 4px; -} -QCheckBox::indicator:unchecked { background-color: transparent; } -QCheckBox::indicator:checked { background-color: rgb(74,100,255); } - -QPushButton { + QPushButton { width: 40px; height: 20px; background-color: transparent; diff --git a/ui/powercontrol.ui b/ui/powercontrol.ui index 372cf8395f..021506bc68 100644 --- a/ui/powercontrol.ui +++ b/ui/powercontrol.ui @@ -590,6 +590,9 @@ color: #9013fe; 0 + + QFrame::NoFrame + Qt::ScrollBarAlwaysOff @@ -602,7 +605,7 @@ color: #9013fe; 0 0 218 - 471 + 473 @@ -1088,6 +1091,11 @@ QPushButton:disabled { + + adiscope::CustomSwitch + QPushButton +
customSwitch.hpp
+
adiscope::DetachDragZone QWidget @@ -1105,11 +1113,6 @@ QPushButton:disabled { QPushButton
linked_button.hpp
- - adiscope::CustomSwitch - QPushButton -
customSwitch.hpp
-
QwtThermo QWidget diff --git a/ui/preferences.ui b/ui/preferences.ui index 96f1aed21f..12be93daf1 100644 --- a/ui/preferences.ui +++ b/ui/preferences.ui @@ -1591,40 +1591,6 @@ color: white;
- - - - 0 - - - - - - - - - - - - Enable Debug Messages (Only for Debugging, Bugreporting) - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - @@ -1704,6 +1670,40 @@ color: white; + + + + 0 + + + + + + + + + + + + Enable Debug Messages (Only for Debugging, Bugreporting) + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + +
diff --git a/ui/signal_generator.ui b/ui/signal_generator.ui index 383eed93a4..66f6bd9ef3 100644 --- a/ui/signal_generator.ui +++ b/ui/signal_generator.ui @@ -121,10 +121,7 @@ true - - - 0 - + 0 @@ -137,7 +134,7 @@ 0 - + diff --git a/ui/spectrum_analyzer.ui b/ui/spectrum_analyzer.ui index 101043b0e5..fec2e2c3a7 100644 --- a/ui/spectrum_analyzer.ui +++ b/ui/spectrum_analyzer.ui @@ -313,6 +313,26 @@ min-width: 6em; 10 + + + + + + + 0 + + + + + + + + 200 + 200 + + + + @@ -461,7 +481,7 @@ min-width: 6em; - 2 + 4 @@ -992,6 +1012,9 @@ min-width: 64px; + + QFrame::NoFrame + Qt::ScrollBarAlwaysOff @@ -1004,7 +1027,7 @@ min-width: 64px; 0 0 298 - 521 + 428 @@ -1362,7 +1385,7 @@ color: rgba(255,255,255,51); - + 0 0 @@ -1409,7 +1432,7 @@ color: rgba(255,255,255,51); - + 0 0 @@ -1496,6 +1519,9 @@ color: rgba(255,255,255,51); + + QFrame::NoFrame + Qt::ScrollBarAlwaysOff @@ -2178,6 +2204,7 @@ border-width: 0px; + @@ -2250,23 +2277,7 @@ border-width: 0px; - QCheckBox { - spacing: 8px; - background-color: transparent; - font-size: 14px; - font-weight: bold; -} - -QCheckBox::indicator { - width: 14px; - height: 14px; - border: 2px solid rgb(74,100,255); - border-radius: 4px; -} -QCheckBox::indicator:unchecked { background-color: transparent; } -QCheckBox::indicator:checked { background-color: rgb(74,100,255); } - -QPushButton { + QPushButton { width: 40px; height: 20px; background-color: transparent; @@ -2277,6 +2288,42 @@ QPushButton:hover:!pressed:!checked { border-image: url(:/icons/setup_btn_hover. QPushButton:checked { border-image: url(:/icons/setup_btn_checked.svg); } + + + + Cursors + + + + + + + false + + + + + + true + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 10 + + + + @@ -2351,25 +2398,20 @@ QPushButton:checked { border-image: url(:/icons/setup_btn_checked.svg); }1 - adiscope::InstrumentNotes + adiscope::MenuAnim QWidget -
instrumentnotes.h
+
menu_anim.hpp
1
- adiscope::LinkedButton - QPushButton -
linked_button.hpp
-
- - adiscope::CustomSwitch + adiscope::CustomPushButton QPushButton -
customSwitch.hpp
+
customPushButton.hpp
- adiscope::MenuAnim + adiscope::InstrumentNotes QWidget -
menu_anim.hpp
+
instrumentnotes.h
1
@@ -2379,9 +2421,14 @@ QPushButton:checked { border-image: url(:/icons/setup_btn_checked.svg); }1 - adiscope::CustomPushButton + adiscope::CustomSwitch QPushButton -
customPushButton.hpp
+
customSwitch.hpp
+
+ + adiscope::LinkedButton + QPushButton +
linked_button.hpp
adiscope::MarkerTable @@ -2400,5 +2447,38 @@ QPushButton:checked { border-image: url(:/icons/setup_btn_checked.svg); } - + + + boxCursors + toggled(bool) + btnCursors + setEnabled(bool) + + + 654 + 635 + + + 719 + 635 + + + + + btnCursors + toggled(bool) + btnSettings + setChecked(bool) + + + 719 + 635 + + + 922 + 35 + + + +